示例#1
0
def test_chained_dependencies():

    config_chained = deepcopy(config)
    config_chained["spi_vessel"] = "test_scour_protection_vessel"
    config_chained["scour_protection"] = {"tons_per_substructure": 200}
    config_chained["install_phases"] = {
        "ScourProtectionInstallation": 0,
        "MonopileInstallation": ("ScourProtectionInstallation", 0.1),
        "TurbineInstallation": ("MonopileInstallation", 0.5),
    }

    project = ProjectManager(config_chained)
    project.run_project()

    df = pd.DataFrame(project.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)
示例#2
0
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_project()

    df = pd.DataFrame(project.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
示例#3
0
def test_monthly_revenue():

    project = ProjectManager(complete_project)
    project.run_project()
    _ = project.monthly_revenue

    # Can't generate revenue with "incomplete" project
    config = deepcopy(complete_project)
    _ = config["install_phases"].pop("TurbineInstallation")

    project = ProjectManager(config)
    project.run_project()

    with pytest.raises(ValueError):
        _ = project.monthly_revenue
示例#4
0
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"]
示例#5
0
def test_kwargs_in_ProjectManager():

    base = deepcopy(config_wtiv)
    base["install_phases"] = ["TurbineInstallation"]

    project = ProjectManager(base)
    project.run_project()
    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_project()
        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
示例#6
0
def test_phase_start_dates_with_weather():
    m_start = "03/01/2010"
    t_start = "05/01/2010"

    config_with_start_dates = deepcopy(config)
    config_with_start_dates["install_phases"] = {
        "MonopileInstallation": m_start,
        "TurbineInstallation": t_start,
    }

    project = ProjectManager(config_with_start_dates, weather=weather_df)
    project.run_project()

    df = pd.DataFrame(project.project_actions)
    _fmt = "%m/%d/%Y"
    _target_diff = (datetime.strptime(t_start, _fmt) -
                    datetime.strptime(m_start, _fmt)).days * 24

    _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
示例#7
0
def test_phase_start_dates(m_start, t_start):
    """
    Tests functionality related to passing start dates into 'install_phases' sub-dict.
    """
    config_with_start_dates = deepcopy(config)
    config_with_start_dates["install_phases"] = {
        "MonopileInstallation": m_start,
        "TurbineInstallation": t_start,
    }

    project = ProjectManager(config_with_start_dates)
    project.run_project()

    df = pd.DataFrame(project.project_actions)
    _fmt = "%m/%d/%Y"
    _target_diff = (datetime.strptime(t_start, _fmt) -
                    datetime.strptime(m_start, _fmt)).days * 24

    _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
示例#8
0
def test_cash_flow():

    project = ProjectManager(complete_project)
    project.run_project()
    _ = 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_project()

    cash_flow = project.cash_flow
    assert all(v <= 0 for v in cash_flow.values())
示例#9
0
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
示例#10
0
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
示例#11
0
def test_floating_phase_cost_passing():

    project = ProjectManager(floating)
    project.run_project()

    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_project()

    assert_almost_equal(
        project.phases["SparDesign"].total_cost,
        project.phases["MooredSubInstallation"].system_capex,
    )
示例#12
0
def test_design_phases():

    config_with_design = deepcopy(config)

    # Add MonopileDesign
    config_with_design["design_phases"] = ["MonopileDesign"]

    # Add required parameters
    config_with_design["site"]["mean_windspeed"] = 9
    config_with_design["turbine"]["rotor_diameter"] = 200
    config_with_design["turbine"]["rated_windspeed"] = 10
    config_with_design["monopile_design"] = {}

    # Remove monopile sub dictionary
    _ = config_with_design.pop("monopile")
    project = ProjectManager(config_with_design)
    project.run_project()

    assert isinstance(project.config["monopile"], dict)

    project = ProjectManager(config_with_design)
    project.run_project()
示例#13
0
def test_expected_config_merging():
    """
    Tests for merging of expected configs
    """

    config1 = {
        "site": {
            "distance": "float",
            "depth": "float"
        },
        "plant": {
            "num_turbines": "int"
        },
    }

    config2 = {
        "site": {
            "distance": "float",
            "wave_height": "float"
        },
        "monopile": {
            "diameter": "float"
        },
    }

    config = ProjectManager.merge_dicts(config1, config2)

    assert config == {
        "site": {
            "distance": "float",
            "depth": "float",
            "wave_height": "float",
        },
        "plant": {
            "num_turbines": "int"
        },
        "monopile": {
            "diameter": "float"
        },
    }
示例#14
0
def test_ProjectProgress_with_complete_project():

    project = ProjectManager(complete_project)
    project.run_project()

    _ = project.progress.parse_logs("Substructure")
    _ = project.progress.parse_logs("Turbine")
    _ = project.progress.parse_logs("Array String")
    _ = project.progress.parse_logs("Export System")
    _ = project.progress.parse_logs("Offshore Substation")

    _ = project.progress.complete_export_system
    _ = project.progress.complete_array_strings

    _ = project.progress.energize_points

    new = deepcopy(complete_project)
    new["plant"]["num_turbines"] = 61

    # Uneven strings
    project = ProjectManager(new)
    project.run_project()

    _ = project.progress.energize_points
示例#15
0
def test_kwargs_in_ProjectManager(anchor, key):

    base = deepcopy(config)
    base["mooring_system"]["anchor_type"] = anchor
    base["install_phases"] = ["MooringSystemInstallation"]

    project = ProjectManager(base)
    project.run_project()
    baseline = project.phase_times["MooringSystemInstallation"]

    keywords = ["mooring_system_load_time", "mooring_site_survey_time", key]

    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_project()
        new_time = new_project.phase_times["MooringSystemInstallation"]

        if new_time > baseline:
            pass

        else:
            failed.append(kw)

    if failed:
        raise Exception(f"'{failed}' not affecting results.")

    else:
        assert True
示例#16
0
def test_kwargs_in_ProjectManager():

    base = deepcopy(config)
    base["install_phases"] = ["ScourProtectionInstallation"]

    project = ProjectManager(base)
    project.run()
    baseline = project.phase_times["ScourProtectionInstallation"]

    keywords = ["drop_rocks_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["ScourProtectionInstallation"]

        if new_time > baseline:
            pass

        else:
            failed.append(kw)

    if failed:
        raise Exception(f"'{failed}' not affecting results.")

    else:
        assert True
示例#17
0
def test_phase_specific_definitions():
    """
    Tests that phase specific information makes it to phase_config.
    """

    project = ProjectManager(config)

    phase_config = project.create_config_for_phase("MonopileInstallation")

    assert phase_config["wtiv"]["name"] == "Phase Specific WTIV"
    assert phase_config["site"]["distance"] == 500

    phase_config = project.create_config_for_phase("TurbineInstallation")

    assert phase_config["wtiv"]["name"] == "Example WTIV"
    assert phase_config["site"]["distance"] == 50

    project.run_project()
示例#18
0
def test_npv():

    project = ProjectManager(complete_project)
    project.run_project()
    baseline = project.npv

    config = deepcopy(complete_project)
    config["ncf"] = 0.35
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["offtake_price"] = 70
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["project_lifetime"] = 30
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["discount_rate"] = 0.03
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["opex_rate"] = 120
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline
示例#19
0
def test_npv():

    project = ProjectManager(complete_project)
    project.run_project()
    baseline = project.npv

    config = deepcopy(complete_project)
    config["project_parameters"] = {"ncf": 0.35}
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["project_parameters"] = {"offtake_price": 70}
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["project_parameters"] = {"project_lifetime": 30}
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["project_parameters"] = {"discount_rate": 0.03}
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline

    config = deepcopy(complete_project)
    config["project_parameters"] = {"opex_rate": 120}
    project = ProjectManager(config)
    project.run_project()
    assert project.npv != baseline
def test_orbit_version_ProjectManager():

    config = ProjectManager.compile_input_dict(
        ["MonopileDesign", "MonopileInstallation"])
    assert "orbit_version" in config.keys()
示例#21
0
def test_kwargs_for_export_install_in_ProjectManager():

    new_export_system = {
        "cable": {
            "linear_density": 50.0,
            "sections": [1000],
            "number": 1
        },
        "system_cost": 200e6,
    }
    new_site = {"distance": 50, "depth": 20}
    base = deepcopy(base_config)
    base["export_system"] = new_export_system
    base["site"] = new_site
    base["install_phases"] = ["ExportCableInstallation"]

    project = ProjectManager(base)
    project.run_project()
    baseline = project.phase_times["ExportCableInstallation"]

    keywords = [
        "onshore_construction_time",
        "cable_load_time",
        "site_position_time",
        "cable_prep_time",
        "cable_lower_time",
        "cable_pull_in_time",
        "cable_termination_time",
        "cable_splice_time",
        "tow_plow_speed",
        "pull_winch_speed",
        "cable_raise_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_project()
        new_time = new_project.phase_times["ExportCableInstallation"]

        if new_time > baseline:
            pass

        else:
            failed.append(kw)

    if failed:
        raise Exception(f"ExpInstall: '{failed}' not affecting results.")

    else:
        assert True
示例#22
0
def test_resolve_project_capacity():

    # Missing turbine rating
    config1 = {"plant": {"capacity": 600, "num_turbines": 40}}

    out1 = ProjectManager.resolve_project_capacity(config1)
    assert out1["plant"]["capacity"] == config1["plant"]["capacity"]
    assert out1["plant"]["num_turbines"] == config1["plant"]["num_turbines"]
    assert out1["turbine"]["turbine_rating"] == 15

    # Missing plant capacity
    config2 = {
        "plant": {
            "num_turbines": 40
        },
        "turbine": {
            "turbine_rating": 15
        },
    }

    out2 = ProjectManager.resolve_project_capacity(config2)
    assert out2["plant"]["capacity"] == 600
    assert out2["plant"]["num_turbines"] == config2["plant"]["num_turbines"]
    assert out2["turbine"]["turbine_rating"] == config2["turbine"][
        "turbine_rating"]

    # Missing number of turbines
    config3 = {"plant": {"capacity": 600}, "turbine": {"turbine_rating": 15}}

    out3 = ProjectManager.resolve_project_capacity(config3)
    assert out3["plant"]["capacity"] == config3["plant"]["capacity"]
    assert out3["plant"]["num_turbines"] == 40
    assert out3["turbine"]["turbine_rating"] == config3["turbine"][
        "turbine_rating"]

    # Test for float precision
    config4 = {
        "plant": {
            "capacity": 600,
            "num_turbines": 40
        },
        "turbine": {
            "turbine_rating": 15.0
        },
    }

    out4 = ProjectManager.resolve_project_capacity(config4)
    assert out4["plant"]["capacity"] == config4["plant"]["capacity"]
    assert out4["plant"]["num_turbines"] == config4["plant"]["num_turbines"]
    assert out4["turbine"]["turbine_rating"] == config4["turbine"][
        "turbine_rating"]

    # Non matching calculated value
    config5 = {
        "plant": {
            "capacity": 700,
            "num_turbines": 40
        },
        "turbine": {
            "turbine_rating": 15.0
        },
    }

    with pytest.raises(AttributeError):
        _ = ProjectManager.resolve_project_capacity(config5)

    # Test for not enough information
    config6 = {"plant": {"capacity": 600}}

    out6 = ProjectManager.resolve_project_capacity(config6)
    assert out6["plant"]["capacity"] == config6["plant"]["capacity"]

    with pytest.raises(KeyError):
        _ = out6["turbine"]["turbine_rating"]

    with pytest.raises(KeyError):
        _ = out6["plant"]["num_turbines"]
示例#23
0
def test_exceptions():

    incomplete_config = deepcopy(config)
    _ = incomplete_config["site"].pop("depth")

    with pytest.raises(MissingInputs):
        project = ProjectManager(incomplete_config)
        project.run_project()

    wrong_phases = deepcopy(config)
    wrong_phases["install_phases"].append("IncorrectPhaseName")

    with pytest.raises(PhaseNotFound):
        project = ProjectManager(wrong_phases)
        project.run_project()

    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_project()