From 308254b7d758158b46db42adf6a03b209f738c86 Mon Sep 17 00:00:00 2001 From: "Sujay V. Kumar" Date: Tue, 16 Jan 2024 11:43:42 -0500 Subject: [PATCH] Added the support for CNN-based snow Added the support in LIS for data assimilation of CNN-based AMSR snow retrievals Support for the same dataset was also added in LVT Resolves #1479 --- .../obs/AMSRcnnSnow/AMSRcnnSnowMod.F90 | 339 ++++++++++++++++++ .../obs/AMSRcnnSnow/read_AMSRcnnSnow.F90 | 309 ++++++++++++++++ .../obs/AMSRcnnSnow/write_AMSRcnnSnow.F90 | 115 ++++++ lis/make/default.cfg | 6 + lis/plugins/LIS_DAobs_pluginMod.F90 | 19 + lis/plugins/LIS_lsmda_pluginMod.F90 | 55 ++- lis/plugins/LIS_pluginIndices.F90 | 1 + .../noahmp401_qc_withforest_snowobs.F90 | 102 ++++++ .../da_snow/noahmp401_snow_update.F90 | 33 +- .../da_snwd/noahmp401_dasnwd_Mod.F90 | 49 +++ .../da_snwd/noahmp401_descale_snwd.F90 | 57 +++ .../da_snwd/noahmp401_getsnwdpred.F90 | 59 +++ .../da_snwd/noahmp401_getsnwdvars.F90 | 66 ++++ .../da_snwd/noahmp401_qc_snwdobs.F90 | 102 ++++++ .../noahmp.4.0.1/da_snwd/noahmp401_qcsnwd.F90 | 110 ++++++ .../da_snwd/noahmp401_scale_snwd.F90 | 56 +++ .../da_snwd/noahmp401_setsnwdvars.F90 | 82 +++++ .../da_snwd/noahmp401_updatesnwdvars.F90 | 161 +++++++++ .../AMSREcnnSnow/AMSREcnnSnow_obsMod.F90 | 154 ++++++++ .../AMSREcnnSnow/readAMSREcnnSnowObs.F90 | 218 +++++++++++ .../AMSRcnnSnow/AMSRcnnSnow_obsMod.F90 | 154 ++++++++ .../AMSRcnnSnow/readAMSRcnnSnowObs.F90 | 218 +++++++++++ lvt/make/Filepath | 2 +- lvt/plugins/LVT_datastream_pluginMod.F90 | 7 + lvt/plugins/LVT_pluginIndices.F90 | 1 + 25 files changed, 2464 insertions(+), 11 deletions(-) create mode 100755 lis/dataassim/obs/AMSRcnnSnow/AMSRcnnSnowMod.F90 create mode 100755 lis/dataassim/obs/AMSRcnnSnow/read_AMSRcnnSnow.F90 create mode 100755 lis/dataassim/obs/AMSRcnnSnow/write_AMSRcnnSnow.F90 create mode 100644 lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_qc_withforest_snowobs.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_dasnwd_Mod.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_descale_snwd.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdpred.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdvars.F90 create mode 100644 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qc_snwdobs.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qcsnwd.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_scale_snwd.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_setsnwdvars.F90 create mode 100755 lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_updatesnwdvars.F90 create mode 100755 lvt/datastreams/AMSREcnnSnow/AMSREcnnSnow_obsMod.F90 create mode 100755 lvt/datastreams/AMSREcnnSnow/readAMSREcnnSnowObs.F90 create mode 100755 lvt/datastreams/AMSRcnnSnow/AMSRcnnSnow_obsMod.F90 create mode 100755 lvt/datastreams/AMSRcnnSnow/readAMSRcnnSnowObs.F90 diff --git a/lis/dataassim/obs/AMSRcnnSnow/AMSRcnnSnowMod.F90 b/lis/dataassim/obs/AMSRcnnSnow/AMSRcnnSnowMod.F90 new file mode 100755 index 000000000..940741c4c --- /dev/null +++ b/lis/dataassim/obs/AMSRcnnSnow/AMSRcnnSnowMod.F90 @@ -0,0 +1,339 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! +! !MODULE: AMSRcnnSnowMod +! +! !DESCRIPTION: +! This module contains interfaces and subroutines to +! handle the Margulis Western US Snow Reanalysis dataset. +! Available online at: https://nsidc.org/data/WUS_UCLA_SR/versions/1 +! +! !REVISION HISTORY: +! 05 Jan 2024: Sujay Kumar; Initial version +! +module AMSRcnnSnowMod +! !USES: + use ESMF + use map_utils + use LIS_constantsMod, only : LIS_CONST_PATH_LEN + + implicit none + + PRIVATE + +!----------------------------------------------------------------------------- +! !PUBLIC MEMBER FUNCTIONS: +!----------------------------------------------------------------------------- + public :: AMSRcnnSnow_setup +!----------------------------------------------------------------------------- +! !PUBLIC TYPES: +!----------------------------------------------------------------------------- + public :: AMSRcnnSnow_struc +!EOP + type, public:: AMSRcnnSnow_dec + + logical :: startMode + integer :: nc + integer :: nr + integer :: mi + real :: ssdev_inp + type(proj_info) :: proj + real :: gridDesci(50) + real, allocatable :: rlat(:) + real, allocatable :: rlon(:) + integer, allocatable :: n11(:) + integer, allocatable :: n12(:) + integer, allocatable :: n21(:) + integer, allocatable :: n22(:) + real, allocatable :: w11(:) + real, allocatable :: w12(:) + real, allocatable :: w21(:) + real, allocatable :: w22(:) + end type AMSRcnnSnow_dec + + type(AMSRcnnSnow_dec),allocatable :: AMSRcnnSnow_struc(:) + +contains + +!BOP +! +! !ROUTINE: AMSRcnnSnow_setup +! \label{AMSRcnnSnow_setup} +! +! !INTERFACE: + subroutine AMSRcnnSnow_setup(k, OBS_State, OBS_Pert_State) +! !USES: + use LIS_coreMod + use LIS_timeMgrMod + use LIS_historyMod + use LIS_dataAssimMod + use LIS_perturbMod + use LIS_logmod + use LIS_DAobservationsMod + + implicit none + +! !ARGUMENTS: + integer :: k + type(ESMF_State) :: OBS_State(LIS_rc%nnest) + type(ESMF_State) :: OBS_Pert_State(LIS_rc%nnest) +! +! !DESCRIPTION: +! +! This routine completes the runtime initializations and +! creation of data strctures required for handling +! AMSRcnnSnow data. +! +! The arguments are: +! \begin{description} +! \item[OBS\_State] observation state +! \item[OBS\_Pert\_State] observation perturbations state +! \end{description} +!EOP + + integer :: n,i,t,kk,c,r + real, allocatable :: obserr(:,:) + integer :: ftn + integer :: status + type(ESMF_Field) :: obsField(LIS_rc%nnest) + type(ESMF_ArraySpec) :: intarrspec, realarrspec + type(ESMF_Field) :: pertField(LIS_rc%nnest) + type(ESMF_ArraySpec) :: pertArrSpec + character(len=LIS_CONST_PATH_LEN) :: snodasobsdir + character*100 :: temp + character*1 :: vid(2) + character*40, allocatable :: vname(:) + real , allocatable :: varmin(:) + real , allocatable :: varmax(:) + type(pert_dec_type) :: obs_pert + real, pointer :: obs_temp(:,:) + real, allocatable :: ssdev(:) + real :: cornerlat1, cornerlat2 + real :: cornerlon1, cornerlon2 + + allocate(AMSRcnnSnow_struc(LIS_rc%nnest)) + + call ESMF_ArraySpecSet(intarrspec,rank=1,typekind=ESMF_TYPEKIND_I4,& + rc=status) + call LIS_verify(status) + + call ESMF_ArraySpecSet(realarrspec,rank=1,typekind=ESMF_TYPEKIND_R4,& + rc=status) + call LIS_verify(status) + + call ESMF_ArraySpecSet(pertArrSpec,rank=2,typekind=ESMF_TYPEKIND_R4,& + rc=status) + call LIS_verify(status) + + call ESMF_ConfigFindLabel(LIS_config,"AMSR CNN snow depth data directory:",& + rc=status) + do n=1,LIS_rc%nnest + call ESMF_ConfigGetAttribute(LIS_config,snodasobsdir,& + rc=status) + call LIS_verify(status, 'AMSR CNN snow depth data directory: is missing') + + call ESMF_AttributeSet(OBS_State(n),"Data Directory",& + snodasobsdir, rc=status) + call LIS_verify(status) + enddo + + do n=1,LIS_rc%nnest + call ESMF_AttributeSet(OBS_State(n),"Data Update Status",& + .false., rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(OBS_State(n),"Data Update Time",& + -99.0, rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(OBS_State(n),"Data Assimilate Status",& + .false., rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(OBS_State(n),"Number Of Observations",& + LIS_rc%obs_ngrid(k),rc=status) + call LIS_verify(status) + + enddo + + write(LIS_logunit,*)'[INFO] read AMSR CNN snow depth data specifications' + +!---------------------------------------------------------------------------- +! Create the array containers that will contain the observations and +! the perturbations. AMSRcnnSnow +! observations are in the grid space. Since there is only one layer +! being assimilated, the array size is LIS_rc%obs_ngrid(k). +! +!---------------------------------------------------------------------------- + + do n=1,LIS_rc%nnest + + write(unit=temp,fmt='(i2.2)') 1 + read(unit=temp,fmt='(2a1)') vid + + obsField(n) = ESMF_FieldCreate(arrayspec=realarrspec,& + grid=LIS_obsvecGrid(n,k),& + name="Observation"//vid(1)//vid(2),rc=status) + call LIS_verify(status) + +!Perturbations State + write(LIS_logunit,*) '[INFO] Opening attributes for observations ',& + trim(LIS_rc%obsattribfile(k)) + ftn = LIS_getNextUnitNumber() + open(ftn,file=trim(LIS_rc%obsattribfile(k)),status='old') + read(ftn,*) + read(ftn,*) LIS_rc%nobtypes(k) + read(ftn,*) + + allocate(vname(LIS_rc%nobtypes(k))) + allocate(varmax(LIS_rc%nobtypes(k))) + allocate(varmin(LIS_rc%nobtypes(k))) + + do i=1,LIS_rc%nobtypes(k) + read(ftn,fmt='(a40)') vname(i) + read(ftn,*) varmin(i),varmax(i) + write(LIS_logunit,*) '[INFO] ',vname(i),varmin(i),varmax(i) + enddo + call LIS_releaseUnitNumber(ftn) + + allocate(ssdev(LIS_rc%obs_ngrid(k))) + + if(trim(LIS_rc%perturb_obs(k)).ne."none") then + allocate(obs_pert%vname(1)) + allocate(obs_pert%perttype(1)) + allocate(obs_pert%ssdev(1)) + allocate(obs_pert%stdmax(1)) + allocate(obs_pert%zeromean(1)) + allocate(obs_pert%tcorr(1)) + allocate(obs_pert%xcorr(1)) + allocate(obs_pert%ycorr(1)) + allocate(obs_pert%ccorr(1,1)) + + call LIS_readPertAttributes(1,LIS_rc%obspertAttribfile(k),& + obs_pert) + +! Set obs err to be uniform (will be rescaled later for each grid point). + ssdev = obs_pert%ssdev(1) + AMSRcnnSnow_struc(n)%ssdev_inp = obs_pert%ssdev(1) + + pertField(n) = ESMF_FieldCreate(arrayspec=pertArrSpec,& + grid=LIS_obsensOnGrid(n,k),name="Observation"//vid(1)//vid(2),& + rc=status) + call LIS_verify(status) + +! initializing the perturbations to be zero + call ESMF_FieldGet(pertField(n),localDE=0,farrayPtr=obs_temp,rc=status) + call LIS_verify(status) + obs_temp(:,:) = 0 + + call ESMF_AttributeSet(pertField(n),"Perturbation Type",& + obs_pert%perttype(1), rc=status) + call LIS_verify(status) + + if(LIS_rc%obs_ngrid(k).gt.0) then + call ESMF_AttributeSet(pertField(n),"Standard Deviation",& + ssdev,itemCount=LIS_rc%obs_ngrid(k),rc=status) + call LIS_verify(status) + endif + + call ESMF_AttributeSet(pertField(n),"Std Normal Max",& + obs_pert%stdmax(1), rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(pertField(n),"Ensure Zero Mean",& + obs_pert%zeromean(1),rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(pertField(n),"Temporal Correlation Scale",& + obs_pert%tcorr(1),rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(pertField(n),"X Correlation Scale",& + obs_pert%xcorr(1),rc=status) + + call ESMF_AttributeSet(pertField(n),"Y Correlation Scale",& + obs_pert%ycorr(1),rc=status) + + call ESMF_AttributeSet(pertField(n),"Cross Correlation Strength",& + obs_pert%ccorr(1,:),itemCount=1,rc=status) + + endif + + deallocate(vname) + deallocate(varmax) + deallocate(varmin) + deallocate(ssdev) + + enddo + write(LIS_logunit,*) & + '[INFO] Created the States to hold the AMSR CNN snow observations data' + + do n=1,LIS_rc%nnest + + AMSRcnnSnow_struc(n)%nc = 3599 + AMSRcnnSnow_struc(n)%nr = 700 + + AMSRcnnSnow_struc(n)%gridDesci(1) = 0 + AMSRcnnSnow_struc(n)%gridDesci(2) = AMSRcnnSnow_struc(n)%nc + AMSRcnnSnow_struc(n)%gridDesci(3) = AMSRcnnSnow_struc(n)%nr + AMSRcnnSnow_struc(n)%gridDesci(4) = 0.025 + AMSRcnnSnow_struc(n)%gridDesci(5) = -179.975 + AMSRcnnSnow_struc(n)%gridDesci(6) = 128 + AMSRcnnSnow_struc(n)%gridDesci(7) = 69.925 + AMSRcnnSnow_struc(n)%gridDesci(8) = 179.825 + AMSRcnnSnow_struc(n)%gridDesci(9) = 0.1 + AMSRcnnSnow_struc(n)%gridDesci(10) = 0.1 + AMSRcnnSnow_struc(n)%gridDesci(20) = 64 + + AMSRcnnSnow_struc(n)%mi = AMSRcnnSnow_struc(n)%nc*AMSRcnnSnow_struc(n)%nr + +!----------------------------------------------------------------------------- +! Use interpolation if LIS is running finer than 500 m. +!----------------------------------------------------------------------------- + + allocate(AMSRcnnSnow_struc(n)%rlat(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%rlon(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%n11(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%n12(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%n21(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%n22(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%w11(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%w12(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%w21(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + allocate(AMSRcnnSnow_struc(n)%w22(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k))) + + call bilinear_interp_input_withgrid(& + AMSRcnnSnow_struc(n)%gridDesci(:), & + LIS_rc%obs_gridDesc(k,:),& + LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k),& + AMSRcnnSnow_struc(n)%rlat, AMSRcnnSnow_struc(n)%rlon,& + AMSRcnnSnow_struc(n)%n11, AMSRcnnSnow_struc(n)%n12, & + AMSRcnnSnow_struc(n)%n21, AMSRcnnSnow_struc(n)%n22, & + AMSRcnnSnow_struc(n)%w11, AMSRcnnSnow_struc(n)%w12, & + AMSRcnnSnow_struc(n)%w21, AMSRcnnSnow_struc(n)%w22) + + + call LIS_registerAlarm("AMSRcnnSnow read alarm",& + 86400.0, 86400.0) + AMSRcnnSnow_struc(n)%startMode = .true. + + call ESMF_StateAdd(OBS_State(n),(/obsField(n)/),rc=status) + call LIS_verify(status) + + call ESMF_StateAdd(OBS_Pert_State(n),(/pertField(n)/),rc=status) + call LIS_verify(status) + + enddo + + + end subroutine AMSRcnnSnow_setup + +end module AMSRcnnSnowMod diff --git a/lis/dataassim/obs/AMSRcnnSnow/read_AMSRcnnSnow.F90 b/lis/dataassim/obs/AMSRcnnSnow/read_AMSRcnnSnow.F90 new file mode 100755 index 000000000..df3ccd127 --- /dev/null +++ b/lis/dataassim/obs/AMSRcnnSnow/read_AMSRcnnSnow.F90 @@ -0,0 +1,309 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +#include "LIS_misc.h" +!BOP +! !ROUTINE: read_AMSRcnnSnow +! \label{read_AMSRcnnSnow} +! +! !REVISION HISTORY: +! 08 Jun 2022: Sujay Kumar; Initial version +! +! !INTERFACE: +subroutine read_AMSRcnnSnow(n, k, OBS_State, OBS_Pert_State) +! !USES: + use ESMF + use LIS_mpiMod + use LIS_coreMod + use LIS_logMod + use LIS_timeMgrMod + use LIS_dataAssimMod + use map_utils + use LIS_pluginIndices + use LIS_DAobservationsMod + use LIS_constantsMod, only : LIS_CONST_PATH_LEN + use AMSRcnnSnowMod, only : AMSRcnnSnow_struc +#if ( defined USE_NETCDF3 || defined USE_NETCDF4 ) + use netcdf +#endif + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: k + type(ESMF_State) :: OBS_State + type(ESMF_State) :: OBS_Pert_State +! +! !DESCRIPTION: +! +! reads the AMSRcnnSnow observations and prepares them for DA +! +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest +! \item[OBS\_State] observations state +! \end{description} +! +!EOP + integer :: ftn,status + character(len=LIS_CONST_PATH_LEN) :: sndobsdir + character(len=LIS_CONST_PATH_LEN) :: fname + logical :: alarmCheck + integer :: t,c,r,i,j,p,jj + integer :: sndId,ierr + real, pointer :: obsl(:) + type(ESMF_Field) :: sndfield, pertField + logical*1 :: sndobs_b_ip(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k)) + integer :: gid(LIS_rc%obs_ngrid(k)) + integer :: assimflag(LIS_rc%obs_ngrid(k)) + logical :: data_update + logical :: data_upd_flag(LIS_npes) + logical :: data_upd_flag_local + logical :: data_upd + logical*1, allocatable :: snd_data_b(:) + real :: sndobs(LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k)) + real, allocatable :: var(:,:) + real, allocatable :: snd1d(:) + real :: snd_current(LIS_rc%obs_lnc(k),LIS_rc%obs_lnr(k)) + integer :: fnd + logical :: file_exists + + call ESMF_AttributeGet(OBS_State,"Data Directory",& + sndobsdir, rc=status) + call LIS_verify(status) + call ESMF_AttributeGet(OBS_State,"Data Update Status",& + data_update, rc=status) + call LIS_verify(status) + + sndobs = LIS_rc%udef + data_upd = .false. +!------------------------------------------------------------------------- +! Read both ascending and descending passes at 0Z and then store +! the overpass time as 1.30AM for the descending pass and 1.30PM +! for the ascending pass. +!------------------------------------------------------------------------- + alarmCheck = LIS_isAlarmRinging(LIS_rc, "AMSRcnnSnow read alarm") + + if(alarmCheck.or.AMSRcnnSnow_struc(n)%startMode) then + AMSRcnnSnow_struc(n)%startMode = .false. + sndobs = LIS_rc%udef + + call create_AMSRcnnSnow_filename(sndobsdir, & + LIS_rc%yr, LIS_rc%mo, & + LIS_rc%da, fname) + + inquire(file=fname,exist=file_exists) + + if(file_exists) then + + write(LIS_logunit,*) '[INFO] Reading ',trim(fname) + allocate(snd_data_b(AMSRcnnSnow_struc(n)%nc*AMSRcnnSnow_struc(n)%nr)) + allocate(var(AMSRcnnSnow_struc(n)%nc,AMSRcnnSnow_struc(n)%nr)) + allocate(snd1d(AMSRcnnSnow_struc(n)%nc*AMSRcnnSnow_struc(n)%nr)) + +#if ( defined USE_NETCDF3 || defined USE_NETCDF4 ) + ierr = nf90_open(path=fname,mode=NF90_NOWRITE,ncid=ftn) + call LIS_verify(ierr,'error opening AMSR CNN file') + + ierr = nf90_inq_varid(ftn,'SD',sndId) + call LIS_verify(ierr, 'nf90_inq_varid failed for SDin read_AMSRcnnSnow') + + ierr = nf90_get_var(ftn,sndId, var) + call LIS_verify(ierr, 'nf90_get_var failed for SD') + + ierr = nf90_close(ftn) + call LIS_verify(ierr) +#endif + + snd1d = LIS_rc%udef + snd_data_b = .false. + + do r=1, AMSRcnnSnow_struc(n)%nr + do c=1, AMSRcnnSnow_struc(n)%nc + if(var(c,r).lt.0.or.var(c,r).gt.1000) then + snd1d(c+(AMSRcnnSnow_struc(n)%nr-r)*& + AMSRcnnSnow_struc(n)%nc) = -9999.0 + else + snd1d(c+(AMSRcnnSnow_struc(n)%nr-r)*& + AMSRcnnSnow_struc(n)%nc) = var(c,r)/100.0 !to meters + snd_data_b(c+(AMSRcnnSnow_struc(n)%nr-r)*& + AMSRcnnSnow_struc(n)%nc) = .true. + endif + enddo + enddo + deallocate(var) + +!-------------------------------------------------------------------------- +! Interpolate to the observation grid +!-------------------------------------------------------------------------- + call bilinear_interp(LIS_rc%gridDesc(k,:),& + snd_data_b,snd1d,& + sndobs_b_ip,sndobs,& + AMSRcnnSnow_struc(n)%nc*AMSRcnnSnow_struc(n)%nr,& + LIS_rc%obs_lnc(k)*LIS_rc%obs_lnr(k),& + AMSRcnnSnow_struc(n)%rlat, & + AMSRcnnSnow_struc(n)%rlon, & + AMSRcnnSnow_struc(n)%w11,& + AMSRcnnSnow_struc(n)%w12,& + AMSRcnnSnow_struc(n)%w21,& + AMSRcnnSnow_struc(n)%w22,& + AMSRcnnSnow_struc(n)%n11,& + AMSRcnnSnow_struc(n)%n12,& + AMSRcnnSnow_struc(n)%n21,& + AMSRcnnSnow_struc(n)%n22,& + LIS_rc%udef,status) + + deallocate(snd1d) + deallocate(snd_data_b) + + endif + + call ESMF_StateGet(OBS_State,"Observation01",sndfield,& + rc=status) + call LIS_verify(status, 'Error: StateGet Observation01') + + call ESMF_FieldGet(sndfield,localDE=0,farrayPtr=obsl,rc=status) + call LIS_verify(status, 'Error: FieldGet') + + fnd = 0 + + + do r=1,LIS_rc%obs_lnr(k) + do c=1,LIS_rc%obs_lnc(k) + if(LIS_obs_domain(n,k)%gindex(c,r).ne.-1) then + + if(sndobs(c+(r-1)*LIS_rc%obs_lnc(k)).ge.0) then + fnd = 1 + exit + endif + endif + enddo + enddo + + obsl = LIS_rc%udef + if(fnd.ne.0) then + do r=1, LIS_rc%obs_lnr(k) + do c=1, LIS_rc%obs_lnc(k) + if(LIS_obs_domain(n,k)%gindex(c,r).ne.-1) then + obsl(LIS_obs_domain(n,k)%gindex(c,r))=& + sndobs(c+(r-1)*LIS_rc%obs_lnc(k)) + endif + enddo + enddo + endif + +!------------------------------------------------------------------------- +! Apply LSM based quality control and screening of observations +!------------------------------------------------------------------------- + call lsmdaqcobsstate(trim(LIS_rc%lsm)//"+"& + //trim(LIS_AMSRcnnSnowobsId)//char(0),n, k, OBS_state) + + snd_current = LIS_rc%udef + call LIS_checkForValidObs(n,k,obsl,fnd,sndobs) + + + if(fnd.eq.0) then + data_upd_flag_local = .false. + else + data_upd_flag_local = .true. + endif + +#if (defined SPMD) + call MPI_ALLGATHER(data_upd_flag_local,1, & + MPI_LOGICAL, data_upd_flag(:),& + 1, MPI_LOGICAL, LIS_mpi_comm, status) + data_upd = any(data_upd_flag) +#else + data_upd = data_upd_flag_local +#endif + + if(data_upd) then + do t=1,LIS_rc%obs_ngrid(k) + gid(t) = t + if(obsl(t).ne.-9999.0) then + assimflag(t) = 1 + if(obsl(t).gt.10.0) then + !print *,'WARNING: OBSL > 10.0m; OBSL=',obsl(t) + assimflag(t) = 0 !Do not assimilate values > 10m + endif + else + assimflag(t) = 0 + endif + enddo + + call ESMF_AttributeSet(OBS_State,"Data Update Status",& + .true. , rc=status) + call LIS_verify(status) + + if(LIS_rc%obs_ngrid(k).gt.0) then + call ESMF_AttributeSet(sndField,"Grid Number",& + gid,itemCount=LIS_rc%obs_ngrid(k),rc=status) + call LIS_verify(status) + + call ESMF_AttributeSet(sndField,"Assimilation Flag",& + assimflag,itemCount=LIS_rc%obs_ngrid(k),rc=status) + call LIS_verify(status) + + endif + + else + call ESMF_AttributeSet(OBS_State,"Data Update Status",& + .false., rc=status) + call LIS_verify(status) + endif + else + call ESMF_AttributeSet(OBS_State,"Data Update Status",& + .false., rc=status) + call LIS_verify(status) + endif +end subroutine read_AMSRcnnSnow + + +!BOP +! !ROUTINE: create_AMSRcnnSnow_filename +! \label{create_AMSRcnnSnow_filename} +! +! !INTERFACE: +subroutine create_AMSRcnnSnow_filename(ndir, yr, mo,da, filename) +! !USES: + + implicit none +! !ARGUMENTS: + character(len=*) :: filename + integer :: yr, mo, da + character (len=*) :: ndir +! +! !DESCRIPTION: +! This subroutine creates the AMSRcnnSnow data filename +! +! The arguments are: +! \begin{description} +! \item[ndir] name of the AMSRcnnSnow directory +! \item[yr] current year +! \item[mo] current month +! \item[da] current day +! \item[filename] Generated AMSRcnnSnow filename +! \end{description} +!EOP + + character (len=4) :: fyr + character (len=2) :: fmo,fda + + write(unit=fyr, fmt='(i4.4)') yr + write(unit=fmo, fmt='(i2.2)') mo + write(unit=fda, fmt='(i2.2)') da + + filename = trim(ndir)//'/'//fyr//& + '/AMSR_CNN_NH_'//trim(fyr)//'-'//& + trim(fmo)//'-'//trim(fda)//'.nc' + +end subroutine create_AMSRcnnSnow_filename + + diff --git a/lis/dataassim/obs/AMSRcnnSnow/write_AMSRcnnSnow.F90 b/lis/dataassim/obs/AMSRcnnSnow/write_AMSRcnnSnow.F90 new file mode 100755 index 000000000..1d472fbe9 --- /dev/null +++ b/lis/dataassim/obs/AMSRcnnSnow/write_AMSRcnnSnow.F90 @@ -0,0 +1,115 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! +! !ROUTINE: write_AMSRcnnSnow +! \label{write_AMSRcnnSnow} +! +! !REVISION HISTORY: +! 04 Jan 2024: Sujay Kumar; Initial version +! +! !INTERFACE: +subroutine write_AMSRcnnSnow(n, k, OBS_State) +! !USES: + use ESMF + use LIS_coreMod + use LIS_logMod + use LIS_fileIOMod + use LIS_historyMod + use LIS_DAobservationsMod + use LIS_constantsMod, only : LIS_CONST_PATH_LEN + + implicit none + +! !ARGUMENTS: + + integer, intent(in) :: n + integer, intent(in) :: k + type(ESMF_State) :: OBS_State +! +! !DESCRIPTION: +! +! writes the transformed (interpolated/upscaled/reprojected) +! AMSRcnnSnow observations a file +! +!EOP + type(ESMF_Field) :: snowfield + logical :: data_update + real, pointer :: sndobs(:) + character(len=LIS_CONST_PATH_LEN) :: obsname + integer :: ftn + integer :: status + + call ESMF_AttributeGet(OBS_State, "Data Update Status", & + data_update, rc=status) + call LIS_verify(status) + + if(data_update) then + + call ESMF_StateGet(OBS_State, "Observation01",snowfield, & + rc=status) + call LIS_verify(status) + + call ESMF_FieldGet(snowfield, localDE=0, farrayPtr=sndobs, rc=status) + call LIS_verify(status) + + + if(LIS_masterproc) then + ftn = LIS_getNextUnitNumber() + call AMSRcnnSnow_obsname(n,k,obsname) + + call LIS_create_output_directory('DAOBS') + open(ftn,file=obsname, form='unformatted') + endif + + call LIS_writevar_gridded_obs(ftn,n,k,sndobs) + + if(LIS_masterproc) then + call LIS_releaseUnitNumber(ftn) + endif + + endif + +end subroutine write_AMSRcnnSnow + +!BOP +! !ROUTINE: AMSRcnnSnow_obsname +! \label{AMSRcnnSnow_obsname} +! +! !INTERFACE: +subroutine AMSRcnnSnow_obsname(n,k,obsname) +! !USES: + use LIS_coreMod, only : LIS_rc + +! !ARGUMENTS: + integer :: n + integer :: k + character(len=*) :: obsname +! +! !DESCRIPTION: +! +!EOP + + character(len=12) :: cdate1 + character(len=12) :: cdate + character(len=10) :: cda + + write(unit=cda, fmt='(a2,i2.2)') '.a',k + write(unit=cdate, fmt='(a2,i2.2)') '.d',n + + write(unit=cdate1, fmt='(i4.4, i2.2, i2.2, i2.2, i2.2)') & + LIS_rc%yr, LIS_rc%mo, & + LIS_rc%da, LIS_rc%hr,LIS_rc%mn + + obsname = trim(LIS_rc%odir)//'/DAOBS/'//cdate1(1:6)//& + '/LISDAOBS_'//cdate1// & + trim(cda)//trim(cdate)//'.1gs4r' + +end subroutine AMSRcnnSnow_obsname diff --git a/lis/make/default.cfg b/lis/make/default.cfg index c3b6bf886..8008a4564 100644 --- a/lis/make/default.cfg +++ b/lis/make/default.cfg @@ -766,6 +766,11 @@ enabled: True macro: DA_OBS_GCOMW_AMSR2L3SND path: dataassim/obs/GCOMW_AMSR2L3SND +[DA OBS AMSRCNNSND] +enabled: True +macro: DA_OBS_AMSRCNNSND +path: dataassim/obs/AMSRcnnSnow + [DA OBS SNODAS] enabled: True macro: DA_OBS_SNODAS @@ -1189,6 +1194,7 @@ dependent_comps: WRF coupling, WRF coupling path: surfacemodels/land/noahmp.4.0.1/cpl_wrf_noesmf virtual_da path: surfacemodels/land/noahmp.4.0.1/da_soilm, surfacemodels/land/noahmp.4.0.1/da_snow, + surfacemodels/land/noahmp.4.0.1/da_snwd, surfacemodels/land/noahmp.4.0.1/da_LAI, surfacemodels/land/noahmp.4.0.1/da_tws, surfacemodels/land/noahmp.4.0.1/da_snodep, diff --git a/lis/plugins/LIS_DAobs_pluginMod.F90 b/lis/plugins/LIS_DAobs_pluginMod.F90 index 29ea506db..b9e53e792 100644 --- a/lis/plugins/LIS_DAobs_pluginMod.F90 +++ b/lis/plugins/LIS_DAobs_pluginMod.F90 @@ -225,6 +225,11 @@ subroutine LIS_DAobs_plugin use GCOMW_AMSR2L3SND_Mod, only : GCOMW_AMSR2L3SND_setup #endif +#if ( defined DA_OBS_AMSRCNNSND ) + use AMSRcnnSnowMod, only : AMSRcnnSnow_setup +#endif + + #if ( defined DA_OBS_SMOS_NESDIS ) use SMOSNESDISsm_Mod, only : SMOSNESDISsm_setup #endif @@ -423,6 +428,10 @@ subroutine LIS_DAobs_plugin external read_GCOMW_AMSR2L3SND, write_GCOMW_AMSR2L3sndobs #endif +#if ( defined DA_OBS_AMSRCNNSND ) + external read_AMSRcnnSnow, write_AMSRcnnSnow +#endif + #if ( defined DA_OBS_HYDROWEBWL ) external read_hydrowebWLobs, write_hydrowebWLobs #endif @@ -664,6 +673,16 @@ subroutine LIS_DAobs_plugin write_GCOMW_AMSR2L3sndobs) #endif +#if ( defined DA_OBS_AMSRCNNSND ) + call registerdaobsclass(trim(LIS_AMSRcnnSnowobsId),"LSM") + call registerdaobssetup(trim(LIS_AMSRcnnSnowobsId)//char(0), & + AMSRcnnSnow_setup) + call registerreaddaobs(trim(LIS_AMSRcnnSnowobsId)//char(0), & + read_AMSRcnnSnow) + call registerwritedaobs(trim(LIS_AMSRcnnSnowobsId)//char(0), & + write_AMSRcnnSnow) +#endif + #if ( defined DA_OBS_ANSA_SNWD ) !ANSA SNWD snow obs call registerdaobsclass(trim(LIS_ANSASNWDsnowobsId),"LSM") diff --git a/lis/plugins/LIS_lsmda_pluginMod.F90 b/lis/plugins/LIS_lsmda_pluginMod.F90 index 843266bd3..616fb64d1 100644 --- a/lis/plugins/LIS_lsmda_pluginMod.F90 +++ b/lis/plugins/LIS_lsmda_pluginMod.F90 @@ -200,6 +200,7 @@ subroutine LIS_lsmda_plugin #if ( defined SM_NOAHMP_4_0_1 ) use NoahMP401_dasoilm_Mod use NoahMP401_dasnow_Mod + use NoahMP401_dasnwd_Mod use noahmp401_dasnodep_Mod use noahmp401_dausafsi_Mod use noahmp401_tws_DAlogMod, only : noahmp401_tws_DAlog @@ -484,11 +485,21 @@ subroutine LIS_lsmda_plugin external NoahMP401_getsnowpred external NoahMP401_getswepred external NoahMP401_qcsnow + external NoahMP401_qc_withforest_snowobs external NoahMP401_qc_snowobs external NoahMP401_scale_snow external NoahMP401_descale_snow external NoahMP401_updatesnowvars + external NoahMP401_getsnwdvars + external NoahMP401_setsnwdvars + external NoahMP401_getsnwdpred + external NoahMP401_qcsnwd + external NoahMP401_qc_snwdobs + external NoahMP401_scale_snwd + external NoahMP401_descale_snwd + external NoahMP401_updatesnwdvars + external noahmp401_getvegvars external noahmp401_setvegvars external noahmp401_updatevegvars @@ -2991,10 +3002,50 @@ subroutine LIS_lsmda_plugin trim(LIS_GCOMW_AMSR2L3sndobsId)//char(0),NoahMP401_descale_snow) call registerlsmdaupdatestate(trim(LIS_noahmp401Id)//"+"//& trim(LIS_GCOMW_AMSR2L3sndobsId)//char(0),NoahMP401_updatesnowvars) - call registerlsmdaqcobsstate(trim(LIS_noahmp401Id)//"+"//& - trim(LIS_GCOMW_AMSR2L3sndobsId)//char(0),NoahMP401_qc_snowobs) + #endif +!#if 0 + call registerlsmdainit(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),noahmp401_dasnwd_init) + call registerlsmdagetstatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_getsnwdvars) + call registerlsmdasetstatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_setsnwdvars) + call registerlsmdagetobspred(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_getsnwdpred) + call registerlsmdaqcstate(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_qcsnwd) + call registerlsmdaqcobsstate(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),noahmp401_qc_snwdobs) + call registerlsmdascalestatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_scale_snwd) + call registerlsmdadescalestatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_descale_snwd) + call registerlsmdaupdatestate(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_updatesnwdvars) +#if 0 + + call registerlsmdainit(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),noahmp401_dasnow_init) + call registerlsmdagetstatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_getsnowvars) + call registerlsmdasetstatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_setsnowvars) + call registerlsmdagetobspred(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_getsnowpred) + call registerlsmdaqcstate(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_qcsnow) + call registerlsmdaqcobsstate(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),noahmp401_qc_withforest_snowobs) + call registerlsmdascalestatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_scale_snow) + call registerlsmdadescalestatevar(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_descale_snow) + call registerlsmdaupdatestate(trim(LIS_noahmp401Id)//"+"//& + trim(LIS_AMSRcnnSnowobsId)//char(0),NoahMP401_updatesnowvars) +#endif + ! Yeosang Yoon, SNODEP DA #if ( defined DA_OBS_SNODEP ) ! DA + snodep wirings diff --git a/lis/plugins/LIS_pluginIndices.F90 b/lis/plugins/LIS_pluginIndices.F90 index 4cb3d0bc8..9adc8cf55 100644 --- a/lis/plugins/LIS_pluginIndices.F90 +++ b/lis/plugins/LIS_pluginIndices.F90 @@ -248,6 +248,7 @@ module LIS_pluginIndices character*50, public, parameter :: LIS_AMSREsweobsId = "AMSR-E SWE" ! character*50, public, parameter :: LIS_AMSREsnowobsId = "AMSR-E snow" !yliu character*50, public, parameter :: LIS_PMWsnowobsId = "PMW snow" !yliu + character*50, public, parameter :: LIS_AMSRcnnSnowobsId = "AMSR CNN snow" character*50, public, parameter :: LIS_modisscfId = "MODIS SCF" character*50, public, parameter :: LIS_GRACEtwsobsId = "GRACE TWS" character*50, public, parameter :: LIS_simGRACEJPLobsId = "Simulated GRACE (JPL)" diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_qc_withforest_snowobs.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_qc_withforest_snowobs.F90 new file mode 100644 index 000000000..627899b91 --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_qc_withforest_snowobs.F90 @@ -0,0 +1,102 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_qc_snowobs +! \label{noahmp401_qc_snowobs} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 21 Jul 2011: James Geiger; Modified for Noah 3.2 +! 30 Jan 2015: Yuqiong Liu; added additional QC +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNOW +! +! !INTERFACE: +subroutine noahmp401_qc_withforest_snowobs(n,k,OBS_State) +! !USES: + use ESMF + use LIS_coreMod + use LIS_logMod, only : LIS_verify + use LIS_constantsMod, only : LIS_CONST_TKFRZ + use LIS_DAobservationsMod + use noahmp401_lsmMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: k + type(ESMF_State) :: OBS_State +! +! !DESCRIPTION: +! +! This subroutine performs any model-based QC of the observation +! prior to data assimilation. Here the snow observations +! are flagged when LSM indicates that (1) rain is falling (2) +! ground is fully or partially covered with snow. +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[OBS\_State] ESMF state container for observations \newline +! \end{description} +! +!EOP + type(ESMF_Field) :: obs_snow_field + + real, pointer :: snowobs(:) + integer :: t + integer :: gid + integer :: status + real :: stc1(LIS_rc%npatch(n,LIS_rc%lsm_index)) + real :: vegt(LIS_rc%npatch(n,LIS_rc%lsm_index)) + real :: tv_obs(LIS_rc%obs_ngrid(k)) + real :: stc1_obs(LIS_rc%obs_ngrid(k)) + real :: vegt_obs(LIS_rc%obs_ngrid(k)) + + call ESMF_StateGet(OBS_State,"Observation01",obs_snow_field,rc=status) + call LIS_verify(status,& + "ESMF_StateGet failed in noahmp401_qc_snowobs") + call ESMF_FieldGet(obs_snow_field,localDE=0,farrayPtr=snowobs,rc=status) + call LIS_verify(status,& + "ESMF_FieldGet failed in noahmp401_qc_snowobs") + + do t=1, LIS_rc%npatch(n,LIS_rc%lsm_index) + !stc1(t) = noahmp401_struc(n)%noahmp401(t)%sstc(1) ! get snow/veg temp. + stc1(t) = noahmp401_struc(n)%noahmp401(t)%tslb(1) ! get snow/veg temp. + vegt(t) = LIS_surface(n,1)%tile(t)%vegt + enddo + + call LIS_convertPatchSpaceToObsSpace(n,k,& + LIS_rc%lsm_index, noahmp401_struc(n)%noahmp401(:)%tv,tv_obs) !tv: vegetation temperature. unit: K + + call LIS_convertPatchSpaceToObsSpace(n,k,& + LIS_rc%lsm_index,stc1,stc1_obs) + call LIS_convertPatchSpaceToObsSpace(n,k,& + LIS_rc%lsm_index,vegt,vegt_obs) + + do t=1,LIS_rc%obs_ngrid(k) + if(snowobs(t).ne.LIS_rc%udef) then + if(vegt_obs(t).eq.LIS_rc%glacierclass) then !TML: Eliminate Glaciers + snowobs(t) = LIS_rc%udef +!assume that snow will not form at 5 deg. celcius or higher ground temp. + elseif(tv_obs(t).ge.278.15) then + snowobs(t) = LIS_rc%udef + elseif(stc1_obs(t).ge.278.15) then + snowobs(t) = LIS_rc%udef + endif + endif + enddo + +end subroutine noahmp401_qc_withforest_snowobs + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_snow_update.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_snow_update.F90 index 8f9173232..a02b109b9 100755 --- a/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_snow_update.F90 +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snow/noahmp401_snow_update.F90 @@ -226,24 +226,41 @@ subroutine noahmp401_snow_update(n, t, dsneqv, dsnowh) isnow = -2 dzsnso(-nsnow+1:isnow) = 0 dzsnso(isnow+1) = snowh -dzsnso(0) - ! scale swe in layers by ratio of depth to pack - do snl_idx=-nsnow+1,0 - snice(snl_idx) = sneqv*(dzsnso(snl_idx)/snowh) - enddo +! ! scale swe in layers by ratio of depth to pack +! do snl_idx=-nsnow+1,0 +! snice(snl_idx) = sneqv*(dzsnso(snl_idx)/snowh) +! enddo + if(snice(isnow+1).gt.dsneqv) then + snice(isnow+1) = snice(isnow+1)+dsneqv + else + snice(isnow+1) = 1.0 + snice(0) = sneqv-1.0 + endif snliq(-nsnow+1:isnow) = 0 ! all other cases elseif(snowh.le.(dzsnso(0)+dzsnso(-1)+dzsnso(-2))) then isnow = -3 dzsnso(isnow+1) = snowh -dzsnso(-1) -dzsnso(0) - ! scale swe in layers by ratio of depth to pack - do snl_idx=-nsnow+1,0 - snice(snl_idx) = sneqv*(dzsnso(snl_idx)/snowh) - enddo +! ! scale swe in layers by ratio of depth to pack +! do snl_idx=-nsnow+1,0 +! snice(snl_idx) = sneqv*(dzsnso(snl_idx)/snowh) +! enddo + if(snice(isnow+1).gt.dsneqv) then + snice(isnow+1) = snice(isnow+1)+dsneqv + else + snice(isnow+1) = 1.0 + snice(-1) = sneqv-1.0-snice(0) + endif snliq(-nsnow+1:isnow) = 0 endif endif endif +! check and correct layer number in instances when dzsnso of the top layer is zero + if(dzsnso(isnow+1).eq.0.) then + isnow = isnow + 1 + endif + ! ice fraction at the last timestep, add check for both snice and snliq are 0.0 do snl_idx=isnow+1,0 if(snice(snl_idx)+snliq(snl_idx)>0.0) then diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_dasnwd_Mod.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_dasnwd_Mod.F90 new file mode 100755 index 000000000..e5fefe9ed --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_dasnwd_Mod.F90 @@ -0,0 +1,49 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +#include "LIS_misc.h" +module noahmp401_dasnwd_Mod +!BOP +! +! !MODULE: noahmp401_dasnwd_Mod +! +! !DESCRIPTION: +! +! !REVISION HISTORY: +! +! !USES: + + implicit none + + PRIVATE +!----------------------------------------------------------------------------- +! !PUBLIC MEMBER FUNCTIONS: +!----------------------------------------------------------------------------- + public :: noahmp401_dasnwd_init +!----------------------------------------------------------------------------- +! !PUBLIC TYPES: +!----------------------------------------------------------------------------- +!EOP + + SAVE +contains +!BOP +! +! !ROUTINE: noahmp401_dasnwd_init +! \label{noahmp401_dasnwd_init} +! +! !INTERFACE: + subroutine noahmp401_dasnwd_init() +! !USES: +! !DESCRIPTION: +! +!EOP + implicit none + end subroutine noahmp401_dasnwd_init +end module noahmp401_dasnwd_Mod diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_descale_snwd.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_descale_snwd.F90 new file mode 100755 index 000000000..57e04e05d --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_descale_snwd.F90 @@ -0,0 +1,57 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_descale_snwd +! \label{noahmp401_descale_snwd} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! +! !INTERFACE: +subroutine noahmp401_descale_snwd(n, LSM_State, LSM_Incr_State) + +! !USES: + use ESMF + use LIS_coreMod, only : LIS_rc + use noahmp401_lsmMod + use LIS_logMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + type(ESMF_State) :: LSM_State + type(ESMF_State) :: LSM_Incr_State +! +! !DESCRIPTION: +! +! Returns the snwd related state prognostic variables for +! data assimilation +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[LSM\_State] ESMF State container for LSM state variables \newline +! \end{description} +!EOP + + type(ESMF_Field) :: snodField + + integer :: t + integer :: status + real, pointer :: snod(:) + + +end subroutine noahmp401_descale_snwd + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdpred.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdpred.F90 new file mode 100755 index 000000000..31dd71534 --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdpred.F90 @@ -0,0 +1,59 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_getsnwdpred +! \label{noahmp401_getsnwdpred} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 01 May 2014: Yuqiong Liu; modifed to include mesh8, mesh16, and 0p25 SNODEP data +! 24 May 2017: Yeosang Yoon: updated the file to work with the DA observation +! space updates. +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! +! !INTERFACE: +subroutine noahmp401_getsnwdpred(n, k, obs_pred) + +! !USES: + use ESMF + use LIS_coreMod, only : LIS_rc,LIS_surface + use noahmp401_lsmMod + use LIS_DAobservationsMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: k + real :: obs_pred(LIS_rc%ngrid(n),LIS_rc%nensem(n)) + real :: snwd(LIS_rc%npatch(n,LIS_rc%lsm_index)) +!EOP + +! !DESCRIPTION: +! This routine computes the obspred ('Hx') term for SNOW DA assimilation +! instances. + + integer :: t + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + snwd(t) = noahmp401_struc(n)%noahmp401(t)%snowh ! Keep in meters + enddo + + call LIS_convertPatchSpaceToObsEnsSpace(n,k,& + LIS_rc%lsm_index, & + snwd,& + obs_pred) + +end subroutine noahmp401_getsnwdpred + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdvars.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdvars.F90 new file mode 100755 index 000000000..3803b36b8 --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_getsnwdvars.F90 @@ -0,0 +1,66 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_getsnwdvars +! \label{noahmp401_getsnwdvars} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 03OC2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! +! !INTERFACE: +! +subroutine noahmp401_getsnwdvars(n, LSM_State) +! !USES: + use ESMF + use LIS_coreMod, only : LIS_rc + use LIS_logMod, only : LIS_verify + use noahmp401_lsmMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + type(ESMF_State) :: LSM_State +! +! !DESCRIPTION: +! +! Returns the snwd related state prognostic variables for +! data assimilation +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[LSM\_State] ESMF State container for LSM state variables \newline +! \end{description} +! +!EOP + type(ESMF_Field) :: snodField + + integer :: t + integer :: status + real, pointer :: snod(:) + + + call ESMF_StateGet(LSM_State,"Snowdepth",snodField,rc=status) + call LIS_verify(status) + + call ESMF_FieldGet(snodField,localDE=0,farrayPtr=snod,rc=status) + call LIS_verify(status) + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + snod(t) = noahmp401_struc(n)%noahmp401(t)%snowh + enddo +end subroutine noahmp401_getsnwdvars + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qc_snwdobs.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qc_snwdobs.F90 new file mode 100644 index 000000000..be37fab3b --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qc_snwdobs.F90 @@ -0,0 +1,102 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_qc_snwdobs +! \label{noahmp401_qc_snwdobs} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 21 Jul 2011: James Geiger; Modified for Noah 3.2 +! 30 Jan 2015: Yuqiong Liu; added additional QC +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! +! !INTERFACE: +subroutine noahmp401_qc_snwdobs(n,k,OBS_State) +! !USES: + use ESMF + use LIS_coreMod + use LIS_logMod, only : LIS_verify + use LIS_constantsMod, only : LIS_CONST_TKFRZ + use LIS_DAobservationsMod + use noahmp401_lsmMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: k + type(ESMF_State) :: OBS_State +! +! !DESCRIPTION: +! +! This subroutine performs any model-based QC of the observation +! prior to data assimilation. Here the snwd observations +! are flagged when LSM indicates that (1) rain is falling (2) +! ground is fully or partially covered with snwd. +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[OBS\_State] ESMF state container for observations \newline +! \end{description} +! +!EOP + type(ESMF_Field) :: obs_snwd_field + + real, pointer :: snwdobs(:) + integer :: t + integer :: gid + integer :: status + real :: stc1(LIS_rc%npatch(n,LIS_rc%lsm_index)) + real :: vegt(LIS_rc%npatch(n,LIS_rc%lsm_index)) + real :: tv_obs(LIS_rc%obs_ngrid(k)) + real :: stc1_obs(LIS_rc%obs_ngrid(k)) + real :: vegt_obs(LIS_rc%obs_ngrid(k)) + + call ESMF_StateGet(OBS_State,"Observation01",obs_snwd_field,rc=status) + call LIS_verify(status,& + "ESMF_StateGet failed in noahmp401_qc_snwdobs") + call ESMF_FieldGet(obs_snwd_field,localDE=0,farrayPtr=snwdobs,rc=status) + call LIS_verify(status,& + "ESMF_FieldGet failed in noahmp401_qc_snwdobs") + + do t=1, LIS_rc%npatch(n,LIS_rc%lsm_index) + !stc1(t) = noahmp401_struc(n)%noahmp401(t)%sstc(1) ! get snwd/veg temp. + stc1(t) = noahmp401_struc(n)%noahmp401(t)%tslb(1) ! get snwd/veg temp. + vegt(t) = LIS_surface(n,1)%tile(t)%vegt + enddo + + call LIS_convertPatchSpaceToObsSpace(n,k,& + LIS_rc%lsm_index, noahmp401_struc(n)%noahmp401(:)%tv,tv_obs) !tv: vegetation temperature. unit: K + + call LIS_convertPatchSpaceToObsSpace(n,k,& + LIS_rc%lsm_index,stc1,stc1_obs) + call LIS_convertPatchSpaceToObsSpace(n,k,& + LIS_rc%lsm_index,vegt,vegt_obs) + + do t=1,LIS_rc%obs_ngrid(k) + if(snwdobs(t).ne.LIS_rc%udef) then + if(vegt_obs(t).eq.LIS_rc%glacierclass) then !TML: Eliminate Glaciers + snwdobs(t) = LIS_rc%udef +!assume that snwd will not form at 5 deg. celcius or higher ground temp. + elseif(tv_obs(t).ge.278.15) then + snwdobs(t) = LIS_rc%udef + elseif(stc1_obs(t).ge.278.15) then + snwdobs(t) = LIS_rc%udef + endif + endif + enddo + +end subroutine noahmp401_qc_snwdobs + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qcsnwd.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qcsnwd.F90 new file mode 100755 index 000000000..09ff7e7d7 --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_qcsnwd.F90 @@ -0,0 +1,110 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_qcsnwd +! \label{noahmp401_qcsnwd} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 21 Jul 2011: James Geiger; Modified for Noah 3.2 +! 30 Jan 2015: Yuqiong Liu; added additional QC +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! 09 Jan 2020: Yeosang Yoon; update QC +! +! !INTERFACE: +subroutine noahmp401_qcsnwd(n, LSM_State) + +! !USES: + use ESMF + use LIS_coreMod + use noahmp401_lsmMod + use LIS_logMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + type(ESMF_State) :: LSM_State +! +! !DESCRIPTION: +! +! QC's the related state prognostic variable objects for +! SNWD data assimilation +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[LSM\_State] ESMF State container for LSM state variables \newline +! \end{description} +!EOP + type(ESMF_Field) :: snodField + integer :: t, gid + integer :: status + real, pointer :: snod(:) + + real :: swemax,snodmax + real :: swemin,snodmin + + real :: sndens + logical :: update_flag(LIS_rc%ngrid(n)) + + call ESMF_StateGet(LSM_State,"Snowdepth",snodField,rc=status) + call LIS_verify(status) + call ESMF_FieldGet(snodField,localDE=0,farrayPtr=snod,rc=status) + call LIS_verify(status) + + call ESMF_AttributeGet(snodField,"Max Value",snodmax,rc=status) + call LIS_verify(status) + call ESMF_AttributeGet(snodField,"Min Value",snodmin,rc=status) + call LIS_verify(status) + + update_flag = .true. + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + + gid = LIS_domain(n)%gindex(& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%col,& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%row) + + if((snod(t).lt.snodmin)) then + update_flag(gid) = .false. + endif + + enddo + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + gid = LIS_domain(n)%gindex(& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%col,& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%row) + +!Use the model's snow density from the previous timestep +! sndens = 0.0 +! if(noahmp401_struc(n)%noahmp401(t)%snowh.gt.0) then +! sndens = noahmp401_struc(n)%noahmp401(t)%sneqv/noahmp401_struc(n)%noahmp401(t)%snowh +! endif + +!If the update is unphysical, do not update. + if(update_flag(gid)) then + snod(t) = snod(t) + else ! do not update + snod(t) = noahmp401_struc(n)%noahmp401(t)%snowh + end if + + if(snod(t).gt.snodmax) then + snod(t) = snodmax + endif + + end do + +end subroutine noahmp401_qcsnwd + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_scale_snwd.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_scale_snwd.F90 new file mode 100755 index 000000000..6673cb46c --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_scale_snwd.F90 @@ -0,0 +1,56 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_scale_snwd +! \label{noahmp401_scale_snwd} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! +! !INTERFACE: +subroutine noahmp401_scale_snwd(n, LSM_State) + +! !USES: + use ESMF + use LIS_coreMod, only : LIS_rc + use noahmp401_lsmMod + use LIS_logMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + type(ESMF_State) :: LSM_State +! +! !DESCRIPTION: +! +! Returns the snwd related state prognostic variables for +! data assimilation +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[LSM\_State] ESMF State container for LSM state variables \newline +! \end{description} +!EOP + + type(ESMF_Field) :: snodField + + integer :: t + integer :: status + real, pointer :: snod(:) + +end subroutine noahmp401_scale_snwd + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_setsnwdvars.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_setsnwdvars.F90 new file mode 100755 index 000000000..e3bb64925 --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_setsnwdvars.F90 @@ -0,0 +1,82 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_setsnwdvars +! \label{noahmp401_setsnwdvars} +! +! !REVISION HISTORY: +! 15 Aug 2017: Sujay Kumar; Initial Specification +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 21 Jul 2011: James Geiger; Modified for Noah 3.2 +! 03 Oct 2018: Yeosang Yoon; Modified for NoahMP 3.6 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! +! !INTERFACE: +subroutine noahmp401_setsnwdvars(n, LSM_State) +! !USES: + use ESMF + use LIS_coreMod, only : LIS_rc, LIS_domain, LIS_surface + use LIS_logMod, only : LIS_logunit, LIS_verify, LIS_endrun + use noahmp401_lsmMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + type(ESMF_State) :: LSM_State +! +! !DESCRIPTION: +! +! This routine assigns the snow progognostic variables to noah's +! model space. The state vector consists of total SWE and snow depth. +! This routine also updates other model prognostics (snice, snliq, +! snow thickness, snow temperature) based on the update. +! +!EOP + type(ESMF_Field) :: sweField + type(ESMF_Field) :: snodField + real, pointer :: swe(:) + real, pointer :: snod(:) + real :: dsneqv,dsnowh,snoden + integer :: t + integer :: status + + call ESMF_StateGet(LSM_State,"Snowdepth",snodField,rc=status) + call LIS_verify(status) + + call ESMF_FieldGet(snodField,localDE=0,farrayPtr=snod,rc=status) + call LIS_verify(status) + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + + if(noahmp401_struc(n)%noahmp401(t)%sneqv.gt.0) then + + dsnowh = snod(t) - noahmp401_struc(n)%noahmp401(t)%snowh !in m + + if(noahmp401_struc(n)%noahmp401(t)%snowh.ne.0) then + snoden = noahmp401_struc(n)%noahmp401(t)%sneqv/& + noahmp401_struc(n)%noahmp401(t)%snowh + dsneqv = dsnowh*snoden + else + dsnowh = 0 + dsneqv = 0 + endif + ! update + call noahmp401_snow_update(n, t, dsneqv, dsnowh) + endif + enddo +end subroutine noahmp401_setsnwdvars + + diff --git a/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_updatesnwdvars.F90 b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_updatesnwdvars.F90 new file mode 100755 index 000000000..5c0d960eb --- /dev/null +++ b/lis/surfacemodels/land/noahmp.4.0.1/da_snwd/noahmp401_updatesnwdvars.F90 @@ -0,0 +1,161 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! !ROUTINE: noahmp401_updatesnwdvars +! \label{noahmp401_updatesnwdvars} +! +! !REVISION HISTORY: +! 27Feb2005: Sujay Kumar; Initial Specification +! 25Jun2006: Sujay Kumar: Updated for the ESMF design +! 02 Mar 2010: Sujay Kumar; Modified for Noah 3.1 +! 14 Dec 2018: Yeosang Yoon; Modified for NoahMP 4.0.1 and SNODEP +! 15 May 2019: Yeosang Yoon; Modified for NoahMP 4.0.1 and LDTSI +! 13 Dec 2019: Eric Kemp; Replaced LDTSI with SNWD +! 09 Jan 2020: Yeosang Yoon; Updated QC +! +! !INTERFACE: +subroutine noahmp401_updatesnwdvars(n, LSM_State, LSM_Incr_State) +! !USES: + use ESMF + use LIS_coreMod + use noahmp401_lsmMod + use LIS_logMod, only : LIS_logunit, LIS_verify + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + type(ESMF_State) :: LSM_State + type(ESMF_State) :: LSM_Incr_State +! +! !DESCRIPTION: +! +! Returns the snwd related state prognostic variables for +! data assimilation +! +! The arguments are: +! \begin{description} +! \item[n] index of the nest \newline +! \item[LSM\_State] ESMF State container for LSM state variables \newline +! \item[LSM\_Incr\_State] ESMF State container for LSM state increments \newline +! \end{description} +! +!EOP + + type(ESMF_Field) :: sweField, sweIncrField + type(ESMF_Field) :: snodField, snodIncrField + + integer :: t, gid + integer :: status + real, pointer :: swe(:), sweincr(:) + real, pointer :: snod(:), snodincr(:) + real :: swetmp, snodtmp,sndens + logical :: update_flag(LIS_rc%ngrid(n)) + real :: perc_violation(LIS_rc%ngrid(n)) + + real :: snodmean(LIS_rc%ngrid(n)) + integer :: nsnodmean(LIS_rc%ngrid(n)) + + call ESMF_StateGet(LSM_State,"Snowdepth",snodField,rc=status) + call LIS_verify(status) + + call ESMF_StateGet(LSM_Incr_State,"Snowdepth",snodIncrField,rc=status) + call LIS_verify(status) + + call ESMF_FieldGet(snodField,localDE=0,farrayPtr=snod,rc=status) + call LIS_verify(status) + + call ESMF_FieldGet(snodIncrField,localDE=0,farrayPtr=snodincr,rc=status) + call LIS_verify(status) + + + update_flag = .true. + perc_violation = 0.0 + snodmean = 0.0 + nsnodmean = 0 + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + + gid = LIS_domain(n)%gindex(& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%col,& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%row) + + snodtmp = snod(t) + snodincr(t) + + if((snodtmp.lt.0 )) then + update_flag(gid) = .false. + perc_violation(gid) = perc_violation(gid) +1 + endif + + enddo + + do gid=1,LIS_rc%ngrid(n) + perc_violation(gid) = perc_violation(gid) / real(LIS_rc%nensem(n)) + enddo + +! For ensembles that are unphysical, compute the ensemble average after excluding them. This +! is done only if the majority of the ensemble members are good (>80%) + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + + gid = LIS_domain(n)%gindex(& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%col,& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%row) + + if(.not.update_flag(gid)) then ! false + if(perc_violation(gid).lt.0.2) then + if(snod(t)+snodincr(t).ge.0) then + snodmean(gid) = snodmean(gid) + snod(t)+snodincr(t) + nsnodmean(gid) = nsnodmean(gid) + 1 + else + snodmean(gid) = 0.0 + endif + endif + endif + enddo + + do gid=1,LIS_rc%ngrid(n) + if(nsnodmean(gid).gt.0) then + snodmean(gid) = snodmean(gid) / real(nsnodmean(gid)) + endif + enddo + +! If the update is unphysical, simply set to the average of +! the good ensemble members. If all else fails, do not update. + + do t=1,LIS_rc%npatch(n,LIS_rc%lsm_index) + gid = LIS_domain(n)%gindex(& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%col,& + LIS_surface(n,LIS_rc%lsm_index)%tile(t)%row) + + + snodtmp = snod(t) + snodincr(t) + +!Use the model's snow density from the previous timestep + sndens = 0.0 + if(noahmp401_struc(n)%noahmp401(t)%snowh.gt.0) then + sndens = noahmp401_struc(n)%noahmp401(t)%sneqv/noahmp401_struc(n)%noahmp401(t)%snowh + endif + + if(update_flag(gid)) then + snod(t) = snodtmp + elseif(perc_violation(gid).lt.0.2) then + if(snodtmp.lt.0.0) then ! average of the good ensemble members + snod(t) = snodmean(gid) + else + snod(t) = snodtmp + endif + else ! do not update + snod(t) = noahmp401_struc(n)%noahmp401(t)%snowh + end if + + enddo + +end subroutine noahmp401_updatesnwdvars + diff --git a/lvt/datastreams/AMSREcnnSnow/AMSREcnnSnow_obsMod.F90 b/lvt/datastreams/AMSREcnnSnow/AMSREcnnSnow_obsMod.F90 new file mode 100755 index 000000000..a6d8bf398 --- /dev/null +++ b/lvt/datastreams/AMSREcnnSnow/AMSREcnnSnow_obsMod.F90 @@ -0,0 +1,154 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! +! !MODULE: AMSREcnnSnow_obsMod +! \label(AMSREcnnSnow_obsMod) +! +! !INTERFACE: +module AMSREcnnSnow_obsMod +! +! !USES: + use ESMF + + implicit none + PRIVATE +! +! !INPUT PARAMETERS: +! +! !OUTPUT PARAMETERS: +! +! !DESCRIPTION: +! This module handles the observation plugin for the +! University of Arizona (UA) SWE/Snow Depth data v01. +! The UA SNOW data is provided in the NAD 1983 grid +! with ~4-km resolution. The domain extents are from +! approximately (24N, -125W) to (50N, -66.5W). +! The data entries are 16-bit signed integers. +! +! Temporal coverage is from 1 Oct 1981 - 30 Sep 2017. +! The data is organized by Water Years. +! +! !FILES USED: +! +! !REVISION HISTORY: +! 28 May 2019: Rhae Sung Kim, Initial Specification! +! 19 Jun 2019: David Mocko, Set valid time of data to 12Z +! +!EOP + + PUBLIC :: AMSREcnnSnow_obsinit + PUBLIC :: amsrecnnsnowobs + + type, public :: amsrecnnsnowobsdec + character*100 :: odir + integer :: nc, nr + + real, allocatable :: rlat(:) + real, allocatable :: rlon(:) + integer, allocatable :: n11(:) + integer, allocatable :: n12(:) + integer, allocatable :: n21(:) + integer, allocatable :: n22(:) + real, allocatable :: w11(:) + real, allocatable :: w12(:) + real, allocatable :: w21(:) + real, allocatable :: w22(:) + + end type amsrecnnsnowobsdec + + type(amsrecnnsnowobsdec), allocatable :: amsrecnnsnowobs(:) + +contains + +!BOP +! +! !ROUTINE: AMSREcnnSnow_obsinit +! \label{AMSREcnnSnow_obsinit} +! +! !INTERFACE: + subroutine AMSREcnnSnow_obsinit(i) +! +! !USES: + use LVT_coreMod + use LVT_histDataMod + use LVT_timeMgrMod + use LVT_logMod + + implicit none +! +! !INPUT PARAMETERS: + integer, intent(IN) :: i +! +! !OUTPUT PARAMETERS: +! +! !DESCRIPTION: +! This subroutine initializes and sets up the data structures +! required for reading UA SNOW data. +! +! !FILES USED: +! +!EOP + + real :: gridDesci(50) + integer :: status + + if(.not.allocated(amsrecnnsnowobs)) then + allocate(amsrecnnsnowobs(LVT_rc%nDataStreams)) + endif + + call ESMF_ConfigGetAttribute(LVT_config, amsrecnnsnowobs(i)%odir, & + label='AMSRE CNN snow observation directory:',rc=status) + call LVT_verify(status, 'AMSRE CNN snow observation directory: not defined') + + gridDesci = 0 + call LVT_update_timestep(LVT_rc, 3600) + + allocate(amsrecnnsnowobs(i)%rlat(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%rlon(LVT_rc%lnc*LVT_rc%lnr)) + + allocate(amsrecnnsnowobs(i)%w11(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%w12(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%w21(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%w22(LVT_rc%lnc*LVT_rc%lnr)) + + allocate(amsrecnnsnowobs(i)%n11(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%n12(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%n21(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrecnnsnowobs(i)%n22(LVT_rc%lnc*LVT_rc%lnr)) + + amsrecnnsnowobs(i)%nc = 3599 + amsrecnnsnowobs(i)%nr = 700 + + gridDesci(1) = 0 + gridDesci(2) = 3599 + gridDesci(3) = 700 + gridDesci(4) = 0.025 + gridDesci(5) = -179.975 + gridDesci(6) = 128 + gridDesci(7) = 69.925 + gridDesci(8) = -179.825 + gridDesci(9) = 0.1 + gridDesci(10) = 0.1 + gridDesci(20) = 64 + + call bilinear_interp_input(gridDesci,LVT_rc%gridDesc,& + LVT_rc%lnc*LVT_rc%lnr, & + amsrecnnsnowobs(i)%rlat, amsrecnnsnowobs(i)%rlon, & + amsrecnnsnowobs(i)%n11, amsrecnnsnowobs(i)%n12, & + amsrecnnsnowobs(i)%n21, amsrecnnsnowobs(i)%n22, & + amsrecnnsnowobs(i)%w11, amsrecnnsnowobs(i)%w12, & + amsrecnnsnowobs(i)%w21, amsrecnnsnowobs(i)%w22) + + + end subroutine AMSREcnnSnow_obsinit + + +end module AMSREcnnSnow_obsMod diff --git a/lvt/datastreams/AMSREcnnSnow/readAMSREcnnSnowObs.F90 b/lvt/datastreams/AMSREcnnSnow/readAMSREcnnSnowObs.F90 new file mode 100755 index 000000000..bae256c04 --- /dev/null +++ b/lvt/datastreams/AMSREcnnSnow/readAMSREcnnSnowObs.F90 @@ -0,0 +1,218 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +#include "LVT_misc.h" +!BOP +! +! !ROUTINE: readAMSREcnnSnowObs +! \label{readAMSREcnnSnowObs} +! +! !INTERFACE: +subroutine readAMSREcnnSnowObs(source) +! +! !USES: + use ESMF + use LVT_histDataMod + use LVT_coreMod, only : LVT_rc + use LVT_timeMgrMod, only : LVT_calendar + use LVT_logMod, only : LVT_logunit, LVT_verify + use AMSREcnnSnow_obsMod, only : amsrecnnsnowobs + use map_utils + +#if(defined USE_NETCDF3 || defined USE_NETCDF4) + use netcdf +#endif + + implicit none +! +! !INPUT PARAMETERS: + integer, intent(in) :: source +! +! !OUTPUT PARAMETERS: +! +! !DESCRIPTION: +! This subroutine reads and processes the gridded UA SNOW +! data. The data for a given year is read into memory at +! the start of a year and indexed into during each day. +! +! !REVISION HISTORY: +! 28 May 2019: Rhae Sung Kim, Initial Specification +! 19 Jun 2019: David Mocko, Set valid time of data to 12Z +! 25 Jun 2019: David Mocko, Only read one file per call +! +!EOP + + integer :: ftn + character*100 :: fname + logical :: file_exists + real, allocatable :: snwd1(:,:) + real :: snwd_in(amsrecnnsnowobs(source)%nc*amsrecnnsnowobs(source)%nr) + logical*1 :: lb(amsrecnnsnowobs(source)%nc*amsrecnnsnowobs(source)%nr) + logical*1 :: lo(LVT_rc%lnc*LVT_rc%lnr) + real :: snwd_out(LVT_rc%lnc*LVT_rc%lnr) + real :: snwd_final(LVT_rc%lnc, LVT_rc%lnr) + integer :: t,c,r,k,nt + integer :: nid,varid + integer :: iret + type(ESMF_Time) :: uatime1 + integer :: status + real :: timenow + logical :: alarmCheck + + snwd_out = LVT_rc%udef + snwd_final = LVT_rc%udef + + timenow = float(LVT_rc%dhr(source)*3600 + & + LVT_rc%dmn(source)*60 + LVT_rc%dss(source)) + +! The UA dataset is a daily product, valid approximately +! at 12Z, which is the observation time of many of the +! surface products used to generate the data (personal +! communication with the UA SNOW product generators). + alarmcheck = (mod(timenow, 86400.0).eq.0) + + if (alarmcheck) then + LVT_rc%resetFlag(source) = .false. + + call create_AMSREcnn_filename(amsrecnnsnowobs(source)%odir, & + LVT_rc%dyr(source), LVT_rc%dmo(source), LVT_rc%dda(source),& + fname) + + inquire(file=trim(fname),exist=file_exists) + + if (file_exists) then + write(LVT_logunit,*) '[INFO] Reading AMSRE CNN data ',& + trim(fname) + + allocate(snwd1(amsrecnnsnowobs(source)%nc, & + amsrecnnsnowobs(source)%nr)) + +#if(defined USE_NETCDF3 || defined USE_NETCDF4) + + iret = nf90_open(path=trim(fname),mode=NF90_NOWRITE,ncid=nid) + call LVT_verify(iret, 'Error opening file'//trim(fname)) + + iret = nf90_inq_varid(nid, 'SD',varid) + call LVT_verify(iret, 'Error nf90_inq_varid: SD') + + iret = nf90_get_var(nid,varid, SNWD1) + call LVT_verify(iret, 'Error nf90_get_var: SD') + + iret = nf90_close(nid) + call LVT_verify(iret, 'Error nf90_close') +#endif + do c=1,amsrecnnsnowobs(source)%nc + do r=1,amsrecnnsnowobs(source)%nr + if(snwd1(c,r).lt.0.or.snwd1(c,r).gt.1000) then + snwd_in(c+(amsrecnnsnowobs(source)%nr-r)*& + amsrecnnsnowobs(source)%nc) = -9999.0 + else + snwd_in(c+(amsrecnnsnowobs(source)%nr-r)*& + amsrecnnsnowobs(source)%nc) = snwd1(c,r) + endif + enddo + enddo + +! print*, amsrecnnsnowobs(source)%nc,amsrecnnsnowobs(source)%nr +! open(100,file='test.bin',form='unformatted') +! write(100) snwd_in +! close(100) +! stop + deallocate(snwd1) + + else + write(LVT_logunit,*) '[WARN] AMSRE CNN file not found: ',& + trim(fname) + snwd_in = -9999.0 + endif + + lb = .false. + + do t=1,amsrecnnsnowobs(source)%nc*amsrecnnsnowobs(source)%nr + if(snwd_in(t).ne.-9999.0) then + lb(t) = .true. + endif + enddo + + + call bilinear_interp(LVT_rc%gridDesc,lb,snwd_in, & + lo,snwd_out, & + amsrecnnsnowobs(source)%nc*amsrecnnsnowobs(source)%nr, & + LVT_rc%lnc*LVT_rc%lnr, & + amsrecnnsnowobs(source)%rlat, & + amsrecnnsnowobs(source)%rlon, & + amsrecnnsnowobs(source)%w11, & + amsrecnnsnowobs(source)%w12, & + amsrecnnsnowobs(source)%w21, & + amsrecnnsnowobs(source)%w22, & + amsrecnnsnowobs(source)%n11, & + amsrecnnsnowobs(source)%n12, & + amsrecnnsnowobs(source)%n21, & + amsrecnnsnowobs(source)%n22, & + LVT_rc%udef, iret) + + do r=1,LVT_rc%lnr + do c=1, LVT_rc%lnc + snwd_final(c,r) = snwd_out(c+(r-1)*LVT_rc%lnc) + enddo + enddo + + do r=1,LVT_rc%lnr + do c=1,LVT_rc%lnc + + if(snwd_final(c,r).ge.0) then + snwd_final(c,r) = snwd_final(c,r)/100.0 ! Convert cm to m + else + snwd_final(c,r) = LVT_rc%udef + endif + enddo + enddo +! print*, 'here' +! open(100,file='test.bin',form='unformatted') +! write(100) snwd_final +! close(100) +! stop + endif + + call LVT_logSingleDataStreamVar(LVT_MOC_SNOWDEPTH,source,snwd_final,vlevel=1,units="m") + +end subroutine readAMSREcnnSnowObs + +!BOP +! +! !ROUTINE: create_AMSREcnn_filename +! \label(create_AMSREcnn_filename) +! +! !INTERFACE: +subroutine create_AMSREcnn_filename(odir,yr,mo,da,fname) +! +! !USES: + use LVT_String_Utility + implicit none +! +! !INPUT PARAMETERS: + character(len=*), intent(in) :: odir + integer, intent(in) :: yr,mo,da +! +! !OUTPUT PARAMETERS: + character(len=*), intent(out) :: fname +! + character*4 :: fyr + character*2 :: fmo + character*2 :: fda + + write(fyr, '(i4.4)' ) yr + write(fmo, '(i2.2)' ) mo + write(fda, '(i2.2)' ) da + + fname = trim(odir)//'/'//trim(fyr)//& + '/AMSRE_CNN_NH_'//trim(fyr)//'-'//& + trim(fmo)//'-'//trim(fda)//'.nc' + +end subroutine create_AMSREcnn_filename diff --git a/lvt/datastreams/AMSRcnnSnow/AMSRcnnSnow_obsMod.F90 b/lvt/datastreams/AMSRcnnSnow/AMSRcnnSnow_obsMod.F90 new file mode 100755 index 000000000..9f3a8b81a --- /dev/null +++ b/lvt/datastreams/AMSRcnnSnow/AMSRcnnSnow_obsMod.F90 @@ -0,0 +1,154 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +!BOP +! +! !MODULE: AMSRcnnSnow_obsMod +! \label(AMSRcnnSnow_obsMod) +! +! !INTERFACE: +module AMSRcnnSnow_obsMod +! +! !USES: + use ESMF + + implicit none + PRIVATE +! +! !INPUT PARAMETERS: +! +! !OUTPUT PARAMETERS: +! +! !DESCRIPTION: +! This module handles the observation plugin for the +! University of Arizona (UA) SWE/Snow Depth data v01. +! The UA SNOW data is provided in the NAD 1983 grid +! with ~4-km resolution. The domain extents are from +! approximately (24N, -125W) to (50N, -66.5W). +! The data entries are 16-bit signed integers. +! +! Temporal coverage is from 1 Oct 1981 - 30 Sep 2017. +! The data is organized by Water Years. +! +! !FILES USED: +! +! !REVISION HISTORY: +! 28 May 2019: Rhae Sung Kim, Initial Specification! +! 19 Jun 2019: David Mocko, Set valid time of data to 12Z +! +!EOP + + PUBLIC :: AMSRcnnSnow_obsinit + PUBLIC :: amsrcnnsnowobs + + type, public :: amsrcnnsnowobsdec + character*100 :: odir + integer :: nc, nr + + real, allocatable :: rlat(:) + real, allocatable :: rlon(:) + integer, allocatable :: n11(:) + integer, allocatable :: n12(:) + integer, allocatable :: n21(:) + integer, allocatable :: n22(:) + real, allocatable :: w11(:) + real, allocatable :: w12(:) + real, allocatable :: w21(:) + real, allocatable :: w22(:) + + end type amsrcnnsnowobsdec + + type(amsrcnnsnowobsdec), allocatable :: amsrcnnsnowobs(:) + +contains + +!BOP +! +! !ROUTINE: AMSRcnnSnow_obsinit +! \label{AMSRcnnSnow_obsinit} +! +! !INTERFACE: + subroutine AMSRcnnSnow_obsinit(i) +! +! !USES: + use LVT_coreMod + use LVT_histDataMod + use LVT_timeMgrMod + use LVT_logMod + + implicit none +! +! !INPUT PARAMETERS: + integer, intent(IN) :: i +! +! !OUTPUT PARAMETERS: +! +! !DESCRIPTION: +! This subroutine initializes and sets up the data structures +! required for reading UA SNOW data. +! +! !FILES USED: +! +!EOP + + real :: gridDesci(50) + integer :: status + + if(.not.allocated(amsrcnnsnowobs)) then + allocate(amsrcnnsnowobs(LVT_rc%nDataStreams)) + endif + + call ESMF_ConfigGetAttribute(LVT_config, amsrcnnsnowobs(i)%odir, & + label='AMSR CNN snow observation directory:',rc=status) + call LVT_verify(status, 'AMSR CNN snow observation directory: not defined') + + gridDesci = 0 + call LVT_update_timestep(LVT_rc, 86400) + + allocate(amsrcnnsnowobs(i)%rlat(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%rlon(LVT_rc%lnc*LVT_rc%lnr)) + + allocate(amsrcnnsnowobs(i)%w11(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%w12(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%w21(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%w22(LVT_rc%lnc*LVT_rc%lnr)) + + allocate(amsrcnnsnowobs(i)%n11(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%n12(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%n21(LVT_rc%lnc*LVT_rc%lnr)) + allocate(amsrcnnsnowobs(i)%n22(LVT_rc%lnc*LVT_rc%lnr)) + + amsrcnnsnowobs(i)%nc = 3599 + amsrcnnsnowobs(i)%nr = 700 + + gridDesci(1) = 0 + gridDesci(2) = 3599 + gridDesci(3) = 700 + gridDesci(4) = 0.025 + gridDesci(5) = -179.975 + gridDesci(6) = 128 + gridDesci(7) = 69.925 + gridDesci(8) = 179.825 + gridDesci(9) = 0.1 + gridDesci(10) = 0.1 + gridDesci(20) = 64 + + call bilinear_interp_input(gridDesci,LVT_rc%gridDesc,& + LVT_rc%lnc*LVT_rc%lnr, & + amsrcnnsnowobs(i)%rlat, amsrcnnsnowobs(i)%rlon, & + amsrcnnsnowobs(i)%n11, amsrcnnsnowobs(i)%n12, & + amsrcnnsnowobs(i)%n21, amsrcnnsnowobs(i)%n22, & + amsrcnnsnowobs(i)%w11, amsrcnnsnowobs(i)%w12, & + amsrcnnsnowobs(i)%w21, amsrcnnsnowobs(i)%w22) + + + end subroutine AMSRcnnSnow_obsinit + + +end module AMSRcnnSnow_obsMod diff --git a/lvt/datastreams/AMSRcnnSnow/readAMSRcnnSnowObs.F90 b/lvt/datastreams/AMSRcnnSnow/readAMSRcnnSnowObs.F90 new file mode 100755 index 000000000..7ed1bf205 --- /dev/null +++ b/lvt/datastreams/AMSRcnnSnow/readAMSRcnnSnowObs.F90 @@ -0,0 +1,218 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.4 +! +! Copyright (c) 2022 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +#include "LVT_misc.h" +!BOP +! +! !ROUTINE: readAMSRcnnSnowObs +! \label{readAMSRcnnSnowObs} +! +! !INTERFACE: +subroutine readAMSRcnnSnowObs(source) +! +! !USES: + use ESMF + use LVT_histDataMod + use LVT_coreMod, only : LVT_rc + use LVT_timeMgrMod, only : LVT_calendar + use LVT_logMod, only : LVT_logunit, LVT_verify + use AMSRcnnSnow_obsMod, only : amsrcnnsnowobs + use map_utils + +#if(defined USE_NETCDF3 || defined USE_NETCDF4) + use netcdf +#endif + + implicit none +! +! !INPUT PARAMETERS: + integer, intent(in) :: source +! +! !OUTPUT PARAMETERS: +! +! !DESCRIPTION: +! This subroutine reads and processes the gridded UA SNOW +! data. The data for a given year is read into memory at +! the start of a year and indexed into during each day. +! +! !REVISION HISTORY: +! 28 May 2019: Rhae Sung Kim, Initial Specification +! 19 Jun 2019: David Mocko, Set valid time of data to 12Z +! 25 Jun 2019: David Mocko, Only read one file per call +! +!EOP + + integer :: ftn + character*100 :: fname + logical :: file_exists + real, allocatable :: snwd1(:,:) + real :: snwd_in(amsrcnnsnowobs(source)%nc*amsrcnnsnowobs(source)%nr) + logical*1 :: lb(amsrcnnsnowobs(source)%nc*amsrcnnsnowobs(source)%nr) + logical*1 :: lo(LVT_rc%lnc*LVT_rc%lnr) + real :: snwd_out(LVT_rc%lnc*LVT_rc%lnr) + real :: snwd_final(LVT_rc%lnc, LVT_rc%lnr) + integer :: t,c,r,k,nt + integer :: nid,varid + integer :: iret + type(ESMF_Time) :: uatime1 + integer :: status + real :: timenow + logical :: alarmCheck + + snwd_out = LVT_rc%udef + snwd_final = LVT_rc%udef + + timenow = float(LVT_rc%dhr(source)*3600 + & + LVT_rc%dmn(source)*60 + LVT_rc%dss(source)) + +! The UA dataset is a daily product, valid approximately +! at 12Z, which is the observation time of many of the +! surface products used to generate the data (personal +! communication with the UA SNOW product generators). + alarmcheck = (mod(timenow, 86400.0).eq.0) + + if (alarmcheck) then + LVT_rc%resetFlag(source) = .false. + + call create_AMSRcnn_filename(amsrcnnsnowobs(source)%odir, & + LVT_rc%dyr(source), LVT_rc%dmo(source), LVT_rc%dda(source),& + fname) + + inquire(file=trim(fname),exist=file_exists) + + if (file_exists) then + write(LVT_logunit,*) '[INFO] Reading AMSR CNN data ',& + trim(fname) + + allocate(snwd1(amsrcnnsnowobs(source)%nc, & + amsrcnnsnowobs(source)%nr)) + +#if(defined USE_NETCDF3 || defined USE_NETCDF4) + + iret = nf90_open(path=trim(fname),mode=NF90_NOWRITE,ncid=nid) + call LVT_verify(iret, 'Error opening file'//trim(fname)) + + iret = nf90_inq_varid(nid, 'SD',varid) + call LVT_verify(iret, 'Error nf90_inq_varid: SD') + + iret = nf90_get_var(nid,varid, SNWD1) + call LVT_verify(iret, 'Error nf90_get_var: SD') + + iret = nf90_close(nid) + call LVT_verify(iret, 'Error nf90_close') +#endif + do c=1,amsrcnnsnowobs(source)%nc + do r=1,amsrcnnsnowobs(source)%nr + if(snwd1(c,r).lt.0.or.snwd1(c,r).gt.1000) then + snwd_in(c+(amsrcnnsnowobs(source)%nr-r)*& + amsrcnnsnowobs(source)%nc) = -9999.0 + else + snwd_in(c+(amsrcnnsnowobs(source)%nr-r)*& + amsrcnnsnowobs(source)%nc) = snwd1(c,r) + endif + enddo + enddo + +! print*, amsrcnnsnowobs(source)%nc,amsrcnnsnowobs(source)%nr +! open(100,file='test.bin',form='unformatted') +! write(100) snwd_in +! close(100) +! stop + deallocate(snwd1) + + else + write(LVT_logunit,*) '[WARN] AMSR CNN file not found: ',& + trim(fname) + snwd_in = -9999.0 + endif + + lb = .false. + + do t=1,amsrcnnsnowobs(source)%nc*amsrcnnsnowobs(source)%nr + if(snwd_in(t).ne.-9999.0) then + lb(t) = .true. + endif + enddo + + + call bilinear_interp(LVT_rc%gridDesc,lb,snwd_in, & + lo,snwd_out, & + amsrcnnsnowobs(source)%nc*amsrcnnsnowobs(source)%nr, & + LVT_rc%lnc*LVT_rc%lnr, & + amsrcnnsnowobs(source)%rlat, & + amsrcnnsnowobs(source)%rlon, & + amsrcnnsnowobs(source)%w11, & + amsrcnnsnowobs(source)%w12, & + amsrcnnsnowobs(source)%w21, & + amsrcnnsnowobs(source)%w22, & + amsrcnnsnowobs(source)%n11, & + amsrcnnsnowobs(source)%n12, & + amsrcnnsnowobs(source)%n21, & + amsrcnnsnowobs(source)%n22, & + LVT_rc%udef, iret) + + do r=1,LVT_rc%lnr + do c=1, LVT_rc%lnc + snwd_final(c,r) = snwd_out(c+(r-1)*LVT_rc%lnc) + enddo + enddo + + do r=1,LVT_rc%lnr + do c=1,LVT_rc%lnc + + if(snwd_final(c,r).ge.0) then + snwd_final(c,r) = snwd_final(c,r)/100.0 ! Convert cm to m + else + snwd_final(c,r) = LVT_rc%udef + endif + enddo + enddo +! print*, 'here' +! open(100,file='test.bin',form='unformatted') +! write(100) snwd_final +! close(100) +! stop + endif + + call LVT_logSingleDataStreamVar(LVT_MOC_SNOWDEPTH,source,snwd_final,vlevel=1,units="m") + +end subroutine readAMSRcnnSnowObs + +!BOP +! +! !ROUTINE: create_AMSRcnn_filename +! \label(create_AMSRcnn_filename) +! +! !INTERFACE: +subroutine create_AMSRcnn_filename(odir,yr,mo,da,fname) +! +! !USES: + use LVT_String_Utility + implicit none +! +! !INPUT PARAMETERS: + character(len=*), intent(in) :: odir + integer, intent(in) :: yr,mo,da +! +! !OUTPUT PARAMETERS: + character(len=*), intent(out) :: fname +! + character*4 :: fyr + character*2 :: fmo + character*2 :: fda + + write(fyr, '(i4.4)' ) yr + write(fmo, '(i2.2)' ) mo + write(fda, '(i2.2)' ) da + + fname = trim(odir)//'/'//trim(fyr)//& + '/AMSR_CNN_NH_'//trim(fyr)//'-'//& + trim(fmo)//'-'//trim(fda)//'.nc' + +end subroutine create_AMSRcnn_filename diff --git a/lvt/make/Filepath b/lvt/make/Filepath index d0034d33b..efcbff53f 100644 --- a/lvt/make/Filepath +++ b/lvt/make/Filepath @@ -1 +1 @@ -dirs := . ../main ../core ../metrics ../plugins ../interp ../lib/bil ../domains/UTM ../domains/lambert ../domains/latlon ../datastreams/template ../datastreams/LISout ../datastreams/LISDAobs ../datastreams/ISCCP_Tskin ../datastreams/CEOP ../datastreams/SCAN ../datastreams/SCANGMAO ../datastreams/NASMD ../datastreams/GHCN ../datastreams/SNOTEL ../datastreams/SURFRAD ../datastreams/WGPBMR ../datastreams/LSWG_Tb ../datastreams/FMI_SWE ../datastreams/FMI_SNWD ../datastreams/CMC_SNWD ../datastreams/SNODAS ../datastreams/NASA_AMSRE_sm ../datastreams/LPRM_AMSRE_sm ../datastreams/AMMA ../datastreams/Ameriflux ../datastreams/ARM ../datastreams/SMOSREX ../datastreams/AGRMET ../datastreams/GlobSnow ../datastreams/SNODEPmetobs ../datastreams/SNODEP ../datastreams/MOD10A1 ../datastreams/MODSCAG ../datastreams/MOD10A1V6 ../datastreams/ANSA_SNWD ../datastreams/ANSA_SWE ../datastreams/CPC_PRCP ../datastreams/USGS_streamflow_gridded ../datastreams/USGS_streamflow ../datastreams/Natural_streamflow ../datastreams/ISMN ../datastreams/FLUXNETmte ../datastreams/FLUXNET2015 ../datastreams/FLUXNET2015_NC ../datastreams/MOD16A2 ../datastreams/UWET ../datastreams/ARSsm ../datastreams/NLDAS2 ../datastreams/ALEXI ../datastreams/ALEXIesi ../datastreams/GRACE ../datastreams/simGRACE ../datastreams/USGS_GWwell ../datastreams/PBOH2O ../datastreams/SMOS_L2sm ../datastreams/SMOS_NESDIS ../datastreams/SMOS_L1TB ../datastreams/SMOS_CATDS_L3sm ../datastreams/GCOMW_AMSR2L3sm ../datastreams/GCOMW_AMSR2L3snd ../datastreams/SMOPS ../datastreams/MODIS_LST ../datastreams/GLERL_HydroData ../datastreams/JULESdata ../datastreams/JULES2Ddata ../datastreams/ESACCI_sm ../datastreams/GIMMS_AVHRR_NDVI ../datastreams/GIMMS_MODIS_NDVI ../datastreams/GLDAS1 ../datastreams/GLDAS2 ../datastreams/MERRA2 ../datastreams/MERRA2asm ../datastreams/MERRA-Land ../datastreams/SSEBop ../datastreams/GRDC ../datastreams/GOES_LST ../datastreams/ERAinterimLand ../datastreams/SMAPsm ../datastreams/SMAPvod ../datastreams/LPRMvod ../datastreams/SMAPvwc ../datastreams/SMAP_L3TB ../datastreams/SMAPTB ../datastreams/GOME2_SIF ../datastreams/LVTbenchmarkOUT ../datastreams/LIS6out ../datastreams/LISDAdiag ../datastreams/Daymet ../datastreams/CMORPH ../datastreams/CHIRPSv2 ../datastreams/3B42V7 ../datastreams/USCRNsm ../datastreams/GLEAM ../datastreams/USDM ../datastreams/LVTpercentile ../datastreams/IMD_PRCP ../datastreams/APHRO_PRCP ../datastreams/GLASSlai ../datastreams/MODISsportLAI ../datastreams/FLUXCOM ../datastreams/HAR ../datastreams/OCO2_SIF ../datastreams/ECMWFforc ../datastreams/GDASforc ../datastreams/ASO_SWE ../runmodes/DataComp ../runmodes/557post ../runmodes/LISpost ../runmodes/DAstats ../runmodes/optUE ../runmodes/Benchmarking ../runmodes/USAFSIpost ../training/LinearRegression/ ../datastreams/GLASSalbedo ../datastreams/IMERG ../datastreams/UA_SNOW ../datastreams/OzFlux ../datastreams/jasmin ../datastreams/MCD15A2H ../datastreams/ERA5 ../datastreams/FluxSat_GPP ../datastreams/THySM/ ../datastreams/GRUNrunoff ../datastreams/UASMAP/ ../datastreams/COAMPSout/ ../datastreams/SMAP_E_OPL/ +dirs := . ../main ../core ../metrics ../plugins ../interp ../lib/bil ../domains/UTM ../domains/lambert ../domains/latlon ../datastreams/template ../datastreams/LISout ../datastreams/LISDAobs ../datastreams/ISCCP_Tskin ../datastreams/CEOP ../datastreams/SCAN ../datastreams/SCANGMAO ../datastreams/NASMD ../datastreams/GHCN ../datastreams/SNOTEL ../datastreams/SURFRAD ../datastreams/WGPBMR ../datastreams/LSWG_Tb ../datastreams/FMI_SWE ../datastreams/FMI_SNWD ../datastreams/CMC_SNWD ../datastreams/SNODAS ../datastreams/NASA_AMSRE_sm ../datastreams/LPRM_AMSRE_sm ../datastreams/AMMA ../datastreams/Ameriflux ../datastreams/ARM ../datastreams/SMOSREX ../datastreams/AGRMET ../datastreams/GlobSnow ../datastreams/SNODEPmetobs ../datastreams/SNODEP ../datastreams/MOD10A1 ../datastreams/MODSCAG ../datastreams/MOD10A1V6 ../datastreams/ANSA_SNWD ../datastreams/ANSA_SWE ../datastreams/CPC_PRCP ../datastreams/USGS_streamflow_gridded ../datastreams/USGS_streamflow ../datastreams/Natural_streamflow ../datastreams/ISMN ../datastreams/FLUXNETmte ../datastreams/FLUXNET2015 ../datastreams/FLUXNET2015_NC ../datastreams/MOD16A2 ../datastreams/UWET ../datastreams/ARSsm ../datastreams/NLDAS2 ../datastreams/ALEXI ../datastreams/ALEXIesi ../datastreams/GRACE ../datastreams/simGRACE ../datastreams/USGS_GWwell ../datastreams/PBOH2O ../datastreams/SMOS_L2sm ../datastreams/SMOS_NESDIS ../datastreams/SMOS_L1TB ../datastreams/SMOS_CATDS_L3sm ../datastreams/GCOMW_AMSR2L3sm ../datastreams/GCOMW_AMSR2L3snd ../datastreams/SMOPS ../datastreams/MODIS_LST ../datastreams/GLERL_HydroData ../datastreams/JULESdata ../datastreams/JULES2Ddata ../datastreams/ESACCI_sm ../datastreams/GIMMS_AVHRR_NDVI ../datastreams/GIMMS_MODIS_NDVI ../datastreams/GLDAS1 ../datastreams/GLDAS2 ../datastreams/MERRA2 ../datastreams/MERRA2asm ../datastreams/MERRA-Land ../datastreams/SSEBop ../datastreams/GRDC ../datastreams/GOES_LST ../datastreams/ERAinterimLand ../datastreams/SMAPsm ../datastreams/SMAPvod ../datastreams/LPRMvod ../datastreams/SMAPvwc ../datastreams/SMAP_L3TB ../datastreams/SMAPTB ../datastreams/GOME2_SIF ../datastreams/LVTbenchmarkOUT ../datastreams/LIS6out ../datastreams/LISDAdiag ../datastreams/Daymet ../datastreams/CMORPH ../datastreams/CHIRPSv2 ../datastreams/3B42V7 ../datastreams/USCRNsm ../datastreams/GLEAM ../datastreams/USDM ../datastreams/LVTpercentile ../datastreams/IMD_PRCP ../datastreams/APHRO_PRCP ../datastreams/GLASSlai ../datastreams/MODISsportLAI ../datastreams/FLUXCOM ../datastreams/HAR ../datastreams/OCO2_SIF ../datastreams/ECMWFforc ../datastreams/GDASforc ../datastreams/ASO_SWE ../runmodes/DataComp ../runmodes/557post ../runmodes/LISpost ../runmodes/DAstats ../runmodes/optUE ../runmodes/Benchmarking ../runmodes/USAFSIpost ../training/LinearRegression/ ../datastreams/GLASSalbedo ../datastreams/IMERG ../datastreams/UA_SNOW ../datastreams/AMSRcnnSnow ../datastreams/OzFlux ../datastreams/jasmin ../datastreams/MCD15A2H ../datastreams/ERA5 ../datastreams/FluxSat_GPP ../datastreams/THySM/ ../datastreams/GRUNrunoff ../datastreams/UASMAP/ ../datastreams/COAMPSout/ ../datastreams/SMAP_E_OPL/ diff --git a/lvt/plugins/LVT_datastream_pluginMod.F90 b/lvt/plugins/LVT_datastream_pluginMod.F90 index 1016c4e7b..495af2e4b 100644 --- a/lvt/plugins/LVT_datastream_pluginMod.F90 +++ b/lvt/plugins/LVT_datastream_pluginMod.F90 @@ -173,6 +173,7 @@ subroutine LVT_datastream_plugin use ASOSWE_obsMod, only : ASOSWE_obsinit use IMERG_dataMod, only : IMERG_datainit use UASNOW_obsMod, only : UASNOW_obsinit + use AMSRcnnSnow_obsMod, only : AMSRcnnSnow_obsinit use OzFlux_obsMod, only : OzFlux_obsinit use JASMINsm_obsMod, only : JASMINsm_obsInit use MCD15A2H_obsMod, only : MCD15A2H_obsinit @@ -285,6 +286,7 @@ subroutine LVT_datastream_plugin external readASOSWEObs external readIMERGdata external readUASNOWObs + external readAMSRcnnSnowObs external readOzFluxObs external readJASMINsmobs external readMCD15A2Hobs @@ -705,6 +707,11 @@ subroutine LVT_datastream_plugin call registerobssetup(trim(LVT_UASNOWdataId)//char(0), UASNOW_obsinit) call registerobsread(trim(LVT_UASNOWdataId)//char(0) , readUASNOWObs) + call registerobssetup(trim(LVT_AMSRcnnSnowdataId)//char(0), & + AMSRcnnSnow_obsinit) + call registerobsread(trim(LVT_AMSRcnnSnowdataId)//char(0) , & + readAMSRcnnSnowObs) + call registerobssetup(trim(LVT_OzFluxdataId)//char(0), OzFlux_obsinit) call registerobsread(trim(LVT_OzFluxdataId)//char(0) , readOzFluxObs) diff --git a/lvt/plugins/LVT_pluginIndices.F90 b/lvt/plugins/LVT_pluginIndices.F90 index e188f6197..43a4dd1cc 100644 --- a/lvt/plugins/LVT_pluginIndices.F90 +++ b/lvt/plugins/LVT_pluginIndices.F90 @@ -263,6 +263,7 @@ module LVT_pluginIndices character*50, public, parameter :: LVT_ASOSWEdataId = "ASO SWE" character*50, public, parameter :: LVT_IMERGdataId = "GPM IMERG" character*50, public, parameter :: LVT_UASNOWdataId = "UA SNOW" + character*50, public, parameter :: LVT_AMSRcnnSnowdataId = "AMSR CNN snow" character*50, public, parameter :: LVT_ozFluxdataId = "OzFlux" character*50, public, parameter :: LVT_JASMINsmobsId = "JASMIN soil moisture" character*50, public, parameter :: LVT_MCD15A2HobsId = "MCD15A2H LAI"