void
INSStaggeredVCStokesOperator::modifyRhsForInhomogeneousBc(
    SAMRAIVectorReal<NDIM,double>& y)
{
    // Set y := y - A*0, i.e., shift the right-hand-side vector to account for
    // inhomogeneous boundary conditions.
    if (!d_homogeneous_bc)
    {
        d_correcting_rhs = true;

        Pointer<SAMRAIVectorReal<NDIM,double> > x = y.cloneVector("");
        x->allocateVectorData();
        x->setToScalar(0.0);

        Pointer<SAMRAIVectorReal<NDIM,double> > b = y.cloneVector("");
        b->allocateVectorData();
        b->setToScalar(0.0);

        apply(*x,*b);
        y.subtract(Pointer<SAMRAIVectorReal<NDIM,double> >(&y, false), b);

        x->freeVectorComponents();
        x.setNull();

        b->freeVectorComponents();
        b.setNull();

        d_correcting_rhs = false;
    }
    return;
}// modifyRhsForInhomogeneousBc
void PETScSNESFunctionGOWrapper::initializeOperatorState(const SAMRAIVectorReal<NDIM, double>& in,
                                                         const SAMRAIVectorReal<NDIM, double>& out)
{
    if (d_is_initialized) deallocateOperatorState();
    d_x = in.cloneVector("");
    d_y = out.cloneVector("");
    MPI_Comm comm;
    int ierr = PetscObjectGetComm(reinterpret_cast<PetscObject>(d_petsc_snes), &comm);
    IBTK_CHKERRQ(ierr);
    d_petsc_x = PETScSAMRAIVectorReal::createPETScVector(d_x, comm);
    d_petsc_y = PETScSAMRAIVectorReal::createPETScVector(d_y, comm);
    d_is_initialized = true;
    return;
} // initializeOperatorState
Beispiel #3
0
void
PETScPCLSWrapper::initializeSolverState(const SAMRAIVectorReal<NDIM, double>& x,
                                        const SAMRAIVectorReal<NDIM, double>& b)
{
    if (d_is_initialized) deallocateSolverState();
    d_x = x.cloneVector("");
    d_b = b.cloneVector("");
    MPI_Comm comm;
    int ierr = PetscObjectGetComm(reinterpret_cast<PetscObject>(d_petsc_pc), &comm);
    IBTK_CHKERRQ(ierr);
    d_petsc_x = PETScSAMRAIVectorReal::createPETScVector(d_x, comm);
    d_petsc_b = PETScSAMRAIVectorReal::createPETScVector(d_b, comm);
    d_is_initialized = true;
    return;
} // initializeSolverState
void
INSStaggeredVCStokesOperator::initializeOperatorState(
    const SAMRAIVectorReal<NDIM,double>& in,
    const SAMRAIVectorReal<NDIM,double>& /*out*/)
{
    IBAMR_TIMER_START(t_initialize_operator_state);

    if (d_is_initialized) deallocateOperatorState();

    d_x_scratch = in.cloneVector("INSStaggeredVCStokesOperator::x_scratch");
    d_x_scratch->allocateVectorData();

    typedef HierarchyGhostCellInterpolation::InterpolationTransactionComponent InterpolationTransactionComponent;
    InterpolationTransactionComponent U_scratch_component(d_x_scratch->getComponentDescriptorIndex(0), U_DATA_COARSEN_TYPE, BDRY_EXTRAP_TYPE, CONSISTENT_TYPE_2_BDRY);
    InterpolationTransactionComponent P_scratch_component(d_x_scratch->getComponentDescriptorIndex(1), P_DATA_COARSEN_TYPE, BDRY_EXTRAP_TYPE, CONSISTENT_TYPE_2_BDRY);
    InterpolationTransactionComponent mu_component(d_mu_data_idx, MU_DATA_COARSEN_TYPE, BDRY_EXTRAP_TYPE, CONSISTENT_TYPE_2_BDRY);

    std::vector<InterpolationTransactionComponent> U_P_MU_components(3);
    U_P_MU_components[0] = U_scratch_component;
    U_P_MU_components[1] = P_scratch_component;
    U_P_MU_components[2] = mu_component;

    d_U_P_MU_bdry_fill_op = new HierarchyGhostCellInterpolation();
    d_U_P_MU_bdry_fill_op->initializeOperatorState(U_P_MU_components, d_x_scratch->getPatchHierarchy());

    d_is_initialized = true;

    IBAMR_TIMER_STOP(t_initialize_operator_state);
    return;
}// initializeOperatorState
Beispiel #5
0
void
FACPreconditioner::initializeSolverState(
    const SAMRAIVectorReal<NDIM,double>& solution,
    const SAMRAIVectorReal<NDIM,double>& rhs)
{
    // Deallocate the solver state if the solver is already initialized.
    if (d_is_initialized)
    {
        deallocateSolverState();
    }

    // Setup operator state.
    d_hierarchy   = solution.getPatchHierarchy();
    d_coarsest_ln = solution.getCoarsestLevelNumber();
    d_finest_ln   = solution.getFinestLevelNumber();

#ifdef DEBUG_CHECK_ASSERTIONS
    TBOX_ASSERT(d_hierarchy   == rhs.getPatchHierarchy());
    TBOX_ASSERT(d_coarsest_ln == rhs.getCoarsestLevelNumber());
    TBOX_ASSERT(d_finest_ln   == rhs.getFinestLevelNumber());
#endif
    d_fac_strategy->initializeOperatorState(solution, rhs);

    // Create temporary vectors.
    if (!(d_cycle_type == V_CYCLE && d_num_pre_sweeps == 0))
    {
        d_f = rhs.cloneVector("");
        d_f->allocateVectorData();

        d_r = rhs.cloneVector("");
        d_r->allocateVectorData();
    }

    // Indicate the operator is initialized.
    d_is_initialized = true;
    return;
}// initializeSolverState
Beispiel #6
0
void GeneralOperator::applyAdd(SAMRAIVectorReal<NDIM, double>& x,
                               SAMRAIVectorReal<NDIM, double>& y,
                               SAMRAIVectorReal<NDIM, double>& z)
{
    // Guard against the case that y == z.
    Pointer<SAMRAIVectorReal<NDIM, double> > zz = z.cloneVector(z.getName());
    zz->allocateVectorData();
    zz->copyVector(Pointer<SAMRAIVectorReal<NDIM, double> >(&z, false));
    apply(x, *zz);
    z.add(Pointer<SAMRAIVectorReal<NDIM, double> >(&y, false), zz);
    zz->deallocateVectorData();
    zz->freeVectorComponents();
    zz.setNull();
    return;
} // applyAdd
Beispiel #7
0
void
LinearOperator::modifyRhsForBcs(SAMRAIVectorReal<NDIM, double>& y)
{
    if (d_homogeneous_bc) return;

    // Set y := y - A*0, i.e., shift the right-hand-side vector to account for
    // inhomogeneous boundary conditions.
    Pointer<SAMRAIVectorReal<NDIM, double> > x = y.cloneVector("");
    Pointer<SAMRAIVectorReal<NDIM, double> > b = y.cloneVector("");
    x->allocateVectorData();
    b->allocateVectorData();
    x->setToScalar(0.0);
    apply(*x, *b);
    y.subtract(Pointer<SAMRAIVectorReal<NDIM, double> >(&y, false), b);
    x->freeVectorComponents();
    b->freeVectorComponents();
    return;
} // modifyRhsForBcs
void StaggeredStokesOperator::initializeOperatorState(const SAMRAIVectorReal<NDIM, double>& in,
                                                      const SAMRAIVectorReal<NDIM, double>& out)
{
    IBAMR_TIMER_START(t_initialize_operator_state);

    // Deallocate the operator state if the operator is already initialized.
    if (d_is_initialized) deallocateOperatorState();

    // Setup solution and rhs vectors.
    d_x = in.cloneVector(in.getName());
    d_b = out.cloneVector(out.getName());
    d_x->allocateVectorData();

    // Setup the interpolation transaction information.
    d_U_fill_pattern = new SideNoCornersFillPattern(SIDEG, false, false, true);
    d_P_fill_pattern = new CellNoCornersFillPattern(CELLG, false, false, true);
    typedef HierarchyGhostCellInterpolation::InterpolationTransactionComponent InterpolationTransactionComponent;
    d_transaction_comps.resize(2);
    d_transaction_comps[0] = InterpolationTransactionComponent(d_x->getComponentDescriptorIndex(0),
                                                               in.getComponentDescriptorIndex(0),
                                                               DATA_REFINE_TYPE,
                                                               USE_CF_INTERPOLATION,
                                                               DATA_COARSEN_TYPE,
                                                               BDRY_EXTRAP_TYPE,
                                                               CONSISTENT_TYPE_2_BDRY,
                                                               d_U_bc_coefs,
                                                               d_U_fill_pattern);
    d_transaction_comps[1] = InterpolationTransactionComponent(in.getComponentDescriptorIndex(1),
                                                               DATA_REFINE_TYPE,
                                                               USE_CF_INTERPOLATION,
                                                               DATA_COARSEN_TYPE,
                                                               BDRY_EXTRAP_TYPE,
                                                               CONSISTENT_TYPE_2_BDRY,
                                                               d_P_bc_coef,
                                                               d_P_fill_pattern);

    // Initialize the interpolation operators.
    d_hier_bdry_fill = new HierarchyGhostCellInterpolation();
    d_hier_bdry_fill->initializeOperatorState(d_transaction_comps, d_x->getPatchHierarchy());

    // Initialize hierarchy math ops object.
    if (!d_hier_math_ops_external)
    {
        d_hier_math_ops = new HierarchyMathOps(d_object_name + "::HierarchyMathOps",
                                               in.getPatchHierarchy(),
                                               in.getCoarsestLevelNumber(),
                                               in.getFinestLevelNumber());
    }
#if !defined(NDEBUG)
    else
    {
        TBOX_ASSERT(d_hier_math_ops);
    }
#endif

    // Indicate the operator is initialized.
    d_is_initialized = true;

    IBAMR_TIMER_STOP(t_initialize_operator_state);
    return;
} // initializeOperatorState
Beispiel #9
0
void
FACPreconditioner::initializeSolverState(
   const SAMRAIVectorReal<double>& solution,
   const SAMRAIVectorReal<double>& rhs)
{
   /*
    * First get rid of current data.
    */
   deallocateSolverState();
   /*
    * Set hierarchy and levels to solve.
    */
   d_patch_hierarchy = solution.getPatchHierarchy();
   d_coarsest_ln = solution.getCoarsestLevelNumber();
   d_finest_ln = solution.getFinestLevelNumber();
   /*
    * Set the solution-vector-dependent scratch space.
    */
   d_error_vector = solution.cloneVector(d_object_name + "::error");
   d_error_vector->allocateVectorData();
   if (d_algorithm_choice == "mccormick-s4.3") {
      d_tmp_error = solution.cloneVector(d_object_name + "::temporary_error");
      d_tmp_error->allocateVectorData();
   }
   d_residual_vector = rhs.cloneVector(d_object_name + "::residual");
   d_residual_vector->allocateVectorData();
   d_tmp_residual = rhs.cloneVector(d_object_name + "::FAC coarser residual");
   d_tmp_residual->allocateVectorData();
   /*
    * Set the controlled level operators, which depend on the number
    * of components in the solution vector.
    */
   math::HierarchyDataOpsManager* ops_manager =
      math::HierarchyDataOpsManager::getManager();
   int num_components = solution.getNumberOfComponents();
   d_controlled_level_ops.resize(num_components);
   for (int i = 0; i < num_components; ++i) {
      d_controlled_level_ops[i] =
         ops_manager->getOperationsDouble(
            solution.getComponentVariable(i),
            d_patch_hierarchy,
            true);
      /*
       * Note: the variable used above is only for the purpose of determining
       * the variable alignment on the grid.  It is not specific to any
       * instance.
       */
   }
   /*
    * Error checking.
    */
#ifdef DEBUG_CHECK_ASSERTIONS
   if (d_patch_hierarchy != rhs.getPatchHierarchy()) {
      TBOX_ERROR(d_object_name << ": vectors must have the same hierarchy.\n");
   }
   if (d_coarsest_ln < 0) {
      TBOX_ERROR(d_object_name << ": coarsest level must not be negative.\n");
   }
   if (d_coarsest_ln > d_finest_ln) {
      TBOX_ERROR(d_object_name << ": coarsest level must be <= finest"
                               << "level.\n");
   }
#endif
   for (int ln = d_coarsest_ln; ln <= d_finest_ln; ++ln) {
      if (!d_patch_hierarchy->getPatchLevel(ln)) {
         TBOX_ERROR("FACPreconditioner::initializeSolverState error ..."
            << "\n   object name = " << d_object_name
            << "\n   hierarchy level " << ln
            << " does not exist" << std::endl);
      }
   }
   d_fac_operator->initializeOperatorState(solution, rhs);
}
void PETScNewtonKrylovSolver::initializeSolverState(const SAMRAIVectorReal<NDIM, double>& x,
                                                    const SAMRAIVectorReal<NDIM, double>& b)
{
    IBTK_TIMER_START(t_initialize_solver_state);

    int ierr;

// Rudimentary error checking.
#if !defined(NDEBUG)
    if (x.getNumberOfComponents() != b.getNumberOfComponents())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have the same number of components"
                                 << std::endl);
    }

    const Pointer<PatchHierarchy<NDIM> >& patch_hierarchy = x.getPatchHierarchy();
    if (patch_hierarchy != b.getPatchHierarchy())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have the same hierarchy" << std::endl);
    }

    const int coarsest_ln = x.getCoarsestLevelNumber();
    if (coarsest_ln < 0)
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  coarsest level number must not be negative"
                                 << std::endl);
    }
    if (coarsest_ln != b.getCoarsestLevelNumber())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have same coarsest level number"
                                 << std::endl);
    }

    const int finest_ln = x.getFinestLevelNumber();
    if (finest_ln < coarsest_ln)
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  finest level number must be >= coarsest level number"
                                 << std::endl);
    }
    if (finest_ln != b.getFinestLevelNumber())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have same finest level number"
                                 << std::endl);
    }

    for (int ln = coarsest_ln; ln <= finest_ln; ++ln)
    {
        if (!patch_hierarchy->getPatchLevel(ln))
        {
            TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                     << "  hierarchy level " << ln << " does not exist"
                                     << std::endl);
        }
    }
#endif
    // Deallocate the solver state if the solver is already initialized.
    if (d_is_initialized)
    {
        d_reinitializing_solver = true;
        deallocateSolverState();
    }

    // Create the SNES solver.
    if (d_managing_petsc_snes)
    {
        ierr = SNESCreate(d_petsc_comm, &d_petsc_snes);
        IBTK_CHKERRQ(ierr);
        resetSNESOptions();
    }
    else if (!d_petsc_snes)
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  cannot initialize solver state for wrapped PETSc SNES "
                                    "object if the wrapped object is NULL" << std::endl);
    }

    // Setup solution and rhs vectors.
    d_x = x.cloneVector(x.getName());
    d_petsc_x = PETScSAMRAIVectorReal::createPETScVector(d_x, d_petsc_comm);

    d_b = b.cloneVector(b.getName());
    d_petsc_b = PETScSAMRAIVectorReal::createPETScVector(d_b, d_petsc_comm);

    d_r = b.cloneVector(b.getName());
    d_petsc_r = PETScSAMRAIVectorReal::createPETScVector(d_r, d_petsc_comm);

    // Setup the nonlinear operator.
    if (d_F) d_F->initializeOperatorState(*d_x, *d_b);
    if (d_managing_petsc_snes || d_user_provided_function) resetSNESFunction();

    // Setup the Jacobian.
    if (d_J) d_J->initializeOperatorState(*d_x, *d_b);
    if (d_managing_petsc_snes || d_user_provided_jacobian) resetSNESJacobian();

    // Set the SNES options from the PETSc options database.
    if (d_options_prefix != "")
    {
        ierr = SNESSetOptionsPrefix(d_petsc_snes, d_options_prefix.c_str());
        IBTK_CHKERRQ(ierr);
    }
    ierr = SNESSetFromOptions(d_petsc_snes);
    IBTK_CHKERRQ(ierr);

    // Reset the member state variables to correspond to the values used by the
    // SNES object.  (Command-line options always take precedence.)
    ierr = SNESGetTolerances(d_petsc_snes,
                             &d_abs_residual_tol,
                             &d_rel_residual_tol,
                             &d_solution_tol,
                             &d_max_iterations,
                             &d_max_evaluations);
    IBTK_CHKERRQ(ierr);

    // Setup the KrylovLinearSolver wrapper to correspond to the KSP employed by
    // the SNES solver.
    KSP petsc_ksp;
    ierr = SNESGetKSP(d_petsc_snes, &petsc_ksp);
    IBTK_CHKERRQ(ierr);
    Pointer<PETScKrylovLinearSolver> p_krylov_solver = d_krylov_solver;
    if (p_krylov_solver) p_krylov_solver->resetWrappedKSP(petsc_ksp);

    // Setup the Krylov solver.
    if (d_krylov_solver) d_krylov_solver->initializeSolverState(*d_x, *d_b);

    // Indicate that the solver is initialized.
    d_reinitializing_solver = false;
    d_is_initialized = true;

    IBTK_TIMER_STOP(t_initialize_solver_state);
    return;
} // initializeSolverState
void PETScKrylovLinearSolver::initializeSolverState(const SAMRAIVectorReal<NDIM, double>& x,
                                                    const SAMRAIVectorReal<NDIM, double>& b)
{
    IBTK_TIMER_START(t_initialize_solver_state);

    int ierr;

// Rudimentary error checking.
#if !defined(NDEBUG)
    if (x.getNumberOfComponents() != b.getNumberOfComponents())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have the same number of components"
                                 << std::endl);
    }

    const Pointer<PatchHierarchy<NDIM> >& patch_hierarchy = x.getPatchHierarchy();
    if (patch_hierarchy != b.getPatchHierarchy())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have the same hierarchy" << std::endl);
    }

    const int coarsest_ln = x.getCoarsestLevelNumber();
    if (coarsest_ln < 0)
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  coarsest level number must not be negative"
                                 << std::endl);
    }
    if (coarsest_ln != b.getCoarsestLevelNumber())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have same coarsest level number"
                                 << std::endl);
    }

    const int finest_ln = x.getFinestLevelNumber();
    if (finest_ln < coarsest_ln)
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  finest level number must be >= coarsest level number"
                                 << std::endl);
    }
    if (finest_ln != b.getFinestLevelNumber())
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                 << "  vectors must have same finest level number"
                                 << std::endl);
    }

    for (int ln = coarsest_ln; ln <= finest_ln; ++ln)
    {
        if (!patch_hierarchy->getPatchLevel(ln))
        {
            TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                                     << "  hierarchy level " << ln << " does not exist"
                                     << std::endl);
        }
    }
#endif
    // Deallocate the solver state if the solver is already initialized.
    if (d_is_initialized)
    {
        d_reinitializing_solver = true;
        deallocateSolverState();
    }

    // Create the KSP solver.
    if (d_managing_petsc_ksp)
    {
        ierr = KSPCreate(d_petsc_comm, &d_petsc_ksp);
        IBTK_CHKERRQ(ierr);
        resetKSPOptions();
    }
    else if (!d_petsc_ksp)
    {
        TBOX_ERROR(d_object_name
                   << "::initializeSolverState()\n"
                   << "  cannot initialize solver state for wrapped PETSc KSP object "
                      "if the wrapped object is NULL" << std::endl);
    }

    // Setup solution and rhs vectors.
    d_x = x.cloneVector(x.getName());
    d_petsc_x = PETScSAMRAIVectorReal::createPETScVector(d_x, d_petsc_comm);

    d_b = b.cloneVector(b.getName());
    d_petsc_b = PETScSAMRAIVectorReal::createPETScVector(d_b, d_petsc_comm);

    // Initialize the linear operator and preconditioner objects.
    if (d_A) d_A->initializeOperatorState(*d_x, *d_b);
    if (d_managing_petsc_ksp || d_user_provided_mat) resetKSPOperators();

    if (d_pc_solver) d_pc_solver->initializeSolverState(*d_x, *d_b);
    if (d_managing_petsc_ksp || d_user_provided_pc) resetKSPPC();

    // Set the KSP options from the PETSc options database.
    if (d_options_prefix != "")
    {
        ierr = KSPSetOptionsPrefix(d_petsc_ksp, d_options_prefix.c_str());
        IBTK_CHKERRQ(ierr);
    }
    ierr = KSPSetFromOptions(d_petsc_ksp);
    IBTK_CHKERRQ(ierr);

    // Reset the member state variables to correspond to the values used by the
    // KSP object.  (Command-line options always take precedence.)
    const char* ksp_type;
    ierr = KSPGetType(d_petsc_ksp, &ksp_type);
    IBTK_CHKERRQ(ierr);
    d_ksp_type = ksp_type;
    PetscBool initial_guess_nonzero;
    ierr = KSPGetInitialGuessNonzero(d_petsc_ksp, &initial_guess_nonzero);
    IBTK_CHKERRQ(ierr);
    d_initial_guess_nonzero = (initial_guess_nonzero == PETSC_TRUE);
    ierr = KSPGetTolerances(
        d_petsc_ksp, &d_rel_residual_tol, &d_abs_residual_tol, NULL, &d_max_iterations);
    IBTK_CHKERRQ(ierr);

    // Configure the nullspace object.
    resetKSPNullspace();

    // Indicate that the solver is initialized.
    d_reinitializing_solver = false;
    d_is_initialized = true;

    IBTK_TIMER_STOP(t_initialize_solver_state);
    return;
} // initializeSolverState
bool BGaussSeidelPreconditioner::solveSystem(SAMRAIVectorReal<NDIM, double>& x, SAMRAIVectorReal<NDIM, double>& b)
{
    // Initialize the preconditioner, when necessary.
    const bool deallocate_after_solve = !d_is_initialized;
    if (deallocate_after_solve) initializeSolverState(x, b);

#if !defined(NDEBUG)
    Pointer<PatchHierarchy<NDIM> > hierarchy = x.getPatchHierarchy();
    const int coarsest_ln = x.getCoarsestLevelNumber();
    const int finest_ln = x.getFinestLevelNumber();
    TBOX_ASSERT(x.getNumberOfComponents() == b.getNumberOfComponents());
    TBOX_ASSERT(hierarchy == b.getPatchHierarchy());
    TBOX_ASSERT(coarsest_ln == b.getCoarsestLevelNumber());
    TBOX_ASSERT(finest_ln == b.getFinestLevelNumber());
#endif
    bool ret_val = true;

// Zero out the initial guess.
#if !defined(NDEBUG)
    TBOX_ASSERT(d_initial_guess_nonzero == false);
#endif
    x.setToScalar(0.0, /*interior_only*/ false);

    // Setup SAMRAIVectorReal objects to correspond to the individual vector
    // components.
    std::vector<Pointer<SAMRAIVectorReal<NDIM, double> > > x_comps =
        getComponentVectors(Pointer<SAMRAIVectorReal<NDIM, double> >(&x, false));
    std::vector<Pointer<SAMRAIVectorReal<NDIM, double> > > b_comps =
        getComponentVectors(Pointer<SAMRAIVectorReal<NDIM, double> >(&b, false));

    // Clone the right-hand-side vector to avoid modifying it during the
    // preconditioning operation.
    Pointer<SAMRAIVectorReal<NDIM, double> > f = b.cloneVector(b.getName());
    f->allocateVectorData();
    f->copyVector(Pointer<SAMRAIVectorReal<NDIM, double> >(&b, false), false);
    std::vector<Pointer<SAMRAIVectorReal<NDIM, double> > > f_comps = getComponentVectors(f);

    // Setup the order in which the component preconditioner are to be applied.
    const int ncomps = x.getNumberOfComponents();
    std::vector<int> comps;
    comps.reserve(2 * ncomps - 1);
    if (!d_reverse_order)
    {
        // Standard order: Run from comp = 0 to comp = ncomp-1.
        for (int comp = 0; comp < ncomps; ++comp)
        {
            comps.push_back(comp);
        }
        if (d_symmetric_preconditioner)
        {
            for (int comp = ncomps - 2; comp >= 0; --comp)
            {
                comps.push_back(comp);
            }
        }
    }
    else
    {
        // Reversed order: Run from comp = ncomp-1 to comp = 0.
        for (int comp = ncomps - 1; comp >= 0; --comp)
        {
            comps.push_back(comp);
        }
        if (d_symmetric_preconditioner)
        {
            for (int comp = 1; comp < ncomps; ++comp)
            {
                comps.push_back(comp);
            }
        }
    }

    // Apply the component preconditioners.
    int count = 0;
    for (std::vector<int>::const_iterator it = comps.begin(); it != comps.end(); ++it, ++count)
    {
        const int comp = (*it);

        Pointer<SAMRAIVectorReal<NDIM, double> > x_comp = x_comps[comp];
        Pointer<SAMRAIVectorReal<NDIM, double> > b_comp = b_comps[comp];
        Pointer<SAMRAIVectorReal<NDIM, double> > f_comp = f_comps[comp];

        // Update the right-hand-side vector.
        f_comp->setToScalar(0.0);
        for (int c = 0; c < ncomps; ++c)
        {
            if (c == comp) continue;
            d_linear_ops_map[comp][c]->applyAdd(*x_comps[c], *f_comp, *f_comp);
        }
        f_comp->subtract(b_comp, f_comp);

        // Configure the component preconditioner.
        Pointer<LinearSolver> pc_comp = d_pc_map[comp];
        pc_comp->setInitialGuessNonzero(count >= ncomps);
        pc_comp->setMaxIterations(d_max_iterations);
        pc_comp->setAbsoluteTolerance(d_abs_residual_tol);
        pc_comp->setRelativeTolerance(d_rel_residual_tol);

        // Apply the component preconditioner.
        const bool ret_val_comp = pc_comp->solveSystem(*x_comp, *f_comp);
        ret_val = ret_val && ret_val_comp;
    }

    // Free the copied right-hand-side vector data.
    f->deallocateVectorData();
    f->freeVectorComponents();

    // Deallocate the preconditioner, when necessary.
    if (deallocate_after_solve) deallocateSolverState();
    return ret_val;
} // solveSystem