Changeset 6054


Ignore:
Timestamp:
Dec 10, 2008, 11:16:27 AM (16 years ago)
Author:
ole
Message:

Restructure culvert metadata

Location:
anuga_core/source/anuga/culvert_flows
Files:
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • anuga_core/source/anuga/culvert_flows/culvert_class.py

    r6051 r6054  
    99
    1010class Culvert_flow:
     11    """Culvert flow - transfer water from one hole to another
     12   
     13
     14    Input: Two points, pipe_size (either diameter or width, height),
     15    mannings_rougness,
     16    inlet/outlet energy_loss_coefficients, internal_bend_coefficent,
     17    top-down_blockage_factor and bottom_up_blockage_factor
     18   
     19    """
     20
     21    def __init__(self,
     22                 domain,
     23                 
     24                 label=None,
     25                 description=None,
     26                 end_point0=None,
     27                 end_point1=None,
     28                 
     29                 
     30
     31                 manning=None,          # Mannings Roughness for Culvert
     32                 invert_level0=None,    # Invert level at opening 0
     33                 invert_level1=None,    # Invert level at opening 1
     34                 loss_exit=None,
     35                 loss_entry=None,
     36                 loss_bend=None,
     37                 loss_special=None,
     38                 blockage_topdwn=None,
     39                 blockage_bottup=None,
     40                 culvert_routine=None,
     41                 number_of_barrels=1,
     42                 update_interval=None,
     43                 verbose=False):
     44       
     45        from Numeric import sqrt, sum
     46
     47        # Input check
     48        if diameter is not None:
     49            self.culvert_type = 'circle'
     50            self.diameter = diameter
     51            if height is not None or width is not None:
     52                msg = 'Either diameter or width&height must be specified, '
     53                msg += 'but not both.'
     54                raise Exception, msg
     55        else:
     56            if height is not None:
     57                if width is None:
     58                    self.culvert_type = 'square'                               
     59                    width = height
     60                else:
     61                    self.culvert_type = 'rectangle'
     62            elif width is not None:
     63                if height is None:
     64                    self.culvert_type = 'square'                               
     65                    height = width
     66            else:
     67                msg = 'Either diameter or width&height must be specified.'
     68                raise Exception, msg               
     69               
     70            if height == width:
     71                self.culvert_type = 'square'                                               
     72               
     73            self.height = height
     74            self.width = width
     75
     76           
     77        assert self.culvert_type in ['circle', 'square', 'rectangle']
     78       
     79        assert number_of_barrels >= 1
     80        self.number_of_barrels = number_of_barrels
     81       
     82       
     83        # Set defaults
     84        if manning is None: manning = 0.012   # Default roughness for pipe
     85        if loss_exit is None: loss_exit = 1.00
     86        if loss_entry is None: loss_entry = 0.50
     87        if loss_bend is None: loss_bend=0.00
     88        if loss_special is None: loss_special=0.00
     89        if blockage_topdwn is None: blockage_topdwn=0.00
     90        if blockage_bottup is None: blockage_bottup=0.00
     91        if culvert_routine is None:
     92            culvert_routine=boyd_generalised_culvert_model
     93           
     94        if label is None: label = 'culvert_flow'
     95        label += '_' + str(id(self))
     96        self.label = label
     97       
     98        # File for storing culvert quantities
     99        self.timeseries_filename = label + '_timeseries.csv'
     100        fid = open(self.timeseries_filename, 'w')
     101        fid.write('time, E0, E1, Velocity, Discharge\n')
     102        fid.close()
     103
     104        # Log file for storing general textual output
     105        self.log_filename = label + '.log'         
     106        log_to_file(self.log_filename, self.label)       
     107        log_to_file(self.log_filename, description)
     108        log_to_file(self.log_filename, self.culvert_type)       
     109
     110
     111        # Create the fundamental culvert polygons from POLYGON
     112        if self.culvert_type == 'circle':
     113            # Redefine width and height for use with create_culvert_polygons
     114            width = height = diameter
     115       
     116        P = create_culvert_polygons(end_point0,
     117                                    end_point1,
     118                                    width=width,   
     119                                    height=height,
     120                                    number_of_barrels=number_of_barrels)
     121       
     122        if verbose is True:
     123            pass
     124            #plot_polygons([[end_point0, end_point1],
     125            #               P['exchange_polygon0'],
     126            #               P['exchange_polygon1'],
     127            #               P['enquiry_polygon0'],
     128            #               P['enquiry_polygon1']],
     129            #              figname='culvert_polygon_output')
     130            #import sys; sys.exit()                           
     131
     132
     133        # Check that all polygons lie within the mesh.
     134        bounding_polygon = domain.get_boundary_polygon()
     135        for key in P.keys():
     136            if key in ['exchange_polygon0',
     137                       'exchange_polygon1',
     138                       'enquiry_polygon0',
     139                       'enquiry_polygon1']:
     140                for point in P[key]:
     141               
     142                    msg = 'Point %s in polygon %s for culvert %s did not'\
     143                        %(str(point), key, self.label)
     144                    msg += 'fall within the domain boundary.'
     145                    assert is_inside_polygon(point, bounding_polygon), msg
     146       
     147
     148        # Create inflow object at each end of the culvert.
     149        self.openings = []
     150        self.openings.append(Inflow(domain,
     151                                    polygon=P['exchange_polygon0']))
     152
     153        self.openings.append(Inflow(domain,
     154                                    polygon=P['exchange_polygon1']))                                   
     155
     156
     157        # Assume two openings for now: Referred to as 0 and 1
     158        assert len(self.openings) == 2
     159       
     160        # Store basic geometry
     161        self.end_points = [end_point0, end_point1]
     162        self.invert_levels = [invert_level0, invert_level1]               
     163        #self.enquiry_polygons = [P['enquiry_polygon0'], P['enquiry_polygon1']]
     164        self.enquiry_polylines = [P['enquiry_polygon0'][:2],
     165                                  P['enquiry_polygon1'][:2]]
     166        self.vector = P['vector']
     167        self.length = P['length']; assert self.length > 0.0
     168        self.verbose = verbose
     169        self.last_time = 0.0       
     170        self.last_update = 0.0 # For use with update_interval       
     171        self.update_interval = update_interval
     172       
     173
     174        # Store hydraulic parameters
     175        self.manning = manning
     176        self.loss_exit = loss_exit
     177        self.loss_entry = loss_entry
     178        self.loss_bend = loss_bend
     179        self.loss_special = loss_special
     180        self.sum_loss = loss_exit + loss_entry + loss_bend + loss_special
     181        self.blockage_topdwn = blockage_topdwn
     182        self.blockage_bottup = blockage_bottup
     183
     184        # Store culvert routine
     185        self.culvert_routine = culvert_routine
     186
     187       
     188        # Create objects to update momentum (a bit crude at this stage)
     189
     190       
     191        xmom0 = General_forcing(domain, 'xmomentum',
     192                                polygon=P['exchange_polygon0'])
     193
     194        xmom1 = General_forcing(domain, 'xmomentum',
     195                                polygon=P['exchange_polygon1'])
     196
     197        ymom0 = General_forcing(domain, 'ymomentum',
     198                                polygon=P['exchange_polygon0'])
     199
     200        ymom1 = General_forcing(domain, 'ymomentum',
     201                                polygon=P['exchange_polygon1'])
     202
     203        self.opening_momentum = [ [xmom0, ymom0], [xmom1, ymom1] ]
     204       
     205
     206        # Print something
     207        s = 'Culvert Effective Length = %.2f m' %(self.length)
     208        log_to_file(self.log_filename, s)
     209   
     210        s = 'Culvert Direction is %s\n' %str(self.vector)
     211        log_to_file(self.log_filename, s)       
     212       
     213       
     214    def __call__(self, domain):
     215        from anuga.utilities.numerical_tools import mean
     216       
     217        from anuga.config import g, epsilon
     218        from Numeric import take, sqrt
     219        from anuga.config import velocity_protection       
     220
     221
     222        log_filename = self.log_filename
     223         
     224        # Time stuff
     225        time = domain.get_time()
     226       
     227       
     228        update = False
     229        if self.update_interval is None:
     230            update = True
     231        else:   
     232            if time - self.last_update > self.update_interval or time == 0.0:
     233                update = True
     234
     235        #print 'call', time, time - self.last_update
     236               
     237                               
     238        if update is True:
     239            #print 'Updating', time, time - self.last_update
     240            self.last_update = time
     241       
     242            delta_t = time-self.last_time
     243            s = '\nTime = %.2f, delta_t = %f' %(time, delta_t)
     244            log_to_file(log_filename, s)
     245       
     246            msg = 'Time did not advance'
     247            if time > 0.0: assert delta_t > 0.0, msg
     248
     249
     250            # Get average water depths at each opening       
     251            openings = self.openings   # There are two Opening [0] and [1]
     252            for i, opening in enumerate(openings):
     253                dq = domain.quantities
     254               
     255                # Compute mean values of selected quantitites in the
     256                # exchange area in front of the culvert
     257                # Stage and velocity comes from enquiry area
     258                # and elevation from exchange area
     259               
     260                stage = dq['stage'].get_values(location='centroids',
     261                                               indices=opening.exchange_indices)           
     262                w = mean(stage) # Average stage
     263
     264                # Use invert level instead of elevation if specified
     265                invert_level = self.invert_levels[i]
     266                if invert_level is not None:
     267                    z = invert_level
     268                else:
     269                    elevation = dq['elevation'].get_values(location='centroids',
     270                                                           indices=opening.exchange_indices)
     271                    z = mean(elevation) # Average elevation
     272
     273                # Estimated depth above the culvert inlet
     274                d = w - z  # Used for calculations involving depth
     275                if d < 0.0:
     276                    # This is possible since w and z are taken at different locations
     277                    #msg = 'D < 0.0: %f' %d
     278                    #raise msg
     279                    d = 0.0
     280               
     281
     282                # Ratio of depth to culvert height.
     283                # If ratio > 1 then culvert is running full
     284                if self.culvert_type == 'circle':
     285                    ratio = d/self.diameter
     286                else:   
     287                    ratio = d/self.height 
     288                opening.ratio = ratio
     289                   
     290                   
     291                # Average measures of energy in front of this opening
     292                polyline = self.enquiry_polylines[i]
     293                #print 't = %.4f, opening=%d,' %(domain.time, i),
     294                opening.total_energy = domain.get_energy_through_cross_section(polyline,
     295                                                                               kind='total')           
     296                #print 'Et = %.3f m' %opening.total_energy
     297
     298                # Store current average stage and depth with each opening object
     299                opening.depth = d
     300                opening.depth_trigger = d # Use this for now
     301                opening.stage = w
     302                opening.elevation = z
     303               
     304
     305            #################  End of the FOR loop ################################################
     306
     307            # We now need to deal with each opening individually
     308               
     309            # Determine flow direction based on total energy difference
     310            delta_Et = openings[0].total_energy - openings[1].total_energy
     311
     312            if delta_Et > 0:
     313                #print 'Flow U/S ---> D/S'
     314                inlet = openings[0]
     315                outlet = openings[1]
     316
     317                inlet.momentum = self.opening_momentum[0]
     318                outlet.momentum = self.opening_momentum[1]
     319
     320            else:
     321                #print 'Flow D/S ---> U/S'
     322                inlet = openings[1]
     323                outlet = openings[0]
     324
     325                inlet.momentum = self.opening_momentum[1]
     326                outlet.momentum = self.opening_momentum[0]
     327               
     328                delta_Et = -delta_Et
     329
     330            self.inlet = inlet
     331            self.outlet = outlet
     332               
     333            msg = 'Total energy difference is negative'
     334            assert delta_Et > 0.0, msg
     335
     336            delta_h = inlet.stage - outlet.stage
     337            delta_z = inlet.elevation - outlet.elevation
     338            culvert_slope = (delta_z/self.length)
     339
     340            if culvert_slope < 0.0:
     341                # Adverse gradient - flow is running uphill
     342                # Flow will be purely controlled by uphill outlet face
     343                if self.verbose is True:
     344                    print 'WARNING: Flow is running uphill. Watch Out!', inlet.elevation, outlet.elevation
     345
     346
     347            s = 'Delta total energy = %.3f' %(delta_Et)
     348            log_to_file(log_filename, s)
     349
     350
     351            # Calculate discharge for one barrel and set inlet.rate and outlet.rate
     352            Q, barrel_velocity, culvert_outlet_depth = self.culvert_routine(self, inlet, outlet, delta_Et, g)
     353       
     354            # Adjust discharge for multiple barrels
     355            Q *= self.number_of_barrels
     356
     357            # Compute barrel momentum
     358            barrel_momentum = barrel_velocity*culvert_outlet_depth
     359                   
     360            s = 'Barrel velocity = %f' %barrel_velocity
     361            log_to_file(log_filename, s)
     362
     363            # Compute momentum vector at outlet
     364            outlet_mom_x, outlet_mom_y = self.vector * barrel_momentum
     365               
     366            s = 'Directional momentum = (%f, %f)' %(outlet_mom_x, outlet_mom_y)
     367            log_to_file(log_filename, s)
     368
     369            # Log timeseries to file
     370            fid = open(self.timeseries_filename, 'a')       
     371            fid.write('%f, %f, %f, %f, %f\n'\
     372                          %(time,
     373                            openings[0].total_energy,
     374                            openings[1].total_energy,
     375                            barrel_velocity,
     376                            Q))
     377            fid.close()
     378
     379            # Update momentum       
     380            delta_t = time - self.last_time
     381            if delta_t > 0.0:
     382                xmomentum_rate = outlet_mom_x - outlet.momentum[0].value
     383                xmomentum_rate /= delta_t
     384                   
     385                ymomentum_rate = outlet_mom_y - outlet.momentum[1].value
     386                ymomentum_rate /= delta_t
     387                       
     388                s = 'X Y MOM_RATE = (%f, %f) ' %(xmomentum_rate, ymomentum_rate)
     389                log_to_file(log_filename, s)                   
     390            else:
     391                xmomentum_rate = ymomentum_rate = 0.0
     392
     393
     394            # Set momentum rates for outlet jet
     395            outlet.momentum[0].rate = xmomentum_rate
     396            outlet.momentum[1].rate = ymomentum_rate
     397
     398            # Remember this value for next step (IMPORTANT)
     399            outlet.momentum[0].value = outlet_mom_x
     400            outlet.momentum[1].value = outlet_mom_y                   
     401
     402            if int(domain.time*100) % 100 == 0:
     403                s = 'T=%.5f, Culvert Discharge = %.3f f'\
     404                    %(time, Q)
     405                s += ' Depth= %0.3f  Momentum = (%0.3f, %0.3f)'\
     406                     %(culvert_outlet_depth, outlet_mom_x,outlet_mom_y)
     407                s += ' Momentum rate: (%.4f, %.4f)'\
     408                     %(xmomentum_rate, ymomentum_rate)                   
     409                s+='Outlet Vel= %.3f'\
     410                    %(barrel_velocity)
     411                log_to_file(log_filename, s)
     412           
     413               
     414
     415
     416        # Execute flow term for each opening
     417        # This is where Inflow objects are evaluated and update the domain
     418        for opening in self.openings:
     419            opening(domain)
     420
     421        # Execute momentum terms
     422        # This is where Inflow objects are evaluated and update the domain
     423        self.outlet.momentum[0](domain)
     424        self.outlet.momentum[1](domain)       
     425           
     426        # Store value of time #FIXME(Ole): Maybe only every time we update   
     427        self.last_time = time
     428
     429
     430
     431       
     432       
     433
     434class Culvert_flow_energy:
    11435    """Culvert flow - transfer water from one hole to another
    12436   
     
    452876
    453877
     878       
  • anuga_core/source/anuga/culvert_flows/example_rating_curve.csv

    r6052 r6054  
    1 Delta W (m),Q (m3/s),Velocity (m/s)
     1Name, type, width or diameter, height, length, losses, description     
     2Test Culvert, box, 3, 1.8, 5, 1, 50% blocked test case
     3
     4
     5Rating Curve
     6Delta W (m), Q (m3/s), Velocity (m/s)
    270,0,0
    380.1,0.720243203,0.800270226
Note: See TracChangeset for help on using the changeset viewer.