source: anuga_core/source/anuga/pmesh/mesh_interface.py @ 5866

Last change on this file since 5866 was 5717, checked in by duncan, 17 years ago

adding a data check

File size: 11.9 KB
Line 
1
2from anuga.coordinate_transforms.geo_reference import Geo_reference,DEFAULT_ZONE
3from anuga.utilities.polygon import  point_in_polygon ,populate_polygon
4from anuga.utilities.numerical_tools import ensure_numeric
5from Numeric import Float
6from anuga.utilities.polygon import inside_polygon
7
8
9
10# This is due to pmesh being a package and a module and
11# the current dir being unknown
12try:
13    from anuga.pmesh.mesh import Mesh
14except ImportError: 
15    from mesh import Mesh
16
17import exceptions
18class PolygonError(exceptions.Exception): pass
19class SegmentError(exceptions.Exception): pass
20
21def create_mesh_from_regions(bounding_polygon,
22                             boundary_tags,
23                             maximum_triangle_area=None,
24                             filename=None,
25                             interior_regions=None,
26                             interior_holes=None,
27                             poly_geo_reference=None,
28                             mesh_geo_reference=None,
29                             minimum_triangle_angle=28.0,
30                             fail_if_polygons_outside=True,
31                             use_cache=False,
32                             verbose=True):
33    """Create mesh from bounding polygons, and resolutions.
34
35    bounding_polygon is a list of points in Eastings and Northings,
36    relative to the poly_geo_reference.
37
38    Boundary tags is a dictionary of symbolic tags. For every tag there
39    is a list of indices referring to segments associated with that tag.
40    If a segment is omitted it will be assigned the default tag ''.
41
42    maximum_triangle_area is the maximal area per triangle
43    for the bounding polygon, excluding the  interior regions.
44
45    Interior_regions is a list of tuples consisting of (polygon,
46    resolution) for each region to be separately refined. Do not have
47    polygon lines cross or be on-top of each other.  Also do not have
48    polygon close to each other.
49   
50    NOTE: If a interior_region is outside the bounding_polygon it should
51    throw an error
52   
53    Interior_holes is a list of ploygons for each hole.
54
55    This function does not allow segments to share points - use underlying
56    pmesh functionality for that
57
58    poly_geo_reference is the geo_reference of the bounding polygon and
59    the interior polygons.
60    If none, assume absolute.  Please pass one though, since absolute
61    references have a zone.
62   
63    mesh_geo_reference is the geo_reference of the mesh to be created.
64    If none is given one will be automatically generated.  It was use
65    the lower left hand corner of  bounding_polygon (absolute)
66    as the x and y values for the geo_ref.
67   
68    Returns the mesh instance if no filename is given
69
70    Note, interior regions should be fully nested, as overlaps may cause
71    unintended resolutions.
72
73    fail_if_polygons_outside: If True (the default) Exception in thrown
74    where interior polygons fall outside bounding polygon. If False, these
75    will be ignored and execution continued.
76       
77   
78    """
79   
80    # Build arguments and keyword arguments for use with caching or apply.
81    args = (bounding_polygon,
82            boundary_tags)
83   
84    kwargs = {'maximum_triangle_area': maximum_triangle_area,
85              'filename': filename,
86              'interior_regions': interior_regions,
87              'interior_holes': interior_holes,
88              'poly_geo_reference': poly_geo_reference,
89              'mesh_geo_reference': mesh_geo_reference,
90              'minimum_triangle_angle': minimum_triangle_angle,
91              'fail_if_polygons_outside': fail_if_polygons_outside,
92              'verbose': verbose}   # FIXME (Ole): Should be bypassed one day
93                                    # What should be bypassed? Verbose?
94   
95    #print 'kwargs', kwargs
96
97    # Call underlying engine with or without caching
98    if use_cache is True:
99        try:
100            from anuga.caching import cache
101        except:
102            msg = 'Caching was requested, but caching module'+\
103                  'could not be imported'
104            raise msg
105
106
107        m = cache(_create_mesh_from_regions,
108                  args, kwargs,
109                  verbose=verbose,
110                  compression=False)
111    else:
112        m = apply(_create_mesh_from_regions,
113                  args, kwargs)
114
115    return m   
116       
117
118
119def _create_mesh_from_regions(bounding_polygon,
120                              boundary_tags,
121                              maximum_triangle_area=None,
122                              filename=None,                             
123                              interior_regions=None,
124                              interior_holes=None,
125                              poly_geo_reference=None,
126                              mesh_geo_reference=None,
127                              minimum_triangle_angle=28.0,
128                              fail_if_polygons_outside=True,
129                              verbose=True):
130    """_create_mesh_from_regions - internal function.
131
132    See create_mesh_from_regions for documentation.
133    """
134
135   
136    # check the segment indexes - throw an error if they are out of bounds
137    if boundary_tags is not None:
138        max_segs = len(bounding_polygon)
139        for key in boundary_tags.keys():
140            if len([x for x in boundary_tags[key] if x > max_segs-1]) >= 1:
141                msg = 'Boundary tag %s has segment out of bounds.'\
142                      %(str(key))
143                raise SegmentError, msg
144
145       
146
147   
148    #In addition I reckon the polygons could be of class Geospatial_data
149    #(DSG) If polygons were classes caching would break in places.
150
151    # Simple check
152    bounding_polygon = ensure_numeric(bounding_polygon, Float)
153    msg = 'Bounding polygon must be a list of points or an Nx2 array'
154    assert len(bounding_polygon.shape) == 2, msg
155    assert bounding_polygon.shape[1] == 2, msg   
156
157    #
158    if interior_regions is not None:
159       
160        # Test that all the interior polygons are inside the
161        # bounding_poly and throw out those that aren't fully
162        # included.  #Note, Both poly's have the same geo_ref,
163        # therefore don't take into account # geo_ref
164
165
166        polygons_inside_boundary = []
167        for interior_polygon, res in interior_regions:
168            indices = inside_polygon(interior_polygon, bounding_polygon,
169                                     closed = True, verbose = False)
170   
171            if len(indices) <> len(interior_polygon): 
172                msg = 'Interior polygon %s is not fully inside'\
173                      %(str(interior_polygon))
174                msg += ' bounding polygon: %s.' %(str(bounding_polygon))
175
176                if fail_if_polygons_outside is True:
177                    raise PolygonError, msg                   
178                else:
179                    msg += ' I will ignore it.'
180                    print msg
181
182            else:
183                polygons_inside_boundary.append([interior_polygon, res])
184               
185        # Record only those that were fully contained       
186        interior_regions = polygons_inside_boundary
187
188           
189   
190# the following segment of code could be used to Test that all the
191# interior polygons are inside the bounding_poly... however it might need
192# to be change a bit   
193#
194#count = 0
195#for i in range(len(interior_regions)):
196#    region = interior_regions[i]
197#    interior_polygon = region[0]
198#    if len(inside_polygon(interior_polygon, bounding_polygon,
199#                   closed = True, verbose = False)) <> len(interior_polygon):
200#        print 'WARNING: interior polygon %d is outside bounding polygon' %(i)
201#        count += 1
202
203#if count == 0:
204#    print 'interior regions OK'
205#else:
206#    print 'check out your interior polygons'
207#    print 'check %s in production directory' %figname
208#    import sys; sys.exit()
209   
210
211    if interior_holes is not None:       
212        # Test that all the interior polygons are inside the bounding_poly
213        for interior_polygon in interior_holes:
214            indices = inside_polygon(interior_polygon, bounding_polygon,
215                                     closed = True, verbose = False)
216   
217            if len(indices) <> len(interior_polygon): 
218                msg = 'Interior polygon %s is outside bounding polygon: %s'\
219                      %(str(interior_polygon), str(bounding_polygon))
220                raise PolygonError, msg
221
222    # Resolve geo referencing       
223    if mesh_geo_reference is None:
224        xllcorner = min(bounding_polygon[:,0])
225        yllcorner = min(bounding_polygon[:,1])   
226        #
227        if poly_geo_reference is None:
228            zone = DEFAULT_ZONE
229        else:
230            zone = poly_geo_reference.get_zone()
231            [(xllcorner,yllcorner)] = poly_geo_reference.get_absolute( \
232            [(xllcorner,yllcorner)])
233        # create a geo_ref, based on the llc of the bounding_polygon
234        mesh_geo_reference = Geo_reference(xllcorner = xllcorner,
235                                           yllcorner = yllcorner,
236                                           zone = zone)
237
238    m = Mesh(geo_reference=mesh_geo_reference)
239
240    # Do bounding polygon
241    m.add_region_from_polygon(bounding_polygon,
242                              segment_tags=boundary_tags,
243                              geo_reference=poly_geo_reference)
244
245    # Find one point inside region automatically
246    if interior_regions is not None:
247        excluded_polygons = []       
248        for polygon, res in interior_regions:
249            excluded_polygons.append( polygon )
250    else:
251        excluded_polygons = None
252
253    # Convert bounding poly to absolute values
254    # this sort of thing can be fixed with the geo_points class
255    if poly_geo_reference is not None:
256        bounding_polygon_absolute = \
257            poly_geo_reference.get_absolute(bounding_polygon)
258    else:
259        bounding_polygon_absolute = bounding_polygon
260   
261    inner_point = point_in_polygon(bounding_polygon_absolute)
262    inner = m.add_region(inner_point[0], inner_point[1])
263    inner.setMaxArea(maximum_triangle_area)
264
265    # Do interior regions
266#    if interior_regions is not None:   
267#        for polygon, res in interior_regions:
268#            m.add_region_from_polygon(polygon,
269#                                      geo_reference=poly_geo_reference)
270#            # convert bounding poly to absolute values
271#            if poly_geo_reference is not None:
272#                polygon_absolute = \
273#                    poly_geo_reference.get_absolute(polygon)
274#            else:
275#                polygon_absolute = polygon
276#            inner_point = point_in_polygon(polygon_absolute)
277#            region = m.add_region(inner_point[0], inner_point[1])
278#            region.setMaxArea(res)
279           
280           
281    if interior_regions is not None:   
282        for polygon, res in interior_regions:
283            m.add_region_from_polygon(polygon,
284                                      max_triangle_area=res,
285                                      geo_reference=poly_geo_reference)
286   
287           
288    # Do interior holes
289    if interior_holes is not None:   
290        for polygon in interior_holes:
291            m.add_hole_from_polygon(polygon,
292                                    geo_reference=poly_geo_reference)
293       
294
295
296
297    # NOTE (Ole): This was moved here as it is annoying if mesh is always
298    # stored irrespective of whether the computation
299    # was cached or not. This caused Domain to
300    # recompute as it has meshfile as a dependency
301
302    # Decide whether to store this mesh or return it   
303    if filename is None:
304        return m
305    else:
306        if verbose: print 'Generating mesh to file "%s"' %filename
307        m.generate_mesh(minimum_triangle_angle=minimum_triangle_angle,
308                        verbose=verbose)
309        m.export_mesh_file(filename)
310
311
Note: See TracBrowser for help on using the repository browser.