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
void
INSCollocatedPPMConvectiveOperator::initializeOperatorState(
    const SAMRAIVectorReal<NDIM,double>& in,
    const SAMRAIVectorReal<NDIM,double>& out)
{
    IBAMR_TIMER_START(t_initialize_operator_state);

    if (d_is_initialized) deallocateOperatorState();

    // Get the hierarchy configuration.
    d_hierarchy = in.getPatchHierarchy();
    d_coarsest_ln = in.getCoarsestLevelNumber();
    d_finest_ln = in.getFinestLevelNumber();
#ifdef DEBUG_CHECK_ASSERTIONS
    TBOX_ASSERT(d_hierarchy == out.getPatchHierarchy());
    TBOX_ASSERT(d_coarsest_ln == out.getCoarsestLevelNumber());
    TBOX_ASSERT(d_finest_ln == out.getFinestLevelNumber());
#else
    NULL_USE(out);
#endif
    Pointer<CartesianGridGeometry<NDIM> > grid_geom = d_hierarchy->getGridGeometry();

    // Setup the coarsen algorithm, operator, and schedules.
    Pointer<CoarsenOperator<NDIM> > coarsen_op = grid_geom->lookupCoarsenOperator(d_u_flux_var, "CONSERVATIVE_COARSEN");
    d_coarsen_alg = new CoarsenAlgorithm<NDIM>();
    if (d_difference_form == ADVECTIVE    || d_difference_form == SKEW_SYMMETRIC) d_coarsen_alg->registerCoarsen(d_u_extrap_idx, d_u_extrap_idx, coarsen_op);
    if (d_difference_form == CONSERVATIVE || d_difference_form == SKEW_SYMMETRIC) d_coarsen_alg->registerCoarsen(d_u_flux_idx,   d_u_flux_idx,   coarsen_op);
    d_coarsen_scheds.resize(d_finest_ln+1);
    for (int ln = d_coarsest_ln+1; ln <= d_finest_ln; ++ln)
    {
        Pointer<PatchLevel<NDIM> >         level = d_hierarchy->getPatchLevel(ln  );
        Pointer<PatchLevel<NDIM> > coarser_level = d_hierarchy->getPatchLevel(ln-1);
        d_coarsen_scheds[ln] = d_coarsen_alg->createSchedule(coarser_level, level);
    }

    // Setup the refine algorithm, operator, patch strategy, and schedules.
    Pointer<RefineOperator<NDIM> > refine_op = grid_geom->lookupRefineOperator(d_U_var, "CONSERVATIVE_LINEAR_REFINE");
    d_ghostfill_alg = new RefineAlgorithm<NDIM>();
    d_ghostfill_alg->registerRefine(d_U_scratch_idx, in.getComponentDescriptorIndex(0), d_U_scratch_idx, refine_op);
    d_ghostfill_strategy = new CartExtrapPhysBdryOp(d_U_scratch_idx, d_bdry_extrap_type);
    d_ghostfill_scheds.resize(d_finest_ln+1);
    for (int ln = d_coarsest_ln; ln <= d_finest_ln; ++ln)
    {
        Pointer<PatchLevel<NDIM> > level = d_hierarchy->getPatchLevel(ln);
        d_ghostfill_scheds[ln] = d_ghostfill_alg->createSchedule(level, ln-1, d_hierarchy, d_ghostfill_strategy);
    }

    // Allocate scratch data.
    for (int ln = d_coarsest_ln; ln <= d_finest_ln; ++ln)
    {
        Pointer<PatchLevel<NDIM> > level = d_hierarchy->getPatchLevel(ln);
        if (!level->checkAllocated(d_U_scratch_idx))
        {
            level->allocatePatchData(d_U_scratch_idx);
            level->allocatePatchData(d_u_extrap_idx);
            if (d_difference_form == CONSERVATIVE || d_difference_form == SKEW_SYMMETRIC) level->allocatePatchData(d_u_flux_idx);
        }
    }
    d_is_initialized = true;

    IBAMR_TIMER_STOP(t_initialize_operator_state);
    return;
}// initializeOperatorState
void StaggeredStokesOperator::apply(SAMRAIVectorReal<NDIM, double>& x, SAMRAIVectorReal<NDIM, double>& y)
{
    IBAMR_TIMER_START(t_apply);

    // Get the vector components.
    const int U_idx = x.getComponentDescriptorIndex(0);
    const int P_idx = x.getComponentDescriptorIndex(1);
    const int A_U_idx = y.getComponentDescriptorIndex(0);
    const int A_P_idx = y.getComponentDescriptorIndex(1);
    const int U_scratch_idx = d_x->getComponentDescriptorIndex(0);

    Pointer<SideVariable<NDIM, double> > U_sc_var = x.getComponentVariable(0);
    Pointer<CellVariable<NDIM, double> > P_cc_var = x.getComponentVariable(1);
    Pointer<SideVariable<NDIM, double> > A_U_sc_var = y.getComponentVariable(0);
    Pointer<CellVariable<NDIM, double> > A_P_cc_var = y.getComponentVariable(1);

    // Simultaneously fill ghost cell values for all components.
    typedef HierarchyGhostCellInterpolation::InterpolationTransactionComponent InterpolationTransactionComponent;
    std::vector<InterpolationTransactionComponent> transaction_comps(2);
    transaction_comps[0] = InterpolationTransactionComponent(U_scratch_idx,
                                                             U_idx,
                                                             DATA_REFINE_TYPE,
                                                             USE_CF_INTERPOLATION,
                                                             DATA_COARSEN_TYPE,
                                                             BDRY_EXTRAP_TYPE,
                                                             CONSISTENT_TYPE_2_BDRY,
                                                             d_U_bc_coefs,
                                                             d_U_fill_pattern);
    transaction_comps[1] = InterpolationTransactionComponent(P_idx,
                                                             DATA_REFINE_TYPE,
                                                             USE_CF_INTERPOLATION,
                                                             DATA_COARSEN_TYPE,
                                                             BDRY_EXTRAP_TYPE,
                                                             CONSISTENT_TYPE_2_BDRY,
                                                             d_P_bc_coef,
                                                             d_P_fill_pattern);
    d_hier_bdry_fill->resetTransactionComponents(transaction_comps);
    d_hier_bdry_fill->setHomogeneousBc(d_homogeneous_bc);
    StaggeredStokesPhysicalBoundaryHelper::setupBcCoefObjects(
        d_U_bc_coefs, d_P_bc_coef, U_scratch_idx, P_idx, d_homogeneous_bc);
    d_hier_bdry_fill->fillData(d_solution_time);
    StaggeredStokesPhysicalBoundaryHelper::resetBcCoefObjects(d_U_bc_coefs, d_P_bc_coef);
    //  d_bc_helper->enforceDivergenceFreeConditionAtBoundary(U_scratch_idx);
    d_hier_bdry_fill->resetTransactionComponents(d_transaction_comps);

    // Compute the action of the operator:
    //
    // A*[U;P] := [A_U;A_P] = [(C*I+D*L)*U + Grad P; -Div U]
    d_hier_math_ops->grad(A_U_idx,
                          A_U_sc_var,
                          /*cf_bdry_synch*/ false,
                          1.0,
                          P_idx,
                          P_cc_var,
                          d_no_fill,
                          d_new_time);
    d_hier_math_ops->laplace(A_U_idx,
                             A_U_sc_var,
                             d_U_problem_coefs,
                             U_scratch_idx,
                             U_sc_var,
                             d_no_fill,
                             d_new_time,
                             1.0,
                             A_U_idx,
                             A_U_sc_var);
    d_hier_math_ops->div(A_P_idx,
                         A_P_cc_var,
                         -1.0,
                         U_scratch_idx,
                         U_sc_var,
                         d_no_fill,
                         d_new_time,
                         /*cf_bdry_synch*/ true);
    d_bc_helper->copyDataAtDirichletBoundaries(A_U_idx, U_scratch_idx);

    IBAMR_TIMER_STOP(t_apply);
    return;
} // apply
void
IBImplicitModHelmholtzPETScLevelSolver::initializeSolverState(
    const SAMRAIVectorReal<NDIM,double>& x,
    const SAMRAIVectorReal<NDIM,double>& b)
{
    IBAMR_TIMER_START(t_initialize_solver_state);

    // Rudimentary error checking.
#ifdef DEBUG_CHECK_ASSERTIONS
    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).isNull())
        {
            TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                       << "  hierarchy level " << ln << " does not exist" << std::endl);
        }
    }

    if (coarsest_ln != finest_ln)
    {
        TBOX_ERROR(d_object_name << "::initializeSolverState()\n"
                   << "  coarsest_ln != finest_ln in IBImplicitModHelmholtzPETScLevelSolver" << std::endl);
    }
#endif
    // Deallocate the solver state if the solver is already initialized.
    if (d_is_initialized) deallocateSolverState();

    // Get the hierarchy information.
    d_hierarchy = x.getPatchHierarchy();
    d_level_num = x.getCoarsestLevelNumber();
#ifdef DEBUG_CHECK_ASSERTIONS
    TBOX_ASSERT(d_level_num == x.getFinestLevelNumber());
#endif

    const int x_idx = x.getComponentDescriptorIndex(0);
    Pointer<SideVariable<NDIM,double> > x_var = x.getComponentVariable(0);
    const int b_idx = b.getComponentDescriptorIndex(0);
    Pointer<SideVariable<NDIM,double> > b_var = b.getComponentVariable(0);

    // Allocate DOF index data.
    VariableDatabase<NDIM>* var_db = VariableDatabase<NDIM>::getDatabase();
    Pointer<SideDataFactory<NDIM,double> > x_fac =
        var_db->getPatchDescriptor()->getPatchDataFactory(x_idx);
    const int depth = x_fac->getDefaultDepth();
    Pointer<SideDataFactory<NDIM,int> > dof_index_fac =
        var_db->getPatchDescriptor()->getPatchDataFactory(d_dof_index_idx);
    dof_index_fac->setDefaultDepth(depth);
    Pointer<PatchLevel<NDIM> > level = d_hierarchy->getPatchLevel(d_level_num);
    if (!level->checkAllocated(d_dof_index_idx)) level->allocatePatchData(d_dof_index_idx);

    // Setup PETSc objects.
    int ierr;
    PETScVecUtilities::constructPatchLevelVec(d_petsc_x, x_idx, x_var, level);
    PETScVecUtilities::constructPatchLevelVec(d_petsc_b, b_idx, b_var, level);
    PETScVecUtilities::constructPatchLevelDOFIndices(d_dof_index_idx, d_dof_index_var, x_idx, x_var, level);
    const double C = d_poisson_spec.cIsZero() ? 0.0 : d_poisson_spec.getCConstant();
    const double D = d_poisson_spec.getDConstant();
    PETScMatUtilities::constructPatchLevelLaplaceOp(d_petsc_mat, C, D, x_idx, x_var, d_dof_index_idx, d_dof_index_var, level, d_dof_index_fill);
    if (d_SJR_mat != PETSC_NULL)
    {
        ierr = PETScMatOps::MatAXPY(d_petsc_mat, 1.0, d_SJR_mat); IBTK_CHKERRQ(ierr);
    }
    ierr = MatSetBlockSize(d_petsc_mat, NDIM); IBTK_CHKERRQ(ierr);

    ierr = KSPCreate(PETSC_COMM_WORLD, &d_petsc_ksp); IBTK_CHKERRQ(ierr);
    ierr = KSPSetOperators(d_petsc_ksp, d_petsc_mat, d_petsc_mat, SAME_PRECONDITIONER); IBTK_CHKERRQ(ierr);
    if (!d_options_prefix.empty())
    {
        ierr = KSPSetOptionsPrefix(d_petsc_ksp, d_options_prefix.c_str()); IBTK_CHKERRQ(ierr);
    }
    ierr = KSPSetFromOptions(d_petsc_ksp); IBTK_CHKERRQ(ierr);

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

    IBAMR_TIMER_STOP(t_initialize_solver_state);
    return;
}// initializeSolverState
Пример #5
0
void
FACPreconditioner::facCycle_McCormick(
   SAMRAIVectorReal<double>& e,
   SAMRAIVectorReal<double>& r,
   SAMRAIVectorReal<double>& u,
   int lmax,
   int lmin,
   int ln)
{

   /*
    * The steps 1-4 in this function correspond to McCormick's steps
    * those in his description.
    *
    * 1. If on the coarsest level, solve it.
    * 2. Presmoothing.
    * 3. Recurse to next lower level.
    * 4. Postsmoothing.
    */

   /*
    * Step 1.
    */
   if (ln == lmin) {
      /*
       * Solve coarsest level.
       */
      d_fac_operator->solveCoarsestLevel(e,
         r,
         ln);
   } else {

      int i, num_components = e.getNumberOfComponents();

      /*
       * Step 2a.
       */
      d_fac_operator->computeCompositeResidualOnLevel(*d_tmp_residual,
         e,
         r,
         ln,
         true);
      for (i = 0; i < num_components; ++i) {
         int tmp_id = d_tmp_error->getComponentDescriptorIndex(i);
         d_controlled_level_ops[i]->resetLevels(ln,
            ln);
         d_controlled_level_ops[i]->setToScalar(tmp_id,
            0.0);
      }
      /*
       * Step 2b.
       */
      d_fac_operator->smoothError(*d_tmp_error,
         *d_tmp_residual,
         ln,
         d_presmoothing_sweeps);
      /*
       * Step 2c.
       */
      for (i = 0; i < num_components; ++i) {
         int tmp_id = d_tmp_error->getComponentDescriptorIndex(i);
         int id = e.getComponentDescriptorIndex(i);
         d_controlled_level_ops[i]->resetLevels(ln,
            ln);
         d_controlled_level_ops[i]->add(id,
            id,
            tmp_id);
      }
      /*
       * Step 3a.
       */
      d_fac_operator->computeCompositeResidualOnLevel(*d_tmp_residual,
         e,
         r,
         ln,
         true);
      d_fac_operator->restrictResidual(*d_tmp_residual,
         *d_tmp_residual,
         ln - 1);
      /*
       * Step 3b.
       */
      for (i = 0; i < num_components; ++i) {
         int tmp_id = e.getComponentDescriptorIndex(i);
         d_controlled_level_ops[i]->resetLevels(ln - 1,
            ln - 1);
         d_controlled_level_ops[i]->setToScalar(tmp_id,
            0.0);
      }
      /*
       * Step 3c.
       */
      facCycle_McCormick(e,
         r,
         u,
         lmax,
         lmin,
         ln - 1);
      /*
       * Step 3d.
       */
      d_fac_operator->prolongErrorAndCorrect(e,
         e,
         ln);
      /*
       * Step 4a.
       */
      d_fac_operator->computeCompositeResidualOnLevel(*d_tmp_residual,
         e,
         r,
         ln,
         true);
      for (i = 0; i < num_components; ++i) {
         int tmp_id = d_tmp_error->getComponentDescriptorIndex(i);
         d_controlled_level_ops[i]->resetLevels(ln,
            ln);
         d_controlled_level_ops[i]->setToScalar(tmp_id,
            0.0);
      }
      /*
       * Step 4b.
       */
      d_fac_operator->smoothError(*d_tmp_error,
         *d_tmp_residual,
         ln,
         d_postsmoothing_sweeps);
      /*
       * Step 4c.
       */
      for (i = 0; i < num_components; ++i) {
         int tmp_id = d_tmp_error->getComponentDescriptorIndex(i);
         int id = e.getComponentDescriptorIndex(i);
         d_controlled_level_ops[i]->resetLevels(ln,
            ln);
         d_controlled_level_ops[i]->add(id,
            id,
            tmp_id);
      }

   }
}
Пример #6
0
bool
FACPreconditioner::solveSystem(
   SAMRAIVectorReal<double>& u,
   SAMRAIVectorReal<double>& f)
{

   d_residual_norm = tbox::MathUtilities<double>::getSignalingNaN();
   d_avg_convergence_factor = tbox::MathUtilities<double>::getSignalingNaN();

   /*
    * Set the solution-vector-dependent data if not preset.
    */
   bool clear_hierarchy_configuration_when_done = false;
   if (!d_patch_hierarchy) {
      clear_hierarchy_configuration_when_done = true;
      initializeSolverState(u, f);
   } else {
#ifdef DEBUG_CHECK_ASSERTIONS
      if (!checkVectorStateCompatibility(u, f)) {
         TBOX_ERROR(d_object_name << ": Incompatible vectors for\n"
                                  << "current state in solveSystem.\n");
      }
#endif
   }

   t_solve_system->start();

   d_error_vector->setToScalar(0.0, false);
   if (d_tmp_error) {
      d_tmp_error->setToScalar(0.0, false);
   }
   d_residual_vector->setToScalar(0.0);

   const double initial_residual_norm = d_residual_norm =
         computeFullCompositeResidual(*d_residual_vector,
            u,
            f);
   /*
    * Above step has the side effect of filling the residual
    * vector d_residual_vector.
    */

   double effective_residual_tolerance = d_residual_tolerance;
   if (d_relative_residual_tolerance >= 0) {
      double tmp = d_fac_operator->computeResidualNorm(f,
            d_finest_ln,
            d_coarsest_ln);
      tmp *= d_relative_residual_tolerance;
      if (effective_residual_tolerance < tmp) effective_residual_tolerance =
            tmp;
   }

   if (static_cast<int>(d_convergence_factor.size()) < d_max_iterations)
      d_convergence_factor.resize(d_max_iterations);
   d_number_iterations = 0;
   /*
    * Use a do loop instead of a while loop until convergence.
    * It is important to go through the loop at least once
    * because the residual norm can be less than the tolerance
    * when the solution is 0 and the rhs is less than the tolerance.
    */
   do {

      /*
       * In zeroing the error vector, also zero out the ghost values.
       * This gives the FAC operator an oportunity to bypass the
       * ghost filling if it decides that the ghost values do not
       * change.
       */
      d_error_vector->setToScalar(0.0, false);
      /*
       * Both the recursive and non-recursive fac cycling functions
       * were coded to find the problem due presmoothing.  Both give
       * the same results, but the problem due to presmoothing still
       * exists.  BTNG.
       */
      if (d_algorithm_choice == "default") {
         facCycle_Recursive(*d_error_vector,
            *d_residual_vector,
            u,
            d_finest_ln,
            d_coarsest_ln,
            d_finest_ln);
      } else if (d_algorithm_choice == "mccormick-s4.3") {
         facCycle_McCormick(*d_error_vector,
            *d_residual_vector,
            u,
            d_finest_ln,
            d_coarsest_ln,
            d_finest_ln);
      } else if (d_algorithm_choice == "pernice") {
         facCycle(*d_error_vector,
            *d_residual_vector,
            u,
            d_finest_ln,
            d_coarsest_ln);
      }

      int i, num_components = d_error_vector->getNumberOfComponents();
      /*
       * u += e
       */
      for (i = 0; i < num_components; ++i) {
         int soln_id = u.getComponentDescriptorIndex(i);
         int err_id = d_error_vector->getComponentDescriptorIndex(i);
         d_controlled_level_ops[i]->resetLevels(d_coarsest_ln, d_finest_ln);
         d_controlled_level_ops[i]->add(soln_id,
            soln_id,
            err_id);
      }

      /*
       * Synchronize solution across levels by coarsening the
       * more accurate fine-level solutions.
       */
      for (int ln = d_finest_ln - 1; ln >= d_coarsest_ln; --ln) {
         d_fac_operator->restrictSolution(u,
            u,
            ln);
      }

      /*
       * Compute convergence factor and new residual norm.
       * 1. Temporarily save pre-cycle residual norm in
       *    convergence factor stack.
       * 2. Compute post-cycle residual norm.
       * 3. Set convergence factor to ratio of post-cycle to pre-cycle
       *    residual norms.
       */
      d_convergence_factor[d_number_iterations] = d_residual_norm;
      d_residual_norm = computeFullCompositeResidual(*d_residual_vector,
            u,
            f);

// Disable Intel warning on real comparison
#ifdef __INTEL_COMPILER
#pragma warning (disable:1572)
#endif
      if (d_convergence_factor[d_number_iterations] != 0) {
         d_convergence_factor[d_number_iterations] =
            d_residual_norm / d_convergence_factor[d_number_iterations];
      } else {
         d_convergence_factor[d_number_iterations] = 0;
      }

      /*
       * Increment the iteration counter.
       * The rest of this block expects it to have the incremented value.
       * In particular, d_fac_operator->postprocessOneCycle does.
       */
      ++d_number_iterations;

      /*
       * Compute the convergence factors because they may be accessed
       * from the operator's postprocessOneCycle function.
       */
      d_net_convergence_factor = d_residual_norm
         / (initial_residual_norm + 1e-20);
      d_avg_convergence_factor = pow(d_net_convergence_factor,
            1.0 / d_number_iterations);

      d_fac_operator->postprocessOneCycle(d_number_iterations - 1,
         u,
         *d_residual_vector);

   } while ((d_residual_norm > effective_residual_tolerance)
            && (d_number_iterations < d_max_iterations));

   t_solve_system->stop();

   if (clear_hierarchy_configuration_when_done) {
      deallocateSolverState();
   }

   return d_residual_norm < effective_residual_tolerance;

}
void
INSStaggeredVCStokesOperator::apply(
    const bool /*homogeneous_bc*/,
    SAMRAIVectorReal<NDIM,double>& x,
    SAMRAIVectorReal<NDIM,double>& y)
{
    IBAMR_TIMER_START(t_apply);

    // Get the vector components.
//  const int U_in_idx       =            x.getComponentDescriptorIndex(0);
//  const int P_in_idx       =            x.getComponentDescriptorIndex(1);
    const int U_out_idx      =            y.getComponentDescriptorIndex(0);
    const int P_out_idx      =            y.getComponentDescriptorIndex(1);
    const int U_scratch_idx  = d_x_scratch->getComponentDescriptorIndex(0);
    const int P_scratch_idx  = d_x_scratch->getComponentDescriptorIndex(1);

    const Pointer<Variable<NDIM> >& U_out_var = y.getComponentVariable(0);
    const Pointer<Variable<NDIM> >& P_out_var = y.getComponentVariable(1);

    Pointer<SideVariable<NDIM,double> > U_out_sc_var = U_out_var;
    Pointer<CellVariable<NDIM,double> > P_out_cc_var = P_out_var;

    const Pointer<Variable<NDIM> >& U_scratch_var = d_x_scratch->getComponentVariable(0);
    const Pointer<Variable<NDIM> >& P_scratch_var = d_x_scratch->getComponentVariable(1);

    Pointer<SideVariable<NDIM,double> > U_scratch_sc_var = U_scratch_var;
    Pointer<CellVariable<NDIM,double> > P_scratch_cc_var = P_scratch_var;

    d_x_scratch->copyVector(Pointer<SAMRAIVectorReal<NDIM,double> >(&x,false));

    // Reset the interpolation operators and fill the data.
    typedef HierarchyGhostCellInterpolation::InterpolationTransactionComponent InterpolationTransactionComponent;
    InterpolationTransactionComponent U_scratch_component(U_scratch_idx, U_DATA_COARSEN_TYPE, BDRY_EXTRAP_TYPE, CONSISTENT_TYPE_2_BDRY);
    InterpolationTransactionComponent P_scratch_component(P_scratch_idx, 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->resetTransactionComponents(U_P_MU_components);
    d_U_P_MU_bdry_fill_op->fillData(d_new_time);

    // Setup hierarchy data ops object for U.
    HierarchyDataOpsManager<NDIM>* hier_ops_manager = HierarchyDataOpsManager<NDIM>::getManager();
    Pointer<PatchHierarchy<NDIM> > hierarchy = y.getPatchHierarchy();
    Pointer<HierarchySideDataOpsReal<NDIM,double> > hier_sc_data_ops =
        hier_ops_manager->getOperationsDouble(U_out_var, hierarchy, true);

    // Compute the action of the operator:
    //      A*[u;p] = [(rho/dt)*u-0.5*div*(mu*(grad u + (grad u)^T)) + grad p; -div u].
    //
    static const bool cf_bdry_synch = true;

    d_hier_math_ops->pointwiseMultiply(
	U_out_idx, U_out_sc_var,
        d_rho_data_idx, d_rho_var,
        U_scratch_idx, U_scratch_sc_var,
        0.0, -1, NULL);

    d_hier_math_ops->vc_laplace(
        U_out_idx, U_out_sc_var,
        -0.5, 0.0, d_mu_data_idx, d_mu_var,
        U_scratch_idx, U_scratch_sc_var, d_no_fill_op, d_new_time,
        1.0/d_dt, U_out_idx, U_out_sc_var);

    d_hier_math_ops->grad(
        U_out_idx, U_out_sc_var,
        cf_bdry_synch,
        1.0, P_scratch_idx, P_scratch_cc_var, d_no_fill_op, d_new_time,
        1.0, U_out_idx, U_out_sc_var);

    d_hier_math_ops->div(
        P_out_idx, P_out_cc_var,
        -1.0, U_scratch_idx, U_scratch_sc_var, d_no_fill_op, d_new_time,
        cf_bdry_synch);

    IBAMR_TIMER_STOP(t_apply);
    return;
}// apply
bool
StaggeredStokesProjectionPreconditioner::solveSystem(SAMRAIVectorReal<NDIM, double>& x,
                                                     SAMRAIVectorReal<NDIM, double>& b)
{
    IBAMR_TIMER_START(t_solve_system);

    // Initialize the solver (if necessary).
    const bool deallocate_at_completion = !d_is_initialized;
    if (!d_is_initialized) initializeSolverState(x, b);

    // Determine whether we are solving a steady-state problem.
    const bool steady_state =
        d_U_problem_coefs.cIsZero() ||
        (d_U_problem_coefs.cIsConstant() && MathUtilities<double>::equalEps(d_U_problem_coefs.getCConstant(), 0.0));

    // Get the vector components.
    const int F_U_idx = b.getComponentDescriptorIndex(0);
    const int F_P_idx = b.getComponentDescriptorIndex(1);

    const Pointer<Variable<NDIM> >& F_U_var = b.getComponentVariable(0);
    const Pointer<Variable<NDIM> >& F_P_var = b.getComponentVariable(1);

    Pointer<SideVariable<NDIM, double> > F_U_sc_var = F_U_var;
    Pointer<CellVariable<NDIM, double> > F_P_cc_var = F_P_var;

    const int U_idx = x.getComponentDescriptorIndex(0);
    const int P_idx = x.getComponentDescriptorIndex(1);

    const Pointer<Variable<NDIM> >& U_var = x.getComponentVariable(0);
    const Pointer<Variable<NDIM> >& P_var = x.getComponentVariable(1);

    Pointer<SideVariable<NDIM, double> > U_sc_var = U_var;
    Pointer<CellVariable<NDIM, double> > P_cc_var = P_var;

    // Setup the component solver vectors.
    Pointer<SAMRAIVectorReal<NDIM, double> > F_U_vec;
    F_U_vec = new SAMRAIVectorReal<NDIM, double>(d_object_name + "::F_U", d_hierarchy, d_coarsest_ln, d_finest_ln);
    F_U_vec->addComponent(F_U_sc_var, F_U_idx, d_velocity_wgt_idx, d_velocity_data_ops);

    Pointer<SAMRAIVectorReal<NDIM, double> > U_vec;
    U_vec = new SAMRAIVectorReal<NDIM, double>(d_object_name + "::U", d_hierarchy, d_coarsest_ln, d_finest_ln);
    U_vec->addComponent(U_sc_var, U_idx, d_velocity_wgt_idx, d_velocity_data_ops);

    Pointer<SAMRAIVectorReal<NDIM, double> > Phi_scratch_vec;
    Phi_scratch_vec =
        new SAMRAIVectorReal<NDIM, double>(d_object_name + "::Phi_scratch", d_hierarchy, d_coarsest_ln, d_finest_ln);
    Phi_scratch_vec->addComponent(d_Phi_var, d_Phi_scratch_idx, d_pressure_wgt_idx, d_pressure_data_ops);

    Pointer<SAMRAIVectorReal<NDIM, double> > F_Phi_vec;
    F_Phi_vec = new SAMRAIVectorReal<NDIM, double>(d_object_name + "::F_Phi", d_hierarchy, d_coarsest_ln, d_finest_ln);
    F_Phi_vec->addComponent(d_F_Phi_var, d_F_Phi_idx, d_pressure_wgt_idx, d_pressure_data_ops);

    Pointer<SAMRAIVectorReal<NDIM, double> > P_vec;
    P_vec = new SAMRAIVectorReal<NDIM, double>(d_object_name + "::P", d_hierarchy, d_coarsest_ln, d_finest_ln);
    P_vec->addComponent(P_cc_var, P_idx, d_pressure_wgt_idx, d_pressure_data_ops);

    // Allocate scratch data.
    for (int ln = d_coarsest_ln; ln <= d_finest_ln; ++ln)
    {
        Pointer<PatchLevel<NDIM> > level = d_hierarchy->getPatchLevel(ln);
        level->allocatePatchData(d_Phi_scratch_idx);
        level->allocatePatchData(d_F_Phi_idx);
    }

    // (1) Solve the velocity sub-problem for an initial approximation to U.
    //
    // U^* := inv(rho/dt - K*mu*L) F_U
    //
    // An approximate Helmholtz solver is used.
    d_velocity_solver->setHomogeneousBc(true);
    LinearSolver* p_velocity_solver = dynamic_cast<LinearSolver*>(d_velocity_solver.getPointer());
    if (p_velocity_solver) p_velocity_solver->setInitialGuessNonzero(false);
    d_velocity_solver->solveSystem(*U_vec, *F_U_vec);

    // (2) Solve the pressure sub-problem.
    //
    // We treat two cases:
    //
    // (i) rho/dt = 0.
    //
    // In this case,
    //
    //    U - U^* + G Phi = 0
    //    -D U = F_P
    //
    // so that
    //
    //    Phi := inv(-L_p) * F_Phi = inv(-L_p) * (-F_P - D U^*)
    //    P   := -K*mu*F_Phi
    //
    // in which L_p = D*G.
    //
    // (ii) rho/dt != 0.
    //
    // In this case,
    //
    //    rho (U - U^*) + G Phi = 0
    //    -D U = F_P
    //
    // so that
    //
    //    Phi := inv(-L_rho) * F_phi = inv(-L_rho) * (-F_P - D U^*)
    //    P   := (1/dt - K*mu*L_rho)*Phi = (1/dt) Phi - K*mu*F_phi
    //
    // in which L_rho = D*(1/rho)*G.
    //
    // Approximate Poisson solvers are used in both cases.
    d_hier_math_ops->div(d_F_Phi_idx,
                         d_F_Phi_var,
                         -1.0,
                         U_idx,
                         U_sc_var,
                         d_no_fill_op,
                         d_new_time,
                         /*cf_bdry_synch*/ true,
                         -1.0,
                         F_P_idx,
                         F_P_cc_var);
    d_pressure_solver->setHomogeneousBc(true);
    LinearSolver* p_pressure_solver = dynamic_cast<LinearSolver*>(d_pressure_solver.getPointer());
    p_pressure_solver->setInitialGuessNonzero(false);
    d_pressure_solver->solveSystem(*Phi_scratch_vec, *F_Phi_vec);
    if (steady_state)
    {
        d_pressure_data_ops->scale(P_idx, -d_U_problem_coefs.getDConstant(), d_F_Phi_idx);
    }
    else
    {
        d_pressure_data_ops->linearSum(
            P_idx, 1.0 / getDt(), d_Phi_scratch_idx, -d_U_problem_coefs.getDConstant(), d_F_Phi_idx);
    }

    // (3) Evaluate U in terms of U^* and Phi.
    //
    // We treat two cases:
    //
    // (i) rho = 0.  In this case,
    //
    //    U = U^* - G Phi
    //
    // (ii) rho != 0.  In this case,
    //
    //    U = U^* - (1.0/rho) G Phi
    double coef;
    if (steady_state)
    {
        coef = -1.0;
    }
    else
    {
        coef = d_P_problem_coefs.getDConstant();
    }
    d_hier_math_ops->grad(U_idx,
                          U_sc_var,
                          /*cf_bdry_synch*/ true,
                          coef,
                          d_Phi_scratch_idx,
                          d_Phi_var,
                          d_Phi_bdry_fill_op,
                          d_pressure_solver->getSolutionTime(),
                          1.0,
                          U_idx,
                          U_sc_var);

    // Account for nullspace vectors.
    correctNullspace(U_vec, P_vec);

    // Deallocate scratch data.
    for (int ln = d_coarsest_ln; ln <= d_finest_ln; ++ln)
    {
        Pointer<PatchLevel<NDIM> > level = d_hierarchy->getPatchLevel(ln);
        level->deallocatePatchData(d_Phi_scratch_idx);
        level->deallocatePatchData(d_F_Phi_idx);
    }

    // Deallocate the solver (if necessary).
    if (deallocate_at_completion) deallocateSolverState();

    IBAMR_TIMER_STOP(t_solve_system);
    return true;
} // solveSystem