source: anuga_work/development/pyvolution-1d/quantity.py @ 3929

Last change on this file since 3929 was 3510, checked in by jakeman, 19 years ago

Files now contain inmplementation of method in which advection terms and
pressure terms are split. problems are present.

File size: 29.0 KB
Line 
1"""Class Quantity - Implements values at each 1d element
2
3To create:
4
5   Quantity(domain, vertex_values)
6
7   domain: Associated domain structure. Required.
8
9   vertex_values: N x 2 array of values at each vertex for each element.
10                  Default None
11
12   If vertex_values are None Create array of zeros compatible with domain.
13   Otherwise check that it is compatible with dimenions of domain.
14   Otherwise raise an exception
15"""
16
17
18class Quantity:
19
20    def __init__(self, domain, vertex_values=None):
21
22        from domain import Domain
23        from Numeric import array, zeros, Float
24
25        msg = 'First argument in Quantity.__init__ '
26        msg += 'must be of class Domain (or a subclass thereof)'
27        assert isinstance(domain, Domain), msg
28
29        if vertex_values is None:
30            N = domain.number_of_elements
31            self.vertex_values = zeros((N, 2), Float)
32        else:
33            self.vertex_values = array(vertex_values, Float)
34
35            N, V = self.vertex_values.shape
36            assert V == 2,\
37                   'Two vertex values per element must be specified'
38
39
40            msg = 'Number of vertex values (%d) must be consistent with'\
41                  %N
42            msg += 'number of elements in specified domain (%d).'\
43                   %domain.number_of_elements
44
45            assert N == domain.number_of_elements, msg
46
47        self.domain = domain
48
49        #Allocate space for other quantities
50        self.centroid_values = zeros(N, Float)
51        #self.edge_values = zeros((N, 2), Float)
52        #edge values are values of the ends of each interval
53     
54        #Intialise centroid values
55        self.interpolate()
56
57    #Methods for operator overloading
58    def __len__(self):
59        return self.centroid_values.shape[0]
60   
61    def interpolate(self):
62        """Compute interpolated values at centroid
63        Pre-condition: vertex_values have been set
64        """
65
66        N = self.vertex_values.shape[0]
67        for i in range(N):
68            v0 = self.vertex_values[i, 0]
69            v1 = self.vertex_values[i, 1]
70
71            self.centroid_values[i] = (v0 + v1)/2
72
73    def set_values(self, X, location='vertices'):
74        """Set values for quantity
75
76        X: Compatible list, Numeric array (see below), constant or function
77        location: Where values are to be stored.
78                  Permissible options are: vertices, centroid
79                  Default is "vertices"
80
81        In case of location == 'centroid' the dimension values must
82        be a list of a Numerical array of length N, N being the number
83        of elements in the mesh. Otherwise it must be of dimension Nx3
84
85        The values will be stored in elements following their
86        internal ordering.
87
88        If values are described a function, it will be evaluated at specified points
89
90        If selected location is vertices, values for centroid and edges
91        will be assigned interpolated values.
92        In any other case, only values for the specified locations
93        will be assigned and the others will be left undefined.
94        """
95
96        if location not in ['vertices', 'centroids']:#, 'edges']:
97            msg = 'Invalid location: %s, (possible choices vertices, centroids)' %location
98            raise msg
99
100        if X is None:
101            msg = 'Given values are None'
102            raise msg
103
104        import types
105
106        if callable(X):
107            #Use function specific method
108            self.set_function_values(X, location)
109        elif type(X) in [types.FloatType, types.IntType, types.LongType]:
110            if location == 'centroids':
111                self.centroid_values[:] = X
112            else:
113                self.vertex_values[:] = X
114
115        else:
116            #Use array specific method
117            self.set_array_values(X, location)
118
119        if location == 'vertices':
120            #Intialise centroid and edge values
121            self.interpolate()
122
123
124
125
126    def set_function_values(self, f, location='vertices'):
127        """Set values for quantity using specified function
128
129        f: x -> z Function where x and z are arrays
130        location: Where values are to be stored.
131                  Permissible options are: vertices, centroid
132                  Default is "vertices"
133        """
134       
135        if location == 'centroids':
136           
137            P = self.domain.centroids
138            self.set_values(f(P), location)
139        else:
140            #Vertices
141            P = self.domain.get_vertices()
142           
143            for i in range(2):
144                self.vertex_values[:,i] = f(P[:,i])       
145
146    def set_array_values(self, values, location='vertices'):
147        """Set values for quantity
148
149        values: Numeric array
150        location: Where values are to be stored.
151                  Permissible options are: vertices, centroid, edges
152                  Default is "vertices"
153
154        In case of location == 'centroid' the dimension values must
155        be a list of a Numerical array of length N, N being the number
156        of elements in the mesh. Otherwise it must be of dimension Nx2
157
158        The values will be stored in elements following their
159        internal ordering.
160
161        If selected location is vertices, values for centroid
162        will be assigned interpolated values.
163        In any other case, only values for the specified locations
164        will be assigned and the others will be left undefined.
165        """
166
167        from Numeric import array, Float
168
169        values = array(values).astype(Float)
170
171        N = self.centroid_values.shape[0]
172
173        msg = 'Number of values must match number of elements'
174        assert values.shape[0] == N, msg
175
176        if location == 'centroids':
177            assert len(values.shape) == 1, 'Values array must be 1d'
178            self.centroid_values = values
179        #elif location == 'edges':
180        #    assert len(values.shape) == 2, 'Values array must be 2d'
181        #    msg = 'Array must be N x 2'
182        #    self.edge_values = values
183        else:
184            assert len(values.shape) == 2, 'Values array must be 2d'
185            msg = 'Array must be N x 2'
186            assert values.shape[1] == 2, msg
187
188            self.vertex_values = values
189
190
191    def get_values(self, location='vertices', indices = None):
192        """get values for quantity
193
194        return X, Compatible list, Numeric array (see below)
195        location: Where values are to be stored.
196                  Permissible options are: vertices, edges, centroid
197                  and unique vertices. Default is 'vertices'
198
199        In case of location == 'centroids' the dimension values must
200        be a list of a Numerical array of length N, N being the number
201        of elements. Otherwise it must be of dimension Nx3
202
203        The returned values with be a list the length of indices
204        (N if indices = None).  Each value will be a list of the three
205        vertex values for this quantity.
206
207        Indices is the set of element ids that the operation applies to.
208
209        """
210        from Numeric import take
211
212        #if location not in ['vertices', 'centroids', 'edges', 'unique vertices']:
213        if location not in ['vertices', 'centroids', 'unique vertices']:
214            msg = 'Invalid location: %s' %location
215            raise msg
216
217        import types, Numeric
218        assert type(indices) in [types.ListType, types.NoneType,
219                                 Numeric.ArrayType],\
220                                 'Indices must be a list or None'
221
222        if location == 'centroids':
223            if (indices ==  None):
224                indices = range(len(self))
225            return take(self.centroid_values,indices)
226        #elif location == 'edges':
227        #    if (indices ==  None):
228        #        indices = range(len(self))
229        #    return take(self.edge_values,indices)
230        elif location == 'unique vertices':
231            if (indices ==  None):
232                indices=range(self.domain.coordinates.shape[0])
233            vert_values = []
234            #Go through list of unique vertices
235            for unique_vert_id in indices:
236                triangles = self.domain.vertexlist[unique_vert_id]
237
238                #In case there are unused points
239                if triangles is None:
240                    msg = 'Unique vertex not associated with triangles'
241                    raise msg
242
243                # Go through all triangle, vertex pairs
244                # Average the values
245                sum = 0
246                for triangle_id, vertex_id in triangles:
247                    sum += self.vertex_values[triangle_id, vertex_id]
248                vert_values.append(sum/len(triangles))
249            return Numeric.array(vert_values)
250        else:
251            if (indices ==  None):
252                indices = range(len(self))
253            return take(self.vertex_values,indices)
254
255    #Method for outputting model results
256    #FIXME: Split up into geometric and numeric stuff.
257    #FIXME: Geometric (X,Y,V) should live in mesh.py
258    #FIXME: STill remember to move XY to mesh
259    def get_vertex_values(self,
260                          #xy=True,
261                          x=True,
262                          smooth = None,
263                          precision = None,
264                          reduction = None):
265        """Return vertex values like an OBJ format
266
267        The vertex values are returned as one sequence in the 1D float array A.
268        If requested the coordinates will be returned in 1D arrays X and Y.
269
270        The connectivity is represented as an integer array, V, of dimension
271        M x 3, where M is the number of volumes. Each row has three indices
272        into the X, Y, A arrays defining the triangle.
273
274        if smooth is True, vertex values corresponding to one common
275        coordinate set will be smoothed according to the given
276        reduction operator. In this case vertex coordinates will be
277        de-duplicated.
278
279        If no smoothings is required, vertex coordinates and values will
280        be aggregated as a concatenation of values at
281        vertices 0, vertices 1 and vertices 2
282
283
284        Calling convention
285        if xy is True:
286           X,Y,A,V = get_vertex_values
287        else:
288           A,V = get_vertex_values
289
290        """
291
292        from Numeric import concatenate, zeros, Float, Int, array, reshape
293
294
295        if smooth is None:
296            smooth = self.domain.smooth
297
298        if precision is None:
299            precision = Float
300
301        if reduction is None:
302            reduction = self.domain.reduction
303
304        #Create connectivity
305
306        if smooth == True:
307
308            V = self.domain.get_vertices()
309            N = len(self.domain.vertexlist)
310            #N = len(self.domain.vertices)
311            A = zeros(N, precision)
312
313            #Smoothing loop
314            for k in range(N):
315                L = self.domain.vertexlist[k]
316                #L = self.domain.vertices[k]
317
318                #Go through all triangle, vertex pairs
319                #contributing to vertex k and register vertex value
320
321                if L is None: continue #In case there are unused points
322
323                contributions = []
324                for volume_id, vertex_id in L:
325                    v = self.vertex_values[volume_id, vertex_id]
326                    contributions.append(v)
327
328                A[k] = reduction(contributions)
329
330
331            #if xy is True:
332            if x is True:
333                 #X = self.domain.coordinates[:,0].astype(precision)
334                 X = self.domain.coordinates[:].astype(precision)
335                 #Y = self.domain.coordinates[:,1].astype(precision)
336
337                 #return X, Y, A, V
338                 return X, A, V
339           
340            #else:
341            return A, V
342        else:
343            #Don't smooth
344            #obj machinery moved to general_mesh
345
346            # Create a V like [[0 1 2], [3 4 5]....[3*m-2 3*m-1 3*m]]
347            # These vert_id's will relate to the verts created below
348            #m = len(self.domain)  #Number of volumes
349            #M = 3*m        #Total number of unique vertices
350            #V = reshape(array(range(M)).astype(Int), (m,3))
351
352            #V = self.domain.get_triangles(obj=True)
353            V = self.domain.get_vertices
354            #FIXME use get_vertices, when ready
355
356            A = self.vertex_values.flat
357
358            #Do vertex coordinates
359            #if xy is True:
360            if x is True:
361                C = self.domain.get_vertex_coordinates()
362
363                X = C[:,0:6:2].copy()
364                Y = C[:,1:6:2].copy()
365
366                return X.flat, Y.flat, A, V
367            else:
368                return A, V
369
370
371class Conserved_quantity(Quantity):
372    """Class conserved quantity adds to Quantity:
373
374    storage and method for updating, and
375    methods for extrapolation from centropid to vertices inluding
376    gradients and limiters
377    """
378
379    def __init__(self, domain, vertex_values=None):
380        Quantity.__init__(self, domain, vertex_values)
381
382        from Numeric import zeros, Float
383       
384        #Allocate space for boundary values
385        #L = len(domain.boundary)
386        self.boundary_values = zeros(2, Float) #assumes no parrellism
387
388        #Allocate space for updates of conserved quantities by
389        #flux calculations and forcing functions
390       
391        N = domain.number_of_elements
392        self.explicit_update = zeros(N, Float )
393        self.semi_implicit_update = zeros(N, Float )
394
395        self.gradients = zeros(N, Float)
396        self.qmax = zeros(self.centroid_values.shape, Float)
397        self.qmin = zeros(self.centroid_values.shape, Float)
398
399        self.beta = domain.beta
400
401
402    def update(self, timestep):
403        """Update centroid values based on values stored in
404        explicit_update and semi_implicit_update as well as given timestep
405        """
406
407        from Numeric import sum, equal, ones, Float
408
409        N = self.centroid_values.shape[0]
410
411        #Explicit updates
412        self.centroid_values += timestep*self.explicit_update
413
414        #SECOND ORDER RUNGE_KUTTA
415        #Re-evaluate source term with updated centroid values
416        #and update conserved quantities accordingly
417        """
418        self.explicit_update = zeros(N, Float)
419        self.domain.compute_forcing_terms()
420        self.centroid_values += 0.5*timestep*(explicit_update
421        """
422       
423##         #Semi implicit updates
424##         denominator = ones(N, Float)-timestep*self.semi_implicit_update
425
426##         if sum(equal(denominator, 0.0)) > 0.0:
427##             msg = 'Zero division in semi implicit update. Call Stephen :-)'
428##             raise msg
429##         else:
430##             #Update conserved_quantities from semi implicit updates
431##             self.centroid_values /= denominator
432
433
434    def compute_gradients(self):
435        """Compute gradients of piecewise linear function defined by centroids of
436        neighbouring volumes.
437        """
438
439
440        from Numeric import array, zeros, Float
441
442        N = self.centroid_values.shape[0]
443
444
445        G = self.gradients
446        Q = self.centroid_values
447        X = self.domain.centroids
448
449        for k in range(N):
450
451            # first and last elements have boundaries
452
453            if k == 0:
454
455                #Get data
456                k0 = k
457                k1 = k+1
458
459                q0 = Q[k0]
460                q1 = Q[k1]
461
462                x0 = X[k0] #V0 centroid
463                x1 = X[k1] #V1 centroid
464
465                #Gradient
466                G[k] = (q1 - q0)/(x1 - x0)
467
468            elif k == N-1:
469
470                #Get data
471                k0 = k
472                k1 = k-1
473
474                q0 = Q[k0]
475                q1 = Q[k1]
476
477                x0 = X[k0] #V0 centroid
478                x1 = X[k1] #V1 centroid
479
480                #Gradient
481                G[k] = (q1 - q0)/(x1 - x0)
482
483            else:
484                #Interior Volume (2 neighbours)
485
486                #Get data
487                k0 = k-1
488                k2 = k+1
489
490                q0 = Q[k0]
491                q1 = Q[k]
492                q2 = Q[k2]
493
494                x0 = X[k0] #V0 centroid
495                x1 = X[k]  #V1 centroid (Self)
496                x2 = X[k2] #V2 centroid
497
498                #Gradient
499                #G[k] = (q2-q0)/(x2-x0)
500                G[k] = ((q0-q1)/(x0-x1)*(x2-x1) - (q2-q1)/(x2-x1)*(x0-x1))/(x2-x0)
501
502
503    def compute_minmod_gradients(self):
504        """Compute gradients of piecewise linear function defined by centroids of
505        neighbouring volumes.
506        """
507
508        from Numeric import array, zeros, Float,sign
509       
510        def xmin(a,b):
511            return 0.5*(sign(a)+sign(b))*min(abs(a),abs(b))
512
513        def xmic(t,a,b):
514            return xmin(t*xmin(a,b), 0.50*(a+b) )
515
516
517
518        N = self.centroid_values.shape[0]
519
520
521        G = self.gradients
522        Q = self.centroid_values
523        X = self.domain.centroids
524
525        for k in range(N):
526
527            # first and last elements have boundaries
528
529            if k == 0:
530
531                #Get data
532                k0 = k
533                k1 = k+1
534
535                q0 = Q[k0]
536                q1 = Q[k1]
537
538                x0 = X[k0] #V0 centroid
539                x1 = X[k1] #V1 centroid
540
541                #Gradient
542                G[k] = (q1 - q0)/(x1 - x0)
543
544            elif k == N-1:
545
546                #Get data
547                k0 = k
548                k1 = k-1
549
550                q0 = Q[k0]
551                q1 = Q[k1]
552
553                x0 = X[k0] #V0 centroid
554                x1 = X[k1] #V1 centroid
555
556                #Gradient
557                G[k] = (q1 - q0)/(x1 - x0)
558
559            else:
560                #Interior Volume (2 neighbours)
561
562                #Get data
563                k0 = k-1
564                k2 = k+1
565
566                q0 = Q[k0]
567                q1 = Q[k]
568                q2 = Q[k2]
569
570                x0 = X[k0] #V0 centroid
571                x1 = X[k]  #V1 centroid (Self)
572                x2 = X[k2] #V2 centroid
573
574                # assuming uniform grid
575                d1 = (q1 - q0)/(x1-x0)
576                d2 = (q2 - q1)/(x2-x1)
577
578                #Gradient
579                #G[k] = (d1+d2)*0.5
580                #G[k] = (d1*(x2-x1) - d2*(x0-x1))/(x2-x0)               
581                G[k] = xmic( self.domain.beta, d1, d2 )
582       
583
584    def extrapolate_first_order(self):
585        """Extrapolate conserved quantities from centroid to
586        vertices for each volume using
587        first order scheme.
588        """
589
590        qc = self.centroid_values
591        qv = self.vertex_values
592
593        for i in range(2):
594            qv[:,i] = qc
595
596
597    def extrapolate_second_order(self):
598        """Extrapolate conserved quantities from centroid to
599        vertices for each volume using
600        second order scheme.
601        """
602
603        Z = self.gradients
604        #print "gradients 1",Z
605       
606        self.compute_minmod_gradients()
607        #print "gradients 2", Z
608
609        G = self.gradients
610        V = self.domain.vertices
611        qc = self.centroid_values
612        qv = self.vertex_values       
613       
614        #Check each triangle
615        for k in range(self.domain.number_of_elements):
616            #Centroid coordinates
617            x = self.domain.centroids[k]
618
619            #vertex coordinates
620            x0, x1 = V[k,:]
621
622            #Extrapolate
623            qv[k,0] = qc[k] + G[k]*(x0-x)
624            qv[k,1] = qc[k] + G[k]*(x1-x)
625
626    """    def limit(self):
627        Limit slopes for each volume to eliminate artificial variance
628        introduced by e.g. second order extrapolator
629
630        This is an unsophisticated limiter as it does not take into
631        account dependencies among quantities.
632
633        precondition:
634        vertex values are estimated from gradient
635        postcondition:
636        vertex values are updated
637       
638        print "in Q.limit"
639        from Numeric import zeros, Float
640
641        N = self.domain.number_of_elements
642        beta = self.beta
643
644        qc = self.centroid_values
645        qv = self.vertex_values
646
647        #Find min and max of this and neighbour's centroid values
648        qmax = self.qmax
649        qmin = self.qmin
650
651        for k in range(N):
652            qmax[k] = qmin[k] = qc[k]
653
654            for i in [-1,1]:
655                n = k+i
656                if (n >= 0) & (n <= N-1):
657                    qn = qc[n] #Neighbour's centroid value
658
659                    qmin[k] = min(qmin[k], qn)
660                    qmax[k] = max(qmax[k], qn)
661
662        #Phi limiter
663        for k in range(N):
664
665            #Diffences between centroids and maxima/minima
666            dqmax = qmax[k] - qc[k]
667            dqmin = qmin[k] - qc[k]
668
669            #Deltas between vertex and centroid values
670            dq = [0.0, 0.0]
671            for i in range(2):
672                dq[i] = qv[k,i] - qc[k]
673
674            #Find the gradient limiter (phi) across vertices
675            phi = 1.0
676            for i in range(2):
677                r = 1.0
678                if (dq[i] > 0): r = dqmax/dq[i]
679                if (dq[i] < 0): r = dqmin/dq[i]
680
681                phi = min( min(r*beta, 1), phi )
682
683            #Then update using phi limiter
684            for i in range(2):
685                qv[k,i] = qc[k] + phi*dq[i]
686    """
687
688    """def limit(self):
689        Limit slopes for each volume to eliminate artificial variance
690        introduced by e.g. second order extrapolator
691
692        This is an unsophisticated limiter as it does not take into
693        account dependencies among quantities.
694
695        precondition:
696        vertex values are estimated from gradient
697        postcondition:
698        vertex values are updated
699       
700        from Numeric import zeros, Float
701
702        N = self.domain.number_of_elements
703        beta = self.beta
704        #beta = 0.8
705
706        qc = self.centroid_values
707        qv = self.vertex_values
708
709        #Find min and max of this and neighbour's centroid values
710        qmax = self.qmax
711        qmin = self.qmin
712
713        for k in range(N):
714            qmax[k] = qmin[k] = qc[k]
715            for i in range(2):
716                n = self.domain.neighbours[k,i]
717                if n >= 0:
718                    qn = qc[n] #Neighbour's centroid value
719
720                    qmin[k] = min(qmin[k], qn)
721                    qmax[k] = max(qmax[k], qn)
722
723
724        #Diffences between centroids and maxima/minima
725        dqmax = qmax - qc
726        dqmin = qmin - qc
727
728        #Deltas between vertex and centroid values
729        dq = zeros(qv.shape, Float)
730        for i in range(2):
731            dq[:,i] = qv[:,i] - qc
732
733        #Phi limiter
734        for k in range(N):
735
736            #Find the gradient limiter (phi) across vertices
737            phi = 1.0
738            for i in range(2):
739                r = 1.0
740                if (dq[k,i] > 0): r = dqmax[k]/dq[k,i]
741                if (dq[k,i] < 0): r = dqmin[k]/dq[k,i]
742
743                phi = min( min(r*beta, 1), phi )
744
745            #Then update using phi limiter
746            for i in range(2):
747                qv[k,i] = qc[k] + phi*dq[k,i]
748
749    """
750   
751   
752    def limit(self):
753        """Limit slopes for each volume to eliminate artificial variance
754         introduced by e.g. second order extrapolator
755         
756        This is an unsophisticated limiter as it does not take into
757        account dependencies among quantities.
758
759        precondition:
760        vertex values are estimated from gradient
761        postcondition:
762        vertex values are updated
763
764        """
765        import sys
766        from Numeric import zeros, Float
767        from util import minmod, minmod_kurganov, maxmod, vanleer
768
769        N = self.domain.number_of_elements
770        limiter = self.domain.limiter
771        limiter_type = self.domain.limiter_type
772           
773        qc = self.centroid_values
774        qv = self.vertex_values
775
776        #Find min and max of this and neighbour's centroid values
777        beta_p = zeros(N,Float)
778        beta_m = zeros(N,Float)
779        beta_x = zeros(N,Float)
780        C = self.domain.centroids
781        X = self.domain.vertices
782
783        for k in range(N):
784       
785            n0 = self.domain.neighbours[k,0]
786            n1 = self.domain.neighbours[k,1]
787            if limiter_type == "slope":
788                if ( n0 >= 0) & (n1 >= 0):
789                    #SLOPE DERIVATIVE LIMIT
790                    beta_p[k] = (qc[k]-qc[k-1])/(C[k]-C[k-1])
791                    beta_m[k] = (qc[k+1]-qc[k])/(C[k+1]-C[k])
792                    beta_x[k] = (qc[k+1]-qc[k-1])/(C[k+1]-C[k-1])
793            elif limiter_type == "flux":
794                if (n0 >= 0) & (n1 >= 0):
795                    # Check denominator not zero
796                    if (qc[k+1]-qc[k]) == 0.0:
797                        beta_p[k] = float(sys.maxint)
798                        beta_m[k] = float(sys.maxint)
799                    else:
800                        #STEVE LIMIT
801                        beta_p[k] = (qc[k]-qc[k-1])/(qc[k+1]-qc[k])
802                        beta_m[k] = (qc[k+2]-qc[k+1])/(qc[k+1]-qc[k])
803
804        #Deltas between vertex and centroid values
805        dq = zeros(qv.shape, Float)
806        for i in range(2):
807            dq[:,i] =self.domain.vertices[:,i]-self.domain.centroids
808           
809        #Phi limiter
810        for k in range(N):
811            if limiter_type == "slope":
812                if limiter == "minmod":
813                    phi = minmod(beta_p[k],beta_m[k])
814
815                elif limiter == "minmod_kurganov":
816                    # Also known as monotonized central difference limiter
817                    # if theta = 2.0
818                    theta = 2.0 
819                    phi = minmod_kurganov(theta*beta_p[k],theta*beta_m[k],beta_x[k])
820                elif limiter == "superbee":
821                    slope1 = minmod(beta_m[k],2.0*beta_p[k])
822                    slope2 = minmod(2.0*beta_m[k],beta_p[k])
823                    phi = maxmod(slope1,slope2)
824                    #phi = max(0.0,min(1.0,2.0*beta_m[k]),min(2.0,beta_m[k]))+max(0.0,min(1.0,2.0*beta_p[k]),min(2.0,beta_p[k]))-1.0
825
826                elif limiter == "vanleer":
827                    phi = vanleer(beta_p[k],beta_m[k])
828
829
830                elif limiter == "muscl":
831
832                    #MINMOD
833                    #phi = minmod(1.0,beta_m[k])
834                    #SUPERBEE
835                    #phi = max(0.0,min(2.0*beta_m[k],1.0),min(beta_m[k],2.0))
836                    #VAN LEER
837                    phi = (beta_m[k]+abs(beta_m[k]))/(1.0+abs(beta_m[k]))
838                   
839                for i in range(2):
840                    qv[k,i] = qc[k] + phi*dq[k,i]
841               
842            elif limiter_type == "flux":
843                phi = 0.0
844                if limiter == "flux_minmod":
845                    #FLUX MINMOD
846                    phi = minmod_kurganov(1.0,beta_m[k],beta_p[k])
847                elif limiter == "flux_superbee":
848                    #FLUX SUPERBEE
849                    phi = max(0.0,min(1.0,2.0*beta_m[k]),min(2.0,beta_m[k]))+max(0.0,min(1.0,2.0*beta_p[k]),min(2.0,beta_p[k]))-1.0
850                elif limiter == "flux_muscl":
851                    #FLUX MUSCL
852                    phi = max(0.0,min(2.0,2.0*beta_m[k],2.0*beta_p[k],0.5*(beta_m[k]+beta_p[k])))
853                elif limiter == "flux_vanleer":
854                    #FLUX VAN LEER
855                    phi = (beta_m[k]+abs(beta_m[k]))/(1.0+abs(beta_m[k]))+(beta_p[k]+abs(beta_p[k]))/(1.0+abs(beta_p[k]))-1.0
856
857                #Then update using phi limiter
858                n = self.domain.neighbours[k,1]
859                if n>=0:
860                    #qv[k,0] = qc[k] - 0.5*phi*(qc[k+1]-qc[k])
861                    #qv[k,1] = qc[k] + 0.5*phi*(qc[k+1]-qc[k])
862                    qv[k,0] = qc[k] + 0.5*phi*(qv[k,0]-qc[k])
863                    qv[k,1] = qc[k] + 0.5*phi*(qv[k,1]-qc[k])
864                else:
865                    qv[k,i] = qc[k]
866                   
867           
868def newLinePlot(title='Simple Plot'):
869    import Gnuplot
870    g = Gnuplot.Gnuplot()
871    g.title(title)
872    g('set data style linespoints') 
873    g.xlabel('x')
874    g.ylabel('y')
875    return g
876
877def linePlot(g,x,y):
878    import Gnuplot
879    g.plot(Gnuplot.PlotItems.Data(x.flat,y.flat))
880
881
882
883
884
885if __name__ == "__main__":
886    from domain import Domain
887    from Numeric import arange
888   
889    points1 = [0.0, 1.0, 2.0, 3.0]
890    vertex_values = [[1.0,2.0],[4.0,5.0],[-1.0,2.0]]
891
892    D1 = Domain(points1)
893
894    Q1 = Conserved_quantity(D1, vertex_values)
895
896    print Q1.vertex_values
897    print Q1.centroid_values
898
899    new_vertex_values = [[2.0,1.0],[3.0,4.0],[-2.0,4.0]]
900
901    Q1.set_values(new_vertex_values)
902
903    print Q1.vertex_values
904    print Q1.centroid_values
905
906    new_centroid_values = [20,30,40]
907    Q1.set_values(new_centroid_values,'centroids')
908
909    print Q1.vertex_values
910    print Q1.centroid_values
911
912    class FunClass:
913        def __init__(self,value):
914            self.value = value
915
916        def __call__(self,x):
917            return self.value*(x**2)
918
919
920    fun = FunClass(1.0)
921    Q1.set_values(fun,'vertices')
922
923    print Q1.vertex_values
924    print Q1.centroid_values
925
926    Xc = Q1.domain.vertices
927    Qc = Q1.vertex_values
928    print Xc
929    print Qc
930
931    Qc[1,0] = 3
932
933    Q1.beta = 1.0
934    Q1.extrapolate_second_order()
935    Q1.limit()
936
937    g1 = newLinePlot('plot 1')
938    linePlot(g1,Xc,Qc)
939
940    points2 = arange(10)
941    D2 = Domain(points2)
942
943    Q2 = Conserved_quantity(D2)
944    Q2.set_values(fun,'vertices')
945    Xc = Q2.domain.vertices
946    Qc = Q2.vertex_values
947
948    g2 = newLinePlot('plot 2')
949    linePlot(g2,Xc,Qc)
950
951
952   
953    Q2.extrapolate_second_order()
954    Q2.limit()
955    Xc = Q2.domain.vertices
956    Qc = Q2.vertex_values
957
958    print Q2.centroid_values
959    print Qc
960    raw_input('press_return')
961   
962    g3 = newLinePlot('plot 3')
963    linePlot(g3,Xc,Qc)
964    raw_input('press return')
965
966
967    for i in range(10):
968        fun = FunClass(i/10.0)
969        Q2.set_values(fun,'vertices')
970        Qc = Q2.vertex_values
971        linePlot(g3,Xc,Qc)
972
973    raw_input('press return')
974
Note: See TracBrowser for help on using the repository browser.