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

Last change on this file since 1452 was 1424, checked in by steve, 20 years ago
File size: 6.1 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 realtime_visualisation_new import Visualiser
27from domain import *
28Generic_domain = Domain #Rename
29
30class Domain(Generic_domain):
31
32    def __init__(self, coordinates, vertices, boundary = None, velocity = None):
33
34
35        Generic_domain.__init__(self, coordinates, vertices, boundary,['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.visualise_color_stage = False
48        self.visualise_timer = True
49        self.visualise_range_z = None
50
51        self.smooth = True
52
53
54
55    def initialise_visualiser(self,scale_z=1.0):
56        #Realtime visualisation
57        self.visualiser = Visualiser(self,scale_z)
58        self.visualise = True
59
60
61    def check_integrity(self):
62        Generic_domain.check_integrity(self)
63
64        msg = 'Conserved quantity must be "stage"'
65        assert self.conserved_quantities[0] == 'stage', msg
66
67
68    def flux_function(self, normal, ql, qr, zl=None, zr=None):
69        """Compute outward flux as inner product between velocity
70        vector v=(v_1, v_2) and normal vector n.
71
72        if <n,v> > 0 flux direction is outward bound and its magnitude is
73        determined by the quantity inside volume: ql.
74        Otherwise it is inbound and magnitude is determined by the
75        quantity outside the volume: qr.
76        """
77
78        v1 = self.velocity[0]
79        v2 = self.velocity[1]
80
81
82        normal_velocity = v1*normal[0] + v2*normal[1]
83
84        if normal_velocity < 0:
85            flux = qr * normal_velocity
86        else:
87            flux = ql * normal_velocity
88
89        max_speed = abs(normal_velocity)
90        return flux, max_speed
91
92
93    def compute_fluxes(self):
94        """Compute all fluxes and the timestep suitable for all volumes
95        in domain.
96
97        Compute total flux for each conserved quantity using "flux_function"
98
99        Fluxes across each edge are scaled by edgelengths and summed up
100        Resulting flux is then scaled by area and stored in
101        domain.explicit_update
102
103        The maximal allowable speed computed by the flux_function
104        for each volume
105        is converted to a timestep that must not be exceeded. The minimum of
106        those is computed as the next overall timestep.
107
108        Post conditions:
109        domain.explicit_update is reset to computed flux values
110        domain.timestep is set to the largest step satisfying all volumes.
111        """
112
113        import sys
114        from Numeric import zeros, Float
115        from config import max_timestep
116
117        N = self.number_of_elements
118
119        neighbours = self.neighbours
120        neighbour_edges = self.neighbour_edges
121        normals = self.normals
122
123        areas = self.areas
124        radii = self.radii
125        edgelengths = self.edgelengths
126
127        timestep = max_timestep #FIXME: Get rid of this
128
129        #Shortcuts
130        Stage = self.quantities['stage']
131
132        #Arrays
133        stage = Stage.edge_values
134
135        stage_bdry = Stage.boundary_values
136
137        flux = zeros(1, Float) #Work array for summing up fluxes
138
139        #Loop
140        for k in range(N):
141            optimal_timestep = float(sys.maxint)
142
143            flux[:] = 0.  #Reset work array
144            for i in range(3):
145                #Quantities inside volume facing neighbour i
146                ql = stage[k, i]
147
148                #Quantities at neighbour on nearest face
149                n = neighbours[k,i]
150                if n < 0:
151                    m = -n-1 #Convert neg flag to index
152                    qr = stage_bdry[m]
153                else:
154                    m = neighbour_edges[k,i]
155                    qr = stage[n, m]
156
157
158                #Outward pointing normal vector
159                normal = normals[k, 2*i:2*i+2]
160
161                #Flux computation using provided function
162                edgeflux, max_speed = self.flux_function(normal, ql, qr)
163                flux -= edgeflux * edgelengths[k,i]
164
165                #Update optimal_timestep
166                try:
167                    optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
168                except ZeroDivisionError:
169                    pass
170
171            #Normalise by area and store for when all conserved
172            #quantities get updated
173            flux /= areas[k]
174            Stage.explicit_update[k] = flux[0]
175
176            timestep = min(timestep, optimal_timestep)
177
178        self.timestep = timestep
179
180
181
182    def evolve(self, yieldstep = None, finaltime = None):
183        """Specialisation of basic evolve method from parent class
184        """
185
186        #Initialise real time viz if requested
187        if self.visualise is True and self.time == 0.0:
188            import realtime_visualisation_new as visualise
189            self.visualiser.update_quantity('stage')
190            self.visualiser.update_timer()
191
192        #Call basic machinery from parent class
193        for t in Generic_domain.evolve(self, yieldstep, finaltime):
194            #Real time viz
195            if self.visualise is True:
196                self.visualiser.update_quantity('stage')
197                self.visualiser.update_timer()
198
199            #Pass control on to outer loop for more specific actions
200            yield(t)
Note: See TracBrowser for help on using the repository browser.