Metadata-Version: 2.4
Name: us-marine-energy-resource
Version: 0.3.1
Summary: Download, visualize, and analyze the U.S. DOE Hydropower and Hydrokinetic Office (H2O) High Resolution Tidal Hindcast dataset
Project-URL: Homepage, https://github.com/US-Marine-Energy-Resource/us-marine-energy-resource-python
Project-URL: Repository, https://github.com/US-Marine-Energy-Resource/us-marine-energy-resource-python
Project-URL: Bug Tracker, https://github.com/US-Marine-Energy-Resource/us-marine-energy-resource-python/issues
Project-URL: Data Source, https://data.openei.org/s3_viewer?bucket=marine-energy-data&prefix=us-tidal%2F
Author-email: Andrew Simms <andrew.simms@nlr.gov>
Maintainer-email: Andrew Simms <andrew.simms@nlr.gov>
License: BSD 3-Clause License
        
        Copyright (c) 2026, Alliance for Energy Innovation, LLC under the terms of Contract
        DE-AC36-08GO28308. The U.S. Government retains certain rights in this software.
        All rights reserved.
        
        Redistribution and use in source and binary forms, with or without
        modification, are permitted provided that the following conditions are met:
        
        1. Redistributions of source code must retain the above copyright notice, this
           list of conditions and the following disclaimer.
        
        2. Redistributions in binary form must reproduce the above copyright notice,
           this list of conditions and the following disclaimer in the documentation
           and/or other materials provided with the distribution.
        
        3. Neither the name of the copyright holder nor the names of its
           contributors may be used to endorse or promote products derived from
           this software without specific prior written permission.
        
        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
        AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
        FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
        OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License-File: LICENSE
Keywords: DOE,H20,hindcast,hydrokinetic,marine energy,ocean current,renewable energy,tidal energy
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.10
Requires-Dist: boto3>=1.34
Requires-Dist: cmocean>=3.1
Requires-Dist: duckdb>=1.5.0
Requires-Dist: matplotlib>=3.9
Requires-Dist: mhkit[tidal]>=1.0
Requires-Dist: numpy>=2.0
Requires-Dist: pandas>=2.2
Requires-Dist: pyarrow>=18.0
Requires-Dist: s3fs>=2024.1
Requires-Dist: scipy>=1.13
Requires-Dist: seaborn>=0.13
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.9
Requires-Dist: utide>=0.3
Requires-Dist: windrose>=1.9
Provides-Extra: analysis
Requires-Dist: scikit-learn>=1.5; extra == 'analysis'
Provides-Extra: dev
Requires-Dist: boto3-stubs[s3]>=1.34; extra == 'dev'
Requires-Dist: pandas-stubs>=2.2; extra == 'dev'
Requires-Dist: pyarrow-stubs>=18.0; extra == 'dev'
Requires-Dist: pyright>=1.1.390; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Requires-Dist: scipy-stubs>=1.13; extra == 'dev'
Provides-Extra: examples
Requires-Dist: folium>=0.17; extra == 'examples'
Requires-Dist: ipykernel>=6.0; extra == 'examples'
Requires-Dist: jupytext>=1.16; extra == 'examples'
Requires-Dist: nbconvert>=7.0; extra == 'examples'
Requires-Dist: notebook>=7.0; extra == 'examples'
Description-Content-Type: text/markdown

# US Marine Energy Resource


## Overview

`us-marine-energy-resource` is a Python library for accessing the [U.S.
DOE H2O High Resolution Tidal
Hindcast](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/)
dataset, a high-resolution, 3D tidal current hindcast for five US
coastal regions, generated with the [Finite Volume Community Ocean Model
(FVCOM)](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/).

> [!IMPORTANT]
>
> This library is in early development and the API is subject to change.
> The core functionality of downloading and visualizing tidal hindcast
> data at specific points is stable, but additional features and
> datasets are still being added. Please reach out if you have questions
> or would like to contribute!

> [!NOTE]
>
> At this time this libary does not support for the U.S. DOE H20 wave
> energy hindcast dataset. The marine and hydrokinetic toolkit (MHKiT)
> can access using the `wave.io.hindcast` module showcased in this [wave
> hindcast
> example](https://mhkit-software.github.io/MHKiT/WPTO_hindcast_example.html)
> that leverages the [NLR Resource eXtraction tool
> (rex)](https://github.com/NatLabRockies/rex) to access wave hindcast
> data.

## Installation

``` bash
pip install git+https://github.com/US-Marine-Energy-Resource/us-marine-energy-resource-python.git@main
```

## Tidal Quick Start

`us_marine_energy_resource.tidal_hindcast.get_data_at_point` takes a
latitude and longitude as input and fetch a full year of tidal current
data at US coastal coordinate within the 5 locations listed above and
visualize current speed across all 10 depth layers over the entire
hindcast year.

The dataset covers a full year at each region at hourly or half-hourly
resolution across 10 terrain-following [sigma
layers](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/sigma-layers/)
from the sea surface to the seafloor.

| Region                          | Period    | Timestep    | Grid Points |
|---------------------------------|-----------|-------------|-------------|
| Cook Inlet, Alaska              | 2005      | hourly      | 392,002     |
| Aleutian Islands, Alaska        | 2010–2011 | hourly      | 797,978     |
| Puget Sound, Washington         | 2015      | half-hourly | 1,734,765   |
| Piscataqua River, New Hampshire | 2007      | half-hourly | 292,927     |
| Western Passage, Maine          | 2017      | half-hourly | 231,208     |

Full dataset documentation, variable definitions, methodology, and
validation are at
[us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/).

``` python
import matplotlib.pyplot as plt
import pandas as pd

from us_marine_energy_resource import tidal_hindcast as tidal
from us_marine_energy_resource.tidal_hindcast import PlotSettings

# Cook Inlet near Nikiski AK,
lat=60.735016
lon=-151.431396
location_name = "Cook Inlet, Near Nikiski, AK"

df = tidal.get_data_at_point(lat=lat, lon=lon)
```

`us_marine_energy_resource` has functions to plot the point data at the
10 uniform depths over time. The underlying data contains speed \[m/s\]
and direction \[deg cw from True North\] calculated from the underlying
model `u` and `v` variables at each sigma layer at each time step. To
convert this to a plot this library uses the calculated sigma depth and
uniform model specification to “extract” volume data, and convert the
data from a compacted format to a format usable for engineering
analysis.

The following visualization uses `plot_sigma_layers_speed` function with
the downloaded and extracted pandas DataFrame, `df` and a `PlotSettings`
object (custom class for this library to control plot styling) and
outputs a visualization of speed at each volume over time.

Each horizontal band is one of 10 sigma layers model results, expanded
to color an entire volume, spanning the full water column from the sea
surface (top) to the seabed (bottom). Color encodes current speed in
m/s. The tidal cycle and spring–neap modulation are immediately visible
across the full hindcast year.

``` python
settings=PlotSettings(
    title=f"Full Model 1 Year | Current Speed | {location_name}",
    fig_width=9,
    fig_height=2.5,
    caption=f"Latitude: {lat}, Longitude: {lon}",
    save_path="docs/images/quickstart-sigma-speed-year.png",
)

tidal.plot_sigma_layers_speed(df, settings=settings)
```

![Full year current speed across sigma layers — Cook Inlet near Nikiski,
AK](docs/images/quickstart-sigma-speed-year.png)

Additionally we can plot direction \[deg clockwise from true north\] at
all depths over time.

``` python
settings.title = settings.title.replace("Current Speed", "Direction [deg cw from True North]")
settings.save_path = "docs/images/quickstart-sigma-direction-year.png"

tidal.plot_sigma_layers_direction(df, settings=settings)
```

![Full year direction across sigma layers — Cook Inlet near Nikiski,
AK](docs/images/quickstart-sigma-direction-year.png)

It is also possible to zoom into specific start dates within the model
run. The simplest way to do this is to create time objects from the data
and use variables to control the offset from the start of the dataset
and the number of days visible.

``` python
n_days = 3
start_day_offset = 7
start_date=str((df.index[0] + pd.Timedelta(days=start_day_offset)).date())
end_date=str((df.index[0] + pd.Timedelta(days=start_day_offset + n_days)).date())

settings = PlotSettings(
    title=f"{n_days} Days | Current Speed | {location_name}",
    start_date=start_date,
    end_date=end_date,
    fig_width=8,
    fig_height=3,
    caption=f"Latitude: {lat}, Longitude: {lon}",
    save_path="docs/images/quickstart-sigma-speed-3day.png",
)

tidal.plot_sigma_layers_speed(df, settings=settings)
```

![3-day current speed across sigma layers — Cook Inlet near Nikiski,
AK](docs/images/quickstart-sigma-speed-3day.png)

``` python
settings.title = settings.title.replace("Current Speed", "Direction [deg cw from True North]")
settings.save_path = "docs/images/quickstart-sigma-direction-3day.png"

tidal.plot_sigma_layers_direction(df, settings=settings)
```

![3-day direction across sigma layers — Cook Inlet near Nikiski,
AK](docs/images/quickstart-sigma-direction-3day.png)

The same `df` can be used to visualize tidal joint probability
distributions (single sigma layer) and velocity exceedance curves
(multiple sigma layers):

``` python
tidal.generate_tidal_joint_probability(
    df,
    sigma_layer=4,
    settings=PlotSettings(
        title=f"Joint Probability Distribution\n{location_name}\nSigma Layer 4",
        fig_width=8,
        fig_height=8,
        save_path="docs/images/quickstart-jpd-layer-4.png",
    ),
)
```

![Joint probability distribution at sigma layer 4 — Cook Inlet near
Nikiski, AK](docs/images/quickstart-jpd-layer-4.png)

``` python
_, stats = tidal.plot_velocity_exceedance(
    df,
    settings=PlotSettings(
        title=f"Velocity Exceedance | {location_name}",
        fig_width=10,
        fig_height=5,
        caption=f"Latitude: {lat}, Longitude: {lon}",
        save_path="docs/images/quickstart-velocity-exceedance.png",
    ),
)
```

![Velocity exceedance across all sigma layers — Cook Inlet near Nikiski,
AK](docs/images/quickstart-velocity-exceedance.png)

`plot_velocity_profile_with_histograms` produces a five-panel diagnostic
overview of the full vertical structure of the tidal resource. From left
to right: a mean velocity profile with per-layer box plots showing
spread and whiskers; a depth vs. speed scatter colored by direction with
quadratic mean and maximum fit curves; and per-layer histograms of
current speed, current direction, and sigma-layer depth. Before
plotting, dry time steps and anomalously thin (“smushed”) sigma layers
are removed — the data-quality summary in the top-left corner reports
what was filtered.

``` python
tidal.plot_velocity_profile_with_histograms(
    df,
    settings=PlotSettings(
        title=f"Velocity and Direction Overview | {location_name}",
        fig_width=10,
        fig_height=16,
        caption=f"Latitude: {lat}, Longitude: {lon}",
        save_path="docs/images/quickstart-velocity-profile.png",
    ),
)
```

![Velocity profile with histograms — Cook Inlet near Nikiski,
AK](docs/images/quickstart-velocity-profile.png)

## Dataset Variables

The [full variable
reference](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/)
documents every field in the dataset. The key summary variables
(available in the manifest for every grid point) are:

| Variable | Units | Description |
|----|----|----|
| [Mean Current Speed](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/mean-current-speed/) | m/s | Annual average depth-averaged current speed |
| [95th Percentile Current Speed](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/95th-percentile-current-speed/) | m/s | Extreme current speed, outlier-tolerant |
| [Mean Power Density](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/mean-power-density/) | W/m² | Annual average depth-averaged kinetic energy flux |
| [95th Percentile Power Density](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/95th-percentile-power-density/) | W/m² | Extreme power density, robust to cubic-velocity sensitivity |
| [Tidal Range](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/tidal-range/) | m | Max − min sea surface elevation over the hindcast year |
| [Minimum Water Depth](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/minimum-water-depth/) | m | Minimum depth over the hindcast year (navigation constraint) |
| [Full Year S3 URI](https://us-marine-energy-resource.github.io/tidal/high_resolution_hindcast/variables/full_year_s3_uri/) | — | Direct S3 link to the time-series parquet for each grid point |

The time-series parquet (one file per grid point) contains hourly or
half-hourly records for one year with columns for speed, direction,
power density, and sigma-layer depth bounds at all 10 vertical levels.

Using a downloaded dataframe as an example, the column names for speed,
direction, power density, and sigma-layer depth bounds at each of the 10
vertical levels are:

``` python
df
```

## Usage examples

The following sections walk through data retrieval and three core
visualizations — time series, velocity exceedance, and joint probability
distribution — for six candidate tidal energy sites across the US.

### Site definitions

``` python
sites = [
    {"label": "Upper Cook Inlet, AK",            "lat": 60.735016,  "lon": -151.431396},
    {"label": "Tacoma Narrows, WA",              "lat": 47.270191,  "lon": -122.548172},
    {"label": "Admiralty Inlet, WA",             "lat": 48.173931,  "lon": -122.774963},
    {"label": "UNH Living Bridge, NH",           "lat": 43.079498,  "lon": -70.752319},
    {"label": "Moose Island, Western Passage, ME", "lat": 44.920837, "lon": -66.988762},
    {"label": "False Pass, Aleutian Islands, AK", "lat": 54.803799,  "lon": -163.364441},
]

cook_inlet = sites[0]
```

### Load data for all sites

`get_data_at_point` finds the nearest grid point in the manifest and
downloads (or returns from cache) the full-year time-series parquet. It
returns a `DataFrame` with a `DatetimeIndex` and columns for speed,
direction, power density, and sigma-layer depth bounds at all 10
vertical levels.

``` python
site_data = {}

for site in sites:
    print(f"Loading {site['label']} …")
    site_data[site["label"]] = tidal.get_data_at_point(site["lat"], site["lon"])
    site_df = site_data[site["label"]]
    date_range = f"{site_df.index[0].date()} → {site_df.index[-1].date()}"
    print(f"  {len(site_df):,} timesteps  ({date_range})\n")
```

    Loading Upper Cook Inlet, AK …
      8,760 timesteps  (2005-01-01 → 2005-12-31)

    Loading Tacoma Narrows, WA …
      17,472 timesteps  (2015-01-01 → 2015-12-30)

    Loading Admiralty Inlet, WA …
      17,472 timesteps  (2015-01-01 → 2015-12-30)

    Loading UNH Living Bridge, NH …
      17,520 timesteps  (2007-01-01 → 2007-12-31)

    Loading Moose Island, Western Passage, ME …
      17,520 timesteps  (2017-01-01 → 2017-12-31)

    Loading False Pass, Aleutian Islands, AK …
      8,760 timesteps  (2010-06-03 → 2011-06-02)

## Primary site deep-dive — Upper Cook Inlet, AK

Cook Inlet has some of the most energetic tidal currents in North
America. Spring tidal ranges exceed 9 m and the geometry of the upper
inlet amplifies current speeds to 3–4 m/s — among the highest in the US.
It is a natural first site for demonstrating what this dataset reveals
about the vertical structure and variability of a tidal energy resource.

### Current speed across depth and time

The depth-time cross-section shows current speed across all 10 sigma
layers for the full hindcast year. Each band spans one sigma layer —
equal fractions of the water column from surface to seafloor. The
spring–neap cycle, the tidal asymmetry between flood and ebb, and the
vertical shear between the fast surface and slower near-bed layers are
all directly visible.

``` python
df_primary = site_data[cook_inlet["label"]]
lat, lon = cook_inlet["lat"], cook_inlet["lon"]

tidal.plot_sigma_layers_speed(
    df_primary,
    settings=PlotSettings(
        title=f"Current Speed Across Sigma Layers — {cook_inlet['label']}",
        fig_height=3,
        fig_width=8,
        caption=f"Latitude: {lat}, Longitude: {lon}",
        save_path="docs/images/cook-inlet-sigma-speed.png",
    ),
)
```

![Current speed across sigma layers — Upper Cook Inlet,
AK](docs/images/cook-inlet-sigma-speed.png)

### Velocity exceedance

Exceedance probability curves across all ten sigma layers. Annotated
percentiles show the current speed exceeded for 50%, 25%, 10%, … of the
hindcast record — the key inputs for turbine capacity-factor estimates.

``` python
_, exc_stats = tidal.plot_velocity_exceedance(
    df_primary,
    settings=PlotSettings(
        title=f"Velocity Exceedance — {cook_inlet['label']}",
        fig_width=10,
        fig_height=5,
        caption=f"Latitude: {lat}, Longitude: {lon}",
        save_path="docs/images/cook-inlet-exceedance.png",
    ),
)
```

![Velocity exceedance across all sigma layers — Upper Cook Inlet,
AK](docs/images/cook-inlet-exceedance.png)

The returned `exc_stats` dict is keyed by `"Layer {i}"` and contains
per-layer exceedance speeds at each annotated percentile. We can create
a `pd.DataFrame` from this data to display in tabular form.

``` python
exc_stats = pd.DataFrame(exc_stats).T[["mean", "5%", "1%", "0.1%", "max"]]
exc_stats
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&#10;    .dataframe tbody tr th {
        vertical-align: top;
    }
&#10;    .dataframe thead th {
        text-align: right;
    }
</style>

|         | mean     | 5%       | 1%       | 0.1%     | max      |
|---------|----------|----------|----------|----------|----------|
| Layer 0 | 1.845529 | 3.139129 | 3.393487 | 3.543426 | 3.601168 |
| Layer 1 | 1.795470 | 3.047897 | 3.293689 | 3.438518 | 3.494025 |
| Layer 2 | 1.746668 | 2.959500 | 3.196892 | 3.339104 | 3.391897 |
| Layer 3 | 1.695603 | 2.866398 | 3.096244 | 3.235751 | 3.286159 |
| Layer 4 | 1.640122 | 2.768487 | 2.988489 | 3.123703 | 3.172075 |
| Layer 5 | 1.577625 | 2.660134 | 2.868485 | 2.998511 | 3.044529 |
| Layer 6 | 1.503978 | 2.530808 | 2.727775 | 2.852564 | 2.895835 |
| Layer 7 | 1.411291 | 2.370027 | 2.554669 | 2.670877 | 2.711424 |
| Layer 8 | 1.280689 | 2.147953 | 2.313955 | 2.418449 | 2.455549 |
| Layer 9 | 1.041188 | 1.743161 | 1.877486 | 1.960242 | 1.990621 |

</div>

### Joint probability distribution

Polar histogram of current speed vs. direction at the mid-column sigma
layer (layer 4). Shows the dominant flow direction and how speed is
distributed across the tidal cycle.

``` python
tidal.generate_tidal_joint_probability(
    df_primary,
    sigma_layer=4,
    settings=PlotSettings(
        title=f"Joint Probability Distribution — {cook_inlet['label']}",
        fig_width=8,
        fig_height=8,
        caption=f"Latitude: {lat}, Longitude: {lon}",
        save_path="docs/images/cook-inlet-jpd-layer-4.png",
    ),
)
```

![Joint probability distribution at sigma layer 4 — Upper Cook Inlet,
AK](docs/images/cook-inlet-jpd-layer-4.png)

------------------------------------------------------------------------

## All-sites comparison

The following three visualizations compare the same plot type across all
six candidate sites. A single `analysis_depth` variable controls the
nominal depth used for layer selection, keeping the exceedance and JPD
panels on an apples-to-apples basis.

### Setup — depth and layer selection

``` python
import math

analysis_depth = 10.0  # m — nominal analysis depth
depth_reference = "surface"  # "surface" or "sea_floor"

# Select the sigma layer closest to analysis_depth for each site.
site_layers = {}
for site in sites:
    layer, actual_depth = tidal.select_layer_for_depth(
        site_data[site["label"]],
        analysis_depth,
        relative_to=depth_reference,
    )
    site_layers[site["label"]] = (layer, actual_depth)
    print(
        f"{site['label']:<40} layer {layer}  "
        f"(mean depth {actual_depth:.1f} m)"
    )
```

    Upper Cook Inlet, AK                     layer 2  (mean depth 8.4 m)
    Tacoma Narrows, WA                       layer 1  (mean depth 9.4 m)
    Admiralty Inlet, WA                      layer 1  (mean depth 8.8 m)
    UNH Living Bridge, NH                    layer 4  (mean depth 9.7 m)
    Moose Island, Western Passage, ME        layer 2  (mean depth 10.0 m)
    False Pass, Aleutian Islands, AK         layer 2  (mean depth 11.4 m)

### Current speed across depth and time — all sites

Each panel covers the full hindcast year at one site. The colorbar range
is shared across all six: `vmax` is the maximum speed in the dataset,
rounded up to the nearest 0.5 m/s.

``` python
# Compute shared "nice max" colorbar limit.
all_max_speeds = [
    float(
        site_data[site["label"]][
            [f"vap_sea_water_speed_layer_{i}" for i in range(10)]
        ].max().max()
    )
    for site in sites
]
speed_vmax = math.ceil(max(all_max_speeds) / 0.5) * 0.5

for site in sites:
    slug = site["label"].lower().replace(", ", "-").replace(" ", "-").replace(".", "")
    site_df = site_data[site["label"]]
    tidal.plot_sigma_layers_speed(
        site_df,
        settings=PlotSettings(
            title=f"Current Speed Across Sigma Layers — {site['label']}",
            caption=f"Lat: {site['lat']}, Lon: {site['lon']}",
            colorbar_max=speed_vmax,
            fig_width=9,
            fig_height=2.5,
            save_path=f"docs/images/sigma-speed-{slug}.png",
        ),
    )
```

![Current speed — Upper Cook Inlet,
AK](docs/images/sigma-speed-upper-cook-inlet-ak.png) ![Current speed —
Tacoma Narrows, WA](docs/images/sigma-speed-tacoma-narrows-wa.png)
![Current speed — Admiralty Inlet,
WA](docs/images/sigma-speed-admiralty-inlet-wa.png) ![Current speed —
UNH Living Bridge, NH](docs/images/sigma-speed-unh-living-bridge-nh.png)
![Current speed — Moose Island, Western Passage,
ME](docs/images/sigma-speed-moose-island-western-passage-me.png)
![Current speed — False Pass, Aleutian Islands,
AK](docs/images/sigma-speed-false-pass-aleutian-islands-ak.png)

### Velocity exceedance — all sites

All six sites on one figure at their respective analysis-depth layers.

``` python
colors = plt.cm.tab10.colors
site_records_exc = [
    (site["label"], site_data[site["label"]], site_layers[site["label"]][0], colors[i])
    for i, site in enumerate(sites)
]

tidal.plot_multi_site_exceedance_overlay(
    site_records_exc,
    settings=PlotSettings(
        title=f"Velocity Exceedance — All Sites  (analysis depth ≈ {analysis_depth} m {depth_reference})",
        fig_height=3,
        fig_width=8,
        save_path="docs/images/all-sites-exceedance-overlay.png",
    ),
)
```

![Velocity exceedance overlay — all six
sites](docs/images/all-sites-exceedance-overlay.png)

### Joint probability distribution — all sites

2 × 3 grid of JPD polar histograms with a shared color scale.

``` python
site_records_jpd = [
    (site["label"], site_data[site["label"]], site_layers[site["label"]][0])
    for site in sites
]

tidal.plot_jpd_comparison_grid(
    site_records_jpd,
    ncols=2,
    settings=PlotSettings(
        title=f"Joint Probability Distribution — All Sites  (analysis depth ≈ {analysis_depth} m {depth_reference})",
        fig_width=10,
        fig_height=13,
        save_path="docs/images/all-sites-jpd-grid.png",
    ),
)
```

![Joint probability distribution grid — all six
sites](docs/images/all-sites-jpd-grid.png)

## Command Line Interface

Installing via pip includes the `us-tidal` CLI for querying and
downloading tidal hindcast data directly from the command line — no
Python required.

### Available options

``` bash
us-tidal --help
```

    Usage: us-tidal [OPTIONS] [LOCATION]                                           
                                                                                    
     Query and download modeled tidal current data from the U.S. DOE H2O High       
     Resolution Tidal Hindcast — FVCOM simulations covering five U.S. coastal       
     regions: Cook Inlet AK, Aleutian Islands AK, Salish Sea WA, Piscataqua River   
     NH, and Western Passage ME.                                                    
                                                                                    
     A point query returns the mesh face containing the coordinate. Area and        
     transect queries return all faces whose triangles geometrically intersect the  
     specified geometry. Each matched face downloads as a full-year, hourly or      
     half-hourly time series of current speed, direction, and kinetic power density 
     at 10 depth layers (sea surface to seafloor).                                  
                                                                                    
     Dataset citation: https://mhkdr.openei.org/submissions/632                     
     Documentation:                                                                 
     https://github.com/US-Marine-Energy-Resource/us-marine-energy-resource-python  
     AWS S3 browser:                                                                
     https://data.openei.org/s3_viewer?bucket=marine-energy-data&prefix=us-tidal%2F 
                                                                                    
     Provide exactly one geometry input: a positional lat,lon for                   
     a point query, or one of --coord, --bbox, --file,                              
     or --wkt for area queries.                                                     
                                                                                    
    ╭─ Arguments ──────────────────────────────────────────────────────────────────╮
    │   location      [LOCATION]  Point as lat,lon (e.g. 60.73,-151.43).           │
    ╰──────────────────────────────────────────────────────────────────────────────╯
    ╭─ Options ────────────────────────────────────────────────────────────────────╮
    │ --coord               -c      TEXT   Transect waypoint as lat,lon. Repeat    │
    │                                      for multi-segment lines.                │
    │ --bbox                        TEXT   Bounding box as                         │
    │                                      lat_min,lon_min,lat_max,lon_max.        │
    │ --file                -f      PATH   Polygon from a GeoJSON file. Draw one   │
    │                                      at https://geojson.io/next/.            │
    │ --wkt                         TEXT   Polygon as a WKT POLYGON string or path │
    │                                      to a .wkt file.                         │
    │ --output-dir          -o      PATH   Copy downloaded parquet files to this   │
    │                                      directory.                              │
    │ --csv                                Export downloaded data as CSV files.    │
    │                                      Written to --output-dir if set,         │
    │                                      otherwise to the current directory.     │
    │ --dry-run                            Show size estimate without downloading. │
    │ --max-size-mb                 FLOAT  Abort if uncached data to download      │
    │                                      exceeds this limit (MB). 0 = no limit.  │
    │                                      [env var: US_TIDAL_MAX_SIZE_MB]         │
    │                                      [default: 500.0]                        │
    │ --max-distance-km             FLOAT  Reject if nearest face is farther than  │
    │                                      this (km). Point queries only.          │
    │ --config                      PATH   Path to config file (default:           │
    │                                      ~/.us_tidal.toml).                      │
    │ --aws-profile                 TEXT   Override AWS profile from config.       │
    │ --cache-dir                   PATH   Override local cache directory from     │
    │                                      config.                                 │
    │ --use-hpc                            Use HPC local filesystem instead of S3. │
    │ --hpc-base-path               TEXT   Override HPC dataset root path from     │
    │                                      config.                                 │
    │ --clear-cache                        Clear the local cache before running.   │
    │ --install-completion                 Install completion for the current      │
    │                                      shell.                                  │
    │ --show-completion                    Show completion for the current shell,  │
    │                                      to copy it or customize the             │
    │                                      installation.                           │
    │ --help                               Show this message and exit.             │
    ╰──────────────────────────────────────────────────────────────────────────────╯
    ╭─ Dataset Info ───────────────────────────────────────────────────────────────╮
    │ --info                           Show dataset metadata, schema, and          │
    │                                  statistics without downloading. Reads only  │
    │                                  the parquet footer (fast range requests).   │
    │ --info-speed                     Show speed category info only (implies      │
    │                                  --info).                                    │
    │ --info-direction                 Show direction category info only (implies  │
    │                                  --info).                                    │
    │ --info-power                     Show power density category info only       │
    │                                  (implies --info).                           │
    │ --info-depth                     Show depth/water-level category info only   │
    │                                  (implies --info).                           │
    │ --layer                 INTEGER  Sigma layer for --info statistics           │
    │                                  (0=surface, 9=near-bed). Repeat to select   │
    │                                  multiple layers.                            │
    │ --depth                 FLOAT    Select the sigma layer nearest to this      │
    │                                  depth (m from surface) for --info           │
    │                                  statistics. Approximate — uses footer depth │
    │                                  stats.                                      │
    │ --depth-avg                      Average --info statistics across all sigma  │
    │                                  layers.                                     │
    ╰──────────────────────────────────────────────────────────────────────────────╯
                                                                                    
     Examples                                                                       
     us-tidal 60.73,-151.43                              Point query                
     us-tidal --coord 60.7,-151.4 --coord 60.9,-151.2   Transect                    
     us-tidal --bbox 60.7,-151.5,60.9,-151.2            Bounding box                
     us-tidal --file study_area.geojson                  Polygon from file          
     us-tidal --wkt "POLYGON((-151.5 60.7,...))"         Polygon from WKT           
     us-tidal 60.73,-151.43 --dry-run                    Size estimate              
     us-tidal 60.73,-151.43 --info                       Dataset info (no download) 
     us-tidal 60.73,-151.43 --info-speed                 Speed category only        
     us-tidal 60.73,-151.43 --info --layer 3             Layer 3 stats              
     us-tidal 60.73,-151.43 --info --depth 15.0          Layer nearest 15 m         
     us-tidal 60.73,-151.43 --info --depth-avg           Average all layers         
     us-tidal --bbox 60.7,-151.5,60.9,-151.2 --info      Aggregate area info        
     us-tidal 60.73,-151.43 --output-dir ./data          Save parquet files         
     us-tidal 60.73,-151.43 --csv                        Export CSV to current dir  
     us-tidal 60.73,-151.43 --csv --output-dir ./data    Export CSV to ./data       
     Config file (~/.us_tidal.toml) sets defaults for AWS, cache, and HPC options.

### Point query — nearest grid point

`us-tidal` accepts a positional `lat,lon` argument. Start with
`--dry-run` to check the size before committing to a download.

``` bash
us-tidal 60.73,-151.43 --dry-run
```

    face_id    00126601                                                            
     location   AK_cook_inlet                                                       
     latitude   60.7298317                                                          
     longitude  -151.4297485                                                        
     distance   0.00 km (containing cell)                                           
     file       AK_cook_inlet/v1.0.0/b1_vap_by_point_partition/lat_deg=60/lon_deg=… 
     s3         s3://marine-energy-data/us-tidal/AK_cook_inlet/v1.0.0/b1_vap_by_po… 
     url        https://marine-energy-data.s3.us-west-2.amazonaws.com/us-tidal/AK_… 
      Files matched          1  
      Total size        3.6 MB  
      Already cached    3.6 MB  
      To download       0.0 MB

On first run the file is fetched from S3. Subsequent calls read from the
local cache with no network traffic.

``` bash
# First run — downloads from S3
us-tidal 60.73,-151.43
```

    face_id    00126601                                                            
     location   AK_cook_inlet                                                       
     latitude   60.7298317                                                          
     longitude  -151.4297485                                                        
     distance   0.00 km (containing cell)                                           
     file       AK_cook_inlet/v1.0.0/b1_vap_by_point_partition/lat_deg=60/lon_deg=… 
     s3         s3://marine-energy-data/us-tidal/AK_cook_inlet/v1.0.0/b1_vap_by_po… 
     url        https://marine-energy-data.s3.us-west-2.amazonaws.com/us-tidal/AK_… 

                 Statistics  (surface layer)             
                                                         
      metric                   mean       p90       max  
     ─────────────────────────────────────────────────── 
      Speed (m/s)             1.963     3.165      4.04  
      Power density (W/m²)   6533.1   16244.9   33806.0  
                                                         

      ✓  1 file cached at ~/.us_tidal_cache/marine-energy-data

      Elapsed: 2.0s  (S3 download)

``` bash
# Second run — served from local cache
us-tidal 60.73,-151.43
```

    face_id    00126601                                                            
     location   AK_cook_inlet                                                       
     latitude   60.7298317                                                          
     longitude  -151.4297485                                                        
     distance   0.00 km (containing cell)                                           
     file       AK_cook_inlet/v1.0.0/b1_vap_by_point_partition/lat_deg=60/lon_deg=… 
     s3         s3://marine-energy-data/us-tidal/AK_cook_inlet/v1.0.0/b1_vap_by_po… 
     url        https://marine-energy-data.s3.us-west-2.amazonaws.com/us-tidal/AK_… 

                 Statistics  (surface layer)             
                                                         
      metric                   mean       p90       max  
     ─────────────────────────────────────────────────── 
      Speed (m/s)             1.963     3.165      4.04  
      Power density (W/m²)   6533.1   16244.9   33806.0  
                                                         

      ✓  1 file cached at ~/.us_tidal_cache/marine-energy-data

      Elapsed: 1.0s  (local cache)

### Area query — all grid points in a bounding box

`--bbox` takes `lat_min,lon_min,lat_max,lon_max`. Use `--dry-run` first
— bbox queries can match thousands of faces.

``` bash
us-tidal --bbox 60.725,-151.445,60.735,-151.425 --dry-run
```

    Matched 103 faces  ·  AK_cook_inlet
                                                                  
      face_id    location             lat          lon   dist_km  
     ──────────────────────────────────────────────────────────── 
      00127584   AK_cook_inlet   60.72406    -151.4444       0.0  
      00126347   AK_cook_inlet   60.73291   -151.43512       0.0  
      00127215   AK_cook_inlet   60.72453   -151.42508       0.0  
      00127216   AK_cook_inlet   60.72458   -151.42688       0.0  
      00127220   AK_cook_inlet   60.72469   -151.43073       0.0  
      00127219   AK_cook_inlet   60.72481   -151.43262       0.0  
      00127383   AK_cook_inlet   60.72487   -151.43976       0.0  
      00127585   AK_cook_inlet    60.7249    -151.4458       0.0  
      00127382   AK_cook_inlet   60.72509   -151.44177       0.0  
      00127380   AK_cook_inlet   60.72521   -151.43649       0.0  
      00127007   AK_cook_inlet   60.72524   -151.42371       0.0  
      00127217   AK_cook_inlet   60.72542   -151.42734       0.0  
      00127381   AK_cook_inlet   60.72544   -151.43842       0.0  
      00127218   AK_cook_inlet   60.72548   -151.42923       0.0  
      00127200   AK_cook_inlet    60.7257   -151.43311       0.0  
      00127201   AK_cook_inlet   60.72588   -151.43506       0.0  
      00127384   AK_cook_inlet    60.7259    -151.4422       0.0  
      00127006   AK_cook_inlet    60.7261   -151.42401       0.0  
      00127387   AK_cook_inlet   60.72612   -151.44556       0.0  
      00127008   AK_cook_inlet   60.72623   -151.42584       0.0  
                                                                  
      … and 83 more
      Files matched           103  
      Total size        ~367.3 MB  
      Already cached       3.6 MB  
      To download       ~363.7 MB

``` bash
# Download all matched faces (~367 MB)
us-tidal --bbox 60.725,-151.445,60.735,-151.425 --output-dir ./data
```

### Transect query — grid points along a line

`--coord` defines a waypoint; repeat it to build a multi-segment path.
All faces whose triangles geometrically intersect the path are returned.

``` bash
us-tidal --coord 60.72,-151.43 --coord 60.75,-151.44 --dry-run
```

    Matched 39 faces  ·  AK_cook_inlet
                                                                  
      face_id    location             lat          lon   dist_km  
     ──────────────────────────────────────────────────────────── 
      00127818   AK_cook_inlet   60.72053   -151.43036       0.0  
      00127621   AK_cook_inlet   60.72163   -151.43011       0.0  
      00127622   AK_cook_inlet   60.72207   -151.43176       0.0  
      00127423   AK_cook_inlet   60.72301   -151.43188       0.0  
      00127422   AK_cook_inlet   60.72375   -151.43024       0.0  
      00127220   AK_cook_inlet   60.72469   -151.43073       0.0  
      00127219   AK_cook_inlet   60.72481   -151.43262       0.0  
      00127200   AK_cook_inlet    60.7257   -151.43311       0.0  
      00127012   AK_cook_inlet   60.72645   -151.43164       0.0  
      00126992   AK_cook_inlet   60.72733   -151.43219       0.0  
      00126807   AK_cook_inlet   60.72812   -151.43073       0.0  
      00126788   AK_cook_inlet   60.72897   -151.43127       0.0  
      00126787   AK_cook_inlet   60.72909   -151.43335       0.0  
      00126764   AK_cook_inlet      60.73   -151.43396       0.0  
      00126581   AK_cook_inlet   60.73064   -151.43268       0.0  
      00126558   AK_cook_inlet   60.73155   -151.43317       0.0  
      00126557   AK_cook_inlet    60.7319   -151.43494       0.0  
      00126345   AK_cook_inlet   60.73349   -151.43335       0.0  
      00126347   AK_cook_inlet   60.73291   -151.43512       0.0  
      00126128   AK_cook_inlet    60.7345   -151.43329       0.0  
                                                                  
      … and 19 more
      Files matched            39  
      Total size        ~139.1 MB  
      Already cached       0.0 MB  
      To download       ~139.1 MB

``` bash
# Download all matched faces (~139 MB)
us-tidal --coord 60.72,-151.43 --coord 60.75,-151.44 --output-dir ./data
```

### Export options

``` bash
# Save parquet files to a directory
us-tidal 60.73,-151.43 --output-dir ./data

# Export as CSV instead
us-tidal 60.73,-151.43 --csv --output-dir ./data
```

### Configuration file

`~/.us_tidal.toml` sets persistent defaults for AWS credentials, cache
location, and HPC paths. CLI flags always override the config file.

``` toml
# ~/.us_tidal.toml
aws_profile   = "my-aws-profile"
cache_dir     = "/scratch/us_tidal_cache"
```

## Direct Downloads using the `tidal_hindcast` API

Tidal hindcast data is accessible via multiple functions that can be
used independently of the plotting functions. This allows users to
access the underlying data at specific points, along lines, or within
rectangular areas. This downloads data to a local cache directory and
returns the path to the downloaded files, which can be loaded and
analyzed with the `load_parquet` and `prepare_dataframe` functions in
the `analysis` module.

`tidal._state` is initialized lazily on the first `get_data_at_point()`
call; call that once to populate the shared cache and manifest before
accessing `_state` directly.

``` python
from us_marine_energy_resource import tidal_hindcast as tidal
from us_marine_energy_resource.analysis import load_parquet, prepare_dataframe

# Initialize the shared cache and manifest (no-op if already done above).
tidal.get_data_at_point(lat=60.73, lon=-151.43)

# Access the underlying cache and manifest directly.
cache = tidal._state.cache
query = tidal._state.query   # TidalManifestQuery instance

# --- Spatial queries against the manifest -----------------------------------

# Single nearest point
point = query.query_nearest_point(lat=60.73, lon=-151.43)

# All faces whose triangles intersect the bounding box
area = query.query_all_within_rectangular_area(
    60.7, 60.8, -151.5, -151.4
)

# All faces whose triangles are crossed by the line segment
line = query.query_all_on_line(
    60.7, -151.4, 60.8, -151.5
)

print(
    f"Nearest point : face {point['point']['face_id']}"
    f"  ({point['point']['lat']:.4f}, {point['point']['lon']:.4f})"
    f"  —  {point['distance_km']:.3f} km"
)
print(f"Area query    : {len(area)} grid centroids in bbox")
print(f"Line query    : {len(line)} grid centroids along transect")
```

    Nearest point : face 00126601  (60.7298, -151.4297)  —  0.000 km
    Area query    : 3741 grid centroids in bbox
    Line query    : 126 grid centroids along transect

``` python
# Load a specific grid point's full-year time-series parquet.
local_path = cache.get(point["point"]["file_path"])
raw_df, file_meta, var_meta = load_parquet(local_path)
df = prepare_dataframe(raw_df, file_meta)
print(f"Loaded {len(df):,} timesteps, {df.shape[1]} columns")
```

    Loaded 8,760 timesteps, 136 columns
