Servicing Strategies#

In this example, we'll demonstrate the essential differences in scheduled servicing, unscheduled servicing, and tow-to-port repair strategies. Each of the examples demonstrated below will be based on the 2015 Dinwoodie, et al. paper, though the variations will be for demonstration purposes only.

WOMBAT Setup and Variables#

The vessels that will be changed in this demonstration are the field support vessel (FSV) with capability: "SCN", the heavy lift vessel (HLV) with capability: "LCN", and the tugboats, which have capability: "TOW".

Note

When running tow-to-port a Port configuration is also required, which will control the tugboats. However, the port costs will still be accounted for in the FixedCosts class as port fees are assumed to be constant. These costs are not considered in this example, so differences in cost should be taken with a grain of salt given the reduction of HLV and FSV operational and mobilization costs.

Scenario descriptions:

  • Scheduled: exactly the same as the base case (fsv_scheduled.yaml and hlv_scheduled.yaml)

  • Unscheduled: requests: the FSV and HLV are called to site when 10 requests that they can service are logged (fsv_requests.yaml and hlv_requests.yaml)

  • Unscheduled: downtime: the FSV and HLV are called to site once the wind farm's operating level hits 90% or lower (fsv_downtime.yaml and hlv_downtime.yaml)

  • Unscheduled: tow-to-port: the FSV and HLV will be replaced with three identical tugboats (tugboat1.yaml, tugboat2.yaml, tugboat3.yaml), and all the failures associated with the FSV and HLV will be changed to capability "TOW" to trigger the tow-to-port repairs. These processes will be triggered on the first request (WOMBAT base assumption that can't be changed for now).

In this example, we will demonstrate how the results for the base case for the Dinwoodie, et al. example vary based on how each of the vessels are scheduled. The configuration details all remain the same, regardless of details, except for the strategy information, which is defined as follows:

This example is set up similarly to that of the validation cases to show how the results differ, and not a step-by-step guide for setting up the analyses. We refer the reader to the extensive documentation and How To example for more information.

Imports and notebook configuration#

from copy import deepcopy
from time import perf_counter

import pandas as pd

from wombat.core import Simulation
from wombat.core.library import DINWOODIE

pd.set_option("display.max_rows", 1000)
pd.set_option("display.max_columns", 1000)
pd.options.display.float_format = '{:,.2f}'.format

Simulation and results setup#

Here we're providing the names of the configuration files (found at: dinwoodie / config) without their .yaml extensions (added in later) and the results that we want to compare between simulations to understand some of the timing and cost trade-offs between simulations.

The dictionary of keys and lists will be used to create the results data frame where the keys will be the indices and the lists will be the row values for each of the above configurations.

configs = [
    "base_scheduled",
    "base_requests",
    "base_downtime",
    "base_tow_to_port",
]

columns = deepcopy(configs) # Create a unique copy of the config names for column naming
results = {
    "availability - time based": [],
    "availability - production based": [],
    "capacity factor - net": [],
    "capacity factor - gross": [],
    "power production": [],
    "task completion rate": [],
    "annual direct O&M cost": [],
    "annual vessel cost": [],
    "ctv cost": [],
    "fsv cost": [],
    "hlv cost": [],
    "tow cost": [],
    "annual repair cost": [],
    "annual technician cost": [],
    "ctv utilization": [],
    "fsv utilization": [],
    "hlv utilization": [],
    "tow utilization": [],
}

Run the simulations and display the results#

timing_df = pd.DataFrame([], columns=["Load Time (min)", "Run Time (min)"], index=configs)
timing_df.index.name = "Scenario"

for config in configs:

    # Load the simulation
    start = perf_counter()
    sim = Simulation(DINWOODIE , f"{config}.yaml")
    end = perf_counter()
    timing_df.loc[config, "Load Time (min)"] = (end - start) / 60

    # Run the simulation
    start = perf_counter()
    sim.run()
    end = perf_counter()
    timing_df.loc[config, "Run Time (min)"] = (end - start) / 60

    # Gather the results of interest
    years = sim.metrics.events.year.unique().shape[0]
    mil = 1000000

    # Gather the high-level results for the simulation
    availability_time = sim.metrics.time_based_availability(frequency="project", by="windfarm")
    availability_production = sim.metrics.production_based_availability(frequency="project", by="windfarm")
    cf_net = sim.metrics.capacity_factor(which="net", frequency="project", by="windfarm")
    cf_gross = sim.metrics.capacity_factor(which="gross", frequency="project", by="windfarm")
    power_production = sim.metrics.power_production(frequency="project", by="windfarm")
    completion_rate = sim.metrics.task_completion_rate(which="both", frequency="project")
    parts = sim.metrics.events[["materials_cost"]].sum().sum()
    techs = sim.metrics.project_fixed_costs(frequency="project", resolution="low").operations[0]
    total = sim.metrics.events[["total_cost"]].sum().sum()

    # Gather the equipment costs and separate the results by equipment type
    equipment = sim.metrics.equipment_costs(frequency="project", by_equipment=True)
    equipment_sum = equipment.sum().sum()
    hlv = equipment[[el for el in equipment.columns if "Heavy Lift Vessel" in el]].sum().sum()
    fsv = equipment[[el for el in equipment.columns if "Field Support Vessel" in el]].sum().sum()
    ctv = equipment[[el for el in equipment.columns if "Crew Transfer Vessel" in el]].sum().sum()
    tow = equipment[[el for el in equipment.columns if "Tugboat" in el]].sum().sum()

    # Gather the equipment utilization data frame and separate the results by equipment type
    utilization = sim.metrics.service_equipment_utilization(frequency="project")
    hlv_ur = utilization[[el for el in utilization.columns if "Heavy Lift Vessel" in el]].mean().mean()
    fsv_ur = utilization[[el for el in utilization.columns if "Field Support Vessel" in el]].mean().mean()
    ctv_ur = utilization[[el for el in utilization.columns if "Crew Transfer Vessel" in el]].mean().mean()
    tow_ur = utilization[[el for el in utilization.columns if "Tugboat" in el]].mean().mean()

    # Log the results of interest
    results["availability - time based"].append(availability_time.values[0][0])
    results["availability - production based"].append(availability_production.values[0][0])
    results["capacity factor - net"].append(cf_net.values[0][0])
    results["capacity factor - gross"].append(cf_gross.values[0][0])
    results["power production"].append(power_production.values[0][0])
    results["task completion rate"].append(completion_rate.values[0][0])
    results["annual direct O&M cost"].append((total + techs) / mil / years)
    results["annual vessel cost"].append(equipment_sum / mil / years)
    results["ctv cost"].append(ctv / mil / years)
    results["fsv cost"].append(fsv / mil / years)
    results["hlv cost"].append(hlv / mil / years)
    results["tow cost"].append(tow / mil / years)
    results["annual repair cost"].append(parts / mil / years)
    results["annual technician cost"].append(techs / mil / years)
    results["ctv utilization"].append(ctv_ur)
    results["fsv utilization"].append(fsv_ur)
    results["hlv utilization"].append(hlv_ur)
    results["tow utilization"].append(tow_ur)

    # Clear the logs
    sim.env.cleanup_log_files()

timing_df
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/environment.py:503: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  .resample("H")
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/post_processor.py:731: FutureWarning: <class 'pandas.core.arrays.string_.StringArray'>._reduce will require a `keepdims` parameter in the future
  costs = costs.fillna(costs.max(axis=0)).T
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/environment.py:503: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  .resample("H")
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/post_processor.py:731: FutureWarning: <class 'pandas.core.arrays.string_.StringArray'>._reduce will require a `keepdims` parameter in the future
  costs = costs.fillna(costs.max(axis=0)).T
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/environment.py:503: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  .resample("H")
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/post_processor.py:731: FutureWarning: <class 'pandas.core.arrays.string_.StringArray'>._reduce will require a `keepdims` parameter in the future
  costs = costs.fillna(costs.max(axis=0)).T
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/environment.py:503: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  .resample("H")
/opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/wombat/core/post_processor.py:731: FutureWarning: <class 'pandas.core.arrays.string_.StringArray'>._reduce will require a `keepdims` parameter in the future
  costs = costs.fillna(costs.max(axis=0)).T
Load Time (min) Run Time (min)
Scenario
base_scheduled 0.04 0.93
base_requests 0.04 0.94
base_downtime 0.05 0.85
base_tow_to_port 0.04 0.99
results_df = pd.DataFrame(results.values(), columns=columns, index=results.keys()).fillna(0)
results_df
base_scheduled base_requests base_downtime base_tow_to_port
availability - time based 0.97 0.97 0.97 0.96
availability - production based 0.97 0.97 0.97 0.96
capacity factor - net 0.46 0.46 0.46 0.46
capacity factor - gross 0.48 0.48 0.48 0.48
power production 9,681.59 9,688.53 9,739.35 9,651.99
task completion rate 0.98 0.98 0.99 0.96
annual direct O&M cost 18.63 15.45 5.42 10.91
annual vessel cost 12.73 9.41 1.92 2.06
ctv cost 1.92 1.92 1.92 1.92
fsv cost 0.27 0.32 0.00 0.00
hlv cost 10.54 7.17 0.00 0.00
tow cost 0.00 0.00 0.00 0.14
annual repair cost 4.30 4.44 1.91 5.25
annual technician cost 1.60 1.60 1.60 1.60
ctv utilization 1.00 1.00 1.00 1.00
fsv utilization 1.00 0.93 0.00 0.00
hlv utilization 0.96 0.93 0.00 0.00
tow utilization 0.00 0.00 0.00 0.83