Changeset 1641


Ignore:
Timestamp:
Jul 26, 2005, 5:16:04 PM (20 years ago)
Author:
ole
Message:

Undid changes committed in r1458 and r1459:

svn merge -r 1459:1457 https://datamining/...../pyvolution

and thus brought back Matt's optimisations

modified shallow_water.py
modified shallow_water_ext.c

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

Legend:

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

    r1636 r1641  
    5656
    5757from domain import *
    58 from region import *
     58from region import *#
     59
    5960Generic_domain = Domain #Rename
    6061
     
    8182        #Realtime visualisation
    8283        self.visualiser = None
    83         self.visualise = False
     84        self.visualise  = False
    8485        self.visualise_color_stage = False
    8586        self.visualise_stage_range = 1.0
     
    107108        #self.eta = self.quantities['friction']
    108109
     110    def initialise_visualiser(self,scale_z=1.0,rect=None):
     111        #Realtime visualisation
     112        if self.visualiser is None:
     113            from realtime_visualisation_new import Visualiser
     114            self.visualiser = Visualiser(self,scale_z,rect)
     115        self.visualise = True
     116
    109117    def check_integrity(self):
    110118        Generic_domain.check_integrity(self)
     
    119127        assert self.conserved_quantities[2] == 'ymomentum', msg
    120128
     129    def extrapolate_second_order_sw(self):
     130        #Call correct module function
     131        #(either from this module or C-extension)
     132        extrapolate_second_order_sw(self)
    121133
    122134    def compute_fluxes(self):
     
    250262        self.writer.store_timestep(name)
    251263
     264####################MH 090605 new extrapolation function belonging to domain class
     265def extrapolate_second_order_sw(domain):
     266    """extrapolate conserved quntities to the vertices of the triangles
     267    Python version to be written after the C version
     268    """
     269    msg = 'Method extrapolate_second_order_sw should be implemented in C'
     270    raise msg
     271####################MH 090605 ###########################################
    252272
    253273    def initialise_visualiser(self,scale_z=1.0,rect=None):
     
    436456
    437457    flux = zeros(3, Float) #Work array for summing up fluxes
     458
    438459
    439460    #Loop
     
    482503    domain.timestep = timestep
    483504
     505#MH090605 The following method belongs to the shallow_water domain class
     506#see comments in the corresponding method in shallow_water_ext.c
     507def extrapolate_second_order_sw_c(domain):
     508    """Wrapper calling C version of extrapolate_second_order_sw
     509    """
     510    import sys
     511    from Numeric import zeros, Float
     512
     513    N = domain.number_of_elements
     514
     515    #Shortcuts
     516    Stage = domain.quantities['stage']
     517    Xmom = domain.quantities['xmomentum']
     518    Ymom = domain.quantities['ymomentum']
     519    from shallow_water_ext import extrapolate_second_order_sw
     520    extrapolate_second_order_sw(domain,domain.surrogate_neighbours,
     521                                domain.number_of_boundaries,
     522                                domain.centroid_coordinates,
     523                                Stage.centroid_values,
     524                                Xmom.centroid_values,
     525                                Ymom.centroid_values,
     526                                domain.vertex_coordinates,
     527                                Stage.vertex_values,
     528                                Xmom.vertex_values,
     529                                Ymom.vertex_values)
    484530
    485531def compute_fluxes_c(domain):
     
    516562                                     Stage.explicit_update,
    517563                                     Xmom.explicit_update,
    518                                      Ymom.explicit_update)
     564                                     Ymom.explicit_update,
     565                                     domain.already_computed_flux)
    519566
    520567
     
    545592    """
    546593
     594    from config import optimised_gradient_limiter
     595
    547596    #Remove very thin layers of water
    548597    protect_against_infinitesimal_and_negative_heights(domain)
    549598
    550599    #Extrapolate all conserved quantities
    551     for name in domain.conserved_quantities:
    552         Q = domain.quantities[name]
    553         if domain.order == 1:
    554             Q.extrapolate_first_order()
     600    if optimised_gradient_limiter:
     601        #MH090605 if second order,
     602        #perform the extrapolation and limiting on
     603        #all of the conserved quantitie
     604       
     605        if (domain.order == 1):
     606            for name in domain.conserved_quantities:
     607                Q = domain.quantities[name]
     608                Q.extrapolate_first_order()
    555609        elif domain.order == 2:
    556             Q.extrapolate_second_order()
    557             Q.limit()
     610            domain.extrapolate_second_order_sw()
    558611        else:
    559612            raise 'Unknown order'
     613    else:   
     614        #old code:
     615        for name in domain.conserved_quantities:
     616            Q = domain.quantities[name]
     617            if domain.order == 1:
     618                Q.extrapolate_first_order()
     619            elif domain.order == 2:
     620                Q.extrapolate_second_order()
     621                Q.limit()
     622            else:
     623                raise 'Unknown order'
     624           
    560625
    561626    #Take bed elevation into account when water heights are small
     
    738803
    739804    #Call C-extension
    740     from shallow_water_ext import h_limiter
     805    from shallow_water_ext import h_limiter_sw as h_limiter
    741806    hvbar = h_limiter(domain, hc, hv)
    742807
     
    909974            raise msg
    910975
    911         #Handy shorthands
    912         self.stage = domain.quantities['stage'].edge_values
    913         self.xmom = domain.quantities['xmomentum'].edge_values
    914         self.ymom = domain.quantities['ymomentum'].edge_values
    915         self.normals = domain.normals
    916 
    917         from Numeric import zeros, Float
    918         self.conserved_quantities = zeros(3, Float)
     976        #Handy shorthands
     977        self.stage  = domain.quantities['stage'].edge_values
     978        self.xmom    = domain.quantities['xmomentum'].edge_values
     979        self.ymom    = domain.quantities['ymomentum'].edge_values
     980        self.normals = domain.normals
     981
     982        from Numeric import zeros, Float
     983        self.conserved_quantities = zeros(3, Float)
    919984
    920985    def __repr__(self):
     
    927992        """
    928993
    929         q = self.conserved_quantities
    930         q[0] = self.stage[vol_id, edge_id]
    931         q[1] = self.xmom[vol_id, edge_id]
    932         q[2] = self.ymom[vol_id, edge_id]
    933 
    934         normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
     994        q = self.conserved_quantities
     995        q[0] = self.stage[vol_id, edge_id]
     996        q[1] = self.xmom[vol_id, edge_id]
     997        q[2] = self.ymom[vol_id, edge_id]
     998
     999        normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
    9351000
    9361001
     
    16471712    from shallow_water_ext import rotate, assign_windfield_values
    16481713    compute_fluxes = compute_fluxes_c
     1714    extrapolate_second_order_sw=extrapolate_second_order_sw_c
    16491715    gravity = gravity_c
    16501716    manning_friction = manning_friction_c
  • inundation/ga/storm_surge/pyvolution/shallow_water_ext.c

    r1636 r1641  
    4747}
    4848
    49 
     49int find_qmin_and_qmax(double dq0, double dq1, double dq2, double *qmin, double *qmax){
     50  //Considering the centroid of an FV triangle and the vertices of its auxiliary triangle, find
     51  //qmin=min(q)-qc and qmax=max(q)-qc, where min(q) and max(q) are respectively min and max over the
     52  //four values (at the centroid of the FV triangle and the auxiliary triangle vertices),
     53  //and qc is the centroid
     54  //dq0=q(vertex0)-q(centroid of FV triangle)
     55  //dq1=q(vertex1)-q(vertex0)
     56  //dq2=q(vertex2)-q(vertex0)
     57  if (dq0>=0.0){
     58    if (dq1>=dq2){
     59      if (dq1>=0.0)
     60        *qmax=dq0+dq1;
     61      else
     62        *qmax=dq0;
     63      if ((*qmin=dq0+dq2)<0)
     64        ;//qmin is already set to correct value
     65      else
     66        *qmin=0.0;
     67    }
     68    else{//dq1<dq2
     69      if (dq2>0)
     70        *qmax=dq0+dq2;
     71      else
     72        *qmax=dq0;
     73      if ((*qmin=dq0+dq1)<0)
     74        ;//qmin is the correct value
     75      else
     76        *qmin=0.0;
     77    }
     78  }
     79  else{//dq0<0
     80    if (dq1<=dq2){
     81      if (dq1<0.0)
     82        *qmin=dq0+dq1;
     83      else
     84        *qmin=dq0;
     85      if ((*qmax=dq0+dq2)>0.0)
     86        ;//qmax is already set to the correct value
     87      else
     88        *qmax=0.0;
     89    }
     90    else{//dq1>dq2
     91      if (dq2<0.0)
     92        *qmin=dq0+dq2;
     93      else
     94        *qmin=dq0;
     95      if ((*qmax=dq0+dq1)>0.0)
     96        ;//qmax is already set to the correct value
     97      else
     98        *qmax=0.0;
     99    }
     100  }
     101  return 0;
     102}
     103
     104int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
     105  //given provisional jumps dqv from the FV triangle centroid to its vertices and
     106  //jumps qmin (qmax) between the centroid of the FV triangle and the
     107  //minimum (maximum) of the values at the centroid of the FV triangle and the auxiliary triangle vertices,
     108  //calculate a multiplicative factor phi by which the provisional vertex jumps are to be limited
     109  int i;
     110  double r=1000.0, r0=1.0, phi=1.0;
     111  static double TINY = 1.0e-100;//to avoid machine accuracy problems.
     112  //Any provisional jump with magnitude < TINY does not contribute to the limiting process.
     113  for (i=0;i<3;i++){
     114    if (dqv[i]<-TINY)
     115      r0=qmin/dqv[i];
     116    if (dqv[i]>TINY)
     117      r0=qmax/dqv[i];
     118    r=min(r0,r);
     119    //
     120  }
     121  phi=min(r*beta_w,1.0);
     122  for (i=0;i<3;i++)
     123    dqv[i]=dqv[i]*phi;
     124  return 0;
     125}
    50126
    51127// Computational function for flux computation (using stage w=z+h)
     
    170246      if (h >= eps) {
    171247        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
    172         S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
     248        //S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
     249        S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
    173250        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
    174251
     
    423500}
    424501
     502PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
     503  /*Compute the vertex values based on a linear reconstruction on each triangle
     504    These values are calculated as follows:
     505    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
     506    formed by the centroids of its three neighbours.
     507    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
     508    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
     509    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
     510    original triangle has gradient (a,b).
     511    3) Provisional vertex junmps dqv[0,1,2] are computed and these are then limited by calling the functions
     512    find_qmin_and_qmax and limit_gradient
     513
     514    Python call:
     515    extrapolate_second_order_sw(domain.surrogate_neighbours,
     516                                domain.number_of_boundaries
     517                                domain.centroid_coordinates,
     518                                Stage.centroid_values
     519                                Xmom.centroid_values
     520                                Ymom.centroid_values
     521                                domain.vertex_coordinates,
     522                                Stage.vertex_values,
     523                                Xmom.vertex_values,
     524                                Ymom.vertex_values)
     525
     526    Post conditions:
     527            The vertices of each triangle have values from a limited linear reconstruction
     528            based on centroid values
     529
     530  */
     531  PyArrayObject *surrogate_neighbours,
     532    *number_of_boundaries,
     533    *centroid_coordinates,
     534    *stage_centroid_values,
     535    *xmom_centroid_values,
     536    *ymom_centroid_values,
     537    *vertex_coordinates,
     538    *stage_vertex_values,
     539    *xmom_vertex_values,
     540    *ymom_vertex_values;
     541  PyObject *domain, *Tmp;
     542  //Local variables
     543  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
     544  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
     545  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
     546  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
     547  double dqv[3], qmin, qmax, beta_w;//provisional jumps from centroids to v'tices and safety factor re limiting
     548  //by which these jumps are limited
     549  // Convert Python arguments to C
     550  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
     551                        &domain,
     552                        &surrogate_neighbours,
     553                        &number_of_boundaries,
     554                        &centroid_coordinates,
     555                        &stage_centroid_values,
     556                        &xmom_centroid_values,
     557                        &ymom_centroid_values,
     558                        &vertex_coordinates,
     559                        &stage_vertex_values,
     560                        &xmom_vertex_values,
     561                        &ymom_vertex_values)) {
     562    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
     563    return NULL;
     564  }
     565
     566  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
     567  Tmp = PyObject_GetAttrString(domain, "beta_w");
     568  if (!Tmp)
     569    return NULL;
     570  beta_w = PyFloat_AsDouble(Tmp);
     571  Py_DECREF(Tmp);
     572  number_of_elements = stage_centroid_values -> dimensions[0];
     573  for (k=0; k<number_of_elements; k++) {
     574    k3=k*3;
     575    k6=k*6;
     576
     577    if (((long *) number_of_boundaries->data)[k]==3){/*no neighbours, set gradient on the triangle to zero*/
     578      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
     579      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
     580      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
     581      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
     582      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
     583      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
     584      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
     585      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
     586      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
     587      continue;
     588    }
     589    else {//we will need centroid coordinates and vertex coordinates of the triangle
     590      //get the vertex coordinates of the FV triangle
     591      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1];
     592      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3];
     593      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5];
     594      //get the centroid coordinates of the FV triangle
     595      coord_index=2*k;
     596      x=((double *)centroid_coordinates->data)[coord_index];
     597      y=((double *)centroid_coordinates->data)[coord_index+1];
     598      //store x- and y- differentials for the vertices of the FV triangle relative to the centroid
     599      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
     600      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
     601    }
     602    if (((long *)number_of_boundaries->data)[k]<=1){
     603      //if no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
     604      //if one boundary, auxiliary triangle is formed from this centroid and its two neighbours
     605      k0=((long *)surrogate_neighbours->data)[k3];
     606      k1=((long *)surrogate_neighbours->data)[k3+1];
     607      k2=((long *)surrogate_neighbours->data)[k3+2];
     608      //get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
     609      coord_index=2*k0;
     610      x0=((double *)centroid_coordinates->data)[coord_index];
     611      y0=((double *)centroid_coordinates->data)[coord_index+1];
     612      coord_index=2*k1;
     613      x1=((double *)centroid_coordinates->data)[coord_index];
     614      y1=((double *)centroid_coordinates->data)[coord_index+1];
     615      coord_index=2*k2;
     616      x2=((double *)centroid_coordinates->data)[coord_index];
     617      y2=((double *)centroid_coordinates->data)[coord_index+1];
     618      //store x- and y- differentials for the vertices of the auxiliary triangle
     619      dx1=x1-x0; dx2=x2-x0;
     620      dy1=y1-y0; dy2=y2-y0;
     621      //calculate 2*area of the auxiliary triangle
     622      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
     623      //If the mesh is 'weird' near the boundary, the trianlge might be flat or clockwise:
     624      if (area2<=0)
     625        return NULL;
     626
     627      //### stage ###
     628      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
     629      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
     630      //calculate differentials between the vertices of the auxiliary triangle
     631      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
     632      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
     633      //calculate the gradient of stage on the auxiliary triangle
     634      a = dy2*dq1 - dy1*dq2;
     635      a /= area2;
     636      b = dx1*dq2 - dx2*dq1;
     637      b /= area2;
     638      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
     639      dqv[0]=a*dxv0+b*dyv0;
     640      dqv[1]=a*dxv1+b*dyv1;
     641      dqv[2]=a*dxv2+b*dyv2;
     642      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
     643      //and compute jumps from the centroid to the min and max
     644      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
     645      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
     646      for (i=0;i<3;i++)
     647        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
     648
     649      //### xmom ###
     650      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
     651      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
     652      //calculate differentials between the vertices of the auxiliary triangle
     653      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
     654      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
     655      //calculate the gradient of xmom on the auxiliary triangle
     656      a = dy2*dq1 - dy1*dq2;
     657      a /= area2;
     658      b = dx1*dq2 - dx2*dq1;
     659      b /= area2;
     660      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
     661      dqv[0]=a*dxv0+b*dyv0;
     662      dqv[1]=a*dxv1+b*dyv1;
     663      dqv[2]=a*dxv2+b*dyv2;
     664      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
     665      //and compute jumps from the centroid to the min and max
     666      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
     667      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
     668      for (i=0;i<3;i++)
     669        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
     670
     671      //### ymom ###
     672      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
     673      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
     674      //calculate differentials between the vertices of the auxiliary triangle
     675      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
     676      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
     677      //calculate the gradient of xmom on the auxiliary triangle
     678      a = dy2*dq1 - dy1*dq2;
     679      a /= area2;
     680      b = dx1*dq2 - dx2*dq1;
     681      b /= area2;
     682      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
     683      dqv[0]=a*dxv0+b*dyv0;
     684      dqv[1]=a*dxv1+b*dyv1;
     685      dqv[2]=a*dxv2+b*dyv2;
     686      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
     687      //and compute jumps from the centroid to the min and max
     688      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
     689      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
     690      for (i=0;i<3;i++)
     691        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
     692    }//if (number_of_boundaries[k]<=1)
     693    else{//number_of_boundaries==2
     694      //one internal neighbour and gradient is in direction of the neighbour's centroid
     695      //find the only internal neighbour
     696      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
     697        if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
     698          break;
     699      }
     700      if ((k2==k3+3))//if we didn't find an internal neighbour
     701        return NULL;//error
     702      k1=((long *)surrogate_neighbours->data)[k2];
     703      //the coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
     704      coord_index=2*k1;
     705      x1=((double *)centroid_coordinates->data)[coord_index];
     706      y1=((double *)centroid_coordinates->data)[coord_index+1];
     707      //compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
     708      dx1=x1-x; dy1=y1-y;
     709      //set area2 as the square of the distance
     710      area2=dx1*dx1+dy1*dy1;
     711      //set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
     712      //respectively correspond to the x- and y- gradients of the conserved quantities
     713      dx2=1.0/area2;
     714      dy2=dx2*dy1;
     715      dx2*=dx1;
     716
     717      //## stage ###
     718      //compute differentials
     719      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
     720      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
     721      a=dq1*dx2;
     722      b=dq1*dy2;
     723      //calculate provisional vertex jumps, to be limited
     724      dqv[0]=a*dxv0+b*dyv0;
     725      dqv[1]=a*dxv1+b*dyv1;
     726      dqv[2]=a*dxv2+b*dyv2;
     727      //now limit the jumps
     728      if (dq1>=0.0){
     729        qmin=0.0;
     730        qmax=dq1;
     731      }
     732      else{
     733        qmin=dq1;
     734        qmax=0.0;
     735      }
     736      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
     737      for (i=0;i<3;i++)
     738        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
     739
     740      //## xmom ###
     741      //compute differentials
     742      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
     743      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
     744      a=dq1*dx2;
     745      b=dq1*dy2;
     746      //calculate provisional vertex jumps, to be limited
     747      dqv[0]=a*dxv0+b*dyv0;
     748      dqv[1]=a*dxv1+b*dyv1;
     749      dqv[2]=a*dxv2+b*dyv2;
     750      //now limit the jumps
     751      if (dq1>=0.0){
     752        qmin=0.0;
     753        qmax=dq1;
     754      }
     755      else{
     756        qmin=dq1;
     757        qmax=0.0;
     758      }
     759      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
     760      for (i=0;i<3;i++)
     761        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
     762
     763      //## ymom ###
     764      //compute differentials
     765      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
     766      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
     767      a=dq1*dx2;
     768      b=dq1*dy2;
     769      //calculate provisional vertex jumps, to be limited
     770      dqv[0]=a*dxv0+b*dyv0;
     771      dqv[1]=a*dxv1+b*dyv1;
     772      dqv[2]=a*dxv2+b*dyv2;
     773      //now limit the jumps
     774      if (dq1>=0.0){
     775        qmin=0.0;
     776        qmax=dq1;
     777      }
     778      else{
     779        qmin=dq1;
     780        qmax=0.0;
     781      }
     782      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
     783      for (i=0;i<3;i++)
     784        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
     785    }//else [number_of_boudaries==2]
     786  }//for k=0 to number_of_elements-1
     787  return Py_BuildValue("");
     788}//extrapolate_second-order_sw
     789
    425790PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
    426791  //
     
    480845}
    481846
    482 
    483847PyObject *compute_fluxes(PyObject *self, PyObject *args) {
    484848  /*Compute all fluxes and the timestep suitable for all volumes
     
    499863    domain.timestep = compute_fluxes(timestep,
    500864                                     domain.epsilon,
    501                                      domain.g,
     865                                     domain.g,
    502866                                     domain.neighbours,
    503867                                     domain.neighbour_edges,
     
    515879                                     Stage.explicit_update,
    516880                                     Xmom.explicit_update,
    517                                      Ymom.explicit_update)
     881                                     Ymom.explicit_update,
     882                                     already_computed_flux)
    518883
    519884
     
    537902    *stage_explicit_update,
    538903    *xmom_explicit_update,
    539     *ymom_explicit_update;
     904    *ymom_explicit_update,
     905    *already_computed_flux;//tracks whether the flux across an edge has already been computed
    540906
    541907
     
    543909  double timestep, max_speed, epsilon, g;
    544910  double normal[2], ql[3], qr[3], zl, zr;
    545   double flux[3], edgeflux[3]; //Work arrays for summing up fluxes
    546 
    547   int number_of_elements, k, i, j, m, n;
    548   int ki, nm, ki2; //Index shorthands
     911  double edgeflux[3]; //Work arrays for summing up fluxes
     912
     913  int number_of_elements, k, i, m, n;
     914  int ki, nm=0, ki2; //Index shorthands
     915  static long call=1;
    549916
    550917
    551918  // Convert Python arguments to C
    552   if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOO",
     919  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOO",
    553920                        &timestep,
    554921                        &epsilon,
     
    567934                        &stage_explicit_update,
    568935                        &xmom_explicit_update,
    569                         &ymom_explicit_update)) {
     936                        &ymom_explicit_update,
     937                        &already_computed_flux)) {
    570938    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
    571939    return NULL;
    572940  }
    573 
    574941  number_of_elements = stage_edge_values -> dimensions[0];
    575 
    576 
     942  call++;//a static local variable to which already_computed_flux is compared
     943  //set explicit_update to zero for all conserved_quantities.
     944  //This assumes compute_fluxes called before forcing terms
    577945  for (k=0; k<number_of_elements; k++) {
    578 
    579     //Reset work array
    580     for (j=0; j<3; j++) flux[j] = 0.0;
    581 
    582     //Loop through neighbours and compute edge flux for each
     946    ((double *) stage_explicit_update -> data)[k]=0.0;
     947    ((double *) xmom_explicit_update -> data)[k]=0.0;
     948    ((double *) ymom_explicit_update -> data)[k]=0.0;
     949  }
     950  //Loop through neighbours and compute edge flux for each
     951  for (k=0; k<number_of_elements; k++) {
    583952    for (i=0; i<3; i++) {
    584953      ki = k*3+i;
     954      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
     955        continue;
    585956      ql[0] = ((double *) stage_edge_values -> data)[ki];
    586957      ql[1] = ((double *) xmom_edge_values -> data)[ki];
     
    598969      } else {
    599970        m = ((long *) neighbour_edges -> data)[ki];
    600 
    601971        nm = n*3+m;
    602972        qr[0] = ((double *) stage_edge_values -> data)[nm];
     
    605975        zr =    ((double *) bed_edge_values -> data)[nm];
    606976      }
    607 
    608       //printf("%d %d [%d] (%d, %d): %.2f %.2f %.2f\n", k, i, ki, n, m,
    609       //             ql[0], ql[1], ql[2]);
    610 
    611 
    612977      // Outward pointing normal vector
    613978      // normal = domain.normals[k, 2*i:2*i+2]
     
    615980      normal[0] = ((double *) normals -> data)[ki2];
    616981      normal[1] = ((double *) normals -> data)[ki2+1];
    617 
    618982      //Edge flux computation
    619983      flux_function(ql, qr, zl, zr,
     
    621985                    epsilon, g,
    622986                    edgeflux, &max_speed);
    623 
    624 
    625       //flux -= edgeflux * edgelengths[k,i]
    626       for (j=0; j<3; j++) {
    627         flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
     987      //update triangle k
     988      ((long *) already_computed_flux->data)[ki]=call;
     989      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
     990      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
     991      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
     992      //update the neighbour n
     993      if (n>=0){
     994        ((long *) already_computed_flux->data)[nm]=call;
     995        ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
     996        ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
     997        ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
    628998      }
    629 
    630       //Update timestep
    631       //timestep = min(timestep, domain.radii[k]/max_speed)
    632       //FIXME: SR Add parameter for CFL condition
    633       if (max_speed > epsilon) {
    634         timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
    635       }
     999      ///for (j=0; j<3; j++) {
     1000        ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
     1001        ///}
     1002        //Update timestep
     1003        //timestep = min(timestep, domain.radii[k]/max_speed)
     1004        //FIXME: SR Add parameter for CFL condition
     1005        if (max_speed > epsilon) {
     1006          timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
     1007          //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
     1008          if (n>=0)
     1009            timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
     1010        }
    6361011    } // end for i
    637 
    6381012    //Normalise by area and store for when all conserved
    6391013    //quantities get updated
    640     // flux /= areas[k]
    641     for (j=0; j<3; j++) {
    642       flux[j] /= ((double *) areas -> data)[k];
    643     }
    644 
    645     ((double *) stage_explicit_update -> data)[k] = flux[0];
    646     ((double *) xmom_explicit_update -> data)[k] = flux[1];
    647     ((double *) ymom_explicit_update -> data)[k] = flux[2];
    648 
     1014    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
     1015    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
     1016    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
    6491017  } //end for k
    650 
    6511018  return Py_BuildValue("d", timestep);
    6521019}
    653 
    654 
    6551020
    6561021PyObject *protect(PyObject *self, PyObject *args) {
     
    8121177}
    8131178
    814 
    815 
     1179PyObject *h_limiter_sw(PyObject *self, PyObject *args) {
     1180  //a faster version of h_limiter above
     1181  PyObject *domain, *Tmp;
     1182  PyArrayObject
     1183    *hv, *hc, //Depth at vertices and centroids
     1184    *hvbar,   //Limited depth at vertices (return values)
     1185    *neighbours;
     1186
     1187  int k, i, N, k3,k0,k1,k2;
     1188  int dimensions[2];
     1189  double beta_h; //Safety factor (see config.py)
     1190  double hmin, hmax, dh[3];
     1191  // Convert Python arguments to C
     1192  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
     1193    return NULL;
     1194  neighbours = get_consecutive_array(domain, "neighbours");
     1195
     1196  //Get safety factor beta_h
     1197  Tmp = PyObject_GetAttrString(domain, "beta_h");
     1198  if (!Tmp)
     1199    return NULL;
     1200  beta_h = PyFloat_AsDouble(Tmp);
     1201
     1202  Py_DECREF(Tmp);
     1203
     1204  N = hc -> dimensions[0];
     1205
     1206  //Create hvbar
     1207  dimensions[0] = N;
     1208  dimensions[1] = 3;
     1209  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
     1210  for (k=0;k<N;k++){
     1211    k3=k*3;
     1212    //get the ids of the neighbours
     1213    k0 = ((long*) neighbours -> data)[k3];
     1214    k1 = ((long*) neighbours -> data)[k3+1];
     1215    k2 = ((long*) neighbours -> data)[k3+2];
     1216    //set hvbar provisionally
     1217    for (i=0;i<3;i++){
     1218      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
     1219      dh[i]=((double*) hvbar -> data)[k3+i]-((double*) hc -> data)[k];
     1220    }
     1221    hmin=((double*) hc -> data)[k];
     1222    hmax=hmin;
     1223    if (k0>=0){
     1224      hmin=min(hmin,((double*) hc -> data)[k0]);
     1225      hmax=max(hmax,((double*) hc -> data)[k0]);
     1226    }
     1227    if (k1>=0){
     1228      hmin=min(hmin,((double*) hc -> data)[k1]);
     1229      hmax=max(hmax,((double*) hc -> data)[k1]);
     1230    }
     1231    if (k2>=0){
     1232      hmin=min(hmin,((double*) hc -> data)[k2]);
     1233      hmax=max(hmax,((double*) hc -> data)[k2]);
     1234    }
     1235    hmin-=((double*) hc -> data)[k];
     1236    hmax-=((double*) hc -> data)[k];
     1237    limit_gradient(dh,hmin,hmax,beta_h);
     1238    for (i=0;i<3;i++)
     1239      ((double*) hvbar -> data)[k3+i] = ((double*) hc -> data)[k]+dh[i];
     1240  }
     1241  return PyArray_Return(hvbar);
     1242}
    8161243
    8171244PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
     
    8641291
    8651292  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
     1293  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
    8661294  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
    8671295  {"gravity", gravity, METH_VARARGS, "Print out"},
     
    8701298   METH_VARARGS, "Print out"},
    8711299  {"h_limiter", h_limiter,
     1300   METH_VARARGS, "Print out"},
     1301  {"h_limiter_sw", h_limiter_sw,
    8721302   METH_VARARGS, "Print out"},
    8731303  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
Note: See TracChangeset for help on using the changeset viewer.