Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Replace the below example with any added or modified files, and briefly describe

## Additional supporting information

<!--Fil out at least the versions listed below and those of any packages that may be related.-->
<!--Fill out at least the versions listed below and those of any packages that may be related.-->
Python version: 3.x
WOMBAT version (`wombat.__version__`): 0.x

Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CHANGELOG

## Unreleased
## v0.13 - 23 December 2025

### Default Data Now Available

Expand All @@ -9,6 +9,9 @@
- `"default"` library is now made available with a validated fixed and floating offshore wind reference
case based on the 2025 Cost of Wind Energy Review (COWER), and an experimental land-based
reference data set based on a variety of incomplete sources in onshore O&M studies.
- A new example
([examples/default_data_demonstration.ipynb](https://github.com/WISDEM/WOMBAT/blob/develop/examples/default_data_demonstration.ipynb))
is available to see key statistics of each scenario.
- A new example
([examples/COWER_om_workflow.ipynb](https://github.com/WISDEM/WOMBAT/blob/develop/examples/COWER_om_workflow.ipynb))
is available to reproduce the current year's offshore COWER results.
Expand Down
28 changes: 13 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ distributed, land-based, and offshore windfarms using a discrete event simultaio
framework.

WOMBAT is written around the [`SimPy`](https://gitlab.com/team-simpy/simpy) discrete
event simulation framework. Additionally, this is supported using a flexible and modular
event simulation framework. Additionally, this is supported using a flexible
object-oriented code base, which enables the modeling of arbitrarily large (or small)
windfarms with as many or as few failure and maintenance tasks that can be encoded.

Please note that this is still heavily under development, so you may find some functionality
Please note that this is still under development, so you may find some functionality
to be incomplete at the current moment, but rest assured the functionality is expanding.
With that said, it would be greatly appreciated for issues or PRs to be submitted for
any improvements at all, from fixing typos (guaranteed to be a few) to features to
Expand Down Expand Up @@ -66,12 +66,11 @@ folder, but here are a few highlights:
`validation exercise <https://github.com/WISDEM/WOMBAT/blob/main/examples/iea_26_validation.ipynb>`_.
* Presentations: `slides <https://github.com/WISDEM/WOMBAT/blob/main/presentation_material/>`_.


## Setup

### Requirements

* Python 3.11 through 3.13. Python 3.14 will be compatible once PyArrow 22.0 is released.
* Python 3.11+

### Environment Setup

Expand Down Expand Up @@ -117,10 +116,7 @@ Install it directly into an activated virtual environment:

```console
git clone https://github.com/WISDEM/WOMBAT.git
cd wombat
python setup.py install

# Alternatively:
cd WOMBAT
pip install .
```

Expand Down Expand Up @@ -187,16 +183,16 @@ Basic pre-commit issues that users might encounter and their remedies:

```console
git clone https://github.com/WISDEM/WOMBAT.git
cd wombat
cd WOMBAT
pip install -e '.[docs]'
```

Build the site

> **Note**
> You may want to change the "execute_notebooks" parameter in the `docs/_config.yaml`
> file to "off" unless you're updating the coded examples, or they will be run every
> time you build the site.
> file to "off" unless you're updating the coded examples, or they will run every time
> there is an update to the base files.

```console
jupyter-book build docs
Expand All @@ -216,11 +212,11 @@ pip install -e '.[all]'

Standard dependencies:

* attrs>=21
* attrs>=24.1
* numpy>=1.21
* scipy>=1.8
* pandas>=2
* polars>=0.17
* polars>=1.33.1
* pyarrow>=10
* jupyterlab>=3
* simpy>=4.0.1
Expand All @@ -232,20 +228,22 @@ Standard dependencies:
* types-typed-ast>=1.5
* types-PyYAML>=6
* types-python-dateutil>=2.8
* python-dateutil
* "polars-lts-cpu; sys_platform == 'darwin'",

Optional "dev" dependencies:

* pre-commit>=2.20
* isort>=5.10
* pytest>=7
* pytest-cov>=4
* mypy==0.991
* mypy
* ruff>=0.2
* pyupgrade

Optional "docs" dependencies:

* jupyter-book>=0.15
* jupyter-book>1,<2
* myst-nb>=0.16
* myst-parser>=0.17
* linkify-it-py>=2
Expand Down
8 changes: 1 addition & 7 deletions docs/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exclude_patterns: [_build, Thumbs.db, .DS_Store, "**.ipynb_checkpoints"]
# Force re-execution of notebooks on each build.
# See https://jupyterbook.org/content/execute.html
execute:
execute_notebooks: off
execute_notebooks: auto
timeout: -1
allow_errors: true
exclude_patterns:
Expand Down Expand Up @@ -97,12 +97,6 @@ sphinx:
icon: "https://img.shields.io/pypi/v/WOMBAT",
type: url,
},
{
name: PyPI downloads,
url: "https://pypi.org/project/WOMBAT/",
icon: "https://img.shields.io/pypi/dm/WOMBAT",
type: url,
},
{
name: Launch Binder,
url: "https://mybinder.org/v2/gh/WISDEM/WOMBAT/main?filepath=examples",
Expand Down
1 change: 1 addition & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ parts:
- file: examples/how_to
- file: examples/strategy_demonstration
- file: examples/metrics_demonstration
- file: examples/default_data_demonstration
- file: examples/examples_reference
- file: API/index
sections:
Expand Down
198 changes: 198 additions & 0 deletions docs/examples/default_data_demonstration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
jupytext:
formats: md:myst
text_representation:
extension: .md
format_name: myst
kernelspec:
display_name: Python 3
language: python
name: python3
---

# Default Data Demonstration

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/WISDEM/WOMBAT/main?filepath=examples)

In this example, we'll show what each of the reference plants look like and what results they yield when simulated.

```{important}
The land-based data are expiremental, and should only be used as a starting point for
developing a more robust simulation. Please see the
[default data section of the user guide for further details](index.md#default-data)
```

## Imports

```{code-cell} ipython3
from time import perf_counter

import numpy as np
import pandas as pd

from wombat import Simulation
from wombat.utilities import plot
from wombat.core.library import DEFAULT_DATA

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

## Initialize the simulations

```{code-cell} ipython3
SEED = 48

lbw_sim = Simulation(DEFAULT_DATA, "base_lbw.yaml", random_seed=SEED)
osw_fixed_sim = Simulation(DEFAULT_DATA, "base_osw_fixed.yaml", random_seed=SEED)
osw_floating_sim = Simulation(DEFAULT_DATA, "base_osw_floating.yaml", random_seed=SEED)
```

### View the farms

Using the plotting library, we can observe the layout for each of the farms

```{code-cell} ipython3
print(f"N turbines: {len(lbw_sim.windfarm.turbine_id)}, N substations: {len(lbw_sim.windfarm.substation_id)}")
plot.plot_farm_layout(lbw_sim.windfarm)
```

```{code-cell} ipython3
print(f"N turbines: {len(osw_fixed_sim.windfarm.turbine_id)}, N substations: {len(osw_fixed_sim.windfarm.substation_id)}")
plot.plot_farm_layout(osw_fixed_sim.windfarm)
```

```{code-cell} ipython3
print(f"N turbines: {len(osw_floating_sim.windfarm.turbine_id)}, N substations: {len(osw_floating_sim.windfarm.substation_id)}")
plot.plot_farm_layout(osw_floating_sim.windfarm)
```

## Run the simulations

Now we can run all three simulations, delete the simulation log files, and view the run time for
each simulation.

```{code-cell} ipython3
start = perf_counter()
lbw_sim.run(delete_logs=True, save_metrics_inputs=False)
run_time = perf_counter() - start
print(f"Run time: {run_time // 60} minutes {run_time % 60:.1f} seconds")

start = perf_counter()
osw_fixed_sim.run(delete_logs=True, save_metrics_inputs=False)
run_time = perf_counter() - start
print(f"Run time: {run_time // 60} minutes {run_time % 60:.1f} seconds")

start = perf_counter()
osw_floating_sim.run(delete_logs=True, save_metrics_inputs=False)
run_time = perf_counter() - start
print(f"Run time: {run_time // 60} minutes {run_time % 60:.1f} seconds")
```

### Gather the results

First we will simplify the process of getting results, ensure that all simulations are
20 years, and gather the capacities.

```{code-cell} ipython3
metrics_lbw = lbw_sim.metrics
metrics_osw_fixed = osw_fixed_sim.metrics
metrics_osw_floating = osw_floating_sim.metrics

years_check = (
lbw_sim.env.simulation_years,
osw_fixed_sim.env.simulation_years,
osw_floating_sim.env.simulation_years
)
print(f"All are 20 years: {all(x == 20 for x in years_check)}")
years = 20

capacities = [ # MW
metrics_lbw.project_capacity,
metrics_osw_fixed.project_capacity,
metrics_osw_floating.project_capacity,
]

columns = ["Metric", "Units", "Land-Based", "OSW-Fixed", "OSW-Floating"]
sort_order = [
"Project Capacity",
"Production Based Availability",
"Total OpEx",
"Materials",
"Direct Labor",
"Port Fees",
"Fixed Costs (operations, indirect labor, etc.)",
"Service Equipment",
"Truck 1",
"Truck 2",
"Truck 3",
"Crawler Crane - 1350 tonnes",
"Crew Transfer Vessel 1",
"Crew Transfer Vessel 2",
"Crew Transfer Vessel 3",
"Cable Laying Vessel",
"Diving Support Vessel",
"Heavy Lift Vessel",
"Anchor Handling Tug",
"Tugboat 1",
"Tugboat 2",
]
```

Now, we can gather some of the high level availability and cost statistics for each
of the base scenarios.

```{code-cell} ipython3
capacity = pd.DataFrame([["Project Capacity", "MW"] + capacities], columns=columns).set_index(["Metric", "Units"])

availability = [
"Production Based Availability",
"%",
metrics_lbw.production_based_availability("project", "windfarm").squeeze() * 100,
metrics_osw_fixed.production_based_availability("project", "windfarm").squeeze() * 100,
metrics_osw_floating.production_based_availability("project", "windfarm").squeeze() * 100,
]
availability = pd.DataFrame([availability], columns=columns).set_index(["Metric", "Units"])
```

```{code-cell} ipython3
opex = (
metrics_lbw.opex("project", "windfarm").rename({0: "Land-Based"}).T
.join(metrics_osw_fixed.opex("project", "windfarm").rename({0: "OSW-Fixed"}).T)
.join(metrics_osw_floating.opex("project", "windfarm").rename({0: "OSW-Floating"}).T)
/ years
/ (np.array(capacities) * 1000)
)
opex.index = [
"Fixed Costs (operations, indirect labor, etc.)",
"Port Fees",
"Service Equipment",
"Direct Labor",
"Materials",
"Total OpEx"
]
opex["Units"] = "$/kw/yr"
opex = opex.set_index("Units", append=True).iloc[::-1]
```

```{code-cell} ipython3
equipment = (
metrics_lbw.equipment_costs("project", by_equipment=True).rename({0: "Land-Based"}).T
.join(metrics_osw_fixed.equipment_costs("project", by_equipment=True).rename({0: "OSW-Fixed"}).T, how="outer")
.join(metrics_osw_floating.equipment_costs("project", by_equipment=True).rename({0: "OSW-Floating"}).T, how="outer")
.fillna(0.0)
/ years
/ (np.array(capacities) * 1000)
)
equipment["Units"] = "$/kw/yr"
equipment = equipment.set_index("Units", append=True)
```

With each of the core costs gathered, we can combine them into a single DataFrame and
view them.

```{code-cell} ipython3
results = pd.concat([capacity, availability, opex, equipment]).loc[sort_order]
results
```
6 changes: 6 additions & 0 deletions docs/examples/examples_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ This is a Jupyter Notebook version of the
[*Strategy Demonstration* section](./strategy_demonstration.md) of the documentation
that allows users to interact with the walk through.

### `default_data_demonstration.ipynb`

This is a Jupyter Notebook version of the
[*Default Data Demonstration* section](./default_data_demonstration.md) of the documentation
that allows users to interact with the examples.

### `metrics_demonstration.ipynb`

This is a Jupyter Notebook version of the
Expand Down
3 changes: 2 additions & 1 deletion docs/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ offshore wind data sets, respectively. See the `examples/COWER_om_workflow.ipnyb

The default library provides a validated, ready-to-use data set for fixed and floating offshore wind,
and an experimental land-based data set. For all three, users can use the pre-configured base models
or use them as a starting point for building custom models.
or use them as a starting point for building custom models. Example results can be seen in
`examples/default_data_demonstration.ipynb` or [online](default_data_demonstration.md)

### Overview

Expand Down
Loading