Demonstration of the Available Metrics#

Binder

For a complete list of metrics and their documentation, please see the API Metrics documentation.

This demonstration will rely on the results produced in the "How To" notebook and serves as an extension of the API documentation to show what the results will look like depending on what inputs are provided.

A Jupyter notebook of this tutorial can be run from examples/metrics_demonstration.ipynb locally, or through binder.

from pprint import pprint
from functools import partial

import pandas as pd
from pandas.io.formats.style import Styler

from wombat.core import Simulation, Metrics
from wombat.utilities import plot

# Clean up the aesthetics for the pandas outputs
pd.set_option("display.max_rows", 30)
pd.set_option("display.max_columns", 10)
style = partial(
  Styler,
  table_attributes='style="font-size: 14px; grid-column-count: 6"',
  precision=2,
  thousands=",",
)

Table of Contents#

Below is a list of top-level sections to demonstrate how to use WOMBAT's Metrics class methods and an explanation of each individual metric.

If you don't see a metric or result computation that is core to your work, please submit an issue with details on what the metric is, and how it should be computed.

Setup#

The simulations from the How To notebook are going to be rerun as it is not recommended to create a Metrics class from scratch due to the large number of inputs that are required, and the initialization is provided in the simulation API's run method.

To simplify this process, a feature has been added to save the simulation outputs required to generate the Metrics inputs and a method to reload those outputs as inputs.

sim = Simulation("COREWIND", "morro_bay_in_situ.yaml")

# Both of these parameters are True by default for convenience
sim.run(create_metrics=True, save_metrics_inputs=True)

# Load the metrics data
fpath = sim.env.metrics_input_fname.parent
fname = sim.env.metrics_input_fname.name
metrics = Metrics.from_simulation_outputs(fpath, fname)

# Delete the log files now that they're loaded in
sim.env.cleanup_log_files()

# Alternatively, in this case because the simulation was run, we can use the
# following for convenience convenience only
metrics = sim.metrics
Simulation failed at hour 1,348.999932, simulation time: 2002-02-26 05:00:00
/opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/environment.py:507: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  .resample("H")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/service_equipment.py:1600, in ServiceEquipment.in_situ_repair(self, request, time_processed, prior_operation_level, initial)
   1599 # Register the repair
-> 1600 self.register_repair_with_subassembly(
   1601     subassembly, request, starting_operational_level
   1602 )
   1603 action = "maintenance" if isinstance(request.details, Maintenance) else "repair"

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/service_equipment.py:492, in ServiceEquipment.register_repair_with_subassembly(self, subassembly, repair, starting_operating_level)
    489     _ = self.manager.purge_subassembly_requests(
    490         repair.system_id, repair.subassembly_id
    491     )
--> 492     subassembly.recreate_processes()
    493 elif operation_reduction == 1:

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/windfarm/system/subassembly.py:89, in Subassembly.recreate_processes(self)
     85 """If a turbine is being reset after a tow-to-port repair or replacement, then
     86 all processes are assumed to be reset to 0, and not pick back up where they left
     87 off.
     88 """
---> 89 self.processes = dict(self._create_processes())

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/windfarm/system/subassembly.py:71, in Subassembly._create_processes(self)
     70 for maintenance in self.data.maintenance:
---> 71     maintenance._update_event_timing(
     72         self.env.start_datetime, self.env.end_datetime, self.env.max_run_time
     73     )
     75 for failure in self.data.failures:

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/data_classes.py:579, in Maintenance._update_event_timing(self, start, end, max_run_time)
    578 basis = self.frequency_basis.replace("date-", "")
--> 579 diff = relativedelta(**{basis: self.frequency})  # type: ignore
    580 years = end.year - min(self.start_date.year, start.year) + 1

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/dateutil/relativedelta.py:229, in relativedelta.__init__(self, dt1, dt2, years, months, days, leapdays, weeks, hours, minutes, seconds, microseconds, year, month, day, weekday, yearday, nlyearday, hour, minute, second, microsecond)
    227             raise ValueError("invalid year day (%d)" % yday)
--> 229 self._fix()

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/dateutil/relativedelta.py:247, in relativedelta._fix(self)
    246     self.hours += div * s
--> 247 if abs(self.hours) > 23:
    248     s = _sign(self.hours)

TypeError: '>' not supported between instances of 'relativedelta' and 'int'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/service_equipment.py:1571, in ServiceEquipment.in_situ_repair(self, request, time_processed, prior_operation_level, initial)
   1570 if self.settings.non_stop_shift:
-> 1571     yield self.env.process(
   1572         self.in_situ_repair(
   1573             request,
   1574             time_processed=hours_processed + time_processed,
   1575             prior_operation_level=starting_operational_level,
   1576         )
   1577     )
   1578     return

TypeError: '>' not supported between instances of 'relativedelta' and 'int'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/service_equipment.py:1818, in ServiceEquipment.run_unscheduled_in_situ(self)
   1817     yield system.servicing
-> 1818     yield self.env.process(self.in_situ_repair(request, initial=True))
   1820 # Wait for next shift to start

TypeError: '>' not supported between instances of 'relativedelta' and 'int'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/repair_management.py:306, in RepairManager._run_equipment_requests(self, request)
    305 else:
--> 306     yield self.env.process(equipment_obj.run_unscheduled_in_situ())
    308     # Move the dispatched capability to the end of list to ensure proper
    309     # cycling of available servicing equipment

TypeError: '>' not supported between instances of 'relativedelta' and 'int'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
Cell In[2], line 4
      1 sim = Simulation("COREWIND", "morro_bay_in_situ.yaml")
      3 # Both of these parameters are True by default for convenience
----> 4 sim.run(create_metrics=True, save_metrics_inputs=True)
      6 # Load the metrics data
      7 fpath = sim.env.metrics_input_fname.parent

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/simulation_api.py:439, in Simulation.run(self, until, create_metrics, save_metrics_inputs)
    416 def run(
    417     self,
    418     until: int | float | Event | None = None,
    419     create_metrics: bool = True,
    420     save_metrics_inputs: bool = True,
    421 ):
    422     """Calls ``WombatEnvironment.run()`` and gathers the results for
    423     post-processing. See ``wombat.simulation.WombatEnvironment.run`` or
    424     ``simpy.Environment.run`` for more details.
   (...)    437         False, the data will not be saved, by default True.
    438     """
--> 439     self.env.run(until=until)
    440     if save_metrics_inputs:
    441         self.save_metrics_inputs()

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/environment.py:251, in WombatEnvironment.run(self, until)
    246     self._operations_csv.close()
    247     print(
    248         f"Simulation failed at hour {self.now:,.6f},"
    249         f" simulation time: {self.simulation_time}"
    250     )
--> 251     raise e
    253 # Ensure all logged events make it to their target file
    254 self._events_writer.writerows(self._events_buffer)

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/core/environment.py:238, in WombatEnvironment.run(self, until)
    236     until = self.max_run_time
    237 try:
--> 238     super().run(until=until)
    239 except BaseException as e:
    240     # Flush the logs to so the simulation up to the point of failure is logged
    241     self._events_writer.writerows(self._events_buffer)

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/simpy/core.py:246, in Environment.run(self, until)
    244 try:
    245     while True:
--> 246         self.step()
    247 except StopSimulation as exc:
    248     return exc.args[0]  # == until.value

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/simpy/core.py:204, in Environment.step(self)
    202 exc = type(event._value)(*event._value.args)
    203 exc.__cause__ = event._value
--> 204 raise exc

TypeError: '>' not supported between instances of 'relativedelta' and 'int'

Common Parameter Explanations#

Before diving into each and every metric, and how they can be customized, it is worth noting some of the most common parameters used throughout, and their meanings to reduce redundancy. The varying output forms are demonstrated in the availability section below.

frequency#

project

Computed across the whole simulation, with the resulting DataFrame having an empty index.

annual

Summary of each year in the simulation, with the resulting DataFrame having "year" as the index.

monthly

Summary of each month of the year, aggregated across years, with the resulting DataFrame having "month" as the index.

month-year

computed on a month-by-year basis, producing the results for every month of the simulation, with the resulting DataFrame having "year" and "month" as the index.

by#

windfarm

Aggregated across all turbines, with the resulting DataFrame having only "windfarm" as a column

turbine

Computed for each turbine, with the resulting DataFrame having a column for each turbine

Availability#

There are two methods to produce availability, which have their own function calls:

Here, we will go through the various input definitions to get time-based availability data as both methods use the same inputs, and provide outputs in the same format.

Inputs:

  • frequency, as explained above options: "project", "annual", "monthly", and "month-year"

  • by, as explained above options: "windfarm" and "turbine"

Below is a demonstration of the variations on frequency and by for time_based_availability.

style(metrics.time_based_availability(frequency="project", by="windfarm"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 style(metrics.time_based_availability(frequency="project", by="windfarm"))

NameError: name 'metrics' is not defined
style(metrics.production_based_availability(frequency="project", by="windfarm"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 style(metrics.production_based_availability(frequency="project", by="windfarm"))

NameError: name 'metrics' is not defined

Note that in the two above examples, that the values are equal. This is due to the fact that the example simulation does not have any operating reduction applied to failures, unless it's a catastrophic failure, so there is no expected difference.

# Demonstrate the by turbine granularity
style(metrics.time_based_availability(frequency="project", by="turbine"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 2
      1 # Demonstrate the by turbine granularity
----> 2 style(metrics.time_based_availability(frequency="project", by="turbine"))

NameError: name 'metrics' is not defined
# Demonstrate the annualized outputs
style(metrics.time_based_availability(frequency="annual", by="windfarm"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 2
      1 # Demonstrate the annualized outputs
----> 2 style(metrics.time_based_availability(frequency="annual", by="windfarm"))

NameError: name 'metrics' is not defined
# Demonstrate the month aggregations
style(metrics.time_based_availability(frequency="monthly", by="windfarm"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[7], line 2
      1 # Demonstrate the month aggregations
----> 2 style(metrics.time_based_availability(frequency="monthly", by="windfarm"))

NameError: name 'metrics' is not defined
# Demonstrate the granular monthly reporting
style(metrics.time_based_availability(frequency="month-year", by="windfarm"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[8], line 2
      1 # Demonstrate the granular monthly reporting
----> 2 style(metrics.time_based_availability(frequency="month-year", by="windfarm"))

NameError: name 'metrics' is not defined

Plotting Availability#

As of v0.9, the ability to plot the wind farm and turbine availability has been enabled as an experimental feature. Please see the plotting API documentation for more details.

# Demonstrate the granular monthly reporting
plot.plot_farm_availability(sim=sim, which="energy", farm_95_CI=True)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[9], line 2
      1 # Demonstrate the granular monthly reporting
----> 2 plot.plot_farm_availability(sim=sim, which="energy", farm_95_CI=True)

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/wombat/utilities/plot.py:121, in plot_farm_availability(sim, which, individual_turbines, farm_95_CI, figure_kwargs, plot_kwargs, legend_kwargs, tick_fontsize, label_fontsize, return_fig)
     84 """Plots a line chart of the monthly availability at the wind farm level.
     85 
     86 Parameters
   (...)    118     _description_
    119 """
    120 # Get the availability data
--> 121 metrics = sim.metrics
    122 if which == "time":
    123     availability = (
    124         metrics.time_based_availability("project", "windfarm")
    125         .astype(float)
    126         .values[0][0]
    127     )

AttributeError: 'Simulation' object has no attribute 'metrics'

Capacity Factor#

The capacity factor is the ratio of actual (net) or potential (gross) energy production divided by the project's capacity. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.capacity_factor().

Inputs:

  • which

    • "net": net capacity factor, actual production divided by the plant capacity

    • "gross": gross capacity factor, potential production divided by the plant capacity

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by, as explained above, options: "windfarm" and "turbine"

Example Usage:

net_cf = metrics.capacity_factor(which="net", frequency="project", by="windfarm").values[0][0]
gross_cf = metrics.capacity_factor(which="gross", frequency="project", by="windfarm").values[0][0]
print(f"  Net capacity factor: {net_cf:.2%}")
print(f"Gross capacity factor: {gross_cf:.2%}")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[10], line 1
----> 1 net_cf = metrics.capacity_factor(which="net", frequency="project", by="windfarm").values[0][0]
      2 gross_cf = metrics.capacity_factor(which="gross", frequency="project", by="windfarm").values[0][0]
      3 print(f"  Net capacity factor: {net_cf:.2%}")

NameError: name 'metrics' is not defined

Task Completion Rate#

The task completion rate is the ratio of tasks completed aggregated to the desired frequency. It is possible to have a >100% completion rate if all maintenance and failure requests submitted in a time period were completed in addition to those that went unfinished in prior time periods. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.task_completion_rate().

Inputs:

  • which

    • "scheduled": scheduled maintenance only (classified as maintenance tasks in inputs)

    • "unscheduled": unscheduled maintenance only (classified as failure events in inputs)

    • "both": Combined completion rate for all tasks

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

Example Usage:

scheduled = metrics.task_completion_rate(which="scheduled", frequency="project").values[0][0]
unscheduled = metrics.task_completion_rate(which="unscheduled", frequency="project").values[0][0]
combined = metrics.task_completion_rate(which="both", frequency="project").values[0][0]
print(f"  Scheduled Task Completion Rate: {scheduled:.2%}")
print(f"Unscheduled Task Completion Rate: {unscheduled:.2%}")
print(f"    Overall Task Completion Rate: {combined:.2%}")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[11], line 1
----> 1 scheduled = metrics.task_completion_rate(which="scheduled", frequency="project").values[0][0]
      2 unscheduled = metrics.task_completion_rate(which="unscheduled", frequency="project").values[0][0]
      3 combined = metrics.task_completion_rate(which="both", frequency="project").values[0][0]

NameError: name 'metrics' is not defined

Equipment Costs#

Sum of the costs associated with a simulation's servicing equipment, which excludes materials, downtime, etc. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.equipment_costs().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_equipment

    • True: Aggregates all equipment into a single cost

    • False: Computes for each unit of servicing equipment

Example Usage:

# Project total at the whole wind farm level
style(metrics.equipment_costs(frequency="project", by_equipment=False))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[12], line 2
      1 # Project total at the whole wind farm level
----> 2 style(metrics.equipment_costs(frequency="project", by_equipment=False))

NameError: name 'metrics' is not defined
# Project totals at servicing equipment level
style(metrics.equipment_costs(frequency="project", by_equipment=True))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 2
      1 # Project totals at servicing equipment level
----> 2 style(metrics.equipment_costs(frequency="project", by_equipment=True))

NameError: name 'metrics' is not defined

Service Equipment Utilization Rate#

Ratio of days when the servicing equipment is in use (not delayed for a whole day due to either weather or lack of repairs to be completed) to the number of days it's present in the simulation. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.service_equipment_utilization().

Inputs:

  • frequency, as explained above, options: "project" and "annual"

Example Usage:

# Project totals
style(metrics.service_equipment_utilization(frequency="project"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[14], line 2
      1 # Project totals
----> 2 style(metrics.service_equipment_utilization(frequency="project"))

NameError: name 'metrics' is not defined

Vessel-Crew Hours at Sea#

The number of vessel hours or crew hours at sea for offshore wind power plant simulations. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.vessel_crew_hours_at_sea().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_equipment

    • True: Aggregates all equipment into a single cost

    • False: Computes for each unit of servicing equipment

  • vessel_crew_assumption: A dictionary of vessel names (ServiceEquipment.settings.name, but also found at Metrics.service_equipment_names) and the number of crew onboard at any given time. The application of this assumption transforms the results from vessel hours at sea to crew hours at sea.

Example Usage:

# Project total, not broken out by vessel
style(metrics.vessel_crew_hours_at_sea(frequency="project", by_equipment=False))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[15], line 2
      1 # Project total, not broken out by vessel
----> 2 style(metrics.vessel_crew_hours_at_sea(frequency="project", by_equipment=False))

NameError: name 'metrics' is not defined
# Annual project totals, broken out by vessel
style(metrics.vessel_crew_hours_at_sea(frequency="annual", by_equipment=True))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[16], line 2
      1 # Annual project totals, broken out by vessel
----> 2 style(metrics.vessel_crew_hours_at_sea(frequency="annual", by_equipment=True))

NameError: name 'metrics' is not defined

Number of Tows#

The number of tows performed during the simulation. If tow-to-port was not used in the simulation, a DataFrame with a single value of 0 will be returned. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.number_of_tows().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_tug

    • True: Computed for each tugboat (towing vessel)

    • False: Aggregates all the tugboats

  • by_direction

    • True: Computed for each direction a tow was performed (to port or to site)

    • False: Aggregates to the total number of tows

Example Usage:

# Project Total
# NOTE: This example has no towing, so it will return 0
style(metrics.number_of_tows(frequency="project"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[17], line 3
      1 # Project Total
      2 # NOTE: This example has no towing, so it will return 0
----> 3 style(metrics.number_of_tows(frequency="project"))

NameError: name 'metrics' is not defined

Labor Costs#

Sum of all labor costs associated with servicing equipment, excluding the labor defined in the fixed costs, which can be broken out by type. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.labor_costs().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_type

    • True: Computed for each labor type (salary and hourly)

    • False: Aggregates all the labor costs

Example Usage:

# Project total at the whole wind farm level
total = metrics.labor_costs(frequency="project", by_type=False)
print(f"Project total: ${total.values[0][0] / metrics.project_capacity:,.2f}/MW")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[18], line 2
      1 # Project total at the whole wind farm level
----> 2 total = metrics.labor_costs(frequency="project", by_type=False)
      3 print(f"Project total: ${total.values[0][0] / metrics.project_capacity:,.2f}/MW")

NameError: name 'metrics' is not defined
# Project totals for each type of labor
style(metrics.labor_costs(frequency="project", by_type=True))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[19], line 2
      1 # Project totals for each type of labor
----> 2 style(metrics.labor_costs(frequency="project", by_type=True))

NameError: name 'metrics' is not defined

Equipment and Labor Costs#

Sum of all labor and servicing equipment costs, excluding the labor defined in the fixed costs, which can be broken out by each category. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.equipment_labor_cost_breakdown().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_category

    • True: Computed for each unit servicing equipment and labor category

    • False: Aggregated to the sum of all costs

reason definitions:

  • Maintenance: routine maintenance, or events defined as a wombat.core.data_classes.Maintenance

  • Repair: unscheduled maintenance, ranging from inspections to replacements, or events defined as a wombat.core.data_classes.Failure

  • Mobilization: Cost of mobilizing servicing equipment

  • Crew Transfer: Costs incurred while crew are transferring between a turbine or substation and the servicing equipment

  • Site Travel: Costs incurred while transiting to/from the site and while at the site

  • Weather Delay: Any delays caused by unsafe weather conditions

  • No Requests: Equipment and labor is active, but there are no repairs or maintenance tasks to be completed

  • Not in Shift: Any time outside the operating hours of the wind farm (or the servicing equipment's specific operating hours)

Example Usage:

# Project totals
style(metrics.equipment_labor_cost_breakdowns(frequency="project", by_category=False))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[20], line 2
      1 # Project totals
----> 2 style(metrics.equipment_labor_cost_breakdowns(frequency="project", by_category=False))

NameError: name 'metrics' is not defined
# Project totals by each category
style(metrics.equipment_labor_cost_breakdowns(frequency="project", by_category=True))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[21], line 2
      1 # Project totals by each category
----> 2 style(metrics.equipment_labor_cost_breakdowns(frequency="project", by_category=True))

NameError: name 'metrics' is not defined

Emissions#

Emissions (tons or other provided units) of all servicing equipment activity, except overnight waiting periods between shifts. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.emissions().

Inputs:

  • emissions_factors: Dictionary of servicing equipment names and the emissions per hour of the following activities: transit, maneuvering, idle at site, and idle at port, where port is stand-in for wherever the servicing equipment might be based when not at site.

  • maneuvering_factor: The proportion of transit time that can generally be associated with positioning servicing, by default 10%.

  • port_engine_on_factor: The proportion of the idling at port time when the engine is running and producing emissions, by default 25%.

# Create the emissions factors, in tons per hour
emissions_factors = {
    "Crew Transfer Vessel 1": {
        "transit": 4,
        "maneuvering": 3,
        "idle at site": 0.5,
        "idle at port": 0.25,
    },
    "Field Support Vessel": {
        "transit": 6,
        "maneuvering": 4,
        "idle at site": 1,
        "idle at port": 0.5,
    },
    "Heavy Lift Vessel": {
        "transit": 12,
        "maneuvering": 7,
        "idle at site": 1,
        "idle at port": 0.5,
    },
    "Diving Support Vessel": {
        "transit": 4,
        "maneuvering": 7,
        "idle at site": 0.2,
        "idle at port": 0.2,
    },
    "Anchor Handling Vessel": {
        "transit": 4,
        "maneuvering": 3,
        "idle at site": 1,
        "idle at port": 0.25,
    },
}

# Add in CTVs 2 through 7
for i in range(2, 8):
    emissions_factors[f"Crew Transfer Vessel {i}"] = emissions_factors[f"Crew Transfer Vessel 1"]

style(metrics.emissions(emissions_factors=emissions_factors, maneuvering_factor=0.075, port_engine_on_factor=0.20))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[22], line 39
     36 for i in range(2, 8):
     37     emissions_factors[f"Crew Transfer Vessel {i}"] = emissions_factors[f"Crew Transfer Vessel 1"]
---> 39 style(metrics.emissions(emissions_factors=emissions_factors, maneuvering_factor=0.075, port_engine_on_factor=0.20))

NameError: name 'metrics' is not defined

Component Costs#

All the costs associated with maintenance and failure events during the simulation, including delays incurred during the repair process, but excluding costs not directly tied to a repair. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.component_costs().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_category

    • True: Computed across each cost category

    • False: Aggregated to the sum of all categories

  • by_action

    • True: Computed by each of "repair", "maintenance", and "delay", and is included in the MultiIndex

    • False: Aggregated as the sum of all actions

action definitions:

  • maintenance: routine maintenance

  • repair: unscheduled maintenance, ranging from inspections to replacements

  • delay: Any delays caused by unsafe weather conditions or not being able to finish a process within a single shift

Example Usage:

# Project totals by component
style(metrics.component_costs(frequency="project", by_category=False, by_action=False))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[23], line 2
      1 # Project totals by component
----> 2 style(metrics.component_costs(frequency="project", by_category=False, by_action=False))

NameError: name 'metrics' is not defined
# Project totals by each category and action type
style(metrics.component_costs(frequency="project", by_category=True, by_action=True))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[24], line 2
      1 # Project totals by each category and action type
----> 2 style(metrics.component_costs(frequency="project", by_category=True, by_action=True))

NameError: name 'metrics' is not defined

Fixed Cost Impacts#

Computes the total costs of the fixed costs categories. For further documentation, see the definition docs, here: wombat.core.data_classes.FixedCosts, or the API docs here: wombat.core.post_processor.Metrics.fixed_costs().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • resolution (also, demonstrated below)

    • "high": Computed across the most granular cost levels

    • "medium": Computed for each general cost category

    • "low": Aggregated to a single sum of costs

pprint(metrics.fixed_costs.hierarchy)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[25], line 1
----> 1 pprint(metrics.fixed_costs.hierarchy)

NameError: name 'metrics' is not defined

Example Usage:

# Project totals at the highest level
# NOTE: there were no fixed costs defined in this example, so all values will be 0, so
#       this will just be demonstrating the output format
style(metrics.project_fixed_costs(frequency="project", resolution="low"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[26], line 4
      1 # Project totals at the highest level
      2 # NOTE: there were no fixed costs defined in this example, so all values will be 0, so
      3 #       this will just be demonstrating the output format
----> 4 style(metrics.project_fixed_costs(frequency="project", resolution="low"))

NameError: name 'metrics' is not defined
# Project totals at the medium level
style(metrics.project_fixed_costs(frequency="project", resolution="medium"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[27], line 2
      1 # Project totals at the medium level
----> 2 style(metrics.project_fixed_costs(frequency="project", resolution="medium"))

NameError: name 'metrics' is not defined
# Project totals at the lowest level
style(metrics.project_fixed_costs(frequency="project", resolution="high"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[28], line 2
      1 # Project totals at the lowest level
----> 2 style(metrics.project_fixed_costs(frequency="project", resolution="high"))

NameError: name 'metrics' is not defined

OpEx#

Computes the total cost of all operating expenditures for the duration of the simulation, including fixed costs. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.opex().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by_category

    • True shows the port fees, fixed costs, labor costs, equipment costs, and materials costs in addition the total OpEx

    • False shows only the total OpEx

Example Usage:

style(metrics.opex("annual"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[29], line 1
----> 1 style(metrics.opex("annual"))

NameError: name 'metrics' is not defined
style(metrics.opex("annual", by_category=True))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[30], line 1
----> 1 style(metrics.opex("annual", by_category=True))

NameError: name 'metrics' is not defined

Process Times#

Computes the total number of hours spent from repair request submission to completion, performing repairs, and the number of request for each repair category. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.process_times().

Example Usage:

style(metrics.process_times())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[31], line 1
----> 1 style(metrics.process_times())

NameError: name 'metrics' is not defined

Power Production#

Computes the total power production for the wind farm. For further documentation, see the API docs here: wombat.core.post_processor.Metrics.power_production().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • by, as explained above options: "windfarm" and "turbine"

  • units

    • "kwh": kilowatt-hours (kWh)

    • "mwh": megawatt-hours (MWh)

    • "gwh": gigawatt-hours (GWh)

Example Usage:

# Project totals, in kWh, at the wind farm level
style(metrics.power_production(frequency="project", by="windfarm", units="kwh"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[32], line 2
      1 # Project totals, in kWh, at the wind farm level
----> 2 style(metrics.power_production(frequency="project", by="windfarm", units="kwh"))

NameError: name 'metrics' is not defined
# Project totals, in MWh, at the wind farm level
style(metrics.power_production(frequency="project", units="mwh"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[33], line 2
      1 # Project totals, in MWh, at the wind farm level
----> 2 style(metrics.power_production(frequency="project", units="mwh"))

NameError: name 'metrics' is not defined
# Project totals, in GWh, at the wind farm level
style(metrics.power_production(frequency="project"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[34], line 2
      1 # Project totals, in GWh, at the wind farm level
----> 2 style(metrics.power_production(frequency="project"))

NameError: name 'metrics' is not defined

Net Present Value#

Calcualtes the net present value (NPV) for the project, as \(NPV = (Power * OfftakePrice - OpEx) / (1 + DiscountRate)\).

For further documentation, see the API docs here: wombat.core.post_processor.Metrics.npv().

Inputs:

  • frequency, as explained above, options: "project", "annual", "monthly", and "month-year"

  • discount_rate: The rate of return that could be earned on alternative investments, by default 0.025.

  • offtake_price: Price of energy, per MWh, by default 80.

style(metrics.opex("annual"))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[35], line 1
----> 1 style(metrics.opex("annual"))

NameError: name 'metrics' is not defined