def test_fixed_phase_cost_passing(): project = ProjectManager(fixed) project.run() assert_almost_equal( project.phases["MonopileDesign"].total_cost, project.phases["MonopileInstallation"].system_capex, ) assert_almost_equal( project.phases["ScourProtectionDesign"].total_cost, project.phases["ScourProtectionInstallation"].system_capex, ) assert_almost_equal( project.phases["ArraySystemDesign"].total_cost, project.phases["ArrayCableInstallation"].system_capex, ) assert_almost_equal( project.phases["ExportSystemDesign"].total_cost, project.phases["ExportCableInstallation"].system_capex, ) assert_almost_equal( project.phases["OffshoreSubstationDesign"].total_cost, project.phases["OffshoreSubstationInstallation"].system_capex, )
def test_chained_dependencies(): config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { "tonnes_per_substructure": 200, "cost_per_tonne": 45, } config_chained["install_phases"] = { "ScourProtectionInstallation": 0, "MonopileInstallation": ("ScourProtectionInstallation", 0.1), "TurbineInstallation": ("MonopileInstallation", 0.5), } project = ProjectManager(config_chained) project.run() df = pd.DataFrame(project.actions) sp = list(df.loc[df["phase"] == "ScourProtectionInstallation"]["time"]) mp = list(df.loc[df["phase"] == "MonopileInstallation"]["time"]) tu = list(df.loc[df["phase"] == "TurbineInstallation"]["time"]) assert min(sp) == 0 assert min(mp) == (max(sp) - min(sp)) * 0.1 assert min(tu) == (max(mp) - min(mp)) * 0.5 + min(mp)
def test_duplicate_phase_definitions(): config_with_duplicates = deepcopy(config) config_with_duplicates["MonopileInstallation_1"] = { "plant": { "num_turbines": 5 } } config_with_duplicates["MonopileInstallation_2"] = { "plant": { "num_turbines": 5 }, "site": { "distance": 100 }, } config_with_duplicates["install_phases"] = { "MonopileInstallation_1": 0, "MonopileInstallation_2": 800, "TurbineInstallation": 1600, } project = ProjectManager(config_with_duplicates) project.run() df = (pd.DataFrame(project.actions).groupby(["phase", "action"]).count()["time"]) assert df.loc[("MonopileInstallation_1", "Drive Monopile")] == 5 assert df.loc[("MonopileInstallation_2", "Drive Monopile")] == 5 assert df.loc[("TurbineInstallation", "Attach Tower Section")] == 10
def test_incomplete_config(): incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") with pytest.raises(MissingInputs): project = ProjectManager(incomplete_config) project.run()
def test_wrong_phases(): wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") with pytest.raises(PhaseNotFound): project = ProjectManager(wrong_phases) project.run()
def test_complete_run(weather): project = ProjectManager(config, weather=weather) project.run() actions = pd.DataFrame(project.actions) phases = ["MonopileInstallation", "TurbineInstallation"] assert all(p in list(actions["phase"]) for p in phases)
def test_for_equal_results(): config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) project.run() parametric = ParametricManager(config, params, funcs) parametric.run() df = parametric.results.set_index("site.distance") assert df.loc[20]["bos_capex"] == project.bos_capex
def test_bad_dates(): bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", "TurbineInstallation": "05/01/2015", } with pytest.raises(WeatherProfileError): project = ProjectManager(bad_dates, weather=weather_df) project.run()
def test_no_defined_start(): missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), "TurbineInstallation": ("MonopileInstallation", 0.1), } with pytest.raises(ValueError): project = ProjectManager(missing_start) project.run()
def test_ProjectProgress_with_incomplete_project(): project = ProjectManager(config) project.run() _ = project.progress.parse_logs("Substructure") _ = project.progress.parse_logs("Turbine") with pytest.raises(ValueError): project.progress.complete_export_system with pytest.raises(ValueError): project.progress.complete_array_strings
def test_circular_dependencies(): circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = {"tons_per_substructure": 200} circular_deps["install_phases"] = { "ScourProtectionInstallation": 0, "MonopileInstallation": ("TurbineInstallation", 0.1), "TurbineInstallation": ("MonopileInstallation", 0.1), } with pytest.raises(PhaseDependenciesInvalid): project = ProjectManager(circular_deps) project.run_project()
def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): config = self.compile_orbit_config_file(inputs, outputs, discrete_inputs, discrete_outputs) project = ProjectManager(config) project.run() outputs["bos_capex"] = project.bos_capex outputs["total_capex"] = project.total_capex outputs["total_capex_kW"] = project.total_capex_per_kw outputs["installation_time"] = project.installation_time outputs["installation_capex"] = project.installation_capex
def test_dependent_phase_ordering(): wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = {"tons_per_substructure": 200} wrong_order["install_phases"] = { "ScourProtectionInstallation": ("TurbineInstallation", 0.1), "TurbineInstallation": ("MonopileInstallation", 0.1), "MonopileInstallation": 0, } project = ProjectManager(wrong_order) project.run_project() assert len(project.phase_times) == 3
def test_phase_specific_file_extraction(): project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") assert isinstance(turbine_config["wtiv"], dict) assert isinstance(monopile_config["wtiv"], dict) bad_config = deepcopy(config) _ = bad_config.pop("TurbineInstallation") bad_config["wtiv"] = "example_wtiv" bad_config["MonopileInstallation"]["wtiv"] = "missing_vessel" with pytest.raises(LibraryItemNotFoundError): bad_project = ProjectManager(bad_config)
def test_kwargs_in_ProjectManager(): base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] project = ProjectManager(base) project.run() baseline = project.phase_times["OffshoreSubstationInstallation"] keywords = [ "mono_embed_len", "mono_drive_rate", "mono_fasten_time", "mono_release_time", "tp_bolt_time", "site_position_time", "crane_reequip_time", "rov_survey_time", "topside_fasten_time", "topside_release_time", ] failed = [] for kw in keywords: default = pt[kw] if kw == "mono_drive_rate": _new = default - 2 if _new <= 0: raise Exception(f"'{kw}' is less than 0.") processes = {kw: _new} else: processes = {kw: default + 2} new_config = deepcopy(base) new_config["processes"] = processes new_project = ProjectManager(new_config) new_project.run() new_time = new_project.phase_times["OffshoreSubstationInstallation"] if new_time > baseline: pass else: failed.append(kw) if failed: raise Exception(f"'{failed}' not affecting results.") else: assert True
def test_start_dates_with_weather(m_start, t_start, expected): config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, "TurbineInstallation": t_start, } project = ProjectManager(config_with_defined_starts, weather=weather_df) project.run() df = pd.DataFrame(project.actions) _m = df.loc[df["phase"] == "MonopileInstallation"].iloc[0] _t = df.loc[df["phase"] == "TurbineInstallation"].iloc[0] _diff = (_t["time"] - _t["duration"]) - (_m["time"] - _m["duration"]) assert _diff == expected
def test_install_phase_start_parsing(): config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, "TurbineInstallation": "10/22/2009", "ArrayCableInstallation": ("MonopileInstallation", 0.5), } project = ProjectManager(config_mixed_starts, weather=weather_df) defined, depends = project._parse_install_phase_values( config_mixed_starts["install_phases"]) assert len(defined) == 2 assert len(depends) == 1 assert defined["MonopileInstallation"] == 0 assert defined["TurbineInstallation"] == 1
def test_soft_costs(): project = ProjectManager(complete_project) baseline = project.soft_capex config = deepcopy(complete_project) config["project_parameters"] = {"construction_insurance": 50} project = ProjectManager(config) assert project.soft_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"construction_financing": 190} project = ProjectManager(config) assert project.soft_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"contingency": 320} project = ProjectManager(config) assert project.soft_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"contingency": 320} project = ProjectManager(config) assert project.soft_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"commissioning": 50} project = ProjectManager(config) assert project.soft_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"decommissioning": 50} project = ProjectManager(config) assert project.soft_capex != baseline
def test_mono_and_tp_definition(): test_config = deepcopy(config) project = ProjectManager(test_config) project.run_project() for key, value in config["monopile"].items(): if key == "type": continue assert project.config["monopile"][key] == value for key, value in config["transition_piece"].items(): if key == "type": continue assert project.config["transition_piece"][key] == value
def _run_config(self, run, **kwargs): """Run an individual config.""" config = deepcopy(self.base) config.merge(run) if self.module is not None: project = self.module(config, weather=self.weather, **kwargs) project.run() else: project = ProjectManager(config, weather=self.weather, **kwargs) project.run() results = self.map_funcs(project, self.funcs) data = {**run, **results} return data
def test_kwargs_for_array_install_in_ProjectManager(): base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] project = ProjectManager(base) project.run() baseline = project.phase_times["ArrayCableInstallation"] keywords = [ "cable_load_time", "site_position_time", "cable_prep_time", "cable_lower_time", "cable_pull_in_time", "cable_termination_time", ] failed = [] for kw in keywords: default = pt[kw] if "speed" in kw: _new = default - 0.05 if _new <= 0: raise Exception(f"'{kw}' is less than 0.") processes = {kw: _new} else: processes = {kw: default + 2} new_config = deepcopy(base) new_config["processes"] = processes new_project = ProjectManager(new_config) new_project.run() new_time = new_project.phase_times["ArrayCableInstallation"] if new_time > baseline: pass else: failed.append(kw) if failed: raise Exception(f"ExpInstall: '{failed}' not affecting results.") else: assert True
def test_monthly_expenses(): project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses # Still report expenses for "incomplete" project config = deepcopy(complete_project) _ = config["install_phases"].pop("TurbineInstallation") project = ProjectManager(config) project.run() _ = project.monthly_expenses
def test_index_starts(m_start, t_start): """ Tests functionality related to passing index starts into 'install_phases' sub-dict. """ _target_diff = t_start - m_start config_with_index_starts = deepcopy(config) config_with_index_starts["install_phases"] = { "MonopileInstallation": m_start, "TurbineInstallation": t_start, } project = ProjectManager(config_with_index_starts) project.run() df = pd.DataFrame(project.actions) _m = df.loc[df["phase"] == "MonopileInstallation"].iloc[0] _t = df.loc[df["phase"] == "TurbineInstallation"].iloc[0] _diff = (_t["time"] - _t["duration"]) - (_m["time"] - _m["duration"]) assert _diff == _target_diff
def instantiate_orbit(): ProjectManager.compile_input_dict(phases) path = os.path.join(os.getcwd(), "..\general_library") ORBIT_project = ProjectManager(config, weather=None, library_path=path) ORBIT_project.run_project() print('OSS', ORBIT_project._phases["OffshoreSubstationDesign"].design_result) return ORBIT_project
def test_monthly_revenue(): project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue # Can't generate revenue with "incomplete" project config = deepcopy(complete_project) _ = config["install_phases"].pop("TurbineInstallation") project = ProjectManager(config) project.run() with pytest.raises(ValueError): _ = project.monthly_revenue
def test_kwargs_in_ProjectManager(): base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] project = ProjectManager(base) project.run() baseline = project.phase_times["TurbineInstallation"] keywords = [ "tower_section_fasten_time", "tower_section_release_time", "tower_section_attach_time", "nacelle_fasten_time", "nacelle_release_time", "nacelle_attach_time", "blade_fasten_time", "blade_release_time", "blade_attach_time", "site_position_time", "crane_reequip_time", ] failed = [] for kw in keywords: default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) new_config["processes"] = processes new_project = ProjectManager(new_config) new_project.run() new_time = new_project.phase_times["TurbineInstallation"] if new_time > baseline: pass else: failed.append(kw) if failed: raise Exception(f"'{failed}' not affecting results.") else: assert True
def test_capex_categories(): project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown _ = project.capex_breakdown_per_kw new_config = deepcopy(complete_project) new_config["install_phases"]["ExportCableInstallation_1"] = 0 new_project = ProjectManager(new_config) new_project.run() new_breakdown = new_project.capex_breakdown assert new_breakdown["Export System"] > baseline["Export System"] assert (new_breakdown["Export System Installation"] > baseline["Export System Installation"])
def test_cash_flow(): project = ProjectManager(complete_project) project.run() _ = project.cash_flow # Can't generate revenue with "incomplete" project but cash flow will still # be reported config = deepcopy(complete_project) _ = config["install_phases"].pop("TurbineInstallation") project = ProjectManager(config) project.run() cash_flow = project.cash_flow assert all(v <= 0 for v in cash_flow.values())
def test_project_costs(): project = ProjectManager(complete_project) baseline = project.project_capex config = deepcopy(complete_project) config["project_parameters"] = {"site_auction_price": 50e6} project = ProjectManager(config) assert project.project_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"site_assessment_cost": 25e6} project = ProjectManager(config) assert project.project_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"construction_plan_cost": 25e6} project = ProjectManager(config) assert project.project_capex != baseline config = deepcopy(complete_project) config["project_parameters"] = {"installation_plan_cost": 25e6} project = ProjectManager(config) assert project.project_capex != baseline
def test_floating_phase_cost_passing(): project = ProjectManager(floating) project.run() assert_almost_equal( project.phases["MooringSystemDesign"].total_cost, project.phases["MooringSystemInstallation"].system_capex, ) assert_almost_equal( project.phases["SemiSubmersibleDesign"].total_cost, project.phases["MooredSubInstallation"].system_capex, ) assert_almost_equal( project.phases["ArraySystemDesign"].total_cost, project.phases["ArrayCableInstallation"].system_capex, ) assert_almost_equal( project.phases["ExportSystemDesign"].total_cost, project.phases["ExportCableInstallation"].system_capex, ) assert_almost_equal( project.phases["OffshoreSubstationDesign"].total_cost, project.phases["OffshoreSubstationInstallation"].system_capex, ) spar = deepcopy(floating) spar["design_phases"].remove("SemiSubmersibleDesign") spar["design_phases"].append("SparDesign") project = ProjectManager(spar) project.run() assert_almost_equal( project.phases["SparDesign"].total_cost, project.phases["MooredSubInstallation"].system_capex, )