diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 298ab5b4..b53ca9ca 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -365,7 +365,7 @@ def compile_input_dict(cls, phases): " commissioning_factor)" ), "construction_insurance_factor": ( - "float (optional, default: 0.0115)" + "float (optional, default: 0.0207)" ), "construction_financing_factor": ( "$/kW (optional, default: value calculated using" @@ -379,7 +379,7 @@ def compile_input_dict(cls, phases): ), "tax_rate": "float (optional, default: 0.26", "interest_during_construction": ( - "float (optional, default: 0.044" + "float (optional, default: 0.065" ), "procurement_contingency_factor": ( "float (optional, default: 0.0575)" @@ -387,12 +387,12 @@ def compile_input_dict(cls, phases): "installation_contingency_factor": ( "float (optional, default: 0.345)" ), - "decommissioning_factor": ("float (optional, default: 0.1725)"), + "decommissioning_factor": ("float (optional, default: 0.2)"), "commissioning_factor": "float (optional, default: 0.0115)", - "site_auction_price": "$ (optional, default: 100e6)", - "site_assessment_cost": "$ (optional, default: 50e6)", - "construction_plan_cost": "$ (optional, default: 1e6)", - "installation_plan_cost": "$ (optional, default: 0.25e6)", + "site_auction_price": "$ (optional, default: 105e6)", + "site_assessment_cost": "$ (optional, default: 200e6)", + "construction_plan_cost": "$ (optional, default: 25e6)", + "installation_plan_cost": "$ (optional, default: 25e6)", } config["design_phases"] = [*design_phases.keys()] @@ -670,7 +670,7 @@ def run_install_phase(self, name, start, **kwargs): if phase.installation_capex: self.installation_costs[name] = phase.installation_capex - + return time, logs def get_phase_class(self, phase): @@ -747,6 +747,8 @@ def run_design_phase(self, name, **kwargs): self.detailed_outputs, phase.detailed_output ) + + def run_multiple_phases_in_serial(self, phase_list, **kwargs): """ Runs multiple phases listed in self.config['install_phases'] in serial. @@ -1054,6 +1056,8 @@ def outputs(self, include_logs=False, npv_detailed=False): "npv": self.npv, "supply_chain_capex": self.supply_chain_capex, "supply_chain_capex_kw": self.supply_chain_capex_per_kw, + "onshore_substation_capex": self.onshore_substation_capex, + "onshore_substation_capex_kw": self.onshore_substation_capex_per_kw, } if include_logs: @@ -1442,6 +1446,8 @@ def capex_breakdown(self): else: outputs[name] = cost + outputs["Onshore Substation"] = self.onshore_substation_capex + outputs["Turbine"] = self.turbine_capex outputs["Soft"] = self.soft_capex @@ -1491,7 +1497,7 @@ def capex_detailed_soft_capex_breakdown_per_kw(self): def bos_capex(self): """Returns total balance of system CapEx.""" - return self.system_capex + self.installation_capex + return self.system_capex + self.installation_capex + self.onshore_substation_capex @property def bos_capex_per_kw(self): @@ -1562,6 +1568,27 @@ def supply_chain_capex_per_kw(self): return _capex + @property + def onshore_substation_capex(self): + """Returns the onshore substation CapEx if available in 'ElectricalDesign', otherwise 0.""" + if "ElectricalDesign" in self.phases: + try: + return self.phases["ElectricalDesign"].detailed_output["export_system"]["onshore_substation_costs"] + except KeyError: + return 0 + return 0 + + @property + def onshore_substation_capex_per_kw(self): + """Returns the onshore substation CapEx/kW. + """ + if "ElectricalDesign" in self.phases: + try: + return self.onshore_substation_capex / (self.capacity * 1000) + except KeyError: + return None + return None + @property def overnight_capex(self): """Returns the overnight capital cost of the project.""" @@ -1616,7 +1643,7 @@ def construction_insurance_capex(self): ) contruction_insurance_factor = self.project_params.get( - "construction_insurance_factor", 0.0115 + "construction_insurance_factor", 0.0207 ) if construction_insurance_per_kW is not None: @@ -1642,7 +1669,7 @@ def decommissioning_capex(self): ) decommissioning_factor = self.project_params.get( - "decommissioning_factor", 0.175 + "decommissioning_factor", 0.2 ) if decommissioning_per_kW is not None: @@ -1747,7 +1774,7 @@ def construction_financing_factor(self): ) tax_rate = self.project_params.get("tax_rate", 0.26) interest_during_construction = self.project_params.get( - "interest_during_construction", 0.044 + "interest_during_construction", 0.065 ) _check = 0 @@ -1808,15 +1835,15 @@ def project_capex(self): the keys below should be passed to the 'project_parameters' subdict. """ - site_auction = self.project_params.get("site_auction_price", 122698898) + site_auction = self.project_params.get("site_auction_price", 105000000) site_assessment = self.project_params.get( - "site_assessment_cost", 61349449 + "site_assessment_cost", 200000000 ) construction_plan = self.project_params.get( - "construction_plan_cost", 1226989 + "construction_plan_cost", 25000000 ) installation_plan = self.project_params.get( - "installation_plan_cost", 306747 + "installation_plan_cost", 25000000 ) return sum( diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 5cee1899..d5ec6b38 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -9,6 +9,22 @@ Unreleased configuration input. - Move the matplotlib import from the import section of ``/ORBIT/phases/design/array_system_design.py`` to the ``CustomArraySystemDesign.plot_array_system`` for missing module error handling. +- Updated default `soft_capex` factors. `PR #201 `_ + - `construction_insurance_factor` updated from 0.115 to 0.0207 based on industry benchmarking, resulting in higher construction insurance costs. + - `interest_during_construction` updated from 4.4% to 6.5% based on financial assumptions from the 2025 Annual Technology Baseline (ATB), increasing construction financing costs. + - `decommissioning_factor` updated from 0.175 to 0.2 based on industry benchmarking, leading to higher decommissioning costs than in previous versions. +- Updated default `project_capex` values. `PR #201 `_ + - `site_auction_price` increased from 100M to 105M USD to account for rent fees before operation. + - `site_assessment_cost`, `construction_plan_cost`, and `installation_plan_cost` increased from 50M, 1M, and 0.25M USD to 200M, 25M, and 25M USD, respectively. + - Total `project_capex` excluding `site_auction_price` now sums to 250M USD, aligning with DevEx recommendations based on industry benchmarking. + - These updates lead to higher default total project costs than in previous versions. +- Included onshore substation costs in BOS CapEx and project breakdown. `PR #201 `_ + - The `ElectricalDesign` module previously calculated onshore substation costs but did not include them in `capex_breakdown` or `bos_capex`. + - These costs are now incorporated when `ElectricalDesign` is used, resulting in higher `bos_capex`, `soft_capex`, and `total_capex` than in prior versions. +- Cable configuration file updates. `PR #201 `_ + - Added a new dynamic cable configuration file for floating cases: `library/cables/XLPE_1200mm_220kV_dynamic.yaml`. + - Updated cost values for `library/cables/XLPE_630mm_66kV.yaml` and `library/cables/XLPE_630mm_66kV_dynamic.yaml` based on industry benchmarking. + - All cable cost updates are expressed in 2024 USD for consistency with other library configuration files. 1.2.4 ----- diff --git a/library/cables/XLPE_1200mm_220kV_dynamic.yaml b/library/cables/XLPE_1200mm_220kV_dynamic.yaml new file mode 100644 index 00000000..d3308df7 --- /dev/null +++ b/library/cables/XLPE_1200mm_220kV_dynamic.yaml @@ -0,0 +1,13 @@ +# Caveat: cable specs not from a spec sheet +# Assumed to have a cable with these costs +# and a capacity of 400 MW (seen on industry) +ac_resistance: 0.16 # ohm/km +capacitance: 190 # nF/km +conductor_size: 1200 # mm^2 +cost_per_km: 1801082 # $ +current_capacity: 1125 # A +inductance: 0.38 # mH/km +linear_density: 115 # t/km +rated_voltage: 220 # kV +cable_type: HVAC # HVDC vs HVAC +name: XLPE_1200mm_220kV_dynamic diff --git a/library/cables/XLPE_630mm_66kV.yaml b/library/cables/XLPE_630mm_66kV.yaml index 3697f6e0..72d11be2 100644 --- a/library/cables/XLPE_630mm_66kV.yaml +++ b/library/cables/XLPE_630mm_66kV.yaml @@ -1,7 +1,7 @@ ac_resistance: 0.04 capacitance: 300 conductor_size: 630 -cost_per_km: 483084 +cost_per_km: 650000 current_capacity: 775 inductance: 0.35 linear_density: 42.5 diff --git a/library/cables/XLPE_630mm_66kV_dynamic.yaml b/library/cables/XLPE_630mm_66kV_dynamic.yaml index 7a3737e8..4220f671 100644 --- a/library/cables/XLPE_630mm_66kV_dynamic.yaml +++ b/library/cables/XLPE_630mm_66kV_dynamic.yaml @@ -1,7 +1,7 @@ ac_resistance: 0.04 capacitance: 300 conductor_size: 630 -cost_per_km: 579700 # $ (20% adder over XLPE_630mm_66kV) +cost_per_km: 780000 # $ (20% adder over XLPE_630mm_66kV) current_capacity: 775 inductance: 0.35 linear_density: 42.5 diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 82ceff95..7fabe212 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -948,22 +948,22 @@ def test_project_costs(): baseline = project.project_capex config = deepcopy(complete_project) - config["project_parameters"] = {"site_auction_price": 50e6} + config["project_parameters"] = {"site_auction_price": 30e6} project = ProjectManager(config) assert project.project_capex != baseline config = deepcopy(complete_project) - config["project_parameters"] = {"site_assessment_cost": 25e6} + config["project_parameters"] = {"site_assessment_cost": 30e6} project = ProjectManager(config) assert project.project_capex != baseline config = deepcopy(complete_project) - config["project_parameters"] = {"construction_plan_cost": 25e6} + config["project_parameters"] = {"construction_plan_cost": 30e6} project = ProjectManager(config) assert project.project_capex != baseline config = deepcopy(complete_project) - config["project_parameters"] = {"installation_plan_cost": 25e6} + config["project_parameters"] = {"installation_plan_cost": 30e6} project = ProjectManager(config) assert project.project_capex != baseline @@ -995,14 +995,14 @@ def test_total_capex(): fix_project.run() assert fix_project.total_capex == pytest.approx( - 1593220043.059402, abs=1e-1 + 1843929494.9506452, abs=1e-1 ) flt_project = ProjectManager(complete_floating_project) flt_project.run() assert flt_project.total_capex == pytest.approx( - 4087665127.1458263, abs=1e-1 + 4448212431.513601, abs=1e-1 )