source: inundation/ga/storm_surge/parallel/advection.py @ 1280

Last change on this file since 1280 was 1280, checked in by steve, 19 years ago

Consolidated files in to parallel directory

File size: 5.7 KB
Line 
1import sys
2from os import sep
3sys.path.append('..'+sep+'pyvolution')
4
5"""Class Domain -
62D triangular domains for finite-volume computations of
7the advection equation.
8
9This module contains a specialisation of class Domain from module domain.py
10consisting of methods specific to the advection equantion
11
12The equation is
13
14  u_t + (v_1 u)_x + (v_2 u)_y = 0
15
16There is only one conserved quantity, the stage u
17
18The advection equation is a very simple specialisation of the generic
19domain and may serve as an instructive example or a test of other
20components such as visualisation.
21
22Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
23Geoscience Australia, 2004
24"""
25
26from domain import *
27Generic_domain = Domain #Rename
28
29class Domain(Generic_domain):
30
31    def __init__(self, coordinates, vertices, boundary = None, velocity = None):
32
33
34        Generic_domain.__init__(self, coordinates, vertices, boundary,
35                                ['stage'])
36
37        if velocity is None:
38            self.velocity = [1,0]
39        else:
40            self.velocity = velocity
41
42        #Only first is implemented for advection
43        self.default_order = self.order = 1
44
45        #Realtime visualisation
46        self.visualise = False
47        self.smooth = True
48        self.range_z = None
49
50
51    def check_integrity(self):
52        Generic_domain.check_integrity(self)
53
54        msg = 'Conserved quantity must be "stage"'
55        assert self.conserved_quantities[0] == 'stage', msg
56
57
58    def flux_function(self, normal, ql, qr, zl=None, zr=None):
59        """Compute outward flux as inner product between velocity
60        vector v=(v_1, v_2) and normal vector n.
61
62        if <n,v> > 0 flux direction is outward bound and its magnitude is
63        determined by the quantity inside volume: ql.
64        Otherwise it is inbound and magnitude is determined by the
65        quantity outside the volume: qr.
66        """
67
68        v1 = self.velocity[0]
69        v2 = self.velocity[1]
70
71
72        normal_velocity = v1*normal[0] + v2*normal[1]
73
74        if normal_velocity < 0:
75            flux = qr * normal_velocity
76        else:
77            flux = ql * normal_velocity
78
79        max_speed = abs(normal_velocity)
80        return flux, max_speed
81
82
83    def compute_fluxes(self):
84        """Compute all fluxes and the timestep suitable for all volumes
85        in domain.
86
87        Compute total flux for each conserved quantity using "flux_function"
88
89        Fluxes across each edge are scaled by edgelengths and summed up
90        Resulting flux is then scaled by area and stored in
91        domain.explicit_update
92
93        The maximal allowable speed computed by the flux_function
94        for each volume
95        is converted to a timestep that must not be exceeded. The minimum of
96        those is computed as the next overall timestep.
97
98        Post conditions:
99        domain.explicit_update is reset to computed flux values
100        domain.timestep is set to the largest step satisfying all volumes.
101        """
102
103        import sys
104        from Numeric import zeros, Float
105        from config import max_timestep
106
107        N = self.number_of_elements
108
109        neighbours = self.neighbours
110        neighbour_edges = self.neighbour_edges
111        normals = self.normals
112
113        areas = self.areas
114        radii = self.radii
115        edgelengths = self.edgelengths
116
117        timestep = max_timestep #FIXME: Get rid of this
118
119        #Shortcuts
120        Stage = self.quantities['stage']
121
122        #Arrays
123        stage = Stage.edge_values
124
125        stage_bdry = Stage.boundary_values
126
127        flux = zeros(1, Float) #Work array for summing up fluxes
128
129        #Loop
130        for k in range(N):
131            optimal_timestep = float(sys.maxint)
132
133            flux[:] = 0.  #Reset work array
134            for i in range(3):
135                #Quantities inside volume facing neighbour i
136                ql = stage[k, i]
137
138                #Quantities at neighbour on nearest face
139                n = neighbours[k,i]
140                if n < 0:
141                    m = -n-1 #Convert neg flag to index
142                    qr = stage_bdry[m]
143                else:
144                    m = neighbour_edges[k,i]
145                    qr = stage[n, m]
146
147
148                #Outward pointing normal vector
149                normal = normals[k, 2*i:2*i+2]
150
151                #Flux computation using provided function
152                edgeflux, max_speed = self.flux_function(normal, ql, qr)
153                flux -= edgeflux * edgelengths[k,i]
154
155                #Update optimal_timestep
156                try:
157                    optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
158                except ZeroDivisionError:
159                    pass
160
161            #Normalise by area and store for when all conserved
162            #quantities get updated
163            flux /= areas[k]
164            Stage.explicit_update[k] = flux[0]
165
166            timestep = min(timestep, optimal_timestep)
167
168        self.timestep = timestep
169
170
171
172    def evolve(self, yieldstep = None, finaltime = None):
173        """Specialisation of basic evolve method from parent class
174        """
175
176        #Initialise real time viz if requested
177        if self.visualise is True and self.time == 0.0:
178            import realtime_visualisation_new as visualise
179            visualise.create_surface(self,range_z =  self.range_z)
180
181        #Call basic machinery from parent class
182        for t in Generic_domain.evolve(self, yieldstep, finaltime):
183            #Real time viz
184            if self.visualise is True:
185                visualise.update(self)
186
187            #Pass control on to outer loop for more specific actions
188            yield(t)
Note: See TracBrowser for help on using the repository browser.