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.
meshprovides ngh and the interior size;b_paddedis the solver’s own padded bed (solver.b, shape(nx + 2*ngh, ny + 2*ngh));x0,y0are 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;dxis 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,jare 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*dxandy0 = y0_global + j0*dyfor the rank’s offset(i0, j0)in global interior cells. With the global origin every rank places the gauge at the same local cell andGaugeBank.write_allhas every rank overwrite the samegauge_<name>.csv.
- class geoswe.gauges.GaugeBank(gauges, every_s=60.0)[source]¶
Bases:
objectManage 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:
gauges (Sequence[GaugeRecorder])
every_s (float)
- class geoswe.gauges.GaugeRecorder(name, i, j, x=None, y=None, bed_b=None, history=<factory>, padded_shape=None)[source]¶
Bases:
objectTime-series recorder at fixed (i, j) cell indices on the solver grid.
- Parameters: