Changeset 8135
- Timestamp:
- Mar 10, 2011, 3:31:46 PM (14 years ago)
- 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 1 1 2 2 from anuga import Domain 3 from anuga import Quantity 3 4 from anuga.utilities.sparse import Sparse, Sparse_CSR 4 5 from anuga.utilities.cg_solve import conjugate_gradient 5 6 import anuga.abstract_2d_finite_volumes.neighbour_mesh as neighbour_mesh 6 from anuga .abstract_2d_finite_volumes.generic_boundary_conditionsimport Dirichlet_boundary7 from anuga import Dirichlet_boundary 7 8 import numpy as num 8 9 import kinematic_viscosity_ext … … 11 12 class Kinematic_Viscosity: 12 13 """ 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 14 36 """ 15 37 16 def __init__(self, domain, triangle_areas=True, verbose=False):38 def __init__(self, domain, diffusivity = None, triangle_areas=True, verbose=False): 17 39 if verbose: log.critical('Kinematic Viscosity: Beginning Initialisation') 18 40 #Expose the domain attributes … … 21 43 self.mesh = domain.mesh 22 44 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 23 58 self.n = len(self.domain) 24 59 self.dt = 1e-6 #Need to set to domain.timestep 25 60 self.boundary_len = len(domain.boundary) 26 61 self.tot_len = self.n + self.boundary_len 62 63 # FIXME SR: maybe this should already exist in mesh! 27 64 self.boundary_enum = self.enumerate_boundary() 65 28 66 self.verbose = verbose 29 67 30 68 #Geometric Information 31 69 if verbose: log.critical('Kinematic Viscosity: Building geometric structure') 70 32 71 self.geo_structure_indices = num.zeros((self.n, 3), num.int) 33 72 self.geo_structure_values = num.zeros((self.n, 3), num.float) 73 74 # Only needs to built once, doesn't change 34 75 kinematic_viscosity_ext.build_geo_structure(self, self.n, self.tot_len) 76 77 # Setup type of scaling 35 78 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) 37 82 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] 39 84 40 self.triangle_areas = Sparse_CSR( self.triangle_areas)41 42 # Application Information85 self.triangle_areas = Sparse_CSR(temp) 86 87 # FIXME SR: More to do with solving equation 43 88 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 44 91 self.operator_matrix = Sparse(self.n, self.tot_len) 45 92 … … 49 96 self.operator_colind = num.zeros((4 * self.n, ), num.int) 50 97 #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() 55 105 56 106 self.parabolic_solve = False #Are we doing a parabolic solve at the moment? … … 61 111 def enumerate_boundary(self): 62 112 #Enumerate by boundary index 113 # FIXME SR: Probably should be part of mesh 63 114 enumeration = {} 64 115 for i in range(self.n): … … 70 121 71 122 def set_qty_considered(self, qty): 123 # FIXME SR: Probably should just be set by quantity to which operation is applied 72 124 if qty == 1 or qty == 'u': 73 125 self.qty_considered = 1 … … 78 130 assert 0 == 1, msg 79 131 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 117 192 #Tidy up 118 193 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 122 196 123 197 def elliptic_multiply(self, V, qty_considered=None, include_boundary=True): -
trunk/anuga_core/source/anuga/operators/kinematic_viscosity_ext.c
r8128 r8135 85 85 } 86 86 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 88 int 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, 94 95 long *colind) { 95 96 int i, k, edge, j[4], *sorted_j, this_index; … … 102 103 j[edge] = geo_indices[3*i+edge]; 103 104 if (j[edge]<n) { //interior 104 h_j = h[j[edge]];105 h_j = cell_data[j[edge]]; 105 106 } else { //boundary 106 h_j = b oundary_heights[j[edge]-n];107 } 108 v[edge] = -0.5*( h[i] + h_j)*geo_values[3*i+edge]; //the negative of the individual interaction109 v_i += 0.5*( h[i] + h_j)*geo_values[3*i+edge]; //sum the three interactions107 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 110 111 } 111 112 //Organise the set of 4 values/indices into the data and colind arrays … … 131 132 } 132 133 134 int 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 133 180 /** 134 181 * Python wrapper methods … … 147 194 148 195 //Convert Python arguments to C 149 if (!PyArg_ParseTuple(args, "Oii", &kv_operator , &n, &tot_len)) {196 if (!PyArg_ParseTuple(args, "Oii", &kv_operator)) { 150 197 PyErr_SetString(PyExc_RuntimeError, "build_geo_structure could not parse input"); 151 198 return NULL; … … 158 205 159 206 //Extract parameters 207 n = get_python_integer(kv_operator,"n"); 208 tot_len = get_python_integer(kv_operator,"tot_len"); 209 160 210 centroid_coordinates = get_consecutive_array(mesh,"centroid_coordinates"); 161 211 neighbours = get_consecutive_array(mesh,"neighbours"); … … 195 245 int n, tot_len, err; 196 246 PyArrayObject 197 * h,198 *b oundary_heights,247 *cell_data, 248 *bdry_data, 199 249 *geo_indices, 200 250 *geo_values, … … 203 253 204 254 //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 210 265 geo_indices = get_consecutive_array(kv_operator,"geo_structure_indices"); 211 266 geo_values = get_consecutive_array(kv_operator,"geo_structure_values"); … … 216 271 (long *)geo_indices -> data, 217 272 (double *)geo_values -> data, 218 (double *) h -> data,219 (double *)b oundary_heights -> data,273 (double *)cell_data -> data, 274 (double *)bdry_data -> data, 220 275 (double *)_data -> data, 221 276 (long *)colind -> data); … … 233 288 } 234 289 290 291 static 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 235 339 static struct PyMethodDef MethodTable[] = { 236 340 {"build_geo_structure",py_build_geo_structure,METH_VARARGS,"Print out"}, 237 341 {"build_operator_matrix",py_build_operator_matrix,METH_VARARGS,"Print out"}, 342 {"update_operator_matrix",py_update_operator_matrix,METH_VARARGS,"Print out"}, 238 343 {NULL,NULL,0,NULL} // sentinel 239 344 }; -
trunk/anuga_core/source/anuga/operators/test_kinematic_viscosity.py
r8128 r8135 29 29 domain.set_boundary({'edge0': D0, 'edge1': D1, 'edge2': D2}) 30 30 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 31 39 domain.update_boundary() 32 40 33 41 34 print domain.quantities['elevation'].boundary_values42 #print domain.quantities['stage'].boundary_values 35 43 36 44 return Kinematic_Viscosity(domain) … … 88 96 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)]])) 89 97 90 def test_ apply_heights(self):98 def test_elliptic_matrix(self): 91 99 operator1 = self.operator1() 92 100 operator2 = self.operator2() 93 101 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 96 111 assert num.allclose(A.todense(), num.array([-6.0-12.0/sqrt(5), 6.0, 6.0/sqrt(5), 6.0/sqrt(5)])) 97 112 98 h = num.array([2.0]) 99 A = operator1. apply_stage_heights(h)113 114 A = operator1.elliptic_operator_matrix 100 115 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)])) 101 116
Note: See TracChangeset
for help on using the changeset viewer.