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

Last change on this file since 5571 was 4888, checked in by duncan, 16 years ago

tweaking the tagging of regions

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