NOAA-OWP / noah-owp-modular

Modularized version of the NOAH-MP land surface model.
Other
8 stars 19 forks source link

Add support for NWM 3.0 baseline variables #91

Closed GreyREvenson closed 9 months ago

GreyREvenson commented 10 months ago

Purpose

This PR adds support for a subset of NWM 3.0 variables that will be simulated by the non-gridded version of Noah-OM.

Additions

The following variables were added as output variables and exposed via the Noah-OM BMI:

The variable ACSNOM was added to the water_type derived data type and an additional line of code was added to WaterModule to calculate (following NWM 3.0) ACSNOM per time step as:

water%ACSNOM = (water%PONDING+water%PONDING1+water%PONDING2+(water%QSNBOT*domain%DT))

The variable SNOWT_AVG was added to the energy_type derived data type and code was added to the end of SnowWaterModule to calculate (following NWM 3.0) SNOWT_AVG per time step as:

   if (sum(water%SNICE(-levels%nsnow+1:0) + water%SNLIQ(-levels%nsnow+1:0)).gt.0.) then
      energy%SNOWT_AVG = SUM(energy%STC(-levels%nsnow+1:0)*(water%SNICE(-levels%nsnow+1:0)+water%SNLIQ(-levels%nsnow+1:0))) / &
                         SUM(water%SNICE(-levels%nsnow+1:0)+water%SNLIQ(-levels%nsnow+1:0))
   else
      energy%SNOWT_AVG = huge(1.)
   end if

Changes

The variables QSEVA, ETRAN, and EVAPOTRANS were already in output_items in /bmi/bmi_noahowp.f90 but did not have the same units as the corresponding variable in NWM 3.0. This PR modified these variables' listings in noahowp_var_units, noahowp_get_float, and noahowp_set_float such that the BMI-user will get/set these variables using NWM 3.0 variable units. This PR does not change the units of these variables as implemented within the rest of the Noah-OM code base.

(m2mm = unit conversion factor = 1000.) (mm2m = unit conversion factor = 0.001)

Testing

/test/noahowp_driver_test.f90 (the unit test) was updated to support the newly added variables and types. The unit tests were then re-executed, which gave this result.

Notes

SNLIQ was the only non-scalar variable added by this PR. This PR adds a new grid identifier (grid id = 1 and type vector) and SNLIQ was associated with this new grid identifier. All other variables are associated with the existing grid identifier (grid id = 0 and type scalar).

GreyREvenson commented 10 months ago

@SnowHydrology, @ajkhattak, @rlmcdaniel: I tagged you all in case you'd like to look this over.

GreyREvenson commented 10 months ago

@SnowHydrology, something that I should have mentioned: I did not implement the newly added variables in the BMI set_value functions; I only implemented the variables in the get_value functions. Let me know if you think we should include them in the set_value functions.

SnowHydrology commented 10 months ago

@GreyEvenson-NOAA, I tested these updates and ran into a couple hiccups.

  1. When I run the module in NextGen, I get really large output values for SNOWT_AVG and GH
image

For SNOWT_AVG, this may be a result of ISNOW = 0 because there is no snowpack temperature to report. The massive value generally means the variable has been initialized with huge() and then never updated with real data.

  1. When I run the model in standalone mode, I get reasonable output for the STC var (from which SNOWT_AVG is derived). When ISNOW = 0 the STC values for snow elements are all 0. Additionally, SNOWT_AVG returns a reasonable value in the unit test when snow is present.
image

However, GH still returns the huge() value.

image
GreyREvenson commented 10 months ago

Appreciate the catches!

I fixed GH by adding a line of code to calculate GH. This line was in the gridded branch but I forgot to add it into this branch by mistake.

I fixed SNOWT_AVG by changing the way that SNOWT_AVG is calculated. We were previously calculating SNOWT_AVG as:

   if (sum(water%SNICE(-levels%nsnow+1:0) + water%SNLIQ(-levels%nsnow+1:0)).gt.0.) then
      energy%SNOWT_AVG = SUM(energy%STC(-levels%nsnow+1:0)*(water%SNICE(-levels%nsnow+1:0)+water%SNLIQ(-levels%nsnow+1:0))) / &
                         SUM(water%SNICE(-levels%nsnow+1:0)+water%SNLIQ(-levels%nsnow+1:0))
   else
      energy%SNOWT_AVG = huge(1.)
   end if

However, SNOWT_AVG is now calculated as:

   if (sum(water%SNICE(-levels%nsnow+1:0) + water%SNLIQ(-levels%nsnow+1:0)).gt.0.) then
      energy%SNOWT_AVG = SUM(energy%STC(-levels%nsnow+1:0)*(water%SNICE(-levels%nsnow+1:0)+water%SNLIQ(-levels%nsnow+1:0))) / &
                         SUM(water%SNICE(-levels%nsnow+1:0)+water%SNLIQ(-levels%nsnow+1:0))
   else
      energy%SNOWT_AVG = realMissing
   end if

where realMissing = -999999.0. Hence, when there is no snow/ice, SNOWT_AVG should be -999999.0 instead of huge(). I did this because the WRF HYDRO NWM repo has SNOWT_AVG being set to undefined_value, which was defined as REAL, PARAMETER :: undefined_value = -1.E36. This change will need to be made in the gridded branch as well but I'll wait for feedback before implementing the change.

GreyREvenson commented 10 months ago

Okay, @SnowHydrology, I believe this is ready for you again. I re-ran the unit test and GH and SNOWT_AVG had valid values in this unit test output. I also ran it via NextGen and verified that GH has valid values and that SNOWT_AVG has a value of -9999999.0 where ISNOW = 0. Here is the NextGen output for cat-27 with the verified SNOWT_AVG values.