From 0cfe42ea08e39f8ce5119bdf5f6a62d72e040947 Mon Sep 17 00:00:00 2001 From: "J. Michelle Hu" <43484205+jmichellehu@users.noreply.github.com> Date: Thu, 1 Oct 2026 17:51:31 -0600 Subject: [PATCH] Distribute - Albedo - set vis and ir albedo to None when sun is down - Zero-fill of vis and ir from PR #27 overrides broadband albedo branch in SolarHRRR.calculate_net_solar - Results in net_solar radiation being made equivalent to incoming solar - Explicit None definition ensures broadband albedo branch kicks in correctly --- smrf/distribute/albedo.py | 4 +-- smrf/tests/distribute/test_albedo.py | 26 ++++++++++++++++ smrf/tests/distribute/test_solar_hrrr.py | 38 +++++++++++++++++++++++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/smrf/distribute/albedo.py b/smrf/distribute/albedo.py index 2f81ef7b..cfa3f3e5 100755 --- a/smrf/distribute/albedo.py +++ b/smrf/distribute/albedo.py @@ -194,8 +194,8 @@ def distribute( self.albedo_ir = utils.set_min_max(alb_ir, self.min, self.max) else: - self.albedo_vis = np.zeros(storm_day.shape) - self.albedo_ir = np.zeros(storm_day.shape) + self.albedo_vis = None + self.albedo_ir = None def date_method( self, diff --git a/smrf/tests/distribute/test_albedo.py b/smrf/tests/distribute/test_albedo.py index 9d67ad0c..a241d32b 100644 --- a/smrf/tests/distribute/test_albedo.py +++ b/smrf/tests/distribute/test_albedo.py @@ -98,6 +98,32 @@ def test_distribute_file_broadband(self, mock_read_netcdf): npt.assert_equal(subject.albedo, values) mock_source.load.assert_called_with("albedo", TIMESTEP) + @patch("smrf.distribute.variable_base.ReadNetCDF") + def test_distribute_file_broadband_after_sun_down(self, mock_read_netcdf): + # A night step must not set vis/ir values, as these take priority over the + # broadband albedo in the net solar calculation + values = np.array([0.9, 0.5]) + mock_source = MagicMock() + mock_source.variables = ["albedo"] + mock_source.load.return_value = values + mock_read_netcdf.return_value = mock_source + + config = self._copy_config(CONFIG) + config["albedo"]["source_files"] = "path/to/files" + subject = Albedo(config, topo_mock()) + subject.initialize(pd.DataFrame()) + + # Sun is down + subject.distribute(TIMESTEP, None, STORM_DAYS) + self.assertIsNone(subject.albedo_vis) + self.assertIsNone(subject.albedo_ir) + + # Sun is up + subject.distribute(TIMESTEP, COS_Z, STORM_DAYS) + npt.assert_equal(subject.albedo, values) + self.assertIsNone(subject.albedo_vis) + self.assertIsNone(subject.albedo_ir) + @patch("smrf.distribute.variable_base.ReadNetCDF") def test_distribute_file_vis_ir(self, mock_read_netcdf): values_vis = np.array([0.8, 0.7]) diff --git a/smrf/tests/distribute/test_solar_hrrr.py b/smrf/tests/distribute/test_solar_hrrr.py index a64bd4b0..37c8c91d 100644 --- a/smrf/tests/distribute/test_solar_hrrr.py +++ b/smrf/tests/distribute/test_solar_hrrr.py @@ -1,5 +1,5 @@ import unittest -from unittest.mock import patch +from unittest.mock import MagicMock, patch import numpy as np import numpy.testing as npt @@ -114,6 +114,42 @@ def test_distribute_with_vegetation(self, vegetation_mock): diffuse, self.subject.veg_tau ) + @patch("smrf.distribute.variable_base.ReadNetCDF") + @patch("smrf.distribute.solar_hrrr.mask_for_shade") + def test_net_solar_broadband_albedo_after_sun_down( + self, shade_mock, mock_read_netcdf + ): + shade_mock.return_value = ILLUMINATION_MOCK, np.array([1, 1]) + + broadband = np.array([[0.8, 0.5]], dtype=np.float32) + mock_source = MagicMock() + mock_source.variables = ["albedo"] + mock_source.load.return_value = broadband + mock_read_netcdf.return_value = mock_source + + config = { + "time": {"start_date": "2025-10-01 00:00", "time_zone": "utc"}, + "albedo": {"decay_method": None, "source_files": "path/to/files"}, + "solar": {"correct_veg": False}, + } + albedo = Albedo(config=config, topo=topo_mock()) + albedo.initialize(pd.DataFrame()) + + # A night step precedes the first daylight step, like at the start of a run + storm_days = np.zeros_like(ILLUMINATION_MOCK) + albedo.distribute(DATETIME, None, storm_days) + albedo.distribute(DATETIME, COS_Z, storm_days) + + self.subject.distribute( + DATETIME, DATA_MOCK, COS_Z, AZIMUTH, ILLUMINATION_MOCK, albedo + ) + + # Net solar is reduced by the broadband albedo and not passed through + npt.assert_allclose( + self.subject.net_solar, self.subject.hrrr_solar * (1 - broadband) + ) + self.assertTrue(np.all(self.subject.net_solar < self.subject.hrrr_solar)) + def test_distribute_sun_is_down(self): self.subject.distribute( DATETIME,