source: anuga_core/source/anuga/advection/advection.py @ 4964

Last change on this file since 4964 was 4964, checked in by steve, 17 years ago

Proucing faster c code which is linked via f2py

File size: 9.0 KB
Line 
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
12There is only one conserved quantity, the stage u
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
19Geoscience Australia, 2004
20"""
21
22
23#import logging, logging.config
24#logger = logging.getLogger('advection')
25#logger.setLevel(logging.WARNING)
26#
27#try:
28#    logging.config.fileConfig('log.ini')
29#except:
30#    pass
31
32
33from anuga.abstract_2d_finite_volumes.domain import *
34Generic_domain = Domain # Rename
35
36class Domain(Generic_domain):
37
38    def __init__(self,
39                 coordinates,
40                 vertices,
41                 boundary = None,
42                 tagged_elements = None,
43                 geo_reference = None,
44                 use_inscribed_circle=False,
45                 velocity = None,
46                 full_send_dict=None,
47                 ghost_recv_dict=None,
48                 processor=0,
49                 numproc=1
50                 ):
51
52        conserved_quantities = ['stage']
53        other_quantities = []
54        Generic_domain.__init__(self,
55                                source=coordinates,
56                                triangles=vertices,
57                                boundary=boundary,
58                                conserved_quantities=conserved_quantities,
59                                other_quantities=other_quantities,
60                                tagged_elements=tagged_elements,
61                                geo_reference=geo_reference,
62                                use_inscribed_circle=use_inscribed_circle,
63                                full_send_dict=full_send_dict,
64                                ghost_recv_dict=ghost_recv_dict,
65                                processor=processor,
66                                numproc=numproc)
67
68
69        if velocity is None:
70            self.velocity = [1,0]
71        else:
72            self.velocity = velocity
73
74        #Only first is implemented for advection
75        self.default_order = self.order = 1
76
77        self.smooth = True
78
79    def check_integrity(self):
80        Generic_domain.check_integrity(self)
81
82        msg = 'Conserved quantity must be "stage"'
83        assert self.conserved_quantities[0] == 'stage', msg
84
85
86    def flux_function(self, normal, ql, qr, zl=None, zr=None):
87        """Compute outward flux as inner product between velocity
88        vector v=(v_1, v_2) and normal vector n.
89
90        if <n,v> > 0 flux direction is outward bound and its magnitude is
91        determined by the quantity inside volume: ql.
92        Otherwise it is inbound and magnitude is determined by the
93        quantity outside the volume: qr.
94        """
95
96        v1 = self.velocity[0]
97        v2 = self.velocity[1]
98
99
100        normal_velocity = v1*normal[0] + v2*normal[1]
101
102        if normal_velocity < 0:
103            flux = qr * normal_velocity
104        else:
105            flux = ql * normal_velocity
106
107        max_speed = abs(normal_velocity)
108        return flux, max_speed
109
110    def compute_fluxes(self):
111
112        try:
113            self.compute_fluxes_ext()
114        except:
115            self.compute_fluxes_python()
116 
117
118
119    def compute_fluxes_python(self):
120        """Compute all fluxes and the timestep suitable for all volumes
121        in domain.
122
123        Compute total flux for each conserved quantity using "flux_function"
124
125        Fluxes across each edge are scaled by edgelengths and summed up
126        Resulting flux is then scaled by area and stored in
127        domain.explicit_update
128
129        The maximal allowable speed computed by the flux_function
130        for each volume
131        is converted to a timestep that must not be exceeded. The minimum of
132        those is computed as the next overall timestep.
133
134        Post conditions:
135        domain.explicit_update is reset to computed flux values
136        domain.timestep is set to the largest step satisfying all volumes.
137        """
138
139        import sys
140        from Numeric import zeros, Float
141        from anuga.config import max_timestep
142
143        N = len(self)
144
145        neighbours = self.neighbours
146        neighbour_edges = self.neighbour_edges
147        normals = self.normals
148
149        areas = self.areas
150        radii = self.radii
151        edgelengths = self.edgelengths
152
153        timestep = max_timestep #FIXME: Get rid of this
154
155        #Shortcuts
156        Stage = self.quantities['stage']
157
158        #Arrays
159        stage = Stage.edge_values
160
161        stage_bdry = Stage.boundary_values
162
163        flux = zeros(1, Float) #Work array for summing up fluxes
164
165        #Loop
166        for k in range(N):
167            optimal_timestep = float(sys.maxint)
168
169            flux[:] = 0.  #Reset work array
170            for i in range(3):
171                #Quantities inside volume facing neighbour i
172                ql = stage[k, i]
173
174                #Quantities at neighbour on nearest face
175                n = neighbours[k,i]
176                if n < 0:
177                    m = -n-1 #Convert neg flag to index
178                    qr = stage_bdry[m]
179                else:
180                    m = neighbour_edges[k,i]
181                    qr = stage[n, m]
182
183
184                #Outward pointing normal vector
185                normal = normals[k, 2*i:2*i+2]
186
187                #Flux computation using provided function
188                edgeflux, max_speed = self.flux_function(normal, ql, qr)
189                flux -= edgeflux * edgelengths[k,i]
190
191                #Update optimal_timestep
192                if  self.tri_full_flag[k] == 1 :
193                    try:
194                        optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
195                    except ZeroDivisionError:
196                        pass
197
198            #Normalise by area and store for when all conserved
199            #quantities get updated
200            flux /= areas[k]
201            Stage.explicit_update[k] = flux[0]
202
203            timestep = min(timestep, optimal_timestep)
204
205        self.timestep = timestep
206
207
208    def compute_fluxes_ext(self):
209        """Compute all fluxes and the timestep suitable for all volumes
210        in domain.
211
212        Compute total flux for each conserved quantity using "flux_function"
213
214        Fluxes across each edge are scaled by edgelengths and summed up
215        Resulting flux is then scaled by area and stored in
216        domain.explicit_update
217
218        The maximal allowable speed computed by the flux_function
219        for each volume
220        is converted to a timestep that must not be exceeded. The minimum of
221        those is computed as the next overall timestep.
222
223        Post conditions:
224        domain.explicit_update is reset to computed flux values
225        domain.timestep is set to the largest step satisfying all volumes.
226        """
227
228        import sys
229        from Numeric import zeros, Float
230        from anuga.config import max_timestep
231
232        import weave
233        from weave import converters
234
235        N = len(self)
236
237
238        timestep    = zeros( 1, Float);
239        timestep[0] = float(max_timestep) #FIXME: Get rid of this
240
241        #Shortcuts
242        Stage = self.quantities['stage']
243
244        #Arrays
245        neighbours      = self.neighbours
246        neighbour_edges = self.neighbour_edges
247        normals         = self.normals
248        areas           = self.areas
249        radii           = self.radii
250        edgelengths     = self.edgelengths
251        tri_full_flag   = self.tri_full_flag
252
253        stage_edge      = Stage.edge_values
254        stage_bdry      = Stage.boundary_values
255        stage_update    = Stage.explicit_update
256
257        huge_timestep = float(sys.maxint)
258
259        v = self.velocity
260
261        from advection_ext import compute_fluxes
262               
263        compute_fluxes(stage_edge,stage_bdry,stage_update,
264                       neighbours,neighbour_edges,normals,
265                       areas,radii,edgelengths,
266                       tri_full_flag,
267                       huge_timestep,timestep,v)                         
268
269        self.timestep = timestep
270
271
272    def evolve(self,
273               yieldstep = None,
274               finaltime = None,
275               duration = None,
276               skip_initial_step = False):
277
278        """Specialisation of basic evolve method from parent class
279        """
280
281        #Call basic machinery from parent class
282        for t in Generic_domain.evolve(self,
283                                       yieldstep=yieldstep,
284                                       finaltime=finaltime,
285                                       duration=duration,
286                                       skip_initial_step=skip_initial_step):
287
288            #Pass control on to outer loop for more specific actions
289            yield(t)
Note: See TracBrowser for help on using the repository browser.