#ifdef PETSC_RCS_HEADER
static char vcid[] = "$Id: elemvec.c,v 1.13 2000/07/16 23:20:02 knepley Exp $";
#endif

#include "src/grid/gridimpl.h"    /*I "grid.h" I*/

/* Logging support */
int ELEMENT_VEC_COOKIE;
int ELEMENT_MAT_COOKIE;

/*---------------------------------------------- Element Matrix Functions -------------------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "ElementMatCreate"
/*@C ElementMatCreate
  This function creates an element matrix for a finite element calculation.

  Collective on MPI_Comm

  Input Parameters:
+ comm    - The communicator to associate with the matrix
. rowSize - The number of test functions per element
- colSize - The number of basis functions per element

  Output Parameter:
. mat     - The element matrix

  Level: beginner

.keywords element matrix, finite element
.seealso ElementMatDestroy(), ElementVecCreate()
@*/
int ElementMatCreate(MPI_Comm comm, int rowSize, int colSize, ElementMat *mat)
{
  ElementMat m;
  int        ierr;

  PetscFunctionBegin;
  PetscValidPointer(mat);
  *mat = PETSC_NULL;
#ifndef PETSC_USE_DYNAMIC_LIBRARIES
  ierr = GridInitializePackage(PETSC_NULL);                                                               CHKERRQ(ierr);
#endif

  PetscHeaderCreate(m, _ElementMat, int, ELEMENT_MAT_COOKIE, 0, "ElementMat", comm, ElementMatDestroy, 0);
  PetscLogObjectCreate(m);
  m->rowSize       = rowSize;
  m->colSize       = colSize;
  m->reduceRowSize = rowSize;
  m->reduceColSize = colSize;
  ierr = PetscMalloc(rowSize*colSize            * sizeof(PetscScalar), &m->array);                        CHKERRQ(ierr);
  ierr = PetscMalloc(rowSize                    * sizeof(int),         &m->rowIndices);                   CHKERRQ(ierr);
  ierr = PetscMalloc(colSize                    * sizeof(int),         &m->colIndices);                   CHKERRQ(ierr);
  ierr = PetscMalloc(colSize                    * sizeof(int),         &m->reduceCols);                   CHKERRQ(ierr);
  ierr = PetscMalloc(rowSize*colSize            * sizeof(PetscScalar), &m->tempArray);                    CHKERRQ(ierr);
  ierr = PetscMalloc(PetscMax(rowSize, colSize) * sizeof(int),         &m->tempIndices);                  CHKERRQ(ierr);
  PetscLogObjectMemory(m, (rowSize + colSize*2 + PetscMax(rowSize, colSize)) * sizeof(int) + (rowSize*colSize*2) * sizeof(PetscScalar));
  *mat = m;

  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatDestroy"
/*@C ElementMatDestroy
  This function destroys an element matrix.

  Not collective

  Input Parameter:
. vec - The element matrix

  Level: beginner

.keywords element matrix, finite element
.seealso ElementMatCreate(), ElementVecDestroy()
@*/
int ElementMatDestroy(ElementMat mat)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  if (--mat->refct > 0)
    PetscFunctionReturn(0);
  ierr = PetscFree(mat->array);                                                                          CHKERRQ(ierr);
  ierr = PetscFree(mat->rowIndices);                                                                     CHKERRQ(ierr);
  ierr = PetscFree(mat->colIndices);                                                                     CHKERRQ(ierr);
  ierr = PetscFree(mat->reduceCols);                                                                     CHKERRQ(ierr);
  ierr = PetscFree(mat->tempArray);                                                                      CHKERRQ(ierr);
  ierr = PetscFree(mat->tempIndices);                                                                    CHKERRQ(ierr);
  PetscLogObjectDestroy(mat);
  PetscHeaderDestroy(mat);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatView"
/*@C ElementMatView
  This function destroys an element matrix.

  Not collective

  Input Parameter:
. vec - The element matrix

  Level: beginner

.keywords element matrix, finite element
.seealso ElementMatCreate(), ElementVecView()
@*/
int ElementMatView(ElementMat mat, PetscViewer viewer)
{
  int        row, col;
  PetscTruth isascii;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat,    ELEMENT_MAT_COOKIE);
  PetscValidHeaderSpecific(viewer, PETSC_VIEWER_COOKIE);
  ierr = PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_ASCII, &isascii);                            CHKERRQ(ierr);
  if (isascii == PETSC_TRUE) {
    if (mat->reduceColSize > 0) {
      PetscViewerASCIIPrintf(viewer, "      %3d", mat->colIndices[0]);
      for(col = 1; col < mat->reduceColSize; col++)
        PetscViewerASCIIPrintf(viewer, "   %3d", mat->colIndices[col]);
      PetscViewerASCIIPrintf(viewer, "\n");
    }
    for(row = 0; row < mat->reduceRowSize; row++) {
      PetscViewerASCIIPrintf(viewer, "%3d ", mat->rowIndices[row]);
      for(col = 0; col < mat->reduceColSize; col++)
        PetscViewerASCIIPrintf(viewer, "%5.2g ", PetscRealPart(mat->array[row*mat->reduceColSize+col]));
      PetscViewerASCIIPrintf(viewer, "\n");
    }
  }
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatDuplicate"
/*@C ElementMatDuplicate
  This function duplicates an element matrix.

  Collective on ElementMat

  Input Parameter:
. mat    - The original element matrix

  Output Parameter:
. newmat - The new element matrix

  Level: beginner

.keywords element matrix, finite element
.seealso GridCalcElementMatIndices()
@*/
int ElementMatDuplicate(ElementMat mat, ElementMat *newmat)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidPointer(newmat);
  ierr = ElementMatCreate(mat->comm, mat->rowSize, mat->colSize, newmat);                                CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatDuplicateIndices"
/*@C ElementMatDuplicateIndices
  This function copies the global matrix indices to another element matrix.

  Collective on ElementMat

  Input Parameter:
. mat    - The original element matrix

  Output Parameter:
. newmat - The element matrix with updated indices

  Level: intermediate

.keywords element matrix, finite element
.seealso GridCalcElementMatIndices()
@*/
int ElementMatDuplicateIndices(ElementMat mat, ElementMat newmat)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat,    ELEMENT_MAT_COOKIE);
  PetscValidHeaderSpecific(newmat, ELEMENT_MAT_COOKIE);
  if (mat == newmat)
    PetscFunctionReturn(0);
  if ((mat->rowSize != newmat->rowSize) || (mat->colSize != newmat->colSize)) {
    SETERRQ(PETSC_ERR_ARG_INCOMP, "Incompatible matrix sizes");
  }
  ierr = PetscMemcpy(newmat->rowIndices, mat->rowIndices, mat->rowSize * sizeof(int));                   CHKERRQ(ierr);
  ierr = PetscMemcpy(newmat->colIndices, mat->colIndices, mat->colSize * sizeof(int));                   CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatZero"
/*@C ElementMatZero
  This function sets all the entries in the element matrix to zero.

  Collective on ElementMat

  Output Parameter:
. mat - The element matrix

  Level: beginner

.keywords element matrix, finite element
.seealso ElementMatCreate()
@*/
int ElementMatZero(ElementMat mat)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  ierr = PetscMemzero(mat->array, mat->rowSize*mat->colSize * sizeof(PetscScalar));                       CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatSetValues"
/*@C ElementMatSetValues
  This function puts all the entries in the element matrix into
  the global matrix.

  Collective on GMat

  Input Parameters:
+ mat  - The element matrix
- addv - The insertion mode
 
  Output Parameter:
. M - The global matrix

  Level: beginner

.keywords element matrix, finite element
.seealso ElementMatCreate
@*/
int ElementMatSetValues(ElementMat mat, GMat M, InsertMode addv)
{
  int ierr;

  PetscFunctionBegin;
  /* Place entries in the global matrix */
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidHeaderSpecific(M,   MAT_COOKIE);
  ierr = MatSetValues(M, mat->reduceRowSize, mat->rowIndices, mat->reduceColSize, mat->colIndices, mat->array, addv);
  CHKERRQ(ierr);
  mat->reduceRowSize = mat->rowSize;
  mat->reduceColSize = mat->colSize;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatSetDiagonalValues"
/*@C ElementMatSetDiagonalValues
  This function puts only the diagonal entries of the element matrix into a global vector.

  Collective on GVec

  Input Parameters:
+ mat  - The element matrix
- addv - The insertion mode
 
  Output Parameter:
. d    - The global vector

  Level: beginner

.keywords element matrix, finite element
.seealso ElementMatSetValues
@*/
int ElementMatSetDiagonalValues(ElementMat mat, GVec d, InsertMode addv)
{
  int *rows = mat->rowIndices;
  int *cols = mat->colIndices;
  int  row, col;
  int  ierr;

  PetscFunctionBegin;
  /* Place entries in the global matrix */
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidHeaderSpecific(d,   VEC_COOKIE);
  for(row = 0; row < mat->reduceRowSize; row++) {
    for(col = 0; col < mat->reduceColSize; col++) {
      if (rows[row] == cols[col]) {
        ierr = VecSetValue(d, rows[row], mat->array[row*mat->reduceColSize+col], addv);                   CHKERRQ(ierr);
      }
    }
  }
  mat->reduceRowSize = mat->rowSize;
  mat->reduceColSize = mat->colSize;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatGetSize"
/*@C ElementMatGetSize
  This function returns the size of the element matrix.

  Not collective

  Input Parameter:
. mat     - The element matrix
 
  Output Parameters:
+ rowSize - The number of rows
- colSize - The number of rows

  Level: intermediate

.keywords element matrix, finite element
.seealso ElementMatGetReduceSize(), ElementMatCreate()
@*/
int ElementMatGetSize(ElementMat mat, int *rowSize, int *colSize)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidPointer(rowSize);
  PetscValidPointer(colSize);
  *rowSize = mat->rowSize;
  *colSize = mat->colSize;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatGetReduceSize"
/*@C
  ElementMatGetReduceSize - This function returns the size of the element matrix
  after all reduction have been carried out..

  Not collective

  Input Parameter:
. mat     - The element matrix
 
  Output Parameters:
+ rowSize - The number of rows
- colSize - The number of rows

  Level: intermediate

.keywords: element matrix, finite element
.seealso: ElementMatGetSize(), ElementMatCreate()
@*/
int ElementMatGetReduceSize(ElementMat mat, int *rowSize, int *colSize)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidPointer(rowSize);
  PetscValidPointer(colSize);
  *rowSize = mat->reduceRowSize;
  *colSize = mat->reduceColSize;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatGetIndices"
/*@C ElementMatGetIndices
  This function returns the index mappings for the element matrix.

  Collective on ElementMat

  Input Parameter:
. mat     - The element matrix
 
  Output Parameters:
+ rowIdx - The row mapping
- colIdx - The column mapping

  Level: intermediate

.keywords element matrix, finite element
.seealso ElementMatCreate
@*/
int ElementMatGetIndices(ElementMat mat, int **rowIdx, int **colIdx)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidPointer(rowIdx);
  PetscValidPointer(colIdx);
  *rowIdx = mat->rowIndices;
  *colIdx = mat->colIndices;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementMatGetArray"
/*@C ElementMatGetArray
  This function allows access directly to the element matrix;

  Collective on ElementMat

  Input Parameters:
. mat   - The element matrix
 
  Output Parameter:
. array - The array of values

  Level: intermediate

.keywords element matrix, finite element
.seealso ElementMatCreate
@*/
int ElementMatGetArray(ElementMat mat, PetscScalar **array)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(mat, ELEMENT_MAT_COOKIE);
  PetscValidPointer(array);
  *array = mat->array;
  PetscFunctionReturn(0);
}

/*---------------------------------------------- Element Vector Functions -------------------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "ElementVecCreate"
/*@C ElementVecCreate
  This function creates an element vector for a finite element calculation.

  Collective on MPI_Comm

  Input Parameters:
+ comm - The communicator to associate with the vector
- size - The number of local variables per element

  Output Parameter:
. vec - The element vector

  Level: beginner

.keywords: element vector
.seealso: ElementVecDestroy(), ElementMatCreate()
@*/
int ElementVecCreate(MPI_Comm comm, int size, ElementVec *vec)
{
  ElementVec v;
  int        ierr;

  PetscFunctionBegin;
  PetscValidPointer(vec);
  *vec = PETSC_NULL;
#ifndef PETSC_USE_DYNAMIC_LIBRARIES
  ierr = GridInitializePackage(PETSC_NULL);                                                               CHKERRQ(ierr);
#endif

  PetscHeaderCreate(v, _ElementVec, int, ELEMENT_VEC_COOKIE, 0, "ElementVec", comm, ElementVecDestroy, 0);
  PetscLogObjectCreate(v);
  v->size       = size;
  v->reduceSize = size;
  ierr = PetscMalloc(size * sizeof(PetscScalar), &v->array);                                              CHKERRQ(ierr);
  ierr = PetscMalloc(size * sizeof(int),         &v->indices);                                            CHKERRQ(ierr);
  PetscLogObjectMemory(v, size * (sizeof(int) + sizeof(PetscScalar)));
  *vec = v;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecDestroy"
/*@C ElementVecDestroy
  This function destroys an element vector.

  Not collective

  Input Parameter:
. vec - The element vector

  Level: beginner

.keywords: element vector
.seealso: ElementVecCreate(), ElementMatDestroy()
@*/
int ElementVecDestroy(ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  if (--vec->refct > 0)
    PetscFunctionReturn(0);
  ierr = PetscFree(vec->array);                                                                          CHKERRQ(ierr);
  ierr = PetscFree(vec->indices);                                                                        CHKERRQ(ierr);
  PetscLogObjectDestroy(vec);
  PetscHeaderDestroy(vec);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecDuplicate"
/*@C ElementVecDuplicate
  This function duplicates an element vector.

  Collective on ElementVec

  Input Parameter:
. vec    - The original element vector

  Output Parameter:
. newvec - The new element vector

  Level: beginner

.keywords element vector, finite element
.seealso GridCalcElementVecIndices()
@*/
int ElementVecDuplicate(ElementVec vec, ElementVec *newvec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidPointer(newvec);
  ierr = ElementVecCreate(vec->comm, vec->size, newvec);                                                 CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecDuplicateIndices"
/*@C ElementVecDuplicateIndices
  This function copies the global vector indices to another element vector.

  Collective on ElementVec

  Input Parameter:
. vec    - The original element vector

  Output Parameter:
. newvec - The element vector with updated indices

  Level: intermediate

.keywords element vector, finite element
.seealso GridCalcElementVecIndices()
@*/
int ElementVecDuplicateIndices(ElementVec vec, ElementVec newvec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec,    ELEMENT_VEC_COOKIE);
  PetscValidHeaderSpecific(newvec, ELEMENT_VEC_COOKIE);
  if (vec == newvec)
    PetscFunctionReturn(0);
  if (vec->size != newvec->size) SETERRQ(PETSC_ERR_ARG_INCOMP, "Incompatible vector sizes");
  ierr = PetscMemcpy(newvec->indices, vec->indices, vec->size * sizeof(int));                            CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecZero"
/*@C ElementVecZero
  This function sets all the entries in the element vector to zero.

  Collective on ElementVec  

  Output Parameter:
. vec - The element vector

  Level: beginner

.keywords: element vector
.seealso: ElementVecCreate()
@*/
int ElementVecZero(ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  ierr = PetscMemzero(vec->array, vec->size * sizeof(PetscScalar));                                       CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecSetValues"
/*@C ElementVecSetValues
  This function puts all the entries in the element vector into
  the global vector.

  Collective on GVec

  Input Parameters:
+ vec  - The element vector
- addv - The insertion mode
 
  Output Parameter:
. M - The global vector

  Level: beginner

.keywords: element vector
.seealso: ElementVecCreate()
@*/
int ElementVecSetValues(ElementVec vec, GVec v, InsertMode addv)
{
  int ierr;

  PetscFunctionBegin;
  /* Place entries in the global vector */
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidHeaderSpecific(v,   VEC_COOKIE);
  ierr = VecSetValues(v, vec->reduceSize, vec->indices, vec->array, addv);                               CHKERRQ(ierr);
  vec->reduceSize = vec->size;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecGetSize"
/*@C ElementVecGetSize
  This function returns the size of the element vector.

  Not collective

  Input Parameter:
. vec  - The element vector
 
  Output Parameter:
+ size - The number of rows

  Level: intermediate

.keywords element vector, finite element
.seealso ElementVecGetReduceSize(), ElementVecCreate()
@*/
int ElementVecGetSize(ElementVec vec, int *size)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidPointer(size);
  *size = vec->size;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecGetReduceSize"
/*@C
  ElementVecGetReduceSize - This function returns the size of the element vector
  after all reductions have been carried out.

  Not collective

  Input Parameter:
. vec  - The element vector
 
  Output Parameter:
+ size - The number of rows

  Level: intermediate

.keywords: element vector, finite element
.seealso: ElementVecGetSize(), ElementVecCreate()
@*/
int ElementVecGetReduceSize(ElementVec vec, int *size)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidPointer(size);
  *size = vec->reduceSize;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecGetIndices"
/*@C ElementVecGetIndices
  This function returns the index mapping for the element vector.

  Collective on ElementVec

  Input Parameter:
. vec - The element vector
 
  Output Parameter:
. idx - The mapping

  Level: intermediate

.keywords: element vector
.seealso: ElementVecCreate()
@*/
int ElementVecGetIndices(ElementVec vec, int **idx)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidPointer(idx);
  *idx = vec->indices;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecGetArray"
/*@C ElementVecGetArray
  This function allows access directly to the element vector;

  Collective on ElementVec

  Input Parameter:
. vec   - The element vector
 
  Output Parameter:
. array - The array of values

  Level: intermediate

.keywords element vector, finite element
.seealso ElementVecRestoreArray(), ElementVecCreate()
@*/
int ElementVecGetArray(ElementVec vec, PetscScalar **array)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidPointer(array);
  *array = vec->array;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "ElementVecRestoreArray"
/*@C ElementVecRestoreArray
  This function relinquishes access to the element vector;

  Collective on ElementVec

  Input Parameters:
+ vec   - The element vector
- array - The array of values

  Level: intermediate

.keywords element vector, finite element
.seealso ElementVecGetArray(), ElementVecCreate()
@*/
int ElementVecRestoreArray(ElementVec vec, PetscScalar **array)
{
  PetscFunctionBegin;
  PetscValidHeaderSpecific(vec, ELEMENT_VEC_COOKIE);
  PetscValidPointer(array);
  /* Right now we don't check */
  PetscFunctionReturn(0);
}

/*------------------------------------- Element Vector Index Calculation Functions ----------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "GridCalcElementVecIndices"
/*@C
  GridCalcElementVecIndices - This function calculates the global row indices for a particular element.

  Not collective

  Input Parameters:
+ grid - The Grid
- elem - The element

  Output Parameter:
. vec - The element vector

  Level: advanced

.keywords: element vector, index
.seealso: GridCalcLocalElementVecIndices(), GridCalcInterpolationElementVecIndices(), GridCalcBoundaryElementVecIndices(),
          ElementVecSetValues()
@*/
int GridCalcElementVecIndices(Grid grid, int elem, ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  ierr = GridCalcGeneralElementVecIndices(grid, elem, grid->order, PETSC_NULL, PETSC_FALSE, vec);         CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcLocalElementVecIndices"
/*@C
  GridCalcLocalElementVecIndices - This function calculates the local row indices for a particular element.

  Not collective

  Input Parameters:
+ grid - The Grid
- elem - The element

  Output Parameter:
. vec - The element vector

  Level: advanced

.keywords: element vector, index, local
.seealso: GridCalcElementVecIndices(), GridCalcInterpolationElementVecIndices(), GridCalcBoundaryElementVecIndices(),
          ElementVecSetValues()
@*/
int GridCalcLocalElementVecIndices(Grid grid, int elem, ElementVec vec)
{
  PetscTruth expConst;
  int        ierr;

  PetscFunctionBegin;
  ierr = GridGetExplicitConstraints(grid, &expConst);                                                    CHKERRQ(ierr);
  if (expConst == PETSC_FALSE) {
    ierr = GridCalcGeneralElementVecIndices(grid, elem, grid->order,           PETSC_NULL, PETSC_TRUE, vec);CHKERRQ(ierr);
  } else {
    ierr = GridCalcGeneralElementVecIndices(grid, elem, grid->constraintOrder, PETSC_NULL, PETSC_TRUE, vec);CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcGeneralElementVecIndices"
/*@C
  GridCalcGeneralElementVecIndices - This function calculates the row and column indices
  for a particular element using alternate variable orderings.

  Not collective

  Input Parameters:
+ grid           - The Grid
. elem           - The element
. order          - The global variable ordering
. reductionOrder - The ordering on the reduction space, or PETSC_NULL for the default
- useLocal       - The flag for local numbering of ghost nodes

  Output Parameter:
. vec            - The element vector

  Level: advanced

.keywords: element vector, index, general
.seealso: ElementVecSetValues()
@*/
int GridCalcGeneralElementVecIndices(Grid grid, int elem, VarOrdering order, VarOrdering reductionOrder,
                                     PetscTruth useLocal, ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,  GRID_COOKIE);
  PetscValidHeaderSpecific(order, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(vec,   ELEMENT_VEC_COOKIE);
  if (reductionOrder == PETSC_NULL) {
    ierr = (*grid->ops->gridcalcelemvecidx)(grid, grid->mesh, elem, order, grid->reduceOrder, useLocal, PETSC_FALSE, vec);
    CHKERRQ(ierr);
  } else {
    PetscValidHeaderSpecific(reductionOrder, VAR_ORDER_COOKIE);
    ierr = (*grid->ops->gridcalcelemvecidx)(grid, grid->mesh, elem, order, reductionOrder, useLocal, PETSC_FALSE, vec);
    CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcInterpolationElementVecIndices"
/*@C
  GridCalcInterpolationElementVecIndices - This function calculates the local row indices for
  a particular element using values of the previous mesh and ordering.

  Not collective

  Input Parameters:
+ grid  - The Grid
. mesh  - The old mesh
. elem  - The element
- order - The new global variable ordering

  Output Parameter:
. vec   - The element vector

  Level: advanced

.keywords: element vector, index, interpolation
.seealso: GridCalcElementVecIndices(), GridCalcLocalElementVecIndices(), GridCalcBoundaryElementVecIndices(),
          ElementVecSetValues()
@*/
int GridCalcInterpolationElementVecIndices(Grid grid, Mesh mesh, int elem, VarOrdering order, ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,  GRID_COOKIE);
  PetscValidHeaderSpecific(mesh,  MESH_COOKIE);
  PetscValidHeaderSpecific(order, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(vec,   ELEMENT_VEC_COOKIE);
  ierr = (*grid->ops->gridcalcelemvecidx)(grid, mesh, elem, order, grid->reduceOrder, PETSC_TRUE, PETSC_TRUE, vec);
  CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcBoundaryElementVecIndices"
/*@C
  GridCalcBoundaryElementVecIndices - This function calculates the global row indices for a particular boundary element.

  Not collective

  Input Parameters:
+ grid     - The discretization context
. bd       - The boundary index
. edge     - The boundary element
. midNode  - The midnode on an edge, or -1 if none exists
. order    - The new global variable ordering
- useLocal - The flag for local numbering of ghost nodes

  Output Parameter:
. vec      - The element vector

  Note:
  The boundary is specified by its index, not marker. Use
  MeshGetBoundaryIndex() to retrieve this from the marker.

  Level: advanced

.keywords element vector, index, boundary
.seealso: GridCalcElementVecIndices(), GridCalcLocalElementVecIndices(), GridCalcInterpolationElementVecIndices(),
          ElementVecSetValues()
@*/
int GridCalcBoundaryElementVecIndices(Grid grid, int bd, int edge, int midNode, VarOrdering order, PetscTruth useLocal,
                                      ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,  GRID_COOKIE);
  PetscValidHeaderSpecific(order, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(vec,   ELEMENT_VEC_COOKIE);
  if ((bd < 0) || (bd >= grid->numBd)) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE, "Invalid boundary index %d", bd);
  ierr = (*grid->ops->gridcalcboundaryelemvecidx)(grid, bd, edge, midNode, order, grid->reduceOrder, useLocal, vec);
  CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*----------------------------------------- Element Vector Projection Functions -------------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "GridProjectElementVec"
/*@C
  GridProjectElementVec - This function calculates the global row and column indices
  for a particular element using alternate variable orderings, in the space constrained variables.

  Not collective

  Input Parameters:
+ grid      - The Grid
. mesh      - The mesh
. elem      - The element
. order     - The global variable ordering
- constrain - The flag for constraining (applying P^T), or unconstraining (applying P)

  Output Parameter:
. vec       - The element vector

  Level: advanced

.keywords: element vector, constraint, projection
.seealso: ElementVecSetValues()
@*/
int GridProjectElementVec(Grid grid, Mesh mesh, int elem, VarOrdering order, PetscTruth constrain, ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,  GRID_COOKIE);
  PetscValidHeaderSpecific(vec,   ELEMENT_VEC_COOKIE);
  ierr = (*grid->ops->gridprojectelemvec)(grid, mesh, elem, order, grid->reduceOrder, constrain, PETSC_FALSE, vec);
  CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridProjectInterpolationElementVec"
/*@C
  GridProjectInterpolationElementVec - This function calculates the global row and column indices
  for a particular element using alternate variable orderings, in the space constrained variables,
  and uses the previous numbering constructs for interpolation.

  Not collective

  Input Parameters:
+ grid      - The Grid
. mesh      - The mesh
. elem      - The element
. order     - The global variable ordering
- constrain - The flag for constraining (applying P^T), or unconstraining (applying P)

  Output Parameter:
. vec       - The element vector

  Level: advanced

.keywords: element vector, constraint, projection
.seealso: ElementVecSetValues()
@*/
int GridProjectInterpolationElementVec(Grid grid, Mesh mesh, int elem, VarOrdering order, PetscTruth constrain, ElementVec vec)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,  GRID_COOKIE);
  PetscValidHeaderSpecific(vec,   ELEMENT_VEC_COOKIE);
  ierr = (*grid->ops->gridprojectelemvec)(grid, mesh, elem, order, grid->reduceOrder, constrain, PETSC_TRUE, vec);
  CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*------------------------------------- Element Matrix Index Calculation Functions ----------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "GridCalcElementMatIndices"
/*@C
  GridCalcElementMatIndices - This function calculates the global row and column indices for a particular element.

  Not collective

  Input Parameters:
+ grid - The Grid
- elem - The element

  Output Parameter:
. mat  - The element matrix

  Level: advanced

.keywords: element matrix, index
.seealso: ElementMatSetValues()
@*/
int GridCalcElementMatIndices(Grid grid, int elem, ElementMat mat)
{
  int ierr;

  PetscFunctionBegin;
  ierr = GridCalcGeneralElementMatIndices(grid, elem, grid->order, grid->order, PETSC_FALSE, mat);       CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcLocalElementMatIndices"
/*@C
  GridCalcLocalElementMatIndices - This function calculates the local row and column indices for a particular element.

  Not collective

  Input Parameters:
+ grid - The Grid
- elem - The element

  Output Parameter:
. mat  - The element matrix

  Level: advanced

.keywords: element matrix, index, local
.seealso: ElementMatSetValues()
@*/
int GridCalcLocalElementMatIndices(Grid grid, int elem, ElementMat mat)
{
  int ierr;

  PetscFunctionBegin;
  ierr = GridCalcGeneralElementMatIndices(grid, elem, grid->order, grid->order, PETSC_TRUE, mat);        CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcGeneralElementMatIndices"
/*@C
  GridCalcGeneralElementMatIndices - This function calculates the row and column indices
  for a particular element using alternate variable orderings.

  Not collective

  Input Parameters:
+ grid     - The Grid
. elem     - The element
. sOrder   - The global variable ordering for the shape functions 
. tOrder   - The global variable ordering for the test functions 
- useLocal - The flag for local numbering of ghost nodes

  Output Parameter:
. mat      - The element matrix

  Level: advanced

.keywords: element matrix, index, general
.seealso: ElementMatSetValues()
@*/
int GridCalcGeneralElementMatIndices(Grid grid, int elem, VarOrdering sOrder, VarOrdering tOrder, PetscTruth useLocal,
                                     ElementMat mat)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,   GRID_COOKIE);
  PetscValidHeaderSpecific(sOrder, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(tOrder, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(mat,    ELEMENT_MAT_COOKIE);
  ierr = (*grid->ops->gridcalcelemmatidx)(grid, elem, sOrder, tOrder, grid->reduceOrder, useLocal, mat); CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "GridCalcBoundaryElementMatIndices"
/*@C
  GridCalcBoundaryElementMatIndices - This function calculates the global row and column indices
  for a particular boundary element using alternate variable orderings.

  Not collective

  Input Parameters:
+ grid     - The Grid
. bd       - The boundary index
. edge     - The canonical edge number
. midNode  - [Optional] The canonical node number of the midnode on the edge, or -1 if none exists
. sOrder   - The global variable ordering for the shape functions 
. tOrder   - The global variable ordering for the test functions 
- useLocal - The flag for local numbering of ghost nodes

  Output Parameter:
. mat      - The element matrix

  Note:
  The boundary is specified by its index, not marker. Use
  MeshGetBoundaryIndex() to retrieve this from the marker.

  Level: advanced

.keywords: element matrix, index, boundary
.seealso: ElementMatSetValues()
@*/
int GridCalcBoundaryElementMatIndices(Grid grid, int bd, int edge, int midNode, VarOrdering sOrder, VarOrdering tOrder,
                                      PetscTruth useLocal, ElementMat mat)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid,   GRID_COOKIE);
  PetscValidHeaderSpecific(sOrder, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(tOrder, VAR_ORDER_COOKIE);
  PetscValidHeaderSpecific(mat,    ELEMENT_MAT_COOKIE);
  if ((bd < 0) || (bd >= grid->numBd)) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE, "Invalid boundary index %d", bd);
  ierr = (*grid->ops->gridcalcboundaryelemmatidx)(grid, bd, edge, midNode, sOrder, tOrder, grid->reduceOrder, useLocal, mat);
  CHKERRQ(ierr);
  PetscFunctionReturn(0);
}
