diff --git a/docs/LIS_users_guide/user_cfg_table.adoc b/docs/LIS_users_guide/user_cfg_table.adoc index 63962d576..8e03b7d5d 100644 --- a/docs/LIS_users_guide/user_cfg_table.adoc +++ b/docs/LIS_users_guide/user_cfg_table.adoc @@ -31,7 +31,8 @@ | GSWP2 | On | AGRMET | Off | PRINCETON | On -| NLDAS2 | On +| NLDAS2 grib | On +| NLDAS2 netcdf | On | GLDAS | On | GFS | On | MERRA2 | On diff --git a/lis/configs/lis.config.adoc b/lis/configs/lis.config.adoc index 4c239990a..e1a1f0278 100644 --- a/lis/configs/lis.config.adoc +++ b/lis/configs/lis.config.adoc @@ -346,7 +346,8 @@ Acceptable values for the sources are: |"`GSWP2`" | GSWP2 |"`AGRMET`" | AGRMET |"`PRINCETON`" | Princeton -|"`NLDAS2`" | NLDAS2 +|"`NLDAS2 grib`" | NLDAS-2 GRIB-1 format +|"`NLDAS2 netcdf`" | NLDAS-2 v020 netCDF-4 format |"`GLDAS`" | GLDAS |"`GFS`" | GFS |"`MERRA2`" | MERRA2 @@ -5883,15 +5884,14 @@ SCAN forcing directory: ./input/FORCING/SCAN SCAN metadata file: ./input/FORCING/SCAN/msu_scan.mdata .... +[[sssec_forcings_nldas2,NLDAS2 (grib)]] +==== NLDAS2 (grib) -[[sssec_forcings_nldas2,NLDAS2]] -==== NLDAS2 +`NLDAS2 forcing directory:` specifies the location of the NLDAS-2 +GRIB-1 forcing files. -`NLDAS2 forcing directory:` specifies the location of the NLDAS2 -forcing files. - -`NLDAS2 data center source:` specifies the center that produced -the NLDAS2 files. (This is specified to distinguish the filenames.) +`NLDAS2 data center source:` specifies the center that produced the +NLDAS-2 GRIB-1 files. (This is specified to distinguish the filenames.) Acceptable values are: |==== @@ -5903,7 +5903,7 @@ Acceptable values are: `NLDAS2 use model level data:` specifies whether or not to read in the model level data (instead of 2/10m fields) from the -NLDAS2 forcing dataset (will open up and read "`B`" files). +NLDAS-2 forcing dataset (will open up and read "`B`" files). This data is at the height of the NARR lowest model level. Note that this will read in "`Height of Atmospheric Forcing`" @@ -5920,7 +5920,7 @@ Acceptable values are: `NLDAS2 use model based swdown:` specifies whether or not to read in the un-bias corrected model downward shortwave radiation -data (in leiu of the bias corrected data) from the NLDAS2 forcing +data (in leiu of the bias corrected data) from the NLDAS-2 forcing dataset (will open up and read "`B`" files). The data source is the NARR shortwave. Acceptable values are: @@ -5934,7 +5934,7 @@ Acceptable values are: `NLDAS2 use model based precip:` specifies whether or not to read in the model based precipitation data (instead of the -observation based precipitation) from the NLDAS2 forcing +observation based precipitation) from the NLDAS-2 forcing dataset (will open up and read "`B`" files). The data source is the NARR precipitation. Acceptable values are: @@ -5946,10 +5946,9 @@ Acceptable values are: |1 | use |==== -`NLDAS2 use model based pressure:` specifies whether or -not to read in the model base pressure data (instead of the -observation based pressure) from the NLDAS2 forcing dataset -(will open up and read "`B`" files). The data source is +`NLDAS2 use model based pressure:` specifies whether or not +to read in the model base pressure data from the NLDAS-2 forcing +dataset (will open up and read "`B`" files). The data source is the pressure at the NARR lowest model level. Acceptable values are: @@ -5970,6 +5969,103 @@ NLDAS2 use model based precip: 0 NLDAS2 use model based pressure: 0 .... +[[sssec_forcings_nldas20,NLDAS-2.0 (netcdf)]] +==== NLDAS-2.0 (netcdf) + +`NLDAS-2.0 FORA forcing directory:` specifies the location of the +NLDAS-2.0 v020 "`FORA`" netCDF-4 forcing files. + +`NLDAS-2.0 FORB forcing directory:` specifies the location of the +NLDAS-2.0 v020 "`FORB`" netCDF-4 forcing files. This config entry +is not required unless one of the following FORB data use flags is +set to "`1`". + +`NLDAS-2.0 use FORB model level data:` specifies whether or not to +read in and use the model level data (instead of 2/10-m fields) from +the NLDAS-2 "`FORB`" forcing dataset. This data is at the height +of the NARR lowest model level. The fields that are used are air +temperature, air humidity, winds, height of the lowest model level, +and the aerodynamic conductance. This config entry is not required, +and the default will be to not use this FORB data. However, if the +FORB model level data is chosen, you must specify the directory of +the FORB data using the "`NLDAS-2.0 FORB forcing directory:`" config. + +Note that this will read in "`Height of Atmospheric Forcing`" +and "`Surface Exchange Coefficient for Heat`" (aka, aerodynamic +conductance). You must make sure that "`Forc_Hgt:`" and "`Ch:`" +(respectively) are included in your forcing variables list file. + +Acceptable values are: + +|==== +|Value | Description + +|0 | do not use +|1 | use +|==== + +`NLDAS-2.0 use FORB model-based SWdown:` specifies whether or not +to read in and use the un-bias-corrected model downward shortwave +radiation data (in leiu of the bias-corrected data) from the NLDAS-2 +"`FORB`" forcing dataset. The data source is the NARR shortwave. +This config entry is not required, and the default will be to not +use this FORB data. However, if the FORB model-based SWdown is +chosen, you must specify the directory of the FORB data using the +"`NLDAS-2.0 FORB forcing directory:`" config. +Acceptable values are: + +|==== +|Value | Description + +|0 | do not use +|1 | use +|==== + +`NLDAS-2.0 use FORB model-based precip:` specifies whether or not +to read in and use the model-based precipitation data (instead of +the observation-based precipitation) from the NLDAS-2 "`FORB`" +forcing dataset. The data source is the NARR precipitation. +This config entry is not required, and the default will be to not +use this FORB data. However, if the FORB model-based precip is +chosen, you must specify the directory of the FORB data using the +"`NLDAS-2.0 FORB forcing directory:`" config. +Acceptable values are: + +|==== +|Value | Description + +|0 | do not use +|1 | use +|==== + +`NLDAS-2.0 use FORB model-based pressure:` specifies whether or +not to read in and use the pressure data from the NLDAS-2 "`FORB`" +forcing dataset. This data is at the height of the NARR lowest +model level. This config entry is not required, and the default +will be to not use this FORB data. However, if the FORB model-based +pressure is chosen, you must specify the directory of the FORB data +using the "`NLDAS-2.0 FORB forcing directory:`" config. +Acceptable values are: + +Acceptable values are: + +|==== +|Value | Description + +|0 | do not use +|1 | use +|==== + +.Example _lis.config_ entry +.... +NLDAS-2.0 FORA forcing directory: ./input/NLDAS2/FORA +NLDAS-2.0 FORB forcing directory: ./input/NLDAS2/FORB +NLDAS-2.0 use FORB model level data: 0 +NLDAS-2.0 use FORB model-based SWdown: 0 +NLDAS-2.0 use FORB model-based precip: 0 +NLDAS-2.0 use FORB model-based pressure: 0 +.... + [[sssec_forcings_COAMPS,COAMPS]] ==== COAMPS diff --git a/lis/make/default.cfg b/lis/make/default.cfg index 8b7538b29..8228d2bdd 100644 --- a/lis/make/default.cfg +++ b/lis/make/default.cfg @@ -267,6 +267,11 @@ enabled: True macro: MF_NLDAS2 path: metforcing/nldas2 +[NLDAS20] +enabled: True +macro: MF_NLDAS20 +path: metforcing/nldas-2.0 + [GLDAS] enabled: True macro: MF_GLDAS diff --git a/lis/metforcing/nldas-2.0/0Intro_nldas20.txt b/lis/metforcing/nldas-2.0/0Intro_nldas20.txt new file mode 100644 index 000000000..5a8fb65a7 --- /dev/null +++ b/lis/metforcing/nldas-2.0/0Intro_nldas20.txt @@ -0,0 +1,23 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +! +!BOP +!\section{NLDAS20} +!The atmospheric forcing used in the North American Land Data +!Assimilation System Phase 2 (NLDAS-2) features products at an +!hourly 0.125$^\circ$ spatial resolution, from 25 to 53 North +!and from -125 to -67 West, from January 1979 to present. +!For details, see Xia et al. (2012, JGR) and visit: +! https://ldas.gsfc.nasa.gov/nldas/v2/forcing +! +!This metforcing reader handles the netcdf-4 version 020 format +!of the NLDAS-2 forcing available from the NASA GES DISC. +! +!EOP diff --git a/lis/metforcing/nldas-2.0/finalize_nldas20.F90 b/lis/metforcing/nldas-2.0/finalize_nldas20.F90 new file mode 100644 index 000000000..992038740 --- /dev/null +++ b/lis/metforcing/nldas-2.0/finalize_nldas20.F90 @@ -0,0 +1,73 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: finalize_nldas20 +! \label{finalize_nldas20} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from finalize_nldas2.F90) +! +! !INTERFACE: +subroutine finalize_nldas20(findex) +! !USES: + use LIS_coreMod, only : LIS_rc + use nldas20_forcingMod, only : nldas20_struc + + implicit none +! !ARGUMENTS: + integer :: findex +! +! !DESCRIPTION: +! Routine to cleanup nldas20 forcing related memory allocations. +! +!EOP + integer :: n + + do n = 1,LIS_rc%nnest + if (trim(LIS_rc%met_interp(findex)).eq."bilinear") then + deallocate(nldas20_struc(n)%n111) + deallocate(nldas20_struc(n)%n121) + deallocate(nldas20_struc(n)%n211) + deallocate(nldas20_struc(n)%n221) + deallocate(nldas20_struc(n)%w111) + deallocate(nldas20_struc(n)%w121) + deallocate(nldas20_struc(n)%w211) + deallocate(nldas20_struc(n)%w221) + elseif (trim(LIS_rc%met_interp(findex)).eq."budget-bilinear") & + then + deallocate(nldas20_struc(n)%n111) + deallocate(nldas20_struc(n)%n121) + deallocate(nldas20_struc(n)%n211) + deallocate(nldas20_struc(n)%n221) + deallocate(nldas20_struc(n)%w111) + deallocate(nldas20_struc(n)%w121) + deallocate(nldas20_struc(n)%w211) + deallocate(nldas20_struc(n)%w221) + deallocate(nldas20_struc(n)%n112) + deallocate(nldas20_struc(n)%n122) + deallocate(nldas20_struc(n)%n212) + deallocate(nldas20_struc(n)%n222) + deallocate(nldas20_struc(n)%w112) + deallocate(nldas20_struc(n)%w122) + deallocate(nldas20_struc(n)%w212) + deallocate(nldas20_struc(n)%w222) + elseif(trim(LIS_rc%met_interp(findex)).eq."neighbor") then + deallocate(nldas20_struc(n)%n113) + endif + + if (LIS_rc%met_ecor(findex).ne."none") then + deallocate(nldas20_struc(n)%orig_ediff) + endif + enddo + deallocate(nldas20_struc) + +end subroutine finalize_nldas20 + diff --git a/lis/metforcing/nldas-2.0/get_netcdf4_filenames.F90 b/lis/metforcing/nldas-2.0/get_netcdf4_filenames.F90 new file mode 100644 index 000000000..eb3b590aa --- /dev/null +++ b/lis/metforcing/nldas-2.0/get_netcdf4_filenames.F90 @@ -0,0 +1,213 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: netcdf4_nldas20filea +! \label{netcdf4_nldas20filea} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from get_gesdisc_filenames.F90) +! +! !INTERFACE: +subroutine netcdf4_nldas20filea(n,kk,findex,filename, & + nldas20dir,yr,mo,da,doy,hr) +! !USES: + use LIS_coreMod + use LIS_logMod + use LIS_forecastMod + + implicit none +! !ARGUMENTS: + integer :: n + integer :: kk + integer :: findex + character(len=*), intent(out) :: filename + character(len=*), intent(in) :: nldas20dir + integer, intent(in) :: yr,mo,da,doy,hr +! +! !DESCRIPTION: +! This subroutine assembles GES DISC NLDAS-2 netCDF-4 "A" filenames +! for 1 hour file intervals. +! +! The arguments are: +! \begin{description} +! \item[nldas20dir] +! Name of the NLDAS-2 directory +! \item[yr] +! year +! \item[mo] +! month +! \item[da] +! day of month +! \item[doy] +! Julian day of year (needed for subdirectory structure) +! \item[hr] +! hour of day +! \item[filename] +! name of the timestamped GES DISC NLDAS-2 netCDF-4 file +! \end{description} +! +!EOP + character*4 :: fyr + character*3 :: fdoy + character*2 :: fmo, fda, fhr + integer :: doy2 + +!=== end variable definition =========================================== + + if (LIS_rc%forecastMode.eq.0) then !hindcast run + write(unit=fyr, fmt="(i4.4)") yr + write(unit=fdoy,fmt="(i3.3)") doy + write(unit=fmo, fmt="(i2.2)") mo + write(unit=fda, fmt="(i2.2)") da + write(unit=fhr, fmt="(i2.2)") hr + +!=== Assemble GES DISC NLDAS-2 netCDF-4 FORA filename: + filename = trim(nldas20dir)//"/"//fyr//"/"//fdoy// & + "/NLDAS_FORA0125_H.A"//fyr//fmo//fda//"."//fhr// & + "00.020.nc" + + else ! forecast mode + doy2 = doy +! IF Forecast Year is a leap years, for doy: + if ((mod(LIS_rc%yr,4).eq.0.and.mod(LIS_rc%yr,100).ne.0) & + .or.(mod(LIS_rc%yr,400).eq.0)) then + if (doy.gt.59) then ! Make sure to remove extra day + doy2 = doy - 1 + endif + endif + +! Sample yr, mo, da + call LIS_sample_forecastDate(n,kk,findex,yr,mo,da) + +! Account for member year - leap years for doy: + if ((mod(yr,4).eq.0.and.mod(yr,100).ne.0) & + .or.(mod(yr,400).eq.0)) then + if (doy.gt.59) then + doy2 = doy2 + 1 + endif + endif + + write(unit=fdoy,fmt="(i3.3)") doy2 + write(unit=fyr, fmt="(i4.4)") yr + write(unit=fmo, fmt="(i2.2)") mo + write(unit=fda, fmt="(i2.2)") da + write(unit=fhr, fmt="(i2.2)") hr + +!=== Assemble GES DISC NLDAS-2 netCDF-4 FORA filename: + filename = trim(nldas20dir)//"/"//fyr//"/"//fdoy// & + "/NLDAS_FORA0125_H.A"//fyr//fmo//fda//"."//fhr// & + "00.020.nc" + endif + +end subroutine netcdf4_nldas20filea + +!BOP +! !ROUTINE: netcdf4_nldas20fileb +! \label{netcdf4_nldas20fileb} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from get_gesdisc_filenames.F90) +! +! !INTERFACE: +subroutine netcdf4_nldas20fileb(n,kk,findex,filename, & + nldas20dir,yr,mo,da,doy,hr) +! !USES: + use LIS_coreMod + use LIS_logMod + use LIS_forecastMod + + implicit none +! !ARGUMENTS: + integer :: n + integer :: kk + integer :: findex + character(len=*), intent(out) :: filename + character(len=*), intent(in) :: nldas20dir + integer, intent(in) :: yr,mo,da,doy,hr +! +! !DESCRIPTION: +! This subroutine assembles GES DISC NLDAS-2 netCDF-4 "B" filenames +! for 1 hour file intervals. +! +! The arguments are: +! \begin{description} +! \item[nldas20dir] +! Name of the NLDAS-2 directory +! \item[yr] +! year +! \item[mo] +! month +! \item[da] +! day of month +! \item[doy] +! Julian day of year (needed for subdirectory structure) +! \item[hr] +! hour of day +! \item[filename] +! name of the timestamped GES DISC NLDAS-2 netCDF-4 file +! \end{description} +! +!EOP + character*4 :: fyr + character*3 :: fdoy + character*2 :: fmo, fda, fhr + integer :: doy2 + +!=== end variable definition ============================================= + + if (LIS_rc%forecastMode.eq.0) then !hindcast run + write(unit=fyr, fmt="(i4.4)") yr + write(unit=fdoy,fmt="(i3.3)") doy + write(unit=fmo, fmt="(i2.2)") mo + write(unit=fda, fmt="(i2.2)") da + write(unit=fhr, fmt="(i2.2)") hr + +!=== Assemble GES DISC NLDAS-2 netCDF-4 FORB filename: + filename = trim(nldas20dir)//"/"//fyr//"/"//fdoy// & + "/NLDAS_FORB0125_H.A"//fyr//fmo//fda//"."//fhr// & + "00.020.nc" + + else !forecast mode + doy2 = doy +! IF Forecast Year is a leap years, for doy: + if ((mod(LIS_rc%yr,4).eq.0.and.mod(LIS_rc%yr,100).ne.0) & + .or.(mod(LIS_rc%yr,400).eq.0)) then + if (doy.gt.59) then ! Make sure to remove extra day + doy2 = doy - 1 + endif + endif + +! Sample yr, mo, da + call LIS_sample_forecastDate(n,kk,findex,yr,mo,da) + +! Account for member year - leap years for doy: + if ((mod(yr,4).eq.0.and.mod(yr,100).ne.0) & + .or.(mod(yr,400).eq.0)) then + if (doy.gt.59) then + doy2 = doy + 1 + endif + endif + + write(unit=fdoy,fmt="(i3.3)") doy2 + write(unit=fyr, fmt="(i4.4)") yr + write(unit=fmo, fmt="(i2.2)") mo + write(unit=fda, fmt="(i2.2)") da + write(unit=fhr, fmt="(i2.2)") hr + +!=== Assemble GES DISC NLDAS-2 netCDF-4 FORB filename: + filename = trim(nldas20dir)//"/"//fyr//"/"//fdoy// & + "/NLDAS_FORB0125_H.A"//fyr//fmo//fda//"."//fhr// & + "00.020.nc" + endif + +end subroutine netcdf4_nldas20fileb + diff --git a/lis/metforcing/nldas-2.0/get_nldas20.F90 b/lis/metforcing/nldas-2.0/get_nldas20.F90 new file mode 100644 index 000000000..8d4a41c10 --- /dev/null +++ b/lis/metforcing/nldas-2.0/get_nldas20.F90 @@ -0,0 +1,274 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: get_nldas20 +! \label{get_nldas20} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from get_nldas2.F90) +! +! !INTERFACE: +subroutine get_nldas20(n,findex) +! !USES: + use LIS_coreMod, only : LIS_rc + use LIS_timeMgrMod, only : LIS_tick + use LIS_metforcingMod, only : LIS_forc + use LIS_logMod, only : LIS_logunit,LIS_endrun + use nldas20_forcingMod, only : nldas20_struc + use LIS_constantsMod, only : LIS_CONST_PATH_LEN + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: findex +! +! !DESCRIPTION: +! Opens, reads, and interpolates hourly, NLDAS-2 forcing (NARR based). +! At the beginning of a simulation, the code reads the most recent +! past data (nearest hourly interval), and the nearest future data. +! These two datasets are used to temporally interpolate the data to +! the current model timestep. The strategy for missing data is to +! go backwards up to 10 days to get forcing at the same time of day. +! +! The arguments are: +! \begin{description} +! \item[n] +! index of the nest +! \end{description} +! +! The routines invoked are: +! \begin{description} +! \item[LIS\_tick](\ref{LIS_tick}) \newline +! determines the NLDAS-2 data times +! \item[netcdf4\_nldas20filea](\ref{netcdf4_nldas20filea}) \newline +! Puts together appropriate timestamped GES DISC filename - a data +! \item[netcdf4\_nldas20fileb](\ref{netcdf4_nldas20fileb}) \newline +! Puts together appropriate timestamped GES DISC filename - b data +! \item[read\_nldas20a](\ref{read_nldas20a}) \newline +! Reads and Interpolates NLDAS-2 A data to LIS grid +! \item[read\_nldas20b](\ref{read_nldas20b}) \newline +! Reads and Interpolates NLDAS-2 B data to LIS grid +! \end{description} +! +!EOP + integer :: c,f,ferrora,ferrorb,ferror,try + integer :: order + integer :: readbfile + real*8 :: time1,time2,timenow + real*8 :: dtime1, dtime2 + integer :: yr1,mo1,da1,hr1,mn1,ss1,doy1 + integer :: yr2,mo2,da2,hr2,mn2,ss2,doy2 + character(len=LIS_CONST_PATH_LEN) :: name_a,name_b + real :: gmt1,gmt2,ts1,ts2 + integer :: movetime ! 1=move time 2 data into time 1 + integer :: kk ! Forecast member index + + external :: netcdf4_nldas20filea + external :: read_nldas20a + external :: netcdf4_nldas20fileb + external :: read_nldas20b + +!=== End Variable Definition =========================================== + try = -999 + +!=== Check to see if b-file needs to be opened + readbfile = 0 + if ((nldas20_struc(n)%model_level_data.gt.0).or. & + (nldas20_struc(n)%model_dswrf_data.gt.0).or. & + (nldas20_struc(n)%model_level_press.gt.0).or. & + (nldas20_struc(n)%model_pcp_data.gt.0)) then + readbfile = 1 + endif + +!=== Assumption will be not to find or move any data + nldas20_struc(n)%findtime1 = 0 + nldas20_struc(n)%findtime2 = 0 + movetime = 0 + +!=== Determine Required NLDAS-2 Data Times (The previous hour and the future hour) + yr1 = LIS_rc%yr + mo1 = LIS_rc%mo + da1 = LIS_rc%da + hr1 = LIS_rc%hr + mn1 = LIS_rc%mn + ss1 = 0 + ts1 = 0 + call LIS_tick(timenow,doy1,gmt1,yr1,mo1,da1,hr1,mn1,ss1,ts1) + + if (LIS_rc%ts.gt.3600) then + write(LIS_logunit,*) & + "[ERR] The model timestep is > forcing data timestep" + write(LIS_logunit,*) & + "[ERR] LIS does not support this mode currently" + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + endif + + if (mod(nint(LIS_rc%ts),3600).eq.0) then + if (timenow.ge.nldas20_struc(n)%nldas20time2) then + yr1 = LIS_rc%yr + mo1 = LIS_rc%mo + da1 = LIS_rc%da + hr1 = LIS_rc%hr + mn1 = 0 + ss1 = 0 + ts1 = -60*60 !previous hour + call LIS_tick(time1,doy1,gmt1,yr1,mo1,da1,hr1,mn1,ss1,ts1) + + yr2 = LIS_rc%yr + mo2 = LIS_rc%mo + da2 = LIS_rc%da + hr2 = LIS_rc%hr + mn2 = 0 + ss2 = 0 + ts2 = 0 !current hour + call LIS_tick(time2,doy2,gmt2,yr2,mo2,da2,hr2,mn2,ss2,ts2) + movetime = 1 + nldas20_struc(n)%findtime2 = 1 + endif + else + if (timenow.ge.nldas20_struc(n)%nldas20time2) then + yr1 = LIS_rc%yr + mo1 = LIS_rc%mo + da1 = LIS_rc%da + hr1 = LIS_rc%hr + mn1 = 0 + ss1 = 0 + ts1 = 0 !current hour + call LIS_tick(time1,doy1,gmt1,yr1,mo1,da1,hr1,mn1,ss1,ts1) + + yr2 = LIS_rc%yr + mo2 = LIS_rc%mo + da2 = LIS_rc%da + hr2 = LIS_rc%hr + mn2 = 0 + ss2 = 0 + ts2 = 60*60 !next hour + call LIS_tick(time2,doy2,gmt2,yr2,mo2,da2,hr2,mn2,ss2,ts2) + + movetime = 1 + nldas20_struc(n)%findtime2 = 1 + endif + endif + +! Beginning of the run + if ((LIS_rc%tscount(n).eq.1).or.(LIS_rc%rstflag(n).eq.1)) then + nldas20_struc(n)%findtime1 = 1 + nldas20_struc(n)%findtime2 = 1 + movetime = 0 + LIS_rc%rstflag(n) = 0 + endif + + if (movetime.eq.1) then + nldas20_struc(n)%nldas20time1 = nldas20_struc(n)%nldas20time2 + do f = 1,LIS_rc%met_nf(findex) + do c = 1,LIS_rc%ngrid(n) + nldas20_struc(n)%metdata1(:,f,c) = & + nldas20_struc(n)%metdata2(:,f,c) + enddo + enddo + endif !end of movetime=1 + +! The following looks back 10 days, at the same hour to fill data gaps. + if (nldas20_struc(n)%findtime1.eq.1) then + ferrora = 0 + ferrorb = 0 + ferror = 0 + try = 0 + ts1 = -60*60*24 + do + if (ferror.ne.0) exit + try = try + 1 +!- Obtaining NLDAS-2 File-A: + do kk = nldas20_struc(n)%st_iterid,nldas20_struc(n)%en_iterid + call netcdf4_nldas20filea(n,kk,findex,name_a, & + nldas20_struc(n)%nldas20foradir,yr1,mo1,da1,doy1,hr1) + write(unit=LIS_logunit,fmt=*) & + "[INFO] getting file1a.. ",trim(name_a) + order = 1 + call read_nldas20a(n,kk,findex,order,mo1,name_a,ferrora) + enddo + + if (readbfile.gt.0) then + do kk = nldas20_struc(n)%st_iterid, nldas20_struc(n)%en_iterid + call netcdf4_nldas20fileb(n,kk,findex,name_b, & + nldas20_struc(n)%nldas20forbdir,yr1,mo1,da1,doy1,hr1) + write(unit=LIS_logunit,fmt=*) & + "[INFO] getting file1b.. ",trim(name_b) + call read_nldas20b(n,kk,findex,order,name_b,ferrorb) + enddo + else + ferrorb = 1 + endif + + ferror = ferrora + ferrorb + if (ferror.ge.1) nldas20_struc(n)%nldas20time1 = time1 + call LIS_tick(dtime1,doy1,gmt1,yr1,mo1,da1,hr1,mn1,ss1,ts1) + if (try.gt.11) then + write(LIS_logunit,*) & + "[ERR] NLDAS-2 data gap exceeds 10 days on file 1" + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + endif + enddo +!=== end of data search + endif !end of LIS_rc%findtime=1 + + if (nldas20_struc(n)%findtime2.eq.1) then +! The following looks back 10 days, at the same hour to fill data gaps. + ferrora = 0 + ferrorb = 0 + ferror = 0 + try = 0 + ts2 = -60*60*24 + do + if (ferror.ne.0) exit + try = try+1 + + !- Obtaining NLDAS-2 File-A: + do kk = nldas20_struc(n)%st_iterid,nldas20_struc(n)%en_iterid + call netcdf4_nldas20filea(n,kk,findex,name_a, & + nldas20_struc(n)%nldas20foradir,yr2,mo2,da2,doy2,hr2) + write(unit=LIS_logunit,fmt=*) & + "[INFO] getting file2a.. ",trim(name_a) + order = 2 + call read_nldas20a(n,kk,findex,order,mo2,name_a,ferrora) + enddo + + if (readbfile.gt.0) then + do kk = nldas20_struc(n)%st_iterid, nldas20_struc(n)%en_iterid + call netcdf4_nldas20fileb(n,kk,findex,name_b, & + nldas20_struc(n)%nldas20forbdir,yr2,mo2,da2,doy2,hr2) + write(unit=LIS_logunit,fmt=*) & + "[INFO] getting file2b.. ",trim(name_b) + call read_nldas20b(n,kk,findex,order,name_b,ferrorb) + enddo + else + ferrorb = 1 + endif + + ferror = ferrora + ferrorb + if (ferror.ge.1) then + nldas20_struc(n)%nldas20time2 = time2 + endif + call LIS_tick(dtime2,doy2,gmt2,yr2,mo2,da2,hr2,mn2,ss2,ts2) + if (try.gt.11) then + write(LIS_logunit,*) & + "[ERR] NLDAS-2 data gap exceeds 10 days on file 2" + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + endif + enddo +!=== end of data search + endif ! end of findtime2=1 + +end subroutine get_nldas20 + diff --git a/lis/metforcing/nldas-2.0/nldas20_ec_removal.F90 b/lis/metforcing/nldas-2.0/nldas20_ec_removal.F90 new file mode 100644 index 000000000..7fd653bf8 --- /dev/null +++ b/lis/metforcing/nldas-2.0/nldas20_ec_removal.F90 @@ -0,0 +1,119 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: nldas20_ec_removal +! \label{nldas20_ec_removal} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from nldas2_ec_removal.F90) +! +! !INTERFACE: +subroutine nldas20_ec_removal(nest,point,force_tmp,force_hum, & + force_lwd,force_prs) +! !USES: + use LIS_coreMod, only : LIS_rc + use nldas20_forcingMod, only : nldas20_struc + + implicit none +! !ARGUMENTS: + integer, intent(in) :: nest + integer, intent(in) :: point + real, intent(inout) :: force_tmp,force_hum + real, intent(inout) :: force_lwd,force_prs +! +! !DESCRIPTION: +! Removes Temperature, Pressure, Humidity and Longwave Radiation +! forcing correction. +! +! The corrections are based on the lapse-rate and hypsometric adjustments +! to these variables described in Cosgrove et. al (2003). +! +! Cosgrove, B.A. et.al, Real-time and retrospective forcing in the +! North American Land Data Assimilation (NLDAS) project, Journal of +! Geophysical Research, 108(D22), 8842, DOI: 10.1029/2002JD003118, 2003. +! +! The arguments are: +! \begin{description} +! \item [nest] +! index of the domain or nest. +! \item [point] +! index of the grid point +! \item [force\_tmp] +! temperature value for the grid point +! \item [force\_hum] +! specific humidity for the grid point +! \item [force\_lwd] +! downward longwave radiation for the grid point +! \item [force\_prs] +! surface pressure for the grid point +! \end{description} +! +!EOP + real :: orig_tmp, orig_hum + real :: orig_lwd, orig_prs + real :: elevdiff + real :: mee, mfe, ee, fe, ratio + real :: esat,qsat,rh_corr,fesat,fqsat,femiss,emiss + real :: tbar + integer, parameter :: bb = 2016 + real, parameter :: grav = 9.81 + real, parameter :: rdry = 287. + real, parameter :: lapse = -0.0065 + +! ---------------------------------------------------------------- + + elevdiff = nldas20_struc(nest)%orig_ediff(point) + +! -- Apply elevation correction to temperature: + orig_tmp = force_tmp - (lapse*elevdiff) + tbar = (orig_tmp + force_tmp) / 2.0 + +! -- Apply elevation correction to surface pressure: + orig_prs = force_prs * (exp((grav*elevdiff)/(rdry*tbar))) + +! -- Apply elevation correction to humidity: + if (force_hum.eq.0) force_hum = 1e-08 + + esat = 611.2*(exp((17.67*(orig_tmp-273.15)) / & + ((orig_tmp-273.15)+243.5))) + qsat = (0.622*esat) / (orig_prs-(0.378*esat)) + fesat = 611.2*(exp((17.67*(force_tmp-273.15)) / & + ((force_tmp-273.15)+243.5))) + fqsat = (0.622*fesat) / (force_prs-(0.378*fesat)) + rh_corr = (force_hum / fqsat) * 100.0 + orig_hum = (rh_corr * qsat) / 100.0 + +! -- Apply elevation correction to downward LW radiation: + ee = (orig_hum * orig_prs) / 0.622 + fe = (force_hum * force_prs) / 0.622 + mee = ee / 100.0 + mfe = fe / 100.0 + +!---------------------------------------------------------------------- +! Correct for negative vapor pressure at very low temperatures at +! high latitudes +!---------------------------------------------------------------------- + if (mee.le.0) mee = 1e-08 + if (mfe.le.0) mfe = 1e-08 + + emiss = 1.08 * (1.0-exp(-mee**(orig_tmp/bb))) + femiss = 1.08 * (1.0-exp(-mfe**(force_tmp/bb))) + ratio = (femiss*(force_tmp**4)) / (emiss*(orig_tmp**4)) + orig_lwd = force_lwd / ratio + +!-- Reassign uncorrected fields to LIS forcing fields:: + force_tmp = orig_tmp + force_hum = orig_hum + force_lwd = orig_lwd + force_prs = orig_prs + +end subroutine nldas20_ec_removal + diff --git a/lis/metforcing/nldas-2.0/nldas20_forcingMod.F90 b/lis/metforcing/nldas-2.0/nldas20_forcingMod.F90 new file mode 100644 index 000000000..7dfd35f4a --- /dev/null +++ b/lis/metforcing/nldas-2.0/nldas20_forcingMod.F90 @@ -0,0 +1,344 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 United States Government as represented by the +! Administrator of the National Aeronautics and Space Administration. +! All Rights Reserved. +!-------------------------END NOTICE -- DO NOT EDIT----------------------- +module nldas20_forcingMod +!BOP +! !MODULE: nldas20_forcingMod +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from nldas2_forcingMod.F90) +! +! !USES: + use LIS_constantsMod, only : LIS_CONST_PATH_LEN + + implicit none + + PRIVATE +!----------------------------------------------------------------------------- +! !PUBLIC MEMBER FUNCTIONS: +!----------------------------------------------------------------------------- + public :: init_NLDAS20 !defines the native resolution of the input data +!----------------------------------------------------------------------------- +! !PUBLIC TYPES: +!----------------------------------------------------------------------------- + public :: nldas20_struc +! +! !DESCRIPTION: +! This module contains variables and data structures that are used +! for the implementation of the forcing data used in the North American +! Land Data Assimilation System Phase 2. The variables are produced +! at 0.125 degree spatial resolution, and at hourly intervals. +! For more details please view the forcing files manual available +! at the following URL: +! https://ldas.gsfc.nasa.gov/nldas/v2/forcing +! +! The implementation in LIS has the derived data type {\tt nldas20\_struc} +! that includes the variables that specify the runtime options, and the +! weights and neighbor information to be used for spatial interpolation. +! They are described below: +! \begin{description} +! \item[ncold] +! Number of columns (along the east west dimension) for the input data +! \item[nrold] +! Number of rows (along the north south dimension) for the input data +! \item[nldas20time1] +! The nearest, previous hourly instance of the incoming +! data (as a real time). +! \item[nldas20time2] +! The nearest, next hourly instance of the incoming +! data (as a real time). +! \item[nldas20foradir] +! Directory containing the FORA netCDF-4 input data +! \item[nldas20foradir] +! Directory containing the FORB netCDF-4 input data +! \item[mi] +! Number of points in the input grid +! \item[n111,n121,n211,n221] +! Arrays containing the neighbor information of the input grid +! for each grid point in LIS, for bilinear interpolation. +! \item[w111,w121,w211,w221] +! Arrays containing the weights of the input grid +! for each grid point in LIS, for bilinear interpolation. +! \item[n122,n122,n212,n222] +! Arrays containing the neighbor information of the input grid +! for each grid point in LIS, for conservative interpolation. +! \item[w112,w122,w212,w222] +! Arrays containing the weights of the input grid +! for each grid point in LIS, for conservative interpolation. +! \item[n113] +! Arrays containing the neighbor information of the input grid +! for each grid point in LIS, for nearest neighbor interpolation. +! \item[findtime1, findtime2] +! boolean flags to indicate which time is to be read for +! temporal interpolation. +! \end{description} +! +!EOP + type, public :: nldas20_type_dec + real :: ts + integer :: ncold, nrold ! AWIPS 212 dimensions + character(len=LIS_CONST_PATH_LEN) :: nldas20foradir,nldas20forbdir + real*8 :: nldas20time1,nldas20time2 + integer :: model_level_data + integer :: model_level_press + integer :: model_pcp_data + integer :: model_dswrf_data + + real, allocatable :: orig_ediff(:) + real :: gridDesc(50) + integer :: mi + integer, allocatable :: n111(:) + integer, allocatable :: n121(:) + integer, allocatable :: n211(:) + integer, allocatable :: n221(:) + real, allocatable :: w111(:),w121(:) + real, allocatable :: w211(:),w221(:) + integer, allocatable :: n112(:,:) + integer, allocatable :: n122(:,:) + integer, allocatable :: n212(:,:) + integer, allocatable :: n222(:,:) + real, allocatable :: w112(:,:),w122(:,:) + real, allocatable :: w212(:,:),w222(:,:) + integer, allocatable :: n113(:) + + integer :: findtime1, findtime2 + integer :: nIter, st_iterid,en_iterid ! Forecast parameters + + real, allocatable :: metdata1(:,:,:) + real, allocatable :: metdata2(:,:,:) + + end type nldas20_type_dec + + type(nldas20_type_dec), allocatable :: nldas20_struc(:) + +contains +!BOP +! +! !ROUTINE: init_NLDAS20 +! \label{init_NLDAS20} +! +! !INTERFACE: + subroutine init_NLDAS20(findex) +! !USES: + use LIS_coreMod, only : LIS_rc + use LIS_timeMgrMod, only : LIS_update_timestep + use LIS_logMod, only : LIS_logunit,LIS_endrun + use map_utils, only : proj_latlon + use LIS_spatialDownscalingMod, only : LIS_init_pcpclimo_native + use LIS_forecastMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: findex +! +! !DESCRIPTION: +! Defines the native resolution of the input forcing for NLDAS-2 +! data. The grid description arrays are based on the netCDF-4 +! data and followed in the LIS interpolation schemes +! (see Section~\ref{interp}). +! +! The routines invoked are: +! \begin{description} +! \item[readcrd\_nldas20](\ref{readcrd_nldas20}) \newline +! reads the runtime options specified for NLDAS-2 data +! \item[bilinear\_interp\_input](\ref{bilinear_interp_input}) \newline +! computes the neighbor, weights for bilinear interpolation +! \item[conserv\_interp\_input](\ref{conserv_interp_input}) \newline +! computes the neighbor, weights for conservative interpolation +! \item[read\_nldas20\_elev](\ref{read_nldas20_elev}) \newline +! reads the native elevation of the NLDAS-2 data to be used +! for topographic adjustments to the forcing +! \end{description} +! +!EOP + integer :: n + + external :: readcrd_nldas20 + external :: bilinear_interp_input + external :: conserv_interp_input + external :: neighbor_interp_input + external :: read_orig_nldas20_elevdiff + external :: read_nldas20_elev + + + allocate(nldas20_struc(LIS_rc%nnest)) + call readcrd_nldas20() + + do n = 1,LIS_rc%nnest + nldas20_struc(n)%ts = 3600 + call LIS_update_timestep(LIS_rc,n,nldas20_struc(n)%ts) + enddo + + LIS_rc%met_nf(findex) = 13 + +! Set NLDAS-2 grid dimensions and extent information: + nldas20_struc(:)%ncold = 464 + nldas20_struc(:)%nrold = 224 + + do n = 1,LIS_rc%nnest + +! Forecast mode: + if (LIS_rc%forecastMode.eq.1) then + if (mod(LIS_rc%nensem(n), & + LIS_forecast_struc(1)%niterations).ne.0) then + write(LIS_logunit,*) & + "[ERR] The number of ensembles must be a multiple" + write(LIS_logunit,*) & + "[ERR] of the number of iterations" + write(LIS_logunit,*) & + "[ERR] nensem = ",LIS_rc%nensem(n) + write(LIS_logunit,*) & + "[ERR] niter = ",LIS_forecast_struc(1)%niterations + call LIS_endrun() + endif + + allocate(nldas20_struc(n)%metdata1( & + LIS_forecast_struc(1)%niterations, & + LIS_rc%met_nf(findex),LIS_rc%ngrid(n))) + allocate(nldas20_struc(n)%metdata2( & + LIS_forecast_struc(1)%niterations, & + LIS_rc%met_nf(findex),LIS_rc%ngrid(n))) + + nldas20_struc(n)%st_iterid = LIS_forecast_struc(1)%st_iterId + nldas20_struc(n)%en_iterId = LIS_forecast_struc(1)%niterations + nldas20_struc(n)%nIter = LIS_forecast_struc(1)%niterations + +! Regular retrospective or non-forecast mode: + else + allocate(nldas20_struc(n)%metdata1(1,LIS_rc%met_nf(findex), & + LIS_rc%ngrid(n))) + allocate(nldas20_struc(n)%metdata2(1,LIS_rc%met_nf(findex), & + LIS_rc%ngrid(n))) + + nldas20_struc(n)%st_iterid = 1 + nldas20_struc(n)%en_iterId = 1 + nldas20_struc(n)%nIter = 1 + endif + + nldas20_struc(n)%metdata1 = 0 + nldas20_struc(n)%metdata2 = 0 + nldas20_struc(n)%gridDesc = 0 + nldas20_struc(n)%findtime1 = 0 + nldas20_struc(n)%findtime2 = 0 + nldas20_struc(n)%gridDesc(1) = 0 + nldas20_struc(n)%gridDesc(2) = nldas20_struc(n)%ncold + nldas20_struc(n)%gridDesc(3) = nldas20_struc(n)%nrold + nldas20_struc(n)%gridDesc(4) = 25.0625 + nldas20_struc(n)%gridDesc(5) = -124.9375 + nldas20_struc(n)%gridDesc(6) = 128 + nldas20_struc(n)%gridDesc(7) = 52.9375 + nldas20_struc(n)%gridDesc(8) = -67.0625 + nldas20_struc(n)%gridDesc(9) = 0.125 + nldas20_struc(n)%gridDesc(10) = 0.125 + nldas20_struc(n)%gridDesc(20) = 64 + +! Check for grid and interp option selected: + if ((nldas20_struc(n)%gridDesc(9).eq.LIS_rc%gridDesc(n,9)).and. & + (nldas20_struc(n)%gridDesc(10).eq.LIS_rc%gridDesc(n,10)).and. & + (LIS_rc%gridDesc(n,1).eq.proj_latlon).and. & + (LIS_rc%met_interp(findex).ne."neighbor")) then + write(LIS_logunit,*) & + "[ERR] The NLDAS grid was selected for the LIS run domain;" + write(LIS_logunit,*) & + "[ERR] however, 'bilinear', 'budget-bilinear', or some" + write(LIS_logunit,*) & + "[ERR] other unknown option was selected to spatially" + write(LIS_logunit,*) & + "[ERR] downscale the grid, which will cause errors" + write(LIS_logunit,*) & + "[ERR] during runtime. Please select 'neighbor'." + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + endif + + nldas20_struc(n)%mi = nldas20_struc(n)%ncold*nldas20_struc(n)%nrold + +! Setting up weights for spatial interpolation: + select case(LIS_rc%met_interp(findex)) + + case ("bilinear") + allocate(nldas20_struc(n)%n111(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%n121(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%n211(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%n221(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w111(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w121(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w211(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w221(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + + call bilinear_interp_input(n,nldas20_struc(n)%gridDesc(:), & + nldas20_struc(n)%n111,nldas20_struc(n)%n121, & + nldas20_struc(n)%n211,nldas20_struc(n)%n221, & + nldas20_struc(n)%w111,nldas20_struc(n)%w121, & + nldas20_struc(n)%w211,nldas20_struc(n)%w221) + + case ("budget-bilinear") + allocate(nldas20_struc(n)%n111(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%n121(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%n211(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%n221(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w111(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w121(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w211(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + allocate(nldas20_struc(n)%w221(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + + call bilinear_interp_input(n,nldas20_struc(n)%gridDesc(:), & + nldas20_struc(n)%n111,nldas20_struc(n)%n121, & + nldas20_struc(n)%n211,nldas20_struc(n)%n221, & + nldas20_struc(n)%w111,nldas20_struc(n)%w121, & + nldas20_struc(n)%w211,nldas20_struc(n)%w221) + + allocate(nldas20_struc(n)%n112(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%n122(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%n212(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%n222(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%w112(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%w122(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%w212(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + allocate(nldas20_struc(n)%w222(LIS_rc%lnc(n)*LIS_rc%lnr(n),25)) + + call conserv_interp_input(n,nldas20_struc(n)%gridDesc(:), & + nldas20_struc(n)%n112,nldas20_struc(n)%n122, & + nldas20_struc(n)%n212,nldas20_struc(n)%n222, & + nldas20_struc(n)%w112,nldas20_struc(n)%w122, & + nldas20_struc(n)%w212,nldas20_struc(n)%w222) + + case ("neighbor") + allocate(nldas20_struc(n)%n113(LIS_rc%lnc(n)*LIS_rc%lnr(n))) + call neighbor_interp_input(n,nldas20_struc(n)%gridDesc(:), & + nldas20_struc(n)%n113) + + case default + write(LIS_logunit,*) & + "[ERR] Interpolation option not specified for NLDAS-2" + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + end select + +! Read in elevation difference and NLDAS-2 elevation maps: + if (LIS_rc%met_ecor(findex).ne."none") then + allocate(nldas20_struc(n)%orig_ediff( & + nldas20_struc(n)%ncold*nldas20_struc(n)%nrold)) + call read_orig_nldas20_elevdiff(n) + call read_nldas20_elev(n,findex) + endif + +! Set up precipitation climate downscaling: + if (LIS_rc%pcp_downscale(findex).ne.0) then + call LIS_init_pcpclimo_native(n,findex, & + nint(nldas20_struc(n)%gridDesc(2)), & + nint(nldas20_struc(n)%gridDesc(3))) + endif + enddo + + end subroutine init_NLDAS20 + +end module nldas20_forcingMod + diff --git a/lis/metforcing/nldas-2.0/read_nldas20_elev.F90 b/lis/metforcing/nldas-2.0/read_nldas20_elev.F90 new file mode 100644 index 000000000..1e614c64e --- /dev/null +++ b/lis/metforcing/nldas-2.0/read_nldas20_elev.F90 @@ -0,0 +1,95 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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_nldas20_elev +! \label{read_nldas20_elev} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from read_nldas2_elev.F90) +! +! !INTERFACE: +subroutine read_nldas20_elev(n,findex) +! !USES: + use LIS_coreMod + use LIS_metforcingMod + use LIS_logMod + use nldas20_forcingMod + use LIS_fileIOMod +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + use netcdf +#endif + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: findex +! +! !DESCRIPTION: +! +! Opens, reads, and interpolates NLDAS-2 model elevation to the +! LIS grid. The data will be used to perform any topographical +! adjustments to the forcing. +! +! The arguments are: +! \begin{description} +! \item[n] +! index of the nest +! \end{description} +! +! The routines invoked are: +! \begin{description} +! \item[ij\_to\_latlon](\ref{ij_to_latlon}) \newline +! computes the lat lon values in LIS grid projection +! \end{description} +! +!EOP + logical :: file_exists + integer :: nid,elevId + integer :: c,r + real :: elev(LIS_rc%gnc(n),LIS_rc%gnr(n)) + real :: elev_subset(LIS_rc%lnc(n),LIS_rc%lnr(n)) + +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + inquire(file=LIS_rc%paramfile(n),exist=file_exists) + if (file_exists) then + write(LIS_logunit,*) & + "[INFO] Reading NLDAS-2 elevation data ... " + + call LIS_verify(nf90_open(path=LIS_rc%paramfile(n), & + mode=NF90_NOWRITE,ncid=nid), & + "nf90_open failed in read_nldas20_elev") + call LIS_verify(nf90_inq_varid(nid,"ELEV_NLDAS2",elevId), & + "nf90_inq_varid failed in read_nldas20_elev") + call LIS_verify(nf90_get_var(nid,elevId,elev), & + "nf90_get_var failed in read_nldas20_elev") + call LIS_verify(nf90_close(nid)) + + elev_subset(:,:) = elev(LIS_ews_halo_ind(n,LIS_localPet+1): & + LIS_ewe_halo_ind(n,LIS_localPet+1), & + LIS_nss_halo_ind(n,LIS_localPet+1): & + LIS_nse_halo_ind(n,LIS_localPet+1)) + + do r = 1,LIS_rc%lnr(n) + do c = 1,LIS_rc%lnc(n) + if (LIS_domain(n)%gindex(c,r).ne.-1) then + LIS_forc(n,findex)%modelelev(LIS_domain(n)%gindex(c,r)) = elev_subset(c,r) + endif + enddo + enddo + endif + + write(LIS_logunit,*) & + "[INFO] Finished reading original NLDAS-2 elevation data" +#endif + +end subroutine read_nldas20_elev + diff --git a/lis/metforcing/nldas-2.0/read_nldas20a.F90 b/lis/metforcing/nldas-2.0/read_nldas20a.F90 new file mode 100644 index 000000000..bd38878f1 --- /dev/null +++ b/lis/metforcing/nldas-2.0/read_nldas20a.F90 @@ -0,0 +1,357 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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_nldas20a +! \label{read_nldas20a} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from read_nldas2a.F90) +! +! !INTERFACE: +subroutine read_nldas20a(n,kk,findex,order,month,name,ferror) +! !USES: + use LIS_coreMod + use LIS_logMod, only : LIS_logunit,LIS_verify,LIS_warning + use LIS_metforcingMod, only : LIS_forc + use nldas20_forcingMod, only : nldas20_struc +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + use netcdf +#endif + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: kk ! Forecast member index + integer, intent(in) :: findex ! Forcing index + integer, intent(in) :: order + integer, intent(out) :: month + character(len=*), intent(in) :: name + integer, intent(out) :: ferror +! +! !DESCRIPTION: +! For the given time, reads values from NLDAS-2 netCDF-4 FORA data, +! transforms into 11 variables, and interpolates to the LIS domain. +! +! The arguments are: +! \begin{description} +! \item[n] +! index of the nest +! \item[kk] +! forecast member index +! \item[findex] +! forcing index +! \item[order] +! flag indicating which data to be read (order=1, read the previous +! hourly instance, order=2, read the next hourly instance) +! \item[month] +! current month +! \item[name] +! name of the hourly NLDAS-2 forecast file +! \item[ferror] +! flag to indicate success of the call (=1 indicates success) +! \end{description} +! +! The routines invoked are: +! \begin{description} +! \item[interp\_nldas20](\ref{interp_nldas20}) \newline +! spatially interpolates a NLDAS-2 variable +! \end{description} +! +!EOP + integer :: iv,ftn + integer :: nldas20,paramid + integer :: k,t,c,r,iret,rc + real, parameter :: missingValue = -9999.0 + integer, parameter :: nvars = 11 + logical :: pcp_flag + logical :: file_exists + character(len=20) :: input_varname(nvars) + logical*1, allocatable :: lb(:) + real, allocatable :: f(:) + real, allocatable :: nldas20_forcing(:,:) + real :: varfield(LIS_rc%lnc(n),LIS_rc%lnr(n)) + real :: dummy(nldas20_struc(n)%ncold,nldas20_struc(n)%nrold) + + ferror = 1 + iv = 0 + + input_varname(1) = "Tair" + input_varname(2) = "Qair" + input_varname(3) = "SWdown" + input_varname(4) = "LWdown" + input_varname(5) = "Wind_E" + input_varname(6) = "Wind_N" + input_varname(7) = "PSurf" + input_varname(8) = "Rainf" + input_varname(9) = "CRainf_frac" + input_varname(10) = "PotEvap" + input_varname(11) = "CAPE" + +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + nldas20 = (nldas20_struc(n)%ncold*nldas20_struc(n)%nrold) + + allocate(nldas20_forcing(nldas20_struc(n)%ncold*nldas20_struc(n)%nrold,nvars)) + + varfield = 0 + ferror = 1 + + inquire(file=name,exist=file_exists) + if (file_exists) then + iret = nf90_open(path=name,mode=NF90_NOWRITE,ncid=ftn) + if (iret.ne.0) then + write(LIS_logunit,*) "[WARN] Could not open file: ",trim(name) + ferror = 0 + return + endif + + allocate(lb(nldas20_struc(n)%ncold*nldas20_struc(n)%nrold)) + allocate(f(nldas20_struc(n)%ncold*nldas20_struc(n)%nrold)) + + do k = 1,nvars + iret = nf90_inq_varid(ftn,trim(input_varname(k)),paramid) + call LIS_verify(iret,trim(input_varname(k))// & + " field not found in the hourly file") + iret = nf90_get_var(ftn,paramid,dummy) + call LIS_verify(iret,"Error in nf90_get_var") + + ! write(LIS_logunit,*) "[INFO] Read field: ",input_varname(k) + + f = LIS_rc%udef ! Initialize forcing + t = 0 + do r = 1,nldas20_struc(n)%nrold + do c = 1,nldas20_struc(n)%ncold + t = t + 1 + f(t) = dummy(c,r) + enddo + enddo + + lb = .false. + do t = 1,nldas20 + if (f(t).ne.missingValue) then + nldas20_forcing(t,k) = f(t) + lb(t) = .true. + else + nldas20_forcing(t,k) = LIS_rc%udef + endif + enddo + enddo + deallocate(f) + + iret = nf90_close(ftn) + + if (LIS_rc%met_ecor(findex).ne."none") then + do t = 1,nldas20 + if (lb(t)) then + call nldas20_ec_removal(n,t,nldas20_forcing(t,1), & + nldas20_forcing(t,2),nldas20_forcing(t,4), & + nldas20_forcing(t,7)) + endif + enddo + endif + + do iv = 1,nvars + pcp_flag = .false. + if ((iv.eq.8).or.(iv.eq.9)) pcp_flag = .true. + + call interp_nldas20(n,findex,month,pcp_flag,nldas20, & + nldas20_forcing(:,iv), & + lb,LIS_rc%gridDesc(n,:), & + LIS_rc%lnc(n),LIS_rc%lnr(n),varfield) + + do r = 1,LIS_rc%lnr(n) + do c = 1,LIS_rc%lnc(n) + if (LIS_domain(n)%gindex(c,r).ne.-1) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,iv, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,iv, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + enddo + enddo + enddo + deallocate(lb) + else + write(LIS_logunit,*) "[WARN] Could not find file: ",trim(name) + ferror = 0 + endif + + deallocate(nldas20_forcing) +#endif + +end subroutine read_nldas20a + +!BOP +! !ROUTINE: interp_nldas20 +! \label{interp_nldas20} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from read_nldas2a.F90) +! +! !INTERFACE: +subroutine interp_nldas20(n,findex,month,pcp_flag,input_size, & + input_data,input_bitmap,lis_gds,nc,nr,output_2d) +! !USES: + use LIS_coreMod, only : LIS_rc,LIS_domain + use nldas20_forcingMod, only : nldas20_struc + use LIS_spatialDownscalingMod + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: findex + integer, intent(in) :: month + logical, intent(in) :: pcp_flag + integer, intent(in) :: input_size + real, intent(in) :: input_data(input_size) + logical*1, intent(in) :: input_bitmap(input_size) + real, intent(in) :: lis_gds(50) + integer, intent(in) :: nc + integer, intent(in) :: nr + real, intent(inout) :: output_2d(nc,nr) +! +! !DESCRIPTION: +! This subroutine interpolates a given NLDAS-2 field to the LIS grid. +! The arguments are: +! \begin{description} +! \item[n] +! index of the nest +! \item[findex] +! forcing index +! \item[month] +! current month +! \item[pcp_flag] +! flag indicating if it is a precip field +! \item[input\_size] +! number of elements in the input grid +! \item[input\_bitmap] +! input bitmap +! \item[lis\_gds] +! array description of the LIS grid +! \item[nc] +! number of columns (in the east-west dimension) in the LIS grid +! \item[nr] +! number of rows (in the north-south dimension) in the LIS grid +! \item[output\_2d] +! output interpolated field +! \end{description} +! +! The routines invoked are: +! \begin{description} +! \item[bilinear\_interp](\ref{bilinear_interp}) \newline +! spatially interpolate the forcing data using bilinear interpolation +! \item[conserv\_interp](\ref{conserv_interp}) \newline +! spatially interpolate the forcing data using conservative interpolation +! \item[neighbor\_interp](\ref{neighbor_interp}) \newline +! spatially interpolate the forcing data using nearest neighbor interpolation +! \end{description} +! +!EOP + integer :: iret + integer :: mo + integer :: count1,i,j + real, dimension(nc*nr) :: output_data + logical*1 :: output_bitmap(nc*nr) + +!=== End variable declarations + + mo = nc*nr +!----------------------------------------------------------------------- +! Initialize output bitmap. +!----------------------------------------------------------------------- + output_bitmap = .true. + +!----------------------------------------------------------------------- +! Apply downscaling +!----------------------------------------------------------------------- + +!Bailing Li +! if LIS_rc%pcp_downscale(findex).eq.1: spatial downscaling and scaling factors are calculated in LIS +! if LIS_rc%pcp_downscale(findex).eq.2: spatial downscaling and bias-correction using ratios of two +! PCP climatologies which are calculated in LDT and stored in lis input file + + if (pcp_flag) then + if (LIS_rc%pcp_downscale(findex).eq.1) then +!input_data becomes the ratio field. + call LIS_generatePcpClimoRatioField(n,findex,"NLDAS2", & + month,input_size,input_data,input_bitmap) + elseif (pcp_flag.and.(LIS_rc%pcp_downscale(findex).eq.2)) then + call LIS_readPcpClimoRatioField(n,findex,month) + endif + endif + +!----------------------------------------------------------------------- +! Interpolate to LIS grid +!----------------------------------------------------------------------- + select case(LIS_rc%met_interp(findex)) + + case("bilinear") + call bilinear_interp(lis_gds,input_bitmap,input_data, & + output_bitmap,output_data,nldas20_struc(n)%mi,mo, & + LIS_domain(n)%lat,LIS_domain(n)%lon, & + nldas20_struc(n)%w111,nldas20_struc(n)%w121, & + nldas20_struc(n)%w211,nldas20_struc(n)%w221, & + nldas20_struc(n)%n111,nldas20_struc(n)%n121, & + nldas20_struc(n)%n211,nldas20_struc(n)%n221, & + LIS_rc%udef,iret) + + case("budget-bilinear") + if (pcp_flag) then + call conserv_interp(lis_gds,input_bitmap,input_data, & + output_bitmap,output_data,nldas20_struc(n)%mi,mo, & + LIS_domain(n)%lat,LIS_domain(n)%lon, & + nldas20_struc(n)%w112,nldas20_struc(n)%w122, & + nldas20_struc(n)%w212,nldas20_struc(n)%w222, & + nldas20_struc(n)%n112,nldas20_struc(n)%n122, & + nldas20_struc(n)%n212,nldas20_struc(n)%n222, & + LIS_rc%udef,iret) + + else + call bilinear_interp(lis_gds,input_bitmap,input_data, & + output_bitmap,output_data,nldas20_struc(n)%mi,mo, & + LIS_domain(n)%lat,LIS_domain(n)%lon, & + nldas20_struc(n)%w111,nldas20_struc(n)%w121, & + nldas20_struc(n)%w211,nldas20_struc(n)%w221, & + nldas20_struc(n)%n111,nldas20_struc(n)%n121, & + nldas20_struc(n)%n211,nldas20_struc(n)%n221, & + LIS_rc%udef,iret) + endif + + case("neighbor") + call neighbor_interp(lis_gds,input_bitmap,input_data, & + output_bitmap,output_data,nldas20_struc(n)%mi,mo, & + LIS_domain(n)%lat,LIS_domain(n)%lon, & + nldas20_struc(n)%n113,LIS_rc%udef,iret) + + end select + + if (pcp_flag.and.(LIS_rc%pcp_downscale(findex).ne.0)) then + call LIS_pcpClimoDownscaling(n,findex,month,nc*nr, & + output_data,output_bitmap) + endif + +!----------------------------------------------------------------------- +! convert the interpolated data to 2d. +!----------------------------------------------------------------------- + count1 = 0 + do j = 1,nr + do i = 1,nc + output_2d(i,j) = output_data(i+count1) + enddo + count1 = count1 + nc + enddo + +end subroutine interp_nldas20 + diff --git a/lis/metforcing/nldas-2.0/read_nldas20b.F90 b/lis/metforcing/nldas-2.0/read_nldas20b.F90 new file mode 100644 index 000000000..b4de60393 --- /dev/null +++ b/lis/metforcing/nldas-2.0/read_nldas20b.F90 @@ -0,0 +1,303 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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_nldas20b +! \label{read_nldas20b} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from read_nldas2b.F90) +! +! !INTERFACE: +subroutine read_nldas20b(n,kk,findex,order,name,ferror) +! !USES: + use LIS_coreMod, only : LIS_rc,LIS_domain + use LIS_logMod, only : LIS_logunit,LIS_verify,LIS_warning + use LIS_metforcingMod, only : LIS_forc + use nldas20_forcingMod, only : nldas20_struc +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + use netcdf +#endif + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: kk ! Forecast member index + integer, intent(in) :: findex ! Forcing index + integer, intent(in) :: order + character(len=*), intent(in) :: name + integer, intent(out) :: ferror +! +! !DESCRIPTION: +! For the given time, reads values from NLDAS-2 netCDF-4 FORB data, +! transforms into 10 variables, and interpolates to the LIS domain. +! +! The arguments are: +! \begin{description} +! \item[n] +! index of the nest +! \item[kk] +! forecast member index +! \item[findex] +! forcing index +! \item[order] +! flag indicating which data to be read (order=1, read the previous +! hourly instance, order=2, read the next hourly instance) +! \item[name] +! name of the hourly NLDAS-2 forecast file +! \item[ferror] +! flag to indicate success of the call (=1 indicates success) +! \end{description} +! +! The routines invoked are: +! \begin{description} +! \item[interp\_nldas20](\ref{interp_nldas20}) \newline +! spatially interpolates a NLDAS-2 variable +! \end{description} +! +!EOP + integer :: iv,ftn + integer :: nldas20,paramid + integer :: k,t,c,r,iret,rc + real, parameter :: missingValue = -9999.0 + integer, parameter :: nvars = 10 + logical :: pcp_flag + logical :: file_exists + character(len=20) :: input_varname(nvars) + logical*1, allocatable :: lb(:) + real, allocatable :: f(:) + real, allocatable :: nldas20_forcing(:,:) + real :: varfield(LIS_rc%lnc(n),LIS_rc%lnr(n)) + real :: dummy(nldas20_struc(n)%ncold,nldas20_struc(n)%nrold) + + ferror = 1 + iv = 0 + + input_varname(1) = "SWdown" + input_varname(2) = "Rainf" + input_varname(3) = "CRainf" + input_varname(4) = "ACond" + input_varname(5) = "Tair" + input_varname(6) = "Qair" + input_varname(7) = "PSurf" + input_varname(8) = "Wind_E" + input_varname(9) = "Wind_N" + input_varname(10) = "PhiS" + +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + nldas20 = (nldas20_struc(n)%ncold*nldas20_struc(n)%nrold) + + allocate(nldas20_forcing(nldas20_struc(n)%ncold*nldas20_struc(n)%nrold,nvars)) + + varfield = 0 + ferror = 1 + + inquire(file=name,exist=file_exists) + if (file_exists) then + iret = nf90_open(path=name,mode=NF90_NOWRITE,ncid=ftn) + if (iret.ne.0) then + write(LIS_logunit,*) "[WARN] Could not open file: ",trim(name) + ferror = 0 + return + endif + + allocate(lb(nldas20_struc(n)%ncold*nldas20_struc(n)%nrold)) + allocate(f(nldas20_struc(n)%ncold*nldas20_struc(n)%nrold)) + + do k = 1,nvars + iret = nf90_inq_varid(ftn,trim(input_varname(k)),paramid) + call LIS_verify(iret,trim(input_varname(k))// & + " field not found in the hourly file") + iret = nf90_get_var(ftn,paramid,dummy) + call LIS_verify(iret,"Error in nf90_get_var") + ! write(LIS_logunit,*) "[INFO] Read field: ",input_varname(k) + + f = LIS_rc%udef ! Initialize forcing + t = 0 + do r = 1,nldas20_struc(n)%nrold + do c = 1,nldas20_struc(n)%ncold + t = t + 1 + f(t) = dummy(c,r) + enddo + enddo + + lb = .false. + do t = 1,nldas20 + if (f(t).ne.missingValue) then + nldas20_forcing(t,k) = f(t) + lb(t) = .true. + else + nldas20_forcing(t,k) = LIS_rc%udef + endif + enddo + enddo + deallocate(f) + + iret = nf90_close(ftn) + + do iv = 1,nvars + pcp_flag = .false. + if ((iv.eq.2).or.(iv.eq.3)) pcp_flag = .true. + + call interp_nldas20(n,findex,LIS_rc%mo,pcp_flag,nldas20, & + nldas20_forcing(:,iv), & + lb,LIS_rc%gridDesc(n,:), & + LIS_rc%lnc(n),LIS_rc%lnr(n),varfield) + + do r = 1,LIS_rc%lnr(n) + do c = 1,LIS_rc%lnc(n) + if (LIS_domain(n)%gindex(c,r).ne.-1) then + +! MODEL LEVEL TAIR CASE + if (iv.eq.5) then + if (nldas20_struc(n)%model_level_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,1, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,1, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL LEVEL SPFH CASE + if (iv.eq.6) then + if (nldas20_struc(n)%model_level_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,2, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,2, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! USE MODEL BASED DSWRF CASE + if (iv.eq.1) then + if (nldas20_struc(n)%model_dswrf_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,3, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,3, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL LEVEL USE AERODYNAMIC CONDUCTANCE + if (iv.eq.4) then + if (nldas20_struc(n)%model_level_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,13, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,13, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL LEVEL UWIND CASE + if (iv.eq.8) then + if (nldas20_struc(n)%model_level_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,5, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,5, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL LEVEL VWIND CASE + if (iv.eq.9) then + if (nldas20_struc(n)%model_level_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,6, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,6, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL LEVEL PRESSURE CASE + if (iv.eq.7) then + if (nldas20_struc(n)%model_level_press.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,7, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,7, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL BASED PRECIP CASE + if (iv.eq.2) then + if (nldas20_struc(n)%model_pcp_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,8, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,8, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL BASED CONV. PRECIP CASE + if (iv.eq.3) then + if (nldas20_struc(n)%model_pcp_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,9, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,9, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + +! MODEL FORCING HEIGHT CASE + if (iv.eq.10) then + if (nldas20_struc(n)%model_level_data.gt.0) then + if (order.eq.1) then + nldas20_struc(n)%metdata1(kk,12, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + elseif (order.eq.2) then + nldas20_struc(n)%metdata2(kk,12, & + LIS_domain(n)%gindex(c,r)) = varfield(c,r) + endif + endif + endif + + endif + enddo + enddo + enddo + deallocate(lb) + else + write(LIS_logunit,*) "[WARN] Could not find file: ",trim(name) + ferror = 0 + endif + + deallocate(nldas20_forcing) +#endif + +end subroutine read_nldas20b + diff --git a/lis/metforcing/nldas-2.0/read_orig_nldas20_elevdiff.F90 b/lis/metforcing/nldas-2.0/read_orig_nldas20_elevdiff.F90 new file mode 100644 index 000000000..394cc39a0 --- /dev/null +++ b/lis/metforcing/nldas-2.0/read_orig_nldas20_elevdiff.F90 @@ -0,0 +1,78 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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_orig_nldas20_elevdiff +! \label{read_orig_nldas20_elevdiff} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from read_orig_nldas2_elevdiff.F90) +! +! !INTERFACE: +subroutine read_orig_nldas20_elevdiff(n) +! !USES: + use LIS_coreMod + use nldas20_forcingMod, only : nldas20_struc + use LIS_logmod +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + use netcdf +#endif + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n +! +! !DESCRIPTION: +! Open and read in original NLDAS elevation difference file. +! +! The arguments are: +! \begin{description} +! \item [n] +! index of the domain or nest. +! \end{description} +! +!EOP + integer :: i, err + logical :: file_exists + integer :: nid,elevId + integer :: c,r + real :: elevdiff(nldas20_struc(n)%ncold,nldas20_struc(n)%nrold) + +#if (defined USE_NETCDF3 || defined USE_NETCDF4) + + inquire(file=LIS_rc%paramfile(n),exist=file_exists) + + if (file_exists) then + write(LIS_logunit,*) & + "[INFO] Reading NLDAS-2 original elevation difference file ..." + + call LIS_verify(nf90_open(path=LIS_rc%paramfile(n), & + mode=NF90_NOWRITE,ncid=nid), & + "nf90_open failed in read_orig_nldas20_elevdiff") + call LIS_verify(nf90_inq_varid(nid,"ELEVDIFF_NLDAS2",elevId), & + "nf90_inq_varid failed in read_orig_nldas20_elevdiff") + call LIS_verify(nf90_get_var(nid,elevId,elevdiff), & + "nf90_get_var failed in read_orig_nldas20_elevdiff") + call LIS_verify(nf90_close(nid)) + + do r = 1,nldas20_struc(n)%nrold + do c = 1,nldas20_struc(n)%ncold + nldas20_struc(n)%orig_ediff(c+(r-1)*nldas20_struc(n)%ncold) = elevdiff(c,r) + enddo + enddo + endif + + write(LIS_logunit,*) "[INFO] Finished reading original NLDAS-2" + write(LIS_logunit,*) "[INFO] elevation difference data." +#endif + +end subroutine read_orig_nldas20_elevdiff + diff --git a/lis/metforcing/nldas-2.0/readcrd_nldas20.F90 b/lis/metforcing/nldas-2.0/readcrd_nldas20.F90 new file mode 100644 index 000000000..2f599f52e --- /dev/null +++ b/lis/metforcing/nldas-2.0/readcrd_nldas20.F90 @@ -0,0 +1,117 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: readcrd_nldas20 +! \label{readcrd_nldas20} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from readcrd_nldas2.F90) +! +! !INTERFACE: +subroutine readcrd_nldas20() +! !USES: + use ESMF + use LIS_coreMod, only : LIS_rc,LIS_config + use LIS_logMod, only : LIS_logunit,LIS_verify,LIS_endrun + use nldas20_forcingMod, only : nldas20_struc + + implicit none +! +! !DESCRIPTION: +! This routine reads the options specific to NLDAS-2 forcing from +! the LIS configuration file. +! +!EOP + integer :: n,rc + + do n = 1,LIS_rc%nnest + nldas20_struc(n)%model_level_data = 0 + nldas20_struc(n)%model_level_press = 0 + nldas20_struc(n)%model_pcp_data = 0 + nldas20_struc(n)%model_dswrf_data = 0 + enddo + + call ESMF_ConfigFindLabel(LIS_config, & + "NLDAS-2.0 FORA forcing directory:",rc=rc) + call LIS_verify(rc, & + "NLDAS-2.0 FORA forcing directory: not defined") + do n = 1,LIS_rc%nnest + call ESMF_ConfigGetAttribute(LIS_config, & + nldas20_struc(n)%nldas20foradir,rc=rc) + enddo + + call ESMF_ConfigFindLabel(LIS_config, & + "NLDAS-2.0 use FORB model level data:",rc=rc) + do n = 1,LIS_rc%nnest + call ESMF_ConfigGetAttribute(LIS_config, & + nldas20_struc(n)%model_level_data,default=0,rc=rc) + call LIS_verify(rc, & + "NLDAS-2.0 use FORB model level data: is not defined") + enddo + + call ESMF_ConfigFindLabel(LIS_config, & + "NLDAS-2.0 use FORB model-based SWdown:",rc=rc) + do n = 1,LIS_rc%nnest + call ESMF_ConfigGetAttribute(LIS_config, & + nldas20_struc(n)%model_dswrf_data,default=0,rc=rc) + call LIS_verify(rc, & + "NLDAS-2.0 use FORB model-based SWdown: not defined") + enddo + + call ESMF_ConfigFindLabel(LIS_config, & + "NLDAS-2.0 use FORB model-based precip:",rc=rc) + do n = 1,LIS_rc%nnest + call ESMF_ConfigGetAttribute(LIS_config, & + nldas20_struc(n)%model_pcp_data,default=0,rc=rc) + call LIS_verify(rc, & + "NLDAS-2.0 use FORB model-based precip: not defined") + enddo + + call ESMF_ConfigFindLabel(LIS_config, & + "NLDAS-2.0 use FORB model-based pressure:",rc=rc) + do n = 1,LIS_rc%nnest + call ESMF_ConfigGetAttribute(LIS_config, & + nldas20_struc(n)%model_level_press,default=0,rc=rc) + call LIS_verify(rc, & + "NLDAS-2.0 use FORB model-based pressure: not defined") + enddo + + write(unit=LIS_logunit,fmt=*) & + "[INFO] Using NLDAS-2.0 v020 netCDF-4 forcing" + + do n = 1,LIS_rc%nnest + write(unit=LIS_logunit,fmt=*) & + "[INFO] NLDAS-2.0 FORA forcing directory: ", & + trim(nldas20_struc(n)%nldas20foradir) + nldas20_struc(n)%ncold = 464 + nldas20_struc(n)%nrold = 224 + nldas20_struc(n)%nldas20time1 = 3000.0 + nldas20_struc(n)%nldas20time2 = 0.0 + + if ((nldas20_struc(n)%model_level_data.eq.1).or. & + (nldas20_struc(n)%model_dswrf_data.eq.1).or. & + (nldas20_struc(n)%model_pcp_data.eq.1).or. & + (nldas20_struc(n)%model_level_press.eq.1)) then + call ESMF_ConfigFindLabel(LIS_config, & + "NLDAS-2.0 FORB forcing directory:",rc=rc) + call LIS_verify(rc, & + "NLDAS-2.0 FORB forcing directory: not defined") + call ESMF_ConfigGetAttribute(LIS_config, & + nldas20_struc(n)%nldas20forbdir,rc=rc) + write(unit=LIS_logunit,fmt=*) & + "[INFO] NLDAS-2.0 FORB forcing directory: ", & + trim(nldas20_struc(n)%nldas20forbdir) + endif + enddo + +end subroutine readcrd_nldas20 + diff --git a/lis/metforcing/nldas-2.0/reset_nldas20.F90 b/lis/metforcing/nldas-2.0/reset_nldas20.F90 new file mode 100644 index 000000000..bf3fa4add --- /dev/null +++ b/lis/metforcing/nldas-2.0/reset_nldas20.F90 @@ -0,0 +1,39 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: reset_nldas20 +! \label{reset_nldas20} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from reset_nldas2.F90) +! +! !INTERFACE: +subroutine reset_nldas20() +! !USES: + use LIS_coreMod, only : LIS_rc + use nldas20_forcingMod, only : nldas20_struc + + implicit none +! +! !DESCRIPTION: +! Routine to reset NLDAS-2 forcing related memory allocations. +! +!EOP + integer :: n + integer :: findex + + do n = 1,LIS_rc%nnest + nldas20_struc(n)%nldas20time1 = 3000.0 + nldas20_struc(n)%nldas20time2 = 0.0 + enddo + +end subroutine reset_nldas20 + diff --git a/lis/metforcing/nldas-2.0/timeinterp_nldas20.F90 b/lis/metforcing/nldas-2.0/timeinterp_nldas20.F90 new file mode 100644 index 000000000..f0e04750d --- /dev/null +++ b/lis/metforcing/nldas-2.0/timeinterp_nldas20.F90 @@ -0,0 +1,482 @@ +!-----------------------BEGIN NOTICE -- DO NOT EDIT----------------------- +! NASA Goddard Space Flight Center +! Land Information System Framework (LISF) +! Version 7.5 +! +! Copyright (c) 2024 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: timeinterp_nldas20 +! \label{timeinterp_nldas20} +! +! !REVISION HISTORY: +! 11 Jul 2024: David Mocko, Initial Specification +! (derived from timeinterp_nldas2.F90) +! +! !INTERFACE: +subroutine timeinterp_nldas20(n,findex) +! !USES: + use ESMF + use LIS_FORC_AttributesMod + use LIS_coreMod, only : LIS_rc,LIS_domain + use LIS_constantsMod, only : LIS_CONST_SOLAR + use LIS_metforcingMod, only : LIS_forc,LIS_FORC_Base_State + use LIS_timeMgrMod, only : LIS_tick,LIS_time2date + use LIS_logMod, only : LIS_logunit,LIS_verify,LIS_endrun + use nldas20_forcingMod, only : nldas20_struc + use LIS_forecastMod, only : LIS_get_iteration_index + + implicit none +! !ARGUMENTS: + integer, intent(in) :: n + integer, intent(in) :: findex +! +! !DESCRIPTION: +! Temporally interpolates the forcing data to the current model +! timestep. Downward shortwave radiation is interpolated using +! a zenith-angled based approach. Precipitation fields are not +! temporally interpolated, as it is backward-accumulated in the +! forcing files. All other variables are linearly interpolated +! between the hourly blocks. +! +! The routines invoked are: +! \begin{description} +! \item[LIS\_time2date](\ref{LIS_time2date}) \newline +! converts the time to a date format +! \item[LIS\_tick](\ref{LIS_tick}) \newline +! advances or retracts time by the specified amount +! \item[zterp](\ref{zterp}) \newline +! zenith-angle based interpolation +! \end{description} +! +!EOP + integer :: zdoy + real :: zw1,zw2 + real :: czm,cze,czb + real :: wt1,wt2,swt1,swt2 + real :: gmt1,gmt2,tempbts + integer :: t,index1 + integer :: bdoy,byr,bmo,bda,bhr,bmn + real*8 :: btime,newtime1,newtime2 + real :: tempgmt1,tempgmt2 + integer :: tempbdoy,tempbyr,tempbmo,tempbda,tempbhr,tempbmn + integer :: tempbss + + integer :: status + type(ESMF_Field) :: tmpField,q2Field,uField,vField,swdField,lwdField + type(ESMF_Field) :: psurfField,pcpField,cpcpField,fhgtField,acondField + type(ESMF_Field) :: PETField,CAPEField + real, pointer :: tmp(:),q2(:),uwind(:),vwind(:) + real, pointer :: swd(:),lwd(:),psurf(:),pcp(:),cpcp(:) + real, pointer :: fheight(:),acond(:),pet(:),cape(:) + logical :: forcing_z,forcing_ch,forcing_pet,forcing_cape + integer :: mfactor,m,k,kk + +!________________________________________ + + btime = nldas20_struc(n)%nldas20time1 + call LIS_time2date(btime,bdoy,gmt1,byr,bmo,bda,bhr,bmn) + + tempbdoy = bdoy + tempgmt1 = gmt1 + tempbyr = byr + tempbmo = bmo + tempbda = bda + tempbhr = bhr + if (tempbhr.eq.24) tempbhr = 0 + tempbmn = bmn + tempbss = 0 + tempbts = 0 + call LIS_tick(newtime1,tempbdoy,tempgmt1,tempbyr,tempbmo,tempbda, & + tempbhr,tempbmn,tempbss,tempbts) + + btime = nldas20_struc(n)%nldas20time2 + call LIS_time2date(btime,bdoy,gmt2,byr,bmo,bda,bhr,bmn) + tempbdoy = bdoy + tempgmt2 = gmt2 + tempbyr = byr + tempbmo = bmo + tempbda = bda + tempbhr = bhr + if (tempbhr.eq.24) tempbhr = 0 + tempbmn = bmn + tempbss = 0 + tempbts = 0 + call LIS_tick(newtime2,tempbdoy,tempgmt2,tempbyr,tempbmo,tempbda, & + tempbhr,tempbmn,tempbss,tempbts) + +!=== Interpolate Data in time + wt1 = (nldas20_struc(n)%nldas20time2 - LIS_rc%time) / & + (nldas20_struc(n)%nldas20time2 - nldas20_struc(n)%nldas20time1) + wt2 = 1.0 - wt1 + swt1 = (newtime2 - LIS_rc%time) / (newtime2 - newtime1) + swt2 = 1.0 - swt1 + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Tair%varname(1),tmpField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Tair in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Qair%varname(1),q2Field,rc=status) + call LIS_verify(status, & + "[ERR] Enable Qair in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_SWdown%varname(1),swdField,rc=status) + call LIS_verify(status, & + "[ERR] Enable SWdown in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_LWdown%varname(1),lwdField,rc=status) + call LIS_verify(status, & + "[ERR] Enable LWdown in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Wind_E%varname(1),uField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Wind_E in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Wind_N%varname(1),vField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Wind_N in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Psurf%varname(1),psurfField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Psurf in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Rainf%varname(1),pcpField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Rainf in the forcing variables list") + + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_CRainf%varname(1),cpcpField,rc=status) + call LIS_verify(status, & + "[ERR] Enable CRainf in the forcing variables list") + + forcing_z = .false. + forcing_ch = .false. + if (nldas20_struc(n)%model_level_data.eq.1) then + if (LIS_FORC_Forc_Hgt%selectOpt.eq.1) then + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Forc_Hgt%varname(1),fhgtField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Forc_Hgt in the forcing variables list") + forcing_z = .true. + else + write(LIS_logunit,*) & + "[ERR] Trying to use the NLDAS-2 FORB forcing data" + write(LIS_logunit,*) & + "[ERR] without turning on Forc_Hgt variable in the" + write(LIS_logunit,*) & + "[ERR] Forcing variable list file. Please turn the" + write(LIS_logunit,*) & + "[ERR] Forc_Hgt variable on when using FORB data." + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + endif + + if (LIS_FORC_Ch%selectOpt.eq.1) then + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_Ch%varname(1),acondField,rc=status) + call LIS_verify(status, & + "[ERR] Enable Ch in the forcing variables list") + forcing_ch = .true. + else + write(LIS_logunit,*) & + "[ERR] Trying to use the NLDAS-2 FORB forcing data" + write(LIS_logunit,*) & + "[ERR] without turning on Ch variable in the" + write(LIS_logunit,*) & + "[ERR] Forcing variable list file. Please turn the" + write(LIS_logunit,*) & + "[ERR] Ch variable on when using FORB data." + write(LIS_logunit,*) "[ERR] Program stopping ..." + call LIS_endrun() + endif + endif + + if (LIS_FORC_PET%selectOpt.eq.1) then + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_PET%varname(1),PETField,rc=status) + call LIS_verify(status, & + "[ERR] Enable PET in the forcing variables list") + forcing_pet = .true. + else + forcing_pet = .false. + endif + + if (LIS_FORC_CAPE%selectOpt.eq.1) then + call ESMF_StateGet(LIS_FORC_Base_State(n,findex), & + LIS_FORC_CAPE%varname(1),CAPEField,rc=status) + call LIS_verify(status, & + "[ERR] Enable CAPE in the forcing variables list") + forcing_cape = .true. + else + forcing_cape = .false. + endif + + call ESMF_FieldGet(swdField,localDE=0,farrayPtr=swd,rc=status) + call LIS_verify(status) + +! Loop over number of forcing ensembles: + mfactor = LIS_rc%nensem(n) / nldas20_struc(n)%nIter + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + zdoy = LIS_rc%doy + ! Compute and apply zenith angle weights + call zterp(1,LIS_domain(n)%grid(index1)%lat, & + LIS_domain(n)%grid(index1)%lon, & + gmt1,gmt2,LIS_rc%gmt,zdoy,zw1,zw2, & + czb,cze,czm,LIS_rc) + + kk = LIS_get_iteration_index(n,k,index1,mfactor) + + if ((nldas20_struc(n)%metdata1(kk,3,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,3,index1).ne.LIS_rc%udef)) then + swd(t) = (nldas20_struc(n)%metdata1(kk,3,index1)*zw1) + & + (nldas20_struc(n)%metdata2(kk,3,index1)*zw2) + ! In cases of small cos(zenith) angles, use linear weighting + ! to avoid overly large weights. + if ((swd(t).gt.nldas20_struc(n)%metdata1(kk,3,index1)).and. & + (swd(t).gt.nldas20_struc(n)%metdata2(kk,3,index1)).and. & + ((czb.lt.0.1).or.(cze.lt.0.1))) then + swd(t) = (nldas20_struc(n)%metdata1(kk,3,index1)*swt1) + & + (nldas20_struc(n)%metdata2(kk,3,index1)*swt2) + endif + endif + + if (swd(t).gt.LIS_CONST_SOLAR) then + write(unit=LIS_logunit,fmt=*) & + "[WARN] sw radiation too high!!" + write(unit=LIS_logunit,fmt=*) & + "[WARN] it is: ",swd(t) + write(unit=LIS_logunit,fmt=*) & + "[WARN] data1 =",nldas20_struc(n)%metdata1(kk,3,index1) + write(unit=LIS_logunit,fmt=*) & + "[WARN] data2 =",nldas20_struc(n)%metdata2(kk,3,index1) + write(unit=LIS_logunit,fmt=*) & + "[WARN] zw1 =",zw1,"zw2 =",zw2 + write(unit=LIS_logunit,fmt=*) & + "[WARN] swt1 =",swt1,"swt2 =",swt2 + endif + enddo + enddo ! End for SWdown + +! Do block precipitation interpolation + call ESMF_FieldGet(pcpField,localDE=0,farrayPtr=pcp,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if (nldas20_struc(n)%metdata2(kk,8,index1).ne.LIS_rc%udef) then + pcp(t) = nldas20_struc(n)%metdata2(kk,8,index1) + pcp(t) = pcp(t) / (60.0*60.0) + endif + enddo + enddo + + call ESMF_FieldGet(cpcpField,localDE=0,farrayPtr=cpcp,rc=status) + call LIS_verify(status) + +! Input is actually convective precip fraction; Calc actual CPCP below + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if (nldas20_struc(n)%metdata2(kk,9,index1).ne.LIS_rc%udef) then + cpcp(t) = nldas20_struc(n)%metdata2(kk,9,index1) + if (nldas20_struc(n)%model_pcp_data.gt.0) then + cpcp(t) = cpcp(t) / (60.0*60.0) + else + cpcp(t) = cpcp(t) * pcp(t) + endif + endif + enddo + enddo + +! Linearly interpolate everything else + call ESMF_FieldGet(tmpField,localDE=0,farrayPtr=tmp,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,1,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,1,index1).ne.LIS_rc%udef)) then + tmp(t) = (nldas20_struc(n)%metdata1(kk,1,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,1,index1)*wt2) + endif + enddo + enddo + + call ESMF_FieldGet(q2Field,localDE=0,farrayPtr=q2,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,2,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,2,index1).ne.LIS_rc%udef)) then + q2(t) = (nldas20_struc(n)%metdata1(kk,2,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,2,index1)*wt2) + endif + enddo + enddo + + call ESMF_FieldGet(lwdField,localDE=0,farrayPtr=lwd,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,4,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,4,index1).ne.LIS_rc%udef)) then + lwd(t) = (nldas20_struc(n)%metdata1(kk,4,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,4,index1)*wt2) + endif + enddo + enddo + + call ESMF_FieldGet(uField,localDE=0,farrayPtr=uwind,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,5,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,5,index1).ne.LIS_rc%udef)) then + uwind(t) = (nldas20_struc(n)%metdata1(kk,5,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,5,index1)*wt2) + endif + enddo + enddo + + call ESMF_FieldGet(vField,localDE=0,farrayPtr=vwind,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,6,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,6,index1).ne.LIS_rc%udef)) then + vwind(t) = (nldas20_struc(n)%metdata1(kk,6,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,6,index1)*wt2) + endif + enddo + enddo + + call ESMF_FieldGet(psurfField,localDE=0,farrayPtr=psurf,rc=status) + call LIS_verify(status) + + do k = 1,(LIS_rc%ntiles(n)/mfactor) + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,7,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,7,index1).ne.LIS_rc%udef)) then + psurf(t) = (nldas20_struc(n)%metdata1(kk,7,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,7,index1)*wt2) + endif + enddo + enddo + + if (forcing_PET) then + call ESMF_FieldGet(PETField,localDE=0,farrayPtr=pet,rc=status) + call LIS_verify(status) + + do k = 1,LIS_rc%ntiles(n)/mfactor + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,10,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,10,index1).ne.LIS_rc%udef)) then + pet(t) = (nldas20_struc(n)%metdata1(kk,10,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,10,index1)*wt2) + ! Convert NLDAS-2 PET from kg/m^2 to kg/m^2/sec - dmm + pet(t) = pet(t)/(60.0*60.0) + endif + enddo + enddo + endif + + if (forcing_CAPE) then + call ESMF_FieldGet(CAPEField,localDE=0,farrayPtr=cape,rc=status) + call LIS_verify(status) + + do k = 1,LIS_rc%ntiles(n)/mfactor + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,11,index1).ne.LIS_rc%udef) .and. & + (nldas20_struc(n)%metdata2(kk,11,index1).ne.LIS_rc%udef)) then + cape(t) = (nldas20_struc(n)%metdata1(kk,11,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,11,index1)*wt2) + endif + enddo + enddo + endif + + if (forcing_z) then + call ESMF_FieldGet(fhgtField,localDE=0,farrayPtr=fheight,rc=status) + call LIS_verify(status) + + do k = 1,LIS_rc%ntiles(n)/mfactor + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,12,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,12,index1).ne.LIS_rc%udef)) then + fheight(t) = (nldas20_struc(n)%metdata1(kk,12,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,12,index1)*wt2) + endif + enddo + enddo + endif + + if (forcing_ch) then + call ESMF_FieldGet(acondField,localDE=0,farrayPtr=acond,rc=status) + call LIS_verify(status) + + do k = 1,LIS_rc%ntiles(n)/mfactor + do m = 1,mfactor + t = m + (k-1)*mfactor + index1 = LIS_domain(n)%tile(t)%index + kk = LIS_get_iteration_index(n,k,index1,mfactor) + if ((nldas20_struc(n)%metdata1(kk,13,index1).ne.LIS_rc%udef).and. & + (nldas20_struc(n)%metdata2(kk,13,index1).ne.LIS_rc%udef)) then + acond(t) = (nldas20_struc(n)%metdata1(kk,13,index1)*wt1) + & + (nldas20_struc(n)%metdata2(kk,13,index1)*wt2) + endif + enddo + enddo + endif + +end subroutine timeinterp_nldas20 + diff --git a/lis/plugins/LIS_metforcing_pluginMod.F90 b/lis/plugins/LIS_metforcing_pluginMod.F90 index 9136d42bf..d889437f6 100644 --- a/lis/plugins/LIS_metforcing_pluginMod.F90 +++ b/lis/plugins/LIS_metforcing_pluginMod.F90 @@ -208,6 +208,10 @@ subroutine LIS_metforcing_plugin use nldas2_forcingMod #endif +#if ( defined MF_NLDAS20 ) + use nldas20_forcingMod +#endif + #if ( defined MF_NARR ) use narr_forcingMod #endif @@ -504,6 +508,13 @@ subroutine LIS_metforcing_plugin external reset_nldas2 #endif +#if ( defined MF_NLDAS20 ) + external get_nldas20 + external timeinterp_nldas20 + external finalize_nldas20 + external reset_nldas20 +#endif + #if ( defined MF_NARR ) external get_narr external timeinterp_narr @@ -970,7 +981,7 @@ subroutine LIS_metforcing_plugin #endif #if ( defined MF_NLDAS2 ) -! - NLDAS2 Forcing: +! - NLDAS2 Forcing (GRIB-1 format): call registerinitmetforc(trim(LIS_nldas2Id)//char(0),init_NLDAS2) call registerretrievemetforc(trim(LIS_nldas2Id)//char(0),get_nldas2) call registertimeinterpmetforc(trim(LIS_nldas2Id)//char(0), & @@ -979,6 +990,16 @@ subroutine LIS_metforcing_plugin call registerresetmetforc(trim(LIS_nldas2Id)//char(0),reset_nldas2) #endif +#if ( defined MF_NLDAS20 ) +! - NLDAS-2.0 Forcing (netCDF format): + call registerinitmetforc(trim(LIS_nldas20Id)//char(0),init_NLDAS20) + call registerretrievemetforc(trim(LIS_nldas20Id)//char(0),get_nldas20) + call registertimeinterpmetforc(trim(LIS_nldas20Id)//char(0), & + timeinterp_nldas20) + call registerfinalmetforc(trim(LIS_nldas20Id)//char(0),finalize_nldas20) + call registerresetmetforc(trim(LIS_nldas20Id)//char(0),reset_nldas20) +#endif + #if ( defined MF_NARR ) ! - NARR profile data for CRTM call registerinitmetforc(trim(LIS_narrId)//char(0),init_NARR) diff --git a/lis/plugins/LIS_pluginIndices.F90 b/lis/plugins/LIS_pluginIndices.F90 index c6623509a..81fc78686 100644 --- a/lis/plugins/LIS_pluginIndices.F90 +++ b/lis/plugins/LIS_pluginIndices.F90 @@ -130,8 +130,8 @@ module LIS_pluginIndices character*50, public, parameter :: LIS_gswp2Id = "GSWP2" character*50, public, parameter :: LIS_agrmetId = "AGRMET" character*50, public, parameter :: LIS_princetonId = "PRINCETON" - character*50, public, parameter :: LIS_nldas2Id = "NLDAS2" - + character*50, public, parameter :: LIS_nldas2Id = "NLDAS2 grib" + character*50, public, parameter :: LIS_nldas20Id = "NLDAS2 netcdf" character*50, public, parameter :: LIS_gldasId = "GLDAS" character*50, public, parameter :: LIS_gfsId = "GFS" character*50, public, parameter :: LIS_merra2Id = "MERRA2"