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

Last change on this file since 1452 was 1264, checked in by steve, 20 years ago

Using vpython faces to speed up visualisation

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