def create_mesh_from_regions(bounding_polygon, boundary_tags, maximum_triangle_area=None, filename=None, interior_regions=None, interior_holes=None, hole_tags=None, poly_geo_reference=None, mesh_geo_reference=None, minimum_triangle_angle=28.0, fail_if_polygons_outside=True, breaklines=None, use_cache=False, verbose=True, regionPtArea=None): """Create mesh from bounding polygons, and resolutions. bounding_polygon is a list of points in Eastings and Northings, relative to the poly_geo_reference. Boundary tags is a dictionary of symbolic tags. For every tag there is a list of indices referring to segments associated with that tag. If a segment is omitted an Exception will be raised. maximum_triangle_area is the maximal area per triangle for the bounding polygon, excluding the interior regions. Interior_regions is a list of tuples consisting of (polygon, resolution) for each region to be separately refined. Do not have polygon lines cross or be on-top of each other. Also do not have polygon close to each other. NOTE: If a interior_region is outside the bounding_polygon it should throw an error Interior_holes is a list of polygons for each hole. hole_tags is an optional list of boundary tags for the holes, see boundary_tags parameter. This function does not allow segments to share points - use underlying pmesh functionality for that poly_geo_reference is the geo_reference of the bounding polygon and the interior polygons. If none, assume absolute. Please pass one though, since absolute references have a zone. mesh_geo_reference is the geo_reference of the mesh to be created. If none is given one will be automatically generated. It was use the lower left hand corner of bounding_polygon (absolute) as the x and y values for the geo_ref. breaklines is a list of polygons. These lines will be preserved by the triangulation algorithm - useful for coastlines, walls, etc. The polygons are not closed. Returns the mesh instance if no filename is given Note, interior regions should be fully nested, as overlaps may cause unintended resolutions. fail_if_polygons_outside: If True (the default) Exception in thrown where interior polygons fall outside bounding polygon. If False, these will be ignored and execution continued. """ if verbose: log.resource_usage_timing(log.logging.INFO, "start_") if verbose: log.timingInfo("maximum_triangle_area, " + str(maximum_triangle_area)) if verbose: log.timingInfo("minimum_triangle_angle, " + str(minimum_triangle_angle)) if verbose: log.timingInfo("startMesh, '%s'" % log.CurrentDateTime()) # Build arguments and keyword arguments for use with caching or apply. args = (bounding_polygon, boundary_tags) kwargs = {'maximum_triangle_area': maximum_triangle_area, 'filename': filename, 'interior_regions': interior_regions, 'interior_holes': interior_holes, 'hole_tags': hole_tags, 'poly_geo_reference': poly_geo_reference, 'mesh_geo_reference': mesh_geo_reference, 'minimum_triangle_angle': minimum_triangle_angle, 'fail_if_polygons_outside': fail_if_polygons_outside, 'breaklines': breaklines, 'verbose': verbose, 'regionPtArea': regionPtArea} # FIXME (Ole): Should be bypassed one day. See ticket:14 # Call underlying engine with or without caching if use_cache is True: try: from anuga.caching import cache except: msg = 'Caching was requested, but caching module'+\ 'could not be imported' raise Exception(msg) m = cache(_create_mesh_from_regions, args, kwargs, verbose=verbose, compression=False) else: m = apply(_create_mesh_from_regions, args, kwargs) return m
def create_mesh_from_regions(bounding_polygon, boundary_tags, maximum_triangle_area=None, filename=None, interior_regions=None, interior_holes=None, hole_tags=None, poly_geo_reference=None, mesh_geo_reference=None, minimum_triangle_angle=28.0, fail_if_polygons_outside=True, breaklines=None, use_cache=False, verbose=True, regionPtArea=None): """Create mesh from bounding polygons, and resolutions. bounding_polygon is a list of points in Eastings and Northings, relative to the poly_geo_reference. Boundary tags is a dictionary of symbolic tags. For every tag there is a list of indices referring to segments associated with that tag. If a segment is omitted an Exception will be raised. maximum_triangle_area is the maximal area per triangle for the bounding polygon, excluding the interior regions. Interior_regions is a list of tuples consisting of (polygon, resolution) for each region to be separately refined. Do not have polygon lines cross or be on-top of each other. Also do not have polygon close to each other. NOTE: If a interior_region is outside the bounding_polygon it should throw an error Interior_holes is a list of polygons for each hole. hole_tags is an optional list of boundary tags for the holes, see boundary_tags parameter. This function does not allow segments to share points - use underlying pmesh functionality for that poly_geo_reference is the geo_reference of the bounding polygon and the interior polygons. If none, assume absolute. Please pass one though, since absolute references have a zone. mesh_geo_reference is the geo_reference of the mesh to be created. If none is given one will be automatically generated. It was use the lower left hand corner of bounding_polygon (absolute) as the x and y values for the geo_ref. breaklines is a list of polygons. These lines will be preserved by the triangulation algorithm - useful for coastlines, walls, etc. The polygons are not closed. Returns the mesh instance if no filename is given Note, interior regions should be fully nested, as overlaps may cause unintended resolutions. fail_if_polygons_outside: If True (the default) Exception in thrown where interior polygons fall outside bounding polygon. If False, these will be ignored and execution continued. """ if verbose: log.resource_usage_timing(log.logging.INFO, "start_") if verbose: log.timingInfo("maximum_triangle_area, " + str(maximum_triangle_area)) if verbose: log.timingInfo("minimum_triangle_angle, " + str(minimum_triangle_angle)) if verbose: log.timingInfo("startMesh, '%s'" % log.CurrentDateTime()) # Build arguments and keyword arguments for use with caching or apply. args = (bounding_polygon, boundary_tags) kwargs = { 'maximum_triangle_area': maximum_triangle_area, 'filename': filename, 'interior_regions': interior_regions, 'interior_holes': interior_holes, 'hole_tags': hole_tags, 'poly_geo_reference': poly_geo_reference, 'mesh_geo_reference': mesh_geo_reference, 'minimum_triangle_angle': minimum_triangle_angle, 'fail_if_polygons_outside': fail_if_polygons_outside, 'breaklines': breaklines, 'verbose': verbose, 'regionPtArea': regionPtArea } # FIXME (Ole): Should be bypassed one day. See ticket:14 # Call underlying engine with or without caching if use_cache is True: try: from anuga.caching import cache except: msg = 'Caching was requested, but caching module'+\ 'could not be imported' raise Exception(msg) m = cache(_create_mesh_from_regions, args, kwargs, verbose=verbose, compression=False) else: m = apply(_create_mesh_from_regions, args, kwargs) return m
def __init__(self, nodes, triangles, geo_reference=None, use_inscribed_circle=False, verbose=False): """Build triangular 2d mesh from nodes and triangle information Input: nodes: x,y coordinates represented as a sequence of 2-tuples or a Nx2 numeric array of floats. triangles: sequence of 3-tuples or Mx3 numeric array of non-negative integers representing indices into the nodes array. georeference (optional): If specified coordinates are assumed to be relative to this origin. """ if verbose: log.critical('General_mesh: Building basic mesh structure') self.use_inscribed_circle = use_inscribed_circle self.triangles = num.array(triangles, num.int) if verbose: log.timingInfo("numTriangles, " + str(self.triangles.shape[0])) self.nodes = num.array(nodes, num.float) # Register number of elements and nodes self.number_of_triangles = N = self.triangles.shape[0] self.number_of_nodes = self.nodes.shape[0] # FIXME: this stores a geo_reference, but when coords are returned # This geo_ref is not taken into account! if geo_reference is None: self.geo_reference = Geo_reference() # Use defaults else: self.geo_reference = geo_reference # Input checks msg = ('Triangles must an Mx3 numeric array or a sequence of 3-tuples. ' 'The supplied array has the shape: %s' % str(self.triangles.shape)) assert len(self.triangles.shape) == 2, msg msg = ('Nodes must an Nx2 numeric array or a sequence of 2-tuples' 'The supplied array has the shape: %s' % str(self.nodes.shape)) assert len(self.nodes.shape) == 2, msg msg = 'Vertex indices reference non-existing coordinate sets' assert num.max(self.triangles) < self.nodes.shape[0], msg # FIXME: Maybe move to statistics? # Or use with get_extent xy_extent = [min(self.nodes[:,0]), min(self.nodes[:,1]), max(self.nodes[:,0]), max(self.nodes[:,1])] self.xy_extent = num.array(xy_extent, num.float) # Allocate space for geometric quantities self.normals = num.zeros((N, 6), num.float) self.areas = num.zeros(N, num.float) self.edgelengths = num.zeros((N, 3), num.float) # Get x,y coordinates for all triangle vertices and store self.centroid_coordinates = num.zeros((N, 2), num.float) #Allocate space for geometric quantities self.radii = num.zeros(N, num.float) # Get x,y coordinates for all triangle vertices and store self.vertex_coordinates = V = self.compute_vertex_coordinates() # Get x,y coordinates for all triangle edge midpoints and store self.edge_midpoint_coordinates = self.compute_edge_midpoint_coordinates() # Initialise each triangle if verbose: log.critical('General_mesh: Computing areas, normals, ' 'edgelengths, centroids and radii') # Calculate Areas V0 = V[0:3*N:3, :] V1 = V[1:3*N:3, :] V2 = V[2:3*N:3, :] # Area x0 = V0[:,0] y0 = V0[:,1] x1 = V1[:,0] y1 = V1[:,1] x2 = V2[:,0] y2 = V2[:,1] self.areas[:] = -((x1*y0-x0*y1) + (x2*y1-x1*y2) + (x0*y2-x2*y0))/2.0 #areas = -((x0-x1)*(y2-y1) - (y0-y1)*(x2-x1))/2.0 #assert num.allclose(self.areas, areas) ind = num.where(self.areas <= 0.0) msg = 'Degenerate Triangle(s) '+str(ind[0]) assert num.all(self.areas > 0.0), msg #print V.shape, V0.shape, V1.shape, V2.shape # #print E.shape, E[0:3*M:3, :].shape, E[1:3*M:3, :].shape, E[2:3*M:3, :].shape # E[0:3*M:3, :] = 0.5*(V1+V2) # E[1:3*M:3, :] = 0.5*(V2+V0) # E[2:3*M:3, :] = 0.5*(V0+V1) i0 = self.triangles[:,0] i1 = self.triangles[:,1] i2 = self.triangles[:,2] assert num.allclose( x0, self.nodes[i0,0] ) assert num.allclose( y0, self.nodes[i0,1] ) assert num.allclose( x1, self.nodes[i1,0] ) assert num.allclose( y1, self.nodes[i1,1] ) assert num.allclose( x2, self.nodes[i2,0] ) assert num.allclose( y2, self.nodes[i2,1] ) xn0 = x2-x1 yn0 = y2-y1 l0 = num.sqrt(xn0**2 + yn0**2) xn0 /= l0 yn0 /= l0 xn1 = x0-x2 yn1 = y0-y2 l1 = num.sqrt(xn1**2 + yn1**2) xn1 /= l1 yn1 /= l1 xn2 = x1-x0 yn2 = y1-y0 l2 = num.sqrt(xn2**2 + yn2**2) xn2 /= l2 yn2 /= l2 # Compute and store self.normals[:,0] = yn0 self.normals[:,1] = -xn0 self.normals[:,2] = yn1 self.normals[:,3] = -xn1 self.normals[:,4] = yn2 self.normals[:,5] = -xn2 self.edgelengths[:,0] = l0 self.edgelengths[:,1] = l1 self.edgelengths[:,2] = l2 self.centroid_coordinates[:,0] = (x0 + x1 + x2)/3 self.centroid_coordinates[:,1] = (y0 + y1 + y2)/3 if self.use_inscribed_circle == False: #OLD code. Computed radii may exceed that of an #inscribed circle #Midpoints xm0 = (x1 + x2)/2 ym0 = (y1 + y2)/2 xm1 = (x2 + x0)/2 ym1 = (y2 + y0)/2 xm2 = (x0 + x1)/2 ym2 = (y0 + y1)/2 #The radius is the distance from the centroid of #a triangle to the midpoint of the side of the triangle #closest to the centroid d0 = num.sqrt((self.centroid_coordinates[:,0] - xm0)**2 + (self.centroid_coordinates[:,1] - ym0)**2) d1 = num.sqrt((self.centroid_coordinates[:,0] - xm1)**2 + (self.centroid_coordinates[:,1] - ym1)**2) d2 = num.sqrt((self.centroid_coordinates[:,0] - xm2)**2 + (self.centroid_coordinates[:,1] - ym2)**2) self.radii[:] = num.minimum(num.minimum(d0, d1), d2) else: #NEW code added by Peter Row. True radius #of inscribed circle is computed a = num.sqrt((x0-x1)**2+(y0-y1)**2) b = num.sqrt((x1-x2)**2+(y1-y2)**2) c = num.sqrt((x2-x0)**2+(y2-y0)**2) self.radii[:]=2.0*self.areas/(a+b+c) # for i in range(N): # if verbose and i % ((N+10)/10) == 0: log.critical('(%d/%d)' % (i, N)) # # x0, y0 = V[3*i, :] # x1, y1 = V[3*i+1, :] # x2, y2 = V[3*i+2, :] # # # i0 = self.triangles[i][0] # i1 = self.triangles[i][1] # i2 = self.triangles[i][2] # ## assert x0 == self.nodes[i0][0] ## assert y0 == self.nodes[i0][1] ## ## assert x1 == self.nodes[i1][0] ## assert y1 == self.nodes[i1][1] ## ## assert x2 == self.nodes[i2][0] ## assert y2 == self.nodes[i2][1] # ## # Area ## self.areas[i] = abs((x1*y0-x0*y1) + (x2*y1-x1*y2) + (x0*y2-x2*y0))/2 ## ## msg = 'Triangle %g (%f,%f), (%f,%f), (%f, %f)' % (i,x0,y0,x1,y1,x2,y2) ## msg += ' is degenerate: area == %f' % self.areas[i] ## assert self.areas[i] > 0.0, msg # # # Normals # # The normal vectors # # - point outward from each edge # # - are orthogonal to the edge # # - have unit length # # - Are enumerated according to the opposite corner: # # (First normal is associated with the edge opposite # # the first vertex, etc) # # - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle # n0 = num.array([x2-x1, y2-y1], num.float) # l0 = num.sqrt(num.sum(n0**2)) # # n1 = num.array([x0-x2, y0-y2], num.float) # l1 = num.sqrt(num.sum(n1**2)) # # n2 = num.array([x1-x0, y1-y0], num.float) # l2 = num.sqrt(num.sum(n2**2)) # # # Normalise # n0 /= l0 # n1 /= l1 # n2 /= l2 # ## # Compute and store ## self.normals[i, :] = [n0[1], -n0[0], ## n1[1], -n1[0], ## n2[1], -n2[0]] # # # Edgelengths # #self.edgelengths[i, :] = [l0, l1, l2] # # # # #Compute centroid ## centroid = num.array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3], num.float) ### self.centroid_coordinates[i] = centroid ## ## ## if self.use_inscribed_circle == False: ## #OLD code. Computed radii may exceed that of an ## #inscribed circle ## ## #Midpoints ## m0 = num.array([(x1 + x2)/2, (y1 + y2)/2], num.float) ## m1 = num.array([(x0 + x2)/2, (y0 + y2)/2], num.float) ## m2 = num.array([(x1 + x0)/2, (y1 + y0)/2], num.float) ## ## #The radius is the distance from the centroid of ## #a triangle to the midpoint of the side of the triangle ## #closest to the centroid ## d0 = num.sqrt(num.sum( (centroid-m0)**2 )) ## d1 = num.sqrt(num.sum( (centroid-m1)**2 )) ## d2 = num.sqrt(num.sum( (centroid-m2)**2 )) ## ## #self.radii[i] = min(d0, d1, d2) ## ## else: ## #NEW code added by Peter Row. True radius ## #of inscribed circle is computed ## ## a = num.sqrt((x0-x1)**2+(y0-y1)**2) ## b = num.sqrt((x1-x2)**2+(y1-y2)**2) ## c = num.sqrt((x2-x0)**2+(y2-y0)**2) ## ## self.radii[i]=2.0*self.areas[i]/(a+b+c) # Build structure listing which triangles belong to which node. if verbose: log.critical('General Mesh: Building inverted triangle structure') self.build_inverted_triangle_structure() if verbose: log.timingInfo("aoi, '%s'" % self.get_area())
def __init__(self, nodes, triangles, geo_reference=None, use_inscribed_circle=False, verbose=False): """Build triangular 2d mesh from nodes and triangle information Input: nodes: x,y coordinates represented as a sequence of 2-tuples or a Nx2 numeric array of floats. triangles: sequence of 3-tuples or Mx3 numeric array of non-negative integers representing indices into the nodes array. georeference (optional): If specified coordinates are assumed to be relative to this origin. """ self.verbose = verbose if verbose: log.critical('General_mesh: Building basic mesh structure') self.use_inscribed_circle = use_inscribed_circle self.triangles = num.array(triangles, num.int) if verbose: log.timingInfo("numTriangles, " + str(self.triangles.shape[0])) self.nodes = num.array(nodes, num.float) # Register number of elements and nodes self.number_of_triangles = N = int(self.triangles.shape[0]) self.number_of_nodes = self.nodes.shape[0] # FIXME: this stores a geo_reference, but when coords are returned # This geo_ref is not taken into account! if geo_reference is None: self.geo_reference = Geo_reference() # Use defaults else: self.geo_reference = geo_reference # Input checks msg = ( 'Triangles must an Mx3 numeric array or a sequence of 3-tuples. ' 'The supplied array has the shape: %s' % str(self.triangles.shape)) assert len(self.triangles.shape) == 2, msg msg = ('Nodes must an Nx2 numeric array or a sequence of 2-tuples' 'The supplied array has the shape: %s' % str(self.nodes.shape)) assert len(self.nodes.shape) == 2, msg msg = 'Vertex indices reference non-existing coordinate sets' assert num.max(self.triangles) < self.nodes.shape[0], msg # FIXME: Maybe move to statistics? # Or use with get_extent xy_extent = [ min(self.nodes[:, 0]), min(self.nodes[:, 1]), max(self.nodes[:, 0]), max(self.nodes[:, 1]) ] self.xy_extent = num.array(xy_extent, num.float) # Allocate space for geometric quantities self.normals = num.zeros((N, 6), num.float) self.areas = num.zeros(N, num.float) self.edgelengths = num.zeros((N, 3), num.float) # Get x,y coordinates for all triangle vertices and store self.centroid_coordinates = num.zeros((N, 2), num.float) #Allocate space for geometric quantities self.radii = num.zeros(N, num.float) # Get x,y coordinates for all triangle vertices and store self.vertex_coordinates = V = self.compute_vertex_coordinates() # Get x,y coordinates for all triangle edge midpoints and store self.edge_midpoint_coordinates = self.compute_edge_midpoint_coordinates( ) # Initialise each triangle if verbose: log.critical('General_mesh: Computing areas, normals, ' 'edgelengths, centroids and radii') # Calculate Areas V0 = V[0:3 * N:3, :] V1 = V[1:3 * N:3, :] V2 = V[2:3 * N:3, :] # Area x0 = V0[:, 0] y0 = V0[:, 1] x1 = V1[:, 0] y1 = V1[:, 1] x2 = V2[:, 0] y2 = V2[:, 1] self.areas[:] = -((x1 * y0 - x0 * y1) + (x2 * y1 - x1 * y2) + (x0 * y2 - x2 * y0)) / 2.0 #areas = -((x0-x1)*(y2-y1) - (y0-y1)*(x2-x1))/2.0 #assert num.allclose(self.areas, areas) ind = num.where(self.areas <= 0.0) msg = 'Degenerate Triangle(s) ' + str(ind[0]) assert num.all(self.areas > 0.0), msg #print V.shape, V0.shape, V1.shape, V2.shape # #print E.shape, E[0:3*M:3, :].shape, E[1:3*M:3, :].shape, E[2:3*M:3, :].shape # E[0:3*M:3, :] = 0.5*(V1+V2) # E[1:3*M:3, :] = 0.5*(V2+V0) # E[2:3*M:3, :] = 0.5*(V0+V1) i0 = self.triangles[:, 0] i1 = self.triangles[:, 1] i2 = self.triangles[:, 2] assert num.allclose(x0, self.nodes[i0, 0]) assert num.allclose(y0, self.nodes[i0, 1]) assert num.allclose(x1, self.nodes[i1, 0]) assert num.allclose(y1, self.nodes[i1, 1]) assert num.allclose(x2, self.nodes[i2, 0]) assert num.allclose(y2, self.nodes[i2, 1]) xn0 = x2 - x1 yn0 = y2 - y1 l0 = num.sqrt(xn0**2 + yn0**2) xn0 /= l0 yn0 /= l0 xn1 = x0 - x2 yn1 = y0 - y2 l1 = num.sqrt(xn1**2 + yn1**2) xn1 /= l1 yn1 /= l1 xn2 = x1 - x0 yn2 = y1 - y0 l2 = num.sqrt(xn2**2 + yn2**2) xn2 /= l2 yn2 /= l2 # Compute and store self.normals[:, 0] = yn0 self.normals[:, 1] = -xn0 self.normals[:, 2] = yn1 self.normals[:, 3] = -xn1 self.normals[:, 4] = yn2 self.normals[:, 5] = -xn2 self.edgelengths[:, 0] = l0 self.edgelengths[:, 1] = l1 self.edgelengths[:, 2] = l2 self.centroid_coordinates[:, 0] = old_div((x0 + x1 + x2), 3) self.centroid_coordinates[:, 1] = old_div((y0 + y1 + y2), 3) if self.use_inscribed_circle == False: #OLD code. Computed radii may exceed that of an #inscribed circle #Midpoints xm0 = old_div((x1 + x2), 2) ym0 = old_div((y1 + y2), 2) xm1 = old_div((x2 + x0), 2) ym1 = old_div((y2 + y0), 2) xm2 = old_div((x0 + x1), 2) ym2 = old_div((y0 + y1), 2) #The radius is the distance from the centroid of #a triangle to the midpoint of the side of the triangle #closest to the centroid d0 = num.sqrt((self.centroid_coordinates[:, 0] - xm0)**2 + (self.centroid_coordinates[:, 1] - ym0)**2) d1 = num.sqrt((self.centroid_coordinates[:, 0] - xm1)**2 + (self.centroid_coordinates[:, 1] - ym1)**2) d2 = num.sqrt((self.centroid_coordinates[:, 0] - xm2)**2 + (self.centroid_coordinates[:, 1] - ym2)**2) self.radii[:] = num.minimum(num.minimum(d0, d1), d2) else: #NEW code added by Peter Row. True radius #of inscribed circle is computed a = num.sqrt((x0 - x1)**2 + (y0 - y1)**2) b = num.sqrt((x1 - x2)**2 + (y1 - y2)**2) c = num.sqrt((x2 - x0)**2 + (y2 - y0)**2) self.radii[:] = old_div(2.0 * self.areas, (a + b + c)) # for i in range(N): # if verbose and i % ((N+10)/10) == 0: log.critical('(%d/%d)' % (i, N)) # # x0, y0 = V[3*i, :] # x1, y1 = V[3*i+1, :] # x2, y2 = V[3*i+2, :] # # # i0 = self.triangles[i][0] # i1 = self.triangles[i][1] # i2 = self.triangles[i][2] # ## assert x0 == self.nodes[i0][0] ## assert y0 == self.nodes[i0][1] ## ## assert x1 == self.nodes[i1][0] ## assert y1 == self.nodes[i1][1] ## ## assert x2 == self.nodes[i2][0] ## assert y2 == self.nodes[i2][1] # ## # Area ## self.areas[i] = abs((x1*y0-x0*y1) + (x2*y1-x1*y2) + (x0*y2-x2*y0))/2 ## ## msg = 'Triangle %g (%f,%f), (%f,%f), (%f, %f)' % (i,x0,y0,x1,y1,x2,y2) ## msg += ' is degenerate: area == %f' % self.areas[i] ## assert self.areas[i] > 0.0, msg # # # Normals # # The normal vectors # # - point outward from each edge # # - are orthogonal to the edge # # - have unit length # # - Are enumerated according to the opposite corner: # # (First normal is associated with the edge opposite # # the first vertex, etc) # # - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle # n0 = num.array([x2-x1, y2-y1], num.float) # l0 = num.sqrt(num.sum(n0**2)) # # n1 = num.array([x0-x2, y0-y2], num.float) # l1 = num.sqrt(num.sum(n1**2)) # # n2 = num.array([x1-x0, y1-y0], num.float) # l2 = num.sqrt(num.sum(n2**2)) # # # Normalise # n0 /= l0 # n1 /= l1 # n2 /= l2 # ## # Compute and store ## self.normals[i, :] = [n0[1], -n0[0], ## n1[1], -n1[0], ## n2[1], -n2[0]] # # # Edgelengths # #self.edgelengths[i, :] = [l0, l1, l2] # # # # #Compute centroid ## centroid = num.array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3], num.float) ### self.centroid_coordinates[i] = centroid ## ## ## if self.use_inscribed_circle == False: ## #OLD code. Computed radii may exceed that of an ## #inscribed circle ## ## #Midpoints ## m0 = num.array([(x1 + x2)/2, (y1 + y2)/2], num.float) ## m1 = num.array([(x0 + x2)/2, (y0 + y2)/2], num.float) ## m2 = num.array([(x1 + x0)/2, (y1 + y0)/2], num.float) ## ## #The radius is the distance from the centroid of ## #a triangle to the midpoint of the side of the triangle ## #closest to the centroid ## d0 = num.sqrt(num.sum( (centroid-m0)**2 )) ## d1 = num.sqrt(num.sum( (centroid-m1)**2 )) ## d2 = num.sqrt(num.sum( (centroid-m2)**2 )) ## ## #self.radii[i] = min(d0, d1, d2) ## ## else: ## #NEW code added by Peter Row. True radius ## #of inscribed circle is computed ## ## a = num.sqrt((x0-x1)**2+(y0-y1)**2) ## b = num.sqrt((x1-x2)**2+(y1-y2)**2) ## c = num.sqrt((x2-x0)**2+(y2-y0)**2) ## ## self.radii[i]=2.0*self.areas[i]/(a+b+c) # Build structure listing which triangles belong to which node. if verbose: log.critical('General Mesh: Building inverted triangle structure') self.build_inverted_triangle_structure() if verbose: log.timingInfo("aoi, '%s'" % self.get_area())
def __init__(self, coordinates, triangles, boundary=None, tagged_elements=None, geo_reference=None, use_inscribed_circle=False, verbose=False): """ Build Mesh Input x,y coordinates (sequence of 2-tuples or Mx2 numeric array of floats) triangles (sequence of 3-tuples or Nx3 numeric array of non-negative integers). """ General_mesh.__init__(self, coordinates, triangles, geo_reference=geo_reference, use_inscribed_circle=use_inscribed_circle, verbose=verbose) if verbose: log.critical('Mesh: Initialising') N = len(self) #Number_of_triangles # Allocate arrays for neighbour data self.neighbours = -1*num.ones((N, 3), num.int) self.neighbour_edges = -1*num.ones((N, 3), num.int) self.number_of_boundaries = num.zeros(N, num.int) self.surrogate_neighbours = num.zeros((N, 3), num.int) #Get x,y coordinates for all triangles and store V = self.vertex_coordinates # Relative coordinates # #Initialise each triangle # if verbose: log.critical('Mesh: Computing centroids and radii') # for i in range(N): # if verbose and i % ((N+10)/10) == 0: log.critical('(%d/%d)' % (i, N)) # # x0, y0 = V[3*i, :] # x1, y1 = V[3*i+1, :] # x2, y2 = V[3*i+2, :] # # #x0 = V[i, 0]; y0 = V[i, 1] # #x1 = V[i, 2]; y1 = V[i, 3] # #x2 = V[i, 4]; y2 = V[i, 5] # # #Compute centroid # centroid = num.array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3], num.float) # self.centroid_coordinates[i] = centroid # # # if self.use_inscribed_circle == False: # #OLD code. Computed radii may exceed that of an # #inscribed circle # # #Midpoints # m0 = num.array([(x1 + x2)/2, (y1 + y2)/2], num.float) # m1 = num.array([(x0 + x2)/2, (y0 + y2)/2], num.float) # m2 = num.array([(x1 + x0)/2, (y1 + y0)/2], num.float) # # #The radius is the distance from the centroid of # #a triangle to the midpoint of the side of the triangle # #closest to the centroid # d0 = num.sqrt(num.sum( (centroid-m0)**2 )) # d1 = num.sqrt(num.sum( (centroid-m1)**2 )) # d2 = num.sqrt(num.sum( (centroid-m2)**2 )) # # self.radii[i] = min(d0, d1, d2) # # else: # #NEW code added by Peter Row. True radius # #of inscribed circle is computed # # a = num.sqrt((x0-x1)**2+(y0-y1)**2) # b = num.sqrt((x1-x2)**2+(y1-y2)**2) # c = num.sqrt((x2-x0)**2+(y2-y0)**2) # # self.radii[i]=2.0*self.areas[i]/(a+b+c) # # # #Initialise Neighbours (-1 means that it is a boundary neighbour) # self.neighbours[i, :] = [-1, -1, -1] # # #Initialise edge ids of neighbours # #In case of boundaries this slot is not used # self.neighbour_edges[i, :] = [-1, -1, -1] #Build neighbour structure if verbose: log.critical('Mesh: Building neigbour structure') self.build_neighbour_structure() #Build surrogate neighbour structure if verbose: log.critical('Mesh: Building surrogate neigbour structure') self.build_surrogate_neighbour_structure() #Build boundary dictionary mapping (id, edge) to symbolic tags if verbose: log.critical('Mesh: Building boundary dictionary') self.build_boundary_dictionary(boundary) #Update boundary_enumeration self.build_boundary_neighbours() #Build tagged element dictionary mapping (tag) to array of elements if verbose: log.critical('Mesh: Building tagged elements dictionary') self.build_tagged_elements_dictionary(tagged_elements) # Build a list of vertices that are not connected to any triangles self.lone_vertices = [] #Check that all vertices have been registered for node, count in enumerate(self.number_of_triangles_per_node): #msg = 'Node %d does not belong to an element.' %node #assert count > 0, msg if count == 0: self.lone_vertices.append(node) #Update boundary indices FIXME: OBSOLETE #self.build_boundary_structure() #FIXME check integrity? if verbose: log.critical('Mesh: Done') if verbose: log.timingInfo("finishMesh, '%s'" % log.CurrentDateTime()) if verbose: log.resource_usage_timing(log.logging.INFO, "finishMesh_")