Skip to content

Commit 9741f5d

Browse files
author
Rusty Holleman
committed
Merge branch 'master' of https://github.com/rustychris/stompy
2 parents 7ec9048 + 4aa1a61 commit 9741f5d

File tree

5 files changed

+993
-95
lines changed

5 files changed

+993
-95
lines changed

stompy/grid/unstructured_grid.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -7053,6 +7053,7 @@ def shortest_path(self,n1,n2,return_type='nodes',
70537053
return_type:
70547054
'nodes': list of node indexes
70557055
'edges' or 'sides': array of edge indices
7056+
'halfedges': edge indices, but 1s complement when the natural direction is opposite path
70567057
'cost': just the total cost
70577058
selector: given an edge index and direction, return True if the edge should be considered.
70587059
edge_weight: None: use euclidean distance, otherwise function taking an
@@ -7158,7 +7159,7 @@ def shortest_path(self,n1,n2,return_type='nodes',
71587159
# update/replace the return values in results based on return_type
71597160
return_values=[] # (node/cell, <return value>)
71607161
for i,result in enumerate(results):
7161-
if return_type in ['nodes','edges','sides','cells']:
7162+
if return_type in ['nodes','edges','sides','halfedges','cells']:
71627163
# reconstruct the path:
71637164
path = [result['n']] # will be a cell if traverse=='cells'
71647165
while 1:
@@ -7181,6 +7182,18 @@ def shortest_path(self,n1,n2,return_type='nodes',
71817182
for i in range(len(path)-1)] )
71827183
else:
71837184
raise Exception("Bad value for traverse: %s"%traverse)
7185+
elif return_type == 'halfedges':
7186+
assert traverse=='nodes'
7187+
hes=[]
7188+
for a,b in zip(path[:-1],path[1:]):
7189+
j=self.nodes_to_edge(a,b)
7190+
if self.edges['nodes'][j,0]==a:
7191+
pass
7192+
elif self.edges['nodes'][j,0]==b:
7193+
j=~j
7194+
hes.append(j)
7195+
return_value=np.array( hes )
7196+
71847197
elif return_type=='cost':
71857198
return_value=done[result['n']][0]
71867199
return_values.append( (result['n'],return_value) )

stompy/model/openfoam/depth_average.py

+94-48
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,11 @@ def bboxes(self):
199199
if self._bboxes is None:
200200
bboxes=[]
201201
for proc in range(self.n_procs):
202-
print(f"Calculating bboxes for processor {proc}")
202+
print(f"Read mesh for processor {proc}")
203203
mesh_state = self.read_mesh_state(proc)
204-
bbox = mesh_ops.mesh_cell_bboxes(*mesh_state)
204+
print(f"Calculate bboxes for processor {proc}")
205+
# bbox = mesh_ops.mesh_cell_bboxes(*mesh_state)
206+
bbox = mesh_ops.mesh_cell_bboxes_nb(*mesh_state)
205207
bboxes.append(bbox)
206208

207209
# Appears there are no ghost cells,
@@ -434,6 +436,14 @@ def precalc_raster_info_clipping(self, fld, force=False):
434436
raster_weights = sparse.hstack( (raster_weights,proc_raster_weights) )
435437
self.raster_precalc = raster_weights
436438

439+
# def get_raster_cache_fn(self,label,fld,proc=None,**kw):
440+
# hash_input=[fld.extents,fld.F.shape,self.rot]
441+
# hash_out = hashlib.md5(pickle.dumps(hash_input)).hexdigest()
442+
#
443+
# cache_dir=os.path.join(self.proc_dir(proc),"cache")
444+
# cache_fn=os.path.join(cache_dir,
445+
# f"raster_weights-{fld.dx:.3g}x_{fld.dy:.3g}y-{hash_out}")
446+
437447
def precalc_raster_weights_proc_by_faces(self,proc,fld,force=False):
438448
hash_input=[fld.extents,fld.F.shape,self.rot]
439449
hash_out = hashlib.md5(pickle.dumps(hash_input)).hexdigest()
@@ -456,55 +466,71 @@ def precalc_raster_weights_proc_by_faces(self,proc,fld,force=False):
456466
pickle.dump(raster_weights, fp, -1)
457467
return raster_weights
458468

459-
def to_raster(self, variable, timename, force_precalc=False):
460-
if variable=='wse':
461-
return self.raster_wse(timename)
462-
463-
self.read_timestep(timename)
469+
def to_raster(self, variable, timename, force_precalc=False, cache=True):
464470
n_components=None
465471
if variable=='U':
466472
n_components = 3
467473
fld = field.SimpleGrid.zeros(extents=self.raster_xxyy,
468474
dx=self.raster_dx,dy=self.raster_dy,
469475
n_components=n_components)
476+
477+
if cache:
478+
hash_input=[fld.extents,fld.F.shape,self.rot]
479+
hash_out = hashlib.md5(pickle.dumps(hash_input)).hexdigest()
480+
cache_dir=os.path.join(self.sim_dir,"cache")
481+
cache_fn=os.path.join(cache_dir,
482+
f"{variable}-{timename}-{fld.dx:.3g}x_{fld.dy:.3g}y-{hash_out}.tif")
483+
if os.path.exists(cache_fn):
484+
return field.GdalGrid(cache_fn)
470485

471-
if self.raster_precalc is None:
472-
self.precalc_raster_info(fld,force=force_precalc)
473-
474-
raster_weights = self.raster_precalc
475-
476-
fld_x,fld_y = fld.xy()
486+
if variable=='wse':
487+
fld = self.raster_wse(timename)
488+
else:
489+
self.read_timestep(timename)
490+
491+
if self.raster_precalc is None:
492+
self.precalc_raster_info(fld,force=force_precalc)
493+
494+
raster_weights = self.raster_precalc
495+
496+
fld_x,fld_y = fld.xy()
497+
498+
# for sanity, process each component in sequence (tho memory inefficient)
499+
for comp in range(n_components or 1):
500+
501+
if variable=='U':
502+
# this
503+
num = raster_weights.dot(self.alphas*self.vels[:,comp])
504+
den = raster_weights.dot(self.alphas)
505+
506+
# seems like division by zero should be handled by 'divide', but
507+
# so far it trips 'invalid'
508+
with np.errstate(divide='ignore',invalid='ignore'):
509+
u = num/den
510+
u[ np.abs(den)<1e-10 ] = np.nan
511+
512+
fld.F[:,:,comp] = u.reshape( (fld.F.shape[0],fld.F.shape[1]) )
513+
elif variable=='depth_bad':
514+
# this field and inv_depth_bad are not good approximations
515+
# and left here only for comparison to other approaches.
516+
# measure up from the bed, which is assumed flat
517+
# This will not be a good estimate when the bed is not flat,
518+
# non-simple, or the domain doesn't fill the pixel.
519+
fld.F[:,:] = raster_weights.dot(self.alphas).reshape( fld.F.shape )
520+
elif variable=='inv_depth_bad':
521+
# More likely that the top of the domain is flat than the
522+
# bed being flat, but still has errors when the freesurface
523+
# intersects the walls.
524+
fld.F[:,:] = raster_weights.dot(1.0-self.alphas).reshape( fld.F.shape )
525+
else:
526+
raise Exception(f"Not ready for other fields like {variable}")
527+
528+
if cache:
529+
cache_dir = os.path.dirname(cache_fn)
530+
if not os.path.exists(cache_dir):
531+
os.makedirs(cache_dir)
532+
fld.write_gdal(cache_fn)
477533

478-
# for sanity, process each component in sequence (tho memory inefficient)
479-
for comp in range(n_components or 1):
480-
481-
if variable=='U':
482-
# this
483-
num = raster_weights.dot(self.alphas*self.vels[:,comp])
484-
den = raster_weights.dot(self.alphas)
485-
486-
# seems like division by zero should be handled by 'divide', but
487-
# so far it trips 'invalid'
488-
with np.errstate(divide='ignore',invalid='ignore'):
489-
u = num/den
490-
u[ np.abs(den)<1e-10 ] = np.nan
491-
492-
fld.F[:,:,comp] = u.reshape( (fld.F.shape[0],fld.F.shape[1]) )
493-
elif variable=='depth_bad':
494-
# this field and inv_depth_bad are not good approximations
495-
# and left here only for comparison to other approaches.
496-
# measure up from the bed, which is assumed flat
497-
# This will not be a good estimate when the bed is not flat,
498-
# non-simple, or the domain doesn't fill the pixel.
499-
fld.F[:,:] = raster_weights.dot(self.alphas).reshape( fld.F.shape )
500-
elif variable=='inv_depth_bad':
501-
# More likely that the top of the domain is flat than the
502-
# bed being flat, but still has errors when the freesurface
503-
# intersects the walls.
504-
fld.F[:,:] = raster_weights.dot(1.0-self.alphas).reshape( fld.F.shape )
505-
else:
506-
raise Exception(f"Not ready for other fields like {variable}")
507-
508534
return fld
509535

510536
def rot_name(self):
@@ -930,25 +956,44 @@ def precalc_raster_weights_proc_by_faces(fld, xyz, face_nodes, face_cells, cell_
930956

931957
fld_x,fld_y = fld.xy() # I think these are pixel centers
932958

959+
# unclear whether numba version is sketch or not.
960+
slicer = mesh_ops.mesh_slice_nb # mesh_slice_nb
961+
962+
if 0: # debugging checks
963+
print("Checking cells before any operations")
964+
for cIdx in utils.progress(range(len(mesh_state[3])), func=print):
965+
if not mesh_ops.mesh_check_cell(cIdx,False,mesh_state):
966+
import pdb
967+
pdb.set_trace()
968+
mesh_ops.mesh_check_cell(cIdx,True,mesh_state)
969+
970+
print("Check complete")
971+
933972
cell_mapping=None
934973
for col in utils.progress(range(fld.shape[1])):
935974
if col==0: continue
936975
xmin=fld_x[col]-fld.dx/2
937976
xmax=fld_x[col]+fld.dx/2
938-
cell_mapping, mesh_state = mesh_ops.mesh_slice(np.r_[1,0,0], xmin, cell_mapping, *mesh_state)
977+
cell_mapping, mesh_state = slicer(np.r_[1,0,0], xmin, cell_mapping, *mesh_state)
939978

940979
if 0: # debugging checks
941980
print("Checking cells")
942981
for cIdx in utils.progress(range(len(mesh_state[3])), func=print):
943-
assert mesh_ops.mesh_check_cell(cIdx,False,mesh_state)
982+
if not mesh_ops.mesh_check_cell(cIdx,False,mesh_state):
983+
print(f"cIdx={cIdx} failed check")
984+
mesh_ops.mesh_check_cell(cIdx,True,mesh_state)
985+
raise Exception(f"cIdx={cIdx} failed check")
986+
944987
print("Check complete")
945-
988+
946989
# Slice the mesh so all cells are in exactly one pixel
990+
print("Slicing by row")
947991
for row in utils.progress(range(fld.shape[0])):
992+
print("Row:", row)
948993
if row==0: continue
949994
ymin=fld_y[row]-fld.dy/2
950995
ymax=fld_y[row]+fld.dy/2
951-
cell_mapping, mesh_state = mesh_ops.mesh_slice(np.r_[0,1,0], ymin, cell_mapping, *mesh_state)
996+
cell_mapping, mesh_state = slicer(np.r_[0,1,0], ymin, cell_mapping, *mesh_state)
952997

953998
if 0: # debugging checks
954999
print("Checking cells after all slicing")
@@ -957,8 +1002,9 @@ def precalc_raster_weights_proc_by_faces(fld, xyz, face_nodes, face_cells, cell_
9571002
print("Check complete")
9581003

9591004
print("Calculate volume")
960-
volumes,centers = mesh_ops.mesh_cell_volume_centers(*mesh_state)
1005+
volumes,centers = mesh_ops.mesh_cell_volume_centers_nb(*mesh_state)
9611006

1007+
print("Assemble matrix")
9621008
raster_weights = sparse.dok_matrix((fld.F.shape[0]*fld.F.shape[1],
9631009
n_cells_orig),
9641010
np.float64)

0 commit comments

Comments
 (0)