Changeset 198 for inundation/ga


Ignore:
Timestamp:
Aug 20, 2004, 3:28:34 PM (20 years ago)
Author:
ole
Message:

More work on limiters
Started working on gradients

Location:
inundation/ga/storm_surge/pyvolution
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/pyvolution/config.py

    r195 r198  
    5757
    5858use_extensions = True   #Try to use C-extensions
    59 #use_extensions = False   #Do not use C-extensions
     59use_extensions = False   #Do not use C-extensions
    6060
    6161use_psyco = True  #Use psyco optimisations
  • inundation/ga/storm_surge/pyvolution/mesh.py

    r195 r198  
    201201    def build_neighbour_structure(self):
    202202        """Update all registered triangles to point to their neighbours.
     203       
     204        Also, keep a tally of the number of boundaries for each triangle
    203205
    204206        Postconditions:
     
    297299        if they exist. Otherwise point to the triangle itself.
    298300
    299         Also, keep a tally of the number of boundaries for each triangle
    300 
    301301        The surrogate neighbour structure is useful for computing gradients
    302302        based on centroid values of neighbours.
  • inundation/ga/storm_surge/pyvolution/quantity.py

    r195 r198  
    106106            self.centroid_values /= denominator
    107107
     108    def compute_gradients(self):
     109        """Compute gradients of triangle surfaces defined by centroids of
     110        neighbouring volumes.
     111        If one face is on the boundary, use own centroid as neighbour centroid.
     112        If two or more are on the boundary, fall back to first order scheme.
     113       
     114        Also return minimum and maximum of conserved quantities
     115        """
     116
     117       
     118        from Numeric import array, zeros, Float
     119        from util import gradient
     120
     121        N = self.centroid_values.shape[0]
     122
     123        a = zeros(N, Float)
     124        b = zeros(N, Float)
     125       
     126        for k in range(N):
     127       
     128            number_of_boundaries = self.domain.number_of_boundaries[k]
     129
     130            if number_of_boundaries == 3:                 
     131                #We have zero neighbouring volumes -
     132                #Fall back to first order scheme
     133
     134                pass
     135           
     136            elif number_of_boundaries == 2:
     137                #Special case where we have only one neighbouring volume.
     138
     139                k0 = k  #Self
     140               
     141                #Find index of the one neighbour
     142                for k1 in self.domain.neighbours[k,:]:
     143                    if k1 >= 0:
     144                        break
     145                assert k1 != k0
     146                assert k1 >= 0                     
     147                   
     148                #Get data
     149                q0 = self.centroid_values[k0]
     150                q1 = self.centroid_values[k1]
     151
     152                x0, y0 = self.domain.centroids[k0] #V0 centroid
     153                x1, y1 = self.domain.centroids[k1] #V1 centroid       
     154
     155                #Gradient
     156                det = x0*y1 - x1*y0
     157                if det != 0.0:
     158                    a[k] = (y1*q0 - y0*q1)/det
     159                    b[k] = (x0*q1 - x1*q0)/det
     160
     161            else:
     162                #One or zero missing neighbours
     163                #In case of one boundary - own centroid
     164                #has been inserted as a surrogate for the one
     165                #missing neighbour in neighbour_surrogates
     166
     167                #Get data       
     168                k0 = self.domain.surrogate_neighbours[k,0]
     169                k1 = self.domain.surrogate_neighbours[k,1]
     170                k2 = self.domain.surrogate_neighbours[k,2]
     171
     172                q0 = self.centroid_values[k0]
     173                q1 = self.centroid_values[k1]
     174                q2 = self.centroid_values[k2]                   
     175
     176                x0, y0 = self.domain.centroids[k0] #V0 centroid
     177                x1, y1 = self.domain.centroids[k1] #V1 centroid
     178                x2, y2 = self.domain.centroids[k2] #V2 centroid
     179
     180                #Gradient
     181                a[k], b[k] = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)
     182                                      #array([q0]), array([q1]), array([q2]))
     183       
     184        return a, b
     185       
    108186
    109187    def second_order_limiter(self):
     
    189267            self.first_order_limiter()
    190268        elif order == 2:
     269            a, b = self.compute_gradients()
     270           
    191271            self.second_order_limiter()
    192272        else:
  • inundation/ga/storm_surge/pyvolution/shallow_water.py

    r195 r198  
    267267####################################
    268268# Functions for gradient limiting (distribute_to_vertices_and_edges)
    269 def first_order_limiter(domain):
    270     """First order limiter function, specific to the shallow water wave
    271     equation.
    272    
    273     It will ensure that h (w-z) is always non-negative even in the
    274     presence of steep bed-slopes (see comment in code)
    275     In addition, momemtums get distributed as constant values.
    276 
    277     Precondition:
    278       All quantities defined at centroids and bed elevation defined at
    279       vertices.
    280 
    281     Postcondition
    282       Conserved quantities defined at vertices
     269
     270def protect_against_infinitesimal_heights_centroid(domain):
     271    """Adjust height and momentum at centroid if height is less than
     272    minimum allowed height
    283273    """
    284 
     274   
    285275    #Water levels at centroids
    286276    wc = domain.quantities['level'].centroid_values
     
    296286    ymomc = domain.quantities['ymomentum'].centroid_values       
    297287
    298     #Water levels at vertices
    299     wv = domain.quantities['level'].vertex_values
    300 
    301     #Bed elevations at vertices
    302     zv = domain.quantities['elevation'].vertex_values
    303    
    304288    for k in range(domain.number_of_elements):
    305289        #Protect against infinitesimal heights and high velocities
     
    312296            xmomc[k] = ymomc[k] = 0.0
    313297               
     298
     299   
     300
     301def first_order_limiter(domain):
     302    """First order limiter function, specific to the shallow water wave
     303    equation.
     304   
     305    It will ensure that h (w-z) is always non-negative even in the
     306    presence of steep bed-slopes (see comment in code)
     307    In addition, momemtums get distributed as constant values.
     308
     309    Precondition:
     310      All quantities defined at centroids and bed elevation defined at
     311      vertices.
     312
     313    Postcondition
     314      Conserved quantities defined at vertices
     315    """
     316
     317    #FIXME: Might go elsewhere
     318    protect_against_infinitesimal_heights_centroid(domain)
     319   
     320    #Update conserved quantities using straight first order
     321    for name in domain.conserved_quantities:
     322        Q = domain.quantities[name]
     323        Q.first_order_limiter()
     324
     325       
     326    #Water levels at centroids
     327    wc = domain.quantities['level'].centroid_values
     328
     329    #Bed elevations at centroids
     330    zc = domain.quantities['elevation'].centroid_values
     331
     332    #Water depths at centroids   
     333    hc = wc - zc
     334
     335    #Water levels at vertices
     336    wv = domain.quantities['level'].vertex_values
     337
     338    #Bed elevations at vertices
     339    zv = domain.quantities['elevation'].vertex_values
    314340               
     341    #Water depths at vertices
     342    hv = wv-zv
     343   
     344   
     345    #Computed weighted balance between constant levels and and
     346    #levels parallel to the bed elevation.     
     347    for k in range(domain.number_of_elements):               
    315348               
    316349        #Compute maximal variation in bed elevation
     
    327360        #  wvi = (1-alpha)*(zvi+hc) + alpha*(zc+hc) =
    328361        #  (1-alpha)*zvi + alpha*zc + hc =
    329         #  zvi + hc + alpha*(zc-zvi);
     362        #  zvi + hc + alpha*(zc-zvi)
    330363        #
    331         #where alpha in [0,1] and defined as the ration between hc and
     364        #where alpha in [0,1] and defined as the ratio between hc and
    332365        #the maximal difference from zc to zv0, zv1 and zv2
     366        #
     367        #Mathematically the following can be continued on using hc as
     368        #  wvi =
     369        #  zvi + hc + alpha*(zc+hc-zvi-hc) =
     370        #  zvi + hc + alpha*(hvi-hc)
     371        #since hvi = zc+hc-zvi in the constant case
     372
    333373       
    334374        if z_range > 0.0:
     
    339379        #Update stage
    340380        for i in range(3):
    341             wv[k,i] = zv[k,i] + hc[k] + alpha*(zc[k]-zv[k,i])
    342 
    343     #Update momentum using straight first order
    344     for name in ['xmomentum', 'ymomentum']:
    345         Q = domain.quantities[name]
    346         for i in range(3):
    347             Q.vertex_values[:, i] = Q.centroid_values
     381            #wv[k,i] = zv[k,i] + hc[k] + alpha*(zc[k]-zv[k,i])
     382            wv[k,i] = zv[k,i] + hc[k] + alpha*(hv[k,i]-hc[k])
     383
    348384
    349385       
     
    370406   
    371407    """
     408
     409    #FIXME: Might go elsewhere
     410    protect_against_infinitesimal_heights_centroid(domain)
     411   
     412    #Update conserved quantities using straight second order
     413    for name in domain.conserved_quantities:
     414        Q = domain.quantities[name]
     415        Q.second_order_limiter()
     416
    372417
    373418    #Water levels at centroids
  • inundation/ga/storm_surge/pyvolution/test_quantity.py

    r195 r198  
    145145
    146146
     147    def test_gradient(self):
     148        quantity = Quantity(self.mesh4)
     149
     150        #Set up for a gradient of (1,0)
     151        quantity.set_values([2.0/3, 4.0/3, 8.0/3, 2.0/3],
     152                            location = 'centroids')
     153       
     154        #Gradients
     155        quantity.compute_gradients()
     156
     157        #FIXME:
     158
     159        #HERTIL
     160       
     161        #Gradient of fitted pwl surface   
     162        #a, b = compute_gradient(v2.id)
     163
     164        #assert a == 1.0
     165        #assert b == 0.0
     166
     167
     168        #And now for the second order stuff       
     169        # - the full second order extrapolation
     170        #domain.order = 2
     171        #domain.limiter = dummy_limiter
     172        #distribute_to_vertices_and_edges(domain)       
     173   
     174        #assert v2.conserved_quantities_vertex0 == 0.0
     175        #assert v2.conserved_quantities_vertex1 == 2.0       
     176        #assert v2.conserved_quantities_vertex2 == 2.0       
     177
     178
     179
     180#     def test_second_order_extrapolation2(self):
     181
     182#         initialise_consecutive_datastructure(points=6+4, elements=4)               
     183       
     184#         a = Point (0.0, 0.0)
     185#         b = Point (0.0, 2.0)
     186#         c = Point (2.0, 0.0)
     187#         d = Point (0.0, 4.0)
     188#         e = Point (2.0, 2.0)
     189#         f = Point (4.0, 0.0)
     190
     191#         #Set up for a gradient of (3,1), f(x) = 3x+y
     192#         v1 = Volume(b,a,c,array([2.0+2.0/3,0,0]))       
     193#         v2 = Volume(b,c,e,array([4.0+4.0/3,0,0]))
     194#         v3 = Volume(e,c,f,array([8.0+2.0/3,0,0]))
     195#         v4 = Volume(d,b,e,array([2.0+8.0/3,0,0]))
     196
     197#         #Setup neighbour structure
     198#         domain = Domain([v1,v2,v3,v4])
     199#         domain.precompute()
     200#       domain.check_integrity()
     201       
     202#         #Lets's check first order first, hey
     203#       domain.order = 1
     204#       domain.limiter = dummy_limiter
     205#         distribute_to_vertices_and_edges(domain)             
     206       
     207#         assert allclose(v2.conserved_quantities_vertex0,
     208#                         v2.conserved_quantities_centroid)
     209#         assert allclose(v2.conserved_quantities_vertex1,
     210#                         v2.conserved_quantities_centroid)
     211#         assert allclose(v2.conserved_quantities_vertex2,
     212#                         v2.conserved_quantities_centroid)               
     213
     214
     215#         #Flux across right edge of volume 1
     216#         #Outward pointing normal vector
     217#         from shallow_water import flux_using_stage as flux_function
     218#         normals = Volume.normals
     219       
     220#         normal = Vector.coordinates[normals[1][2]]
     221#         ql = Volume.conserved_quantities_face2[1]
     222#         qr = Volume.conserved_quantities_face1[0]
     223#         fl = array([0.,0.])
     224#         fr = array([0.,0.])
     225#         flux0, max_speed = flux_function(normal, ql, qr, fl, fr)
     226
     227#         #print flux0, max_speed       
     228
     229#         #print
     230#         #print v1.conserved_quantities_face0,\
     231#         #      v2.conserved_quantities_face0,\
     232#         #      v3.conserved_quantities_face0,\
     233#         #      v4.conserved_quantities_face0             
     234#         #print
     235#         #edgelengths = Volume.geometric[:,2:]
     236#         #print
     237#         #print
     238       
     239#         from python_versions import compute_flux
     240#         compute_flux(domain, 100)
     241#         F1 = Volume.explicit_update
     242
     243#         from domain import compute_flux
     244#         compute_flux(domain, 100)
     245#         F2 = Volume.explicit_update       
     246
     247#         assert allclose(F1, F2)
     248       
     249#         #print F1
     250#         #print F2
     251       
     252
     253
     254#         #Gradient of fitted pwl surface   
     255#       a, b = compute_gradient(v2.id) 
     256
     257#         assert abs(a[0] - 3.0) < epsilon
     258#         assert abs(b[0] - 1.0) < epsilon
     259#         #assert qmin[0] == 2.0 + 2.0/3
     260#         #assert qmax[0] == 8.0 + 2.0/3               
     261
     262#         #And now for the second order stuff       
     263#         # - the full second order extrapolation
     264#       domain.order = 2
     265#       domain.limiter = dummy_limiter
     266#         distribute_to_vertices_and_edges(domain)             
     267
     268#         assert allclose(v2.conserved_quantities_vertex0[0], 2.0)
     269#         assert allclose(v2.conserved_quantities_vertex1[0], 6.0)       
     270#         assert allclose(v2.conserved_quantities_vertex2[0], 8.0)
     271
     272
     273
     274
     275#     def test_limiter(self):
     276
     277#         initialise_consecutive_datastructure(points=6+4, elements=4)         
     278       
     279#         a = Point (0.0, 0.0)
     280#         b = Point (0.0, 2.0)
     281#         c = Point (2.0, 0.0)
     282#         d = Point (0.0, 4.0)
     283#         e = Point (2.0, 2.0)
     284#         f = Point (4.0, 0.0)
     285
     286#         #Set up for a gradient of (3,1), f(x) = 3x+y
     287#         v1 = Volume(b,a,c,array([0.0,0,0]))       
     288#         v2 = Volume(b,c,e,array([1.0,0,0]))
     289#         v3 = Volume(e,c,f,array([10.0,0,0]))
     290#         v4 = Volume(d,b,e,array([0.0,0,0]))
     291
     292#         #Setup neighbour structure
     293#         domain = Domain([v1,v2,v3,v4])
     294#         domain.precompute()
     295       
     296#         #Lets's check first order first, hey
     297#       domain.order = 1
     298#       domain.limiter = None
     299#         distribute_to_vertices_and_edges(domain)
     300#         assert allclose(v2.conserved_quantities_vertex0,
     301#                         v2.conserved_quantities_centroid)
     302#         assert allclose(v2.conserved_quantities_vertex1,
     303#                         v2.conserved_quantities_centroid)
     304#         assert allclose(v2.conserved_quantities_vertex2,
     305#                         v2.conserved_quantities_centroid)
     306
     307
     308#         #Gradient of fitted pwl surface
     309#         a, b = compute_gradient(v2.id)
     310       
     311
     312#         assert abs(a[0] - 5.0) < epsilon
     313#         assert abs(b[0]) < epsilon       
     314#         #assert qminr[0] == 0.0
     315#         #assert qmaxr[0] == 10.0
     316       
     317#         #And now for the second order stuff       
     318#         # - the full second order extrapolation
     319#       domain.order = 2       
     320#         distribute_to_vertices_and_edges(domain)
     321
     322
     323#         qmin = qmax = v2.conserved_quantities_centroid
     324
     325#         qmin = minimum(qmin, v1.conserved_quantities_centroid)
     326#         qmax = maximum(qmax, v1.conserved_quantities_centroid)
     327
     328#         qmin = minimum(qmin, v3.conserved_quantities_centroid)
     329#         qmax = maximum(qmax, v3.conserved_quantities_centroid)
     330
     331#         qmin = minimum(qmin, v4.conserved_quantities_centroid)
     332#         qmax = maximum(qmax, v4.conserved_quantities_centroid)                   
     333#         #assert qminr == qmin
     334#         #assert qmaxr == qmax
     335
     336#         assert v2.conserved_quantities_vertex0 <= qmax
     337#         assert v2.conserved_quantities_vertex0 >= qmin
     338#         assert v2.conserved_quantities_vertex1 <= qmax
     339#         assert v2.conserved_quantities_vertex1 >= qmin
     340#         assert v2.conserved_quantities_vertex2 <= qmax
     341#         assert v2.conserved_quantities_vertex2 >= qmin                   
     342
     343
     344#         #Check that volume has been preserved   
     345
     346#         q = v2.conserved_quantities_centroid[0]
     347#         w = (v2.conserved_quantities_vertex0[0] +
     348#              v2.conserved_quantities_vertex1[0] +
     349#              v2.conserved_quantities_vertex2[0])/3
     350
     351#         assert allclose(q, w)
     352
     353
     354       
     355
     356
    147357    def test_first_order_limiter(self):
    148358        quantity = Quantity(self.mesh4)
     
    161371
    162372    def test_second_order_limiter(self):
    163 
    164         #FIXME:!!!!!!!
    165        
    166         quantity = Quantity(self.mesh4)
    167 
    168         quantity.set_values([2., 4., 5., 5.], location = 'centroids')
    169         #Assume gradient
    170 
    171         #Extrapolate
     373        quantity = Quantity(self.mesh4)
     374
     375        #Create a deliberate overshoot (e.g. from gradient computation)
     376        quantity.set_values([[0,3,3], [6,2,2], [3,8,5], [3,5,8]])
     377
     378        #Limit and extrapolate
    172379        quantity.second_order_limiter()
    173         #print quantity.vertex_values
    174 
    175 
     380
     381
     382        #Assert that central triangle is limited by neighbours
     383        assert quantity.vertex_values[1,0] <= quantity.vertex_values[2,2]
     384        assert quantity.vertex_values[1,0] <= quantity.vertex_values[3,1]
     385       
     386        assert quantity.vertex_values[1,1] <= quantity.vertex_values[3,0]
     387        assert quantity.vertex_values[1,1] >= quantity.vertex_values[0,2]
     388       
     389        assert quantity.vertex_values[1,2] <= quantity.vertex_values[2,0]
     390        assert quantity.vertex_values[1,2] >= quantity.vertex_values[0,1]
     391
     392       
     393        #Assert that quantities are conserved
     394        from Numeric import sum
     395        for k in range(quantity.centroid_values.shape[0]):
     396            assert allclose (quantity.centroid_values[k],
     397                             sum(quantity.vertex_values[k,:])/3)
     398       
    176399       
    177400        #Check vertices but not edge values
  • inundation/ga/storm_surge/pyvolution/test_shallow_water.py

    r195 r198  
    2222        ql = zeros( 3, Float )
    2323        qr = zeros( 3, Float )
    24         normal = zeros( 3, Float )
     24        normal = zeros( 2, Float )
    2525        zl = zr = 0.
    2626        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
     
    110110
    111111        assert domain.get_conserved_quantities(0, edge=1) == 0.   
    112 
    113112
    114113
     
    602601                                      [val3, val3, val3]])
    603602
     603        E = domain.quantities['elevation'].vertex_values
    604604        L = domain.quantities['level'].vertex_values       
    605         E = domain.quantities['elevation'].vertex_values
    606605
    607606       
     
    612611        domain.first_order_limiter()
    613612
    614         #Check that all levels are above elevation (within eps)
     613        #Check that all levels are above elevation (within eps)
     614
     615       
    615616        assert alltrue(alltrue(greater_equal(L,E-epsilon)))               
    616617       
  • inundation/ga/storm_surge/pyvolution/util.py

    r196 r198  
    100100           'Vector of conserved quantities must have length 3'\
    101101           'for 2D shallow water equation'
     102
    102103    try:
    103104        l = len(normal)
     
    105106        raise 'Normal vector must be an Numeric array'
    106107
     108    #FIXME: Put this test into C-extension as well
    107109    assert l == 2, 'Normal vector must have 2 components'
    108110
  • inundation/ga/storm_surge/pyvolution/util_ext.c

    r195 r198  
    117117    return NULL;
    118118  } 
    119    
     119 
    120120  //Allocate space for return vectors a and b 
    121121 
Note: See TracChangeset for help on using the changeset viewer.