Source code for stompy.model.delft.hydro_utils
"""
Tools for additional manipulations and data munging related
to Hydro objects, but not central to typical D-WAQ hydro
usage.
"""
import datetime
import numpy as np
import xarray as xr
from ... import utils
[docs]def extract_water_level(hydro,xy,start_time,end_time):
""" Not sure about the code location here...
Try to pull together grid geometry to map point xy to an element,
then to the set of segments, evaluate their volumes within the given
time range, normalize by planform area, and pack the resulting time
series of free surface elevation into an xarray Dataset. too much
going on...
"""
start_idx=hydro.datetime_to_index(start_time)
end_idx =hydro.datetime_to_index(end_time )
time_indexes=np.arange(start_idx,end_idx)
g=hydro.grid()
elt=g.select_cells_nearest(xy)
hydro.infer_2d_elements()
segs=np.nonzero( (hydro.seg_to_2d_element==elt) )[0]
V=[]
for t_idx in time_indexes:
V.append( np.sum( hydro.volumes(hydro.t_secs[t_idx])[segs] ) )
t_secs=hydro.t_secs[time_indexes]
t_dts=[ hydro.time0 + datetime.timedelta(seconds=int(t_sec))
for t_sec in t_secs ]
seg_areas=hydro.planform_areas().data[segs]
assert np.allclose( seg_areas[0], seg_areas )
ds=xr.Dataset()
ds['station']=( ('station',), [0] )
ds['x']=( ('station',),[xy[0]] )
ds['y']=( ('station',),[xy[1]] )
ds['time']=( ('time',), t_dts )
ds['water_depths']= ( ('station','time'), (np.array(V) / seg_areas[0])[None,:] )
bottom_depth=hydro.bottom_depths().data[segs[-1]]
ds['bottom_depth'] = ( ('station',), [bottom_depth] )
ds['water_level'] = ds.water_depths + bottom_depth
return ds
[docs]def extract_velocity(hydro,xy,start_time,end_time):
""" Not sure about the code location here...
Try to pull together grid geometry to map point xy to an element,
then to the set of segments, then exchanges, estimate a cell-centered
velocity based on the exchange fluxes. sketchy.
"""
start_idx=hydro.datetime_to_index(start_time)
end_idx =hydro.datetime_to_index(end_time)
time_indexes=np.arange(start_idx,end_idx)
g=hydro.grid()
elt=g.select_cells_nearest(xy)
hydro.infer_2d_elements()
segs=np.nonzero( (hydro.seg_to_2d_element==elt) )[0]
hydro.infer_2d_elements()
poi0=hydro.pointers-1
ds=xr.Dataset()
ds['station']=( ('station',), [0] )
ds['bin']=( ('bin',), np.arange(len(segs)) )
ds['segment'] = ( ('bin',), segs)
ds['x']=( ('station',),[xy[0]] )
ds['y']=( ('station',),[xy[1]] )
t_secs=hydro.t_secs[time_indexes]
t_dts=[ hydro.time0 + datetime.timedelta(seconds=int(t_sec))
for t_sec in t_secs ]
ds['time']=( ('time',), t_dts )
# This part gets a bit sketchy -- no guarantee that there is enough
# data in the waq output to get proper velocity.
# these map segments to the time-independent data for extracting velocity
seg_exchs={} # segment => array of horizontal exchange indices
seg_matrix={} # segment => matrix of exchange normals
def exch_normal(exch):
elt_from,elt_to = hydro.seg_to_2d_element[ poi0[exch,:2] ]
vec=g.cells_center()[elt_to] - g.cells_center()[elt_from]
return vec / utils.mag(vec)
for seg in segs:
# only worry about horizontal exchanges
seg_exch,sign = np.nonzero( poi0[:hydro.n_exch_x+hydro.n_exch_y,:2]==seg )
seg_exchs[seg]=seg_exch
seg_matrix[seg]=np.array( [exch_normal(e) for e in seg_exch] )
U=np.zeros( (len(time_indexes),len(segs),2 ), 'f8' )
Udavg=np.zeros( (len(time_indexes),2 ), 'f8' )
residuals=np.zeros( (len(time_indexes),len(segs) ), 'f8' )
for ti, t_idx in enumerate(time_indexes):
print(ti)
t_sec=hydro.t_secs[t_idx]
flows=hydro.flows(t_sec)
areas=hydro.areas(t_sec)
vols=hydro.volumes(t_sec)
for seg_i,seg in enumerate(segs):
seg_exch=seg_exchs[seg]
Bcol = flows[seg_exch] / areas[seg_exch]
seg_uv,residual,rank,singular=np.linalg.lstsq(seg_matrix[seg],Bcol)
rel_error=residual / utils.mag(seg_uv)
if rel_error>0.05: # probably have to relax that..
hydro.log.warning("Relative error in velo reconstruction %.2f"%rel_error)
U[ti,seg_i,:] = seg_uv
residuals[ti,seg_i] = residual
Udavg[ti,:] = (U[ti,:,:] * vols[segs,None]).sum(axis=0) / vols[segs].sum()
ds['u'] = ( ('time','bin'), U[:,:,0] )
ds['v'] = ( ('time','bin'), U[:,:,1] )
ds['u_davg'] = ( ('time',), Udavg[:,0] )
ds['v_davg'] = ( ('time',), Udavg[:,1] )
ds['residual'] = ( ('time','bin'), residuals )
return ds