Changeset 5736


Ignore:
Timestamp:
Sep 5, 2008, 11:30:19 AM (16 years ago)
Author:
ole
Message:

Implemented run-time version of get_energy_through_cross_section and tested it.

Location:
anuga_core/source/anuga
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py

    r5729 r5736  
    10121012        associated matrices will be reused to save time.
    10131013       
    1014         The argument interpolation points must be given as either a list of absolute UTM coordinates or
    1015         a geospatial data object.
    1016         """
    1017 
    1018         # FIXME (Ole): Could do with an input check (should be generalised and used widely)
    1019         # That will check that interpolation points is either a list of points, Nx2 array, or geospatial
     1014        The argument interpolation points must be given as either a
     1015        list of absolute UTM coordinates or a geospatial data object.
     1016        """
     1017
     1018        # FIXME (Ole): Could do with an input check (should be generalised
     1019        # and used widely)
     1020        # That will check that interpolation points is either a list of
     1021        # points, Nx2 array, or geospatial
    10201022       
    10211023        # Ensure points are converted to coordinates relative to mesh origin
    1022         # FIXME (Ole): This could all be refactored using the 'change_points_geo_ref' method
    1023         # of Class geo_reference. The purpose is to make interpolation points relative
     1024        # FIXME (Ole): This could all be refactored using the
     1025        # 'change_points_geo_ref' method of Class geo_reference.
     1026        # The purpose is to make interpolation points relative
    10241027        # to the mesh origin.
    10251028        #
     
    10341037        interpolation_points = ensure_numeric(interpolation_points)
    10351038       
    1036         # Get internal (discontinuous) triangles for use with the interpolation object.
     1039       
     1040       
     1041        # Get internal (discontinuous) triangles for use with the
     1042        # interpolation object.
    10371043        x, y, vertex_values, triangles = self.get_vertex_values(xy=True,
    10381044                                                                smooth=False)
  • anuga_core/source/anuga/coordinate_transforms/geo_reference.py

    r5730 r5736  
    212212        assert points.shape[1] == 2, msg               
    213213
    214            
     214       
     215        # FIXME (Ole): Could also check if zone, xllcorner, yllcorner
     216        # are identical in the two geo refs.   
    215217        if points_geo_ref is not self:
    216             #add point geo ref to points
     218            # If georeferences are different
     219       
    217220            if not points_geo_ref is None:
     221                # Convert points to absolute coordinates
    218222                points[:,0] += points_geo_ref.xllcorner
    219223                points[:,1] += points_geo_ref.yllcorner
    220224       
    221             #subtract primary geo ref from points
     225            # Make points relative to primary geo reference
    222226            points[:,0] -= self.xllcorner
    223227            points[:,1] -= self.yllcorner
  • anuga_core/source/anuga/shallow_water/data_manager.py

    r5734 r5736  
    64666466                                     kind = 'total',
    64676467                                     verbose=False):
    6468     """Obtain flow (m^3/s) perpendicular to specified cross section.
     6468    """Obtain average energy head [m] across specified cross section.
    64696469
    64706470    Inputs:
    6471         filename: Name of sww file
    64726471        polyline: Representation of desired cross section - it may contain
    64736472                  multiple sections allowing for complex shapes. Assume
     
    64786477
    64796478    Output:
    6480         time: All stored times in sww file
    6481         Q: Average energy [m] across given segments for all stored times.
    6482 
    6483     The average velocity is computed for each triangle intersected by the polyline
    6484     and averaged weigted by segment lengths.
    6485 
    6486     The typical usage of this function would be to get average energy of flow in a channel,
    6487     and the polyline would then be a cross section perpendicular to the flow.
    6488 
    6489    
    6490     #FIXME (Ole) - need name for this energy reflecting that its dimension is [m].
     6479        E: Average energy [m] across given segments for all stored times.
     6480
     6481    The average velocity is computed for each triangle intersected by
     6482    the polyline and averaged weighted by segment lengths.
     6483
     6484    The typical usage of this function would be to get average energy of
     6485    flow in a channel, and the polyline would then be a cross section
     6486    perpendicular to the flow.
     6487
     6488    #FIXME (Ole) - need name for this energy reflecting that its dimension
     6489    is [m].
    64916490    """
    64926491
     
    65016500    # Get values for quantities at each midpoint of poly line from sww file
    65026501    X = get_interpolated_quantities_at_polyline_midpoints(filename,
    6503                                                           quantity_names=quantity_names,
     6502                                                          quantity_names=\
     6503                                                          quantity_names,
    65046504                                                          polyline=polyline,
    65056505                                                          verbose=verbose)   
  • anuga_core/source/anuga/shallow_water/shallow_water_domain.py

    r5730 r5736  
    384384        """Get the total flow through an arbitrary poly line.       
    385385       
    386         This is a run-time equivalent of the function with same name in data_manager.py
     386        This is a run-time equivalent of the function with same name
     387        in data_manager.py
    387388       
    388389        Input:
     
    410411        midpoints = segment_midpoints(segments)       
    411412       
    412         # FIXME (Ole): HACK - need to make midpoints Geospatial instances
    413         #midpoints = self.geo_reference.get_absolute(midpoints)       
    414        
    415413        # Make midpoints Geospatial instances
    416414        midpoints = ensure_geospatial(midpoints, self.geo_reference)       
     
    439437            # Accumulate
    440438            total_flow += segment_flow
    441 
    442439           
    443440        return total_flow
    444        
     441
     442       
     443               
     444    def get_energy_through_cross_section(self, polyline,
     445                                         kind = 'total',
     446                                         verbose=False):               
     447        """Obtain average energy head [m] across specified cross section.
     448
     449        Inputs:
     450            polyline: Representation of desired cross section - it may contain
     451                      multiple sections allowing for complex shapes. Assume
     452                      absolute UTM coordinates.
     453                      Format [[x0, y0], [x1, y1], ...]
     454            kind:     Select which energy to compute.
     455                      Options are 'specific' and 'total' (default)
     456
     457        Output:
     458            E: Average energy [m] across given segments for all stored times.
     459
     460        The average velocity is computed for each triangle intersected by
     461        the polyline and averaged weighted by segment lengths.
     462
     463        The typical usage of this function would be to get average energy of
     464        flow in a channel, and the polyline would then be a cross section
     465        perpendicular to the flow.
     466
     467        #FIXME (Ole) - need name for this energy reflecting that its dimension
     468        is [m].
     469        """
     470
     471        from anuga.config import g, epsilon, velocity_protection as h0       
     472                                         
     473       
     474        # Adjust polyline to mesh spatial origin
     475        polyline = self.geo_reference.get_relative(polyline)
     476       
     477        # Find all intersections and associated triangles.
     478        segments = self.get_intersecting_segments(polyline, verbose=verbose)
     479
     480        msg = 'No segments found'
     481        assert len(segments) > 0, msg
     482       
     483        # Get midpoints
     484        midpoints = segment_midpoints(segments)       
     485       
     486        # Make midpoints Geospatial instances
     487        midpoints = ensure_geospatial(midpoints, self.geo_reference)       
     488       
     489        # Compute energy       
     490        if verbose: print 'Computing %s energy' %kind       
     491       
     492        # Get interpolated values
     493        stage = self.get_quantity('stage')       
     494        elevation = self.get_quantity('elevation')               
     495        xmomentum = self.get_quantity('xmomentum')
     496        ymomentum = self.get_quantity('ymomentum')       
     497
     498        w = stage.get_values(interpolation_points=midpoints)
     499        z = elevation.get_values(interpolation_points=midpoints)       
     500        uh = xmomentum.get_values(interpolation_points=midpoints)
     501        vh = ymomentum.get_values(interpolation_points=midpoints)       
     502        h = w-z # Depth
     503       
     504        # Compute total length of polyline for use with weighted averages
     505        total_line_length = 0.0
     506        for segment in segments:
     507            total_line_length += segment.length
     508       
     509        # Compute and sum flows across each segment
     510        average_energy=0.0
     511        for i in range(len(w)):
     512           
     513            # Average velocity across this segment
     514            if h[i] > epsilon:
     515                # Use protection against degenerate velocities
     516                u = uh[i]/(h[i] + h0/h[i])
     517                v = vh[i]/(h[i] + h0/h[i])
     518            else:
     519                u = v = 0.0
     520               
     521            speed_squared = u*u + v*v   
     522            kinetic_energy = 0.5*speed_squared/g
     523           
     524            if kind == 'specific':
     525                segment_energy = h[i] + kinetic_energy
     526            elif kind == 'total':
     527                segment_energy = w[i] + kinetic_energy               
     528            else:
     529                msg = 'Energy kind must be either "specific" or "total".'
     530                msg += ' I got %s' %kind
     531               
     532
     533            # Add to weighted average
     534            weigth = segments[i].length/total_line_length
     535            average_energy += segment_energy*weigth
     536             
     537           
     538        return average_energy
     539       
     540
     541                       
    445542
    446543    def check_integrity(self):
     
    15331630
    15341631class General_forcing:
    1535     """Class General_forcing - general explicit forcing term for update of quantity
     1632    """General explicit forcing term for update of quantity
    15361633   
    15371634    This is used by Inflow and Rainfall for instance
     
    15411638
    15421639    domain:     ANUGA computational domain
    1543     quantity_name: Name of quantity to update. It must be a known conserved quantity.
     1640    quantity_name: Name of quantity to update.
     1641                   It must be a known conserved quantity.
     1642                   
    15441643    rate [?/s]: Total rate of change over the specified area. 
    15451644                This parameter can be either a constant or a
     
    16251724
    16261725            for point in periphery_points:
    1627                 msg = 'Point %s on periphery for forcing term did not' %(str(point))
    1628                 msg += ' fall within the domain boundary.'
     1726                msg = 'Point %s on periphery for forcing term' %(str(point))
     1727                msg += ' did not fall within the domain boundary.'
    16291728                assert is_inside_polygon(point, bounding_polygon), msg
    16301729
     
    16351734            # Check that polygon lies within the mesh.
    16361735            for point in self.polygon:
    1637                 msg = 'Point %s in polygon for forcing term did not' %(str(point))
    1638                 msg += 'fall within the domain boundary.'
     1736                msg = 'Point %s in polygon for forcing term' %(str(point))
     1737                msg += ' did not fall within the domain boundary.'
    16391738                assert is_inside_polygon(point, bounding_polygon), msg
    1640        
    1641 
    1642 
    1643            
    16441739
    16451740
    16461741        # Pointer to update vector
    1647         self.update = domain.quantities[self.quantity_name].explicit_update           
     1742        self.update = domain.quantities[self.quantity_name].explicit_update
    16481743
    16491744        # Determine indices in flow area
     
    16611756            for k in range(N):
    16621757                x, y = points[k,:] # Centroid
    1663                 if ((x-self.center[0])**2+(y-self.center[1])**2) < self.radius**2:
     1758               
     1759                c = self.center
     1760                if ((x-c[0])**2+(y-c[1])**2) < self.radius**2:
    16641761                    self.exchange_indices.append(k)
    16651762                   
     
    16761773       
    16771774            if len(self.exchange_indices) == 0:
    1678                 msg = 'No triangles have been identified in specified region: %s' %inlet_region
     1775                msg = 'No triangles have been identified in '
     1776                msg += 'specified region: %s' %inlet_region
    16791777                raise Exception, msg
    16801778
     
    17231821        """Return values for specified quantity restricted to opening
    17241822        """
    1725         return self.domain.quantities[self.quantity_name].get_values(indices=self.exchange_indices)
     1823       
     1824        q = self.domain.quantities[self.quantity_name]
     1825        return q.get_values(indices=self.exchange_indices)
    17261826   
    17271827
     
    17291829        """Set values for specified quantity restricted to opening
    17301830        """
    1731         self.domain.quantities[self.quantity_name].set_values(val, indices=self.exchange_indices)   
     1831
     1832        q = self.domain.quantities[self.quantity_name]               
     1833        q.set_values(val, indices=self.exchange_indices)   
    17321834
    17331835
     
    17661868    How to put them in a run File...
    17671869       
    1768     #--------------------------------------------------------------------------
     1870    #------------------------------------------------------------------------
    17691871    # Setup specialised forcing terms
    1770     #--------------------------------------------------------------------------
     1872    #------------------------------------------------------------------------
    17711873    # This is the new element implemented by Ole and Rudy to allow direct
    17721874    # input of Inflow in mm/s
     
    18421944
    18431945
    1844     #--------------------------------------------------------------------------
     1946    #------------------------------------------------------------------------
    18451947    # Setup specialised forcing terms
    1846     #--------------------------------------------------------------------------
     1948    #------------------------------------------------------------------------
    18471949    # This is the new element implemented by Ole to allow direct input
    18481950    # of Inflow in m^3/s
     
    18621964                 polygon=None,
    18631965                 verbose=False):                 
    1864 
    1865 
    1866         #msg = 'Class Inflow must have either center & radius or a polygon specified.'
    1867         #assert center is not None and radius is not None or\
    1868         #       polygon is not None, msg
    18691966
    18701967
     
    18821979        overriding version in descendant
    18831980
    1884         This one converts m^3/s to m/s which can be added directly to 'stage' in ANUGA
     1981        This one converts m^3/s to m/s which can be added directly
     1982        to 'stage' in ANUGA
    18851983        """
    18861984
  • anuga_core/source/anuga/shallow_water/test_shallow_water_domain.py

    r5730 r5736  
    15021502                assert allclose(Q, uh*width)
    15031503
     1504
     1505       
     1506    def test_get_energy_through_cross_section_with_geo(self):
     1507        """test_get_energy_through_cross_section(self):
     1508
     1509        Test that the total and specific energy through a cross section can be
     1510        correctly obtained at run-time from the ANUGA domain.
     1511       
     1512        This test creates a flat bed with a known flow through it and tests
     1513        that the function correctly returns the expected energies.
     1514
     1515        The specifics are
     1516        e = -1 m
     1517        u = 2 m/s
     1518        h = 2 m
     1519        w = 3 m (width of channel)
     1520
     1521        q = u*h*w = 12 m^3/s
     1522
     1523
     1524        This run tries it with georeferencing and with elevation = -1
     1525       
     1526        """
     1527
     1528        import time, os
     1529        from Numeric import array, zeros, allclose, Float, concatenate
     1530        from Scientific.IO.NetCDF import NetCDFFile
     1531
     1532        # Setup
     1533        from mesh_factory import rectangular
     1534
     1535        # Create basic mesh (20m x 3m)
     1536        width = 3
     1537        length = 20
     1538        t_end = 1
     1539        points, vertices, boundary = rectangular(length, width,
     1540                                                 length, width)
     1541
     1542        # Create shallow water domain
     1543        domain = Domain(points, vertices, boundary,
     1544                        geo_reference=Geo_reference(56,308500,6189000))
     1545
     1546        domain.default_order = 2
     1547        domain.set_quantities_to_be_stored(None)
     1548
     1549
     1550        e = -1.0
     1551        w = 1.0
     1552        h = w-e
     1553        u = 2.0
     1554        uh = u*h
     1555
     1556        Br = Reflective_boundary(domain)     # Side walls
     1557        Bd = Dirichlet_boundary([w, uh, 0])  # 2 m/s across the 3 m inlet:
     1558
     1559
     1560        # Initial conditions
     1561        domain.set_quantity('elevation', e)
     1562        domain.set_quantity('stage', w)
     1563        domain.set_quantity('xmomentum', uh)
     1564        domain.set_boundary( {'left': Bd, 'right': Bd, 'top': Br, 'bottom': Br})
     1565       
     1566       
     1567        # Interpolation points down the middle
     1568        I = [[0, width/2.],
     1569             [length/2., width/2.],
     1570             [length, width/2.]]
     1571        interpolation_points = domain.geo_reference.get_absolute(I)       
     1572       
     1573        # Shortcuts to quantites
     1574        stage = domain.get_quantity('stage')       
     1575        xmomentum = domain.get_quantity('xmomentum')       
     1576        ymomentum = domain.get_quantity('ymomentum')               
     1577
     1578        for t in domain.evolve(yieldstep=0.1, finaltime = t_end):
     1579            # Check that quantities are they should be in the interior
     1580
     1581            w_t = stage.get_values(interpolation_points)           
     1582            uh_t = xmomentum.get_values(interpolation_points)
     1583            vh_t = ymomentum.get_values(interpolation_points)           
     1584           
     1585            assert allclose(w_t, w)
     1586            assert allclose(uh_t, uh)           
     1587            assert allclose(vh_t, 0.0)                       
     1588           
     1589           
     1590            # Check energies through the middle
     1591            for i in range(5):
     1592                x = length/2. + i*0.23674563 # Arbitrary
     1593                cross_section = [[x, 0], [x, width]]
     1594
     1595                cross_section = domain.geo_reference.get_absolute(cross_section)   
     1596                Es = domain.get_energy_through_cross_section(cross_section,
     1597                                                             kind='specific',
     1598                                                             verbose=False)
     1599                                                     
     1600                assert allclose(Es, h + 0.5*u*u/g)
     1601           
     1602                Et = domain.get_energy_through_cross_section(cross_section,
     1603                                                             kind='total',
     1604                                                             verbose=False)
     1605                assert allclose(Et, w + 0.5*u*u/g)           
    15041606
    15051607           
Note: See TracChangeset for help on using the changeset viewer.