Changeset 1387


Ignore:
Timestamp:
May 13, 2005, 6:15:08 PM (19 years ago)
Author:
steve
Message:

Need to look at uint test for inscribed circle

Location:
inundation/ga/storm_surge
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/parallel/parallel_advection.py

    r1363 r1387  
    1414"""
    1515
    16 #Subversion keywords:
    17 #
    18 #$LastChangedDate:  $
    19 #$LastChangedRevision:  $
    20 #$LastChangedBy: $
     16from advection import *
     17Advection_Domain = Domain
     18from Numeric import zeros, Float, Int
    2119
    22 class Parallel_Domain(Domain):
     20class Parallel_Domain(Advection_Domain):
    2321
    24     def __init__(self, coordinates, vertices, boundary = None, velocity = None):
     22    def __init__(self, coordinates, vertices, boundary = None, velocity = None,
     23                 processor = 0, global_ids = None):
    2524
     25        Advection_Domain.__init__(self, coordinates, vertices, boundary, velocity)
    2626
    27         Generic_domain.__init__(self, coordinates, vertices, boundary,
    28                                 ['stage'])
     27        self.processor = processor
    2928
    30         if velocity is None:
    31             self.velocity = [1,0]
     29        N = self.number_of_elements
     30
     31        if  global_ids == None:
     32            self.global_ids = global_ids
    3233        else:
    33             self.velocity = velocity
    34 
    35         #Only first is implemented for advection
    36         self.default_order = self.order = 1
    37 
    38         #Realtime visualisation
    39         self.visualise = False
    40         self.visualise_color_stage = False
    41         self.visualise_timer = True
    42         self.visualise_range_z = None
    43         self.smooth = True
    44 
     34            self.global_ids = zeros(N, Int)
    4535
    4636
    4737    def check_integrity(self):
    48         Generic_domain.check_integrity(self)
     38        Advection_Domain.check_integrity(self)
    4939
    50         msg = 'Conserved quantity must be "stage"'
     40        msg = 'Will need to check global and local numbering'
    5141        assert self.conserved_quantities[0] == 'stage', msg
    5242
    53 
    54     def flux_function(self, normal, ql, qr, zl=None, zr=None):
    55         """Compute outward flux as inner product between velocity
    56         vector v=(v_1, v_2) and normal vector n.
    57 
    58         if <n,v> > 0 flux direction is outward bound and its magnitude is
    59         determined by the quantity inside volume: ql.
    60         Otherwise it is inbound and magnitude is determined by the
    61         quantity outside the volume: qr.
    62         """
    63 
    64         v1 = self.velocity[0]
    65         v2 = self.velocity[1]
    66 
    67 
    68         normal_velocity = v1*normal[0] + v2*normal[1]
    69 
    70         if normal_velocity < 0:
    71             flux = qr * normal_velocity
    72         else:
    73             flux = ql * normal_velocity
    74 
    75         max_speed = abs(normal_velocity)
    76         return flux, max_speed
    77 
    78 
    79     def compute_fluxes(self):
    80         """Compute all fluxes and the timestep suitable for all volumes
    81         in domain.
    82 
    83         Compute total flux for each conserved quantity using "flux_function"
    84 
    85         Fluxes across each edge are scaled by edgelengths and summed up
    86         Resulting flux is then scaled by area and stored in
    87         domain.explicit_update
    88 
    89         The maximal allowable speed computed by the flux_function
    90         for each volume
    91         is converted to a timestep that must not be exceeded. The minimum of
    92         those is computed as the next overall timestep.
    93 
    94         Post conditions:
    95         domain.explicit_update is reset to computed flux values
    96         domain.timestep is set to the largest step satisfying all volumes.
    97         """
    98 
    99         import sys
    100         from Numeric import zeros, Float
    101         from config import max_timestep
    102 
    103         N = self.number_of_elements
    104 
    105         neighbours = self.neighbours
    106         neighbour_edges = self.neighbour_edges
    107         normals = self.normals
    108 
    109         areas = self.areas
    110         radii = self.radii
    111         edgelengths = self.edgelengths
    112 
    113         timestep = max_timestep #FIXME: Get rid of this
    114 
    115         #Shortcuts
    116         Stage = self.quantities['stage']
    117 
    118         #Arrays
    119         stage = Stage.edge_values
    120 
    121         stage_bdry = Stage.boundary_values
    122 
    123         flux = zeros(1, Float) #Work array for summing up fluxes
    124 
    125         #Loop
    126         for k in range(N):
    127             optimal_timestep = float(sys.maxint)
    128 
    129             flux[:] = 0.  #Reset work array
    130             for i in range(3):
    131                 #Quantities inside volume facing neighbour i
    132                 ql = stage[k, i]
    133 
    134                 #Quantities at neighbour on nearest face
    135                 n = neighbours[k,i]
    136                 if n < 0:
    137                     m = -n-1 #Convert neg flag to index
    138                     qr = stage_bdry[m]
    139                 else:
    140                     m = neighbour_edges[k,i]
    141                     qr = stage[n, m]
    142 
    143 
    144                 #Outward pointing normal vector
    145                 normal = normals[k, 2*i:2*i+2]
    146 
    147                 #Flux computation using provided function
    148                 edgeflux, max_speed = self.flux_function(normal, ql, qr)
    149                 flux -= edgeflux * edgelengths[k,i]
    150 
    151                 #Update optimal_timestep
    152                 try:
    153                     optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
    154                 except ZeroDivisionError:
    155                     pass
    156 
    157             #Normalise by area and store for when all conserved
    158             #quantities get updated
    159             flux /= areas[k]
    160             Stage.explicit_update[k] = flux[0]
    161 
    162             timestep = min(timestep, optimal_timestep)
    163 
    164         self.timestep = timestep
    16543
    16644
     
    17351        if self.visualise is True and self.time == 0.0:
    17452            import realtime_visualisation_new as visualise
    175             visualise.create_surface(self)
     53            self.visualiser = visualise.Visualiser(self)
    17654
    17755        #Call basic machinery from parent class
    178         for t in Generic_domain.evolve(self, yieldstep, finaltime):
     56        for t in Advection_Domain.evolve(self, yieldstep, finaltime):
    17957            #Real time viz
    18058            if self.visualise is True:
    181                 visualise.update(self)
     59                self.visualiser.update_quantity('stage')
    18260
    18361            #Pass control on to outer loop for more specific actions
    18462            yield(t)
     63
     64
     65
     66def rectangular_with_ghosts(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
     67
     68    """Setup a rectangular grid of triangles
     69    with m+1 by n+1 grid points
     70    and side lengths len1, len2. If side lengths are omitted
     71    the mesh defaults to the unit square.
     72
     73    len1: x direction (left to right)
     74    len2: y direction (bottom to top)
     75
     76    Also returns a list of
     77
     78    Return to lists: points and elements suitable for creating a Mesh or
     79    FVMesh object, e.g. Mesh(points, elements)
     80    """
     81
     82    from config import epsilon
     83
     84    #E = m*n*2        #Number of triangular elements
     85    #P = (m+1)*(n+1)  #Number of initial vertices
     86
     87    delta1 = float(len1)/m
     88    delta2 = float(len2)/n
     89
     90    #Dictionary of vertex objects
     91    vertices = {}
     92    points = []
     93
     94    for i in range(m+1):
     95        for j in range(n+1):
     96            vertices[i,j] = len(points)
     97            points.append([i*delta1 + origin[0], j*delta2 + origin[1]])
     98
     99
     100
     101    #Construct 2 triangles per rectangular element and assign tags to boundary
     102    elements = []
     103    boundary = {}
     104    for i in range(m):
     105        for j in range(n):
     106            v1 = vertices[i,j+1]
     107            v2 = vertices[i,j]
     108            v3 = vertices[i+1,j+1]
     109            v4 = vertices[i+1,j]
     110
     111            #Update boundary dictionary and create elements
     112            if i == m-1:
     113                boundary[(len(elements), 2)] = 'right'
     114            if j == 0:
     115                boundary[(len(elements), 1)] = 'bottom'
     116            elements.append([v4,v3,v2]) #Lower element
     117
     118            if i == 0:
     119                boundary[(len(elements), 2)] = 'left'
     120            if j == n-1:
     121                boundary[(len(elements), 1)] = 'top'
     122            elements.append([v1,v2,v3]) #Upper element
     123
     124    ghosts = {}
     125    i=0
     126    for j in range(n):
     127        v1 = vertices[i,j+1]
     128        v2 = vertices[i,j]
     129        v3 = vertices[i+1,j+1]
     130        v4 = vertices[i+1,j]
     131        ghosts.append(elements.index([
     132
     133    return points, elements, boundary
  • inundation/ga/storm_surge/parallel/run_advection.py

    r1363 r1387  
    1919
    2020domain.visualise = True
    21 #domain.visualise_range_z = 1.0
    22 domain.visualise_color_stage = True
     21domain.visualise_range_z = 0.5
     22#domain.visualise_color_stage = True
    2323
    2424
  • inundation/ga/storm_surge/parallel/run_parallel_advection.py

    r1363 r1387  
    66from config import g, epsilon
    77from Numeric import allclose, array, zeros, ones, Float
    8 from advection import *
     8from parallel_advection import *
    99from Numeric import array
    1010
    1111from mesh_factory import rectangular
    1212
    13 points, vertices, boundary = rectangular(60, 60)
     13points, vertices, boundary = rectangular(30, 30)
    1414
    1515#Create advection domain with direction (1,-1)
    16 domain = Domain(points, vertices, boundary, velocity=[1.0, 0.0])
     16domain = Parallel_Domain(points, vertices, boundary, velocity=[1.0, 0.0])
    1717
    1818# Initial condition is zero by default
     
    2929
    3030
    31 domain.set_boundary( {'left': D, 'right': T, 'bottom': T, 'top': T} )
     31domain.set_boundary( {'left': T, 'right': T, 'bottom': T, 'top': T} )
    3232domain.check_integrity()
     33
     34class Set_Stage:
     35    """Set an initial condition with constant water height, for x<x0
     36    """
     37
     38    def __init__(self, x0=0.25, x1=0.5, h=1.0):
     39        self.x0 = x0
     40        self.x1 = x1
     41        self.h  = h
     42
     43    def __call__(self, x, y):
     44        return self.h*((x>self.x0)&(x<self.x1))
     45
     46domain.set_quantity('stage', Set_Stage(0.2,0.4,1.0))
    3347
    3448#Check that the boundary value gets propagated to all elements
  • inundation/ga/storm_surge/parallel/small.tsh

    r1363 r1387  
    1131 0 # <# of verts> <# of vert attributes>, next lines <vertex #> <x> <y> [attributes] ...Triangulation Vertices...
    2 0 554.0 -242.0 
    3 1 443.0 -190.0 
    4 2 340.0 -184.0 
    5 3 276.0 -237.0 
    6 4 281.0 -347.0 
    7 5 282.0 -380.0 
    8 6 312.0 -425.0 
    9 7 387.0 -472.0 
    10 8 465.0 -487.0 
    11 9 549.0 -469.0 
    12 10 566.0 -413.0 
    13 11 589.0 -359.0 
    14 12 472.0 -258.0 
    15 13 377.0 -411.0 
    16 14 428.0 -257.0 
    17 15 386.0 -278.0 
    18 16 372.0 -325.0 
    19 17 369.0 -371.0 
    20 18 433.0 -422.0 
    21 19 476.0 -361.0 
    22 20 502.0 -304.0 
    23 21 333.0 -225.0 
    24 22 305.0 -244.0 
    25 23 333.0 -270.0 
    26 24 369.0 -237.0 
    27 25 278.5 -292.0 
    28 26 499.90712817 -423.516449623 
    29 27 532.621862616 -366.885237781 
    30 28 498.5 -216.0 
    31 29 322.359287054 -318.872505543 
    32 30 571.5 -300.5 
     20 554.0 -242.0
     31 443.0 -190.0
     42 340.0 -184.0
     53 276.0 -237.0
     64 281.0 -347.0
     75 282.0 -380.0
     86 312.0 -425.0
     97 387.0 -472.0
     108 465.0 -487.0
     119 549.0 -469.0
     1210 566.0 -413.0
     1311 589.0 -359.0
     1412 472.0 -258.0
     1513 377.0 -411.0
     1614 428.0 -257.0
     1715 386.0 -278.0
     1816 372.0 -325.0
     1917 369.0 -371.0
     2018 433.0 -422.0
     2119 476.0 -361.0
     2220 502.0 -304.0
     2321 333.0 -225.0
     2422 305.0 -244.0
     2523 333.0 -270.0
     2624 369.0 -237.0
     2725 278.5 -292.0
     2826 499.90712817 -423.516449623
     2927 532.621862616 -366.885237781
     3028 498.5 -216.0
     3129 322.359287054 -318.872505543
     3230 571.5 -300.5
    3333# attribute column titles ...Triangulation Vertex Titles...
    343438 # <# of triangles>, next lines <triangle #> [<vertex #>] [<neigbouring triangle #>] [attribute of region] ...Triangulation Triangles...
    35 0 29 5 17 1 5 26  
    36 1 17 5 6 -1 3 0 
    37 2 10 11 27 28 21 -1 
    38 3 13 17 6 1 6 -1 
    39 4 15 23 16 24 -1 16 
    40 5 16 29 17 0 -1 24 
    41 6 6 7 13 37 3 -1 
    42 7 29 23 25 9 8 24 
    43 8 25 4 29 26 7 -1 
    44 9 25 23 22 10 18 7 
    45 10 22 23 21 13 11 9  
    46 11 3 22 21 10 15 18 
    47 12 21 24 2 14 15 13 
    48 13 24 21 23 10 16 12 
    49 14 2 24 1 27 -1 12 
    50 15 21 2 3 -1 11 12 
    51 16 24 23 15 4 30 13 
    52 17 27 30 20 31 36 28  
    53 18 22 3 25 -1 9 11 
    54 19 7 8 18 35 37 -1 
    55 20 8 9 26 23 35 -1 
    56 21 26 10 27 2 25 23 
    57 22 26 19 18 -1 35 25  
    58 23 10 26 9 20 -1 21 
    59 24 16 23 29 7 5 4 
    60 25 26 27 19 36 22 21 
    61 26 29 4 5 -1 0 8 
    62 27 14 1 24 14 30 29  
    63 28 27 11 30 -1 17 2 
    64 29 1 14 12 -1 33 27  
    65 30 14 24 15 16 -1 27 
    66 31 20 30 0 -1 34 17 
    67 32 12 0 28 -1 33 34 
    68 33 12 28 1 -1 29 32 
    69 34 0 12 20 -1 31 32 
    70 35 8 26 18 22 19 20 
    71 36 27 20 19 -1 25 17 
    72 37 18 13 7 6 19 -1 
     350 29 5 17 1 5 26 building
     361 17 5 6 -1 3 0
     372 10 11 27 28 21 -1
     383 13 17 6 1 6 -1
     394 15 23 16 24 -1 16
     405 16 29 17 0 -1 24
     416 6 7 13 37 3 -1
     427 29 23 25 9 8 24
     438 25 4 29 26 7 -1
     449 25 23 22 10 18 7
     4510 22 23 21 13 11 9 building
     4611 3 22 21 10 15 18
     4712 21 24 2 14 15 13
     4813 24 21 23 10 16 12
     4914 2 24 1 27 -1 12
     5015 21 2 3 -1 11 12
     5116 24 23 15 4 30 13
     5217 27 30 20 31 36 28 house
     5318 22 3 25 -1 9 11
     5419 7 8 18 35 37 -1
     5520 8 9 26 23 35 -1
     5621 26 10 27 2 25 23
     5722 26 19 18 -1 35 25 building
     5823 10 26 9 20 -1 21
     5924 16 23 29 7 5 4
     6025 26 27 19 36 22 21
     6126 29 4 5 -1 0 8
     6227 14 1 24 14 30 29 house
     6328 27 11 30 -1 17 2
     6429 1 14 12 -1 33 27 oval
     6530 14 24 15 16 -1 27
     6631 20 30 0 -1 34 17
     6732 12 0 28 -1 33 34
     6833 12 28 1 -1 29 32
     6934 0 12 20 -1 31 32
     7035 8 26 18 22 19 20
     7136 27 20 19 -1 25 17
     7237 18 13 7 6 19 -1
    737328 # <# of segments>, next lines <segment #> <vertex #>  <vertex #> [boundary tag] ...Triangulation Segments...
    74740 14 12 exterior
     
    81817 19 20 exterior
    82828 12 20 exterior
    83 9 21 22 
    84 10 23 22 
    85 11 23 24 
    86 12 21 24 
     839 21 22
     8410 23 22
     8511 23 24
     8612 21 24
    878713 4 25 exterior
    888814 7 6 exterior
     
    10110127 30 11 exterior
    10210225 0 # <# of verts> <# of vert attributes>, next lines <vertex #> <x> <y> [attributes] ...Mesh Vertices...
    103 0 554.0 -242.0 
    104 1 443.0 -190.0 
    105 2 340.0 -184.0 
    106 3 276.0 -237.0 
    107 4 281.0 -347.0 
    108 5 282.0 -380.0 
    109 6 312.0 -425.0 
    110 7 387.0 -472.0 
    111 8 465.0 -487.0 
    112 9 549.0 -469.0 
    113 10 566.0 -413.0 
    114 11 589.0 -359.0 
    115 12 472.0 -258.0 
    116 13 377.0 -411.0 
    117 14 428.0 -257.0 
    118 15 386.0 -278.0 
    119 16 372.0 -325.0 
    120 17 369.0 -371.0 
    121 18 433.0 -422.0 
    122 19 476.0 -361.0 
    123 20 502.0 -304.0 
    124 21 333.0 -225.0 
    125 22 305.0 -244.0 
    126 23 333.0 -270.0 
    127 24 369.0 -237.0 
     1030 554.0 -242.0
     1041 443.0 -190.0
     1052 340.0 -184.0
     1063 276.0 -237.0
     1074 281.0 -347.0
     1085 282.0 -380.0
     1096 312.0 -425.0
     1107 387.0 -472.0
     1118 465.0 -487.0
     1129 549.0 -469.0
     11310 566.0 -413.0
     11411 589.0 -359.0
     11512 472.0 -258.0
     11613 377.0 -411.0
     11714 428.0 -257.0
     11815 386.0 -278.0
     11916 372.0 -325.0
     12017 369.0 -371.0
     12118 433.0 -422.0
     12219 476.0 -361.0
     12320 502.0 -304.0
     12421 333.0 -225.0
     12522 305.0 -244.0
     12623 333.0 -270.0
     12724 369.0 -237.0
    12812825 # <# of segments>, next lines <segment #> <vertex #>  <vertex #> [boundary tag] ...Mesh Segments...
    129 0 14 12 
    130 1 15 14 
    131 2 16 15 
    132 3 17 16 
    133 4 13 17 
    134 5 18 13 
    135 6 19 18 
    136 7 20 19 
    137 8 12 20 
    138 9 22 21 
    139 10 23 22 
    140 11 24 23 
    141 12 21 24 
    142 13 3 4 
    143 14 6 7 
    144 15 5 6 
    145 16 2 3 
    146 17 4 5 
    147 18 7 8 
    148 19 9 10 
    149 20 8 9 
    150 21 0 1 
    151 22 1 2 
    152 23 11 0 
    153 24 10 11 
     1290 14 12
     1301 15 14
     1312 16 15
     1323 17 16
     1334 13 17
     1345 18 13
     1356 19 18
     1367 20 19
     1378 12 20
     1389 22 21
     13910 23 22
     14011 24 23
     14112 21 24
     14213 3 4
     14314 6 7
     14415 5 6
     14516 2 3
     14617 4 5
     14718 7 8
     14819 9 10
     14920 8 9
     15021 0 1
     15122 1 2
     15223 11 0
     15324 10 11
    1541541 # <# of holes>, next lines <Hole #> <x> <y> ...Mesh Holes...
    1551550 418.0 -332.0
    1561561 # <# of regions>, next lines <Region #> <x> <y> <tag>...Mesh Regions...
    157 0 334.0 -243.0 
     1570 334.0 -243.0
    1581581 # <# of regions>, next lines <Region #> [Max Area] ...Mesh Regions...
    159 0 
     1590
    160160# Geo reference
    16116156
  • inundation/ga/storm_surge/pyvolution/domain.py

    r1360 r1387  
    260260        x = self.boundary.keys()
    261261        x.sort()
     262
    262263        for k, (vol_id, edge_id) in enumerate(x):
    263264            tag = self.boundary[ (vol_id, edge_id) ]
  • inundation/ga/storm_surge/pyvolution/general_mesh.py

    r1178 r1387  
    66
    77    A triangular element is defined in terms of three vertex ids,
    8     ordered counter clock-wise, 
     8    ordered counter clock-wise,
    99    each corresponding to a given coordinate set.
    1010    Vertices from different elements can point to the same
     
    1212
    1313    Coordinate sets are implemented as an N x 2 Numeric array containing
    14     x and y coordinates. 
    15    
     14    x and y coordinates.
     15
    1616
    1717    To instantiate:
     
    3333        c = [2.0,0.0]
    3434        e = [2.0, 2.0]
    35        
     35
    3636        points = [a, b, c, e]
    37         triangles = [ [1,0,2], [1,2,3] ]   #bac, bce 
     37        triangles = [ [1,0,2], [1,2,3] ]   #bac, bce
    3838        mesh = Mesh(points, triangles)
    39    
     39
    4040        #creates two triangles: bac and bce
    4141
    4242    Other:
    43    
     43
    4444      In addition mesh computes an Nx6 array called vertex_coordinates.
    45       This structure is derived from coordinates and contains for each 
     45      This structure is derived from coordinates and contains for each
    4646      triangle the three x,y coordinates at the vertices.
    47                                
    48 
    49         This is a cut down version of mesh from pyvolution\mesh.py
     47
     48
     49        This is a cut down version of mesh from pyvolution mesh.py
    5050    """
    5151
     
    5858
    5959        origin is a 3-tuple consisting of UTM zone, easting and northing.
    60         If specified coordinates are assumed to be relative to this origin. 
     60        If specified coordinates are assumed to be relative to this origin.
    6161        """
    6262
     
    6767
    6868        if geo_reference is None:
    69             self.geo_reference = Geo_reference(DEFAULT_ZONE,0.0,0.0) 
     69            self.geo_reference = Geo_reference(DEFAULT_ZONE,0.0,0.0)
    7070        else:
    7171            self.geo_reference = geo_reference
    7272
    7373        #Input checks
    74         msg = 'Triangles must an Nx2 Numeric array or a sequence of 2-tuples'
     74        msg = 'Triangles must an Nx3 Numeric array or a sequence of 3-tuples'
    7575        assert len(self.triangles.shape) == 2, msg
    7676
    7777        msg = 'Coordinates must an Mx2 Numeric array or a sequence of 2-tuples'
    78         assert len(self.coordinates.shape) == 2, msg       
     78        assert len(self.coordinates.shape) == 2, msg
    7979
    8080        msg = 'Vertex indices reference non-existing coordinate sets'
     
    8484        #Register number of elements (N)
    8585        self.number_of_elements = N = self.triangles.shape[0]
    86    
    87         #Allocate space for geometric quantities       
     86
     87        #Allocate space for geometric quantities
    8888        self.normals = zeros((N, 6), Float)
    8989        self.areas = zeros(N, Float)
     
    9292        #Get x,y coordinates for all triangles and store
    9393        self.vertex_coordinates = V = self.compute_vertex_coordinates()
    94        
     94
    9595        #Initialise each triangle
    9696        for i in range(N):
    9797            #if i % (N/10) == 0: print '(%d/%d)' %(i, N)
    98            
     98
    9999            x0 = V[i, 0]; y0 = V[i, 1]
    100100            x1 = V[i, 2]; y1 = V[i, 3]
    101             x2 = V[i, 4]; y2 = V[i, 5]           
     101            x2 = V[i, 4]; y2 = V[i, 5]
    102102
    103103            #Area
     
    107107            msg += ' is degenerate:  area == %f' %self.areas[i]
    108108            assert self.areas[i] > 0.0, msg
    109        
     109
    110110
    111111            #Normals
     
    120120
    121121            n0 = array([x2 - x1, y2 - y1])
    122             l0 = sqrt(sum(n0**2))
     122            l0 = sqrt(sum(n0**2))
    123123
    124124            n1 = array([x0 - x2, y0 - y2])
     
    137137                                  n1[1], -n1[0],
    138138                                  n2[1], -n2[0]]
    139            
     139
    140140            #Edgelengths
    141141            self.edgelengths[i, :] = [l0, l1, l2]
    142142
    143143        #Build vertex list
    144         self.build_vertexlist()       
    145            
     144        self.build_vertexlist()
     145
    146146    def __len__(self):
    147147        return self.number_of_elements
     
    154154        """Return all normal vectors.
    155155        Return normal vectors for all triangles as an Nx6 array
    156         (ordered as x0, y0, x1, y1, x2, y2 for each triangle)       
     156        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
    157157        """
    158158        return self.normals
     
    163163        Return value is the numeric array slice [x, y]
    164164        """
    165         return self.normals[i, 2*j:2*j+2]     
    166    
    167 
    168            
     165        return self.normals[i, 2*j:2*j+2]
     166
     167
     168
    169169    def get_vertex_coordinates(self):
    170170        """Return all vertex coordinates.
    171171        Return all vertex coordinates for all triangles as an Nx6 array
    172         (ordered as x0, y0, x1, y1, x2, y2 for each triangle)       
     172        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
    173173        """
    174174        return self.vertex_coordinates
     
    179179        Return value is the numeric array slice [x, y]
    180180        """
    181         return self.vertex_coordinates[i, 2*j:2*j+2]     
     181        return self.vertex_coordinates[i, 2*j:2*j+2]
    182182
    183183
     
    189189        #FIXME: Perhaps they should be ordered as in obj files??
    190190        #See quantity.get_vertex_values
    191        
     191
    192192        from Numeric import zeros, Float
    193193
    194194        N = self.number_of_elements
    195         vertex_coordinates = zeros((N, 6), Float) 
     195        vertex_coordinates = zeros((N, 6), Float)
    196196
    197197        for i in range(N):
     
    203203
    204204        return vertex_coordinates
    205    
     205
    206206    def get_vertices(self,  indexes=None):
    207207        """Get connectivity
    208208        indexes is the set of element ids of interest
    209209        """
    210        
     210
    211211        from Numeric import take
    212        
     212
    213213        if (indexes ==  None):
    214214            indexes = range(len(self))  #len(self)=number of elements
    215            
     215
    216216        return  take(self.triangles, indexes)
    217217
     
    220220        unique_verts = {}
    221221        for triangle in triangles:
    222            unique_verts[triangle[0]] = 0 
    223            unique_verts[triangle[1]] = 0 
     222           unique_verts[triangle[0]] = 0
     223           unique_verts[triangle[1]] = 0
    224224           unique_verts[triangle[2]] = 0
    225         return unique_verts.keys()   
    226        
     225        return unique_verts.keys()
     226
    227227    def build_vertexlist(self):
    228228        """Build vertexlist index by vertex ids and for each entry (point id)
     
    231231
    232232        Preconditions:
    233           self.coordinates and self.triangles are defined 
    234        
     233          self.coordinates and self.triangles are defined
     234
    235235        Postcondition:
    236236          self.vertexlist is built
     
    242242            a = self.triangles[i, 0]
    243243            b = self.triangles[i, 1]
    244             c = self.triangles[i, 2]           
     244            c = self.triangles[i, 2]
    245245
    246246            #Register the vertices v as lists of
     
    251251                    vertexlist[v] = []
    252252
    253                 vertexlist[v].append( (i, vertex_id) )   
     253                vertexlist[v].append( (i, vertex_id) )
    254254
    255255        self.vertexlist = vertexlist
    256    
     256
    257257
    258258    def get_extent(self):
     
    264264        X = C[:,0:6:2].copy()
    265265        Y = C[:,1:6:2].copy()
    266        
     266
    267267        xmin = min(X.flat)
    268268        xmax = max(X.flat)
    269269        ymin = min(Y.flat)
    270         ymax = max(Y.flat)               
    271        
     270        ymax = max(Y.flat)
     271
    272272        return xmin, xmax, ymin, ymax
    273273
     
    277277        """
    278278
    279         return sum(self.areas)         
    280        
     279        return sum(self.areas)
  • inundation/ga/storm_surge/pyvolution/mesh.py

    r1360 r1387  
    130130                c = sqrt((x2-x0)**2+(y2-y0)**2)
    131131
    132                 self.radii[i]=2.0*self.areas[i]/(a+b+c)
     132                self.radii[i]=self.areas[i]/(a+b+c)
    133133
    134134
  • inundation/ga/storm_surge/pyvolution/mesh_factory.py

    r820 r1387  
    44
    55
    6 def rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
     6def rectangular_old(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
    77
    88    """Setup a rectangular grid of triangles
     
    1010    and side lengths len1, len2. If side lengths are omitted
    1111    the mesh defaults to the unit square.
    12    
     12
    1313    len1: x direction (left to right)
    1414    len2: y direction (bottom to top)
    1515
    1616    Return to lists: points and elements suitable for creating a Mesh or
    17     FVMesh object, e.g. Mesh(points, elements) 
     17    FVMesh object, e.g. Mesh(points, elements)
    1818    """
    1919
    2020    from config import epsilon
    21    
     21
    2222    #E = m*n*2        #Number of triangular elements
    2323    #P = (m+1)*(n+1)  #Number of initial vertices
    2424
    2525    delta1 = float(len1)/m
    26     delta2 = float(len2)/n   
     26    delta2 = float(len2)/n
    2727
    2828    #Dictionary of vertex objects
     
    4343        for j in range(n):
    4444            v1 = vertices[i,j+1]
    45             v2 = vertices[i,j]           
    46             v3 = vertices[i+1,j+1]           
    47             v4 = vertices[i+1,j]           
     45            v2 = vertices[i,j]
     46            v3 = vertices[i+1,j+1]
     47            v4 = vertices[i+1,j]
    4848
    4949            #Update boundary dictionary and create elements
     
    5151                boundary[(len(elements), 2)] = 'right'
    5252            if j == 0:
    53                 boundary[(len(elements), 1)] = 'bottom'               
     53                boundary[(len(elements), 1)] = 'bottom'
    5454            elements.append([v4,v3,v2]) #Lower element
    5555
     
    5757                boundary[(len(elements), 2)] = 'left'
    5858            if j == n-1:
    59                 boundary[(len(elements), 1)] = 'top'
    60             elements.append([v1,v2,v3]) #Upper element   
    61 
    62     return points, elements, boundary       
    63 
     59                boundary[(len(elements), 1)] = 'top'
     60            elements.append([v1,v2,v3]) #Upper element
     61
     62    return points, elements, boundary
     63
     64def rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
     65
     66    """Setup a rectangular grid of triangles
     67    with m+1 by n+1 grid points
     68    and side lengths len1, len2. If side lengths are omitted
     69    the mesh defaults to the unit square.
     70
     71    len1: x direction (left to right)
     72    len2: y direction (bottom to top)
     73
     74    Return to lists: points and elements suitable for creating a Mesh or
     75    FVMesh object, e.g. Mesh(points, elements)
     76    """
     77
     78    from config import epsilon
     79    from Numeric import zeros, Float, Int
     80
     81    delta1 = float(len1)/m
     82    delta2 = float(len2)/n
     83
     84    #Calculate number of points
     85    Np = (m+1)*(n+1)
     86
     87    class Index:
     88
     89        def __init__(self, n,m):
     90            self.n = n
     91            self.m = m
     92
     93        def __call__(self, i,j):
     94            return j+i*(self.n+1)
     95
     96
     97    index = Index(n,m)
     98
     99    points = zeros( (Np,2), Float)
     100
     101    for i in range(m+1):
     102        for j in range(n+1):
     103
     104            points[index(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
     105
     106    #Construct 2 triangles per rectangular element and assign tags to boundary
     107    #Calculate number of triangles
     108    Nt = 2*m*n
     109
     110
     111    elements = zeros( (Nt,3), Int)
     112    boundary = {}
     113    nt = -1
     114    for i in range(m):
     115        for j in range(n):
     116            nt = nt + 1
     117            i1 = index(i,j+1)
     118            i2 = index(i,j)
     119            i3 = index(i+1,j+1)
     120            i4 = index(i+1,j)
     121
     122            #Update boundary dictionary and create elements
     123            if i == m-1:
     124                boundary[nt, 2] = 'right'
     125            if j == 0:
     126                boundary[nt, 1] = 'bottom'
     127            elements[nt,:] = [i4,i3,i2] #Lower element
     128            nt = nt + 1
     129
     130            if i == 0:
     131                boundary[nt, 2] = 'left'
     132            if j == n-1:
     133                boundary[nt, 1] = 'top'
     134            elements[nt,:] = [i1,i2,i3] #Upper element
     135
     136    return points, elements, boundary
    64137
    65138def oblique(m, n, lenx = 1.0, leny = 1.0, theta = 8.95, origin = (0.0, 0.0)):
     
    97170    for i in range(m+1):
    98171        x = deltax*i
    99         for j in range(n+1):     
     172        for j in range(n+1):
    100173            y = deltay*j
    101174            if x > 0.25*lenx:
    102175                y = a1 + a2*x + a3*y + a4*x*y
    103                
     176
    104177            vertices[i,j] = len(points)
    105178            points.append([x + origin[0], y + origin[1]])
    106179
    107     # Construct 2 triangles per element       
     180    # Construct 2 triangles per element
    108181    elements = []
    109182    boundary = {}
     
    111184        for j in range(n):
    112185            v1 = vertices[i,j+1]
    113             v2 = vertices[i,j]           
    114             v3 = vertices[i+1,j+1]           
     186            v2 = vertices[i,j]
     187            v3 = vertices[i+1,j+1]
    115188            v4 = vertices[i+1,j]
    116            
     189
    117190            #Update boundary dictionary and create elements
    118191            if i == m-1:
    119192                boundary[(len(elements), 2)] = 'right'
    120193            if j == 0:
    121                 boundary[(len(elements), 1)] = 'bottom'               
     194                boundary[(len(elements), 1)] = 'bottom'
    122195            elements.append([v4,v3,v2]) #Lower
    123196
     
    125198                boundary[(len(elements), 2)] = 'left'
    126199            if j == n-1:
    127                 boundary[(len(elements), 1)] = 'top' 
    128              
     200                boundary[(len(elements), 1)] = 'top'
     201
    129202            elements.append([v1,v2,v3]) #Upper
    130203
    131     return points, elements, boundary       
     204    return points, elements, boundary
    132205
    133206
     
    136209    with n radial segments. If radius is are omitted the mesh defaults to
    137210    the unit circle radius.
    138  
     211
    139212    radius: radius of circle
    140    
     213
    141214    #FIXME: The triangles become degenerate for large values of m or n.
    142215    """
    143216
    144217
    145    
     218
    146219    from math import pi, cos, sin
    147220
     
    152225    points = [[0.0, 0.0]] #Center point
    153226    vertices[0, 0] = 0
    154    
     227
    155228    for i in range(n):
    156229        theta = 2*i*pi/n
     
    162235            points.append([delta*x, delta*y])
    163236
    164     #Construct 2 triangles per element       
     237    #Construct 2 triangles per element
    165238    elements = []
    166239    for i in range(n):
    167240        for j in range(1,m):
    168241
    169             i1 = (i + 1) % n  #Wrap around 
    170            
     242            i1 = (i + 1) % n  #Wrap around
     243
    171244            v1 = vertices[i,j+1]
    172             v2 = vertices[i,j]           
    173             v3 = vertices[i1,j+1]           
     245            v2 = vertices[i,j]
     246            v3 = vertices[i1,j+1]
    174247            v4 = vertices[i1,j]
    175248
    176             elements.append([v4,v2,v3]) #Lower               
     249            elements.append([v4,v2,v3]) #Lower
    177250            elements.append([v1,v3,v2]) #Upper
    178251
     
    181254    v1 = vertices[0,0]
    182255    for i in range(n):
    183         i1 = (i + 1) % n  #Wrap around         
     256        i1 = (i + 1) % n  #Wrap around
    184257        v2 = vertices[i,1]
    185258        v3 = vertices[i1,1]
    186259
    187260        elements.append([v1,v2,v3]) #center
    188          
     261
    189262    return points, elements
    190263
     
    205278        filename = name + '.poly'
    206279
    207    
     280
    208281    fid = open(filename)
    209282
    210283    points = []    #x, y
    211284    values = []    #z
    212     ##vertex_values = []    #Repeated z   
     285    ##vertex_values = []    #Repeated z
    213286    triangles = [] #v0, v1, v2
    214    
     287
    215288    lines = fid.readlines()
    216289
     
    237310        x = float(xyz[0])
    238311        y = float(xyz[1])
    239         z = float(xyz[2])       
     312        z = float(xyz[2])
    240313
    241314        points.append([x, y])
    242315        values.append(z)
    243        
    244 
    245     k = i   
     316
     317
     318    k = i
    246319    while keyword == 'POLYS':
    247320        line = lines[i].strip()
     
    251324            keyword = line
    252325            break
    253        
     326
    254327
    255328        fields = line.split(':')
     
    269342        y1 = points[i1][1]
    270343        x2 = points[i2][0]
    271         y2 = points[i2][1]               
     344        y2 = points[i2][1]
    272345
    273346        area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
     
    281354            a0 = anglediff(v1, v0)
    282355            a1 = anglediff(v2, v1)
    283             a2 = anglediff(v0, v2)       
    284 
    285            
     356            a2 = anglediff(v0, v2)
     357
     358
    286359            if a0 < pi and a1 < pi and a2 < pi:
    287360                #all is well
     
    294367                j1 = i0
    295368                j2 = i2
    296                
     369
    297370            triangles.append([j0, j1, j2])
    298371            ##vertex_values.append([values[j0], values[j1], values[j2]])
    299372        else:
    300             offending +=1 
     373            offending +=1
    301374
    302375    print 'Removed %d offending triangles out of %d' %(offending, len(lines))
     
    311384    from math import pi
    312385    from util import anglediff
    313    
    314    
     386
     387
    315388    fid = open(filename)
    316389    points = []    # List of x, y coordinates
    317390    triangles = [] # List of vertex ids as listed in the file
    318    
     391
    319392    for line in fid.readlines():
    320393        fields = line.split()
     
    337410        v1 = t[1]
    338411        v2 = t[2]
    339        
     412
    340413        x0 = points[v0][0]
    341414        y0 = points[v0][1]
     
    343416        y1 = points[v1][1]
    344417        x2 = points[v2][0]
    345         y2 = points[v2][1]               
     418        y2 = points[v2][1]
    346419
    347420        #Check that points are arranged in counter clock-wise order
     
    352425        a0 = anglediff(vec1, vec0)
    353426        a1 = anglediff(vec2, vec1)
    354         a2 = anglediff(vec0, vec2)       
     427        a2 = anglediff(vec0, vec2)
    355428
    356429        if a0 < pi and a1 < pi and a2 < pi:
    357430            elements.append([v0, v1, v2])
    358431        else:
    359             elements.append([v0, v2, v1])       
    360 
    361     return points, elements                             
     432            elements.append([v0, v2, v1])
     433
     434    return points, elements
    362435
    363436# #Map from edge number to indices of associated vertices
     
    365438
    366439
    367                                          
    368    
  • inundation/ga/storm_surge/pyvolution/netherlands.py

    r1360 r1387  
    1010#
    1111from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
    12      Transmissive_boundary, Constant_height
     12     Transmissive_boundary, Constant_height, Constant_stage
    1313
    1414from mesh_factory import rectangular
     
    8080N = 130 #size = 33800
    8181N = 600 #Size = 720000
    82 N = 60
     82N = 50
     83M = 40
    8384
    8485#N = 15
     
    8687print 'Creating domain'
    8788#Create basic mesh
    88 points, vertices, boundary = rectangular(N, N)
     89points, vertices, boundary = rectangular(N, M)
    8990
    9091#Create shallow water domain
     
    102103
    103104#Set bed-slope and friction
    104 inflow_stage = 0.1
    105 manning = 0.02
     105inflow_stage = 0.2
     106manning = 0.00
    106107Z = Weir(inflow_stage)
    107108
     
    148149#
    149150print 'Initial condition'
    150 domain.set_quantity('stage', Constant_height(Z, 0.))
     151domain.set_quantity('stage', Constant_height(Z, 0.0))
     152#domain.set_quantity('stage', Constant_stage(-1.0))
    151153
    152154#Evolve
     
    154156t0 = time.time()
    155157
    156 for t in domain.evolve(yieldstep = 0.05, finaltime = 10.0):
     158for t in domain.evolve(yieldstep = 0.01, finaltime = 5.0):
    157159    domain.write_time()
     160    #domain.visualiser.scale_z = 1.0
     161    domain.visualiser.update_quantity_color('xmomentum',scale_z = 4.0)
    158162
    159163
  • inundation/ga/storm_surge/pyvolution/realtime_visualisation_new.py

    r1363 r1387  
    33elevation_color = (0.3,0.4,0.5)
    44stage_color = (0.1,0.4,0.99)
     5other_color = (0.99,0.4,0.1)
    56
    67class Visualiser:
     
    117118
    118119
    119     def update_quantity(self,qname,qcolor=None):
     120    def update_quantity(self,qname,qcolor=None,scale_z=None):
    120121
    121122        #print 'update '+qname+' arrays'
    122123
    123124        if qcolor is None:
     125            qcolor = other_color
     126
    124127            if qname=='elevation':
    125128                qcolor = elevation_color
     
    128131                qcolor = stage_color
    129132
     133        if scale_z is None:
     134            scale_z = self.scale_z
    130135
    131136        try:
    132             self.update_arrays(self.domain.quantities[qname].vertex_values, qcolor)
     137            self.update_arrays(self.domain.quantities[qname].vertex_values, qcolor, scale_z)
    133138
    134139            #print 'update bed image'
     
    140145            pass
    141146
    142     def update_quantity_color(self,qname,qcolor=None):
     147    def update_quantity_color(self,qname,qcolor=None,scale_z=None):
    143148
    144149        #print 'update '+qname+' arrays'
     
    151156                qcolor = stage_color
    152157
     158        if scale_z is None:
     159            scale_z = self.scale_z
    153160
    154161        #try:
    155         self.update_arrays_color(self.domain.quantities[qname].vertex_values, qcolor)
     162        self.update_arrays_color(self.domain.quantities[qname].vertex_values, qcolor, scale_z)
    156163
    157164            #print 'update bed image'
     
    164171
    165172
    166     def update_arrays(self,quantity,qcolor):
     173    def update_arrays(self,quantity,qcolor,scale_z):
    167174
    168175        col = asarray(qcolor)
     
    170177        N = len(self.domain)
    171178
    172         scale_z = self.scale_z
    173179        min_x = self.min_x
    174180        min_y = self.min_y
     
    189195
    190196
    191     def update_arrays_color(self,quantity,qcolor):
     197    def update_arrays_color(self,quantity,qcolor,scale_z):
    192198
    193199        col = asarray(qcolor)
     
    195201        N = len(self.domain)
    196202
    197         scale_z = self.scale_z
    198203        min_x = self.min_x
    199204        min_y = self.min_y
     
    308313            normal(1) = normal(1)/norm;
    309314            normal(2) = normal(2)/norm;
     315
    310316
    311317            for (int j=0; j<3; j++) {
  • inundation/ga/storm_surge/pyvolution/shallow_water.py

    r1363 r1387  
    15071507
    15081508
     1509class Constant_stage:
     1510    """Set an initial condition with constant stage
     1511    """
     1512    def __init__(self, s):
     1513        self.s = s
     1514
     1515    def __call__(self, x, y):
     1516        return self.s
     1517
    15091518class Constant_height:
    15101519    """Set an initial condition with constant water height, e.g
    15111520    stage s = z+h
    15121521    """
     1522
    15131523    def __init__(self, W, h):
    15141524        self.W = W
  • inundation/ga/storm_surge/pyvolution/shallow_water_ext.c

    r1017 r1387  
    22//
    33// To compile (Python2.3):
    4 //  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O 
    5 //  gcc -shared domain_ext.o  -o domain_ext.so 
     4//  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O
     5//  gcc -shared domain_ext.o  -o domain_ext.so
    66//
    77// or use python compile.py
     
    1111//
    1212// Ole Nielsen, GA 2004
    13    
    14    
     13
     14
    1515#include "Python.h"
    1616#include "Numeric/arrayobject.h"
    1717#include "math.h"
     18#include <stdio.h>
    1819
    1920//Shared code snippets
     
    2627  /*Rotate the momentum component q (q[1], q[2])
    2728    from x,y coordinates to coordinates based on normal vector (n1, n2).
    28    
    29     Result is returned in array 3x1 r     
     29
     30    Result is returned in array 3x1 r
    3031    To rotate in opposite direction, call rotate with (q, n1, -n2)
    31    
    32     Contents of q are changed by this function */   
     32
     33    Contents of q are changed by this function */
    3334
    3435
    3536  double q1, q2;
    36  
     37
    3738  //Shorthands
    3839  q1 = q[1];  //uh momentum
     
    4142  //Rotate
    4243  q[1] =  n1*q1 + n2*q2;
    43   q[2] = -n2*q1 + n1*q2; 
     44  q[2] = -n2*q1 + n1*q2;
    4445
    4546  return 0;
    46 } 
    47 
    48 
    49        
     47}
     48
     49
     50
    5051// Computational function for flux computation (using stage w=z+h)
    51 int flux_function(double *q_left, double *q_right, 
    52                   double z_left, double z_right, 
    53                   double n1, double n2, 
    54                   double epsilon, double g, 
     52int flux_function(double *q_left, double *q_right,
     53                  double z_left, double z_right,
     54                  double n1, double n2,
     55                  double epsilon, double g,
    5556                  double *edgeflux, double *max_speed) {
    56  
     57
    5758  /*Compute fluxes between volumes for the shallow water wave equation
    58     cast in terms of the 'stage', w = h+z using 
     59    cast in terms of the 'stage', w = h+z using
    5960    the 'central scheme' as described in
    60    
     61
    6162    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
    6263    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
    6364    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
    64    
    65     The implemented formula is given in equation (3.15) on page 714 
     65
     66    The implemented formula is given in equation (3.15) on page 714
    6667  */
    67        
     68
    6869  int i;
    69        
     70
    7071  double w_left, h_left, uh_left, vh_left, u_left;
    7172  double w_right, h_right, uh_right, vh_right, u_right;
    7273  double s_min, s_max, soundspeed_left, soundspeed_right;
    7374  double denom, z;
    74   double q_left_copy[3], q_right_copy[3];   
     75  double q_left_copy[3], q_right_copy[3];
    7576  double flux_right[3], flux_left[3];
    76  
     77
    7778  //Copy conserved quantities to protect from modification
    7879  for (i=0; i<3; i++) {
    7980    q_left_copy[i] = q_left[i];
    8081    q_right_copy[i] = q_right[i];
    81   } 
    82    
     82  }
     83
    8384  //Align x- and y-momentum with x-axis
    8485  _rotate(q_left_copy, n1, n2);
    85   _rotate(q_right_copy, n1, n2);   
     86  _rotate(q_right_copy, n1, n2);
    8687
    8788  z = (z_left+z_right)/2; //Take average of field values
     
    9596    h_left = 0.0;  //Could have been negative
    9697    u_left = 0.0;
    97   } else { 
     98  } else {
    9899    u_left = uh_left/h_left;
    99100  }
    100  
     101
    101102  w_right = q_right_copy[0];
    102103  h_right = w_right-z;
     
    106107    h_right = 0.0; //Could have been negative
    107108    u_right = 0.0;
    108   } else { 
     109  } else {
    109110    u_right = uh_right/h_right;
    110111  }
    111112
    112   //Momentum in y-direction             
     113  //Momentum in y-direction
    113114  vh_left  = q_left_copy[2];
    114   vh_right = q_right_copy[2];   
    115        
     115  vh_right = q_right_copy[2];
     116
    116117
    117118  //Maximal and minimal wave speeds
    118   soundspeed_left  = sqrt(g*h_left); 
     119  soundspeed_left  = sqrt(g*h_left);
    119120  soundspeed_right = sqrt(g*h_right);
    120    
     121
    121122  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
    122   if (s_max < 0.0) s_max = 0.0; 
    123  
     123  if (s_max < 0.0) s_max = 0.0;
     124
    124125  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
    125   if (s_min > 0.0) s_min = 0.0;   
    126  
    127   //Flux formulas 
     126  if (s_min > 0.0) s_min = 0.0;
     127
     128  //Flux formulas
    128129  flux_left[0] = u_left*h_left;
    129130  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
    130131  flux_left[2] = u_left*vh_left;
    131  
     132
    132133  flux_right[0] = u_right*h_right;
    133134  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
    134135  flux_right[2] = u_right*vh_right;
    135    
    136 
    137   //Flux computation   
     136
     137
     138  //Flux computation
    138139  denom = s_max-s_min;
    139140  if (denom == 0.0) {
    140141    for (i=0; i<3; i++) edgeflux[i] = 0.0;
    141142    *max_speed = 0.0;
    142   } else {   
     143  } else {
    143144    for (i=0; i<3; i++) {
    144145      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
    145146      edgeflux[i] += s_max*s_min*(q_right_copy[i]-q_left_copy[i]);
    146147      edgeflux[i] /= denom;
    147     } 
    148        
     148    }
     149
    149150    //Maximal wavespeed
    150151    *max_speed = max(fabs(s_max), fabs(s_min));
    151    
    152     //Rotate back       
     152
     153    //Rotate back
    153154    _rotate(edgeflux, n1, -n2);
    154155  }
    155156  return 0;
    156157}
    157        
    158 void _manning_friction(double g, double eps, int N, 
    159                        double* w, double* z, 
    160                        double* uh, double* vh, 
    161                        double* eta, double* xmom, double* ymom) {     
     158
     159void _manning_friction(double g, double eps, int N,
     160                       double* w, double* z,
     161                       double* uh, double* vh,
     162                       double* eta, double* xmom, double* ymom) {
    162163
    163164  int k;
    164165  double S, h;
    165  
     166
    166167  for (k=0; k<N; k++) {
    167168    if (eta[k] > eps) {
     
    180181  }
    181182}
    182            
     183
    183184
    184185
    185186int _balance_deep_and_shallow(int N,
    186187                              double* wc,
    187                               double* zc, 
    188                               double* hc,                             
    189                               double* wv, 
    190                               double* zv, 
     188                              double* zc,
     189                              double* hc,
     190                              double* wv,
     191                              double* zv,
    191192                              double* hv,
    192                               double* hvbar,                         
    193                               double* xmomc, 
    194                               double* ymomc, 
    195                               double* xmomv, 
    196                               double* ymomv) { 
    197  
     193                              double* hvbar,
     194                              double* xmomc,
     195                              double* ymomc,
     196                              double* xmomv,
     197                              double* ymomv) {
     198
    198199  int k, k3, i;
    199200  double dz, hmin, alpha;
    200  
     201
    201202  //Compute linear combination between w-limited stages and
    202   //h-limited stages close to the bed elevation.     
    203  
     203  //h-limited stages close to the bed elevation.
     204
    204205  for (k=0; k<N; k++) {
    205206    // Compute maximal variation in bed elevation
     
    211212
    212213    k3 = 3*k;
    213    
     214
    214215    //FIXME: Try with this one precomputed
    215216    dz = 0.0;
     
    220221    }
    221222
    222    
    223     //Create alpha in [0,1], where alpha==0 means using the h-limited 
     223
     224    //Create alpha in [0,1], where alpha==0 means using the h-limited
    224225    //stage and alpha==1 means using the w-limited stage as
    225226    //computed by the gradient limiter (both 1st or 2nd order)
     
    227228    //If hmin > dz/2 then alpha = 1 and the bed will have no effect
    228229    //If hmin < 0 then alpha = 0 reverting to constant height above bed.
    229    
     230
    230231
    231232    if (dz > 0.0)
    232       //if (hmin<0.0) 
     233      //if (hmin<0.0)
    233234      //        alpha = 0.0;
    234235      //else
    235236      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
    236237      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
    237    
    238238    else
    239239      alpha = 1.0;  //Flat bed
    240240
     241    //alpha = 1.0;
     242
    241243    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
    242244
    243     //  Let 
    244     // 
    245     //    wvi be the w-limited stage (wvi = zvi + hvi)       
     245    //  Let
     246    //
     247    //    wvi be the w-limited stage (wvi = zvi + hvi)
    246248    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
    247     //     
    248     //     
     249    //
     250    //
    249251    //  where i=0,1,2 denotes the vertex ids
    250     // 
    251     //  Weighted balance between w-limited and h-limited stage is 
    252     //   
    253     //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)   
    254     // 
     252    //
     253    //  Weighted balance between w-limited and h-limited stage is
     254    //
     255    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
     256    //
    255257    //  It follows that the updated wvi is
    256258    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
    257     //   
     259    //
    258260    //   Momentum is balanced between constant and limited
    259261
    260     if (alpha < 1) {         
     262    if (alpha < 1) {
    261263      for (i=0; i<3; i++) {
    262264        wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
    263            
    264         //Update momentum as a linear combination of 
     265
     266        //Update momentum as a linear combination of
    265267        //xmomc and ymomc (shallow) and momentum
    266268        //from extrapolator xmomv and ymomv (deep).
    267         xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];           
     269        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
    268270        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
    269       } 
     271      }
    270272    }
    271   }         
     273  }
    272274  return 0;
    273275}
     
    275277
    276278
    277 int _protect(int N, 
    278              double minimum_allowed_height,       
     279int _protect(int N,
     280             double minimum_allowed_height,
    279281             double* wc,
    280              double* zc, 
    281              double* xmomc, 
     282             double* zc,
     283             double* xmomc,
    282284             double* ymomc) {
    283  
    284   int k; 
     285
     286  int k;
    285287  double hc;
    286  
     288
    287289  //Protect against initesimal and negative heights
    288  
     290
    289291  for (k=0; k<N; k++) {
    290292    hc = wc[k] - zc[k];
    291    
    292     if (hc < minimum_allowed_height) {   
    293       wc[k] = zc[k];       
     293
     294    if (hc < minimum_allowed_height) {
     295      wc[k] = zc[k];
    294296      xmomc[k] = 0.0;
    295       ymomc[k] = 0.0;     
     297      ymomc[k] = 0.0;
    296298    }
    297    
     299
    298300  }
    299301  return 0;
     
    309311int _assign_wind_field_values(int N,
    310312                              double* xmom_update,
    311                               double* ymom_update, 
     313                              double* ymom_update,
    312314                              double* s_vec,
    313315                              double* phi_vec,
     
    318320  int k;
    319321  double S, s, phi, u, v;
    320  
     322
    321323  for (k=0; k<N; k++) {
    322    
     324
    323325    s = s_vec[k];
    324326    phi = phi_vec[k];
     
    330332    u = s*cos(phi);
    331333    v = s*sin(phi);
    332        
     334
    333335    //Compute wind stress
    334336    S = cw * sqrt(u*u + v*v);
    335337    xmom_update[k] += S*u;
    336     ymom_update[k] += S*v;       
    337   }
    338   return 0; 
    339 }           
     338    ymom_update[k] += S*v;
     339  }
     340  return 0;
     341}
    340342
    341343
     
    348350  //  gravity(g, h, v, x, xmom, ymom)
    349351  //
    350  
    351  
     352
     353
    352354  PyArrayObject *h, *v, *x, *xmom, *ymom;
    353355  int k, i, N, k3, k6;
    354356  double g, avg_h, zx, zy;
    355357  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
    356    
     358
    357359  if (!PyArg_ParseTuple(args, "dOOOOO",
    358                         &g, &h, &v, &x, 
    359                         &xmom, &ymom)) 
    360     return NULL; 
     360                        &g, &h, &v, &x,
     361                        &xmom, &ymom))
     362    return NULL;
    361363
    362364  N = h -> dimensions[0];
    363365  for (k=0; k<N; k++) {
    364366    k3 = 3*k;  // base index
    365     k6 = 6*k;  // base index   
    366    
     367    k6 = 6*k;  // base index
     368
    367369    avg_h = 0.0;
    368370    for (i=0; i<3; i++) {
    369371      avg_h += ((double *) h -> data)[k3+i];
    370     }   
     372    }
    371373    avg_h /= 3;
    372        
    373    
     374
     375
    374376    //Compute bed slope
    375377    x0 = ((double*) x -> data)[k6 + 0];
    376     y0 = ((double*) x -> data)[k6 + 1];   
     378    y0 = ((double*) x -> data)[k6 + 1];
    377379    x1 = ((double*) x -> data)[k6 + 2];
    378     y1 = ((double*) x -> data)[k6 + 3];       
     380    y1 = ((double*) x -> data)[k6 + 3];
    379381    x2 = ((double*) x -> data)[k6 + 4];
    380     y2 = ((double*) x -> data)[k6 + 5];           
     382    y2 = ((double*) x -> data)[k6 + 5];
    381383
    382384
    383385    z0 = ((double*) v -> data)[k3 + 0];
    384386    z1 = ((double*) v -> data)[k3 + 1];
    385     z2 = ((double*) v -> data)[k3 + 2];       
     387    z2 = ((double*) v -> data)[k3 + 2];
    386388
    387389    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
     
    389391    //Update momentum
    390392    ((double*) xmom -> data)[k] += -g*zx*avg_h;
    391     ((double*) ymom -> data)[k] += -g*zy*avg_h;       
    392   }
    393    
     393    ((double*) ymom -> data)[k] += -g*zy*avg_h;
     394  }
     395
    394396  return Py_BuildValue("");
    395397}
     
    400402  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
    401403  //
    402  
    403  
     404
     405
    404406  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
    405407  int N;
    406408  double g, eps;
    407    
     409
    408410  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
    409                         &g, &eps, &w, &z, &uh, &vh, &eta, 
    410                         &xmom, &ymom)) 
    411     return NULL; 
    412 
    413   N = w -> dimensions[0];   
     411                        &g, &eps, &w, &z, &uh, &vh, &eta,
     412                        &xmom, &ymom))
     413    return NULL;
     414
     415  N = w -> dimensions[0];
    414416  _manning_friction(g, eps, N,
    415417                    (double*) w -> data,
    416                     (double*) z -> data,                   
    417                     (double*) uh -> data, 
    418                     (double*) vh -> data, 
     418                    (double*) z -> data,
     419                    (double*) uh -> data,
     420                    (double*) vh -> data,
    419421                    (double*) eta -> data,
    420                     (double*) xmom -> data, 
     422                    (double*) xmom -> data,
    421423                    (double*) ymom -> data);
    422424
    423425  return Py_BuildValue("");
    424 }                   
     426}
    425427
    426428PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
     
    431433  // normal a Float numeric array of length 2.
    432434
    433  
     435
    434436  PyObject *Q, *Normal;
    435437  PyArrayObject *q, *r, *normal;
    436  
     438
    437439  static char *argnames[] = {"q", "normal", "direction", NULL};
    438440  int dimensions[1], i, direction=1;
    439441  double n1, n2;
    440442
    441   // Convert Python arguments to C 
    442   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, 
    443                                    &Q, &Normal, &direction)) 
    444     return NULL; 
     443  // Convert Python arguments to C
     444  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
     445                                   &Q, &Normal, &direction))
     446    return NULL;
    445447
    446448  //Input checks (convert sequences into numeric arrays)
    447   q = (PyArrayObject *) 
     449  q = (PyArrayObject *)
    448450    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
    449   normal = (PyArrayObject *) 
     451  normal = (PyArrayObject *)
    450452    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
    451453
    452  
     454
    453455  if (normal -> dimensions[0] != 2) {
    454456    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
     
    456458  }
    457459
    458   //Allocate space for return vector r (don't DECREF) 
     460  //Allocate space for return vector r (don't DECREF)
    459461  dimensions[0] = 3;
    460462  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
     
    462464  //Copy
    463465  for (i=0; i<3; i++) {
    464     ((double *) (r -> data))[i] = ((double *) (q -> data))[i]; 
    465   }
    466  
     466    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
     467  }
     468
    467469  //Get normal and direction
    468   n1 = ((double *) normal -> data)[0]; 
    469   n2 = ((double *) normal -> data)[1];   
     470  n1 = ((double *) normal -> data)[0];
     471  n2 = ((double *) normal -> data)[1];
    470472  if (direction == -1) n2 = -n2;
    471473
     
    474476
    475477  //Release numeric arrays
    476   Py_DECREF(q);   
     478  Py_DECREF(q);
    477479  Py_DECREF(normal);
    478        
     480
    479481  //return result using PyArray to avoid memory leak
    480482  return PyArray_Return(r);
    481 }   
     483}
    482484
    483485
     
    490492    Fluxes across each edge are scaled by edgelengths and summed up
    491493    Resulting flux is then scaled by area and stored in
    492     explicit_update for each of the three conserved quantities 
     494    explicit_update for each of the three conserved quantities
    493495    stage, xmomentum and ymomentum
    494496
     
    496498    is converted to a timestep that must not be exceeded. The minimum of
    497499    those is computed as the next overall timestep.
    498    
     500
    499501    Python call:
    500     domain.timestep = compute_fluxes(timestep, 
    501                                      domain.epsilon, 
     502    domain.timestep = compute_fluxes(timestep,
     503                                     domain.epsilon,
    502504                                     domain.g,
    503505                                     domain.neighbours,
    504506                                     domain.neighbour_edges,
    505507                                     domain.normals,
    506                                      domain.edgelengths,                       
     508                                     domain.edgelengths,
    507509                                     domain.radii,
    508510                                     domain.areas,
    509                                      Stage.edge_values, 
    510                                      Xmom.edge_values, 
    511                                      Ymom.edge_values, 
    512                                      Bed.edge_values,   
     511                                     Stage.edge_values,
     512                                     Xmom.edge_values,
     513                                     Ymom.edge_values,
     514                                     Bed.edge_values,
    513515                                     Stage.boundary_values,
    514516                                     Xmom.boundary_values,
     
    517519                                     Xmom.explicit_update,
    518520                                     Ymom.explicit_update)
    519        
     521
    520522
    521523    Post conditions:
    522524      domain.explicit_update is reset to computed flux values
    523       domain.timestep is set to the largest step satisfying all volumes. 
    524 
    525            
     525      domain.timestep is set to the largest step satisfying all volumes.
     526
     527
    526528  */
    527529
    528  
     530
    529531  PyArrayObject *neighbours, *neighbour_edges,
    530532    *normals, *edgelengths, *radii, *areas,
    531     *stage_edge_values, 
    532     *xmom_edge_values, 
    533     *ymom_edge_values, 
    534     *bed_edge_values,   
     533    *stage_edge_values,
     534    *xmom_edge_values,
     535    *ymom_edge_values,
     536    *bed_edge_values,
    535537    *stage_boundary_values,
    536538    *xmom_boundary_values,
     
    540542    *ymom_explicit_update;
    541543
    542    
    543   //Local variables 
     544
     545  //Local variables
    544546  double timestep, max_speed, epsilon, g;
    545547  double normal[2], ql[3], qr[3], zl, zr;
     
    548550  int number_of_elements, k, i, j, m, n;
    549551  int ki, nm, ki2; //Index shorthands
    550  
    551  
    552   // Convert Python arguments to C 
     552
     553
     554  // Convert Python arguments to C
    553555  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOO",
    554556                        &timestep,
    555557                        &epsilon,
    556558                        &g,
    557                         &neighbours, 
     559                        &neighbours,
    558560                        &neighbour_edges,
    559                         &normals, 
     561                        &normals,
    560562                        &edgelengths, &radii, &areas,
    561                         &stage_edge_values, 
    562                         &xmom_edge_values, 
    563                         &ymom_edge_values, 
    564                         &bed_edge_values,   
     563                        &stage_edge_values,
     564                        &xmom_edge_values,
     565                        &ymom_edge_values,
     566                        &bed_edge_values,
    565567                        &stage_boundary_values,
    566568                        &xmom_boundary_values,
     
    574576
    575577  number_of_elements = stage_edge_values -> dimensions[0];
    576  
    577    
     578
     579
    578580  for (k=0; k<number_of_elements; k++) {
    579581
    580582    //Reset work array
    581583    for (j=0; j<3; j++) flux[j] = 0.0;
    582                          
     584
    583585    //Loop through neighbours and compute edge flux for each
    584586    for (i=0; i<3; i++) {
     
    586588      ql[0] = ((double *) stage_edge_values -> data)[ki];
    587589      ql[1] = ((double *) xmom_edge_values -> data)[ki];
    588       ql[2] = ((double *) ymom_edge_values -> data)[ki];           
    589       zl =    ((double *) bed_edge_values -> data)[ki];                 
     590      ql[2] = ((double *) ymom_edge_values -> data)[ki];
     591      zl =    ((double *) bed_edge_values -> data)[ki];
    590592
    591593      //Quantities at neighbour on nearest face
     
    593595      if (n < 0) {
    594596        m = -n-1; //Convert negative flag to index
    595         qr[0] = ((double *) stage_boundary_values -> data)[m]; 
    596         qr[1] = ((double *) xmom_boundary_values -> data)[m];   
    597         qr[2] = ((double *) ymom_boundary_values -> data)[m];   
     597        qr[0] = ((double *) stage_boundary_values -> data)[m];
     598        qr[1] = ((double *) xmom_boundary_values -> data)[m];
     599        qr[2] = ((double *) ymom_boundary_values -> data)[m];
    598600        zr = zl; //Extend bed elevation to boundary
    599       } else {   
     601      } else {
    600602        m = ((long *) neighbour_edges -> data)[ki];
    601        
    602         nm = n*3+m;     
     603
     604        nm = n*3+m;
    603605        qr[0] = ((double *) stage_edge_values -> data)[nm];
    604606        qr[1] = ((double *) xmom_edge_values -> data)[nm];
    605         qr[2] = ((double *) ymom_edge_values -> data)[nm];           
    606         zr =    ((double *) bed_edge_values -> data)[nm];                 
     607        qr[2] = ((double *) ymom_edge_values -> data)[nm];
     608        zr =    ((double *) bed_edge_values -> data)[nm];
    607609      }
    608610
    609611      //printf("%d %d [%d] (%d, %d): %.2f %.2f %.2f\n", k, i, ki, n, m,
    610       //             ql[0], ql[1], ql[2]);       
    611 
    612      
    613       // Outward pointing normal vector   
     612      //             ql[0], ql[1], ql[2]);
     613
     614
     615      // Outward pointing normal vector
    614616      // normal = domain.normals[k, 2*i:2*i+2]
    615617      ki2 = 2*ki; //k*6 + i*2
    616618      normal[0] = ((double *) normals -> data)[ki2];
    617       normal[1] = ((double *) normals -> data)[ki2+1];     
     619      normal[1] = ((double *) normals -> data)[ki2+1];
    618620
    619621      //Edge flux computation
    620       flux_function(ql, qr, zl, zr, 
     622      flux_function(ql, qr, zl, zr,
    621623                    normal[0], normal[1],
    622                     epsilon, g, 
     624                    epsilon, g,
    623625                    edgeflux, &max_speed);
    624626
    625                    
     627
    626628      //flux -= edgeflux * edgelengths[k,i]
    627       for (j=0; j<3; j++) { 
     629      for (j=0; j<3; j++) {
    628630        flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
    629631      }
    630      
     632
    631633      //Update timestep
    632634      //timestep = min(timestep, domain.radii[k]/max_speed)
     
    634636      if (max_speed > epsilon) {
    635637        timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
    636       }   
     638      }
    637639    } // end for i
    638    
     640
    639641    //Normalise by area and store for when all conserved
    640642    //quantities get updated
    641643    // flux /= areas[k]
    642     for (j=0; j<3; j++) { 
     644    for (j=0; j<3; j++) {
    643645      flux[j] /= ((double *) areas -> data)[k];
    644646    }
     
    646648    ((double *) stage_explicit_update -> data)[k] = flux[0];
    647649    ((double *) xmom_explicit_update -> data)[k] = flux[1];
    648     ((double *) ymom_explicit_update -> data)[k] = flux[2];       
     650    ((double *) ymom_explicit_update -> data)[k] = flux[2];
    649651
    650652  } //end for k
    651653
    652654  return Py_BuildValue("d", timestep);
    653 }   
     655}
    654656
    655657
     
    658660  //
    659661  //    protect(minimum_allowed_height, wc, zc, xmomc, ymomc)
    660  
    661 
    662   PyArrayObject 
     662
     663
     664  PyArrayObject
    663665  *wc,            //Stage at centroids
    664   *zc,            //Elevation at centroids   
     666  *zc,            //Elevation at centroids
    665667  *xmomc,         //Momentums at centroids
    666   *ymomc; 
    667 
    668    
    669   int N; 
     668  *ymomc;
     669
     670
     671  int N;
    670672  double minimum_allowed_height;
    671  
    672   // Convert Python arguments to C 
    673   if (!PyArg_ParseTuple(args, "dOOOO", 
     673
     674  // Convert Python arguments to C
     675  if (!PyArg_ParseTuple(args, "dOOOO",
    674676                        &minimum_allowed_height,
    675677                        &wc, &zc, &xmomc, &ymomc))
     
    677679
    678680  N = wc -> dimensions[0];
    679    
     681
    680682  _protect(N,
    681683           minimum_allowed_height,
    682684           (double*) wc -> data,
    683            (double*) zc -> data, 
    684            (double*) xmomc -> data, 
     685           (double*) zc -> data,
     686           (double*) xmomc -> data,
    685687           (double*) ymomc -> data);
    686  
    687   return Py_BuildValue(""); 
     688
     689  return Py_BuildValue("");
    688690}
    689691
     
    694696  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
    695697  //                             xmomc, ymomc, xmomv, ymomv)
    696  
    697 
    698   PyArrayObject 
     698
     699
     700  PyArrayObject
    699701    *wc,            //Stage at centroids
    700     *zc,            //Elevation at centroids   
    701     *hc,            //Height at centroids       
     702    *zc,            //Elevation at centroids
     703    *hc,            //Height at centroids
    702704    *wv,            //Stage at vertices
    703705    *zv,            //Elevation at vertices
    704     *hv,            //Depths at vertices   
    705     *hvbar,         //h-Limited depths at vertices       
     706    *hv,            //Depths at vertices
     707    *hvbar,         //h-Limited depths at vertices
    706708    *xmomc,         //Momentums at centroids and vertices
    707     *ymomc, 
    708     *xmomv, 
    709     *ymomv;   
    710    
     709    *ymomc,
     710    *xmomv,
     711    *ymomv;
     712
    711713  int N; //, err;
    712  
    713   // Convert Python arguments to C 
    714   if (!PyArg_ParseTuple(args, "OOOOOOOOOOO", 
    715                         &wc, &zc, &hc, 
     714
     715  // Convert Python arguments to C
     716  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
     717                        &wc, &zc, &hc,
    716718                        &wv, &zv, &hv, &hvbar,
    717719                        &xmomc, &ymomc, &xmomv, &ymomv))
     
    719721
    720722  N = wc -> dimensions[0];
    721    
     723
    722724  _balance_deep_and_shallow(N,
    723725                            (double*) wc -> data,
    724                             (double*) zc -> data, 
    725                             (double*) hc -> data,                           
    726                             (double*) wv -> data, 
    727                             (double*) zv -> data, 
     726                            (double*) zc -> data,
     727                            (double*) hc -> data,
     728                            (double*) wv -> data,
     729                            (double*) zv -> data,
    728730                            (double*) hv -> data,
    729                             (double*) hvbar -> data,                       
    730                             (double*) xmomc -> data, 
    731                             (double*) ymomc -> data, 
    732                             (double*) xmomv -> data, 
    733                             (double*) ymomv -> data); 
    734  
    735  
    736   return Py_BuildValue(""); 
     731                            (double*) hvbar -> data,
     732                            (double*) xmomc -> data,
     733                            (double*) ymomc -> data,
     734                            (double*) xmomv -> data,
     735                            (double*) ymomv -> data);
     736
     737
     738  return Py_BuildValue("");
    737739}
    738740
     
    740742
    741743PyObject *h_limiter(PyObject *self, PyObject *args) {
    742  
     744
    743745  PyObject *domain, *Tmp;
    744   PyArrayObject 
    745     *hv, *hc, //Depth at vertices and centroids       
     746  PyArrayObject
     747    *hv, *hc, //Depth at vertices and centroids
    746748    *hvbar,   //Limited depth at vertices (return values)
    747749    *neighbours;
    748    
     750
    749751  int k, i, n, N, k3;
    750752  int dimensions[2];
    751753  double beta_h; //Safety factor (see config.py)
    752754  double *hmin, *hmax, hn;
    753  
    754   // Convert Python arguments to C 
    755   if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) 
     755
     756  // Convert Python arguments to C
     757  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
    756758    return NULL;
    757759
     
    759761
    760762  //Get safety factor beta_h
    761   Tmp = PyObject_GetAttrString(domain, "beta_h"); 
    762   if (!Tmp) 
    763     return NULL;
    764      
    765   beta_h = PyFloat_AsDouble(Tmp); 
    766  
    767   Py_DECREF(Tmp);   
     763  Tmp = PyObject_GetAttrString(domain, "beta_h");
     764  if (!Tmp)
     765    return NULL;
     766
     767  beta_h = PyFloat_AsDouble(Tmp);
     768
     769  Py_DECREF(Tmp);
    768770
    769771  N = hc -> dimensions[0];
    770  
     772
    771773  //Create hvbar
    772774  dimensions[0] = N;
    773   dimensions[1] = 3; 
     775  dimensions[1] = 3;
    774776  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
    775  
     777
    776778
    777779  //Find min and max of this and neighbour's centroid values
    778780  hmin = malloc(N * sizeof(double));
    779   hmax = malloc(N * sizeof(double)); 
     781  hmax = malloc(N * sizeof(double));
    780782  for (k=0; k<N; k++) {
    781783    k3=k*3;
    782    
     784
    783785    hmin[k] = ((double*) hc -> data)[k];
    784786    hmax[k] = hmin[k];
    785    
     787
    786788    for (i=0; i<3; i++) {
    787789      n = ((long*) neighbours -> data)[k3+i];
    788      
     790
    789791      //Initialise hvbar with values from hv
    790       ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i]; 
    791      
     792      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
     793
    792794      if (n >= 0) {
    793795        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
    794          
     796
    795797        hmin[k] = min(hmin[k], hn);
    796798        hmax[k] = max(hmax[k], hn);
     
    798800    }
    799801  }
    800  
     802
    801803  // Call underlying standard routine
    802804  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
    803          
    804   // // //Py_DECREF(domain); //FIXME: NEcessary?         
     805
     806  // // //Py_DECREF(domain); //FIXME: NEcessary?
    805807  free(hmin);
    806   free(hmax); 
    807  
    808   //return result using PyArray to avoid memory leak 
     808  free(hmax);
     809
     810  //return result using PyArray to avoid memory leak
    809811  return PyArray_Return(hvbar);
    810   //return Py_BuildValue("");   
     812  //return Py_BuildValue("");
    811813}
    812814
     
    819821  //                              s_vec, phi_vec, self.const)
    820822
    821  
     823
    822824
    823825  PyArrayObject   //(one element per triangle)
    824   *s_vec,         //Speeds 
    825   *phi_vec,       //Bearings 
     826  *s_vec,         //Speeds
     827  *phi_vec,       //Bearings
    826828  *xmom_update,   //Momentum updates
    827   *ymom_update; 
    828 
    829    
    830   int N; 
     829  *ymom_update;
     830
     831
     832  int N;
    831833  double cw;
    832  
    833   // Convert Python arguments to C 
    834   if (!PyArg_ParseTuple(args, "OOOOd", 
     834
     835  // Convert Python arguments to C
     836  if (!PyArg_ParseTuple(args, "OOOOd",
    835837                        &xmom_update,
    836                         &ymom_update,                   
    837                         &s_vec, &phi_vec, 
     838                        &ymom_update,
     839                        &s_vec, &phi_vec,
    838840                        &cw))
    839841    return NULL;
    840842
    841843  N = xmom_update -> dimensions[0];
    842    
     844
    843845  _assign_wind_field_values(N,
    844846           (double*) xmom_update -> data,
    845            (double*) ymom_update -> data, 
    846            (double*) s_vec -> data, 
     847           (double*) ymom_update -> data,
     848           (double*) s_vec -> data,
    847849           (double*) phi_vec -> data,
    848850           cw);
    849  
    850   return Py_BuildValue(""); 
    851 }
    852 
    853 
    854 
    855 
    856 //////////////////////////////////////////     
     851
     852  return Py_BuildValue("");
     853}
     854
     855
     856
     857
     858//////////////////////////////////////////
    857859// Method table for python module
    858860static struct PyMethodDef MethodTable[] = {
     
    861863   * three.
    862864   */
    863  
     865
    864866  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
    865   {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},   
    866   {"gravity", gravity, METH_VARARGS, "Print out"},     
    867   {"manning_friction", manning_friction, METH_VARARGS, "Print out"},       
    868   {"balance_deep_and_shallow", balance_deep_and_shallow, 
    869    METH_VARARGS, "Print out"},         
    870   {"h_limiter", h_limiter, 
    871    METH_VARARGS, "Print out"},             
    872   {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},   
    873   {"assign_windfield_values", assign_windfield_values, 
    874    METH_VARARGS | METH_KEYWORDS, "Print out"},     
    875   //{"distribute_to_vertices_and_edges", 
    876   // distribute_to_vertices_and_edges, METH_VARARGS},   
    877   //{"update_conserved_quantities", 
    878   // update_conserved_quantities, METH_VARARGS},       
    879   //{"set_initialcondition", 
    880   // set_initialcondition, METH_VARARGS},   
     867  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
     868  {"gravity", gravity, METH_VARARGS, "Print out"},
     869  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
     870  {"balance_deep_and_shallow", balance_deep_and_shallow,
     871   METH_VARARGS, "Print out"},
     872  {"h_limiter", h_limiter,
     873   METH_VARARGS, "Print out"},
     874  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
     875  {"assign_windfield_values", assign_windfield_values,
     876   METH_VARARGS | METH_KEYWORDS, "Print out"},
     877  //{"distribute_to_vertices_and_edges",
     878  // distribute_to_vertices_and_edges, METH_VARARGS},
     879  //{"update_conserved_quantities",
     880  // update_conserved_quantities, METH_VARARGS},
     881  //{"set_initialcondition",
     882  // set_initialcondition, METH_VARARGS},
    881883  {NULL, NULL}
    882884};
    883        
    884 // Module initialisation   
     885
     886// Module initialisation
    885887void initshallow_water_ext(void){
    886888  Py_InitModule("shallow_water_ext", MethodTable);
    887  
    888   import_array();     //Necessary for handling of NumPY structures 
    889 }
     889
     890  import_array();     //Necessary for handling of NumPY structures
     891}
  • inundation/ga/storm_surge/pyvolution/util.py

    r1289 r1387  
    22
    33It is also a clearing house for functions that may later earn a module
    4 of their own. 
     4of their own.
    55"""
    66
     
    1717    v2 = v[1]/l
    1818
    19     try:       
     19    try:
    2020        theta = acos(v1)
    2121    except ValueError, e:
     
    3131            theta = 3.1415926535897931
    3232        print 'WARNING (util.py): angle v1 is %f, setting acos to %f '\
    33               %(v1, theta)   
    34              
     33              %(v1, theta)
     34
    3535    if v2 < 0:
    3636        #Quadrant 3 or 4
     
    4343    """Compute difference between angle of vector x0, y0 and x1, y1.
    4444    This is used for determining the ordering of vertices,
    45     e.g. for checking if they are counter clockwise. 
    46    
     45    e.g. for checking if they are counter clockwise.
     46
    4747    Always return a positive value
    4848    """
    49        
     49
    5050    from math import pi
    51    
     51
    5252    a0 = angle(v0)
    5353    a1 = angle(v1)
     
    5656    if a0 < a1:
    5757        a0 += 2*pi
    58            
     58
    5959    return a0-a1
    6060
     
    6565
    6666
    67 def point_on_line(x, y, x0, y0, x1, y1): 
    68     """Determine whether a point is on a line segment 
    69    
     67def point_on_line(x, y, x0, y0, x1, y1):
     68    """Determine whether a point is on a line segment
     69
    7070    Input: x, y, x0, x0, x1, y1: where
    7171        point is given by x, y
    7272        line is given by (x0, y0) and (x1, y1)
    73        
    74     """
    75        
     73
     74    """
     75
    7676    from Numeric import array, dot, allclose
    7777    from math import sqrt
    7878
    79     a = array([x - x0, y - y0]) 
     79    a = array([x - x0, y - y0])
    8080    a_normal = array([a[1], -a[0]])
    81                        
     81
    8282    b = array([x1 - x0, y1 - y0])
    83    
     83
    8484    if dot(a_normal, b) == 0:
    8585        #Point is somewhere on the infinite extension of the line
    8686
    87         len_a = sqrt(sum(a**2))               
    88         len_b = sqrt(sum(b**2))                                 
     87        len_a = sqrt(sum(a**2))
     88        len_b = sqrt(sum(b**2))
    8989        if dot(a, b) >= 0 and len_a <= len_b:
    9090           return True
    91         else:   
     91        else:
    9292           return False
    9393    else:
    94       return False 
    95    
     94      return False
     95
    9696def ensure_numeric(A, typecode = None):
    9797    """Ensure that sequence is a Numeric array.
     
    117117        if type(A) == ArrayType:
    118118            if A.typecode == typecode:
    119                 return array(A)           
     119                return array(A)
    120120            else:
    121121                return A.astype(typecode)
    122122        else:
    123123            return array(A).astype(typecode)
    124        
    125    
     124
     125
    126126
    127127def file_function(filename, domain=None, quantities = None, interpolation_points = None, verbose = False):
     
    133133    #In fact, this is where origin should be converted to that of domain
    134134    #Also, check that file covers domain fully.
    135    
     135
    136136    assert type(filename) == type(''),\
    137137               'First argument to File_function must be a string'
     
    148148
    149149    if domain is not None:
    150         quantities = domain.conserved_quantities   
     150        quantities = domain.conserved_quantities
    151151    else:
    152152        quantities = None
    153        
    154     #Choose format 
     153
     154    #Choose format
    155155    #FIXME: Maybe these can be merged later on
    156156    if line[:3] == 'CDF':
    157157        return File_function_NetCDF(filename, domain, quantities, interpolation_points, verbose = verbose)
    158158    else:
    159         return File_function_ASCII(filename, domain, quantities, interpolation_points)   
    160            
    161              
     159        return File_function_ASCII(filename, domain, quantities, interpolation_points)
     160
     161
    162162class File_function_NetCDF:
    163     """Read time history of spatial data from NetCDF sww file and 
    164     return a callable object f(t,x,y) 
    165     which will return interpolated values based on the input file.   
    166    
     163    """Read time history of spatial data from NetCDF sww file and
     164    return a callable object f(t,x,y)
     165    which will return interpolated values based on the input file.
     166
    167167    x, y may be either scalars or vectors
    168    
     168
    169169    #FIXME: More about format, interpolation  and order of quantities
    170    
     170
    171171    The quantities returned by the callable objects are specified by
    172     the list quantities which must contain the names of the 
     172    the list quantities which must contain the names of the
    173173    quantities to be returned and also reflect the order, e.g. for
    174     the shallow water wave equation, on would have 
     174    the shallow water wave equation, on would have
    175175    quantities = ['stage', 'xmomentum', 'ymomentum']
    176    
    177     interpolation_points decides at which points interpolated 
     176
     177    interpolation_points decides at which points interpolated
    178178    quantities are to be computed whenever object is called.
    179    
    180    
    181    
     179
     180
     181
    182182    If None, return average value
    183183    """
    184    
     184
    185185    def  __init__(self, filename, domain=None, quantities=None,
    186186                  interpolation_points=None, verbose = False):
     
    189189        If domain is specified, model time (domain.starttime)
    190190        will be checked and possibly modified
    191        
     191
    192192        All times are assumed to be in UTC
    193193        """
     
    196196        #(both in UTM coordinates)
    197197        #If not - modify those from file to match domain
    198        
     198
    199199        import time, calendar
    200200        from config import time_format
    201         from Scientific.IO.NetCDF import NetCDFFile     
     201        from Scientific.IO.NetCDF import NetCDFFile
    202202
    203203        #Open NetCDF file
     
    213213             if not fid.variables.has_key(quantity):
    214214                 missing.append(quantity)
    215                  
     215
    216216        if len(missing) > 0:
    217217            msg = 'Quantities %s could not be found in file %s'\
    218218                  %(str(missing), filename)
    219219            raise msg
    220                  
     220
    221221
    222222        #Get first timestep
    223223        try:
    224224            self.starttime = fid.starttime[0]
    225         except ValueError:   
     225        except ValueError:
    226226            msg = 'Could not read starttime from file %s' %filename
    227227            raise msg
     
    229229        #Get origin
    230230        self.xllcorner = fid.xllcorner[0]
    231         self.yllcorner = fid.yllcorner[0]           
    232    
     231        self.yllcorner = fid.yllcorner[0]
     232
    233233        self.number_of_values = len(quantities)
    234234        self.fid = fid
     
    249249                if verbose: print 'Domain starttime is now set to %f' %domain.starttime
    250250
    251         #Read all data in and produce values for desired data points at each timestep 
    252         self.spatial_interpolation(interpolation_points, verbose = verbose) 
     251        #Read all data in and produce values for desired data points at each timestep
     252        self.spatial_interpolation(interpolation_points, verbose = verbose)
    253253        fid.close()
    254254
    255255    def spatial_interpolation(self, interpolation_points, verbose = False):
    256         """For each timestep in fid: read surface, interpolate to desired points 
     256        """For each timestep in fid: read surface, interpolate to desired points
    257257        and store values for use when object is called.
    258258        """
    259        
     259
    260260        from Numeric import array, zeros, Float, alltrue, concatenate, reshape
    261261
     
    263263        from least_squares import Interpolation
    264264        import time, calendar
    265        
     265
    266266        fid = self.fid
    267267
     
    273273        triangles = fid.variables['volumes'][:]
    274274        time = fid.variables['time'][:]
    275        
     275
    276276        #Check
    277277        msg = 'File %s must list time as a monotonuosly ' %self.filename
    278278        msg += 'increasing sequence'
    279         assert alltrue(time[1:] - time[:-1] > 0 ), msg 
    280        
    281 
    282         if interpolation_points is not None: 
    283        
     279        assert alltrue(time[1:] - time[:-1] > 0 ), msg
     280
     281
     282        if interpolation_points is not None:
     283
    284284            try:
    285                 P = ensure_numeric(interpolation_points) 
     285                P = ensure_numeric(interpolation_points)
    286286            except:
    287287                msg = 'Interpolation points must be an N x 2 Numeric array or a list of points\n'
    288288                msg += 'I got: %s.' %( str(interpolation_points)[:60] + '...')
    289289                raise msg
    290            
    291            
     290
     291
    292292            self.T = time[:]  #Time assumed to be relative to starttime
    293             self.index = 0    #Initial time index       
    294 
    295             self.values = {}               
     293            self.index = 0    #Initial time index
     294
     295            self.values = {}
    296296            for name in self.quantities:
    297                 self.values[name] = zeros( (len(self.T), 
    298                                             len(interpolation_points)), 
    299                                             Float)                 
     297                self.values[name] = zeros( (len(self.T),
     298                                            len(interpolation_points)),
     299                                            Float)
    300300
    301301            #Build interpolator
    302302            if verbose: print 'Build interpolation matrix'
    303303            x = reshape(x, (len(x),1))
    304             y = reshape(y, (len(y),1))               
     304            y = reshape(y, (len(y),1))
    305305            vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
    306306
    307             interpol = Interpolation(vertex_coordinates, 
     307            interpol = Interpolation(vertex_coordinates,
    308308                                     triangles,
    309309                                     point_coordinates = P,
    310                                      alpha = 0, 
     310                                     alpha = 0,
    311311                                     verbose = verbose)
    312312
     
    318318                for name in self.quantities:
    319319                    self.values[name][i, :] =\
    320                     interpol.interpolate(fid.variables[name][i,:])   
     320                    interpol.interpolate(fid.variables[name][i,:])
    321321
    322322            #Report
     
    327327                print '  Reference:'
    328328                print '    Lower left corner: [%f, %f]'\
    329                       %(self.xllcorner, self.yllcorner) 
     329                      %(self.xllcorner, self.yllcorner)
    330330                print '    Start time (file):   %f' %self.starttime
    331331                #print '    Start time (domain): %f' %domain.starttime
     
    342342                    print '    %s in [%f, %f]' %(name, min(q), max(q))
    343343
    344                    
     344
    345345                print '  Interpolation points (xi, eta):'\
    346346                      'number of points == %d ' %P.shape[0]
     
    349349                print '  Interpolated quantities (over all timesteps):'
    350350                for name in self.quantities:
    351                     q = self.values[name][:].flat                   
     351                    q = self.values[name][:].flat
    352352                    print '    %s at interpolation points in [%f, %f]'\
    353                           %(name, min(q), max(q))               
    354                
    355                
    356                
     353                          %(name, min(q), max(q))
     354
     355
     356
    357357
    358358                print '------------------------------------------------'
     
    367367    def __call__(self, t, x=None, y=None, point_id = None):
    368368        """Evaluate f(t, point_id)
    369        
     369
    370370        Inputs:
    371           t: time - Model time (tau = domain.starttime-self.starttime+t) 
    372                     must lie within existing timesteps   
    373           point_id: index of one of the preprocessed points. 
     371          t: time - Model time (tau = domain.starttime-self.starttime+t)
     372                    must lie within existing timesteps
     373          point_id: index of one of the preprocessed points.
    374374                    If point_id is None all preprocessed points are computed
    375375
    376           FIXME: point_id could also be a slice     
    377           FIXME: One could allow arbitrary x, y coordinates 
     376          FIXME: point_id could also be a slice
     377          FIXME: One could allow arbitrary x, y coordinates
    378378          (requires computation of a new interpolator)
    379379          Maybe not,.,.
    380           FIXME: What if x and y are vectors? 
     380          FIXME: What if x and y are vectors?
    381381        """
    382382
     
    393393        #
    394394        # domain.starttime + t == self.starttime + tau
    395        
     395
    396396        if self.domain is not None:
    397397            tau = self.domain.starttime-self.starttime+t
     
    403403        #print 'S start', self.starttime
    404404        #print 't', t
    405         #print 'tau', tau             
    406                
     405        #print 'tau', tau
     406
    407407        msg = 'Time interval derived from file %s [%s:%s]'\
    408408              %(self.filename, self.T[0], self.T[1])
     
    411411
    412412        if tau < self.T[0]: raise msg
    413         if tau > self.T[-1]: raise msg       
     413        if tau > self.T[-1]: raise msg
    414414
    415415
     
    424424            #Protect against case where tau == T[-1] (last time)
    425425            # - also works in general when tau == T[i]
    426             ratio = 0 
     426            ratio = 0
    427427        else:
    428             #t is now between index and index+1           
     428            #t is now between index and index+1
    429429            ratio = (tau - self.T[self.index])/\
    430430                    (self.T[self.index+1] - self.T[self.index])
     
    432432
    433433
    434                
     434
    435435        #Compute interpolated values
    436436        q = zeros( len(self.quantities), Float)
    437437
    438438        for i, name in enumerate(self.quantities):
    439             Q = self.values[name]   
     439            Q = self.values[name]
    440440
    441441            if ratio > 0:
     
    450450        #Return vector of interpolated values
    451451        return q
    452                
    453              
     452
     453
    454454class File_function_ASCII:
    455455    """Read time series from file and return a callable object:
     
    468468    interpolated values, one each value stated in the file.
    469469
    470    
     470
    471471    E.g
    472472
     
    477477    ignoring x and y, which returns three values per call.
    478478
    479    
     479
    480480    NOTE: At this stage the function is assumed to depend on
    481481    time only, i.e  no spatial dependency!!!!!
    482482    When that is needed we can use the least_squares interpolation.
    483    
    484     #FIXME: This should work with netcdf (e.g. sww) and thus render the 
     483
     484    #FIXME: This should work with netcdf (e.g. sww) and thus render the
    485485    #spatio-temporal boundary condition in shallow water fully general
    486    
    487     #FIXME: Specified quantites not used here - 
     486
     487    #FIXME: Specified quantites not used here -
    488488    #always return whatever is in the file
    489489    """
    490490
    491    
     491
    492492    def __init__(self, filename, domain=None, quantities = None, interpolation_points=None):
    493493        """Initialise callable object from a file.
     
    507507        line = fid.readline()
    508508        fid.close()
    509    
     509
    510510        fields = line.split(',')
    511511        msg = 'File %s must have the format date, value0 value1 value2 ...'
     
    516516        try:
    517517            starttime = calendar.timegm(time.strptime(fields[0], time_format))
    518         except ValueError:   
     518        except ValueError:
    519519            msg = 'First field in file %s must be' %filename
    520520            msg += ' date-time with format %s.\n' %time_format
    521             msg += 'I got %s instead.' %fields[0] 
     521            msg += 'I got %s instead.' %fields[0]
    522522            raise msg
    523523
     
    529529
    530530        q = ensure_numeric(values)
    531        
     531
    532532        msg = 'ERROR: File must contain at least one independent value'
    533533        assert len(q.shape) == 1, msg
    534            
     534
    535535        self.number_of_values = len(q)
    536536
     
    549549                ##if verbose: print msg
    550550                domain.starttime = self.starttime #Modifying model time
    551        
     551
    552552            #if domain.starttime is None:
    553553            #    domain.starttime = self.starttime
     
    563563            #        domain.starttime = self.starttime #Modifying model time
    564564
    565         if mode == 2:       
     565        if mode == 2:
    566566            self.read_times() #Now read all times in.
    567567        else:
    568568            raise 'x,y dependency not yet implemented'
    569569
    570        
     570
    571571    def read_times(self):
    572         """Read time and values 
     572        """Read time and values
    573573        """
    574574        from Numeric import zeros, Float, alltrue
    575575        from config import time_format
    576576        import time, calendar
    577        
    578         fid = open(self.filename)       
     577
     578        fid = open(self.filename)
    579579        lines = fid.readlines()
    580580        fid.close()
    581        
     581
    582582        N = len(lines)
    583583        d = self.number_of_values
     
    585585        T = zeros(N, Float)       #Time
    586586        Q = zeros((N, d), Float)  #Values
    587        
     587
    588588        for i, line in enumerate(lines):
    589589            fields = line.split(',')
     
    603603        self.index = 0 #Initial index
    604604
    605        
     605
    606606    def __repr__(self):
    607607        return 'File function'
     
    613613        result is a vector of same length as x and y
    614614        FIXME: Naaaa
    615        
     615
    616616        FIXME: Rethink semantics when x,y are vectors.
    617617        """
    618618
    619619        from math import pi, cos, sin, sqrt
    620        
     620
    621621
    622622        #Find time tau such that
    623623        #
    624624        # domain.starttime + t == self.starttime + tau
    625        
     625
    626626        if self.domain is not None:
    627627            tau = self.domain.starttime-self.starttime+t
    628628        else:
    629629            tau = t
    630        
    631                
     630
     631
    632632        msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\
    633633              %(self.filename, self.T[0], self.T[1], tau)
    634634        if tau < self.T[0]: raise msg
    635         if tau > self.T[-1]: raise msg       
     635        if tau > self.T[-1]: raise msg
    636636
    637637        oldindex = self.index
     
    647647        #Compute interpolated values
    648648        q = self.Q[self.index,:] +\
    649             ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 
     649            ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
    650650
    651651        #Return vector of interpolated values
     
    662662                N = len(x)
    663663                assert len(y) == N, 'x and y must have same length'
    664              
     664
    665665                res = []
    666666                for col in q:
    667667                    res.append(col*ones(N, Float))
    668            
     668
    669669                return res
    670            
    671            
    672 #FIXME: TEMP       
     670
     671
     672#FIXME: TEMP
    673673class File_function_copy:
    674674    """Read time series from file and return a callable object:
     
    687687    interpolated values, one each value stated in the file.
    688688
    689    
     689
    690690    E.g
    691691
     
    696696    ignoring x and y, which returns three values per call.
    697697
    698    
     698
    699699    NOTE: At this stage the function is assumed to depend on
    700700    time only, i.e  no spatial dependency!!!!!
    701701    When that is needed we can use the least_squares interpolation.
    702    
    703     #FIXME: This should work with netcdf (e.g. sww) and thus render the 
     702
     703    #FIXME: This should work with netcdf (e.g. sww) and thus render the
    704704    #spatio-temporal boundary condition in shallow water fully general
    705705    """
    706706
    707    
     707
    708708    def __init__(self, filename, domain=None):
    709709        """Initialise callable object from a file.
     
    742742        try:
    743743            starttime = calendar.timegm(time.strptime(fields[0], time_format))
    744         except ValueError:   
     744        except ValueError:
    745745            msg = 'First field in file %s must be' %filename
    746746            msg += ' date-time with format %s.\n' %time_format
    747             msg += 'I got %s instead.' %fields[0] 
     747            msg += 'I got %s instead.' %fields[0]
    748748            raise msg
    749749
     
    755755
    756756        q = ensure_numeric(values)
    757        
     757
    758758        msg = 'ERROR: File must contain at least one independent value'
    759759        assert len(q.shape) == 1, msg
    760            
     760
    761761        self.number_of_values = len(q)
    762762
     
    779779                    domain.starttime = self.starttime #Modifying model time
    780780
    781         if mode == 2:       
     781        if mode == 2:
    782782            self.read_times() #Now read all times in.
    783783        else:
    784784            raise 'x,y dependency not yet implemented'
    785785
    786        
     786
    787787    def read_times(self):
    788         """Read time and values 
     788        """Read time and values
    789789        """
    790790        from Numeric import zeros, Float, alltrue
    791791        from config import time_format
    792792        import time, calendar
    793        
    794         fid = open(self.filename)       
     793
     794        fid = open(self.filename)
    795795        lines = fid.readlines()
    796796        fid.close()
    797        
     797
    798798        N = len(lines)
    799799        d = self.number_of_values
     
    801801        T = zeros(N, Float)       #Time
    802802        Q = zeros((N, d), Float)  #Values
    803        
     803
    804804        for i, line in enumerate(lines):
    805805            fields = line.split(',')
     
    819819        self.index = 0 #Initial index
    820820
    821        
     821
    822822    def __repr__(self):
    823823        return 'File function'
    824824
    825        
     825
    826826
    827827    def __call__(self, t, x=None, y=None):
     
    834834
    835835        from math import pi, cos, sin, sqrt
    836        
     836
    837837
    838838        #Find time tau such that
    839839        #
    840840        # domain.starttime + t == self.starttime + tau
    841        
     841
    842842        if self.domain is not None:
    843843            tau = self.domain.starttime-self.starttime+t
    844844        else:
    845845            tau = t
    846        
    847                
     846
     847
    848848        msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\
    849849              %(self.filename, self.T[0], self.T[1], tau)
    850850        if tau < self.T[0]: raise msg
    851         if tau > self.T[-1]: raise msg       
     851        if tau > self.T[-1]: raise msg
    852852
    853853        oldindex = self.index
     
    863863        #Compute interpolated values
    864864        q = self.Q[self.index,:] +\
    865             ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 
     865            ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
    866866
    867867        #Return vector of interpolated values
     
    878878                N = len(x)
    879879                assert len(y) == N, 'x and y must have same length'
    880              
     880
    881881                res = []
    882882                for col in q:
    883883                    res.append(col*ones(N, Float))
    884            
     884
    885885                return res
    886            
     886
    887887
    888888def read_xya(filename, format = 'netcdf'):
     
    892892
    893893    Format can be either ASCII or NetCDF
    894    
     894
    895895    Return list of points, list of attributes and
    896896    attribute names if present otherwise None
    897897    """
    898898    #FIXME: Probably obsoleted by similar function in load_ASCII
    899    
     899
    900900    from Scientific.IO.NetCDF import NetCDFFile
    901901
    902     if format.lower() == 'netcdf': 
     902    if format.lower() == 'netcdf':
    903903        #Get NetCDF
    904        
    905         fid = NetCDFFile(filename, 'r') 
    906      
     904
     905        fid = NetCDFFile(filename, 'r')
     906
    907907        # Get the variables
    908908        points = fid.variables['points']
     
    913913        #Don't close - arrays are needed outside this function,
    914914        #alternatively take a copy here
    915     else:   
     915    else:
    916916        #Read as ASCII file assuming that it is separated by whitespace
    917917        fid = open(filename)
     
    930930            attribute_names = ['elevation']  #HACK
    931931
    932         attributes = {}   
     932        attributes = {}
    933933        for key in attribute_names:
    934934            attributes[key] = []
     
    940940            for i, key in enumerate(attribute_names):
    941941                attributes[key].append( float(fields[2+i]) )
    942        
     942
    943943    return points, attributes
    944    
     944
    945945
    946946#####################################
     
    950950
    951951
    952              
    953 #Redefine these to use separate_by_polygon which will put all inside indices 
     952
     953#Redefine these to use separate_by_polygon which will put all inside indices
    954954#in the first part of the indices array and outside indices in the last
    955955
     
    957957    """See separate_points_by_polygon for documentation
    958958    """
    959    
    960     from Numeric import array, Float, reshape   
    961    
    962     if verbose: print 'Checking input to inside_polygon'   
     959
     960    from Numeric import array, Float, reshape
     961
     962    if verbose: print 'Checking input to inside_polygon'
    963963    try:
    964         points = ensure_numeric(points, Float)             
     964        points = ensure_numeric(points, Float)
    965965    except:
    966966        msg = 'Points could not be converted to Numeric array'
    967         raise msg       
    968        
     967        raise msg
     968
    969969    try:
    970         polygon = ensure_numeric(polygon, Float)           
     970        polygon = ensure_numeric(polygon, Float)
    971971    except:
    972972        msg = 'Polygon could not be converted to Numeric array'
    973         raise msg               
    974    
    975    
    976    
     973        raise msg
     974
     975
     976
    977977    if len(points.shape) == 1:
    978978        one_point = True
    979979        points = reshape(points, (1,2))
    980     else:       
     980    else:
    981981        one_point = False
    982982
    983     indices, count = separate_points_by_polygon(points, polygon, 
    984                                                 closed, verbose)     
    985    
     983    indices, count = separate_points_by_polygon(points, polygon,
     984                                                closed, verbose)
     985
    986986    if one_point:
    987987        return count == 1
    988988    else:
    989         return indices[:count]   
    990        
     989        return indices[:count]
     990
    991991def outside_polygon(points, polygon, closed = True, verbose = False):
    992992    """See separate_points_by_polygon for documentation
    993993    """
    994    
    995     from Numeric import array, Float, reshape   
    996    
    997     if verbose: print 'Checking input to outside_polygon'   
     994
     995    from Numeric import array, Float, reshape
     996
     997    if verbose: print 'Checking input to outside_polygon'
    998998    try:
    999         points = ensure_numeric(points, Float)             
     999        points = ensure_numeric(points, Float)
    10001000    except:
    10011001        msg = 'Points could not be converted to Numeric array'
    1002         raise msg       
    1003        
     1002        raise msg
     1003
    10041004    try:
    1005         polygon = ensure_numeric(polygon, Float)           
     1005        polygon = ensure_numeric(polygon, Float)
    10061006    except:
    10071007        msg = 'Polygon could not be converted to Numeric array'
    1008         raise msg               
    1009    
    1010    
    1011    
     1008        raise msg
     1009
     1010
     1011
    10121012    if len(points.shape) == 1:
    10131013        one_point = True
    10141014        points = reshape(points, (1,2))
    1015     else:       
     1015    else:
    10161016        one_point = False
    10171017
    1018     indices, count = separate_points_by_polygon(points, polygon, 
    1019                                                 closed, verbose)     
    1020    
     1018    indices, count = separate_points_by_polygon(points, polygon,
     1019                                                closed, verbose)
     1020
    10211021    if one_point:
    10221022        return count != 1
    10231023    else:
    1024         return indices[count:][::-1]  #return reversed   
    1025        
    1026 
    1027 def separate_points_by_polygon(points, polygon, 
     1024        return indices[count:][::-1]  #return reversed
     1025
     1026
     1027def separate_points_by_polygon(points, polygon,
    10281028                               closed = True, verbose = False):
    10291029    """Determine whether points are inside or outside a polygon
    1030    
     1030
    10311031    Input:
    10321032       points - Tuple of (x, y) coordinates, or list of tuples
    10331033       polygon - list of vertices of polygon
    1034        closed - (optional) determine whether points on boundary should be 
    1035        regarded as belonging to the polygon (closed = True) 
    1036        or not (closed = False) 
    1037    
     1034       closed - (optional) determine whether points on boundary should be
     1035       regarded as belonging to the polygon (closed = True)
     1036       or not (closed = False)
     1037
    10381038    Outputs:
    1039        indices: array of same length as points with indices of points falling 
    1040        inside the polygon listed from the beginning and indices of points 
     1039       indices: array of same length as points with indices of points falling
     1040       inside the polygon listed from the beginning and indices of points
    10411041       falling outside listed from the end.
    1042        
     1042
    10431043       count: count of points falling inside the polygon
    1044        
     1044
    10451045       The indices of points inside are obtained as indices[:count]
    1046        The indices of points outside are obtained as indices[count:]       
    1047        
    1048        
     1046       The indices of points outside are obtained as indices[count:]
     1047
     1048
    10491049    Examples:
    10501050       U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    1051        
     1051
    10521052       separate_points_by_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U)
    1053        will return the indices [0, 2, 1] and count == 2 as only the first 
     1053       will return the indices [0, 2, 1] and count == 2 as only the first
    10541054       and the last point are inside the unit square
    1055        
     1055
    10561056    Remarks:
    10571057       The vertices may be listed clockwise or counterclockwise and
    1058        the first point may optionally be repeated.   
     1058       the first point may optionally be repeated.
    10591059       Polygons do not need to be convex.
    1060        Polygons can have holes in them and points inside a hole is 
    1061        regarded as being outside the polygon.         
    1062                
    1063     Algorithm is based on work by Darel Finley, 
    1064     http://www.alienryderflex.com/polygon/ 
    1065    
    1066     """   
     1060       Polygons can have holes in them and points inside a hole is
     1061       regarded as being outside the polygon.
     1062
     1063    Algorithm is based on work by Darel Finley,
     1064    http://www.alienryderflex.com/polygon/
     1065
     1066    """
    10671067
    10681068    from Numeric import array, Float, reshape, Int, zeros
    1069    
    1070    
    1071     #Input checks
    1072     try:
    1073         points = ensure_numeric(points, Float)             
    1074     except:
    1075         msg = 'Points could not be converted to Numeric array'
    1076         raise msg       
    1077        
    1078     try:
    1079         polygon = ensure_numeric(polygon, Float)           
    1080     except:
    1081         msg = 'Polygon could not be converted to Numeric array'
    1082         raise msg               
    1083 
    1084     assert len(polygon.shape) == 2,\
    1085        'Polygon array must be a 2d array of vertices'
    1086 
    1087     assert polygon.shape[1] == 2,\
    1088        'Polygon array must have two columns'
    1089 
    1090     assert len(points.shape) == 2,\
    1091        'Points array must be a 2d array'
    1092        
    1093     assert points.shape[1] == 2,\
    1094        'Points array must have two columns'
    1095        
    1096     N = polygon.shape[0] #Number of vertices in polygon
    1097     M = points.shape[0]  #Number of points
    1098    
    1099     px = polygon[:,0]
    1100     py = polygon[:,1]   
    1101 
    1102     #Used for an optimisation when points are far away from polygon
    1103     minpx = min(px); maxpx = max(px)
    1104     minpy = min(py); maxpy = max(py)   
    1105 
    1106 
    1107     #Begin main loop
    1108     indices = zeros(M, Int)
    1109    
    1110     inside_index = 0    #Keep track of points inside
    1111     outside_index = M-1 #Keep track of points outside (starting from end)
    1112    
    1113     for k in range(M):
    1114 
    1115         if verbose:
    1116             if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
    1117        
    1118         #for each point   
    1119         x = points[k, 0]
    1120         y = points[k, 1]       
    1121 
    1122         inside = False
    1123 
    1124         if not x > maxpx or x < minpx or y > maxpy or y < minpy:
    1125             #Check polygon
    1126             for i in range(N):
    1127                 j = (i+1)%N
    1128                
    1129                 #Check for case where point is contained in line segment       
    1130                 if point_on_line(x, y, px[i], py[i], px[j], py[j]):
    1131                     if closed:
    1132                         inside = True
    1133                     else:       
    1134                         inside = False
    1135                     break
    1136                 else:   
    1137                     #Check if truly inside polygon                 
    1138                     if py[i] < y and py[j] >= y or\
    1139                        py[j] < y and py[i] >= y:
    1140                         if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
    1141                             inside = not inside
    1142        
    1143         if inside:
    1144             indices[inside_index] = k
    1145             inside_index += 1
    1146         else:
    1147             indices[outside_index] = k
    1148             outside_index -= 1   
    1149            
    1150     return indices, inside_index
    1151 
    1152 
    1153 def separate_points_by_polygon_c(points, polygon,
    1154                                  closed = True, verbose = False):
    1155     """Determine whether points are inside or outside a polygon
    1156 
    1157     C-wrapper
    1158     """   
    1159 
    1160     from Numeric import array, Float, reshape, zeros, Int
    1161    
    1162 
    1163     if verbose: print 'Checking input to separate_points_by_polygon'   
     1069
     1070
    11641071    #Input checks
    11651072    try:
     
    11691076        raise msg
    11701077
    1171     #if verbose: print 'Checking input to separate_points_by_polygon 2'
    11721078    try:
    11731079        polygon = ensure_numeric(polygon, Float)
    11741080    except:
    11751081        msg = 'Polygon could not be converted to Numeric array'
    1176         raise msg               
    1177 
    1178     if verbose: print 'check'
    1179    
     1082        raise msg
     1083
    11801084    assert len(polygon.shape) == 2,\
    11811085       'Polygon array must be a 2d array of vertices'
     
    11861090    assert len(points.shape) == 2,\
    11871091       'Points array must be a 2d array'
    1188        
     1092
    11891093    assert points.shape[1] == 2,\
    11901094       'Points array must have two columns'
    1191        
    1192     N = polygon.shape[0] #Number of vertices in polygon 
     1095
     1096    N = polygon.shape[0] #Number of vertices in polygon
    11931097    M = points.shape[0]  #Number of points
    11941098
     1099    px = polygon[:,0]
     1100    py = polygon[:,1]
     1101
     1102    #Used for an optimisation when points are far away from polygon
     1103    minpx = min(px); maxpx = max(px)
     1104    minpy = min(py); maxpy = max(py)
     1105
     1106
     1107    #Begin main loop
     1108    indices = zeros(M, Int)
     1109
     1110    inside_index = 0    #Keep track of points inside
     1111    outside_index = M-1 #Keep track of points outside (starting from end)
     1112
     1113    for k in range(M):
     1114
     1115        if verbose:
     1116            if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
     1117
     1118        #for each point
     1119        x = points[k, 0]
     1120        y = points[k, 1]
     1121
     1122        inside = False
     1123
     1124        if not x > maxpx or x < minpx or y > maxpy or y < minpy:
     1125            #Check polygon
     1126            for i in range(N):
     1127                j = (i+1)%N
     1128
     1129                #Check for case where point is contained in line segment
     1130                if point_on_line(x, y, px[i], py[i], px[j], py[j]):
     1131                    if closed:
     1132                        inside = True
     1133                    else:
     1134                        inside = False
     1135                    break
     1136                else:
     1137                    #Check if truly inside polygon
     1138                    if py[i] < y and py[j] >= y or\
     1139                       py[j] < y and py[i] >= y:
     1140                        if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
     1141                            inside = not inside
     1142
     1143        if inside:
     1144            indices[inside_index] = k
     1145            inside_index += 1
     1146        else:
     1147            indices[outside_index] = k
     1148            outside_index -= 1
     1149
     1150    return indices, inside_index
     1151
     1152
     1153def separate_points_by_polygon_c(points, polygon,
     1154                                 closed = True, verbose = False):
     1155    """Determine whether points are inside or outside a polygon
     1156
     1157    C-wrapper
     1158    """
     1159
     1160    from Numeric import array, Float, reshape, zeros, Int
     1161
     1162
     1163    if verbose: print 'Checking input to separate_points_by_polygon'
     1164    #Input checks
     1165    try:
     1166        points = ensure_numeric(points, Float)
     1167    except:
     1168        msg = 'Points could not be converted to Numeric array'
     1169        raise msg
     1170
     1171    #if verbose: print 'Checking input to separate_points_by_polygon 2'
     1172    try:
     1173        polygon = ensure_numeric(polygon, Float)
     1174    except:
     1175        msg = 'Polygon could not be converted to Numeric array'
     1176        raise msg
     1177
     1178    if verbose: print 'check'
     1179
     1180    assert len(polygon.shape) == 2,\
     1181       'Polygon array must be a 2d array of vertices'
     1182
     1183    assert polygon.shape[1] == 2,\
     1184       'Polygon array must have two columns'
     1185
     1186    assert len(points.shape) == 2,\
     1187       'Points array must be a 2d array'
     1188
     1189    assert points.shape[1] == 2,\
     1190       'Points array must have two columns'
     1191
     1192    N = polygon.shape[0] #Number of vertices in polygon
     1193    M = points.shape[0]  #Number of points
     1194
    11951195    from util_ext import separate_points_by_polygon
    11961196
     
    11991199    indices = zeros( M, Int )
    12001200
    1201     if verbose: print 'Calling C-version of inside poly' 
     1201    if verbose: print 'Calling C-version of inside poly'
    12021202    count = separate_points_by_polygon(points, polygon, indices,
    12031203                                       int(closed), int(verbose))
    12041204
    1205     return indices, count 
     1205    return indices, count
    12061206
    12071207
    12081208
    12091209class Polygon_function:
    1210     """Create callable object f: x,y -> z, where a,y,z are vectors and 
    1211     where f will return different values depending on whether x,y belongs 
     1210    """Create callable object f: x,y -> z, where a,y,z are vectors and
     1211    where f will return different values depending on whether x,y belongs
    12121212    to specified polygons.
    1213    
     1213
    12141214    To instantiate:
    1215      
     1215
    12161216       Polygon_function(polygons)
    1217        
     1217
    12181218    where polygons is a list of tuples of the form
    1219    
     1219
    12201220      [ (P0, v0), (P1, v1), ...]
    1221      
    1222       with Pi being lists of vertices defining polygons and vi either 
     1221
     1222      with Pi being lists of vertices defining polygons and vi either
    12231223      constants or functions of x,y to be applied to points with the polygon.
    1224      
    1225     The function takes an optional argument, default which is the value 
     1224
     1225    The function takes an optional argument, default which is the value
    12261226    (or function) to used for points not belonging to any polygon.
    12271227    For example:
    1228    
    1229        Polygon_function(polygons, default = 0.03)       
    1230      
    1231     If omitted the default value will be 0.0 
    1232    
     1228
     1229       Polygon_function(polygons, default = 0.03)
     1230
     1231    If omitted the default value will be 0.0
     1232
    12331233    Note: If two polygons overlap, the one last in the list takes precedence
    12341234
     
    12361236
    12371237    """
    1238    
     1238
    12391239    def __init__(self, regions, default = 0.0):
    1240        
     1240
    12411241        try:
    12421242            len(regions)
    12431243        except:
    1244             msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons           
     1244            msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons
    12451245            raise msg
    12461246
    12471247
    1248         T = regions[0]                                   
     1248        T = regions[0]
    12491249        try:
    12501250            a = len(T)
    1251         except:   
    1252             msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons           
    1253             raise msg   
    1254                    
    1255         assert a == 2, 'Must have two component each: %s' %T       
    1256 
    1257         self.regions = regions             
     1251        except:
     1252            msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons
     1253            raise msg
     1254
     1255        assert a == 2, 'Must have two component each: %s' %T
     1256
     1257        self.regions = regions
    12581258        self.default = default
    1259          
    1260          
     1259
     1260
    12611261    def __call__(self, x, y):
    12621262        from util import inside_polygon
    12631263        from Numeric import ones, Float, concatenate, array, reshape, choose
    1264        
     1264
    12651265        x = array(x).astype(Float)
    1266         y = array(y).astype(Float)     
    1267        
     1266        y = array(y).astype(Float)
     1267
    12681268        N = len(x)
    12691269        assert len(y) == N
    1270        
    1271         points = concatenate( (reshape(x, (N, 1)), 
     1270
     1271        points = concatenate( (reshape(x, (N, 1)),
    12721272                               reshape(y, (N, 1))), axis=1 )
    12731273
    12741274        if callable(self.default):
    12751275            z = self.default(x,y)
    1276         else:                   
     1276        else:
    12771277            z = ones(N, Float) * self.default
    1278            
     1278
    12791279        for polygon, value in self.regions:
    12801280            indices = inside_polygon(points, polygon)
    1281            
    1282             #FIXME: This needs to be vectorised 
     1281
     1282            #FIXME: This needs to be vectorised
    12831283            if callable(value):
    12841284                for i in indices:
     
    12861286                    yy = array([y[i]])
    12871287                    z[i] = value(xx, yy)[0]
    1288             else:   
     1288            else:
    12891289                for i in indices:
    1290                     z[i] = value 
    1291 
    1292         return z                 
     1290                    z[i] = value
     1291
     1292        return z
    12931293
    12941294def read_polygon(filename):
    12951295    """Read points assumed to form a polygon
    12961296       There must be exactly two numbers in each line
    1297     """             
    1298    
     1297    """
     1298
    12991299    #Get polygon
    13001300    fid = open(filename)
     
    13061306        polygon.append( [float(fields[0]), float(fields[1])] )
    13071307
    1308     return polygon     
    1309    
     1308    return polygon
     1309
    13101310def populate_polygon(polygon, number_of_points, seed = None):
    13111311    """Populate given polygon with uniformly distributed points.
     
    13131313    Input:
    13141314       polygon - list of vertices of polygon
    1315        number_of_points - (optional) number of points 
     1315       number_of_points - (optional) number of points
    13161316       seed - seed for random number generator (default=None)
    1317        
     1317
    13181318    Output:
    13191319       points - list of points inside polygon
    1320        
     1320
    13211321    Examples:
    13221322       populate_polygon( [[0,0], [1,0], [1,1], [0,1]], 5 )
    1323        will return five randomly selected points inside the unit square 
     1323       will return five randomly selected points inside the unit square
    13241324    """
    13251325
     
    13341334    max_y = min_y = polygon[0][1]
    13351335    for point in polygon[1:]:
    1336         x = point[0] 
     1336        x = point[0]
    13371337        if x > max_x: max_x = x
    1338         if x < min_x: min_x = x           
    1339         y = point[1] 
     1338        if x < min_x: min_x = x
     1339        y = point[1]
    13401340        if y > max_y: max_y = y
    1341         if y < min_y: min_y = y           
    1342 
    1343 
    1344     while len(points) < number_of_points:     
     1341        if y < min_y: min_y = y
     1342
     1343
     1344    while len(points) < number_of_points:
    13451345        x = uniform(min_x, max_x)
    1346         y = uniform(min_y, max_y)       
     1346        y = uniform(min_y, max_y)
    13471347
    13481348        if inside_polygon( [x,y], polygon ):
     
    13531353def tsh2sww(filename, verbose=True):
    13541354    """
    1355     to check if a tsh/msh file 'looks' good. 
     1355    to check if a tsh/msh file 'looks' good.
    13561356    """
    13571357    from shallow_water import Domain
    13581358    from pmesh2domain import pmesh_to_domain_instance
    1359     import time, os 
    1360     from data_manager import get_dataobject 
    1361     from os import sep, path 
     1359    import time, os
     1360    from data_manager import get_dataobject
     1361    from os import sep, path
    13621362    #from util import mean
    1363    
     1363
    13641364    if verbose == True:print 'Creating domain from', filename
    13651365    domain = pmesh_to_domain_instance(filename, Domain)
     
    13781378    if verbose == True:
    13791379        print "Output written to " + domain.get_datadir() + sep + \
    1380               domain.filename + "." + domain.format 
     1380              domain.filename + "." + domain.format
    13811381    sww = get_dataobject(domain)
    13821382    sww.store_connectivity()
     
    13901390    """
    13911391    """
    1392    
    1393     det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0)           
     1392
     1393    det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0)
    13941394    a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0)
    13951395    a /= det
    13961396
    13971397    b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0)
    1398     b /= det           
     1398    b /= det
    13991399
    14001400    return a, b
     
    14161416    pass
    14171417
    1418    
    1419    
    1420    
    1421    
    1422 
    1423 #OBSOLETED STUFF   
     1418
     1419
     1420
     1421
     1422
     1423#OBSOLETED STUFF
    14241424def inside_polygon_old(point, polygon, closed = True, verbose = False):
    14251425    #FIXME Obsoleted
    14261426    """Determine whether points are inside or outside a polygon
    1427    
     1427
    14281428    Input:
    14291429       point - Tuple of (x, y) coordinates, or list of tuples
    14301430       polygon - list of vertices of polygon
    1431        closed - (optional) determine whether points on boundary should be 
    1432        regarded as belonging to the polygon (closed = True) 
    1433        or not (closed = False) 
    1434    
     1431       closed - (optional) determine whether points on boundary should be
     1432       regarded as belonging to the polygon (closed = True)
     1433       or not (closed = False)
     1434
    14351435    Output:
    14361436       If one point is considered, True or False is returned.
    1437        If multiple points are passed in, the function returns indices 
    1438        of those points that fall inside the polygon     
    1439        
     1437       If multiple points are passed in, the function returns indices
     1438       of those points that fall inside the polygon
     1439
    14401440    Examples:
    14411441       U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    14421442       inside_polygon( [0.5, 0.5], U)
    1443        will evaluate to True as the point 0.5, 0.5 is inside the unit square 
    1444        
     1443       will evaluate to True as the point 0.5, 0.5 is inside the unit square
     1444
    14451445       inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U)
    1446        will return the indices [0, 2] as only the first and the last point 
     1446       will return the indices [0, 2] as only the first and the last point
    14471447       is inside the unit square
    1448        
     1448
    14491449    Remarks:
    14501450       The vertices may be listed clockwise or counterclockwise and
    1451        the first point may optionally be repeated.   
     1451       the first point may optionally be repeated.
    14521452       Polygons do not need to be convex.
    1453        Polygons can have holes in them and points inside a hole is 
    1454        regarded as being outside the polygon.         
    1455                
    1456        
    1457     Algorithm is based on work by Darel Finley, 
    1458     http://www.alienryderflex.com/polygon/ 
    1459    
    1460     """   
     1453       Polygons can have holes in them and points inside a hole is
     1454       regarded as being outside the polygon.
     1455
     1456
     1457    Algorithm is based on work by Darel Finley,
     1458    http://www.alienryderflex.com/polygon/
     1459
     1460    """
    14611461
    14621462    from Numeric import array, Float, reshape
    1463    
    1464    
     1463
     1464
    14651465    #Input checks
    14661466    try:
    1467         point = array(point).astype(Float)         
     1467        point = array(point).astype(Float)
    14681468    except:
    14691469        msg = 'Point %s could not be converted to Numeric array' %point
    1470         raise msg       
    1471        
     1470        raise msg
     1471
    14721472    try:
    1473         polygon = array(polygon).astype(Float)             
     1473        polygon = array(polygon).astype(Float)
    14741474    except:
    14751475        msg = 'Polygon %s could not be converted to Numeric array' %polygon
    1476         raise msg               
    1477    
     1476        raise msg
     1477
    14781478    assert len(polygon.shape) == 2,\
    14791479       'Polygon array must be a 2d array of vertices: %s' %polygon
    14801480
    1481        
     1481
    14821482    assert polygon.shape[1] == 2,\
    1483        'Polygon array must have two columns: %s' %polygon   
     1483       'Polygon array must have two columns: %s' %polygon
    14841484
    14851485
     
    14871487        one_point = True
    14881488        points = reshape(point, (1,2))
    1489     else:       
     1489    else:
    14901490        one_point = False
    14911491        points = point
    14921492
    1493     N = polygon.shape[0] #Number of vertices in polygon 
     1493    N = polygon.shape[0] #Number of vertices in polygon
    14941494    M = points.shape[0]  #Number of points
    1495    
     1495
    14961496    px = polygon[:,0]
    1497     py = polygon[:,1]   
     1497    py = polygon[:,1]
    14981498
    14991499    #Used for an optimisation when points are far away from polygon
    15001500    minpx = min(px); maxpx = max(px)
    1501     minpy = min(py); maxpy = max(py)   
     1501    minpy = min(py); maxpy = max(py)
    15021502
    15031503
     
    15081508        if verbose:
    15091509            if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
    1510        
    1511         #for each point   
    1512         x = points[k, 0]
    1513         y = points[k, 1]       
     1510
     1511        #for each point
     1512        x = points[k, 0]
     1513        y = points[k, 1]
    15141514
    15151515        inside = False
     
    15171517        #Optimisation
    15181518        if x > maxpx or x < minpx: continue
    1519         if y > maxpy or y < minpy: continue       
    1520 
    1521         #Check polygon 
     1519        if y > maxpy or y < minpy: continue
     1520
     1521        #Check polygon
    15221522        for i in range(N):
    15231523            j = (i+1)%N
    1524            
    1525             #Check for case where point is contained in line segment   
     1524
     1525            #Check for case where point is contained in line segment
    15261526            if point_on_line(x, y, px[i], py[i], px[j], py[j]):
    15271527                if closed:
    15281528                    inside = True
    1529                 else:       
     1529                else:
    15301530                    inside = False
    15311531                break
    1532             else:       
    1533                 #Check if truly inside polygon             
     1532            else:
     1533                #Check if truly inside polygon
    15341534                if py[i] < y and py[j] >= y or\
    15351535                   py[j] < y and py[i] >= y:
    15361536                    if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
    15371537                        inside = not inside
    1538                    
     1538
    15391539        if inside: indices.append(k)
    15401540
    1541     if one_point: 
     1541    if one_point:
    15421542        return inside
    15431543    else:
    15441544        return indices
    1545              
     1545
    15461546
    15471547#def remove_from(A, B):
     
    15521552#    ind = search_sorted(A, B)
    15531553
    1554    
     1554
    15551555
    15561556def outside_polygon_old(point, polygon, closed = True, verbose = False):
    15571557    #OBSOLETED
    15581558    """Determine whether points are outside a polygon
    1559    
     1559
    15601560    Input:
    15611561       point - Tuple of (x, y) coordinates, or list of tuples
    15621562       polygon - list of vertices of polygon
    1563        closed - (optional) determine whether points on boundary should be 
    1564        regarded as belonging to the polygon (closed = True) 
    1565        or not (closed = False) 
    1566    
     1563       closed - (optional) determine whether points on boundary should be
     1564       regarded as belonging to the polygon (closed = True)
     1565       or not (closed = False)
     1566
    15671567    Output:
    15681568       If one point is considered, True or False is returned.
    1569        If multiple points are passed in, the function returns indices 
    1570        of those points that fall outside the polygon     
    1571        
     1569       If multiple points are passed in, the function returns indices
     1570       of those points that fall outside the polygon
     1571
    15721572    Examples:
    1573        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square   
     1573       U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    15741574       outside_polygon( [0.5, 0.5], U )
    15751575       will evaluate to False as the point 0.5, 0.5 is inside the unit square
     
    15771577       ouside_polygon( [1.5, 0.5], U )
    15781578       will evaluate to True as the point 1.5, 0.5 is outside the unit square
    1579        
     1579
    15801580       outside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U )
    1581        will return the indices [1] as only the first and the last point 
     1581       will return the indices [1] as only the first and the last point
    15821582       is inside the unit square
    15831583    """
    15841584
    15851585    #FIXME: This is too slow
    1586    
     1586
    15871587    res  = inside_polygon(point, polygon, closed, verbose)
    15881588
     
    16021602
    16031603    C-wrapper
    1604     """   
     1604    """
    16051605
    16061606    from Numeric import array, Float, reshape, zeros, Int
    1607    
    1608 
    1609     if verbose: print 'Checking input to inside_polygon'   
     1607
     1608
     1609    if verbose: print 'Checking input to inside_polygon'
    16101610    #Input checks
    16111611    try:
    1612         point = array(point).astype(Float)         
     1612        point = array(point).astype(Float)
    16131613    except:
    16141614        msg = 'Point %s could not be converted to Numeric array' %point
    1615         raise msg       
    1616        
     1615        raise msg
     1616
    16171617    try:
    1618         polygon = array(polygon).astype(Float)             
     1618        polygon = array(polygon).astype(Float)
    16191619    except:
    16201620        msg = 'Polygon %s could not be converted to Numeric array' %polygon
    1621         raise msg               
    1622    
     1621        raise msg
     1622
    16231623    assert len(polygon.shape) == 2,\
    16241624       'Polygon array must be a 2d array of vertices: %s' %polygon
    16251625
    1626        
     1626
    16271627    assert polygon.shape[1] == 2,\
    1628        'Polygon array must have two columns: %s' %polygon   
     1628       'Polygon array must have two columns: %s' %polygon
    16291629
    16301630
     
    16321632        one_point = True
    16331633        points = reshape(point, (1,2))
    1634     else:       
     1634    else:
    16351635        one_point = False
    16361636        points = point
     
    16421642    indices = zeros( points.shape[0], Int )
    16431643
    1644     if verbose: print 'Calling C-version of inside poly' 
     1644    if verbose: print 'Calling C-version of inside poly'
    16451645    count = inside_polygon(points, polygon, indices,
    16461646                           int(closed), int(verbose))
     
    16501650    else:
    16511651        if verbose: print 'Got %d points' %count
    1652        
     1652
    16531653        return indices[:count]   #Return those indices that were inside
    1654 
  • inundation/ga/storm_surge/zeus/anuga-workspace.zwi

    r1363 r1387  
    22<workspace name="anuga-workspace">
    33    <mode>Debug</mode>
    4     <active>parallel</active>
     4    <active>steve</active>
    55    <project name="Merimbula">Merimbula.zpi</project>
    66    <project name="parallel">parallel.zpi</project>
  • inundation/ga/storm_surge/zeus/parallel.zpi

    r1363 r1387  
    7474    <ReleaseProjectReload>Off</ReleaseProjectReload>
    7575    <file>..\parallel\advection.py</file>
     76    <file>..\parallel\domain.py</file>
    7677    <file>..\parallel\parallel_advection.py</file>
    7778    <file>..\parallel\run_advection.py</file>
  • inundation/ga/storm_surge/zeus/steve.zpi

    r1290 r1387  
    7373    <ReleaseProjectSaveAll>Off</ReleaseProjectSaveAll>
    7474    <ReleaseProjectReload>Off</ReleaseProjectReload>
     75    <file>..\steve\get_triangle_attribute.py</file>
    7576    <file>..\steve\get_triangle_data.py</file>
    7677    <file>..\steve\get_triangle_data_new.py</file>
     78    <file>..\hobart\run_hobart_buildings.py</file>
    7779    <file>..\pyvolution-parallel\vtk-pylab.py</file>
    7880    <folder name="Header Files" />
Note: See TracChangeset for help on using the changeset viewer.