Changeset 4886


Ignore:
Timestamp:
Dec 12, 2007, 5:38:37 PM (17 years ago)
Author:
steve
Message:

Working towards an edge limiter (at least in quantity)

Location:
anuga_core/source/anuga
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py

    r4883 r4886  
    229229        #(either from this module or C-extension)
    230230        interpolate_from_vertices_to_edges(self)
     231
     232    def interpolate_from_edges_to_vertices(self):
     233        #Call correct module function
     234        #(either from this module or C-extension)
     235        interpolate_from_edges_to_vertices(self)
    231236
    232237
     
    14001405
    14011406
    1402 ##     def limit_by_vertex(self):
    1403 ##         #Call correct module function
    1404 ##         #(either from this module or C-extension)
    1405 ##         limit_by_vertex()
    1406 
    1407 
    1408 ##     def limit_by_edge(self):
    1409 ##         #Call correct module function
    1410 ##         #(either from this module or C-extension)
    1411 ##         limit_by_edge()       
     1407    def limit_by_vertex(self):
     1408        #Call correct module function
     1409        #(either from this module or C-extension)
     1410        limit_by_vertex(self)
     1411
     1412
     1413    def limit_by_edge(self):
     1414        #Call correct module function
     1415        #(either from this module or C-extension)
     1416        limit_by_edge(self)       
    14121417
    14131418    def extrapolate_second_order(self):
     
    14391444         compute_gradients,\
    14401445         limit_old,\
     1446         limit_by_vertex,\
     1447         limit_by_edge,\
    14411448         extrapolate_second_order,\
    14421449         interpolate_from_vertices_to_edges,\
     1450         interpolate_from_edges_to_vertices,\
    14431451         update   
    14441452else:
  • anuga_core/source/anuga/abstract_2d_finite_volumes/quantity_ext.c

    r4883 r4886  
    122122                y2 = vertex_coordinates[k6 + 5];
    123123
    124                 // Extrapolate
     124                // Extrapolate to Vertices
    125125                vertex_values[k3+0] = centroid_values[k] + a[k]*(x0-x) + b[k]*(y0-y);
    126126                vertex_values[k3+1] = centroid_values[k] + a[k]*(x1-x) + b[k]*(y1-y);
    127127                vertex_values[k3+2] = centroid_values[k] + a[k]*(x2-x) + b[k]*(y2-y);
    128128
    129 
     129                // Extrapolate to Edges (midpoints)
    130130                edge_values[k3+0] = 0.5*(vertex_values[k3 + 1]+vertex_values[k3 + 2]);
    131131                edge_values[k3+1] = 0.5*(vertex_values[k3 + 2]+vertex_values[k3 + 0]);
     
    137137
    138138
    139 
    140 
    141 int _interpolate(int N,
     139int _limit_by_vertex(int N, double beta,
     140                     double* centroid_values,
     141                     double* vertex_values,
     142                     double* edge_values,
     143                     long*   neighbours) {
     144
     145        int i, k, k2, k3, k6;
     146        long n;
     147        double qmin, qmax, qn, qc;
     148        double dq, dqa[3], phi, r;
     149
     150        for (k=0; k<N; k++){
     151                k6 = 6*k;
     152                k3 = 3*k;
     153                k2 = 2*k;
     154
     155                qc = centroid_values[k];
     156                qmin = qc;
     157                qmax = qc;
     158
     159                for (i=0; i<3; i++) {
     160                    n = neighbours[k3+i];
     161                    if (n >= 0) {
     162                        qn = centroid_values[n]; //Neighbour's centroid value
     163
     164                        qmin = min(qmin, qn);
     165                        qmax = max(qmax, qn);
     166                    }
     167                }
     168
     169                phi = 1.0;
     170                for (i=0; i<3; i++) {   
     171                    r = 1.0;
     172     
     173                    dq = vertex_values[k3+i] - qc;    //Delta between vertex and centroid values
     174                    dqa[i] = dq;                      //Save dq for use in updating vertex values
     175     
     176                    if (dq > 0.0) r = (qmax - qc)/dq;
     177                    if (dq < 0.0) r = (qmin - qc)/dq;     
     178 
     179                   
     180                    phi = min( min(r*beta, 1.0), phi);   
     181                }
     182   
     183                //Update vertex and edge values using phi limiter
     184                vertex_values[k3+0] = qc + phi*dqa[0];
     185                vertex_values[k3+1] = qc + phi*dqa[1];
     186                vertex_values[k3+2] = qc + phi*dqa[2];
     187               
     188                edge_values[k3+0] = 0.5*(vertex_values[k3+1] + vertex_values[k3+2]);
     189                edge_values[k3+1] = 0.5*(vertex_values[k3+2] + vertex_values[k3+0]);
     190                edge_values[k3+2] = 0.5*(vertex_values[k3+0] + vertex_values[k3+1]);
     191
     192        }
     193
     194        return 0;
     195}
     196
     197int _limit_by_edge(int N, double beta,
     198                     double* centroid_values,
     199                     double* vertex_values,
     200                     double* edge_values,
     201                     long*   neighbours) {
     202
     203        int i, k, k2, k3, k6;
     204        long n;
     205        double qmin, qmax, qn, qc;
     206        double dq, dqa[3], phi, r;
     207
     208        for (k=0; k<N; k++){
     209                k6 = 6*k;
     210                k3 = 3*k;
     211                k2 = 2*k;
     212
     213                qc = centroid_values[k];
     214                qmin = qc;
     215                qmax = qc;
     216
     217                for (i=0; i<3; i++) {
     218                    n = neighbours[k3+i];
     219                    if (n >= 0) {
     220                        qn = centroid_values[n]; //Neighbour's centroid value
     221
     222                        qmin = min(qmin, qn);
     223                        qmax = max(qmax, qn);
     224                    }
     225                }
     226
     227                phi = 1.0;
     228                for (i=0; i<3; i++) {   
     229                    r = 1.0;
     230     
     231                    dq = edge_values[k3+i] - qc;     //Delta between edge and centroid values
     232                    dqa[i] = dq;                      //Save dq for use in updating vertex values
     233     
     234                    if (dq > 0.0) r = (qmax - qc)/dq;
     235                    if (dq < 0.0) r = (qmin - qc)/dq;     
     236 
     237                   
     238                    phi = min( min(r*beta, 1.0), phi);   
     239                }
     240   
     241                //Update vertex and edge values using phi limiter
     242                edge_values[k3+0] = qc + phi*dqa[0];
     243                edge_values[k3+1] = qc + phi*dqa[1];
     244                edge_values[k3+2] = qc + phi*dqa[2];
     245               
     246                vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0];
     247                vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1];
     248                vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2];
     249
     250        }
     251
     252        return 0;
     253}
     254
     255
     256
     257int _interpolate_from_vertices_to_edges(int N,
    142258                 double* vertex_values,
    143259                 double* edge_values) {
     
    157273                edge_values[k3 + 1] = 0.5*(q0+q2);
    158274                edge_values[k3 + 2] = 0.5*(q0+q1);
     275        }
     276        return 0;
     277}
     278
     279
     280int _interpolate_from_edges_to_vertices(int N,
     281                 double* vertex_values,
     282                 double* edge_values) {
     283
     284        int k, k3;
     285        double e0, e1, e2;
     286
     287
     288        for (k=0; k<N; k++) {
     289                k3 = 3*k;
     290
     291                e0 = edge_values[k3 + 0];
     292                e1 = edge_values[k3 + 1];
     293                e2 = edge_values[k3 + 2];
     294
     295                vertex_values[k3 + 0] = e1 + e2 - e0;
     296                vertex_values[k3 + 1] = e2 + e0 - e1;
     297                vertex_values[k3 + 2] = e0 + e1 - e2;
    159298        }
    160299        return 0;
     
    458597        N = vertex_values -> dimensions[0];
    459598
    460         err = _interpolate(N,
     599        err = _interpolate_from_vertices_to_edges(N,
     600                           (double*) vertex_values -> data,
     601                           (double*) edge_values -> data);
     602
     603        if (err != 0) {
     604          PyErr_SetString(PyExc_RuntimeError,
     605                          "Interpolate could not be computed");
     606          return NULL;
     607        }
     608
     609        // Release and return
     610        Py_DECREF(vertex_values);
     611        Py_DECREF(edge_values);
     612
     613        return Py_BuildValue("");
     614}
     615
     616
     617PyObject *interpolate_from_edges_to_vertices(PyObject *self, PyObject *args) {
     618        //
     619        //Compute vertex values from edge values using linear interpolation
     620        //
     621       
     622        PyObject *quantity;
     623        PyArrayObject *vertex_values, *edge_values;
     624
     625        int N, err;
     626
     627        // Convert Python arguments to C
     628        if (!PyArg_ParseTuple(args, "O", &quantity)) {
     629          PyErr_SetString(PyExc_RuntimeError,
     630                          "quantity_ext.c: interpolate_from_edges_to_vertices could not parse input");
     631          return NULL;
     632        }
     633       
     634        vertex_values = get_consecutive_array(quantity, "vertex_values");
     635        edge_values = get_consecutive_array(quantity, "edge_values");
     636
     637        N = vertex_values -> dimensions[0];
     638
     639        err = _interpolate_from_edges_to_vertices(N,
    461640                           (double*) vertex_values -> data,
    462641                           (double*) edge_values -> data);
     
    795974
    796975
     976PyObject *limit_by_vertex(PyObject *self, PyObject *args) {
     977  //Limit slopes for each volume to eliminate artificial variance
     978  //introduced by e.g. second order extrapolator
     979
     980  //This is an unsophisticated limiter as it does not take into
     981  //account dependencies among quantities.
     982
     983  //precondition:
     984  //  vertex values are estimated from gradient
     985  //postcondition:
     986  //  vertex and edge values are updated
     987  //
     988
     989        PyObject *quantity, *domain, *Tmp;
     990        PyArrayObject
     991            *vertex_values,   //Conserved quantities at vertices
     992            *centroid_values, //Conserved quantities at centroids
     993            *edge_values,     //Conserved quantities at edges
     994            *neighbours;
     995
     996        double beta_w; //Safety factor
     997        int N, err;
     998
     999
     1000        // Convert Python arguments to C
     1001        if (!PyArg_ParseTuple(args, "O", &quantity)) {
     1002          PyErr_SetString(PyExc_RuntimeError,
     1003                          "quantity_ext.c: limit_by_vertex could not parse input");
     1004          return NULL;
     1005        }
     1006
     1007        domain = PyObject_GetAttrString(quantity, "domain");
     1008        if (!domain) {
     1009          PyErr_SetString(PyExc_RuntimeError,
     1010                          "quantity_ext.c: limit_by_vertex could not obtain domain object from quantity");                     
     1011         
     1012          return NULL;
     1013        }
     1014
     1015        // Get safety factor beta_w
     1016        Tmp = PyObject_GetAttrString(domain, "beta_w");
     1017        if (!Tmp) {
     1018          PyErr_SetString(PyExc_RuntimeError,
     1019                          "quantity_ext.c: limit_by_vertex could not obtain beta_w object from domain");                       
     1020         
     1021          return NULL;
     1022        }       
     1023
     1024
     1025        // Get pertinent variables
     1026        neighbours       = get_consecutive_array(domain, "neighbours");
     1027        centroid_values  = get_consecutive_array(quantity, "centroid_values");
     1028        vertex_values    = get_consecutive_array(quantity, "vertex_values");
     1029        edge_values      = get_consecutive_array(quantity, "edge_values");
     1030        beta_w           = PyFloat_AsDouble(Tmp);
     1031
     1032
     1033        N = centroid_values -> dimensions[0];
     1034
     1035        err = _limit_by_vertex(N, beta_w,
     1036                               (double*) centroid_values -> data,
     1037                               (double*) vertex_values -> data,
     1038                               (double*) edge_values -> data,
     1039                               (long*)   neighbours -> data);
     1040
     1041        if (err != 0) {
     1042          PyErr_SetString(PyExc_RuntimeError,
     1043                          "Internal function _limit_by_vertex failed");
     1044          return NULL;
     1045        }       
     1046
     1047
     1048        // Release
     1049        Py_DECREF(neighbours);
     1050        Py_DECREF(centroid_values);
     1051        Py_DECREF(vertex_values);
     1052        Py_DECREF(edge_values);
     1053        Py_DECREF(Tmp);
     1054
     1055
     1056        return Py_BuildValue("");
     1057}
     1058
     1059
     1060
     1061PyObject *limit_by_edge(PyObject *self, PyObject *args) {
     1062  //Limit slopes for each volume to eliminate artificial variance
     1063  //introduced by e.g. second order extrapolator
     1064
     1065  //This is an unsophisticated limiter as it does not take into
     1066  //account dependencies among quantities.
     1067
     1068  //precondition:
     1069  //  vertex values are estimated from gradient
     1070  //postcondition:
     1071  //  vertex and edge values are updated
     1072  //
     1073
     1074        PyObject *quantity, *domain, *Tmp;
     1075        PyArrayObject
     1076            *vertex_values,   //Conserved quantities at vertices
     1077            *centroid_values, //Conserved quantities at centroids
     1078            *edge_values,     //Conserved quantities at edges
     1079            *neighbours;
     1080
     1081        double beta_w; //Safety factor
     1082        int N, err;
     1083
     1084
     1085        // Convert Python arguments to C
     1086        if (!PyArg_ParseTuple(args, "O", &quantity)) {
     1087          PyErr_SetString(PyExc_RuntimeError,
     1088                          "quantity_ext.c: limit_by_edge could not parse input");
     1089          return NULL;
     1090        }
     1091
     1092        domain = PyObject_GetAttrString(quantity, "domain");
     1093        if (!domain) {
     1094          PyErr_SetString(PyExc_RuntimeError,
     1095                          "quantity_ext.c: limit_by_edge could not obtain domain object from quantity");                       
     1096         
     1097          return NULL;
     1098        }
     1099
     1100        // Get safety factor beta_w
     1101        Tmp = PyObject_GetAttrString(domain, "beta_w");
     1102        if (!Tmp) {
     1103          PyErr_SetString(PyExc_RuntimeError,
     1104                          "quantity_ext.c: limit_by_edge could not obtain beta_w object from domain");                 
     1105         
     1106          return NULL;
     1107        }       
     1108
     1109
     1110        // Get pertinent variables
     1111        neighbours       = get_consecutive_array(domain, "neighbours");
     1112        centroid_values  = get_consecutive_array(quantity, "centroid_values");
     1113        vertex_values    = get_consecutive_array(quantity, "vertex_values");
     1114        edge_values      = get_consecutive_array(quantity, "edge_values");
     1115        beta_w           = PyFloat_AsDouble(Tmp);
     1116
     1117
     1118        N = centroid_values -> dimensions[0];
     1119
     1120        err = _limit_by_edge(N, beta_w,
     1121                               (double*) centroid_values -> data,
     1122                               (double*) vertex_values -> data,
     1123                               (double*) edge_values -> data,
     1124                               (long*)   neighbours -> data);
     1125
     1126        if (err != 0) {
     1127          PyErr_SetString(PyExc_RuntimeError,
     1128                          "Internal function _limit_by_vertex failed");
     1129          return NULL;
     1130        }       
     1131
     1132
     1133        // Release
     1134        Py_DECREF(neighbours);
     1135        Py_DECREF(centroid_values);
     1136        Py_DECREF(vertex_values);
     1137        Py_DECREF(edge_values);
     1138        Py_DECREF(Tmp);
     1139
     1140
     1141        return Py_BuildValue("");
     1142}
     1143
     1144
    7971145
    7981146// Method table for python module
    7991147static struct PyMethodDef MethodTable[] = {
    8001148        {"limit_old", limit_old, METH_VARARGS, "Print out"},
     1149        {"limit_by_vertex", limit_by_vertex, METH_VARARGS, "Print out"},
     1150        {"limit_by_edge", limit_by_edge, METH_VARARGS, "Print out"},
    8011151        {"update", update, METH_VARARGS, "Print out"},
    8021152        {"backup_centroid_values", backup_centroid_values, METH_VARARGS, "Print out"},
     
    8081158                interpolate_from_vertices_to_edges,
    8091159                METH_VARARGS, "Print out"},
     1160        {"interpolate_from_edges_to_vertices",
     1161                interpolate_from_edges_to_vertices,
     1162                METH_VARARGS, "Print out"},
    8101163        {"average_vertex_values", average_vertex_values, METH_VARARGS, "Print out"},           
    8111164        {NULL, NULL, 0, NULL}   // sentinel
  • anuga_core/source/anuga/abstract_2d_finite_volumes/test_quantity.py

    r4883 r4886  
    14451445
    14461446
    1447     def test_limiter(self):
     1447    def test_vertex_limiter(self):
    14481448        quantity = Conserved_quantity(self.mesh4)
    14491449
     
    14531453
    14541454        #Limit
    1455         quantity.limit()
     1455        quantity.limit_by_vertex()
    14561456
    14571457        #Assert that central triangle is limited by neighbours
     
    14741474
    14751475
     1476
     1477    def test_edge_limiter(self):
     1478        quantity = Conserved_quantity(self.mesh4)
     1479
     1480        #Create a deliberate overshoot (e.g. from gradient computation)
     1481        quantity.set_values([[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
     1482
     1483
     1484        #Limit
     1485        quantity.limit_by_edge()
     1486
     1487        #Assert that central triangle is limited by neighbours
     1488        assert quantity.edge_values[1,0] <= quantity.centroid_values[2]
     1489        assert quantity.edge_values[1,0] >= quantity.centroid_values[0]
     1490
     1491        assert quantity.edge_values[1,1] <= quantity.centroid_values[2]
     1492        assert quantity.edge_values[1,1] >= quantity.centroid_values[0]
     1493
     1494        assert quantity.edge_values[1,2] <= quantity.centroid_values[2]
     1495        assert quantity.edge_values[1,2] <= quantity.centroid_values[0]
     1496
     1497
     1498
     1499        #Assert that quantities are conserved
     1500        from Numeric import sum
     1501        for k in range(quantity.centroid_values.shape[0]):
     1502            assert allclose (quantity.centroid_values[k],
     1503                             sum(quantity.vertex_values[k,:])/3)
     1504
     1505
    14761506    def test_limiter2(self):
    14771507        """Taken from test_shallow_water
     
    15181548
    15191549
    1520         #Extrapolate
     1550        #Extrapolate from centroid to vertices and edges
    15211551        quantity.extrapolate_first_order()
    15221552
    15231553        #Interpolate
    1524         quantity.interpolate_from_vertices_to_edges()
     1554        #quantity.interpolate_from_vertices_to_edges()
    15251555
    15261556        assert allclose(quantity.vertex_values,
     
    15281558        assert allclose(quantity.edge_values, [[1,1,1], [2,2,2],
    15291559                                               [3,3,3], [4, 4, 4]])
     1560
     1561
     1562    def test_interpolate_from_vertices_to_edges(self):
     1563        quantity = Quantity(self.mesh4)
     1564
     1565        quantity.vertex_values = array([[1,0,2], [1,2,4], [4,2,5], [3,1,4]],Float)
     1566
     1567        quantity.interpolate_from_vertices_to_edges()
     1568
     1569        assert allclose(quantity.edge_values, [[1., 1.5, 0.5],
     1570                                               [3., 2.5, 1.5],
     1571                                               [3.5, 4.5, 3.],
     1572                                               [2.5, 3.5, 2]])
     1573
     1574
     1575    def test_interpolate_from_edges_to_vertices(self):
     1576        quantity = Quantity(self.mesh4)
     1577
     1578        quantity.edge_values = array([[1., 1.5, 0.5],
     1579                                [3., 2.5, 1.5],
     1580                                [3.5, 4.5, 3.],
     1581                                [2.5, 3.5, 2]],Float)
     1582
     1583        quantity.interpolate_from_edges_to_vertices()
     1584
     1585        assert allclose(quantity.vertex_values,
     1586                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
     1587
    15301588
    15311589
  • anuga_core/source/anuga/utilities/util_ext.h

    r4883 r4886  
    166166
    167167
    168 void _limit_by_edge(int N, double beta, double* qc, double* qv,
    169             double* qmin, double* qmax) {
    170 
    171   //N are the number of elements
    172   int k, i, k3;
    173   double dq, dqa[3], phi, r;
    174  
    175   //printf("INSIDE\n");
    176   for (k=0; k<N; k++) {
    177     k3 = k*3;
    178    
    179     //Find the gradient limiter (phi) across vertices 
    180     phi = 1.0;
    181     for (i=0; i<3; i++) {   
    182       r = 1.0;
    183      
    184       dq = qv[k3+i] - qc[k];    //Delta between vertex and centroid values
    185       dqa[i] = dq;              //Save dq for use in the next loop
    186      
    187       if (dq > 0.0) r = (qmax[k] - qc[k])/dq;
    188       if (dq < 0.0) r = (qmin[k] - qc[k])/dq;     
    189  
    190  
    191       phi = min( min(r*beta, 1.0), phi);   
    192     }
    193    
    194     //Then update using phi limiter
    195     for (i=0; i<3; i++) {   
    196       qv[k3+i] = qc[k] + phi*dqa[i];
    197     }
    198   }
    199 }
    200 
    201 void _limit_by_vertex(int N, double beta, double* qc, double* qv,
    202             double* qmin, double* qmax) {
    203 
    204   //N are the number of elements
    205   int k, i, k3;
    206   double dq, dqa[3], phi, r;
    207  
    208   //printf("INSIDE\n");
    209   for (k=0; k<N; k++) {
    210     k3 = k*3;
    211    
    212     //Find the gradient limiter (phi) across vertices 
    213     phi = 1.0;
    214     for (i=0; i<3; i++) {   
    215       r = 1.0;
    216      
    217       dq = qv[k3+i] - qc[k];    //Delta between vertex and centroid values
    218       dqa[i] = dq;              //Save dq for use in the next loop
    219      
    220       if (dq > 0.0) r = (qmax[k] - qc[k])/dq;
    221       if (dq < 0.0) r = (qmin[k] - qc[k])/dq;     
    222  
    223  
    224       phi = min( min(r*beta, 1.0), phi);   
    225     }
    226    
    227     //Then update using phi limiter
    228     for (i=0; i<3; i++) {   
    229       qv[k3+i] = qc[k] + phi*dqa[i];
    230     }
    231   }
    232 }
    233168
    234169
Note: See TracChangeset for help on using the changeset viewer.