Changeset 1486


Ignore:
Timestamp:
May 31, 2005, 2:24:14 PM (20 years ago)
Author:
ole
Message:

Applyed new formula for computing gradients for triangles that have only one neighbour (thanks to Matt for pointing out the bug) and added unit tests as appropriate.
See util_ext.c for documentation of the derivation

Location:
inundation/ga/storm_surge/pyvolution
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/pyvolution/quantity.py

    r1393 r1486  
    792792
    793793            #Gradient
    794             det = x0*y1 - x1*y0
    795             if det != 0.0:
    796                 a[k] = (y1*q0 - y0*q1)/det
    797                 b[k] = (x0*q1 - x1*q0)/det
    798 
     794            a[k], b[k] = gradient2(x0, y0, x1, y1, q0, q1)         
    799795        else:
    800796            #No true neighbours -
  • inundation/ga/storm_surge/pyvolution/quantity_ext.c

    r1156 r1486  
    2929
    3030  int i, k, k0, k1, k2, index3;
    31   double x0, x1, x2, y0, y1, y2, q0, q1, q2, det;
     31  double x0, x1, x2, y0, y1, y2, q0, q1, q2; //, det;
    3232
    3333
     
    8080      x1 = centroids[k1*2]; y1 = centroids[k1*2+1];
    8181
    82       //Gradient
    83       det = x0*y1 - x1*y0;
    84       if (det != 0.0) {
    85         a[k] = (y1*q0 - y0*q1)/det;
    86         b[k] = (x0*q1 - x1*q0)/det;
    87       }
     82      //Two point gradient
     83      _gradient2(x0, y0, x1, y1, q0, q1, &a[k], &b[k]);     
     84     
     85     
     86      //Old (wrong code)
     87      //det = x0*y1 - x1*y0;
     88      //if (det != 0.0) {
     89      //        a[k] = (y1*q0 - y0*q1)/det;
     90      //        b[k] = (x0*q1 - x1*q0)/det;
     91      //}
    8892    }
    8993    //    else:
  • inundation/ga/storm_surge/pyvolution/test_quantity.py

    r1393 r1486  
    8484        quantity.extrapolate_second_order()
    8585
    86         assert allclose(quantity.vertex_values, [[2., 2., 2.],
    87                                                [3.+2./3, 6.+2./3, 4.+2./3],
    88                                                [7.5, 0.5, 1.],
    89                                                [-5, -2.5, 7.5]])
    90 
     86        #print quantity.vertex_values
     87        #assert allclose(quantity.vertex_values, [[2., 2., 2.],
     88        #                                         [3.+2./3, 6.+2./3, 4.+2./3],
     89        #                                         [7.5, 0.5, 1.],
     90        #                                         [-5, -2.5, 7.5]])
     91
     92        assert allclose(quantity.vertex_values[1,:],[3.+2./3, 6.+2./3, 4.+2./3])
     93        #FIXME: Work out the others
     94       
     95                                         
    9196        #print quantity.edge_values
    9297        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
     
    267272        quantity = Conserved_quantity(self.mesh4)
    268273
    269         #Set up for a gradient of (3,0) at mid triangle
    270         quantity.set_values([2.0, 4.0, 8.0, 2.0],
     274        #Set up for a gradient of (2,0) at mid triangle
     275        quantity.set_values([2.0, 4.0, 6.0, 2.0],
    271276                            location = 'centroids')
    272 
    273277
    274278
     
    276280        a, b = quantity.compute_gradients()
    277281
    278         #gradient bewteen t0 and t1 is undefined as det==0
    279         assert a[0] == 0.0
    280         assert b[0] == 0.0
    281         #The others are OK
    282         for i in range(1,4):
    283             assert a[i] == 3.0
    284             assert b[i] == 0.0
    285 
    286 
     282        #print self.mesh4.centroid_coordinates
     283        #print a, b
     284
     285        #The central triangle (1)
     286        #(using standard gradient based on neigbours controid values)
     287        assert a[1] == 2.0
     288        assert b[1] == 0.0
     289
     290
     291        #Left triangle (0) using two point gradient
     292        #q0 = q1 + a*(x0-x1) + b*(y0-y1)  <=>
     293        #2  = 4  + a*(-2/3)  + b*(-2/3)
     294        assert a[0] + b[0] == 3
     295        #From orthogonality (a*(y0-y1) + b*(x0-x1) == 0)       
     296        assert a[0] - b[0] == 0
     297
     298
     299        #Right triangle (2) using two point gradient
     300        #q2 = q1 + a*(x2-x1) + b*(y2-y1)  <=>
     301        #6  = 4  + a*(4/3)  + b*(-2/3)       
     302        assert 2*a[2] - b[2] == 3
     303        #From orthogonality (a*(y1-y2) + b*(x2-x1) == 0)
     304        assert a[2] + 2*b[2] == 0
     305
     306
     307        #Top triangle (3) using two point gradient
     308        #q3 = q1 + a*(x3-x1) + b*(y3-y1)  <=>
     309        #2  = 4  + a*(-2/3)  + b*(4/3)       
     310        assert a[3] - 2*b[3] == 3
     311        #From orthogonality (a*(y1-y3) + b*(x3-x1) == 0)       
     312        assert 2*a[3] + b[3] == 0
     313
     314
     315
     316        #print a, b
    287317        quantity.extrapolate_second_order()
    288318
    289         #print quantity.vertex_values
    290         assert allclose(quantity.vertex_values, [[2., 2.,  2.],
    291                                                  [0., 6.,  6.],
    292                                                  [6., 6., 12.],
    293                                                  [0., 0.,  6.]])
     319        #Apply q(x,y) = qc + a*(x-xc) + b*(y-yc)
     320        assert allclose(quantity.vertex_values[0,:], [3., 0.,  3.])
     321        assert allclose(quantity.vertex_values[1,:], [4./3, 16./3,  16./3])
     322
     323
     324        #a = 1.2, b=-0.6
     325        #q(4,0) = 6 + a*(4 - 8/3) + b*(-2/3)
     326        assert allclose(quantity.vertex_values[2,2], 8)       
    294327
    295328
     
    304337        a, b = quantity.compute_gradients()
    305338
    306         #gradient bewteen t0 and t1 is undefined as det==0
    307         assert a[0] == 0.0
    308         assert b[0] == 0.0
    309         #The others are OK
    310         for i in range(1,4):
    311             assert allclose(a[i], 3.0)
    312             assert allclose(b[i], 1.0)
    313 
     339        #print a, b
     340
     341        assert a[1] == 3.0
     342        assert b[1] == 1.0
     343       
     344        #Work out the others
     345       
    314346        quantity.extrapolate_second_order()
    315347
  • inundation/ga/storm_surge/pyvolution/test_util.py

    r1137 r1486  
    3131        assert zy == 0.0
    3232
    33 
    34 
    35 
    36     def test_gradient2(self):
    37 
    38         from util import gradient
     33    def test_gradient_more(self):
    3934        x0 = 2.0/3; y0 = 2.0/3
    4035        x1=  8.0/3; y1 = 2.0/3
     
    5146        assert abs(b - 1.0) < epsilon
    5247
     48
     49    def test_gradient2(self):
     50        """Test two-point gradient
     51        """
     52       
     53        x0 = 5.0; y0 = 5.0; z0 = 10.0
     54        x1 = 8.0; y1 = 2.0; z1 = 1.0
     55        x2 = 8.0; y2 = 8.0; z2 = 10.0
     56
     57        #Reference
     58        zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
     59        a, b = gradient2(x0, y0, x1, y1, z0, z1)
     60
     61        assert zx == a
     62        assert zy == b
     63
     64        z2_computed = z0 + a*(x2-x0) + b*(y2-y0)
     65        assert z2_computed == z2
     66       
     67    def test_gradient2_more(self):
     68        """Test two-point gradient more
     69        """
     70        x0 = 2.0; y0 = 2.0
     71        x1 = 8.0; y1 = 3.0
     72        x2 = 1.0; y2 = 8.0
     73
     74        q0 = 2.0
     75        q1 = 8.0
     76        q2 = q0
     77
     78        #Gradient of fitted pwl surface
     79        a_ref, b_ref = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)
     80        a, b = gradient2(x0, y0, x1, y1, q0, q1)       
     81
     82        assert a == a_ref
     83        assert b == b_ref
    5384
    5485
  • inundation/ga/storm_surge/pyvolution/util.py

    r1387 r1486  
    14011401
    14021402
     1403def gradient2_python(x0, y0, x1, y1, q0, q1):
     1404    """Compute radient based on two points and enforce zero gradient
     1405    in the direction orthogonal to (x1-x0), (y1-y0)
     1406    """
     1407
     1408    #Old code
     1409    #det = x0*y1 - x1*y0
     1410    #if det != 0.0:
     1411    #    a = (y1*q0 - y0*q1)/det
     1412    #    b = (x0*q1 - x1*q0)/det
     1413
     1414    #Correct code (ON)
     1415    det = (x1-x0)**2 + (y1-y0)**2
     1416    if det != 0.0:
     1417        a = (x1-x0)*(q1-q0)/det
     1418        b = (y1-y0)*(q1-q0)/det
     1419       
     1420    return a, b       
     1421
    14031422
    14041423##############################################
     
    14071426import compile
    14081427if compile.can_use_C_extension('util_ext.c'):
    1409     from util_ext import gradient, point_on_line
     1428    from util_ext import gradient, gradient2, point_on_line
    14101429    separate_points_by_polygon = separate_points_by_polygon_c
    14111430else:
    14121431    gradient = gradient_python
     1432    gradient2 = gradient2_python   
    14131433
    14141434
  • inundation/ga/storm_surge/pyvolution/util_ext.c

    r1093 r1486  
    272272}
    273273
     274PyObject *gradient2(PyObject *self, PyObject *args) {
     275  //
     276  // a,b = gradient2(x0, y0, x1, y1, q0, q1)
     277  //
     278
     279  double x0, y0, x1, y1, q0, q1, a, b;
     280  PyObject *result;
     281
     282  // Convert Python arguments to C
     283  if (!PyArg_ParseTuple(args, "dddddd", &x0, &y0, &x1, &y1, &q0, &q1))
     284    return NULL;
     285
     286
     287  // Call underlying routine
     288  _gradient2(x0, y0, x1, y1, q0, q1, &a, &b);
     289
     290  // Return values a and b
     291  result = Py_BuildValue("dd", a, b);
     292  return result;
     293}
    274294
    275295// Method table for python module
     
    282302  //{"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
    283303  {"gradient", gradient, METH_VARARGS, "Print out"},
     304  {"gradient2", gradient2, METH_VARARGS, "Print out"}, 
    284305  {"point_on_line", point_on_line, METH_VARARGS, "Print out"},
    285306  //{"inside_polygon", inside_polygon, METH_VARARGS, "Print out"},
  • inundation/ga/storm_surge/pyvolution/util_ext.h

    r1137 r1486  
    4747  *b /= det;
    4848
     49  return 0;
     50}
     51
     52
     53int _gradient2(double x0, double y0,
     54               double x1, double y1,
     55               double q0, double q1,
     56               double *a, double *b) {
     57  /*Compute gradient (a,b) between two points (x0,y0) and (x1,y1)
     58  with values q0 and q1 such that the plane is constant in the direction
     59  orthogonal to (x1-x0, y1-y0).
     60 
     61  Extrapolation formula
     62    q(x,y) = q0 + a*(x-x0) + b*(y-y0)                    (1)
     63 
     64  Substituting the known values for q1 into (1) yields an
     65  under determined  equation for a and b
     66      q1-q0 = a*(x1-x0) + b*(y1-y0)                      (2)
     67     
     68     
     69  Now add the additional requirement that the gradient in the direction
     70  orthogonal to (x1-x0, y1-y0) should be zero. The orthogonal direction
     71  is given by the vector (y0-y1, x1-x0).
     72 
     73  Define the point (x2, y2) = (x0 + y0-y1, y0 + x1-x0) on the orthognal line.
     74  Then we know that the corresponding value q2 should be equal to q0 in order
     75  to obtain the zero gradient, hence applying (1) again   
     76      q0 = q2 = q(x2, y2) = q0 + a*(x2-x0) + b*(y2-y0)
     77                          = q0 + a*(x0 + y0-y1-x0) + b*(y0 + x1-x0 - y0)
     78                          = q0 + a*(y0-y1) + b*(x1-x0)
     79                         
     80  leads to the orthogonality constraint
     81     a*(y0-y1) + b*(x1-x0) = 0                           (3)
     82     
     83  which closes the system and yields
     84 
     85  /               \  /   \   /       \ 
     86  |  x1-x0  y1-y0 |  | a |   | q1-q0 |
     87  |               |  |   | = |       |
     88  |  y0-y1  x1-x0 |  | b |   |   0   |
     89  \               /  \   /   \       /
     90   
     91  which is solved using the standard determinant technique   
     92     
     93  */
     94
     95  double det, xx, yy, qq;
     96 
     97  xx = x1-x0;
     98  yy = y1-y0;
     99  qq = q1-q0;
     100   
     101  det = xx*xx + yy*yy;  //FIXME  catch det == 0
     102  *a = xx*qq/det;
     103  *b = yy*qq/det;
     104       
    49105  return 0;
    50106}
Note: See TracChangeset for help on using the changeset viewer.