#ifdef PETSC_RCS_HEADER
static char vcid[] = "$Id: meshreg.c,v 1.5 2000/01/10 03:54:25 knepley Exp $";
#endif

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

PetscFList MeshList                       = PETSC_NULL;
PetscTruth MeshRegisterAllCalled          = PETSC_FALSE;
PetscFList MeshSerializeList              = PETSC_NULL;
PetscTruth MeshSerializeRegisterAllCalled = PETSC_FALSE;
PetscFList MeshOrderingList               = PETSC_NULL;
PetscTruth MeshOrderingRegisterAllCalled  = PETSC_FALSE;

#undef __FUNCT__  
#define __FUNCT__ "MeshSetType"
/*@C
  MeshSetType - Sets the creation method for the mesh.

  Collective on Mesh

  Input Parameters:
+ mesh   - The Mesh context
- method - A known method

  Options Database Command:
. -mesh_type <method> - Sets the method; use -help for a list
                        of available methods (for instance, tri2d)

  Notes:
  See "petsc/include/mesh.h" for available methods (for instance)
. MESH_TRIANGULAR_2D - Triangular 2D mesh

  Normally, it is best to use the MeshSetFromOptions() command and
  then set the Mesh type from the options database rather than by using
  this routine.  Using the options database provides the user with
  maximum flexibility in evaluating the many different solvers.
  The MeshSetType() routine is provided for those situations
  where it is necessary to set the application ordering independently of the
  command line or options database.  This might be the case, for example,
  when the choice of solver changes during the execution of the
  program, and the user's application is taking responsibility for
  choosing the appropriate method.  In other words, this routine is
  not for beginners.

  Level: intermediate

.keywords: mesh, set, type
.seealso MeshSetSerializeType()
@*/
int MeshSetType(Mesh mesh, MeshType method)
{
  int      (*r)(Mesh);
  PetscTruth match;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  ierr = PetscTypeCompare((PetscObject) mesh, method, &match);                                            CHKERRQ(ierr);
  if (match == PETSC_TRUE) PetscFunctionReturn(0);

  /* Get the function pointers for the method requested */
  if (MeshRegisterAllCalled == PETSC_FALSE) {
    ierr = MeshRegisterAll(PETSC_NULL);                                                                   CHKERRQ(ierr);
  }
  ierr = PetscFListFind(mesh->comm, MeshList, method, (void (**)(void)) &r);                              CHKERRQ(ierr);
  if (!r) SETERRQ1(PETSC_ERR_ARG_WRONG, "Unknown mesh type: %s", method);

  if (mesh->ops->destroy != PETSC_NULL) {
    ierr = (*mesh->ops->destroy)(mesh);                                                                   CHKERRQ(ierr);
  }
  ierr = (*r)(mesh);                                                                                      CHKERRQ(ierr);

  ierr = PetscObjectChangeTypeName((PetscObject) mesh, method);                                           CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "MeshGetType"
/*@C
  MeshGetType - Gets the Mesh method type name (as a string).

  Not collective

  Input Parameter:
. mesh - The mesh

  Output Parameter:
. type - The name of Mesh method

  Level: intermediate

.keywords: mesh, get, type, name
.seealso MeshSetType()
@*/
int MeshGetType(Mesh mesh, MeshType *type)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  PetscValidPointer(type);
  if (MeshRegisterAllCalled == PETSC_FALSE) {
    ierr = MeshRegisterAll(PETSC_NULL);                                                                   CHKERRQ(ierr);
  }
  *type = mesh->type_name;
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "MeshSetSerializeType"
/*@C
  MeshSetSerializeType - Sets the serialization method for the mesh.

  Collective on Mesh

  Input Parameters:
+ mesh   - The Mesh context
- method - A known method

  Options Database Command:
. -mesh_serialize_type <method> - Sets the method; use -help for a list
                                  of available methods (for instance, tri2d_binary)

  Notes:
  See "petsc/include/mesh.h" for available methods (for instance)
. MESH_SER_TRIANGULAR_2D_BINARY - Triangular 2D mesh to binary file

  Normally, it is best to use the MeshSetFromOptions() command and
  then set the Mesh type from the options database rather than by using
  this routine.  Using the options database provides the user with
  maximum flexibility in evaluating the many different solvers.
  The MeshSetSerializeType() routine is provided for those situations
  where it is necessary to set the application ordering independently of the
  command line or options database.  This might be the case, for example,
  when the choice of solver changes during the execution of the
  program, and the user's application is taking responsibility for
  choosing the appropriate method.  In other words, this routine is
  not for beginners.

  Level: intermediate

.keywords: mesh, set, type, serialization
.seealso MeshSetType()
@*/
int MeshSetSerializeType(Mesh mesh, MeshSerializeType method)
{
  int      (*r)(MPI_Comm, Mesh *, PetscViewer, PetscTruth);
  PetscTruth match;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  ierr = PetscSerializeCompare((PetscObject) mesh, method, &match);                                       CHKERRQ(ierr);
  if (match == PETSC_TRUE) PetscFunctionReturn(0);

  /* Get the function pointers for the method requested but do not call */
  if (MeshSerializeRegisterAllCalled == PETSC_FALSE) {
    ierr = MeshSerializeRegisterAll(PETSC_NULL);                                                          CHKERRQ(ierr);
  }
  ierr = PetscFListFind(mesh->comm, MeshSerializeList, method, (void (**)(void)) &r);                     CHKERRQ(ierr);
  if (!r) SETERRQ1(PETSC_ERR_ARG_WRONG, "Unknown mesh serialization type: %s", method);

  ierr = PetscObjectChangeSerializeName((PetscObject) mesh, method);                                      CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "MeshGetSerializeType"
/*@C
  MeshGetSerializeType - Gets the Mesh serialization method (as a string).

  Not collective

  Input Parameter:
. mesh - The mesh

  Output Parameter:
. type - The name of Mesh serialization method

  Level: intermediate

.keywords: mesh, get, serialize, type, name
.seealso MeshSetType()
@*/
int MeshGetSerializeType(Mesh mesh, MeshSerializeType *type)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);
  PetscValidPointer(type);
  if (MeshSerializeRegisterAllCalled == PETSC_FALSE) {
    ierr = MeshSerializeRegisterAll(PETSC_NULL);                                                          CHKERRQ(ierr);
  }
  *type = mesh->serialize_name;
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "MeshGetOrdering"
/*@C
  MeshGetOrdering - Gets a reordering for the mesh

  Collective on Mesh

  Input Parameters:
+ mesh     - The mesh
- type     - type of reordering, one of the following:
$    MATORDERING_NATURAL - Natural
$    MATORDERING_ND      - Nested Dissection
$    MATORDERING_1WD     - One-way Dissection
$    MATORDERING_RCM     - Reverse Cuthill-McKee
$    MATORDERING_QMD     - Quotient Minimum Degree

  Output Parameter:
. ordering - The new node ordering

  Options Database Keys:
  To specify the ordering through the options database, use one of
  the following 
$   -mesh_ordering_type natural, -mesh_ordering_type nd, -mesh_ordering_type 1wd, 
$   -mesh_ordering_type rcm, -mesh_ordering_type qmd

  Level: intermediate

  Note:
  The user can define additional orderings, see MeshOrderingRegister().

.keywords: mesh, set, ordering, reordering, natural, Nested Dissection,
           One-way Dissection, Reverse Cuthill-McKee, Quotient Minimum Degree
.seealso: MeshOrderingRegister()
@*/
int MeshGetOrdering(Mesh mesh, MeshOrderingType type, AO *ordering)
{
  int      (*r)(Mesh, MeshOrderingType, AO*);
  char       orderName[256];
  PetscTruth opt;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(mesh, MESH_COOKIE);

  if (MeshOrderingRegisterAllCalled == PETSC_FALSE) {
    ierr = MeshOrderingRegisterAll(PETSC_NULL);                                                           CHKERRQ(ierr);
  }

  /* Check for type in command line arguments */
  ierr = PetscOptionsGetString(mesh->prefix, "-mesh_ordering_type", orderName, 256, &opt);                CHKERRQ(ierr);
  if (opt == PETSC_TRUE) {
    type = orderName;
  }

  ierr =  PetscFListFind(mesh->comm, MeshOrderingList, type, (void (**)(void)) &r);                       CHKERRQ(ierr);
  if (!r) SETERRQ1(PETSC_ERR_ARG_WRONG, "Unknown mesh ordering type: %s", type);
  ierr = (*r)(mesh, type, ordering);                                                                      CHKERRQ(ierr);

  PetscFunctionReturn(0);
}

/*--------------------------------------------------------------------------------------------------------------------*/
/*@C
  MeshRegister - Adds a creation method to the mesh package.

  Synopsis:

  MeshRegister(char *name, char *path, char *func_name, int (*create_func)(Mesh))

  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 the creation routine
- create_func - The creation routine itself

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

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

  Sample usage:
.vb
  MeshRegisterDynamic("my_mesh", "/home/username/my_lib/lib/libO/solaris/libmy.a", "MyMeshCreate", MyMeshCreate);
.ve

  Then, your mesh type can be chosen with the procedural interface via
.vb
    MeshCreate(MPI_Comm, Mesh *);
    MeshSetType(vec, "my_mesh")
.ve
  or at runtime via the option
.vb
    -mesh_type my_mesh
.ve

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

  Level: advanced

.keywords: Mesh, register
.seealso: MeshRegisterAll(), MeshRegisterDestroy()
@*/
#undef __FUNCT__  
#define __FUNCT__ "MeshRegister"
int MeshRegister(const char sname[], const char path[], const char name[], int (*function)(Mesh))
{
  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(&MeshList, sname, fullname, (void (*)(void)) function);                            CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*@C
  MeshSerializeRegister - Adds a serialization method to the mesh package.

  Synopsis:

  MeshSerializeRegister(char *name, char *path, char *func_name,
                        int (*serialize_func)(MPI_Comm, Mesh *, PetscViewer, PetscTruth))

  Not Collective

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

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

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

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

  Then, your serialization can be chosen with the procedural interface via
.vb
    MeshSetSerializeType(mesh, "my_store")
.ve
  or at runtime via the option
.vb
    -mesh_serialize_type my_store
.ve

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

  Level: advanced

.keywords: mesh, register
.seealso: MeshSerializeRegisterAll(), MeshSerializeRegisterDestroy()
M*/
#undef __FUNCT__  
#define __FUNCT__ "MeshSerializeRegister"
int MeshSerializeRegister(const char sname[], const char path[], const char name[],
                          int (*function)(MPI_Comm, Mesh *, 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(&MeshSerializeList, sname, fullname, (void (*)(void)) function);                   CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*MC
  MeshOrderingRegister - Adds an ordering method to the mesh package.

  Synopsis:

  MeshOrderingRegister(char *order_name, char *path, char *order_func_name,
                       int (*order_func)(MPI_Comm, Mesh *, PetscViewer, PetscTruth))

  Not Collective

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

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

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

  Sample usage:
.vb
  MeshOrderingRegister("my_order", /home/username/my_lib/lib/libO/solaris/mylib.a, "MyOrderFunc", MyOrderFunc);
.ve

  Then, your serialization can be chosen with the procedural interface via
$     MeshGetOrdering(mesh, "my_order", &ao)
  or at runtime via the option
$     -mesh_ordering_type my_order

  Level: advanced

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

.keywords: mesh, register
.seealso: MeshOrderingRegisterAll(), MeshOrderingRegisterDestroy()
M*/
#undef __FUNCT__  
#define __FUNCT__ "MeshOrderingRegister"
int MeshOrderingRegister(const char sname[], const char path[], const char name[],
                         int (*function)(Mesh, MeshOrderingType, AO *))
{
  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(&MeshOrderingList, sname, fullname, (void (*)(void)) function);                    CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*-------------------------------------------------------------------------------------------------------------------*/
#undef __FUNCT__  
#define __FUNCT__ "MeshRegisterDestroy"
/*@C
  MeshRegisterDestroy - Frees the list of creation routines for
  meshes that were registered by MeshRegister().

  Not collective

  Level: advanced

.keywords: mesh, register, destroy
.seealso: MeshRegister(), MeshRegisterAll(), MeshSerializeRegisterDestroy()
@*/
int MeshRegisterDestroy()
{
  int ierr;

  PetscFunctionBegin;
  if (MeshList != PETSC_NULL) {
    ierr = PetscFListDestroy(&MeshList);                                                                  CHKERRQ(ierr);
    MeshList = PETSC_NULL;
  }
  MeshRegisterAllCalled = PETSC_FALSE;
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "MeshSerializeRegisterDestroy"
/*@C
  MeshSerializeRegisterDestroy - Frees the list of serialization routines for
  meshes that were registered by FListAdd().

  Not collective

  Level: advanced

.keywords: mesh, serialization, register, destroy
.seealso: MeshSerializeRegisterAll(), MeshRegisterDestroy()
@*/
int MeshSerializeRegisterDestroy()
{
  int ierr;

  PetscFunctionBegin;
  if (MeshSerializeList) {
    ierr = PetscFListDestroy(&MeshSerializeList);                                                         CHKERRQ(ierr);
    MeshSerializeList = PETSC_NULL;
  }
  MeshSerializeRegisterAllCalled = PETSC_FALSE;
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "MeshOrderingRegisterDestroy"
/*@C
  MeshOrderingRegisterDestroy - Frees the list of ordering routines for
  meshes that were registered by MeshSerializeRegister().

  Not collective

  Level: advanced

.keywords: mesh, ordering, register, destroy
.seealso: MeshOrderingRegisterAll(), MeshRegisterDestroy()
@*/
int MeshOrderingRegisterDestroy()
{
  int ierr;

  PetscFunctionBegin;
  if (MeshOrderingList) {
    ierr = PetscFListDestroy(&MeshOrderingList);                                                          CHKERRQ(ierr);
    MeshOrderingList = PETSC_NULL;
  }
  MeshOrderingRegisterAllCalled = PETSC_FALSE;
  PetscFunctionReturn(0);
}
