[pooma-dev] Chevron Code Using New Field Abstractions

Jeffrey Oldham oldham at codesourcery.com
Wed Jul 25 22:20:45 UTC 2001


On Wed, Jul 25, 2001 at 02:12:49PM -0700, Jeffrey Oldham wrote:
> Attached is a very preliminary version of the Chevron code written
> using C++ pseudocode closely related to the proposed NewField
> revisions.  It does not compile since the underlying NewField and mesh
> routines have not yet been implemented.
> 
> The next steps are:
> 
> 1. To ensure that the algorithm is correct.
> 2. To add more comments describing my assumptions about functions and
>    classes.

I have added comments near the beginning of the file.

> 3. To discuss whether the syntax is acceptable.
> 4. To make the code available in some portion of the Pooma CVS tree.

Thanks,
Jeffrey D. Oldham
oldham at codesourcery.com
-------------- next part --------------
// Oldham, Jeffrey D.
// 2001Jul25
// Pooma

// Chevron Kernel Written Using POOMA's Proposed Field Abstraction

#include <iostream>
#include <cstdlib>
#include "Pooma/NewFields.h"

// This program implements "Implementation of a Flux-Continuous Fnite
// Difference Method for Stratigraphic, Hexahedron Grids," by
// S. H. Lee, H. Tchelepi, and L. J. DeChant, \emph{1999 SPE Reservoir
// Simulation Symposium}, SPE (Society of Petroleum Engineers) 51901.

// Preprocessor symbols:
// PSEUDOCODE: Do not define this symbol.  Surrounds desired code to
//	       deal with different granularity fields.
// DEBUG: If defined, print some information about internal program
//	  values.


/** QUESTIONS **/

// o. If several different fields are created using the same mesh
//    object, is the mesh object shared?
// o. Can meshes be queried without going through an associated field?
// o. According to my understanding, the Chevron algorithm should be
//    imbedded inside a loop of some type that repeatedly updates the
//    coordinates.
// o. I omitted a separate coordinates field, presumably updated each
//    iteration, in favor of using the mesh.  Since I do not know how
//    the coordinates are updated, I omitted updating the mesh.
// o. Is it important to flesh out the linear algebra solution?  We
//    might learn something about field syntax, but it will also take
//    time for me to determine the correct operands.
// o. The eight spoke-centered flux values are discontinuous, right?
// o. Creating non-canonical edge and face centerings requires
//    dimension-dependent code.  Is this acceptable?


/** UNFINISHED WORK **/

// o ConstField = a Field with values that do not change
// o nearestNeighbors(inputCentering, outputCentering)
// o replicate(field, std::vector<FieldOffsetList>)
// o meshLayout.unitCoordinateNormals()
// o field.mesh()
// o field.mesh().normals()
// o field.mesh().normals().signedMagnitude()
// o sum(field, FieldOffsetList)


/** EXPLANATIONS **/

// o Centering<Dim> canonicalCentering<Dim>(CellType, Continuous):
//    returns a centering object for a cell-centered field with one
//    value at the cell's center (in logical coordinate space)
// o subcell: This centering contains four cell-centered values at
//    positions (0.25, 0.25), (0.25, 0.75), (0.75, 0.75), (0.75, 0.25).  
//    Since this centering is not a canonical centering, it must be
//    constructed.  To do so, we start with a cell-centered centering
//    without any values and repeatedly add values.  The orientation,
//    ignored for cell-centered values, indicates which coordinate values
//    are fixed and which are not.  Using a (1,...,1) indicates that
//    all coordinate values may be changed.
// o spoke: This face-centering has two values on each face.  It, too,
//    has to be constructed since it is not a normal centering.
// o The Chevron algorithm first solves a linear program.  I have
//    omitted since computation since it does not illustrate field
//    computations.
// o replicate(field, std::vector<FieldOffsetList>): This function,
//    syntactic sugar for a nearest neighbors computation, copies the
//    field values to the positions indicated by the
//    std::vector<FieldOffsetList>.  Each field value is copied to one
//    or more values.  replicate() could be replaced by sum(), but the
//    latter function has an unnecessary loop since each output value
//    equals one input value.
// o nearestNeighbors(inputCentering, outputCentering): This function
//    returns a std::vector of FieldOffsetList's, one for each output
//    value specified by the given output centering.  For each output
//    value, the closest input values, wrt Manhattan distance, are
//    returned.  Eventually, these may be pre-computed or cached to
//    reduce running time.
// o meshLayout.unitCoordinateNormals(): This returns a discontinuous
//    face-centered field with unit-length normals all pointing in
//    positive directions.
// o field.mesh(): Returns the mesh object associated with the field.
// o spokeFlux.mesh().normals(): Returns a face-centered field of
//    normal vectors perpendicular to each face.  The magnitude of each
//    normal equals the face's area/volume.
// o spokeFlux.mesh().normals().signedMagnitude(): Returns a
//    face-centered field of scalars, each having absolute value
//    equalling the face's area/volume and sign equalling whether the
//    face's normal is in a positive direction, e.g., the positive
//    x-direction vs. the negative x-direction.
// o sum(field, FieldOffsetList): this parallel-data statement adds
//    the values indicated in the FieldOffsetList to form each output value


/** THE PROGRAM **/

int main(int argc, char *argv[])
{
  // Set up the Pooma library.
  Pooma::initialize(argc,argv);
#ifdef DEBUG
  std::cout << "Start program." << std::endl;
#endif // DEBUG


  /* DECLARATIONS */

  // Create a simple layout.
  const unsigned Dim = 2;		// Work in a 2D world.
  const unsigned nXs = 5;		// number of horizontal vertices
  const unsigned nYs = 4;		// number of vertical vertices
  Interval<Dim> meshDomain;
  meshDomain[0] = Interval<1>(nXs);
  meshDomain[1] = Interval<1>(nYs);
  DomainLayout<Dim> meshLayout(meshDomain, GuardLayers<Dim>(1));

  // Preparation for Field creation.

  Vector<Dim> origin(0.0);
  Vector<Dim> spacings(1.0,1.0);
  typedef UniformRectilinear<Dim, double, Cartesian<Dim> > Geometry_t;
  typedef Field<Geometry_t, double, Brick> Fields_t;
  typedef Field<Geometry_t, double, Brick> ConstFields_t; // TODO: Change to ConstField when ConstField is available.
  typedef Tensor<Dim,double,Full> Tensor_t;
  typedef Field<Geometry_t, Tensor_t, Brick> FieldT_t;
  typedef Field<Geometry_t, Tensor_t, Brick> ConstFieldT_t; // TODO: Change to ConstField when ConstField is available.
  typedef Field<Geometry_t, Vector<Dim>, Brick> Fieldv_t;
  typedef Field<Geometry_t, Vector<Dim>, Brick> ConstFieldv_t; // TODO: Change to ConstField when ConstField is available.

  // Cell-centered Fields.

  Centering<Dim> cell = canonicalCentering<Dim>(CellType, Continuous);
  ConstFieldT_t permeability	(cell, meshLayout, origin, spacings);
  ConstFields_t pressure	(cell, meshLayout, origin, spacings);
  Fields_t totalFlux		(cell, meshLayout, origin, spacings);

  // Subcell-centered Field.

  typedef Centering<Dim>::Orientation Orientation;
  typedef Centering<Dim>::Position Position;
  Position position;
  Centering<Dim> subcell(CellType, Continuous);
  position(0) = 0.25;
  position(1) = 0.25; subcell.addValue(Orientation(1), position);
  position(1) = 0.75; subcell.addValue(Orientation(1), position);
  position(0) = 0.75; subcell.addValue(Orientation(1), position);
  position(1) = 0.25; subcell.addValue(Orientation(1), position);
  Fields_t pressureGradient	(subcell, meshLayout, origin, spacings);

  // Spoke-centered Field.

  Centering<Dim> spoke(FaceType, Discontinuous);
  // QUESTION: These are supposed to be Discontinuous, right?
  Orientation orientation;
  // NOTE: This code is not dimension-independent.
  for (int zeroFace = 0; zeroFace < 2; ++zeroFace) {
    orientation = 1; orientation[zeroFace] = 0;
    position(zeroFace) = 0.0;
    position(1-zeroFace) = 0.25; spoke.addValue(orientation, position);
    position(1-zeroFace) = 0.75; spoke.addValue(orientation, position);
    position(zeroFace) = 1.0;
    position(1-zeroFace) = 0.25; spoke.addValue(orientation, position);
    position(1-zeroFace) = 0.75; spoke.addValue(orientation, position);
  }
  Fields_t spokeFlux		(spoke, meshLayout, origin, spacings);

  // Face-centered.

  Centering<Dim> disFace = canonicalCentering<Dim>(FaceType, Discontinuous);


  /* INITIALIZATION */

#ifdef PSEUDOCODE
  // Initialize tensors.
  // Initialize the pressures.
  // Initialize coordinates.
#endif // PSEUDOCODE


  /* COMPUTATION */

#ifdef PSEUDOCODE
  // Compute pressureGradients by simultaneously solving several
  // linear equations.  The operands have different centerings.
  // FIXME
  pressureGradients =
    linearAlgebra<2>(pressure /* cell-centered */,
		     /* Interpolate from vertex-centered to cell-centered: */
		     interpolate<Cell,Vertex>(coordinates),
		     permeability /* cell-centered */,
		     normals /* face-centered */);
#endif // PSEUDOCODE

  // Compute the spoke fluxes.

  // We must multiply three quantities, each with a different
  // centering, to yield values at a fourth-centering.  permeability
  // is cell-centered.  pressureGradient is subcell-centered.  The
  // normals are face-centered.  The product is spoke-centered.

  spokeFlux = 
    dot(replicate(dot(replicate(permeability, nearestNeighbors(cell, subcell)),
		      pressureGradient),
		  nearestNeighbors(subcell, spoke)),
	replicate(meshLayout.unitCoordinateNormals(),
		  nearestNeighbors(disFace, spoke)));

  // Sum the spoke fluxes into a cell flux.

  // Q = \sum_{faces f of cell} sign_f area_f \sum_{subfaces sf of f} q_{sf}
  // We compute this in three steps:
  // 1. Add together the flux values on each face to form a
  //    face-centered field.
  // 2. Multiply each value by the magnitude of the face's normal.
  // 3. Add together each face's value.

  totalFlux =
    sum(spokeFlux.mesh().normals().signedMagnitude() *
	sum(spokeFlux, nearestNeighbors(spoke, disFace)),
	nearestNeighbors(disFace, cell));


  /* TERMINATION */

  std::cout << "total flux:\n" << totalFlux << std::endl;
#ifdef DEBUG
  std::cout << "End program." << std::endl;
#endif // DEBUG
  Pooma::finalize();
  return EXIT_SUCCESS;
}


More information about the pooma-dev mailing list