#ifdef PETSC_RCS_HEADER
static char vcid[] = "$Id: meshCSR.c,v 1.19 2000/10/17 13:48:57 knepley Exp $";
#endif

/*
     Defines the interface to the CSR mesh functions
*/

#include "src/mesh/meshimpl.h"    /*I "mesh.h" I*/

#undef  __FUNCT__
#define __FUNCT__ "MeshCreateLocalCSR"
/*@
  MeshCreateLocalCSR - Returns the local mesh in CSR format. All off
  processor edges are ignored, and only the symmetric part of the matrix
  is stored if symmetric is true.

  Not collective

  Input Parameters:
+ mesh          - The mesh
. numBC         - [Optional] The number of constrained nodes to be eliminated
. bcNodes       - [Optional] The numbers of constrained nodes
- symmetric     - Whether to return the entire adjacency list

  Output Parameters:
+ numVertices   - The number of vertices in the graph
. numEdges      - The number of edges in the graph.
. vertOffsets   - The list of offsets into the neighbor array for each vertex
. vertNeighbors - The list of vertex neighbors
- vertCoords    - The list of vertex coordinates

  Note:
  If any array, such as vertCoords, is passed as PETSC_NULL, then no return
  value will be calculated.

  Level: advanced

.keywords: mesh, partition, CSR
.seealso: MeshDestroyLocalCSR(), MeshPartition()
@*/
int MeshCreateLocalCSR(Mesh mesh, int *numVertices, int *numEdges, int **vertOffsets, int **vertNeighbors,
                       double **vertCoords, int numBC, int *bcNodes, PetscTruth symmetric)
{
  int num;
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  PetscValidIntPointer(numVertices);
  PetscValidIntPointer(numEdges);
  if (vertOffsets   != PETSC_NULL) {PetscValidIntPointer(vertOffsets);}
  if (vertNeighbors != PETSC_NULL) {PetscValidIntPointer(vertNeighbors);}
  if (vertCoords    != PETSC_NULL) {PetscValidIntPointer(vertCoords);}
  if (numBC > 0) {
    PetscValidIntPointer(bcNodes);
    num = numBC;
  } else {
    num = 0;
  }
  if (!mesh->ops->createlocalcsr) {
    SETERRQ(PETSC_ERR_SUP, "Not supported by this Mesh object");
  }
  ierr = PetscLogEventBegin(MESH_CreateLocalCSR, mesh, 0, 0, 0);                                           CHKERRQ(ierr);
  ierr = (*mesh->ops->createlocalcsr)(mesh, numVertices, numEdges, vertOffsets, vertNeighbors, vertCoords, num, bcNodes, symmetric);
                                                                                                          CHKERRQ(ierr);
  ierr = PetscLogEventEnd(MESH_CreateLocalCSR, mesh, 0, 0, 0);                                             CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshDestroyLocalCSR"
/*@
  MeshDestroyLocalCSR - Destroys the local mesh in CSR format

  Not collective

  Input Parameters:
+ mesh          - The mesh
. vertOffsets   - The list of offsets into the neighbor array for each element
. vertNeighbors - The list of element neighbors
- vertCoords    - The list of vertex coordinates

  Level: advanced

.keywords: mesh, partition
.seealso: MeshCreateLocalCSR(), MeshPartition()
@*/
int MeshDestroyLocalCSR(Mesh mesh, int *vertOffsets, int *vertNeighbors, double *vertCoords)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  if (vertOffsets   != PETSC_NULL) {
    ierr = PetscFree(vertOffsets);                                                                        CHKERRQ(ierr);
  }
  if (vertNeighbors != PETSC_NULL) {
    ierr = PetscFree(vertNeighbors);                                                                      CHKERRQ(ierr);
  }
  if (vertCoords    != PETSC_NULL) {
    ierr = PetscFree(vertCoords);                                                                         CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshCreateFullCSR"
/*@
  MeshCreateFullCSR - Returns the full mesh including all nodes in CSR format.

  Not collective

  Input Parameters:
+ mesh          - The mesh
- constrain     - The flag for including connection between constrained nodes

  Output Parameters:
+ numVertices   - The number of vertices in the graph
. numEdges      - The number of edges in the graph.
. vertOffsets   - List of offsets into the neighbor array for each vertex
- vertNeighbors - List of vertex neighbors

  Level: advanced

.keywords: mesh, partition, CSR
.seealso: MeshDestroyFullCSR(), MeshPartition()
@*/
int MeshCreateFullCSR(Mesh mesh, PetscTruth constrain, int *numVertices, int *numEdges, int **vertOffsets, int **vertNeighbors)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  PetscValidIntPointer(numVertices);
  PetscValidIntPointer(numEdges);
  PetscValidIntPointer(vertOffsets);
  PetscValidIntPointer(vertNeighbors);
  if ((mesh->partitioned) && (mesh->part->numProcs > 1)) {
    SETERRQ(PETSC_ERR_SUP, "Not yet supported on multiple processors");
  }
  if (!mesh->ops->createfullcsr) {
    SETERRQ(PETSC_ERR_SUP, "Not supported by this Mesh object");
  }
  ierr = PetscLogEventBegin(MESH_CreateFullCSR, mesh, 0, 0, 0);                                            CHKERRQ(ierr);
  ierr = (*mesh->ops->createfullcsr)(mesh, constrain, numVertices, numEdges, vertOffsets, vertNeighbors); CHKERRQ(ierr);
  ierr = PetscLogEventEnd(MESH_CreateFullCSR, mesh, 0, 0, 0);                                              CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshDestroyFullCSR"
/*@
  MeshDestroyFullCSR - Destroys the full mesh in CSR format

  Not collective

  Input Parameters:
+ mesh          - The mesh
. vertOffsets   - List of offsets into the neighbor array for each element
- vertNeighbors - List of element neighbors

  Level: advanced

.keywords: mesh, partition
.seealso: MeshCreateFullCSR(), MeshPartition()
@*/
int MeshDestroyFullCSR(Mesh mesh, int *vertOffsets, int *vertNeighbors)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  ierr = PetscFree(vertOffsets);                                                                          CHKERRQ(ierr);
  ierr = PetscFree(vertNeighbors);                                                                        CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshCreateDualCSR"
/*@
  MeshCreateDualCSR - Returns the dual of the mesh in distributed CSR format

  Collective on Mesh

  Input Parameter:
. mesh          - The mesh

  Output Parameters:
+ elemOffsets   - List of offsets into the neighbor array for each element
. elemNeighbors - List of element neighbors
. edgeWeights   - [Optional] List of edge weights for the dual graph
- weight        - [Optional] Weight for each edge

  Level: advanced

.keywords: mesh, partition, dual
.seealso: MeshDestroyDualCSR(), MeshPartition()
@*/
int MeshCreateDualCSR(Mesh mesh, int **elemOffsets, int **elemNeighbors, int **edgeWeights, int weight)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  PetscValidIntPointer(elemOffsets);
  PetscValidIntPointer(elemNeighbors);
  if (weight != 0) PetscValidIntPointer(edgeWeights);
  if (!mesh->ops->createdualcsr) {
    SETERRQ(PETSC_ERR_SUP, "Not supported by this Mesh object");
  }
  ierr = PetscLogEventBegin(MESH_CreateDualCSR, mesh, 0, 0, 0);                                            CHKERRQ(ierr);
  ierr = (*mesh->ops->createdualcsr)(mesh, elemOffsets, elemNeighbors, edgeWeights, weight);              CHKERRQ(ierr);
  ierr = PetscLogEventEnd(MESH_CreateDualCSR, mesh, 0, 0, 0);                                              CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshDestroyDualCSR"
/*@
  MeshDestroyDualCSR - Destroys the dual of the mesh in distributed CSR format

  Not collective

  Input Parameters:
+ mesh          - The mesh
. elemOffsets   - List of offsets into the neighbor array for each element
. elemNeighbors - List of element neighbors
- edgeWeights   - List of edge weights for the dual graph

  Level: advanced

.keywords: mesh, partition, dual
.seealso: MeshCreateDualCSR(), MeshPartition()
@*/
int MeshDestroyDualCSR(Mesh mesh, int *elemOffsets, int *elemNeighbors, int *edgeWeights)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  ierr = PetscFree(elemOffsets);                                                                          CHKERRQ(ierr);
  ierr = PetscFree(elemNeighbors);                                                                        CHKERRQ(ierr);
  if (edgeWeights != PETSC_NULL) {
    ierr = PetscFree(edgeWeights);                                                                        CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}
