From 3789bf6fb07dd698245d29c0fbf1b516649592e4 Mon Sep 17 00:00:00 2001 From: Javier Lopez Lorente Date: Tue, 21 Apr 2026 13:22:02 +0200 Subject: [PATCH 1/4] Add calculate dhi option to PVSystem class --- solarfarmer/models/pvsystem/pvsystem.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/solarfarmer/models/pvsystem/pvsystem.py b/solarfarmer/models/pvsystem/pvsystem.py index 32290c7..f04be5d 100644 --- a/solarfarmer/models/pvsystem/pvsystem.py +++ b/solarfarmer/models/pvsystem/pvsystem.py @@ -198,7 +198,10 @@ class PVSystem: If True, generates loss tree timeseries output (default is True). enable_spectral_modeling : bool If True, enables spectral modeling in the calculation (default is False). - + calculate_dhi_weather: bool + If True, the calculation will calculate DHI from the provided GHI in the weather file. + This needs to be set to True when the weather file does not contain DHI data. + Methods ------- - horizon(elevation_angles, azimuth_angles) @@ -271,6 +274,7 @@ class PVSystem: generate_pvsyst_format_timeseries: bool = True generate_loss_tree_timeseries: bool = True enable_spectral_modeling: bool = False + calculate_dhi_weather: bool = False # Auxiliary files _pan_files: dict[str, Path] = field(default_factory=dict, repr=False) @@ -832,6 +836,7 @@ def describe(self, verbose=False) -> None: print("\n--- MODELING OPTIONS ---") print(f"Enable Spectral Modeling: {self.enable_spectral_modeling}") print(f"Module IAM Model Override: {self.module_iam_model_override}") + print(f"Calculate DHI (from GHI in weather file): {self.calculate_dhi_weather}") # Output Options print("\n--- OUTPUT OPTIONS ---") @@ -1105,6 +1110,7 @@ def construct_plant(pvplant: PVSystem) -> str: pvplant.generate_pvsyst_format_timeseries ) calculation_options.apply_spectral_mismatch_modifier = pvplant.enable_spectral_modeling + calculation_options.calculate_dhi = pvplant.calculate_dhi_weather # Build the full inputs model inputs = EnergyCalculationInputs( From c0aaf45b34669d8d8943f6ead16eab0208df2e7d Mon Sep 17 00:00:00 2001 From: Javier Lopez Lorente Date: Tue, 21 Apr 2026 13:35:29 +0200 Subject: [PATCH 2/4] Fix linting error --- solarfarmer/models/pvsystem/pvsystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solarfarmer/models/pvsystem/pvsystem.py b/solarfarmer/models/pvsystem/pvsystem.py index f04be5d..8a126e5 100644 --- a/solarfarmer/models/pvsystem/pvsystem.py +++ b/solarfarmer/models/pvsystem/pvsystem.py @@ -201,7 +201,7 @@ class PVSystem: calculate_dhi_weather: bool If True, the calculation will calculate DHI from the provided GHI in the weather file. This needs to be set to True when the weather file does not contain DHI data. - + Methods ------- - horizon(elevation_angles, azimuth_angles) From a30a67adf242a34708f1c9a967881fd610d7c673 Mon Sep 17 00:00:00 2001 From: Javier Lopez Lorente Date: Wed, 22 Apr 2026 09:57:48 +0200 Subject: [PATCH 3/4] Update property name to 'calculate_dhi_from_ghi' --- solarfarmer/models/pvsystem/pvsystem.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/solarfarmer/models/pvsystem/pvsystem.py b/solarfarmer/models/pvsystem/pvsystem.py index 8a126e5..9365156 100644 --- a/solarfarmer/models/pvsystem/pvsystem.py +++ b/solarfarmer/models/pvsystem/pvsystem.py @@ -198,9 +198,12 @@ class PVSystem: If True, generates loss tree timeseries output (default is True). enable_spectral_modeling : bool If True, enables spectral modeling in the calculation (default is False). - calculate_dhi_weather: bool - If True, the calculation will calculate DHI from the provided GHI in the weather file. - This needs to be set to True when the weather file does not contain DHI data. + calculate_dhi_from_ghi : bool + Whether to calculate diffuse horizontal irradiance (DHI) from global + horizontal irradiance (GHI) when the ``DHI`` column is missing from the + meteorological file. If ``False`` and ``DHI`` is missing, the calculation + will fail. Set to ``True`` when using weather files that only provide GHI. + Provided DHI is preferred over engine decomposition (default is False). Methods ------- @@ -274,7 +277,7 @@ class PVSystem: generate_pvsyst_format_timeseries: bool = True generate_loss_tree_timeseries: bool = True enable_spectral_modeling: bool = False - calculate_dhi_weather: bool = False + calculate_dhi_from_ghi: bool = False # Auxiliary files _pan_files: dict[str, Path] = field(default_factory=dict, repr=False) @@ -836,7 +839,7 @@ def describe(self, verbose=False) -> None: print("\n--- MODELING OPTIONS ---") print(f"Enable Spectral Modeling: {self.enable_spectral_modeling}") print(f"Module IAM Model Override: {self.module_iam_model_override}") - print(f"Calculate DHI (from GHI in weather file): {self.calculate_dhi_weather}") + print(f"Calculate DHI (from GHI in weather file): {self.calculate_dhi_from_ghi}") # Output Options print("\n--- OUTPUT OPTIONS ---") @@ -1110,7 +1113,7 @@ def construct_plant(pvplant: PVSystem) -> str: pvplant.generate_pvsyst_format_timeseries ) calculation_options.apply_spectral_mismatch_modifier = pvplant.enable_spectral_modeling - calculation_options.calculate_dhi = pvplant.calculate_dhi_weather + calculation_options.calculate_dhi = pvplant.calculate_dhi_from_ghi # Build the full inputs model inputs = EnergyCalculationInputs( From 9b500e75af4e481c3c08c040223fab7459c11a2f Mon Sep 17 00:00:00 2001 From: Javier Lopez Lorente Date: Wed, 22 Apr 2026 09:58:06 +0200 Subject: [PATCH 4/4] Add tests --- tests/test_construct_plant.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_construct_plant.py b/tests/test_construct_plant.py index 149ed7b..8e27e47 100644 --- a/tests/test_construct_plant.py +++ b/tests/test_construct_plant.py @@ -57,6 +57,16 @@ def test_spectral_modeling_on_when_enabled(self, plant): payload = json.loads(construct_plant(plant)) assert payload["energyCalculationOptions"]["applySpectralMismatchModifier"] is True + def test_calculate_dhi_off_by_default(self, plant): + payload = json.loads(construct_plant(plant)) + opts = payload["energyCalculationOptions"] + assert opts.get("calculateDHI", False) is False + + def test_calculate_dhi_on_when_enabled(self, plant): + plant.calculate_dhi_from_ghi = True + payload = json.loads(construct_plant(plant)) + assert payload["energyCalculationOptions"]["calculateDHI"] is True + def test_horizon_keys_absent_when_not_set(self, plant): payload = json.loads(construct_plant(plant)) assert "horizonAzimuths" not in payload