From 46da6e1de824f6316561a391abbc6792feb02c73 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 18 Nov 2024 16:01:45 -0500 Subject: [PATCH 01/12] Test "WeatherInputDaymet" now checks for bug #345 - check that relative humidity is calculated from vp, tmax, and tmin -> test is now correctly failing (i.e., indicating the presence of bug #345): ``` [ RUN ] WeatherFixtureTest.WeatherInputDayMet tests/gtests/test_SW_Weather.cc:1033: Failure The difference between SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0] and expectedResult is 72.577207808923504, which exceeds tol6, where SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0] evaluates to 0.73310310918104549, expectedResult evaluates to 73.310310918104548, and tol6 evaluates to 9.9999999999999995e-07. tests/gtests/test_SW_Weather.cc:1042: Failure The difference between SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay] and expectedResult is 73.035512241813024, which exceeds tol6, where SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay] evaluates to 0.73773244688700024, expectedResult evaluates to 73.773244688700018, and tol6 evaluates to 9.9999999999999995e-07. [ FAILED ] WeatherFixtureTest.WeatherInputDayMet (1 ms) ``` --- tests/gtests/test_SW_Weather.cc | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/gtests/test_SW_Weather.cc b/tests/gtests/test_SW_Weather.cc index c61c73966..4394e0b26 100644 --- a/tests/gtests/test_SW_Weather.cc +++ b/tests/gtests/test_SW_Weather.cc @@ -978,35 +978,35 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { // input value from Input/data_weather_daymet/weath.1980 day 1 EXPECT_NEAR(result, expectedResult, tol6); - result = SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0]; - - // Get expected result from Input/data_weather_daymet/weath.1980 day 1 - // Tmax_C = -.37, Tmin_C = -9.2, and vp_kPa = .3 - expectedResult = (-.37 - 9.2) / 2.; - expectedResult = svp(expectedResult, &tempSlope); - expectedResult = .3 / expectedResult; - // Based on actual vapor pressure, test if relative humidity - // was calculated reasonably - EXPECT_NEAR(result, expectedResult, tol6); + // Check relative humidity [0, 100] % --- + // Expect that relative humidity is calculated from vp, tmax, and tmin - // Expect that daily relative humidity is derived from vp_kPa, Tmax_C, and - // Tmin_C (and is not interpolated from mean monthly values) - expectedResult = (-.81 - 9.7) / 2.; - expectedResult = svp(expectedResult, &tempSlope); - expectedResult = .29 / expectedResult; + // Check on day 1 (values from Input/data_weather_daymet/weath.1980) + // Calculate relative humidity from vp (0.3), tmax (-.37), and tmin (-9.2) + expectedResult = 100. * .3 / svp((-.37 - 9.2) / 2., &tempSlope); + EXPECT_NEAR( + SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0], + expectedResult, + tol6 + ); + // Check on day 15 (values from Input/data_weather_daymet/weath.1980) + // Calculate relative humidity from vp (0.29), tmax (-.81), and tmin (-9.7) + expectedResult = 100. * .29 / svp((-.81 - 9.7) / 2., &tempSlope); EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], expectedResult, tol6 ); + // Check that value on day 15 is not interpolated from mean monthly values EXPECT_NE( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], SW_Run.Sky.r_humidity[0] ); + // We have observed radiation and missing cloud cover EXPECT_FALSE(missing(SW_Run.Weather.allHist[yearIndex]->shortWaveRad[0])); EXPECT_TRUE(missing(SW_Run.Weather.allHist[yearIndex]->cloudcov_daily[0])); From 9db82b212825f95e55943f468c69c7d7af4a1f34 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 18 Nov 2024 16:09:22 -0500 Subject: [PATCH 02/12] New test "WeatherInputMACAtype2" checks for bug #345 - check that relative humidity is calculated from specific humidity, tmax, and tmin -> test is correctly failing (i.e., indicating the presence of bug #345): ``` [ RUN ] WeatherFixtureTest.WeatherInputMACAtype2 tests/gtests/test_SW_Weather.cc:1322: Failure The difference between SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0] and 100. * e / es is 20.125763304504432, which exceeds tol6, where SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0] evaluates to 100, 100. * e / es evaluates to 79.874236695495568, and tol6 evaluates to 9.9999999999999995e-07. tests/gtests/test_SW_Weather.cc:1333: Failure The difference between SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay] and 100. * e / es is 21.22859263656683, which exceeds tol6, where SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay] evaluates to 100, 100. * e / es evaluates to 78.77140736343317, and tol6 evaluates to 9.9999999999999995e-07. [ FAILED ] WeatherFixtureTest.WeatherInputMACAtype2 (8 ms) ``` --- .../Input/data_weather_maca-type2/weath.1980 | 368 ++++++++++++++++++ .../Input/data_weather_maca-type2/weath.1981 | 367 +++++++++++++++++ tests/gtests/test_SW_Weather.cc | 172 ++++++++ 3 files changed, 907 insertions(+) create mode 100644 tests/example/Input/data_weather_maca-type2/weath.1980 create mode 100644 tests/example/Input/data_weather_maca-type2/weath.1981 diff --git a/tests/example/Input/data_weather_maca-type2/weath.1980 b/tests/example/Input/data_weather_maca-type2/weath.1980 new file mode 100644 index 000000000..278264058 --- /dev/null +++ b/tests/example/Input/data_weather_maca-type2/weath.1980 @@ -0,0 +1,368 @@ +# weather for site maca example at -105.58 / 39.59 year = 1980 +# DOY, Tmax_C, Tmin_C, PPT_cm, uas_mPERs, vas_mPERs, huss_gPERkg, rsds_WPERm2 +1 -0.01 -11.99 0.00 3.31 -0.85 1.92 107.19 +2 1.27 -10.98 0.00 4.20 0.16 2.11 103.02 +3 1.92 -8.39 0.00 4.43 -0.39 2.50 98.53 +4 -0.30 -12.19 0.00 3.55 -1.13 2.09 104.83 +5 2.59 -9.32 0.05 5.20 0.67 2.29 94.22 +6 2.36 -5.47 0.17 4.33 1.44 3.07 84.92 +7 1.31 -12.42 0.04 2.48 -2.06 2.08 101.75 +8 -1.29 -15.72 0.00 4.68 -1.43 1.51 100.37 +9 -2.03 -12.36 0.00 5.14 -1.80 1.66 100.46 +10 -7.37 -17.86 0.00 3.19 -3.01 1.14 101.56 +11 -2.26 -13.70 0.00 4.01 -2.66 1.59 98.21 +12 1.45 -8.76 0.04 3.86 -2.18 2.28 97.27 +13 -0.45 -11.69 0.00 2.20 1.27 2.00 88.14 +14 -1.86 -12.80 0.08 1.74 -2.15 1.66 99.31 +15 -4.31 -17.34 0.00 2.82 -0.40 1.30 110.65 +16 -3.82 -14.63 0.00 3.86 0.28 1.67 113.33 +17 -4.41 -13.59 0.00 3.84 0.27 1.62 114.64 +18 -4.50 -15.44 0.29 1.91 -1.95 1.36 112.11 +19 -5.80 -16.78 0.00 3.72 -1.73 1.23 114.54 +20 -2.88 -14.31 0.04 3.80 -2.31 1.61 118.84 +21 -3.49 -14.30 0.00 2.86 -3.47 1.51 128.65 +22 3.97 -13.27 0.00 4.47 -1.21 1.63 130.84 +23 5.25 -8.02 0.00 4.77 -0.21 2.16 123.71 +24 5.25 -7.08 0.00 4.30 -0.61 2.40 112.36 +25 2.88 -5.61 0.00 4.81 -0.06 3.45 96.92 +26 6.18 -3.81 0.29 4.29 1.89 3.79 99.92 +27 4.90 -7.22 0.25 3.99 0.66 3.31 111.12 +28 -1.29 -12.68 0.00 3.91 -0.54 1.83 134.32 +29 -2.04 -10.49 0.03 5.41 0.25 1.93 106.29 +30 -3.91 -14.06 0.00 4.54 0.59 1.52 110.88 +31 -2.46 -10.47 0.33 4.68 3.05 1.93 118.97 +32 -2.62 -23.24 0.68 2.88 -2.45 1.23 143.27 +33 -11.72 -29.23 0.00 4.43 -0.86 0.50 151.17 +34 -11.07 -17.25 0.37 2.03 0.38 1.38 115.73 +35 -11.53 -22.21 0.10 2.64 -2.40 0.92 131.28 +36 -13.15 -23.32 0.00 2.47 -4.48 0.78 130.91 +37 -9.55 -19.67 0.00 3.05 -2.56 0.99 135.24 +38 -3.85 -20.32 0.00 2.81 -0.25 1.29 157.53 +39 -6.22 -17.65 0.03 1.51 -0.45 1.23 116.59 +40 -8.05 -16.28 0.00 1.81 0.33 1.25 135.56 +41 -6.60 -17.63 0.00 2.52 -1.15 1.13 140.08 +42 -3.13 -16.05 0.00 3.27 -1.47 1.39 146.14 +43 0.76 -16.86 0.00 3.81 -1.37 1.35 158.94 +44 2.59 -9.04 0.00 5.89 -2.59 2.48 153.32 +45 2.25 -9.35 0.00 5.63 -3.66 2.08 147.54 +46 2.78 -8.99 0.17 7.78 -1.58 2.24 154.36 +47 1.04 -9.79 0.00 8.10 -2.28 1.91 147.47 +48 8.07 -6.99 0.10 10.05 -0.14 2.08 169.41 +49 5.85 -6.87 0.00 9.81 0.50 2.38 164.50 +50 5.74 -4.76 0.00 9.48 1.56 2.27 154.78 +51 4.82 -3.81 0.63 10.06 0.36 2.31 178.37 +52 7.51 -4.73 0.00 7.64 2.38 2.64 168.90 +53 8.68 -1.79 0.00 7.19 5.75 3.07 167.14 +54 8.41 -9.35 0.15 7.49 -1.00 1.84 161.69 +55 -0.12 -12.41 0.25 9.27 -0.28 1.68 165.76 +56 -2.23 -15.39 0.00 4.50 -4.24 1.45 173.74 +57 -3.58 -20.16 0.00 3.83 -1.24 1.23 182.45 +58 4.74 -9.91 0.10 4.71 -0.81 2.21 170.36 +59 9.52 -5.62 0.00 6.42 -1.04 2.84 178.84 +60 8.48 -6.21 0.00 5.58 -0.49 2.79 177.17 +61 7.43 -6.81 0.00 4.75 0.07 2.74 175.51 +62 7.62 -7.71 0.00 2.28 -0.41 2.37 192.41 +63 9.59 -8.10 0.00 2.98 1.50 2.09 203.34 +64 9.92 -5.46 0.00 4.07 1.32 2.41 198.57 +65 10.06 -3.88 0.03 4.62 1.03 2.57 170.20 +66 9.57 -2.67 0.00 3.20 0.54 3.21 192.33 +67 10.14 -5.28 0.00 2.84 4.40 2.33 199.85 +68 9.48 -6.87 0.00 5.18 1.40 1.94 199.73 +69 4.57 -10.47 0.00 3.41 1.40 1.83 212.08 +70 5.22 -9.16 0.06 3.58 -0.11 1.88 198.11 +71 7.39 -8.48 0.03 2.99 4.11 1.74 167.23 +72 6.48 -3.21 0.16 4.07 2.39 2.51 165.11 +73 3.12 -9.67 0.06 -0.63 -0.55 2.07 175.34 +74 3.92 -6.35 0.11 2.49 2.04 2.07 162.68 +75 6.94 -7.89 0.13 3.61 0.33 1.98 203.53 +76 7.35 -5.13 0.06 4.40 1.21 2.38 167.30 +77 5.98 -8.28 0.04 2.38 -0.82 2.44 193.87 +78 1.13 -9.60 1.06 -2.00 -3.47 2.23 174.78 +79 -0.92 -11.74 0.30 2.16 -4.93 1.95 194.58 +80 2.36 -10.42 0.00 4.93 -4.23 1.95 209.74 +81 2.44 -9.07 0.00 4.61 -5.36 2.05 187.04 +82 0.96 -10.67 0.05 3.76 -6.25 2.17 173.95 +83 0.87 -6.18 0.00 2.80 -6.42 2.51 180.27 +84 7.67 -5.31 0.00 2.45 -6.05 2.47 206.31 +85 10.43 -7.58 0.00 3.58 -2.47 2.17 229.14 +86 10.99 -6.15 0.00 3.00 -2.60 2.16 201.77 +87 7.31 -9.39 0.00 1.35 -0.07 2.14 211.64 +88 10.00 -7.26 0.00 2.97 -2.37 2.15 229.08 +89 11.87 -8.34 0.00 3.80 -1.68 1.63 232.16 +90 15.72 -4.49 0.00 4.62 -1.18 1.93 230.35 +91 14.84 0.13 0.00 4.75 -0.58 2.53 217.67 +92 11.92 0.12 0.06 3.88 1.93 2.95 229.55 +93 9.46 -8.27 0.00 3.96 -0.35 1.92 230.83 +94 7.31 -2.76 0.00 -0.75 1.57 1.91 171.16 +95 2.61 -4.19 0.09 -0.68 -3.81 2.90 172.95 +96 5.89 -8.29 0.06 3.28 0.50 2.64 216.06 +97 6.59 -3.89 0.00 3.96 2.03 2.93 178.43 +98 5.25 -6.96 0.00 3.60 0.24 2.69 217.21 +99 3.75 -9.55 0.00 2.08 -2.39 2.28 212.61 +100 2.20 -9.97 0.11 2.41 -0.07 2.09 207.41 +101 4.93 -12.22 0.03 2.73 -2.73 1.53 241.60 +102 12.76 -7.10 0.00 3.94 1.99 1.45 233.00 +103 12.77 2.66 0.00 5.72 4.04 1.66 191.67 +104 6.37 -2.56 0.53 4.41 -1.21 2.80 199.06 +105 5.24 -3.39 0.86 -4.18 2.20 2.74 113.21 +106 -0.03 -8.04 1.19 -3.90 0.86 2.85 143.25 +107 1.18 -12.90 0.24 -0.53 -3.43 2.41 247.94 +108 1.44 -7.06 0.04 2.05 -3.11 2.87 217.92 +109 2.82 -5.99 0.00 2.44 -3.06 2.91 216.47 +110 11.87 -5.29 0.00 4.67 -1.38 3.12 258.27 +111 12.48 -0.71 0.20 6.19 0.00 2.70 248.47 +112 11.66 -1.69 0.00 5.32 0.87 3.00 225.29 +113 10.68 0.69 0.00 6.53 3.01 2.18 248.25 +114 9.99 -4.63 0.00 4.86 1.71 2.55 222.17 +115 3.53 -7.79 0.35 3.84 -3.10 2.58 244.71 +116 5.89 -11.60 0.00 2.28 1.43 1.93 240.95 +117 7.28 0.30 0.00 3.62 1.10 2.77 230.00 +118 8.62 -7.46 0.00 3.12 -2.49 2.35 277.74 +119 12.04 -1.58 0.04 2.41 4.74 2.31 207.54 +120 11.78 0.86 0.00 4.67 1.65 3.64 225.43 +121 10.02 -4.20 0.00 4.07 -0.17 2.83 239.21 +122 10.41 -5.36 0.00 3.63 1.90 2.53 270.55 +123 11.01 -4.05 0.00 3.45 -1.37 2.25 294.79 +124 14.12 -1.29 0.06 -0.93 2.93 2.25 256.98 +125 13.92 1.50 0.00 2.53 -0.29 2.35 206.56 +126 6.96 -2.40 0.90 -1.36 1.75 3.38 202.81 +127 6.18 -1.60 1.09 2.62 -1.59 3.28 231.55 +128 2.42 -7.54 0.13 3.12 -3.19 2.70 248.95 +129 8.31 -4.07 0.00 4.71 -0.39 2.64 238.26 +130 11.59 -1.47 0.00 5.07 0.55 2.97 266.50 +131 11.22 -1.16 0.06 1.26 -0.59 2.86 240.28 +132 8.98 1.81 0.50 -2.48 3.09 3.65 200.77 +133 10.72 -1.81 0.32 3.12 1.66 3.44 292.55 +134 10.98 -1.62 0.11 -2.01 -4.19 3.36 255.87 +135 5.19 -4.44 0.83 -4.71 -0.41 3.03 221.26 +136 -0.24 -7.45 1.10 -5.54 1.90 2.79 183.91 +137 3.49 -4.55 0.42 -0.42 5.80 3.76 200.66 +138 12.26 -1.49 0.00 2.70 3.45 4.28 274.30 +139 12.82 1.88 0.00 3.40 1.84 4.83 236.68 +140 12.93 0.60 0.15 1.93 -1.68 4.63 275.95 +141 11.31 1.21 0.58 -1.47 0.22 4.98 247.80 +142 12.33 0.98 1.32 -1.46 3.27 5.18 241.73 +143 13.80 2.72 0.30 1.72 2.86 4.98 281.69 +144 15.13 1.30 0.48 1.66 2.80 4.22 289.54 +145 14.93 1.86 0.56 1.24 3.54 4.33 289.86 +146 14.90 1.45 0.44 1.67 2.34 4.51 297.24 +147 14.71 2.69 0.26 2.34 0.68 4.89 296.27 +148 15.06 4.52 0.11 1.63 -2.27 5.67 274.73 +149 14.16 3.79 1.27 0.80 -1.12 5.54 274.76 +150 10.48 1.03 0.86 2.85 -1.22 5.87 275.50 +151 17.50 2.38 0.00 3.14 3.13 4.61 292.94 +152 16.20 0.13 0.00 3.84 1.36 3.66 300.32 +153 16.60 1.67 0.00 3.82 2.63 3.37 297.57 +154 16.36 3.64 0.00 5.51 2.00 3.07 301.60 +155 15.14 -0.98 0.00 2.18 -1.84 3.08 302.33 +156 14.60 0.91 0.03 -2.25 -0.15 3.78 280.84 +157 14.77 4.14 0.17 -2.61 3.26 5.53 262.81 +158 20.08 4.20 0.00 2.32 4.23 4.10 297.52 +159 20.17 3.22 0.00 2.29 3.12 3.52 290.48 +160 21.53 5.79 0.00 4.09 4.60 3.22 302.90 +161 21.39 3.60 0.00 3.62 -0.72 3.12 305.32 +162 17.18 2.93 0.21 -2.25 1.78 3.40 288.03 +163 14.15 0.83 2.83 -3.75 -2.53 4.52 240.87 +164 13.75 -0.32 0.00 -0.72 -1.41 4.10 300.72 +165 16.82 -0.26 0.05 2.25 2.74 3.40 305.96 +166 21.31 3.94 0.00 3.21 2.37 3.34 302.26 +167 20.95 4.50 0.00 1.92 1.32 3.95 288.10 +168 20.96 4.27 0.00 2.51 0.97 3.92 298.06 +169 20.70 4.15 0.00 1.84 -2.85 3.63 298.61 +170 20.85 6.52 0.00 0.71 2.23 4.37 279.59 +171 20.04 5.98 0.19 -1.06 1.41 4.88 278.99 +172 20.42 7.57 0.00 0.72 3.27 5.21 289.00 +173 23.63 8.49 0.04 3.33 2.59 3.85 286.01 +174 23.20 7.17 0.00 4.08 2.05 3.44 286.75 +175 23.18 5.62 0.00 4.07 0.74 2.69 299.18 +176 22.75 5.27 0.00 4.01 -0.49 3.30 303.47 +177 21.91 4.24 0.00 2.97 -0.20 3.88 305.43 +178 21.85 7.13 0.00 4.25 4.13 2.95 303.61 +179 21.22 4.95 0.03 3.05 1.84 3.13 298.84 +180 20.55 6.31 0.17 1.28 2.71 4.10 273.64 +181 19.57 5.95 0.11 2.70 2.35 5.01 279.16 +182 20.55 7.11 0.08 3.26 -0.14 5.88 282.12 +183 21.25 6.87 0.00 2.91 -1.31 4.68 288.43 +184 22.50 4.83 0.00 1.61 1.12 4.24 294.69 +185 23.78 4.62 0.04 1.58 0.72 4.33 291.33 +186 25.39 7.57 0.00 2.09 1.74 4.30 292.71 +187 26.02 8.85 0.00 2.66 2.00 3.96 286.91 +188 25.60 8.96 0.12 2.78 0.91 4.30 277.59 +189 25.53 9.42 0.00 2.55 1.71 4.85 299.76 +190 25.30 9.14 0.08 1.96 2.78 4.80 295.12 +191 23.38 8.19 0.10 1.16 3.63 4.24 286.02 +192 22.54 10.08 0.31 3.44 4.82 5.24 281.61 +193 20.00 8.46 1.33 3.56 3.54 6.88 270.26 +194 18.57 8.33 0.72 2.63 0.61 8.85 271.64 +195 19.93 7.37 0.94 2.50 3.12 7.37 281.95 +196 18.03 7.29 1.14 2.38 3.39 7.84 250.04 +197 20.81 7.00 0.81 3.59 0.84 7.39 280.92 +198 21.91 5.81 0.00 5.34 0.79 4.62 291.94 +199 21.29 3.70 0.05 3.44 -1.45 3.83 291.79 +200 20.38 4.42 0.25 0.94 -0.89 4.44 279.13 +201 20.55 6.38 0.72 2.12 -1.01 4.51 266.10 +202 19.97 7.06 0.86 3.46 -0.19 4.75 252.43 +203 18.98 6.53 0.61 3.52 -0.74 5.11 263.29 +204 18.09 6.36 1.18 2.28 -1.22 7.22 263.61 +205 17.18 6.65 1.05 2.24 0.92 7.43 255.76 +206 16.73 5.70 0.66 2.38 3.54 6.81 255.20 +207 15.57 3.17 0.86 1.57 4.15 6.07 172.37 +208 13.60 3.82 1.07 2.21 3.46 7.05 212.20 +209 15.98 4.51 0.72 3.08 1.97 7.21 244.73 +210 17.08 3.17 0.00 3.45 0.51 6.36 251.73 +211 17.58 3.86 0.11 3.46 -0.13 5.78 249.90 +212 17.33 5.14 0.17 3.16 -1.42 6.92 238.46 +213 17.56 5.22 0.55 2.74 -1.66 7.87 262.74 +214 17.68 6.17 1.12 2.08 -0.09 7.85 229.10 +215 16.75 7.55 0.50 2.25 2.34 8.77 228.92 +216 17.67 7.19 0.46 2.66 2.75 8.22 225.18 +217 18.39 5.29 0.07 2.95 1.77 6.94 234.15 +218 19.07 4.74 0.18 3.19 0.75 5.92 255.75 +219 19.52 3.56 0.53 2.10 -1.19 5.69 265.60 +220 19.17 4.26 0.00 -1.47 -0.68 6.73 251.55 +221 18.62 5.77 0.31 0.13 2.83 7.56 266.45 +222 21.72 5.85 0.00 2.24 1.22 6.08 277.95 +223 23.11 4.63 0.00 2.91 -0.51 3.65 279.35 +224 22.79 5.22 0.00 2.56 -0.71 3.10 260.86 +225 21.51 8.10 0.00 -1.48 -0.52 5.16 235.06 +226 21.61 7.35 0.00 0.54 3.81 6.58 252.65 +227 22.36 7.29 0.09 2.93 1.33 6.24 265.12 +228 21.83 5.30 0.00 2.00 -0.12 6.24 256.03 +229 21.71 5.50 0.28 1.51 2.60 6.39 252.98 +230 21.95 7.36 0.07 2.83 2.53 6.27 255.10 +231 20.24 7.53 0.35 2.81 2.20 6.95 245.86 +232 19.96 7.37 0.83 3.54 1.89 7.07 260.17 +233 19.69 7.88 0.59 2.81 -0.32 7.16 238.86 +234 17.96 7.73 0.63 0.94 -2.85 8.85 235.31 +235 14.70 6.62 1.31 -1.99 -0.62 8.59 215.83 +236 18.89 6.36 0.77 1.93 -0.28 7.76 235.41 +237 19.56 3.48 0.04 3.71 0.27 5.24 247.45 +238 18.73 2.62 0.00 3.03 -1.47 5.03 241.69 +239 19.62 2.81 0.00 2.65 0.30 4.55 263.11 +240 20.03 3.22 0.00 3.34 -0.46 3.96 262.55 +241 19.16 7.30 0.00 3.78 4.16 4.21 236.62 +242 19.54 6.98 0.00 3.15 5.15 4.59 229.18 +243 18.10 3.86 0.00 3.78 4.44 4.19 242.80 +244 14.91 -0.23 0.09 2.45 -1.13 4.09 248.03 +245 14.49 0.20 0.21 -1.73 -1.18 4.26 241.79 +246 15.19 0.37 0.85 0.08 0.25 4.51 224.70 +247 15.23 4.20 2.02 0.36 -1.34 5.44 218.28 +248 15.68 2.91 0.00 7.02 -1.11 4.86 236.00 +249 14.37 -0.36 0.00 2.42 -1.64 4.34 189.86 +250 15.99 0.22 0.00 2.11 0.05 4.52 247.63 +251 19.10 3.57 0.00 3.02 3.25 4.17 244.03 +252 18.99 1.84 0.00 3.35 -1.14 3.85 246.89 +253 19.25 2.35 0.00 1.37 2.45 3.94 245.86 +254 19.59 5.91 0.00 2.30 3.38 4.40 227.63 +255 20.05 4.82 0.00 2.84 1.68 4.67 242.81 +256 19.91 5.21 0.06 3.09 2.17 4.56 240.92 +257 19.20 5.99 0.09 4.18 2.88 4.47 226.35 +258 15.44 0.90 0.35 2.32 0.71 5.37 203.15 +259 8.77 -4.05 0.27 1.52 -4.87 3.58 211.29 +260 12.44 -5.14 0.00 2.39 1.88 3.54 240.99 +261 12.74 0.52 0.00 3.24 2.87 3.98 193.59 +262 15.04 1.65 0.00 3.95 -1.60 4.47 231.36 +263 17.08 1.55 0.04 2.96 0.94 4.18 223.20 +264 17.24 3.69 0.00 3.97 0.20 4.48 205.51 +265 17.60 4.83 0.00 3.74 0.88 5.51 190.80 +266 13.82 3.49 0.24 3.82 0.00 5.69 198.75 +267 10.51 -3.05 0.00 0.84 -1.21 4.08 208.02 +268 11.87 -0.08 0.22 0.96 1.68 4.62 204.14 +269 14.00 0.50 0.06 1.69 2.20 4.84 211.54 +270 14.51 3.69 0.33 2.42 2.46 4.99 194.78 +271 16.67 3.76 0.10 3.12 3.10 4.85 208.06 +272 16.57 3.75 0.00 4.32 1.49 4.20 195.78 +273 13.47 -1.93 0.31 2.90 -0.87 4.83 158.74 +274 1.11 -10.34 1.34 -3.02 -4.31 2.95 203.05 +275 1.88 -10.70 0.00 2.17 2.36 2.87 200.86 +276 3.78 -3.82 0.57 2.57 5.59 3.65 131.38 +277 6.19 -1.97 0.26 3.98 5.50 4.49 165.34 +278 5.65 -6.05 0.10 5.47 -0.05 3.60 205.43 +279 5.92 -1.87 1.32 3.31 2.81 4.17 170.81 +280 6.79 -4.77 0.00 5.49 0.05 3.73 209.40 +281 10.24 -2.44 0.00 4.31 2.65 3.81 203.87 +282 10.51 -0.31 0.00 3.58 3.09 4.17 191.61 +283 10.50 0.22 0.00 5.56 1.15 3.92 199.32 +284 8.93 -0.02 0.52 3.10 5.04 4.37 125.12 +285 7.56 -4.97 0.17 9.97 2.09 3.82 187.20 +286 5.08 -6.74 0.04 7.44 0.18 3.03 169.79 +287 5.73 -2.59 1.02 5.01 0.28 3.51 150.71 +288 1.17 -12.14 0.34 2.51 -4.76 2.13 160.58 +289 -4.53 -14.71 0.06 3.24 -3.62 1.47 178.39 +290 0.64 -10.37 0.00 4.35 -0.95 2.25 132.68 +291 0.85 -6.05 0.00 4.39 -2.35 2.88 152.46 +292 2.45 -4.41 0.00 4.68 -1.49 2.95 135.46 +293 3.95 -4.45 0.00 4.31 -1.46 3.18 144.83 +294 5.13 -3.68 0.00 3.26 -0.92 3.23 145.86 +295 8.73 -4.12 0.00 3.99 -0.37 3.19 167.97 +296 7.66 -0.98 0.03 4.52 -2.29 3.44 170.80 +297 9.01 -3.16 0.00 5.70 -2.07 3.29 166.00 +298 9.11 -2.95 0.35 5.25 -0.92 3.36 144.77 +299 7.70 -1.85 0.53 8.05 0.55 3.39 154.72 +300 4.13 -8.76 0.04 1.58 -0.21 2.37 145.58 +301 -0.49 -11.01 0.53 2.15 0.44 2.16 171.71 +302 -2.82 -11.27 0.18 -1.44 4.15 1.78 114.87 +303 -2.54 -15.24 1.26 -4.61 -2.15 1.58 113.98 +304 -8.61 -20.93 0.28 2.51 -2.92 0.97 146.68 +305 -5.15 -17.46 0.00 2.59 -2.11 1.52 154.19 +306 -3.39 -13.66 0.05 2.51 -1.21 1.76 136.35 +307 2.16 -11.03 0.00 4.02 -2.36 2.38 151.39 +308 2.90 -8.20 0.00 3.65 -3.57 2.62 154.84 +309 6.76 -6.73 0.00 3.96 -0.98 2.77 155.93 +310 6.54 -2.24 0.03 4.92 1.10 3.71 125.77 +311 6.17 -3.40 0.15 5.70 -1.70 3.00 133.79 +312 1.96 -5.40 0.00 3.54 -1.30 2.46 130.67 +313 1.67 -5.04 0.05 4.51 -1.95 2.49 129.80 +314 1.59 -6.45 0.00 4.65 -2.34 2.70 122.47 +315 3.51 -3.75 0.00 7.33 -0.87 3.24 126.14 +316 2.20 -11.53 0.00 2.54 -3.05 2.31 130.49 +317 1.13 -13.66 0.00 3.78 0.26 1.50 143.31 +318 4.62 -8.35 0.00 3.92 0.55 1.85 127.42 +319 1.48 -10.90 0.05 2.40 -0.06 1.81 118.19 +320 1.37 -12.88 0.00 4.69 -0.82 1.69 140.39 +321 0.73 -9.23 0.00 7.28 -0.68 1.71 119.02 +322 -1.53 -12.73 0.04 3.47 3.68 1.68 95.61 +323 -2.95 -16.72 0.15 4.56 1.68 1.55 118.75 +324 -9.60 -19.83 0.10 2.89 2.88 0.89 124.83 +325 -6.69 -16.65 2.19 -4.02 -1.18 1.12 83.99 +326 -5.23 -22.59 0.00 3.34 0.11 1.22 136.64 +327 2.12 -14.27 0.00 7.58 -1.34 2.03 123.78 +328 4.32 -5.05 0.00 8.41 0.04 2.70 116.83 +329 4.04 -3.98 0.06 8.92 0.28 2.85 112.90 +330 2.04 -15.27 0.19 4.14 -4.04 1.70 111.99 +331 -6.79 -17.15 0.05 2.34 -2.04 0.93 128.19 +332 5.53 -12.00 0.52 4.97 -0.16 2.65 107.99 +333 4.68 -9.62 0.00 4.77 -6.75 2.37 101.29 +334 2.68 -7.32 0.00 4.59 -4.04 2.79 102.05 +335 6.33 -7.37 0.09 5.37 -2.84 2.84 122.83 +336 5.47 -4.72 0.00 5.53 -1.77 2.85 113.01 +337 4.78 -8.22 0.12 3.75 -2.08 2.72 101.73 +338 0.22 -13.33 0.00 3.02 -0.15 1.84 121.16 +339 -1.37 -10.98 0.00 4.22 -0.69 2.05 100.77 +340 -4.10 -11.58 0.00 2.45 -1.01 1.91 102.91 +341 -0.87 -8.93 0.40 4.79 -1.13 2.26 107.22 +342 -7.80 -18.97 0.00 2.87 -3.26 1.05 119.57 +343 -5.97 -15.37 0.00 3.92 -1.19 1.38 116.91 +344 -4.40 -13.50 0.00 3.87 -0.26 1.65 109.39 +345 -5.17 -12.14 0.05 2.66 1.44 1.74 98.29 +346 -6.15 -14.34 0.05 0.87 -0.77 1.56 84.88 +347 -7.68 -16.15 0.11 -0.02 0.41 1.51 81.65 +348 -6.25 -11.53 0.09 0.97 0.95 1.94 67.86 +349 -1.69 -15.38 0.03 3.39 0.48 1.90 98.56 +350 -0.27 -10.50 0.15 5.64 2.54 1.92 102.62 +351 1.75 -5.46 0.00 4.79 5.35 2.47 103.33 +352 -0.58 -9.89 0.11 3.19 2.87 2.42 95.10 +353 -6.38 -18.08 0.15 3.71 0.36 1.48 104.17 +354 -9.20 -21.47 0.00 4.14 0.44 0.85 103.84 +355 -3.06 -16.68 0.00 6.15 0.23 1.42 104.52 +356 2.13 -11.09 0.18 7.12 2.67 2.12 98.43 +357 3.06 -6.76 0.67 5.84 2.13 2.60 85.75 +358 -3.86 -14.60 0.00 3.38 0.14 1.83 98.67 +359 -11.69 -19.89 0.00 4.90 -0.87 1.03 103.73 +360 -6.92 -18.86 0.07 4.37 1.39 1.28 75.57 +361 2.65 -10.15 0.29 4.14 2.82 2.74 103.53 +362 2.34 -7.83 1.74 3.97 1.60 2.71 103.28 +363 -3.74 -17.65 0.05 3.52 -0.07 1.56 101.19 +364 2.77 -9.81 0.25 4.51 3.99 2.97 93.45 +365 -2.36 -8.74 0.58 4.01 2.44 3.45 69.89 +366 4.79 -2.78 0.30 4.88 1.74 3.26 95.32 diff --git a/tests/example/Input/data_weather_maca-type2/weath.1981 b/tests/example/Input/data_weather_maca-type2/weath.1981 new file mode 100644 index 000000000..2de915b79 --- /dev/null +++ b/tests/example/Input/data_weather_maca-type2/weath.1981 @@ -0,0 +1,367 @@ +# weather for site maca example at -105.58 / 39.59 year = 1981 +# DOY, Tmax_C, Tmin_C, PPT_cm, uas_mPERs, vas_mPERs, huss_gPERkg, rsds_WPERm2 +1 2.90 -12.88 0.17 4.07 -3.74 2.01 104.99 +2 -6.43 -16.16 0.00 2.59 -3.29 1.21 109.03 +3 2.30 -12.13 0.00 4.66 -1.15 1.63 111.17 +4 1.95 -8.65 0.00 4.40 -1.64 2.09 101.51 +5 0.98 -8.11 0.12 4.70 -0.19 2.38 98.79 +6 1.62 -14.39 0.21 1.22 -3.08 1.77 99.31 +7 -4.83 -18.65 0.00 1.76 -0.54 0.99 113.70 +8 -0.32 -13.61 0.00 3.95 0.21 1.89 107.55 +9 -0.42 -10.01 0.00 3.80 -2.00 2.23 92.42 +10 1.53 -9.85 0.00 3.74 -1.49 2.26 103.25 +11 2.58 -6.74 0.06 4.80 0.48 2.42 97.47 +12 0.37 -9.88 0.16 1.96 -0.25 2.43 83.66 +13 -5.22 -14.55 0.00 1.30 -1.94 1.80 82.04 +14 -6.54 -14.96 0.21 -2.16 -1.05 1.76 60.66 +15 -6.70 -11.84 0.76 -4.51 2.89 1.92 60.21 +16 -5.76 -13.43 0.19 1.91 -0.18 1.71 98.41 +17 -4.17 -16.20 0.06 3.54 -0.50 1.52 109.54 +18 -1.60 -10.32 0.07 3.92 0.00 2.40 97.12 +19 -1.56 -10.35 0.00 2.89 0.00 2.38 99.38 +20 -2.43 -12.25 0.00 3.39 -1.07 2.07 101.14 +21 -4.03 -14.94 0.05 2.32 -2.07 1.51 103.79 +22 -4.94 -19.71 0.00 4.52 -1.17 1.28 131.63 +23 -5.94 -16.07 0.00 2.37 0.08 1.39 102.61 +24 -7.95 -20.08 0.21 -0.15 -2.80 1.17 133.23 +25 -5.35 -18.43 0.00 5.11 -1.83 1.35 101.46 +26 -4.70 -11.85 0.06 4.68 -1.41 1.80 104.60 +27 -4.72 -14.74 0.13 4.17 0.12 1.78 98.46 +28 -6.21 -13.98 0.15 -1.49 2.08 1.75 89.02 +29 -5.81 -14.60 0.50 -0.90 2.25 1.72 84.89 +30 -5.27 -13.77 0.00 2.54 0.96 1.89 106.18 +31 -9.36 -20.87 0.18 2.43 -1.27 1.14 134.22 +32 -11.09 -25.22 0.21 3.07 -0.18 0.76 149.11 +33 -10.14 -25.62 0.11 3.42 -0.16 0.91 143.34 +34 -8.91 -19.27 0.00 3.64 -2.19 1.17 131.14 +35 -2.64 -18.55 0.00 4.56 -1.83 1.30 153.88 +36 0.26 -12.87 0.00 5.63 -2.18 1.99 138.21 +37 0.36 -11.11 0.00 4.44 -2.23 2.29 133.10 +38 0.09 -12.22 0.00 3.72 -2.06 2.12 157.37 +39 0.29 -7.92 0.00 4.34 -2.20 2.69 129.11 +40 1.17 -7.93 0.03 3.98 -0.80 2.63 135.44 +41 2.27 -8.60 0.00 3.75 0.59 2.63 134.98 +42 1.40 -6.41 0.23 2.72 3.23 2.93 108.44 +43 -0.17 -9.80 0.25 1.65 0.13 2.56 114.70 +44 -2.27 -17.11 0.44 1.36 -1.94 1.61 156.53 +45 -1.58 -15.77 0.12 2.63 -0.53 1.58 150.79 +46 -0.26 -15.45 0.00 3.21 -1.88 1.87 170.87 +47 2.45 -12.47 0.00 3.50 -1.20 2.11 164.91 +48 4.16 -11.12 0.00 3.11 -1.17 2.54 179.35 +49 5.43 -9.77 0.00 3.38 0.86 2.33 179.58 +50 6.05 -9.40 0.03 2.50 2.09 2.47 183.91 +51 4.49 -8.35 0.00 -1.06 1.53 2.87 151.69 +52 1.99 -7.02 0.18 0.12 3.20 3.03 133.84 +53 1.62 -7.59 0.19 2.24 0.54 2.97 143.58 +54 0.85 -7.87 0.08 1.72 1.49 2.86 133.50 +55 0.55 -6.98 0.49 1.81 -0.18 2.98 129.79 +56 0.48 -10.66 0.00 1.15 1.38 2.47 151.23 +57 0.14 -7.63 0.22 0.37 2.90 2.80 115.48 +58 0.13 -6.99 1.52 -1.84 4.56 2.89 114.19 +59 -0.74 -11.35 0.20 3.98 1.10 2.44 147.77 +60 -1.68 -11.54 0.24 3.39 -2.07 2.31 160.69 +61 -0.83 -10.92 0.25 -2.21 2.17 2.12 145.82 +62 1.69 -8.51 0.71 1.81 2.53 2.58 151.62 +63 2.57 -6.08 0.22 3.67 0.15 3.05 164.52 +64 2.75 -5.82 0.00 2.12 -2.94 2.63 165.42 +65 1.61 -10.95 0.06 1.93 -4.37 2.19 180.53 +66 5.35 -9.59 0.06 3.44 -0.32 2.35 207.11 +67 4.60 -4.23 0.04 4.43 0.63 2.96 162.41 +68 5.83 -3.61 0.00 4.31 -0.54 3.16 175.52 +69 5.61 -3.38 0.00 3.88 1.49 3.25 167.17 +70 4.42 -5.81 1.05 1.24 -2.23 2.94 133.28 +71 0.51 -9.94 0.32 0.36 -4.87 2.33 167.32 +72 1.85 -11.86 0.07 2.04 -2.46 2.17 197.06 +73 3.87 -8.39 0.00 2.75 1.95 2.49 191.94 +74 5.55 -4.03 0.00 4.11 3.35 3.05 168.95 +75 5.46 -4.45 0.09 3.47 2.97 3.10 190.09 +76 4.11 -7.66 0.83 -0.99 -2.34 2.94 177.58 +77 0.57 -9.01 0.31 -3.58 -4.36 2.91 169.33 +78 3.83 -9.44 0.25 -1.27 -2.26 2.48 223.03 +79 7.95 -8.10 0.00 1.31 -0.97 2.51 228.57 +80 7.93 -6.43 0.00 2.43 -0.06 2.63 202.61 +81 3.69 -5.95 1.06 -2.65 0.22 3.45 103.77 +82 0.30 -7.73 1.81 -4.24 -4.21 2.57 101.88 +83 1.25 -11.37 0.15 -0.35 -4.03 2.27 220.58 +84 5.44 -11.04 0.00 3.21 0.54 2.22 220.39 +85 7.20 -5.17 0.03 4.92 -0.97 2.76 225.37 +86 9.69 -3.85 0.00 4.23 0.92 3.40 198.88 +87 10.96 -3.32 0.00 3.85 1.38 3.46 212.84 +88 9.48 -0.96 0.00 4.04 4.38 3.49 193.17 +89 7.34 -8.20 0.00 4.70 -2.35 2.42 206.45 +90 5.32 -9.09 0.00 3.87 1.40 2.33 201.77 +91 2.66 -9.25 0.16 3.38 -2.74 2.23 221.25 +92 2.20 -13.17 0.17 1.59 -2.89 1.62 237.62 +93 10.52 -10.45 0.00 2.94 2.28 1.58 237.39 +94 11.58 -2.86 0.00 4.39 2.34 2.18 219.36 +95 11.10 -5.32 0.00 2.95 2.27 2.73 217.78 +96 10.57 -3.91 0.00 3.04 0.11 2.37 222.01 +97 6.12 -9.47 0.29 1.53 -6.34 1.90 213.73 +98 7.27 -10.87 0.00 -2.01 -5.02 1.44 240.94 +99 11.72 -8.85 0.00 1.68 -0.31 1.51 239.67 +100 13.91 -1.75 0.06 5.03 0.40 1.51 243.65 +101 12.60 -4.39 0.05 1.02 0.24 1.73 204.56 +102 9.56 -1.44 0.25 -1.78 3.13 2.46 200.78 +103 8.53 -2.66 0.94 2.05 1.38 3.97 195.46 +104 7.10 -2.09 0.04 2.83 -2.20 3.76 222.33 +105 7.76 -6.15 0.00 1.39 0.24 3.05 207.58 +106 11.12 0.79 0.00 3.70 2.38 3.67 223.34 +107 10.02 -0.51 0.86 1.75 4.01 3.86 216.43 +108 7.89 -5.14 3.96 -0.99 3.09 3.85 195.66 +109 3.50 -6.19 2.49 -4.42 -4.81 2.73 155.51 +110 -1.40 -10.51 1.25 -1.25 -4.40 2.09 179.36 +111 -3.85 -12.27 0.87 -1.43 0.06 2.38 180.48 +112 -2.83 -9.97 1.17 -4.24 0.64 2.66 150.89 +113 -1.22 -9.57 2.02 -3.43 -1.12 2.70 183.64 +114 0.57 -7.34 0.12 0.28 2.35 2.95 193.39 +115 2.45 -6.83 0.62 2.57 4.29 3.25 186.16 +116 4.00 -1.62 0.49 2.69 1.10 3.68 206.17 +117 3.92 -6.69 0.87 -1.75 -0.94 3.35 180.44 +118 1.90 -5.09 0.44 -1.31 0.91 3.19 201.88 +119 4.44 -7.18 0.05 -0.88 1.92 3.04 234.72 +120 7.56 -5.28 0.20 2.39 0.19 3.04 236.87 +121 7.00 -5.76 0.04 2.94 1.24 2.87 274.05 +122 6.32 -2.16 0.10 2.79 2.06 3.64 200.65 +123 11.50 -2.97 0.00 2.44 2.25 3.67 241.68 +124 12.42 -2.38 0.00 3.40 1.04 3.62 265.14 +125 12.05 0.74 0.05 4.54 1.85 3.64 263.77 +126 9.08 -4.97 0.00 3.12 -4.82 2.96 289.76 +127 6.11 -8.32 0.00 1.67 -3.14 2.37 300.58 +128 12.56 -0.93 0.00 2.00 5.18 2.23 246.11 +129 13.90 -1.31 0.00 2.84 -0.94 2.85 297.98 +130 15.69 -0.98 0.00 0.64 3.70 2.56 288.32 +131 14.98 0.95 0.04 3.83 -0.25 2.54 269.97 +132 11.31 -3.90 0.07 1.83 -4.06 2.71 301.79 +133 15.82 -0.71 0.00 1.91 4.03 2.40 296.48 +134 18.91 4.95 0.07 5.06 6.90 2.68 292.57 +135 16.50 4.35 0.05 4.51 6.00 3.56 251.39 +136 15.00 2.36 0.00 4.11 6.10 3.06 292.02 +137 13.21 -1.02 0.39 2.78 -0.60 3.44 268.24 +138 8.81 -1.92 0.75 1.84 -4.17 3.91 275.06 +139 13.80 -2.11 0.00 2.54 3.52 3.23 295.07 +140 14.32 2.94 0.17 3.45 8.65 3.16 285.40 +141 16.75 1.12 0.05 2.91 5.20 3.42 299.76 +142 16.16 2.22 0.00 2.85 6.12 2.32 283.07 +143 14.32 -0.87 0.06 4.64 2.17 1.96 297.72 +144 12.75 -1.08 0.00 5.87 -1.46 2.82 276.55 +145 9.86 -1.50 0.00 -0.33 0.18 3.33 239.92 +146 8.94 0.53 0.21 -1.75 4.83 3.83 235.95 +147 12.83 -1.17 0.27 2.62 2.21 4.09 290.73 +148 15.49 2.23 0.00 3.04 5.12 3.36 298.27 +149 16.48 -1.91 0.00 4.49 2.54 2.71 301.62 +150 16.33 0.63 0.00 3.84 -0.93 2.64 292.77 +151 14.16 0.97 0.00 1.41 -1.93 2.79 299.03 +152 15.95 -0.21 0.00 -0.09 2.49 3.40 296.49 +153 19.04 0.92 0.00 3.04 1.58 3.14 305.13 +154 19.36 6.92 0.00 5.51 -1.22 2.52 301.75 +155 16.98 0.68 0.00 1.97 -1.58 3.03 288.90 +156 15.08 4.76 0.00 0.51 2.27 3.84 244.20 +157 11.57 1.15 0.92 -1.19 -0.46 4.77 285.28 +158 10.98 -0.66 0.30 -1.07 2.09 4.15 287.79 +159 14.15 -1.14 0.16 2.64 2.66 4.00 293.53 +160 16.31 4.69 1.68 2.92 3.16 4.97 280.07 +161 18.76 3.35 0.00 2.63 0.30 4.76 300.21 +162 18.89 3.98 0.00 1.66 -1.02 4.86 299.63 +163 21.40 4.46 0.00 1.82 2.41 4.32 302.53 +164 22.15 4.33 0.00 4.01 1.61 2.98 303.55 +165 21.91 3.73 0.00 1.80 -1.86 3.18 301.13 +166 23.47 5.79 0.00 -1.98 2.01 3.53 299.99 +167 22.94 5.13 0.00 0.73 1.99 3.63 299.03 +168 22.58 5.04 0.00 1.27 -1.67 3.85 300.31 +169 19.46 5.35 0.22 -1.79 -0.55 4.77 284.14 +170 18.77 4.41 0.07 1.16 4.20 4.41 293.74 +171 21.64 7.21 0.04 2.59 4.98 4.90 291.92 +172 24.43 7.34 0.00 3.48 4.50 3.24 305.69 +173 23.85 4.91 0.00 4.44 1.21 2.54 304.19 +174 23.74 5.83 0.00 3.69 2.22 2.41 305.82 +175 24.63 4.80 0.00 4.43 0.99 2.24 306.28 +176 24.02 6.36 0.00 4.67 1.48 2.27 303.15 +177 23.90 6.64 0.00 3.61 2.60 2.43 301.29 +178 23.64 8.66 0.08 3.18 3.05 3.51 292.22 +179 21.59 8.62 0.00 3.45 2.74 4.56 297.59 +180 20.53 8.26 0.03 3.63 -0.10 4.96 273.07 +181 20.43 7.35 0.14 2.31 -2.88 6.22 257.92 +182 20.06 5.14 0.22 0.90 -1.28 5.60 277.20 +183 19.38 6.13 0.15 1.65 2.03 5.83 271.60 +184 21.12 5.58 0.81 0.56 1.27 5.80 289.26 +185 23.69 5.92 0.08 1.55 0.50 4.54 292.78 +186 24.07 8.08 0.00 1.20 2.48 3.94 280.41 +187 23.64 8.11 0.00 2.86 0.12 4.90 299.63 +188 26.29 7.37 0.00 1.86 0.53 4.80 300.39 +189 25.82 8.41 0.00 3.51 -1.22 3.36 300.32 +190 19.93 4.31 0.08 -1.16 -3.46 4.25 282.24 +191 19.76 5.26 0.15 -2.45 0.04 6.04 263.14 +192 21.61 6.34 0.00 1.33 0.89 5.73 291.95 +193 21.92 6.77 0.28 0.84 -3.65 5.97 257.41 +194 15.45 -0.75 0.46 -1.94 -0.94 5.47 277.17 +195 14.77 2.57 0.17 0.82 4.88 6.24 233.42 +196 21.26 5.14 0.00 2.21 2.13 6.15 285.15 +197 21.25 5.29 0.00 4.46 -0.89 4.30 288.23 +198 21.17 5.44 0.00 4.19 -0.42 3.79 292.19 +199 21.11 4.36 0.00 2.20 -0.31 4.43 266.96 +200 21.46 8.47 0.00 2.29 1.99 4.78 256.22 +201 21.37 9.55 0.00 3.07 0.67 5.11 262.61 +202 21.46 8.54 0.35 2.74 0.36 5.47 258.91 +203 22.04 8.94 0.06 3.10 1.36 5.62 275.95 +204 22.49 9.42 0.41 3.14 1.83 5.17 269.86 +205 22.02 9.64 0.06 4.81 1.77 4.49 286.15 +206 21.52 5.11 0.09 3.51 0.28 3.65 285.67 +207 21.15 4.29 0.06 2.11 2.05 4.28 264.61 +208 21.65 8.78 0.14 3.53 2.12 5.29 272.28 +209 20.93 8.01 0.06 2.67 -0.03 5.45 269.15 +210 20.12 8.58 0.25 2.55 1.32 7.10 264.52 +211 18.91 9.01 0.79 1.88 -0.19 8.93 248.69 +212 19.12 7.51 1.11 -0.18 2.65 8.54 248.94 +213 19.60 8.19 0.67 2.51 1.53 8.11 259.98 +214 18.98 8.37 1.13 2.29 1.56 7.69 247.00 +215 18.97 6.92 0.55 1.93 -0.13 7.42 257.48 +216 19.53 6.72 0.64 2.93 0.89 6.70 263.95 +217 19.53 6.85 1.16 2.19 -2.23 7.99 211.57 +218 12.65 3.05 0.82 -1.72 -3.82 7.37 156.85 +219 12.40 1.67 0.50 1.10 -1.88 6.30 242.89 +220 17.08 2.84 0.00 1.81 1.24 6.70 263.87 +221 20.12 4.31 0.08 2.64 1.19 6.27 277.19 +222 19.62 6.95 0.03 2.08 0.39 7.19 237.05 +223 20.31 7.02 0.08 2.39 0.38 7.09 256.75 +224 20.87 5.54 0.00 2.50 -1.69 5.86 262.90 +225 19.91 5.28 0.34 -1.17 -2.12 6.86 261.04 +226 18.47 8.55 0.29 -2.74 1.19 8.56 215.52 +227 16.88 7.49 0.22 -1.34 3.23 8.58 207.37 +228 19.12 9.70 0.04 1.72 3.62 8.57 234.60 +229 19.72 8.66 0.12 3.73 0.34 7.88 244.62 +230 19.86 6.71 0.09 2.31 -2.47 6.44 229.04 +231 19.47 5.53 0.23 1.79 -0.06 7.03 255.19 +232 18.89 4.15 0.13 1.94 -2.66 6.07 269.99 +233 17.93 3.75 0.09 -2.04 -0.20 6.57 244.95 +234 17.35 5.00 0.73 -2.26 2.44 7.90 220.04 +235 17.68 6.26 0.55 0.21 3.21 7.78 232.77 +236 17.91 6.49 0.20 1.48 1.88 6.51 232.88 +237 17.94 6.76 0.50 -0.11 2.21 7.34 236.46 +238 19.43 7.50 0.04 1.75 1.87 7.76 246.53 +239 19.31 4.13 0.00 1.81 -1.31 5.33 255.34 +240 19.47 6.60 0.00 2.58 0.39 5.36 244.82 +241 20.08 3.27 0.00 0.84 -2.50 4.51 246.38 +242 18.41 3.49 0.00 -1.95 0.55 5.27 222.98 +243 20.34 7.03 0.00 2.39 3.36 4.77 231.88 +244 19.49 5.98 0.00 2.90 2.53 4.86 234.13 +245 18.02 4.98 0.10 2.74 2.72 5.95 208.81 +246 14.69 7.00 0.48 2.35 2.97 7.17 192.12 +247 16.73 6.14 0.33 2.13 3.08 6.50 217.60 +248 17.05 5.24 0.15 2.03 3.20 5.50 222.22 +249 16.96 5.11 1.08 2.54 1.23 6.03 218.46 +250 16.39 6.04 1.23 1.67 1.14 6.55 207.52 +251 16.56 4.97 0.25 2.08 0.20 6.41 218.22 +252 18.46 3.67 0.00 3.92 -2.05 5.08 238.94 +253 18.05 2.80 0.00 4.71 -1.48 4.19 247.08 +254 17.43 3.58 0.00 4.67 -2.08 3.86 232.79 +255 16.39 1.36 0.00 1.40 -2.20 4.24 239.77 +256 16.92 2.60 0.00 -0.03 4.04 3.52 210.76 +257 16.02 4.74 0.00 1.87 3.06 3.67 194.80 +258 14.37 3.23 0.00 1.78 2.42 3.97 203.15 +259 13.95 2.21 0.37 1.93 2.65 4.08 209.29 +260 16.16 2.21 0.33 3.32 2.39 4.46 213.42 +261 14.99 5.17 0.61 3.86 0.39 5.25 186.78 +262 12.38 2.71 0.33 3.48 -2.52 5.53 207.89 +263 14.02 -0.64 0.00 2.50 -1.25 4.58 229.11 +264 14.24 0.48 0.00 2.27 -0.07 4.15 205.30 +265 15.53 2.87 0.00 3.67 2.59 4.19 203.74 +266 15.36 3.50 0.15 2.90 -0.16 5.05 201.96 +267 13.40 -1.12 0.52 -2.38 2.25 5.48 160.39 +268 11.53 -0.50 0.89 -0.17 4.18 4.99 175.43 +269 14.17 3.78 0.00 3.01 2.92 5.85 200.85 +270 13.33 2.15 0.19 3.21 -0.17 5.72 214.45 +271 15.19 1.77 0.00 2.06 1.02 5.40 194.61 +272 15.98 2.12 0.00 3.18 0.37 5.21 204.25 +273 15.70 3.77 0.00 2.58 1.67 5.27 165.68 +274 15.21 3.08 0.00 3.79 0.09 5.86 198.52 +275 15.52 1.82 0.08 4.29 0.29 4.83 180.33 +276 15.10 -0.10 0.00 3.97 0.00 4.03 207.83 +277 15.24 0.73 0.00 5.13 -0.58 2.93 211.79 +278 14.79 -0.64 0.00 2.01 0.53 2.99 181.43 +279 15.80 4.01 0.00 3.60 2.25 3.03 174.00 +280 15.22 2.70 0.00 2.57 0.77 3.65 151.39 +281 11.33 0.24 0.05 1.73 2.86 4.75 201.55 +282 10.86 -3.04 0.35 1.78 -2.90 4.08 170.60 +283 6.11 -6.26 0.06 1.61 -1.97 3.31 202.93 +284 10.37 -6.39 0.00 2.24 1.45 2.99 205.30 +285 13.01 -2.20 0.00 3.77 0.12 2.77 182.27 +286 13.83 -0.23 0.00 5.40 -0.25 2.24 178.74 +287 12.73 -2.99 0.00 4.32 -0.51 2.46 191.94 +288 12.91 -2.98 0.00 3.69 -0.21 2.39 184.29 +289 11.90 -1.05 0.00 0.80 0.31 2.44 145.93 +290 11.44 -1.35 0.00 -1.48 1.23 2.41 178.52 +291 11.70 -1.68 0.22 0.46 2.25 3.27 175.79 +292 13.27 -1.04 0.00 2.40 1.92 4.11 180.63 +293 14.44 0.73 0.00 3.53 0.58 5.37 174.79 +294 13.68 1.18 0.00 3.51 0.66 4.64 188.27 +295 12.34 0.53 0.47 2.21 -0.24 4.10 135.98 +296 9.52 -0.21 0.00 0.12 2.39 3.77 143.78 +297 10.68 -1.06 0.00 3.03 1.60 4.06 175.29 +298 10.46 -0.73 0.15 1.86 0.51 3.94 159.45 +299 9.40 -0.00 0.16 1.40 2.65 4.18 139.50 +300 10.45 0.32 0.12 2.87 2.46 4.44 149.57 +301 10.57 1.74 0.19 3.09 1.90 5.19 118.51 +302 6.74 -2.71 1.40 2.21 -1.06 4.37 110.94 +303 4.21 -4.23 0.30 4.07 -3.10 3.14 123.37 +304 3.79 -6.39 0.08 4.07 -0.25 2.58 129.44 +305 1.95 -11.95 0.00 7.22 -3.96 1.63 163.44 +306 -1.59 -13.65 0.00 3.78 -1.80 1.56 169.01 +307 0.84 -7.32 0.00 4.01 0.22 2.03 129.79 +308 -0.07 -12.01 0.07 3.03 -4.45 1.80 166.57 +309 1.75 -9.86 0.00 4.05 -0.28 1.77 121.89 +310 1.38 -11.99 0.22 3.48 -5.11 1.66 140.13 +311 -5.61 -12.84 0.38 3.43 -5.70 1.59 121.37 +312 -9.23 -15.54 0.16 3.38 -4.82 1.25 122.35 +313 -7.41 -15.77 0.18 1.24 -4.02 1.48 140.09 +314 -4.11 -16.93 0.00 2.18 -1.51 1.57 156.42 +315 -1.82 -14.14 0.00 3.32 -1.63 1.68 146.70 +316 1.18 -13.01 0.00 3.16 -1.35 1.73 142.58 +317 -0.76 -9.96 0.00 1.24 1.91 2.21 104.33 +318 4.64 -6.59 0.00 3.05 2.61 2.68 113.97 +319 3.34 -6.30 0.00 4.18 0.78 2.68 121.88 +320 5.73 -3.12 0.00 3.35 1.67 2.88 114.10 +321 7.67 -2.05 0.11 3.13 2.86 3.37 103.68 +322 6.82 -2.00 0.00 3.64 1.43 3.35 96.01 +323 3.81 -6.05 0.00 4.45 0.22 2.65 126.78 +324 2.54 -5.70 0.00 3.83 1.93 2.69 106.75 +325 5.60 -3.70 0.14 2.37 5.64 2.86 90.76 +326 5.80 -6.89 0.28 4.99 1.74 2.62 121.39 +327 -1.72 -13.58 0.00 4.00 0.14 1.77 133.24 +328 5.23 -9.19 0.00 5.15 0.33 2.16 121.20 +329 5.81 -5.51 0.00 4.54 1.06 2.38 123.39 +330 2.69 -6.41 0.00 4.28 1.19 2.38 110.84 +331 1.64 -10.98 0.00 2.92 0.73 1.90 123.58 +332 1.25 -9.21 0.06 3.37 0.54 2.22 114.55 +333 1.32 -8.59 0.00 4.06 -0.41 2.10 104.34 +334 3.56 -7.44 0.00 6.81 -0.64 1.98 104.60 +335 6.45 -4.58 0.00 7.14 -0.55 2.71 100.34 +336 5.64 -3.70 0.00 8.39 -1.10 3.05 113.98 +337 4.90 -4.86 0.05 4.22 1.68 3.33 90.80 +338 8.48 -3.61 0.22 5.59 2.51 3.31 93.89 +339 7.92 -4.83 0.58 5.26 2.42 3.47 100.28 +340 -2.54 -15.34 0.00 4.25 -0.07 1.31 119.00 +341 -7.07 -12.77 0.00 4.99 1.29 1.43 101.18 +342 -3.74 -13.03 0.18 7.88 1.49 1.57 103.06 +343 -3.68 -13.48 0.00 6.09 -1.76 1.78 89.50 +344 1.34 -9.80 0.32 4.53 0.68 2.39 100.11 +345 0.34 -10.40 0.00 5.40 -2.20 1.76 99.64 +346 2.26 -11.13 0.06 5.02 -0.85 2.25 89.44 +347 2.51 -6.72 0.00 4.48 -1.28 2.91 101.05 +348 4.71 -6.40 0.00 4.35 -0.74 2.75 101.64 +349 4.52 -4.40 0.00 4.23 0.30 3.09 102.40 +350 -0.83 -9.18 0.19 3.14 0.40 2.62 84.88 +351 -4.14 -12.76 0.57 2.79 -1.00 1.71 99.87 +352 -5.36 -13.72 0.39 2.26 3.27 1.56 82.04 +353 -6.03 -19.58 0.11 2.07 -2.03 1.43 97.57 +354 -11.32 -23.77 0.13 2.43 -0.76 0.91 103.97 +355 -1.80 -17.88 0.00 4.28 1.33 1.73 89.21 +356 -3.38 -12.73 0.00 4.69 -1.58 1.76 98.89 +357 -2.25 -12.88 0.41 5.13 -0.16 1.70 88.40 +358 3.73 -4.98 0.35 8.56 0.26 3.17 102.32 +359 1.47 -5.76 0.06 6.64 -0.28 2.46 97.92 +360 4.23 -4.64 0.00 6.60 -1.25 2.90 104.11 +361 4.33 -4.08 0.05 6.04 -0.92 2.68 102.54 +362 3.23 -6.83 0.18 4.67 -0.34 2.67 100.36 +363 -4.03 -13.57 0.34 5.26 -1.34 1.58 102.21 +364 -10.55 -20.44 0.21 3.67 -1.81 1.25 100.21 +365 -12.35 -22.83 0.00 2.39 -1.04 0.81 106.85 diff --git a/tests/gtests/test_SW_Weather.cc b/tests/gtests/test_SW_Weather.cc index 4394e0b26..579e118de 100644 --- a/tests/gtests/test_SW_Weather.cc +++ b/tests/gtests/test_SW_Weather.cc @@ -1117,6 +1117,178 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], SW_Run.Sky.r_humidity[0] ); +} + +TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { + + /* + This section assures that a variable aside from humidity-related ones, + wind speed in this case, is calculated reasonably based on its + components. + + * This section uses the test directory "*_maca-type2" (huss) + */ + + double result; + double expectedResult; + double tmean; + double es; + double e; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; + int doy; + double snowpack[TWO_DAYS] = {0.}; + + /* Test correct priority is being given to input values from MACA */ + + SW_WTH_setup( + &SW_Run.Weather, + SW_Domain.PathInfo.InFiles, + SW_Domain.PathInfo.weather_prefix, + &LogInfo + ); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + // Switch directory to the input folder of the + // second type of MACA (huss) + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_maca-type2/weath" + ); + + // Turn off monthly flags + SW_Run.Weather.use_cloudCoverMonthly = swFALSE; + SW_Run.Weather.use_windSpeedMonthly = swFALSE; + SW_Run.Weather.use_humidityMonthly = swFALSE; + + // Manually edit index/flag arrays in SW_WEATHER to make test as + // realistic as possible + // Note: Indices are based on the directory: + // Input/data_weather_maca-type1/weath.1980 + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; + SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 0; + SW_Run.Weather.dailyInputIndices[WIND_EAST] = 3; + SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 4; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 0; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 5; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; + SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 0; + SW_Run.Weather.dailyInputIndices[SHORT_WR] = 6; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_EAST] = swTRUE; + SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swTRUE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swFALSE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; + SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swFALSE; + SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + + SW_Run.Weather.n_input_forcings = 7; + SW_Run.Weather.desc_rsds = 1; // MACA rsds is flux density over 24 hours + + // Reset daily weather values + clear_hist_weather(SW_Run.Weather.allHist[0]); + + // Using the new inputs folder, read in year = 1980 + read_weather_hist( + year, + SW_Run.Weather.allHist[0], + SW_Run.Weather.name_prefix, + SW_Run.Weather.n_input_forcings, + SW_Run.Weather.dailyInputIndices, + SW_Run.Weather.dailyInputFlags, + &LogInfo + ); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + + // Check that weather contains reasonable values + checkAllWeather(&SW_Run.Weather, &LogInfo); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + + // Check that no value is missing + for (doy = 1; doy < 366; doy++) { + SW_WTH_new_day( + &SW_Run.Weather, &SW_Run.Site, snowpack, doy, year, &LogInfo + ); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + } + + + // Check wind speed + result = SW_Run.Weather.allHist[yearIndex]->windspeed_daily[0]; + + // Get expected result from Input/data_weather_maca-type1/weath.1980 day 1 + // uas_mPERs = 3.31 and vas_mPERs = -.85 + expectedResult = sqrt(squared(3.31) + squared(-.85)); + + // Test if wind speed was calculated within reasonable range to + // the expected result + EXPECT_NEAR(result, expectedResult, tol6); + + // Expect that daily wind speed is derived from uas_mPERs and vas_mPERs + // (and is not interpolated from mean monthly values) + expectedResult = sqrt(squared(2.82) + squared(-.4)); + + EXPECT_NEAR( + SW_Run.Weather.allHist[yearIndex]->windspeed_daily[midJanDay], + expectedResult, + tol6 + ); + + EXPECT_NE( + SW_Run.Weather.allHist[yearIndex]->windspeed_daily[midJanDay], + SW_Run.Sky.windspeed[0] + ); + + + // Check relative humidity [0, 100] % --- + // Expect that relative humidity is calculated from huss + + // Check on day 1 (values from Input/data_weather_gridmet/weath.1980) + // Calculate relative humidity from huss (1.92), tmax (-.01), tmin (-11.99) + tmean = (-.01 - 11.99) / 2.; + es = 6.112 * exp((17.67 * tmean) / (tmean + 243.5)); + e = (1.92 * 1.01325) / (.000378 * 1.92 + .622); + EXPECT_NEAR( + SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0], + 100. * e / es, + tol6 + ); + + // Check on day 15 (values from Input/data_weather_gridmet/weath.1980) + // Calculate relative humidity from huss (1.30), tmax (-4.31), tmin (-17.34) + tmean = (-4.31 - 17.34) / 2.; + es = 6.112 * exp((17.67 * tmean) / (tmean + 243.5)); + e = (1.30 * 1.01325) / (.000378 * 1.30 + .622); + EXPECT_NEAR( + SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], + 100. * e / es, + tol6 + ); + + // Check that value on day 15 is not interpolated from mean monthly values + EXPECT_NE( + SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], + SW_Run.Sky.r_humidity[0] + ); + // We have observed radiation and missing cloud cover EXPECT_FALSE(missing(SW_Run.Weather.allHist[yearIndex]->shortWaveRad[0])); From 4a6a92698cd8371e16ae76e38b3dcb3cbe53feb7 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 18 Nov 2024 16:30:09 -0500 Subject: [PATCH 03/12] Full documentation of units for weather-related variables - each attribute of structs SW_WEATHER_NOW, SW_WEATHER_HIST, and SW_SKY are now documented with units - clarify internal units of specific humidity (mass of water vapor in unit mass of moist air) [g kg-1] - add comment that specify the correct units in read_weather_hist() - checkAllWeather() now warns if relative humidity is within 0-1 --- include/SW_datastructs.h | 84 +++++++++++++++++++++++-------- src/SW_Weather.c | 54 ++++++++++++++------ tests/example/Input/weathsetup.in | 2 +- 3 files changed, 104 insertions(+), 36 deletions(-) diff --git a/include/SW_datastructs.h b/include/SW_datastructs.h index b8d5fc84d..6e7ca026f 100644 --- a/include/SW_datastructs.h +++ b/include/SW_datastructs.h @@ -617,19 +617,58 @@ typedef struct { /* Weather structs */ /* --------------------------------------------------- */ +/** Weather values of the current simulation day */ typedef struct { - /* Weather values of the current simulation day */ - RealD temp_avg, temp_max, temp_min, ppt, rain, cloudCover, windSpeed, - relHumidity, shortWaveRad, actualVaporPressure; + /** Daily near-surface average air temperature [C] */ + double temp_avg; + /** Daily near-surface maximum air temperature [C] */ + double temp_max; + /** Daily near-surface minimum air temperature [C] */ + double temp_min; + /** Daily precipitation amount [cm] */ + double ppt; + /** Daily precipitation amount that falls as rain [cm] */ + double rain; + /** Daily cloud cover [%] */ + double cloudCover; + /** Daily mean near-surface wind speed [m s-1] */ + double windSpeed; + /** Daily mean near-surface relative humidity [%] */ + double relHumidity; + /** Daily downward surface shortwave radiation: + global horizontal irradiation [MJ / m2] or flux density [W / m2], + see #SW_WEATHER.desc_rsds + */ + double shortWaveRad; + /** Daily mean near-surface actual vapor pressure [kPa] */ + double actualVaporPressure; } SW_WEATHER_NOW; +/** Daily weather values for one calendar year */ typedef struct { - /* Daily weather values for one year */ - RealD temp_max[MAX_DAYS], temp_min[MAX_DAYS], temp_avg[MAX_DAYS], - ppt[MAX_DAYS], cloudcov_daily[MAX_DAYS], windspeed_daily[MAX_DAYS], - r_humidity_daily[MAX_DAYS], shortWaveRad[MAX_DAYS], - actualVaporPressure[MAX_DAYS]; - // RealD temp_month_avg[MAX_MONTHS], temp_year_avg; // currently not used + /** Daily maximum near-surface air temperature [C] */ + double temp_max[MAX_DAYS]; + /** Daily minimum near-surface air temperature [C] */ + double temp_min[MAX_DAYS]; + /** Daily average near-surface air temperature [C] */ + double temp_avg[MAX_DAYS]; + /** Daily precipitation amount [cm] */ + double ppt[MAX_DAYS]; + /** Daily cloud cover [%] */ + double cloudcov_daily[MAX_DAYS]; + /** Daily mean near-surface wind speed [m s-1] */ + double windspeed_daily[MAX_DAYS]; + /** Daily mean near-surface relative humidity [%] */ + double r_humidity_daily[MAX_DAYS]; + /** Daily downward surface shortwave radiation: + global horizontal irradiation [MJ / m2] or flux density [W / m2], + see #SW_WEATHER.desc_rsds + */ + double shortWaveRad[MAX_DAYS]; + /** Daily mean near-surface actual vapor pressure [kPa] */ + double actualVaporPressure[MAX_DAYS]; + + // double temp_month_avg[MAX_MONTHS], temp_year_avg; // currently not used } SW_WEATHER_HIST; /* accumulators for output values hold only the */ @@ -925,18 +964,23 @@ typedef struct { /* Sky structs */ /* --------------------------------------------------- */ +/** Across-year mean monthly climate variables */ typedef struct { - RealD cloudcov[MAX_MONTHS], /* monthly cloud cover (frac) */ - windspeed[MAX_MONTHS], /* windspeed (m/s) */ - r_humidity[MAX_MONTHS], /* relative humidity (%) */ - snow_density[MAX_MONTHS], /* snow density (kg/m3) */ - n_rain_per_day[MAX_MONTHS]; /* number of precipitation events per month - (currently used in interception - functions) */ - - RealD snow_density_daily[MAX_DAYS + 1]; /* interpolated daily snow density - (kg/m3) */ - + /** Across-year mean monthly mean cloud cover [%] */ + double cloudcov[MAX_MONTHS]; + /** Across-year mean mean monthly mean near-surface wind speed [m s-1] */ + double windspeed[MAX_MONTHS]; + /** Across-year mean monthly mean near-surface relative humidity [%] */ + double r_humidity[MAX_MONTHS]; + /** Across-year mean monthly mean snow density [kg m-3] */ + double snow_density[MAX_MONTHS]; + /** Across-year mean monthly count of precipitation events */ + /* currently used in interception functions */ + double n_rain_per_day[MAX_MONTHS]; + + /** Across-year mean daily snow density [kg m-3], + interpolated from monthly values */ + double snow_density_daily[MAX_DAYS + 1]; } SW_SKY; /* =================================================== */ diff --git a/src/SW_Weather.c b/src/SW_Weather.c index d912ebb3d..7498b561b 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -1272,21 +1272,32 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { return; // Exit function prematurely due to error } else if (!missing(weathHist[year]->r_humidity_daily[doy]) && - (weathHist[year]->r_humidity_daily[doy] < 0. || + (weathHist[year]->r_humidity_daily[doy] <= 1. || weathHist[year]->r_humidity_daily[doy] > 100.)) { // Otherwise, check if relative humidity is less than 0% or // greater than 100% - // Fail - LogError( - LogInfo, - LOGERROR, - "Invalid daily/calculated relative humidity value did" - " not fall in the range [0, 100] (relative humidity = " - "%f). ", - weathHist[year]->r_humidity_daily[doy] - ); - return; // Exit function prematurely due to error + if ((weathHist[year]->r_humidity_daily[doy] >= 0.) && + (weathHist[year]->r_humidity_daily[doy] <= 1.)) { + LogError( + LogInfo, + LOGWARN, + "Daily/calculated relative humidity value (%f) is " + "within [0, 1] indicating a possibly incorrect unit " + "(expectation: value within [0, 100] %%).", + weathHist[year]->r_humidity_daily[doy] + ); + } else { + LogError( + LogInfo, + LOGERROR, + "Invalid daily/calculated relative humidity value did" + " not fall in the range [0, 100] (relative humidity = " + "%f). ", + weathHist[year]->r_humidity_daily[doy] + ); + return; // Exit function prematurely due to error + } } else if (!missing(weathHist[year]->cloudcov_daily[doy]) && (weathHist[year]->cloudcov_daily[doy] < 0. || @@ -2256,11 +2267,14 @@ void _read_weather_hist( /* --- Make the assignments ---- */ doy--; // base1 -> base0 + // Temperature [C] yearWeather->temp_max[doy] = weathInput[dailyInputIndices[TEMP_MAX]]; yearWeather->temp_min[doy] = weathInput[dailyInputIndices[TEMP_MIN]]; + + // Precipitation [cm] yearWeather->ppt[doy] = weathInput[dailyInputIndices[PPT]]; - // Calculate average air temperature if min/max not missing + // Calculate average air temperature [C] if min/max not missing if (!missing(weathInput[dailyInputIndices[TEMP_MAX]]) && !missing(weathInput[dailyInputIndices[TEMP_MIN]])) { @@ -2271,11 +2285,13 @@ void _read_weather_hist( } if (dailyInputFlags[CLOUD_COV]) { + // Cloud cover [0-100 %] yearWeather->cloudcov_daily[doy] = weathInput[dailyInputIndices[CLOUD_COV]]; } if (dailyInputFlags[WIND_SPEED]) { + // Wind speed [m s-1] yearWeather->windspeed_daily[doy] = weathInput[dailyInputIndices[WIND_SPEED]]; @@ -2286,6 +2302,7 @@ void _read_weather_hist( if (!missing(weathInput[dailyInputIndices[WIND_EAST]]) && !missing(weathInput[dailyInputIndices[WIND_NORTH]])) { + // Wind speed [m s-1] yearWeather->windspeed_daily[doy] = sqrt( squared(weathInput[dailyInputIndices[WIND_EAST]]) + squared(weathInput[dailyInputIndices[WIND_NORTH]]) @@ -2304,6 +2321,7 @@ void _read_weather_hist( if (!missing(weathInput[dailyInputIndices[REL_HUMID_MAX]]) && !missing(weathInput[dailyInputIndices[REL_HUMID_MIN]])) { + // Relative humidity [0-100 %] yearWeather->r_humidity_daily[doy] = (weathInput[dailyInputIndices[REL_HUMID_MAX]] + weathInput[dailyInputIndices[REL_HUMID_MIN]]) / @@ -2311,6 +2329,7 @@ void _read_weather_hist( } } else if (dailyInputFlags[REL_HUMID]) { + // Relative humidity [0-100 %] yearWeather->r_humidity_daily[doy] = weathInput[dailyInputIndices[REL_HUMID]]; @@ -2321,11 +2340,11 @@ void _read_weather_hist( // are holding the value "SW_MISSING" if (!missing(yearWeather->temp_avg[doy]) && !missing(weathInput[dailyInputIndices[SPEC_HUMID]])) { - - // Specific Humidity (Bolton 1980) + // Relative humidity [0-100 %] from + // specific humidity [g kg-1] and temperature [C] es = (6.112 * exp(17.67 * yearWeather->temp_avg[doy]) / - (yearWeather->temp_avg[doy] + 243.5)); + (yearWeather->temp_avg[doy] + 243.5)); // Bolton 1980 e = (weathInput[dailyInputIndices[SPEC_HUMID]] * 1013.25) / (.378 * weathInput[dailyInputIndices[SPEC_HUMID]] + .622 @@ -2345,12 +2364,14 @@ void _read_weather_hist( // Deal with actual vapor pressure if (dailyInputFlags[ACTUAL_VP]) { + // Actual vapor pressure [kPa] yearWeather->actualVaporPressure[doy] = weathInput[dailyInputIndices[ACTUAL_VP]]; } else if (dailyInputFlags[TEMP_DEWPOINT] && !missing(weathInput[dailyInputIndices[TEMP_DEWPOINT]])) { + // Actual vapor pressure [kPa] from dewpoint temperature [C] yearWeather->actualVaporPressure[doy] = actualVaporPressure3( weathInput[dailyInputIndices[TEMP_DEWPOINT]] ); @@ -2365,6 +2386,7 @@ void _read_weather_hist( !missing(weathInput[dailyInputIndices[REL_HUMID_MAX]]) && !missing(weathInput[dailyInputIndices[REL_HUMID_MIN]])) { + // Actual vapor pressure [kPa] yearWeather->actualVaporPressure[doy] = actualVaporPressure2( weathInput[dailyInputIndices[REL_HUMID_MAX]], @@ -2385,6 +2407,7 @@ void _read_weather_hist( if (!missing(yearWeather->r_humidity_daily[doy]) && !missing(yearWeather->temp_avg[doy])) { + // Actual vapor pressure [kPa] yearWeather->actualVaporPressure[doy] = actualVaporPressure1( yearWeather->r_humidity_daily[doy], @@ -2410,6 +2433,7 @@ void _read_weather_hist( svpVal = svp(yearWeather->temp_avg[doy], &tempSlope); + // Relative humidity [0-100 %] yearWeather->r_humidity_daily[doy] = yearWeather->actualVaporPressure[doy] / svpVal; } diff --git a/tests/example/Input/weathsetup.in b/tests/example/Input/weathsetup.in index 74e611c9d..f7a25010a 100755 --- a/tests/example/Input/weathsetup.in +++ b/tests/example/Input/weathsetup.in @@ -38,7 +38,7 @@ 0 # Relative humidity [%] 0 # Maximum relative humidity [%] 0 # Minimum relative humidity [%] -0 # Specific humidity [%] +0 # Specific humidity [g kg-1] 0 # Dew point temperature [C] 0 # Actual vapor pressure [kPa] 0 # Downward surface shortwave radiation (see `Daily weather input descriptions`) From 4f78480cb6eee61a349bd052d54bfbabe89ac975 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 19 Nov 2024 09:11:24 -0500 Subject: [PATCH 04/12] Correctly calculate relative humidity - fix #435 * read_weather_hist() now uses relativeHumidity1() to calculate relative humidity from vapor pressure -- fixing first part of bug #435 * read_weather_hist() now uses relativeHumidity2() to calculate relative humidity from specific humidity inputs -- fixing second part of bug #435 ** the conversion from specific to relative humidity is not exact, the code snaps estimated values within 100-150% to 100% relative humidity (with a warning) --> the new tests introduced in recent commits (b04a09e05bd7f74487e179b86b0de42310970af9, 6457893f749e9bf775a18521d80cfdc7153e9d07) are now passing - new functions * relativeHumidity1() calculates relative humidity from vapor pressure and temperature by estimating saturated vapor pressure * relativeHumidity2() calculates relative humidity from specific humidity and temperature with a pressure correction from elevation * actualVaporPressure4()calculates vapor pressure from specific humidity with a pressure correction from elevation - other changes * readAllWeather() and read_weather_hist() gain argument "elevation" which is used for the pressure correction when calculating relative humidity from specific humidity inputs * update unit tests to reflect changes --- include/SW_Flow_lib_PET.h | 9 +++-- include/SW_Weather.h | 2 ++ src/SW_Flow_lib_PET.c | 57 ++++++++++++++++++++++++++++++ src/SW_Weather.c | 62 +++++++++++++++++++++++---------- tests/gtests/test_SW_Weather.cc | 33 +++++++++--------- 5 files changed, 125 insertions(+), 38 deletions(-) diff --git a/include/SW_Flow_lib_PET.h b/include/SW_Flow_lib_PET.h index 1280af18c..8283956df 100644 --- a/include/SW_Flow_lib_PET.h +++ b/include/SW_Flow_lib_PET.h @@ -96,15 +96,17 @@ double petfunc( LOG_INFO *LogInfo ); +double atmospheric_pressure(double elev); + +double psychrometric_constant(double pressure); double svp(double T, double *slope_svp_to_t); double svp2(double temp); -double atmospheric_pressure(double elev); - -double psychrometric_constant(double pressure); +double relativeHumidity1(double vp, double meanTemp); +double relativeHumidity2(double huss, double meanTemp, double elevation); double actualVaporPressure1(double hurs, double meanTemp); @@ -114,6 +116,7 @@ double actualVaporPressure2( double actualVaporPressure3(double dewpointTemp); +double actualVaporPressure4(double huss, double elevation); #ifdef __cplusplus } diff --git a/include/SW_Weather.h b/include/SW_Weather.h index 8774d3430..715470474 100644 --- a/include/SW_Weather.h +++ b/include/SW_Weather.h @@ -150,6 +150,7 @@ void _read_weather_hist( unsigned int n_input_forcings, unsigned int *dailyInputIndices, Bool *dailyInputFlags, + double elevation, LOG_INFO *LogInfo ); @@ -168,6 +169,7 @@ void readAllWeather( RealD *cloudcov, RealD *windspeed, RealD *r_humidity, + double elevation, TimeInt cum_monthdays[], TimeInt days_in_month[], LOG_INFO *LogInfo diff --git a/src/SW_Flow_lib_PET.c b/src/SW_Flow_lib_PET.c index a630b2fa8..c61f06f3d 100644 --- a/src/SW_Flow_lib_PET.c +++ b/src/SW_Flow_lib_PET.c @@ -1242,6 +1242,35 @@ double svp2(double temp) { return .6108 * exp((17.27 * temp) / (temp + 237.3)); } +/** +@brief Calculate relative humidity from vapor pressure and temperature + +@param vp Daily mean vapor pressure [kPa] +@param meanTemp Daily mean air temperature [C] + +@return Calculated relative humidity [0-100 %] +*/ +double relativeHumidity1(double vp, double meanTemp) { + double tempSlope; + double svpVal = svp(meanTemp, &tempSlope); + return 100. * vp / svpVal; +} + +/** +@brief Calculate relative humidity from specific humidity and temperature + +@param huss Daily mean specific humidity [g kg-1] +@param meanTemp Daily mean air temperature [C] +@param elevation Site elevation [m above mean sea level] + +@return Calculated relative humidity [0-100 %] +*/ +double relativeHumidity2(double huss, double meanTemp, double elevation) { + double vpVal = actualVaporPressure4(huss, elevation); + + return relativeHumidity1(vpVal, meanTemp); +} + /** @brief Calculate actual vapor pressure based on relative humidity and mean temperature @@ -1294,6 +1323,34 @@ double actualVaporPressure3(double dewpointTemp) { return svp2(dewpointTemp); } +/** +@brief Calculate actual vapor pressure from specific humidity and elevation + +@param huss Daily mean specific humidity [g kg-1] +@param elevation Site elevation [m above mean sea level]. + +@return Calculated actual vapor pressure [kPa] +*/ +double actualVaporPressure4(double huss, double elevation) { + // Rd = specific gas constant for dry air (J kg−1 K−1) + // Rv = specific gas constant for water vapor (J kg−1 K−1) + // e = vapor pressure (Pa) + // p = air pressure (Pa) + + double vpVal; + + /* Rd / Rv = 287.052874 [J kg−1 K−1] / 461.50 [J kg−1 K−1] */ + static const double RdToRv = 0.6220; + double p = atmospheric_pressure(elevation); + + huss *= 1e-3; /* convert [g kg-1] to [kg kg-1] */ + + /* huss = q = Rd / Rv * e / (p - e * (1 - Rd / Rv)) */ + vpVal = huss * p / (RdToRv + huss * (1. - RdToRv)); + + return vpVal; +} + /** @brief Daily potential evapotranspiration diff --git a/src/SW_Weather.c b/src/SW_Weather.c index 7498b561b..0b23ab610 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -643,6 +643,9 @@ series values to be interpolated @param[in] r_humidity Array of size #MAX_MONTHS holding monthly relative humidity values to be interpolated +@param[in] elevation Site elevation above sea level [m]; + utilized only if specific humidity is provided as input for + calculating relative humidity @param[in] cum_monthdays Monthly cumulative number of days for "current" year @param[in] days_in_month Number of days per month for "current" year @param[out] LogInfo Holds information on warnings and errors @@ -662,6 +665,7 @@ void readAllWeather( RealD *cloudcov, RealD *windspeed, RealD *r_humidity, + double elevation, TimeInt cum_monthdays[], TimeInt days_in_month[], LOG_INFO *LogInfo @@ -721,6 +725,7 @@ void readAllWeather( n_input_forcings, dailyInputIndices, dailyInputFlags, + elevation, LogInfo ); @@ -2124,6 +2129,7 @@ void SW_WTH_read( SW_Sky->cloudcov, SW_Sky->windspeed, SW_Sky->r_humidity, + SW_Model->elevation, SW_Model->cum_monthdays, SW_Model->days_in_month, LogInfo @@ -2133,7 +2139,7 @@ void SW_WTH_read( /** @brief Read the historical (observed) weather file for a simulation year. -The naming convection of the weather input files: +The naming convention of the weather input files: `[weather-data path/][weather-file prefix].[year]` Format of a input file (white-space separated values): @@ -2150,6 +2156,9 @@ Format of a input file (white-space separated values): calculated column number of which a certain variable resides @param dailyInputFlags An array of size MAX_INPUT_COLUMNS holding booleans specifying what variable has daily input on disk +@param elevation Site elevation above sea level [m]; + utilized only if specific humidity is provided as input + for calculating relative humidity @param[out] LogInfo Holds information on warnings and errors */ void _read_weather_hist( @@ -2159,6 +2168,7 @@ void _read_weather_hist( unsigned int n_input_forcings, unsigned int *dailyInputIndices, Bool *dailyInputFlags, + double elevation, LOG_INFO *LogInfo ) { /* =================================================== */ @@ -2196,9 +2206,8 @@ void _read_weather_hist( (Bool) (hasMaxMinRelHumid || dailyInputFlags[REL_HUMID] || dailyInputFlags[SPEC_HUMID] || dailyInputFlags[ACTUAL_VP]); - double es, e, relHum, tempSlope, svpVal; - - char fname[MAX_FILENAMESIZE], inbuf[MAX_FILENAMESIZE]; + char fname[MAX_FILENAMESIZE]; + char inbuf[MAX_FILENAMESIZE]; // Create file name: `[weather-file prefix].[year]` snprintf(fname, MAX_FILENAMESIZE, "%s.%4d", weather_prefix, year); @@ -2340,20 +2349,37 @@ void _read_weather_hist( // are holding the value "SW_MISSING" if (!missing(yearWeather->temp_avg[doy]) && !missing(weathInput[dailyInputIndices[SPEC_HUMID]])) { - // Relative humidity [0-100 %] from + + // Relative humidity [0-100 %] calculated from // specific humidity [g kg-1] and temperature [C] - es = - (6.112 * exp(17.67 * yearWeather->temp_avg[doy]) / - (yearWeather->temp_avg[doy] + 243.5)); // Bolton 1980 + yearWeather->r_humidity_daily[doy] = relativeHumidity2( + weathInput[dailyInputIndices[SPEC_HUMID]], + yearWeather->temp_avg[doy], + elevation + ); - e = (weathInput[dailyInputIndices[SPEC_HUMID]] * 1013.25) / - (.378 * weathInput[dailyInputIndices[SPEC_HUMID]] + .622 + // Snap relative humidity in 100-150% to 100% + if (yearWeather->r_humidity_daily[doy] > 100. && + yearWeather->r_humidity_daily[doy] <= 150.) { + LogError( + LogInfo, + LOGWARN, + "Year %d - day %d: relative humidity set to 100%%: " + "based on assumption that " + "a presumed minor mismatch in inputs " + "(specific humidity (%f), " + "temperature (%f) and elevation (%f)) " + "caused the calculated value (%f) to exceed 100%%.", + year, + doy, + weathInput[dailyInputIndices[SPEC_HUMID]], + yearWeather->temp_avg[doy], + elevation, + yearWeather->r_humidity_daily[doy] ); - relHum = e / es; - relHum = fmax(0., relHum); - - yearWeather->r_humidity_daily[doy] = fmin(100., relHum); + yearWeather->r_humidity_daily[doy] = 100.; + } } else { // Set relative humidity to "SW_MISSING" @@ -2431,11 +2457,11 @@ void _read_weather_hist( if (!missing(yearWeather->temp_avg[doy]) && !missing(yearWeather->actualVaporPressure[doy])) { - svpVal = svp(yearWeather->temp_avg[doy], &tempSlope); - // Relative humidity [0-100 %] - yearWeather->r_humidity_daily[doy] = - yearWeather->actualVaporPressure[doy] / svpVal; + yearWeather->r_humidity_daily[doy] = relativeHumidity1( + yearWeather->actualVaporPressure[doy], + yearWeather->temp_avg[doy] + ); } } } diff --git a/tests/gtests/test_SW_Weather.cc b/tests/gtests/test_SW_Weather.cc index 579e118de..629c28b69 100644 --- a/tests/gtests/test_SW_Weather.cc +++ b/tests/gtests/test_SW_Weather.cc @@ -38,6 +38,7 @@ TEST_F(WeatherFixtureTest, WeatherDefaultValues) { SW_Run.Sky.cloudcov, SW_Run.Sky.windspeed, SW_Run.Sky.r_humidity, + SW_Run.Model.elevation, SW_Run.Model.cum_monthdays, SW_Run.Model.days_in_month, &LogInfo @@ -860,6 +861,7 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { SW_Run.Weather.n_input_forcings, SW_Run.Weather.dailyInputIndices, SW_Run.Weather.dailyInputFlags, + SW_Run.Model.elevation, &LogInfo ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error @@ -921,8 +923,11 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { * This section uses the test directory "*_daymet". */ - double result, expectedResult, tempSlope; - int yearIndex = 0, year = 1980, midJanDay = 14; + double result; + double expectedResult; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; /* Test correct priority is being given to input values from DAYMET */ SW_WTH_setup( @@ -964,6 +969,7 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { SW_Run.Weather.n_input_forcings, SW_Run.Weather.dailyInputIndices, SW_Run.Weather.dailyInputFlags, + SW_Run.Model.elevation, &LogInfo ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error @@ -984,19 +990,17 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { // Check on day 1 (values from Input/data_weather_daymet/weath.1980) // Calculate relative humidity from vp (0.3), tmax (-.37), and tmin (-9.2) - expectedResult = 100. * .3 / svp((-.37 - 9.2) / 2., &tempSlope); EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0], - expectedResult, + relativeHumidity1(0.30, (-0.37 - 9.2) / 2.), tol6 ); // Check on day 15 (values from Input/data_weather_daymet/weath.1980) // Calculate relative humidity from vp (0.29), tmax (-.81), and tmin (-9.7) - expectedResult = 100. * .29 / svp((-.81 - 9.7) / 2., &tempSlope); EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], - expectedResult, + relativeHumidity1(0.29, (-0.81 - 9.7) / 2.), tol6 ); @@ -1076,6 +1080,7 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { SW_Run.Weather.n_input_forcings, SW_Run.Weather.dailyInputIndices, SW_Run.Weather.dailyInputFlags, + SW_Run.Model.elevation, &LogInfo ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error @@ -1131,9 +1136,7 @@ TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { double result; double expectedResult; - double tmean; - double es; - double e; + double elevation = SW_Run.Model.elevation; int const yearIndex = 0; int const year = 1980; int const midJanDay = 14; @@ -1212,6 +1215,7 @@ TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { SW_Run.Weather.n_input_forcings, SW_Run.Weather.dailyInputIndices, SW_Run.Weather.dailyInputFlags, + SW_Run.Model.elevation, &LogInfo ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error @@ -1263,23 +1267,17 @@ TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { // Check on day 1 (values from Input/data_weather_gridmet/weath.1980) // Calculate relative humidity from huss (1.92), tmax (-.01), tmin (-11.99) - tmean = (-.01 - 11.99) / 2.; - es = 6.112 * exp((17.67 * tmean) / (tmean + 243.5)); - e = (1.92 * 1.01325) / (.000378 * 1.92 + .622); EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0], - 100. * e / es, + relativeHumidity2(1.92, (-0.01 - 11.99) / 2., elevation), tol6 ); // Check on day 15 (values from Input/data_weather_gridmet/weath.1980) // Calculate relative humidity from huss (1.30), tmax (-4.31), tmin (-17.34) - tmean = (-4.31 - 17.34) / 2.; - es = 6.112 * exp((17.67 * tmean) / (tmean + 243.5)); - e = (1.30 * 1.01325) / (.000378 * 1.30 + .622); EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], - 100. * e / es, + relativeHumidity2(1.30, (-4.31 - 17.34) / 2., elevation), tol6 ); @@ -1403,6 +1401,7 @@ TEST_F(WeatherFixtureTest, WeatherDailyInputWrongColumnNumberDeathTest) { SW_Run.Weather.n_input_forcings, SW_Run.Weather.dailyInputIndices, SW_Run.Weather.dailyInputFlags, + SW_Run.Model.elevation, &LogInfo ); // expect error: don't exit test program via `sw_fail_on_error(&LogInfo)` From af6258966fb2d71e11290f16748601d986fc5363 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 19 Nov 2024 09:33:01 -0500 Subject: [PATCH 05/12] Improve weather-related tests - test now checks for all weather variables: tests "WeatherDefaultValues" and "WeatherSomeMissingValuesDays" - renamed tests for consistency * test "WeatherInputGridMET" was previously "WeatherInputDailyGridMet" * test "WaterBalanceWithGridMET" was previously "WaterBalanceWithGRIDMET" * test "WeatherInputDaymet" was previously "WeatherInputDayMet" * test "WeatherInputMACAtype1" was previously "WeatherInputMACA" * test "WaterBalanceWithMACAtype1" was previously" WaterBalanceWithMACA" - renamed "maca" example input data to "maca-type1" for consistency - tests with weather data types ("WeatherInput*" and "WaterBalanceWith*" with * in {"GridMET", "MACAtype1", "MACAtype2" and "Daymet"}) now * set every value of dailyInputIndices and dailyInputFlags to clarify which inputs are available and which are not available * new checks that no weather value is missing (except for Daymet which does not provide inputs for wind speed) * updated checks for relative humidity - new test "WaterBalanceWithMACAtype2" --- .../weath.1980 | 0 .../weath.1981 | 0 tests/gtests/test_SW_Weather.cc | 229 ++++++++++++++---- tests/gtests/test_WaterBalance.cc | 163 ++++++++++++- 4 files changed, 346 insertions(+), 46 deletions(-) rename tests/example/Input/{data_weather_maca => data_weather_maca-type1}/weath.1980 (100%) rename tests/example/Input/{data_weather_maca => data_weather_maca-type1}/weath.1981 (100%) diff --git a/tests/example/Input/data_weather_maca/weath.1980 b/tests/example/Input/data_weather_maca-type1/weath.1980 similarity index 100% rename from tests/example/Input/data_weather_maca/weath.1980 rename to tests/example/Input/data_weather_maca-type1/weath.1980 diff --git a/tests/example/Input/data_weather_maca/weath.1981 b/tests/example/Input/data_weather_maca-type1/weath.1981 similarity index 100% rename from tests/example/Input/data_weather_maca/weath.1981 rename to tests/example/Input/data_weather_maca-type1/weath.1981 diff --git a/tests/gtests/test_SW_Weather.cc b/tests/gtests/test_SW_Weather.cc index 629c28b69..36ba13736 100644 --- a/tests/gtests/test_SW_Weather.cc +++ b/tests/gtests/test_SW_Weather.cc @@ -51,6 +51,13 @@ TEST_F(WeatherFixtureTest, WeatherDefaultValues) { EXPECT_NEAR(SW_Run.Weather.allHist[0]->temp_avg[0], -8.095000, tol6); EXPECT_NEAR(SW_Run.Weather.allHist[0]->temp_min[0], -15.670000, tol6); EXPECT_NEAR(SW_Run.Weather.allHist[0]->ppt[0], .220000, tol6); + EXPECT_NEAR(SW_Run.Weather.allHist[0]->cloudcov_daily[0], 66.483871, tol6); + EXPECT_NEAR(SW_Run.Weather.allHist[0]->windspeed_daily[0], 1.300000, tol6); + EXPECT_NEAR( + SW_Run.Weather.allHist[0]->r_humidity_daily[0], 61.000000, tol6 + ); + EXPECT_TRUE(missing(SW_Run.Weather.allHist[0]->actualVaporPressure[0])); + EXPECT_TRUE(missing(SW_Run.Weather.allHist[0]->shortWaveRad[0])); } TEST_F(WeatherFixtureTest, WeatherNoMemoryLeakIfDecreasedNumberOfYears) { @@ -106,6 +113,17 @@ TEST_F(WeatherFixtureTest, WeatherSomeMissingValuesDays) { EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->temp_min[2])); EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->ppt[0])); EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->ppt[3])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->cloudcov_daily[0])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->cloudcov_daily[3])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->windspeed_daily[0])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->windspeed_daily[3])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->r_humidity_daily[0])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->r_humidity_daily[3])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->actualVaporPressure[0])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[0]->actualVaporPressure[3])); + + EXPECT_TRUE(missing(SW_Run.Weather.allHist[0]->shortWaveRad[0])); + EXPECT_TRUE(missing(SW_Run.Weather.allHist[0]->shortWaveRad[0])); } TEST_F(WeatherFixtureTest, WeatherSomeMissingValuesYears) { @@ -805,7 +823,7 @@ TEST_F(WeatherFixtureTest, WeatherMonthlyInputPrioritization) { ); } -TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { +TEST_F(WeatherFixtureTest, WeatherInputGridMET) { /* This section tests humidity-related values that can be averaged, @@ -815,8 +833,13 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { * This section uses the test directory "*_gridmet". */ - double result, expectedResult; - int yearIndex = 0, year = 1980, midJanDay = 14; + double result; + double expectedResult; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; + int doy; + double snowpack[TWO_DAYS] = {0.}; /* Test correct priority is being given to input values from DAYMET */ SW_WTH_setup( @@ -839,14 +862,36 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { // realistic as possible // Note: Indices are based on the directory: // Input/data_weather_gridmet/weath.1980 + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 3; + SW_Run.Weather.dailyInputIndices[WIND_EAST] = 0; + SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 4; SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 5; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; + SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 0; SW_Run.Weather.dailyInputIndices[SHORT_WR] = 6; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swTRUE; + SW_Run.Weather.dailyInputFlags[WIND_EAST] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swTRUE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; + SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swFALSE; SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + SW_Run.Weather.n_input_forcings = 7; SW_Run.Weather.desc_rsds = 1; // gridMET rsds is flux density over 24 hours @@ -866,29 +911,48 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - result = SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0]; - // Get expected average from Input/data_weather_gridmet/weath.1980 day 1 - // hursmax_pct and hursmin_pct - expectedResult = (74.17 + 31.42) / 2.; + // Check that weather contains reasonable values + checkAllWeather(&SW_Run.Weather, &LogInfo); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + + // Check that no value is missing + for (doy = 1; doy < 366; doy++) { + SW_WTH_new_day( + &SW_Run.Weather, &SW_Run.Site, snowpack, doy, year, &LogInfo + ); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + } + + + // Check relative humidity [0, 100] % --- + // Expect that relative humidity is calculated from hursmax and hursmin - // Test if the average of relative humidity has been calculated - // instead of being based on huss for the first day of 1980 - EXPECT_NEAR(result, expectedResult, tol3); + // Check on day 1 (values from Input/data_weather_gridmet/weath.1980) + // Calculate relative humidity from hursmax (74.17) and hursmin (31.42) + EXPECT_NEAR( + SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0], + (74.17 + 31.42) / 2., + tol6 + ); - // Expect that daily relative humidity is derived from hursmax_pct and - // hursmin_pct (and is not interpolated from mean monthly values) + // Check on day 15 (values from Input/data_weather_gridmet/weath.1980) + // Calculate relative humidity from hursmax (88.35) and hursmin (34.35) EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], (88.35 + 34.35) / 2., tol6 ); + // Check that value on day 15 is not interpolated from mean monthly values EXPECT_NE( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], SW_Run.Sky.r_humidity[0] ); + + // Check vapor pressure result = SW_Run.Weather.allHist[yearIndex]->actualVaporPressure[0]; // Get expected result from Input/data_weather_gridmet/weath.1980 day 1 @@ -903,14 +967,9 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { // We have observed radiation and missing cloud cover EXPECT_FALSE(missing(SW_Run.Weather.allHist[yearIndex]->shortWaveRad[0])); EXPECT_TRUE(missing(SW_Run.Weather.allHist[yearIndex]->cloudcov_daily[0])); - - - // Make sure calculations and set input values are within reasonable range - checkAllWeather(&SW_Run.Weather, &LogInfo); - sw_fail_on_error(&LogInfo); // exit test program if unexpected error } -TEST_F(WeatherFixtureTest, WeatherInputDayMet) { +TEST_F(WeatherFixtureTest, WeatherInputDaymet) { /* This section covers the assurance that if a daily value is provided @@ -950,10 +1009,36 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { // realistic as possible // Note: Indices are based on the directory: // Input/data_weather_daymet/weath.1980 + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; + SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 0; + SW_Run.Weather.dailyInputIndices[WIND_EAST] = 0; + SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 0; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 3; SW_Run.Weather.dailyInputIndices[SHORT_WR] = 4; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_EAST] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swFALSE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swTRUE; SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + SW_Run.Weather.n_input_forcings = 5; // DayMet rsds is flux density over daylight period SW_Run.Weather.desc_rsds = 2; @@ -974,6 +1059,13 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + // Check that weather contains reasonable values + checkAllWeather(&SW_Run.Weather, &LogInfo); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + + // Check vapor pressure result = SW_Run.Weather.allHist[yearIndex]->actualVaporPressure[0]; // Get expected result from Input/data_weather_daymet/weath.1980 day 1 @@ -1014,25 +1106,25 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { // We have observed radiation and missing cloud cover EXPECT_FALSE(missing(SW_Run.Weather.allHist[yearIndex]->shortWaveRad[0])); EXPECT_TRUE(missing(SW_Run.Weather.allHist[yearIndex]->cloudcov_daily[0])); - - - // Make sure calculations and set input values are within reasonable range - checkAllWeather(&SW_Run.Weather, &LogInfo); - sw_fail_on_error(&LogInfo); // exit test program if unexpected error } -TEST_F(WeatherFixtureTest, WeatherInputMACA) { +TEST_F(WeatherFixtureTest, WeatherInputMACAtype1) { /* This section assures that a variable aside from humidity-related ones, wind speed in this case, is calculated reasonably based on its components. - * This section uses the test directory "*_maca". + * This section uses the test directory "*_maca-type1" (hursmin, hursmax) */ - double result, expectedResult; - int yearIndex = 0, year = 1980, midJanDay = 14; + double result; + double expectedResult; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; + int doy; + double snowpack[TWO_DAYS] = {0.}; /* Test correct priority is being given to input values from MACA */ @@ -1044,8 +1136,14 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - // Switch directory to daymet input folder - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_maca/weath"); + // Switch directory to the input folder of the + // first type of MACA (hursmin, hursmax) + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_maca-type1/weath" + ); // Turn off monthly flags SW_Run.Weather.use_cloudCoverMonthly = swFALSE; @@ -1055,17 +1153,37 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { // Manually edit index/flag arrays in SW_WEATHER to make test as // realistic as possible // Note: Indices are based on the directory: - // Input/data_weather_maca/weath.1980 + // Input/data_weather_maca-type1/weath.1980 + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; + SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 0; SW_Run.Weather.dailyInputIndices[WIND_EAST] = 3; SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 4; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 5; SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 6; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; + SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 0; SW_Run.Weather.dailyInputIndices[SHORT_WR] = 7; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swFALSE; SW_Run.Weather.dailyInputFlags[WIND_EAST] = swTRUE; SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swTRUE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swTRUE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; + SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swFALSE; SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + SW_Run.Weather.n_input_forcings = 8; SW_Run.Weather.desc_rsds = 1; // MACA rsds is flux density over 24 hours @@ -1085,9 +1203,25 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + // Check that weather contains reasonable values + checkAllWeather(&SW_Run.Weather, &LogInfo); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + + // Check that no value is missing + for (doy = 1; doy < 366; doy++) { + SW_WTH_new_day( + &SW_Run.Weather, &SW_Run.Site, snowpack, doy, year, &LogInfo + ); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + } + + + // Check wind speed result = SW_Run.Weather.allHist[yearIndex]->windspeed_daily[0]; - // Get expected result from Input/data_weather_maca/weath.1980 day 1 + // Get expected result from Input/data_weather_maca-type1/weath.1980 day 1 // uas_mPERs = 3.31 and vas_mPERs = -.85 expectedResult = sqrt(squared(3.31) + squared(-.85)); @@ -1110,18 +1244,36 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { SW_Run.Sky.windspeed[0] ); - // Expect that daily relative humidity is derived from hursmax_pct and - // hursmin_pct (and is not interpolated from mean monthly values) + + // Check relative humidity [0, 100] % --- + // Expect that relative humidity is calculated from hursmax and hursmin + + // Check on day 1 (values from Input/data_weather_maca-type1/weath.1980) + // Calculate relative humidity from hursmax (83.82) and hursmin (33.27) + EXPECT_NEAR( + SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[0], + (83.82 + 33.27) / 2., + tol6 + ); + + // Check on day 15 (values from Input/data_weather_maca-type1/weath.1980) + // Calculate relative humidity from hursmax (80.55) and hursmin (32.28) EXPECT_NEAR( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], (80.55 + 32.28) / 2., tol6 ); + // Check that value on day 15 is not interpolated from mean monthly values EXPECT_NE( SW_Run.Weather.allHist[yearIndex]->r_humidity_daily[midJanDay], SW_Run.Sky.r_humidity[0] ); + + + // We have observed radiation and missing cloud cover + EXPECT_FALSE(missing(SW_Run.Weather.allHist[yearIndex]->shortWaveRad[0])); + EXPECT_TRUE(missing(SW_Run.Weather.allHist[yearIndex]->cloudcov_daily[0])); } TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { @@ -1136,7 +1288,7 @@ TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { double result; double expectedResult; - double elevation = SW_Run.Model.elevation; + const double elevation = SW_Run.Model.elevation; int const yearIndex = 0; int const year = 1980; int const midJanDay = 14; @@ -1205,10 +1357,10 @@ TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { SW_Run.Weather.desc_rsds = 1; // MACA rsds is flux density over 24 hours // Reset daily weather values - clear_hist_weather(SW_Run.Weather.allHist[0]); + _clear_hist_weather(SW_Run.Weather.allHist[0]); // Using the new inputs folder, read in year = 1980 - read_weather_hist( + _read_weather_hist( year, SW_Run.Weather.allHist[0], SW_Run.Weather.name_prefix, @@ -1291,11 +1443,6 @@ TEST_F(WeatherFixtureTest, WeatherInputMACAtype2) { // We have observed radiation and missing cloud cover EXPECT_FALSE(missing(SW_Run.Weather.allHist[yearIndex]->shortWaveRad[0])); EXPECT_TRUE(missing(SW_Run.Weather.allHist[yearIndex]->cloudcov_daily[0])); - - - // Make sure calculations and set input values are within reasonable range - checkAllWeather(&SW_Run.Weather, &LogInfo); - sw_fail_on_error(&LogInfo); // exit test program if unexpected error } TEST_F(WeatherFixtureTest, WeatherDailyLOCFInputValues) { diff --git a/tests/gtests/test_WaterBalance.cc b/tests/gtests/test_WaterBalance.cc index 1db149c2e..f49ae0df0 100644 --- a/tests/gtests/test_WaterBalance.cc +++ b/tests/gtests/test_WaterBalance.cc @@ -351,10 +351,36 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithDaymet) { SW_Run.Weather.use_windSpeedMonthly = swTRUE; SW_Run.Weather.use_humidityMonthly = swFALSE; + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; + SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 0; + SW_Run.Weather.dailyInputIndices[WIND_EAST] = 0; + SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 0; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 3; SW_Run.Weather.dailyInputIndices[SHORT_WR] = 4; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_EAST] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swFALSE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swTRUE; SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + SW_Run.Weather.n_input_forcings = 5; // Daymet rsds is flux density over daylight period SW_Run.Weather.desc_rsds = 2; @@ -384,7 +410,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithDaymet) { } } -TEST_F(WaterBalanceFixtureTest, WaterBalanceWithGRIDMET) { +TEST_F(WaterBalanceFixtureTest, WaterBalanceWithGridMET) { int i; // Point to gridMET weather data @@ -399,14 +425,36 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithGRIDMET) { SW_Run.Weather.use_windSpeedMonthly = swFALSE; SW_Run.Weather.use_humidityMonthly = swFALSE; + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 3; + SW_Run.Weather.dailyInputIndices[WIND_EAST] = 0; + SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 4; SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 5; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; + SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 0; SW_Run.Weather.dailyInputIndices[SHORT_WR] = 6; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swTRUE; + SW_Run.Weather.dailyInputFlags[WIND_EAST] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swTRUE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swTRUE; - SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swTRUE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; + SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swFALSE; SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + SW_Run.Weather.n_input_forcings = 7; SW_Run.Weather.desc_rsds = 1; // gridMET rsds is flux density over 24 hours @@ -435,11 +483,17 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithGRIDMET) { } } -TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACA) { +TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACAtype1) { int i; - // Point to MACA weather data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_maca/weath"); + // Switch directory to the input folder of the + // first type of MACA (hursmin, hursmax) + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_maca-type1/weath" + ); // Adjust simulation years: we have 2 years of MACA inputs SW_Run.Model.startyr = 1980; @@ -450,16 +504,36 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACA) { SW_Run.Weather.use_windSpeedMonthly = swFALSE; SW_Run.Weather.use_humidityMonthly = swFALSE; + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; + SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 0; SW_Run.Weather.dailyInputIndices[WIND_EAST] = 3; SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 4; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 5; SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 6; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; + SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 0; SW_Run.Weather.dailyInputIndices[SHORT_WR] = 7; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swFALSE; SW_Run.Weather.dailyInputFlags[WIND_EAST] = swTRUE; SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swTRUE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swTRUE; SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; + SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swFALSE; SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + SW_Run.Weather.n_input_forcings = 8; SW_Run.Weather.desc_rsds = 1; // MACA rsds is flux density over 24 hours @@ -488,6 +562,85 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACA) { } } +TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACAtype2) { + int i; + + // Switch directory to the input folder of the + // second type of MACA (huss) + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_maca-type2/weath" + ); + + // Adjust simulation years: we have 2 years of MACA inputs + SW_Run.Model.startyr = 1980; + SW_Run.Model.endyr = 1981; + + // Describe daily MACA inputs + SW_Run.Weather.use_cloudCoverMonthly = swFALSE; + SW_Run.Weather.use_windSpeedMonthly = swFALSE; + SW_Run.Weather.use_humidityMonthly = swFALSE; + + SW_Run.Weather.dailyInputIndices[TEMP_MAX] = 0; + SW_Run.Weather.dailyInputIndices[TEMP_MIN] = 1; + SW_Run.Weather.dailyInputIndices[PPT] = 2; + SW_Run.Weather.dailyInputIndices[CLOUD_COV] = 0; + SW_Run.Weather.dailyInputIndices[WIND_SPEED] = 0; + SW_Run.Weather.dailyInputIndices[WIND_EAST] = 3; + SW_Run.Weather.dailyInputIndices[WIND_NORTH] = 4; + SW_Run.Weather.dailyInputIndices[REL_HUMID] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MAX] = 0; + SW_Run.Weather.dailyInputIndices[REL_HUMID_MIN] = 0; + SW_Run.Weather.dailyInputIndices[SPEC_HUMID] = 5; + SW_Run.Weather.dailyInputIndices[TEMP_DEWPOINT] = 0; + SW_Run.Weather.dailyInputIndices[ACTUAL_VP] = 0; + SW_Run.Weather.dailyInputIndices[SHORT_WR] = 6; + + SW_Run.Weather.dailyInputFlags[TEMP_MAX] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_MIN] = swTRUE; + SW_Run.Weather.dailyInputFlags[PPT] = swTRUE; + SW_Run.Weather.dailyInputFlags[CLOUD_COV] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_SPEED] = swFALSE; + SW_Run.Weather.dailyInputFlags[WIND_EAST] = swTRUE; + SW_Run.Weather.dailyInputFlags[WIND_NORTH] = swTRUE; + SW_Run.Weather.dailyInputFlags[REL_HUMID] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MAX] = swFALSE; + SW_Run.Weather.dailyInputFlags[REL_HUMID_MIN] = swFALSE; + SW_Run.Weather.dailyInputFlags[SPEC_HUMID] = swTRUE; + SW_Run.Weather.dailyInputFlags[TEMP_DEWPOINT] = swFALSE; + SW_Run.Weather.dailyInputFlags[ACTUAL_VP] = swFALSE; + SW_Run.Weather.dailyInputFlags[SHORT_WR] = swTRUE; + + SW_Run.Weather.n_input_forcings = 7; + SW_Run.Weather.desc_rsds = 1; // MACA rsds is flux density over 24 hours + + // Prepare weather data + SW_WTH_read(&SW_Run.Weather, &SW_Run.Sky, &SW_Run.Model, &LogInfo); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + SW_WTH_finalize_all_weather( + &SW_Run.Markov, + &SW_Run.Weather, + SW_Run.Model.cum_monthdays, + SW_Run.Model.days_in_month, + &LogInfo + ); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + // Run the simulation + SW_CTL_main(&SW_Run, &SW_Domain.OutDom, &LogInfo); + sw_fail_on_error(&LogInfo); // exit test program if unexpected error + + // Collect and output from daily checks + for (i = 0; i < N_WBCHECKS; i++) { + EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) + << "Water balance error in test " << i << ": " + << (char *) SW_Run.SoilWat.wbErrorNames[i]; + } +} + TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSpinup) { int i; From 101c581db81f625ca9fc6031f882a7a3ba6982f2 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 20 Nov 2024 12:01:39 -0500 Subject: [PATCH 06/12] Update NEWS --- NEWS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.md b/NEWS.md index 9f4b29c4f..ebac35cc0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # NEWS +# SOILWAT2 v8.0.1 +* Fix the calculation of relative humidity (#435; @dschlaep). + Previously, relative humidity was incorrectly calculated if based on + vapor pressure or specific humidity. + + # SOILWAT2 v8.0.0 * Simulation output remains the same as the previous version. However, output of establishment/recruitment for two species is now From 277d5082c060d77d9069a72f61e8e5bbf93fb5d1 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Thu, 21 Nov 2024 17:47:12 -0500 Subject: [PATCH 07/12] read_weather_hist() now checks if elevation is valid if used --- src/SW_Weather.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/SW_Weather.c b/src/SW_Weather.c index 0b23ab610..c7ead4db9 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -2206,10 +2206,21 @@ void _read_weather_hist( (Bool) (hasMaxMinRelHumid || dailyInputFlags[REL_HUMID] || dailyInputFlags[SPEC_HUMID] || dailyInputFlags[ACTUAL_VP]); + if (useHumidityDaily && !hasMaxMinRelHumid && !dailyInputFlags[REL_HUMID] && + dailyInputFlags[SPEC_HUMID] && missing(elevation)) { + LogError( + LogInfo, + LOGERROR, + "Elevation is missing but required to calculate relative humidity " + "from specific humidity." + ); + return; // Exit function prematurely due to error + } + + // Create file name: `[weather-file prefix].[year]` char fname[MAX_FILENAMESIZE]; char inbuf[MAX_FILENAMESIZE]; - // Create file name: `[weather-file prefix].[year]` snprintf(fname, MAX_FILENAMESIZE, "%s.%4d", weather_prefix, year); if (NULL == (f = fopen(fname, "r"))) { From 74e7b8ccded36f768aa0e79bfbe628c442bf5804 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Fri, 22 Nov 2024 13:25:19 -0500 Subject: [PATCH 08/12] read_weather_hist() now also snaps relative humidity if calculated from vapor pressure --- src/SW_Weather.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/SW_Weather.c b/src/SW_Weather.c index c7ead4db9..dd674e657 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -2473,6 +2473,27 @@ void _read_weather_hist( yearWeather->actualVaporPressure[doy], yearWeather->temp_avg[doy] ); + + // Snap relative humidity in 100-150% to 100% + if (yearWeather->r_humidity_daily[doy] > 100. && + yearWeather->r_humidity_daily[doy] <= 150.) { + LogError( + LogInfo, + LOGWARN, + "Year %d - day %d: relative humidity set to 100%%: " + "based on assumption that " + "a presumed minor mismatch in inputs " + "(vapor pressure (%f) and temperature (%f)) " + "caused the calculated value (%f) to exceed 100%%.", + year, + doy, + yearWeather->actualVaporPressure[doy], + yearWeather->temp_avg[doy], + yearWeather->r_humidity_daily[doy] + ); + + yearWeather->r_humidity_daily[doy] = 100.; + } } } } From 018dbac42b69cac83e3bc3f8bb71b497afa150cc Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 25 Nov 2024 15:00:52 -0500 Subject: [PATCH 09/12] Fix LOCF in generateMissingWeather() - close #437 "Incorrect count of LOCF in generateMissingWeather()" - the number of days on which LOCF was applied is now correctly counting only the days when there was a missing value that was replaced by a non-missing value - previously, any day with a missing value was counted -- even if it was not replaced by a non-missing value - for instance, inputs without solar radiation or without vapor pressure previously caused that every day was counted towards the maximum permissible number of LOCFs - note: initial values for LOCF changed from 0 to "missing" -- this matters only for days at the beginning of the time period that have missing values before a later day with a first non-missing value --- src/SW_Weather.c | 85 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/src/SW_Weather.c b/src/SW_Weather.c index dd674e657..70105812a 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -96,6 +96,15 @@ #include // for atoi, free #include // for memset, NULL, strcpy + +/* Weather generation methods */ +/** Markov weather generator method, see generateMissingWeather() */ +const static unsigned int wgMKV = 2; + +/** Weather generation method LOCF, see generateMissingWeather() */ +const static unsigned int wgLOCF = 1; + + /* =================================================== */ /* Local Function Definitions */ /* --------------------------------------------------- */ @@ -1037,12 +1046,20 @@ void generateMissingWeather( LOG_INFO *LogInfo ) { - int year; - unsigned int yearIndex, numDaysYear, day, iMissing; - - double yesterdayPPT = 0., yesterdayTempMin = 0., yesterdayTempMax = 0., - yesterdayCloudCov = 0., yesterdayWindSpeed = 0., - yesterdayRelHum = 0., yesterdayShortWR = 0., yesterdayActVP = 0.; + unsigned int year; + unsigned int yearIndex; + unsigned int numDaysYear; + unsigned int day; + unsigned int nFilledLOCF; + + double yesterdayPPT = SW_MISSING; + double yesterdayTempMin = SW_MISSING; + double yesterdayTempMax = SW_MISSING; + double yesterdayCloudCov = SW_MISSING; + double yesterdayWindSpeed = SW_MISSING; + double yesterdayRelHum = SW_MISSING; + double yesterdayShortWR = SW_MISSING; + double yesterdayActVP = SW_MISSING; Bool any_missing; Bool missing_Tmax = swFALSE, missing_Tmin = swFALSE, missing_PPT = swFALSE, @@ -1073,15 +1090,16 @@ void generateMissingWeather( for (yearIndex = 0; yearIndex < n_years; yearIndex++) { year = yearIndex + startYear; numDaysYear = Time_get_lastdoy_y(year); - iMissing = 0; + nFilledLOCF = 0; for (day = 0; day < numDaysYear; day++) { + /* Determine variables with missing values */ + missing_Tmax = (Bool) missing(allHist[yearIndex]->temp_max[day]); missing_Tmin = (Bool) missing(allHist[yearIndex]->temp_min[day]); missing_PPT = (Bool) missing(allHist[yearIndex]->ppt[day]); - if (method != 2) { - // `SW_MKV_today()` currently generates only Tmax, Tmin, and PPT + if (method == wgLOCF) { missing_CloudCov = (Bool) missing(allHist[yearIndex]->cloudcov_daily[day]); missing_WindSpeed = @@ -1102,8 +1120,8 @@ void generateMissingWeather( if (any_missing) { // some of today's values are missing - if (method == 2) { - // Weather generator + if (method == wgMKV) { + // Markov weather generator (Tmax, Tmin, and PPT) allHist[yearIndex]->ppt[day] = yesterdayPPT; SW_MKV_today( SW_Markov, @@ -1118,7 +1136,7 @@ void generateMissingWeather( return; // Exit function prematurely due to error } - } else if (method == 1) { + } else if (method == wgLOCF) { // LOCF (temp, cloud cover, wind speed, relative humidity, // shortwave radiation, and actual vapor pressure) + 0 (PPT) allHist[yearIndex]->temp_max[day] = @@ -1157,11 +1175,23 @@ void generateMissingWeather( missing_PPT ? 0. : allHist[yearIndex]->ppt[day]; - // Throw an error if too many values per calendar year are - // missing - iMissing++; + // Throw an error if too many missing values have + // been replaced with non-missing values by the LOCF method + // per calendar year + if ( + (missing_Tmax && !missing(yesterdayTempMax)) || + (missing_Tmin && !missing(yesterdayTempMin)) || + (missing_PPT && !missing(allHist[yearIndex]->ppt[day])) || + (missing_CloudCov && !missing(yesterdayCloudCov)) || + (missing_WindSpeed && !missing(yesterdayWindSpeed)) || + (missing_RelHum && !missing(yesterdayRelHum)) || + (missing_ShortWR && !missing(yesterdayShortWR)) || + (missing_ActVP && !missing(yesterdayActVP)) + ) { + nFilledLOCF++; + } - if (iMissing > optLOCF_nMax) { + if (nFilledLOCF > optLOCF_nMax) { LogError( LogInfo, LOGERROR, @@ -1184,13 +1214,16 @@ void generateMissingWeather( } yesterdayPPT = allHist[yearIndex]->ppt[day]; - yesterdayTempMax = allHist[yearIndex]->temp_max[day]; - yesterdayTempMin = allHist[yearIndex]->temp_min[day]; - yesterdayCloudCov = allHist[yearIndex]->cloudcov_daily[day]; - yesterdayWindSpeed = allHist[yearIndex]->windspeed_daily[day]; - yesterdayRelHum = allHist[yearIndex]->r_humidity_daily[day]; - yesterdayShortWR = allHist[yearIndex]->shortWaveRad[day]; - yesterdayActVP = allHist[yearIndex]->actualVaporPressure[day]; + + if (method == wgLOCF) { + yesterdayTempMax = allHist[yearIndex]->temp_max[day]; + yesterdayTempMin = allHist[yearIndex]->temp_min[day]; + yesterdayCloudCov = allHist[yearIndex]->cloudcov_daily[day]; + yesterdayWindSpeed = allHist[yearIndex]->windspeed_daily[day]; + yesterdayRelHum = allHist[yearIndex]->r_humidity_daily[day]; + yesterdayShortWR = allHist[yearIndex]->shortWaveRad[day]; + yesterdayActVP = allHist[yearIndex]->actualVaporPressure[day]; + } } } } @@ -1750,18 +1783,18 @@ void SW_WTH_setup( case 1: // weather generator - SW_Weather->generateWeatherMethod = 2; + SW_Weather->generateWeatherMethod = wgMKV; break; case 2: // weather generatory only - SW_Weather->generateWeatherMethod = 2; + SW_Weather->generateWeatherMethod = wgMKV; SW_Weather->use_weathergenerator_only = swTRUE; break; case 3: // LOCF (temp) + 0 (PPT) - SW_Weather->generateWeatherMethod = 1; + SW_Weather->generateWeatherMethod = wgLOCF; break; default: From f63b238b1c83f75a73ad60afa34c9f83f1261a7f Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 25 Nov 2024 17:49:56 -0500 Subject: [PATCH 10/12] Update NEWS --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index ebac35cc0..7391bcc4c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,10 @@ * Fix the calculation of relative humidity (#435; @dschlaep). Previously, relative humidity was incorrectly calculated if based on vapor pressure or specific humidity. +* Fix the count of days on which a missing weather value was replaced by a + non-missing value from the preceding day for the method `"LOCF"` + (last observation carried forward; #437; @dschlaep). Previously, any day + with a missing weather value was counted. # SOILWAT2 v8.0.0 From 3e3293485f711e02263d5bff2b9633075aedeb53 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 25 Nov 2024 17:51:21 -0500 Subject: [PATCH 11/12] Run clang format --- src/SW_Weather.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/SW_Weather.c b/src/SW_Weather.c index 70105812a..2a43a138a 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -104,7 +104,6 @@ const static unsigned int wgMKV = 2; /** Weather generation method LOCF, see generateMissingWeather() */ const static unsigned int wgLOCF = 1; - /* =================================================== */ /* Local Function Definitions */ /* --------------------------------------------------- */ @@ -1178,16 +1177,15 @@ void generateMissingWeather( // Throw an error if too many missing values have // been replaced with non-missing values by the LOCF method // per calendar year - if ( - (missing_Tmax && !missing(yesterdayTempMax)) || + if ((missing_Tmax && !missing(yesterdayTempMax)) || (missing_Tmin && !missing(yesterdayTempMin)) || - (missing_PPT && !missing(allHist[yearIndex]->ppt[day])) || + (missing_PPT && !missing(allHist[yearIndex]->ppt[day]) + ) || (missing_CloudCov && !missing(yesterdayCloudCov)) || (missing_WindSpeed && !missing(yesterdayWindSpeed)) || (missing_RelHum && !missing(yesterdayRelHum)) || (missing_ShortWR && !missing(yesterdayShortWR)) || - (missing_ActVP && !missing(yesterdayActVP)) - ) { + (missing_ActVP && !missing(yesterdayActVP))) { nFilledLOCF++; } From 21382280f39088821fd8aa787accef6751838fc0 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 25 Nov 2024 17:53:03 -0500 Subject: [PATCH 12/12] Fix order of static const --- src/SW_Weather.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SW_Weather.c b/src/SW_Weather.c index 2a43a138a..2a90d5d2d 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -99,10 +99,10 @@ /* Weather generation methods */ /** Markov weather generator method, see generateMissingWeather() */ -const static unsigned int wgMKV = 2; +static const unsigned int wgMKV = 2; /** Weather generation method LOCF, see generateMissingWeather() */ -const static unsigned int wgLOCF = 1; +static const unsigned int wgLOCF = 1; /* =================================================== */ /* Local Function Definitions */