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

Last change on this file since 7340 was 7317, checked in by rwilson, 16 years ago

Replaced 'print' statements with log.critical() calls.

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