comments inline

On Mon, 13 Sep 2010 15:18:30 +0200 (CEST), Tim Kroeger 
<[email protected]> wrote:
> Index: include/solvers/petsc_linear_solver.h
> ===================================================================
> --- include/solvers/petsc_linear_solver.h     (Revision 3957)
> +++ include/solvers/petsc_linear_solver.h     (Arbeitskopie)
> @@ -122,7 +122,15 @@
>     * Initialize data structures if not done so already plus much more
>     */
>    void init (PetscMatrix<T>* matrix);
> +
>    /**
> +   * After calling this method, all successive solves will be limited
> +   * to the given set of dofs.  This mode can be disabled by calling
> +   * this method with \p dofs being a \p NULL pointer.
> +   */
> +  virtual void solve_only_on (const std::set<unsigned int>* const dofs);
> +
> +  /**
>     * Call the Petsc solver.  It calls the method below, using the
>     * same matrix for the system and preconditioner matrices.
>     */    
> @@ -253,13 +261,36 @@
>     * Krylov subspace context
>     */
>    KSP _ksp;
> +
> +  /**
> +   * Set of dofs to which any solve is limited (\p NULL means solve on
> +   * all dofs).
> +   */
> +  const std::set<unsigned int>* _solve_only_on_dofs;

I don't think a set is the correct data structure because the order
actually matters (it affects memory performance and the strength of
preconditioners).  I also don't see why it needs to be kept separate
from the IS, you're duplicating information, it uses more memory and
will have to be kept consistent.

> +
> +  /**
> +   * PETSc index set containing the dofs on which to solve (\p NULL
> +   * means solve on all dofs).
> +   */
> +  IS _solve_only_on_is;
> +
> +  /**
> +   * PETSc index set containing dofs from 0 to n-1 where n is the
> +   * number of dofs on which to solve (\p NULL means solve on all
> +   * dofs).
> +   */
> +  IS _solve_only_on_is_seq;

You don't need this IS, see below.

> +
>  };
>  
>  
>  /*----------------------- functions ----------------------------------*/
>  template <typename T>
>  inline
> -PetscLinearSolver<T>::PetscLinearSolver ()
> +  PetscLinearSolver<T>::PetscLinearSolver ():
> +  _solve_only_on_dofs(NULL),
> +  _solve_only_on_is(NULL),
> +  _solve_only_on_is_seq(NULL)
>  {
>    if (libMesh::n_processors() == 1)
>      this->_preconditioner_type = ILU_PRECOND;
> Index: include/solvers/linear_solver.h
> ===================================================================
> --- include/solvers/linear_solver.h   (Revision 3957)
> +++ include/solvers/linear_solver.h   (Arbeitskopie)
> @@ -24,6 +24,7 @@
>  
>  
>  // C++ includes
> +#include <set>
>  
>  // Local includes
>  #include "libmesh_common.h"
> @@ -117,6 +118,13 @@
>    void attach_preconditioner(Preconditioner<T> * preconditioner);
>  
>    /**
> +   * After calling this method, all successive solves will be limited
> +   * to the given set of dofs.  This mode can be disabled by calling
> +   * this method with \p dofs being a \p NULL pointer.
> +   */
> +  virtual void solve_only_on (const std::set<unsigned int>* const dofs);
> +
> +  /**
>     * This function calls the solver
>     * "_solver_type" preconditioned with the
>     * "_preconditioner_type" preconditioner.  Note that this method
> Index: src/solvers/petsc_linear_solver.C
> ===================================================================
> --- src/solvers/petsc_linear_solver.C (Revision 3957)
> +++ src/solvers/petsc_linear_solver.C (Arbeitskopie)
> @@ -98,6 +98,8 @@
>  {
>    if (this->initialized())
>      {
> +      this->solve_only_on(NULL);
> +
>        this->_is_initialized = false;
>  
>        int ierr=0;
> @@ -360,9 +362,59 @@
>  
>  
>  
> +template <typename T>
> +void
> +PetscLinearSolver<T>::solve_only_on (const std::set<unsigned int>* const 
> dofs)
> +{
> +  libmesh_assert(this->initialized());
>  
> +  int ierr=0;
>  
> +  if(_solve_only_on_is!=NULL)
> +    {
> +      ierr = ISDestroy(_solve_only_on_is);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      _solve_only_on_is = NULL;
> +    }
>  
> +  if(_solve_only_on_is_seq!=NULL)
> +    {
> +      ierr = ISDestroy(_solve_only_on_is_seq);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      _solve_only_on_is_seq = NULL;
> +    }
> +
> +  _solve_only_on_dofs = dofs;

So the LinearSolver doesn't take ownership of this set?  It seems
horrible to make the user responsible for that.

> +
> +  if(dofs!=NULL)
> +    {
> +      PetscInt* petsc_dofs;
> +      PetscInt* petsc_dofs_seq;
> +      ierr = PetscMalloc(dofs->size()*sizeof(PetscInt),&petsc_dofs);
> +      ierr = PetscMalloc(dofs->size()*sizeof(PetscInt),&petsc_dofs_seq);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      std::set<unsigned int>::const_iterator it = dofs->begin();
> +      std::set<unsigned int>::const_iterator itEnd = dofs->end();
> +      size_t count = 0;
> +      while(it!=itEnd)
> +     {
> +       petsc_dofs[count] = *it;
> +       petsc_dofs_seq[count] = count;
> +       count++;
> +       it++;
> +     }
> +      libmesh_assert(count=dofs->size());
> +
> +      ierr = 
> ISCreateGeneralNC(libMesh::COMM_WORLD,count,petsc_dofs,&_solve_only_on_is);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = 
> ISCreateGeneralNC(libMesh::COMM_WORLD,count,petsc_dofs_seq,&_solve_only_on_is_seq);

Could build this IS with

  PetscErrorCode ISCreateStride(MPI_Comm comm,PetscInt n,PetscInt 
first,PetscInt step,IS *is);

but you don't need the IS at all, see below.

> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +    }
> +}
> +
> +
> +
>  template <typename T>
>  std::pair<unsigned int, Real> 
>  PetscLinearSolver<T>::solve (SparseMatrix<T>&  matrix_in,
> @@ -406,6 +458,11 @@
>    
>  // 2.1.x & earlier style      
>  #if PETSC_VERSION_LESS_THAN(2,2,0)
> +
> +  if(_solve_only_on_is!=NULL)
> +    {
> +      libmesh_not_implemented();
> +    }
>        
>    // Set operators. The input matrix works as the preconditioning matrix
>    ierr = SLESSetOperators(_sles, matrix->mat(), precond->mat(),
> @@ -431,6 +488,11 @@
>  // 2.2.0
>  #elif PETSC_VERSION_LESS_THAN(2,2,1)
>        
> +  if(_solve_only_on_is!=NULL)
> +    {
> +      libmesh_not_implemented();
> +    }
> +      
>    // Set operators. The input matrix works as the preconditioning matrix
>    //ierr = KSPSetOperators(_ksp, matrix->mat(), precond->mat(),
>        //                      SAME_NONZERO_PATTERN);
> @@ -475,19 +537,34 @@
>  // 2.2.1 & newer style
>  #else
>        
> -  // Set operators. The input matrix works as the preconditioning matrix
> -  if(!this->same_preconditioner)
> -  {
> -    ierr = KSPSetOperators(_ksp, matrix->mat(), precond->mat(),
> -                        SAME_NONZERO_PATTERN);
> -           CHKERRABORT(libMesh::COMM_WORLD,ierr);
> -  }
> +  Mat submat = NULL;
> +  Mat subprecond = NULL;
> +
> +  // Set operators.
> +  if(_solve_only_on_is!=NULL)
> +    {
> +      libmesh_assert(_solve_only_on_is_seq!=NULL);
> +
> +      ierr = MatGetSubMatrix(matrix->mat(),
> +                          _solve_only_on_is,_solve_only_on_is,
> +                          PETSC_DECIDE,MAT_INITIAL_MATRIX,&submat);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = MatGetSubMatrix(precond->mat(),
> +                          _solve_only_on_is,_solve_only_on_is,
> +                          PETSC_DECIDE,MAT_INITIAL_MATRIX,&subprecond);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = KSPSetOperators(_ksp, submat, subprecond,
> +                          this->same_preconditioner ? SAME_PRECONDITIONER : 
> SAME_NONZERO_PATTERN);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +    }
>    else
> -  {
> -    ierr = KSPSetOperators(_ksp, matrix->mat(), precond->mat(),
> -               SAME_PRECONDITIONER);
> -           CHKERRABORT(libMesh::COMM_WORLD,ierr);
> -  }
> +    {
> +      ierr = KSPSetOperators(_ksp, matrix->mat(), precond->mat(),
> +                          this->same_preconditioner ? SAME_PRECONDITIONER : 
> SAME_NONZERO_PATTERN);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +    }

Use of this->same_preconditioner is an unrelated change, correct?  Note
that there are more than two values in that enum.  Also, you really have
a DIFFERENT_NONZERO_PATTERN if you just switched matrices to solve on a
different index set.

>  
>    // Set the tolerances for the iterative solver.  Use the user-supplied
>    // tolerance for the relative residual & leave the others at default 
> values.
> @@ -496,8 +573,56 @@
>           CHKERRABORT(libMesh::COMM_WORLD,ierr);
>  
>    // Solve the linear system
> -  ierr = KSPSolve (_ksp, rhs->vec(), solution->vec());
> -         CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +  if(_solve_only_on_is!=NULL)
> +    {
> +      libmesh_assert(_solve_only_on_is_seq!=NULL);
> +      libmesh_assert(_solve_only_on_dofs!=NULL);
> +      Vec subrhs;
> +      Vec subsolution;
> +
> +      ierr = 
> VecCreateSeq(libMesh::COMM_WORLD,_solve_only_on_dofs->size(),&subrhs);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = 
> VecCreateSeq(libMesh::COMM_WORLD,_solve_only_on_dofs->size(),&subsolution);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);

Why are you specializing this to only work in serial?

> +
> +      VecScatter scatter;
> +      ierr = VecScatterCreate(rhs->vec(),_solve_only_on_is,
> +                           subrhs,_solve_only_on_is_seq,
> +                           &scatter);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);

Can use NULL for the second IS, it means "scatter to the whole vector".

> +
> +      ierr = 
> VecScatterBegin(scatter,rhs->vec(),subrhs,INSERT_VALUES,SCATTER_FORWARD);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      ierr = 
> VecScatterEnd(scatter,rhs->vec(),subrhs,INSERT_VALUES,SCATTER_FORWARD);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = 
> VecScatterBegin(scatter,solution->vec(),subsolution,INSERT_VALUES,SCATTER_FORWARD);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      ierr = 
> VecScatterEnd(scatter,solution->vec(),subsolution,INSERT_VALUES,SCATTER_FORWARD);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = KSPSolve (_ksp, subrhs, subsolution);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = 
> VecScatterBegin(scatter,subsolution,solution->vec(),INSERT_VALUES,SCATTER_REVERSE);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      ierr = 
> VecScatterEnd(scatter,subsolution,solution->vec(),INSERT_VALUES,SCATTER_REVERSE);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = VecScatterDestroy(scatter);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +
> +      ierr = VecDestroy(subsolution);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      ierr = VecDestroy(subrhs);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +    }
> +  else
> +    {
> +      ierr = KSPSolve (_ksp, rhs->vec(), solution->vec());
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +    }
>        
>    // Get the number of iterations required for convergence
>    ierr = KSPGetIterationNumber (_ksp, &its);
> @@ -507,6 +632,14 @@
>    ierr = KSPGetResidualNorm (_ksp, &final_resid);
>           CHKERRABORT(libMesh::COMM_WORLD,ierr);
>        
> +  if(_solve_only_on_is!=NULL)
> +    {
> +      ierr = MatDestroy(submat);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +      ierr = MatDestroy(subprecond);
> +      CHKERRABORT(libMesh::COMM_WORLD,ierr);
> +    }
> +
>  #endif
>  
>    STOP_LOG("solve()", "PetscLinearSolver");
> Index: src/solvers/linear_solver.C
> ===================================================================
> --- src/solvers/linear_solver.C       (Revision 3957)
> +++ src/solvers/linear_solver.C       (Arbeitskopie)
> @@ -115,7 +115,18 @@
>    _preconditioner = preconditioner;
>  }
>  
> +template <typename T>
> +void
> +LinearSolver<T>::solve_only_on(const std::set<unsigned int>* const dofs)
> +{
> +  if(dofs!=NULL)
> +    {
> +      libmesh_not_implemented();
> +    }
> +}

If dofs == NULL, this function is a no-op?

>  
> +
> +
>  //------------------------------------------------------------------
>  // Explicit instantiations
>  template class LinearSolver<Number>;

------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
Libmesh-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libmesh-users

Reply via email to