From 70439d19842b8b6fb911ef7215e113f99fb8e16f Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:23:13 -0800 Subject: [PATCH 1/6] remove hybridbosse from dependencies --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5056ee3fa..cef772a71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,6 @@ dependencies = [ "floris==4.3", "future", "global_land_mask", - "hybridbosse", "lcoe", "lxml", "matplotlib", From fcd9a5df4bf056546e7bfc55ef397c5f1be6da72 Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:30:47 -0800 Subject: [PATCH 2/6] remove hybridbosse references from legacy --- examples/legacy/analysis/main_usa_new.py | 8 ++++---- examples/legacy/analysis/multi_location.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/legacy/analysis/main_usa_new.py b/examples/legacy/analysis/main_usa_new.py index 05e482cfc..b1e056e1f 100644 --- a/examples/legacy/analysis/main_usa_new.py +++ b/examples/legacy/analysis/main_usa_new.py @@ -132,7 +132,7 @@ def run_hopp_calc(Site, scenario_description, bos_details, total_hybrid_plant_ca save_outputs contains a dictionary of all results for the hopp calculation. :param scenario_description: Project scenario - 'greenfield' or 'solar addition'. - :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE). + :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup). :param total_hybrid_plant_capacity_mw: capacity in MW of hybrid plant. :param solar_size_mw: capacity in MW of solar component of plant. :param wind_size_mw: capacity in MW of wind component of plant. @@ -210,7 +210,7 @@ def run_hybrid_calc(site_num, scenario_descriptions, results_dir, load_resource_ :param solar_size: capacity in MW of solar component of plant. :param hybrid_size: capacity in MW of hybrid plant. :param bos_details: contains bos details including type of analysis to conduct (cost/mw, - json lookup, HybridBOSSE). + json lookup). :param ppa_price: PPA price in USD($). :param solar_tracking_mode: solar tracking mode (e.g. fixed, single-axis, two-axis). :param hub_height: hub height in meters. @@ -477,7 +477,7 @@ def run_all_hybrid_calcs(site_details, scenario_descriptions, results_dir, load_ :param wind_size: capacity in MW of wind plant. :param solar_size: capacity in MW of solar plant. :param hybrid_size: capacity in MW of hybrid plant. - :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE). + :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup). :param ppa_price: ppa price in $(USD) :param solar_tracking_mode: solar tracking mode :param hub_height: hub height in meters. @@ -558,7 +558,7 @@ def run_all_hybrid_calcs(site_details, scenario_descriptions, results_dir, load_ scenario_descriptions = ['Wind Only', 'Solar Only', 'Hybrid - Wind & Solar', 'Solar Addition', 'Wind Overbuild', 'Solar Overbuild', 'Hybrid Vs. Wind + Solar Greenfield'] bos_details = dict() - bos_details['BOSSource'] = 'JSONLookup' # Cost/MW, JSONLookup, HybridBOSSE, HybridBOSSE_manual + bos_details['BOSSource'] = 'JSONLookup' # Cost/MW, JSONLookup bos_details['BOSFile'] = 'UPDATED_BOS_Summary_Results.json' bos_details['BOSScenario'] = 'TBD in analysis' # Will be set to Wind Only, Solar Only, # Variable Ratio Wind and Solar Greenfield, or Solar Addition diff --git a/examples/legacy/analysis/multi_location.py b/examples/legacy/analysis/multi_location.py index 9a83b1aed..bed24cc27 100644 --- a/examples/legacy/analysis/multi_location.py +++ b/examples/legacy/analysis/multi_location.py @@ -140,7 +140,7 @@ def run_hopp_calc(Site, scenario_description, bos_details, total_hybrid_plant_ca save_outputs contains a dictionary of all results for the hopp calculation. :param scenario_description: Project scenario - 'greenfield' or 'solar addition'. - :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE). + :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup). :param total_hybrid_plant_capacity_mw: capacity in MW of hybrid plant. :param solar_size_mw: capacity in MW of solar component of plant. :param wind_size_mw: capacity in MW of wind component of plant. @@ -242,7 +242,7 @@ def run_hybrid_calc(year, site_num, scenario_descriptions, results_dir, load_res :param hybrid_size: capacity in MW of hybrid plant. :param interconnection_size: capacity in MW of interconnection. :param bos_details: contains bos details including type of analysis to conduct (cost/mw, - json lookup, HybridBOSSE). + json lookup). :param ppa_price: PPA price in USD($). :param solar_tracking_mode: solar tracking mode (e.g. fixed, single-axis, two-axis). :param hub_height: hub height in meters. @@ -479,7 +479,7 @@ def run_all_hybrid_calcs(site_details, scenario_descriptions, results_dir, load_ :param wind_size: capacity in MW of wind plant. :param solar_size: capacity in MW of solar plant. :param hybrid_size: capacity in MW of hybrid plant. - :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE). + :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup). :param ppa_price: ppa price in $(USD) :param solar_tracking_mode: solar tracking mode :param hub_height: hub height in meters. @@ -539,7 +539,7 @@ def eprint(*args): # Establish Project Scenarios and Parameter Ranges: bos_details = dict() - bos_details['BOSSource'] = 'costpermw' # costpermw, BOSLookup, HybridBOSSE, HybridBOSSE_manual + bos_details['BOSSource'] = 'costpermw' # costpermw, BOSLookup bos_details['BOSFile'] = 'UPDATED_BOS_Summary_Results.json' bos_details['BOSScenario'] = 'TBD in analysis' # Will be set to Wind Only, Solar Only, # Variable Ratio Wind and Solar Greenfield, or Solar Addition From e499d2b83ce70061b909f84ffc33bc4acf94f7f7 Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:31:36 -0800 Subject: [PATCH 3/6] remove hybridbosse from legacy --- examples/legacy/analysis/single_location.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/legacy/analysis/single_location.py b/examples/legacy/analysis/single_location.py index ba57bfbb6..e08e1fc1a 100644 --- a/examples/legacy/analysis/single_location.py +++ b/examples/legacy/analysis/single_location.py @@ -133,7 +133,7 @@ def run_hopp_calc(Site, scenario_description, bos_details, total_hybrid_plant_ca save_outputs contains a dictionary of all results for the hopp calculation. :param scenario_description: Project scenario - 'greenfield' or 'solar addition'. - :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE). + :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup). :param total_hybrid_plant_capacity_mw: capacity in MW of hybrid plant. :param solar_size_mw: capacity in MW of solar component of plant. :param wind_size_mw: capacity in MW of wind component of plant. @@ -218,7 +218,7 @@ def run_hybrid_calc(year, site_num, scenario_descriptions, results_dir, load_res :param hybrid_size: capacity in MW of hybrid plant. :param interconnection_size: capacity in MW of interconnection. :param bos_details: contains bos details including type of analysis to conduct (cost/mw, - json lookup, HybridBOSSE). + json lookup). :param ppa_price: PPA price in USD($). :param solar_tracking_mode: solar tracking mode (e.g. fixed, single-axis, two-axis). :param hub_height: hub height in meters. @@ -437,7 +437,7 @@ def run_all_hybrid_calcs(site_details, scenario_descriptions, results_dir, load_ :param wind_size: capacity in MW of wind plant. :param solar_size: capacity in MW of solar plant. :param hybrid_size: capacity in MW of hybrid plant. - :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE). + :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup). :param ppa_price: ppa price in $(USD) :param solar_tracking_mode: solar tracking mode :param hub_height: hub height in meters. @@ -477,7 +477,7 @@ def run_all_hybrid_calcs(site_details, scenario_descriptions, results_dir, load_ # Establish Project Scenarios and Parameter Ranges: bos_details = dict() - bos_details['BOSSource'] = 'BOSLookup' # Cost/MW, BOSLookup, HybridBOSSE, HybridBOSSE_manual + bos_details['BOSSource'] = 'BOSLookup' # Cost/MW, BOSLookup bos_details['BOSFile'] = 'UPDATED_BOS_Summary_Results.json' bos_details['BOSScenario'] = 'TBD in analysis' # Will be set to Wind Only, Solar Only, # Variable Ratio Wind and Solar Greenfield, or Solar Addition From 2c8ff430aee74dd2b4e57de12dc976c620e8f1ac Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:33:14 -0800 Subject: [PATCH 4/6] remove hybridbosse from cost calculator --- hopp/tools/analysis/bos/cost_calculator.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hopp/tools/analysis/bos/cost_calculator.py b/hopp/tools/analysis/bos/cost_calculator.py index dbab2c11b..f48606f55 100644 --- a/hopp/tools/analysis/bos/cost_calculator.py +++ b/hopp/tools/analysis/bos/cost_calculator.py @@ -1,6 +1,5 @@ from .bos_model import BOSCostPerMW, BOSCalculator from .bos_lookup import BOSLookup -# from .hybrid_bosse import HybridBOSSE from hopp.utilities.log import bos_logger as logger import numpy as np @@ -25,8 +24,7 @@ def __init__(self, cost_reductions=[]): """ - :param bos_cost_source: Defines the type of bos analysis used. Options are 'JSONLookup', 'Cost/MW', - 'HybridBOSSE', 'HybridBOSSE manual' + :param bos_cost_source: Defines the type of bos analysis used. Options are 'JSONLookup' or 'Cost/MW' :param scenario: 'greenfield' or 'solar addition' :param interconnection_size: Size (MW) of interconnection :param wind_installed_cost_mw: $USD cost/mw for installed wind From ba397444c4b6a67e3d8ce5d54882026c1543ce40 Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:34:39 -0800 Subject: [PATCH 5/6] remove hybridbosse wrapper and client --- hopp/tools/analysis/bos/hybrid_bosse.py | 87 ------------------- hopp/tools/analysis/bos/hybridbosse_client.py | 52 ----------- 2 files changed, 139 deletions(-) delete mode 100644 hopp/tools/analysis/bos/hybrid_bosse.py delete mode 100644 hopp/tools/analysis/bos/hybridbosse_client.py diff --git a/hopp/tools/analysis/bos/hybrid_bosse.py b/hopp/tools/analysis/bos/hybrid_bosse.py deleted file mode 100644 index 240a52d29..000000000 --- a/hopp/tools/analysis/bos/hybrid_bosse.py +++ /dev/null @@ -1,87 +0,0 @@ -import warnings -import math - -from hopp.utilities.log import bos_logger as logger -from hybridbosse.hybridbosse_api.run_hybridbosse import run as run_hybridbosse - -from .bos_model import BOSCalculator - - -class HybridBOSSE(BOSCalculator): - @staticmethod - def _calculate(wind_size, solar_size, interconnection_rating, specify_construction_duration): - warnings.filterwarnings('ignore') # ignore pandas FutureWarning - hybrids_input_dict = dict() - - # shared infra inputs - hybrids_input_dict['shared_interconnection'] = True - hybrids_input_dict['distance_to_interconnect_mi'] = 1 # Input not used for projects <= 15 MW - hybrids_input_dict['new_switchyard'] = True - grid_size_multiplier = 1 - grid_size = wind_size * grid_size_multiplier - if grid_size > 15: - hybrids_input_dict['distance_to_interconnect_mi'] = (0.0263 * grid_size) - 0.2632 - else: - hybrids_input_dict['distance_to_interconnect_mi'] = 0 - if grid_size < 20: - hybrids_input_dict['interconnect_voltage_kV'] = 15 - elif 20 < grid_size < 40: - hybrids_input_dict['interconnect_voltage_kV'] = 34.5 - elif 40 <= grid_size < 75: - hybrids_input_dict['interconnect_voltage_kV'] = 69 # should be 69 - elif grid_size >= 75: - hybrids_input_dict['interconnect_voltage_kV'] = 138 # should be 138 - hybrids_input_dict['grid_interconnection_rating_MW'] = wind_size + solar_size - hybrids_input_dict['shared_substation'] = True - hybrids_input_dict['hybrid_substation_rating_MW'] = wind_size + solar_size - - # Wind farm required inputs - hybrids_input_dict['turbine_rating_MW'] = 1.5 - num_turbines = math.ceil(wind_size/hybrids_input_dict['turbine_rating_MW']) - hybrids_input_dict['num_turbines'] = num_turbines - hybrids_input_dict[ - 'wind_dist_interconnect_mi'] = 0 # Only used for calculating grid cost of wind only. Input not used for projects <= 15 MW - hybrids_input_dict['wind_construction_time_months'] = 5 - hybrids_input_dict['project_id'] = 'hybrids' - - # Solar farm required inputs - hybrids_input_dict['solar_system_size_MW_DC'] = solar_size - hybrids_input_dict[ - 'solar_construction_time_months'] = 5 # Optional. Overrides the internal scaling MW vs. construction time relationship - hybrids_input_dict['solar_dist_interconnect_mi'] = 0 - - # pre-processed input data: - hybrids_input_dict['wind_plant_size_MW'] = hybrids_input_dict['num_turbines'] * \ - hybrids_input_dict['turbine_rating_MW'] - - hybrids_input_dict['hybrid_plant_size_MW'] = hybrids_input_dict['wind_plant_size_MW'] + \ - hybrids_input_dict['solar_system_size_MW_DC'] - - hybrids_input_dict['hybrid_construction_months'] = \ - hybrids_input_dict['wind_construction_time_months'] + \ - hybrids_input_dict['solar_construction_time_months'] - - hybrid_results, wind_only, solar_only = run_hybridbosse(hybrids_input_dict) - - logger.info('Hybrid Dictionary Results: {}'.format(hybrid_results)) - logger.info('Wind Only Dictionary Results:'.format(wind_only)) - logger.info('Solar Only Dictionary Results:'.format(solar_only)) - - wind_hybrid_bos_cost = hybrid_results['Wind_BOS_results']['total_bos_cost'] - solar_hybrid_bos_cost = hybrid_results['Solar_BOS_results']['total_bos_cost'] - hybrid_total_bos_cost = wind_hybrid_bos_cost + solar_hybrid_bos_cost #hybrid_results['hybrid']['hybrid_BOS_usd'] - - return wind_hybrid_bos_cost, solar_hybrid_bos_cost, hybrid_total_bos_cost - - def _calculate_greenfield(self, wind_mw: float, solar_mw: float, interconnection_mw: float = 0): - logger.info("Implemented") - specify_construction_duration = False - return HybridBOSSE._calculate(wind_mw, solar_mw, interconnection_mw, specify_construction_duration) - - def _calculate_solar_addition(self, wind_mw: float, solar_mw: float, interconnection_mw: float = 0): - logger.error("Not yet implemented. Returning results for greenfield site") - specify_construction_duration = False - return HybridBOSSE._calculate(wind_mw, solar_mw, interconnection_mw, specify_construction_duration) - - def calculate_bos_costs(self, wind_mw, solar_mw, interconnection_mw, scenario_info): - raise NotImplementedError diff --git a/hopp/tools/analysis/bos/hybridbosse_client.py b/hopp/tools/analysis/bos/hybridbosse_client.py deleted file mode 100644 index 9742490e6..000000000 --- a/hopp/tools/analysis/bos/hybridbosse_client.py +++ /dev/null @@ -1,52 +0,0 @@ -from hybridbosse.hybridbosse_api.run_hybridbosse import run as run_hybridbosse -import warnings - -warnings.filterwarnings('ignore') # ignore pandas FutureWarning - -hybrids_input_dict = dict() - -# shared infra inputs -hybrids_input_dict['shared_interconnection'] = True -hybrids_input_dict['distance_to_interconnect_mi'] = 1 # Input not used for projects <= 15 MW -hybrids_input_dict['new_switchyard'] = True -hybrids_input_dict['interconnect_voltage_kV'] = 15 -hybrids_input_dict['shared_substation'] = True -hybrids_input_dict['hybrid_substation_rating_MW'] = 7.5 - -# Wind farm required inputs -hybrids_input_dict['num_turbines'] = 5 -hybrids_input_dict['turbine_rating_MW'] = 1.5 -hybrids_input_dict['wind_dist_interconnect_mi'] = 0 # Only used for calculating grid cost of wind only. Input not used for projects <= 15 MW -hybrids_input_dict['wind_construction_time_months'] = 5 -hybrids_input_dict['project_id'] = 'hybrids' - -# Solar farm required inputs -hybrids_input_dict['solar_system_size_MW_DC'] = 7.5 -hybrids_input_dict['solar_construction_time_months'] = 5 # Optional. Overrides the internal scaling MW vs. construction time relationship -hybrids_input_dict['solar_dist_interconnect_mi'] = 0 - -# pre-processed input data: -hybrids_input_dict['wind_plant_size_MW'] = hybrids_input_dict['num_turbines'] * \ - hybrids_input_dict['turbine_rating_MW'] - -hybrids_input_dict['hybrid_plant_size_MW'] = hybrids_input_dict['wind_plant_size_MW'] + \ - hybrids_input_dict['solar_system_size_MW_DC'] - -hybrids_input_dict['hybrid_construction_months'] = \ - hybrids_input_dict['wind_construction_time_months'] + \ - hybrids_input_dict['solar_construction_time_months'] - -hybrids_input_dict['grid_interconnection_rating_MW'] = 100 -hybrid_results, wind_only, solar_only = run_hybridbosse(hybrids_input_dict) - -print('Hybrid Dictionary Results:') -print('') -print(hybrid_results) -print('') -print('Wind Only Dictionary Results:') -print('') -print(wind_only) -print('') -print('Solar Only Dictionary Results:') -print('') -print(solar_only) From 0acf9532da52ada75cb7b2adacf5b22627155e11 Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:38:26 -0800 Subject: [PATCH 6/6] update changelog --- RELEASE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE.md b/RELEASE.md index 0c09788cc..5da8c4255 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -8,6 +8,7 @@ * Add load following heuristic dispatch test * Consolidated utilities, renamed MHKConfig to MHKWaveConfig * Updated solar resource download to use GOES Aggregated PSM v4 download +* Deprecate support for HybridBOSSE. ## Version 3.3.0, April 30, 2025