Changeset 316


Ignore:
Timestamp:
Sep 16, 2004, 5:31:08 PM (21 years ago)
Author:
duncan
Message:

bigger least squares tests. Making it more stand-alone

Location:
inundation/ga/storm_surge/pyvolution
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/pyvolution/least_squares.py

    r309 r316  
    77
    88
    9 from mesh import Mesh
    10 
     9"""Classes implementing general 2D geometrical mesh of triangles.
     10
     11   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
     12   Geoscience Australia, 2004   
     13"""
     14
     15
     16class Mesh:
     17    """Collection of triangular elements (purely geometric)
     18
     19    A triangular element is defined in terms of three vertex ids,
     20    ordered counter clock-wise,
     21    each corresponding to a given coordinate set.
     22    Vertices from different elements can point to the same
     23    coordinate set.
     24
     25    Coordinate sets are implemented as an N x 2 Numeric array containing
     26    x and y coordinates.
     27   
     28
     29    To instantiate:
     30       Mesh(coordinates, triangles)
     31
     32    where
     33
     34      coordinates is either a list of 2-tuples or an Mx2 Numeric array of
     35      floats representing all x, y coordinates in the mesh.
     36
     37      triangles is either a list of 3-tuples or an Nx3 Numeric array of
     38      integers representing indices of all vertices in the mesh.
     39      Each vertex is identified by its index i in [0, M-1].
     40
     41
     42    Example:
     43        a = [0.0, 0.0]
     44        b = [0.0, 2.0]
     45        c = [2.0,0.0]
     46        e = [2.0, 2.0]
     47       
     48        points = [a, b, c, e]
     49        triangles = [ [1,0,2], [1,2,3] ]   #bac, bce
     50        mesh = Mesh(points, triangles)
     51   
     52        #creates two triangles: bac and bce
     53
     54        This is a cut down version of mesh from pyvolution\mesh.py
     55    """
     56
     57    def __init__(self, coordinates, triangles):
     58        """
     59        Build triangles from x,y coordinates (sequence of 2-tuples or
     60        Mx2 Numeric array of floats) and triangles (sequence of 3-tuples
     61        or Nx3 Numeric array of non-negative integers).
     62        """
     63
     64        from Numeric import array, zeros, Int, Float, maximum, sqrt, sum
     65
     66        self.triangles = array(triangles).astype(Int)
     67        self.coordinates = array(coordinates)
     68
     69        #Input checks
     70        msg = 'Triangles must an Nx2 Numeric array or a sequence of 2-tuples'
     71        assert len(self.triangles.shape) == 2, msg
     72
     73        msg = 'Coordinates must an Mx2 Numeric array or a sequence of 2-tuples'
     74        assert len(self.coordinates.shape) == 2, msg       
     75
     76        msg = 'Vertex indices reference non-existing coordinate sets'
     77        assert max(max(self.triangles)) <= self.coordinates.shape[0], msg
     78
     79
     80        #Register number of elements (N)
     81        self.number_of_elements = N = self.triangles.shape[0]
     82   
     83       
     84        self.normals = zeros((N, 6), Float)
     85
     86        #Get x,y coordinates for all triangles and store
     87        self.vertex_coordinates = V = self.compute_vertex_coordinates()
     88       
     89        #Initialise each triangle
     90        for i in range(N):
     91            #if i % (N/10) == 0: print '(%d/%d)' %(i, N)
     92           
     93            x0 = V[i, 0]; y0 = V[i, 1]
     94            x1 = V[i, 2]; y1 = V[i, 3]
     95            x2 = V[i, 4]; y2 = V[i, 5]           
     96
     97            #Area
     98            area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
     99
     100            msg = 'Triangle (%f,%f), (%f,%f), (%f, %f)' %(x0,y0,x1,y1,x2,y2)
     101            msg += ' is degenerate:  area == %f' %area
     102            assert area > 0.0, msg
     103       
     104
     105            #Normals
     106            #The normal vectors
     107            # - point outward from each edge
     108            # - are orthogonal to the edge
     109            # - have unit length
     110            # - Are enumerated according to the opposite corner:
     111            #   (First normal is associated with the edge opposite
     112            #    the first vertex, etc)
     113            # - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle
     114
     115            n0 = array([x2 - x1, y2 - y1])
     116            l0 = sqrt(sum(n0**2))
     117
     118            n1 = array([x0 - x2, y0 - y2])
     119            l1 = sqrt(sum(n1**2))
     120
     121            n2 = array([x1 - x0, y1 - y0])
     122            l2 = sqrt(sum(n2**2))
     123
     124            #Normalise
     125            n0 /= l0
     126            n1 /= l1
     127            n2 /= l2
     128
     129            #Compute and store
     130            self.normals[i, :] = [n0[1], -n0[0],
     131                                  n1[1], -n1[0],
     132                                  n2[1], -n2[0]]             
     133
     134         
     135        #Build vertex list
     136        self.build_vertexlist()       
     137
     138
     139       
     140    def __len__(self):
     141        return self.number_of_elements
     142
     143    def __repr__(self):
     144        return 'Mesh: %d triangles, %d elements'\
     145               %(self.coordinates.shape[0], len(self))
     146
     147
     148
     149    #DSG I don't know if I need this
     150    def build_vertexlist(self):
     151        pass
     152   
     153    # maybe add this latter..   
     154    def check_integrity(self):
     155        pass
     156   
     157
     158    def get_normals(self):
     159        """Return all normal vectors.
     160        Return normal vectors for all triangles as an Nx6 array
     161        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)       
     162        """
     163        return self.normals
     164
     165
     166    def get_normal(self, i, j):
     167        """Return normal vector j of the i'th triangle.
     168        Return value is the numeric array slice [x, y]
     169        """
     170        return self.normals[i, 2*j:2*j+2]     
     171   
     172
     173           
     174    def get_vertex_coordinates(self):
     175        """Return all vertex coordinates.
     176        Return all vertex coordinates for all triangles as an Nx6 array
     177        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)       
     178        """
     179        return self.vertex_coordinates
     180
     181
     182    def get_vertex_coordinate(self, i, j):
     183        """Return coordinates for vertex j of the i'th triangle.
     184        Return value is the numeric array slice [x, y]
     185        """
     186        return self.vertex_coordinates[i, 2*j:2*j+2]     
     187
     188
     189    def compute_vertex_coordinates(self):
     190        """Return vertex coordinates for all triangles as an Nx6 array
     191        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
     192        """
     193
     194        #FIXME: Perhaps they should be ordered as in obj files??
     195        #See quantity.get_vertex_values
     196       
     197        from Numeric import zeros, Float
     198
     199        N = self.number_of_elements
     200        vertex_coordinates = zeros((N, 6), Float)
     201
     202        for i in range(N):
     203            for j in range(3):
     204                k = self.triangles[i,j]  #Index of vertex 0
     205                v_k = self.coordinates[k]
     206                vertex_coordinates[i, 2*j+0] = v_k[0]
     207                vertex_coordinates[i, 2*j+1] = v_k[1]
     208
     209        return vertex_coordinates
     210 
     211    def get_triangles(self, unique=False):
     212        """Get connectivity
     213        If unique is True give them only once as stored internally.
     214        If unique is False return
     215        """
     216
     217        if unique is True:
     218            return self.triangles
     219        else:
     220            from Numeric import reshape, array, Int
     221               
     222            m = len(self)  #Number of volumes
     223            M = 3*m        #Total number of unique vertices
     224            return reshape(array(range(M)).astype(Int), (m,3))
     225
     226
     227
     228from Numeric import zeros, array, Float, Int, dot,transpose
     229from LinearAlgebra import solve_linear_equations
     230
     231EPSILON = 1.0e-13
    11232
    12233class Interpolation(Mesh):
    13234
    14     def __init__(self, vertex_coordinates, triangles, data_coordinates):
     235    def __init__(self, vertex_coordinates, triangles, point_coordinates):
    15236        """ Build interpolation matrix mapping from
    16237        function values at vertices to function values at data points
     
    24245          integers representing indices of all vertices in the mesh.
    25246
    26           data_coordinates: List of coordinate pairs [x, y] of data points
     247          point_coordinates: List of coordinate pairs [x, y] of data points
    27248          (or an nx2 Numeric array)
    28249         
    29250        """
    30251
    31         from Numeric import zeros, array, Float, Int, dot
    32         from config import epsilon
    33 
    34252        #Convert input to Numeric arrays
    35         data_coordinates = array(data_coordinates).astype(Float)
     253        point_coordinates = array(point_coordinates).astype(Float)
    36254        vertex_coordinates = array(vertex_coordinates).astype(Float)
    37255        triangles = array(triangles).astype(Int)               
     
    43261        #Build n x m interpolation matrix       
    44262        m = vertex_coordinates.shape[0] #Number of basis functions (1/vertex)
    45         n = data_coordinates.shape[0]               #Number of data points         
     263        n = point_coordinates.shape[0]               #Number of data points         
    46264
    47265        self.A_m = zeros((n,m), Float)
     
    51269            #For each data_coordinate point
    52270
    53             x = data_coordinates[i]
     271            x = point_coordinates[i]
    54272            for k in range(len(self)):
    55273                #For each triangle (brute force)
     
    72290
    73291                #FIXME: Maybe move out to test or something
    74                 assert abs(sigma0 + sigma1 + sigma2 - 1.0) < epsilon
     292                assert abs(sigma0 + sigma1 + sigma2 - 1.0) < EPSILON
    75293
    76294               
     
    89307
    90308    def smooth_to_mesh(self, z):
    91         from Numeric import zeros, array, Float,transpose,dot
    92         from LinearAlgebra import solve_linear_equations
     309        """ Linearly interpolate point data values to the vertices.
     310       
     311        Inputs:
     312          z: Vector of data at the point_coordinates.  One value per point.
     313         
     314        """
    93315        #Convert input to Numeric arrays
    94316        z = array(z).astype(Float)
     
    100322        f = solve_linear_equations(self.AtA_m,Atz_m)
    101323        return f
     324
     325    def smooth_to_points(self, f):
     326        """ Linearly interpolate point data values to the vertices.
     327       
     328        Inputs:
     329          z: Vector of data at the point_coordinates.  One value per point.
     330         
     331        """
     332        return dot(self.A_m,f)
  • inundation/ga/storm_surge/pyvolution/test_least_squares.py

    r309 r316  
    159159        assert allclose(f, answer)
    160160       
     161    def test_smooth_to_meshII(self):
     162        a = [0.0, 0.0]
     163        b = [0.0, 5.0]
     164        c = [5.0, 0.0]
     165        points = [a, b, c]
     166        triangles = [ [1,0,2] ]   #bac
     167         
     168        d1 = [1.0, 1.0]
     169        d2 = [1.0, 2.0]
     170        d3 = [3.0,1.0]
     171        data_coords = [ d1, d2, d3]       
     172        z = self.linear_function(data_coords)
     173        mesh = Interpolation(points, triangles, data_coords)
     174        f =  mesh.smooth_to_mesh(z)
     175        answer = self.linear_function(points)
     176        assert allclose(f, answer)
     177   
     178    def test_smooth_to_meshIII(self):
     179        a = [-1.0, 0.0]
     180        b = [3.0, 4.0]
     181        c = [4.0,1.0]
     182        d = [-3.0, 2.0] #3
     183        e = [-1.0,-2.0]
     184        f = [1.0, -2.0] #5
     185
     186        vertices = [a, b, c, d,e,f]
     187        triangles = [[0,1,3],[1,0,2],[0,4,5], [0,5,2]] #abd bac aef afc
     188
     189         
     190        point_coords = [[-2.0, 2.0],
     191                        [-1.0, 1.0],
     192                        [0.0,2.0],
     193                        [1.0, 1.0],
     194                        [2.0, 1.0],
     195                        [0.0,0.0],
     196                        [1.0, 0.0],
     197                        [0.0, -1.0],
     198                        [-0.2,-0.5],
     199                        [-0.9, -1.5],
     200                        [0.5, -1.9],
     201                        [3.0,1.0]]
     202       
     203        z = self.linear_function(point_coords)
     204        mesh = Interpolation(vertices, triangles, point_coords)
     205        f =  mesh.smooth_to_mesh(z)
     206        answer = self.linear_function(vertices)
     207        assert allclose(f, answer)
     208       
     209    def linear_function(self,point):
     210        point = array(point)
     211        return point[:,0]+point[:,1]
     212   
     213    def test_smooth_to_points(self):
     214        v0 = [0.0, 0.0]
     215        v1 = [0.0, 5.0]
     216        v2 = [5.0, 0.0]
     217       
     218        vertices = [v0, v1, v2]
     219        triangles = [ [1,0,2] ]   #bac
     220       
     221         
     222        d0 = [1.0, 1.0]
     223        d1 = [1.0, 2.0]
     224        d2 = [3.0,1.0]
     225        point_coords = [ d0, d1, d2]
     226       
     227        mesh = Interpolation(vertices, triangles, point_coords)
     228        f = self.linear_function(vertices)
     229        z =  mesh.smooth_to_points(f)
     230        answer = self.linear_function(point_coords)
     231        #print "z",z
     232        #print "answer",answer
     233        assert allclose(z, answer)
     234       
     235    def test_smooth_to_pointsII(self):
     236        a = [-1.0, 0.0]
     237        b = [3.0, 4.0]
     238        c = [4.0,1.0]
     239        d = [-3.0, 2.0] #3
     240        e = [-1.0,-2.0]
     241        f = [1.0, -2.0] #5
     242
     243        vertices = [a, b, c, d,e,f]
     244        triangles = [[0,1,3],[1,0,2],[0,4,5], [0,5,2]] #abd bac aef afc
     245
     246         
     247        point_coords = [[-2.0, 2.0],
     248                        [-1.0, 1.0],
     249                        [0.0,2.0],
     250                        [1.0, 1.0],
     251                        [2.0, 1.0],
     252                        [0.0,0.0],
     253                        [1.0, 0.0],
     254                        [0.0, -1.0],
     255                        [-0.2,-0.5],
     256                        [-0.9, -1.5],
     257                        [0.5, -1.9],
     258                        [3.0,1.0]]
     259       
     260        mesh = Interpolation(vertices, triangles, point_coords)
     261        f = self.linear_function(vertices)
     262        z =  mesh.smooth_to_points(f)
     263        answer = self.linear_function(point_coords)
     264        #print "z",z
     265        #print "answer",answer
     266        assert allclose(z, answer)
    161267#-------------------------------------------------------------
    162268if __name__ == "__main__":
Note: See TracChangeset for help on using the changeset viewer.