Changeset 8135


Ignore:
Timestamp:
Mar 10, 2011, 3:31:46 PM (14 years ago)
Author:
steve
Message:

Changing over kv to use quantities

Location:
trunk/anuga_core/source/anuga/operators
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/anuga_core/source/anuga/operators/kinematic_viscosity.py

    r8128 r8135  
    11
    22from anuga import Domain
     3from anuga import Quantity
    34from anuga.utilities.sparse import Sparse, Sparse_CSR
    45from anuga.utilities.cg_solve import conjugate_gradient
    56import anuga.abstract_2d_finite_volumes.neighbour_mesh as neighbour_mesh
    6 from anuga.abstract_2d_finite_volumes.generic_boundary_conditions import Dirichlet_boundary
     7from anuga import Dirichlet_boundary
    78import numpy as num
    89import kinematic_viscosity_ext
     
    1112class Kinematic_Viscosity:
    1213    """
    13     Class for setting up structures and matrices for kinematic viscosity
     14    Class for setting up structures and matrices for kinematic viscosity differential
     15    operator using centroid values.
     16
     17    div ( diffusivity grad )
     18
     19    where diffusvity is scalar quantity (defaults to quantity with values = 1)
     20    boundary values of f are used to setup entries associated with cells with boundaries
     21
     22    There are procedures to apply this operator, ie
     23
     24    (1) Calculate div( diffusivity grad u )
     25    using boundary values stored in u
     26
     27    (2) Calculate ( u + dt div( diffusivity grad u )
     28    using boundary values stored in u
     29
     30    (3) Solve div( diffusivity grad u ) = f
     31    for quantity f and using boundary values stored in u
     32
     33    (4) Solve ( u + dt div( diffusivity grad u ) = f
     34    for quantity f using boundary values stored in u
     35
    1436    """
    1537
    16     def __init__(self, domain, triangle_areas=True, verbose=False):
     38    def __init__(self, domain, diffusivity = None, triangle_areas=True, verbose=False):
    1739        if verbose: log.critical('Kinematic Viscosity: Beginning Initialisation')
    1840        #Expose the domain attributes
     
    2143        self.mesh = domain.mesh
    2244        self.boundary = domain.boundary
     45
     46        # Setup diffusivity quantity
     47        if diffusivity is None:
     48            diffusivity = Quantity(domain)
     49            diffusivity.set_values(1.0)
     50        #check that diffusivity is a quantity associated with domain
     51        assert diffusivity.domain == domain
     52
     53        self.diffusivity = diffusivity
     54        self.diffusivity_bdry_data = self.diffusivity.boundary_values
     55        self.diffusivity_data = self.diffusivity.centroid_values
     56
     57
    2358        self.n = len(self.domain)
    2459        self.dt = 1e-6 #Need to set to domain.timestep
    2560        self.boundary_len = len(domain.boundary)
    2661        self.tot_len = self.n + self.boundary_len
     62
     63        # FIXME SR: maybe this should already exist in mesh!
    2764        self.boundary_enum = self.enumerate_boundary()
     65       
    2866        self.verbose = verbose
    2967
    3068        #Geometric Information
    3169        if verbose: log.critical('Kinematic Viscosity: Building geometric structure')
     70
    3271        self.geo_structure_indices = num.zeros((self.n, 3), num.int)
    3372        self.geo_structure_values = num.zeros((self.n, 3), num.float)
     73
     74        # Only needs to built once, doesn't change
    3475        kinematic_viscosity_ext.build_geo_structure(self, self.n, self.tot_len)
     76
     77        # Setup type of scaling
    3578        self.apply_triangle_areas = triangle_areas
    36         self.triangle_areas = Sparse(self.n, self.n)
     79
     80        # FIXME SR: should this really be a matrix?
     81        temp  = Sparse(self.n, self.n)
    3782        for i in range(self.n):
    38             self.triangle_areas[i, i] = 1.0 / self.mesh.areas[i]
     83            temp[i, i] = 1.0 / self.mesh.areas[i]
    3984           
    40         self.triangle_areas = Sparse_CSR(self.triangle_areas)
    41 
    42         #Application Information
     85        self.triangle_areas = Sparse_CSR(temp)
     86
     87        # FIXME SR: More to do with solving equation
    4388        self.qty_considered = 1 #1 or 2 (uh or vh respectively)
     89
     90        #FIXME SR: Do we need Sparse or should we just go with Sparse_CSR
    4491        self.operator_matrix = Sparse(self.n, self.tot_len)
    4592
     
    4996        self.operator_colind = num.zeros((4 * self.n, ), num.int)
    5097        #Sparse_CSR.rowptr (4 entries in every row, we know this already) = [0,4,8,...,4*n]
    51         self.operator_rowptr = 4 * num.indices((self.n + 1, ))[0, :]
    52         self.stage_heights = num.zeros((self.n, 1), num.float)
    53         self.stage_heights_scaling = Sparse(self.n, self.n)
    54         self.boundary_vector = num.zeros((self.n, ), num.float)
     98        self.operator_rowptr = 4 * num.arange(self.n + 1)
     99
     100        # Build matrix self.elliptic_operator_matrix [A B]
     101        self.build_elliptic_operator()
     102
     103        # Build self.boundary_term
     104        self.build_operator_boundary_term()
    55105
    56106        self.parabolic_solve = False #Are we doing a parabolic solve at the moment?
     
    61111    def enumerate_boundary(self):
    62112        #Enumerate by boundary index
     113        # FIXME SR: Probably should be part of mesh
    63114        enumeration = {}
    64115        for i in range(self.n):
     
    70121
    71122    def set_qty_considered(self, qty):
     123        # FIXME SR: Probably should just be set by quantity to which operation is applied
    72124        if qty == 1 or qty == 'u':
    73125            self.qty_considered = 1
     
    78130            assert 0 == 1, msg
    79131
    80     def apply_stage_heights(self, h):
    81         msg = "(KV_Operator.apply_stage_heights) h vector has incorrect length"
    82         assert h.size == self.n, msg
    83 
    84         self.operator_matrix = Sparse(self.n, self.tot_len)
    85 
    86         #Evaluate the boundary stage heights - use generic_domain.update_boundary? (check enumeration)
    87         boundary_heights = num.zeros((self.boundary_len, 1), num.float)
    88         for key in self.boundary_enum.keys():
    89             boundary_heights[self.boundary_enum[key]] = self.boundary[key].evaluate()[0]
    90 
    91         kinematic_viscosity_ext.build_operator_matrix(self, self.n, self.tot_len, h, boundary_heights)
    92         self.operator_matrix = \
    93             Sparse_CSR(None, self.operator_data, self.operator_colind, self.operator_rowptr, self.n, self.tot_len)
    94 
    95         self.stage_heights = h
    96         #Set up the scaling matrix
    97         data = h
    98         num.putmask(data, data != 0, 1 / data) #take the reciprocal of each entry unless it is zero
    99         self.stage_heights_scaling = \
    100             Sparse_CSR(None, data, num.arange(self.n), num.append(num.arange(self.n), self.n), self.n, self.n)
    101 
    102         self.build_boundary_vector()
    103 
    104         return self.operator_matrix
    105 
    106     def build_boundary_vector(self):
    107         #Require stage heights applied
    108         X = num.zeros((self.tot_len, 2), num.float)
    109         for key in self.boundary_enum.keys():
    110             quantities = self.boundary[key].evaluate()
    111             h_i = quantities[0]
    112             if h_i == 0.0:
    113                 X[self.n + self.boundary_enum[key], :] = num.array([0.0, 0.0])
    114             else:
    115                 X[self.n + self.boundary_enum[key], :] = quantities[1:] / h_i
    116         self.boundary_vector = self.operator_matrix * X
     132    def build_elliptic_operator(self):
     133        """
     134        Builds matrix representing
     135
     136        div ( diffusivity grad )
     137
     138        which has the form [ A B ]
     139        """
     140
     141        #Arrays self.operator_data, self.operator_colind, self.operator_rowptr
     142        # are setup via this call
     143        kinematic_viscosity_ext.build_operator_matrix(self,self.diffusivity_data, self.diffusivity_bdry_data)
     144
     145        self.elliptic_operator_matrix = Sparse_CSR(None, \
     146                self.operator_data, self.operator_colind, self.operator_rowptr, \
     147                self.n, self.tot_len)
     148
     149#        #Set up the scaling matrix
     150#        data = h
     151#        num.putmask(data, data != 0, 1 / data) #take the reciprocal of each entry unless it is zero
     152#        self.stage_heights_scaling = \
     153#            Sparse_CSR(None, self.diffusivity_data, num.arange(self.n), num.arange(self.n +1), self.n, self.n)
     154
     155    def update_elliptic_operator(self):
     156        """
     157        Updates the data values of matrix representing
     158
     159        div ( diffusivity grad )
     160
     161        (as when diffusivitiy has changed)
     162        """
     163
     164        #Array self.operator_data is changed by this call, which should flow
     165        # through to the Sparse_CSR matrix.
     166
     167        kinematic_viscosity_ext.update_operator_matrix(self, self.n, self.tot_len, \
     168          self.diffusivity_data, self.diffusivity_bdry_data)
     169
     170
     171
     172
     173    def build_operator_boundary_term(self):
     174        """
     175        Operator has form [A B] and U = [ u ; b]
     176
     177        This procedure calculates B b which can be calculated as
     178
     179        [A B] [ 0 ; b]
     180        """
     181
     182        n = self.n
     183        tot_len = self.tot_len
     184
     185        self.boundary_term = num.zeros((n, ), num.float)
     186       
     187        X = num.zeros((tot_len,), num.float)
     188
     189        X[n:] = self.diffusivity_bdry_data
     190        self.boundary_term[:] = self.operator_matrix * X
     191
    117192        #Tidy up
    118193        if self.apply_triangle_areas:
    119             self.boundary_vector = self.triangle_areas * self.boundary_vector
    120 
    121         return self.boundary_vector
     194            self.boundary_term[:] = self.triangle_areas * self.boundary_term
     195
    122196
    123197    def elliptic_multiply(self, V, qty_considered=None, include_boundary=True):
  • trunk/anuga_core/source/anuga/operators/kinematic_viscosity_ext.c

    r8128 r8135  
    8585}
    8686
    87 int build_operator_matrix(int n,
    88                           int tot_len,
    89                           long *geo_indices,
    90                           double *geo_values,
    91                           double *h,
    92                           double *boundary_heights,
    93                           double *data,
     87
     88int build_operator_matrix(int n,
     89                          int tot_len,
     90                          long *geo_indices,
     91                          double *geo_values,
     92                          double *cell_data,
     93                          double *bdry_data,
     94                          double *data,
    9495                          long *colind) {
    9596        int i, k, edge, j[4], *sorted_j, this_index;
     
    102103                        j[edge] = geo_indices[3*i+edge];
    103104                        if (j[edge]<n) { //interior
    104                                 h_j = h[j[edge]];
     105                                h_j = cell_data[j[edge]];
    105106                        } else { //boundary
    106                                 h_j = boundary_heights[j[edge]-n];
    107                         }
    108                         v[edge] = -0.5*(h[i] + h_j)*geo_values[3*i+edge]; //the negative of the individual interaction
    109                         v_i += 0.5*(h[i] + h_j)*geo_values[3*i+edge]; //sum the three interactions
     107                                h_j = bdry_data[j[edge]-n];
     108                        }
     109                        v[edge] = -0.5*(cell_data[i] + h_j)*geo_values[3*i+edge]; //the negative of the individual interaction
     110                        v_i += 0.5*(cell_data[i] + h_j)*geo_values[3*i+edge]; //sum the three interactions
    110111                }
    111112                //Organise the set of 4 values/indices into the data and colind arrays
     
    131132}
    132133
     134int update_operator_matrix(int n,
     135                          int tot_len,
     136                          long *geo_indices,
     137                          double *geo_values,
     138                          double *cell_data,
     139                          double *bdry_data,
     140                          double *data,
     141                          long *colind) {
     142        int i, k, edge, j[4], *sorted_j, this_index;
     143        double h_j, v[3], v_i; //v[k] = value of the interaction of edge k in a given triangle, v_i = (i,i) entry
     144        for (i=0; i<n; i++) {
     145                v_i = 0.0;
     146                j[3] = i;
     147                //Get the values of each interaction, and the column index at which they occur
     148                for (edge=0; edge<3; edge++) {
     149                        j[edge] = geo_indices[3*i+edge];
     150                        if (j[edge]<n) { //interior
     151                                h_j = cell_data[j[edge]];
     152                        } else { //boundary
     153                                h_j = bdry_data[j[edge]-n];
     154                        }
     155                        v[edge] = -0.5*(cell_data[i] + h_j)*geo_values[3*i+edge]; //the negative of the individual interaction
     156                        v_i += 0.5*(cell_data[i] + h_j)*geo_values[3*i+edge]; //sum the three interactions
     157                }
     158                //Organise the set of 4 values/indices into the data and colind arrays
     159                sorted_j = quicksort((int *)j,4);
     160                for (k=0; k<4; k++) { //loop through the nonzero indices
     161                        this_index = sorted_j[k];
     162                        if (this_index == i) {
     163                                data[4*i+k] = v_i;
     164                                colind[4*i+k] = i;
     165                        } else if (this_index == j[0]) {
     166                                data[4*i+k] = v[0];
     167                                colind[4*i+k] = j[0];
     168                        } else if (this_index == j[1]) {
     169                                data[4*i+k] = v[1];
     170                                colind[4*i+k] = j[1];
     171                        } else { //this_index == j[2]
     172                                data[4*i+k] = v[2];
     173                                colind[4*i+k] = j[2];
     174                        }
     175                }
     176        }
     177        return 0;
     178}
     179
    133180/**
    134181* Python wrapper methods
     
    147194   
    148195    //Convert Python arguments to C
    149     if (!PyArg_ParseTuple(args, "Oii", &kv_operator, &n, &tot_len)) {
     196    if (!PyArg_ParseTuple(args, "Oii", &kv_operator)) {
    150197        PyErr_SetString(PyExc_RuntimeError, "build_geo_structure could not parse input");
    151198        return NULL;
     
    158205
    159206    //Extract parameters
     207    n       = get_python_integer(kv_operator,"n");
     208    tot_len = get_python_integer(kv_operator,"tot_len");
     209
    160210    centroid_coordinates = get_consecutive_array(mesh,"centroid_coordinates");
    161211    neighbours = get_consecutive_array(mesh,"neighbours");
     
    195245        int n, tot_len, err;
    196246        PyArrayObject
    197                 *h,
    198                 *boundary_heights,
     247                *cell_data,
     248                *bdry_data,
    199249                *geo_indices,
    200250                *geo_values,
     
    203253       
    204254        //Convert Python arguments to C
    205     if (!PyArg_ParseTuple(args, "OiiOO", &kv_operator, &n, &tot_len, &h, &boundary_heights)) {
    206         PyErr_SetString(PyExc_RuntimeError, "get_stage_height_interactions could not parse input");
    207         return NULL;
    208     }
    209        
     255    if (!PyArg_ParseTuple(args, "OOO", &kv_operator, &cell_data, &bdry_data)) {
     256        PyErr_SetString(PyExc_RuntimeError, "build_operator_matrix could not parse input");
     257        return NULL;
     258    }
     259
     260
     261    n       = get_python_integer(kv_operator,"n");
     262    tot_len = get_python_integer(kv_operator,"tot_len");
     263
     264
    210265        geo_indices = get_consecutive_array(kv_operator,"geo_structure_indices");
    211266        geo_values = get_consecutive_array(kv_operator,"geo_structure_values");
     
    216271                                                                (long *)geo_indices -> data,
    217272                                                                (double *)geo_values -> data,
    218                                                                 (double *)h -> data,
    219                                                                 (double *)boundary_heights -> data,
     273                                                                (double *)cell_data -> data,
     274                                                                (double *)bdry_data -> data,
    220275                                                                (double *)_data -> data,
    221276                                                                (long *)colind -> data);
     
    233288}
    234289
     290
     291static PyObject *py_update_operator_matrix(PyObject *self, PyObject *args) {
     292        PyObject *kv_operator;
     293        int n, tot_len, err;
     294        PyArrayObject
     295                *cell_data,
     296                *bdry_data,
     297                *geo_indices,
     298                *geo_values,
     299                *_data,
     300                *colind;
     301
     302        //Convert Python arguments to C
     303    if (!PyArg_ParseTuple(args, "OOO", &kv_operator, &cell_data, &bdry_data)) {
     304        PyErr_SetString(PyExc_RuntimeError, "update_operator_matrix could not parse input");
     305        return NULL;
     306    }
     307
     308
     309    n       = get_python_integer(kv_operator,"n");
     310    tot_len = get_python_integer(kv_operator,"tot_len");
     311
     312
     313        geo_indices = get_consecutive_array(kv_operator,"geo_structure_indices");
     314        geo_values = get_consecutive_array(kv_operator,"geo_structure_values");
     315        _data = get_consecutive_array(kv_operator,"operator_data");
     316        colind = get_consecutive_array(kv_operator,"operator_colind");
     317
     318        err = update_operator_matrix(n,tot_len,
     319                                                                (long *)geo_indices -> data,
     320                                                                (double *)geo_values -> data,
     321                                                                (double *)cell_data -> data,
     322                                                                (double *)bdry_data -> data,
     323                                                                (double *)_data -> data,
     324                                                                (long *)colind -> data);
     325    if (err != 0) {
     326        PyErr_SetString(PyExc_RuntimeError, "Could not get stage height interactions");
     327        return NULL;
     328    }
     329
     330        Py_DECREF(geo_indices);
     331        Py_DECREF(geo_values);
     332        Py_DECREF(_data);
     333        Py_DECREF(colind);
     334
     335    return Py_BuildValue("");
     336
     337}
     338
    235339static struct PyMethodDef MethodTable[] = {
    236340        {"build_geo_structure",py_build_geo_structure,METH_VARARGS,"Print out"},
    237341                {"build_operator_matrix",py_build_operator_matrix,METH_VARARGS,"Print out"},
     342        {"update_operator_matrix",py_update_operator_matrix,METH_VARARGS,"Print out"},
    238343        {NULL,NULL,0,NULL} // sentinel
    239344};
  • trunk/anuga_core/source/anuga/operators/test_kinematic_viscosity.py

    r8128 r8135  
    2929        domain.set_boundary({'edge0': D0, 'edge1': D1, 'edge2': D2})
    3030
     31        domain.set_quantity('stage', lambda x,y : x+2*y )
     32        domain.set_quantity('elevation', lambda x,y : 3*x+5*y )
     33
     34
     35        #print domain.quantities['stage'].vertex_values
     36
     37        #print domain.quantities['stage'].edge_values
     38
    3139        domain.update_boundary()
    3240
    3341
    34         print domain.quantities['elevation'].boundary_values
     42        #print domain.quantities['stage'].boundary_values
    3543       
    3644        return Kinematic_Viscosity(domain)
     
    8896        assert num.allclose(values, num.array([[-3.0,-6.0/sqrt(5),-6.0/sqrt(5)],[-6.0/sqrt(5),-3.0,-6.0/sqrt(5)]]))
    8997
    90     def test_apply_heights(self):
     98    def test_elliptic_matrix(self):
    9199        operator1 = self.operator1()
    92100        operator2 = self.operator2()
    93101
    94         h = num.array([1.0])
    95         A = operator1.apply_stage_heights(h)
     102        domain1 = operator1.domain
     103        domain2 = operator2.domain
     104
     105
     106        A = operator1.elliptic_operator_matrix
     107
     108        print A
     109        print num.array([-6.0-12.0/sqrt(5), 6.0,  6.0/sqrt(5), 6.0/sqrt(5)])
     110       
    96111        assert num.allclose(A.todense(), num.array([-6.0-12.0/sqrt(5), 6.0,  6.0/sqrt(5), 6.0/sqrt(5)]))
    97112
    98         h = num.array([2.0])
    99         A = operator1.apply_stage_heights(h)
     113
     114        A = operator1.elliptic_operator_matrix
    100115        assert num.allclose(A.todense(), 1.5*num.array([-6.0-12.0/sqrt(5), 6.0, 6.0/sqrt(5), 6.0/sqrt(5)]))
    101116
Note: See TracChangeset for help on using the changeset viewer.