source: branches/source_numpy_conversion/anuga/advection/advection.py @ 7177

Last change on this file since 7177 was 5908, checked in by rwilson, 16 years ago

NumPy? conversion.

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