import os
import pickle
from copy import deepcopy
from time import perf_counter
from pprint import pprint
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from wombat.core import Simulation
from wombat.core.library import IEA_26, load_yaml
pd.set_option("display.max_rows", 1000)
pd.set_option("display.max_columns", 1000)
%matplotlib inline
tech_salary_annual = 100000
techs = 30
capacity = 400 * 1000 # 400MW -> kW
tech_salary_annual * techs / capacity
7.5
configs = [
"one_mobilization",
"one_mobilization_100pct_reduction",
"two_mobilizations",
"two_mobilizations_100pct_reduction",
"three_mobilizations",
"three_mobilizations_100pct_reduction",
]
columns = deepcopy(configs)
results = {
"availability - time based": [],
"availability - production based": [],
"capacity factor - net": [],
"capacity factor - gross": [],
"power production": [],
"task completion rate": [],
"total annual costs": [],
"technicians": [],
"materials": [],
"vessels": [],
"ctv cost": [],
"hlv cost": [],
"dsv cost": [],
"cab cost": [],
"manual reset": [],
"minor repair": [],
"major repair": [],
"major replacement": [],
"remote reset": [],
"annual service": [],
"bos": [], # substructure inspection + scour repair + substation inspection + small/large transformer repairs
"total downtime": [],
"ctv utilization": [],
"hlv utilization": [],
"dsv utilization": [],
"cab utilization": [],
}
for config in configs:
# Run the simulation
start = perf_counter()
config = load_yaml(os.path.join(str(IEA_26), "config"), f"{config}.yaml")
sim = Simulation.from_inputs(**config)
sim.run()
end = perf_counter()
print(f"{config['name'].rjust(45)} | {(end - start) / 60:.2f} m")
# Gather the results of interest
years = sim.metrics.events.year.unique().shape[0]
mil = 1000000
availability = 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_turbine=False).values[0][0]
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="medium").labor[0]
total = sim.metrics.events[["total_cost"]].sum().sum()
equipment = sim.metrics.equipment_costs(frequency="project", by_equipment=True)
equipment_sum = equipment.sum().sum()
ctv = equipment[[el for el in equipment.columns if "Crew Transfer Vessel" in el]].sum().sum()
hlv = equipment[[el for el in equipment.columns if "Jack-up Vessel" in el]].sum().sum()
dsv = equipment[[el for el in equipment.columns if "Diving Support Vessel" in el]].sum().sum()
cab = equipment[[el for el in equipment.columns if "Cable Laying Vessel" in el]].sum().sum()
times = sim.metrics.process_times()
times = times / years / 24 / 100 # events per turbine and year
utilization = sim.metrics.service_equipment_utilization(frequency="project")
ctv_ur = utilization[[el for el in utilization.columns if "Crew Transfer Vessel" in el]].mean().mean()
hlv_ur = utilization[[el for el in utilization.columns if "Jack-up Vessel" in el]].mean().mean()
dsv_ur = utilization[[el for el in utilization.columns if "Diving Support Vessel" in el]].mean().mean()
cab_ur = utilization[[el for el in utilization.columns if "Cable Laying Vessel" in el]].mean().mean()
# Log the results of interest
results["availability - time based"].append(availability)
results["availability - production based"].append(availability_production)
results["capacity factor - net"].append(cf_net)
results["capacity factor - gross"].append(cf_gross)
results["power production"].append(power_production)
results["task completion rate"].append(completion_rate)
results["total annual costs"].append((total + techs) / mil / years)
results["technicians"].append(techs / mil / years)
results["materials"].append(parts / mil / years)
results["vessels"].append(equipment_sum / mil / years)
results["ctv cost"].append(ctv / mil / years)
results["hlv cost"].append(hlv / mil / years)
results["dsv cost"].append(dsv / mil / years)
results["cab cost"].append(cab / mil / years)
results["manual reset"].append(times.loc[times.index.intersection(["manual reset"]), "downtime"].sum())
results["minor repair"].append(times.loc[times.index.intersection(["minor repair", ]), "downtime"].sum())
results["major repair"].append(times.loc[times.index.intersection(["major repair"]), "downtime"].sum())
results["major replacement"].append(times.loc[times.index.intersection(["major replacement"]), "downtime"].sum())
results["remote reset"].append(times.loc[times.index.intersection(["remote reset"]), "downtime"].sum())
results["annual service"].append(times.loc[times.index.intersection(["annual service"]), "downtime"].sum())
ix = [
"substructure inspection", "substation inspection",
"small foundation/scour repair", "cable replacement",
"small transformer repair", "large transformer repair"
]
results["bos"].append(times.loc[times.index.intersection(ix), "downtime"].sum())
results["total downtime"].append(times.loc[:, "downtime"].sum())
results["ctv utilization"].append(ctv_ur)
results["hlv utilization"].append(hlv_ur)
results["dsv utilization"].append(dsv_ur)
results["cab utilization"].append(cab_ur)
iea_26_one_mobilization | 8.23 m iea_26_one_mobilization_100pct_reduction | 11.13 m iea_26_two_mobilizations | 8.89 m iea_26_two_mobilizations_100pct_reduction | 10.59 m iea_26_three_mobilizations | 9.75 m iea_26_three_mobilizations_100pct_reduction | 12.67 m
# Save the results
# pickled dictionary format
with open(os.path.join(str(IEA_26), "outputs", "results_dict.pkl"), "wb") as f:
pickle.dump(results, f)
# dataframe/csv format
results_df = pd.DataFrame(results.values(), columns=columns, index=results.keys()).fillna(0)
results_df.to_csv(os.path.join(str(IEA_26), "outputs", "results_data.csv"), index_label="result")
pd.options.display.float_format = '{:,.2f}'.format
results_df
one_mobilization | one_mobilization_100pct_reduction | two_mobilizations | two_mobilizations_100pct_reduction | three_mobilizations | three_mobilizations_100pct_reduction | |
---|---|---|---|---|---|---|
availability - time based | 0.66 | 0.74 | 0.84 | 0.82 | 0.95 | 0.91 |
availability - production based | 0.66 | 0.74 | 0.84 | 0.82 | 0.95 | 0.91 |
capacity factor - net | 0.39 | 0.44 | 0.49 | 0.48 | 0.56 | 0.54 |
capacity factor - gross | 0.59 | 0.59 | 0.59 | 0.59 | 0.59 | 0.59 |
power production | 27,389,328,921.00 | 30,735,833,503.50 | 34,598,056,055.00 | 33,863,780,889.50 | 39,287,511,766.00 | 37,670,119,797.00 |
task completion rate | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
total annual costs | 15.27 | 15.22 | 20.99 | 20.83 | 24.78 | 24.46 |
technicians | 3.00 | 3.00 | 3.00 | 3.00 | 3.00 | 3.00 |
materials | 4.08 | 4.03 | 6.13 | 5.98 | 6.90 | 6.55 |
vessels | 8.19 | 8.19 | 11.86 | 11.85 | 14.88 | 14.91 |
ctv cost | 2.56 | 2.56 | 2.56 | 2.56 | 2.56 | 2.56 |
hlv cost | 3.56 | 3.56 | 7.23 | 7.22 | 10.25 | 10.28 |
dsv cost | 0.53 | 0.53 | 0.53 | 0.53 | 0.53 | 0.53 |
cab cost | 1.55 | 1.55 | 1.55 | 1.55 | 1.55 | 1.55 |
manual reset | 0.42 | 4.43 | 0.54 | 5.44 | 0.66 | 7.80 |
minor repair | 0.94 | 2.17 | 1.21 | 2.65 | 1.48 | 3.01 |
major repair | 0.57 | 0.67 | 0.70 | 0.83 | 0.78 | 0.90 |
major replacement | 78.54 | 59.59 | 49.31 | 44.78 | 10.96 | 9.25 |
remote reset | 0.02 | 2.36 | 0.04 | 2.57 | 0.06 | 2.85 |
annual service | 1.98 | 0.00 | 1.63 | 0.00 | 1.84 | 0.00 |
bos | 0.02 | 3.54 | 0.02 | 3.09 | 0.02 | 3.86 |
total downtime | 82.70 | 72.84 | 53.68 | 59.47 | 16.09 | 27.81 |
ctv utilization | 0.68 | 0.35 | 0.74 | 0.40 | 0.88 | 0.46 |
hlv utilization | 1.00 | 0.98 | 1.00 | 0.98 | 0.73 | 0.71 |
dsv utilization | 0.20 | 0.23 | 0.21 | 0.23 | 0.29 | 0.23 |
cab utilization | 0.01 | 0.01 | 0.00 | 0.01 | 0.01 | 0.03 |