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
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,22 @@
directly into the documentation site.
- The `save_config` function is now compatible with the `ProjectManager.config` object, allowing
for direct saving without user modification.
- Fixes a bug in `CustomArraySystemDesign.create_project_csv()` where the output file location does
not adjust to the user's `folder` input.
- Adds a contributor's guide to clearly delineate how to install and use the various developer's
tools.
- Modernize and streamline the installation instructions.
- Converts all the materials found in `examples/` to either tutorials or topical guides in the
documentation.
- Adds a documentation build shell script to help automatically clean existing documentation site
materials, build the documentation, copy over the output example Jupyter Notebooks to `examples/`,
and run the pre-commit workflow for basic file handling.
- Places the ORBIT tech report citation more prominently throughout the repository and documentation.

### Bug Fixes

- Fixes a bug in `CustomArraySystemDesign.create_project_csv()` where the output file location does
not adjust to the user's `folder` input.
- Corrects the `ProjectManager.overnight_capex` to reflect the definition provided in the ATB as all
capital costs excluding construction financing and grid connection costs.

### Deprecations

Expand Down
10 changes: 10 additions & 0 deletions CITATION.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@techreport{orbit_tech_report,
author={Nunemaker, Jacob and Shields, Matthew and Hammond, Robert and Duffy, Patrick},
title={ORBIT: Offshore Renewables Balance-of-System and Installation Tool},
institution={National Renewable Energy Laboratory (NREL), Golden, CO (United States)},
doi={10.2172/1660132},
url={https://www.osti.gov/biblio/1660132},
place={United States},
year={2020},
month={08}
}
6 changes: 4 additions & 2 deletions ORBIT/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1598,9 +1598,11 @@ def onshore_substation_capex_per_kw(self):

@property
def overnight_capex(self):
"""Returns the overnight capital cost of the project."""
"""Returns the overnight capital cost of the project, which is all
capital costs excluding grid connection and construction financing.
"""

return self.system_capex + self.turbine_capex
return self.total_capex - self.construction_financing_capex()

@property
def soft_capex(self):
Expand Down
12 changes: 4 additions & 8 deletions ORBIT/phases/install/install_phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,10 @@ def setup_simulation(self):
def initialize_port(self):
"""Initializes a Port object with N number of cranes."""

self.port = Port(self.env)

try:
cranes = self.config["port"]["num_cranes"]
self.port.crane = simpy.Resource(self.env, cranes)

except KeyError:
self.port.crane = simpy.Resource(self.env, 1)
port_config = self.config.get("port", {})
cranes = port_config.get("num_cranes", 1)
self.port = Port(self.env, **port_config)
self.port.crane = simpy.Resource(self.env, cranes)

def run(self, until=None):
"""
Expand Down
2 changes: 0 additions & 2 deletions ORBIT/phases/install/jacket_install/standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ class JacketInstallation(InstallPhase):
"enabled": "(optional, default: False)",
"substructure_delivery_time": "h (optional, default: 168)",
"num_substructures_delivered": "int (optional: default: 1)",
"substructure_storage": "int (optional, default: inf)",
},
}

Expand Down Expand Up @@ -137,7 +136,6 @@ def initialize_substructure_delivery(self):
delivery_time = self.supply_chain.get(
"substructure_delivery_time", 168
)
# storage = self.supply_chain.get("substructure_storage", "inf")
supply_chain = SubstructureDelivery(
"Jacket",
self.num_jackets,
Expand Down
2 changes: 0 additions & 2 deletions ORBIT/phases/install/monopile_install/standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ class MonopileInstallation(InstallPhase):
"enabled": "(optional, default: False)",
"substructure_delivery_time": "h (optional, default: 168)",
"num_substructures_delivered": "int (optional: default: 1)",
"substructure_storage": "int (optional, default: inf)",
},
}

Expand Down Expand Up @@ -121,7 +120,6 @@ def initialize_substructure_delivery(self):
delivery_time = self.supply_chain.get(
"substructure_delivery_time", 168
)
# storage = self.supply_chain.get("substructure_storage", "inf")
supply_chain = SubstructureDelivery(
"Monopile",
self.num_monopiles,
Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Offshore Renewables Balance of system and Installation Tool
[![PyPI downloads](https://img.shields.io/pypi/dm/orbit-nrel?link=https%3A%2F%2Fpypi.org%2Fproject%2Forbit-nrel%2F)](https://pypi.org/project/orbit-nrel/)
[![Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![image](https://img.shields.io/pypi/pyversions/orbit-nrel.svg)](https://pypi.python.org/pypi/orbit-nrel)
[![DOI:10.2172/1660132](https://zenodo.org/badge/DOI/10.2172/1660132.svg)](https://doi.org/10.2172/1660132)

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/NLRWindSystems/ORBIT/dev?filepath=examples)
[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
Expand All @@ -24,10 +25,31 @@ Offshore Renewables Balance of system and Installation Tool

- Rob Hammond

## Documentation
## Documentationa

Please visit the documentation site at https://nlrwindsystems.github.io/ORBIT/

## Citing ORBIT

Please cite this repository using the following citation, or with proceeding Bibtex.

> Nunemaker, Jacob, Shields, Matthew, Hammond, Robert, et al.,
> "ORBIT: Offshore Renewables Balance-of-System and Installation Tool," (2020),
> https://doi.org/10.2172/1660132

```bibtex
@techreport{orbit_tech_report,
author={Nunemaker, Jacob and Shields, Matthew and Hammond, Robert and Duffy, Patrick},
title={ORBIT: Offshore Renewables Balance-of-System and Installation Tool},
institution={National Renewable Energy Laboratory (NREL), Golden, CO (United States)},
doi={10.2172/1660132},
url={https://www.osti.gov/biblio/1660132},
place={United States},
year={2020},
month={08}
}
```

## Installation

`pip install orbit-nrel`
Expand Down
11 changes: 10 additions & 1 deletion docs/topical_guides/cost_curves.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,16 @@ mpl.rcParams["figure.autolayout"] = True

# Ensure the correct examples directory is used when running this in docs or in examples
here = Path(".").resolve()
example_dir = here.parents[1] / "examples" if here.stem == "topical_guides" else here
match here.stem:
case "examples":
example_dir = here
case "topical_guides":
example_dir = here.parents[1] / "examples"
case "ORBIT":
example_dir = here / "examples"
case _:
msg = "Please manually change `example_dir` if running in a custom location."
raise FileNotFoundError(msg)
```

## Configuration
Expand Down
68 changes: 54 additions & 14 deletions docs/topical_guides/export_cable_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ from copy import deepcopy
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import StrMethodFormatter

from ORBIT.phases.design import ElectricalDesign
from ORBIT import ProjectManager, ParametricManager
Expand All @@ -46,7 +47,7 @@ base_config = {
"site": {
"distance": 100,
"depth": 20,
"distance_to_landfall": 50,
"distance_to_landfall": 80,
},
"plant": {
"capacity": 1000,
Expand Down Expand Up @@ -106,46 +107,51 @@ capex_df

## Setup The Parametric Runs

From the two base cases above, we see that HVDC cables are more cost effective than HVAC by
roughly 30%. However, the offshore substation (OSS) is over three times the cost of an HVAC OSS.
To compare this sensitivity and see if there is an point that these technologies cross we'll use
the `ParametricManager` and sweep each cable for a range of plant capacities.
From the two base cases above, we see that HVDC cables are more cost effective than HVAC at roughly
30% of the HVAC cable costs. However, the offshore substation (OSS) is over three times the cost of
an HVAC OSS. To compare this sensitivity and see if there is an point that these technologies cross
we'll use the `ParametricManager` and sweep each cable for a range of plant capacities.

```{code-cell} ipython3
capacity_range = np.arange(100, 4100, 100)
parameters = {
"export_system_design.cables": ["XLPE_1000mm_220kV", "HVDC_2000mm_320kV"],
"plant.capacity": np.arange(100, 2100, 100),
"plant.capacity": capacity_range,
}

results = {
"cable_cost": lambda run: run.total_cable_cost,
"oss_cost": lambda run: run.substation_cost,
"oss_cost": lambda run: run.total_substation_cost,
"num_cables": lambda run: run.num_cables,
"num_substations": lambda run: run.num_substations,
}
```

```{code-cell} ipython3
parametric = ParametricManager(
base_config, parameters, results, module = ElectricalDesign, product=True
base_config, parameters, results, module=ElectricalDesign, product=True
)
parametric.run()
```

## Compare the Cost vs Capacity Trade Off

The inflection point of the below graph shows that for a project that has less than 700 MW of
capacity, HVAC is more cost effective, and for projects greater than 700 MW should, HVDC is more
cost effective.
The inflection point of the below graph shows that for projects with about 100 km of export cabling
that 1,400 MW of capacity is the point at which HVDC becomes more cost effective than HVAC.

Not shown in this example, but generally for near shore projects, HVAC will be more cost effective,
but as the cabling length grows, the project size required for the economics to favor HVDC shrinks.

```{code-cell} ipython3
df = pd.DataFrame(parametric.results)

fig = plt.figure(figsize=(6,4), dpi=200)
ax = fig.subplots(1)

hvac_df = df[df["export_system_design.cables.XLPE_1000mm_220kV.name"] == "XLPE_1000mm_220kV"]
hvdc_df = df[df["export_system_design.cables.HVDC_2000mm_320kV.name"] == "HVDC_2000mm_320kV"]
```

```{code-cell} ipython3
fig = plt.figure(figsize=(6,4), dpi=200)
ax = fig.subplots(1)

ax.plot(
hvac_df["plant.capacity"],
Expand All @@ -159,10 +165,44 @@ ax.plot(
label="HVDC",
)

ax.set_xlim(0, capacity_range.max())
ax.set_ylim(0, 2500)

ax.xaxis.set_major_formatter(StrMethodFormatter("{x:,.0f}"))
ax.yaxis.set_major_formatter(StrMethodFormatter("{x:,.0f}"))

ax.set_ylabel("CapEx [$M]")
ax.set_xlabel("Capacity [MW]")
ax.legend()
ax.grid()

fig.tight_layout()
```

Comparing the below figure to the CapEx figure above, highlights that CapEx increases for the HVDC
system correspond to an increase in the number of substations (each requires a single cable),
whereas for HVAC system, these increases primarily correspond to an increase in the number of export
cables with a smaller increase stemming from the substation requiremensts.

```{code-cell} ipython3
fig = plt.figure(figsize=(6,4), dpi=200)
ax = fig.subplots(1)

ax.plot(hvac_df["plant.capacity"], hvac_df["num_substations"], c="tab:blue", ls="--", label="HVAC Substations")
ax.plot(hvac_df["plant.capacity"], hvac_df["num_cables"], c="tab:blue", ls="-", label="HVAC Export Cables")
ax.plot(hvdc_df["plant.capacity"], hvdc_df["num_substations"], c="tab:orange", ls="dotted", label="HVDC Substations")
ax.plot(hvdc_df["plant.capacity"], hvdc_df["num_cables"], c="tab:orange", ls="-", label="HVDC Substations")

ax.set_xlim(0, capacity_range.max())
ax.set_ylim(0, 16)

ax.xaxis.set_major_formatter(StrMethodFormatter("{x:,.0f}"))
ax.yaxis.set_major_formatter(StrMethodFormatter("{x:,.0f}"))

ax.set_xlabel("Capacity [MW]")
ax.set_ylabel("Export Infrastructure Requirements")
ax.legend()
ax.grid()

fig.tight_layout()
```
11 changes: 10 additions & 1 deletion docs/topical_guides/fixed_bottom_installations.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,16 @@ pd.options.display.float_format = '{:,.0f}'.format

# Set the example path for use in the docs and standalone examples usage
here = Path(".").resolve()
example_path = here.parents[1] / "examples" if here.stem == "topical_guides" else here
match here.stem:
case "examples":
example_path = here
case "topical_guides":
example_path = here.parents[1] / "examples"
case "ORBIT":
example_path = here / "examples"
case _:
msg = "Please manually change `example_path` if running in a custom location."
raise FileNotFoundError(msg)

weather = pd.read_csv(
example_path / "data/example_weather.csv", parse_dates=["datetime"]
Expand Down
12 changes: 11 additions & 1 deletion docs/topical_guides/supply_chains.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ from ORBIT.phases.install import MonopileInstallation, JacketInstallation

# Set the example path for use in the docs and standalone examples usage
here = Path(".").resolve()
example_path = here.parents[1] / "examples" if here.stem == "topical_guides" else here
match here.stem:
case "examples":
example_path = here
case "topical_guides":
example_path = here.parents[1] / "examples"
case "ORBIT":
example_path = here / "examples"
case _:
msg = "Please manually change `example_path` if running in a custom location."
raise FileNotFoundError(msg)

weather = pd.read_csv(
example_path / "data/example_weather.csv", parse_dates=["datetime"]
Expand Down Expand Up @@ -201,4 +210,5 @@ ax.set_xlabel("Simulation Time (h)")
ax.set_ylabel("Substructures")

ax.legend()
fig.show()
```
Loading
Loading