source: inundation/ga/storm_surge/pyvolution/general_mesh.py @ 521

Last change on this file since 521 was 521, checked in by ole, 20 years ago
File size: 7.3 KB
Line 
1   
2class General_mesh:
3    """Collection of triangular elements (purely geometric)
4
5    A triangular element is defined in terms of three vertex ids,
6    ordered counter clock-wise,
7    each corresponding to a given coordinate set.
8    Vertices from different elements can point to the same
9    coordinate set.
10
11    Coordinate sets are implemented as an N x 2 Numeric array containing
12    x and y coordinates.
13   
14
15    To instantiate:
16       Mesh(coordinates, triangles)
17
18    where
19
20      coordinates is either a list of 2-tuples or an Mx2 Numeric array of
21      floats representing all x, y coordinates in the mesh.
22
23      triangles is either a list of 3-tuples or an Nx3 Numeric array of
24      integers representing indices of all vertices in the mesh.
25      Each vertex is identified by its index i in [0, M-1].
26
27
28    Example:
29        a = [0.0, 0.0]
30        b = [0.0, 2.0]
31        c = [2.0,0.0]
32        e = [2.0, 2.0]
33       
34        points = [a, b, c, e]
35        triangles = [ [1,0,2], [1,2,3] ]   #bac, bce
36        mesh = Mesh(points, triangles)
37   
38        #creates two triangles: bac and bce
39       
40
41        This is a cut down version of mesh from pyvolution\mesh.py
42    """
43
44    def __init__(self, coordinates, triangles):
45        """
46        Build triangles from x,y coordinates (sequence of 2-tuples or
47        Mx2 Numeric array of floats) and triangles (sequence of 3-tuples
48        or Nx3 Numeric array of non-negative integers).
49        """
50
51        from Numeric import array, zeros, Int, Float, maximum, sqrt, sum
52
53        self.triangles = array(triangles).astype(Int)
54        self.coordinates = array(coordinates)
55
56        #Input checks
57        msg = 'Triangles must an Nx2 Numeric array or a sequence of 2-tuples'
58        assert len(self.triangles.shape) == 2, msg
59
60        msg = 'Coordinates must an Mx2 Numeric array or a sequence of 2-tuples'
61        assert len(self.coordinates.shape) == 2, msg       
62
63        msg = 'Vertex indices reference non-existing coordinate sets'
64        assert max(max(self.triangles)) <= self.coordinates.shape[0], msg
65
66
67        #Register number of elements (N)
68        self.number_of_elements = N = self.triangles.shape[0]
69   
70        #Allocate space for geometric quantities       
71        self.normals = zeros((N, 6), Float)
72        self.areas = zeros(N, Float)
73        self.edgelengths = zeros((N, 3), Float)
74
75        #Get x,y coordinates for all triangles and store
76        self.vertex_coordinates = V = self.compute_vertex_coordinates()
77       
78        #Initialise each triangle
79        for i in range(N):
80            #if i % (N/10) == 0: print '(%d/%d)' %(i, N)
81           
82            x0 = V[i, 0]; y0 = V[i, 1]
83            x1 = V[i, 2]; y1 = V[i, 3]
84            x2 = V[i, 4]; y2 = V[i, 5]           
85
86            #Area
87            self.areas[i] = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
88
89            msg = 'Triangle (%f,%f), (%f,%f), (%f, %f)' %(x0,y0,x1,y1,x2,y2)
90            msg += ' is degenerate:  area == %f' %self.areas[i]
91            assert self.areas[i] > 0.0, msg
92       
93
94            #Normals
95            #The normal vectors
96            # - point outward from each edge
97            # - are orthogonal to the edge
98            # - have unit length
99            # - Are enumerated according to the opposite corner:
100            #   (First normal is associated with the edge opposite
101            #    the first vertex, etc)
102            # - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle
103
104            n0 = array([x2 - x1, y2 - y1])
105            l0 = sqrt(sum(n0**2))
106
107            n1 = array([x0 - x2, y0 - y2])
108            l1 = sqrt(sum(n1**2))
109
110            n2 = array([x1 - x0, y1 - y0])
111            l2 = sqrt(sum(n2**2))
112
113            #Normalise
114            n0 /= l0
115            n1 /= l1
116            n2 /= l2
117
118            #Compute and store
119            self.normals[i, :] = [n0[1], -n0[0],
120                                  n1[1], -n1[0],
121                                  n2[1], -n2[0]]
122           
123            #Edgelengths
124            self.edgelengths[i, :] = [l0, l1, l2]
125
126        #Build vertex list
127        self.build_vertexlist()       
128           
129    def __len__(self):
130        return self.number_of_elements
131
132    def __repr__(self):
133        return 'Mesh: %d triangles, %d elements'\
134               %(self.coordinates.shape[0], len(self))
135
136    def get_normals(self):
137        """Return all normal vectors.
138        Return normal vectors for all triangles as an Nx6 array
139        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)       
140        """
141        return self.normals
142
143
144    def get_normal(self, i, j):
145        """Return normal vector j of the i'th triangle.
146        Return value is the numeric array slice [x, y]
147        """
148        return self.normals[i, 2*j:2*j+2]     
149   
150
151           
152    def get_vertex_coordinates(self):
153        """Return all vertex coordinates.
154        Return all vertex coordinates for all triangles as an Nx6 array
155        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)       
156        """
157        return self.vertex_coordinates
158
159
160    def get_vertex_coordinate(self, i, j):
161        """Return coordinates for vertex j of the i'th triangle.
162        Return value is the numeric array slice [x, y]
163        """
164        return self.vertex_coordinates[i, 2*j:2*j+2]     
165
166
167    def compute_vertex_coordinates(self):
168        """Return vertex coordinates for all triangles as an Nx6 array
169        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
170        """
171
172        #FIXME: Perhaps they should be ordered as in obj files??
173        #See quantity.get_vertex_values
174       
175        from Numeric import zeros, Float
176
177        N = self.number_of_elements
178        vertex_coordinates = zeros((N, 6), Float) 
179
180        for i in range(N):
181            for j in range(3):
182                k = self.triangles[i,j]  #Index of vertex 0
183                v_k = self.coordinates[k]
184                vertex_coordinates[i, 2*j+0] = v_k[0]
185                vertex_coordinates[i, 2*j+1] = v_k[1]
186
187        return vertex_coordinates
188 
189    def get_triangles(self, unique=False):
190        """Get connectivity
191        If unique is True give them only once as stored internally.
192        If unique is False return
193        """
194
195        if unique is True:
196            return self.triangles
197        else:
198            from Numeric import reshape, array, Int
199               
200            m = len(self)  #Number of volumes
201            M = 3*m        #Total number of unique vertices
202            return reshape(array(range(M)).astype(Int), (m,3))
203
204   
205    def build_vertexlist(self):
206        """Build vertexlist index by vertex ids and for each entry (point id)
207        build a list of (triangles, vertex_id) pairs that use the point
208        as vertex.
209
210        Preconditions:
211          self.coordinates and self.triangles are defined 
212       
213        Postcondition:
214          self.vertexlist is built
215        """
216
217        vertexlist = [None]*len(self.coordinates)
218        for i in range(self.number_of_elements):
219
220            a = self.triangles[i, 0]
221            b = self.triangles[i, 1]
222            c = self.triangles[i, 2]           
223
224            #Register the vertices v as lists of
225            #(triangle_id, vertex_id) tuples associated with them
226            #This is used for smoothing
227            for vertex_id, v in enumerate([a,b,c]):
228                if vertexlist[v] is None:
229                    vertexlist[v] = []
230
231                vertexlist[v].append( (i, vertex_id) )   
232
233        self.vertexlist = vertexlist
234   
235
Note: See TracBrowser for help on using the repository browser.