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
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
[1363]19Geoscience Australia, 2004
[195]20"""
21
[1556]22
[4796]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
[1556]31
32
[4793]33from anuga.abstract_2d_finite_volumes.domain import *
[4794]34Generic_domain = Domain # Rename
[195]35
36class Domain(Generic_domain):
37
[2813]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                 ):
[195]51
[1556]52        conserved_quantities = ['stage']
53        other_quantities = []
[2813]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)
[195]67
[1556]68
[195]69        if velocity is None:
70            self.velocity = [1,0]
71        else:
72            self.velocity = velocity
73
[1363]74        #Only first is implemented for advection
75        self.default_order = self.order = 1
[195]76
[271]77        self.smooth = True
[195]78
79    def check_integrity(self):
80        Generic_domain.check_integrity(self)
81
[773]82        msg = 'Conserved quantity must be "stage"'
83        assert self.conserved_quantities[0] == 'stage', msg
[195]84
[1363]85
[195]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.
[1363]89
[195]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        """
[1363]95
[195]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
[1363]106
[195]107        max_speed = abs(normal_velocity)
[1363]108        return flux, max_speed
[195]109
[1556]110    def compute_fluxes(self):
[1363]111
[1575]112        try:
[4964]113            self.compute_fluxes_ext()
[1575]114        except:
115            self.compute_fluxes_python()
[4964]116 
[1575]117
118
[1556]119    def compute_fluxes_python(self):
[195]120        """Compute all fluxes and the timestep suitable for all volumes
121        in domain.
[1363]122
[195]123        Compute total flux for each conserved quantity using "flux_function"
[1363]124
[195]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
[1363]136        domain.timestep is set to the largest step satisfying all volumes.
[195]137        """
138
139        import sys
140        from Numeric import zeros, Float
[3514]141        from anuga.config import max_timestep
[195]142
[3928]143        N = len(self)
[1363]144
[195]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
[1363]152
[195]153        timestep = max_timestep #FIXME: Get rid of this
154
155        #Shortcuts
[773]156        Stage = self.quantities['stage']
[195]157
158        #Arrays
[773]159        stage = Stage.edge_values
[195]160
[773]161        stage_bdry = Stage.boundary_values
[1363]162
[195]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
[773]172                ql = stage[k, i]
[195]173
174                #Quantities at neighbour on nearest face
[1363]175                n = neighbours[k,i]
[195]176                if n < 0:
177                    m = -n-1 #Convert neg flag to index
[773]178                    qr = stage_bdry[m]
[1363]179                else:
[195]180                    m = neighbour_edges[k,i]
[773]181                    qr = stage[n, m]
[195]182
[1363]183
184                #Outward pointing normal vector
[195]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]
[1363]190
[195]191                #Update optimal_timestep
[3167]192                if  self.tri_full_flag[k] == 1 :
[3021]193                    try:
194                        optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
195                    except ZeroDivisionError:
196                        pass
[195]197
198            #Normalise by area and store for when all conserved
199            #quantities get updated
200            flux /= areas[k]
[773]201            Stage.explicit_update[k] = flux[0]
[1363]202
[195]203            timestep = min(timestep, optimal_timestep)
204
[1363]205        self.timestep = timestep
[195]206
[4964]207
208    def compute_fluxes_ext(self):
[1556]209        """Compute all fluxes and the timestep suitable for all volumes
210        in domain.
[271]211
[1556]212        Compute total flux for each conserved quantity using "flux_function"
[1363]213
[1556]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
[3514]230        from anuga.config import max_timestep
[1556]231
232        import weave
233        from weave import converters
234
[3928]235        N = len(self)
[1556]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
[3021]251        tri_full_flag   = self.tri_full_flag
[1556]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
[4964]259        v = self.velocity
[1556]260
[4964]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)                         
[1556]268
[4964]269        self.timestep = timestep
[1556]270
271
[2494]272    def evolve(self,
273               yieldstep = None,
274               finaltime = None,
[2813]275               duration = None,
[2494]276               skip_initial_step = False):
[2813]277
[271]278        """Specialisation of basic evolve method from parent class
279        """
[1363]280
[271]281        #Call basic machinery from parent class
[2494]282        for t in Generic_domain.evolve(self,
283                                       yieldstep=yieldstep,
284                                       finaltime=finaltime,
285                                       duration=duration,
286                                       skip_initial_step=skip_initial_step):
[2050]287
[1363]288            #Pass control on to outer loop for more specific actions
[271]289            yield(t)
Note: See TracBrowser for help on using the repository browser.