// =====================================================
  void PetscPreconditioner::set_petsc_preconditioner_type
  (const PreconditionerType & preconditioner_type, PC & pc,  const int &parallelOverlapping) {
    int ierr = 0;
    switch(preconditioner_type)  {

      case IDENTITY_PRECOND:
        ierr = PCSetType(pc, (char*) PCNONE);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case CHOLESKY_PRECOND:
        ierr = PCSetType(pc, (char*) PCCHOLESKY);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case ICC_PRECOND:
        ierr = PCSetType(pc, (char*) PCICC);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;


      case ILU_PRECOND:
      {
        int nprocs;
        MPI_Comm_size(MPI_COMM_WORLD, &nprocs); //TODO
        // In serial, just set the ILU preconditioner type
        if(nprocs == 1)
        {
          ierr = PCSetType(pc, (char*) PCILU);
          CHKERRABORT(MPI_COMM_WORLD, ierr);
        }
        else
        {
//        But PETSc has no truly parallel ILU, instead you have to set
//        an actual parallel preconditioner (e.g. block Jacobi (parlleloverlapping 0) or ASM (parlleloverlapping >0))
//	  and then assign ILU sub-preconditioners.

          set_petsc_preconditioner_type(ASM_PRECOND, pc);
          PCASMSetOverlap(pc, parallelOverlapping);
          PCSetUp(pc);

          // Set ILU as the sub preconditioner type
          set_petsc_subpreconditioner_type(PCILU, pc);
        }
        break;
      }
      case LU_PRECOND: {
        int nprocs;
        MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
        if(nprocs == 1) {
          ierr = PCSetType(pc, (char*) PCLU);
          CHKERRABORT(MPI_COMM_WORLD, ierr);
        }
        else {
          ierr = PCSetType(pc, (char*) PCLU);
          CHKERRABORT(MPI_COMM_WORLD, ierr);

          ierr = PCFactorSetMatSolverPackage(pc, MATSOLVERMUMPS);
          CHKERRABORT(MPI_COMM_WORLD, ierr);
          ierr = PCFactorSetUpMatSolverPackage(pc);
          CHKERRABORT(MPI_COMM_WORLD, ierr);
          Mat       F;
          ierr = PCFactorGetMatrix(pc, &F);
          CHKERRABORT(MPI_COMM_WORLD, ierr);
          ierr = MatMumpsSetIcntl(F, 14, 30);
          CHKERRABORT(MPI_COMM_WORLD, ierr);
        }
        break;
      }

      case SLU_PRECOND:
        ierr = PCSetType(pc, (char*) PCLU);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        ierr = PCFactorSetMatSolverPackage(pc, MATSOLVERSUPERLU_DIST);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;    //here we set the SuperLU_dist solver package

      case MLU_PRECOND: //here we set the MUMPS parallel direct solver package
        ierr = PCSetType(pc, (char*) PCLU);
        CHKERRABORT(MPI_COMM_WORLD, ierr);

        ierr = PCFactorSetMatSolverPackage(pc, MATSOLVERMUMPS);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        ierr = PCFactorSetUpMatSolverPackage(pc);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        Mat       F;
        ierr = PCFactorGetMatrix(pc, &F);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        ierr = MatMumpsSetIcntl(F, 14, 30);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case ULU_PRECOND: //here we set the Umfpack serial direct solver package
        ierr = PCSetType(pc, (char*) PCLU);
        CHKERRABORT(MPI_COMM_WORLD, ierr);

        ierr = PCFactorSetMatSolverPackage(pc, MATSOLVERUMFPACK);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        ierr = PCFactorSetUpMatSolverPackage(pc);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case MCC_PRECOND:
        ierr = PCSetType(pc, (char*) PCCHOLESKY);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        ierr = PCFactorSetMatSolverPackage(pc, MATSOLVERMUMPS);
        CHKERRABORT(MPI_COMM_WORLD, ierr);                   //here we set the MUMPS parallel direct solver package
        break;

      case ASM_PRECOND:
        ierr = PCSetType(pc, (char*) PCASM);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case FIELDSPLIT_PRECOND:
        ierr = PCSetType(pc, (char*) PCFIELDSPLIT);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case JACOBI_PRECOND:
        ierr = PCSetType(pc, (char*) PCJACOBI);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case BLOCK_JACOBI_PRECOND:
        ierr = PCSetType(pc, (char*) PCBJACOBI);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case SOR_PRECOND:
        ierr = PCSetType(pc, (char*) PCSOR);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case EISENSTAT_PRECOND:
        ierr = PCSetType(pc, (char*) PCEISENSTAT);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case AMG_PRECOND:
        ierr = PCSetType(pc, (char*) PCHYPRE);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case MG_PRECOND:
        ierr = PCSetType(pc, (char*) PCMG);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      case LSC_PRECOND:
        ierr = PCSetType(pc, (char*) PCLSC);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

#if !(PETSC_VERSION_LESS_THAN(2,1,2))
        // Only available for PETSC >= 2.1.2
      case USER_PRECOND:
        ierr = PCSetType(pc, (char*) PCMAT);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;
#endif

      case SHELL_PRECOND:
        ierr = PCSetType(pc, (char*) PCSHELL);
        CHKERRABORT(MPI_COMM_WORLD, ierr);
        break;

      default:
        std::cerr << "ERROR:  Unsupported PETSC Preconditioner: "
                  << preconditioner_type << std::endl
                  << "Continuing with PETSC defaults" << std::endl;
    }

    //Let the commandline override stuff
    if(preconditioner_type != AMG_PRECOND && preconditioner_type != MG_PRECOND)   PCSetFromOptions(pc);   //!!!!!!
  }
void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc)
{
  int ierr = 0;

  // get the communicator from the PETSc object
  Parallel::communicator comm;
  PetscObjectGetComm((PetscObject)pc, &comm);
  Parallel::Communicator communicator(comm);

  switch (preconditioner_type)
  {
  case IDENTITY_PRECOND:
    ierr = PCSetType (pc, (char*) PCNONE);      CHKERRABORT(comm,ierr); break;

  case CHOLESKY_PRECOND:
    ierr = PCSetType (pc, (char*) PCCHOLESKY);  CHKERRABORT(comm,ierr); break;

  case ICC_PRECOND:
    ierr = PCSetType (pc, (char*) PCICC);       CHKERRABORT(comm,ierr); break;

  case ILU_PRECOND:
    {
      // In serial, just set the ILU preconditioner type
      if (communicator.size())
	{
	  ierr = PCSetType (pc, (char*) PCILU);
	  CHKERRABORT(comm,ierr);
	}
      else
	{
	  // But PETSc has no truly parallel ILU, instead you have to set
	  // an actual parallel preconditioner (e.g. block Jacobi) and then
	  // assign ILU sub-preconditioners.
	  ierr = PCSetType (pc, (char*) PCBJACOBI);
	  CHKERRABORT(comm,ierr);

	  // Set ILU as the sub preconditioner type
	  set_petsc_subpreconditioner_type(PCILU, pc);
	}
      break;
    }

  case LU_PRECOND:
    {
      // In serial, just set the LU preconditioner type
      if (communicator.size())
	{
	  ierr = PCSetType (pc, (char*) PCLU);
	  CHKERRABORT(comm,ierr);
	}
      else
	{
	  // But PETSc has no truly parallel LU, instead you have to set
	  // an actual parallel preconditioner (e.g. block Jacobi) and then
	  // assign LU sub-preconditioners.
	  ierr = PCSetType (pc, (char*) PCBJACOBI);
	  CHKERRABORT(comm,ierr);

	  // Set ILU as the sub preconditioner type
	  set_petsc_subpreconditioner_type(PCLU, pc);
	}
      break;
    }

  case ASM_PRECOND:
    {
      // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
      // I tried setting a different sub-preconditioner here, but apparently the matrix
      // is not in the correct state (at this point) to call PCSetUp().
      ierr = PCSetType (pc, (char*) PCASM);
      CHKERRABORT(comm,ierr);
      break;
    }

  case JACOBI_PRECOND:
    ierr = PCSetType (pc, (char*) PCJACOBI);    CHKERRABORT(comm,ierr); break;

  case BLOCK_JACOBI_PRECOND:
    ierr = PCSetType (pc, (char*) PCBJACOBI);   CHKERRABORT(comm,ierr); break;

  case SOR_PRECOND:
    ierr = PCSetType (pc, (char*) PCSOR);       CHKERRABORT(comm,ierr); break;

  case EISENSTAT_PRECOND:
    ierr = PCSetType (pc, (char*) PCEISENSTAT); CHKERRABORT(comm,ierr); break;

  case AMG_PRECOND:
    ierr = PCSetType (pc, (char*) PCHYPRE);     CHKERRABORT(comm,ierr); break;

#if !(PETSC_VERSION_LESS_THAN(2,1,2))
    // Only available for PETSC >= 2.1.2
  case USER_PRECOND:
    ierr = PCSetType (pc, (char*) PCMAT);       CHKERRABORT(comm,ierr); break;
#endif

  case SHELL_PRECOND:
    ierr = PCSetType (pc, (char*) PCSHELL);     CHKERRABORT(comm,ierr); break;

  default:
    libMesh::err << "ERROR:  Unsupported PETSC Preconditioner: "
                  << preconditioner_type       << std::endl
                  << "Continuing with PETSC defaults" << std::endl;
  }

  // Set additional options if we are doing AMG and
  // HYPRE is available
#ifdef LIBMESH_HAVE_PETSC_HYPRE
  if (preconditioner_type == AMG_PRECOND)
    {
      ierr = PCHYPRESetType(pc, "boomeramg");
      CHKERRABORT(comm,ierr);
    }
#endif

  // Let the commandline override stuff
  // FIXME: Unless we are doing AMG???
  if (preconditioner_type != AMG_PRECOND)
    {
      ierr = PCSetFromOptions(pc);
      CHKERRABORT(comm,ierr);
    }
}