Ignore:
Timestamp:
Jun 30, 2009, 2:07:41 PM (15 years ago)
Author:
ole
Message:

Merged numpy branch back into the trunk.

In ~/sandpit/anuga/anuga_core/source
svn merge -r 6246:HEAD ../../branches/numpy .

In ~/sandpit/anuga/anuga_validation
svn merge -r 6417:HEAD ../branches/numpy_anuga_validation .

In ~/sandpit/anuga/misc
svn merge -r 6809:HEAD ../branches/numpy_misc .

For all merges, I used numpy version where conflicts existed

The suites test_all.py (in source/anuga) and validate_all.py passed using Python2.5 with numpy on my Ubuntu Linux box.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • anuga_core/source/anuga/shallow_water/shallow_water_domain.py

    r7090 r7276  
    1 """Finite-volume computations of the shallow water wave equation.
     1"""
     2Finite-volume computations of the shallow water wave equation.
    23
    34Title: ANGUA shallow_water_domain - 2D triangular domains for finite-volume
     
    5354    Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
    5455
    55     Hydrodynamic modelling of coastal inundation. 
     56    Hydrodynamic modelling of coastal inundation.
    5657    Nielsen, O., S. Roberts, D. Gray, A. McPherson and A. Hitchman
    5758    In Zerger, A. and Argent, R.M. (eds) MODSIM 2005 International Congress on
     
    7172    $Author$
    7273    $Date$
    73 
    7474"""
    7575
     
    8080# $LastChangedBy$
    8181
    82 import Numeric as num
     82
     83import numpy as num
    8384
    8485from anuga.abstract_2d_finite_volumes.neighbour_mesh import segment_midpoints
     
    9697from anuga.abstract_2d_finite_volumes.generic_boundary_conditions\
    9798     import AWI_boundary
    98 from anuga.abstract_2d_finite_volumes.generic_boundary_conditions\
    99      import AWI_boundary
    10099
    101100from anuga.pmesh.mesh_interface import create_mesh_from_regions
     
    114113from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
    115114
    116 from anuga.fit_interpolate.interpolate import Modeltime_too_late, Modeltime_too_early
    117 
    118 from anuga.utilities.polygon import inside_polygon, polygon_area, is_inside_polygon
     115from anuga.fit_interpolate.interpolate import Modeltime_too_late, \
     116                                              Modeltime_too_early
     117
     118from anuga.utilities.polygon import inside_polygon, polygon_area, \
     119                                    is_inside_polygon
    119120
    120121from types import IntType, FloatType
    121122from warnings import warn
    122123
    123 import math
    124 
    125 #
     124
     125################################################################################
    126126# Shallow water domain
    127 #---------------------
     127################################################################################
     128
     129##
     130# @brief Class for a shallow water domain.
    128131class Domain(Generic_Domain):
    129132
    130133    conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
    131134    other_quantities = ['elevation', 'friction']
    132    
     135
     136    ##
     137    # @brief Instantiate a shallow water domain.
     138    # @param coordinates
     139    # @param vertices
     140    # @param boundary
     141    # @param tagged_elements
     142    # @param geo_reference
     143    # @param use_inscribed_circle
     144    # @param mesh_filename
     145    # @param use_cache
     146    # @param verbose
     147    # @param full_send_dict
     148    # @param ghost_recv_dict
     149    # @param processor
     150    # @param numproc
     151    # @param number_of_full_nodes
     152    # @param number_of_full_triangles
    133153    def __init__(self,
    134154                 coordinates=None,
     
    147167                 number_of_full_nodes=None,
    148168                 number_of_full_triangles=None):
    149 
    150169
    151170        other_quantities = ['elevation', 'friction']
     
    167186                                numproc,
    168187                                number_of_full_nodes=number_of_full_nodes,
    169                                 number_of_full_triangles=number_of_full_triangles)
    170 
     188                                number_of_full_triangles=number_of_full_triangles)
    171189
    172190        self.set_minimum_allowed_height(minimum_allowed_height)
    173        
     191
    174192        self.maximum_allowed_speed = maximum_allowed_speed
    175193        self.g = g
    176         self.beta_w      = beta_w
    177         self.beta_w_dry  = beta_w_dry
    178         self.beta_uh     = beta_uh
     194        self.beta_w = beta_w
     195        self.beta_w_dry = beta_w_dry
     196        self.beta_uh = beta_uh
    179197        self.beta_uh_dry = beta_uh_dry
    180         self.beta_vh     = beta_vh
     198        self.beta_vh = beta_vh
    181199        self.beta_vh_dry = beta_vh_dry
    182200        self.alpha_balance = alpha_balance
     
    193211        self.set_store_vertices_uniquely(False)
    194212        self.minimum_storable_height = minimum_storable_height
    195         self.quantities_to_be_stored = ['stage','xmomentum','ymomentum']
     213        self.quantities_to_be_stored = ['stage', 'xmomentum', 'ymomentum']
    196214
    197215        # Limiters
     
    200218        self.use_centroid_velocities = use_centroid_velocities
    201219
    202 
     220    ##
     221    # @brief
     222    # @param beta
    203223    def set_all_limiters(self, beta):
    204         """Shorthand to assign one constant value [0,1[ to all limiters.
     224        """Shorthand to assign one constant value [0,1] to all limiters.
    205225        0 Corresponds to first order, where as larger values make use of
    206         the second order scheme. 
    207         """
    208 
    209         self.beta_w      = beta
    210         self.beta_w_dry  = beta
     226        the second order scheme.
     227        """
     228
     229        self.beta_w = beta
     230        self.beta_w_dry = beta
    211231        self.quantities['stage'].beta = beta
    212        
    213         self.beta_uh     = beta
     232
     233        self.beta_uh = beta
    214234        self.beta_uh_dry = beta
    215235        self.quantities['xmomentum'].beta = beta
    216        
    217         self.beta_vh     = beta
     236
     237        self.beta_vh = beta
    218238        self.beta_vh_dry = beta
    219239        self.quantities['ymomentum'].beta = beta
    220        
    221        
    222 
     240
     241    ##
     242    # @brief
     243    # @param flag
     244    # @param reduction
    223245    def set_store_vertices_uniquely(self, flag, reduction=None):
    224246        """Decide whether vertex values should be stored uniquely as
     
    235257            #self.reduction = min  #Looks better near steep slopes
    236258
    237 
     259    ##
     260    # @brief Set the minimum depth that will be written to an SWW file.
     261    # @param minimum_storable_height The minimum stored height (in m).
    238262    def set_minimum_storable_height(self, minimum_storable_height):
    239         """
    240         Set the minimum depth that will be recognised when writing
     263        """Set the minimum depth that will be recognised when writing
    241264        to an sww file. This is useful for removing thin water layers
    242265        that seems to be caused by friction creep.
     
    244267        The minimum allowed sww depth is in meters.
    245268        """
     269
    246270        self.minimum_storable_height = minimum_storable_height
    247271
    248 
     272    ##
     273    # @brief
     274    # @param minimum_allowed_height
    249275    def set_minimum_allowed_height(self, minimum_allowed_height):
    250         """
    251         Set the minimum depth that will be recognised in the numerical
    252         scheme
     276        """Set minimum depth that will be recognised in the numerical scheme.
    253277
    254278        The minimum allowed depth is in meters.
     
    263287        #and deal with them adaptively similarly to how we used to use 1 order
    264288        #steps to recover.
     289
    265290        self.minimum_allowed_height = minimum_allowed_height
    266         self.H0 = minimum_allowed_height   
    267        
    268 
     291        self.H0 = minimum_allowed_height
     292
     293    ##
     294    # @brief
     295    # @param maximum_allowed_speed
    269296    def set_maximum_allowed_speed(self, maximum_allowed_speed):
    270         """
    271         Set the maximum particle speed that is allowed in water
     297        """Set the maximum particle speed that is allowed in water
    272298        shallower than minimum_allowed_height. This is useful for
    273299        controlling speeds in very thin layers of water and at the same time
    274300        allow some movement avoiding pooling of water.
    275 
    276         """
     301        """
     302
    277303        self.maximum_allowed_speed = maximum_allowed_speed
    278304
    279 
    280     def set_points_file_block_line_size(self,points_file_block_line_size):
    281         """
    282         Set the minimum depth that will be recognised when writing
     305    ##
     306    # @brief
     307    # @param points_file_block_line_size
     308    def set_points_file_block_line_size(self, points_file_block_line_size):
     309        """Set the minimum depth that will be recognised when writing
    283310        to an sww file. This is useful for removing thin water layers
    284311        that seems to be caused by friction creep.
     
    287314        """
    288315        self.points_file_block_line_size = points_file_block_line_size
    289        
    290        
     316
     317    ##
     318    # @brief Set the quantities that will be written to an SWW file.
     319    # @param q The quantities to be written.
     320    # @note Param 'q' may be None, single quantity or list of quantity strings.
     321    # @note If 'q' is None, no quantities will be stored in the SWW file.
    291322    def set_quantities_to_be_stored(self, q):
    292323        """Specify which quantities will be stored in the sww file.
     
    300331        each yieldstep (This is in addition to the quantities elevation
    301332        and friction)
    302        
     333
    303334        If q is None, storage will be switched off altogether.
    304335        """
    305 
    306336
    307337        if q is None:
     
    315345        # Check correcness
    316346        for quantity_name in q:
    317             msg = 'Quantity %s is not a valid conserved quantity'\
    318                   %quantity_name
    319            
     347            msg = ('Quantity %s is not a valid conserved quantity'
     348                   % quantity_name)
    320349            assert quantity_name in self.conserved_quantities, msg
    321350
    322351        self.quantities_to_be_stored = q
    323352
    324 
    325 
     353    ##
     354    # @brief
     355    # @param indices
    326356    def get_wet_elements(self, indices=None):
    327357        """Return indices for elements where h > minimum_allowed_height
     
    333363            indices = get_wet_elements()
    334364
    335         Note, centroid values are used for this operation           
     365        Note, centroid values are used for this operation
    336366        """
    337367
     
    340370        from anuga.config import minimum_allowed_height
    341371
    342        
    343372        elevation = self.get_quantity('elevation').\
     373                        get_values(location='centroids', indices=indices)
     374        stage = self.get_quantity('stage').\
    344375                    get_values(location='centroids', indices=indices)
    345         stage = self.get_quantity('stage').\
    346                 get_values(location='centroids', indices=indices)       
    347376        depth = stage - elevation
    348377
     
    350379        wet_indices = num.compress(depth > minimum_allowed_height,
    351380                                   num.arange(len(depth)))
    352         return wet_indices
    353 
    354 
     381        return wet_indices
     382
     383    ##
     384    # @brief
     385    # @param indices
    355386    def get_maximum_inundation_elevation(self, indices=None):
    356387        """Return highest elevation where h > 0
     
    362393            q = get_maximum_inundation_elevation()
    363394
    364         Note, centroid values are used for this operation           
     395        Note, centroid values are used for this operation
    365396        """
    366397
    367398        wet_elements = self.get_wet_elements(indices)
    368399        return self.get_quantity('elevation').\
    369                get_maximum_value(indices=wet_elements)
    370 
    371 
     400                   get_maximum_value(indices=wet_elements)
     401
     402    ##
     403    # @brief
     404    # @param indices
    372405    def get_maximum_inundation_location(self, indices=None):
    373406        """Return location of highest elevation where h > 0
     
    379412            q = get_maximum_inundation_location()
    380413
    381         Note, centroid values are used for this operation           
     414        Note, centroid values are used for this operation
    382415        """
    383416
    384417        wet_elements = self.get_wet_elements(indices)
    385418        return self.get_quantity('elevation').\
    386                get_maximum_location(indices=wet_elements)   
    387                
    388                
    389                
    390                
    391     def get_flow_through_cross_section(self, polyline,
    392                                        verbose=False):               
    393         """Get the total flow through an arbitrary poly line.       
    394        
    395         This is a run-time equivalent of the function with same name
     419                   get_maximum_location(indices=wet_elements)
     420
     421    ##
     422    # @brief Get the total flow through an arbitrary poly line.
     423    # @param polyline Representation of desired cross section.
     424    # @param verbose True if this method is to be verbose.
     425    # @note 'polyline' may contain multiple sections allowing complex shapes.
     426    # @note Assume absolute UTM coordinates.
     427    def get_flow_through_cross_section(self, polyline, verbose=False):
     428        """Get the total flow through an arbitrary poly line.
     429
     430        This is a run-time equivalent of the function with same name
    396431        in data_manager.py
    397        
     432
    398433        Input:
    399             polyline: Representation of desired cross section - it may contain 
    400                       multiple sections allowing for complex shapes. Assume 
     434            polyline: Representation of desired cross section - it may contain
     435                      multiple sections allowing for complex shapes. Assume
    401436                      absolute UTM coordinates.
    402                       Format [[x0, y0], [x1, y1], ...]       
    403                  
    404         Output:       
     437                      Format [[x0, y0], [x1, y1], ...]
     438
     439        Output:
    405440            Q: Total flow [m^3/s] across given segments.
    406        
    407          
    408         """       
    409        
     441        """
     442
    410443        # Find all intersections and associated triangles.
    411         segments = self.get_intersecting_segments(polyline,
    412                                                   use_cache=True,
     444        segments = self.get_intersecting_segments(polyline, use_cache=True,
    413445                                                  verbose=verbose)
    414446
    415447        # Get midpoints
    416         midpoints = segment_midpoints(segments)       
    417        
     448        midpoints = segment_midpoints(segments)
     449
    418450        # Make midpoints Geospatial instances
    419         midpoints = ensure_geospatial(midpoints, self.geo_reference)       
    420        
    421         # Compute flow       
     451        midpoints = ensure_geospatial(midpoints, self.geo_reference)
     452
     453        # Compute flow
    422454        if verbose: print 'Computing flow through specified cross section'
    423        
     455
    424456        # Get interpolated values
    425457        xmomentum = self.get_quantity('xmomentum')
    426         ymomentum = self.get_quantity('ymomentum')       
    427        
    428         uh = xmomentum.get_values(interpolation_points=midpoints, use_cache=True)
    429         vh = ymomentum.get_values(interpolation_points=midpoints, use_cache=True)
    430        
     458        ymomentum = self.get_quantity('ymomentum')
     459
     460        uh = xmomentum.get_values(interpolation_points=midpoints,
     461                                  use_cache=True)
     462        vh = ymomentum.get_values(interpolation_points=midpoints,
     463                                  use_cache=True)
     464
    431465        # Compute and sum flows across each segment
    432         total_flow=0
     466        total_flow = 0
    433467        for i in range(len(uh)):
    434            
    435             # Inner product of momentum vector with segment normal [m^2/s]
     468            # Inner product of momentum vector with segment normal [m^2/s]
    436469            normal = segments[i].normal
    437             normal_momentum = uh[i]*normal[0] + vh[i]*normal[1] 
    438                
     470            normal_momentum = uh[i]*normal[0] + vh[i]*normal[1]
     471
    439472            # Flow across this segment [m^3/s]
    440473            segment_flow = normal_momentum*segments[i].length
     
    442475            # Accumulate
    443476            total_flow += segment_flow
    444            
     477
    445478        return total_flow
    446479
    447        
    448                
     480    ##
     481    # @brief
     482    # @param polyline Representation of desired cross section.
     483    # @param kind Select energy type to compute ('specific' or 'total').
     484    # @param verbose True if this method is to be verbose.
     485    # @note 'polyline' may contain multiple sections allowing complex shapes.
     486    # @note Assume absolute UTM coordinates.
    449487    def get_energy_through_cross_section(self, polyline,
    450488                                         kind='total',
    451                                          verbose=False):               
     489                                         verbose=False):
    452490        """Obtain average energy head [m] across specified cross section.
    453491
    454492        Inputs:
    455             polyline: Representation of desired cross section - it may contain 
    456                       multiple sections allowing for complex shapes. Assume 
     493            polyline: Representation of desired cross section - it may contain
     494                      multiple sections allowing for complex shapes. Assume
    457495                      absolute UTM coordinates.
    458496                      Format [[x0, y0], [x1, y1], ...]
    459             kind:     Select which energy to compute. 
     497            kind:     Select which energy to compute.
    460498                      Options are 'specific' and 'total' (default)
    461499
     
    463501            E: Average energy [m] across given segments for all stored times.
    464502
    465         The average velocity is computed for each triangle intersected by 
    466         the polyline and averaged weighted by segment lengths. 
    467 
    468         The typical usage of this function would be to get average energy of 
    469         flow in a channel, and the polyline would then be a cross section 
     503        The average velocity is computed for each triangle intersected by
     504        the polyline and averaged weighted by segment lengths.
     505
     506        The typical usage of this function would be to get average energy of
     507        flow in a channel, and the polyline would then be a cross section
    470508        perpendicular to the flow.
    471509
    472         #FIXME (Ole) - need name for this energy reflecting that its dimension 
     510        #FIXME (Ole) - need name for this energy reflecting that its dimension
    473511        is [m].
    474512        """
    475513
    476         from anuga.config import g, epsilon, velocity_protection as h0       
    477                                          
    478        
     514        from anuga.config import g, epsilon, velocity_protection as h0
     515
    479516        # Find all intersections and associated triangles.
    480         segments = self.get_intersecting_segments(polyline,
    481                                                   use_cache=True,
     517        segments = self.get_intersecting_segments(polyline, use_cache=True,
    482518                                                  verbose=verbose)
    483519
    484520        # Get midpoints
    485         midpoints = segment_midpoints(segments)       
    486        
     521        midpoints = segment_midpoints(segments)
     522
    487523        # Make midpoints Geospatial instances
    488         midpoints = ensure_geospatial(midpoints, self.geo_reference)       
    489        
    490         # Compute energy       
    491         if verbose: print 'Computing %s energy' %kind       
    492        
     524        midpoints = ensure_geospatial(midpoints, self.geo_reference)
     525
     526        # Compute energy
     527        if verbose: print 'Computing %s energy' %kind
     528
    493529        # Get interpolated values
    494         stage = self.get_quantity('stage')       
    495         elevation = self.get_quantity('elevation')               
     530        stage = self.get_quantity('stage')
     531        elevation = self.get_quantity('elevation')
    496532        xmomentum = self.get_quantity('xmomentum')
    497         ymomentum = self.get_quantity('ymomentum')       
     533        ymomentum = self.get_quantity('ymomentum')
    498534
    499535        w = stage.get_values(interpolation_points=midpoints, use_cache=True)
    500         z = elevation.get_values(interpolation_points=midpoints, use_cache=True)       
    501         uh = xmomentum.get_values(interpolation_points=midpoints, use_cache=True)
    502         vh = ymomentum.get_values(interpolation_points=midpoints, use_cache=True)
    503         h = w-z # Depth
    504        
     536        z = elevation.get_values(interpolation_points=midpoints, use_cache=True)
     537        uh = xmomentum.get_values(interpolation_points=midpoints,
     538                                  use_cache=True)
     539        vh = ymomentum.get_values(interpolation_points=midpoints,
     540                                  use_cache=True)
     541        h = w-z                # Depth
     542
    505543        # Compute total length of polyline for use with weighted averages
    506544        total_line_length = 0.0
    507545        for segment in segments:
    508546            total_line_length += segment.length
    509        
     547
    510548        # Compute and sum flows across each segment
    511         average_energy=0.0
     549        average_energy = 0.0
    512550        for i in range(len(w)):
    513            
    514551            # Average velocity across this segment
    515552            if h[i] > epsilon:
     
    519556            else:
    520557                u = v = 0.0
    521                
    522             speed_squared = u*u + v*v   
     558
     559            speed_squared = u*u + v*v
    523560            kinetic_energy = 0.5*speed_squared/g
    524            
     561
    525562            if kind == 'specific':
    526563                segment_energy = h[i] + kinetic_energy
    527564            elif kind == 'total':
    528                 segment_energy = w[i] + kinetic_energy               
     565                segment_energy = w[i] + kinetic_energy
    529566            else:
    530567                msg = 'Energy kind must be either "specific" or "total".'
    531568                msg += ' I got %s' %kind
    532                
    533569
    534570            # Add to weighted average
    535571            weigth = segments[i].length/total_line_length
    536572            average_energy += segment_energy*weigth
    537              
    538            
     573
    539574        return average_energy
    540        
    541 
    542                        
    543 
     575
     576    ##
     577    # @brief Run integrity checks on shallow water domain.
    544578    def check_integrity(self):
    545579        Generic_Domain.check_integrity(self)
    546580
    547581        #Check that we are solving the shallow water wave equation
    548 
    549582        msg = 'First conserved quantity must be "stage"'
    550583        assert self.conserved_quantities[0] == 'stage', msg
     
    554587        assert self.conserved_quantities[2] == 'ymomentum', msg
    555588
     589    ##
     590    # @brief
    556591    def extrapolate_second_order_sw(self):
    557         #Call correct module function
    558         #(either from this module or C-extension)
     592        #Call correct module function (either from this module or C-extension)
    559593        extrapolate_second_order_sw(self)
    560594
     595    ##
     596    # @brief
    561597    def compute_fluxes(self):
    562         #Call correct module function
    563         #(either from this module or C-extension)
     598        #Call correct module function (either from this module or C-extension)
    564599        compute_fluxes(self)
    565600
     601    ##
     602    # @brief
    566603    def distribute_to_vertices_and_edges(self):
    567604        # Call correct module function
    568605        if self.use_edge_limiter:
    569             distribute_using_edge_limiter(self)           
     606            distribute_using_edge_limiter(self)
    570607        else:
    571608            distribute_using_vertex_limiter(self)
    572609
    573 
    574 
    575 
     610    ##
     611    # @brief Evolve the model by one step.
     612    # @param yieldstep
     613    # @param finaltime
     614    # @param duration
     615    # @param skip_initial_step
    576616    def evolve(self,
    577                yieldstep = None,
    578                finaltime = None,
    579                duration = None,
    580                skip_initial_step = False):
    581         """Specialisation of basic evolve method from parent class
    582         """
     617               yieldstep=None,
     618               finaltime=None,
     619               duration=None,
     620               skip_initial_step=False):
     621        """Specialisation of basic evolve method from parent class"""
    583622
    584623        # Call check integrity here rather than from user scripts
    585624        # self.check_integrity()
    586625
    587         msg = 'Parameter beta_w must be in the interval [0, 2['
     626        msg = 'Attribute self.beta_w must be in the interval [0, 2]'
    588627        assert 0 <= self.beta_w <= 2.0, msg
    589628
    590 
    591629        # Initial update of vertex and edge values before any STORAGE
    592         # and or visualisation
     630        # and or visualisation.
    593631        # This is done again in the initialisation of the Generic_Domain
    594         # evolve loop but we do it here to ensure the values are ok for storage
     632        # evolve loop but we do it here to ensure the values are ok for storage.
    595633        self.distribute_to_vertices_and_edges()
    596634
    597635        if self.store is True and self.time == 0.0:
    598636            self.initialise_storage()
    599             # print 'Storing results in ' + self.writer.filename
    600637        else:
    601638            pass
     
    606643
    607644        # Call basic machinery from parent class
    608         for t in Generic_Domain.evolve(self,
    609                                        yieldstep=yieldstep,
    610                                        finaltime=finaltime,
    611                                        duration=duration,
     645        for t in Generic_Domain.evolve(self, yieldstep=yieldstep,
     646                                       finaltime=finaltime, duration=duration,
    612647                                       skip_initial_step=skip_initial_step):
    613 
    614648            # Store model data, e.g. for subsequent visualisation
    615649            if self.store is True:
     
    622656            yield(t)
    623657
    624 
     658    ##
     659    # @brief
    625660    def initialise_storage(self):
    626661        """Create and initialise self.writer object for storing data.
     
    636671        self.writer.store_connectivity()
    637672
    638 
     673    ##
     674    # @brief
     675    # @param name
    639676    def store_timestep(self, name):
    640677        """Store named quantity and time.
     
    643680           self.write has been initialised
    644681        """
     682
    645683        self.writer.store_timestep(name)
    646684
    647        
     685    ##
     686    # @brief Get time stepping statistics string for printing.
     687    # @param track_speeds
     688    # @param triangle_id
    648689    def timestepping_statistics(self,
    649690                                track_speeds=False,
    650                                 triangle_id=None):       
     691                                triangle_id=None):
    651692        """Return string with time stepping statistics for printing or logging
    652693
     
    656697        """
    657698
    658         from anuga.config import epsilon, g               
    659 
     699        from anuga.config import epsilon, g
    660700
    661701        # Call basic machinery from parent class
    662         msg = Generic_Domain.timestepping_statistics(self,
    663                                                      track_speeds,
     702        msg = Generic_Domain.timestepping_statistics(self, track_speeds,
    664703                                                     triangle_id)
    665704
    666705        if track_speeds is True:
    667 
    668706            # qwidth determines the text field used for quantities
    669707            qwidth = self.qwidth
    670        
     708
    671709            # Selected triangle
    672710            k = self.k
     
    674712            # Report some derived quantities at vertices, edges and centroid
    675713            # specific to the shallow water wave equation
    676 
    677714            z = self.quantities['elevation']
    678             w = self.quantities['stage']           
     715            w = self.quantities['stage']
    679716
    680717            Vw = w.get_values(location='vertices', indices=[k])[0]
     
    684721            Vz = z.get_values(location='vertices', indices=[k])[0]
    685722            Ez = z.get_values(location='edges', indices=[k])[0]
    686             Cz = z.get_values(location='centroids', indices=[k])                             
    687                
     723            Cz = z.get_values(location='centroids', indices=[k])
    688724
    689725            name = 'depth'
     
    691727            Eh = Ew-Ez
    692728            Ch = Cw-Cz
    693            
     729
    694730            s  = '    %s: vertex_values =  %.4f,\t %.4f,\t %.4f\n'\
    695731                 %(name.ljust(qwidth), Vh[0], Vh[1], Vh[2])
    696            
     732
    697733            s += '    %s: edge_values =    %.4f,\t %.4f,\t %.4f\n'\
    698734                 %(name.ljust(qwidth), Eh[0], Eh[1], Eh[2])
    699            
     735
    700736            s += '    %s: centroid_value = %.4f\n'\
    701                  %(name.ljust(qwidth), Ch[0])                               
    702            
     737                 %(name.ljust(qwidth), Ch[0])
     738
    703739            msg += s
    704740
     
    709745            Euh = uh.get_values(location='edges', indices=[k])[0]
    710746            Cuh = uh.get_values(location='centroids', indices=[k])
    711            
     747
    712748            Vvh = vh.get_values(location='vertices', indices=[k])[0]
    713749            Evh = vh.get_values(location='edges', indices=[k])[0]
     
    717753            Vu = Vuh/(Vh + epsilon)
    718754            Eu = Euh/(Eh + epsilon)
    719             Cu = Cuh/(Ch + epsilon)           
     755            Cu = Cuh/(Ch + epsilon)
    720756            name = 'U'
    721757            s  = '    %s: vertex_values =  %.4f,\t %.4f,\t %.4f\n'\
    722758                 %(name.ljust(qwidth), Vu[0], Vu[1], Vu[2])
    723            
     759
    724760            s += '    %s: edge_values =    %.4f,\t %.4f,\t %.4f\n'\
    725761                 %(name.ljust(qwidth), Eu[0], Eu[1], Eu[2])
    726            
     762
    727763            s += '    %s: centroid_value = %.4f\n'\
    728                  %(name.ljust(qwidth), Cu[0])                               
    729            
     764                 %(name.ljust(qwidth), Cu[0])
     765
    730766            msg += s
    731767
    732768            Vv = Vvh/(Vh + epsilon)
    733769            Ev = Evh/(Eh + epsilon)
    734             Cv = Cvh/(Ch + epsilon)           
     770            Cv = Cvh/(Ch + epsilon)
    735771            name = 'V'
    736772            s  = '    %s: vertex_values =  %.4f,\t %.4f,\t %.4f\n'\
    737773                 %(name.ljust(qwidth), Vv[0], Vv[1], Vv[2])
    738            
     774
    739775            s += '    %s: edge_values =    %.4f,\t %.4f,\t %.4f\n'\
    740776                 %(name.ljust(qwidth), Ev[0], Ev[1], Ev[2])
    741            
     777
    742778            s += '    %s: centroid_value = %.4f\n'\
    743                  %(name.ljust(qwidth), Cv[0])                               
    744            
     779                 %(name.ljust(qwidth), Cv[0])
     780
    745781            msg += s
    746 
    747782
    748783            # Froude number in each direction
     
    751786            Efx = Eu/(num.sqrt(g*Eh) + epsilon)
    752787            Cfx = Cu/(num.sqrt(g*Ch) + epsilon)
    753            
     788
    754789            s  = '    %s: vertex_values =  %.4f,\t %.4f,\t %.4f\n'\
    755790                 %(name.ljust(qwidth), Vfx[0], Vfx[1], Vfx[2])
    756            
     791
    757792            s += '    %s: edge_values =    %.4f,\t %.4f,\t %.4f\n'\
    758793                 %(name.ljust(qwidth), Efx[0], Efx[1], Efx[2])
    759            
     794
    760795            s += '    %s: centroid_value = %.4f\n'\
    761                  %(name.ljust(qwidth), Cfx[0])                               
    762            
     796                 %(name.ljust(qwidth), Cfx[0])
     797
    763798            msg += s
    764 
    765799
    766800            name = 'Froude (y)'
     
    768802            Efy = Ev/(num.sqrt(g*Eh) + epsilon)
    769803            Cfy = Cv/(num.sqrt(g*Ch) + epsilon)
    770            
     804
    771805            s  = '    %s: vertex_values =  %.4f,\t %.4f,\t %.4f\n'\
    772806                 %(name.ljust(qwidth), Vfy[0], Vfy[1], Vfy[2])
    773            
     807
    774808            s += '    %s: edge_values =    %.4f,\t %.4f,\t %.4f\n'\
    775809                 %(name.ljust(qwidth), Efy[0], Efy[1], Efy[2])
    776            
     810
    777811            s += '    %s: centroid_value = %.4f\n'\
    778                  %(name.ljust(qwidth), Cfy[0])                               
    779            
    780             msg += s           
    781 
    782                
     812                 %(name.ljust(qwidth), Cfy[0])
     813
     814            msg += s
    783815
    784816        return msg
    785         
     817       
    786818       
    787819
     
    880912        """Create volumetric balance report suitable for printing or logging.
    881913        """
    882 
    883         X = self.compute_boundary_flows()
    884         boundary_flows, total_boundary_inflow, total_boundary_outflow = X
     914       
     915        (boundary_flows, total_boundary_inflow,
     916         total_boundary_outflow) = self.compute_boundary_flows()
    885917       
    886918        s = '---------------------------\n'       
    887919        s += 'Volumetric balance report:\n'
    888920        s += '--------------------------\n'
    889         s += 'Total boundary inflow [m^3/s]: %.2e\n' % total_boundary_inflow
    890         s += 'Total boundary outflow [m^3/s]: %.2e\n' % total_boundary_outflow       
     921        s += 'Total boundary inflow [m^3/s]: %.2f\n' % total_boundary_inflow
     922        s += 'Total boundary outflow [m^3/s]: %.2f\n' % total_boundary_outflow       
    891923        s += 'Net boundary flow by tags [m^3/s]\n'
    892924        for tag in boundary_flows:
    893             s += '    %s [m^3/s]: %.2e\n' % (tag, boundary_flows[tag])
    894        
    895         s += 'Total net boundary flow [m^3/s]: %.2e\n' % (total_boundary_inflow + total_boundary_outflow)
    896         s += 'Total volume in domain [m^3]: %.2e\n' % self.compute_total_volume()
     925            s += '    %s [m^3/s]: %.2f\n' % (tag, boundary_flows[tag])
     926       
     927        s += 'Total net boundary flow [m^3/s]: %.2f\n' % (total_boundary_inflow + total_boundary_outflow)
     928        s += 'Total volume in domain [m^3]: %.2f\n' % self.compute_total_volume()
    897929       
    898930        # The go through explicit forcing update and record the rate of change for stage and
     
    904936        return s       
    905937           
    906            
    907            
    908            
    909                
    910 #=============== End of class Shallow Water Domain ===============================
    911 
     938################################################################################
     939# End of class Shallow Water Domain
     940################################################################################
    912941
    913942#-----------------
     
    915944#-----------------
    916945
     946## @brief Compute fluxes and timestep suitable for all volumes in domain.
     947# @param domain The domain to calculate fluxes for.
    917948def compute_fluxes(domain):
    918     """Compute all fluxes and the timestep suitable for all volumes
    919     in domain.
     949    """Compute fluxes and timestep suitable for all volumes in domain.
    920950
    921951    Compute total flux for each conserved quantity using "flux_function"
     
    933963      domain.explicit_update is reset to computed flux values
    934964      domain.timestep is set to the largest step satisfying all volumes.
    935    
    936965
    937966    This wrapper calls the underlying C version of compute fluxes
     
    939968
    940969    import sys
    941 
    942     N = len(domain) # number_of_triangles
     970    from shallow_water_ext import compute_fluxes_ext_central \
     971                                  as compute_fluxes_ext
     972
     973    N = len(domain)    # number_of_triangles
    943974
    944975    # Shortcuts
     
    949980
    950981    timestep = float(sys.maxint)
    951     from shallow_water_ext import\
    952          compute_fluxes_ext_central as compute_fluxes_ext
    953 
    954982
    955983    flux_timestep = compute_fluxes_ext(timestep,
     
    9801008    domain.flux_timestep = flux_timestep
    9811009
    982 
    983 
    984 #---------------------------------------
     1010################################################################################
    9851011# Module functions for gradient limiting
    986 #---------------------------------------
    987 
    988 
    989 # MH090605 The following method belongs to the shallow_water domain class
    990 # see comments in the corresponding method in shallow_water_ext.c
     1012################################################################################
     1013
     1014##
     1015# @brief Wrapper for C version of extrapolate_second_order_sw.
     1016# @param domain The domain to operate on.
     1017# @note MH090605 The following method belongs to the shallow_water domain class
     1018#       see comments in the corresponding method in shallow_water_ext.c
    9911019def extrapolate_second_order_sw(domain):
    992     """Wrapper calling C version of extrapolate_second_order_sw
    993     """
     1020    """Wrapper calling C version of extrapolate_second_order_sw"""
     1021
    9941022    import sys
     1023    from shallow_water_ext import extrapolate_second_order_sw as extrapol2
    9951024
    9961025    N = len(domain) # number_of_triangles
     
    10021031    Elevation = domain.quantities['elevation']
    10031032
    1004     from shallow_water_ext import extrapolate_second_order_sw as extrapol2
    10051033    extrapol2(domain,
    10061034              domain.surrogate_neighbours,
     
    10181046              int(domain.optimise_dry_cells))
    10191047
    1020 
     1048##
     1049# @brief Distribution from centroids to vertices specific to the SWW eqn.
     1050# @param domain The domain to operate on.
    10211051def distribute_using_vertex_limiter(domain):
    1022     """Distribution from centroids to vertices specific to the
    1023     shallow water wave
    1024     equation.
     1052    """Distribution from centroids to vertices specific to the SWW equation.
    10251053
    10261054    It will ensure that h (w-z) is always non-negative even in the
     
    10391067    Postcondition
    10401068      Conserved quantities defined at vertices
    1041 
    10421069    """
    1043 
    1044    
    10451070
    10461071    # Remove very thin layers of water
     
    10731098                raise 'Unknown order'
    10741099
    1075 
    10761100    # Take bed elevation into account when water heights are small
    10771101    balance_deep_and_shallow(domain)
     
    10821106        Q.interpolate_from_vertices_to_edges()
    10831107
    1084 
    1085 
     1108##
     1109# @brief Distribution from centroids to edges specific to the SWW eqn.
     1110# @param domain The domain to operate on.
    10861111def distribute_using_edge_limiter(domain):
    1087     """Distribution from centroids to edges specific to the
    1088     shallow water wave
    1089     equation.
     1112    """Distribution from centroids to edges specific to the SWW eqn.
    10901113
    10911114    It will ensure that h (w-z) is always non-negative even in the
     
    11031126    Postcondition
    11041127      Conserved quantities defined at vertices
    1105 
    11061128    """
    11071129
    11081130    # Remove very thin layers of water
    11091131    protect_against_infinitesimal_and_negative_heights(domain)
    1110 
    11111132
    11121133    for name in domain.conserved_quantities:
     
    11261147        Q.interpolate_from_vertices_to_edges()
    11271148
    1128 
     1149##
     1150# @brief  Protect against infinitesimal heights and associated high velocities.
     1151# @param domain The domain to operate on.
    11291152def protect_against_infinitesimal_and_negative_heights(domain):
    1130     """Protect against infinitesimal heights and associated high velocities
    1131     """
     1153    """Protect against infinitesimal heights and associated high velocities"""
     1154
     1155    from shallow_water_ext import protect
    11321156
    11331157    # Shortcuts
     
    11371161    ymomc = domain.quantities['ymomentum'].centroid_values
    11381162
    1139     from shallow_water_ext import protect
    1140 
    11411163    protect(domain.minimum_allowed_height, domain.maximum_allowed_speed,
    11421164            domain.epsilon, wc, zc, xmomc, ymomc)
    11431165
    1144 
    1145 
     1166##
     1167# @brief Wrapper for C function balance_deep_and_shallow_c().
     1168# @param domain The domain to operate on.
    11461169def balance_deep_and_shallow(domain):
    11471170    """Compute linear combination between stage as computed by
     
    11581181    """
    11591182
    1160     from shallow_water_ext import balance_deep_and_shallow as balance_deep_and_shallow_c
    1161 
     1183    from shallow_water_ext import balance_deep_and_shallow \
     1184                                  as balance_deep_and_shallow_c
    11621185
    11631186    # Shortcuts
    11641187    wc = domain.quantities['stage'].centroid_values
    11651188    zc = domain.quantities['elevation'].centroid_values
    1166 
    11671189    wv = domain.quantities['stage'].vertex_values
    11681190    zv = domain.quantities['elevation'].vertex_values
     
    11771199
    11781200    balance_deep_and_shallow_c(domain,
    1179                                wc, zc, wv, zv, wc, 
     1201                               wc, zc, wv, zv, wc,
    11801202                               xmomc, ymomc, xmomv, ymomv)
    11811203
    11821204
    1183 
    1184 
    1185 #------------------------------------------------------------------
     1205################################################################################
    11861206# Boundary conditions - specific to the shallow water wave equation
    1187 #------------------------------------------------------------------
     1207################################################################################
     1208
     1209##
     1210# @brief Class for a reflective boundary.
     1211# @note Inherits from Boundary.
    11881212class Reflective_boundary(Boundary):
    11891213    """Reflective boundary returns same conserved quantities as
     
    11951219    """
    11961220
    1197     def __init__(self, domain = None):
     1221    ##
     1222    # @brief Instantiate a Reflective_boundary.
     1223    # @param domain
     1224    def __init__(self, domain=None):
    11981225        Boundary.__init__(self)
    11991226
    12001227        if domain is None:
    12011228            msg = 'Domain must be specified for reflective boundary'
    1202             raise msg
     1229            raise Exception, msg
    12031230
    12041231        # Handy shorthands
    1205         self.stage   = domain.quantities['stage'].edge_values
    1206         self.xmom    = domain.quantities['xmomentum'].edge_values
    1207         self.ymom    = domain.quantities['ymomentum'].edge_values
     1232        self.stage = domain.quantities['stage'].edge_values
     1233        self.xmom = domain.quantities['xmomentum'].edge_values
     1234        self.ymom = domain.quantities['ymomentum'].edge_values
    12081235        self.normals = domain.normals
    12091236
    1210         self.conserved_quantities = num.zeros(3, num.Float)
    1211 
     1237        self.conserved_quantities = num.zeros(3, num.float)
     1238
     1239    ##
     1240    # @brief Return a representation of this instance.
    12121241    def __repr__(self):
    12131242        return 'Reflective_boundary'
    12141243
    1215 
     1244    ##
     1245    # @brief Calculate reflections (reverse outward momentum).
     1246    # @param vol_id
     1247    # @param edge_id
    12161248    def evaluate(self, vol_id, edge_id):
    12171249        """Reflective boundaries reverses the outward momentum
     
    12261258        normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
    12271259
    1228 
    12291260        r = rotate(q, normal, direction = 1)
    12301261        r[1] = -r[1]
     
    12341265
    12351266
    1236 
    1237 
     1267##
     1268# @brief Class for a transmissive boundary.
     1269# @note Inherits from Boundary.
    12381270class Transmissive_momentum_set_stage_boundary(Boundary):
    12391271    """Returns same momentum conserved quantities as
     
    12441276    Example:
    12451277
    1246     def waveform(t): 
     1278    def waveform(t):
    12471279        return sea_level + normalized_amplitude/cosh(t-25)**2
    12481280
    12491281    Bts = Transmissive_momentum_set_stage_boundary(domain, waveform)
    1250    
    12511282
    12521283    Underlying domain must be specified when boundary is instantiated
    12531284    """
    12541285
    1255     def __init__(self, domain = None, function=None):
     1286    ##
     1287    # @brief Instantiate a Reflective_boundary.
     1288    # @param domain
     1289    # @param function
     1290    def __init__(self, domain=None, function=None):
    12561291        Boundary.__init__(self)
    12571292
    12581293        if domain is None:
    12591294            msg = 'Domain must be specified for this type boundary'
    1260             raise msg
     1295            raise Exception, msg
    12611296
    12621297        if function is None:
    12631298            msg = 'Function must be specified for this type boundary'
    1264             raise msg
    1265 
    1266         self.domain   = domain
     1299            raise Exception, msg
     1300
     1301        self.domain = domain
    12671302        self.function = function
    12681303
     1304    ##
     1305    # @brief Return a representation of this instance.
    12691306    def __repr__(self):
    12701307        return 'Transmissive_momentum_set_stage_boundary(%s)' %self.domain
    12711308
     1309    ##
     1310    # @brief Calculate transmissive results.
     1311    # @param vol_id
     1312    # @param edge_id
    12721313    def evaluate(self, vol_id, edge_id):
    12731314        """Transmissive momentum set stage boundaries return the edge momentum
     
    12771318        q = self.domain.get_conserved_quantities(vol_id, edge = edge_id)
    12781319
    1279 
    12801320        t = self.domain.get_time()
    12811321
    12821322        if hasattr(self.function, 'time'):
    1283             # Roll boundary over if time exceeds           
     1323            # Roll boundary over if time exceeds
    12841324            while t > self.function.time[-1]:
    1285                 msg = 'WARNING: domain time %.2f has exceeded' %t
     1325                msg = 'WARNING: domain time %.2f has exceeded' % t
    12861326                msg += 'time provided in '
    12871327                msg += 'transmissive_momentum_set_stage boundary object.\n'
     
    12901330                t -= self.function.time[-1]
    12911331
    1292 
    12931332        value = self.function(t)
    12941333        try:
     
    12961335        except:
    12971336            x = float(value[0])
    1298            
     1337
    12991338        q[0] = x
    13001339        return q
    1301 
    13021340
    13031341        # FIXME: Consider this (taken from File_boundary) to allow
     
    13101348
    13111349
    1312 # Backward compatibility       
    1313 # FIXME(Ole): Deprecate
     1350##
     1351# @brief Deprecated boundary class.
    13141352class Transmissive_Momentum_Set_Stage_boundary(Transmissive_momentum_set_stage_boundary):
    13151353    pass
    13161354
    1317      
    1318 
     1355
     1356##
     1357# @brief A transmissive boundary, momentum set to zero.
     1358# @note Inherits from Bouondary.
    13191359class Transmissive_stage_zero_momentum_boundary(Boundary):
    1320     """Return same stage as those present in its neighbour volume. Set momentum to zero.
     1360    """Return same stage as those present in its neighbour volume.
     1361    Set momentum to zero.
    13211362
    13221363    Underlying domain must be specified when boundary is instantiated
    13231364    """
    13241365
     1366    ##
     1367    # @brief Instantiate a Transmissive (zero momentum) boundary.
     1368    # @param domain
    13251369    def __init__(self, domain=None):
    13261370        Boundary.__init__(self)
    13271371
    13281372        if domain is None:
    1329             msg = 'Domain must be specified for '
    1330             msg += 'Transmissive_stage_zero_momentum boundary'
     1373            msg = ('Domain must be specified for '
     1374                   'Transmissive_stage_zero_momentum boundary')
    13311375            raise Exception, msg
    13321376
    13331377        self.domain = domain
    13341378
     1379    ##
     1380    # @brief Return a representation of this instance.
    13351381    def __repr__(self):
    1336         return 'Transmissive_stage_zero_momentum_boundary(%s)' %self.domain
    1337 
     1382        return 'Transmissive_stage_zero_momentum_boundary(%s)' % self.domain
     1383
     1384    ##
     1385    # @brief Calculate transmissive (zero momentum) results.
     1386    # @param vol_id
     1387    # @param edge_id
    13381388    def evaluate(self, vol_id, edge_id):
    13391389        """Transmissive boundaries return the edge values
     
    13421392
    13431393        q = self.domain.get_conserved_quantities(vol_id, edge=edge_id)
    1344        
     1394
    13451395        q[1] = q[2] = 0.0
    13461396        return q
    13471397
    13481398
    1349        
     1399##
     1400# @brief Class for a Dirichlet discharge boundary.
     1401# @note Inherits from Boundary.
    13501402class Dirichlet_discharge_boundary(Boundary):
    13511403    """
     
    13561408    """
    13571409
     1410    ##
     1411    # @brief Instantiate a Dirichlet discharge boundary.
     1412    # @param domain
     1413    # @param stage0
     1414    # @param wh0
    13581415    def __init__(self, domain=None, stage0=None, wh0=None):
    13591416        Boundary.__init__(self)
    13601417
    13611418        if domain is None:
    1362             msg = 'Domain must be specified for this type boundary'
    1363             raise msg
     1419            msg = 'Domain must be specified for this type of boundary'
     1420            raise Exception, msg
    13641421
    13651422        if stage0 is None:
    1366             raise 'set stage'
     1423            raise Exception, 'Stage must be specified for this type of boundary'
    13671424
    13681425        if wh0 is None:
    13691426            wh0 = 0.0
    13701427
    1371         self.domain   = domain
    1372         self.stage0  = stage0
     1428        self.domain = domain
     1429        self.stage0 = stage0
    13731430        self.wh0 = wh0
    13741431
     1432    ##
     1433    # @brief Return a representation of this instance.
    13751434    def __repr__(self):
    1376         return 'Dirichlet_Discharge_boundary(%s)' %self.domain
    1377 
     1435        return 'Dirichlet_Discharge_boundary(%s)' % self.domain
     1436
     1437    ##
     1438    # @brief Calculate Dirichlet discharge boundary results.
     1439    # @param vol_id
     1440    # @param edge_id
    13781441    def evaluate(self, vol_id, edge_id):
    1379         """Set discharge in the (inward) normal direction
    1380         """
     1442        """Set discharge in the (inward) normal direction"""
    13811443
    13821444        normal = self.domain.get_normal(vol_id,edge_id)
    13831445        q = [self.stage0, -self.wh0*normal[0], -self.wh0*normal[1]]
    13841446        return q
    1385 
    13861447
    13871448        # FIXME: Consider this (taken from File_boundary) to allow
     
    13941455
    13951456
    1396        
    1397 # Backward compatibility       
     1457# Backward compatibility
    13981458# FIXME(Ole): Deprecate
     1459##
     1460# @brief Deprecated
    13991461class Dirichlet_Discharge_boundary(Dirichlet_discharge_boundary):
    14001462    pass
    1401                                                    
    1402    
    1403 
    1404 
    1405    
     1463
     1464
    14061465class Inflow_boundary(Boundary):
    14071466    """Apply given flow in m^3/s to boundary segment.
     
    14911550       
    14921551class Field_boundary(Boundary):
    1493     """Set boundary from given field represented in an sww file containing values
    1494     for stage, xmomentum and ymomentum.
    1495     Optionally, the user can specify mean_stage to offset the stage provided in the
    1496     sww file.
    1497 
    1498     This function is a thin wrapper around the generic File_boundary. The
     1552    """Set boundary from given field represented in an sww file containing
     1553    values for stage, xmomentum and ymomentum.
     1554
     1555    Optionally, the user can specify mean_stage to offset the stage provided
     1556    in the sww file.
     1557
     1558    This function is a thin wrapper around the generic File_boundary. The
    14991559    difference between the file_boundary and field_boundary is only that the
    15001560    field_boundary will allow you to change the level of the stage height when
    1501     you read in the boundary condition. This is very useful when running 
    1502     different tide heights in the same area as you need only to convert one 
    1503     boundary condition to a SWW file, ideally for tide height of 0 m 
     1561    you read in the boundary condition. This is very useful when running
     1562    different tide heights in the same area as you need only to convert one
     1563    boundary condition to a SWW file, ideally for tide height of 0 m
    15041564    (saving disk space). Then you can use field_boundary to read this SWW file
    15051565    and change the stage height (tide) on the fly depending on the scenario.
    1506    
    15071566    """
    15081567
    1509 
    1510     def __init__(self, filename, domain,
     1568    ##
     1569    # @brief Construct an instance of a 'field' boundary.
     1570    # @param filename Name of SWW file containing stage, x and ymomentum.
     1571    # @param domain Shallow water domain for which the boundary applies.
     1572    # @param mean_stage Mean water level added to stage derived from SWW file.
     1573    # @param time_thinning Time step thinning factor.
     1574    # @param time_limit
     1575    # @param boundary_polygon
     1576    # @param default_boundary None or an instance of Boundary.
     1577    # @param use_cache True if caching is to be used.
     1578    # @param verbose True if this method is to be verbose.
     1579    def __init__(self,
     1580                 filename,
     1581                 domain,
    15111582                 mean_stage=0.0,
    15121583                 time_thinning=1,
    15131584                 time_limit=None,
    1514                  boundary_polygon=None,   
    1515                  default_boundary=None,                 
     1585                 boundary_polygon=None,
     1586                 default_boundary=None,
    15161587                 use_cache=False,
    15171588                 verbose=False):
     
    15231594                    from the boundary condition
    15241595        time_thinning: Will set how many time steps from the sww file read in
    1525                        will be interpolated to the boundary. For example if 
     1596                       will be interpolated to the boundary. For example if
    15261597                       the sww file has 1 second time steps and is 24 hours
    1527                        in length it has 86400 time steps. If you set 
    1528                        time_thinning to 1 it will read all these steps. 
     1598                       in length it has 86400 time steps. If you set
     1599                       time_thinning to 1 it will read all these steps.
    15291600                       If you set it to 100 it will read every 100th step eg
    15301601                       only 864 step. This parameter is very useful to increase
    1531                        the speed of a model run that you are setting up 
     1602                       the speed of a model run that you are setting up
    15321603                       and testing.
    1533                        
    1534         default_boundary: Must be either None or an instance of a 
     1604
     1605        default_boundary: Must be either None or an instance of a
    15351606                          class descending from class Boundary.
    1536                           This will be used in case model time exceeds 
     1607                          This will be used in case model time exceeds
    15371608                          that available in the underlying data.
     1609
    15381610                          Note that mean_stage will also be added to this.
    15391611                                               
    15401612        use_cache:
    15411613        verbose:
    1542        
    15431614        """
    15441615
    15451616        # Create generic file_boundary object
    1546         self.file_boundary = File_boundary(filename, domain,
     1617        self.file_boundary = File_boundary(filename,
     1618                                           domain,
    15471619                                           time_thinning=time_thinning,
    15481620                                           time_limit=time_limit,
     
    15521624                                           verbose=verbose)
    15531625
    1554        
    15551626        # Record information from File_boundary
    15561627        self.F = self.file_boundary.F
    15571628        self.domain = self.file_boundary.domain
    1558        
     1629
    15591630        # Record mean stage
    15601631        self.mean_stage = mean_stage
    15611632
    1562 
     1633    ##
     1634    # @note Generate a string representation of this instance.
    15631635    def __repr__(self):
    15641636        return 'Field boundary'
    15651637
    1566 
     1638    ##
     1639    # @brief Calculate 'field' boundary results.
     1640    # @param vol_id
     1641    # @param edge_id
    15671642    def evaluate(self, vol_id=None, edge_id=None):
    15681643        """Return linearly interpolated values based on domain.time
     
    15701645        vol_id and edge_id are ignored
    15711646        """
    1572        
     1647
    15731648        # Evaluate file boundary
    15741649        q = self.file_boundary.evaluate(vol_id, edge_id)
     
    15801655        return q
    15811656
    1582    
    1583 
    1584 #-----------------------
     1657
     1658################################################################################
    15851659# Standard forcing terms
    1586 #-----------------------
    1587 
     1660################################################################################
     1661
     1662##
     1663# @brief Apply gravitational pull in the presence of bed slope.
     1664# @param domain The domain to apply gravity to.
     1665# @note Wrapper for C function gravity_c().
    15881666def gravity(domain):
    15891667    """Apply gravitational pull in the presence of bed slope
     
    15911669    """
    15921670
     1671    from shallow_water_ext import gravity as gravity_c
     1672
    15931673    xmom = domain.quantities['xmomentum'].explicit_update
    15941674    ymom = domain.quantities['ymomentum'].explicit_update
     
    16021682    x = domain.get_vertex_coordinates()
    16031683    g = domain.g
    1604    
    1605 
    1606     from shallow_water_ext import gravity as gravity_c
    1607     gravity_c(g, h, z, x, xmom, ymom) #, 1.0e-6)
    1608 
    1609 
    1610 
     1684
     1685    gravity_c(g, h, z, x, xmom, ymom)    #, 1.0e-6)
     1686
     1687##
     1688# @brief Apply friction to a surface (implicit).
     1689# @param domain The domain to apply Manning friction to.
     1690# @note Wrapper for C function manning_friction_c().
    16111691def manning_friction_implicit(domain):
    1612     """Apply (Manning) friction to water momentum   
     1692    """Apply (Manning) friction to water momentum
    16131693    Wrapper for c version
    16141694    """
    16151695
    1616 
    1617     #print 'Implicit friction'
     1696    from shallow_water_ext import manning_friction as manning_friction_c
    16181697
    16191698    xmom = domain.quantities['xmomentum']
     
    16341713    g = domain.g
    16351714
    1636     from shallow_water_ext import manning_friction as manning_friction_c
    16371715    manning_friction_c(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update)
    16381716
    1639 
     1717##
     1718# @brief Apply friction to a surface (explicit).
     1719# @param domain The domain to apply Manning friction to.
     1720# @note Wrapper for C function manning_friction_c().
    16401721def manning_friction_explicit(domain):
    1641     """Apply (Manning) friction to water momentum   
     1722    """Apply (Manning) friction to water momentum
    16421723    Wrapper for c version
    16431724    """
    16441725
    1645     # print 'Explicit friction'
     1726    from shallow_water_ext import manning_friction as manning_friction_c
    16461727
    16471728    xmom = domain.quantities['xmomentum']
     
    16621743    g = domain.g
    16631744
    1664     from shallow_water_ext import manning_friction as manning_friction_c
    16651745    manning_friction_c(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update)
    16661746
    16671747
    16681748# FIXME (Ole): This was implemented for use with one of the analytical solutions (Sampson?)
    1669 # Is it still needed (30 Oct 2007)?
     1749##
     1750# @brief Apply linear friction to a surface.
     1751# @param domain The domain to apply Manning friction to.
     1752# @note Is this still used (30 Oct 2007)?
    16701753def linear_friction(domain):
    16711754    """Apply linear friction to water momentum
     
    16991782                xmom_update[k] += S*uh[k]
    17001783                ymom_update[k] += S*vh[k]
    1701 
    1702 
    1703 
    17041784
    17051785def depth_dependent_friction(domain, default_friction,
     
    17221802    """
    17231803
    1724     import Numeric as num
     1804    import numpy as num
    17251805   
    17261806    # Create a temp array to store updated depth dependent friction for wet elements
    17271807    # EHR this is outwardly inneficient but not obvious how to avoid recreating each call??????
    17281808    N=len(domain)
    1729     wet_friction    = num.zeros(N, num.Float)
     1809    wet_friction    = num.zeros(N, num.float)
    17301810    wet_friction[:] = default_n0   # Initially assign default_n0 to all array so sure have no zeros values
    17311811   
     
    17741854
    17751855
    1776 
    1777 
    1778 
    1779 
    1780 #---------------------------------
     1856################################################################################
    17811857# Experimental auxiliary functions
    1782 #---------------------------------
     1858################################################################################
     1859
     1860##
     1861# @brief Check forcefield parameter.
     1862# @param f Object to check.
     1863# @note 'f' may be a callable object or a scalar value.
    17831864def check_forcefield(f):
    1784     """Check that f is either
     1865    """Check that force object is as expected.
     1866   
     1867    Check that f is either:
    17851868    1: a callable object f(t,x,y), where x and y are vectors
    17861869       and that it returns an array or a list of same length
     
    17911874    if callable(f):
    17921875        N = 3
    1793         x = num.ones(3, num.Float)
    1794         y = num.ones(3, num.Float)
     1876        x = num.ones(3, num.float)
     1877        y = num.ones(3, num.float)
    17951878        try:
    17961879            q = f(1.0, x=x, y=y)
     
    17981881            msg = 'Function %s could not be executed:\n%s' %(f, e)
    17991882            # FIXME: Reconsider this semantics
    1800             raise msg
     1883            raise Exception, msg
    18011884
    18021885        try:
    1803             q = num.array(q, num.Float)
     1886            q = num.array(q, num.float)
    18041887        except:
    1805             msg = 'Return value from vector function %s could ' %f
    1806             msg += 'not be converted into a Numeric array of floats.\n'
    1807             msg += 'Specified function should return either list or array.'
    1808             raise msg
     1888            msg = ('Return value from vector function %s could not '
     1889                   'be converted into a numeric array of floats.\nSpecified '
     1890                   'function should return either list or array.' % f)
     1891            raise Exception, msg
    18091892
    18101893        # Is this really what we want?
    1811         msg = 'Return vector from function %s ' %f
    1812         msg += 'must have same lenght as input vectors'
    1813         assert len(q) == N, msg
    1814 
     1894        # info is "(func name, filename, defining line)"
     1895        func_info = (f.func_name, f.func_code.co_filename,
     1896                     f.func_code.co_firstlineno)
     1897        func_msg = 'Function %s (defined in %s, line %d)' % func_info
     1898        try:
     1899            result_len = len(q)
     1900        except:
     1901            msg = '%s must return vector' % func_msg
     1902            self.fail(msg)
     1903        msg = '%s must return vector of length %d' % (func_msg, N)
     1904        assert result_len == N, msg
    18151905    else:
    18161906        try:
    18171907            f = float(f)
    18181908        except:
    1819             msg = 'Force field %s must be either a scalar' %f
    1820             msg += ' or a vector function'
    1821             raise Exception(msg)
     1909            msg = ('Force field %s must be a scalar value coercible to float.'
     1910                   % str(f))
     1911            raise Exception, msg
     1912
    18221913    return f
    18231914
    18241915
     1916##
     1917# Class to apply a wind stress to a domain.
    18251918class Wind_stress:
    18261919    """Apply wind stress to water momentum in terms of
     
    18281921    """
    18291922
     1923    ##
     1924    # @brief Create an instance of Wind_stress.
     1925    # @param *args
     1926    # @param **kwargs
    18301927    def __init__(self, *args, **kwargs):
    18311928        """Initialise windfield from wind speed s [m/s]
     
    18801977        else:
    18811978           # Assume info is in 2 keyword arguments
    1882 
    18831979           if len(kwargs) == 2:
    18841980               s = kwargs['s']
    18851981               phi = kwargs['phi']
    18861982           else:
    1887                raise 'Assumes two keyword arguments: s=..., phi=....'
     1983               raise Exception, 'Assumes two keyword arguments: s=..., phi=....'
    18881984
    18891985        self.speed = check_forcefield(s)
     
    18921988        self.const = eta_w*rho_a/rho_w
    18931989
    1894 
     1990    ##
     1991    # @brief 'execute' this class instance.
     1992    # @param domain
    18951993    def __call__(self, domain):
    1896         """Evaluate windfield based on values found in domain
    1897         """
     1994        """Evaluate windfield based on values found in domain"""
    18981995
    18991996        from math import pi, cos, sin, sqrt
     
    19021999        ymom_update = domain.quantities['ymomentum'].explicit_update
    19032000
    1904         N = len(domain) # number_of_triangles
     2001        N = len(domain)    # number_of_triangles
    19052002        t = domain.time
    19062003
     
    19102007        else:
    19112008            # Assume s is a scalar
    1912 
    19132009            try:
    1914                 s_vec = self.speed * num.ones(N, num.Float)
     2010                s_vec = self.speed * num.ones(N, num.float)
    19152011            except:
    19162012                msg = 'Speed must be either callable or a scalar: %s' %self.s
    19172013                raise msg
    1918 
    19192014
    19202015        if callable(self.phi):
     
    19252020
    19262021            try:
    1927                 phi_vec = self.phi * num.ones(N, num.Float)
     2022                phi_vec = self.phi * num.ones(N, num.float)
    19282023            except:
    19292024                msg = 'Angle must be either callable or a scalar: %s' %self.phi
     
    19342029
    19352030
     2031##
     2032# @brief Assign wind field values
     2033# @param xmom_update
     2034# @param ymom_update
     2035# @param s_vec
     2036# @param phi_vec
     2037# @param const
    19362038def assign_windfield_values(xmom_update, ymom_update,
    19372039                            s_vec, phi_vec, const):
    19382040    """Python version of assigning wind field to update vectors.
    1939     A c version also exists (for speed)
     2041    A C version also exists (for speed)
    19402042    """
     2043
    19412044    from math import pi, cos, sin, sqrt
    19422045
     
    19592062
    19602063
    1961 
    1962 
    1963 
     2064##
     2065# @brief A class for a general explicit forcing term.
    19642066class General_forcing:
    19652067    """General explicit forcing term for update of quantity
    1966    
     2068
    19672069    This is used by Inflow and Rainfall for instance
    1968    
     2070
    19692071
    19702072    General_forcing(quantity_name, rate, center, radius, polygon)
    19712073
    19722074    domain:     ANUGA computational domain
    1973     quantity_name: Name of quantity to update. 
     2075    quantity_name: Name of quantity to update.
    19742076                   It must be a known conserved quantity.
    1975                    
    1976     rate [?/s]: Total rate of change over the specified area. 
     2077
     2078    rate [?/s]: Total rate of change over the specified area.
    19772079                This parameter can be either a constant or a
    1978                 function of time. Positive values indicate increases, 
     2080                function of time. Positive values indicate increases,
    19792081                negative values indicate decreases.
    19802082                Rate can be None at initialisation but must be specified
     
    19902092    Either center, radius or polygon can be specified but not both.
    19912093    If neither are specified the entire domain gets updated.
    1992     All coordinates to be specified in absolute UTM coordinates (x, y) assuming the zone of domain.   
    1993    
     2094    All coordinates to be specified in absolute UTM coordinates (x, y) assuming the zone of domain.
     2095
    19942096    Inflow or Rainfall for examples of use
    19952097    """
     
    19982100    # FIXME (AnyOne) : Add various methods to allow spatial variations
    19992101
     2102    ##
     2103    # @brief Create an instance of this forcing term.
     2104    # @param domain
     2105    # @param quantity_name
     2106    # @param rate
     2107    # @param center
     2108    # @param radius
     2109    # @param polygon
     2110    # @param default_rate
     2111    # @param verbose
    20002112    def __init__(self,
    20012113                 domain,
    20022114                 quantity_name,
    20032115                 rate=0.0,
    2004                  center=None, radius=None,
     2116                 center=None,
     2117                 radius=None,
    20052118                 polygon=None,
    20062119                 default_rate=None,
    20072120                 verbose=False):
    2008                      
     2121
     2122        from math import pi, cos, sin
     2123
    20092124        if center is None:
    2010             msg = 'I got radius but no center.'       
     2125            msg = 'I got radius but no center.'
    20112126            assert radius is None, msg
    2012            
     2127
    20132128        if radius is None:
    2014             msg += 'I got center but no radius.'       
     2129            msg += 'I got center but no radius.'
    20152130            assert center is None, msg
    2016            
    2017            
    2018                      
    2019         from math import pi, cos, sin
    20202131
    20212132        self.domain = domain
     
    20242135        self.center = ensure_numeric(center)
    20252136        self.radius = radius
    2026         self.polygon = polygon       
     2137        self.polygon = polygon
    20272138        self.verbose = verbose
    2028         self.value = 0.0 # Can be used to remember value at
    2029                          # previous timestep in order to obtain rate
     2139        self.value = 0.0    # Can be used to remember value at
     2140                            # previous timestep in order to obtain rate
    20302141
    20312142        # Get boundary (in absolute coordinates)
    20322143        bounding_polygon = domain.get_boundary_polygon()
    2033 
    20342144
    20352145        # Update area if applicable
     
    20392149            assert polygon is None, msg
    20402150
    2041 
    20422151            # Check that circle center lies within the mesh.
    2043             msg = 'Center %s specified for forcing term did not' %(str(center))
     2152            msg = 'Center %s specified for forcing term did not' % str(center)
    20442153            msg += 'fall within the domain boundary.'
    20452154            assert is_inside_polygon(center, bounding_polygon), msg
     
    20492158            periphery_points = []
    20502159            for i in range(N):
    2051 
    20522160                theta = 2*pi*i/100
    2053                
     2161
    20542162                x = center[0] + radius*cos(theta)
    20552163                y = center[1] + radius*sin(theta)
     
    20572165                periphery_points.append([x,y])
    20582166
    2059 
    20602167            for point in periphery_points:
    2061                 msg = 'Point %s on periphery for forcing term' %(str(point))
     2168                msg = 'Point %s on periphery for forcing term' % str(point)
    20622169                msg += ' did not fall within the domain boundary.'
    20632170                assert is_inside_polygon(point, bounding_polygon), msg
    20642171
    2065        
    20662172        if polygon is not None:
    2067 
    20682173            # Check that polygon lies within the mesh.
    20692174            for point in self.polygon:
    2070                 msg = 'Point %s in polygon for forcing term' %(point)
     2175                msg = 'Point %s in polygon for forcing term' % str(point)
    20712176                msg += ' did not fall within the domain boundary.'
    20722177                assert is_inside_polygon(point, bounding_polygon), msg
    2073                
    2074                                  
    20752178
    20762179        # Pointer to update vector
     
    20782181
    20792182        # Determine indices in flow area
    2080         N = len(domain)   
     2183        N = len(domain)
    20812184        points = domain.get_centroid_coordinates(absolute=True)
    20822185
     
    20852188        if self.center is not None and self.radius is not None:
    20862189            # Inlet is circular
    2087            
    2088             inlet_region = 'center=%s, radius=%s' %(self.center, self.radius)
    2089            
     2190            inlet_region = 'center=%s, radius=%s' % (self.center, self.radius)
     2191
    20902192            self.exchange_indices = []
    20912193            for k in range(N):
    2092                 x, y = points[k,:] # Centroid
    2093                
     2194                x, y = points[k,:]    # Centroid
     2195
    20942196                c = self.center
    20952197                if ((x-c[0])**2+(y-c[1])**2) < self.radius**2:
    20962198                    self.exchange_indices.append(k)
    2097                    
    2098         if self.polygon is not None:                   
     2199
     2200        if self.polygon is not None:
    20992201            # Inlet is polygon
    2100            
    21012202            inlet_region = 'polygon=%s' % (self.polygon)
    21022203            self.exchange_indices = inside_polygon(points, self.polygon)
    2103            
    2104            
    2105            
     2204
    21062205        if self.exchange_indices is None:
    21072206            self.exchange_area = polygon_area(bounding_polygon)
     
    21092208            if len(self.exchange_indices) == 0:
    21102209                msg = 'No triangles have been identified in '
    2111                 msg += 'specified region: %s' %inlet_region
     2210                msg += 'specified region: %s' % inlet_region
    21122211                raise Exception, msg
    21132212
     
    21272226           
    21282227        # Check and store default_rate
    2129         msg = 'Keyword argument default_rate must be either None '
    2130         msg += 'or a function of time.\n I got %s' %(str(default_rate))
    2131         assert default_rate is None or \
    2132                type(default_rate) in [IntType, FloatType] or \
    2133                callable(default_rate), msg
    2134        
     2228        msg = ('Keyword argument default_rate must be either None '
     2229               'or a function of time.\nI got %s.' % str(default_rate))
     2230        assert (default_rate is None or
     2231                type(default_rate) in [IntType, FloatType] or
     2232                callable(default_rate)), msg
     2233
    21352234        if default_rate is not None:
    2136 
    21372235            # If it is a constant, make it a function
    21382236            if not callable(default_rate):
     
    21402238                default_rate = lambda t: tmp
    21412239
    2142            
    21432240            # Check that default_rate is a function of one argument
    21442241            try:
     
    21482245
    21492246        self.default_rate = default_rate
    2150         self.default_rate_invoked = False    # Flag       
    2151        
    2152 
     2247        self.default_rate_invoked = False    # Flag
     2248
     2249    ##
     2250    # @brief Execute this instance.
     2251    # @param domain
    21532252    def __call__(self, domain):
    2154         """Apply inflow function at time specified in domain and update stage
    2155         """
     2253        """Apply inflow function at time specified in domain, update stage"""
    21562254
    21572255        # Call virtual method allowing local modifications
    2158 
    21592256        t = domain.get_time()
    21602257        try:
     
    21642261        except Modeltime_too_late, e:
    21652262            if self.default_rate is None:
    2166                 raise Exception, e # Reraise exception
     2263                raise Exception, e    # Reraise exception
    21672264            else:
    21682265                # Pass control to default rate function
    21692266                rate = self.default_rate(t)
    2170                
     2267
    21712268                if self.default_rate_invoked is False:
    21722269                    # Issue warning the first time
    2173                     msg = '%s' %str(e)
    2174                     msg += 'Instead I will use the default rate: %s\n'\
    2175                         %str(self.default_rate)
    2176                     msg += 'Note: Further warnings will be supressed'
     2270                    msg = ('%s\n'
     2271                           'Instead I will use the default rate: %s\n'
     2272                           'Note: Further warnings will be supressed'
     2273                           % (str(e), str(self.default_rate)))
    21772274                    warn(msg)
    2178                    
     2275
    21792276                    # FIXME (Ole): Replace this crude flag with
    21802277                    # Python's ability to print warnings only once.
    21812278                    # See http://docs.python.org/lib/warning-filter.html
    21822279                    self.default_rate_invoked = True
    2183                    
    2184 
    2185            
    2186                
    21872280
    21882281        if rate is None:
    2189             msg = 'Attribute rate must be specified in General_forcing'
    2190             msg += ' or its descendants before attempting to call it'
     2282            msg = ('Attribute rate must be specified in General_forcing '
     2283                   'or its descendants before attempting to call it')
    21912284            raise Exception, msg
    2192        
    21932285
    21942286        # Now rate is a number
    21952287        if self.verbose is True:
    2196             print 'Rate of %s at time = %.2f = %f' %(self.quantity_name,
    2197                                                      domain.get_time(),
    2198                                                      rate)
    2199 
     2288            print 'Rate of %s at time = %.2f = %f' % (self.quantity_name,
     2289                                                      domain.get_time(),
     2290                                                      rate)
    22002291
    22012292        if self.exchange_indices is None:
     
    22062297                self.update[k] += rate
    22072298
    2208 
     2299    ##
     2300    # @brief Update the internal rate.
     2301    # @param t A callable or scalar used to set the rate.
     2302    # @return The new rate.
    22092303    def update_rate(self, t):
    22102304        """Virtual method allowing local modifications by writing an
    22112305        overriding version in descendant
    2212        
    2213         """
    2214         if callable(self.rate):
    2215             rate = self.rate(t)
    2216         else:
    2217             rate = self.rate
     2306        """
     2307
     2308        if callable(self.rate):
     2309            rate = self.rate(t)
     2310        else:
     2311            rate = self.rate
    22182312
    22192313        return rate
    22202314
    2221 
     2315    ##
     2316    # @brief Get values for the specified quantity.
     2317    # @param quantity_name Name of the quantity of interest.
     2318    # @return The value(s) of the quantity.
     2319    # @note If 'quantity_name' is None, use self.quantity_name.
    22222320    def get_quantity_values(self, quantity_name=None):
    2223         """Return values for specified quantity restricted to opening 
    2224        
     2321        """Return values for specified quantity restricted to opening
     2322
    22252323        Optionally a quantity name can be specified if values from another
    22262324        quantity is sought
    22272325        """
    2228        
     2326
    22292327        if quantity_name is None:
    22302328            quantity_name = self.quantity_name
    2231            
     2329
    22322330        q = self.domain.quantities[quantity_name]
    2233         return q.get_values(location='centroids', 
     2331        return q.get_values(location='centroids',
    22342332                            indices=self.exchange_indices)
    2235    
    2236 
     2333
     2334    ##
     2335    # @brief Set value for the specified quantity.
     2336    # @param val The value object used to set value.
     2337    # @param quantity_name Name of the quantity of interest.
     2338    # @note If 'quantity_name' is None, use self.quantity_name.
    22372339    def set_quantity_values(self, val, quantity_name=None):
    2238         """Set values for specified quantity restricted to opening 
    2239        
     2340        """Set values for specified quantity restricted to opening
     2341
    22402342        Optionally a quantity name can be specified if values from another
    2241         quantity is sought       
     2343        quantity is sought
    22422344        """
    22432345
    22442346        if quantity_name is None:
    22452347            quantity_name = self.quantity_name
    2246                    
    2247         q = self.domain.quantities[self.quantity_name]               
    2248         q.set_values(val,
    2249                      location='centroids',
    2250                      indices=self.exchange_indices)   
    2251 
    2252 
    2253 
     2348
     2349        q = self.domain.quantities[self.quantity_name]
     2350        q.set_values(val,
     2351                     location='centroids',
     2352                     indices=self.exchange_indices)
     2353
     2354
     2355##
     2356# @brief A class for rainfall forcing function.
     2357# @note Inherits from General_forcing.
    22542358class Rainfall(General_forcing):
    22552359    """Class Rainfall - general 'rain over entire domain' forcing term.
    2256    
     2360
    22572361    Used for implementing Rainfall over the entire domain.
    2258        
    2259         Current Limited to only One Gauge..
    2260        
    2261         Need to add Spatial Varying Capability
    2262         (This module came from copying and amending the Inflow Code)
    2263    
     2362
     2363        Current Limited to only One Gauge..
     2364
     2365        Need to add Spatial Varying Capability
     2366        (This module came from copying and amending the Inflow Code)
     2367
    22642368    Rainfall(rain)
    22652369
    2266     domain   
    2267     rain [mm/s]:  Total rain rate over the specified domain. 
    2268                   NOTE: Raingauge Data needs to reflect the time step.
    2269                   IE: if Gauge is mm read at a time step, then the input
     2370    domain
     2371    rain [mm/s]:  Total rain rate over the specified domain.
     2372                  NOTE: Raingauge Data needs to reflect the time step.
     2373                  IE: if Gauge is mm read at a time step, then the input
    22702374                  here is as mm/(timeStep) so 10mm in 5minutes becomes
    22712375                  10/(5x60) = 0.0333mm/s.
    2272        
    2273        
     2376
    22742377                  This parameter can be either a constant or a
    2275                   function of time. Positive values indicate inflow, 
     2378                  function of time. Positive values indicate inflow,
    22762379                  negative values indicate outflow.
    22772380                  (and be used for Infiltration - Write Seperate Module)
     
    22792382                  the inflow region and then applied to update the
    22802383                  stage quantity.
    2281                  
    2282                   Note also that any reference to the internal attribute 'rate'
    2283                   later will use the one converted to m/s.
    22842384
    22852385    polygon: Specifies a polygon to restrict the rainfall.
    2286    
     2386
    22872387    Examples
    22882388    How to put them in a run File...
    2289        
     2389
    22902390    #------------------------------------------------------------------------
    22912391    # Setup specialised forcing terms
     
    22942394    # input of Rainfall in mm/s
    22952395
    2296     catchmentrainfall = Rainfall(rain=file_function('Q100_2hr_Rain.tms')) 
     2396    catchmentrainfall = Rainfall(rain=file_function('Q100_2hr_Rain.tms'))
    22972397                        # Note need path to File in String.
    22982398                        # Else assumed in same directory
     
    23012401    """
    23022402
    2303    
     2403    ##
     2404    # @brief Create an instance of the class.
     2405    # @param domain Domain of interest.
     2406    # @param rate Total rain rate over the specified domain (mm/s).
     2407    # @param center
     2408    # @param radius
     2409    # @param polygon Polygon  to restrict rainfall.
     2410    # @param default_rate
     2411    # @param verbose True if this instance is to be verbose.
    23042412    def __init__(self,
    23052413                 domain,
    2306                  rate=0.0,
    2307                  center=None, radius=None,
     2414                 rate=0.0,
     2415                 center=None,
     2416                 radius=None,
    23082417                 polygon=None,
    2309                  default_rate=None,                 
     2418                 default_rate=None,
    23102419                 verbose=False):
    23112420
     
    23162425            rain = rate/1000.0
    23172426
    2318         if default_rate is not None:   
     2427        if default_rate is not None:
    23192428            if callable(default_rate):
    23202429                default_rain = lambda t: default_rate(t)/1000.0
     
    23242433            default_rain = None
    23252434
    2326 
    23272435           
    23282436           
     
    23312439                                 'stage',
    23322440                                 rate=rain,
    2333                                  center=center, radius=radius,
     2441                                 center=center,
     2442                                 radius=radius,
    23342443                                 polygon=polygon,
    23352444                                 default_rate=default_rain,
    23362445                                 verbose=verbose)
    23372446
    2338        
    2339 
    2340 
    2341 
    2342 
     2447
     2448##
     2449# @brief A class for inflow (rain and drain) forcing function.
     2450# @note Inherits from General_forcing.
    23432451class Inflow(General_forcing):
    23442452    """Class Inflow - general 'rain and drain' forcing term.
    2345    
     2453
    23462454    Useful for implementing flows in and out of the domain.
    2347    
     2455
    23482456    Inflow(flow, center, radius, polygon)
    23492457
    23502458    domain
    2351     rate [m^3/s]: Total flow rate over the specified area. 
     2459    rate [m^3/s]: Total flow rate over the specified area.
    23522460                  This parameter can be either a constant or a
    2353                   function of time. Positive values indicate inflow, 
     2461                  function of time. Positive values indicate inflow,
    23542462                  negative values indicate outflow.
    23552463                  The specified flow will be divided by the area of
    2356                   the inflow region and then applied to update stage.     
     2464                  the inflow region and then applied to update stage.
    23572465    center [m]: Coordinates at center of flow point
    23582466    radius [m]: Size of circular area
     
    23602468
    23612469    Either center, radius or polygon must be specified
    2362    
     2470
    23632471    Examples
    23642472
    23652473    # Constant drain at 0.003 m^3/s.
    23662474    # The outflow area is 0.07**2*pi=0.0154 m^2
    2367     # This corresponds to a rate of change of 0.003/0.0154 = 0.2 m/s 
    2368     #                                     
     2475    # This corresponds to a rate of change of 0.003/0.0154 = 0.2 m/s
     2476    #
    23692477    Inflow((0.7, 0.4), 0.07, -0.003)
    23702478
     
    23722480    # Tap turning up to a maximum inflow of 0.0142 m^3/s.
    23732481    # The inflow area is 0.03**2*pi = 0.00283 m^2
    2374     # This corresponds to a rate of change of 0.0142/0.00283 = 5 m/s     
     2482    # This corresponds to a rate of change of 0.0142/0.00283 = 5 m/s
    23752483    # over the specified area
    23762484    Inflow((0.5, 0.5), 0.03, lambda t: min(0.01*t, 0.0142))
     
    23872495
    23882496    domain.forcing_terms.append(hydrograph)
    2389    
    23902497    """
    23912498
    2392 
     2499    ##
     2500    # @brief Create an instance of the class.
     2501    # @param domain Domain of interest.
     2502    # @param rate Total rain rate over the specified domain (mm/s).
     2503    # @param center
     2504    # @param radius
     2505    # @param polygon Polygon  to restrict rainfall.
     2506    # @param default_rate
     2507    # @param verbose True if this instance is to be verbose.
    23932508    def __init__(self,
    23942509                 domain,
    2395                  rate=0.0,
    2396                  center=None, radius=None,
     2510                 rate=0.0,
     2511                 center=None,
     2512                 radius=None,
    23972513                 polygon=None,
    23982514                 default_rate=None,
    2399                  verbose=False):                 
    2400 
    2401 
     2515                 verbose=False):
    24022516        # Create object first to make area is available
    24032517        General_forcing.__init__(self,
     
    24052519                                 'stage',
    24062520                                 rate=rate,
    2407                                  center=center, radius=radius,
     2521                                 center=center,
     2522                                 radius=radius,
    24082523                                 polygon=polygon,
    24092524                                 default_rate=default_rate,
    24102525                                 verbose=verbose)
    24112526
     2527    ##
     2528    # @brief Update the instance rate.
     2529    # @param t New rate object.
    24122530    def update_rate(self, t):
    24132531        """Virtual method allowing local modifications by writing an
    24142532        overriding version in descendant
    24152533
    2416         This one converts m^3/s to m/s which can be added directly 
     2534        This one converts m^3/s to m/s which can be added directly
    24172535        to 'stage' in ANUGA
    24182536        """
    24192537
    2420         if callable(self.rate):
    2421             _rate = self.rate(t)/self.exchange_area
    2422         else:
    2423             _rate = self.rate/self.exchange_area
     2538        if callable(self.rate):
     2539            _rate = self.rate(t)/self.exchange_area
     2540        else:
     2541            _rate = self.rate/self.exchange_area
    24242542
    24252543        return _rate
    24262544
    24272545
    2428 
    2429 
    2430 #------------------
     2546################################################################################
    24312547# Initialise module
    2432 #------------------
    2433 
     2548################################################################################
    24342549
    24352550from anuga.utilities import compile
    24362551if compile.can_use_C_extension('shallow_water_ext.c'):
    2437     # Underlying C implementations can be accessed
    2438 
     2552    # Underlying C implementations can be accessed
    24392553    from shallow_water_ext import rotate, assign_windfield_values
    24402554else:
    2441     msg = 'C implementations could not be accessed by %s.\n ' %__file__
     2555    msg = 'C implementations could not be accessed by %s.\n ' % __file__
    24422556    msg += 'Make sure compile_all.py has been run as described in '
    24432557    msg += 'the ANUGA installation guide.'
    24442558    raise Exception, msg
    2445 
    24462559
    24472560# Optimisation with psyco
     
    24562569            #Psyco isn't supported on 64 bit systems, but it doesn't matter
    24572570        else:
    2458             msg = 'WARNING: psyco (speedup) could not import'+\
    2459                   ', you may want to consider installing it'
     2571            msg = ('WARNING: psyco (speedup) could not be imported, '
     2572                   'you may want to consider installing it')
    24602573            print msg
    24612574    else:
     
    24632576        psyco.bind(Domain.compute_fluxes)
    24642577
     2578
    24652579if __name__ == "__main__":
    24662580    pass
    2467 
    2468 
Note: See TracChangeset for help on using the changeset viewer.