Gauge time series

geoswe.gauges records depth, velocity and water-surface elevation at fixed cells and writes one gauge_<name>.csv per gauge, which is how a run is compared against a tide or stream gauge. It is an output helper and not part of the solver: nothing in geoswe.solver or the run driver calls it, so you drive it yourself, from the step callback. NumPy is all it needs.

Everything here indexes the solver’s padded arrays. GaugeRecorder.i and .j are interior indices plus mesh.ngh, so the state and bed to sample are solver.q and solver.b, not solver.q_interior, solver.depth() and the interior bed you handed Solver2D. gauges_from_coords checks the bed it is handed and stamps the shape on each recorder, which then checks every sample, because the interior bed is the plausible mistake: it used to place the gauge ngh cells away and report that cell’s water, silently unless the gauge sat within ngh of the far edge.

import numpy as np
from geoswe import Config, Mesh2D, Solver2D
from geoswe.gauges import GaugeBank, gauges_from_coords

mesh = Mesh2D(nx=20, ny=20, dx=10.0, dy=10.0)
bed = np.zeros((20, 20))
q0 = np.zeros((3, 20, 20)); q0[0] = 1.0
solver = Solver2D(mesh, Config(), q0, bed)

# x0, y0 are the outer edge of cell (0, 0) in the bed's own CRS, and
# solver.b is the padded bed, so the returned (i, j) are padded too.
bank = GaugeBank(gauges_from_coords([("G1", 105.0, 105.0)], mesh, solver.b,
                                    x0=0.0, y0=0.0, dx=mesh.dx),
                 every_s=60.0)
solver.run(t_end=600.0, callback=lambda s, step: bank.step(s.t, s.q, s.b))
print(bank.write_all("gauges_out"))

Under MPI, give each rank its own rank-local mesh and interior origin: gauges_from_coords has no way to tell a global origin from a local one, and with a global one every rank places the gauge at the same local cell and then overwrites the same CSV.

geoswe.gauges.gauges_from_coords(coords, mesh, b_padded, x0, y0, dx)[source]

Build GaugeRecorder list from (name, x, y) projected coordinates.

mesh provides ngh and the interior size; b_padded is the solver’s own padded bed (solver.b, shape (nx + 2*ngh, ny + 2*ngh)); x0, y0 are the lower-left corner of the interior (un-padded) domain in the same projected CRS, i.e. the OUTER EDGE of cell (0, 0), not its centre; dx is the cell size (assumed square for now). A gauge is assigned to the cell whose [edge, edge+dx) interval contains it: index = floor((coord - origin)/dx).

The returned i, j are PADDED indices, so feed the recorders the padded state as well (bank.step(t, solver.q, solver.b)).

Under MPI, pass the RANK-LOCAL mesh and the rank’s own interior origin, x0 = x0_global + i0*dx and y0 = y0_global + j0*dy for the rank’s offset (i0, j0) in global interior cells. With the global origin every rank places the gauge at the same local cell and GaugeBank.write_all has every rank overwrite the same gauge_<name>.csv.

Parameters:
Return type:

List[GaugeRecorder]

class geoswe.gauges.GaugeBank(gauges, every_s=60.0)[source]

Bases: object

Manage a list of gauges + periodic sampling.

Samples on the fixed grid 0, every_s, 2*``every_s``, …: each sample is taken at the first step at or after a grid time, so the series stays on the simulation clock whatever the step size does.

Parameters:
step(t_s, q, b)[source]

Sample if t_s >= next sample time. Returns True if it sampled.

Parameters:

t_s (float)

Return type:

bool

write_all(out_dir)[source]

Write one gauge_<name>.csv per gauge into out_dir; returns the paths.

Parameters:

out_dir (str)

Return type:

List[str]

class geoswe.gauges.GaugeRecorder(name, i, j, x=None, y=None, bed_b=None, history=<factory>, padded_shape=None)[source]

Bases: object

Time-series recorder at fixed (i, j) cell indices on the solver grid.

Parameters:
name: str
i: int
j: int
x: float | None = None
y: float | None = None
bed_b: float | None = None
history: List[Tuple[float, float, float, float, float]]
padded_shape: Tuple[int, int] | None = None
sample(t_s, q, b)[source]

Record (t, h, u, v, wse) at the gauge cell from the padded state q and bed b.

Parameters:

t_s (float)

Return type:

None

to_csv(path)[source]

Write the recorded series to path as CSV with a one-line header comment.

Parameters:

path (str)

Return type:

None