- Timestamp:
- Oct 30, 2007, 5:13:17 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py
r4768 r4769 332 332 333 333 334 # General input checks334 # General input checks 335 335 L = [numeric, quantity, function, geospatial_data, points, filename] 336 336 msg = 'Exactly one of the arguments '+\ … … 360 360 361 361 362 # Determine which 'set_values_from_...' to use362 # Determine which 'set_values_from_...' to use 363 363 364 364 if numeric is not None: … … 1337 1337 1338 1338 1339 def update(quantity, timestep):1340 """Update centroid values based on values stored in1341 explicit_update and semi_implicit_update as well as given timestep1342 1343 Function implementing forcing terms must take on argument1344 which is the domain and they must update either explicit1345 or implicit updates, e,g,:1346 1347 def gravity(domain):1348 ....1349 domain.quantities['xmomentum'].explicit_update = ...1350 domain.quantities['ymomentum'].explicit_update = ...1351 1352 1353 1354 Explicit terms must have the form1355 1356 G(q, t)1357 1358 and explicit scheme is1359 1360 q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t)1361 1362 1363 Semi implicit forcing terms are assumed to have the form1364 1365 G(q, t) = H(q, t) q1366 1367 and the semi implicit scheme will then be1368 1369 q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1})1370 1371 1372 """1373 1374 from Numeric import sum, equal, ones, exp, Float1375 1376 N = quantity.centroid_values.shape[0]1377 1378 1379 # Divide H by conserved quantity to obtain G (see docstring above)1380 1381 1382 for k in range(N):1383 x = quantity.centroid_values[k]1384 if x == 0.0:1385 #FIXME: Is this right1386 quantity.semi_implicit_update[k] = 0.01387 else:1388 quantity.semi_implicit_update[k] /= x1389 1390 1391 # Semi implicit updates1392 denominator = ones(N, Float)-timestep*quantity.semi_implicit_update1393 1394 if sum(less(denominator, 1.0)) > 0.0:1395 msg = 'denominator < 1.0 in semi implicit update. Call Stephen :-)'1396 raise msg1397 1398 if sum(equal(denominator, 0.0)) > 0.0:1399 msg = 'Zero division in semi implicit update. Call Stephen :-)'1400 raise msg1401 else:1402 #Update conserved_quantities from semi implicit updates1403 quantity.centroid_values /= denominator1404 1405 # quantity.centroid_values = exp(timestep*quantity.semi_implicit_update)*quantity.centroid_values1406 1407 #Explicit updates1408 quantity.centroid_values += timestep*quantity.explicit_update1409 1410 def interpolate_from_vertices_to_edges(quantity):1411 """Compute edge values from vertex values using linear interpolation1412 """1413 1414 for k in range(quantity.vertex_values.shape[0]):1415 q0 = quantity.vertex_values[k, 0]1416 q1 = quantity.vertex_values[k, 1]1417 q2 = quantity.vertex_values[k, 2]1418 1419 quantity.edge_values[k, 0] = 0.5*(q1+q2)1420 quantity.edge_values[k, 1] = 0.5*(q0+q2)1421 quantity.edge_values[k, 2] = 0.5*(q0+q1)1422 1423 1424 1425 def backup_centroid_values(quantity):1426 """Copy centroid values to backup array"""1427 1428 qc = quantity.centroid_values1429 qb = quantity.centroid_backup_values1430 1431 #Check each triangle1432 for k in range(len(quantity.domain)):1433 qb[k] = qc[k]1434 1435 1436 def saxpy_centroid_values(quantity,a,b):1437 """saxpy operation between centroid value and backup"""1438 1439 qc = quantity.centroid_values1440 qb = quantity.centroid_backup_values1441 1442 #Check each triangle1443 for k in range(len(quantity.domain)):1444 qc[k] = a*qc[k]+b*qb[k]1445 1446 1447 def compute_gradients(quantity):1448 """Compute gradients of triangle surfaces defined by centroids of1449 neighbouring volumes.1450 If one edge is on the boundary, use own centroid as neighbour centroid.1451 If two or more are on the boundary, fall back to first order scheme.1452 """1453 1454 from Numeric import zeros, Float1455 from utilitites.numerical_tools import gradient1456 1457 centroid_coordinates = quantity.domain.centroid_coordinates1458 surrogate_neighbours = quantity.domain.surrogate_neighbours1459 centroid_values = quantity.centroid_values1460 number_of_boundaries = quantity.domain.number_of_boundaries1461 1462 N = centroid_values.shape[0]1463 1464 a = zeros(N, Float)1465 b = zeros(N, Float)1466 1467 for k in range(N):1468 if number_of_boundaries[k] < 2:1469 #Two or three true neighbours1470 1471 #Get indices of neighbours (or self when used as surrogate)1472 k0, k1, k2 = surrogate_neighbours[k,:]1473 1474 #Get data1475 q0 = centroid_values[k0]1476 q1 = centroid_values[k1]1477 q2 = centroid_values[k2]1478 1479 x0, y0 = centroid_coordinates[k0] #V0 centroid1480 x1, y1 = centroid_coordinates[k1] #V1 centroid1481 x2, y2 = centroid_coordinates[k2] #V2 centroid1482 1483 #Gradient1484 a[k], b[k] = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)1485 1486 elif number_of_boundaries[k] == 2:1487 #One true neighbour1488 1489 #Get index of the one neighbour1490 for k0 in surrogate_neighbours[k,:]:1491 if k0 != k: break1492 assert k0 != k1493 1494 k1 = k #self1495 1496 #Get data1497 q0 = centroid_values[k0]1498 q1 = centroid_values[k1]1499 1500 x0, y0 = centroid_coordinates[k0] #V0 centroid1501 x1, y1 = centroid_coordinates[k1] #V1 centroid1502 1503 #Gradient1504 a[k], b[k] = gradient2(x0, y0, x1, y1, q0, q1)1505 else:1506 #No true neighbours -1507 #Fall back to first order scheme1508 pass1509 1510 1511 return a, b1512 1513 1514 1515 def limit(quantity):1516 """Limit slopes for each volume to eliminate artificial variance1517 introduced by e.g. second order extrapolator1518 1519 This is an unsophisticated limiter as it does not take into1520 account dependencies among quantities.1521 1522 precondition:1523 vertex values are estimated from gradient1524 postcondition:1525 vertex values are updated1526 """1527 1528 from Numeric import zeros, Float1529 1530 N = quantity.domain.number_of_nodes1531 1532 beta_w = quantity.domain.beta_w1533 1534 qc = quantity.centroid_values1535 qv = quantity.vertex_values1536 1537 #Find min and max of this and neighbour's centroid values1538 qmax = zeros(qc.shape, Float)1539 qmin = zeros(qc.shape, Float)1540 1541 for k in range(N):1542 qmax[k] = qc[k]1543 qmin[k] = qc[k]1544 for i in range(3):1545 n = quantity.domain.neighbours[k,i]1546 if n >= 0:1547 qn = qc[n] #Neighbour's centroid value1548 1549 qmin[k] = min(qmin[k], qn)1550 qmax[k] = max(qmax[k], qn)1551 qmax[k] = min(qmax[k], 2.0*qc[k])1552 qmin[k] = max(qmin[k], 0.5*qc[k])1553 1554 1555 #Diffences between centroids and maxima/minima1556 dqmax = qmax - qc1557 dqmin = qmin - qc1558 1559 #Deltas between vertex and centroid values1560 dq = zeros(qv.shape, Float)1561 for i in range(3):1562 dq[:,i] = qv[:,i] - qc1563 1564 #Phi limiter1565 for k in range(N):1566 1567 #Find the gradient limiter (phi) across vertices1568 phi = 1.01569 for i in range(3):1570 r = 1.01571 if (dq[k,i] > 0): r = dqmax[k]/dq[k,i]1572 if (dq[k,i] < 0): r = dqmin[k]/dq[k,i]1573 1574 phi = min( min(r*beta_w, 1), phi )1575 1576 #Then update using phi limiter1577 for i in range(3):1578 qv[k,i] = qc[k] + phi*dq[k,i]1579 1580 1581 1339 1582 1340 from anuga.utilities import compile 1583 if compile.can_use_C_extension('quantity_ext.c'): 1584 # Replace python version with c implementations1341 if compile.can_use_C_extension('quantity_ext.c'): 1342 # Underlying C implementations can be accessed 1585 1343 1586 1344 from quantity_ext import average_vertex_values, backup_centroid_values, \ … … 1588 1346 1589 1347 from quantity_ext import compute_gradients, limit,\ 1590 extrapolate_second_order, interpolate_from_vertices_to_edges, update 1348 extrapolate_second_order, interpolate_from_vertices_to_edges, update 1349 else: 1350 msg = 'C implementations could not be accessed by %s.\n ' %__file__ 1351 msg += 'Make sure compile_all.py has been run as described in ' 1352 msg += 'the ANUGA installation guide.' 1353 raise Exception, msg 1354 1355 1356
Note: See TracChangeset
for help on using the changeset viewer.