source: trunk/anuga_core/source/anuga/structures/riverwall.py @ 9130

Last change on this file since 9130 was 9130, checked in by davies, 10 years ago

Adding a smoothing_timescale to parallel_boyd_box_operator

File size: 27.1 KB
Line 
1import numpy
2
3class RiverWall:
4    """Define the elevation of 'riverwalls'.
5
6    These are located along each cell edge, and can have an elevation different
7    from the bed elevation.
8
9    For the DE algorithms, they are used in computing the 'z_half' value [if they
10    are greater than either edge elevation].
11
12    In addition, the DE fluxes at riverwalls are adjusted to agree with a weir relation,
13    so long as the riverwall is not too deeply submerged.
14
15    As of 22/04/2014, they are only implemented for DE0 and DE1 [the shallow water
16    component would be more difficult to implement with other algorithms]
17       
18    How the flux over the riverwall is computed:
19    # We have a riverwall, which is treated as a weir.
20    #
21    # Say the headwater-head is the upstream water depth above the weir elevation (min 0), and
22    #   the tailwater head is the downstream water depth above the weir elevation (min 0).
23    #   By definition headwater-head > tailwater-head.
24    #
25    # Let s = (headwater head) / (tailwater head), and h = (tailwater head)/(weir height)
26    #  where 'weir height' is the elevation of the weir crest above the minimum
27    #  of the left/right bed elevations
28    #
29    # Denote ID as the 'ideal' weir flow, computed from the hydraulic
30    # formula (including a submergence correction factor from Villemonte,
31    # 1947),
32    #      Q1 = 2/3*headwater_head*sqrt(g*2/3*headwater_head)*Qfactor
33    #      Q2 = 2/3*tailwater_head*sqrt(g*2/3*headwater_head)*Qfactor
34    # ID = Q1*(1-Q2/Q1)**0.385
35    #
36    # Denote SW as the 'shallow-water' weir flux, computed from the approximate
37    # reimann solver, where the mid-edge-elevation is the weir crest elevation.
38    # This makes clear sense for DE0 and DE1. Cell centroid stage/height/bed_elevation
39    # are used in the flux computation
40    #
41    # Then the flux over the weir is computed from:
42    #   w1 = min( max(s-s1, 0.)/(s2-s1), 1.0) # Factor describing relative submergence
43    #   w1' = min( max(h-h1,0.)/(h2-h1), 1.0) # Factor describing absolute submergence
44    #  flux_over_weir = (w1*SW + (1-w1)*ID)*( 1-w1') + (w1')*SW
45    #
46    # The key idea is that if s<s1, h<h1, then the ideal weir solution is
47    # used. Otherwise, we linearly blend with the SW solution,
48    # and the SW solution is used completely if s>s2 or h>h2
49
50    """
51   
52    def __init__(self, domain):
53        """Riverwall data structure
54
55        Allows reasonably efficient storage of riverwall elevations and hydraulic
56        properties
57
58        NOTE: In domain.edge_flux_type, riverwalls correspond to the value 1
59
60        RiverWall variables are initialised to dummy values, because even
61        if no riverwalls are used, some values have to be passed to the flux computation
62
63        Hydraulic parameters are
64        Qfactor -- Multiplicative factor for ideal weir relation (calibration coef)
65        s1 --  Submergence ratio at which we start blending with the shallow water solution (<s2)
66        s2 -- Submergence ratio at which we entirely use the shallow water solution  (>s1)
67        h1 -- Tailwater head / weir height at which we start blending with the shallow water solution (<h2)
68        h2 -- Tailwater head / weir height at which we entirely use the shallow water solution (>h1)
69
70        # Default riverwall hydraulic parameters
71        default_riverwallPar={'Qfactor':1.0, 
72                              's1': 0.9,     
73                              's2': 0.95,     
74                              'h1': 1.0,     
75                              'h2': 1.5       
76                              }
77
78        Other variables are:
79
80            riverwall_elevation -- Variable to hold riverwall elevations.
81                                   len = number of riverwall edges in the domain.
82                                   First entry corresponds to first riverwall edge in domain.edge_coordinates,
83                                   second entry to second riverwall edge in domain.edge_coordinates, etc
84
85            hydraulic_properties_rowIndex --  Variable to hold the row-index of the hydraulic properties table
86                                               len = number of riverwall edges
87                                                     in the domain, ordered like riverwall_elevation
88
89            riverwall_edges -- Holds indices of edges in domain which are riverwalls, ordered like riverwall_elevation
90
91            names -- list with the names of the riverwalls
92                     len = number of riverwalls which cover edges in the domain
93
94            hydraulic_variable_names -- Variables to hold the names of variables in columns of the hydraulic
95                                        properties table. THE ORDER IS IMPORTANT -- C code ASSUMES IT
96
97            ncol_hydraulic_properties -- Number of columns in the hydraulic properties table
98                                        [ = len(hydraulic_variable_names) ]
99
100            hydraulic_properties -- Array with the hydraulic parameters for each riverwall.
101                                      number of rows = number of riverwalls which cover edges in the domain
102                                      number of cols = number of hydraulic variable names
103
104                                   
105            input_riverwall_geo, input_riverwall_par -- holds input information
106
107        """
108        self.domain=domain
109
110        default_float=-9.0e+20
111        default_int=-9e+20
112        self.riverwall_elevation=numpy.array([default_float])
113
114        self.hydraulic_properties_rowIndex=numpy.array([default_int])
115
116        self.names=[ ]
117
118        # Default riverwall hydraulic parameters
119        self.default_riverwallPar={'Qfactor':1.0, 
120                                   's1': 0.9,     
121                                   's2': 0.95,     
122                                   'h1': 1.0,     
123                                   'h2': 1.5       
124                                   }
125
126        # DO NOT CHANGE THE ORDER OF hydraulic_variable_names
127        # It needs to match hard-coded assumptions in C [compute_fluxes_central]
128        # If you add a variable, append it to the end of hydraulic_variable_names
129        self.hydraulic_variable_names=('Qfactor', 's1', 's2', 'h1', 'h2')
130
131        self.ncol_hydraulic_properties=len(self.hydraulic_variable_names)
132        # Variable to hold the riverwall hydraulic properties in a table
133        #  number of rows = number of riverwalls which cover edges in the domain
134        #  number of cols = number of hydraulic variable names
135        self.hydraulic_properties=numpy.array([ [default_float] ])
136
137        # Variable to hold the indices of riverwall edges
138        #    len = number of riverwall edges in the domain
139        self.riverwall_edges=numpy.array([default_int])
140
141        # Input info
142        self.input_riverwall_geo=None
143        self.input_riverwallPar=None
144
145
146    def create_riverwalls(self, riverwalls, riverwallPar={ },
147                          default_riverwallPar={ },
148                          tol=1.0e-04, verbose=True):
149        """Add riverwalls at chosen locations along the mesh
150
151        As of 22/04/2014, these only work with DE0 and DE1 [for which the concept is natural]
152
153        The walls MUST EXACTLY COINCIDE with edges along the mesh
154       
155        You can force the mesh to do this by passing riverwalls.values()
156        to the 'breaklines' argument in the function create_mesh_from_regions. You
157        may also need to set the maximum_triangle_area for regions, if the breaklines
158        split the region.  Do this with the regionPtArea argument in
159        create_mesh_from_regions.
160
161        As of 22/04/2014, the computational method used here is very 'brute-force'
162        For each segment on each riverwall, every point in the mesh is checked to see
163        if it is on the segment. A possibly faster/less memory method would be to
164        'walk' through connected edges on the mesh.
165
166        Inputs:
167            riverwalls: Dictionary of '3D polygons', containing xyz locations of named riverwalls.
168
169                exampleRiverWalls = { # Left bank n1 --
170                                      'n1': [[1.0, 1000., 2.],
171                                             [1.0, 50., 3.]],
172                                      # Left bank n2
173                                       'n2': [[2.0, 30., 1.0],
174                                              [3.0, 20., 2.],
175                                              [2.5, 15., 1.5]]
176                                    }
177
178            riverwallPar: Dictionary containing a dictionary of named hydraulic parameters for each named riverwall
179                          If parameters are not provided, default values will be used.
180                          See the help for class 'RiverWall' for an explanation of these
181
182                exampleRiverWallPar = {'n2': {'Qfactor':0.5} }
183                    This would use a Qfactor of 0.5 for riverwall 'n2', while the other riverwall would have the default values
184
185            default_riverwallPar:  Dictionary containing default values of the riverwall parameters, to be used
186                                   if they are not explicitly set.
187                                   If not provided, defaults from __init__ are used. See the help for class 'RiverWall' for more info
188
189                example_default_riverwallPar = {'Qfactor':1.5, 
190                                                's1': 0.9,     
191                                                's2': 0.95,     
192                                                'h1': 1.0,     
193                                                'h2': 1.5       
194                                               }
195
196                example_default_riverwallPar = {'Qfactor':1.5, 
197                                                's1': 10000.,     
198                                                's2': 20000.     
199                                               } # Here h1/h2 defaults will come from __init__
200                 
201
202            tol: Edges will be assigned a riverwall elevation if they are within 'tol' of
203                 a segment in riverwalls. Round-off error means this should not be too small.
204
205            verbose: TRUE/FALSE Print lots of information
206
207        Outputs:
208            None, but it sets domain.edge_flux_type = 1 for every edge on a riverwall
209            Also, it adds a RiverWall object domain.riverwallData to the domain
210            The latter contains the riverwall heights, names, and hydraulic properties for each edge, in
211              a way we can pass in/out of C code.
212
213        """
214
215        if(verbose):       
216            print ' '
217            print 'WARNING: Riverwall is an experimental feature'
218            print '         At each riverwall edge, we place a thin "wall" between'
219            print '          the 2 edges -- so each sees its neighbour edge as having'
220            print '          bed elevation = max(levee height, neighbour bed elevation)'
221            print '         We also force the discharge with a weir relation, blended with'
222            print '          the shallow water flux solution as the ratio (min_head)/(weir_height) becomes '
223            print '          large, or the ratio (downstream_head)/(upstream_head) becomes large'
224            print ' '
225            print '  It works in parallel, but you must use domain.riverwallData.create_riverwall AFTER distributing the mesh'
226            print ' '
227
228        # NOTE: domain.riverwallData is initialised in shallow_water_domain.py for DE0 and DE1
229
230        domain=self.domain
231
232       
233        # Check flow algorithm
234        if(not domain.get_using_discontinuous_elevation()):
235            raise Exception, 'Riverwalls are currently only supported when domain.flow_algorithm="DE0" and "DE1"'
236
237        if(len(self.names)>0):
238            # Delete any existing riverwall data
239            # The function cannot presently be used to partially edit riverwall data
240            if(verbose):
241                print 'Warning: There seems to be existing riverwall data'
242                print 'It will be deleted and overwritten with this function call'
243            domain.riverwallData.__init__(domain)
244
245        # Store input parameters
246        # FIXME: Is this worth it?
247        self.input_riverwall_geo=riverwalls
248        self.input_riverwallPar=riverwallPar
249
250        # Update self.default_riverwallPar
251        for i in self.default_riverwallPar.keys():
252            if(default_riverwallPar.has_key(i)):
253                self.default_riverwallPar[i]=default_riverwallPar[i]
254
255        # Check that all the keys in default_riverwallPar are allowed
256        for i in default_riverwallPar.keys():
257            if(not self.default_riverwallPar.has_key(i)):
258                msg='Key ', i + ' in default_riverwallPar not recognized'
259                raise Exception, msg
260        # Final default river-wall parameters
261        default_riverwallPar=self.default_riverwallPar
262       
263        # Check that all named inputs in riverwallPar correspond to names in
264        # riverwall
265        for i in riverwallPar.keys():
266            if not riverwalls.has_key(i):
267                msg= 'Key ', i, ' in riverwallPar has no corresponding key in riverwall'
268                raise Exception, msg
269            #
270            # Check that all hydraulic parameter names in riverwallPar correspond
271            # to names in default_riverwallPar
272            #
273            for j in riverwallPar[i].keys():
274                if not default_riverwallPar.has_key(j):
275                    msg = 'Hydraulic parameter named ', j ,\
276                          ' not recognised in default_riverwallPar'
277                    raise Exception, msg
278       
279        if(verbose):
280            print 'Setting riverwall elevations ...'
281
282        # Set up geometry
283        exy=domain.edge_coordinates
284        llx=domain.mesh.geo_reference.get_xllcorner()
285        lly=domain.mesh.geo_reference.get_yllcorner()
286
287        # Temporary variables
288        from anuga.config import max_float
289        riverwall_elevation=exy[:,0]*0. - max_float
290        riverwall_Qfactor=exy[:,0]*0.
291        riverwall_rowIndex=exy[:,0]*0 -1.
292        riverwall_rowIndex.astype(int)
293
294        # Loop over all segments in each riverwall, and set its elevation
295        nw=range(len(riverwalls))
296        nw_names=riverwalls.keys() # Not guarenteed to be in deterministic order
297        for i in nw:
298            # Name of riverwall
299            riverwalli_name=nw_names[i]
300            # Look at the ith riverwall
301            riverwalli=riverwalls[riverwalli_name]
302
303            ns=len(riverwalli)-1
304
305            if(verbose):
306                print 'Wall ' + str(i) +' ....'
307
308            for j in range(ns):
309                if(verbose):
310                    print '    Segment ' + str(j) +' ....'
311                # Start and end xyz coordinates
312                start=riverwalli[j]
313                end=riverwalli[j+1]
314
315                if(len(start)!=3 | len(end)!=3):
316                    msg='Each riverwall coordinate must have at exactly 3 values [xyz]'
317                    raise Exception, msg
318
319                # Find length
320                segLen=( (start[0]-end[0])**2+(start[1]-end[1])**2)**0.5
321                if(segLen<tol):
322                    print 'Segment with length < tolerance ' + str(tol) +' ignored'
323                    continue 
324               
325                # Find edge indices which are within 'tol' of the segment
326                # We use a simple, inefficient method [but likely ok in practice
327                # except for very complex riverwalls]
328               
329                # Unit vector along segment
330                se_0=-(start[0]-end[0])/segLen
331                se_1=-(start[1]-end[1])/segLen
332
333                # Vector from 'start' to every point on mesh
334                # NOTE: We account for georeferencing
335                pv_0 = exy[:,0]-(start[0]-llx)
336                pv_1 = exy[:,1]-(start[1]-lly)
337
338                pvLen=( pv_0**2 + pv_1**2)**0.5
339
340                # Dot product of pv and se == along-segment distance of projection
341                # of each point onto segment
342                pv_dot_se = pv_0*se_0+pv_1*se_1
343                # Normal distance^2 of each point to segment
344                perp_len_sq = pvLen**2.-pv_dot_se**2.
345               
346                # Point is on a levee if the perpendicular distance is < tol,
347                # AND it is between start and end [within a tolerance]
348                onLevee=(perp_len_sq<tol**2)*(pv_dot_se > 0.-tol)*(pv_dot_se<segLen+tol)
349                onLevee=onLevee.nonzero()
350                onLevee=onLevee[0]
351                if(len(onLevee)==0):
352                    continue
353
354                if(verbose):
355                    print '       Finding ' + str(len(onLevee)) + ' edges on this segment '
356           
357                # Levee has Edge_flux_type=1 
358                domain.edge_flux_type[onLevee]=1
359     
360                # Get edge elevations as weighted averages of start/end elevations
361                w0=pv_dot_se[onLevee]/segLen
362                w0=w0*(w0>=0.0) # Enforce min of 0
363                w0=w0*(w0<=1.0) + 1.0*(w0>1.0) # Max of 1
364                riverwall_elevation[onLevee]= start[2]*(1.0-w0)+w0*end[2]
365
366                # Record row index
367                riverwall_rowIndex[onLevee] = i
368
369        # Now, condense riverwall_elevation to array with length = number of riverwall edges
370        #
371        # FIXME: We do this to avoid storing a riverwall_elevation for every edge in the mesh
372        #        However, the data structure ends up being quite complex -- maybe there is a better way?
373        #
374        # The zeroth index in domain.edge_flux_type which = 1 will correspond to riverwall_elevation[0]
375        # The first index will correspond to riverwall_elevation[1]
376        # etc
377        #
378        riverwallInds=(domain.edge_flux_type==1).nonzero()[0]
379        # elevation
380        self.riverwall_elevation=\
381            riverwall_elevation[riverwallInds]
382        # corresponding row in the hydraulic properties table
383        self.hydraulic_properties_rowIndex=\
384            riverwall_rowIndex[riverwallInds].astype(int)
385        # index of edges which are riverwalls [FIXME: Not really needed, can easily back-calculate from edge_flux_type]
386        self.riverwall_edges=riverwallInds
387
388        # Record the names of the riverwalls
389        self.names=nw_names
390
391       
392        # Now create the hydraulic properties table
393
394        # Temporary variable to hold hydraulic properties table
395        # This will have as many rows are there are distinct riverwalls,
396        # and as many columns as there are hydraulic variables
397        hydraulicTmp=numpy.zeros((len(riverwalls), len(default_riverwallPar)))*numpy.nan
398       
399        if(verbose):
400            print ' ' 
401        # Loop over every riverwall / hydraulic parameter, and set its value
402        for i in nw:
403            # Get the riverwall's name and specified parameters
404            name_riverwalli=nw_names[i]
405            if(riverwallPar.has_key(name_riverwalli)):
406                riverwalli_Par=riverwallPar[name_riverwalli]
407            else:
408                riverwalli_Par=None
409
410            # Set the ith riverwall's hydraulic properties
411            for j, hydraulicVar in enumerate(self.hydraulic_variable_names):   
412                if((riverwalli_Par is not None) and (riverwalli_Par.has_key(hydraulicVar))):
413                    if(verbose): 
414                        print 'Using provided ', hydraulicVar,\
415                           riverwalli_Par[hydraulicVar], ' for riverwall ', name_riverwalli
416                    hydraulicTmp[i,j]=riverwalli_Par[hydraulicVar] 
417                else:
418                    if(verbose): 
419                        print 'Using default ',  hydraulicVar,\
420                            default_riverwallPar[hydraulicVar], ' for riverwall ', name_riverwalli
421                    hydraulicTmp[i,j]=default_riverwallPar[hydraulicVar]
422
423        if(verbose):
424            print ' '
425
426        # Check that s1 < s2
427        for i in nw:
428            if(hydraulicTmp[i,1]>= hydraulicTmp[i,2]):
429                msg = 's1 >= s2 on riverwall ' + nw_names[i] +'. This is not allowed' 
430                raise Exception, msg
431            if( (hydraulicTmp[i,1]<0.) or (hydraulicTmp[i,2] < 0.)):
432                raise Exception, 's1 and s2 must be positive, with s1<s2'
433
434        # Check that h1 < h2
435        for i in nw:
436            if(hydraulicTmp[i,3]>= hydraulicTmp[i,4]):
437                msg = 'h1 >= h2 on riverwall ' + nw_names[i] +'. This is not allowed' 
438                raise Exception, msg
439            if((hydraulicTmp[i,3]<0.) or (hydraulicTmp[i,4] < 0.)):
440                raise Exception, 'h1 and h2 must be positive, with h1<h2'
441       
442        # Define the hydraulic properties
443        self.hydraulic_properties=hydraulicTmp
444
445        # Check for riverwall 'connectedness' errors (e.g. theoretically possible
446        # to miss an edge due to round-off)
447        self.check_riverwall_connectedness(domain, verbose,tol=tol)
448         
449        return()
450   
451    #####################################################################################
452
453    def get_centroids_corresponding_to_edgeInds(self, riverwalledgeInds):
454        """
455          Get indices of centroids containing edges with indices riverwalledgeInds
456        """
457        riverwallCentInds=numpy.floor(riverwalledgeInds/3.)
458        riverwallCentInds=riverwallCentInds.astype(int)
459
460        return riverwallCentInds
461
462    #####################################################################################
463
464    def get_vertices_corresponding_to_edgeInds(self, riverwalledgeInds, tol=1.0e-04):
465        """
466         Get indices of vertices corresponding to edges at index riverwalledgeInds
467         Since each edge has 2 vertices, use V1 and V2
468         We have to work to compute these, I can't see a simple formula
469        """
470
471        domain=self.domain
472
473        riverwallCentInds=self.get_centroids_corresponding_to_edgeInds(riverwalledgeInds)
474
475        rwV0Inds=3*riverwallCentInds #+((resid+1)%3)
476        rwV1Inds=3*riverwallCentInds+1 #((resid+2)%3)
477        rwV2Inds=3*riverwallCentInds+2 #((resid+2)%3)
478
479        # Find which 2 vertices have the edge value, by testing the
480        # x coordinate.
481        X01=0.5*(domain.vertex_coordinates[rwV0Inds,0]+domain.vertex_coordinates[rwV1Inds,0]) 
482        k01=(abs(X01- domain.edge_coordinates[riverwalledgeInds,0])<tol)
483        X12=0.5*(domain.vertex_coordinates[rwV2Inds,0]+domain.vertex_coordinates[rwV1Inds,0])
484        k12=(abs(X12 - domain.edge_coordinates[riverwalledgeInds,0])<tol)
485        X02=0.5*(domain.vertex_coordinates[rwV2Inds,0]+domain.vertex_coordinates[rwV0Inds,0])
486        k02=(abs(X02 - domain.edge_coordinates[riverwalledgeInds,0])<tol)
487
488        riverwallV2Inds=riverwallCentInds*0
489        riverwallV1Inds=riverwallCentInds*0
490     
491        t1=(k01==1).nonzero()[0]
492        riverwallV2Inds[t1]=rwV0Inds[t1]
493        riverwallV1Inds[t1]=rwV1Inds[t1]
494       
495        t1=(k12==1).nonzero()[0]
496        riverwallV2Inds[t1]=rwV2Inds[t1]
497        riverwallV1Inds[t1]=rwV1Inds[t1]
498       
499        t1=(k02==1).nonzero()[0]
500        riverwallV2Inds[t1]=rwV0Inds[t1]
501        riverwallV1Inds[t1]=rwV2Inds[t1]
502
503        return riverwallV1Inds, riverwallV2Inds
504   
505    #####################################################################################
506
507    def check_riverwall_connectedness(self, warn_only=False, verbose=True, tol=1.0e-04):
508        """
509            We expect riverwalls to be connected [unless they pass over a hole]
510            However, round-off could potentially cause riverwalls to be dis-connected
511            Use this routine to check for that
512
513            Basically, we search for edges which are connected to vertices which
514                themselves are not connected to other edges
515           
516            For a continuous riverwall, this should only occur twice (at the end points)
517
518            Otherwise, the riverwall appears discontinous
519        """
520
521        domain=self.domain
522
523        if(len(self.names)==0):
524            print 'There are no riverwalls'
525            return
526
527        # Shorthand notation
528        rwd=self
529           
530        for i, name in enumerate(rwd.names):
531            # Get indices of edges on this riverwall
532            riverwalledgeInds=rwd.riverwall_edges[(rwd.hydraulic_properties_rowIndex==i).nonzero()[0]]
533            # Get their corresponding centroids
534            riverwallCentInds=rwd.get_centroids_corresponding_to_edgeInds(riverwalledgeInds)
535            # Get their corresponding vertices
536            riverwallV1Inds, riverwallV2Inds = rwd.get_vertices_corresponding_to_edgeInds(riverwalledgeInds, tol=tol)
537
538            # With discontinuous triangles, we expect edges to occur twice
539            # Let's remove duplicates to simplify the analysis
540            repeat=riverwalledgeInds*0
541            lre=len(riverwalledgeInds)
542            # edge coordinates as a complex number, for easy equality checking
543            complex_edge_coordinates=domain.edge_coordinates[riverwalledgeInds,0]+\
544                                     1j*domain.edge_coordinates[riverwalledgeInds,1]
545            for j in range(lre-1):
546                # Ignore if already checked
547                if(repeat[j]==1):
548                    continue 
549                # Check for a dupulicate 
550                dups=(complex_edge_coordinates[(j+1):lre]==complex_edge_coordinates[j]).nonzero()[0]
551                if(len(dups)>0):
552                    repeat[dups+j+1]=1
553           
554            unique_riverwall_edge_indices=(repeat==0).nonzero()[0]
555
556            # Finally, get 'unqiue' edges in the riverwall
557            uEdges=riverwalledgeInds[unique_riverwall_edge_indices]
558            #uCentroids=riverwallCentInds[unique_riverwall_edge_indices]
559            uV1=riverwallV1Inds[unique_riverwall_edge_indices]
560            uV2=riverwallV2Inds[unique_riverwall_edge_indices]
561
562            # Next, count how many times each vertex value occurs.
563            # For a 'connected' riverwall, we only want 2 edges where a vertex occurs only once.
564            lure=len(uEdges)
565            complex_v1_coordinates=domain.vertex_coordinates[uV1,0]+\
566                                   1j*domain.vertex_coordinates[uV1,1]
567            complex_v2_coordinates=domain.vertex_coordinates[uV2,0]+\
568                                   1j*domain.vertex_coordinates[uV2,1]
569            v1Counter=uEdges*0
570            v2Counter=uEdges*0
571            for j in range(lure):
572                v1Counter[j]=(complex_v1_coordinates==complex_v1_coordinates[j]).sum()+\
573                             (complex_v2_coordinates==complex_v1_coordinates[j]).sum()
574                v2Counter[j]=(complex_v1_coordinates==complex_v2_coordinates[j]).sum()+\
575                             (complex_v2_coordinates==complex_v2_coordinates[j]).sum()
576
577            num_disconnected_edges=(v1Counter==1).sum()+(v2Counter==1).sum()
578           
579            if(verbose):   
580                print 'There are ', num_disconnected_edges, ' vertices with only 1 connection on riverwall ', name
581
582            if(num_disconnected_edges==0):
583                print 'Riverwall '+name+' is not on this mesh [typical for a sub-mesh in parallel]'
584            elif(num_disconnected_edges==2):
585                if(verbose):
586                    print "  That's Good, it means the wall is continuous"
587                    print ' '
588            else:
589                msg='Riverwall ' + name +', appears to be discontinuous, possibly due to round-off issues,'+\
590                    ' be careful [try adjusting tol, or use warn_only=True to avoid error] '
591                if(warn_only):
592                    print msg
593                else:
594                    raise Exception, msg
595
596        return
597
Note: See TracBrowser for help on using the repository browser.