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

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

/* Logging support */
int CLASS_MAP_COOKIE;

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapDestroy"
/*@
  FieldClassMapDestroy - Destroys a class map object.

  Collective on FieldClassMap

  Input Parameter:
. map - The map

  Level: beginner

.keywords: class, field class, class map, destroy
.seealso FieldClassMapCreate()
@*/
int FieldClassMapDestroy(FieldClassMap map)
{
  int f, bd;
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map, CLASS_MAP_COOKIE);
  if (--map->refct > 0)
    PetscFunctionReturn(0);
  ierr = PetscFree(map->fields);                                                                         CHKERRQ(ierr);
  for(f = 0; f < map->numFields; f++) {
    ierr = PetscFree(map->fieldClasses[f]);                                                              CHKERRQ(ierr);
  }
  ierr = PetscFree(map->fieldClasses);                                                                   CHKERRQ(ierr);
  ierr = PetscFree(map->classes);                                                                        CHKERRQ(ierr);
  ierr = PetscFree(map->classSizes);                                                                     CHKERRQ(ierr);
  if (map->isReduced == PETSC_TRUE) {
    for(f = 0; f < map->numFields; f++) {
      ierr = PetscFree(map->reduceFieldClasses[f]);                                                      CHKERRQ(ierr);
    }
    ierr = PetscFree(map->reduceFieldClasses);                                                           CHKERRQ(ierr);
  }
  ierr = PetscFree(map->isClassConstrained);                                                             CHKERRQ(ierr);
  ierr = PetscFree(map->classSizeDiffs);                                                                 CHKERRQ(ierr);
  if (map->classMap != PETSC_NULL) {
    for(bd = 0; bd < map->mapSize; bd++) {
      ierr = PetscFree(map->classMap[bd]);                                                               CHKERRQ(ierr);
    }
    ierr = PetscFree(map->classMap);                                                                     CHKERRQ(ierr);
  }
  ierr = (*map->ops->destroy)(map);                                                                      CHKERRQ(ierr);
  PetscLogObjectDestroy(map);
  PetscHeaderDestroy(map); 
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapView"
/*@
  FieldClassMapView - Views a class map object.

  Collective on FieldClassMap

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

  Level: beginner

.keywords: class, field class, class map, view
.seealso: FieldClassMapDestroy(), PetscViewerDrawOpen()
@*/
int FieldClassMapView(FieldClassMap map, PetscViewer viewer)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map, CLASS_MAP_COOKIE);
  if (viewer == PETSC_NULL)
    viewer = PETSC_VIEWER_STDOUT_SELF;
  else
    PetscValidHeaderSpecific(viewer, PETSC_VIEWER_COOKIE);
  ierr = (*map->ops->view)(map, viewer);                                                                 CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*MC
  FieldClassMapRegister - Adds a creation method to the class map package.

  Synopsis:

  FieldClassMapRegister(char *name, char *path, char *func_name, int (*create_func)(FieldClassMap))

  Not Collective

  Input Parameters:
+ name        - The name of a new user-defined creation routine
. path        - The path (either absolute or relative) of the library containing this routine
. func_name   - The name of routine to create method context
- create_func - The creation routine itself

  Notes:
  FieldClassMapRegister() may be called multiple times to add several user-defined mapes.

  If dynamic libraries are used, then the fourth input argument (create_func) is ignored.

  Sample usage:
.vb
  FieldClassMapRegister("my_map", /home/username/my_lib/lib/libO/solaris/mylib.a, "MyFunc", MyFunc);
.ve

  Then, your map type can be chosen with the procedural interface via
$     FieldClassMapSetType(vec, "my_map")
  or at runtime via the option
$     -class_map_type my_map

  Level: advanced

  $PETSC_ARCH and $BOPT occuring in pathname will be replaced with appropriate values.

.keywords: class, field class, class map, register
.seealso: FieldClassMapRegisterAll(), FieldClassMapRegisterDestroy()
M*/
#undef __FUNCT__  
#define __FUNCT__ "FieldClassMapRegister_Private"
int FieldClassMapRegister_Private(const char sname[], const char path[], const char name[],
                                  int (*function)(FieldClassMap))
{
  char fullname[256];
  int  ierr;

  PetscFunctionBegin;
  ierr = PetscStrcpy(fullname, path);                                                                     CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, ":");                                                                      CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, name);                                                                     CHKERRQ(ierr);
  ierr = PetscFListAdd(&FieldClassMapList, sname, fullname, (void (*)(void)) function);                   CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*MC
  FieldClassMapSerializeRegister - Adds a serialization method to the class map package.

  Synopsis:

  FieldClassMapSerializeRegister(char *serialize_name, char *path, char *serialize_func_name,
                                 int (*serialize_func)(MPI_Comm, FieldClassMap *, PetscViewer, PetscTruth))

  Not Collective

  Input Parameters:
+ serialize_name      - The name of a new user-defined serialization routine
. path                - The path (either absolute or relative) of the library containing this routine
. serialize_func_name - The name of routine to create method context
- serialize_func      - The serialization routine itself

  Notes:
  FieldClassMapSerializeRegister() may be called multiple times to add several user-defined solvers.

  If dynamic libraries are used, then the fourth input argument (serialize_func) is ignored.

  Sample usage:
.vb
  FieldClassMapSerializeRegister("my_store", /home/username/my_lib/lib/libO/solaris/mylib.a, "MyStoreFunc", MyStoreFunc);
.ve

  Then, your serialization can be chosen with the procedural interface via
$     FieldClassMapSetSerializeType(map, "my_store")
  or at runtime via the option
$     -class_map_serialize_type my_store

  Level: advanced

  $PETSC_ARCH and $BOPT occuring in pathname will be replaced with appropriate values.

.keywords: class, field class, class map, register
.seealso: FieldClassMapSerializeRegisterAll(), FieldClassMapSerializeRegisterDestroy()
M*/
#undef __FUNCT__  
#define __FUNCT__ "FieldClassMapSerializeRegister_Private"
int FieldClassMapSerializeRegister_Private(const char sname[], const char path[], const char name[],
                                           int (*function)(MPI_Comm, FieldClassMap *, PetscViewer, PetscTruth))
{
  char fullname[256];
  int  ierr;

  PetscFunctionBegin;
  ierr = PetscStrcpy(fullname, path);                                                                     CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, ":");                                                                      CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, name);                                                                     CHKERRQ(ierr);
  ierr = PetscFListAdd(&FieldClassMapSerializeList, sname, fullname, (void (*)(void)) function);          CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapCreateSubset"
/*@
  FieldClassMapCreateSubset - This function creates a new class map from an existing
  one on a subset of the fields.
  
  Collective on FieldClassMap

  Input Parameter:
. map    - The map

  Output Parameter:
. newMap - The new map

  Level: beginner

.keywords: class, field class, class map, subset
.seealso FieldClassMapCreate()
@*/
int FieldClassMapCreateSubset(FieldClassMap map, int numFields, int *fields, FieldClassMap *newMap)
{
  FieldClassMap cm;
  int           f, g, bd;
  int           ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map, CLASS_MAP_COOKIE);
  PetscValidPointer(newMap);
  /* Check for consistency */
  for(f = 0; f < numFields; f++) {
    for(g = 0; g < map->numFields; g++) {
      if (map->fields[g] == fields[f])
        break;
    }
    if (g == map->numFields) {
      SETERRQ1(PETSC_ERR_ARG_INCOMP, "Fields not a subset: field %d not in the existing order", fields[f]);
    }
  }
  /* Create new map */
  ierr = FieldClassMapCreate(map->comm, &cm);                                                             CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->ops, map->ops, sizeof(FieldClassMapOps));                                        CHKERRQ(ierr);
  ierr = PetscStrallocpy(map->type_name, &cm->type_name);                                                 CHKERRQ(ierr);
  cm->data = PETSC_NULL;

  cm->numFields        = numFields;
  ierr = PetscMalloc(cm->numFields * sizeof(int), &cm->fields);                                           CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->fields, fields, cm->numFields * sizeof(int));                                    CHKERRQ(ierr);
  cm->numNodes         = map->numNodes;
  cm->numGhostNodes    = map->numGhostNodes;
  cm->numOverlapNodes  = map->numOverlapNodes;
  cm->numClasses       = map->numClasses;
  ierr = PetscMalloc(cm->numFields * sizeof(int *), &cm->fieldClasses);                                   CHKERRQ(ierr);
  for(f = 0; f < cm->numFields; f++) {
    for(g = 0; g < map->numFields; g++)
      if (cm->fields[f] == map->fields[g])
        break;
    if (g == map->numFields) {
      SETERRQ1(PETSC_ERR_PLIB, "Unable to locate field %d in superset", cm->fields[f]);
    }
    ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->fieldClasses[f]);                               CHKERRQ(ierr);
    ierr = PetscMemcpy(cm->fieldClasses[f], map->fieldClasses[g], cm->numClasses * sizeof(int));          CHKERRQ(ierr);
  }
  ierr = PetscMalloc(cm->numOverlapNodes  * sizeof(int), &cm->classes);                                   CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->classes, map->classes, cm->numOverlapNodes * sizeof(int));                       CHKERRQ(ierr);
  ierr = PetscMalloc(cm->numClasses       * sizeof(int), &cm->classSizes);                                CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->classSizes, map->classSizes, cm->numClasses * sizeof(int));                      CHKERRQ(ierr);
#if 0
  for(nclass = 0; nclass < cm->numClasses; nclass++) {
    for(g = 0; g < map->numFields; g++) {
      for(f = 0; f < cm->numFields; f++)
        if (cm->fields[f] == map->fields[g])
          break;
      if (f < cm->numFields) continue;
      /* Subtract size of missing fields */
      if (map->fieldClasses[g][nclass]) {
        ierr = GridGetFieldComponents(grid, map->fields[g], &comp);                                       CHKERRQ(ierr);
        cm->classSizes[nclass] -= comp;
      }
    }
  }
#endif
  cm->isReduced = map->isReduced;
  if (map->isReduced == PETSC_TRUE) {
    ierr = PetscMalloc(cm->numFields * sizeof(int *), &cm->reduceFieldClasses);                           CHKERRQ(ierr);
    for(f = 0; f < cm->numFields; f++) {
      for(g = 0; g < map->numFields; g++) {
        if (cm->fields[f] == map->fields[g])
          break;
      }
      if (g == map->numFields) SETERRQ1(PETSC_ERR_PLIB, "Unable to locate field %d in superset", cm->fields[f]);
      ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->reduceFieldClasses[f]);                       CHKERRQ(ierr);
      ierr = PetscMemcpy(cm->reduceFieldClasses[f], map->reduceFieldClasses[g], cm->numClasses * sizeof(int)); CHKERRQ(ierr);
    }
  }
  cm->isConstrained = map->isConstrained;
  ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->isClassConstrained);                              CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->isClassConstrained, map->isClassConstrained, cm->numClasses * sizeof(int));      CHKERRQ(ierr);
  ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->classSizeDiffs);                                  CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->classSizeDiffs, map->classSizeDiffs, cm->numClasses * sizeof(int));              CHKERRQ(ierr);
  cm->mapSize       = map->mapSize;
  cm->numOldClasses = map->numOldClasses;
  if (map->classMap != PETSC_NULL) {
    ierr = PetscMalloc(cm->mapSize * sizeof(int *), &cm->classMap);                                       CHKERRQ(ierr);
    for(bd = 0; bd < cm->mapSize; bd++) {
      ierr = PetscMalloc(cm->numOldClasses * sizeof(int), &cm->classMap[bd]);                             CHKERRQ(ierr);
      ierr = PetscMemcpy(cm->classMap[bd], map->classMap[bd], cm->numOldClasses * sizeof(int));           CHKERRQ(ierr);
    }
  }

  PetscLogObjectMemory(cm, (cm->numFields + cm->mapSize) * sizeof(int *) + (cm->numFields*(cm->numClasses + 1) +
                   cm->numOverlapNodes + cm->numClasses*3 + cm->numOldClasses*cm->mapSize) * sizeof(int));
  *newMap = cm;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapDuplicate"
/*@
  FieldClassMapDuplicate - Duplicates a class map object.
  
  Collective on FieldClassMap

  Input Parameter:
. map    - The map

  Output Parameter:
. newMap - The new map

  Level: beginner

.keywords: class, field class, class map, duplicate
.seealso FieldClassMapCreate()
@*/
int FieldClassMapDuplicate(FieldClassMap map, FieldClassMap *newMap)
{
  FieldClassMap cm;
  int           f, bd;
  int           ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map, CLASS_MAP_COOKIE);
  PetscValidPointer(newMap);
  ierr = FieldClassMapCreate(map->comm, &cm);                                                             CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->ops, map->ops, sizeof(FieldClassMapOps));                                        CHKERRQ(ierr);
  ierr = PetscStrallocpy(map->type_name, &cm->type_name);                                                 CHKERRQ(ierr);
  cm->data = PETSC_NULL;

  cm->numFields        = map->numFields;
  ierr = PetscMalloc(cm->numFields * sizeof(int), &cm->fields);                                           CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->fields, map->fields, cm->numFields * sizeof(int));                               CHKERRQ(ierr);
  cm->numNodes         = map->numNodes;
  cm->numGhostNodes    = map->numGhostNodes;
  cm->numOverlapNodes  = map->numOverlapNodes;
  cm->numClasses       = map->numClasses;
  ierr = PetscMalloc(cm->numFields * sizeof(int *), &cm->fieldClasses);                                   CHKERRQ(ierr);
  for(f = 0; f < cm->numFields; f++) {
    ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->fieldClasses[f]);                               CHKERRQ(ierr);
    ierr = PetscMemcpy(cm->fieldClasses[f], map->fieldClasses[f], cm->numClasses * sizeof(int));          CHKERRQ(ierr);
  }
  ierr = PetscMalloc(cm->numOverlapNodes * sizeof(int), &cm->classes);                                    CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->classes, map->classes, cm->numOverlapNodes * sizeof(int));                       CHKERRQ(ierr);
  ierr = PetscMalloc(cm->numClasses      * sizeof(int), &cm->classSizes);                                 CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->classSizes, map->classSizes, cm->numClasses * sizeof(int));                      CHKERRQ(ierr);
  cm->isReduced        = map->isReduced;
  if (map->isReduced == PETSC_TRUE) {
    ierr = PetscMalloc(cm->numFields * sizeof(int *), &cm->reduceFieldClasses);                           CHKERRQ(ierr);
    for(f = 0; f < cm->numFields; f++) {
      ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->reduceFieldClasses[f]);                       CHKERRQ(ierr);
      ierr = PetscMemcpy(cm->reduceFieldClasses[f], map->reduceFieldClasses[f], cm->numClasses * sizeof(int)); CHKERRQ(ierr);
    }
  }
  cm->isConstrained = map->isConstrained;
  ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->isClassConstrained);                              CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->isClassConstrained, map->isClassConstrained, cm->numClasses * sizeof(int));      CHKERRQ(ierr);
  ierr = PetscMalloc(cm->numClasses * sizeof(int), &cm->classSizeDiffs);                                  CHKERRQ(ierr);
  ierr = PetscMemcpy(cm->classSizeDiffs, map->classSizeDiffs, cm->numClasses * sizeof(int));              CHKERRQ(ierr);
  cm->mapSize          = map->mapSize;
  cm->numOldClasses    = map->numOldClasses;
  if (map->classMap != PETSC_NULL) {
    ierr = PetscMalloc(cm->mapSize * sizeof(int *), &cm->classMap);                                       CHKERRQ(ierr);
    for(bd = 0; bd < cm->mapSize; bd++) {
      ierr = PetscMalloc(cm->numOldClasses * sizeof(int), &cm->classMap[bd]);                             CHKERRQ(ierr);
      ierr = PetscMemcpy(cm->classMap[bd], map->classMap[bd], cm->numOldClasses * sizeof(int));           CHKERRQ(ierr);
    }
  }

  PetscLogObjectMemory(cm, (cm->numFields + cm->mapSize) * sizeof(int *) + (cm->numFields*(cm->numClasses + 1) +
                       cm->numOverlapNodes + cm->numClasses*3 + cm->numOldClasses*cm->mapSize) * sizeof(int));
  *newMap = cm;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapConstrain"
/*@
  FieldClassMapConstrain - This function creates a new class map from an existing one by implementing
  constraints and boundary conditions registered with the grid.

  Collective on FieldClassMap

  Input Parameters:
+ map      - The map
. grid     - The grid
. useBC    - The flag for reducing boundary conditions
- useConst - The flag for using constraints

  Output Parameter:
. newMap   - The constrained map

  Level: advanced

.keywords: class, field class, class map, constraint
.seealso FieldClassMapCreate()
@*/
int FieldClassMapConstrain(FieldClassMap map, Grid grid, PetscTruth useBC, PetscTruth useConst, FieldClassMap *newMap)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map,  CLASS_MAP_COOKIE);
  PetscValidHeaderSpecific(grid, GRID_COOKIE);
  ierr = (*map->ops->constrain)(map, grid, useBC, useConst, newMap);                                     CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapReduce"
/*@
  FieldClassMapReduce - This function creates a new class map from an existing one which
  lies in the space of variables reduced by boundary conditions.

  Collective on FieldClassMap

  Input Parameters:
+ map    - The map
- grid   - The grid

  Output Parameter:
. newMap - The reduction map

  Note:
  This function is normally used to create operators which map elements from the space of
  boundary values to the calculation space. Thus you can construct a matrix to add boundary
  conditions to the rhs.

  Level: advanced

.keywords: class, field class, class map, reduction
.seealso: FieldClassMapCreate(), FieldClassMapConstrain()
@*/
int FieldClassMapReduce(FieldClassMap map, Grid grid, FieldClassMap *newMap)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map,  CLASS_MAP_COOKIE);
  PetscValidHeaderSpecific(grid, GRID_COOKIE);
  ierr = (*map->ops->reduce)(map, grid, newMap);                                                         CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapIsConstrained"
/*@
  FieldClassMapIsConstrained - This function determines whether or not the map is constrained.

  Not collective

  Input Parameter:
. cm            - The class map

  Output Parameter:
. isConstrained - The constraint flag

  Level: intermediate

.keywords: class, field class, class map
.seealso: FieldClassMapCreate(), FieldClassMapConstrain()
@*/
int FieldClassMapIsConstrained(FieldClassMap cm, PetscTruth *isConstrained) {
  PetscFunctionBegin;
  PetscValidHeaderSpecific(cm, CLASS_MAP_COOKIE);
  PetscValidPointer(isConstrained);
  *isConstrained = cm->isConstrained;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapIsDefined"
/*@
  FieldClassMapIsDefined - This function determines whether a field is defined on
  nodes of a given class, or equivalently whether the field is a member of the class.

  Not collective

  Input Parameters:
+ map     - The map
. field   - The field
- nclass  - The node class

  Output Parameter:
. defined - The flag for class membership

  Level: intermediate

.keywords: class, field class, class map
.seealso: FieldClassMapCreate(), FieldClassMapConstrain()
@*/
int FieldClassMapIsDefined(FieldClassMap map, int field, int nclass, PetscTruth *defined)
{
  int   numFields    = map->numFields;
  int   numClasses   = map->numClasses;
  int  *fields       = map->fields;
  int **fieldClasses = map->fieldClasses;
  int   f;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map, CLASS_MAP_COOKIE);
  PetscValidPointer(defined);
  for(f = 0; f < numFields; f++) {
    if (field == fields[f]) break;
  }
  if (f == numFields) SETERRQ1(PETSC_ERR_ARG_WRONG, "Field %d not present in grid", field);
  if ((nclass < 0) || (nclass >= numClasses)) {
    SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE, "Invalid class %d should be in [0,%d)", nclass, numClasses);
  }
  if (fieldClasses[f][nclass]) {
    *defined = PETSC_TRUE;
  } else {
    *defined = PETSC_FALSE;
  }
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapGetNumFields"
/*@
  FieldClassMapGetNumFields - This function returns the number of fields in the map.

  Not collective

  Input Parameter:
. cm        - The class map

  Output Parameter:
. numFields - The number of fields in the map

  Level: intermediate

.keywords: class, class map, field
.seealso: FieldClassMapGetField(), FieldClassMapCreate()
@*/
int FieldClassMapGetNumFields(FieldClassMap cm, int *numFields) {
  PetscFunctionBegin;
  PetscValidHeaderSpecific(cm, CLASS_MAP_COOKIE);
  PetscValidIntPointer(numFields);
  *numFields = cm->numFields;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapGetField"
/*@
  FieldClassMapGetField - This function returns the canonical field number of a field index in the map.

  Not collective

  Input Parameters:
+ cm    - The class map
- f     - The field index in the map

  Output Parameter:
. field - The canonical field number

  Level: intermediate

.keywords: class, class map, field
.seealso: FieldClassMapGetNumFields(), FieldClassMapCreate()
@*/
int FieldClassMapGetField(FieldClassMap cm, int f, int *field) {
  PetscFunctionBegin;
  PetscValidHeaderSpecific(cm, CLASS_MAP_COOKIE);
  PetscValidIntPointer(field);
  if ((f < 0) || (f >= cm->numFields)) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE, "Field index %d must be in [0,%d)", f, cm->numFields);
  *field = cm->fields[f];
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "FieldClassMapGetNodeClass"
/*@
  FieldClassMapGetNodeClass - This function returns the class for the given node.

  Not collective

  Input Parameters:
+ map    - The map
- node   - The node

  Output Parameter:
. nclass - The node class

  Level: intermediate

.keywords: class, class map
.seealso: FieldClassMapCreate(), FieldClassMapConstrain()
@*/
int FieldClassMapGetNodeClass(FieldClassMap map, int node, int *nclass)
{
  int  numOverlapNodes = map->numOverlapNodes;
  int *classes         = map->classes;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(map, CLASS_MAP_COOKIE);
  PetscValidPointer(nclass);
  if ((node < 0) || (node >= numOverlapNodes)) {
    SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE, "Invalid node %d should be in [0,%d)", node, numOverlapNodes);
  }
  *nclass = classes[node];
  PetscFunctionReturn(0);
}
