Changeset 6054
- Timestamp:
- Dec 10, 2008, 11:16:27 AM (16 years ago)
- 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 9 9 10 10 class 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 434 class Culvert_flow_energy: 11 435 """Culvert flow - transfer water from one hole to another 12 436 … … 452 876 453 877 878 -
anuga_core/source/anuga/culvert_flows/example_rating_curve.csv
r6052 r6054 1 Delta W (m),Q (m3/s),Velocity (m/s) 1 Name, type, width or diameter, height, length, losses, description 2 Test Culvert, box, 3, 1.8, 5, 1, 50% blocked test case 3 4 5 Rating Curve 6 Delta W (m), Q (m3/s), Velocity (m/s) 2 7 0,0,0 3 8 0.1,0.720243203,0.800270226
Note: See TracChangeset
for help on using the changeset viewer.