Changeset 9681 for trunk/anuga_core/anuga/structures
- Timestamp:
- Feb 23, 2015, 9:21:46 AM (10 years ago)
- Location:
- trunk/anuga_core/anuga/structures
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/anuga_core/anuga/structures/boyd_box_operator_Amended3.py
r8125 r9681 32 32 verbose=False): 33 33 34 34 raise Exception('(Feb 2015) This code seems broken -- the structure operator call is incorrect -- retire?') 35 35 36 anuga.Structure_operator.__init__(self, 36 37 domain, -
trunk/anuga_core/anuga/structures/internal_boundary_operator.py
r9672 r9681 3 3 import numpy 4 4 from numpy.linalg import solve 5 import scipy 6 import scipy.optimize as sco 5 7 6 8 … … 75 77 zero_outflow_momentum=zero_outflow_momentum, 76 78 use_old_momentum_method=False, 79 always_use_Q_wetdry_adjustment=False, 77 80 force_constant_inlet_elevations=force_constant_inlet_elevations, 78 81 description=description, … … 227 230 def discharge_routine_implicit(self): 228 231 """Uses semi-implicit discharge estimation: 229 Discharge = 0.5*(Q(H0, T0) +Q(H0 + delta_H, T0+delta_T))232 Discharge = (1-theta)*Q(H0, T0) + theta*Q(H0 + delta_H, T0+delta_T)) 230 233 where H0 = headwater stage, T0 = tailwater stage, delta_H = change in 231 234 headwater stage over a timestep, delta_T = change in tailwater stage over a 232 timestep, and Q is the discharge function 233 234 We can estimate delta_H, delta_T by solving the following system (based on mass conservation): 235 A0*delta_H = -dt/2*( Q(H0, T0) + Q(H0 + delta_H, T0 + delta_T)) 236 A1*delta_T = dt/2*( Q(H0, T0) + Q(H0 + delta_H, T0 + delta_T)) 237 where A0, A1 are the inlet areas, and dt is the timestep 238 239 We linearise the system with the approximation: 240 Q(H0 + delta_H, T0 + delta_T) ~= Q(H0, T0) + delQ/delH * delta_H + delQ/delT*delta_T 241 where delQ/delH and delQ/delT are evaluated with numerical finite differences 242 235 timestep, and Q is the discharge function, and theta is a constant in 236 [0,1] determining the degree of implicitness (currently hard-coded). 237 238 Note this is effectively assuming: 239 1) Q is a function of stage, not energy (so we can relate mass change directly to delta_H, delta_T). We 240 could generalise it to the energy case ok. 241 2) The stage is computed on the exchange line (or the change in 242 stage at the enquiry point is effectively the same as that on the exchange 243 line) 243 244 244 245 """ … … 263 264 E0 = self.inlet0_energy 264 265 E1 = self.inlet1_energy 265 266 # Numerical derivatives267 dE0 = 0.01268 dE1 = 0.01269 dQ_dE0 = (self.internal_boundary_function(E0+dE0, E1) - self.internal_boundary_function(E0-dE0, E1))/(2*dE0)270 dQ_dE1 = (self.internal_boundary_function(E0, E1+dE1) - self.internal_boundary_function(E0, E1-dE1))/(2*dE1)271 272 # Assemble and solve matrix273 266 A0 = self.inlets[0].area 274 267 A1 = self.inlets[1].area 275 hdt = 0.5*dt 276 277 M11 = A0 + dQ_dE0*hdt 278 M12 = dQ_dE1*hdt 279 M21 = -dQ_dE0*hdt 280 M22 = A1 - dQ_dE1*hdt 281 282 lhs = numpy.array([ [M11, M12], [M21, M22]]) 283 rhs = numpy.array([ -Q0*dt, Q0*dt]) 284 # sol contains delta_E0, delta_E1 285 sol = solve(lhs, rhs) 286 287 #Q = 0.5*(Q0 + ( Q0 + sol[0]*dQ_dE0 + sol[1]*dQ_dE1)) 288 Q1 = self.internal_boundary_function(E0 + sol[0], E1 + sol[1]) 289 Q = 0.5*(Q0 + Q1) 268 theta = 1.0 269 270 sol = numpy.array([0., 0.]) # estimate of (delta_H, delta_T) 271 areas = numpy.array([A0, A1]) 272 273 # Use scipy root finding 274 def F_to_solve(sol): 275 Q1 = self.internal_boundary_function(E0 + sol[0], E1 + sol[1]) 276 discharge = (1.0-theta)*Q0 + theta*Q1 277 output = sol*areas - discharge*dt*numpy.array([-1., 1.]) 278 return(output) 279 280 final_sol = sco.root(F_to_solve, sol, method='lm').x 281 Q1 = self.internal_boundary_function(E0 + final_sol[0], E1 + final_sol[1]) 282 Q = (1.0-theta)*Q0 + theta*Q1 283 290 284 else: 291 285 Q = Q0 -
trunk/anuga_core/anuga/structures/structure_operator.py
r9671 r9681 39 39 zero_outflow_momentum=True, 40 40 use_old_momentum_method=True, 41 always_use_Q_wetdry_adjustment=True, 41 42 force_constant_inlet_elevations=False, 42 43 description=None, … … 94 95 raise Exception(msg) 95 96 self.use_old_momentum_method = use_old_momentum_method 97 self.always_use_Q_wetdry_adjustment = always_use_Q_wetdry_adjustment 96 98 97 99 … … 119 121 self.accumulated_flow = 0.0 120 122 self.discharge = 0.0 123 self.discharge_function_value = 0.0 121 124 self.velocity = 0.0 122 125 self.outlet_depth = 0.0 … … 218 221 old_inflow_ymom = self.inflow.get_average_ymom() 219 222 220 #semi_implicit = True221 #if semi_implicit:222 223 # FIXME: This update replaces Q with Q*new_inflow_depth/old_inflow_depth224 # This has good wetting and drying properties but means that225 # discharge != Q.226 # We should be able to check if old_inflow_depth*old_inflow_area > Q*dt,227 # and in that case we don't need this implicit trick, and could228 # have the discharge = Q (whereas in the nearly-dry case we want229 # the trick).230 231 223 # Implement the update of flow over a timestep by 232 224 # using a semi-implict update. This ensures that … … 237 229 dt_Q_on_d = 0.0 238 230 239 # The depth update is: 231 always_use_Q_wetdry_adjustment = self.always_use_Q_wetdry_adjustment 232 use_Q_wetdry_adjustment = ((always_use_Q_wetdry_adjustment) |\ 233 (old_inflow_depth*self.inflow.get_area() <= Q*timestep)) 234 # If we use the 'Q_adjustment', then the discharge is rescaled so that 235 # the depth update is: 240 236 # new_inflow_depth*inflow_area = 241 237 # old_inflow_depth*inflow_area - 242 238 # timestep*Q*(new_inflow_depth/old_inflow_depth) 243 # The last term in () is a wet-dry improvement trick 244 # Note inflow_area is the area of all triangles in the inflow 245 # region -- so this is a volumetric balance equation 239 # The last term in () is a wet-dry improvement trick (which rescales Q) 240 # 241 # Before Feb 2015 this rescaling was always done (even if the flow was 242 # not near wet-dry). Now if use_old_Q_adjustment=False, the rescaling 243 # is only done if required to avoid drying 244 # 246 245 # 247 246 factor = 1.0/(1.0 + dt_Q_on_d/self.inflow.get_area()) 248 new_inflow_depth = old_inflow_depth*factor 247 248 249 if use_Q_wetdry_adjustment: 250 # FIXME: 251 new_inflow_depth = old_inflow_depth*factor 252 253 if(old_inflow_depth>0.): 254 timestep_star = timestep*new_inflow_depth/old_inflow_depth 255 else: 256 timestep_star = 0. 257 258 else: 259 new_inflow_depth = old_inflow_depth - timestep*Q/self.inflow.get_area() 260 timestep_star = timestep 249 261 250 262 if(self.use_old_momentum_method): … … 256 268 else: 257 269 # For the momentum balance, note that Q also advects the momentum, 258 # The volumetric momentum flux should be Q*momentum , where270 # The volumetric momentum flux should be Q*momentum/depth, where 259 271 # momentum has an average value of new_inflow_mom (or 260 # old_inflow_mom). For consistency we keep using the 261 # (new_inflow_depth/old_inflow_depth) factor for discharge: 272 # old_inflow_mom). We use old_inflow_depth for depth 262 273 # 263 274 # new_inflow_xmom*inflow_area = 264 275 # old_inflow_xmom*inflow_area - 265 # [timestep*Q *(new_inflow_depth/old_inflow_depth)]*new_inflow_xmom276 # [timestep*Q]*new_inflow_xmom/old_inflow_depth 266 277 # and: 267 278 # new_inflow_ymom*inflow_area = 268 279 # old_inflow_ymom*inflow_area - 269 # [timestep*Q *(new_inflow_depth/old_inflow_depth)]*new_inflow_ymom280 # [timestep*Q]*new_inflow_ymom/old_inflow_depth 270 281 # 271 # The choice of new_inflow_mom in the final term at the end might be 272 # replaced with old_inflow_mom 282 # The units balance: m^2/s*m^2 = m^2/s*m^2 - s*m^3/s*m^2/s *m^(-1) 273 283 # 274 factor2 = 1.0/(1.0 + dt_Q_on_d*new_inflow_depth/self.inflow.get_area()) 284 if old_inflow_depth > 0.: 285 if use_Q_wetdry_adjustment: 286 # Replace dt*Q with dt*Q*new_inflow_depth/old_inflow_depth = dt_Q_on_d*new_inflow_depth 287 factor2 = 1.0/(1.0 + dt_Q_on_d*new_inflow_depth/(old_inflow_depth*self.inflow.get_area())) 288 else: 289 factor2 = 1.0/(1.0 + timestep*Q/(old_inflow_depth*self.inflow.get_area())) 290 else: 291 factor2 = 0. 292 275 293 new_inflow_xmom = old_inflow_xmom*factor2 276 294 new_inflow_ymom = old_inflow_ymom*factor2 … … 289 307 290 308 # set outflow 291 if old_inflow_depth > 0.0 :292 timestep_star = timestep*new_inflow_depth/old_inflow_depth293 else:294 timestep_star = 0.0295 296 309 outflow_extra_depth = Q*timestep_star/self.outflow.get_area() 297 310 outflow_direction = - self.outflow.outward_culvert_vector … … 306 319 self.accumulated_flow += gain 307 320 self.discharge = Q*timestep_star/timestep 321 self.discharge_function_value = Q 308 322 self.velocity = barrel_speed 309 323 self.outlet_depth = outlet_depth … … 541 555 542 556 message += 'Discharge [m^3/s]: %.2f\n' % self.discharge 557 message += 'Discharge_function_value [m^3/s]: %.2f\n' % self.discharge_function_value 543 558 message += 'Velocity [m/s]: %.2f\n' % self.velocity 544 559 message += 'Outlet Depth [m]: %.2f\n' % self.outlet_depth … … 562 577 self.log_filename = self.domain.get_datadir() + '/' + self.label + '.log' 563 578 log_to_file(self.log_filename, self.statistics(), mode='w') 564 log_to_file(self.log_filename, 'time, discharge, velocity, accumulated_flow, driving_energy, delta_total_energy')579 log_to_file(self.log_filename, 'time, discharge, discharge_function_value, velocity, accumulated_flow, driving_energy, delta_total_energy') 565 580 566 581 #log_to_file(self.log_filename, self.culvert_type) … … 571 586 message = '%.5f, ' % self.domain.get_time() 572 587 message += '%.5f, ' % self.discharge 588 message += '%.5f, ' % self.discharge_function_value 573 589 message += '%.5f, ' % self.velocity 574 590 message += '%.5f, ' % self.accumulated_flow
Note: See TracChangeset
for help on using the changeset viewer.