Changeset 5294
- Timestamp:
- May 8, 2008, 10:58:15 PM (17 years ago)
- Location:
- anuga_core/source/anuga/shallow_water
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
anuga_core/source/anuga/shallow_water/shallow_water_domain.py
r5290 r5294 96 96 import Transmissive_boundary 97 97 98 from anuga.utilities.numerical_tools import gradient, mean 98 from anuga.utilities.numerical_tools import gradient, mean, ensure_numeric 99 99 from anuga.config import minimum_storable_height 100 100 from anuga.config import minimum_allowed_height, maximum_allowed_speed … … 106 106 from anuga.config import use_edge_limiter 107 107 from anuga.config import use_centroid_velocities 108 109 110 from anuga.utilities.polygon import inside_polygon, polygon_area 111 108 112 109 113 … … 1479 1483 1480 1484 1481 class Rainfall: 1485 1486 1487 class General_forcing: 1488 """Class General_forcing - general explicit forcing term for update of quantity 1489 1490 This is used by Inflow and Rainfall for instance 1491 1492 1493 General_forcing(quantity_name, rate, center, radius, polygon) 1494 1495 domain: ANUGA computational domain 1496 quantity_name: Name of quantity to update. It must be a known conserved quantity. 1497 rate [?/s]: Total rate of change over the specified area. 1498 This parameter can be either a constant or a 1499 function of time. Positive values indicate increases, 1500 negative values indicate decreases. 1501 Rate can be None at initialisation but must be specified 1502 before forcting term is applied (i.e. simulation has started). 1503 1504 center [m]: Coordinates at center of flow point 1505 radius [m]: Size of circular area 1506 polygon: Arbitrary polygon. 1507 1508 1509 Either center, radius or polygon can be specified but not both. 1510 If neither are specified the entire domain gets updated. 1511 1512 See Inflow or Rainfall for examples of use 1513 """ 1514 1515 1516 # FIXME (AnyOne) : Add various methods to allow spatial variations 1517 1518 def __init__(self, 1519 domain, 1520 quantity_name, 1521 rate=None, 1522 center=None, radius=None, 1523 polygon=None, 1524 verbose=False): 1525 1526 1527 from math import pi 1528 1529 self.domain = domain 1530 self.quantity_name = quantity_name 1531 self.rate = rate 1532 self.center = ensure_numeric(center) 1533 self.radius = radius 1534 self.polygon = polygon 1535 self.verbose = verbose 1536 1537 # Update area if applicable 1538 self.area = None 1539 if center is not None and radius is not None: 1540 assert len(center) == 2 1541 msg = 'Polygon cannot be specified when center and radius are' 1542 assert polygon is None, msg 1543 1544 self.area = radius**2*pi 1545 1546 if polygon is not None: 1547 self.area = polygon_area(self.polygon) 1548 1549 1550 # Pointer to update vector 1551 self.update = domain.quantities[self.quantity_name].explicit_update 1552 1553 # Determine indices in flow area 1554 N = len(domain) 1555 points = domain.get_centroid_coordinates(absolute=True) 1556 1557 self.indices = None 1558 if self.center is not None and self.radius is not None: 1559 # Inlet is circular 1560 1561 self.indices = [] 1562 for k in range(N): 1563 x, y = points[k,:] # Centroid 1564 if ((x-self.center[0])**2+(y-self.center[1])**2) < self.radius**2: 1565 self.indices.append(k) 1566 1567 if self.polygon is not None: 1568 # Inlet is polygon 1569 self.indices = inside_polygon(points, self.polygon) 1570 1571 1572 1573 1574 1575 def __call__(self, domain): 1576 """Apply inflow function at time specified in domain and update stage 1577 """ 1578 1579 # Call virtual method allowing local modifications 1580 rate = self.update_rate(domain.get_time()) 1581 if rate is None: 1582 msg = 'Attribute rate must be specified in General_forcing' 1583 msg += ' or its descendants before attempting to call it' 1584 raise Exception, msg 1585 1586 1587 # Now rate is a number 1588 if self.verbose is True: 1589 print 'Rate of %s at time = %.2f = %f' %(self.quantity_name, 1590 domain.get_time(), 1591 rate) 1592 1593 1594 if self.indices is None: 1595 self.update[:] += rate 1596 else: 1597 # Brute force assignment of restricted rate 1598 for k in self.indices: 1599 self.update[k] += rate 1600 1601 1602 def update_rate(self, t): 1603 """Virtual method allowing local modifications by writing an 1604 overriding version in descendant 1605 1606 """ 1607 if callable(self.rate): 1608 rate = self.rate(t) 1609 else: 1610 rate = self.rate 1611 1612 return rate 1613 1614 1615 def get_quantity_values(self): 1616 """Return values for specified quantity restricted to opening 1617 """ 1618 return self.domain.quantities[self.quantity_name].get_values(indices=self.indices) 1619 1620 1621 def set_quantity_values(self, val): 1622 """Set values for specified quantity restricted to opening 1623 """ 1624 self.domain.quantities[self.quantity_name].set_values(val, indices=self.indices) 1625 1626 1627 1628 class Rainfall(General_forcing): 1482 1629 """Class Rainfall - general 'rain over entire domain' forcing term. 1483 1630 … … 1490 1637 1491 1638 Rainfall(rain) 1492 1639 1640 domain 1493 1641 rain [mm/s]: Total rain rate over the specified domain. 1494 1642 NOTE: Raingauge Data needs to reflect the time step. … … 1504 1652 The specified flow will be divided by the area of 1505 1653 the inflow region and then applied to update the 1506 quantity in question.1654 stage quantity. 1507 1655 1508 1656 polygon: Specifies a polygon to restrict the rainfall. … … 1524 1672 """ 1525 1673 1526 # FIXME (OLE): Add a polygon as an alternative.1527 # FIXME (AnyOne) : Add various methods to allow spatial variations1528 # FIXME (OLE): Generalise to all quantities1529 1530 1674 1531 1675 def __init__(self, 1532 rain=0.0, 1533 quantity_name='stage', 1534 polygon=None): 1535 1536 self.rain = rain 1537 self.quantity_name = quantity_name 1538 self.polygon = polygon 1539 1540 def __call__(self, domain): 1541 1542 # FIXME(Ole): Move this to top of file eventually 1543 from anuga.utilities.polygon import inside_polygon 1544 1545 # Update rainfall 1546 if callable(self.rain): 1547 rain = self.rain(domain.get_time()) 1548 else: 1549 rain = self.rain 1550 1551 # Now rain is a number 1552 # Converting mm/s to m/s to apply in ANUGA 1553 # 1mm of rainfall is equivalent to 1 litre /m2 1554 # Flow is expressed as m3/s converted to a stage height in (m) 1555 1556 # Note 1m3 = 1x10^9mm3 (mls) 1557 # or is that m3 to Litres ??? Check this how is it applied !!! 1558 rain_fall = rain/1000 1559 1560 # Find indices for coordinates inside polygon if specified 1561 indices = None 1562 if self.polygon is not None: 1563 points = domain.get_centroid_coordinates(absolute=True) 1564 indices = inside_polygon(points, self.polygon) 1565 1566 1567 # Assign rainfall value to explicit update vector to be used as 1568 # a forcing term 1569 quantity = domain.quantities[self.quantity_name].explicit_update 1570 if indices is None: 1571 quantity[:] += rain_fall 1676 domain, 1677 rate=0.0, 1678 center=None, radius=None, 1679 polygon=None, 1680 verbose=False): 1681 1682 # Converting mm/s to m/s to apply in ANUGA) 1683 if callable(rate): 1684 rain = lambda t: rate(t)/1000.0 1572 1685 else: 1573 # Brute force assignment of restricted rainfall 1574 for i in indices: 1575 quantity[i] += rain_fall 1576 1577 1578 1579 1580 1581 1582 class Inflow: 1686 rain = rate/1000.0 1687 1688 General_forcing.__init__(self, 1689 domain, 1690 'stage', 1691 rate=rain, 1692 center=center, radius=radius, 1693 polygon=polygon, 1694 verbose=verbose) 1695 1696 1697 1698 1699 1700 1701 class Inflow(General_forcing): 1583 1702 """Class Inflow - general 'rain and drain' forcing term. 1584 1703 1585 1704 Useful for implementing flows in and out of the domain. 1586 1705 1587 Inflow(center, radius, flow) 1588 1589 center [m]: Coordinates at center of flow point 1590 radius [m]: Size of circular area 1706 Inflow(flow, center, radius, polygon) 1707 1708 domain 1591 1709 flow [m^3/s]: Total flow rate over the specified area. 1592 1710 This parameter can be either a constant or a … … 1595 1713 The specified flow will be divided by the area of 1596 1714 the inflow region and then applied to update the 1597 quantity in question. 1715 quantity in question. 1716 center [m]: Coordinates at center of flow point 1717 radius [m]: Size of circular area 1718 polygon: Arbitrary polygon. 1719 1720 Either center, radius or polygon must be specified 1598 1721 1599 1722 Examples … … 1612 1735 Inflow((0.5, 0.5), 0.03, lambda t: min(0.01*t, 0.0142)) 1613 1736 1737 1614 1738 #-------------------------------------------------------------------------- 1615 1739 # Setup specialised forcing terms … … 1625 1749 """ 1626 1750 1627 # FIXME (OLE): Add a polygon as an alternative.1628 # FIXME (OLE): Generalise to all quantities1629 1751 1630 1752 def __init__(self, 1753 domain, 1754 rate=0.0, 1631 1755 center=None, radius=None, 1632 flow=0.0, 1633 quantity_name='stage', 1634 verbose=False): 1635 1636 from math import pi 1637 1638 1639 1640 if center is not None and radius is not None: 1641 assert len(center) == 2 1756 polygon=None, 1757 verbose=False): 1758 1759 1760 #msg = 'Class Inflow must have either center & radius or a polygon specified.' 1761 #assert center is not None and radius is not None or\ 1762 # polygon is not None, msg 1763 1764 1765 # Create object first to make area is available 1766 General_forcing.__init__(self, 1767 domain, 1768 'stage', 1769 rate=rate, 1770 center=center, radius=radius, 1771 polygon=polygon, 1772 verbose=verbose) 1773 1774 def update_rate(self, t): 1775 """Virtual method allowing local modifications by writing an 1776 overriding version in descendant 1777 1778 This one converts m^3/s to m/s which can be added directly to 'stage' in ANUGA 1779 """ 1780 1781 1782 1783 if callable(self.rate): 1784 _rate = self.rate(t)/self.area 1642 1785 else: 1643 msg = 'Both center and radius must be specified' 1644 raise Exception, msg 1645 1646 self.center = center 1647 self.radius = radius 1648 self.area = radius**2*pi 1649 self.flow = flow 1650 self.quantity_name = quantity_name 1651 self.verbose = verbose 1652 1653 def __call__(self, domain): 1654 1655 # Determine indices in flow area 1656 if not hasattr(self, 'indices'): 1657 center = self.center 1658 radius = self.radius 1659 1660 N = len(domain) 1661 self.indices = [] 1662 coordinates = domain.get_centroid_coordinates() 1663 for k in range(N): 1664 x, y = coordinates[k,:] # Centroid 1665 if ((x-center[0])**2+(y-center[1])**2) < radius**2: 1666 self.indices.append(k) 1667 1668 # Update inflow 1669 if callable(self.flow): 1670 flow = self.flow(domain.get_time()) 1671 else: 1672 flow = self.flow 1673 1674 # Now flow is a number 1675 if self.verbose is True: 1676 print 'Inflow at time = %.2f = %f' %(domain.get_time(), 1677 flow) 1678 1679 quantity = domain.quantities[self.quantity_name].explicit_update 1680 for k in self.indices: 1681 quantity[k] += flow/self.area 1786 _rate = self.rate/self.area 1787 1788 return _rate 1789 1790 1682 1791 1683 1792 -
anuga_core/source/anuga/shallow_water/test_shallow_water_domain.py
r5290 r5294 2194 2194 # Setup only one forcing term, constant rainfall 2195 2195 domain.forcing_terms = [] 2196 domain.forcing_terms.append( Rainfall( rain=2.0) )2196 domain.forcing_terms.append( Rainfall(domain, rate=2.0) ) 2197 2197 2198 2198 domain.compute_forcing_terms() … … 2231 2231 # Setup only one forcing term, constant rainfall restricted to a polygon enclosing triangle #1 (bce) 2232 2232 domain.forcing_terms = [] 2233 domain.forcing_terms.append( Rainfall( rain=2.0, polygon = [[1,1], [2,1], [2,2], [1,2]]))2233 domain.forcing_terms.append( Rainfall(domain, rate=2.0, polygon = [[1,1], [2,1], [2,2], [1,2]])) 2234 2234 2235 2235 domain.compute_forcing_terms() … … 2242 2242 # FIXME: Do Time dependent rainfall with poly 2243 2243 2244 2245 2246 2247 def test_inflow_using_circle(self): 2248 from math import pi, cos, sin 2249 2250 a = [0.0, 0.0] 2251 b = [0.0, 2.0] 2252 c = [2.0, 0.0] 2253 d = [0.0, 4.0] 2254 e = [2.0, 2.0] 2255 f = [4.0, 0.0] 2256 2257 points = [a, b, c, d, e, f] 2258 #bac, bce, ecf, dbe 2259 vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]] 2260 2261 2262 domain = Domain(points, vertices) 2263 2264 # Flat surface with 1m of water 2265 domain.set_quantity('elevation', 0) 2266 domain.set_quantity('stage', 1.0) 2267 domain.set_quantity('friction', 0) 2268 2269 Br = Reflective_boundary(domain) 2270 domain.set_boundary({'exterior': Br}) 2271 2272 # Setup only one forcing term, constant inflow of 2 m^3/s on a circle affecting triangles #0 and #1 (bac and bce) 2273 domain.forcing_terms = [] 2274 domain.forcing_terms.append( Inflow(domain, rate=2.0, center=(1,1), radius=1) ) 2275 2276 domain.compute_forcing_terms() 2277 #print domain.quantities['stage'].explicit_update 2278 2279 assert allclose(domain.quantities['stage'].explicit_update[1], 2.0/pi) 2280 assert allclose(domain.quantities['stage'].explicit_update[0], 2.0/pi) 2281 assert allclose(domain.quantities['stage'].explicit_update[2:], 0) 2282 2283 2284 def test_inflow_using_circle_function(self): 2285 from math import pi, cos, sin 2286 2287 a = [0.0, 0.0] 2288 b = [0.0, 2.0] 2289 c = [2.0, 0.0] 2290 d = [0.0, 4.0] 2291 e = [2.0, 2.0] 2292 f = [4.0, 0.0] 2293 2294 points = [a, b, c, d, e, f] 2295 #bac, bce, ecf, dbe 2296 vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]] 2297 2298 2299 domain = Domain(points, vertices) 2300 2301 # Flat surface with 1m of water 2302 domain.set_quantity('elevation', 0) 2303 domain.set_quantity('stage', 1.0) 2304 domain.set_quantity('friction', 0) 2305 2306 Br = Reflective_boundary(domain) 2307 domain.set_boundary({'exterior': Br}) 2308 2309 # Setup only one forcing term, time dependent inflow of 2 m^3/s on a circle affecting triangles #0 and #1 (bac and bce) 2310 domain.forcing_terms = [] 2311 domain.forcing_terms.append( Inflow(domain, rate=lambda t: 2., center=(1,1), radius=1) ) 2312 2313 domain.compute_forcing_terms() 2314 2315 assert allclose(domain.quantities['stage'].explicit_update[1], 2.0/pi) 2316 assert allclose(domain.quantities['stage'].explicit_update[0], 2.0/pi) 2317 assert allclose(domain.quantities['stage'].explicit_update[2:], 0) 2318 2244 2319 2245 2320 … … 3279 3354 from Numeric import array 3280 3355 3281 # Create basic mesh3356 # Create basic mesh 3282 3357 points, vertices, boundary = rectangular(6, 6) 3283 3358 3284 # Create shallow water domain3359 # Create shallow water domain 3285 3360 domain = Domain(points, vertices, boundary) 3286 3361 domain.smooth = False 3287 domain.default_order =23288 3289 # IC3362 domain.default_order = 2 3363 3364 # IC 3290 3365 def x_slope(x, y): 3291 3366 return x/3 … … 3293 3368 domain.set_quantity('elevation', x_slope) 3294 3369 domain.set_quantity('friction', 0) 3295 domain.set_quantity('stage', 0.4) # Steady3370 domain.set_quantity('stage', 0.4) # Steady 3296 3371 3297 3372 # Boundary conditions (reflective everywhere) … … 3308 3383 3309 3384 3310 # Evolution3385 # Evolution 3311 3386 for t in domain.evolve(yieldstep = 0.05, finaltime = 15.0): 3312 3387 stage = domain.quantities['stage'].get_integral() … … 3314 3389 ymom = domain.quantities['ymomentum'].get_integral() 3315 3390 3316 if allclose(t, 6): # Steady state reached3391 if allclose(t, 6): # Steady state reached 3317 3392 steady_xmom = domain.quantities['xmomentum'].get_integral() 3318 3393 steady_ymom = domain.quantities['ymomentum'].get_integral() … … 3321 3396 if t > 6: 3322 3397 #print '%.2f %14.8f %14.8f' %(t, ymom, steady_ymom) 3323 assert allclose(xmom, steady_xmom) 3398 msg = 'xmom=%.2f, steady_xmom=%.2f' %(xmom, steady_xmom) 3399 assert allclose(xmom, steady_xmom), msg 3324 3400 assert allclose(ymom, steady_ymom) 3325 3401 assert allclose(stage, steady_stage) … … 3405 3481 domain = Domain(points, vertices, boundary) 3406 3482 domain.smooth = False 3407 domain.default_order =23483 domain.default_order = 2 3408 3484 domain.beta_w = 0.9 3409 3485 domain.beta_w_dry = 0.9 … … 3421 3497 domain.check_integrity() 3422 3498 3423 # Evolution3499 # Evolution 3424 3500 for t in domain.evolve(yieldstep = 0.05, finaltime = 0.05): 3425 3501 pass# domain.write_time() 3426 3502 3427 # Data from earlier version of abstract_2d_finite_volumes3503 # Data from earlier version of abstract_2d_finite_volumes 3428 3504 assert allclose(domain.min_timestep, 0.0396825396825) 3429 3505 assert allclose(domain.max_timestep, 0.0396825396825) … … 3566 3642 #domain.minimum_allowed_height = 0.0 #Makes it like the 'oldstyle' balance 3567 3643 domain.H0 = 0 # Backwards compatibility (6/2/7) 3644 domain.use_centroid_velocities = False # Backwards compatibility (8/5/8) 3568 3645 domain.set_maximum_allowed_speed(1.0) 3569 3646 … … 3575 3652 domain.check_integrity() 3576 3653 3577 # Evolution3654 # Evolution 3578 3655 for t in domain.evolve(yieldstep = 0.01, finaltime = 0.03): 3579 3656 pass 3580 3657 3581 3582 assert allclose(domain.min_timestep, 0.0210448446782) 3658 msg = 'min step was %f instead of %f' %(domain.min_timestep, 3659 0.0210448446782) 3660 3661 assert allclose(domain.min_timestep, 0.0210448446782), msg 3583 3662 assert allclose(domain.max_timestep, 0.0210448446782) 3584 3663 … … 3630 3709 domain.beta_vh_dry = 0.9 3631 3710 domain.maximum_allowed_speed = 0.0 #Makes it like the 'oldstyle' 3632 domain.H0 = 0 # Backwards compatibility (6/2/7) 3711 domain.H0 = 0 # Backwards compatibility (6/2/7) 3712 domain.use_centroid_velocities = False # Backwards compatibility (8/5/8) 3633 3713 3634 3714 # Boundary conditions … … 3682 3762 domain.beta_vh_dry = 0.9 3683 3763 domain.H0 = 0 # Backwards compatibility (6/2/7) 3764 domain.use_centroid_velocities = False # Backwards compatibility (8/5/8) 3684 3765 domain.set_maximum_allowed_speed(1.0) 3685 3766
Note: See TracChangeset
for help on using the changeset viewer.