Skip to content

Inside the Station Catalog ​

Comparing a satellite pass against a tide gauge starts with knowing where the gauge sits and what measures the water there, and Tidemark holds both in a table the package ships, src/tidemark/gauges/stations.parquet, carrying every gauge the comparison reads. This page follows that table from the services it is built from, through the filters and the keys that decide which gauges reach it, to its columns.

The Services ​

The gauges this project serves are the network the Gulf of Maine Research Institute and NERACOOS operate along the Maine coast, built from gauges by two makers, Hohonu and Greenstream. NERACOOS publishes one dataset per gauge on its ERDDAP server⁠1⁠, and that server carries gauges from other operators beside them, including the four the USGS runs up the Kennebec at Augusta, Gardiner, and Hallowell and on the Saco at Camp Ellis⁠2⁠ and the two Brown University runs at Rockland, so the catalog reads each USGS gauge's position and datum from the ERDDAP and asks the USGS Water Data API only for the monitoring location its series is read from.

The stations NOAA operates come from its Center for Operational Oceanographic Products and Services (CO-OPS), whose metadata API⁠3⁠ lists its water level stations and, for a station it has removed, the first and last dates of its series. The same answer carries each station's datum table, from which the catalog keeps the heights of NAVD 88 and of mean lower low water above the station datum, their epoch, and the date CO-OPS accepted them, so mise run data:catalog writes a revision of any of them into the table. A station's datum reads NAVD 88 wherever that table lists NAVD88 and mean lower low water otherwise, which leaves Bar Harbor, whose table lists no NAVD 88 tie, on mean lower low water, measured onto NAVD 88 as The NAVD 88 Offset sets out, and A NOAA Station's Reading sets out how its series reads each height on that datum.

The Vendors ​

Each dataset id opens on the name of the gauge's maker or of the network running it, and the vendor the catalog declares under that name sets whether the gauge arrives as an anchor or a target. mise run docs:render writes the table below from Vendor.known in src/tidemark/gauges/vendors.py and from the station catalog.

PrefixVendorIts GaugesGauges in the Table
brownBrown UniversityTargets2
greenstreamGreenstreamTargets5
hohonuHohonuTargets15
usgsUSGSAnchors4

Reading the Sensor Type ​

The catalog holds the instrument a gauge measures the water with where a source states it, a difference that matters for the reasons The Gauge’s Reading gives. The NERACOOS ERDDAP states it for the two datasets at Machias, in each dataset's title and summary, so sensor reads radar and ultrasonic there. Each NOAA station's sensor listing names its water level instrument, and sensor keeps NOAA's word for it, acoustic for Acoustic WL and microwave for Microwave WL, reading only the enabled sensors and leaving out Tsunami WL, a name stating what the channel serves rather than how it measures. The listing names none at Wells, whose sensor stays empty as a notice reports. Every other gauge's stays empty as well, since no source the catalog reads states it.

The Two Filters ​

Two filters decide which gauges the catalog reads:

  1. The catalog searches the ERDDAP for every dataset publishing sea_surface_height_above_geopotential_datum, the CF standard name every water level on that server carries, so a gauge from any maker or operator is found, whatever pattern its dataset id follows.
  2. Of those, the catalog keeps the gauges in Maine, reading the state out of the dataset's id and its title together, since the server publishes no field naming it:
    • Neither field carries the state for every gauge, in that the two Machias datasets name Maine only in the title, while the Squamscott River dataset names New Hampshire only in the id.
    • A dataset naming no state, and one naming two different states, are both left out.

The catalog then writes a gauge it reads only where it declares the vendor its dataset id opens on, as The Vendors sets out, and leaves any other out of the table. Each gauge it writes from the ERDDAP reports the datum its own water level sits on, read from the attribute the ERDDAP publishes on that variable, so the table records a verified reference rather than an assumed one. Every Maine gauge on that server names the North American Vertical Datum of 1988.

The map below sets every gauge the catalog keeps, each NOAA station where CO-OPS places it⁠3⁠, on a coast cut from the provinces' boundary file Statistics Canada publishes⁠4⁠ and the states' file the U.S. Census Bureau publishes⁠5⁠, as every map on the site does.

Anchor
Target
Retired

32 gauges at 31 places along the Maine coast

Commit47945eaDatastations.jsonUnreleased1.2.0

The Machias Pair ​

Two datasets sit at Machias, Hohonu_tide_Machias_radar and Hohonu_tide_Machias_ultrasonic, at the same position and under the same place name, differing only in the sensor each one reads, so a disagreement between them comes from the sensors rather than from the water, making the pair the side-by-side test The Gauge’s Reading names.

The NOAA Stations ​

The CO-OPS listing returns every Maine water level station NOAA still operates, meaning Eastport, Cutler Farris Wharf, Bar Harbor, Portland, and Seavey Island, and the next rebuild writes any station NOAA adds or removes into the table. The listing never returns Wells, which NOAA removed on 2022-08-03, yet the low-cost network's own history reaches back past that date, so the catalog requests Wells by station id and records the removal date the API reports.

A NOAA station's key follows from whether NOAA still operates it:

  • A station NOAA operates takes NWLON_<id>, the id the NERACOOS ERDDAP uses for the dataset it serves that station under, so a NOAA row and a low-cost row read alike. The catalog builds that key rather than reading the dataset back, since the mirror publishes its height under a different variable name and names no datum.
  • A station NOAA has removed takes its bare station id, because that server carries no dataset for a station it no longer receives.

Anchors and Targets ​

The anchor column marks each gauge an agency operates, meaning the NOAA stations and the USGS gauges, which arrive with the vertical reference that agency established. No service publishes it, so the catalog reads every NOAA station as an anchor, and a gauge on the ERDDAP as one wherever its vendor is declared an agency. Every other gauge is a target, a low-cost gauge the Gulf of Maine Research Institute or Brown University runs, whose sensor elevation the comparison estimates.

The NAVD 88 Offset ​

Every comparison reads a gauge's water surface elevation on NAVD 88, whereas Bar Harbor and Camp Ellis, both anchors, publish no surveyed tie to it. Bar Harbor's datum table lists no NAVD 88 at all, since CO-OPS lists NAVD 88 among a station's datums only where two or more of the marks on its bench mark sheet carry a height on it, and only one of Bar Harbor's does⁠3⁠. USGS records Camp Ellis's gage datum at 0.0 ft above NAVD 88, give or take 4.3 ft, as interpolated from an elevation model⁠2⁠. For each such gauge, a rebuild measures the height of the datum the gauge publishes on above NAVD 88, its NAVD 88 offset, which a height on that datum adds to reach NAVD 88, through the first of the routes below that reaches it:

  1. A bench mark on the station's own sheet whose NGS datasheet carries an adjusted height on NAVD 88, the offset being that height less the mark's height on the sheet above the datum the gauge publishes on⁠6⁠. NGS's documentation of its datasheet gives a leveled height's order and class as its only measure of accuracy and states a tolerance for class 0 alone, 8.4 mm for second order. VDatum's estimation of its uncertainties gives the tidal datums of the Gulf of Maine's tide stations a standard deviation of 1.6 cm, so an offset from a mark carries the two as the root of the sum of their squares, the way VDatum combines its own.
  2. NOAA's VDatum, between the gauge's tidal datum and NAVD 88 at the gauge, at the uncertainty VDatum gives, wherever no such mark reaches a gauge publishing on a tidal datum⁠7⁠. At the Bath gauge, on a tidal river, the observation-based offset was 32 cm less than the modeled VDatum offset, and Baranes et al. report on page 10 that it remains uncertain whether river influence, insufficient model resolution, or some other cause explains the discrepancy⁠8⁠.
  3. The altitude the gauge's agency records for its datum, at the accuracy the agency states, for a gauge neither route reaches, which is how Camp Ellis enters the comparison carrying its 4.3 ft.

A rebuild asks VDatum at every NOAA station without a NAVD 88 tie whatever route reaches it, so the two routes can be compared wherever both do. mise run docs:render writes the table below from the station catalog, every height in meters, beside the PID of the mark each offset from a mark is measured from and the offset less VDatum's. At Bar Harbor, the offset from K 22 differs from VDatum's by far less than the uncertainty VDatum gives its own, and each series reads on NAVD 88 through its gauge's offset, as A NOAA Station's Reading and A USGS Gauge's Windows set out.

Bar Harbor’s tide gauge counts from a low-water line 1.821 m below the land survey’s national zero, NAVD 88, so every reading it takes reads 1.821 m lower on NAVD 88.

NAVD 88The land survey’s national zeroMean lower low waterThe low-water line the tide gauge counts fromBench markPE0281Its height on NAVD 88Its height above low waterThe offset−1.821 mVDatum−1.812 mThe gauge1.000 mOn NAVD 88−0.821 m

Point at a part of the drawing, or move to it with the Tab key, to read what it shows. Press the reading to watch it carried onto NAVD 88 again.

Every value as a table
StationGaugeRouteOffsetVDatumLess VDatum's
NWLON_8413320Bar Harbormark at PE0281-1.821 ± 0.018-1.812 ± 0.117-0.009
USGS_tide_Saco_MESaco River at Camp Ellis near Saco, MEagency0.000 ± 1.311None givenNone given
Commit47945eaDatastations.jsonUnreleased1.2.0

The Surveyed Elevation ​

No service publishes the surveyed elevation of a sensor, which the stakeholder holds from the surveys The Unsurveyed Gauge describes. The distance d at a surveyed gauge is that elevation less the published water surface elevation.

Rebuilding the Table ​

The package ships the catalog rather than fetching it, since every step looks a gauge up by the one key the table indexes it under. mise run data:catalog rebuilds it from the services through tidemark catalog, reading each answer through its record on The Service Records. A rebuild sends its requests one at a time, reading the ERDDAP's search, its dataset listing, and the CO-OPS station listing once each, then the information table of each gauge it writes from the ERDDAP for its datum, one answer for each NOAA station, which carries its bench marks and its datum table, its sensor listing, and the USGS monitoring locations within a thousandth of a degree of each USGS gauge, of which the one on a tidal stream or an estuary becomes its usgs_id. A NOAA station whose datum table lists no NAVD 88 then sends three more at once, for its bench mark sheet, for the NGS datasheet of each published mark it lists a PID for, and for VDatum's offset at the station.

A rebuild records what each service answered under data/gauges/catalog/, and parts.json names those answers beside the release that ships them. Each weekly release carries them as catalog.tar.zst, whose bytes stand until a rebuild records other answers, since the answers leave out what moves while an answer stands, the actual_range and ancillary_variables rows of an ERDDAP information table, the self links and stormsurge flags of a CO-OPS answer, and the timeStamp on a USGS answer. mise run data:catalog -- --check seeds any answer data/ lacks from that release and rebuilds the table from them, asking no service, so it reports where the code no longer rebuilds the table the package ships. A rebuild and a check both refuse a shipped table that fails StationSchema, printing the fault and exiting 1.

Every request goes through one session per thread, which names this project in its User-Agent, and a rebuild reads every gauge and every station at once. A request the service never answered, answered with a server error, or refused as too many requests is sent again once its host reopens, at the pace that host's refusals set, as is the 403 the CO-OPS throttle answers with, as The CO-OPS Throttle sets out, whereas a USGS lookup fails at once past the API's hourly limit, as USGS Request Limits sets out.

Rebuild Notices ​

A rebuild and a check both print a notice for anything the services left unread or a gauge the table leaves out, and a notice is information rather than a failure, so a rebuild writes the table from every gauge it can read, whatever it found:

  • A gauge the catalog writes from the ERDDAP names a datum other than NAVD 88 for its own water level, or names none.
  • A USGS gauge sits within a thousandth of a degree of no single USGS monitoring location on a tidal stream or an estuary, or of more than one, so its usgs_id stays empty.
  • A NOAA station whose datum table lists no NAVD 88 is reached by neither a bench mark nor VDatum, so its NAVD 88 offset stays empty.
  • A NOAA station's sensor listing names no single water level instrument, so its sensor stays empty.
  • A column no service publishes has gone missing from the table, so every gauge would read it as empty.
  • A gauge's dataset id opens on a prefix the catalog declares no vendor under, so the table leaves it out, and a check lists it among the stations the rebuild adds until Vendor.known declares its vendor.

The Station Table ​

One row per

gauge

station

Shares station with 4 other tables.

29columns

Commit47945eaDatastations.jsonUnreleased1.2.0

mise run docs:render writes the table below from StationSchema, each column beside the service that fills it, whether the NERACOOS ERDDAP⁠1⁠ or CO-OPS⁠3⁠. The columns no service publishes are read from the table a rebuild is about to replace, so a low-cost gauge's sensor type and the stakeholder's survey values survive one. Since vendor comes from the ERDDAP alone, it stays empty on a row that reached the table from CO-OPS, whereas datum takes the one spelling Datum declares for both services, navd for NAVD 88 and mllw for mean lower low water.

Either
datum_
vdatum_
navd88_
survey_
Either

Each bar is a column’s share of the 32 gauges · point at a gauge for its row

vendorERDDAP

The gauge's maker or the network running it, read from the dataset id's prefix.

WestEast

All 26 gauges the ERDDAP lists hold it, and none of the six CO-OPS stations does.

Every value as a table
ColumnHoldsFilled From
stationA shared key the tables join onThe ERDDAP and CO-OPS
anchorWhether an agency has already established this gauge's vertical referenceThe vendor and CO-OPS
coops_idThe NOAA station id, which stays empty on a gauge NOAA does not operateCO-OPS
datumThe vertical datum this gauge's water levels are read on, meaning the surface that counts as zero heightThe ERDDAP and CO-OPS
datum_acceptedThe date CO-OPS accepted the NOAA station's datum heights, which stays empty on a gauge NOAA does not operateCO-OPS
datum_epochThe years the NOAA station's tidal datums average over, which stays empty on a gauge NOAA does not operateCO-OPS
latitudeWhere the gauge sits in degrees north, inside Maine's extentThe ERDDAP and CO-OPS
longitudeWhere the gauge sits in degrees east, inside Maine's extentThe ERDDAP and CO-OPS
mllw_stnd_mThe height of mean lower low water in meters above the NOAA station's station datumCO-OPS
nameThe place the gauge sitsThe ERDDAP and CO-OPS
navd88_offset_mThe height in meters above NAVD 88 of the datum a gauge without a surveyed NAVD 88 tie publishes on, which a height on that datum adds to reach NAVD 88, and which stays empty on every other gaugeCO-OPS, NGS, VDatum, and USGS
navd88_offset_markThe NGS PID of the bench mark that offset is measured from, which stays empty on every other routeNGS
navd88_offset_routeThe route that offset reaches NAVD 88 by, from a bench mark NGS levels on it as mark, through NOAA's VDatum as vdatum, or as the gauge's agency records it as agencyCO-OPS, NGS, VDatum, and USGS
navd88_offset_uncertainty_mThe uncertainty of that offset in meters, a standard deviationCO-OPS, NGS, VDatum, and USGS
navd88_stnd_mThe height of NAVD 88 in meters above the NOAA station's station datum, which stays empty where the station has no NAVD 88 tieCO-OPS
operatorWho runs the gaugeThe ERDDAP and CO-OPS
retiredThe date NOAA removed the station, which stays empty while it operatesCO-OPS
sensorThe instrument the gauge measures the water with, in the word its source uses, which stays empty where no source states itThe previous table and CO-OPS
sensor_navd88_mThe surveyed elevation of the sensor in meters above NAVD 88, empty where the table carries no surveyThe previous table
sourceWhich service supplied the row, either the NERACOOS ERDDAP or NOAA CO-OPSThe ERDDAP and CO-OPS
survey_dateThe date the survey ran, empty where the table carries no surveyThe previous table
survey_frameThe reference frame the survey worked in, empty where the table carries no surveyThe previous table
survey_geoidThe geoid model the survey read its height above sea level from, empty where the table carries no surveyThe previous table
survey_methodHow the survey established the elevation, empty where the table carries no surveyThe previous table
survey_uncertainty_mThe vertical uncertainty the survey reports in meters, empty where the table carries no surveyThe previous table
usgs_idThe USGS monitoring location a USGS gauge's series is read from, which stays empty on every other gaugeThe USGS Water Data API
vdatum_offset_mThe NAVD 88 offset NOAA's VDatum gives at a NOAA station without a NAVD 88 tie, in meters, which stays empty where its grids do not reach the stationVDatum
vdatum_uncertainty_mThe vertical uncertainty VDatum gives that offset in metersVDatum
vendorThe gauge's maker or the network running it, read from the dataset id's prefixThe ERDDAP
Commit47945eaDatastations.jsonUnreleased1.2.0

The first steps of the analysis graph read the table the package ships and hold its anchors and its targets apart.


  1. 1Gulf of Maine Research Institute & Brown University 2026. "NERACOOS ERDDAP." Northeastern Regional Association of Coastal Ocean Observing Systems. https://data.neracoos.org/erddap/.↩︎ ↩︎

  2. 2United States Geological Survey 1994. "USGS Water Data for the Nation." https://doi.org/10.5066/F7P55KJN.↩︎ ↩︎

  3. 3NOAA CO-OPS 2026. "CO-OPS Data Retrieval API and Metadata API." https://tidesandcurrents.noaa.gov/web_services_info.html.↩︎ ↩︎ ↩︎ ↩︎

  4. 4Statistics Canada 2021. "Provinces/Territories, Cartographic Boundary File, 2021 Census." https://www12.statcan.gc.ca/census-recensement/2021/geo/sip-pis/boundary-limites/files-fichiers/lpr_000b21a_e.zip.↩︎

  5. 5U.S. Census Bureau 2024. "2024 Cartographic Boundary File (SHP), State and Equivalent Entities for United States, 1:500,000." https://www2.census.gov/geo/tiger/GENZ2024/shp/cb_2024_us_state_500k.zip.↩︎

  6. 6National Geodetic Survey 2026. "NGS Data Explorer API." https://geodesy.noaa.gov/web_services/data-explorer.shtml.↩︎

  7. 7NOAA National Ocean Service 2026. "VDatum." https://vdatum.noaa.gov/.↩︎

  8. 8Baranes et al. 2026. "Supporting Coastal Flood Forecasting and Community-Led Adaptation With Tide Gauges, Community Science and Youth Engagement." Frontiers in Climate 8: 1757212. https://doi.org/10.3389/fclim.2026.1757212↩︎