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

Last change on this file since 6347 was 6180, checked in by ole, 16 years ago

Changed documentation of create_mesh_from_regions to match changeset:6177

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
5import Numeric as num
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 an Exception will be raised.
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. See ticket:14
93
94    # Call underlying engine with or without caching
95    if use_cache is True:
96        try:
97            from anuga.caching import cache
98        except:
99            msg = 'Caching was requested, but caching module'+\
100                  'could not be imported'
101            raise msg
102
103
104        m = cache(_create_mesh_from_regions,
105                  args, kwargs,
106                  verbose=verbose,
107                  compression=False)
108    else:
109        m = apply(_create_mesh_from_regions,
110                  args, kwargs)
111
112    return m   
113       
114
115
116def _create_mesh_from_regions(bounding_polygon,
117                              boundary_tags,
118                              maximum_triangle_area=None,
119                              filename=None,                             
120                              interior_regions=None,
121                              interior_holes=None,
122                              poly_geo_reference=None,
123                              mesh_geo_reference=None,
124                              minimum_triangle_angle=28.0,
125                              fail_if_polygons_outside=True,
126                              verbose=True):
127    """_create_mesh_from_regions - internal function.
128
129    See create_mesh_from_regions for documentation.
130    """
131
132   
133    # check the segment indexes - throw an error if they are out of bounds
134    if boundary_tags is not None:
135        max_points = len(bounding_polygon)
136        for key in boundary_tags.keys():
137            if len([x for x in boundary_tags[key] if x > max_points-1]) >= 1:
138                msg = 'Boundary tag %s has segment out of bounds. '\
139                      %(str(key))
140                msg += 'Number of points in bounding polygon = %d' % max_points
141                raise SegmentError, msg
142
143        for i in range(max_points):
144            found = False
145            for tag in boundary_tags:
146                if i in boundary_tags[tag]:
147                    found = True
148            if found is False:
149                msg = 'Segment %d was not asigned a boundary_tag' %i
150                raise Exception, msg
151               
152
153   
154    #In addition I reckon the polygons could be of class Geospatial_data
155    #(DSG) If polygons were classes caching would break in places.
156
157    # Simple check
158    bounding_polygon = ensure_numeric(bounding_polygon, num.Float)
159    msg = 'Bounding polygon must be a list of points or an Nx2 array'
160    assert len(bounding_polygon.shape) == 2, msg
161    assert bounding_polygon.shape[1] == 2, msg   
162
163    #
164    if interior_regions is not None:
165       
166        # Test that all the interior polygons are inside the
167        # bounding_poly and throw out those that aren't fully
168        # included.  #Note, Both poly's have the same geo_ref,
169        # therefore don't take into account # geo_ref
170
171
172        polygons_inside_boundary = []
173        for interior_polygon, res in interior_regions:
174            indices = inside_polygon(interior_polygon, bounding_polygon,
175                                     closed = True, verbose = False)
176   
177            if len(indices) <> len(interior_polygon): 
178                msg = 'Interior polygon %s is not fully inside'\
179                      %(str(interior_polygon))
180                msg += ' bounding polygon: %s.' %(str(bounding_polygon))
181
182                if fail_if_polygons_outside is True:
183                    raise PolygonError, msg                   
184                else:
185                    msg += ' I will ignore it.'
186                    print msg
187
188            else:
189                polygons_inside_boundary.append([interior_polygon, res])
190               
191        # Record only those that were fully contained       
192        interior_regions = polygons_inside_boundary
193
194           
195   
196# the following segment of code could be used to Test that all the
197# interior polygons are inside the bounding_poly... however it might need
198# to be change a bit   
199#
200#count = 0
201#for i in range(len(interior_regions)):
202#    region = interior_regions[i]
203#    interior_polygon = region[0]
204#    if len(inside_polygon(interior_polygon, bounding_polygon,
205#                   closed = True, verbose = False)) <> len(interior_polygon):
206#        print 'WARNING: interior polygon %d is outside bounding polygon' %(i)
207#        count += 1
208
209#if count == 0:
210#    print 'interior regions OK'
211#else:
212#    print 'check out your interior polygons'
213#    print 'check %s in production directory' %figname
214#    import sys; sys.exit()
215   
216
217    if interior_holes is not None:       
218        # Test that all the interior polygons are inside the bounding_poly
219        for interior_polygon in interior_holes:
220            indices = inside_polygon(interior_polygon, bounding_polygon,
221                                     closed = True, verbose = False)
222   
223            if len(indices) <> len(interior_polygon): 
224                msg = 'Interior polygon %s is outside bounding polygon: %s'\
225                      %(str(interior_polygon), str(bounding_polygon))
226                raise PolygonError, msg
227
228    # Resolve geo referencing       
229    if mesh_geo_reference is None:
230        xllcorner = min(bounding_polygon[:,0])
231        yllcorner = min(bounding_polygon[:,1])   
232        #
233        if poly_geo_reference is None:
234            zone = DEFAULT_ZONE
235        else:
236            zone = poly_geo_reference.get_zone()
237            [(xllcorner,yllcorner)] = poly_geo_reference.get_absolute( \
238            [(xllcorner,yllcorner)])
239        # create a geo_ref, based on the llc of the bounding_polygon
240        mesh_geo_reference = Geo_reference(xllcorner = xllcorner,
241                                           yllcorner = yllcorner,
242                                           zone = zone)
243
244    m = Mesh(geo_reference=mesh_geo_reference)
245
246    # Do bounding polygon
247    m.add_region_from_polygon(bounding_polygon,
248                              segment_tags=boundary_tags,
249                              geo_reference=poly_geo_reference)
250
251    # Find one point inside region automatically
252    if interior_regions is not None:
253        excluded_polygons = []       
254        for polygon, res in interior_regions:
255            excluded_polygons.append( polygon )
256    else:
257        excluded_polygons = None
258
259    # Convert bounding poly to absolute values
260    # this sort of thing can be fixed with the geo_points class
261    if poly_geo_reference is not None:
262        bounding_polygon_absolute = \
263            poly_geo_reference.get_absolute(bounding_polygon)
264    else:
265        bounding_polygon_absolute = bounding_polygon
266   
267    inner_point = point_in_polygon(bounding_polygon_absolute)
268    inner = m.add_region(inner_point[0], inner_point[1])
269    inner.setMaxArea(maximum_triangle_area)
270
271    # Do interior regions
272#    if interior_regions is not None:   
273#        for polygon, res in interior_regions:
274#            m.add_region_from_polygon(polygon,
275#                                      geo_reference=poly_geo_reference)
276#            # convert bounding poly to absolute values
277#            if poly_geo_reference is not None:
278#                polygon_absolute = \
279#                    poly_geo_reference.get_absolute(polygon)
280#            else:
281#                polygon_absolute = polygon
282#            inner_point = point_in_polygon(polygon_absolute)
283#            region = m.add_region(inner_point[0], inner_point[1])
284#            region.setMaxArea(res)
285           
286           
287    if interior_regions is not None:   
288        for polygon, res in interior_regions:
289            m.add_region_from_polygon(polygon,
290                                      max_triangle_area=res,
291                                      geo_reference=poly_geo_reference)
292   
293           
294    # Do interior holes
295    if interior_holes is not None:   
296        for polygon in interior_holes:
297            m.add_hole_from_polygon(polygon,
298                                    geo_reference=poly_geo_reference)
299       
300
301
302
303    # NOTE (Ole): This was moved here as it is annoying if mesh is always
304    # stored irrespective of whether the computation
305    # was cached or not. This caused Domain to
306    # recompute as it has meshfile as a dependency
307
308    # Decide whether to store this mesh or return it   
309    if filename is None:
310        return m
311    else:
312        if verbose: print 'Generating mesh to file "%s"' %filename
313        m.generate_mesh(minimum_triangle_angle=minimum_triangle_angle,
314                        verbose=verbose)
315        m.export_mesh_file(filename)
316
317
Note: See TracBrowser for help on using the repository browser.