77
88"""
99from schimpy .schism_yaml import load
10- from schimpy .schism_mesh import SchismMeshGr3Reader
10+ from schimpy .schism_mesh import SchismMeshGr3Reader , BoundaryType
1111import numbers
12+ import numpy as np
13+ import click
1214
1315
1416__all__ = ["load_boundary" ]
1517
1618
19+ @click .command (
20+ help = (
21+ "The tool create SCHISM bctide inputs by reading a number of open boundary condition yaml and mesh \
22+ from a main input yaml \n \n "
23+ "Example:\n "
24+ " bctide bctide_main.yaml\n "
25+ )
26+ )
27+ @click .argument ('main_yaml' , type = click .Path (exists = True ))
28+
1729def load_main_input (main_yaml ):
1830 """ read in main yaml file which contians the grid topology and
1931 boundary condtion yaml files, this input file looks like below
@@ -34,27 +46,53 @@ class and write out the SCHISM boundary condition btdides input file.
3446
3547 mesh_in = main_yaml_dict ["mesh" ]["mesh_inputfile" ]
3648 sr = SchismMeshGr3Reader ()
49+
3750 hgrid = sr .read (mesh_in )
38- open_boundary_grd = None
51+ open_boundary_segments = None
3952 if "open_boundaries" in main_yaml_dict ["mesh" ].keys ():
40- open_boundary_grd = main_yaml_dict ["mesh" ]["open_boundaries" ]
53+ open_boundary_segments = main_yaml_dict ["mesh" ]["open_boundaries" ]
4154
4255 bctides_dic = main_yaml_dict ["bctides" ]
4356 for bctides_key in bctides_dic .keys ():
4457 bctides_yaml = bctides_dic [bctides_key ]
45- by = load_boundary (hgrid ,bctides_yaml ,open_boundary_grd )
58+ by = load_boundary (hgrid ,bctides_yaml ,open_boundary_segments )
4659 by .write_bctides (bctides_key )
4760
48- def load_boundary (hgrid ,fn ,open_boundary_grid ):
49- return boundary (hgrid ,fn ,open_boundary_grid )
61+ def update_mesh_open_boundaries (mesh , segments ):
62+ """Overtide mesh open boundaries with linestrings from segments dict
63+ borrowed from schism_setup.py
64+ segments: dict containing "linestrings" key
65+ """
66+ mesh .clear_boundaries ()
67+ boundary_only = True
68+ linestrings = segments .get ("linestrings" )
69+ if linestrings is None :
70+ raise ValueError ("Linestrings is required for open boundaries specification" )
71+ for item in linestrings :
72+ name = item .get ("name" )
73+ if name is None :
74+ name = item .get ("Name" )
75+ p = np .array (item ["coordinates" ])
76+ start = mesh .find_closest_nodes (p [0 ], 1 , boundary_only )
77+ end = mesh .find_closest_nodes (p [1 ], 1 , boundary_only )
78+ path = mesh ._build_boundary_node_string (start , end , boundary_only )
79+ comment = '! Open boundary "%s"' % name
80+ mesh .add_boundary (path , BoundaryType .OPEN , comment )
81+ mesh .fill_land_and_island_boundaries ()
82+
83+
84+
85+
86+ def load_boundary (hgrid ,fn ,open_boundary_segments ):
87+ return boundary (hgrid ,fn ,open_boundary_segments )
5088
5189
5290class boundary (object ):
5391 """
5492 A class to generate boundary condition input file for SCHISM
5593 """
5694
57- def __init__ (self , hgrid ,bc_yaml = None ,boundary_grid = None ):
95+ def __init__ (self , hgrid ,bc_yaml = None ,boundary_segments = None ):
5896 """ initialize the boundary condition from yaml file"""
5997
6098 main_id = "bctides"
@@ -73,7 +111,25 @@ def __init__(self, hgrid,bc_yaml=None,boundary_grid=None):
73111
74112 ## if boundary grid is provided, use it to override the hgrid boundary
75113 ## grid
76- self .boundary_grid = boundary_grid
114+ self .boundary_segments = boundary_segments
115+ if self .boundary_segments is not None :
116+ ## also check if the number of open boundaries and names match
117+ ## with bctides open boundaries
118+ num_boundary_segments = len (self .boundary_segments ["linestrings" ])
119+ if num_boundary_segments != len (self .open_boundaries ):
120+ raise ValueError (
121+ "number of boundary segments from included open_boundary yaml does not match number of open boundaries in bctides YAML: %s vs %s"
122+ % (num_boundary_segments , len (self .open_boundaries ))
123+ )
124+ for i in range (num_boundary_segments ):
125+ bname_yaml = self .open_boundaries [i ]["name" ]
126+ bname_segment = self .boundary_segments ["linestrings" ][i ]["name" ]
127+ if bname_yaml != bname_segment :
128+ raise ValueError (
129+ "boundary name mismatch between included open_boundary YAML and bctides YAML: %s vs %s"
130+ % (bname_yaml , bname_segment )
131+ )
132+ update_mesh_open_boundaries (self .hgrid , self .boundary_segments )
77133
78134 self .elev_type = {
79135 "elev.th" : 1 ,
@@ -197,14 +253,38 @@ def write_bctides(self, bctides_file):
197253
198254
199255 hgrid = self .hgrid
256+
257+
258+ hgrd_open_boundaries = list (
259+ boundary
260+ for boundary in hgrid .boundaries
261+ if boundary .btype == BoundaryType .OPEN
262+ )
200263
201- if len (hgrid . boundaries ) < len (self .open_boundaries ):
264+ if len (hgrd_open_boundaries ) != len (self .open_boundaries ):
202265 raise ValueError (
203- "boundary YAML has more number of openbounary than model hgrid, YAML:%s hgrid:%s"
204- % (len (self .open_boundaries ), len (hgrid . boundaries ))
266+ "boundary YAML has different number of openbounary than model hgrid, YAML:%s hgrid:%s"
267+ % (len (self .open_boundaries ), len (hgrd_open_boundaries ))
205268 )
206269 else :
207270 num_open_boundaries = len (self .open_boundaries )
271+ ## check to make sure all open_boundaries name match
272+ ## with hgrid boundary names
273+ for i in range (num_open_boundaries ):
274+ bname_yaml = self .open_boundaries [i ]["name" ]
275+ if hgrd_open_boundaries [i ].comment is None :
276+ print ("Warning: hgrid boundary %s has no name, skipping boundary name check" % i )
277+ continue ## skip if hgrid boundary name is empty
278+ bname_hgrid = hgrd_open_boundaries [i ].comment .strip ().split ('"' )[1 ]
279+ ## if bname in hgrid is empty, skip the check
280+ if bname_hgrid == "" :
281+ continue
282+ if bname_yaml != bname_hgrid :
283+ raise ValueError (
284+ "boundary name mismatch between YAML and hgrid: %s vs %s"
285+ % (bname_yaml , bname_hgrid )
286+ )
287+
208288 num_tracer_mod = 0
209289 tracer_mods = []
210290 tracer_mod_pos = {}
@@ -519,8 +599,7 @@ def write_bctides(self, bctides_file):
519599
520600
521601if __name__ == "__main__" :
522- bcyaml = "bctides_main.yaml"
523- by = load_main_input (bcyaml )
602+ by = load_main_input ()
524603
525604
526605
0 commit comments