#ifdef PETSC_RCS_HEADER
static char vcid[] = "$Id: part.c,v 1.6 2000/01/31 17:37:32 knepley Exp $";
#endif

/*
     Defines the interface to the partitioning functions
*/

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

/* Logging support */
int PARTITION_COOKIE;

/*------------------------------------------------ Generic Operations ------------------------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "PartitionSetUp"
/*@
  PartitionSetUp - Set up any required internal data structures for a Partition.

  Collective on Partition

  Input Parameter:
. part - The part

  Level: beginner

.keywords: Partition, setup
.seealso: PartitionDestroy()
@*/
int PartitionSetUp(Partition part)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  if (part->setupcalled) PetscFunctionReturn(0);
  if (part->ops->setup) {
    ierr = (*part->ops->setup)(part);                                                                     CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "PartitionSetTypeFromOptions"
/*
  PartitionSetTypeFromOptions - Sets the type of partitioning from user options.

  Collective on Partition

  Input Parameter:
. part - The partition

  Level: intermediate

.keywords: Partition, set, options, database, type
.seealso: PartitionSetFromOptions(), PartitionSetType()
*/
static int PartitionSetTypeFromOptions(Partition part)
{
  PetscTruth opt;
  char      *defaultType;
  char       typeName[256];
  int        dim;
  int        ierr;

  PetscFunctionBegin;
  ierr = PartitionGetDimension(part, &dim);                                                               CHKERRQ(ierr);
  if (part->type_name != PETSC_NULL) {
    defaultType = part->type_name;
  } else {
    switch(dim)
    {
    case 2:
      defaultType = PARTITION_TRIANGULAR_2D;
      break;
    default:
      SETERRQ1(PETSC_ERR_SUP, "Partition dimension %d is not supported", dim);
    }
  }

  if (!PartitionRegisterAllCalled) {
    ierr = PartitionRegisterAll(PETSC_NULL);                                                              CHKERRQ(ierr);
  }
  ierr = PetscOptionsList("-part_type", "Partition method"," PartitionSetType", PartitionList, defaultType, typeName, 256, &opt);
  CHKERRQ(ierr);
  if (opt == PETSC_TRUE) {
    ierr = PartitionSetType(part, typeName);                                                              CHKERRQ(ierr);
  } else if (part->type_name == PETSC_NULL) {
    ierr = PartitionSetType(part, defaultType);                                                           CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "PartitionSetFromOptions"
/*@
  PartitionSetFromOptions - Sets various Partition parameters from user options.

  Collective on Partition

  Input Parameter:
. part - The partition

  Notes:  To see all options, run your program with the -help option, or consult the users manual.

  Level: intermediate

.keywords: Partition, set, options, database
.seealso: PartitionPrintHelp(), PartitionSetOptionsPrefix()
@*/
int PartitionSetFromOptions(Partition part)
{
  PetscTruth opt;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  ierr = PetscOptionsBegin(part->comm, part->prefix, "Partition options", "Partition");                   CHKERRQ(ierr); 

  /* Handle generic part options */
  ierr = PetscOptionsHasName(PETSC_NULL, "-help", &opt);                                                  CHKERRQ(ierr);
  if (opt == PETSC_TRUE) {
    ierr = PartitionPrintHelp(part);                                                                      CHKERRQ(ierr);
  }

  /* Handle part type options */
  ierr = PartitionSetTypeFromOptions(part);                                                               CHKERRQ(ierr);

  /* Handle specific part options */
  if (part->ops->setfromoptions != PETSC_NULL) {
    ierr = (*part->ops->setfromoptions)(part);                                                            CHKERRQ(ierr);
  }

  ierr = PetscOptionsEnd();                                                                               CHKERRQ(ierr);

  /* Handle subobject options */

  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "PartitionView"
/*@
  PartitionView - Views a partition object.

  Collective on Partition

  Input Parameters:
+ part   - The partition
- viewer - The viewer with which to view the partition

  Level: beginner

.keywords: partition, view
.seealso: PartitionDestroy(), PetscViewerDrawOpen(), PetscViewerOpenASCII()
@*/
int PartitionView(Partition part, PetscViewer viewer)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  if (!viewer) {
    viewer = PETSC_VIEWER_STDOUT_SELF;
  } else {
    PetscValidHeaderSpecific(viewer, PETSC_VIEWER_COOKIE);
  }
  ierr = (*part->ops->view)(part, viewer);                                                               CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "PartitionCopy"
/*@
  PartitionCopy - Copies all the data from one part to another.

  Collective on Partition

  Input Parameter:
. part    - The partition

  Output Parameter:
. newpart - The identical new partition

  Level: beginner

.keywords: Partition, copy
.seealso: PartitionDuplicate()
@*/
int PartitionCopy(Partition part, Partition newpart)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part,    PARTITION_COOKIE);
  PetscValidHeaderSpecific(newpart, PARTITION_COOKIE);
  PetscFunctionBegin;
  if (!part->ops->copy) {
    SETERRQ(PETSC_ERR_SUP, "Not supported by this Partition object");
  }
  ierr = (*part->ops->copy)(part, newpart);                                                               CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "PartitionDuplicate"
/*@
  PartitionDuplicate - Duplicates the Partition.

  Collective on Partition

  Input Parameter:
. part    - The partition

  Output Parameter:
. newpart - The duplicate partition

  Level: beginner

.keywords: part, duplicate, copy
.seealso: PartitionCopy()
@*/
int PartitionDuplicate(Partition part, Partition *newpart)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  PetscValidPointer(newpart);
  if (!part->ops->duplicate) {
    SETERRQ(PETSC_ERR_SUP, "Not supported by this Partition object");
  }
  ierr = (*part->ops->duplicate)(part, newpart);                                                          CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "PartitionDestroy"
/*@
  PartitionDestroy - Destroys a partition object.

  Collective on Partition

  Input Parameter:
. part - The partition

  Level: beginner

.keywords: partition, destroy
.seealso: PartitionCreate()
@*/
int PartitionDestroy(Partition part)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  if (--part->refct > 0) PetscFunctionReturn(0);
  ierr = (*part->ops->destroy)(part);                                                                     CHKERRQ(ierr);
  PetscLogObjectDestroy(part);
  PetscHeaderDestroy(part); 
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "PartitionSetOptionsPrefix"
/*@C
  PartitionSetOptionsPrefix - Sets the prefix used for searching for all Partition options in the database.

  Not collective

  Input Parameters:
+ part   - The part
- prefix - The prefix to prepend to all option names

  Notes:
  A hyphen (-) must NOT be given at the beginning of the prefix name.
  The first character of all runtime options is AUTOMATICALLY the hyphen.

  Level: intermediate

.keywords: Partition, set, options, prefix, database
.seealso: PartitionGetOptionsPrefix(), PartitionAppendOptionsPrefix(), PartitionSetFromOptions()
@*/
int PartitionSetOptionsPrefix(Partition part, char *prefix)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  ierr = PetscObjectSetOptionsPrefix((PetscObject) part, prefix);                                         CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "PartitionAppendOptionsPrefix"
/*@C
  PartitionAppendOptionsPrefix - Appends to the prefix used for searching for all Partition options in the database.

  Not collective

  Input Parameters:
+ part   - The partition
- prefix - The prefix to prepend to all option names

  Notes:
  A hyphen (-) must NOT be given at the beginning of the prefix name.
  The first character of all runtime options is AUTOMATICALLY the hyphen.

  Level: intermediate

.keywords: Partition, append, options, prefix, database
.seealso: PartitionGetOptionsPrefix(), PartitionSetOptionsPrefix(), PartitionSetFromOptions()
@*/
int PartitionAppendOptionsPrefix(Partition part, char *prefix)
{
  int ierr;
  
  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  ierr = PetscObjectAppendOptionsPrefix((PetscObject) part, prefix);                                      CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "PartitionGetOptionsPrefix"
/*@
  PartitionGetOptionsPrefix - Returns the prefix used for searching for all Partition options in the database.

  Input Parameter:
. part   - The partition

  Output Parameter:
. prefix - A pointer to the prefix string used

  Level: intermediate

.keywords: Partition, get, options, prefix, database
.seealso: PartitionSetOptionsPrefix(), PartitionSetOptionsPrefix(), PartitionSetFromOptions()
@*/
int PartitionGetOptionsPrefix(Partition part, char **prefix)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);
  ierr = PetscObjectGetOptionsPrefix((PetscObject) part, prefix);                                         CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "PartitionPrintHelp"
/*@
  PartitionPrintHelp - Prints all options for the Partition.

  Input Parameter:
. part - The partition

  Options Database Keys:
$  -help, -h

  Level: intermediate

.keywords: part, help
.seealso: PartitionSetFromOptions()
@*/
int PartitionPrintHelp(Partition part)
{
  char p[64];
  int  ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(part, PARTITION_COOKIE);

  ierr = PetscStrcpy(p, "-");                                                                             CHKERRQ(ierr);
  if (part->prefix != PETSC_NULL) {
    ierr = PetscStrcat(p, part->prefix);                                                                  CHKERRQ(ierr);
  }

  (*PetscHelpPrintf)(part->comm, "Partition options ------------------------------------------------\n");
  (*PetscHelpPrintf)(part->comm,"   %spartition_type <typename> : Sets the partition type\n", p);
  PetscFunctionReturn(0);
}

/*------------------------------------------- Partition-Specific Operations ------------------------------------------*/
#undef  __FUNCT__
#define __FUNCT__ "PartitionGhostNodeExchange"
/*@C
  PartitionGhostNodeExchange - This functions transfers data between local and ghost storage based on the node ordering.

  Collective on Partition

  Input Parameters:
+ part         - The partition
. addv         - The insert mode, INSERT_VALUES or ADD_VALUES
- mode         - The direction of the transfer, SCATTER_FORWARD or SCATTER_REVERSE

  Output Paramters:
+ locVars      - The local variable array
- ghostVars    - The ghost variables

  Note:
  The data in ghostVars is assumed contiguous and implicitly indexed by the order of
  ghostProcs and ghostIndices. The SCATTER_FORWARD mode will take the requested data
  from locVars and copy it to ghostVars in the order specified by ghostIndices. The
  SCATTER_REVERSE mode will take data from ghostVars and copy it to locVars.

  Level: advanced

.keywords: ghost, exchange, grid
.seealso: GridGhostExchange(), GridGlobalToLocal(), GridLocalToGlobal()
@*/
int PartitionGhostNodeExchange(Partition part, InsertMode addv, ScatterMode mode, int *locVars, int *ghostVars)
{
  int ierr;

  PetscFunctionBegin;
  if (part->numProcs > 1) {
    if (part->ops->ghostnodeexchange == PETSC_NULL) {
      SETERRQ(PETSC_ERR_SUP, "Not implemented for this partition type");
    }
    ierr = (*part->ops->ghostnodeexchange)(part, addv, mode, locVars, ghostVars);                        CHKERRQ(ierr);
  }
  PetscFunctionReturn(0);
}
