Metadata-Version: 2.4
Name: oowl
Version: 0.0.1
Summary: Onshore and offshore wind layout generation.
Author: DTU Wind Energy Systems
License-Expression: MIT
Project-URL: Repository, https://gitlab.windenergy.dtu.dk/fpwra/OOWL
Project-URL: Documentation, https://oowl-4781ed.pages.windenergy.dtu.dk
Keywords: wind farm,onshore,offshore,layout,boundary,geometry
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: shapely>=2.0
Requires-Dist: matplotlib>=3.7
Requires-Dist: scipy>=1.10
Requires-Dist: windIO>=2.0
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: jupyter; extra == "dev"
Requires-Dist: ipykernel; extra == "dev"
Dynamic: license-file

# OOWL

Onshore and Offshore Wind Layouts (OOWL) generates diverse, exact-count
wind-farm layouts from composable geometry and placement methods.

The Python package is currently imported as `oowl`.

```python
import oowl
from oowl import boundaries as B
from oowl import layouts as L

boundary = B.Rectangle(9000, 5000).with_channels(
    n_channels=2, width=500, seed=3
)
farm = oowl.generate_farm(
    boundary,
    L.GridLayout(n_turbines=92, lattice_angle=60, seed=4),
)
farm.plot()
```

## Model

The public API has three independent layers:

- `boundaries` define the allowed polygonal farm area. A `MultiPolygon` remains
  one logical farm; `BoundaryCluster` explicitly represents multiple farms.
- `strings` define optional ordered line guides. Breaks and meanders compose as
  non-mutating geometry modifiers.
- `layouts` place an exact turbine count. Grids occupy selected intersections
  of an aligned parallelogram grid, circular layouts select from boundary-
  clipped concentric rings, contour layouts follow nested inward copies of the
  farm boundary and retain a central point by default, Poisson layouts provide
  blue-noise patterns, and string
  farms distribute turbines along guides.

`oowl.generate_farm(...)` is the single entry point for ordinary boundaries,
multipart farms, clusters, and standalone string layouts.

```python
contours = oowl.generate_farm(
    boundary,
    L.ContourLayout(n_turbines=80, include_center=True),
)
```

## Strings and clusters

```python
from oowl import strings as S

guide = S.Parallel(S.Straight(), n_strings=5, spacing=0.18)
guide = guide.with_meander(roughness=0.03, seed=2)

string_farm = oowl.generate_farm(
    B.Circle(3000),
    L.StringLayout(60, strings=guide),
)

cluster = B.BoundaryCluster.from_components(boundary)
mixed = oowl.generate_farm(
    cluster,
    L.MixedLayout(
        n_turbines=92,
        layouts=[L.GridLayout(), L.StringLayout(strings=S.Straight())],
        seed=8,
    ),
)
```

## Units and windIO

Realized boundary and turbine coordinates are interpreted as metres. String
guide lengths and spacing are relative shape parameters when fitted to a
boundary; standalone `StringLayout.spacing` is dimensional.

`Farm.positions` is an ordered `(N, 2)` array that maps directly to windIO's
`coordinates.x` and `coordinates.y`. Cluster provenance stores contiguous farm
slices so a future adapter can emit windIO's array of wind-farm objects. The
package does not currently depend on windIO or model turbines, substations, or
electrical collection arrays.

## Randomness and provenance

Explicit seeds reproduce a farm. An unseeded generation call receives fresh
entropy and records the resolved seed in `Farm.provenance`, so it can be
replayed later:

```python
farm = oowl.generate_farm(boundary, L.GridLayout(92))
replay = oowl.generate_farm(
    boundary,
    L.GridLayout(92),
    seed=farm.provenance["seed"],
)
```

Random boundaries and guides resolve their seed when constructed. Reusing one
such object therefore reuses the same realized geometry, while constructing a
new unseeded object produces a new geometry.
