[cig-commits] commit: Change CellStokes* to Stokes* for filenames
Mercurial
hg at geodynamics.org
Fri Feb 25 14:12:49 PST 2011
changeset: 13:fe2a9230921b
user: Walter Landry <wlandry at caltech.edu>
date: Fri Dec 31 12:10:26 2010 -0800
files: CellStokesFACOps.C CellStokesFACOps.I CellStokesFACOps.h CellStokesFACSolver.C CellStokesFACSolver.I CellStokesFACSolver.h CellStokesHypreSolver.C CellStokesHypreSolver.I CellStokesHypreSolver.h FACStokes.h Makefile StokesFACOps.C StokesFACOps.I StokesFACOps.h StokesFACSolver.C StokesFACSolver.I StokesFACSolver.h StokesHypreSolver.C StokesHypreSolver.I StokesHypreSolver.h
description:
Change CellStokes* to Stokes* for filenames
diff -r a44a82f15794 -r fe2a9230921b CellStokesFACOps.C
--- a/CellStokesFACOps.C Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2830 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: Operator class for cell-centered scalar Stokes using FAC
- *
- ************************************************************************/
-#ifndef included_solv_CellStokesFACOps_C
-#define included_solv_CellStokesFACOps_C
-
-#include "CellStokesFACOps.h"
-
-#include IOMANIP_HEADER_FILE
-
-#include "SAMRAI/hier/BoundaryBoxUtils.h"
-#include "SAMRAI/geom/CartesianGridGeometry.h"
-#include "SAMRAI/geom/CartesianPatchGeometry.h"
-#include "SAMRAI/hier/Index.h"
-#include "SAMRAI/hier/Variable.h"
-#include "SAMRAI/hier/VariableDatabase.h"
-#include "SAMRAI/pdat/CellDoubleConstantRefine.h"
-#include "SAMRAI/pdat/CellVariable.h"
-#include "SAMRAI/pdat/OutersideData.h"
-#include "SAMRAI/pdat/OutersideVariable.h"
-#include "SAMRAI/hier/PatchData.h"
-#include "SAMRAI/pdat/SideVariable.h"
-#include "SAMRAI/solv/FACPreconditioner.h"
-#include "CellStokesHypreSolver.h"
-#include "SAMRAI/tbox/Array.h"
-#include "SAMRAI/tbox/MathUtilities.h"
-#include "SAMRAI/tbox/StartupShutdownManager.h"
-#include "SAMRAI/tbox/Timer.h"
-#include "SAMRAI/tbox/TimerManager.h"
-#include "SAMRAI/tbox/Utilities.h"
-#include "SAMRAI/tbox/MathUtilities.h"
-#include "SAMRAI/xfer/CoarsenAlgorithm.h"
-#include "SAMRAI/xfer/CoarsenOperator.h"
-#include "SAMRAI/xfer/CoarsenSchedule.h"
-#include "SAMRAI/xfer/RefineAlgorithm.h"
-#include "SAMRAI/xfer/RefineOperator.h"
-#include "SAMRAI/xfer/RefineSchedule.h"
-#include "SAMRAI/xfer/PatchLevelFullFillPattern.h"
-
-#ifndef SAMRAI_INLINE
-#include "CellStokesFACOps.I"
-#endif
-
-namespace SAMRAI {
-namespace solv {
-
-tbox::Pointer<pdat::CellVariable<double> >
-CellStokesFACOps::s_cell_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
-tbox::Pointer<pdat::SideVariable<double> >
-CellStokesFACOps::s_flux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
-tbox::Pointer<pdat::OutersideVariable<double> >
-CellStokesFACOps::s_oflux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
-tbox::StartupShutdownManager::Handler
-CellStokesFACOps::s_finalize_handler(
- 0,
- 0,
- 0,
- CellStokesFACOps::finalizeCallback,
- tbox::StartupShutdownManager::priorityVariables);
-
-extern "C" {
-
-#ifdef __INTEL_COMPILER
-#pragma warning (disable:1419)
-#endif
-
-void F77_FUNC(compfluxvardc2d, COMPFLUXVARDC2D) (
- double* xflux,
- double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const int* dcgi,
- const int* dcgj,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx);
-void F77_FUNC(compfluxcondc2d, COMPFLUXCONDC2D) (
- double* xflux,
- double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double & diff_coef,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx);
-void F77_FUNC(rbgswithfluxmaxvardcvarsf2d, RBGSWITHFLUXMAXVARDCVARSF2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const int* dcgi,
- const int* dcgj,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const double* scalar_field,
- const int* scalar_field_gi,
- const int* scalar_field_gj,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(rbgswithfluxmaxcondcvarsf2d, RBGSWITHFLUXMAXCONDCVARSF2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double & dc,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const double* scalar_field,
- const int* scalar_field_gi,
- const int* scalar_field_gj,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(rbgswithfluxmaxvardcconsf2d, RBGSWITHFLUXMAXVARDCCONSF2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const int* dcgi,
- const int* dcgj,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const double & scalar_field,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(rbgswithfluxmaxcondcconsf2d, RBGSWITHFLUXMAXCONDCCONSF2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double & dc,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const double & scalar_field,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(compresvarsca2d, COMPRESVARSCA2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- double* residual,
- const int* residualgi,
- const int* residualgj,
- const double* scalar_field,
- const int* scalar_field_gi,
- const int* scalar_field_gj,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx);
-void F77_FUNC(compresconsca2d, COMPRESCONSCA2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- double* residual,
- const int* residualgi,
- const int* residualgj,
- const double & scalar_field,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* dx);
-void F77_FUNC(ewingfixfluxvardc2d, EWINGFIXFLUXVARDC2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const int* dcgi,
- const int* dcgj,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* location_index,
- const int* ratio_to_coarser,
- const int* blower,
- const int* bupper,
- const double* dx);
-void F77_FUNC(ewingfixfluxcondc2d, EWINGFIXFLUXCONDC2D) (
- const double* xflux,
- const double* yflux,
- const int* fluxgi,
- const int* fluxgj,
- const double & diff_coef,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* location_index,
- const int* ratio_to_coarser,
- const int* blower,
- const int* bupper,
- const double* dx);
-
-void F77_FUNC(compfluxvardc3d, COMPFLUXVARDC3D) (
- double* xflux,
- double* yflux,
- double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const double* zdiff_coef,
- const int* dcgi,
- const int* dcgj,
- const int* dcgk,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx);
-void F77_FUNC(compfluxcondc3d, COMPFLUXCONDC3D) (
- double* xflux,
- double* yflux,
- double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double & diff_coef,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx);
-void F77_FUNC(rbgswithfluxmaxvardcvarsf3d, RBGSWITHFLUXMAXVARDCVARSF3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const double* zdiff_coef,
- const int* dcgi,
- const int* dcgj,
- const int* dcgk,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const int* rhsgk,
- const double* scalar_field,
- const int* scalar_field_gi,
- const int* scalar_field_gj,
- const int* scalar_field_gk,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(rbgswithfluxmaxcondcvarsf3d, RBGSWITHFLUXMAXCONDCVARSF3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double & dc,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const int* rhsgk,
- const double* scalar_field,
- const int* scalar_field_gi,
- const int* scalar_field_gj,
- const int* scalar_field_gk,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(rbgswithfluxmaxvardcconsf3d, RBGSWITHFLUXMAXVARDCCONSF3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const double* zdiff_coef,
- const int* dcgi,
- const int* dcgj,
- const int* dcgk,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const int* rhsgk,
- const double & scalar_field,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(rbgswithfluxmaxcondcconsf3d, RBGSWITHFLUXMAXCONDCCONSF3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double & dc,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const int* rhsgk,
- const double & scalar_field,
- double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx,
- const int* offset,
- const double* maxres);
-void F77_FUNC(compresvarsca3d, COMPRESVARSCA3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const int* rhsgk,
- double* residual,
- const int* residualgi,
- const int* residualgj,
- const int* residualgk,
- const double* scalar_field,
- const int* scalar_field_gi,
- const int* scalar_field_gj,
- const int* scalar_field_gk,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx);
-void F77_FUNC(compresconsca3d, COMPRESCONSCA3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double* rhs,
- const int* rhsgi,
- const int* rhsgj,
- const int* rhsgk,
- double* residual,
- const int* residualgi,
- const int* residualgj,
- const int* residualgk,
- const double & scalar_field,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* dx);
-void F77_FUNC(ewingfixfluxvardc3d, EWINGFIXFLUXVARDC3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double* xdiff_coef,
- const double* ydiff_coef,
- const double* zdiff_coef,
- const int* dcgi,
- const int* dcgj,
- const int* dcgk,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const int* location_index,
- const int* ratio_to_coarser,
- const int* blower,
- const int* bupper,
- const double* dx);
-void F77_FUNC(ewingfixfluxcondc3d, EWINGFIXFLUXCONDC3D) (
- const double* xflux,
- const double* yflux,
- const double* zflux,
- const int* fluxgi,
- const int* fluxgj,
- const int* fluxgk,
- const double & diff_coef,
- const double* soln,
- const int* solngi,
- const int* solngj,
- const int* solngk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const int* location_index,
- const int* ratio_to_coarser,
- const int* blower,
- const int* bupper,
- const double* dx);
-
-}
-
-/*
- ********************************************************************
- * Constructor. *
- ********************************************************************
- */
-CellStokesFACOps::CellStokesFACOps(
- const tbox::Dimension& dim,
- const std::string& object_name,
- tbox::Pointer<tbox::Database> database):
- d_dim(dim),
- d_object_name(object_name),
- d_hierarchy(),
- d_ln_min(-1),
- d_ln_max(-1),
- d_cf_boundary(),
- d_stokes_spec(object_name + "::Stokes specs"),
- d_smoothing_choice("redblack"),
- d_coarse_solver_choice(
-#ifdef HAVE_HYPRE
- "hypre"
-#else
- "redblack"
-#endif
-
- ),
- d_cf_discretization("Ewing"),
- d_prolongation_method("CONSTANT_REFINE"),
- d_coarse_solver_tolerance(1.e-8),
- d_coarse_solver_max_iterations(10),
- d_residual_tolerance_during_smoothing(-1.0),
- d_flux_id(-1),
-#ifdef HAVE_HYPRE
- d_hypre_solver(dim,
- object_name + "::hypre_solver",
- database && database->isDatabase("hypre_solver") ?
- database->getDatabase("hypre_solver"):
- tbox::Pointer<tbox::Database>(NULL)),
-#endif
- d_physical_bc_coef(NULL),
- d_context(hier::VariableDatabase::getDatabase()
- ->getContext(object_name + "::PRIVATE_CONTEXT")),
- d_cell_scratch_id(-1),
- d_flux_scratch_id(-1),
- d_oflux_scratch_id(-1),
- d_prolongation_refine_operator(),
- d_prolongation_refine_algorithm(),
- d_prolongation_refine_schedules(),
- d_urestriction_coarsen_operator(),
- d_urestriction_coarsen_algorithm(),
- d_urestriction_coarsen_schedules(),
- d_rrestriction_coarsen_operator(),
- d_rrestriction_coarsen_algorithm(),
- d_rrestriction_coarsen_schedules(),
- d_flux_coarsen_operator(),
- d_flux_coarsen_algorithm(),
- d_flux_coarsen_schedules(),
- d_ghostfill_refine_operator(),
- d_ghostfill_refine_algorithm(),
- d_ghostfill_refine_schedules(),
- d_ghostfill_nocoarse_refine_operator(),
- d_ghostfill_nocoarse_refine_algorithm(),
- d_ghostfill_nocoarse_refine_schedules(),
- d_bc_helper(dim,
- d_object_name + "::bc helper"),
- d_enable_logging(false),
- d_preconditioner(NULL),
- d_hopscell(),
- d_hopsside()
-{
-
- t_restrict_solution = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::restrictSolution()");
- t_restrict_residual = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::restrictResidual()");
- t_prolong = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::prolongErrorAndCorrect()");
- t_smooth_error = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::smoothError()");
- t_solve_coarsest = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::solveCoarsestLevel()");
- t_compute_composite_residual = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::computeCompositeResidualOnLevel()");
- t_compute_residual_norm = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesFACOps::computeResidualNorm()");
-
- if (d_dim == tbox::Dimension(1) || d_dim > tbox::Dimension(3)) {
- TBOX_ERROR("CellStokesFACOps : DIM == 1 or > 3 not implemented yet.\n");
- }
-
- if (s_cell_scratch_var[dim.getValue() - 1].isNull()) {
- TBOX_ASSERT(s_cell_scratch_var[dim.getValue() - 1].isNull());
- TBOX_ASSERT(s_cell_scratch_var[dim.getValue() - 1].isNull());
-
- std::ostringstream ss;
- ss << "CellStokesFACOps::private_cell_scratch" << dim.getValue();
- s_cell_scratch_var[dim.getValue() - 1] = new pdat::CellVariable<double>
- (dim, ss.str());
- ss.str("");
- ss << "CellStokesFACOps::private_flux_scratch" << dim.getValue();
- s_flux_scratch_var[dim.getValue() - 1] = new pdat::SideVariable<double>
- (dim, ss.str());
- ss.str("");
- ss << "CellStokesFACOps::private_oflux_scratch" << dim.getValue();
- s_oflux_scratch_var[dim.getValue() - 1] = new pdat::OutersideVariable<double>
- (dim, ss.str());
- }
-
- hier::VariableDatabase* vdb = hier::VariableDatabase::getDatabase();
- d_cell_scratch_id = vdb->
- registerVariableAndContext(s_cell_scratch_var[dim.getValue() - 1],
- d_context,
- hier::IntVector::getOne(dim));
- d_flux_scratch_id = vdb->
- registerVariableAndContext(s_flux_scratch_var[dim.getValue() - 1],
- d_context,
- hier::IntVector::getZero(d_dim));
- d_oflux_scratch_id = vdb->
- registerVariableAndContext(s_oflux_scratch_var[dim.getValue() - 1],
- d_context,
- hier::IntVector::getZero(d_dim));
-
- /*
- * Some variables initialized by default are overriden by input.
- */
- if (database) {
-
- d_coarse_solver_choice =
- database->getStringWithDefault("coarse_solver_choice",
- d_coarse_solver_choice);
- d_coarse_solver_tolerance =
- database->getDoubleWithDefault("coarse_solver_tolerance",
- d_coarse_solver_tolerance);
- d_coarse_solver_max_iterations =
- database->getIntegerWithDefault("coarse_solver_max_iterations",
- d_coarse_solver_max_iterations);
- d_smoothing_choice =
- database->getStringWithDefault("smoothing_choice",
- d_smoothing_choice);
-
- d_cf_discretization =
- database->getStringWithDefault("cf_discretization",
- d_cf_discretization);
-
- d_prolongation_method =
- database->getStringWithDefault("prolongation_method",
- d_prolongation_method);
-
- d_enable_logging =
- database->getBoolWithDefault("enable_logging",
- d_enable_logging);
-
- }
-
- /*
- * Check input validity and correctness.
- */
- checkInputPatchDataIndices();
-
-}
-
-CellStokesFACOps::~CellStokesFACOps(
- void)
-{
-}
-
-/*
- ************************************************************************
- * FACOperatorStrategy virtual initializeOperatorState function. *
- * *
- * Set internal variables to correspond to the solution passed in. *
- * Look up transfer operators. *
- ************************************************************************
- */
-
-void CellStokesFACOps::initializeOperatorState(
- const SAMRAIVectorReal<double>& solution,
- const SAMRAIVectorReal<double>& rhs)
-{
- deallocateOperatorState();
- int ln;
- hier::VariableDatabase* vdb = hier::VariableDatabase::getDatabase();
-
- d_hierarchy = solution.getPatchHierarchy();
- d_ln_min = solution.getCoarsestLevelNumber();
- d_ln_max = solution.getFinestLevelNumber();
- d_hopscell = new math::HierarchyCellDataOpsReal<double>(d_hierarchy,
- d_ln_min,
- d_ln_max);
- d_hopsside = new math::HierarchySideDataOpsReal<double>(d_hierarchy,
- d_ln_min,
- d_ln_max);
-
-#ifdef DEBUG_CHECK_ASSERTIONS
-
- if (d_physical_bc_coef == NULL) {
- /*
- * It's an error not to have bc object set.
- * Note that the bc object cannot be passed in through
- * the argument because the interface is inherited.
- */
- TBOX_ERROR(
- d_object_name << ": No physical bc object in\n"
- <<
- "CellStokesFACOps::initializeOperatorState\n"
- << "You must use "
- <<
- "CellStokesFACOps::setPhysicalBcCoefObject\n"
- <<
- "to set one before calling initializeOperatorState\n");
- }
-
- if (solution.getNumberOfComponents() != 1) {
- TBOX_WARNING(d_object_name
- << ": Solution vector has multiple components.\n"
- << "Solver is for component 0 only.\n");
- }
- if (rhs.getNumberOfComponents() != 1) {
- TBOX_WARNING(d_object_name
- << ": RHS vector has multiple components.\n"
- << "Solver is for component 0 only.\n");
- }
-
- /*
- * Make sure that solution and rhs data
- * are of correct type
- * are allocated
- * has sufficient ghost width
- */
- tbox::Pointer<hier::Variable> var;
- {
- vdb->mapIndexToVariable(rhs.getComponentDescriptorIndex(0),
- var);
- if (!var) {
- TBOX_ERROR(d_object_name << ": RHS component does not\n"
- << "correspond to a variable.\n");
- }
- tbox::Pointer<pdat::CellVariable<double> > cell_var = var;
- if (!cell_var) {
- TBOX_ERROR(d_object_name
- << ": RHS variable is not cell-centered double\n");
- }
- }
- {
- vdb->mapIndexToVariable(solution.getComponentDescriptorIndex(0),
- var);
- if (!var) {
- TBOX_ERROR(d_object_name << ": Solution component does not\n"
- << "correspond to a variable.\n");
- }
- tbox::Pointer<pdat::CellVariable<double> > cell_var = var;
- if (!cell_var) {
- TBOX_ERROR(d_object_name
- << ": Solution variable is not cell-centered double\n");
- }
- }
- for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
- tbox::Pointer<hier::PatchLevel> level_ptr =
- d_hierarchy->getPatchLevel(ln);
- hier::PatchLevel& level = *level_ptr;
- for (hier::PatchLevel::Iterator pi(level); pi; pi++) {
- hier::Patch& patch = **pi;
- tbox::Pointer<hier::PatchData> fd =
- patch.getPatchData(rhs.getComponentDescriptorIndex(0));
- if (fd) {
- /*
- * Some data checks can only be done if the data already exists.
- */
- tbox::Pointer<pdat::CellData<double> > cd = fd;
- if (!cd) {
- TBOX_ERROR(d_object_name
- << ": RHS data is not cell-centered double\n");
- }
- if (cd->getDepth() > 1) {
- TBOX_WARNING(d_object_name
- << ": RHS data has multiple depths.\n"
- << "Solver is for depth 0 only.\n");
- }
- }
- tbox::Pointer<hier::PatchData> ud =
- patch.getPatchData(solution.getComponentDescriptorIndex(0));
- if (ud) {
- /*
- * Some data checks can only be done if the data already exists.
- */
- tbox::Pointer<pdat::CellData<double> > cd = ud;
- if (!cd) {
- TBOX_ERROR(d_object_name
- << ": Solution data is not cell-centered double\n");
- }
- if (cd->getDepth() > 1) {
- TBOX_WARNING(d_object_name
- << ": Solution data has multiple depths.\n"
- << "Solver is for depth 0 only.\n");
- }
- if (cd->getGhostCellWidth() < hier::IntVector::getOne(d_dim)) {
- TBOX_ERROR(d_object_name
- << ": Solution data has insufficient ghost width\n");
- }
- }
- }
- }
-
- /*
- * Solution and rhs must have some similar properties.
- */
- if (rhs.getPatchHierarchy() != d_hierarchy
- || rhs.getCoarsestLevelNumber() != d_ln_min
- || rhs.getFinestLevelNumber() != d_ln_max) {
- TBOX_ERROR(d_object_name << ": solution and rhs do not have\n"
- << "the same set of patch levels.\n");
- }
-
-#endif
-
- /*
- * Initialize the coarse-fine boundary description for the
- * hierarchy.
- */
- d_cf_boundary.resizeArray(d_hierarchy->getNumberOfLevels());
-
- hier::IntVector max_gcw(d_dim, 1);
- for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
- d_cf_boundary[ln] = new hier::CoarseFineBoundary(*d_hierarchy,
- ln,
- max_gcw);
- }
-#ifdef HAVE_HYPRE
- if (d_coarse_solver_choice == "hypre") {
- d_hypre_solver.initializeSolverState(d_hierarchy, d_ln_min);
- /*
- * Share the boundary condition object with the hypre solver
- * to make sure that boundary condition settings are consistent
- * between the two objects.
- */
- d_hypre_solver.setPhysicalBcCoefObject(d_physical_bc_coef);
- d_hypre_solver.setMatrixCoefficients(d_stokes_spec);
- }
-#endif
-
- /*
- * Get the transfer operators.
- * Flux coarsening is conservative.
- * Cell (solution, error, etc) coarsening is conservative.
- * Cell refinement from same level is constant refinement.
- * Cell refinement from coarser level is chosen by the
- * choice of coarse-fine discretization, d_cf_discretization,
- * which should be set to either "Ewing" or one of the
- * acceptable strings for looking up the refine operator.
- */
- tbox::Pointer<geom::CartesianGridGeometry> geometry =
- d_hierarchy->getGridGeometry();
- tbox::Pointer<hier::Variable> variable;
-
- vdb->mapIndexToVariable(d_cell_scratch_id, variable);
- d_prolongation_refine_operator =
- geometry->lookupRefineOperator(variable,
- d_prolongation_method);
-
- vdb->mapIndexToVariable(d_cell_scratch_id, variable);
- d_urestriction_coarsen_operator =
- d_rrestriction_coarsen_operator =
- geometry->lookupCoarsenOperator(variable,
- "CONSERVATIVE_COARSEN");
-
- vdb->mapIndexToVariable(d_oflux_scratch_id, variable);
- d_flux_coarsen_operator =
- geometry->lookupCoarsenOperator(variable,
- "CONSERVATIVE_COARSEN");
-
- vdb->mapIndexToVariable(d_cell_scratch_id, variable);
- d_ghostfill_refine_operator =
- geometry->lookupRefineOperator(variable,
- d_cf_discretization == "Ewing" ?
- "CONSTANT_REFINE" : d_cf_discretization);
-
- vdb->mapIndexToVariable(d_cell_scratch_id, variable);
- d_ghostfill_nocoarse_refine_operator =
- geometry->lookupRefineOperator(variable,
- "CONSTANT_REFINE");
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (!d_prolongation_refine_operator) {
- TBOX_ERROR(d_object_name
- << ": Cannot find prolongation refine operator");
- }
- if (!d_urestriction_coarsen_operator) {
- TBOX_ERROR(d_object_name
- << ": Cannot find restriction coarsening operator");
- }
- if (!d_rrestriction_coarsen_operator) {
- TBOX_ERROR(d_object_name
- << ": Cannot find restriction coarsening operator");
- }
- if (!d_flux_coarsen_operator) {
- TBOX_ERROR(d_object_name
- << ": Cannot find flux coarsening operator");
- }
- if (!d_ghostfill_refine_operator) {
- TBOX_ERROR(d_object_name
- << ": Cannot find ghost filling refinement operator");
- }
- if (!d_ghostfill_nocoarse_refine_operator) {
- TBOX_ERROR(d_object_name
- << ": Cannot find ghost filling refinement operator");
- }
-#endif
-
- for (ln = d_ln_min + 1; ln <= d_ln_max; ++ln) {
- d_hierarchy->getPatchLevel(ln)->
- allocatePatchData(d_oflux_scratch_id);
- }
-
- /*
- * Make space for saving communication schedules.
- * There is no need to delete the old schedules first
- * because we have deallocated the solver state above.
- */
- d_prolongation_refine_schedules.resizeArray(d_ln_max + 1);
- d_ghostfill_refine_schedules.resizeArray(d_ln_max + 1);
- d_ghostfill_nocoarse_refine_schedules.resizeArray(d_ln_max + 1);
- d_urestriction_coarsen_schedules.resizeArray(d_ln_max + 1);
- d_rrestriction_coarsen_schedules.resizeArray(d_ln_max + 1);
- d_flux_coarsen_schedules.resizeArray(d_ln_max + 1);
-
- d_prolongation_refine_algorithm = new xfer::RefineAlgorithm(d_dim);
- d_urestriction_coarsen_algorithm = new xfer::CoarsenAlgorithm(d_dim);
- d_rrestriction_coarsen_algorithm = new xfer::CoarsenAlgorithm(d_dim);
- d_flux_coarsen_algorithm = new xfer::CoarsenAlgorithm(d_dim);
- d_ghostfill_refine_algorithm = new xfer::RefineAlgorithm(d_dim);
- d_ghostfill_nocoarse_refine_algorithm = new xfer::RefineAlgorithm(d_dim);
-
- d_prolongation_refine_algorithm->
- registerRefine(d_cell_scratch_id,
- solution.getComponentDescriptorIndex(0),
- d_cell_scratch_id,
- d_prolongation_refine_operator);
- d_urestriction_coarsen_algorithm->
- registerCoarsen(solution.getComponentDescriptorIndex(0),
- solution.getComponentDescriptorIndex(0),
- d_urestriction_coarsen_operator);
- d_rrestriction_coarsen_algorithm->
- registerCoarsen(rhs.getComponentDescriptorIndex(0),
- rhs.getComponentDescriptorIndex(0),
- d_rrestriction_coarsen_operator);
- d_ghostfill_refine_algorithm->
- registerRefine(solution.getComponentDescriptorIndex(0),
- solution.getComponentDescriptorIndex(0),
- solution.getComponentDescriptorIndex(0),
- d_ghostfill_refine_operator);
- d_flux_coarsen_algorithm->
- registerCoarsen(((d_flux_id != -1) ? d_flux_id : d_flux_scratch_id),
- d_oflux_scratch_id,
- d_flux_coarsen_operator);
- d_ghostfill_nocoarse_refine_algorithm->
- registerRefine(solution.getComponentDescriptorIndex(0),
- solution.getComponentDescriptorIndex(0),
- solution.getComponentDescriptorIndex(0),
- d_ghostfill_nocoarse_refine_operator);
-
- for (int dest_ln = d_ln_min + 1; dest_ln <= d_ln_max; ++dest_ln) {
-
- tbox::Pointer<xfer::PatchLevelFullFillPattern> fill_pattern(
- new xfer::PatchLevelFullFillPattern());
- d_prolongation_refine_schedules[dest_ln] =
- d_prolongation_refine_algorithm->
- createSchedule(fill_pattern,
- d_hierarchy->getPatchLevel(dest_ln),
- tbox::Pointer<hier::PatchLevel>(),
- dest_ln - 1,
- d_hierarchy,
- &d_bc_helper);
- if (!d_prolongation_refine_schedules[dest_ln]) {
- TBOX_ERROR(d_object_name
- << ": Cannot create a refine schedule for prolongation!\n");
- }
- d_ghostfill_refine_schedules[dest_ln] =
- d_ghostfill_refine_algorithm->
- createSchedule(d_hierarchy->getPatchLevel(dest_ln),
- dest_ln - 1,
- d_hierarchy,
- &d_bc_helper);
- if (!d_ghostfill_refine_schedules[dest_ln]) {
- TBOX_ERROR(d_object_name
- << ": Cannot create a refine schedule for ghost filling!\n");
- }
- d_ghostfill_nocoarse_refine_schedules[dest_ln] =
- d_ghostfill_nocoarse_refine_algorithm->
- createSchedule(d_hierarchy->getPatchLevel(dest_ln),
- &d_bc_helper);
- if (!d_ghostfill_nocoarse_refine_schedules[dest_ln]) {
- TBOX_ERROR(
- d_object_name
- <<
- ": Cannot create a refine schedule for ghost filling on bottom level!\n");
- }
- }
- for (int dest_ln = d_ln_min; dest_ln < d_ln_max; ++dest_ln) {
- d_urestriction_coarsen_schedules[dest_ln] =
- d_urestriction_coarsen_algorithm->
- createSchedule(d_hierarchy->getPatchLevel(dest_ln),
- d_hierarchy->getPatchLevel(dest_ln + 1));
- if (!d_urestriction_coarsen_schedules[dest_ln]) {
- TBOX_ERROR(d_object_name
- << ": Cannot create a coarsen schedule for U restriction!\n");
- }
- d_rrestriction_coarsen_schedules[dest_ln] =
- d_rrestriction_coarsen_algorithm->
- createSchedule(d_hierarchy->getPatchLevel(dest_ln),
- d_hierarchy->getPatchLevel(dest_ln + 1));
- if (!d_rrestriction_coarsen_schedules[dest_ln]) {
- TBOX_ERROR(d_object_name
- << ": Cannot create a coarsen schedule for R restriction!\n");
- }
- d_flux_coarsen_schedules[dest_ln] =
- d_flux_coarsen_algorithm->
- createSchedule(d_hierarchy->getPatchLevel(dest_ln),
- d_hierarchy->getPatchLevel(dest_ln + 1));
- if (!d_flux_coarsen_schedules[dest_ln]) {
- TBOX_ERROR(d_object_name
- << ": Cannot create a coarsen schedule for flux transfer!\n");
- }
- }
- d_ghostfill_nocoarse_refine_schedules[d_ln_min] =
- d_ghostfill_nocoarse_refine_algorithm->
- createSchedule(d_hierarchy->getPatchLevel(d_ln_min),
- &d_bc_helper);
- if (!d_ghostfill_nocoarse_refine_schedules[d_ln_min]) {
- TBOX_ERROR(
- d_object_name
- <<
- ": Cannot create a refine schedule for ghost filling on bottom level!\n");
- }
-}
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual deallocateOperatorState *
- * function. Deallocate internal hierarchy-dependent data. *
- * State is allocated iff hierarchy is set. *
- ********************************************************************
- */
-
-void CellStokesFACOps::deallocateOperatorState()
-{
- if (d_hierarchy) {
- int ln;
- for (ln = d_ln_min + 1; ln <= d_ln_max; ++ln) {
- d_hierarchy->getPatchLevel(ln)->
- deallocatePatchData(d_oflux_scratch_id);
- }
- d_cf_boundary.resizeArray(0);
-#ifdef HAVE_HYPRE
- d_hypre_solver.deallocateSolverState();
-#endif
- d_hierarchy.setNull();
- d_ln_min = -1;
- d_ln_max = -1;
-
- d_prolongation_refine_algorithm.setNull();
- d_prolongation_refine_schedules.setNull();
-
- d_urestriction_coarsen_algorithm.setNull();
- d_urestriction_coarsen_schedules.setNull();
-
- d_rrestriction_coarsen_algorithm.setNull();
- d_rrestriction_coarsen_schedules.setNull();
-
- d_flux_coarsen_algorithm.setNull();
- d_flux_coarsen_schedules.setNull();
-
- d_ghostfill_refine_algorithm.setNull();
- d_ghostfill_refine_schedules.setNull();
-
- d_ghostfill_nocoarse_refine_algorithm.setNull();
- d_ghostfill_nocoarse_refine_schedules.setNull();
-
- }
-}
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual postprocessOneCycle function. *
- ********************************************************************
- */
-
-void CellStokesFACOps::postprocessOneCycle(
- int fac_cycle_num,
- const SAMRAIVectorReal<double>& current_soln,
- const SAMRAIVectorReal<double>& residual)
-{
- NULL_USE(current_soln);
- NULL_USE(residual);
-
- if (d_enable_logging) {
- if (d_preconditioner) {
- /*
- * Output convergence progress. This is probably only appropriate
- * if the solver is NOT being used as a preconditioner.
- */
- double avg_factor, final_factor;
- d_preconditioner->getConvergenceFactors(avg_factor, final_factor);
- tbox::plog
- << "iter=" << std::setw(4) << fac_cycle_num
- << " resid=" << d_preconditioner->getResidualNorm()
- << " net conv=" << d_preconditioner->getNetConvergenceFactor()
- << " final conv=" << d_preconditioner->getNetConvergenceFactor()
- << " avg conv=" << d_preconditioner->getAvgConvergenceFactor()
- << std::endl;
- }
- }
-}
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual restrictSolution function. *
- * After restricting solution, update ghost cells of the affected *
- * level. *
- ********************************************************************
- */
-
-void CellStokesFACOps::restrictSolution(
- const SAMRAIVectorReal<double>& s,
- SAMRAIVectorReal<double>& d,
- int dest_ln) {
-
- t_restrict_solution->start();
-
- xeqScheduleURestriction(d.getComponentDescriptorIndex(0),
- s.getComponentDescriptorIndex(0),
- dest_ln);
-
- d_bc_helper.setHomogeneousBc(false);
- d_bc_helper.setTargetDataId(d.getComponentDescriptorIndex(0));
-
- if (dest_ln == d_ln_min) {
- xeqScheduleGhostFillNoCoarse(d.getComponentDescriptorIndex(0),
- dest_ln);
- } else {
- xeqScheduleGhostFill(d.getComponentDescriptorIndex(0),
- dest_ln);
- }
-
- t_restrict_solution->stop();
-}
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual restrictresidual function. *
- ********************************************************************
- */
-
-void CellStokesFACOps::restrictResidual(
- const SAMRAIVectorReal<double>& s,
- SAMRAIVectorReal<double>& d,
- int dest_ln) {
-
- t_restrict_residual->start();
-
- xeqScheduleRRestriction(d.getComponentDescriptorIndex(0),
- s.getComponentDescriptorIndex(0),
- dest_ln);
-
- t_restrict_residual->stop();
-}
-
-/*
- ***********************************************************************
- * FACOperatorStrategy virtual prolongErrorAndCorrect function. *
- * After the prolongation, we set the physical boundary condition *
- * for the correction, which is zero. Other ghost cell values, *
- * which are preset to zero, need not be set. *
- ***********************************************************************
- */
-
-void CellStokesFACOps::prolongErrorAndCorrect(
- const SAMRAIVectorReal<double>& s,
- SAMRAIVectorReal<double>& d,
- int dest_ln) {
-
- t_prolong->start();
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (s.getPatchHierarchy() != d_hierarchy
- || d.getPatchHierarchy() != d_hierarchy) {
- TBOX_ERROR(d_object_name << ": Vector hierarchy does not match\n"
- "internal state hierarchy.");
- }
-#endif
-
- tbox::Pointer<hier::PatchLevel> coarse_level =
- d_hierarchy->getPatchLevel(dest_ln - 1);
- tbox::Pointer<hier::PatchLevel> fine_level =
- d_hierarchy->getPatchLevel(dest_ln);
-
- /*
- * Data is prolonged into the scratch space corresponding
- * to index d_cell_scratch_id and allocated here.
- */
- fine_level->allocatePatchData(d_cell_scratch_id);
-
- /*
- * Refine solution into scratch space to fill the fine level
- * interior in the scratch space, then use that refined data
- * to correct the fine level error.
- */
- d_bc_helper.setTargetDataId(d_cell_scratch_id);
- d_bc_helper.setHomogeneousBc(true);
- const int src_index = s.getComponentDescriptorIndex(0);
- xeqScheduleProlongation(d_cell_scratch_id,
- src_index,
- d_cell_scratch_id,
- dest_ln);
-
- /*
- * Add the refined error in the scratch space
- * to the error currently residing in the destination level.
- */
- math::HierarchyCellDataOpsReal<double>
- hierarchy_math_ops(d_hierarchy, dest_ln, dest_ln);
- const int dst_index = d.getComponentDescriptorIndex(0);
- hierarchy_math_ops.add(dst_index, dst_index, d_cell_scratch_id);
-
- fine_level->deallocatePatchData(d_cell_scratch_id);
-
- t_prolong->stop();
-
-}
-
-/*
- ********************************************************************
- ********************************************************************
- */
-
-void CellStokesFACOps::smoothError(
- SAMRAIVectorReal<double>& data,
- const SAMRAIVectorReal<double>& residual,
- int ln,
- int num_sweeps)
-{
-
- t_smooth_error->start();
-
- checkInputPatchDataIndices();
- if (d_smoothing_choice == "redblack") {
- smoothErrorByRedBlack(data,
- residual,
- ln,
- num_sweeps,
- d_residual_tolerance_during_smoothing);
- } else {
- TBOX_ERROR(d_object_name << ": Bad smoothing choice '"
- << d_smoothing_choice
- << "' in CellStokesFACOps.");
- }
-
- t_smooth_error->stop();
-}
-
-/*
- ********************************************************************
- * Workhorse function to smooth error using red-black *
- * Gauss-Seidel iterations. *
- ********************************************************************
- */
-
-void CellStokesFACOps::smoothErrorByRedBlack(
- SAMRAIVectorReal<double>& data,
- const SAMRAIVectorReal<double>& residual,
- int ln,
- int num_sweeps,
- double residual_tolerance)
-{
-
- checkInputPatchDataIndices();
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (data.getPatchHierarchy() != d_hierarchy
- || residual.getPatchHierarchy() != d_hierarchy) {
- TBOX_ERROR(d_object_name << ": Vector hierarchy does not match\n"
- "internal hierarchy.");
- }
-#endif
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(ln);
-
- const int data_id = data.getComponentDescriptorIndex(0);
-
- const int flux_id = (d_flux_id != -1) ? d_flux_id : d_flux_scratch_id;
-
- d_bc_helper.setTargetDataId(data_id);
- d_bc_helper.setHomogeneousBc(true);
- xeqScheduleGhostFillNoCoarse(data_id, ln);
-
- if (ln > d_ln_min) {
- /*
- * Perform a one-time transfer of data from coarser level,
- * to fill ghost boundaries that will not change through
- * the smoothing loop.
- */
- xeqScheduleGhostFill(data_id, ln);
- }
-
- /*
- * Smooth the number of sweeps specified or until
- * the convergence is satisfactory.
- */
- int isweep;
- double red_maxres, blk_maxres, maxres = 0;
- red_maxres = blk_maxres = residual_tolerance + 1;
- /*
- * Instead of checking residual convergence globally,
- * we check the not_converged flag. This avoids possible
- * round-off errors affecting different processes differently,
- * leading to disagreement on whether to continue smoothing.
- */
- int not_converged = 1;
- for (isweep = 0; isweep < num_sweeps && not_converged; ++isweep) {
- red_maxres = blk_maxres = 0;
-
- // Red sweep.
- xeqScheduleGhostFillNoCoarse(data_id, ln);
- for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
- tbox::Pointer<hier::Patch> patch = *pi;
-
- bool deallocate_flux_data_when_done = false;
- if (flux_id == d_flux_scratch_id) {
- /*
- * Using internal temporary storage for flux.
- * For each patch, make sure the internal
- * side-centered data is allocated and note
- * whether that data should be deallocated when done.
- */
- if (!patch->checkAllocated(flux_id)) {
- patch->allocatePatchData(flux_id);
- deallocate_flux_data_when_done = true;
- }
- }
-
- tbox::Pointer<pdat::CellData<double> >
- scalar_field_data = d_stokes_spec.cIsVariable() ?
- patch->getPatchData(d_stokes_spec.getCPatchDataId()) :
- tbox::Pointer<hier::PatchData>(NULL);
- tbox::Pointer<pdat::CellData<double> >
- err_data = data.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::CellData<double> >
- residual_data = residual.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::SideData<double> >
- flux_data = patch->getPatchData(flux_id);
-
- computeFluxOnPatch(
- *patch,
- level->getRatioToCoarserLevel(),
- *err_data,
- *flux_data);
-
- redOrBlackSmoothingOnPatch(*patch,
- *flux_data,
- *residual_data,
- *err_data,
- 'r',
- &red_maxres);
-
- if (deallocate_flux_data_when_done) {
- patch->deallocatePatchData(flux_id);
- }
- } // End patch number *pi
- xeqScheduleGhostFillNoCoarse(data_id, ln);
-
- // Black sweep.
- for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
- tbox::Pointer<hier::Patch> patch = *pi;
-
- bool deallocate_flux_data_when_done = false;
- if (flux_id == d_flux_scratch_id) {
- /*
- * Using internal temporary storage for flux.
- * For each patch, make sure the internal
- * side-centered data is allocated and note
- * whether that data should be deallocated when done.
- */
- if (!patch->checkAllocated(flux_id)) {
- patch->allocatePatchData(flux_id);
- deallocate_flux_data_when_done = true;
- }
- }
-
- tbox::Pointer<pdat::CellData<double> >
- scalar_field_data = d_stokes_spec.cIsVariable() ?
- patch->getPatchData(d_stokes_spec.getCPatchDataId()) :
- tbox::Pointer<hier::PatchData>(NULL);
- tbox::Pointer<pdat::CellData<double> >
- err_data = data.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::CellData<double> >
- residual_data = residual.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::SideData<double> >
- flux_data = patch->getPatchData(flux_id);
-
- computeFluxOnPatch(
- *patch,
- level->getRatioToCoarserLevel(),
- *err_data,
- *flux_data);
-
- redOrBlackSmoothingOnPatch(*patch,
- *flux_data,
- *residual_data,
- *err_data,
- 'b',
- &blk_maxres);
-
- if (deallocate_flux_data_when_done) {
- patch->deallocatePatchData(flux_id);
- }
- } // End patch number *pi
- xeqScheduleGhostFillNoCoarse(data_id, ln);
- if (residual_tolerance >= 0.0) {
- /*
- * Check for early end of sweeps due to convergence
- * only if it is numerically possible (user gave a
- * non negative value for residual tolerance).
- */
- maxres = tbox::MathUtilities<double>::Max(red_maxres, blk_maxres);
- not_converged = maxres > residual_tolerance;
- const tbox::SAMRAI_MPI& mpi(d_hierarchy->getDomainMappedBoxLevel().getMPI());
- if (mpi.getSize() > 1) {
- mpi.AllReduce(¬_converged, 1, MPI_MAX);
- }
- }
- } // End sweep number isweep
- if (d_enable_logging) tbox::plog
- << d_object_name << " RBGS smoothing maxres = " << maxres << "\n"
- << " after " << isweep << " sweeps.\n";
-
-}
-
-/*
- ********************************************************************
- * Fix flux on coarse-fine boundaries computed from a *
- * constant-refine interpolation of coarse level data. *
- ********************************************************************
- */
-
-void CellStokesFACOps::ewingFixFlux(
- const hier::Patch& patch,
- const pdat::CellData<double>& soln_data,
- pdat::SideData<double>& flux_data,
- const hier::IntVector& ratio_to_coarser) const
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim, patch, soln_data, flux_data,
- ratio_to_coarser);
-
- const int patch_ln = patch.getPatchLevelNumber();
- const hier::GlobalId id = patch.getGlobalId();
- tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
- patch.getPatchGeometry();
- const double* dx = patch_geom->getDx();
- const hier::Box& patch_box(patch.getBox());
- const hier::Index& plower = patch_box.lower();
- const hier::Index& pupper = patch_box.upper();
-
- const tbox::Array<hier::BoundaryBox>& bboxes =
- d_cf_boundary[patch_ln]->getBoundaries(id, 1);
- int bn, nboxes = bboxes.getSize();
-
- if (d_stokes_spec.dIsVariable()) {
-
- tbox::Pointer<pdat::SideData<double> > diffcoef_data;
- diffcoef_data = patch.getPatchData(d_stokes_spec.getDPatchDataId());
-
- for (bn = 0; bn < nboxes; ++bn) {
- const hier::BoundaryBox& boundary_box = bboxes[bn];
-
- TBOX_ASSERT(boundary_box.getBoundaryType() == 1);
-
- const hier::Box& bdry_box = boundary_box.getBox();
- const hier::Index& blower = bdry_box.lower();
- const hier::Index& bupper = bdry_box.upper();
- const int location_index = boundary_box.getLocationIndex();
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(ewingfixfluxvardc2d, EWINGFIXFLUXVARDC2D) (
- flux_data.getPointer(0), flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_data->getPointer(0), diffcoef_data->getPointer(1),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &plower[0], &pupper[0], &plower[1], &pupper[1],
- &location_index,
- &ratio_to_coarser[0],
- &blower[0], &bupper[0],
- dx);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(ewingfixfluxvardc3d, EWINGFIXFLUXVARDC3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- diffcoef_data->getPointer(2),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- &diffcoef_data->getGhostCellWidth()[2],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &plower[0], &pupper[0],
- &plower[1], &pupper[1],
- &plower[2], &pupper[2],
- &location_index,
- &ratio_to_coarser[0],
- &blower[0], &bupper[0],
- dx);
- } else {
- TBOX_ERROR("CellStokesFACOps : DIM > 3 not supported" << std::endl);
- }
-
- }
- } else {
-
- const double diffcoef_constant = d_stokes_spec.getDConstant();
-
- for (bn = 0; bn < nboxes; ++bn) {
- const hier::BoundaryBox& boundary_box = bboxes[bn];
-
- TBOX_ASSERT(boundary_box.getBoundaryType() == 1);
-
- const hier::Box& bdry_box = boundary_box.getBox();
- const hier::Index& blower = bdry_box.lower();
- const hier::Index& bupper = bdry_box.upper();
- const int location_index = boundary_box.getLocationIndex();
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(ewingfixfluxcondc2d, EWINGFIXFLUXCONDC2D) (
- flux_data.getPointer(0), flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &plower[0], &pupper[0],
- &plower[1], &pupper[1],
- &location_index,
- &ratio_to_coarser[0],
- &blower[0], &bupper[0],
- dx);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(ewingfixfluxcondc3d, EWINGFIXFLUXCONDC3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &plower[0], &pupper[0],
- &plower[1], &pupper[1],
- &plower[2], &pupper[2],
- &location_index,
- &ratio_to_coarser[0],
- &blower[0], &bupper[0],
- dx);
- }
- }
- }
-}
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual solveCoarsestLevel *
- * function *
- ********************************************************************
- */
-
-int CellStokesFACOps::solveCoarsestLevel(
- SAMRAIVectorReal<double>& data,
- const SAMRAIVectorReal<double>& residual,
- int coarsest_ln) {
-
- t_solve_coarsest->start();
-
- checkInputPatchDataIndices();
-
- int return_value = 0;
-
- if (d_coarse_solver_choice == "jacobi") {
- d_residual_tolerance_during_smoothing = d_coarse_solver_tolerance;
- smoothError(data,
- residual,
- coarsest_ln,
- d_coarse_solver_max_iterations);
- d_residual_tolerance_during_smoothing = -1.0;
- } else if (d_coarse_solver_choice == "redblack") {
- d_residual_tolerance_during_smoothing = d_coarse_solver_tolerance;
- smoothError(data,
- residual,
- coarsest_ln,
- d_coarse_solver_max_iterations);
- d_residual_tolerance_during_smoothing = -1.0;
- } else if (d_coarse_solver_choice == "hypre") {
-#ifndef HAVE_HYPRE
- TBOX_ERROR(d_object_name << ": Coarse level solver choice '"
- << d_coarse_solver_choice
- << "' unavailable in "
- << "scapCellStokesOps::solveCoarsestLevel.");
-#else
- return_value = solveCoarsestLevel_HYPRE(data, residual, coarsest_ln);
-#endif
- } else {
- TBOX_ERROR(
- d_object_name << ": Bad coarse level solver choice '"
- << d_coarse_solver_choice
- <<
- "' in scapCellStokesOps::solveCoarsestLevel.");
- }
-
- xeqScheduleGhostFillNoCoarse(data.getComponentDescriptorIndex(0),
- coarsest_ln);
-
- t_solve_coarsest->stop();
-
- return return_value;
-}
-
-#ifdef HAVE_HYPRE
-/*
- ********************************************************************
- * Solve coarsest level using Hypre *
- * We only solve for the error, so we always use homogeneous bc. *
- ********************************************************************
- */
-
-int CellStokesFACOps::solveCoarsestLevel_HYPRE(
- SAMRAIVectorReal<double>& data,
- const SAMRAIVectorReal<double>& residual,
- int coarsest_ln) {
-
- NULL_USE(coarsest_ln);
-
-#ifndef HAVE_HYPRE
- TBOX_ERROR(d_object_name << ": Coarse level solver choice '"
- << d_coarse_solver_choice
- << "' unavailable in "
- << "CellStokesFACOps::solveCoarsestLevel.");
-
- return 0;
-
-#else
-
- checkInputPatchDataIndices();
- d_hypre_solver.setStoppingCriteria(d_coarse_solver_max_iterations,
- d_coarse_solver_tolerance);
- const int solver_ret =
- d_hypre_solver.solveSystem(
- data.getComponentDescriptorIndex(0),
- residual.getComponentDescriptorIndex(0),
- true);
- /*
- * Present data on the solve.
- * The Hypre solver returns 0 if converged.
- */
- if (d_enable_logging) tbox::plog
- << d_object_name << " Hypre solve " << (solver_ret ? "" : "NOT ")
- << "converged\n"
- << "\titerations: " << d_hypre_solver.getNumberOfIterations() << "\n"
- << "\tresidual: " << d_hypre_solver.getRelativeResidualNorm() << "\n";
-
- return !solver_ret;
-
-#endif
-
-}
-#endif
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual *
- * computeCompositeResidualOnLevel function *
- ********************************************************************
- */
-
-void CellStokesFACOps::computeCompositeResidualOnLevel(
- SAMRAIVectorReal<double>& residual,
- const SAMRAIVectorReal<double>& solution,
- const SAMRAIVectorReal<double>& rhs,
- int ln,
- bool error_equation_indicator) {
-
- t_compute_composite_residual->start();
-
- checkInputPatchDataIndices();
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (residual.getPatchHierarchy() != d_hierarchy
- || solution.getPatchHierarchy() != d_hierarchy
- || rhs.getPatchHierarchy() != d_hierarchy) {
- TBOX_ERROR(d_object_name << ": Vector hierarchy does not match\n"
- "internal hierarchy.");
- }
-#endif
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(ln);
-
- /*
- * Set up the bc helper so that when we use a refine schedule
- * to fill ghosts, the correct data is operated on.
- */
- const int soln_id = solution.getComponentDescriptorIndex(0);
- d_bc_helper.setTargetDataId(soln_id);
- d_bc_helper.setHomogeneousBc(error_equation_indicator);
-
- const int flux_id = (d_flux_id != -1) ? d_flux_id : d_flux_scratch_id;
-
- /*
- * Assumptions:
- * 1. Data does not yet exist in ghost boundaries.
- * 2. Residual data on next finer grid (if any)
- * has been computed already.
- * 3. Flux data from next finer grid (if any) has
- * been computed but has not been coarsened to
- * this level.
- *
- * Steps:
- * S1. Fill solution ghost data by refinement
- * or setting physical boundary conditions.
- * This also brings in information from coarser
- * to form the composite grid flux.
- * S2. Compute flux on ln.
- * S3. If next finer is available,
- * Coarsen flux data on next finer level,
- * overwriting flux computed from coarse data.
- * S4. Compute residual data from flux.
- */
-
- /* S1. Fill solution ghost data. */
- {
- tbox::Pointer<xfer::RefineSchedule> ln_refine_schedule;
- if (ln > d_ln_min) {
- /* Fill from current, next coarser level and physical boundary */
- xeqScheduleGhostFill(soln_id, ln);
- } else {
- /* Fill from current and physical boundary */
- xeqScheduleGhostFillNoCoarse(soln_id, ln);
- }
- }
-
- /*
- * For the whole level, make sure the internal
- * side-centered data is allocated and note
- * whether that data should be deallocated when done.
- * We do this for the whole level because the data
- * undergoes transfer operations which require the
- * whole level data.
- */
- bool deallocate_flux_data_when_done = false;
- if (flux_id == d_flux_scratch_id) {
- if (!level->checkAllocated(flux_id)) {
- level->allocatePatchData(flux_id);
- deallocate_flux_data_when_done = true;
- }
- }
-
- /*
- * S2. Compute flux on patches in level.
- */
- for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
- tbox::Pointer<hier::Patch> patch = *pi;
-
- tbox::Pointer<pdat::CellData<double> >
- soln_data = solution.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::CellData<double> >
- rhs_data = rhs.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::CellData<double> >
- residual_data = residual.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::SideData<double> >
- flux_data = patch->getPatchData(flux_id);
- computeFluxOnPatch(
- *patch,
- level->getRatioToCoarserLevel(),
- *soln_data,
- *flux_data);
-
- }
-
- /*
- * S3. Coarsen oflux data from next finer level so that
- * the computed flux becomes the composite grid flux.
- */
- if (ln < d_ln_max) {
- xeqScheduleFluxCoarsen(flux_id, d_oflux_scratch_id, ln);
- }
-
- /*
- * S4. Compute residual on patches in level.
- */
- for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
- tbox::Pointer<hier::Patch> patch = *pi;
- tbox::Pointer<pdat::CellData<double> >
- soln_data = solution.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::CellData<double> >
- rhs_data = rhs.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::CellData<double> >
- residual_data = residual.getComponentPatchData(0, *patch);
- tbox::Pointer<pdat::SideData<double> >
- flux_data = patch->getPatchData(flux_id);
- computeResidualOnPatch(*patch,
- *flux_data,
- *soln_data,
- *rhs_data,
- *residual_data);
-
- if (ln > d_ln_min) {
- /*
- * Save outerflux data so that next coarser level
- * can compute its coarse-fine composite flux.
- * This is not strictly needed in this "compute residual"
- * loop through the patches, but we put it here to
- * avoid writing another loop for it.
- */
- tbox::Pointer<pdat::OutersideData<double> >
- oflux_data = patch->getPatchData(d_oflux_scratch_id);
-
- TBOX_ASSERT(oflux_data);
-
- oflux_data->copy(*flux_data);
- }
- }
-
- if (deallocate_flux_data_when_done) {
- level->deallocatePatchData(flux_id);
- }
-
- t_compute_composite_residual->stop();
-}
-
-/*
- ********************************************************************
- * FACOperatorStrategy virtual computeResidualNorm *
- * function *
- ********************************************************************
- */
-
-double CellStokesFACOps::computeResidualNorm(
- const SAMRAIVectorReal<double>& residual,
- int fine_ln,
- int coarse_ln)
-{
-
- if (coarse_ln != residual.getCoarsestLevelNumber() ||
- fine_ln != residual.getFinestLevelNumber()) {
- TBOX_ERROR("CellStokesFACOps::computeResidualNorm() is not\n"
- << "set up to compute residual except on the range of\n"
- << "levels defining the vector.\n");
- }
- t_compute_residual_norm->start();
- /*
- * The residual vector was cloned from vectors that has
- * the proper weights associated with them, so we do not
- * have to explicitly weight the residuals.
- *
- * maxNorm: not good to use because Hypre's norm does not
- * correspond to it. Also maybe too sensitive to spikes.
- * L2Norm: maybe good. But does not correspond to the
- * scale of the quantity.
- * L1Norm: maybe good. Correspond to scale of quantity,
- * but may be too insensitive to spikes.
- * RMSNorm: maybe good.
- */
- double norm = residual.RMSNorm();
- t_compute_residual_norm->stop();
- return norm;
-}
-
-/*
- ********************************************************************
- * Compute the vector weight and put it at a specified patch data *
- * index. *
- ********************************************************************
- */
-
-void CellStokesFACOps::computeVectorWeights(
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- int weight_id,
- int coarsest_ln,
- int finest_ln) const
-{
- TBOX_ASSERT(!hierarchy.isNull());
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
-
- if (coarsest_ln == -1) coarsest_ln = 0;
- if (finest_ln == -1) finest_ln = hierarchy->getFinestLevelNumber();
- if (finest_ln < coarsest_ln) {
- TBOX_ERROR(d_object_name
- << ": Illegal level number range. finest_ln < coarsest_ln.");
- }
-
- int ln;
- for (ln = finest_ln; ln >= coarsest_ln; --ln) {
-
- /*
- * On every level, first assign cell volume to vector weight.
- */
-
- tbox::Pointer<hier::PatchLevel> level =
- hierarchy->getPatchLevel(ln);
- for (hier::PatchLevel::Iterator p(level); p; p++) {
- tbox::Pointer<hier::Patch> patch = *p;
- tbox::Pointer<geom::CartesianPatchGeometry> patch_geometry =
- patch->getPatchGeometry();
- const double* dx = patch_geometry->getDx();
- double cell_vol = dx[0];
- if (d_dim > tbox::Dimension(1)) {
- cell_vol *= dx[1];
- }
-
- if (d_dim > tbox::Dimension(2)) {
- cell_vol *= dx[2];
- }
-
- tbox::Pointer<pdat::CellData<double> > w =
- patch->getPatchData(weight_id);
- if (!w) {
- TBOX_ERROR(d_object_name
- << ": weight id must refer to a pdat::CellVariable");
- }
- w->fillAll(cell_vol);
- }
-
- /*
- * On all but the finest level, assign 0 to vector
- * weight to cells covered by finer cells.
- */
-
- if (ln < finest_ln) {
-
- /*
- * First get the boxes that describe index space of the next finer
- * level and coarsen them to describe corresponding index space
- * at this level.
- */
-
- tbox::Pointer<hier::PatchLevel> next_finer_level =
- hierarchy->getPatchLevel(ln + 1);
- hier::BoxArray coarsened_boxes = next_finer_level->getBoxes();
- hier::IntVector coarsen_ratio(next_finer_level->getRatioToLevelZero());
- coarsen_ratio /= level->getRatioToLevelZero();
- coarsened_boxes.coarsen(coarsen_ratio);
-
- /*
- * Then set vector weight to 0 wherever there is
- * a nonempty intersection with the next finer level.
- * Note that all assignments are local.
- */
-
- for (hier::PatchLevel::Iterator p(level); p; p++) {
-
- tbox::Pointer<hier::Patch> patch = *p;
- for (int i = 0; i < coarsened_boxes.getNumberOfBoxes(); i++) {
-
- hier::Box coarse_box = coarsened_boxes[i];
- hier::Box intersection = coarse_box * (patch->getBox());
- if (!intersection.empty()) {
- tbox::Pointer<pdat::CellData<double> > w =
- patch->getPatchData(weight_id);
- w->fillAll(0.0, intersection);
-
- } // assignment only in non-empty intersection
- } // loop over coarsened boxes from finer level
- } // loop over patches in level
- } // all levels except finest
- } // loop over levels
-}
-
-/*
- ********************************************************************
- * Check the validity and correctness of input data for this class. *
- ********************************************************************
- */
-
-void CellStokesFACOps::checkInputPatchDataIndices() const {
- /*
- * Check input validity and correctness.
- */
- hier::VariableDatabase& vdb(*hier::VariableDatabase::getDatabase());
-
- if (!d_stokes_spec.dIsConstant()
- && d_stokes_spec.getDPatchDataId() != -1) {
- tbox::Pointer<hier::Variable> var;
- vdb.mapIndexToVariable(d_stokes_spec.getDPatchDataId(), var);
- tbox::Pointer<pdat::SideVariable<double> > diffcoef_var = var;
- if (!diffcoef_var) {
- TBOX_ERROR(d_object_name
- << ": Bad diffusion coefficient patch data index.");
- }
- }
-
- if (!d_stokes_spec.cIsConstant() && !d_stokes_spec.cIsZero()) {
- tbox::Pointer<hier::Variable> var;
- vdb.mapIndexToVariable(d_stokes_spec.getCPatchDataId(), var);
- tbox::Pointer<pdat::CellVariable<double> > scalar_field_var = var;
- if (!scalar_field_var) {
- TBOX_ERROR(d_object_name << ": Bad linear term patch data index.");
- }
- }
-
- if (d_flux_id != -1) {
- tbox::Pointer<hier::Variable> var;
- vdb.mapIndexToVariable(d_flux_id, var);
- tbox::Pointer<pdat::SideVariable<double> > flux_var = var;
-
- TBOX_ASSERT(flux_var);
- }
-
-}
-
-/*
- *******************************************************************
- * *
- * AMR-unaware patch-centered computational kernels. *
- * *
- *******************************************************************
- */
-
-void CellStokesFACOps::computeFluxOnPatch(
- const hier::Patch& patch,
- const hier::IntVector& ratio_to_coarser_level,
- const pdat::CellData<double>& w_data,
- pdat::SideData<double>& Dgradw_data) const
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim, patch, ratio_to_coarser_level, w_data,
- Dgradw_data);
- TBOX_ASSERT(patch.inHierarchy());
- TBOX_ASSERT(w_data.getGhostCellWidth() >=
- hier::IntVector::getOne(ratio_to_coarser_level.getDim()));
-
- tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
- patch.getPatchGeometry();
- const hier::Box& box = patch.getBox();
- const int* lower = &box.lower()[0];
- const int* upper = &box.upper()[0];
- const double* dx = patch_geom->getDx();
-
- double D_value;
- tbox::Pointer<pdat::SideData<double> > D_data;
- if (d_stokes_spec.dIsConstant()) {
- D_value = d_stokes_spec.getDConstant();
- } else {
- D_data = patch.getPatchData(d_stokes_spec.getDPatchDataId());
- }
-
- if (d_stokes_spec.dIsConstant()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compfluxcondc2d, COMPFLUXCONDC2D) (
- Dgradw_data.getPointer(0),
- Dgradw_data.getPointer(1),
- &Dgradw_data.getGhostCellWidth()[0],
- &Dgradw_data.getGhostCellWidth()[1],
- D_value,
- w_data.getPointer(),
- &w_data.getGhostCellWidth()[0],
- &w_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compfluxcondc3d, COMPFLUXCONDC3D) (
- Dgradw_data.getPointer(0),
- Dgradw_data.getPointer(1),
- Dgradw_data.getPointer(2),
- &Dgradw_data.getGhostCellWidth()[0],
- &Dgradw_data.getGhostCellWidth()[1],
- &Dgradw_data.getGhostCellWidth()[2],
- D_value,
- w_data.getPointer(),
- &w_data.getGhostCellWidth()[0],
- &w_data.getGhostCellWidth()[1],
- &w_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx);
- }
- } else {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compfluxvardc2d, COMPFLUXVARDC2D) (
- Dgradw_data.getPointer(0),
- Dgradw_data.getPointer(1),
- &Dgradw_data.getGhostCellWidth()[0],
- &Dgradw_data.getGhostCellWidth()[1],
- D_data->getPointer(0),
- D_data->getPointer(1),
- &D_data->getGhostCellWidth()[0],
- &D_data->getGhostCellWidth()[1],
- w_data.getPointer(),
- &w_data.getGhostCellWidth()[0],
- &w_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx);
- }
- if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compfluxvardc3d, COMPFLUXVARDC3D) (
- Dgradw_data.getPointer(0),
- Dgradw_data.getPointer(1),
- Dgradw_data.getPointer(2),
- &Dgradw_data.getGhostCellWidth()[0],
- &Dgradw_data.getGhostCellWidth()[1],
- &Dgradw_data.getGhostCellWidth()[2],
- D_data->getPointer(0),
- D_data->getPointer(1),
- D_data->getPointer(2),
- &D_data->getGhostCellWidth()[0],
- &D_data->getGhostCellWidth()[1],
- &D_data->getGhostCellWidth()[2],
- w_data.getPointer(),
- &w_data.getGhostCellWidth()[0],
- &w_data.getGhostCellWidth()[1],
- &w_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx);
- }
- }
-
- const int patch_ln = patch.getPatchLevelNumber();
-
- if (d_cf_discretization == "Ewing" && patch_ln > d_ln_min) {
- ewingFixFlux(patch,
- w_data,
- Dgradw_data,
- ratio_to_coarser_level);
- }
-
-}
-
-void CellStokesFACOps::computeResidualOnPatch(
- const hier::Patch& patch,
- const pdat::SideData<double>& flux_data,
- const pdat::CellData<double>& soln_data,
- const pdat::CellData<double>& rhs_data,
- pdat::CellData<double>& residual_data) const
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS5(d_dim, patch, flux_data, soln_data, rhs_data,
- residual_data);
-
- tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
- patch.getPatchGeometry();
- const hier::Box& box = patch.getBox();
- const int* lower = &box.lower()[0];
- const int* upper = &box.upper()[0];
- const double* dx = patch_geom->getDx();
-
- tbox::Pointer<pdat::CellData<double> > scalar_field_data;
- double scalar_field_constant;
- if (d_stokes_spec.cIsVariable()) {
- scalar_field_data =
- patch.getPatchData(d_stokes_spec.getCPatchDataId());
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compresvarsca2d, COMPRESVARSCA2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- residual_data.getPointer(),
- &residual_data.getGhostCellWidth()[0],
- &residual_data.getGhostCellWidth()[1],
- scalar_field_data->getPointer(),
- &scalar_field_data->getGhostCellWidth()[0],
- &scalar_field_data->getGhostCellWidth()[1],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0], &lower[1], &upper[1],
- dx);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compresvarsca3d, COMPRESVARSCA3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- residual_data.getPointer(),
- &residual_data.getGhostCellWidth()[0],
- &residual_data.getGhostCellWidth()[1],
- &residual_data.getGhostCellWidth()[2],
- scalar_field_data->getPointer(),
- &scalar_field_data->getGhostCellWidth()[0],
- &scalar_field_data->getGhostCellWidth()[1],
- &scalar_field_data->getGhostCellWidth()[2],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0], &lower[1], &upper[1], &lower[2], &upper[2],
- dx);
- }
- } else if (d_stokes_spec.cIsConstant()) {
- scalar_field_constant = d_stokes_spec.getCConstant();
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compresconsca2d, COMPRESCONSCA2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- residual_data.getPointer(),
- &residual_data.getGhostCellWidth()[0],
- &residual_data.getGhostCellWidth()[1],
- scalar_field_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0], &lower[1], &upper[1],
- dx);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compresconsca3d, COMPRESCONSCA3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- residual_data.getPointer(),
- &residual_data.getGhostCellWidth()[0],
- &residual_data.getGhostCellWidth()[1],
- &residual_data.getGhostCellWidth()[2],
- scalar_field_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0], &lower[1], &upper[1], &lower[2], &upper[2],
- dx);
- }
- } else {
- scalar_field_constant = 0.0;
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compresconsca2d, COMPRESCONSCA2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- residual_data.getPointer(),
- &residual_data.getGhostCellWidth()[0],
- &residual_data.getGhostCellWidth()[1],
- 0.0,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0], &lower[1], &upper[1],
- dx);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compresconsca3d, COMPRESCONSCA3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- residual_data.getPointer(),
- &residual_data.getGhostCellWidth()[0],
- &residual_data.getGhostCellWidth()[1],
- &residual_data.getGhostCellWidth()[2],
- 0.0,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0], &lower[1], &upper[1], &lower[2], &upper[2],
- dx);
- }
- }
-}
-
-void CellStokesFACOps::redOrBlackSmoothingOnPatch(
- const hier::Patch& patch,
- const pdat::SideData<double>& flux_data,
- const pdat::CellData<double>& rhs_data,
- pdat::CellData<double>& soln_data,
- char red_or_black,
- double* p_maxres) const
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim, patch, flux_data, soln_data, rhs_data);
- TBOX_ASSERT(red_or_black == 'r' || red_or_black == 'b');
-
- const int offset = red_or_black == 'r' ? 0 : 1;
- tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
- patch.getPatchGeometry();
- const hier::Box& box = patch.getBox();
- const int* lower = &box.lower()[0];
- const int* upper = &box.upper()[0];
- const double* dx = patch_geom->getDx();
-
- tbox::Pointer<pdat::CellData<double> > scalar_field_data;
- double scalar_field_constant;
- tbox::Pointer<pdat::SideData<double> > diffcoef_data;
- double diffcoef_constant;
-
- if (d_stokes_spec.cIsVariable()) {
- scalar_field_data =
- patch.getPatchData(d_stokes_spec.getCPatchDataId());
- } else if (d_stokes_spec.cIsConstant()) {
- scalar_field_constant = d_stokes_spec.getCConstant();
- } else {
- scalar_field_constant = 0.0;
- }
- if (d_stokes_spec.dIsVariable()) {
- diffcoef_data = patch.getPatchData(d_stokes_spec.getDPatchDataId());
- } else {
- diffcoef_constant = d_stokes_spec.getDConstant();
- }
-
- double maxres = 0.0;
- if (d_stokes_spec.dIsVariable() && d_stokes_spec.cIsVariable()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(rbgswithfluxmaxvardcvarsf2d, RBGSWITHFLUXMAXVARDCVARSF2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- scalar_field_data->getPointer(),
- &scalar_field_data->getGhostCellWidth()[0],
- &scalar_field_data->getGhostCellWidth()[1],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx,
- &offset, &maxres);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(rbgswithfluxmaxvardcvarsf3d, RBGSWITHFLUXMAXVARDCVARSF3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- diffcoef_data->getPointer(2),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- &diffcoef_data->getGhostCellWidth()[2],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- scalar_field_data->getPointer(),
- &scalar_field_data->getGhostCellWidth()[0],
- &scalar_field_data->getGhostCellWidth()[1],
- &scalar_field_data->getGhostCellWidth()[2],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx,
- &offset, &maxres);
- }
- } else if (d_stokes_spec.dIsVariable() && d_stokes_spec.cIsConstant()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(rbgswithfluxmaxvardcconsf2d, RBGSWITHFLUXMAXVARDCCONSF2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- scalar_field_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx,
- &offset, &maxres);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(rbgswithfluxmaxvardcconsf3d, RBGSWITHFLUXMAXVARDCCONSF3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- diffcoef_data->getPointer(2),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- &diffcoef_data->getGhostCellWidth()[2],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- scalar_field_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx,
- &offset, &maxres);
- }
- } else if (d_stokes_spec.dIsVariable() && d_stokes_spec.cIsZero()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(rbgswithfluxmaxvardcconsf2d, RBGSWITHFLUXMAXVARDCCONSF2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- 0.0,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx,
- &offset, &maxres);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(rbgswithfluxmaxvardcconsf3d, RBGSWITHFLUXMAXVARDCCONSF3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_data->getPointer(0),
- diffcoef_data->getPointer(1),
- diffcoef_data->getPointer(2),
- &diffcoef_data->getGhostCellWidth()[0],
- &diffcoef_data->getGhostCellWidth()[1],
- &diffcoef_data->getGhostCellWidth()[2],
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- 0.0,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx,
- &offset, &maxres);
- }
- } else if (!d_stokes_spec.dIsVariable() && d_stokes_spec.cIsVariable()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(rbgswithfluxmaxcondcvarsf2d, RBGSWITHFLUXMAXCONDCVARSF2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_constant,
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- scalar_field_data->getPointer(),
- &scalar_field_data->getGhostCellWidth()[0],
- &scalar_field_data->getGhostCellWidth()[1],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx,
- &offset, &maxres);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(rbgswithfluxmaxcondcvarsf3d, RBGSWITHFLUXMAXCONDCVARSF3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_constant,
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- scalar_field_data->getPointer(),
- &scalar_field_data->getGhostCellWidth()[0],
- &scalar_field_data->getGhostCellWidth()[1],
- &scalar_field_data->getGhostCellWidth()[2],
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx,
- &offset, &maxres);
- }
- } else if (!d_stokes_spec.dIsVariable() && d_stokes_spec.cIsConstant()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(rbgswithfluxmaxcondcconsf2d, RBGSWITHFLUXMAXCONDCCONSF2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_constant,
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- scalar_field_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx,
- &offset, &maxres);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(rbgswithfluxmaxcondcconsf3d, RBGSWITHFLUXMAXCONDCCONSF3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_constant,
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- scalar_field_constant,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx,
- &offset, &maxres);
- }
- } else if (!d_stokes_spec.dIsVariable() && d_stokes_spec.cIsZero()) {
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(rbgswithfluxmaxcondcconsf2d, RBGSWITHFLUXMAXCONDCCONSF2D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- diffcoef_constant,
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- 0.0,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- dx,
- &offset, &maxres);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(rbgswithfluxmaxcondcconsf3d, RBGSWITHFLUXMAXCONDCCONSF3D) (
- flux_data.getPointer(0),
- flux_data.getPointer(1),
- flux_data.getPointer(2),
- &flux_data.getGhostCellWidth()[0],
- &flux_data.getGhostCellWidth()[1],
- &flux_data.getGhostCellWidth()[2],
- diffcoef_constant,
- rhs_data.getPointer(),
- &rhs_data.getGhostCellWidth()[0],
- &rhs_data.getGhostCellWidth()[1],
- &rhs_data.getGhostCellWidth()[2],
- 0.0,
- soln_data.getPointer(),
- &soln_data.getGhostCellWidth()[0],
- &soln_data.getGhostCellWidth()[1],
- &soln_data.getGhostCellWidth()[2],
- &lower[0], &upper[0],
- &lower[1], &upper[1],
- &lower[2], &upper[2],
- dx,
- &offset, &maxres);
- }
- }
-
- *p_maxres = maxres;
-}
-
-void
-CellStokesFACOps::xeqScheduleProlongation(
- int dst_id,
- int src_id,
- int scr_id,
- int dest_ln)
-{
- if (!d_prolongation_refine_schedules[dest_ln]) {
- TBOX_ERROR("Expected schedule not found.");
- }
- xfer::RefineAlgorithm refiner(d_dim);
- refiner.
- registerRefine(dst_id,
- src_id,
- scr_id,
- d_prolongation_refine_operator);
- refiner.
- resetSchedule(d_prolongation_refine_schedules[dest_ln]);
- d_prolongation_refine_schedules[dest_ln]->fillData(0.0);
- d_prolongation_refine_algorithm->
- resetSchedule(d_prolongation_refine_schedules[dest_ln]);
-}
-
-void
-CellStokesFACOps::xeqScheduleURestriction(
- int dst_id,
- int src_id,
- int dest_ln)
-{
- if (!d_urestriction_coarsen_schedules[dest_ln]) {
- TBOX_ERROR("Expected schedule not found.");
- }
-
- xfer::CoarsenAlgorithm coarsener(d_dim);
- coarsener.registerCoarsen(dst_id,
- src_id,
- d_urestriction_coarsen_operator);
- coarsener.resetSchedule(d_urestriction_coarsen_schedules[dest_ln]);
- d_urestriction_coarsen_schedules[dest_ln]->coarsenData();
- d_urestriction_coarsen_algorithm->
- resetSchedule(d_urestriction_coarsen_schedules[dest_ln]);
-}
-
-void
-CellStokesFACOps::xeqScheduleRRestriction(
- int dst_id,
- int src_id,
- int dest_ln)
-{
- if (!d_rrestriction_coarsen_schedules[dest_ln]) {
- TBOX_ERROR("Expected schedule not found.");
- }
-
- xfer::CoarsenAlgorithm coarsener(d_dim);
- coarsener.registerCoarsen(dst_id,
- src_id,
- d_rrestriction_coarsen_operator);
- coarsener.resetSchedule(d_rrestriction_coarsen_schedules[dest_ln]);
- d_rrestriction_coarsen_schedules[dest_ln]->coarsenData();
- d_rrestriction_coarsen_algorithm->
- resetSchedule(d_rrestriction_coarsen_schedules[dest_ln]);
-}
-
-void
-CellStokesFACOps::xeqScheduleFluxCoarsen(
- int dst_id,
- int src_id,
- int dest_ln)
-{
- if (!d_flux_coarsen_schedules[dest_ln]) {
- TBOX_ERROR("Expected schedule not found.");
- }
-
- xfer::CoarsenAlgorithm coarsener(d_dim);
- coarsener.registerCoarsen(dst_id,
- src_id,
- d_flux_coarsen_operator);
-
- coarsener.resetSchedule(d_flux_coarsen_schedules[dest_ln]);
- d_flux_coarsen_schedules[dest_ln]->coarsenData();
- d_flux_coarsen_algorithm->
- resetSchedule(d_flux_coarsen_schedules[dest_ln]);
-}
-
-void
-CellStokesFACOps::xeqScheduleGhostFill(
- int dst_id,
- int dest_ln)
-{
- if (!d_ghostfill_refine_schedules[dest_ln]) {
- TBOX_ERROR("Expected schedule not found.");
- }
- xfer::RefineAlgorithm refiner(d_dim);
- refiner.
- registerRefine(dst_id,
- dst_id,
- dst_id,
- d_ghostfill_refine_operator);
- refiner.
- resetSchedule(d_ghostfill_refine_schedules[dest_ln]);
- d_ghostfill_refine_schedules[dest_ln]->fillData(0.0);
- d_ghostfill_refine_algorithm->
- resetSchedule(d_ghostfill_refine_schedules[dest_ln]);
-}
-
-void
-CellStokesFACOps::xeqScheduleGhostFillNoCoarse(
- int dst_id,
- int dest_ln)
-{
- if (!d_ghostfill_nocoarse_refine_schedules[dest_ln]) {
- TBOX_ERROR("Expected schedule not found.");
- }
- xfer::RefineAlgorithm refiner(d_dim);
- refiner.
- registerRefine(dst_id,
- dst_id,
- dst_id,
- d_ghostfill_nocoarse_refine_operator);
- refiner.
- resetSchedule(d_ghostfill_nocoarse_refine_schedules[dest_ln]);
- d_ghostfill_nocoarse_refine_schedules[dest_ln]->fillData(0.0);
- d_ghostfill_nocoarse_refine_algorithm->
- resetSchedule(d_ghostfill_nocoarse_refine_schedules[dest_ln]);
-}
-
-void
-CellStokesFACOps::finalizeCallback()
-{
- for (int d = 0; d < tbox::Dimension::MAXIMUM_DIMENSION_VALUE; ++d) {
- s_cell_scratch_var[d].setNull();
- s_flux_scratch_var[d].setNull();
- s_oflux_scratch_var[d].setNull();
- }
-}
-
-}
-}
-#endif
diff -r a44a82f15794 -r fe2a9230921b CellStokesFACOps.I
--- a/CellStokesFACOps.I Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: Operator class for solving scalar Stokes using FAC
- *
- ************************************************************************/
-namespace SAMRAI {
-namespace solv {
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setPreconditioner(
- const FACPreconditioner* preconditioner) {
- d_preconditioner = preconditioner;
-}
-
-#ifdef HAVE_HYPRE
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setUseSMG(
- bool use_smg)
-{
- if (d_hierarchy) {
- TBOX_ERROR(
- d_object_name << ": setUseSMG(bool) may NOT be called\n"
- <<
- "while the solver state is initialized, as that\n"
- << "would lead to a corrupted solver state.\n");
- }
- d_hypre_solver.setUseSMG(use_smg);
-}
-#endif
-
-/*
- ********************************************************************
- * Set the physical boundary condition object. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setPhysicalBcCoefObject(
- const RobinBcCoefStrategy* physical_bc_coef)
-{
- d_physical_bc_coef = physical_bc_coef;
- d_bc_helper.setCoefImplementation(physical_bc_coef);
-#ifdef HAVE_HYPRE
- d_hypre_solver.setPhysicalBcCoefObject(d_physical_bc_coef);
-#endif
-}
-
-/*
- ********************************************************************
- * Set the object specifying the parameters of the Stokes equation *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setStokesSpecifications(
- const StokesSpecifications& spec)
-{
- d_stokes_spec = spec;
-}
-
-/*
- ********************************************************************
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::enableLogging(
- bool enable_logging)
-{
- d_enable_logging = enable_logging;
-}
-
-/*
- ********************************************************************
- * Set the patch data id for the flux. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setFluxId(
- int flux_id) {
- d_flux_id = flux_id;
-#ifdef DEBUG_CHECK_ASSERTIONS
- checkInputPatchDataIndices();
-#endif
-}
-
-/*
- ********************************************************************
- * Set the choice for smoothing algorithm. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setSmoothingChoice(
- const std::string& smoothing_choice)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (smoothing_choice != "redblack") {
- TBOX_ERROR(d_object_name << ": Bad smoothing choice '"
- << smoothing_choice
- << "' in CellStokesFACOps::setSmoothingChoice.");
- }
-#endif
- d_smoothing_choice = smoothing_choice;
-}
-
-/*
- ********************************************************************
- * Set the choice for the coarse level solver. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setCoarsestLevelSolverChoice(
- const std::string& choice) {
-#ifdef DEBUG_CHECK_ASSERTIONS
-#ifndef HAVE_HYPRE
- if (choice == "hypre") {
- TBOX_ERROR(d_object_name << ": HYPRe library is not available.\n");
- }
-#endif
-#endif
- if (choice == "redblack"
- || choice == "hypre") {
- d_coarse_solver_choice = choice;
- } else {
- TBOX_ERROR(
- d_object_name << ": Bad coarse level solver choice '"
- << choice
- <<
- "' in scapCellStokesOpsX::setCoarseLevelSolver.");
- }
-}
-
-/*
- ********************************************************************
- * Set the tolerance for the coarse level solver. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setCoarsestLevelSolverTolerance(
- double tol) {
- d_coarse_solver_tolerance = tol;
-}
-
-/*
- ********************************************************************
- * Set the tolerance for the coarse level solver. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setCoarsestLevelSolverMaxIterations(
- int max_iterations) {
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (max_iterations < 0) {
- TBOX_ERROR(d_object_name << ": Invalid number of max iterations\n");
- }
-#endif
- d_coarse_solver_max_iterations = max_iterations;
-}
-
-/*
- ********************************************************************
- * Set the coarse-fine discretization method. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setCoarseFineDiscretization(
- const std::string& coarsefine_method) {
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (d_hierarchy) {
- TBOX_ERROR(
- d_object_name << ": Cannot change coarse-fine\n"
- <<
- "discretization method while operator state\n"
- << "is initialized because that causes a\n"
- << "corruption in the state.\n");
- }
-#endif
- d_cf_discretization = coarsefine_method;
-}
-
-/*
- ********************************************************************
- * Set the prolongation method *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACOps::setProlongationMethod(
- const std::string& prolongation_method) {
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (d_hierarchy) {
- TBOX_ERROR(
- d_object_name << ": Cannot change prolongation method\n"
- <<
- "while operator state is initialized because that\n"
- << "causes a corruption in the state.\n");
- }
-#endif
- d_prolongation_method = prolongation_method;
-}
-
-}
-}
diff -r a44a82f15794 -r fe2a9230921b CellStokesFACOps.h
--- a/CellStokesFACOps.h Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1044 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: Operator class for cell-centered scalar Stokes using FAC
- *
- ************************************************************************/
-#ifndef included_solv_CellStokesFACOps
-#define included_solv_CellStokesFACOps
-
-#include "SAMRAI/SAMRAI_config.h"
-
-#include "SAMRAI/solv/CartesianRobinBcHelper.h"
-#include "SAMRAI/solv/FACPreconditioner.h"
-#include "SAMRAI/solv/FACOperatorStrategy.h"
-#include "SAMRAI/solv/RobinBcCoefStrategy.h"
-#include "CellStokesHypreSolver.h"
-#include "SAMRAI/solv/SAMRAIVectorReal.h"
-#include "StokesSpecifications.h"
-#include "SAMRAI/math/HierarchyCellDataOpsReal.h"
-#include "SAMRAI/math/HierarchySideDataOpsReal.h"
-#include "SAMRAI/pdat/CellData.h"
-#include "SAMRAI/pdat/CellVariable.h"
-#include "SAMRAI/pdat/CellDoubleConstantRefine.h"
-#include "SAMRAI/pdat/OutersideData.h"
-#include "SAMRAI/pdat/OutersideVariable.h"
-#include "SAMRAI/pdat/SideData.h"
-#include "SAMRAI/pdat/SideVariable.h"
-#include "SAMRAI/xfer/CoarsenSchedule.h"
-#include "SAMRAI/xfer/RefineSchedule.h"
-#include "SAMRAI/xfer/CoarsenAlgorithm.h"
-#include "SAMRAI/xfer/CoarsenOperator.h"
-#include "SAMRAI/xfer/RefineAlgorithm.h"
-#include "SAMRAI/xfer/RefineOperator.h"
-#include "SAMRAI/hier/CoarseFineBoundary.h"
-#include "SAMRAI/hier/Patch.h"
-#include "SAMRAI/hier/PatchHierarchy.h"
-#include "SAMRAI/hier/PatchLevel.h"
-#include "SAMRAI/hier/IntVector.h"
-#include "SAMRAI/hier/Box.h"
-#include "SAMRAI/hier/VariableContext.h"
-#include "SAMRAI/tbox/Database.h"
-#include "SAMRAI/tbox/Pointer.h"
-#include "SAMRAI/tbox/Timer.h"
-
-#include <string>
-
-namespace SAMRAI {
-namespace solv {
-
-/*!
- * @brief FAC operator class to solve Stokes's equation on a SAMR grid,
- * using cell-centered, second-order finite-volume method, with Robin
- * boundary conditions.
- *
- * This class provides operators that are used by the FAC
- * preconditioner FACPreconditioner.
- * It is used to solve the scalar Stokes's equation using a cell-centered
- * second-order finite-volume discretization.
- * It is designed to provide all operations specific to
- * the scalar Stokes's equation,
- * @f[ \nabla \cdot D \nabla u + C u = f @f]
- * (see StokesSpecifications) where
- * - C, D and f are indpendent of u
- * - C is a cell-centered scalar field
- * - D is the @em diffusion @em coefficients, stored on faces
- * - f is a cell-centered scalar function
- *
- * You are left to provide the source function, initial guess, etc.,
- * by specifying them in specific forms.
- *
- * This class provides:
- * -# 5-point (second order), cell-centered stencil operations
- * for the discrete Laplacian.
- * -# Red-black Gauss-Seidel smoothing.
- * -# Provisions for working Robin boundary conditions
- * (see RobinBcCoefStrategy).
- *
- * This class is meant to provide the Stokes-specific operator
- * used by the FAC preconditioner, FACPreconditioner.
- * To use the preconditioner with this class, you will have to provide:
- * -# The solution vector SAMRAIVectorReal,
- * with appropriate norm weighting for the cell-centered AMR mesh.
- * This class provides the function computeVectorWeights()
- * to help with computing the appropriate weights.
- * Since this is for a scalar equation, only the first depth
- * of the first component of the vectors are used.
- * All other parts are ignored.
- * -# The source vector SAMRAIVectorReal for f.
- * -# A StokesSpecifications objects to specify
- * the cell-centered scalar field C and the side-centered
- * diffusion coefficients D
- * -# The boundary condition specifications in terms of the coefficients
- * @f$ \alpha @f$, @f$ \beta @f$ and @f$ \gamma @f$ in the
- * Robin formula @f$ \alpha u + \beta u_n = \gamma @f$ applied on the
- * boundary faces. See RobinBcCoefStrategy.
- *
- * This class allocates and deallocates only its own scratch data.
- * Other data that it manipuates are passed in as function arguments.
- * Hence, it owns none of the solution vectors, error vectors,
- * diffusion coefficient data, or any such things.
- *
- * Input Examples
- * @verbatim
- * coarse_solver_choice = "hypre" // see setCoarsestLevelSolverChoice()
- * coarse_solver_tolerance = 1e-14 // see setCoarsestLevelSolverTolerance()
- * coarse_solver_max_iterations = 10 // see setCoarsestLevelSolverMaxIterations()
- * smoothing_choice = "redblack" // see setSmoothingChoice()
- * cf_discretization = "Ewing" // see setCoarseFineDiscretization()
- * prolongation_method = "LINEAR_REFINE" // see setProlongationMethod()
- * hypre_solver = { ... } // tbox::Database for initializing Hypre solver
- * @endverbatim
- */
-class CellStokesFACOps:
- public FACOperatorStrategy
-{
-
-public:
- /*!
- * @brief Constructor.
- *
- * If you want standard output and logging,
- * pass in valid pointers for those streams.
- * @param object_name Ojbect name
- * @param database Input database
- */
- CellStokesFACOps(
- const tbox::Dimension& dim,
- const std::string& object_name = std::string(),
- tbox::Pointer<tbox::Database> database =
- tbox::Pointer<tbox::Database>(NULL));
-
- /*!
- * @brief Destructor.
- *
- * Deallocate internal data.
- */
- ~CellStokesFACOps(
- void);
-
- /*!
- * @brief Set the scalar Stokes equation specifications.
- */
- void
- setStokesSpecifications(
- const StokesSpecifications& spec);
-
- /*!
- * @brief Enable logging.
- *
- * By default, logging is disabled. The logging flag is
- * propagated to the major components used by this class.
- */
- void
- enableLogging(
- bool enable_logging);
-
- //@{
- /*!
- * @name Functions for setting solver mathematic algorithm controls
- */
-
- /*!
- * @brief Set the choice of smoothing algorithms.
- *
- * Current smoothing choices are:
- * - "redblack": Red-black Gauss-Seidel smoothing.
- */
- void
- setSmoothingChoice(
- const std::string& smoothing_choice);
-
- /*!
- * @brief Set coarse level solver.
- *
- * Select from these:
- * - @c "redblack" (red-black smoothing until convergence--very slow!)
- * - @c "hypre" (only if the HYPRE library is available).
- */
- void
- setCoarsestLevelSolverChoice(
- const std::string& choice);
-
- /*!
- * @brief Set tolerance for coarse level solve.
- *
- * If the coarse level solver requires a tolerance (currently, they all do),
- * the specified value is used.
- */
- void
- setCoarsestLevelSolverTolerance(
- double tol);
-
- /*!
- * @brief Set max iterations for coarse level solve.
- *
- * If the coarse level solver requires a max iteration limit
- * (currently, they all do), the specified value is used.
- */
- void
- setCoarsestLevelSolverMaxIterations(
- int max_iterations);
-
- /*!
- * @brief Set the coarse-fine boundary discretization method.
- *
- * Specify the @c op_name std::string which will be passed to
- * xfer::Geometry::lookupRefineOperator() to get the operator
- * for setting fine grid ghost cells from the coarse grid.
- * Note that chosing this operator implicitly choses the
- * discretization method at the coarse-fine boundary.
- *
- * There is one important instance where this std::string is
- * @em not passed to xfer::Geometry::lookupRefineOperator.
- * If this variable is set to "Ewing", Ewing's coarse-fine
- * discretization is used (a constant refinement is performed,
- * and the flux is later corrected to result in Ewing's scheme).
- * For a reference to Ewing's discretization method, see
- * "Local Refinement Techniques for Elliptic Problems on Cell-Centered
- * Grids, I. Error Analysis", Mathematics of Computation, Vol. 56, No. 194,
- * April 1991, pp. 437-461.
- *
- * @param coarsefine_method String selecting the coarse-fine discretization method.
- */
- void
- setCoarseFineDiscretization(
- const std::string& coarsefine_method);
-
- /*!
- * @brief Set the name of the prolongation method.
- *
- * Specify the @c op_name std::string which will be passed to
- * xfer::Geometry::lookupRefineOperator() to get the operator
- * for prolonging the coarse-grid correction.
- *
- * By default, "CONSTANT_REFINE" is used. "LINEAR_REFINE" seems to
- * to lead to faster convergence, but it does NOT satisfy the Galerkin
- * condition.
- *
- * Prolonging using linear refinement requires a Robin bc
- * coefficient implementation that is capable of delivering
- * coefficients for non-hierarchy data, because linear refinement
- * requires boundary conditions to be set on temporary levels.
- *
- * @param prolongation_method String selecting the coarse-fine
- * discretization method.
- */
- void
- setProlongationMethod(
- const std::string& prolongation_method);
-
-#ifdef HAVE_HYPRE
- /*!
- * @brief Set whether to use Hypre's PFMG algorithm instead of the
- * SMG algorithm.
- *
- * This flag affects the Hypre solver (used to solve the coarsest level).
- * The flag is used to select which of HYPRE's linear solver algorithms
- * to use if true, the semicoarsening multigrid algorithm is used, and if
- * false, the ``PF'' multigrid algorithm is used.
- * By default, the SMG algorithm is used.
- *
- * This setting has effect only when Hypre is chosen for the coarsest
- * level solver. See setCoarsestLevelSolverChoice().
- *
- * Changing the algorithm must be done before initializing the solver
- * state and must NOT be done while the state is initialized
- * (the program will exit), as that would corrupt the state.
- */
- void
- setUseSMG(
- bool use_smg);
-#endif
-
- //@}
-
- //@{
- /*!
- * @name Functions for setting patch data indices and coefficients
- */
-
- /*!
- * @brief Set the scratch patch data index for the flux.
- *
- * The use of this function is optional.
- * The patch data index should be a pdat::SideData<DIM> type of variable.
- * If the flux id is -1 (the default initial value), scratch space
- * for the flux is allocated as needed and immediately deallocated
- * afterward, level by level. If you have space preallocated for
- * flux and you would like that to be used, set flux id to the
- * patch data index of that space.
- */
- void
- setFluxId(
- int flux_id);
-
- //@}
-
- /*!
- * @brief Provide an implementation for getting the
- * physical bc coefficients
- *
- * If your solution is fixed at the physical boundary
- * ghost cell centers AND those cells have the correct
- * values before entering solveSystem(), you may use a
- * GhostCellRobinBcCoefs object.
- *
- * If your solution is @b not fixed at the ghost cell centers,
- * the ghost cell values will change as the interior
- * cell values change. In those cases, the flexible
- * Robin boundary conditions are applied. You must
- * call this function to provide the implementation for
- * determining the boundary condition coefficients.
- *
- * @param physical_bc_coef tbox::Pointer to an object that can
- * set the Robin bc coefficients.
- */
- void
- setPhysicalBcCoefObject(
- const RobinBcCoefStrategy* physical_bc_coef);
-
- //@{
-
- /*!
- * @name Functions for checking validity and correctness of state.
- */
-
- /*!
- * @brief Check validity and correctness of input patch data indices.
- *
- * Descriptors checked:
- * -# Diffusion coefficient (see setDiffcoefId())
- * -# Flux (see setFluxId())
- * -# Source (see setScalarFieldId())
- */
- void
- checkInputPatchDataIndices() const;
-
- //@}
-
- /*!
- * @brief Set weight appropriate for computing vector norms.
- *
- * If you this function to set the weights used when you
- * SAMRAIVectorReal::addComponent, you can use the
- * vector norm functions of SAMRAIVectorReal, and
- * the weights will be used to blank out coarse grid
- * regions under fine grids.
- *
- * The weights computed are specific to the cell-centered
- * discretization used by this class. The weight is equal
- * to the cell volume if the cell has not been refined,
- * and zero if it has.
- *
- * This function is state-independent. All inputs are in
- * the argument list.
- *
- * @param hierarchy Hierarchy configuration to compute weights for
- * @param weight_id hier::Patch data index of the weight
- * @param coarsest_ln Coarsest level number. Must be included
- * in hierarchy. Must not be greater than @c finest_ln.
- * Default to 0.
- * @param finest_ln Finest level number. Must be included
- * in hierarchy. Must not be less than @c coarsest_ln.
- * Default to finest level in @c hierarchy.
- */
- void
- computeVectorWeights(
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- int weight_id,
- int coarsest_ln = -1,
- int finest_ln = -1) const;
-
- /*!
- * @brief Set the FAC preconditioner that will be using this object.
- *
- * The FAC preconditioner is accessed to get convergence data during
- * the cycle postprocessing step. It is optional.
- */
- void
- setPreconditioner(
- const FACPreconditioner* preconditioner);
-
- /*!
- * @brief function to compute flux, using general diffusion
- * coefficient data.
- *
- * Recall that this solver class discretizes the PDE
- * @f[ \nabla \cdot D \nabla u + C u = f @f] on an AMR grid. This member
- * function allows users of this solver class to compute gradient
- * terms, @f[ D \nabla w @f], in their code in a manner consistent with the
- * solver discretization. In particular, when solving PDE systems, it may
- * be necessary to discretize the gradient operator appearing in equations
- * not treated by the solver class in the same way as those treated by this
- * class. These funtions allow users to do this easily. The divergence
- * operator used in this solver is the standard sum of centered differences
- * involving flux terms on the cell sides computed by these routines.
- *
- * Note that the patch must exist on a level in an AMR hierarchy so that
- * the discretization can be computed properly at the coarse-fine interface.
- * Stokes coefficients C and D must exist on the patch, if they are variable.
- * Also, calling this function does not affect the internal solver state in any
- * way. However, the solver must be fully initialized before it is called and care
- * should be exercised to pass arguments so that the solver solution quantity and
- * other internal solver quantities are not adversely affected.
- *
- * @param patch patch on which computation will take place
- * @param ratio_to_coarser_level refinement ratio from coarser level to level
- * on which patch lives; if current patch level
- * is level zero, this is ignored
- * @param w_data cell-centered data
- * @param Dgradw_data side-centered flux data (i.e., D (grad w))
- */
- void
- computeFluxOnPatch(
- const hier::Patch& patch,
- const hier::IntVector& ratio_to_coarser_level,
- const pdat::CellData<double>& w_data,
- pdat::SideData<double>& Dgradw_data) const;
-
- //@{ @name FACOperatorStrategy virtuals
-
- virtual void
- restrictSolution(
- const SAMRAIVectorReal<double>& source,
- SAMRAIVectorReal<double>& dest,
- int dest_ln);
- virtual void
- restrictResidual(
- const SAMRAIVectorReal<double>& source,
- SAMRAIVectorReal<double>& dest,
- int dest_ln);
-
- virtual void
- prolongErrorAndCorrect(
- const SAMRAIVectorReal<double>& source,
- SAMRAIVectorReal<double>& dest,
- int dest_ln);
-
- virtual void
- smoothError(
- SAMRAIVectorReal<double>& error,
- const SAMRAIVectorReal<double>& residual,
- int ln,
- int num_sweeps);
-
- virtual int
- solveCoarsestLevel(
- SAMRAIVectorReal<double>& error,
- const SAMRAIVectorReal<double>& residual,
- int coarsest_ln);
-
- virtual void
- computeCompositeResidualOnLevel(
- SAMRAIVectorReal<double>& residual,
- const SAMRAIVectorReal<double>& solution,
- const SAMRAIVectorReal<double>& rhs,
- int ln,
- bool error_equation_indicator);
-
- virtual double
- computeResidualNorm(
- const SAMRAIVectorReal<double>& residual,
- int fine_ln,
- int coarse_ln);
-
- virtual void
- initializeOperatorState(
- const SAMRAIVectorReal<double>& solution,
- const SAMRAIVectorReal<double>& rhs);
-
- virtual void
- deallocateOperatorState();
-
- virtual void
- postprocessOneCycle(
- int fac_cycle_num,
- const SAMRAIVectorReal<double>& current_soln,
- const SAMRAIVectorReal<double>& residual);
-
- //@}
-
-private:
- //@{
- /*!
- * @name Private workhorse functions.
- */
-
- /*!
- * @brief Red-black Gauss-Seidel error smoothing on a level.
- *
- * Smoothes on the residual equation @f$ Ae=r @f$ on a level.
- *
- * @param error error vector
- * @param residual residual vector
- * @param ln level number
- * @param num_sweeps number of sweeps
- * @param residual_tolerance the maximum residual considered to be
- * converged
- */
- void
- smoothErrorByRedBlack(
- SAMRAIVectorReal<double>& error,
- const SAMRAIVectorReal<double>& residual,
- int ln,
- int num_sweeps,
- double residual_tolerance = -1.0);
-
- /*!
- * @brief Solve the coarsest level using HYPRE
- */
- int
- solveCoarsestLevel_HYPRE(
- SAMRAIVectorReal<double>& error,
- const SAMRAIVectorReal<double>& residual,
- int ln);
-
- /*!
- * @brief Fix flux per Ewing's coarse-fine boundary treatment.
- *
- * Ewing's coarse-fine boundary treatment can be implemented
- * using a constant refinement into the fine-grid ghost boundary,
- * naively computing the flux using the constant-refined data then
- * fixing up the flux to correct the error.
- *
- * To use this function
- * -# you must use constant refinement to fill the fine level ghost cells
- * -# the flux must first be computed and stored
- *
- * @param patch patch
- * @param soln_data cell-centered solution data
- * @param flux_data side-centered flux data
- * @param diffcoef_data side-centered diffusion coefficient data
- * @param cfb coarse-fine boundary object for the level
- * in which patch resides
- * @param ratio_to_coarser Refinement ratio to the next coarser level.
- */
- void
- ewingFixFlux(
- const hier::Patch& patch,
- const pdat::CellData<double>& soln_data,
- pdat::SideData<double>& flux_data,
- const hier::IntVector& ratio_to_coarser) const;
-
- /*!
- * @brief AMR-unaware function to compute residual on a single patch,
- * with variable scalar field.
- *
- * @param patch patch
- * @param flux_data side-centered flux data
- * @param soln_data cell-centered solution data
- * @param rhs_data cell-centered rhs data
- * @param residual_data cell-centered residual data
- */
- void
- computeResidualOnPatch(
- const hier::Patch& patch,
- const pdat::SideData<double>& flux_data,
- const pdat::CellData<double>& soln_data,
- const pdat::CellData<double>& rhs_data,
- pdat::CellData<double>& residual_data) const;
-
- /*!
- * @brief AMR-unaware function to red or black smoothing on a single patch,
- * for variable diffusion coefficient and variable scalar field.
- *
- * @param patch patch
- * @param flux_data side-centered flux data
- * @param rhs_data cell-centered rhs data
- * @param scalar_field_data
- * cell-centered scalar field data
- * @param soln_data cell-centered solution data
- * @param red_or_black red-black switch. Set to 'r' or 'b'.
- * @param p_maxres max residual output. Set to NULL to avoid computing.
- */
- void
- redOrBlackSmoothingOnPatch(
- const hier::Patch& patch,
- const pdat::SideData<double>& flux_data,
- const pdat::CellData<double>& rhs_data,
- pdat::CellData<double>& soln_data,
- char red_or_black,
- double* p_maxres = NULL) const;
-
- //@}
-
- //@{ @name For executing, caching and resetting communication schedules.
-
- /*!
- * @brief Execute a refinement schedule
- * for prolonging cell data.
- *
- * General notes regarding internal objects for communication:
- * We maintain objects to support caching schedules to improve
- * efficiency. Communication is needed in 5 distinct tasks.
- * -# Prolongation
- * -# Restriction
- * -# Flux coarsening. Changing the coarse grid flux to the
- * composite grid flux by coarsening the fine grid flux
- * at the coarse-fine boundaries.
- * -# Fill boundary data from other patches in the same level
- * and physical boundary condition.
- * -# Fill boundary data from same level, coarser levels
- * and physical boundary condition.
- *
- * For each task, we maintain a refine or coarsen operator,
- * and a array of communication schedules (one for each
- * destination level).
- *
- * The 5 member functions named @c xeqSchedule... execute
- * communication schedules appropriate for five specific tasks.
- * They use a cached schedule if possible or create and cache
- * a new schedule if needed. These functions and the data
- * they manipulate are as follows:
- * <ol>
- * <li> xeqScheduleProlongation():
- * d_prolongation_refine_operator
- * d_prolongation_refine_schedules
- * <li> xeqScheduleURestriction():
- * d_restriction_coarsen_operator,
- * d_urestriction_coarsen_schedules.
- * <li> xeqScheduleRRestriction():
- * d_restriction_coarsen_operator,
- * d_rrestriction_coarsen_schedules.
- * <li> xeqScheduleFluxCoarsen():
- * d_flux_coarsen_operator,
- * d_flux_coarsen_schedules.
- * <li> xeqScheduleGhostFill():
- * d_ghostfill_refine_operator,
- * d_ghostfill_refine_schedules.
- * <li> xeqScheduleGhostFillNoCoarse():
- * d_ghostfill_nocoarse_refine_operator,
- * d_ghostfill_nocoarse_refine_schedules.
- * </ol>
- *
- * @return refinement schedule for prolongation
- */
- void
- xeqScheduleProlongation(
- int dst_id,
- int src_id,
- int scr_id,
- int dest_ln);
-
- /*!
- * @brief Execute schedule for restricting solution to the specified
- * level or reregister an existing one.
- *
- * See general notes for xeqScheduleProlongation().
- *
- * @return coarsening schedule for restriction
- */
- void
- xeqScheduleURestriction(
- int dst_id,
- int src_id,
- int dest_ln);
-
- /*!
- * @brief Execute schedule for restricting residual to the specified
- * level or reregister an existing one.
- *
- * See general notes for xeqScheduleProlongation().
- *
- * @return coarsening schedule for restriction
- */
- void
- xeqScheduleRRestriction(
- int dst_id,
- int src_id,
- int dest_ln);
-
- /*!
- * @brief Execute schedule for coarsening flux to the specified
- * level or reregister an existing one.
- *
- * See general notes for xeqScheduleProlongation().
- *
- * @return coarsening schedule for setting composite grid flux at
- * coarse-fine boundaries.
- */
- void
- xeqScheduleFluxCoarsen(
- int dst_id,
- int src_id,
- int dest_ln);
-
- /*!
- * @brief Execute schedule for filling ghosts on the specified
- * level or reregister an existing one.
- *
- * See general notes for xeqScheduleProlongation().
- *
- * @return refine schedule for filling ghost data from coarser level
- * and physical bc.
- */
- void
- xeqScheduleGhostFill(
- int dst_id,
- int dest_ln);
-
- /*!
- * @brief Execute schedule for filling ghosts on the specified
- * level or reregister an existing one.
- * This version does not get data from coarser levels.
- *
- * See general notes for xeqScheduleProlongation().
- *
- * This function is used for the bottom solve level, since it does
- * not access data from any coarser level. (Ghost data obtained
- * from coarser level must have been placed there before solve begins!)
- *
- * @return refine schedule for filling ghost data from same level
- * and physical bc.
- */
- void
- xeqScheduleGhostFillNoCoarse(
- int dst_id,
- int dest_ln);
-
- //@}
-
- //! @brief Return the patch data index for cell scratch data.
- int
- registerCellScratch() const;
- //! @brief Return the patch data index for flux scratch data.
- int
- registerFluxScratch() const;
- //! @brief Return the patch data index for outerflux scratch data.
- int
- registerOfluxScratch() const;
-
- //! @brief Free static variables at shutdown time.
- static void
- finalizeCallback();
-
- /*!
- * @brief Object dimension.
- */
- const tbox::Dimension d_dim;
-
- /*!
- * @brief Object name.
- */
- std::string d_object_name;
-
- //@{ @name Hierarchy-dependent objects.
-
- /*!
- * @brief Reference hierarchy
- *
- * This variable is non-null between the initializeOperatorState()
- * and deallocateOperatorState() calls. It is not truly needed,
- * because the hierarchy is obtainable through variables in most
- * function argument lists. We use it to enforce working on one
- * hierarchy at a time.
- */
- tbox::Pointer<hier::PatchHierarchy> d_hierarchy;
-
- /*!
- * @brief Coarsest level for solve.
- */
- int d_ln_min;
-
- /*!
- * @brief Finest level for solve.
- */
- int d_ln_max;
-
- /*!
- * @brief Description of coarse-fine boundaries.
- *
- * There is one coarse-fine boundary object for each level.
- * d_coarse_fine_boundary[i] is the description of
- * the coarse-fine boundary between level i and level i-1.
- * The coarse-fine boundary does not exist at the coarsest level,
- * although the hier::CoarseFineBoundary object still exists (it
- * should not contain any boxes).
- *
- * This array is initialized in initializeOperatorState() and
- * deallocated in deallocateOperatorState(). When allocated,
- * it is allocated for the index range [0,d_ln_max], though
- * the range [0,d_ln_min-1] is not used. This is okay because
- * hier::CoarseFineBoundary is a light object before
- * it is set for a level.
- */
- tbox::Array<tbox::Pointer<hier::CoarseFineBoundary> > d_cf_boundary;
-
- //@}
-
- //@{
- /*!
- * @name Private state variables for solution process.
- */
-
- /*!
- * @brief Scalar Stokes equations specifications.
- * @see setStokesSpecifications().
- */
- StokesSpecifications d_stokes_spec;
-
- /*!
- * @brief Smoothing choice.
- * @see setSmoothingChoice.
- */
- std::string d_smoothing_choice;
-
- /*!
- * @brief Coarse level solver.
- * @see setCoarsestLevelSolverChoice
- */
- std::string d_coarse_solver_choice;
-
- /*!
- * @brief Coarse-fine discretization method.
- * @see setCoarseFineDiscretization().
- */
- std::string d_cf_discretization;
-
- /*!
- * @brief Coarse-fine discretization method.
- *
- * The name of the refinement operator used to prolong the
- * coarse grid correction.
- *
- * @see setProlongationMethod()
- */
- std::string d_prolongation_method;
-
- /*!
- * @brief Tolerance specified to coarse solver
- * @see setCoarsestLevelSolverTolerance()
- */
- double d_coarse_solver_tolerance;
-
- /*!
- * @brief Coarse level solver iteration limit.
- * @see setCoarsestLevelSolverMaxIterations()
- */
- int d_coarse_solver_max_iterations;
-
- /*!
- * @brief Residual tolerance to govern smoothing.
- *
- * When we use one of the internal error smoothing functions
- * and want to terminate the smoothing sweeps at a certain
- * level of residual, this will be set to > 0. If it is
- * < 0, the smoothing function effectively ignores it.
- *
- * This variable is needed because some coarse-level solver
- * simply runs the smoothing function until convergence.
- * It sets this variable to > 0, calls the smoothing function,
- * then resets it to < 0.
- */
- double d_residual_tolerance_during_smoothing;
-
- /*!
- * @brief Id of the flux.
- *
- * If set to -1, create and delete storage space on the fly.
- * Else, user has provided space for flux.
- *
- * @see setFluxId
- */
- int d_flux_id;
-
-#ifdef HAVE_HYPRE
- /*!
- * @brief HYPRE coarse-level solver object.
- */
- CellStokesHypreSolver d_hypre_solver;
-#endif
-
- /*!
- * @brief Externally provided physical boundary condition object.
- *
- * see setPhysicalBcCoefObject()
- */
- const RobinBcCoefStrategy* d_physical_bc_coef;
-
- //@}
-
- //@{ @name Internal context and scratch data
-
- static tbox::Pointer<pdat::CellVariable<double> >
- s_cell_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
- static tbox::Pointer<pdat::SideVariable<double> >
- s_flux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
- static tbox::Pointer<pdat::OutersideVariable<double> >
- s_oflux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
- /*!
- * @brief Default context of internally maintained hierarchy data.
- */
- tbox::Pointer<hier::VariableContext> d_context;
-
- /*!
- * @brief ID of the solution-like scratch data.
- *
- * Set in constructor and never changed.
- * Corresponds to a pdat::CellVariable<double> named
- * @c d_object_name+"::cell_scratch".
- * Scratch data is allocated and removed as needed
- * to reduce memory usage.
- */
- int d_cell_scratch_id;
-
- /*!
- * @brief ID of the side-centered scratch data.
- *
- * Set in constructor and never changed.
- * Corresponds to a pdat::SideVariable<double> named
- * @c d_object_name+"::flux_scratch".
- *
- * This data is allocated only as needed and deallocated
- * immediately after use.
- */
- int d_flux_scratch_id;
-
- /*!
- * @brief ID of the outerside-centered scratch data.
- *
- * Set in constructor and never changed.
- * Corresponds to a pdat::OutersideVariable<double> named
- * @c d_object_name+"::oflux_scratch".
- */
- int d_oflux_scratch_id;
-
- //@}
-
- //@{
- /*!
- * @name Various refine and coarsen objects used internally.
- */
-
- //! @brief Error prolongation (refinement) operator.
- tbox::Pointer<xfer::RefineOperator> d_prolongation_refine_operator;
- tbox::Pointer<xfer::RefineAlgorithm> d_prolongation_refine_algorithm;
- tbox::Array<tbox::Pointer<xfer::RefineSchedule> >
- d_prolongation_refine_schedules;
-
- //! @brief Solution restriction (coarsening) operator.
- tbox::Pointer<xfer::CoarsenOperator> d_urestriction_coarsen_operator;
- tbox::Pointer<xfer::CoarsenAlgorithm> d_urestriction_coarsen_algorithm;
- tbox::Array<tbox::Pointer<xfer::CoarsenSchedule> >
- d_urestriction_coarsen_schedules;
-
- //! @brief Residual restriction (coarsening) operator.
- tbox::Pointer<xfer::CoarsenOperator> d_rrestriction_coarsen_operator;
- tbox::Pointer<xfer::CoarsenAlgorithm> d_rrestriction_coarsen_algorithm;
- tbox::Array<tbox::Pointer<xfer::CoarsenSchedule> >
- d_rrestriction_coarsen_schedules;
-
- //! @brief Coarsen operator for outerflux-to-flux
- tbox::Pointer<xfer::CoarsenOperator> d_flux_coarsen_operator;
- tbox::Pointer<xfer::CoarsenAlgorithm> d_flux_coarsen_algorithm;
- tbox::Array<tbox::Pointer<xfer::CoarsenSchedule> >
- d_flux_coarsen_schedules;
-
- //! @brief Refine operator for cell-like data from coarser level.
- tbox::Pointer<xfer::RefineOperator> d_ghostfill_refine_operator;
- tbox::Pointer<xfer::RefineAlgorithm> d_ghostfill_refine_algorithm;
- tbox::Array<tbox::Pointer<xfer::RefineSchedule> >
- d_ghostfill_refine_schedules;
-
- //! @brief Refine operator for cell-like data from same level.
- tbox::Pointer<xfer::RefineOperator> d_ghostfill_nocoarse_refine_operator;
- tbox::Pointer<xfer::RefineAlgorithm> d_ghostfill_nocoarse_refine_algorithm;
- tbox::Array<tbox::Pointer<xfer::RefineSchedule> >
- d_ghostfill_nocoarse_refine_schedules;
-
- //@}
-
- /*!
- * @brief Utility object employed in setting ghost cells and providing
- * xfer::RefinePatchStrategy implementation.
- *
- * Since this class deals only in scalar variables having
- * Robin boundary conditions, we take advantage of the corresponding
- * implementation in CartesianRobinBcHelper. Whenever
- * we need an implementation of xfer::RefinePatchStrategy,
- * this object is used. Note that in the code, before we
- * use this object to set ghost cell values, directly or
- * indirectly by calling xfer::RefineSchedule::fillData(),
- * we must tell d_bc_helper the patch data index we want
- * to set and whether we are setting data with homogeneous
- * boundary condition.
- */
- CartesianRobinBcHelper d_bc_helper;
-
- //@{
- /*!
- * @name Non-essential objects used in outputs and debugging.
- */
-
- /*!
- * @brief Logging flag.
- */
- bool d_enable_logging;
-
- /*!
- * @brief Preconditioner using this object.
- *
- * See setPreconditioner().
- */
- const FACPreconditioner* d_preconditioner;
-
- /*!
- * @brief Hierarchy cell operator used in debugging.
- */
- tbox::Pointer<math::HierarchyCellDataOpsReal<double> > d_hopscell;
-
- /*!
- * @brief Hierarchy side operator used in debugging.
- */
- tbox::Pointer<math::HierarchySideDataOpsReal<double> > d_hopsside;
-
- /*!
- * @brief Timers for performance measurement.
- */
- tbox::Pointer<tbox::Timer> t_restrict_solution;
- tbox::Pointer<tbox::Timer> t_restrict_residual;
- tbox::Pointer<tbox::Timer> t_prolong;
- tbox::Pointer<tbox::Timer> t_smooth_error;
- tbox::Pointer<tbox::Timer> t_solve_coarsest;
- tbox::Pointer<tbox::Timer> t_compute_composite_residual;
- tbox::Pointer<tbox::Timer> t_compute_residual_norm;
-
- static tbox::StartupShutdownManager::Handler
- s_finalize_handler;
-};
-
-}
-}
-
-#ifdef SAMRAI_INLINE
-#include "CellStokesFACOps.I"
-#endif
-
-#endif // included_solv_CellStokesFACOps
diff -r a44a82f15794 -r fe2a9230921b CellStokesFACSolver.C
--- a/CellStokesFACSolver.C Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,585 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: High-level solver (wrapper) for scalar stokes equation.
- *
- ************************************************************************/
-#ifndef included_solv_CellStokesFACSolver_C
-#define included_solv_CellStokesFACSolver_C
-
-#include "SAMRAI/pdat/CellVariable.h"
-#include "CellStokesFACSolver.h"
-#include "SAMRAI/tbox/PIO.h"
-#include "SAMRAI/tbox/Utilities.h"
-#include "SAMRAI/tbox/StartupShutdownManager.h"
-
-#include IOMANIP_HEADER_FILE
-
-#ifndef SAMRAI_INLINE
-#include "CellStokesFACSolver.I"
-#endif
-
-namespace SAMRAI {
-namespace solv {
-
-/*
- *************************************************************************
- * *
- * Initialize the static data members. *
- * *
- *************************************************************************
- */
-
-bool CellStokesFACSolver::s_initialized = 0;
-int CellStokesFACSolver::s_weight_id[SAMRAI::tbox::Dimension::
- MAXIMUM_DIMENSION_VALUE];
-int CellStokesFACSolver::s_instance_counter[SAMRAI::tbox::Dimension::
- MAXIMUM_DIMENSION_VALUE];
-
-/*
- *************************************************************************
- * *
- * Constructor sets uninitialized solver state. *
- * Set default iteration and convergence parameters. *
- * *
- * By default settings: *
- * - Stokes equation specified has D=1, C=0. *
- * - State is uninitialized *
- * - Logging is disabled *
- * - Context for internal data is set based on object name. *
- * *
- *************************************************************************
- */
-
-CellStokesFACSolver::CellStokesFACSolver(
- const tbox::Dimension& dim,
- const std::string& object_name,
- tbox::Pointer<tbox::Database> database):
- d_dim(dim),
- d_object_name(object_name),
- d_stokes_spec(object_name + "::stokes_spec"),
- d_fac_ops(d_dim, object_name + "::fac_ops"),
- d_fac_precond(object_name + "::fac_precond", d_fac_ops),
- d_bc_object(NULL),
- d_simple_bc(d_dim, object_name + "::bc"),
- d_hierarchy(NULL),
- d_ln_min(-1),
- d_ln_max(-1),
- d_context(hier::VariableDatabase::getDatabase()
- ->getContext(object_name + "::CONTEXT")),
- d_uv(NULL),
- d_fv(NULL),
- d_solver_is_initialized(false),
- d_enable_logging(false)
-{
-
- if (!s_initialized) {
- initializeStatics();
- }
-
- setMaxCycles(10);
- setResidualTolerance(1e-6);
- setPresmoothingSweeps(1);
- setPostsmoothingSweeps(1);
- setCoarseFineDiscretization("Ewing");
-#ifdef HAVE_HYPRE
- setCoarsestLevelSolverChoice("hypre");
- setCoarsestLevelSolverTolerance(1e-10);
- setCoarsestLevelSolverMaxIterations(20);
- setUseSMG(true);
-#else
- setCoarsestLevelSolverChoice("redblack");
- setCoarsestLevelSolverTolerance(1e-8);
- setCoarsestLevelSolverMaxIterations(500);
-#endif
-
- /*
- * Construct integer tag variables and add to variable database. Note that
- * variables and patch data indices are shared among all instances.
- * The VariableDatabase holds the variables, once contructed and
- * registered via the VariableDatabase::registerInternalSAMRAIVariable()
- * function call. Note that variables are registered and patch data indices
- * are made only for the first time through the constructor.
- */
- hier::VariableDatabase* var_db = hier::VariableDatabase::getDatabase();
-
- static std::string weight_variable_name("CellStokesFACSolver_weight");
-
- tbox::Pointer<pdat::CellVariable<double> > weight = var_db->getVariable(
- weight_variable_name);
- if (weight.isNull()) {
- weight = new pdat::CellVariable<double>(d_dim, weight_variable_name, 1);
- }
-
- if (s_weight_id[d_dim.getValue() - 1] < 0) {
- s_weight_id[d_dim.getValue() - 1] = var_db->registerInternalSAMRAIVariable(
- weight,
- hier::IntVector::getZero(d_dim));
- }
-
- /*
- * The default RobinBcCoefStrategy used,
- * SimpleCellRobinBcCoefs only works with constant refine
- * for prolongation. So we use constant refinement
- * for prolongation by default.
- */
- setProlongationMethod("CONSTANT_REFINE");
-
- /*
- * The FAC operator optionally uses the preconditioner
- * to get data for logging.
- */
- d_fac_ops.setPreconditioner((const FACPreconditioner *)(&d_fac_precond));
-
- if (database) {
- getFromInput(database);
- }
-
- s_instance_counter[d_dim.getValue() - 1]++;
-}
-
-/*
- *************************************************************************
- * *
- * Destructor for CellStokesFACSolver. *
- * Deallocate internal data. *
- * *
- *************************************************************************
- */
-
-CellStokesFACSolver::~CellStokesFACSolver()
-{
- s_instance_counter[d_dim.getValue() - 1]--;
-
- deallocateSolverState();
-
- if (s_instance_counter[d_dim.getValue() - 1] == 0) {
- hier::VariableDatabase::getDatabase()->
- removeInternalSAMRAIVariablePatchDataIndex(s_weight_id[d_dim.getValue() - 1]);
- s_weight_id[d_dim.getValue() - 1] = -1;
- }
-}
-
-/*
- ********************************************************************
- * Set state from database *
- * *
- * Do not allow FAC preconditioner and Stokes FAC operators to be *
- * set from database, as that may cause them to be inconsistent *
- * with this object if user does not coordinate the inputs *
- * correctly. This is also why we don't allow direct access to *
- * those objects. The responsibility for maintaining consistency *
- * lies in the public functions to set parameters, so use them *
- * instead of setting the parameters directly in this function. *
- ********************************************************************
- */
-
-void CellStokesFACSolver::getFromInput(
- tbox::Pointer<tbox::Database> database)
-{
- if (database) {
- if (database->isBool("enable_logging")) {
- bool logging = database->getBool("enable_logging");
- enableLogging(logging);
- }
- if (database->isInteger("max_cycles")) {
- int max_cycles = database->getInteger("max_cycles");
- setMaxCycles(max_cycles);
- }
- if (database->isDouble("residual_tol")) {
- double residual_tol = database->getDouble("residual_tol");
- setResidualTolerance(residual_tol);
- }
- if (database->isInteger("num_pre_sweeps")) {
- int num_pre_sweeps = database->getInteger("num_pre_sweeps");
- setPresmoothingSweeps(num_pre_sweeps);
- }
- if (database->isInteger("num_post_sweeps")) {
- int num_post_sweeps = database->getInteger("num_post_sweeps");
- setPostsmoothingSweeps(num_post_sweeps);
- }
- if (database->isString("coarse_fine_discretization")) {
- std::string s = database->getString("coarse_fine_discretization");
- setCoarseFineDiscretization(s);
- }
- if (database->isString("prolongation_method")) {
- std::string s = database->getString("prolongation_method");
- setProlongationMethod(s);
- }
- if (database->isString("coarse_solver_choice")) {
- std::string s = database->getString("coarse_solver_choice");
- setCoarsestLevelSolverChoice(s);
- }
- if (database->isDouble("coarse_solver_tolerance")) {
- double tol = database->getDouble("coarse_solver_tolerance");
- setCoarsestLevelSolverTolerance(tol);
- }
- if (database->isInteger("coarse_solver_max_iterations")) {
- int itr = database->getInteger("coarse_solver_max_iterations");
- setCoarsestLevelSolverMaxIterations(itr);
- }
-#ifdef HAVE_HYPRE
- if (database->isBool("use_smg")) {
- bool smg = database->getBool("use_smg");
- setUseSMG(smg);
- }
-#endif
- }
-}
-
-/*
- *************************************************************************
- * *
- * Prepare internal data for solve. *
- * Allocate scratch data. Create vectors for u and f *
- * required by the FACPreconditioner interface. *
- * Set up internal boundary condition object. *
- * Share data to coordinate with FAC preconditioner and *
- * Stokes FAC operator. *
- * *
- *************************************************************************
- */
-
-void CellStokesFACSolver::initializeSolverState(
- const int solution,
- const int rhs,
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- const int coarse_level,
- const int fine_level)
-{
- TBOX_ASSERT(!hierarchy.isNull());
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
-
- if (d_bc_object == NULL) {
- TBOX_ERROR(
- d_object_name << ": No BC coefficient strategy object!\n"
- <<
- "Use either setBoundaries or setPhysicalBcCoefObject\n"
- << "to specify the boundary conidition.\n");
- }
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (solution < 0 || rhs < 0) {
- TBOX_ERROR(d_object_name << ": Bad patch data id.\n");
- }
-#endif
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (!hierarchy) {
- TBOX_ERROR(d_object_name << ": NULL hierarchy pointer not allowed\n"
- << "in inititialization.");
- }
-#endif
- d_hierarchy = hierarchy;
-
- d_ln_min = coarse_level;
- d_ln_max = fine_level;
- if (d_ln_min == -1) {
- d_ln_min = 0;
- }
- if (d_ln_max == -1) {
- d_ln_max = d_hierarchy->getFinestLevelNumber();
- }
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (d_ln_min < 0 || d_ln_max < 0 || d_ln_min > d_ln_max) {
- TBOX_ERROR(d_object_name << ": Bad range of levels in\n"
- << "inititialization.\n");
- }
-#endif
-
- int ln;
- for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
- d_hierarchy->getPatchLevel(ln)->allocatePatchData(s_weight_id[d_dim.getValue() - 1]);
- }
-
- d_fac_ops.computeVectorWeights(d_hierarchy,
- s_weight_id[d_dim.getValue() - 1],
- d_ln_min,
- d_ln_max);
-
- if (d_bc_object == &d_simple_bc) {
- d_simple_bc.setHierarchy(d_hierarchy,
- d_ln_min,
- d_ln_max);
- if (d_stokes_spec.dIsConstant()) {
- d_simple_bc.setDiffusionCoefConstant(d_stokes_spec.getDConstant());
- } else {
- d_simple_bc.setDiffusionCoefId(d_stokes_spec.getDPatchDataId());
- }
- }
-
- d_fac_ops.setStokesSpecifications(d_stokes_spec);
-
- createVectorWrappers(solution, rhs);
-
- d_fac_precond.initializeSolverState(*d_uv, *d_fv);
-
- d_solver_is_initialized = true;
-}
-
-void CellStokesFACSolver::deallocateSolverState()
-{
- if (d_hierarchy) {
-
- d_fac_precond.deallocateSolverState();
-
- /*
- * Delete internally managed data.
- */
- int ln;
- for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
- d_hierarchy->getPatchLevel(ln)->deallocatePatchData(s_weight_id[d_dim.getValue()
- - 1]);
- }
-
- d_hierarchy.setNull();
- d_ln_min = -1;
- d_ln_max = -1;
- d_solver_is_initialized = false;
-
- destroyVectorWrappers();
-
- }
-}
-
-/*
- *************************************************************************
- * Enable logging and propagate logging flag to major components. *
- *************************************************************************
- */
-
-void CellStokesFACSolver::enableLogging(
- bool logging)
-{
- d_enable_logging = logging;
- d_fac_precond.enableLogging(d_enable_logging);
- d_fac_ops.enableLogging(d_enable_logging);
-}
-
-void CellStokesFACSolver::setBoundaries(
- const std::string& boundary_type,
- const int fluxes,
- const int flags,
- int* bdry_types)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (d_bc_object != NULL && d_bc_object != &d_simple_bc) {
- TBOX_ERROR(
- d_object_name << ": Bad attempt to set boundary condition\n"
- <<
- "by using default bc object after it has been overriden.\n");
- }
-#endif
- d_simple_bc.setBoundaries(boundary_type,
- fluxes,
- flags,
- bdry_types);
- d_bc_object = &d_simple_bc;
- d_fac_ops.setPhysicalBcCoefObject(d_bc_object);
-}
-
-void CellStokesFACSolver::setBcObject(
- const RobinBcCoefStrategy* bc_object)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (!bc_object) {
- TBOX_ERROR(d_object_name << ": NULL pointer for boundary condition\n"
- << "object.\n");
- }
-#endif
- d_bc_object = bc_object;
- d_fac_ops.setPhysicalBcCoefObject(d_bc_object);
-}
-
-/*
- *************************************************************************
- * *
- * Solve the linear system and report whether iteration converged. *
- * *
- * This version is for an initialized solver state. *
- * Before solving, set the final piece of the boundary condition, *
- * which is not known until now, and initialize some internal *
- * solver quantities. *
- * *
- *************************************************************************
- */
-
-bool CellStokesFACSolver::solveSystem(
- const int u,
- const int f)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (!d_solver_is_initialized) {
- TBOX_ERROR(
- d_object_name << ".solveSystem(int,int): uninitialized\n"
- <<
- "solver state. You must call initializeSolverState()\n"
- <<
- "before using this function. Or you can use\n"
- <<
- "solveSystem(int,int,...) to initialize the solver,\n"
- << "solve and deallocate the solver.\n");
- }
- if (u < 0 || f < 0) {
- TBOX_ERROR(d_object_name << ": Bad patch data id.\n");
- }
-#endif
- if (d_bc_object == &d_simple_bc) {
- /*
- * Knowing that we are using the SimpelCellRobinBcCoefsX
- * implementation of RobinBcCoefStrategy, we must save
- * the ghost data in u before solving.
- * The solver overwrites it, but SimpleCellRobinBcCoefs
- * needs to get to access it repeatedly.
- */
- d_simple_bc.cacheDirichletData(u);
- }
-
- createVectorWrappers(u, f);
- bool solver_rval;
- solver_rval = d_fac_precond.solveSystem(*d_uv, *d_fv);
-
- if (d_bc_object == &d_simple_bc) {
- /*
- * Restore the Dirichlet cell data that were overwritten by the
- * solve process. We do this to be backward compatible with the
- * user code.
- */
- d_simple_bc.restoreDirichletData(u);
- }
-
- return solver_rval;
-}
-
-/*
- *************************************************************************
- * *
- * Solve the linear system and report whether iteration converged. *
- * *
- * This version is for an uninitialized solver state. *
- * 1. Initialize the (currently uninitialized) solver state. *
- * 2. Solve. *
- * 3. Deallocate the solver state. *
- * *
- *************************************************************************
- */
-
-bool CellStokesFACSolver::solveSystem(
- const int u,
- const int f,
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- int coarse_ln,
- int fine_ln)
-{
- TBOX_ASSERT(!hierarchy.isNull());
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
-
- if (d_enable_logging) {
- tbox::plog << "CellStokesFACSolver::solveSystem (" << d_object_name
- << ")\n";
- d_stokes_spec.printClassData(tbox::plog);
- }
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (d_solver_is_initialized) {
- TBOX_ERROR(
- d_object_name << ".solveSystem(int,int,...): initialized\n"
- <<
- "solver state. This function can only used when the\n"
- <<
- "solver state is uninitialized. You should deallocate\n"
- <<
- "the solver state or use solveSystem(int,int).\n");
- }
- if (!hierarchy) {
- TBOX_ERROR(d_object_name << ".solveSystem(): Null hierarchy\n"
- << "specified.\n");
- }
-#endif
- initializeSolverState(u, f, hierarchy, coarse_ln, fine_ln);
-
- bool solver_rval;
- solver_rval = solveSystem(u, f);
-
- deallocateSolverState();
-
- return solver_rval;
-}
-
-void CellStokesFACSolver::createVectorWrappers(
- int u,
- int f) {
-
- hier::VariableDatabase& vdb(*hier::VariableDatabase::getDatabase());
- tbox::Pointer<hier::Variable> variable;
-
- if (!d_uv || d_uv->getComponentDescriptorIndex(0) != u) {
- d_uv.setNull();
- d_uv = new SAMRAIVectorReal<double>(d_object_name + "::uv",
- d_hierarchy,
- d_ln_min,
- d_ln_max);
- vdb.mapIndexToVariable(u, variable);
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (!variable) {
- TBOX_ERROR(d_object_name << ": No variable for patch data index "
- << u << "\n");
- }
- tbox::Pointer<pdat::CellVariable<double> > cell_variable = variable;
- if (!cell_variable) {
- TBOX_ERROR(d_object_name << ": hier::Patch data index " << u
- << " is not a cell-double variable.\n");
- }
-#endif
- d_uv->addComponent(variable, u, s_weight_id[d_dim.getValue() - 1]);
- }
-
- if (!d_fv || d_fv->getComponentDescriptorIndex(0) != f) {
- d_fv.setNull();
- d_fv = new SAMRAIVectorReal<double>(d_object_name + "::fv",
- d_hierarchy,
- d_ln_min,
- d_ln_max);
- vdb.mapIndexToVariable(f, variable);
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (!variable) {
- TBOX_ERROR(d_object_name << ": No variable for patch data index "
- << f << "\n");
- }
- tbox::Pointer<pdat::CellVariable<double> > cell_variable = variable;
- if (!cell_variable) {
- TBOX_ERROR(d_object_name << ": hier::Patch data index " << f
- << " is not a cell-double variable.\n");
- }
-#endif
- d_fv->addComponent(variable, f, s_weight_id[d_dim.getValue() - 1]);
- }
-}
-
-/*
- ***********************************************************************
- * Delete the vector wrappers. Do not freeVectorComponents because *
- * we do not control their data allocation. The user does that. *
- ***********************************************************************
- */
-void CellStokesFACSolver::destroyVectorWrappers() {
- d_uv.setNull();
- d_fv.setNull();
-}
-
-void CellStokesFACSolver::initializeStatics() {
-
- for (int d = 0; d < SAMRAI::tbox::Dimension::MAXIMUM_DIMENSION_VALUE; ++d) {
- s_weight_id[d] = -1;
- s_instance_counter[d] = -1;
- }
-
- s_initialized = 1;
-}
-
-}
-}
-#endif
diff -r a44a82f15794 -r fe2a9230921b CellStokesFACSolver.I
--- a/CellStokesFACSolver.I Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: High-level solver (wrapper) for scalar stokes equation.
- *
- ************************************************************************/
-namespace SAMRAI {
-namespace solv {
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setDPatchDataId(
- int id) {
- d_stokes_spec.setDPatchDataId(id);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setDConstant(
- double scalar) {
- d_stokes_spec.setDConstant(scalar);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setCPatchDataId(
- int id) {
- d_stokes_spec.setCPatchDataId(id);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setCConstant(
- double scalar) {
-// Disable Intel warning on real comparison
-#ifdef __INTEL_COMPILER
-#pragma warning (disable:1572)
-#endif
- if (scalar == 0.0) {
- d_stokes_spec.setCZero();
- } else {
- d_stokes_spec.setCConstant(scalar);
- }
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setProlongationMethod(
- const std::string& prolongation_method)
-{
- d_fac_ops.setProlongationMethod(prolongation_method);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setCoarsestLevelSolverChoice(
- const std::string& choice)
-{
- d_fac_ops.setCoarsestLevelSolverChoice(choice);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setCoarsestLevelSolverTolerance(
- double tol)
-{
- d_fac_ops.setCoarsestLevelSolverTolerance(tol);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setCoarsestLevelSolverMaxIterations(
- int max_iterations)
-{
- d_fac_ops.setCoarsestLevelSolverMaxIterations(max_iterations);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setCoarseFineDiscretization(
- const std::string& coarsefine_method)
-{
- d_fac_ops.setCoarseFineDiscretization(coarsefine_method);
-}
-
-#ifdef HAVE_HYPRE
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setUseSMG(
- bool use_smg)
-{
- if (d_solver_is_initialized) {
- TBOX_ERROR(
- d_object_name << ": setUseSMG(bool) may NOT be called\n"
- <<
- "while the solver state is initialized, as that\n"
- << "would lead to a corrupted solver state.\n");
- }
- d_fac_ops.setUseSMG(use_smg);
-}
-#endif
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setPresmoothingSweeps(
- int num_pre_sweeps) {
- d_fac_precond.setPresmoothingSweeps(num_pre_sweeps);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setPostsmoothingSweeps(
- int num_post_sweeps) {
- d_fac_precond.setPostsmoothingSweeps(num_post_sweeps);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setMaxCycles(
- int max_cycles) {
- d_fac_precond.setMaxCycles(max_cycles);
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::setResidualTolerance(
- double residual_tol) {
- d_fac_precond.setResidualTolerance(residual_tol);
-}
-
-SAMRAI_INLINE_KEYWORD
-int CellStokesFACSolver::getNumberOfIterations() const
-{
- return d_fac_precond.getNumberOfIterations();
-}
-
-SAMRAI_INLINE_KEYWORD
-double CellStokesFACSolver::getResidualNorm() const
-{
- return d_fac_precond.getResidualNorm();
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesFACSolver::getConvergenceFactors(
- double& avg_factor,
- double& final_factor)
-const
-{
- d_fac_precond.getConvergenceFactors(avg_factor, final_factor);
-}
-
-}
-}
diff -r a44a82f15794 -r fe2a9230921b CellStokesFACSolver.h
--- a/CellStokesFACSolver.h Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,660 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: High-level solver (wrapper) for scalar stokes equation.
- *
- ************************************************************************/
-#ifndef included_solv_CellStokesFACSolver
-#define included_solv_CellStokesFACSolver
-
-#include "SAMRAI/SAMRAI_config.h"
-
-#include "SAMRAI/solv/FACPreconditioner.h"
-#include "CellStokesFACOps.h"
-#include "StokesSpecifications.h"
-#include "SAMRAI/solv/SimpleCellRobinBcCoefs.h"
-#include "SAMRAI/tbox/Database.h"
-#include "SAMRAI/tbox/Pointer.h"
-
-namespace SAMRAI {
-namespace solv {
-
-/*!
- * @brief Class for solving scalar Stokes's equation on SAMR grid,
- * wrapping up lower-level components (FAC cycling, Stokes equation
- * operations and boundary conditions) in a single high-level interface.
- *
- * Note: this class provides a backward-compatible interface to
- * the soon-to-be obsolete StokesHierarchySolver<DIM> class.
- * Although this class hides the lower-level components (FAC cycling,
- * Stokes equation operations and boundary conditions), it is
- * perfectly acceptable to use those lower-level components directly.
- *
- * We solve the equation
- * div(D grad(u)) + Cu = f
- * where D is a side-centered array and C is a cell-centered array.
- * u and f are also cell-centered.
- * Boundary conditions supported are Dirichlet, Neumann and mixed
- * (Dirichlet on some faces and Neumann on others).
- *
- * This class is a wrapper, providing a single class that coordinates
- * three major components: the FAC solver, the cell-centered Stokes
- * FAC operator and a default Robin bc coefficient implelemtation.
- * It is perfectly acceptable to use those classes outside of this
- * class.
- *
- * The underlying solver is an FAC solver using cell-centered
- * discretization. The difference scheme is second-order
- * central-difference. On coarse-fine boundaries within the
- * solution levels, the composite grid operator uses, by default,
- * the discretization method of Ewing, Lazarov and Vassilevski
- * ("Local Refinement Techniques for Elliptic Problems on
- * Cell-Centered Grids, I. Error Analysis", Mathematics of
- * Computation, Vol. 56, No. 194, April 1991, pp. 437-461).
- *
- * Typical use of this class is:
- * -# Construct a CellStokesFACSolver object, providing it
- * the hierarchy and range of levels participating in the solve.
- * -# Set the parameters C and D using the functions named @c setC...
- * and @c setD... By default, D=1 and C=0 everywhere.
- * -# Call setBoundaries() to state the types boundary conditions,
- * along with supplemental data for setting those boundary
- * conditions.
- * -# Call initializeSolverState() to set up information
- * internal to the solver. This is step is not required
- * but will save setup costs if you are making multiple
- * solves. This commits the object to the current hierarchy state
- * and the specific @em types of boundary conditions you selected,
- * It does NOT commit to the specific @em values of the boundary
- * condition. A hierarchy change (through adaption or other means)
- * invalidates the state, thus you must reinitialize or
- * deallocateSolverState() the state before another solve.
- * -# Solve the equation with solveSystem(). You provide the
- * patch data indices for the solution u and the right hand
- * side f. u must have at least one ghost cell and where
- * a Dirichlet boundary condition applies, those cells
- * must be set to the value on the boundary. If only Neumann
- * boundary conditions are used, the ghost cell values
- * do not matter.
- * -# Call deallocateSolverState() to free up internal resources,
- * if initializeSolverState() was called before the solve.
- *
- * After the solve, information on the solve can be obtained
- * by calling one of these functions:
- * - getNumberOfIterations() gives the number of FAC cycles used.
- * - getConvergenceFactors() gives the average and final convergence
- * factors for the solve.
- * - getResidualNorm() gives the final residual
- *
- * Finer solver controls can be set using the functions in this class.
- *
- * Object of this class can be set using input databases.
- * The following parameters can be set. Each is shown with its
- * default value in the case where hypre is used.
- * @verbatim
- * enable_logging = TRUE // Bool flag to switch logging on/off
- * max_cycles = 10 // Integer number of max FAC cycles to use
- * residual_tol = 1.e-6 // Residual tolerance to solve for
- * num_pre_sweeps = 1 // Number of presmoothing sweeps to use
- * num_post_sweeps = 1 // Number of postsmoothing sweeps to use
- * coarse_fine_discretization = "Ewing" // Name of coarse-fine discretization
- * prolongation_method = "CONSTANT_REFINE" // Name of prolongation method
- * coarse_solver_choice = "hypre" // Name of coarse level solver
- * coarse_solver_tolerance = 1e-10 // Coarse level tolerance
- * coarse_solver_max_iterations = 20 // Coarse level max iterations
- * use_smg = "FALSE" // Whether to use hypre's smg solver
- * // (alternative is the pfmg solver)
- * @endverbatim
- *
- */
-class CellStokesFACSolver
-{
-
-public:
- /*!
- * @brief Construct a solver.
- *
- * If the database is not NULL, initial settings will be set
- * using the database.
- * The solver is uninitialized until initializeSolverState()
- * is called.
- *
- * @param object_name Name of object used in outputs
- * @param database tbox::Database for initialization (may be NULL)
- */
- CellStokesFACSolver(
- const tbox::Dimension& dim,
- const std::string& object_name,
- tbox::Pointer<tbox::Database> database =
- tbox::Pointer<tbox::Database>());
-
- /*!
- * @brief Destructor.
- */
- ~CellStokesFACSolver(
- void);
-
- /*!
- * @brief Enable logging.
- *
- * To disable, pass in @c false.
- */
- void
- enableLogging(
- bool logging);
-
- /*!
- * @brief Solve Stokes's equation, assuming an uninitialized
- * solver state.
- *
- * Here, u is the "solution" patch data index and f is the
- * right hand side patch data index.
- * The return value is true if the solver converged and false otherwise.
- *
- * This function is a wrapper.
- * It simply initializes the solver state, call the
- * solveSystem(const int,const int) for the initialized solver then
- * deallocates the solver state.
- *
- * Upon return from this function,
- * solution will contain the result of the solve.
- *
- * See initializeSolverState() for opportunities to save overhead
- * when using multiple consecutive solves.
- *
- * @see solveSystem(const int,const int)
- *
- * @param solution hier::Patch data index for solution u
- * @param rhs hier::Patch data index for right hand side f
- * @param hierarchy The patch hierarchy to solve on
- * @param coarse_ln The coarsest level in the solve.
- * @param fine_ln The finest level in the solve.
- *
- * @return whether solver converged to specified level
- *
- * @see initializeSolverState
- */
- bool
- solveSystem(
- const int solution,
- const int rhs,
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- int coarse_ln = -1,
- int fine_ln = -1);
-
- /*!
- * @brief Solve Stokes's equation using the current solver state
- * set by initializeSolverState().
- *
- * When the solver state has been initialized, this function may
- * be called repeadedly with different values on the rhs.
- * There is some cost savings for multiple solves when this
- * is done.
- *
- * Before calling this function, the solution and
- * right-hand-side quantities should be set properly by the user
- * on all patch interiors on the range of levels covered by the
- * FAC iteration. All data for these patch data index should be allocated.
- * Thus, the user is responsible for managing the
- * storage for the solution and right-hand-side.
- *
- * @return whether solver converged to specified level
- *
- * @see solveSystem( const int, const int, tbox::Pointer< hier::PatchHierarchy >, int, int);
- */
- bool
- solveSystem(
- const int solution,
- const int rhs);
-
- /*!
- * @brief Specify the boundary conditions that are to be used at the
- * physical domain boundary.
- *
- * This method is used to set up the default SimpleCellRobinBcCoefs
- * object for specifying boundary conditions. Note that you may
- * alternatively provide your own implementation of the Robin
- * boundary condition coefficients using the setBcObject() method.
- *
- * The boundary conditions specified as the
- * std::string argument "boundary_type." The boundary type argument can be
- * "Dirichlet", "Neumann", or "Mixed".
- *
- * If using Dirichlet boundary conditions, then before the solver is
- * called, the storage for the unknown u
- * must have a mapped_box_level of ghost cells at least one cell wide that includes
- * the Dirichlet boundary values.
- *
- * If using Neumann boundary conditions, then before the solver is called,
- * the outerface boundary flux data must be set for the Neumann conditions.
- * The fluxes argument gives the patch data index of this flux
- * data.
- *
- * The mixed boundary type is for a mixture of Dirichlet and Neumann
- * boundary conditions are used at the physical domain boundary.
- * The fluxes argument gives the patch data index of the outerface data
- * that specifies the flux data for the Neumann conditions. The flags
- * array is an outerface data array of integer flags that specifies whether
- * Dirichlet (flag == zero) or Neumann (flag == one) conditions are to be
- * used at a particular cell boundary face. Note that the flag data must
- * be set before the matrix entries can be computed and the flux data
- * must be set before the solver is called. The bdry_types argument can
- * be used if the boundary conditions are mixed but one or more of the
- * faces of the physical boundary are entirely either Dirichlet or
- * Neumann boundaries. The bdry_types argument should be an array of
- * 2*DIM integers, specifying the boundary conditions on each side of
- * the physical domain. It should be ordered {x_lo, x_hi, y_lo, y_hi,
- * z_lo, z_hi}, with the values for each face being 0 for Dirichlet
- * conditions, 1 for Neumann conditions, and 2 for mixed boundary
- * conditions. The bdry_type argument is never required, but if used
- * it can sometimes make the StokesHYPRESolver class more efficient.
- */
-
- void
- setBoundaries(
- const std::string& boundary_type,
- const int fluxes = -1,
- const int flags = -1,
- int* bdry_types = NULL);
-
- /*!
- * @brief Override internal implementation to set boundary condition
- * coefficients with user-provided implementation.
- *
- * This function is used to override the default internal
- * object for setting Robin boundary condition coefficients.
- * You should override when you need to avoid the limitations
- * of the SimpleCellRobinBcCoefs class or you prefer to
- * use your own implementation.
- *
- * Note that an important limitation of the SimpleCellRobinBcCoefs
- * class is the inability to support linear interpolation in
- * the prolongation step.
- *
- * Once the boundary condition object is overwritten by this
- * method, you must no longer call the setBoundaries() method.
- */
- void
- setBcObject(
- const RobinBcCoefStrategy* bc_object);
-
- //!@{ @name Specifying PDE parameters
-
- /*!
- * @brief Set the patch data index for variable D.
- *
- * In addition, disregard any previous D
- * specified by setDConstant().
- */
- void
- setDPatchDataId(
- int id);
-
- /*!
- * @brief Set the scalar value variable D.
- *
- * In addition, disregard any previous D
- * specified by setDPatchDataId().
- */
- void
- setDConstant(
- double scalar);
-
- /*!
- * @brief Set the scalar value variable C.
- *
- * In addition, disregard any previous C
- * specified by setCConstant().
- */
- void
- setCPatchDataId(
- int id);
-
- /*!
- * @brief Set the patch data index for variable C.
- *
- * In addition, disregard any previous C
- * specified by setCConstant().
- */
- void
- setCConstant(
- double scalar);
-
- //@}
-
- //@{ @name Functions for setting solver mathematic algorithm controls
-
- /*!
- * @brief Set coarse level solver.
- *
- * Select from these:
- * - @c "redblack"
- * - @c "hypre" (only if the HYPRE library is available).
- */
- void
- setCoarsestLevelSolverChoice(
- const std::string& choice);
-
- /*!
- * @brief Set tolerance for coarse level solve.
- *
- * If the coarse level solver requires a tolerance
- * (currently, they all do), the specified value is used.
- */
- void
- setCoarsestLevelSolverTolerance(
- double tol);
-
- /*!
- * @brief Set max iterations for coarse level solve.
- *
- * If the coarse level solver requires a max iteration limit
- * (currently, they all do), the specified value is used.
- */
- void
- setCoarsestLevelSolverMaxIterations(
- int max_iterations);
-
-#ifdef HAVE_HYPRE
- /*!
- * @brief Set whether to use HYPRe's PFMG algorithm instead of the
- * SMG algorithm.
- *
- * The flag is used to select which of HYPRE's linear solver algorithms
- * to use if true, the semicoarsening multigrid algorithm is used, and if
- * false, the ``PF'' multigrid algorithm is used.
- * By default, the SMG algorithm is used.
- *
- * This setting has effect only when HYPRe is chosen for the coarsest
- * level solver. See setCoarsestLevelSolverChoice().
- *
- * Changing the algorithm must be done before setting up the matrix
- * coefficients.
- */
- void
- setUseSMG(
- bool use_smg);
-#endif
-
- /*!
- * @brief Set the coarse-fine boundary discretization method.
- *
- * Specify the @c op_name std::string which will be passed to
- * xfer::Geometry::lookupRefineOperator() to get the operator
- * for setting fine grid ghost cells from the coarse grid.
- * Note that chosing this operator implicitly choses the
- * discretization method at the coarse-fine boundary.
- *
- * There is one important instance where this std::string is
- * @em not passed to xfer::Geometry::lookupRefineOperator().
- * If this variable is set to "Ewing", a constant refinement
- * method is used along with Ewing's correction.
- * For a reference to the correction method, see
- * "Local Refinement Techniques for Elliptic Problems on Cell-Centered
- * Grids, I. Error Analysis", Mathematics of Computation, Vol. 56, No. 194,
- * April 1991, pp. 437-461.
- *
- * @param coarsefine_method String selecting the coarse-fine discretization method.
- */
- void
- setCoarseFineDiscretization(
- const std::string& coarsefine_method);
-
- /*!
- * @brief Set the name of the prolongation method.
- *
- * Specify the @c op_name std::string which will be passed to
- * xfer::Geometry::lookupRefineOperator() to get the operator
- * for prolonging the coarse-grid correction.
- *
- * By default, "CONSTANT_REFINE" is used. "LINEAR_REFINE" seems to
- * to lead to faster convergence, but it does NOT satisfy the Galerkin
- * condition.
- *
- * Prolonging using linear refinement requires a Robin bc
- * coefficient implementation that is capable of delivering
- * coefficients for non-hierarchy data, because linear refinement
- * requires boundary conditions to be set on temporary levels.
- *
- * @param prolongation_method String selecting the coarse-fine discretization method.
- */
- void
- setProlongationMethod(
- const std::string& prolongation_method);
-
- /*!
- * @brief Set the number of pre-smoothing sweeps during
- * FAC iteration process.
- *
- * Presmoothing is applied during the fine-to-coarse phase of the
- * iteration. The default is to use one sweep.
- *
- * @param num_pre_sweeps Number of presmoothing sweeps
- */
- void
- setPresmoothingSweeps(
- int num_pre_sweeps);
-
- /*!
- * @brief Set the number of post-smoothing sweeps during
- * FAC iteration process.
- *
- * Postsmoothing is applied during the coarse-to-fine phase of the
- * iteration. The default is to use one sweep.
- *
- * @param num_post_sweeps Number of postsmoothing sweeps
- */
- void
- setPostsmoothingSweeps(
- int num_post_sweeps);
-
- /*!
- * @brief Set the max number of iterations (cycles) to use per solve.
- */
- void
- setMaxCycles(
- int max_cycles);
-
- /*!
- * @brief Set the residual tolerance for stopping.
- *
- * If you want the prescribed maximum number of cycles to always be taken,
- * set the residual tolerance to a negative number.
- */
- void
- setResidualTolerance(
- double residual_tol);
-
- //@}
-
- /*!
- * @brief Prepare the solver's internal state for solving
- *
- * In the interest of efficiency, this class may prepare and
- * cache some hierarchy-dependent objects. Though it is not required,
- * initializing the solver state makes for greater efficiency
- * when you are doing multiple solves on the same system of
- * equation. If you do not initialize the state, it is initialized
- * and deallocated each time you call solveSystem(const int, const int).
- * The state must be reinitialized if the hierarchy or a boundary
- * condition type changes.
- *
- * To unset the data set in this function,
- * see deallocateSolverState().
- *
- * The @c solution and @c rhs patch data indices in the argument
- * list are used to determine the @em form of the data you
- * plan to use in the solve. They need not be the same data
- * you solve on, but they should be similar. Both must represent
- * cell-centered double data. The solution must have at least one
- * ghost cell width, though this is not checked in the initialize
- * phase, because data is not required yet.
- *
- * @param solution solution patch data index for u
- * @param rhs right hand side patch data index for f
- * @param hierarchy The patch hierarchy to solve on
- * @param coarse_level The coarsest level in the solve
- * @param fine_level The finest level in the solve
- */
- void
- initializeSolverState(
- const int solution,
- const int rhs,
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- const int coarse_level = -1,
- const int fine_level = -1);
-
- /*!
- * @brief Remove the solver's internal state data
- *
- * Remove all hierarchy-dependent data set by initializeSolverState.
- * It is safe to call deallocateSolverState() even state is already
- * deallocated, but nothing is done in that case.
- *
- * @see initializeSolverState()
- */
- void
- deallocateSolverState();
-
- //@{
- //! @name Functions to get data on last solve.
-
- /*!
- * @brief Return FAC iteration count from last (or current
- * if there is one) FAC iteration process.
- */
- int
- getNumberOfIterations() const;
-
- /*!
- * @brief Get average convergance rate and convergence rate of
- * the last (or current if there is one) FAC solve.
- *
- * @param avg_factor average convergence factor over current FAC cycles
- * @param final_factor convergence factor of the last FAC cycle
- */
- void
- getConvergenceFactors(
- double& avg_factor,
- double& final_factor) const;
-
- /*!
- * @brief Return residual norm from the just-completed FAC iteration.
- *
- * The norm return value is computed as the maximum norm over all
- * patch levels involved in the solve. The value corresponds to the
- * norm applied in the user-defined residual computation.
- *
- * The latest computed norm is the one returned.
- */
- double
- getResidualNorm() const;
-
- //@}
-
-private:
- /*!
- * @brief Set state using database
- *
- * See the class description for the parameters that can be set
- * from a database.
- *
- * @param database Input database. If a NULL pointer is given,
- * nothing is done.
- */
- void
- getFromInput(
- tbox::Pointer<tbox::Database> database);
-
- /*
- * @brief Set @c d_uv and @c d_fv to vectors wrapping the data
- * specified by patch data indices u and f.
- */
- void
- createVectorWrappers(
- int u,
- int f);
-
- /*
- * @brief Destroy vector wrappers referenced to by @c d_uv and @c d_fv.
- */
- void
- destroyVectorWrappers();
-
- /*
- * @brief Initialize static members
- */
- static void
- initializeStatics();
-
- const tbox::Dimension d_dim;
-
- /*!
- * @brief Object name.
- */
- std::string d_object_name;
-
- /*!
- * @brief Object holding the specifications of the Stokes equation.
- */
- StokesSpecifications d_stokes_spec;
-
- /*!
- * @brief FAC operator implementation corresponding to cell-centered
- * Stokes discretization.
- */
- CellStokesFACOps d_fac_ops;
-
- /*!
- * @brief FAC preconditioner algorithm.
- */
- FACPreconditioner d_fac_precond;
-
- /*!
- * @brief Robin bc object in use.
- */
- const RobinBcCoefStrategy* d_bc_object;
-
- /*
- * @brief Default implementation of RobinBcCoefStrategy
- */
- SimpleCellRobinBcCoefs d_simple_bc;
-
- tbox::Pointer<hier::PatchHierarchy> d_hierarchy;
- int d_ln_min;
- int d_ln_max;
-
- /*!
- * @brief Context for all internally maintained data.
- */
- tbox::Pointer<hier::VariableContext> d_context;
- /*
- * @brief Vector wrapper for solution.
- * @see createVectorWrappers(), destroyVectorWrappers()
- */
- tbox::Pointer<SAMRAIVectorReal<double> > d_uv;
- /*
- * @brief Vector wrapper for source.
- * @see createVectorWrappers(), destroyVectorWrappers()
- */
- tbox::Pointer<SAMRAIVectorReal<double> > d_fv;
-
- bool d_solver_is_initialized;
- bool d_enable_logging;
-
- static bool s_initialized;
- static int s_weight_id[SAMRAI::tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
- static int s_instance_counter[SAMRAI::tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-};
-
-}
-}
-
-#ifdef SAMRAI_INLINE
-#include "CellStokesFACSolver.I"
-#endif
-
-#endif // included_solv_CellStokesFACSolver
diff -r a44a82f15794 -r fe2a9230921b CellStokesHypreSolver.C
--- a/CellStokesHypreSolver.C Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1590 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: Hypre solver interface for diffusion-like elliptic problems.
- *
- ************************************************************************/
-#ifndef included_solv_CellStokesHypreSolver_C
-#define included_solv_CellStokesHypreSolver_C
-
-#include "CellStokesHypreSolver.h"
-
-#ifdef HAVE_HYPRE
-
-#include "SAMRAI/geom/CartesianPatchGeometry.h"
-#include "SAMRAI/geom/CartesianGridGeometry.h"
-#include "SAMRAI/math/ArrayDataBasicOps.h"
-#include "SAMRAI/math/PatchSideDataBasicOps.h"
-#include "SAMRAI/pdat/ArrayData.h"
-#include "SAMRAI/pdat/CellIndex.h"
-#include "SAMRAI/pdat/CellIterator.h"
-#include "SAMRAI/pdat/FaceIndex.h"
-#include "SAMRAI/pdat/SideData.h"
-#include "SAMRAI/pdat/SideIndex.h"
-#include "SAMRAI/pdat/SideVariable.h"
-#include "SAMRAI/pdat/OuterfaceData.h"
-#include "SAMRAI/pdat/OutersideData.h"
-#include "SAMRAI/hier/BoundaryBoxUtils.h"
-#include "SAMRAI/hier/VariableDatabase.h"
-#include "SAMRAI/tbox/MathUtilities.h"
-#include "SAMRAI/tbox/SAMRAI_MPI.h"
-#include "SAMRAI/tbox/SAMRAIManager.h"
-#include "SAMRAI/tbox/PIO.h"
-#include "SAMRAI/tbox/Timer.h"
-#include "SAMRAI/tbox/TimerManager.h"
-#include "SAMRAI/tbox/StartupShutdownManager.h"
-#include "SAMRAI/tbox/Utilities.h"
-
-#include <cstdlib>
-
-#ifndef SAMRAI_INLINE
-#include "CellStokesHypreSolver.I"
-#endif
-
-extern "C" {
-
-#ifdef __INTEL_COMPILER
-#pragma warning (disable:1419)
-#endif
-
-void F77_FUNC(compdiagvariablec2d, COMPDIAGVARIABLEC2D) (
- double* diag,
- const double* c,
- const double* offdiagi,
- const double* offdiagj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* cscale,
- const double* dscale);
-void F77_FUNC(compdiagscalarc2d, COMPDIAGSCALARC2D) (
- double* diag,
- const double* c,
- const double* offdiagi,
- const double* offdiagj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* cscale,
- const double* dscale);
-void F77_FUNC(compdiagzeroc2d, COMPDIAGZEROC2D) (
- double* diag,
- const double* offdiagi,
- const double* offdiagj,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const double* cscale,
- const double* dscale);
-void F77_FUNC(adjbdry2d, ADJBDRY2D) (
- double* diag,
- const double* offdiagi,
- const double* offdiagj,
- const int* pifirst, const int* pilast,
- const int* pjfirst, const int* pjlast,
- const double* acoef,
- const double* bcoef,
- const int* aifirst, const int* ailast,
- const int* ajfirst, const int* ajlast,
- const double* Ak0,
- const int* kifirst, const int* kilast,
- const int* kjfirst, const int* kjlast,
- const int* lower, const int* upper,
- const int* location,
- const double* h);
-void F77_FUNC(adjbdryconstoffdiags2d, ADJBDRYCONSTOFFDIAGS2D) (
- double* diag,
- const double* offdiag,
- const int* pifirst,
- const int* pilast,
- const int* pjfirst,
- const int* pjlast,
- const double* acoef,
- const int* aifirst,
- const int* ailast,
- const int* ajfirst,
- const int* ajlast,
- const double* Ak0,
- const int* kifirst,
- const int* kilast,
- const int* kjfirst,
- const int* kjlast,
- const int* lower, const int* upper,
- const int* location,
- const double* h);
-void F77_FUNC(adjustrhs2d, ADJUSTRHS2D) (double* rhs,
- const int* rifirst,
- const int* rilast,
- const int* rjfirst,
- const int* rjlast,
- const double* Ak0,
- const int* kifirst,
- const int* kilast,
- const int* kjfirst,
- const int* kjlast,
- const double* gcoef,
- const int* aifirst,
- const int* ailast,
- const int* ajfirst,
- const int* ajlast,
- const int* lower, const int* upper,
- const int* location);
-
-void F77_FUNC(compdiagvariablec3d, COMPDIAGVARIABLEC3D) (
- double* diag,
- const double* c,
- const double* offdiagi,
- const double* offdiagj,
- const double* offdiagk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* cscale,
- const double* dscale);
-void F77_FUNC(compdiagscalarc3d, COMPDIAGSCALARC3D) (
- double* diag,
- const double* c,
- const double* offdiagi,
- const double* offdiagj,
- const double* offdiagk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* cscale,
- const double* dscale);
-void F77_FUNC(compdiagzeroc3d, COMPDIAGZEROC3D) (
- double* diag,
- const double* offdiagi,
- const double* offdiagj,
- const double* offdiagk,
- const int* ifirst,
- const int* ilast,
- const int* jfirst,
- const int* jlast,
- const int* kfirst,
- const int* klast,
- const double* cscale,
- const double* dscale);
-void F77_FUNC(adjbdry3d, ADJBDRY3D) (
- double* diag,
- const double* offdiagi,
- const double* offdiagj,
- const double* offdiagk,
- const int* pifirst,
- const int* pilast,
- const int* pjfirst,
- const int* pjlast,
- const int* pkfirst,
- const int* pklast,
- const double* acoef,
- const double* bcoef,
- const int* aifirst,
- const int* ailast,
- const int* ajfirst,
- const int* ajlast,
- const int* akfirst,
- const int* aklast,
- const double* Ak0,
- const int* kifirst,
- const int* kilast,
- const int* kjfirst,
- const int* kjlast,
- const int* kkfirst,
- const int* kklast,
- const int* lower, const int* upper,
- const int* location,
- const double* h);
-void F77_FUNC(adjbdryconstoffdiags3d, ADJBDRYCONSTOFFDIAGS3D) (
- double* diag,
- const double* offdiag,
- const int* pifirst,
- const int* pilast,
- const int* pjfirst,
- const int* pjlast,
- const int* pkfirst,
- const int* pklast,
- const double* acoef,
- const int* aifirst,
- const int* ailast,
- const int* ajfirst,
- const int* ajlast,
- const int* akfirst,
- const int* aklast,
- const double* Ak0,
- const int* kifirst,
- const int* kilast,
- const int* kjfirst,
- const int* kjlast,
- const int* kkfirst,
- const int* kklast,
- const int* lower, const int* upper,
- const int* location,
- const double* h);
-void F77_FUNC(adjustrhs3d, ADJUSTRHS3D) (double* rhs,
- const int* rifirst,
- const int* rilast,
- const int* rjfirst,
- const int* rjlast,
- const int* rkfirst,
- const int* rklast,
- const double* Ak0,
- const int* kifirst,
- const int* kilast,
- const int* kjfirst,
- const int* kjlast,
- const int* kkfirst,
- const int* kklast,
- const double* gcoef,
- const int* aifirst,
- const int* ailast,
- const int* ajfirst,
- const int* ajlast,
- const int* akfirst,
- const int* aklast,
- const int* lower, const int* upper,
- const int* location);
-
-}
-
-namespace SAMRAI {
-namespace solv {
-
-tbox::Pointer<pdat::OutersideVariable<double> >
-CellStokesHypreSolver::s_Ak0_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
-
-tbox::StartupShutdownManager::Handler CellStokesHypreSolver::s_finalize_handler(
- 0,
- 0,
- 0,
- CellStokesHypreSolver::finalizeCallback,
- tbox::StartupShutdownManager::priorityVariables);
-
-/*
- *************************************************************************
- * Constructor *
- *************************************************************************
- */
-
-CellStokesHypreSolver::CellStokesHypreSolver(
- const tbox::Dimension& dim,
- const std::string& object_name,
- tbox::Pointer<tbox::Database> database):
- d_dim(dim),
- d_object_name(object_name),
- d_hierarchy(NULL),
- d_ln(-1),
- d_context(hier::VariableDatabase::getDatabase()->
- getContext(object_name + "::context")),
- d_cf_boundary(),
- d_physical_bc_coef_strategy(&d_physical_bc_simple_case),
- d_physical_bc_variable(NULL),
- d_physical_bc_simple_case(dim, d_object_name + "::simple bc"),
- d_cf_bc_coef(dim, object_name + "::coarse-fine bc coefs"),
- d_coarsefine_bc_variable(NULL),
- d_Ak0_id(-1),
- d_soln_depth(0),
- d_rhs_depth(0),
- d_max_iterations(10),
- d_relative_residual_tol(1e-10),
- d_number_iterations(-1),
- d_num_pre_relax_steps(1),
- d_num_post_relax_steps(1),
- d_relative_residual_norm(-1.0),
- d_use_smg(false),
- d_grid(NULL),
- d_stencil(NULL),
- d_matrix(NULL),
- d_linear_rhs(NULL),
- d_linear_sol(NULL),
- d_mg_data(NULL),
- d_print_solver_info(false)
-{
- if (d_dim == tbox::Dimension(1) || d_dim > tbox::Dimension(3)) {
- TBOX_ERROR(" CellStokesHypreSolver : DIM == 1 or > 3 not implemented");
- }
-
- t_solve_system = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesHypreSolver::solveSystem()");
- t_set_matrix_coefficients = tbox::TimerManager::getManager()->
- getTimer("solv::CellStokesHypreSolver::setMatrixCoefficients()");
-
- hier::VariableDatabase* vdb = hier::VariableDatabase::getDatabase();
- if (s_Ak0_var[d_dim.getValue() - 1].isNull()) {
- s_Ak0_var[d_dim.getValue() - 1] = new
- pdat::OutersideVariable<double>(d_dim, d_object_name + "::Ak0", 1);
- }
- d_Ak0_id =
- vdb->registerVariableAndContext(s_Ak0_var[d_dim.getValue() - 1],
- d_context,
- hier::IntVector::getZero(d_dim));
- if (database) {
- getFromInput(database);
- }
-}
-
-/*
- ********************************************************************
- * Set state from database *
- ********************************************************************
- */
-
-void CellStokesHypreSolver::getFromInput(
- tbox::Pointer<tbox::Database> database)
-{
- if (database) {
- d_print_solver_info = database->getBoolWithDefault("print_solver_info",
- d_print_solver_info);
- d_max_iterations = database->getIntegerWithDefault("max_iterations",
- d_max_iterations);
- d_relative_residual_tol = database->getDoubleWithDefault(
- "relative_residual_tol",
- d_relative_residual_tol);
- if (database->isDouble("residual_tol")) {
- TBOX_ERROR("CellStokesHypreSolver input error.\n"
- << "The parameter 'residual_tol' has been replaced\n"
- << "by 'relative_residual_tol' to be more descriptive.\n"
- << "Please change the parameter name in the input database.");
- }
- d_num_pre_relax_steps =
- database->getIntegerWithDefault("num_pre_relax_steps",
- d_num_pre_relax_steps);
- if (d_num_pre_relax_steps < 0) {
- TBOX_ERROR(d_object_name << ": Number of relaxation steps must be\n"
- << "non-negative.\n");
- }
- d_num_post_relax_steps =
- database->getIntegerWithDefault("num_post_relax_steps",
- d_num_post_relax_steps);
- if (d_num_post_relax_steps < 0) {
- TBOX_ERROR(d_object_name << ": Number of relaxation steps must be\n"
- << "non-negative.\n");
- }
- if (database->isBool("use_smg")) {
- bool use_smg = database->getBool("use_smg");
- if (use_smg != d_use_smg) {
- setUseSMG(use_smg);
- }
- }
- }
-}
-
-/*
- ********************************************************************
- * Initialize internal data for a given hierarchy level *
- * After setting internal data, propagate the information *
- * to the major algorithm objects. Allocate data for *
- * storing boundary condition-dependent quantities for *
- * adding to souce term before solving. *
- ********************************************************************
- */
-
-void CellStokesHypreSolver::initializeSolverState(
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- int ln)
-{
- TBOX_ASSERT(!hierarchy.isNull());
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
-
- deallocateSolverState();
-
- d_hierarchy = hierarchy;
- d_ln = ln;
-
- hier::IntVector max_gcw(d_dim, 1);
- d_cf_boundary = new hier::CoarseFineBoundary(*d_hierarchy, d_ln, max_gcw);
-
- d_physical_bc_simple_case.setHierarchy(d_hierarchy, d_ln, d_ln);
-
- d_number_iterations = -1;
- d_relative_residual_norm = -1.0;
-
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
- level->allocatePatchData(d_Ak0_id);
- allocateHypreData();
-}
-
-/*
- ********************************************************************
- * Deallocate data initialized by initializeSolverState *
- ********************************************************************
- */
-
-void CellStokesHypreSolver::deallocateSolverState()
-{
- if (d_hierarchy.isNull()) return;
-
- d_cf_boundary->clear();
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
- level->deallocatePatchData(d_Ak0_id);
- deallocateHypreData();
- d_hierarchy.setNull();
- d_ln = -1;
-}
-
-/*
- *************************************************************************
- * *
- * Allocate the HYPRE data structures that depend only on the level *
- * and will not change (grid, stencil, matrix, and vectors). *
- * *
- *************************************************************************
- */
-void CellStokesHypreSolver::allocateHypreData()
-{
- tbox::SAMRAI_MPI::Comm communicator = d_hierarchy->getDomainMappedBoxLevel().getMPI().getCommunicator();
-
- /*
- * Set up the grid data - only set grid data for local boxes
- */
-
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
- tbox::Pointer<geom::CartesianGridGeometry> grid_geometry =
- d_hierarchy->getGridGeometry();
- const hier::IntVector ratio = level->getRatioToLevelZero();
- hier::IntVector periodic_shift =
- grid_geometry->getPeriodicShift(ratio);
-
- int periodic_flag[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
- int d;
- bool is_periodic = false;
- for (d = 0; d < d_dim.getValue(); ++d) {
- periodic_flag[d] = periodic_shift[d] != 0;
- is_periodic = is_periodic || periodic_flag[d];
- }
-
- HYPRE_StructGridCreate(communicator, d_dim.getValue(), &d_grid);
- for (hier::PatchLevel::Iterator p(level); p; p++) {
- const hier::Box& box = (*p)->getBox();
- hier::Index lower = box.lower();
- hier::Index upper = box.upper();
- HYPRE_StructGridSetExtents(d_grid, &lower[0], &upper[0]);
- }
-
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (is_periodic) {
- const hier::BoxArray& level_domain = level->getPhysicalDomain();
- hier::Box domain_bound(level_domain[0]);
- for (int i = 1; i < level_domain.size(); ++i) {
- domain_bound.lower().min(level_domain[i].lower());
- domain_bound.upper().max(level_domain[i].upper());
- }
- for (d = 0; d < d_dim.getValue(); ++d) {
- if (periodic_flag[d] == true) {
- int tmpi = 1;
- unsigned int p_of_two;
- for (p_of_two = 0; p_of_two < 8 * sizeof(p_of_two) - 1;
- ++p_of_two) {
- if (tmpi == domain_bound.numberCells(d)) {
- break;
- }
- if (tmpi > domain_bound.numberCells(d)) {
- TBOX_ERROR(
- d_object_name << ": Hypre currently requires\n"
- <<
- "that grid size in periodic directions be\n"
- <<
- "powers of two. (This requirement may go\n"
- <<
- "away in future versions of hypre.)\n"
- << "Size problem in direction "
- << d << "\n"
- << "Domain bound is "
- << domain_bound << ",\n"
- << "Size of "
- << domain_bound.numberCells() << "\n");
- }
- tmpi = tmpi ? tmpi << 1 : 1;
- }
- }
- }
- }
-#endif
-
- HYPRE_StructGridSetPeriodic(d_grid, &periodic_shift[0]);
- HYPRE_StructGridAssemble(d_grid);
-
- {
- /*
- * Allocate stencil data and set stencil offsets
- */
-
- if (d_dim == tbox::Dimension(1)) {
- const int stencil_size = 2;
- int stencil_offsets[2][1] = {
- { -1 }, { 0 }
- };
- HYPRE_StructStencilCreate(d_dim.getValue(), stencil_size, &d_stencil);
- for (int s = 0; s < stencil_size; s++) {
- HYPRE_StructStencilSetElement(d_stencil, s,
- stencil_offsets[s]);
- }
- } else if (d_dim == tbox::Dimension(2)) {
- const int stencil_size = 3;
- int stencil_offsets[3][2] = {
- { -1, 0 }, { 0, -1 }, { 0, 0 }
- };
- HYPRE_StructStencilCreate(d_dim.getValue(), stencil_size, &d_stencil);
- for (int s = 0; s < stencil_size; s++) {
- HYPRE_StructStencilSetElement(d_stencil, s,
- stencil_offsets[s]);
- }
- } else if (d_dim == tbox::Dimension(3)) {
- const int stencil_size = 4;
- int stencil_offsets[4][3] = {
- { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 }, { 0, 0, 0 }
- };
- HYPRE_StructStencilCreate(d_dim.getValue(), stencil_size, &d_stencil);
- for (int s = 0; s < stencil_size; s++) {
- HYPRE_StructStencilSetElement(d_stencil, s,
- stencil_offsets[s]);
- }
- }
- }
-
- {
- int full_ghosts1[2 * 3] = { 1, 1, 0, 0, 0, 0 };
- int no_ghosts1[2 * 3] = { 0, 0, 0, 0, 0, 0 };
-
- int full_ghosts2[2 * 3] = { 1, 1, 1, 1, 0, 0 };
- int no_ghosts2[2 * 3] = { 0, 0, 0, 0, 0, 0 };
-
- int full_ghosts3[2 * 3] = { 1, 1, 1, 1, 1, 1 };
- int no_ghosts3[2 * 3] = { 0, 0, 0, 0, 0, 0 };
-
- /*
- * Allocate the structured matrix
- */
-
- int* full_ghosts = NULL;
- int* no_ghosts = NULL;
-
- if (d_dim == tbox::Dimension(1)) {
- full_ghosts = full_ghosts1;
- no_ghosts = no_ghosts1;
- } else if (d_dim == tbox::Dimension(2)) {
- full_ghosts = full_ghosts2;
- no_ghosts = no_ghosts2;
- } else if (d_dim == tbox::Dimension(3)) {
- full_ghosts = full_ghosts3;
- no_ghosts = no_ghosts3;
- } else {
- TBOX_ERROR(
- "CellStokesHypreSolver does not yet support dimension " << d_dim);
- }
-
- HYPRE_StructMatrixCreate(communicator,
- d_grid,
- d_stencil,
- &d_matrix);
- HYPRE_StructMatrixSetNumGhost(d_matrix, full_ghosts);
- HYPRE_StructMatrixSetSymmetric(d_matrix, 1);
- HYPRE_StructMatrixInitialize(d_matrix);
-
- HYPRE_StructVectorCreate(communicator,
- d_grid,
- &d_linear_rhs);
- HYPRE_StructVectorSetNumGhost(d_linear_rhs, no_ghosts);
- HYPRE_StructVectorInitialize(d_linear_rhs);
-
- HYPRE_StructVectorCreate(communicator,
- d_grid,
- &d_linear_sol);
- HYPRE_StructVectorSetNumGhost(d_linear_sol, full_ghosts);
- HYPRE_StructVectorInitialize(d_linear_sol);
- }
-}
-
-/*
- *************************************************************************
- * *
- * The destructor deallocates solver data. *
- * *
- *************************************************************************
- */
-
-CellStokesHypreSolver::~CellStokesHypreSolver()
-{
- deallocateHypreData();
-
- if (!d_hierarchy.isNull()) {
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(0);
- level->deallocatePatchData(d_Ak0_id);
- }
- hier::VariableDatabase* vdb =
- hier::VariableDatabase::getDatabase();
- vdb->removePatchDataIndex(d_Ak0_id);
-}
-
-/*
- *************************************************************************
- * *
- * Deallocate HYPRE data and solver. HYPRE requires that we *
- * check whether HYPRE has already deallocated this data. *
- * Note that the HYPRE solver, d_mg_data, was created at *
- * the end of setMatrixCoefficients. *
- * *
- *************************************************************************
- */
-
-void CellStokesHypreSolver::deallocateHypreData()
-{
- if (d_stencil) {
- HYPRE_StructStencilDestroy(d_stencil);
- d_stencil = NULL;
- }
- if (d_grid) {
- HYPRE_StructGridDestroy(d_grid);
- d_grid = NULL;
- }
- if (d_matrix) {
- HYPRE_StructMatrixDestroy(d_matrix);
- d_matrix = NULL;
- }
- if (d_linear_rhs) {
- HYPRE_StructVectorDestroy(d_linear_rhs);
- d_linear_rhs = NULL;
- }
- if (d_linear_sol) {
- HYPRE_StructVectorDestroy(d_linear_sol);
- d_linear_sol = NULL;
- }
- destroyHypreSolver();
-}
-
-/*
- *************************************************************************
- * *
- * Copy data into the HYPRE vector structures. *
- * *
- *************************************************************************
- */
-
-void CellStokesHypreSolver::copyToHypre(
- HYPRE_StructVector vector,
- pdat::CellData<double>& src,
- int depth,
- const hier::Box& box)
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS2(d_dim, src, box);
-
- for (pdat::CellIterator c(box); c; c++) {
- hier::IntVector ic = c();
- HYPRE_StructVectorSetValues(vector, &ic[0], src(c(), depth));
- }
-}
-
-/*
- *************************************************************************
- * *
- * Copy data out of the HYPRE vector structures. *
- * *
- *************************************************************************
- */
-
-void CellStokesHypreSolver::copyFromHypre(
- pdat::CellData<double>& dst,
- int depth,
- HYPRE_StructVector vector,
- const hier::Box box)
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS2(d_dim, dst, box);
-
- for (pdat::CellIterator c(box); c; c++) {
- double value;
- hier::IntVector ic = c();
- HYPRE_StructVectorGetValues(vector, &ic[0], &value);
- dst(c(), depth) = value;
- }
-}
-
-/*
- *************************************************************************
- * *
- * Set the matrix coefficients for the linear system. *
- * The matrix coefficients are dependent on the problem *
- * specification described by the StokesSpecificiations *
- * object and by the boundary condition. *
- * *
- *************************************************************************
- */
-
-void CellStokesHypreSolver::setMatrixCoefficients(
- const StokesSpecifications& spec)
-{
- if (d_physical_bc_coef_strategy == NULL) {
- TBOX_ERROR(
- d_object_name << ": No BC coefficient strategy object!\n"
- <<
- "Use either setBoundaries or setPhysicalBcCoefObject\n"
- <<
- "to specify the boundary conidition. Do it before\n"
- << "calling setMatrixCoefficients.");
- }
-
- t_set_matrix_coefficients->start();
-
- int i = 0;
-
- tbox::Pointer<pdat::CellData<double> > C_data;
- tbox::Pointer<pdat::SideData<double> > D_data;
-
- /*
- * Some computations can be done using high-level math objects.
- * Define the math objects.
- */
- math::ArrayDataBasicOps<double> array_math;
- math::PatchSideDataBasicOps<double> patch_side_math;
-
- /*
- * The value of the ghost cell based on the Robin boundary condition
- * can be written as the sum of a constant, k0, plus a multiple of the
- * internal cell value, k1*ui. k1*ui depends on the value of u so it
- * contributes to the product Au,
- * while the constant k0 contributes the right hand side f.
- * We save Ak0 = A*k0(a) to add to f when solving.
- * We assume unit g here because we will multiply it in just before
- * solving, thus allowing everything that does not affect A to change
- * from solve to solve.
- */
- tbox::Pointer<pdat::OutersideData<double> > Ak0;
-
- /*
- * Loop over patches and set matrix entries for each patch.
- */
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
- const hier::IntVector no_ghosts(d_dim, 0);
- for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
-
- hier::Patch& patch = **pi;
-
- tbox::Pointer<geom::CartesianPatchGeometry> pg =
- patch.getPatchGeometry();
-
- const double* h = pg->getDx();
-
- const hier::Box patch_box = patch.getBox();
- const hier::Index patch_lo = patch_box.lower();
- const hier::Index patch_up = patch_box.upper();
-
- if (!spec.cIsZero() && !spec.cIsConstant()) {
- C_data = patch.getPatchData(spec.getCPatchDataId());
- if (C_data.isNull()) {
- TBOX_ERROR(d_object_name << ": Invalid cell variable index "
- << spec.getCPatchDataId()
- << " for the C parameter. It is not\n"
- << "cell-centered double data.");
- }
- }
-
- if (!spec.dIsConstant()) {
- D_data = patch.getPatchData(spec.getDPatchDataId());
- if (D_data.isNull()) {
- TBOX_ERROR(d_object_name << ": Invalid cell variable index "
- << spec.getDPatchDataId()
- <<
- " for diffusion coefficient. It is not\n"
- << "side-centered double data.");
- }
- }
-
- Ak0 = patch.getPatchData(d_Ak0_id);
-
- Ak0->fillAll(0.0);
-
- pdat::CellData<double> diagonal(patch_box, 1, no_ghosts);
-
- /*
- * Set diagonals to zero so we can accumulate to it.
- * Accumulation is used at boundaries to shift weights
- * for ghost cells onto the diagonal.
- */
- diagonal.fillAll(0.0);
-
- const tbox::Pointer<geom::CartesianPatchGeometry>
- geometry = patch.getPatchGeometry();
-
- const hier::Index ifirst = patch_box.lower();
- const hier::Index ilast = patch_box.upper();
-
- /*
- * Storage for off-diagonal entries,
- * which can be variable or constant.
- */
- pdat::SideData<double> off_diagonal(patch_box, 1, no_ghosts);
-
- /*
- * Compute all off-diagonal entries with no regard to BCs.
- * These off-diagonal entries are simply D/(h*h), according
- * to our central difference formula.
- */
- if (spec.dIsConstant()) {
- for (i = 0; i < d_dim.getValue(); ++i) {
- double dhh = spec.getDConstant() / (h[i] * h[i]);
- pdat::ArrayData<double>& off_diag_array(off_diagonal.getArrayData(i));
- off_diag_array.fill(dhh);
- }
- } else {
- for (i = 0; i < d_dim.getValue(); ++i) {
- hier::Box sbox(patch_box);
- sbox.growUpper(i, 1);
- array_math.scale(off_diagonal.getArrayData(i),
- 1.0 / (h[i] * h[i]),
- D_data->getArrayData(i),
- sbox);
- }
- }
-
- /*
- * Compute diagonal entries using off-diagonal contributions.
- */
- if (spec.cIsZero()) {
- computeDiagonalEntries(diagonal,
- off_diagonal,
- patch_box);
- } else if (spec.cIsConstant()) {
- computeDiagonalEntries(diagonal,
- spec.getCConstant(),
- off_diagonal,
- patch_box);
- } else {
- computeDiagonalEntries(diagonal,
- *C_data,
- off_diagonal,
- patch_box);
- }
-
- /*
- * Walk physical domain boundaries and adjust off-diagonals
- * before computation of diagonal entries.
- * The exterior cell's value is
- * uo = ( h*gamma + ui*(beta-h*alpha/2) )/( beta+h*alpha/2 )
- * = k0 + k1*ui
- * where k0 = h*gamma/( beta+h*alpha/2 )
- * k1 = ( beta-h*alpha/2 )/( beta+h*alpha/2 )
- * Split coupling between interior-exterior cells
- * into two parts: interior-interior coupling (k1)
- * and rhs contribution (k0).
- */
- {
- const tbox::Array<hier::BoundaryBox>& surface_boxes =
- pg->getCodimensionBoundaries(1);
- const int n_bdry_boxes = surface_boxes.getSize();
- for (int n = 0; n < n_bdry_boxes; ++n) {
-
- const hier::BoundaryBox& boundary_box = surface_boxes[n];
- if (boundary_box.getBoundaryType() != 1) {
- TBOX_ERROR(
- d_object_name << ": Illegal boundary type in "
- <<
- "CellStokesHypreSolver::setMatrixCoefficients\n");
- }
- const hier::BoundaryBoxUtils bbu(boundary_box);
- const int location_index = boundary_box.getLocationIndex();
- const hier::BoundaryBox trimmed_boundary_box =
- bbu.trimBoundaryBox(patch.getBox());
- const hier::Box bccoef_box =
- bbu.getSurfaceBoxFromBoundaryBox();
- tbox::Pointer<pdat::ArrayData<double> >
- acoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
- tbox::Pointer<pdat::ArrayData<double> >
- bcoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
- tbox::Pointer<pdat::ArrayData<double> >
- gcoef_data(NULL);
- static const double fill_time = 0.0;
- d_physical_bc_coef_strategy->setBcCoefs(acoef_data,
- bcoef_data,
- gcoef_data,
- d_physical_bc_variable,
- patch,
- boundary_box,
- fill_time);
- pdat::ArrayData<double>& Ak0_data =
- Ak0->getArrayData(location_index / 2,
- location_index % 2);
- adjustBoundaryEntries(diagonal,
- off_diagonal,
- patch_box,
- *acoef_data,
- *bcoef_data,
- bccoef_box,
- Ak0_data,
- trimmed_boundary_box,
- h);
- }
- }
-
- /*
- * Walk coarse-fine boundaries and adjust off-diagonals
- * according data in ghost cells.
- */
- if (d_ln > 0) {
- /*
- * There are potentially coarse-fine boundaries to deal with.
- */
-
- tbox::Array<hier::BoundaryBox> surface_boxes;
-
- if (d_dim == tbox::Dimension(2)) {
- surface_boxes = d_cf_boundary->getEdgeBoundaries(pi->getGlobalId());
- } else if (d_dim == tbox::Dimension(3)) {
- surface_boxes = d_cf_boundary->getFaceBoundaries(pi->getGlobalId());
- }
-
- const int n_bdry_boxes = surface_boxes.getSize();
- for (int n = 0; n < n_bdry_boxes; ++n) {
-
- const hier::BoundaryBox& boundary_box = surface_boxes[n];
- if (boundary_box.getBoundaryType() != 1) {
- TBOX_ERROR(
- d_object_name << ": Illegal boundary type in "
- <<
- "CellStokesHypreSolver::setMatrixCoefficients\n");
- }
- const int location_index = boundary_box.getLocationIndex();
- const hier::BoundaryBoxUtils bbu(boundary_box);
- const hier::BoundaryBox trimmed_boundary_box =
- bbu.trimBoundaryBox(patch.getBox());
- const hier::Box bccoef_box =
- bbu.getSurfaceBoxFromBoundaryBox();
- tbox::Pointer<pdat::ArrayData<double> >
- acoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
- tbox::Pointer<pdat::ArrayData<double> >
- bcoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
- tbox::Pointer<pdat::ArrayData<double> >
- gcoef_data(NULL);
- static const double fill_time = 0.0;
- /*
- * Reset invalid ghost data id to help detect use in setBcCoefs.
- */
- d_cf_bc_coef.setGhostDataId(-1, hier::IntVector::getZero(d_dim));
- d_cf_bc_coef.setBcCoefs(acoef_data,
- bcoef_data,
- gcoef_data,
- d_coarsefine_bc_variable,
- patch,
- boundary_box,
- fill_time);
- pdat::ArrayData<double>& Ak0_data =
- Ak0->getArrayData(location_index / 2,
- location_index % 2);
- adjustBoundaryEntries(diagonal,
- off_diagonal,
- patch_box,
- *acoef_data,
- *bcoef_data,
- bccoef_box,
- Ak0_data,
- trimmed_boundary_box,
- h);
- }
- }
-
- /*
- * Copy matrix entries to HYPRE matrix structure. Note that
- * we translate our temporary diagonal/off-diagonal storage into the
- * HYPRE symmetric storage scheme for the stencil specified earlier.
- */
- const int stencil_size = d_dim.getValue() + 1;
- int stencil_indices[stencil_size];
- double mat_entries[stencil_size];
-
- for (i = 0; i < stencil_size; i++) stencil_indices[i] = i;
-
- pdat::CellIterator ic(patch_box);
-
- /*
- * To do: This loop uses inefficient high-level syntax.
- * See if it can be replaced by a Fortran loop or if we
- * can set matrix entries for an entire box at once.
- */
- for ( ; ic; ic++) {
-
- hier::IntVector icell = ic();
- pdat::SideIndex ixlower(ic(),
- pdat::SideIndex::X,
- pdat::SideIndex::Lower);
- mat_entries[0] = (off_diagonal)(ixlower);
-
- if (d_dim > tbox::Dimension(1)) {
- pdat::SideIndex iylower(ic(),
- pdat::SideIndex::Y,
- pdat::SideIndex::Lower);
- mat_entries[1] = (off_diagonal)(iylower);
- }
-
- if (d_dim > tbox::Dimension(2)) {
- pdat::SideIndex izlower(ic(),
- pdat::SideIndex::Z,
- pdat::SideIndex::Lower);
- // The "funny" indexing prevents a warning when compiling for
- // DIM < 2. This code is only reached if DIM > 2 when
- // executing.
- mat_entries[d_dim.getValue() > 2 ? 2 : 0] = (off_diagonal)(izlower);
- }
-
- mat_entries[d_dim.getValue()] = (diagonal)(ic());
- HYPRE_StructMatrixSetValues(d_matrix, &icell[0],
- stencil_size, stencil_indices,
- mat_entries);
- } // end cell loop
-
- } // end patch loop
-
- if (d_print_solver_info) {
- HYPRE_StructMatrixPrint("mat_bA.out", d_matrix, 1);
- }
-
- HYPRE_StructMatrixAssemble(d_matrix);
-
- if (d_print_solver_info) {
- HYPRE_StructMatrixPrint("mat_aA.out", d_matrix, 1);
- }
-
- t_set_matrix_coefficients->stop();
-
- setupHypreSolver();
-}
-
-/*
- **********************************************************************
- * Add g*A*k0(a) from physical boundaries to rhs. *
- * This operation is done for physical as well as cf boundaries, *
- * so it is placed in a function. *
- **********************************************************************
- */
-
-void CellStokesHypreSolver::add_gAk0_toRhs(
- const hier::Patch& patch,
- const tbox::Array<hier::BoundaryBox>& bdry_boxes,
- const RobinBcCoefStrategy* robin_bc_coef,
- pdat::CellData<double>& rhs)
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS2(d_dim, patch, rhs);
-
- /*
- * g*A*k0(a) is the storage for adjustments to be made to the rhs
- * when we solve. This is the value of the weight of the ghost cell
- * value for the interior cell, times k0. It is independent of u,
- * and so is moved to the rhs. Before solving, g*A*k0(a) is added
- * to rhs.
- */
- tbox::Pointer<pdat::OutersideData<double> > Ak0;
-
- tbox::Pointer<geom::CartesianPatchGeometry> pg =
- patch.getPatchGeometry();
-
- Ak0 = patch.getPatchData(d_Ak0_id);
-
- const int n_bdry_boxes = bdry_boxes.getSize();
- for (int n = 0; n < n_bdry_boxes; ++n) {
-
- const hier::BoundaryBox& boundary_box = bdry_boxes[n];
-#ifdef DEBUG_CHECK_ASSERTIONS
- if (boundary_box.getBoundaryType() != 1) {
- TBOX_ERROR(d_object_name << ": Illegal boundary type in "
- << "CellStokesHypreSolver::add_gAk0_toRhs\n");
- }
-#endif
- const int location_index = boundary_box.getLocationIndex();
- const hier::BoundaryBoxUtils bbu(boundary_box);
- const hier::BoundaryBox trimmed_boundary_box =
- bbu.trimBoundaryBox(patch.getBox());
- const hier::Index& lower = trimmed_boundary_box.getBox().lower();
- const hier::Index& upper = trimmed_boundary_box.getBox().upper();
- const hier::Box& rhsbox = rhs.getArrayData().getBox();
- const hier::Box& Ak0box = Ak0->getArrayData(location_index / 2,
- location_index % 2).getBox();
- const hier::Box bccoef_box = bbu.getSurfaceBoxFromBoundaryBox();
- tbox::Pointer<pdat::ArrayData<double> >
- acoef_data(NULL);
- tbox::Pointer<pdat::ArrayData<double> >
- bcoef_data(NULL);
- tbox::Pointer<pdat::ArrayData<double> >
- gcoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
- static const double fill_time = 0.0;
- robin_bc_coef->setBcCoefs(acoef_data,
- bcoef_data,
- gcoef_data,
- d_physical_bc_variable,
- patch,
- boundary_box,
- fill_time);
- /*
- * Nomenclature for indices: cel=first-cell, gho=ghost,
- * beg=beginning, end=ending.
- */
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(adjustrhs2d, ADJUSTRHS2D) (rhs.getPointer(d_rhs_depth),
- &rhsbox.lower()[0],
- &rhsbox.upper()[0],
- &rhsbox.lower()[1],
- &rhsbox.upper()[1],
- Ak0->getPointer(location_index / 2, location_index % 2),
- &Ak0box.lower()[0],
- &Ak0box.upper()[0],
- &Ak0box.lower()[1],
- &Ak0box.upper()[1],
- gcoef_data->getPointer(),
- &bccoef_box.lower()[0],
- &bccoef_box.upper()[0],
- &bccoef_box.lower()[1],
- &bccoef_box.upper()[1],
- &lower[0], &upper[0],
- &location_index);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(adjustrhs3d, ADJUSTRHS3D) (rhs.getPointer(d_rhs_depth),
- &rhsbox.lower()[0],
- &rhsbox.upper()[0],
- &rhsbox.lower()[1],
- &rhsbox.upper()[1],
- &rhsbox.lower()[2],
- &rhsbox.upper()[2],
- Ak0->getPointer(location_index / 2, location_index % 2),
- &Ak0box.lower()[0],
- &Ak0box.upper()[0],
- &Ak0box.lower()[1],
- &Ak0box.upper()[1],
- &Ak0box.lower()[2],
- &Ak0box.upper()[2],
- gcoef_data->getPointer(),
- &bccoef_box.lower()[0],
- &bccoef_box.upper()[0],
- &bccoef_box.lower()[1],
- &bccoef_box.upper()[1],
- &bccoef_box.lower()[2],
- &bccoef_box.upper()[2],
- &lower[0], &upper[0],
- &location_index);
- }
- }
-}
-
-/*
- *************************************************************************
- * Create the hypre solver and set it according to the current state. *
- *************************************************************************
- */
-void CellStokesHypreSolver::setupHypreSolver()
-{
- TBOX_ASSERT(d_mg_data == NULL);
-
- tbox::SAMRAI_MPI::Comm communicator = d_hierarchy->getDomainMappedBoxLevel().getMPI().getCommunicator();
-
- if (d_use_smg) {
- HYPRE_StructSMGCreate(communicator, &d_mg_data);
- HYPRE_StructSMGSetMemoryUse(d_mg_data, 0);
- HYPRE_StructSMGSetMaxIter(d_mg_data, d_max_iterations);
- HYPRE_StructSMGSetTol(d_mg_data, d_relative_residual_tol);
- HYPRE_StructSMGSetLogging(d_mg_data, 1);
- HYPRE_StructSMGSetNumPreRelax(d_mg_data,
- d_num_pre_relax_steps);
- HYPRE_StructSMGSetNumPostRelax(d_mg_data,
- d_num_post_relax_steps);
- HYPRE_StructSMGSetup(d_mg_data,
- d_matrix,
- d_linear_rhs,
- d_linear_sol);
- } else {
- HYPRE_StructPFMGCreate(communicator, &d_mg_data);
- HYPRE_StructPFMGSetMaxIter(d_mg_data, d_max_iterations);
- HYPRE_StructPFMGSetTol(d_mg_data, d_relative_residual_tol);
- HYPRE_StructPFMGSetLogging(d_mg_data, 1);
- HYPRE_StructPFMGSetNumPreRelax(d_mg_data,
- d_num_pre_relax_steps);
- HYPRE_StructPFMGSetNumPostRelax(d_mg_data,
- d_num_post_relax_steps);
- HYPRE_StructPFMGSetup(d_mg_data,
- d_matrix,
- d_linear_rhs,
- d_linear_sol);
- }
-}
-
-void CellStokesHypreSolver::destroyHypreSolver()
-{
- if (d_mg_data != NULL) {
- if (d_use_smg) {
- HYPRE_StructSMGDestroy(d_mg_data);
- } else {
- HYPRE_StructPFMGDestroy(d_mg_data);
- }
- d_mg_data = NULL;
- }
-}
-
-/*
- *************************************************************************
- * *
- * Solve the linear system. This routine assumes that the boundary *
- * conditions and the matrix coefficients have been specified. *
- * *
- *************************************************************************
- */
-
-int CellStokesHypreSolver::solveSystem(
- const int u,
- const int f,
- bool homogeneous_bc)
-{
- if (d_physical_bc_coef_strategy == NULL) {
- TBOX_ERROR(
- d_object_name << ": No BC coefficient strategy object!\n"
- <<
- "Use either setBoundaries or setPhysicalBcCoefObject\n"
- <<
- "to specify the boundary conidition. Do it before\n"
- << "calling solveSystem.");
- }
- // Tracer t("CellStokesHypreSolver::solveSystem");
-
- t_solve_system->start();
-
- tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
-#ifdef DEBUG_CHECK_ASSERTIONS
- TBOX_ASSERT(u >= 0);
- TBOX_ASSERT(
- u < level->getPatchDescriptor()->getMaxNumberRegisteredComponents());
- TBOX_ASSERT(f >= 0);
- TBOX_ASSERT(
- f < level->getPatchDescriptor()->getMaxNumberRegisteredComponents());
-#endif
-
- if (d_physical_bc_coef_strategy == &d_physical_bc_simple_case) {
- /*
- * If we are using the simple bc implementation, the final piece
- * of information it requires is the Dirichlet boundary value
- * set in the ghost cells. Now that we have the ghost cell data,
- * we can complete the boundary condition setup.
- */
- d_physical_bc_simple_case.cacheDirichletData(u);
- }
-
- /*
- * Modify right-hand-side to account for boundary conditions and
- * copy solution and right-hand-side to HYPRE structures.
- */
-
- const hier::IntVector no_ghosts(d_dim, 0);
- const hier::IntVector ghosts(d_dim, 1);
-
- /*
- * At coarse-fine boundaries, we expect ghost cells to have correct
- * values to be used in our bc, so u provides the ghost cell data.
- * Assume that the user only provided data for the immediate first
- * ghost cell, so pass zero for the number of extensions fillable.
- */
- d_cf_bc_coef.setGhostDataId(u, hier::IntVector::getZero(d_dim));
-
- for (hier::PatchLevel::Iterator p(level); p; p++) {
- tbox::Pointer<hier::Patch> patch = *p;
-
- const hier::Box box = patch->getBox();
-
- /*
- * Set up variable data needed to prepare linear system solver.
- */
- tbox::Pointer<pdat::CellData<double> > u_data_ = patch->getPatchData(u);
-#ifdef DEBUG_CHECK_ASSERTIONS
- TBOX_ASSERT(!u_data_.isNull());
-#endif
- pdat::CellData<double>& u_data = *u_data_;
- pdat::CellData<double> rhs_data(box, 1, no_ghosts);
-
- /*
- * Copy rhs and solution from the hierarchy into HYPRE structures.
- * For rhs, add in the contribution from boundary conditions, if
- * needed. If boundary condition is homogenous, this only adds
- * zero, so we skip it.
- */
- copyToHypre(d_linear_sol, u_data, d_soln_depth, box);
- rhs_data.copy(*(patch->getPatchData(f)));
- if (!homogeneous_bc) {
- /*
- * Add g*A*k0(a) from physical and coarse-fine boundaries to rhs.
- */
- add_gAk0_toRhs(*patch,
- patch->getPatchGeometry()->getCodimensionBoundaries(1),
- d_physical_bc_coef_strategy,
- rhs_data);
- add_gAk0_toRhs(*patch,
- d_cf_boundary->getBoundaries(patch->getGlobalId(), 1),
- &d_cf_bc_coef,
- rhs_data);
- }
- copyToHypre(d_linear_rhs, rhs_data, d_rhs_depth, box);
-
- } // end patch loop
-
- /*
- * Reset invalid ghost data id to help detect erroneous further use.
- */
- d_cf_bc_coef.setGhostDataId(-1, hier::IntVector::getZero(d_dim));
-
- /*
- * Finish assembly of the vectors
- */
- HYPRE_StructVectorAssemble(d_linear_sol);
-
- HYPRE_StructVectorAssemble(d_linear_rhs);
-
- /*
- * Solve the system - zero means convergence
- * Solve takes the same arguments as Setup
- */
-
- if (d_print_solver_info) {
- HYPRE_StructVectorPrint("sol0.out", d_linear_sol, 1);
- HYPRE_StructMatrixPrint("mat0.out", d_matrix, 1);
- HYPRE_StructVectorPrint("rhs.out", d_linear_rhs, 1);
- }
-
- if (d_use_smg) {
- // HYPRE_StructSMGSetMaxIter(d_mg_data, d_max_iterations);
- HYPRE_StructSMGSetTol(d_mg_data, d_relative_residual_tol);
- /* converge = */ HYPRE_StructSMGSolve(d_mg_data,
- d_matrix,
- d_linear_rhs,
- d_linear_sol);
- } else {
- // HYPRE_StructPFMGSetMaxIter(d_mg_data, d_max_iterations);
- HYPRE_StructPFMGSetTol(d_mg_data, d_relative_residual_tol);
- /* converge = */ HYPRE_StructPFMGSolve(d_mg_data,
- d_matrix,
- d_linear_rhs,
- d_linear_sol);
- }
-
- if (d_print_solver_info) {
- HYPRE_StructMatrixPrint("mat.out", d_matrix, 1);
- HYPRE_StructVectorPrint("sol.out", d_linear_sol, 1);
- }
-
- if (d_use_smg) {
- HYPRE_StructSMGGetNumIterations(d_mg_data,
- &d_number_iterations);
- HYPRE_StructSMGGetFinalRelativeResidualNorm(d_mg_data,
- &d_relative_residual_norm);
- } else {
- HYPRE_StructPFMGGetNumIterations(d_mg_data,
- &d_number_iterations);
- HYPRE_StructPFMGGetFinalRelativeResidualNorm(d_mg_data,
- &d_relative_residual_norm);
- }
-
- /*
- * Pull the solution vector out of the HYPRE structures
- */
- for (hier::PatchLevel::Iterator ip(level); ip; ip++) {
- tbox::Pointer<hier::Patch> patch = *ip;
- tbox::Pointer<pdat::CellData<double> > u_data_ = patch->getPatchData(u);
- pdat::CellData<double>& u_data = *u_data_;
- copyFromHypre(u_data,
- d_soln_depth,
- d_linear_sol,
- patch->getBox());
- }
-
- t_solve_system->stop();
-
- return d_relative_residual_norm <= d_relative_residual_tol;
-}
-
-void CellStokesHypreSolver::computeDiagonalEntries(
- pdat::CellData<double>& diagonal,
- const pdat::CellData<double>& C_data,
- const pdat::SideData<double>& off_diagonal,
- const hier::Box& patch_box)
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim,
- diagonal,
- C_data,
- off_diagonal,
- patch_box);
-
- const hier::Index patch_lo = patch_box.lower();
- const hier::Index patch_up = patch_box.upper();
- const double c = 1.0, d = 1.0;
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compdiagvariablec2d, COMPDIAGVARIABLEC2D) (diagonal.getPointer(),
- C_data.getPointer(),
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &c, &d);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compdiagvariablec3d, COMPDIAGVARIABLEC3D) (diagonal.getPointer(),
- C_data.getPointer(),
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- off_diagonal.getPointer(2),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &patch_lo[2], &patch_up[2],
- &c, &d);
- }
-}
-
-void CellStokesHypreSolver::computeDiagonalEntries(
- pdat::CellData<double>& diagonal,
- const double C,
- const pdat::SideData<double>& off_diagonal,
- const hier::Box& patch_box)
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS3(d_dim, diagonal, off_diagonal, patch_box);
-
- const hier::Index patch_lo = patch_box.lower();
- const hier::Index patch_up = patch_box.upper();
- const double c = 1.0, d = 1.0;
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compdiagscalarc2d, COMPDIAGSCALARC2D) (diagonal.getPointer(),
- &C,
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &c, &d);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compdiagscalarc3d, COMPDIAGSCALARC3D) (diagonal.getPointer(),
- &C,
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- off_diagonal.getPointer(2),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &patch_lo[2], &patch_up[2],
- &c, &d);
- } else {
- TBOX_ERROR("CellStokesHypreSolver error...\n"
- << "DIM > 3 not supported." << std::endl);
- }
-}
-
-void CellStokesHypreSolver::computeDiagonalEntries(
- pdat::CellData<double>& diagonal,
- const pdat::SideData<double>& off_diagonal,
- const hier::Box& patch_box)
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS3(d_dim, diagonal, off_diagonal, patch_box);
-
- const hier::Index patch_lo = patch_box.lower();
- const hier::Index patch_up = patch_box.upper();
- const double c = 1.0, d = 1.0;
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(compdiagzeroc2d, COMPDIAGZEROC2D) (diagonal.getPointer(),
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &c, &d);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(compdiagzeroc3d, COMPDIAGZEROC3D) (diagonal.getPointer(),
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- off_diagonal.getPointer(2),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &patch_lo[2], &patch_up[2],
- &c, &d);
- } else {
- TBOX_ERROR("CellStokesHypreSolver error...\n"
- << "DIM > 3 not supported." << std::endl);
- }
-}
-
-void CellStokesHypreSolver::adjustBoundaryEntries(
- pdat::CellData<double>& diagonal,
- const pdat::SideData<double>& off_diagonal,
- const hier::Box& patch_box,
- const pdat::ArrayData<double>& acoef_data,
- const pdat::ArrayData<double>& bcoef_data,
- const hier::Box bccoef_box,
- pdat::ArrayData<double>& Ak0_data,
- const hier::BoundaryBox& trimmed_boundary_box,
- const double h[tbox::Dimension::MAXIMUM_DIMENSION_VALUE])
-{
- TBOX_DIM_ASSERT_CHECK_DIM_ARGS8(d_dim, diagonal, off_diagonal, patch_box,
- acoef_data, bcoef_data,
- bccoef_box, Ak0_data, trimmed_boundary_box);
-
- const hier::Index patch_lo = patch_box.lower();
- const hier::Index patch_up = patch_box.upper();
- const int location_index = trimmed_boundary_box.getLocationIndex();
- const hier::Index& lower = trimmed_boundary_box.getBox().lower();
- const hier::Index& upper = trimmed_boundary_box.getBox().upper();
- const hier::Box& Ak0_box = Ak0_data.getBox();
- if (d_dim == tbox::Dimension(2)) {
- F77_FUNC(adjbdry2d, ADJBDRY2D) (diagonal.getPointer(),
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- acoef_data.getPointer(),
- bcoef_data.getPointer(),
- &bccoef_box.lower()[0],
- &bccoef_box.upper()[0],
- &bccoef_box.lower()[1],
- &bccoef_box.upper()[1],
- Ak0_data.getPointer(),
- &Ak0_box.lower()[0],
- &Ak0_box.upper()[0],
- &Ak0_box.lower()[1],
- &Ak0_box.upper()[1],
- &lower[0], &upper[0],
- &location_index, h);
- } else if (d_dim == tbox::Dimension(3)) {
- F77_FUNC(adjbdry3d, ADJBDRY3D) (diagonal.getPointer(),
- off_diagonal.getPointer(0),
- off_diagonal.getPointer(1),
- off_diagonal.getPointer(2),
- &patch_lo[0], &patch_up[0],
- &patch_lo[1], &patch_up[1],
- &patch_lo[2], &patch_up[2],
- acoef_data.getPointer(),
- bcoef_data.getPointer(),
- &bccoef_box.lower()[0],
- &bccoef_box.upper()[0],
- &bccoef_box.lower()[1],
- &bccoef_box.upper()[1],
- &bccoef_box.lower()[2],
- &bccoef_box.upper()[2],
- Ak0_data.getPointer(),
- &Ak0_box.lower()[0],
- &Ak0_box.upper()[0],
- &Ak0_box.lower()[1],
- &Ak0_box.upper()[1],
- &Ak0_box.lower()[2],
- &Ak0_box.upper()[2],
- &lower[0], &upper[0],
- &location_index, h);
- } else {
- TBOX_ERROR("CellStokesHypreSolver error...\n"
- << "DIM > 3 not supported." << std::endl);
- }
-}
-
-void
-CellStokesHypreSolver::finalizeCallback()
-{
- for (int d = 0; d < tbox::Dimension::MAXIMUM_DIMENSION_VALUE; ++d) {
- s_Ak0_var[d].setNull();
- }
-}
-
-}
-}
-
-#endif
-#endif
diff -r a44a82f15794 -r fe2a9230921b CellStokesHypreSolver.I
--- a/CellStokesHypreSolver.I Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: Level solver for diffusion-like elliptic problems.
- *
- ************************************************************************/
-namespace SAMRAI {
-namespace solv {
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setSolnIdDepth(
- const int depth) {
- d_soln_depth = depth;
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setRhsIdDepth(
- const int depth) {
- d_rhs_depth = depth;
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setUseSMG(
- bool use_smg) {
- d_use_smg = use_smg;
-}
-
-/*
- ********************************************************************
- * Specify bc using the default internal bc coefficient object. *
- * Clear up data supporting external bc coefficient setter. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setBoundaries(
- const std::string& boundary_type,
- const int fluxes,
- const int flags,
- int* bdry_types)
-{
- d_physical_bc_simple_case.setBoundaries(boundary_type,
- fluxes,
- flags,
- bdry_types);
- d_physical_bc_coef_strategy = &d_physical_bc_simple_case;
- d_physical_bc_variable.setNull();
-}
-
-/*
- ********************************************************************
- * Set the physical boundary condition object. *
- ********************************************************************
- */
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setPhysicalBcCoefObject(
- const RobinBcCoefStrategy* physical_bc_coef_strategy,
- const tbox::Pointer<hier::Variable> variable)
-{
- d_physical_bc_coef_strategy = physical_bc_coef_strategy;
- d_physical_bc_variable = variable;
-}
-
-SAMRAI_INLINE_KEYWORD
-int CellStokesHypreSolver::getNumberOfIterations() const
-{
- return d_number_iterations;
-}
-
-SAMRAI_INLINE_KEYWORD
-double CellStokesHypreSolver::getRelativeResidualNorm() const
-{
- return d_relative_residual_norm;
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setNumPreRelaxSteps(
- const int steps)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- TBOX_ASSERT(!d_hierarchy.isNull());
-#endif
- d_num_pre_relax_steps = steps;
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setNumPostRelaxSteps(
- const int steps)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- TBOX_ASSERT(!d_hierarchy.isNull());
-#endif
- d_num_post_relax_steps = steps;
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setPrintSolverInfo(
- const bool print)
-{
- d_print_solver_info = print;
-}
-
-SAMRAI_INLINE_KEYWORD
-void CellStokesHypreSolver::setStoppingCriteria(
- const int max_iterations,
- const double residual_tol)
-{
-#ifdef DEBUG_CHECK_ASSERTIONS
- TBOX_ASSERT(max_iterations >= 0);
- TBOX_ASSERT(residual_tol >= 0.0);
-#endif
- d_max_iterations = max_iterations;
- d_relative_residual_tol = residual_tol;
-}
-
-}
-}
diff -r a44a82f15794 -r fe2a9230921b CellStokesHypreSolver.h
--- a/CellStokesHypreSolver.h Fri Dec 31 12:00:54 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,617 +0,0 @@
-/*************************************************************************
- *
- * This file is part of the SAMRAI distribution. For full copyright
- * information, see COPYRIGHT and COPYING.LESSER.
- *
- * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
- * Description: Hypre solver interface for diffusion-like elliptic problems.
- *
- ************************************************************************/
-#ifndef included_solv_CellStokesHypreSolver
-#define included_solv_CellStokesHypreSolver
-
-#include "SAMRAI/SAMRAI_config.h"
-
-#ifdef HAVE_HYPRE
-
-#ifndef included_HYPRE_struct_ls
-/*
- * This might break things if F77_FUNC_ is different for hypre vs
- * SAMRAI autoconf detection. But then C/C++ macros are totally
- * broken due to namespace collision as this example highlights so
- * resorting to hacks are necessary.
- */
-#ifdef F77_FUNC_
-#undef F77_FUNC_
-#endif
-#include "HYPRE_struct_ls.h"
-#define included_HYPRE_struct_ls
-#endif
-
-#include "SAMRAI/solv/GhostCellRobinBcCoefs.h"
-#include "SAMRAI/solv/RobinBcCoefStrategy.h"
-#include "StokesSpecifications.h"
-#include "SAMRAI/solv/SimpleCellRobinBcCoefs.h"
-#include "SAMRAI/pdat/CellData.h"
-#include "SAMRAI/pdat/SideData.h"
-#include "SAMRAI/pdat/OutersideVariable.h"
-#include "SAMRAI/hier/BoxList.h"
-#include "SAMRAI/hier/CoarseFineBoundary.h"
-#include "SAMRAI/hier/PatchHierarchy.h"
-#include "SAMRAI/hier/PatchLevel.h"
-#include "SAMRAI/hier/VariableContext.h"
-#include "SAMRAI/tbox/Database.h"
-#include "SAMRAI/tbox/Pointer.h"
-
-#include <string>
-
-namespace SAMRAI {
-namespace solv {
-
-/*!
- * @brief Use the HYPRE preconditioner library to solve (the cell-centered)
- * Stokes's equation on a single level in a hierarchy.
- *
- * Class CellStokesHypreSolver uses the HYPRE preconditioner library
- * to solve linear equations of the form
- * @f$ \nabla ( D \nabla u ) + C u = f @f$, where
- * C is a cell-centered array, D is a face-centered array,
- * and u and f are cell-centered arrays
- * (see StokesSpecifications).
- * The discretization is the standard second order
- * finite difference stencil.
- *
- * Robin boundary conditions are used through the
- * interface class RobinBcCoefStrategy.
- * Periodic boundary conditions are not supported yet.
- *
- * The user must perform the following steps to use
- * CellStokesHypreSolver:
- * - Create a CellStokesHypreSolver object.
- * - Initialize CellStokesHypreSolver object with a patch hierarchy,
- * using the function initializeSolverState().
- * - Use the functions setPhysicalBcCoefObject()
- * to provide implementations of RobinBcCoefStrategy.
- * (For most problems you can probably find a suitable
- * implementation to use without implementing the
- * strategy yourself. See for example
- * SimpleCellRobinBcCoefs and GhostCellRobinBcCoefs.)
- * - Set the matrix coefficients in the linear system,
- * using the function setMatrixCoefficients().
- * - Specify the stopping criteria using setStoppingCriteria().
- * - Solve the linear system, passing in u and f as the patch
- * indices of the solution and the right hand side, respectively.
- *
- * Sample parameters for initialization from database (and their
- * default values):
- * @verbatim
- * print_solver_info = FALSE // Whether to print some data for debugging
- * max_iterations = 10 // Max iterations used by Hypre
- * relative_residual_tol = 1.0e-8 // Residual tolerance used by Hypre
- * num_pre_relax_steps = 1 // # of presmoothing steps used by Hypre
- * num_post_relax_steps = 1 // # of postsmoothing steps used by Hypre
- * use_smg = FALSE // Whether to use hypre's smg solver
- * // (alternative is the pfmg solver)
- * @endverbatim
- */
-
-class CellStokesHypreSolver
-{
-public:
- /*!
- * @brief Constructor.
- *
- * @param object_name Name of object.
- * @param database tbox::Database for input.
- */
- CellStokesHypreSolver(
- const tbox::Dimension& dim,
- const std::string& object_name,
- tbox::Pointer<tbox::Database> database =
- tbox::Pointer<tbox::Database>(NULL));
-
- /*!
- * The Stokes destructor releases all internally managed data.
- */
- ~CellStokesHypreSolver();
-
- /*!
- * @brief Initialize to a given hierarchy.
- *
- * Initializer Stokes solver for a patch level in a hierarchy.
- *
- * @param hierarchy Hierarchy
- * @param ln Level number
- */
- void
- initializeSolverState(
- tbox::Pointer<hier::PatchHierarchy> hierarchy,
- int ln = 0);
-
- /*!
- * @brief Reset to an uninitialized state.
- */
- void
- deallocateSolverState();
-
- /*!
- * @brief Set the matrix coefficients
- *
- * For information describing the Stokes equation parameters,
- * see the light-weight StokesSpecifications class where
- * you set the values of C and D.
- *
- * This method must be called before solveSystem().
- */
- void
- setMatrixCoefficients(
- const StokesSpecifications& spec);
-
- /*!
- * @brief Set default depth of the solution data involved in the solve.
- *
- * If the solution data has multiple depths,
- * the solver uses just one depth at a time.
- * The default depth is the first depth.
- * Use this function to change it.
- * This is not used to set the depth of the data (which is not
- * controled by this class) but the depth used in the solve.
- *
- * Changing the depth after setting up the matrix is permissible,
- * as the solution data does not affect the matrix.
- */
- void
- setSolnIdDepth(
- const int depth);
-
- /*!
- * @brief Set default depth of the rhs data involved in the solve.
- *
- * If the rhs data has multiple depths,
- * the solver uses just one depth at a time.
- * The default depth is the first depth.
- * Use this function to change it.
- * This is not used to set the depth of the data (which is not
- * controled by this class) but the depth used in the solve.
- *
- * Changing the depth after setting up the matrix is permissible,
- * as the rhs data does not affect the matrix.
- */
- void
- setRhsIdDepth(
- const int depth);
-
- /*!
- * @brief Set the stopping criteria (max iterations and residual
- * tolerance) for the linear solver.
- *
- * @param max_iterations gives the maximum number of iterations
- * @param relative_residual_tol the maximum error tolerance
- */
- void
- setStoppingCriteria(
- const int max_iterations = 10,
- const double relative_residual_tol = 1.0e-6);
-
- /*!
- * @brief Solve the linear system Au=f.
- *
- * The solution u and the right hand side f are
- * specified via patch indices on the patch hierarchy.
- *
- * Member functions getNumberOfIterations() return the iterations
- * from the solver.
- * Note that the matrix coefficients and boundary condition object
- * must have been set up before this function is called.
- * As long as the matrix coefficients do not change,
- * this routine may be called repeatedly to solve any number of linear
- * systems (with the right-hand side varying).
- * If the boundary conditions or matrix coefficients are changed
- * then function setMatrixCoefficients() must be called again.
- *
- * When computing the matrix coefficients in setMatrixCoefficients(),
- * the inhomogeneous portion of the boundary condition (constant
- * terms, independent of u and thus having no effect on the matrix)
- * are saved and added to the source term, f,
- * before performing the matrix solve. In some situations, it may be
- * useful to not add the inhomogeneous portion to f. The flag argument
- * @c homoegneous_bc is used for this. (This is a sort of optimization,
- * to avoid having to re-call setMatrixCoefficients() to change the
- * inhomogeneous portion.)
- *
- * @param u Descriptor of cell-centered unknown variable.
- * @param f Descriptor of cell-centered source variable.
- * @param homogeneous_bc Whether homogeneous boundary conditions
- * are assumed.
- *
- * @return whether solver converged to specified level
- */
- int
- solveSystem(
- const int u,
- const int f,
- bool homogeneous_bc = false);
-
- /*!
- * @brief Return the number of iterations taken by the solver to converge.
- *
- * @return number of iterations taken by the solver to converge
- */
- int
- getNumberOfIterations() const;
-
- /*!
- * @brief Set the number of pre-relax steps used by the Hypre solve.
- */
- void
- setNumPreRelaxSteps(
- const int steps);
-
- /*!
- * @brief Set the number of post-relax steps used by the Hypre solve.
- */
- void
- setNumPostRelaxSteps(
- const int steps);
-
- /*!
- * @brief Return the final residual norm returned by the Hypre solve.
- * @return final residual norm returned by the Hypre solve.
- */
- double
- getRelativeResidualNorm() const;
-
- /*!
- * @brief Set whether to use Hypre's PFMG algorithm instead of the
- * SMG algorithm.
- *
- * The flag is used to select which of HYPRE's linear solver algorithms
- * to use if true, the semicoarsening multigrid algorithm is used, and if
- * false, the "PF" multigrid algorithm is used.
- * By default, the SMG algorithm is used.
- *
- * Changing the algorithm must be done before setting up the matrix
- * coefficients.
- */
- void
- setUseSMG(
- bool use_smg);
-
- /*!
- * @brief Specify boundary condition directly, without using
- * a RobinBcCoefStrategy object.
- *
- * Use @em either setBoundaries() @em or setPhysicalBcCoefObject(),
- * but not both.
- *
- * A SimpleCelBcCoef object is used to interpret and implement
- * the specified boundary conditions.
- * See SimpleCellRobinBcCoefs::setBoundaries()
- * for an explanation of the arguments.
- */
- void
- setBoundaries(
- const std::string& boundary_type,
- const int fluxes = -1,
- const int flags = -1,
- int* bdry_types = NULL);
-
- /*!
- * @brief Specify boundary condition through the use of a
- * Robin boundary condition object.
- *
- * Use @em either setBoundaries() @em or setPhysicalBcCoefObject(),
- * but not both.
- *
- * The Robin boundary condition object is used when setting
- * the matrix coefficient and when solving the system.
- * If your boundary conditions are fixed values at ghost
- * cell centers, use the GhostCellRobinBcCoefs
- * implementation of the RobinBcCoefStrategy strategy.
- *
- * @param physical_bc_coef_strategy tbox::Pointer a concrete
- * implementation of the Robin bc strategy.
- * @param variable hier::Variable pointer to be passed
- * to RobinBcCoefStrategy::setBcCoefs(),
- * but otherwise unused by this class.
- */
- void
- setPhysicalBcCoefObject(
- const RobinBcCoefStrategy* physical_bc_coef_strategy,
- const tbox::Pointer<hier::Variable> variable =
- tbox::Pointer<hier::Variable>(NULL));
-
- /*!
- * @brief Set the flag for printing solver information.
- *
- * This optional function is used primarily for debugging.
- *
- * If set true, it will print the HYPRE matrix information
- * to the following files:
- *
- * - mat_bA.out - before setting matrix coefficients in matrix assemble
- * - mat_aA.out - after setting matrix coefficients in matrix assemble
- * - sol0.out - u before solve (i.e. for system Au = b)
- * - sol.out - u after solve
- * - mat0.out - A before solve
- * - mat.out - A after solve
- * - rhs.out - b before and after solve
- *
- * If this method is not called, or the flag is set false, no printing
- * will occur.
- */
- void
- setPrintSolverInfo(
- const bool print);
-
-private:
- /*!
- * @brief Set state using database
- *
- * See the class description for the parameters that can be set
- * from a database.
- *
- * @param database Input database. If a NULL pointer is given,
- * nothing is done.
- */
- void
- getFromInput(
- tbox::Pointer<tbox::Database> database);
-
- void
- setupHypreSolver();
- void
- destroyHypreSolver();
- void
- allocateHypreData();
- void
- deallocateHypreData();
-
- void
- copyToHypre(
- HYPRE_StructVector vector,
- pdat::CellData<double>& src,
- int depth,
- const hier::Box& box);
- void
- copyFromHypre(
- pdat::CellData<double>& dst,
- int depth,
- HYPRE_StructVector vector,
- const hier::Box box);
-
- /*!
- * @brief Add g*A*k0(a) from boundaries to rhs.
- *
- * Move the constant portion of the boundary condition
- * contribution to the right hand side and add it to the existing rhs.
- * This operation is done for physical as well as cf boundaries,
- * so it is placed in a function.
- *
- * The boundary boxes given must be to either the physical
- * boundary or coarse-fine boundary for the patch. The
- * bc coefficient implementation should correspond to the
- * boundary being worked on.
- */
- void
- add_gAk0_toRhs(
- const hier::Patch& patch,
- const tbox::Array<hier::BoundaryBox>& bdry_boxes,
- const RobinBcCoefStrategy* robin_bc_coef,
- pdat::CellData<double>& rhs);
-
- //@{
-
- /*!
- * @name Dimension-independent functions to organize Fortran interface.
- */
-
- //! @brief Compute diagonal entries of the matrix when C is variable.
- void
- computeDiagonalEntries(
- pdat::CellData<double>& diagonal,
- const pdat::CellData<double>& C_data,
- const pdat::SideData<double>& variable_off_diagonal,
- const hier::Box& patch_box);
- //! @brief Compute diagonal entries of the matrix when C is constant.
- void
- computeDiagonalEntries(
- pdat::CellData<double>& diagonal,
- const double C,
- const pdat::SideData<double>& variable_off_diagonal,
- const hier::Box& patch_box);
- //! @brief Compute diagonal entries of the matrix when C is zero.
- void
- computeDiagonalEntries(
- pdat::CellData<double>& diagonal,
- const pdat::SideData<double>& variable_off_diagonal,
- const hier::Box& patch_box);
- /*!
- * @brief Adjust boundary entries for variable off-diagonals.
- *
- * At the same time, save information that are needed to adjust
- * the rhs.
- */
- void
- adjustBoundaryEntries(
- pdat::CellData<double>& diagonal,
- const pdat::SideData<double>& variable_off_diagonal,
- const hier::Box& patch_box,
- const pdat::ArrayData<double>& acoef_data,
- const pdat::ArrayData<double>& bcoef_data,
- const hier::Box bccoef_box,
- pdat::ArrayData<double>& Ak0_data,
- const hier::BoundaryBox& trimmed_boundary_box,
- const double h[tbox::Dimension::MAXIMUM_DIMENSION_VALUE]);
-
- //@}
-
- //! @brief Free static variables at shutdown time.
- static void
- finalizeCallback();
-
- /*!
- * @brief Object dimension.
- */
- const tbox::Dimension d_dim;
-
- /*!
- * @brief Object name.
- */
- std::string d_object_name;
-
- /*!
- * @brief Associated hierarchy.
- */
- tbox::Pointer<hier::PatchHierarchy> d_hierarchy;
-
- /*!
- * @brief Associated level number.
- *
- * Currently, this must be level number 0.
- */
- int d_ln;
-
- /*!
- * @brief Scratch context for this object.
- */
- tbox::Pointer<hier::VariableContext> d_context;
-
- //@{ @name Boundary condition handling
-
- /*!
- * @brief The coarse-fine boundary description for level d_ln.
- *
- * The coarse-fine boundary is computed when the operator
- * state is initialized. It is used to allow solves on
- * levels that are not the coarsest in the hierarchy.
- */
- tbox::Pointer<hier::CoarseFineBoundary> d_cf_boundary;
-
- /*!
- * @brief Robin boundary coefficient object for physical
- * boundaries.
- *
- * If d_physical_bc_coef_strategy is set, use it, otherwise,
- * use d_physical_bc_simple_case.
- */
- const RobinBcCoefStrategy* d_physical_bc_coef_strategy;
- tbox::Pointer<hier::Variable> d_physical_bc_variable;
-
- /*!
- * @brief Implementation of Robin boundary conefficients
- * for the case of simple boundary conditions.
- */
- SimpleCellRobinBcCoefs d_physical_bc_simple_case;
-
- /*!
- * @brief Robin boundary coefficient object for coarse-fine
- * boundaries.
- *
- * This is a GhostCellRobinBcCoefs object because we
- * expect the users to have the correct ghost cell values
- * in the coarse-fine boundaries before solving.
- */
- GhostCellRobinBcCoefs d_cf_bc_coef;
- tbox::Pointer<hier::Variable> d_coarsefine_bc_variable;
-
- //@}
-
- /*!
- * @brief hier::Patch index of A*k0(a) quantity
- *
- * A*k0(a) is the quantity that is saved for
- * later adding to the rhs.
- *
- * The Robin bc is expressed by the coefficients a and g
- * on the boundary (see RobinBcCoefStrategy).
- * This class uses a central difference approximation of
- * the Robin bc, which results in the value at a ghost cell,
- * uo, being writen as uo = g*k0(a) + k1(a)*ui, where ui is
- * the first interior cell value, k0 and k1 depend on a as
- * indicated.
- *
- * In setting up the Au=f system, the contribution of k1(a)*ui
- * is incorporated into the product Au. The contribution of
- * A*g*k0(a) should be moved to the right hand side and saved for
- * later adding to f. However, the value of g is not provided
- * until solve time. Therefore, we save just A*k0(a) at the
- * patch data index d_Ak0_id.
- */
- int d_Ak0_id;
-
- static tbox::Pointer<pdat::OutersideVariable<double> > s_Ak0_var[tbox::
- Dimension::
- MAXIMUM_DIMENSION_VALUE];
-
- /*!
- * @brief Depth of the solution variable.
- */
- int d_soln_depth;
-
- /*!
- * @brief Depth of the rhs variable.
- */
- int d_rhs_depth;
-
- int d_max_iterations;
- double d_relative_residual_tol;
-
- int d_number_iterations; // iterations in solver
- int d_num_pre_relax_steps; // pre-relax steps in solver
- int d_num_post_relax_steps; // post-relax steps in solver
- double d_relative_residual_norm; // norm from solver
-
- /*@
- * @brief Flag to use SMG or PFMG (default)
- */
- bool d_use_smg;
-
- //@{
- //! @name Hypre object
- //! @brief HYPRE grid
- HYPRE_StructGrid d_grid;
- //! @brief HYPRE stencil
- HYPRE_StructStencil d_stencil;
- //! @brief HYPRE structured matrix
- HYPRE_StructMatrix d_matrix;
- //! @brief Hypre RHS vector for linear solves
- HYPRE_StructVector d_linear_rhs;
- //! @brief Hypre solution vector
- HYPRE_StructVector d_linear_sol;
- //! @brief Hypre SMG solver data
- HYPRE_StructSolver d_mg_data;
- //@}
-
- //@{
-
- //! @name Variables for debugging and analysis.
-
- /*!
- * @brief Flag to print solver info
- *
- * See setPrintSolverInfo().
- */
- bool d_print_solver_info;
-
- //@}
-
- /*!
- * @brief Timers for performance measurement.
- */
- tbox::Pointer<tbox::Timer> t_solve_system;
- tbox::Pointer<tbox::Timer> t_set_matrix_coefficients;
-
- static tbox::StartupShutdownManager::Handler s_finalize_handler;
-};
-
-}
-} // namespace SAMRAI
-
-#ifdef SAMRAI_INLINE
-#include "CellStokesHypreSolver.I"
-#endif
-
-#endif
-
-#endif
diff -r a44a82f15794 -r fe2a9230921b FACStokes.h
--- a/FACStokes.h Fri Dec 31 12:00:54 2010 -0800
+++ b/FACStokes.h Fri Dec 31 12:10:26 2010 -0800
@@ -10,7 +10,7 @@
#ifndef included_FACStokes
#define included_FACStokes
-#include "CellStokesFACSolver.h"
+#include "StokesFACSolver.h"
#include "SAMRAI/pdat/CellVariable.h"
#include "SAMRAI/tbox/Database.h"
#include "SAMRAI/hier/Box.h"
diff -r a44a82f15794 -r fe2a9230921b Makefile
--- a/Makefile Fri Dec 31 12:00:54 2010 -0800
+++ b/Makefile Fri Dec 31 12:10:26 2010 -0800
@@ -29,8 +29,8 @@ CXX_OBJS = main.o FACStokes/FACStok
FACStokes/packDerivedDataIntoDoubleBuffer.o \
FACStokes/resetHierarchyConfiguration.o \
FACStokes/setupPlotter.o \
- FACStokes/solveStokes.o CellStokesFACOps.o \
- CellStokesHypreSolver.o StokesSpecifications.o CellStokesFACSolver.o
+ FACStokes/solveStokes.o StokesFACOps.o \
+ StokesHypreSolver.o StokesSpecifications.o StokesFACSolver.o
F_OBJS = facpoisson2d.o facpoisson3d.o
main: $(CXX_OBJS) $(F_OBJS) $(LIBSAMRAIDEPEND)
diff -r a44a82f15794 -r fe2a9230921b StokesFACOps.C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesFACOps.C Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,2830 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: Operator class for cell-centered scalar Stokes using FAC
+ *
+ ************************************************************************/
+#ifndef included_solv_StokesFACOps_C
+#define included_solv_StokesFACOps_C
+
+#include "StokesFACOps.h"
+
+#include IOMANIP_HEADER_FILE
+
+#include "SAMRAI/hier/BoundaryBoxUtils.h"
+#include "SAMRAI/geom/CartesianGridGeometry.h"
+#include "SAMRAI/geom/CartesianPatchGeometry.h"
+#include "SAMRAI/hier/Index.h"
+#include "SAMRAI/hier/Variable.h"
+#include "SAMRAI/hier/VariableDatabase.h"
+#include "SAMRAI/pdat/CellDoubleConstantRefine.h"
+#include "SAMRAI/pdat/CellVariable.h"
+#include "SAMRAI/pdat/OutersideData.h"
+#include "SAMRAI/pdat/OutersideVariable.h"
+#include "SAMRAI/hier/PatchData.h"
+#include "SAMRAI/pdat/SideVariable.h"
+#include "SAMRAI/solv/FACPreconditioner.h"
+#include "StokesHypreSolver.h"
+#include "SAMRAI/tbox/Array.h"
+#include "SAMRAI/tbox/MathUtilities.h"
+#include "SAMRAI/tbox/StartupShutdownManager.h"
+#include "SAMRAI/tbox/Timer.h"
+#include "SAMRAI/tbox/TimerManager.h"
+#include "SAMRAI/tbox/Utilities.h"
+#include "SAMRAI/tbox/MathUtilities.h"
+#include "SAMRAI/xfer/CoarsenAlgorithm.h"
+#include "SAMRAI/xfer/CoarsenOperator.h"
+#include "SAMRAI/xfer/CoarsenSchedule.h"
+#include "SAMRAI/xfer/RefineAlgorithm.h"
+#include "SAMRAI/xfer/RefineOperator.h"
+#include "SAMRAI/xfer/RefineSchedule.h"
+#include "SAMRAI/xfer/PatchLevelFullFillPattern.h"
+
+#ifndef SAMRAI_INLINE
+#include "StokesFACOps.I"
+#endif
+
+namespace SAMRAI {
+namespace solv {
+
+tbox::Pointer<pdat::CellVariable<double> >
+CellStokesFACOps::s_cell_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+tbox::Pointer<pdat::SideVariable<double> >
+CellStokesFACOps::s_flux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+tbox::Pointer<pdat::OutersideVariable<double> >
+CellStokesFACOps::s_oflux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+tbox::StartupShutdownManager::Handler
+CellStokesFACOps::s_finalize_handler(
+ 0,
+ 0,
+ 0,
+ CellStokesFACOps::finalizeCallback,
+ tbox::StartupShutdownManager::priorityVariables);
+
+extern "C" {
+
+#ifdef __INTEL_COMPILER
+#pragma warning (disable:1419)
+#endif
+
+void F77_FUNC(compfluxvardc2d, COMPFLUXVARDC2D) (
+ double* xflux,
+ double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx);
+void F77_FUNC(compfluxcondc2d, COMPFLUXCONDC2D) (
+ double* xflux,
+ double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double & diff_coef,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx);
+void F77_FUNC(rbgswithfluxmaxvardcvarsf2d, RBGSWITHFLUXMAXVARDCVARSF2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const double* scalar_field,
+ const int* scalar_field_gi,
+ const int* scalar_field_gj,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(rbgswithfluxmaxcondcvarsf2d, RBGSWITHFLUXMAXCONDCVARSF2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double & dc,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const double* scalar_field,
+ const int* scalar_field_gi,
+ const int* scalar_field_gj,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(rbgswithfluxmaxvardcconsf2d, RBGSWITHFLUXMAXVARDCCONSF2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const double & scalar_field,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(rbgswithfluxmaxcondcconsf2d, RBGSWITHFLUXMAXCONDCCONSF2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double & dc,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const double & scalar_field,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(compresvarsca2d, COMPRESVARSCA2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ double* residual,
+ const int* residualgi,
+ const int* residualgj,
+ const double* scalar_field,
+ const int* scalar_field_gi,
+ const int* scalar_field_gj,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx);
+void F77_FUNC(compresconsca2d, COMPRESCONSCA2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ double* residual,
+ const int* residualgi,
+ const int* residualgj,
+ const double & scalar_field,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* dx);
+void F77_FUNC(ewingfixfluxvardc2d, EWINGFIXFLUXVARDC2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* location_index,
+ const int* ratio_to_coarser,
+ const int* blower,
+ const int* bupper,
+ const double* dx);
+void F77_FUNC(ewingfixfluxcondc2d, EWINGFIXFLUXCONDC2D) (
+ const double* xflux,
+ const double* yflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const double & diff_coef,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* location_index,
+ const int* ratio_to_coarser,
+ const int* blower,
+ const int* bupper,
+ const double* dx);
+
+void F77_FUNC(compfluxvardc3d, COMPFLUXVARDC3D) (
+ double* xflux,
+ double* yflux,
+ double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const double* zdiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const int* dcgk,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx);
+void F77_FUNC(compfluxcondc3d, COMPFLUXCONDC3D) (
+ double* xflux,
+ double* yflux,
+ double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double & diff_coef,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx);
+void F77_FUNC(rbgswithfluxmaxvardcvarsf3d, RBGSWITHFLUXMAXVARDCVARSF3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const double* zdiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const int* dcgk,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const int* rhsgk,
+ const double* scalar_field,
+ const int* scalar_field_gi,
+ const int* scalar_field_gj,
+ const int* scalar_field_gk,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(rbgswithfluxmaxcondcvarsf3d, RBGSWITHFLUXMAXCONDCVARSF3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double & dc,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const int* rhsgk,
+ const double* scalar_field,
+ const int* scalar_field_gi,
+ const int* scalar_field_gj,
+ const int* scalar_field_gk,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(rbgswithfluxmaxvardcconsf3d, RBGSWITHFLUXMAXVARDCCONSF3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const double* zdiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const int* dcgk,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const int* rhsgk,
+ const double & scalar_field,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(rbgswithfluxmaxcondcconsf3d, RBGSWITHFLUXMAXCONDCCONSF3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double & dc,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const int* rhsgk,
+ const double & scalar_field,
+ double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx,
+ const int* offset,
+ const double* maxres);
+void F77_FUNC(compresvarsca3d, COMPRESVARSCA3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const int* rhsgk,
+ double* residual,
+ const int* residualgi,
+ const int* residualgj,
+ const int* residualgk,
+ const double* scalar_field,
+ const int* scalar_field_gi,
+ const int* scalar_field_gj,
+ const int* scalar_field_gk,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx);
+void F77_FUNC(compresconsca3d, COMPRESCONSCA3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double* rhs,
+ const int* rhsgi,
+ const int* rhsgj,
+ const int* rhsgk,
+ double* residual,
+ const int* residualgi,
+ const int* residualgj,
+ const int* residualgk,
+ const double & scalar_field,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* dx);
+void F77_FUNC(ewingfixfluxvardc3d, EWINGFIXFLUXVARDC3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double* xdiff_coef,
+ const double* ydiff_coef,
+ const double* zdiff_coef,
+ const int* dcgi,
+ const int* dcgj,
+ const int* dcgk,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const int* location_index,
+ const int* ratio_to_coarser,
+ const int* blower,
+ const int* bupper,
+ const double* dx);
+void F77_FUNC(ewingfixfluxcondc3d, EWINGFIXFLUXCONDC3D) (
+ const double* xflux,
+ const double* yflux,
+ const double* zflux,
+ const int* fluxgi,
+ const int* fluxgj,
+ const int* fluxgk,
+ const double & diff_coef,
+ const double* soln,
+ const int* solngi,
+ const int* solngj,
+ const int* solngk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const int* location_index,
+ const int* ratio_to_coarser,
+ const int* blower,
+ const int* bupper,
+ const double* dx);
+
+}
+
+/*
+ ********************************************************************
+ * Constructor. *
+ ********************************************************************
+ */
+CellStokesFACOps::CellStokesFACOps(
+ const tbox::Dimension& dim,
+ const std::string& object_name,
+ tbox::Pointer<tbox::Database> database):
+ d_dim(dim),
+ d_object_name(object_name),
+ d_hierarchy(),
+ d_ln_min(-1),
+ d_ln_max(-1),
+ d_cf_boundary(),
+ d_stokes_spec(object_name + "::Stokes specs"),
+ d_smoothing_choice("redblack"),
+ d_coarse_solver_choice(
+#ifdef HAVE_HYPRE
+ "hypre"
+#else
+ "redblack"
+#endif
+
+ ),
+ d_cf_discretization("Ewing"),
+ d_prolongation_method("CONSTANT_REFINE"),
+ d_coarse_solver_tolerance(1.e-8),
+ d_coarse_solver_max_iterations(10),
+ d_residual_tolerance_during_smoothing(-1.0),
+ d_flux_id(-1),
+#ifdef HAVE_HYPRE
+ d_hypre_solver(dim,
+ object_name + "::hypre_solver",
+ database && database->isDatabase("hypre_solver") ?
+ database->getDatabase("hypre_solver"):
+ tbox::Pointer<tbox::Database>(NULL)),
+#endif
+ d_physical_bc_coef(NULL),
+ d_context(hier::VariableDatabase::getDatabase()
+ ->getContext(object_name + "::PRIVATE_CONTEXT")),
+ d_cell_scratch_id(-1),
+ d_flux_scratch_id(-1),
+ d_oflux_scratch_id(-1),
+ d_prolongation_refine_operator(),
+ d_prolongation_refine_algorithm(),
+ d_prolongation_refine_schedules(),
+ d_urestriction_coarsen_operator(),
+ d_urestriction_coarsen_algorithm(),
+ d_urestriction_coarsen_schedules(),
+ d_rrestriction_coarsen_operator(),
+ d_rrestriction_coarsen_algorithm(),
+ d_rrestriction_coarsen_schedules(),
+ d_flux_coarsen_operator(),
+ d_flux_coarsen_algorithm(),
+ d_flux_coarsen_schedules(),
+ d_ghostfill_refine_operator(),
+ d_ghostfill_refine_algorithm(),
+ d_ghostfill_refine_schedules(),
+ d_ghostfill_nocoarse_refine_operator(),
+ d_ghostfill_nocoarse_refine_algorithm(),
+ d_ghostfill_nocoarse_refine_schedules(),
+ d_bc_helper(dim,
+ d_object_name + "::bc helper"),
+ d_enable_logging(false),
+ d_preconditioner(NULL),
+ d_hopscell(),
+ d_hopsside()
+{
+
+ t_restrict_solution = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::restrictSolution()");
+ t_restrict_residual = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::restrictResidual()");
+ t_prolong = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::prolongErrorAndCorrect()");
+ t_smooth_error = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::smoothError()");
+ t_solve_coarsest = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::solveCoarsestLevel()");
+ t_compute_composite_residual = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::computeCompositeResidualOnLevel()");
+ t_compute_residual_norm = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesFACOps::computeResidualNorm()");
+
+ if (d_dim == tbox::Dimension(1) || d_dim > tbox::Dimension(3)) {
+ TBOX_ERROR("CellStokesFACOps : DIM == 1 or > 3 not implemented yet.\n");
+ }
+
+ if (s_cell_scratch_var[dim.getValue() - 1].isNull()) {
+ TBOX_ASSERT(s_cell_scratch_var[dim.getValue() - 1].isNull());
+ TBOX_ASSERT(s_cell_scratch_var[dim.getValue() - 1].isNull());
+
+ std::ostringstream ss;
+ ss << "CellStokesFACOps::private_cell_scratch" << dim.getValue();
+ s_cell_scratch_var[dim.getValue() - 1] = new pdat::CellVariable<double>
+ (dim, ss.str());
+ ss.str("");
+ ss << "CellStokesFACOps::private_flux_scratch" << dim.getValue();
+ s_flux_scratch_var[dim.getValue() - 1] = new pdat::SideVariable<double>
+ (dim, ss.str());
+ ss.str("");
+ ss << "CellStokesFACOps::private_oflux_scratch" << dim.getValue();
+ s_oflux_scratch_var[dim.getValue() - 1] = new pdat::OutersideVariable<double>
+ (dim, ss.str());
+ }
+
+ hier::VariableDatabase* vdb = hier::VariableDatabase::getDatabase();
+ d_cell_scratch_id = vdb->
+ registerVariableAndContext(s_cell_scratch_var[dim.getValue() - 1],
+ d_context,
+ hier::IntVector::getOne(dim));
+ d_flux_scratch_id = vdb->
+ registerVariableAndContext(s_flux_scratch_var[dim.getValue() - 1],
+ d_context,
+ hier::IntVector::getZero(d_dim));
+ d_oflux_scratch_id = vdb->
+ registerVariableAndContext(s_oflux_scratch_var[dim.getValue() - 1],
+ d_context,
+ hier::IntVector::getZero(d_dim));
+
+ /*
+ * Some variables initialized by default are overriden by input.
+ */
+ if (database) {
+
+ d_coarse_solver_choice =
+ database->getStringWithDefault("coarse_solver_choice",
+ d_coarse_solver_choice);
+ d_coarse_solver_tolerance =
+ database->getDoubleWithDefault("coarse_solver_tolerance",
+ d_coarse_solver_tolerance);
+ d_coarse_solver_max_iterations =
+ database->getIntegerWithDefault("coarse_solver_max_iterations",
+ d_coarse_solver_max_iterations);
+ d_smoothing_choice =
+ database->getStringWithDefault("smoothing_choice",
+ d_smoothing_choice);
+
+ d_cf_discretization =
+ database->getStringWithDefault("cf_discretization",
+ d_cf_discretization);
+
+ d_prolongation_method =
+ database->getStringWithDefault("prolongation_method",
+ d_prolongation_method);
+
+ d_enable_logging =
+ database->getBoolWithDefault("enable_logging",
+ d_enable_logging);
+
+ }
+
+ /*
+ * Check input validity and correctness.
+ */
+ checkInputPatchDataIndices();
+
+}
+
+CellStokesFACOps::~CellStokesFACOps(
+ void)
+{
+}
+
+/*
+ ************************************************************************
+ * FACOperatorStrategy virtual initializeOperatorState function. *
+ * *
+ * Set internal variables to correspond to the solution passed in. *
+ * Look up transfer operators. *
+ ************************************************************************
+ */
+
+void CellStokesFACOps::initializeOperatorState(
+ const SAMRAIVectorReal<double>& solution,
+ const SAMRAIVectorReal<double>& rhs)
+{
+ deallocateOperatorState();
+ int ln;
+ hier::VariableDatabase* vdb = hier::VariableDatabase::getDatabase();
+
+ d_hierarchy = solution.getPatchHierarchy();
+ d_ln_min = solution.getCoarsestLevelNumber();
+ d_ln_max = solution.getFinestLevelNumber();
+ d_hopscell = new math::HierarchyCellDataOpsReal<double>(d_hierarchy,
+ d_ln_min,
+ d_ln_max);
+ d_hopsside = new math::HierarchySideDataOpsReal<double>(d_hierarchy,
+ d_ln_min,
+ d_ln_max);
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+
+ if (d_physical_bc_coef == NULL) {
+ /*
+ * It's an error not to have bc object set.
+ * Note that the bc object cannot be passed in through
+ * the argument because the interface is inherited.
+ */
+ TBOX_ERROR(
+ d_object_name << ": No physical bc object in\n"
+ <<
+ "CellStokesFACOps::initializeOperatorState\n"
+ << "You must use "
+ <<
+ "CellStokesFACOps::setPhysicalBcCoefObject\n"
+ <<
+ "to set one before calling initializeOperatorState\n");
+ }
+
+ if (solution.getNumberOfComponents() != 1) {
+ TBOX_WARNING(d_object_name
+ << ": Solution vector has multiple components.\n"
+ << "Solver is for component 0 only.\n");
+ }
+ if (rhs.getNumberOfComponents() != 1) {
+ TBOX_WARNING(d_object_name
+ << ": RHS vector has multiple components.\n"
+ << "Solver is for component 0 only.\n");
+ }
+
+ /*
+ * Make sure that solution and rhs data
+ * are of correct type
+ * are allocated
+ * has sufficient ghost width
+ */
+ tbox::Pointer<hier::Variable> var;
+ {
+ vdb->mapIndexToVariable(rhs.getComponentDescriptorIndex(0),
+ var);
+ if (!var) {
+ TBOX_ERROR(d_object_name << ": RHS component does not\n"
+ << "correspond to a variable.\n");
+ }
+ tbox::Pointer<pdat::CellVariable<double> > cell_var = var;
+ if (!cell_var) {
+ TBOX_ERROR(d_object_name
+ << ": RHS variable is not cell-centered double\n");
+ }
+ }
+ {
+ vdb->mapIndexToVariable(solution.getComponentDescriptorIndex(0),
+ var);
+ if (!var) {
+ TBOX_ERROR(d_object_name << ": Solution component does not\n"
+ << "correspond to a variable.\n");
+ }
+ tbox::Pointer<pdat::CellVariable<double> > cell_var = var;
+ if (!cell_var) {
+ TBOX_ERROR(d_object_name
+ << ": Solution variable is not cell-centered double\n");
+ }
+ }
+ for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
+ tbox::Pointer<hier::PatchLevel> level_ptr =
+ d_hierarchy->getPatchLevel(ln);
+ hier::PatchLevel& level = *level_ptr;
+ for (hier::PatchLevel::Iterator pi(level); pi; pi++) {
+ hier::Patch& patch = **pi;
+ tbox::Pointer<hier::PatchData> fd =
+ patch.getPatchData(rhs.getComponentDescriptorIndex(0));
+ if (fd) {
+ /*
+ * Some data checks can only be done if the data already exists.
+ */
+ tbox::Pointer<pdat::CellData<double> > cd = fd;
+ if (!cd) {
+ TBOX_ERROR(d_object_name
+ << ": RHS data is not cell-centered double\n");
+ }
+ if (cd->getDepth() > 1) {
+ TBOX_WARNING(d_object_name
+ << ": RHS data has multiple depths.\n"
+ << "Solver is for depth 0 only.\n");
+ }
+ }
+ tbox::Pointer<hier::PatchData> ud =
+ patch.getPatchData(solution.getComponentDescriptorIndex(0));
+ if (ud) {
+ /*
+ * Some data checks can only be done if the data already exists.
+ */
+ tbox::Pointer<pdat::CellData<double> > cd = ud;
+ if (!cd) {
+ TBOX_ERROR(d_object_name
+ << ": Solution data is not cell-centered double\n");
+ }
+ if (cd->getDepth() > 1) {
+ TBOX_WARNING(d_object_name
+ << ": Solution data has multiple depths.\n"
+ << "Solver is for depth 0 only.\n");
+ }
+ if (cd->getGhostCellWidth() < hier::IntVector::getOne(d_dim)) {
+ TBOX_ERROR(d_object_name
+ << ": Solution data has insufficient ghost width\n");
+ }
+ }
+ }
+ }
+
+ /*
+ * Solution and rhs must have some similar properties.
+ */
+ if (rhs.getPatchHierarchy() != d_hierarchy
+ || rhs.getCoarsestLevelNumber() != d_ln_min
+ || rhs.getFinestLevelNumber() != d_ln_max) {
+ TBOX_ERROR(d_object_name << ": solution and rhs do not have\n"
+ << "the same set of patch levels.\n");
+ }
+
+#endif
+
+ /*
+ * Initialize the coarse-fine boundary description for the
+ * hierarchy.
+ */
+ d_cf_boundary.resizeArray(d_hierarchy->getNumberOfLevels());
+
+ hier::IntVector max_gcw(d_dim, 1);
+ for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
+ d_cf_boundary[ln] = new hier::CoarseFineBoundary(*d_hierarchy,
+ ln,
+ max_gcw);
+ }
+#ifdef HAVE_HYPRE
+ if (d_coarse_solver_choice == "hypre") {
+ d_hypre_solver.initializeSolverState(d_hierarchy, d_ln_min);
+ /*
+ * Share the boundary condition object with the hypre solver
+ * to make sure that boundary condition settings are consistent
+ * between the two objects.
+ */
+ d_hypre_solver.setPhysicalBcCoefObject(d_physical_bc_coef);
+ d_hypre_solver.setMatrixCoefficients(d_stokes_spec);
+ }
+#endif
+
+ /*
+ * Get the transfer operators.
+ * Flux coarsening is conservative.
+ * Cell (solution, error, etc) coarsening is conservative.
+ * Cell refinement from same level is constant refinement.
+ * Cell refinement from coarser level is chosen by the
+ * choice of coarse-fine discretization, d_cf_discretization,
+ * which should be set to either "Ewing" or one of the
+ * acceptable strings for looking up the refine operator.
+ */
+ tbox::Pointer<geom::CartesianGridGeometry> geometry =
+ d_hierarchy->getGridGeometry();
+ tbox::Pointer<hier::Variable> variable;
+
+ vdb->mapIndexToVariable(d_cell_scratch_id, variable);
+ d_prolongation_refine_operator =
+ geometry->lookupRefineOperator(variable,
+ d_prolongation_method);
+
+ vdb->mapIndexToVariable(d_cell_scratch_id, variable);
+ d_urestriction_coarsen_operator =
+ d_rrestriction_coarsen_operator =
+ geometry->lookupCoarsenOperator(variable,
+ "CONSERVATIVE_COARSEN");
+
+ vdb->mapIndexToVariable(d_oflux_scratch_id, variable);
+ d_flux_coarsen_operator =
+ geometry->lookupCoarsenOperator(variable,
+ "CONSERVATIVE_COARSEN");
+
+ vdb->mapIndexToVariable(d_cell_scratch_id, variable);
+ d_ghostfill_refine_operator =
+ geometry->lookupRefineOperator(variable,
+ d_cf_discretization == "Ewing" ?
+ "CONSTANT_REFINE" : d_cf_discretization);
+
+ vdb->mapIndexToVariable(d_cell_scratch_id, variable);
+ d_ghostfill_nocoarse_refine_operator =
+ geometry->lookupRefineOperator(variable,
+ "CONSTANT_REFINE");
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (!d_prolongation_refine_operator) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot find prolongation refine operator");
+ }
+ if (!d_urestriction_coarsen_operator) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot find restriction coarsening operator");
+ }
+ if (!d_rrestriction_coarsen_operator) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot find restriction coarsening operator");
+ }
+ if (!d_flux_coarsen_operator) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot find flux coarsening operator");
+ }
+ if (!d_ghostfill_refine_operator) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot find ghost filling refinement operator");
+ }
+ if (!d_ghostfill_nocoarse_refine_operator) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot find ghost filling refinement operator");
+ }
+#endif
+
+ for (ln = d_ln_min + 1; ln <= d_ln_max; ++ln) {
+ d_hierarchy->getPatchLevel(ln)->
+ allocatePatchData(d_oflux_scratch_id);
+ }
+
+ /*
+ * Make space for saving communication schedules.
+ * There is no need to delete the old schedules first
+ * because we have deallocated the solver state above.
+ */
+ d_prolongation_refine_schedules.resizeArray(d_ln_max + 1);
+ d_ghostfill_refine_schedules.resizeArray(d_ln_max + 1);
+ d_ghostfill_nocoarse_refine_schedules.resizeArray(d_ln_max + 1);
+ d_urestriction_coarsen_schedules.resizeArray(d_ln_max + 1);
+ d_rrestriction_coarsen_schedules.resizeArray(d_ln_max + 1);
+ d_flux_coarsen_schedules.resizeArray(d_ln_max + 1);
+
+ d_prolongation_refine_algorithm = new xfer::RefineAlgorithm(d_dim);
+ d_urestriction_coarsen_algorithm = new xfer::CoarsenAlgorithm(d_dim);
+ d_rrestriction_coarsen_algorithm = new xfer::CoarsenAlgorithm(d_dim);
+ d_flux_coarsen_algorithm = new xfer::CoarsenAlgorithm(d_dim);
+ d_ghostfill_refine_algorithm = new xfer::RefineAlgorithm(d_dim);
+ d_ghostfill_nocoarse_refine_algorithm = new xfer::RefineAlgorithm(d_dim);
+
+ d_prolongation_refine_algorithm->
+ registerRefine(d_cell_scratch_id,
+ solution.getComponentDescriptorIndex(0),
+ d_cell_scratch_id,
+ d_prolongation_refine_operator);
+ d_urestriction_coarsen_algorithm->
+ registerCoarsen(solution.getComponentDescriptorIndex(0),
+ solution.getComponentDescriptorIndex(0),
+ d_urestriction_coarsen_operator);
+ d_rrestriction_coarsen_algorithm->
+ registerCoarsen(rhs.getComponentDescriptorIndex(0),
+ rhs.getComponentDescriptorIndex(0),
+ d_rrestriction_coarsen_operator);
+ d_ghostfill_refine_algorithm->
+ registerRefine(solution.getComponentDescriptorIndex(0),
+ solution.getComponentDescriptorIndex(0),
+ solution.getComponentDescriptorIndex(0),
+ d_ghostfill_refine_operator);
+ d_flux_coarsen_algorithm->
+ registerCoarsen(((d_flux_id != -1) ? d_flux_id : d_flux_scratch_id),
+ d_oflux_scratch_id,
+ d_flux_coarsen_operator);
+ d_ghostfill_nocoarse_refine_algorithm->
+ registerRefine(solution.getComponentDescriptorIndex(0),
+ solution.getComponentDescriptorIndex(0),
+ solution.getComponentDescriptorIndex(0),
+ d_ghostfill_nocoarse_refine_operator);
+
+ for (int dest_ln = d_ln_min + 1; dest_ln <= d_ln_max; ++dest_ln) {
+
+ tbox::Pointer<xfer::PatchLevelFullFillPattern> fill_pattern(
+ new xfer::PatchLevelFullFillPattern());
+ d_prolongation_refine_schedules[dest_ln] =
+ d_prolongation_refine_algorithm->
+ createSchedule(fill_pattern,
+ d_hierarchy->getPatchLevel(dest_ln),
+ tbox::Pointer<hier::PatchLevel>(),
+ dest_ln - 1,
+ d_hierarchy,
+ &d_bc_helper);
+ if (!d_prolongation_refine_schedules[dest_ln]) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot create a refine schedule for prolongation!\n");
+ }
+ d_ghostfill_refine_schedules[dest_ln] =
+ d_ghostfill_refine_algorithm->
+ createSchedule(d_hierarchy->getPatchLevel(dest_ln),
+ dest_ln - 1,
+ d_hierarchy,
+ &d_bc_helper);
+ if (!d_ghostfill_refine_schedules[dest_ln]) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot create a refine schedule for ghost filling!\n");
+ }
+ d_ghostfill_nocoarse_refine_schedules[dest_ln] =
+ d_ghostfill_nocoarse_refine_algorithm->
+ createSchedule(d_hierarchy->getPatchLevel(dest_ln),
+ &d_bc_helper);
+ if (!d_ghostfill_nocoarse_refine_schedules[dest_ln]) {
+ TBOX_ERROR(
+ d_object_name
+ <<
+ ": Cannot create a refine schedule for ghost filling on bottom level!\n");
+ }
+ }
+ for (int dest_ln = d_ln_min; dest_ln < d_ln_max; ++dest_ln) {
+ d_urestriction_coarsen_schedules[dest_ln] =
+ d_urestriction_coarsen_algorithm->
+ createSchedule(d_hierarchy->getPatchLevel(dest_ln),
+ d_hierarchy->getPatchLevel(dest_ln + 1));
+ if (!d_urestriction_coarsen_schedules[dest_ln]) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot create a coarsen schedule for U restriction!\n");
+ }
+ d_rrestriction_coarsen_schedules[dest_ln] =
+ d_rrestriction_coarsen_algorithm->
+ createSchedule(d_hierarchy->getPatchLevel(dest_ln),
+ d_hierarchy->getPatchLevel(dest_ln + 1));
+ if (!d_rrestriction_coarsen_schedules[dest_ln]) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot create a coarsen schedule for R restriction!\n");
+ }
+ d_flux_coarsen_schedules[dest_ln] =
+ d_flux_coarsen_algorithm->
+ createSchedule(d_hierarchy->getPatchLevel(dest_ln),
+ d_hierarchy->getPatchLevel(dest_ln + 1));
+ if (!d_flux_coarsen_schedules[dest_ln]) {
+ TBOX_ERROR(d_object_name
+ << ": Cannot create a coarsen schedule for flux transfer!\n");
+ }
+ }
+ d_ghostfill_nocoarse_refine_schedules[d_ln_min] =
+ d_ghostfill_nocoarse_refine_algorithm->
+ createSchedule(d_hierarchy->getPatchLevel(d_ln_min),
+ &d_bc_helper);
+ if (!d_ghostfill_nocoarse_refine_schedules[d_ln_min]) {
+ TBOX_ERROR(
+ d_object_name
+ <<
+ ": Cannot create a refine schedule for ghost filling on bottom level!\n");
+ }
+}
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual deallocateOperatorState *
+ * function. Deallocate internal hierarchy-dependent data. *
+ * State is allocated iff hierarchy is set. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::deallocateOperatorState()
+{
+ if (d_hierarchy) {
+ int ln;
+ for (ln = d_ln_min + 1; ln <= d_ln_max; ++ln) {
+ d_hierarchy->getPatchLevel(ln)->
+ deallocatePatchData(d_oflux_scratch_id);
+ }
+ d_cf_boundary.resizeArray(0);
+#ifdef HAVE_HYPRE
+ d_hypre_solver.deallocateSolverState();
+#endif
+ d_hierarchy.setNull();
+ d_ln_min = -1;
+ d_ln_max = -1;
+
+ d_prolongation_refine_algorithm.setNull();
+ d_prolongation_refine_schedules.setNull();
+
+ d_urestriction_coarsen_algorithm.setNull();
+ d_urestriction_coarsen_schedules.setNull();
+
+ d_rrestriction_coarsen_algorithm.setNull();
+ d_rrestriction_coarsen_schedules.setNull();
+
+ d_flux_coarsen_algorithm.setNull();
+ d_flux_coarsen_schedules.setNull();
+
+ d_ghostfill_refine_algorithm.setNull();
+ d_ghostfill_refine_schedules.setNull();
+
+ d_ghostfill_nocoarse_refine_algorithm.setNull();
+ d_ghostfill_nocoarse_refine_schedules.setNull();
+
+ }
+}
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual postprocessOneCycle function. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::postprocessOneCycle(
+ int fac_cycle_num,
+ const SAMRAIVectorReal<double>& current_soln,
+ const SAMRAIVectorReal<double>& residual)
+{
+ NULL_USE(current_soln);
+ NULL_USE(residual);
+
+ if (d_enable_logging) {
+ if (d_preconditioner) {
+ /*
+ * Output convergence progress. This is probably only appropriate
+ * if the solver is NOT being used as a preconditioner.
+ */
+ double avg_factor, final_factor;
+ d_preconditioner->getConvergenceFactors(avg_factor, final_factor);
+ tbox::plog
+ << "iter=" << std::setw(4) << fac_cycle_num
+ << " resid=" << d_preconditioner->getResidualNorm()
+ << " net conv=" << d_preconditioner->getNetConvergenceFactor()
+ << " final conv=" << d_preconditioner->getNetConvergenceFactor()
+ << " avg conv=" << d_preconditioner->getAvgConvergenceFactor()
+ << std::endl;
+ }
+ }
+}
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual restrictSolution function. *
+ * After restricting solution, update ghost cells of the affected *
+ * level. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::restrictSolution(
+ const SAMRAIVectorReal<double>& s,
+ SAMRAIVectorReal<double>& d,
+ int dest_ln) {
+
+ t_restrict_solution->start();
+
+ xeqScheduleURestriction(d.getComponentDescriptorIndex(0),
+ s.getComponentDescriptorIndex(0),
+ dest_ln);
+
+ d_bc_helper.setHomogeneousBc(false);
+ d_bc_helper.setTargetDataId(d.getComponentDescriptorIndex(0));
+
+ if (dest_ln == d_ln_min) {
+ xeqScheduleGhostFillNoCoarse(d.getComponentDescriptorIndex(0),
+ dest_ln);
+ } else {
+ xeqScheduleGhostFill(d.getComponentDescriptorIndex(0),
+ dest_ln);
+ }
+
+ t_restrict_solution->stop();
+}
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual restrictresidual function. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::restrictResidual(
+ const SAMRAIVectorReal<double>& s,
+ SAMRAIVectorReal<double>& d,
+ int dest_ln) {
+
+ t_restrict_residual->start();
+
+ xeqScheduleRRestriction(d.getComponentDescriptorIndex(0),
+ s.getComponentDescriptorIndex(0),
+ dest_ln);
+
+ t_restrict_residual->stop();
+}
+
+/*
+ ***********************************************************************
+ * FACOperatorStrategy virtual prolongErrorAndCorrect function. *
+ * After the prolongation, we set the physical boundary condition *
+ * for the correction, which is zero. Other ghost cell values, *
+ * which are preset to zero, need not be set. *
+ ***********************************************************************
+ */
+
+void CellStokesFACOps::prolongErrorAndCorrect(
+ const SAMRAIVectorReal<double>& s,
+ SAMRAIVectorReal<double>& d,
+ int dest_ln) {
+
+ t_prolong->start();
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (s.getPatchHierarchy() != d_hierarchy
+ || d.getPatchHierarchy() != d_hierarchy) {
+ TBOX_ERROR(d_object_name << ": Vector hierarchy does not match\n"
+ "internal state hierarchy.");
+ }
+#endif
+
+ tbox::Pointer<hier::PatchLevel> coarse_level =
+ d_hierarchy->getPatchLevel(dest_ln - 1);
+ tbox::Pointer<hier::PatchLevel> fine_level =
+ d_hierarchy->getPatchLevel(dest_ln);
+
+ /*
+ * Data is prolonged into the scratch space corresponding
+ * to index d_cell_scratch_id and allocated here.
+ */
+ fine_level->allocatePatchData(d_cell_scratch_id);
+
+ /*
+ * Refine solution into scratch space to fill the fine level
+ * interior in the scratch space, then use that refined data
+ * to correct the fine level error.
+ */
+ d_bc_helper.setTargetDataId(d_cell_scratch_id);
+ d_bc_helper.setHomogeneousBc(true);
+ const int src_index = s.getComponentDescriptorIndex(0);
+ xeqScheduleProlongation(d_cell_scratch_id,
+ src_index,
+ d_cell_scratch_id,
+ dest_ln);
+
+ /*
+ * Add the refined error in the scratch space
+ * to the error currently residing in the destination level.
+ */
+ math::HierarchyCellDataOpsReal<double>
+ hierarchy_math_ops(d_hierarchy, dest_ln, dest_ln);
+ const int dst_index = d.getComponentDescriptorIndex(0);
+ hierarchy_math_ops.add(dst_index, dst_index, d_cell_scratch_id);
+
+ fine_level->deallocatePatchData(d_cell_scratch_id);
+
+ t_prolong->stop();
+
+}
+
+/*
+ ********************************************************************
+ ********************************************************************
+ */
+
+void CellStokesFACOps::smoothError(
+ SAMRAIVectorReal<double>& data,
+ const SAMRAIVectorReal<double>& residual,
+ int ln,
+ int num_sweeps)
+{
+
+ t_smooth_error->start();
+
+ checkInputPatchDataIndices();
+ if (d_smoothing_choice == "redblack") {
+ smoothErrorByRedBlack(data,
+ residual,
+ ln,
+ num_sweeps,
+ d_residual_tolerance_during_smoothing);
+ } else {
+ TBOX_ERROR(d_object_name << ": Bad smoothing choice '"
+ << d_smoothing_choice
+ << "' in CellStokesFACOps.");
+ }
+
+ t_smooth_error->stop();
+}
+
+/*
+ ********************************************************************
+ * Workhorse function to smooth error using red-black *
+ * Gauss-Seidel iterations. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::smoothErrorByRedBlack(
+ SAMRAIVectorReal<double>& data,
+ const SAMRAIVectorReal<double>& residual,
+ int ln,
+ int num_sweeps,
+ double residual_tolerance)
+{
+
+ checkInputPatchDataIndices();
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (data.getPatchHierarchy() != d_hierarchy
+ || residual.getPatchHierarchy() != d_hierarchy) {
+ TBOX_ERROR(d_object_name << ": Vector hierarchy does not match\n"
+ "internal hierarchy.");
+ }
+#endif
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(ln);
+
+ const int data_id = data.getComponentDescriptorIndex(0);
+
+ const int flux_id = (d_flux_id != -1) ? d_flux_id : d_flux_scratch_id;
+
+ d_bc_helper.setTargetDataId(data_id);
+ d_bc_helper.setHomogeneousBc(true);
+ xeqScheduleGhostFillNoCoarse(data_id, ln);
+
+ if (ln > d_ln_min) {
+ /*
+ * Perform a one-time transfer of data from coarser level,
+ * to fill ghost boundaries that will not change through
+ * the smoothing loop.
+ */
+ xeqScheduleGhostFill(data_id, ln);
+ }
+
+ /*
+ * Smooth the number of sweeps specified or until
+ * the convergence is satisfactory.
+ */
+ int isweep;
+ double red_maxres, blk_maxres, maxres = 0;
+ red_maxres = blk_maxres = residual_tolerance + 1;
+ /*
+ * Instead of checking residual convergence globally,
+ * we check the not_converged flag. This avoids possible
+ * round-off errors affecting different processes differently,
+ * leading to disagreement on whether to continue smoothing.
+ */
+ int not_converged = 1;
+ for (isweep = 0; isweep < num_sweeps && not_converged; ++isweep) {
+ red_maxres = blk_maxres = 0;
+
+ // Red sweep.
+ xeqScheduleGhostFillNoCoarse(data_id, ln);
+ for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
+ tbox::Pointer<hier::Patch> patch = *pi;
+
+ bool deallocate_flux_data_when_done = false;
+ if (flux_id == d_flux_scratch_id) {
+ /*
+ * Using internal temporary storage for flux.
+ * For each patch, make sure the internal
+ * side-centered data is allocated and note
+ * whether that data should be deallocated when done.
+ */
+ if (!patch->checkAllocated(flux_id)) {
+ patch->allocatePatchData(flux_id);
+ deallocate_flux_data_when_done = true;
+ }
+ }
+
+ tbox::Pointer<pdat::CellData<double> >
+ scalar_field_data = d_stokes_spec.cIsVariable() ?
+ patch->getPatchData(d_stokes_spec.getCPatchDataId()) :
+ tbox::Pointer<hier::PatchData>(NULL);
+ tbox::Pointer<pdat::CellData<double> >
+ err_data = data.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::CellData<double> >
+ residual_data = residual.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::SideData<double> >
+ flux_data = patch->getPatchData(flux_id);
+
+ computeFluxOnPatch(
+ *patch,
+ level->getRatioToCoarserLevel(),
+ *err_data,
+ *flux_data);
+
+ redOrBlackSmoothingOnPatch(*patch,
+ *flux_data,
+ *residual_data,
+ *err_data,
+ 'r',
+ &red_maxres);
+
+ if (deallocate_flux_data_when_done) {
+ patch->deallocatePatchData(flux_id);
+ }
+ } // End patch number *pi
+ xeqScheduleGhostFillNoCoarse(data_id, ln);
+
+ // Black sweep.
+ for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
+ tbox::Pointer<hier::Patch> patch = *pi;
+
+ bool deallocate_flux_data_when_done = false;
+ if (flux_id == d_flux_scratch_id) {
+ /*
+ * Using internal temporary storage for flux.
+ * For each patch, make sure the internal
+ * side-centered data is allocated and note
+ * whether that data should be deallocated when done.
+ */
+ if (!patch->checkAllocated(flux_id)) {
+ patch->allocatePatchData(flux_id);
+ deallocate_flux_data_when_done = true;
+ }
+ }
+
+ tbox::Pointer<pdat::CellData<double> >
+ scalar_field_data = d_stokes_spec.cIsVariable() ?
+ patch->getPatchData(d_stokes_spec.getCPatchDataId()) :
+ tbox::Pointer<hier::PatchData>(NULL);
+ tbox::Pointer<pdat::CellData<double> >
+ err_data = data.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::CellData<double> >
+ residual_data = residual.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::SideData<double> >
+ flux_data = patch->getPatchData(flux_id);
+
+ computeFluxOnPatch(
+ *patch,
+ level->getRatioToCoarserLevel(),
+ *err_data,
+ *flux_data);
+
+ redOrBlackSmoothingOnPatch(*patch,
+ *flux_data,
+ *residual_data,
+ *err_data,
+ 'b',
+ &blk_maxres);
+
+ if (deallocate_flux_data_when_done) {
+ patch->deallocatePatchData(flux_id);
+ }
+ } // End patch number *pi
+ xeqScheduleGhostFillNoCoarse(data_id, ln);
+ if (residual_tolerance >= 0.0) {
+ /*
+ * Check for early end of sweeps due to convergence
+ * only if it is numerically possible (user gave a
+ * non negative value for residual tolerance).
+ */
+ maxres = tbox::MathUtilities<double>::Max(red_maxres, blk_maxres);
+ not_converged = maxres > residual_tolerance;
+ const tbox::SAMRAI_MPI& mpi(d_hierarchy->getDomainMappedBoxLevel().getMPI());
+ if (mpi.getSize() > 1) {
+ mpi.AllReduce(¬_converged, 1, MPI_MAX);
+ }
+ }
+ } // End sweep number isweep
+ if (d_enable_logging) tbox::plog
+ << d_object_name << " RBGS smoothing maxres = " << maxres << "\n"
+ << " after " << isweep << " sweeps.\n";
+
+}
+
+/*
+ ********************************************************************
+ * Fix flux on coarse-fine boundaries computed from a *
+ * constant-refine interpolation of coarse level data. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::ewingFixFlux(
+ const hier::Patch& patch,
+ const pdat::CellData<double>& soln_data,
+ pdat::SideData<double>& flux_data,
+ const hier::IntVector& ratio_to_coarser) const
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim, patch, soln_data, flux_data,
+ ratio_to_coarser);
+
+ const int patch_ln = patch.getPatchLevelNumber();
+ const hier::GlobalId id = patch.getGlobalId();
+ tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
+ patch.getPatchGeometry();
+ const double* dx = patch_geom->getDx();
+ const hier::Box& patch_box(patch.getBox());
+ const hier::Index& plower = patch_box.lower();
+ const hier::Index& pupper = patch_box.upper();
+
+ const tbox::Array<hier::BoundaryBox>& bboxes =
+ d_cf_boundary[patch_ln]->getBoundaries(id, 1);
+ int bn, nboxes = bboxes.getSize();
+
+ if (d_stokes_spec.dIsVariable()) {
+
+ tbox::Pointer<pdat::SideData<double> > diffcoef_data;
+ diffcoef_data = patch.getPatchData(d_stokes_spec.getDPatchDataId());
+
+ for (bn = 0; bn < nboxes; ++bn) {
+ const hier::BoundaryBox& boundary_box = bboxes[bn];
+
+ TBOX_ASSERT(boundary_box.getBoundaryType() == 1);
+
+ const hier::Box& bdry_box = boundary_box.getBox();
+ const hier::Index& blower = bdry_box.lower();
+ const hier::Index& bupper = bdry_box.upper();
+ const int location_index = boundary_box.getLocationIndex();
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(ewingfixfluxvardc2d, EWINGFIXFLUXVARDC2D) (
+ flux_data.getPointer(0), flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_data->getPointer(0), diffcoef_data->getPointer(1),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &plower[0], &pupper[0], &plower[1], &pupper[1],
+ &location_index,
+ &ratio_to_coarser[0],
+ &blower[0], &bupper[0],
+ dx);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(ewingfixfluxvardc3d, EWINGFIXFLUXVARDC3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ diffcoef_data->getPointer(2),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ &diffcoef_data->getGhostCellWidth()[2],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &plower[0], &pupper[0],
+ &plower[1], &pupper[1],
+ &plower[2], &pupper[2],
+ &location_index,
+ &ratio_to_coarser[0],
+ &blower[0], &bupper[0],
+ dx);
+ } else {
+ TBOX_ERROR("CellStokesFACOps : DIM > 3 not supported" << std::endl);
+ }
+
+ }
+ } else {
+
+ const double diffcoef_constant = d_stokes_spec.getDConstant();
+
+ for (bn = 0; bn < nboxes; ++bn) {
+ const hier::BoundaryBox& boundary_box = bboxes[bn];
+
+ TBOX_ASSERT(boundary_box.getBoundaryType() == 1);
+
+ const hier::Box& bdry_box = boundary_box.getBox();
+ const hier::Index& blower = bdry_box.lower();
+ const hier::Index& bupper = bdry_box.upper();
+ const int location_index = boundary_box.getLocationIndex();
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(ewingfixfluxcondc2d, EWINGFIXFLUXCONDC2D) (
+ flux_data.getPointer(0), flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &plower[0], &pupper[0],
+ &plower[1], &pupper[1],
+ &location_index,
+ &ratio_to_coarser[0],
+ &blower[0], &bupper[0],
+ dx);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(ewingfixfluxcondc3d, EWINGFIXFLUXCONDC3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &plower[0], &pupper[0],
+ &plower[1], &pupper[1],
+ &plower[2], &pupper[2],
+ &location_index,
+ &ratio_to_coarser[0],
+ &blower[0], &bupper[0],
+ dx);
+ }
+ }
+ }
+}
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual solveCoarsestLevel *
+ * function *
+ ********************************************************************
+ */
+
+int CellStokesFACOps::solveCoarsestLevel(
+ SAMRAIVectorReal<double>& data,
+ const SAMRAIVectorReal<double>& residual,
+ int coarsest_ln) {
+
+ t_solve_coarsest->start();
+
+ checkInputPatchDataIndices();
+
+ int return_value = 0;
+
+ if (d_coarse_solver_choice == "jacobi") {
+ d_residual_tolerance_during_smoothing = d_coarse_solver_tolerance;
+ smoothError(data,
+ residual,
+ coarsest_ln,
+ d_coarse_solver_max_iterations);
+ d_residual_tolerance_during_smoothing = -1.0;
+ } else if (d_coarse_solver_choice == "redblack") {
+ d_residual_tolerance_during_smoothing = d_coarse_solver_tolerance;
+ smoothError(data,
+ residual,
+ coarsest_ln,
+ d_coarse_solver_max_iterations);
+ d_residual_tolerance_during_smoothing = -1.0;
+ } else if (d_coarse_solver_choice == "hypre") {
+#ifndef HAVE_HYPRE
+ TBOX_ERROR(d_object_name << ": Coarse level solver choice '"
+ << d_coarse_solver_choice
+ << "' unavailable in "
+ << "scapCellStokesOps::solveCoarsestLevel.");
+#else
+ return_value = solveCoarsestLevel_HYPRE(data, residual, coarsest_ln);
+#endif
+ } else {
+ TBOX_ERROR(
+ d_object_name << ": Bad coarse level solver choice '"
+ << d_coarse_solver_choice
+ <<
+ "' in scapCellStokesOps::solveCoarsestLevel.");
+ }
+
+ xeqScheduleGhostFillNoCoarse(data.getComponentDescriptorIndex(0),
+ coarsest_ln);
+
+ t_solve_coarsest->stop();
+
+ return return_value;
+}
+
+#ifdef HAVE_HYPRE
+/*
+ ********************************************************************
+ * Solve coarsest level using Hypre *
+ * We only solve for the error, so we always use homogeneous bc. *
+ ********************************************************************
+ */
+
+int CellStokesFACOps::solveCoarsestLevel_HYPRE(
+ SAMRAIVectorReal<double>& data,
+ const SAMRAIVectorReal<double>& residual,
+ int coarsest_ln) {
+
+ NULL_USE(coarsest_ln);
+
+#ifndef HAVE_HYPRE
+ TBOX_ERROR(d_object_name << ": Coarse level solver choice '"
+ << d_coarse_solver_choice
+ << "' unavailable in "
+ << "CellStokesFACOps::solveCoarsestLevel.");
+
+ return 0;
+
+#else
+
+ checkInputPatchDataIndices();
+ d_hypre_solver.setStoppingCriteria(d_coarse_solver_max_iterations,
+ d_coarse_solver_tolerance);
+ const int solver_ret =
+ d_hypre_solver.solveSystem(
+ data.getComponentDescriptorIndex(0),
+ residual.getComponentDescriptorIndex(0),
+ true);
+ /*
+ * Present data on the solve.
+ * The Hypre solver returns 0 if converged.
+ */
+ if (d_enable_logging) tbox::plog
+ << d_object_name << " Hypre solve " << (solver_ret ? "" : "NOT ")
+ << "converged\n"
+ << "\titerations: " << d_hypre_solver.getNumberOfIterations() << "\n"
+ << "\tresidual: " << d_hypre_solver.getRelativeResidualNorm() << "\n";
+
+ return !solver_ret;
+
+#endif
+
+}
+#endif
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual *
+ * computeCompositeResidualOnLevel function *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::computeCompositeResidualOnLevel(
+ SAMRAIVectorReal<double>& residual,
+ const SAMRAIVectorReal<double>& solution,
+ const SAMRAIVectorReal<double>& rhs,
+ int ln,
+ bool error_equation_indicator) {
+
+ t_compute_composite_residual->start();
+
+ checkInputPatchDataIndices();
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (residual.getPatchHierarchy() != d_hierarchy
+ || solution.getPatchHierarchy() != d_hierarchy
+ || rhs.getPatchHierarchy() != d_hierarchy) {
+ TBOX_ERROR(d_object_name << ": Vector hierarchy does not match\n"
+ "internal hierarchy.");
+ }
+#endif
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(ln);
+
+ /*
+ * Set up the bc helper so that when we use a refine schedule
+ * to fill ghosts, the correct data is operated on.
+ */
+ const int soln_id = solution.getComponentDescriptorIndex(0);
+ d_bc_helper.setTargetDataId(soln_id);
+ d_bc_helper.setHomogeneousBc(error_equation_indicator);
+
+ const int flux_id = (d_flux_id != -1) ? d_flux_id : d_flux_scratch_id;
+
+ /*
+ * Assumptions:
+ * 1. Data does not yet exist in ghost boundaries.
+ * 2. Residual data on next finer grid (if any)
+ * has been computed already.
+ * 3. Flux data from next finer grid (if any) has
+ * been computed but has not been coarsened to
+ * this level.
+ *
+ * Steps:
+ * S1. Fill solution ghost data by refinement
+ * or setting physical boundary conditions.
+ * This also brings in information from coarser
+ * to form the composite grid flux.
+ * S2. Compute flux on ln.
+ * S3. If next finer is available,
+ * Coarsen flux data on next finer level,
+ * overwriting flux computed from coarse data.
+ * S4. Compute residual data from flux.
+ */
+
+ /* S1. Fill solution ghost data. */
+ {
+ tbox::Pointer<xfer::RefineSchedule> ln_refine_schedule;
+ if (ln > d_ln_min) {
+ /* Fill from current, next coarser level and physical boundary */
+ xeqScheduleGhostFill(soln_id, ln);
+ } else {
+ /* Fill from current and physical boundary */
+ xeqScheduleGhostFillNoCoarse(soln_id, ln);
+ }
+ }
+
+ /*
+ * For the whole level, make sure the internal
+ * side-centered data is allocated and note
+ * whether that data should be deallocated when done.
+ * We do this for the whole level because the data
+ * undergoes transfer operations which require the
+ * whole level data.
+ */
+ bool deallocate_flux_data_when_done = false;
+ if (flux_id == d_flux_scratch_id) {
+ if (!level->checkAllocated(flux_id)) {
+ level->allocatePatchData(flux_id);
+ deallocate_flux_data_when_done = true;
+ }
+ }
+
+ /*
+ * S2. Compute flux on patches in level.
+ */
+ for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
+ tbox::Pointer<hier::Patch> patch = *pi;
+
+ tbox::Pointer<pdat::CellData<double> >
+ soln_data = solution.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::CellData<double> >
+ rhs_data = rhs.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::CellData<double> >
+ residual_data = residual.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::SideData<double> >
+ flux_data = patch->getPatchData(flux_id);
+ computeFluxOnPatch(
+ *patch,
+ level->getRatioToCoarserLevel(),
+ *soln_data,
+ *flux_data);
+
+ }
+
+ /*
+ * S3. Coarsen oflux data from next finer level so that
+ * the computed flux becomes the composite grid flux.
+ */
+ if (ln < d_ln_max) {
+ xeqScheduleFluxCoarsen(flux_id, d_oflux_scratch_id, ln);
+ }
+
+ /*
+ * S4. Compute residual on patches in level.
+ */
+ for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
+ tbox::Pointer<hier::Patch> patch = *pi;
+ tbox::Pointer<pdat::CellData<double> >
+ soln_data = solution.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::CellData<double> >
+ rhs_data = rhs.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::CellData<double> >
+ residual_data = residual.getComponentPatchData(0, *patch);
+ tbox::Pointer<pdat::SideData<double> >
+ flux_data = patch->getPatchData(flux_id);
+ computeResidualOnPatch(*patch,
+ *flux_data,
+ *soln_data,
+ *rhs_data,
+ *residual_data);
+
+ if (ln > d_ln_min) {
+ /*
+ * Save outerflux data so that next coarser level
+ * can compute its coarse-fine composite flux.
+ * This is not strictly needed in this "compute residual"
+ * loop through the patches, but we put it here to
+ * avoid writing another loop for it.
+ */
+ tbox::Pointer<pdat::OutersideData<double> >
+ oflux_data = patch->getPatchData(d_oflux_scratch_id);
+
+ TBOX_ASSERT(oflux_data);
+
+ oflux_data->copy(*flux_data);
+ }
+ }
+
+ if (deallocate_flux_data_when_done) {
+ level->deallocatePatchData(flux_id);
+ }
+
+ t_compute_composite_residual->stop();
+}
+
+/*
+ ********************************************************************
+ * FACOperatorStrategy virtual computeResidualNorm *
+ * function *
+ ********************************************************************
+ */
+
+double CellStokesFACOps::computeResidualNorm(
+ const SAMRAIVectorReal<double>& residual,
+ int fine_ln,
+ int coarse_ln)
+{
+
+ if (coarse_ln != residual.getCoarsestLevelNumber() ||
+ fine_ln != residual.getFinestLevelNumber()) {
+ TBOX_ERROR("CellStokesFACOps::computeResidualNorm() is not\n"
+ << "set up to compute residual except on the range of\n"
+ << "levels defining the vector.\n");
+ }
+ t_compute_residual_norm->start();
+ /*
+ * The residual vector was cloned from vectors that has
+ * the proper weights associated with them, so we do not
+ * have to explicitly weight the residuals.
+ *
+ * maxNorm: not good to use because Hypre's norm does not
+ * correspond to it. Also maybe too sensitive to spikes.
+ * L2Norm: maybe good. But does not correspond to the
+ * scale of the quantity.
+ * L1Norm: maybe good. Correspond to scale of quantity,
+ * but may be too insensitive to spikes.
+ * RMSNorm: maybe good.
+ */
+ double norm = residual.RMSNorm();
+ t_compute_residual_norm->stop();
+ return norm;
+}
+
+/*
+ ********************************************************************
+ * Compute the vector weight and put it at a specified patch data *
+ * index. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::computeVectorWeights(
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ int weight_id,
+ int coarsest_ln,
+ int finest_ln) const
+{
+ TBOX_ASSERT(!hierarchy.isNull());
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
+
+ if (coarsest_ln == -1) coarsest_ln = 0;
+ if (finest_ln == -1) finest_ln = hierarchy->getFinestLevelNumber();
+ if (finest_ln < coarsest_ln) {
+ TBOX_ERROR(d_object_name
+ << ": Illegal level number range. finest_ln < coarsest_ln.");
+ }
+
+ int ln;
+ for (ln = finest_ln; ln >= coarsest_ln; --ln) {
+
+ /*
+ * On every level, first assign cell volume to vector weight.
+ */
+
+ tbox::Pointer<hier::PatchLevel> level =
+ hierarchy->getPatchLevel(ln);
+ for (hier::PatchLevel::Iterator p(level); p; p++) {
+ tbox::Pointer<hier::Patch> patch = *p;
+ tbox::Pointer<geom::CartesianPatchGeometry> patch_geometry =
+ patch->getPatchGeometry();
+ const double* dx = patch_geometry->getDx();
+ double cell_vol = dx[0];
+ if (d_dim > tbox::Dimension(1)) {
+ cell_vol *= dx[1];
+ }
+
+ if (d_dim > tbox::Dimension(2)) {
+ cell_vol *= dx[2];
+ }
+
+ tbox::Pointer<pdat::CellData<double> > w =
+ patch->getPatchData(weight_id);
+ if (!w) {
+ TBOX_ERROR(d_object_name
+ << ": weight id must refer to a pdat::CellVariable");
+ }
+ w->fillAll(cell_vol);
+ }
+
+ /*
+ * On all but the finest level, assign 0 to vector
+ * weight to cells covered by finer cells.
+ */
+
+ if (ln < finest_ln) {
+
+ /*
+ * First get the boxes that describe index space of the next finer
+ * level and coarsen them to describe corresponding index space
+ * at this level.
+ */
+
+ tbox::Pointer<hier::PatchLevel> next_finer_level =
+ hierarchy->getPatchLevel(ln + 1);
+ hier::BoxArray coarsened_boxes = next_finer_level->getBoxes();
+ hier::IntVector coarsen_ratio(next_finer_level->getRatioToLevelZero());
+ coarsen_ratio /= level->getRatioToLevelZero();
+ coarsened_boxes.coarsen(coarsen_ratio);
+
+ /*
+ * Then set vector weight to 0 wherever there is
+ * a nonempty intersection with the next finer level.
+ * Note that all assignments are local.
+ */
+
+ for (hier::PatchLevel::Iterator p(level); p; p++) {
+
+ tbox::Pointer<hier::Patch> patch = *p;
+ for (int i = 0; i < coarsened_boxes.getNumberOfBoxes(); i++) {
+
+ hier::Box coarse_box = coarsened_boxes[i];
+ hier::Box intersection = coarse_box * (patch->getBox());
+ if (!intersection.empty()) {
+ tbox::Pointer<pdat::CellData<double> > w =
+ patch->getPatchData(weight_id);
+ w->fillAll(0.0, intersection);
+
+ } // assignment only in non-empty intersection
+ } // loop over coarsened boxes from finer level
+ } // loop over patches in level
+ } // all levels except finest
+ } // loop over levels
+}
+
+/*
+ ********************************************************************
+ * Check the validity and correctness of input data for this class. *
+ ********************************************************************
+ */
+
+void CellStokesFACOps::checkInputPatchDataIndices() const {
+ /*
+ * Check input validity and correctness.
+ */
+ hier::VariableDatabase& vdb(*hier::VariableDatabase::getDatabase());
+
+ if (!d_stokes_spec.dIsConstant()
+ && d_stokes_spec.getDPatchDataId() != -1) {
+ tbox::Pointer<hier::Variable> var;
+ vdb.mapIndexToVariable(d_stokes_spec.getDPatchDataId(), var);
+ tbox::Pointer<pdat::SideVariable<double> > diffcoef_var = var;
+ if (!diffcoef_var) {
+ TBOX_ERROR(d_object_name
+ << ": Bad diffusion coefficient patch data index.");
+ }
+ }
+
+ if (!d_stokes_spec.cIsConstant() && !d_stokes_spec.cIsZero()) {
+ tbox::Pointer<hier::Variable> var;
+ vdb.mapIndexToVariable(d_stokes_spec.getCPatchDataId(), var);
+ tbox::Pointer<pdat::CellVariable<double> > scalar_field_var = var;
+ if (!scalar_field_var) {
+ TBOX_ERROR(d_object_name << ": Bad linear term patch data index.");
+ }
+ }
+
+ if (d_flux_id != -1) {
+ tbox::Pointer<hier::Variable> var;
+ vdb.mapIndexToVariable(d_flux_id, var);
+ tbox::Pointer<pdat::SideVariable<double> > flux_var = var;
+
+ TBOX_ASSERT(flux_var);
+ }
+
+}
+
+/*
+ *******************************************************************
+ * *
+ * AMR-unaware patch-centered computational kernels. *
+ * *
+ *******************************************************************
+ */
+
+void CellStokesFACOps::computeFluxOnPatch(
+ const hier::Patch& patch,
+ const hier::IntVector& ratio_to_coarser_level,
+ const pdat::CellData<double>& w_data,
+ pdat::SideData<double>& Dgradw_data) const
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim, patch, ratio_to_coarser_level, w_data,
+ Dgradw_data);
+ TBOX_ASSERT(patch.inHierarchy());
+ TBOX_ASSERT(w_data.getGhostCellWidth() >=
+ hier::IntVector::getOne(ratio_to_coarser_level.getDim()));
+
+ tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
+ patch.getPatchGeometry();
+ const hier::Box& box = patch.getBox();
+ const int* lower = &box.lower()[0];
+ const int* upper = &box.upper()[0];
+ const double* dx = patch_geom->getDx();
+
+ double D_value;
+ tbox::Pointer<pdat::SideData<double> > D_data;
+ if (d_stokes_spec.dIsConstant()) {
+ D_value = d_stokes_spec.getDConstant();
+ } else {
+ D_data = patch.getPatchData(d_stokes_spec.getDPatchDataId());
+ }
+
+ if (d_stokes_spec.dIsConstant()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compfluxcondc2d, COMPFLUXCONDC2D) (
+ Dgradw_data.getPointer(0),
+ Dgradw_data.getPointer(1),
+ &Dgradw_data.getGhostCellWidth()[0],
+ &Dgradw_data.getGhostCellWidth()[1],
+ D_value,
+ w_data.getPointer(),
+ &w_data.getGhostCellWidth()[0],
+ &w_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compfluxcondc3d, COMPFLUXCONDC3D) (
+ Dgradw_data.getPointer(0),
+ Dgradw_data.getPointer(1),
+ Dgradw_data.getPointer(2),
+ &Dgradw_data.getGhostCellWidth()[0],
+ &Dgradw_data.getGhostCellWidth()[1],
+ &Dgradw_data.getGhostCellWidth()[2],
+ D_value,
+ w_data.getPointer(),
+ &w_data.getGhostCellWidth()[0],
+ &w_data.getGhostCellWidth()[1],
+ &w_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx);
+ }
+ } else {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compfluxvardc2d, COMPFLUXVARDC2D) (
+ Dgradw_data.getPointer(0),
+ Dgradw_data.getPointer(1),
+ &Dgradw_data.getGhostCellWidth()[0],
+ &Dgradw_data.getGhostCellWidth()[1],
+ D_data->getPointer(0),
+ D_data->getPointer(1),
+ &D_data->getGhostCellWidth()[0],
+ &D_data->getGhostCellWidth()[1],
+ w_data.getPointer(),
+ &w_data.getGhostCellWidth()[0],
+ &w_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx);
+ }
+ if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compfluxvardc3d, COMPFLUXVARDC3D) (
+ Dgradw_data.getPointer(0),
+ Dgradw_data.getPointer(1),
+ Dgradw_data.getPointer(2),
+ &Dgradw_data.getGhostCellWidth()[0],
+ &Dgradw_data.getGhostCellWidth()[1],
+ &Dgradw_data.getGhostCellWidth()[2],
+ D_data->getPointer(0),
+ D_data->getPointer(1),
+ D_data->getPointer(2),
+ &D_data->getGhostCellWidth()[0],
+ &D_data->getGhostCellWidth()[1],
+ &D_data->getGhostCellWidth()[2],
+ w_data.getPointer(),
+ &w_data.getGhostCellWidth()[0],
+ &w_data.getGhostCellWidth()[1],
+ &w_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx);
+ }
+ }
+
+ const int patch_ln = patch.getPatchLevelNumber();
+
+ if (d_cf_discretization == "Ewing" && patch_ln > d_ln_min) {
+ ewingFixFlux(patch,
+ w_data,
+ Dgradw_data,
+ ratio_to_coarser_level);
+ }
+
+}
+
+void CellStokesFACOps::computeResidualOnPatch(
+ const hier::Patch& patch,
+ const pdat::SideData<double>& flux_data,
+ const pdat::CellData<double>& soln_data,
+ const pdat::CellData<double>& rhs_data,
+ pdat::CellData<double>& residual_data) const
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS5(d_dim, patch, flux_data, soln_data, rhs_data,
+ residual_data);
+
+ tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
+ patch.getPatchGeometry();
+ const hier::Box& box = patch.getBox();
+ const int* lower = &box.lower()[0];
+ const int* upper = &box.upper()[0];
+ const double* dx = patch_geom->getDx();
+
+ tbox::Pointer<pdat::CellData<double> > scalar_field_data;
+ double scalar_field_constant;
+ if (d_stokes_spec.cIsVariable()) {
+ scalar_field_data =
+ patch.getPatchData(d_stokes_spec.getCPatchDataId());
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compresvarsca2d, COMPRESVARSCA2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ residual_data.getPointer(),
+ &residual_data.getGhostCellWidth()[0],
+ &residual_data.getGhostCellWidth()[1],
+ scalar_field_data->getPointer(),
+ &scalar_field_data->getGhostCellWidth()[0],
+ &scalar_field_data->getGhostCellWidth()[1],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0], &lower[1], &upper[1],
+ dx);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compresvarsca3d, COMPRESVARSCA3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ residual_data.getPointer(),
+ &residual_data.getGhostCellWidth()[0],
+ &residual_data.getGhostCellWidth()[1],
+ &residual_data.getGhostCellWidth()[2],
+ scalar_field_data->getPointer(),
+ &scalar_field_data->getGhostCellWidth()[0],
+ &scalar_field_data->getGhostCellWidth()[1],
+ &scalar_field_data->getGhostCellWidth()[2],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0], &lower[1], &upper[1], &lower[2], &upper[2],
+ dx);
+ }
+ } else if (d_stokes_spec.cIsConstant()) {
+ scalar_field_constant = d_stokes_spec.getCConstant();
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compresconsca2d, COMPRESCONSCA2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ residual_data.getPointer(),
+ &residual_data.getGhostCellWidth()[0],
+ &residual_data.getGhostCellWidth()[1],
+ scalar_field_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0], &lower[1], &upper[1],
+ dx);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compresconsca3d, COMPRESCONSCA3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ residual_data.getPointer(),
+ &residual_data.getGhostCellWidth()[0],
+ &residual_data.getGhostCellWidth()[1],
+ &residual_data.getGhostCellWidth()[2],
+ scalar_field_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0], &lower[1], &upper[1], &lower[2], &upper[2],
+ dx);
+ }
+ } else {
+ scalar_field_constant = 0.0;
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compresconsca2d, COMPRESCONSCA2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ residual_data.getPointer(),
+ &residual_data.getGhostCellWidth()[0],
+ &residual_data.getGhostCellWidth()[1],
+ 0.0,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0], &lower[1], &upper[1],
+ dx);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compresconsca3d, COMPRESCONSCA3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ residual_data.getPointer(),
+ &residual_data.getGhostCellWidth()[0],
+ &residual_data.getGhostCellWidth()[1],
+ &residual_data.getGhostCellWidth()[2],
+ 0.0,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0], &lower[1], &upper[1], &lower[2], &upper[2],
+ dx);
+ }
+ }
+}
+
+void CellStokesFACOps::redOrBlackSmoothingOnPatch(
+ const hier::Patch& patch,
+ const pdat::SideData<double>& flux_data,
+ const pdat::CellData<double>& rhs_data,
+ pdat::CellData<double>& soln_data,
+ char red_or_black,
+ double* p_maxres) const
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim, patch, flux_data, soln_data, rhs_data);
+ TBOX_ASSERT(red_or_black == 'r' || red_or_black == 'b');
+
+ const int offset = red_or_black == 'r' ? 0 : 1;
+ tbox::Pointer<geom::CartesianPatchGeometry> patch_geom =
+ patch.getPatchGeometry();
+ const hier::Box& box = patch.getBox();
+ const int* lower = &box.lower()[0];
+ const int* upper = &box.upper()[0];
+ const double* dx = patch_geom->getDx();
+
+ tbox::Pointer<pdat::CellData<double> > scalar_field_data;
+ double scalar_field_constant;
+ tbox::Pointer<pdat::SideData<double> > diffcoef_data;
+ double diffcoef_constant;
+
+ if (d_stokes_spec.cIsVariable()) {
+ scalar_field_data =
+ patch.getPatchData(d_stokes_spec.getCPatchDataId());
+ } else if (d_stokes_spec.cIsConstant()) {
+ scalar_field_constant = d_stokes_spec.getCConstant();
+ } else {
+ scalar_field_constant = 0.0;
+ }
+ if (d_stokes_spec.dIsVariable()) {
+ diffcoef_data = patch.getPatchData(d_stokes_spec.getDPatchDataId());
+ } else {
+ diffcoef_constant = d_stokes_spec.getDConstant();
+ }
+
+ double maxres = 0.0;
+ if (d_stokes_spec.dIsVariable() && d_stokes_spec.cIsVariable()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(rbgswithfluxmaxvardcvarsf2d, RBGSWITHFLUXMAXVARDCVARSF2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ scalar_field_data->getPointer(),
+ &scalar_field_data->getGhostCellWidth()[0],
+ &scalar_field_data->getGhostCellWidth()[1],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx,
+ &offset, &maxres);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(rbgswithfluxmaxvardcvarsf3d, RBGSWITHFLUXMAXVARDCVARSF3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ diffcoef_data->getPointer(2),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ &diffcoef_data->getGhostCellWidth()[2],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ scalar_field_data->getPointer(),
+ &scalar_field_data->getGhostCellWidth()[0],
+ &scalar_field_data->getGhostCellWidth()[1],
+ &scalar_field_data->getGhostCellWidth()[2],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx,
+ &offset, &maxres);
+ }
+ } else if (d_stokes_spec.dIsVariable() && d_stokes_spec.cIsConstant()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(rbgswithfluxmaxvardcconsf2d, RBGSWITHFLUXMAXVARDCCONSF2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ scalar_field_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx,
+ &offset, &maxres);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(rbgswithfluxmaxvardcconsf3d, RBGSWITHFLUXMAXVARDCCONSF3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ diffcoef_data->getPointer(2),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ &diffcoef_data->getGhostCellWidth()[2],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ scalar_field_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx,
+ &offset, &maxres);
+ }
+ } else if (d_stokes_spec.dIsVariable() && d_stokes_spec.cIsZero()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(rbgswithfluxmaxvardcconsf2d, RBGSWITHFLUXMAXVARDCCONSF2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ 0.0,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx,
+ &offset, &maxres);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(rbgswithfluxmaxvardcconsf3d, RBGSWITHFLUXMAXVARDCCONSF3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_data->getPointer(0),
+ diffcoef_data->getPointer(1),
+ diffcoef_data->getPointer(2),
+ &diffcoef_data->getGhostCellWidth()[0],
+ &diffcoef_data->getGhostCellWidth()[1],
+ &diffcoef_data->getGhostCellWidth()[2],
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ 0.0,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx,
+ &offset, &maxres);
+ }
+ } else if (!d_stokes_spec.dIsVariable() && d_stokes_spec.cIsVariable()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(rbgswithfluxmaxcondcvarsf2d, RBGSWITHFLUXMAXCONDCVARSF2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_constant,
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ scalar_field_data->getPointer(),
+ &scalar_field_data->getGhostCellWidth()[0],
+ &scalar_field_data->getGhostCellWidth()[1],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx,
+ &offset, &maxres);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(rbgswithfluxmaxcondcvarsf3d, RBGSWITHFLUXMAXCONDCVARSF3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_constant,
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ scalar_field_data->getPointer(),
+ &scalar_field_data->getGhostCellWidth()[0],
+ &scalar_field_data->getGhostCellWidth()[1],
+ &scalar_field_data->getGhostCellWidth()[2],
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx,
+ &offset, &maxres);
+ }
+ } else if (!d_stokes_spec.dIsVariable() && d_stokes_spec.cIsConstant()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(rbgswithfluxmaxcondcconsf2d, RBGSWITHFLUXMAXCONDCCONSF2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_constant,
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ scalar_field_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx,
+ &offset, &maxres);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(rbgswithfluxmaxcondcconsf3d, RBGSWITHFLUXMAXCONDCCONSF3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_constant,
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ scalar_field_constant,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx,
+ &offset, &maxres);
+ }
+ } else if (!d_stokes_spec.dIsVariable() && d_stokes_spec.cIsZero()) {
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(rbgswithfluxmaxcondcconsf2d, RBGSWITHFLUXMAXCONDCCONSF2D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ diffcoef_constant,
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ 0.0,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ dx,
+ &offset, &maxres);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(rbgswithfluxmaxcondcconsf3d, RBGSWITHFLUXMAXCONDCCONSF3D) (
+ flux_data.getPointer(0),
+ flux_data.getPointer(1),
+ flux_data.getPointer(2),
+ &flux_data.getGhostCellWidth()[0],
+ &flux_data.getGhostCellWidth()[1],
+ &flux_data.getGhostCellWidth()[2],
+ diffcoef_constant,
+ rhs_data.getPointer(),
+ &rhs_data.getGhostCellWidth()[0],
+ &rhs_data.getGhostCellWidth()[1],
+ &rhs_data.getGhostCellWidth()[2],
+ 0.0,
+ soln_data.getPointer(),
+ &soln_data.getGhostCellWidth()[0],
+ &soln_data.getGhostCellWidth()[1],
+ &soln_data.getGhostCellWidth()[2],
+ &lower[0], &upper[0],
+ &lower[1], &upper[1],
+ &lower[2], &upper[2],
+ dx,
+ &offset, &maxres);
+ }
+ }
+
+ *p_maxres = maxres;
+}
+
+void
+CellStokesFACOps::xeqScheduleProlongation(
+ int dst_id,
+ int src_id,
+ int scr_id,
+ int dest_ln)
+{
+ if (!d_prolongation_refine_schedules[dest_ln]) {
+ TBOX_ERROR("Expected schedule not found.");
+ }
+ xfer::RefineAlgorithm refiner(d_dim);
+ refiner.
+ registerRefine(dst_id,
+ src_id,
+ scr_id,
+ d_prolongation_refine_operator);
+ refiner.
+ resetSchedule(d_prolongation_refine_schedules[dest_ln]);
+ d_prolongation_refine_schedules[dest_ln]->fillData(0.0);
+ d_prolongation_refine_algorithm->
+ resetSchedule(d_prolongation_refine_schedules[dest_ln]);
+}
+
+void
+CellStokesFACOps::xeqScheduleURestriction(
+ int dst_id,
+ int src_id,
+ int dest_ln)
+{
+ if (!d_urestriction_coarsen_schedules[dest_ln]) {
+ TBOX_ERROR("Expected schedule not found.");
+ }
+
+ xfer::CoarsenAlgorithm coarsener(d_dim);
+ coarsener.registerCoarsen(dst_id,
+ src_id,
+ d_urestriction_coarsen_operator);
+ coarsener.resetSchedule(d_urestriction_coarsen_schedules[dest_ln]);
+ d_urestriction_coarsen_schedules[dest_ln]->coarsenData();
+ d_urestriction_coarsen_algorithm->
+ resetSchedule(d_urestriction_coarsen_schedules[dest_ln]);
+}
+
+void
+CellStokesFACOps::xeqScheduleRRestriction(
+ int dst_id,
+ int src_id,
+ int dest_ln)
+{
+ if (!d_rrestriction_coarsen_schedules[dest_ln]) {
+ TBOX_ERROR("Expected schedule not found.");
+ }
+
+ xfer::CoarsenAlgorithm coarsener(d_dim);
+ coarsener.registerCoarsen(dst_id,
+ src_id,
+ d_rrestriction_coarsen_operator);
+ coarsener.resetSchedule(d_rrestriction_coarsen_schedules[dest_ln]);
+ d_rrestriction_coarsen_schedules[dest_ln]->coarsenData();
+ d_rrestriction_coarsen_algorithm->
+ resetSchedule(d_rrestriction_coarsen_schedules[dest_ln]);
+}
+
+void
+CellStokesFACOps::xeqScheduleFluxCoarsen(
+ int dst_id,
+ int src_id,
+ int dest_ln)
+{
+ if (!d_flux_coarsen_schedules[dest_ln]) {
+ TBOX_ERROR("Expected schedule not found.");
+ }
+
+ xfer::CoarsenAlgorithm coarsener(d_dim);
+ coarsener.registerCoarsen(dst_id,
+ src_id,
+ d_flux_coarsen_operator);
+
+ coarsener.resetSchedule(d_flux_coarsen_schedules[dest_ln]);
+ d_flux_coarsen_schedules[dest_ln]->coarsenData();
+ d_flux_coarsen_algorithm->
+ resetSchedule(d_flux_coarsen_schedules[dest_ln]);
+}
+
+void
+CellStokesFACOps::xeqScheduleGhostFill(
+ int dst_id,
+ int dest_ln)
+{
+ if (!d_ghostfill_refine_schedules[dest_ln]) {
+ TBOX_ERROR("Expected schedule not found.");
+ }
+ xfer::RefineAlgorithm refiner(d_dim);
+ refiner.
+ registerRefine(dst_id,
+ dst_id,
+ dst_id,
+ d_ghostfill_refine_operator);
+ refiner.
+ resetSchedule(d_ghostfill_refine_schedules[dest_ln]);
+ d_ghostfill_refine_schedules[dest_ln]->fillData(0.0);
+ d_ghostfill_refine_algorithm->
+ resetSchedule(d_ghostfill_refine_schedules[dest_ln]);
+}
+
+void
+CellStokesFACOps::xeqScheduleGhostFillNoCoarse(
+ int dst_id,
+ int dest_ln)
+{
+ if (!d_ghostfill_nocoarse_refine_schedules[dest_ln]) {
+ TBOX_ERROR("Expected schedule not found.");
+ }
+ xfer::RefineAlgorithm refiner(d_dim);
+ refiner.
+ registerRefine(dst_id,
+ dst_id,
+ dst_id,
+ d_ghostfill_nocoarse_refine_operator);
+ refiner.
+ resetSchedule(d_ghostfill_nocoarse_refine_schedules[dest_ln]);
+ d_ghostfill_nocoarse_refine_schedules[dest_ln]->fillData(0.0);
+ d_ghostfill_nocoarse_refine_algorithm->
+ resetSchedule(d_ghostfill_nocoarse_refine_schedules[dest_ln]);
+}
+
+void
+CellStokesFACOps::finalizeCallback()
+{
+ for (int d = 0; d < tbox::Dimension::MAXIMUM_DIMENSION_VALUE; ++d) {
+ s_cell_scratch_var[d].setNull();
+ s_flux_scratch_var[d].setNull();
+ s_oflux_scratch_var[d].setNull();
+ }
+}
+
+}
+}
+#endif
diff -r a44a82f15794 -r fe2a9230921b StokesFACOps.I
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesFACOps.I Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,213 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: Operator class for solving scalar Stokes using FAC
+ *
+ ************************************************************************/
+namespace SAMRAI {
+namespace solv {
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setPreconditioner(
+ const FACPreconditioner* preconditioner) {
+ d_preconditioner = preconditioner;
+}
+
+#ifdef HAVE_HYPRE
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setUseSMG(
+ bool use_smg)
+{
+ if (d_hierarchy) {
+ TBOX_ERROR(
+ d_object_name << ": setUseSMG(bool) may NOT be called\n"
+ <<
+ "while the solver state is initialized, as that\n"
+ << "would lead to a corrupted solver state.\n");
+ }
+ d_hypre_solver.setUseSMG(use_smg);
+}
+#endif
+
+/*
+ ********************************************************************
+ * Set the physical boundary condition object. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setPhysicalBcCoefObject(
+ const RobinBcCoefStrategy* physical_bc_coef)
+{
+ d_physical_bc_coef = physical_bc_coef;
+ d_bc_helper.setCoefImplementation(physical_bc_coef);
+#ifdef HAVE_HYPRE
+ d_hypre_solver.setPhysicalBcCoefObject(d_physical_bc_coef);
+#endif
+}
+
+/*
+ ********************************************************************
+ * Set the object specifying the parameters of the Stokes equation *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setStokesSpecifications(
+ const StokesSpecifications& spec)
+{
+ d_stokes_spec = spec;
+}
+
+/*
+ ********************************************************************
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::enableLogging(
+ bool enable_logging)
+{
+ d_enable_logging = enable_logging;
+}
+
+/*
+ ********************************************************************
+ * Set the patch data id for the flux. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setFluxId(
+ int flux_id) {
+ d_flux_id = flux_id;
+#ifdef DEBUG_CHECK_ASSERTIONS
+ checkInputPatchDataIndices();
+#endif
+}
+
+/*
+ ********************************************************************
+ * Set the choice for smoothing algorithm. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setSmoothingChoice(
+ const std::string& smoothing_choice)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (smoothing_choice != "redblack") {
+ TBOX_ERROR(d_object_name << ": Bad smoothing choice '"
+ << smoothing_choice
+ << "' in CellStokesFACOps::setSmoothingChoice.");
+ }
+#endif
+ d_smoothing_choice = smoothing_choice;
+}
+
+/*
+ ********************************************************************
+ * Set the choice for the coarse level solver. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setCoarsestLevelSolverChoice(
+ const std::string& choice) {
+#ifdef DEBUG_CHECK_ASSERTIONS
+#ifndef HAVE_HYPRE
+ if (choice == "hypre") {
+ TBOX_ERROR(d_object_name << ": HYPRe library is not available.\n");
+ }
+#endif
+#endif
+ if (choice == "redblack"
+ || choice == "hypre") {
+ d_coarse_solver_choice = choice;
+ } else {
+ TBOX_ERROR(
+ d_object_name << ": Bad coarse level solver choice '"
+ << choice
+ <<
+ "' in scapCellStokesOpsX::setCoarseLevelSolver.");
+ }
+}
+
+/*
+ ********************************************************************
+ * Set the tolerance for the coarse level solver. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setCoarsestLevelSolverTolerance(
+ double tol) {
+ d_coarse_solver_tolerance = tol;
+}
+
+/*
+ ********************************************************************
+ * Set the tolerance for the coarse level solver. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setCoarsestLevelSolverMaxIterations(
+ int max_iterations) {
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (max_iterations < 0) {
+ TBOX_ERROR(d_object_name << ": Invalid number of max iterations\n");
+ }
+#endif
+ d_coarse_solver_max_iterations = max_iterations;
+}
+
+/*
+ ********************************************************************
+ * Set the coarse-fine discretization method. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setCoarseFineDiscretization(
+ const std::string& coarsefine_method) {
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (d_hierarchy) {
+ TBOX_ERROR(
+ d_object_name << ": Cannot change coarse-fine\n"
+ <<
+ "discretization method while operator state\n"
+ << "is initialized because that causes a\n"
+ << "corruption in the state.\n");
+ }
+#endif
+ d_cf_discretization = coarsefine_method;
+}
+
+/*
+ ********************************************************************
+ * Set the prolongation method *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACOps::setProlongationMethod(
+ const std::string& prolongation_method) {
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (d_hierarchy) {
+ TBOX_ERROR(
+ d_object_name << ": Cannot change prolongation method\n"
+ <<
+ "while operator state is initialized because that\n"
+ << "causes a corruption in the state.\n");
+ }
+#endif
+ d_prolongation_method = prolongation_method;
+}
+
+}
+}
diff -r a44a82f15794 -r fe2a9230921b StokesFACOps.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesFACOps.h Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,1044 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: Operator class for cell-centered scalar Stokes using FAC
+ *
+ ************************************************************************/
+#ifndef included_solv_StokesFACOps
+#define included_solv_StokesFACOps
+
+#include "SAMRAI/SAMRAI_config.h"
+
+#include "SAMRAI/solv/CartesianRobinBcHelper.h"
+#include "SAMRAI/solv/FACPreconditioner.h"
+#include "SAMRAI/solv/FACOperatorStrategy.h"
+#include "SAMRAI/solv/RobinBcCoefStrategy.h"
+#include "StokesHypreSolver.h"
+#include "SAMRAI/solv/SAMRAIVectorReal.h"
+#include "StokesSpecifications.h"
+#include "SAMRAI/math/HierarchyCellDataOpsReal.h"
+#include "SAMRAI/math/HierarchySideDataOpsReal.h"
+#include "SAMRAI/pdat/CellData.h"
+#include "SAMRAI/pdat/CellVariable.h"
+#include "SAMRAI/pdat/CellDoubleConstantRefine.h"
+#include "SAMRAI/pdat/OutersideData.h"
+#include "SAMRAI/pdat/OutersideVariable.h"
+#include "SAMRAI/pdat/SideData.h"
+#include "SAMRAI/pdat/SideVariable.h"
+#include "SAMRAI/xfer/CoarsenSchedule.h"
+#include "SAMRAI/xfer/RefineSchedule.h"
+#include "SAMRAI/xfer/CoarsenAlgorithm.h"
+#include "SAMRAI/xfer/CoarsenOperator.h"
+#include "SAMRAI/xfer/RefineAlgorithm.h"
+#include "SAMRAI/xfer/RefineOperator.h"
+#include "SAMRAI/hier/CoarseFineBoundary.h"
+#include "SAMRAI/hier/Patch.h"
+#include "SAMRAI/hier/PatchHierarchy.h"
+#include "SAMRAI/hier/PatchLevel.h"
+#include "SAMRAI/hier/IntVector.h"
+#include "SAMRAI/hier/Box.h"
+#include "SAMRAI/hier/VariableContext.h"
+#include "SAMRAI/tbox/Database.h"
+#include "SAMRAI/tbox/Pointer.h"
+#include "SAMRAI/tbox/Timer.h"
+
+#include <string>
+
+namespace SAMRAI {
+namespace solv {
+
+/*!
+ * @brief FAC operator class to solve Stokes's equation on a SAMR grid,
+ * using cell-centered, second-order finite-volume method, with Robin
+ * boundary conditions.
+ *
+ * This class provides operators that are used by the FAC
+ * preconditioner FACPreconditioner.
+ * It is used to solve the scalar Stokes's equation using a cell-centered
+ * second-order finite-volume discretization.
+ * It is designed to provide all operations specific to
+ * the scalar Stokes's equation,
+ * @f[ \nabla \cdot D \nabla u + C u = f @f]
+ * (see StokesSpecifications) where
+ * - C, D and f are indpendent of u
+ * - C is a cell-centered scalar field
+ * - D is the @em diffusion @em coefficients, stored on faces
+ * - f is a cell-centered scalar function
+ *
+ * You are left to provide the source function, initial guess, etc.,
+ * by specifying them in specific forms.
+ *
+ * This class provides:
+ * -# 5-point (second order), cell-centered stencil operations
+ * for the discrete Laplacian.
+ * -# Red-black Gauss-Seidel smoothing.
+ * -# Provisions for working Robin boundary conditions
+ * (see RobinBcCoefStrategy).
+ *
+ * This class is meant to provide the Stokes-specific operator
+ * used by the FAC preconditioner, FACPreconditioner.
+ * To use the preconditioner with this class, you will have to provide:
+ * -# The solution vector SAMRAIVectorReal,
+ * with appropriate norm weighting for the cell-centered AMR mesh.
+ * This class provides the function computeVectorWeights()
+ * to help with computing the appropriate weights.
+ * Since this is for a scalar equation, only the first depth
+ * of the first component of the vectors are used.
+ * All other parts are ignored.
+ * -# The source vector SAMRAIVectorReal for f.
+ * -# A StokesSpecifications objects to specify
+ * the cell-centered scalar field C and the side-centered
+ * diffusion coefficients D
+ * -# The boundary condition specifications in terms of the coefficients
+ * @f$ \alpha @f$, @f$ \beta @f$ and @f$ \gamma @f$ in the
+ * Robin formula @f$ \alpha u + \beta u_n = \gamma @f$ applied on the
+ * boundary faces. See RobinBcCoefStrategy.
+ *
+ * This class allocates and deallocates only its own scratch data.
+ * Other data that it manipuates are passed in as function arguments.
+ * Hence, it owns none of the solution vectors, error vectors,
+ * diffusion coefficient data, or any such things.
+ *
+ * Input Examples
+ * @verbatim
+ * coarse_solver_choice = "hypre" // see setCoarsestLevelSolverChoice()
+ * coarse_solver_tolerance = 1e-14 // see setCoarsestLevelSolverTolerance()
+ * coarse_solver_max_iterations = 10 // see setCoarsestLevelSolverMaxIterations()
+ * smoothing_choice = "redblack" // see setSmoothingChoice()
+ * cf_discretization = "Ewing" // see setCoarseFineDiscretization()
+ * prolongation_method = "LINEAR_REFINE" // see setProlongationMethod()
+ * hypre_solver = { ... } // tbox::Database for initializing Hypre solver
+ * @endverbatim
+ */
+class CellStokesFACOps:
+ public FACOperatorStrategy
+{
+
+public:
+ /*!
+ * @brief Constructor.
+ *
+ * If you want standard output and logging,
+ * pass in valid pointers for those streams.
+ * @param object_name Ojbect name
+ * @param database Input database
+ */
+ CellStokesFACOps(
+ const tbox::Dimension& dim,
+ const std::string& object_name = std::string(),
+ tbox::Pointer<tbox::Database> database =
+ tbox::Pointer<tbox::Database>(NULL));
+
+ /*!
+ * @brief Destructor.
+ *
+ * Deallocate internal data.
+ */
+ ~CellStokesFACOps(
+ void);
+
+ /*!
+ * @brief Set the scalar Stokes equation specifications.
+ */
+ void
+ setStokesSpecifications(
+ const StokesSpecifications& spec);
+
+ /*!
+ * @brief Enable logging.
+ *
+ * By default, logging is disabled. The logging flag is
+ * propagated to the major components used by this class.
+ */
+ void
+ enableLogging(
+ bool enable_logging);
+
+ //@{
+ /*!
+ * @name Functions for setting solver mathematic algorithm controls
+ */
+
+ /*!
+ * @brief Set the choice of smoothing algorithms.
+ *
+ * Current smoothing choices are:
+ * - "redblack": Red-black Gauss-Seidel smoothing.
+ */
+ void
+ setSmoothingChoice(
+ const std::string& smoothing_choice);
+
+ /*!
+ * @brief Set coarse level solver.
+ *
+ * Select from these:
+ * - @c "redblack" (red-black smoothing until convergence--very slow!)
+ * - @c "hypre" (only if the HYPRE library is available).
+ */
+ void
+ setCoarsestLevelSolverChoice(
+ const std::string& choice);
+
+ /*!
+ * @brief Set tolerance for coarse level solve.
+ *
+ * If the coarse level solver requires a tolerance (currently, they all do),
+ * the specified value is used.
+ */
+ void
+ setCoarsestLevelSolverTolerance(
+ double tol);
+
+ /*!
+ * @brief Set max iterations for coarse level solve.
+ *
+ * If the coarse level solver requires a max iteration limit
+ * (currently, they all do), the specified value is used.
+ */
+ void
+ setCoarsestLevelSolverMaxIterations(
+ int max_iterations);
+
+ /*!
+ * @brief Set the coarse-fine boundary discretization method.
+ *
+ * Specify the @c op_name std::string which will be passed to
+ * xfer::Geometry::lookupRefineOperator() to get the operator
+ * for setting fine grid ghost cells from the coarse grid.
+ * Note that chosing this operator implicitly choses the
+ * discretization method at the coarse-fine boundary.
+ *
+ * There is one important instance where this std::string is
+ * @em not passed to xfer::Geometry::lookupRefineOperator.
+ * If this variable is set to "Ewing", Ewing's coarse-fine
+ * discretization is used (a constant refinement is performed,
+ * and the flux is later corrected to result in Ewing's scheme).
+ * For a reference to Ewing's discretization method, see
+ * "Local Refinement Techniques for Elliptic Problems on Cell-Centered
+ * Grids, I. Error Analysis", Mathematics of Computation, Vol. 56, No. 194,
+ * April 1991, pp. 437-461.
+ *
+ * @param coarsefine_method String selecting the coarse-fine discretization method.
+ */
+ void
+ setCoarseFineDiscretization(
+ const std::string& coarsefine_method);
+
+ /*!
+ * @brief Set the name of the prolongation method.
+ *
+ * Specify the @c op_name std::string which will be passed to
+ * xfer::Geometry::lookupRefineOperator() to get the operator
+ * for prolonging the coarse-grid correction.
+ *
+ * By default, "CONSTANT_REFINE" is used. "LINEAR_REFINE" seems to
+ * to lead to faster convergence, but it does NOT satisfy the Galerkin
+ * condition.
+ *
+ * Prolonging using linear refinement requires a Robin bc
+ * coefficient implementation that is capable of delivering
+ * coefficients for non-hierarchy data, because linear refinement
+ * requires boundary conditions to be set on temporary levels.
+ *
+ * @param prolongation_method String selecting the coarse-fine
+ * discretization method.
+ */
+ void
+ setProlongationMethod(
+ const std::string& prolongation_method);
+
+#ifdef HAVE_HYPRE
+ /*!
+ * @brief Set whether to use Hypre's PFMG algorithm instead of the
+ * SMG algorithm.
+ *
+ * This flag affects the Hypre solver (used to solve the coarsest level).
+ * The flag is used to select which of HYPRE's linear solver algorithms
+ * to use if true, the semicoarsening multigrid algorithm is used, and if
+ * false, the ``PF'' multigrid algorithm is used.
+ * By default, the SMG algorithm is used.
+ *
+ * This setting has effect only when Hypre is chosen for the coarsest
+ * level solver. See setCoarsestLevelSolverChoice().
+ *
+ * Changing the algorithm must be done before initializing the solver
+ * state and must NOT be done while the state is initialized
+ * (the program will exit), as that would corrupt the state.
+ */
+ void
+ setUseSMG(
+ bool use_smg);
+#endif
+
+ //@}
+
+ //@{
+ /*!
+ * @name Functions for setting patch data indices and coefficients
+ */
+
+ /*!
+ * @brief Set the scratch patch data index for the flux.
+ *
+ * The use of this function is optional.
+ * The patch data index should be a pdat::SideData<DIM> type of variable.
+ * If the flux id is -1 (the default initial value), scratch space
+ * for the flux is allocated as needed and immediately deallocated
+ * afterward, level by level. If you have space preallocated for
+ * flux and you would like that to be used, set flux id to the
+ * patch data index of that space.
+ */
+ void
+ setFluxId(
+ int flux_id);
+
+ //@}
+
+ /*!
+ * @brief Provide an implementation for getting the
+ * physical bc coefficients
+ *
+ * If your solution is fixed at the physical boundary
+ * ghost cell centers AND those cells have the correct
+ * values before entering solveSystem(), you may use a
+ * GhostCellRobinBcCoefs object.
+ *
+ * If your solution is @b not fixed at the ghost cell centers,
+ * the ghost cell values will change as the interior
+ * cell values change. In those cases, the flexible
+ * Robin boundary conditions are applied. You must
+ * call this function to provide the implementation for
+ * determining the boundary condition coefficients.
+ *
+ * @param physical_bc_coef tbox::Pointer to an object that can
+ * set the Robin bc coefficients.
+ */
+ void
+ setPhysicalBcCoefObject(
+ const RobinBcCoefStrategy* physical_bc_coef);
+
+ //@{
+
+ /*!
+ * @name Functions for checking validity and correctness of state.
+ */
+
+ /*!
+ * @brief Check validity and correctness of input patch data indices.
+ *
+ * Descriptors checked:
+ * -# Diffusion coefficient (see setDiffcoefId())
+ * -# Flux (see setFluxId())
+ * -# Source (see setScalarFieldId())
+ */
+ void
+ checkInputPatchDataIndices() const;
+
+ //@}
+
+ /*!
+ * @brief Set weight appropriate for computing vector norms.
+ *
+ * If you this function to set the weights used when you
+ * SAMRAIVectorReal::addComponent, you can use the
+ * vector norm functions of SAMRAIVectorReal, and
+ * the weights will be used to blank out coarse grid
+ * regions under fine grids.
+ *
+ * The weights computed are specific to the cell-centered
+ * discretization used by this class. The weight is equal
+ * to the cell volume if the cell has not been refined,
+ * and zero if it has.
+ *
+ * This function is state-independent. All inputs are in
+ * the argument list.
+ *
+ * @param hierarchy Hierarchy configuration to compute weights for
+ * @param weight_id hier::Patch data index of the weight
+ * @param coarsest_ln Coarsest level number. Must be included
+ * in hierarchy. Must not be greater than @c finest_ln.
+ * Default to 0.
+ * @param finest_ln Finest level number. Must be included
+ * in hierarchy. Must not be less than @c coarsest_ln.
+ * Default to finest level in @c hierarchy.
+ */
+ void
+ computeVectorWeights(
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ int weight_id,
+ int coarsest_ln = -1,
+ int finest_ln = -1) const;
+
+ /*!
+ * @brief Set the FAC preconditioner that will be using this object.
+ *
+ * The FAC preconditioner is accessed to get convergence data during
+ * the cycle postprocessing step. It is optional.
+ */
+ void
+ setPreconditioner(
+ const FACPreconditioner* preconditioner);
+
+ /*!
+ * @brief function to compute flux, using general diffusion
+ * coefficient data.
+ *
+ * Recall that this solver class discretizes the PDE
+ * @f[ \nabla \cdot D \nabla u + C u = f @f] on an AMR grid. This member
+ * function allows users of this solver class to compute gradient
+ * terms, @f[ D \nabla w @f], in their code in a manner consistent with the
+ * solver discretization. In particular, when solving PDE systems, it may
+ * be necessary to discretize the gradient operator appearing in equations
+ * not treated by the solver class in the same way as those treated by this
+ * class. These funtions allow users to do this easily. The divergence
+ * operator used in this solver is the standard sum of centered differences
+ * involving flux terms on the cell sides computed by these routines.
+ *
+ * Note that the patch must exist on a level in an AMR hierarchy so that
+ * the discretization can be computed properly at the coarse-fine interface.
+ * Stokes coefficients C and D must exist on the patch, if they are variable.
+ * Also, calling this function does not affect the internal solver state in any
+ * way. However, the solver must be fully initialized before it is called and care
+ * should be exercised to pass arguments so that the solver solution quantity and
+ * other internal solver quantities are not adversely affected.
+ *
+ * @param patch patch on which computation will take place
+ * @param ratio_to_coarser_level refinement ratio from coarser level to level
+ * on which patch lives; if current patch level
+ * is level zero, this is ignored
+ * @param w_data cell-centered data
+ * @param Dgradw_data side-centered flux data (i.e., D (grad w))
+ */
+ void
+ computeFluxOnPatch(
+ const hier::Patch& patch,
+ const hier::IntVector& ratio_to_coarser_level,
+ const pdat::CellData<double>& w_data,
+ pdat::SideData<double>& Dgradw_data) const;
+
+ //@{ @name FACOperatorStrategy virtuals
+
+ virtual void
+ restrictSolution(
+ const SAMRAIVectorReal<double>& source,
+ SAMRAIVectorReal<double>& dest,
+ int dest_ln);
+ virtual void
+ restrictResidual(
+ const SAMRAIVectorReal<double>& source,
+ SAMRAIVectorReal<double>& dest,
+ int dest_ln);
+
+ virtual void
+ prolongErrorAndCorrect(
+ const SAMRAIVectorReal<double>& source,
+ SAMRAIVectorReal<double>& dest,
+ int dest_ln);
+
+ virtual void
+ smoothError(
+ SAMRAIVectorReal<double>& error,
+ const SAMRAIVectorReal<double>& residual,
+ int ln,
+ int num_sweeps);
+
+ virtual int
+ solveCoarsestLevel(
+ SAMRAIVectorReal<double>& error,
+ const SAMRAIVectorReal<double>& residual,
+ int coarsest_ln);
+
+ virtual void
+ computeCompositeResidualOnLevel(
+ SAMRAIVectorReal<double>& residual,
+ const SAMRAIVectorReal<double>& solution,
+ const SAMRAIVectorReal<double>& rhs,
+ int ln,
+ bool error_equation_indicator);
+
+ virtual double
+ computeResidualNorm(
+ const SAMRAIVectorReal<double>& residual,
+ int fine_ln,
+ int coarse_ln);
+
+ virtual void
+ initializeOperatorState(
+ const SAMRAIVectorReal<double>& solution,
+ const SAMRAIVectorReal<double>& rhs);
+
+ virtual void
+ deallocateOperatorState();
+
+ virtual void
+ postprocessOneCycle(
+ int fac_cycle_num,
+ const SAMRAIVectorReal<double>& current_soln,
+ const SAMRAIVectorReal<double>& residual);
+
+ //@}
+
+private:
+ //@{
+ /*!
+ * @name Private workhorse functions.
+ */
+
+ /*!
+ * @brief Red-black Gauss-Seidel error smoothing on a level.
+ *
+ * Smoothes on the residual equation @f$ Ae=r @f$ on a level.
+ *
+ * @param error error vector
+ * @param residual residual vector
+ * @param ln level number
+ * @param num_sweeps number of sweeps
+ * @param residual_tolerance the maximum residual considered to be
+ * converged
+ */
+ void
+ smoothErrorByRedBlack(
+ SAMRAIVectorReal<double>& error,
+ const SAMRAIVectorReal<double>& residual,
+ int ln,
+ int num_sweeps,
+ double residual_tolerance = -1.0);
+
+ /*!
+ * @brief Solve the coarsest level using HYPRE
+ */
+ int
+ solveCoarsestLevel_HYPRE(
+ SAMRAIVectorReal<double>& error,
+ const SAMRAIVectorReal<double>& residual,
+ int ln);
+
+ /*!
+ * @brief Fix flux per Ewing's coarse-fine boundary treatment.
+ *
+ * Ewing's coarse-fine boundary treatment can be implemented
+ * using a constant refinement into the fine-grid ghost boundary,
+ * naively computing the flux using the constant-refined data then
+ * fixing up the flux to correct the error.
+ *
+ * To use this function
+ * -# you must use constant refinement to fill the fine level ghost cells
+ * -# the flux must first be computed and stored
+ *
+ * @param patch patch
+ * @param soln_data cell-centered solution data
+ * @param flux_data side-centered flux data
+ * @param diffcoef_data side-centered diffusion coefficient data
+ * @param cfb coarse-fine boundary object for the level
+ * in which patch resides
+ * @param ratio_to_coarser Refinement ratio to the next coarser level.
+ */
+ void
+ ewingFixFlux(
+ const hier::Patch& patch,
+ const pdat::CellData<double>& soln_data,
+ pdat::SideData<double>& flux_data,
+ const hier::IntVector& ratio_to_coarser) const;
+
+ /*!
+ * @brief AMR-unaware function to compute residual on a single patch,
+ * with variable scalar field.
+ *
+ * @param patch patch
+ * @param flux_data side-centered flux data
+ * @param soln_data cell-centered solution data
+ * @param rhs_data cell-centered rhs data
+ * @param residual_data cell-centered residual data
+ */
+ void
+ computeResidualOnPatch(
+ const hier::Patch& patch,
+ const pdat::SideData<double>& flux_data,
+ const pdat::CellData<double>& soln_data,
+ const pdat::CellData<double>& rhs_data,
+ pdat::CellData<double>& residual_data) const;
+
+ /*!
+ * @brief AMR-unaware function to red or black smoothing on a single patch,
+ * for variable diffusion coefficient and variable scalar field.
+ *
+ * @param patch patch
+ * @param flux_data side-centered flux data
+ * @param rhs_data cell-centered rhs data
+ * @param scalar_field_data
+ * cell-centered scalar field data
+ * @param soln_data cell-centered solution data
+ * @param red_or_black red-black switch. Set to 'r' or 'b'.
+ * @param p_maxres max residual output. Set to NULL to avoid computing.
+ */
+ void
+ redOrBlackSmoothingOnPatch(
+ const hier::Patch& patch,
+ const pdat::SideData<double>& flux_data,
+ const pdat::CellData<double>& rhs_data,
+ pdat::CellData<double>& soln_data,
+ char red_or_black,
+ double* p_maxres = NULL) const;
+
+ //@}
+
+ //@{ @name For executing, caching and resetting communication schedules.
+
+ /*!
+ * @brief Execute a refinement schedule
+ * for prolonging cell data.
+ *
+ * General notes regarding internal objects for communication:
+ * We maintain objects to support caching schedules to improve
+ * efficiency. Communication is needed in 5 distinct tasks.
+ * -# Prolongation
+ * -# Restriction
+ * -# Flux coarsening. Changing the coarse grid flux to the
+ * composite grid flux by coarsening the fine grid flux
+ * at the coarse-fine boundaries.
+ * -# Fill boundary data from other patches in the same level
+ * and physical boundary condition.
+ * -# Fill boundary data from same level, coarser levels
+ * and physical boundary condition.
+ *
+ * For each task, we maintain a refine or coarsen operator,
+ * and a array of communication schedules (one for each
+ * destination level).
+ *
+ * The 5 member functions named @c xeqSchedule... execute
+ * communication schedules appropriate for five specific tasks.
+ * They use a cached schedule if possible or create and cache
+ * a new schedule if needed. These functions and the data
+ * they manipulate are as follows:
+ * <ol>
+ * <li> xeqScheduleProlongation():
+ * d_prolongation_refine_operator
+ * d_prolongation_refine_schedules
+ * <li> xeqScheduleURestriction():
+ * d_restriction_coarsen_operator,
+ * d_urestriction_coarsen_schedules.
+ * <li> xeqScheduleRRestriction():
+ * d_restriction_coarsen_operator,
+ * d_rrestriction_coarsen_schedules.
+ * <li> xeqScheduleFluxCoarsen():
+ * d_flux_coarsen_operator,
+ * d_flux_coarsen_schedules.
+ * <li> xeqScheduleGhostFill():
+ * d_ghostfill_refine_operator,
+ * d_ghostfill_refine_schedules.
+ * <li> xeqScheduleGhostFillNoCoarse():
+ * d_ghostfill_nocoarse_refine_operator,
+ * d_ghostfill_nocoarse_refine_schedules.
+ * </ol>
+ *
+ * @return refinement schedule for prolongation
+ */
+ void
+ xeqScheduleProlongation(
+ int dst_id,
+ int src_id,
+ int scr_id,
+ int dest_ln);
+
+ /*!
+ * @brief Execute schedule for restricting solution to the specified
+ * level or reregister an existing one.
+ *
+ * See general notes for xeqScheduleProlongation().
+ *
+ * @return coarsening schedule for restriction
+ */
+ void
+ xeqScheduleURestriction(
+ int dst_id,
+ int src_id,
+ int dest_ln);
+
+ /*!
+ * @brief Execute schedule for restricting residual to the specified
+ * level or reregister an existing one.
+ *
+ * See general notes for xeqScheduleProlongation().
+ *
+ * @return coarsening schedule for restriction
+ */
+ void
+ xeqScheduleRRestriction(
+ int dst_id,
+ int src_id,
+ int dest_ln);
+
+ /*!
+ * @brief Execute schedule for coarsening flux to the specified
+ * level or reregister an existing one.
+ *
+ * See general notes for xeqScheduleProlongation().
+ *
+ * @return coarsening schedule for setting composite grid flux at
+ * coarse-fine boundaries.
+ */
+ void
+ xeqScheduleFluxCoarsen(
+ int dst_id,
+ int src_id,
+ int dest_ln);
+
+ /*!
+ * @brief Execute schedule for filling ghosts on the specified
+ * level or reregister an existing one.
+ *
+ * See general notes for xeqScheduleProlongation().
+ *
+ * @return refine schedule for filling ghost data from coarser level
+ * and physical bc.
+ */
+ void
+ xeqScheduleGhostFill(
+ int dst_id,
+ int dest_ln);
+
+ /*!
+ * @brief Execute schedule for filling ghosts on the specified
+ * level or reregister an existing one.
+ * This version does not get data from coarser levels.
+ *
+ * See general notes for xeqScheduleProlongation().
+ *
+ * This function is used for the bottom solve level, since it does
+ * not access data from any coarser level. (Ghost data obtained
+ * from coarser level must have been placed there before solve begins!)
+ *
+ * @return refine schedule for filling ghost data from same level
+ * and physical bc.
+ */
+ void
+ xeqScheduleGhostFillNoCoarse(
+ int dst_id,
+ int dest_ln);
+
+ //@}
+
+ //! @brief Return the patch data index for cell scratch data.
+ int
+ registerCellScratch() const;
+ //! @brief Return the patch data index for flux scratch data.
+ int
+ registerFluxScratch() const;
+ //! @brief Return the patch data index for outerflux scratch data.
+ int
+ registerOfluxScratch() const;
+
+ //! @brief Free static variables at shutdown time.
+ static void
+ finalizeCallback();
+
+ /*!
+ * @brief Object dimension.
+ */
+ const tbox::Dimension d_dim;
+
+ /*!
+ * @brief Object name.
+ */
+ std::string d_object_name;
+
+ //@{ @name Hierarchy-dependent objects.
+
+ /*!
+ * @brief Reference hierarchy
+ *
+ * This variable is non-null between the initializeOperatorState()
+ * and deallocateOperatorState() calls. It is not truly needed,
+ * because the hierarchy is obtainable through variables in most
+ * function argument lists. We use it to enforce working on one
+ * hierarchy at a time.
+ */
+ tbox::Pointer<hier::PatchHierarchy> d_hierarchy;
+
+ /*!
+ * @brief Coarsest level for solve.
+ */
+ int d_ln_min;
+
+ /*!
+ * @brief Finest level for solve.
+ */
+ int d_ln_max;
+
+ /*!
+ * @brief Description of coarse-fine boundaries.
+ *
+ * There is one coarse-fine boundary object for each level.
+ * d_coarse_fine_boundary[i] is the description of
+ * the coarse-fine boundary between level i and level i-1.
+ * The coarse-fine boundary does not exist at the coarsest level,
+ * although the hier::CoarseFineBoundary object still exists (it
+ * should not contain any boxes).
+ *
+ * This array is initialized in initializeOperatorState() and
+ * deallocated in deallocateOperatorState(). When allocated,
+ * it is allocated for the index range [0,d_ln_max], though
+ * the range [0,d_ln_min-1] is not used. This is okay because
+ * hier::CoarseFineBoundary is a light object before
+ * it is set for a level.
+ */
+ tbox::Array<tbox::Pointer<hier::CoarseFineBoundary> > d_cf_boundary;
+
+ //@}
+
+ //@{
+ /*!
+ * @name Private state variables for solution process.
+ */
+
+ /*!
+ * @brief Scalar Stokes equations specifications.
+ * @see setStokesSpecifications().
+ */
+ StokesSpecifications d_stokes_spec;
+
+ /*!
+ * @brief Smoothing choice.
+ * @see setSmoothingChoice.
+ */
+ std::string d_smoothing_choice;
+
+ /*!
+ * @brief Coarse level solver.
+ * @see setCoarsestLevelSolverChoice
+ */
+ std::string d_coarse_solver_choice;
+
+ /*!
+ * @brief Coarse-fine discretization method.
+ * @see setCoarseFineDiscretization().
+ */
+ std::string d_cf_discretization;
+
+ /*!
+ * @brief Coarse-fine discretization method.
+ *
+ * The name of the refinement operator used to prolong the
+ * coarse grid correction.
+ *
+ * @see setProlongationMethod()
+ */
+ std::string d_prolongation_method;
+
+ /*!
+ * @brief Tolerance specified to coarse solver
+ * @see setCoarsestLevelSolverTolerance()
+ */
+ double d_coarse_solver_tolerance;
+
+ /*!
+ * @brief Coarse level solver iteration limit.
+ * @see setCoarsestLevelSolverMaxIterations()
+ */
+ int d_coarse_solver_max_iterations;
+
+ /*!
+ * @brief Residual tolerance to govern smoothing.
+ *
+ * When we use one of the internal error smoothing functions
+ * and want to terminate the smoothing sweeps at a certain
+ * level of residual, this will be set to > 0. If it is
+ * < 0, the smoothing function effectively ignores it.
+ *
+ * This variable is needed because some coarse-level solver
+ * simply runs the smoothing function until convergence.
+ * It sets this variable to > 0, calls the smoothing function,
+ * then resets it to < 0.
+ */
+ double d_residual_tolerance_during_smoothing;
+
+ /*!
+ * @brief Id of the flux.
+ *
+ * If set to -1, create and delete storage space on the fly.
+ * Else, user has provided space for flux.
+ *
+ * @see setFluxId
+ */
+ int d_flux_id;
+
+#ifdef HAVE_HYPRE
+ /*!
+ * @brief HYPRE coarse-level solver object.
+ */
+ CellStokesHypreSolver d_hypre_solver;
+#endif
+
+ /*!
+ * @brief Externally provided physical boundary condition object.
+ *
+ * see setPhysicalBcCoefObject()
+ */
+ const RobinBcCoefStrategy* d_physical_bc_coef;
+
+ //@}
+
+ //@{ @name Internal context and scratch data
+
+ static tbox::Pointer<pdat::CellVariable<double> >
+ s_cell_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+ static tbox::Pointer<pdat::SideVariable<double> >
+ s_flux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+ static tbox::Pointer<pdat::OutersideVariable<double> >
+ s_oflux_scratch_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+ /*!
+ * @brief Default context of internally maintained hierarchy data.
+ */
+ tbox::Pointer<hier::VariableContext> d_context;
+
+ /*!
+ * @brief ID of the solution-like scratch data.
+ *
+ * Set in constructor and never changed.
+ * Corresponds to a pdat::CellVariable<double> named
+ * @c d_object_name+"::cell_scratch".
+ * Scratch data is allocated and removed as needed
+ * to reduce memory usage.
+ */
+ int d_cell_scratch_id;
+
+ /*!
+ * @brief ID of the side-centered scratch data.
+ *
+ * Set in constructor and never changed.
+ * Corresponds to a pdat::SideVariable<double> named
+ * @c d_object_name+"::flux_scratch".
+ *
+ * This data is allocated only as needed and deallocated
+ * immediately after use.
+ */
+ int d_flux_scratch_id;
+
+ /*!
+ * @brief ID of the outerside-centered scratch data.
+ *
+ * Set in constructor and never changed.
+ * Corresponds to a pdat::OutersideVariable<double> named
+ * @c d_object_name+"::oflux_scratch".
+ */
+ int d_oflux_scratch_id;
+
+ //@}
+
+ //@{
+ /*!
+ * @name Various refine and coarsen objects used internally.
+ */
+
+ //! @brief Error prolongation (refinement) operator.
+ tbox::Pointer<xfer::RefineOperator> d_prolongation_refine_operator;
+ tbox::Pointer<xfer::RefineAlgorithm> d_prolongation_refine_algorithm;
+ tbox::Array<tbox::Pointer<xfer::RefineSchedule> >
+ d_prolongation_refine_schedules;
+
+ //! @brief Solution restriction (coarsening) operator.
+ tbox::Pointer<xfer::CoarsenOperator> d_urestriction_coarsen_operator;
+ tbox::Pointer<xfer::CoarsenAlgorithm> d_urestriction_coarsen_algorithm;
+ tbox::Array<tbox::Pointer<xfer::CoarsenSchedule> >
+ d_urestriction_coarsen_schedules;
+
+ //! @brief Residual restriction (coarsening) operator.
+ tbox::Pointer<xfer::CoarsenOperator> d_rrestriction_coarsen_operator;
+ tbox::Pointer<xfer::CoarsenAlgorithm> d_rrestriction_coarsen_algorithm;
+ tbox::Array<tbox::Pointer<xfer::CoarsenSchedule> >
+ d_rrestriction_coarsen_schedules;
+
+ //! @brief Coarsen operator for outerflux-to-flux
+ tbox::Pointer<xfer::CoarsenOperator> d_flux_coarsen_operator;
+ tbox::Pointer<xfer::CoarsenAlgorithm> d_flux_coarsen_algorithm;
+ tbox::Array<tbox::Pointer<xfer::CoarsenSchedule> >
+ d_flux_coarsen_schedules;
+
+ //! @brief Refine operator for cell-like data from coarser level.
+ tbox::Pointer<xfer::RefineOperator> d_ghostfill_refine_operator;
+ tbox::Pointer<xfer::RefineAlgorithm> d_ghostfill_refine_algorithm;
+ tbox::Array<tbox::Pointer<xfer::RefineSchedule> >
+ d_ghostfill_refine_schedules;
+
+ //! @brief Refine operator for cell-like data from same level.
+ tbox::Pointer<xfer::RefineOperator> d_ghostfill_nocoarse_refine_operator;
+ tbox::Pointer<xfer::RefineAlgorithm> d_ghostfill_nocoarse_refine_algorithm;
+ tbox::Array<tbox::Pointer<xfer::RefineSchedule> >
+ d_ghostfill_nocoarse_refine_schedules;
+
+ //@}
+
+ /*!
+ * @brief Utility object employed in setting ghost cells and providing
+ * xfer::RefinePatchStrategy implementation.
+ *
+ * Since this class deals only in scalar variables having
+ * Robin boundary conditions, we take advantage of the corresponding
+ * implementation in CartesianRobinBcHelper. Whenever
+ * we need an implementation of xfer::RefinePatchStrategy,
+ * this object is used. Note that in the code, before we
+ * use this object to set ghost cell values, directly or
+ * indirectly by calling xfer::RefineSchedule::fillData(),
+ * we must tell d_bc_helper the patch data index we want
+ * to set and whether we are setting data with homogeneous
+ * boundary condition.
+ */
+ CartesianRobinBcHelper d_bc_helper;
+
+ //@{
+ /*!
+ * @name Non-essential objects used in outputs and debugging.
+ */
+
+ /*!
+ * @brief Logging flag.
+ */
+ bool d_enable_logging;
+
+ /*!
+ * @brief Preconditioner using this object.
+ *
+ * See setPreconditioner().
+ */
+ const FACPreconditioner* d_preconditioner;
+
+ /*!
+ * @brief Hierarchy cell operator used in debugging.
+ */
+ tbox::Pointer<math::HierarchyCellDataOpsReal<double> > d_hopscell;
+
+ /*!
+ * @brief Hierarchy side operator used in debugging.
+ */
+ tbox::Pointer<math::HierarchySideDataOpsReal<double> > d_hopsside;
+
+ /*!
+ * @brief Timers for performance measurement.
+ */
+ tbox::Pointer<tbox::Timer> t_restrict_solution;
+ tbox::Pointer<tbox::Timer> t_restrict_residual;
+ tbox::Pointer<tbox::Timer> t_prolong;
+ tbox::Pointer<tbox::Timer> t_smooth_error;
+ tbox::Pointer<tbox::Timer> t_solve_coarsest;
+ tbox::Pointer<tbox::Timer> t_compute_composite_residual;
+ tbox::Pointer<tbox::Timer> t_compute_residual_norm;
+
+ static tbox::StartupShutdownManager::Handler
+ s_finalize_handler;
+};
+
+}
+}
+
+#ifdef SAMRAI_INLINE
+#include "CellStokesFACOps.I"
+#endif
+
+#endif // included_solv_CellStokesFACOps
diff -r a44a82f15794 -r fe2a9230921b StokesFACSolver.C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesFACSolver.C Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,585 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: High-level solver (wrapper) for scalar stokes equation.
+ *
+ ************************************************************************/
+#ifndef included_solv_StokesFACSolver_C
+#define included_solv_StokesFACSolver_C
+
+#include "SAMRAI/pdat/CellVariable.h"
+#include "StokesFACSolver.h"
+#include "SAMRAI/tbox/PIO.h"
+#include "SAMRAI/tbox/Utilities.h"
+#include "SAMRAI/tbox/StartupShutdownManager.h"
+
+#include IOMANIP_HEADER_FILE
+
+#ifndef SAMRAI_INLINE
+#include "StokesFACSolver.I"
+#endif
+
+namespace SAMRAI {
+namespace solv {
+
+/*
+ *************************************************************************
+ * *
+ * Initialize the static data members. *
+ * *
+ *************************************************************************
+ */
+
+bool CellStokesFACSolver::s_initialized = 0;
+int CellStokesFACSolver::s_weight_id[SAMRAI::tbox::Dimension::
+ MAXIMUM_DIMENSION_VALUE];
+int CellStokesFACSolver::s_instance_counter[SAMRAI::tbox::Dimension::
+ MAXIMUM_DIMENSION_VALUE];
+
+/*
+ *************************************************************************
+ * *
+ * Constructor sets uninitialized solver state. *
+ * Set default iteration and convergence parameters. *
+ * *
+ * By default settings: *
+ * - Stokes equation specified has D=1, C=0. *
+ * - State is uninitialized *
+ * - Logging is disabled *
+ * - Context for internal data is set based on object name. *
+ * *
+ *************************************************************************
+ */
+
+CellStokesFACSolver::CellStokesFACSolver(
+ const tbox::Dimension& dim,
+ const std::string& object_name,
+ tbox::Pointer<tbox::Database> database):
+ d_dim(dim),
+ d_object_name(object_name),
+ d_stokes_spec(object_name + "::stokes_spec"),
+ d_fac_ops(d_dim, object_name + "::fac_ops"),
+ d_fac_precond(object_name + "::fac_precond", d_fac_ops),
+ d_bc_object(NULL),
+ d_simple_bc(d_dim, object_name + "::bc"),
+ d_hierarchy(NULL),
+ d_ln_min(-1),
+ d_ln_max(-1),
+ d_context(hier::VariableDatabase::getDatabase()
+ ->getContext(object_name + "::CONTEXT")),
+ d_uv(NULL),
+ d_fv(NULL),
+ d_solver_is_initialized(false),
+ d_enable_logging(false)
+{
+
+ if (!s_initialized) {
+ initializeStatics();
+ }
+
+ setMaxCycles(10);
+ setResidualTolerance(1e-6);
+ setPresmoothingSweeps(1);
+ setPostsmoothingSweeps(1);
+ setCoarseFineDiscretization("Ewing");
+#ifdef HAVE_HYPRE
+ setCoarsestLevelSolverChoice("hypre");
+ setCoarsestLevelSolverTolerance(1e-10);
+ setCoarsestLevelSolverMaxIterations(20);
+ setUseSMG(true);
+#else
+ setCoarsestLevelSolverChoice("redblack");
+ setCoarsestLevelSolverTolerance(1e-8);
+ setCoarsestLevelSolverMaxIterations(500);
+#endif
+
+ /*
+ * Construct integer tag variables and add to variable database. Note that
+ * variables and patch data indices are shared among all instances.
+ * The VariableDatabase holds the variables, once contructed and
+ * registered via the VariableDatabase::registerInternalSAMRAIVariable()
+ * function call. Note that variables are registered and patch data indices
+ * are made only for the first time through the constructor.
+ */
+ hier::VariableDatabase* var_db = hier::VariableDatabase::getDatabase();
+
+ static std::string weight_variable_name("CellStokesFACSolver_weight");
+
+ tbox::Pointer<pdat::CellVariable<double> > weight = var_db->getVariable(
+ weight_variable_name);
+ if (weight.isNull()) {
+ weight = new pdat::CellVariable<double>(d_dim, weight_variable_name, 1);
+ }
+
+ if (s_weight_id[d_dim.getValue() - 1] < 0) {
+ s_weight_id[d_dim.getValue() - 1] = var_db->registerInternalSAMRAIVariable(
+ weight,
+ hier::IntVector::getZero(d_dim));
+ }
+
+ /*
+ * The default RobinBcCoefStrategy used,
+ * SimpleCellRobinBcCoefs only works with constant refine
+ * for prolongation. So we use constant refinement
+ * for prolongation by default.
+ */
+ setProlongationMethod("CONSTANT_REFINE");
+
+ /*
+ * The FAC operator optionally uses the preconditioner
+ * to get data for logging.
+ */
+ d_fac_ops.setPreconditioner((const FACPreconditioner *)(&d_fac_precond));
+
+ if (database) {
+ getFromInput(database);
+ }
+
+ s_instance_counter[d_dim.getValue() - 1]++;
+}
+
+/*
+ *************************************************************************
+ * *
+ * Destructor for CellStokesFACSolver. *
+ * Deallocate internal data. *
+ * *
+ *************************************************************************
+ */
+
+CellStokesFACSolver::~CellStokesFACSolver()
+{
+ s_instance_counter[d_dim.getValue() - 1]--;
+
+ deallocateSolverState();
+
+ if (s_instance_counter[d_dim.getValue() - 1] == 0) {
+ hier::VariableDatabase::getDatabase()->
+ removeInternalSAMRAIVariablePatchDataIndex(s_weight_id[d_dim.getValue() - 1]);
+ s_weight_id[d_dim.getValue() - 1] = -1;
+ }
+}
+
+/*
+ ********************************************************************
+ * Set state from database *
+ * *
+ * Do not allow FAC preconditioner and Stokes FAC operators to be *
+ * set from database, as that may cause them to be inconsistent *
+ * with this object if user does not coordinate the inputs *
+ * correctly. This is also why we don't allow direct access to *
+ * those objects. The responsibility for maintaining consistency *
+ * lies in the public functions to set parameters, so use them *
+ * instead of setting the parameters directly in this function. *
+ ********************************************************************
+ */
+
+void CellStokesFACSolver::getFromInput(
+ tbox::Pointer<tbox::Database> database)
+{
+ if (database) {
+ if (database->isBool("enable_logging")) {
+ bool logging = database->getBool("enable_logging");
+ enableLogging(logging);
+ }
+ if (database->isInteger("max_cycles")) {
+ int max_cycles = database->getInteger("max_cycles");
+ setMaxCycles(max_cycles);
+ }
+ if (database->isDouble("residual_tol")) {
+ double residual_tol = database->getDouble("residual_tol");
+ setResidualTolerance(residual_tol);
+ }
+ if (database->isInteger("num_pre_sweeps")) {
+ int num_pre_sweeps = database->getInteger("num_pre_sweeps");
+ setPresmoothingSweeps(num_pre_sweeps);
+ }
+ if (database->isInteger("num_post_sweeps")) {
+ int num_post_sweeps = database->getInteger("num_post_sweeps");
+ setPostsmoothingSweeps(num_post_sweeps);
+ }
+ if (database->isString("coarse_fine_discretization")) {
+ std::string s = database->getString("coarse_fine_discretization");
+ setCoarseFineDiscretization(s);
+ }
+ if (database->isString("prolongation_method")) {
+ std::string s = database->getString("prolongation_method");
+ setProlongationMethod(s);
+ }
+ if (database->isString("coarse_solver_choice")) {
+ std::string s = database->getString("coarse_solver_choice");
+ setCoarsestLevelSolverChoice(s);
+ }
+ if (database->isDouble("coarse_solver_tolerance")) {
+ double tol = database->getDouble("coarse_solver_tolerance");
+ setCoarsestLevelSolverTolerance(tol);
+ }
+ if (database->isInteger("coarse_solver_max_iterations")) {
+ int itr = database->getInteger("coarse_solver_max_iterations");
+ setCoarsestLevelSolverMaxIterations(itr);
+ }
+#ifdef HAVE_HYPRE
+ if (database->isBool("use_smg")) {
+ bool smg = database->getBool("use_smg");
+ setUseSMG(smg);
+ }
+#endif
+ }
+}
+
+/*
+ *************************************************************************
+ * *
+ * Prepare internal data for solve. *
+ * Allocate scratch data. Create vectors for u and f *
+ * required by the FACPreconditioner interface. *
+ * Set up internal boundary condition object. *
+ * Share data to coordinate with FAC preconditioner and *
+ * Stokes FAC operator. *
+ * *
+ *************************************************************************
+ */
+
+void CellStokesFACSolver::initializeSolverState(
+ const int solution,
+ const int rhs,
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ const int coarse_level,
+ const int fine_level)
+{
+ TBOX_ASSERT(!hierarchy.isNull());
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
+
+ if (d_bc_object == NULL) {
+ TBOX_ERROR(
+ d_object_name << ": No BC coefficient strategy object!\n"
+ <<
+ "Use either setBoundaries or setPhysicalBcCoefObject\n"
+ << "to specify the boundary conidition.\n");
+ }
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (solution < 0 || rhs < 0) {
+ TBOX_ERROR(d_object_name << ": Bad patch data id.\n");
+ }
+#endif
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (!hierarchy) {
+ TBOX_ERROR(d_object_name << ": NULL hierarchy pointer not allowed\n"
+ << "in inititialization.");
+ }
+#endif
+ d_hierarchy = hierarchy;
+
+ d_ln_min = coarse_level;
+ d_ln_max = fine_level;
+ if (d_ln_min == -1) {
+ d_ln_min = 0;
+ }
+ if (d_ln_max == -1) {
+ d_ln_max = d_hierarchy->getFinestLevelNumber();
+ }
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (d_ln_min < 0 || d_ln_max < 0 || d_ln_min > d_ln_max) {
+ TBOX_ERROR(d_object_name << ": Bad range of levels in\n"
+ << "inititialization.\n");
+ }
+#endif
+
+ int ln;
+ for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
+ d_hierarchy->getPatchLevel(ln)->allocatePatchData(s_weight_id[d_dim.getValue() - 1]);
+ }
+
+ d_fac_ops.computeVectorWeights(d_hierarchy,
+ s_weight_id[d_dim.getValue() - 1],
+ d_ln_min,
+ d_ln_max);
+
+ if (d_bc_object == &d_simple_bc) {
+ d_simple_bc.setHierarchy(d_hierarchy,
+ d_ln_min,
+ d_ln_max);
+ if (d_stokes_spec.dIsConstant()) {
+ d_simple_bc.setDiffusionCoefConstant(d_stokes_spec.getDConstant());
+ } else {
+ d_simple_bc.setDiffusionCoefId(d_stokes_spec.getDPatchDataId());
+ }
+ }
+
+ d_fac_ops.setStokesSpecifications(d_stokes_spec);
+
+ createVectorWrappers(solution, rhs);
+
+ d_fac_precond.initializeSolverState(*d_uv, *d_fv);
+
+ d_solver_is_initialized = true;
+}
+
+void CellStokesFACSolver::deallocateSolverState()
+{
+ if (d_hierarchy) {
+
+ d_fac_precond.deallocateSolverState();
+
+ /*
+ * Delete internally managed data.
+ */
+ int ln;
+ for (ln = d_ln_min; ln <= d_ln_max; ++ln) {
+ d_hierarchy->getPatchLevel(ln)->deallocatePatchData(s_weight_id[d_dim.getValue()
+ - 1]);
+ }
+
+ d_hierarchy.setNull();
+ d_ln_min = -1;
+ d_ln_max = -1;
+ d_solver_is_initialized = false;
+
+ destroyVectorWrappers();
+
+ }
+}
+
+/*
+ *************************************************************************
+ * Enable logging and propagate logging flag to major components. *
+ *************************************************************************
+ */
+
+void CellStokesFACSolver::enableLogging(
+ bool logging)
+{
+ d_enable_logging = logging;
+ d_fac_precond.enableLogging(d_enable_logging);
+ d_fac_ops.enableLogging(d_enable_logging);
+}
+
+void CellStokesFACSolver::setBoundaries(
+ const std::string& boundary_type,
+ const int fluxes,
+ const int flags,
+ int* bdry_types)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (d_bc_object != NULL && d_bc_object != &d_simple_bc) {
+ TBOX_ERROR(
+ d_object_name << ": Bad attempt to set boundary condition\n"
+ <<
+ "by using default bc object after it has been overriden.\n");
+ }
+#endif
+ d_simple_bc.setBoundaries(boundary_type,
+ fluxes,
+ flags,
+ bdry_types);
+ d_bc_object = &d_simple_bc;
+ d_fac_ops.setPhysicalBcCoefObject(d_bc_object);
+}
+
+void CellStokesFACSolver::setBcObject(
+ const RobinBcCoefStrategy* bc_object)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (!bc_object) {
+ TBOX_ERROR(d_object_name << ": NULL pointer for boundary condition\n"
+ << "object.\n");
+ }
+#endif
+ d_bc_object = bc_object;
+ d_fac_ops.setPhysicalBcCoefObject(d_bc_object);
+}
+
+/*
+ *************************************************************************
+ * *
+ * Solve the linear system and report whether iteration converged. *
+ * *
+ * This version is for an initialized solver state. *
+ * Before solving, set the final piece of the boundary condition, *
+ * which is not known until now, and initialize some internal *
+ * solver quantities. *
+ * *
+ *************************************************************************
+ */
+
+bool CellStokesFACSolver::solveSystem(
+ const int u,
+ const int f)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (!d_solver_is_initialized) {
+ TBOX_ERROR(
+ d_object_name << ".solveSystem(int,int): uninitialized\n"
+ <<
+ "solver state. You must call initializeSolverState()\n"
+ <<
+ "before using this function. Or you can use\n"
+ <<
+ "solveSystem(int,int,...) to initialize the solver,\n"
+ << "solve and deallocate the solver.\n");
+ }
+ if (u < 0 || f < 0) {
+ TBOX_ERROR(d_object_name << ": Bad patch data id.\n");
+ }
+#endif
+ if (d_bc_object == &d_simple_bc) {
+ /*
+ * Knowing that we are using the SimpelCellRobinBcCoefsX
+ * implementation of RobinBcCoefStrategy, we must save
+ * the ghost data in u before solving.
+ * The solver overwrites it, but SimpleCellRobinBcCoefs
+ * needs to get to access it repeatedly.
+ */
+ d_simple_bc.cacheDirichletData(u);
+ }
+
+ createVectorWrappers(u, f);
+ bool solver_rval;
+ solver_rval = d_fac_precond.solveSystem(*d_uv, *d_fv);
+
+ if (d_bc_object == &d_simple_bc) {
+ /*
+ * Restore the Dirichlet cell data that were overwritten by the
+ * solve process. We do this to be backward compatible with the
+ * user code.
+ */
+ d_simple_bc.restoreDirichletData(u);
+ }
+
+ return solver_rval;
+}
+
+/*
+ *************************************************************************
+ * *
+ * Solve the linear system and report whether iteration converged. *
+ * *
+ * This version is for an uninitialized solver state. *
+ * 1. Initialize the (currently uninitialized) solver state. *
+ * 2. Solve. *
+ * 3. Deallocate the solver state. *
+ * *
+ *************************************************************************
+ */
+
+bool CellStokesFACSolver::solveSystem(
+ const int u,
+ const int f,
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ int coarse_ln,
+ int fine_ln)
+{
+ TBOX_ASSERT(!hierarchy.isNull());
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
+
+ if (d_enable_logging) {
+ tbox::plog << "CellStokesFACSolver::solveSystem (" << d_object_name
+ << ")\n";
+ d_stokes_spec.printClassData(tbox::plog);
+ }
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (d_solver_is_initialized) {
+ TBOX_ERROR(
+ d_object_name << ".solveSystem(int,int,...): initialized\n"
+ <<
+ "solver state. This function can only used when the\n"
+ <<
+ "solver state is uninitialized. You should deallocate\n"
+ <<
+ "the solver state or use solveSystem(int,int).\n");
+ }
+ if (!hierarchy) {
+ TBOX_ERROR(d_object_name << ".solveSystem(): Null hierarchy\n"
+ << "specified.\n");
+ }
+#endif
+ initializeSolverState(u, f, hierarchy, coarse_ln, fine_ln);
+
+ bool solver_rval;
+ solver_rval = solveSystem(u, f);
+
+ deallocateSolverState();
+
+ return solver_rval;
+}
+
+void CellStokesFACSolver::createVectorWrappers(
+ int u,
+ int f) {
+
+ hier::VariableDatabase& vdb(*hier::VariableDatabase::getDatabase());
+ tbox::Pointer<hier::Variable> variable;
+
+ if (!d_uv || d_uv->getComponentDescriptorIndex(0) != u) {
+ d_uv.setNull();
+ d_uv = new SAMRAIVectorReal<double>(d_object_name + "::uv",
+ d_hierarchy,
+ d_ln_min,
+ d_ln_max);
+ vdb.mapIndexToVariable(u, variable);
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (!variable) {
+ TBOX_ERROR(d_object_name << ": No variable for patch data index "
+ << u << "\n");
+ }
+ tbox::Pointer<pdat::CellVariable<double> > cell_variable = variable;
+ if (!cell_variable) {
+ TBOX_ERROR(d_object_name << ": hier::Patch data index " << u
+ << " is not a cell-double variable.\n");
+ }
+#endif
+ d_uv->addComponent(variable, u, s_weight_id[d_dim.getValue() - 1]);
+ }
+
+ if (!d_fv || d_fv->getComponentDescriptorIndex(0) != f) {
+ d_fv.setNull();
+ d_fv = new SAMRAIVectorReal<double>(d_object_name + "::fv",
+ d_hierarchy,
+ d_ln_min,
+ d_ln_max);
+ vdb.mapIndexToVariable(f, variable);
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (!variable) {
+ TBOX_ERROR(d_object_name << ": No variable for patch data index "
+ << f << "\n");
+ }
+ tbox::Pointer<pdat::CellVariable<double> > cell_variable = variable;
+ if (!cell_variable) {
+ TBOX_ERROR(d_object_name << ": hier::Patch data index " << f
+ << " is not a cell-double variable.\n");
+ }
+#endif
+ d_fv->addComponent(variable, f, s_weight_id[d_dim.getValue() - 1]);
+ }
+}
+
+/*
+ ***********************************************************************
+ * Delete the vector wrappers. Do not freeVectorComponents because *
+ * we do not control their data allocation. The user does that. *
+ ***********************************************************************
+ */
+void CellStokesFACSolver::destroyVectorWrappers() {
+ d_uv.setNull();
+ d_fv.setNull();
+}
+
+void CellStokesFACSolver::initializeStatics() {
+
+ for (int d = 0; d < SAMRAI::tbox::Dimension::MAXIMUM_DIMENSION_VALUE; ++d) {
+ s_weight_id[d] = -1;
+ s_instance_counter[d] = -1;
+ }
+
+ s_initialized = 1;
+}
+
+}
+}
+#endif
diff -r a44a82f15794 -r fe2a9230921b StokesFACSolver.I
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesFACSolver.I Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,142 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: High-level solver (wrapper) for scalar stokes equation.
+ *
+ ************************************************************************/
+namespace SAMRAI {
+namespace solv {
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setDPatchDataId(
+ int id) {
+ d_stokes_spec.setDPatchDataId(id);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setDConstant(
+ double scalar) {
+ d_stokes_spec.setDConstant(scalar);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setCPatchDataId(
+ int id) {
+ d_stokes_spec.setCPatchDataId(id);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setCConstant(
+ double scalar) {
+// Disable Intel warning on real comparison
+#ifdef __INTEL_COMPILER
+#pragma warning (disable:1572)
+#endif
+ if (scalar == 0.0) {
+ d_stokes_spec.setCZero();
+ } else {
+ d_stokes_spec.setCConstant(scalar);
+ }
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setProlongationMethod(
+ const std::string& prolongation_method)
+{
+ d_fac_ops.setProlongationMethod(prolongation_method);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setCoarsestLevelSolverChoice(
+ const std::string& choice)
+{
+ d_fac_ops.setCoarsestLevelSolverChoice(choice);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setCoarsestLevelSolverTolerance(
+ double tol)
+{
+ d_fac_ops.setCoarsestLevelSolverTolerance(tol);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setCoarsestLevelSolverMaxIterations(
+ int max_iterations)
+{
+ d_fac_ops.setCoarsestLevelSolverMaxIterations(max_iterations);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setCoarseFineDiscretization(
+ const std::string& coarsefine_method)
+{
+ d_fac_ops.setCoarseFineDiscretization(coarsefine_method);
+}
+
+#ifdef HAVE_HYPRE
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setUseSMG(
+ bool use_smg)
+{
+ if (d_solver_is_initialized) {
+ TBOX_ERROR(
+ d_object_name << ": setUseSMG(bool) may NOT be called\n"
+ <<
+ "while the solver state is initialized, as that\n"
+ << "would lead to a corrupted solver state.\n");
+ }
+ d_fac_ops.setUseSMG(use_smg);
+}
+#endif
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setPresmoothingSweeps(
+ int num_pre_sweeps) {
+ d_fac_precond.setPresmoothingSweeps(num_pre_sweeps);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setPostsmoothingSweeps(
+ int num_post_sweeps) {
+ d_fac_precond.setPostsmoothingSweeps(num_post_sweeps);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setMaxCycles(
+ int max_cycles) {
+ d_fac_precond.setMaxCycles(max_cycles);
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::setResidualTolerance(
+ double residual_tol) {
+ d_fac_precond.setResidualTolerance(residual_tol);
+}
+
+SAMRAI_INLINE_KEYWORD
+int CellStokesFACSolver::getNumberOfIterations() const
+{
+ return d_fac_precond.getNumberOfIterations();
+}
+
+SAMRAI_INLINE_KEYWORD
+double CellStokesFACSolver::getResidualNorm() const
+{
+ return d_fac_precond.getResidualNorm();
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesFACSolver::getConvergenceFactors(
+ double& avg_factor,
+ double& final_factor)
+const
+{
+ d_fac_precond.getConvergenceFactors(avg_factor, final_factor);
+}
+
+}
+}
diff -r a44a82f15794 -r fe2a9230921b StokesFACSolver.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesFACSolver.h Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,660 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: High-level solver (wrapper) for scalar stokes equation.
+ *
+ ************************************************************************/
+#ifndef included_solv_StokesFACSolver
+#define included_solv_StokesFACSolver
+
+#include "SAMRAI/SAMRAI_config.h"
+
+#include "SAMRAI/solv/FACPreconditioner.h"
+#include "StokesFACOps.h"
+#include "StokesSpecifications.h"
+#include "SAMRAI/solv/SimpleCellRobinBcCoefs.h"
+#include "SAMRAI/tbox/Database.h"
+#include "SAMRAI/tbox/Pointer.h"
+
+namespace SAMRAI {
+namespace solv {
+
+/*!
+ * @brief Class for solving scalar Stokes's equation on SAMR grid,
+ * wrapping up lower-level components (FAC cycling, Stokes equation
+ * operations and boundary conditions) in a single high-level interface.
+ *
+ * Note: this class provides a backward-compatible interface to
+ * the soon-to-be obsolete StokesHierarchySolver<DIM> class.
+ * Although this class hides the lower-level components (FAC cycling,
+ * Stokes equation operations and boundary conditions), it is
+ * perfectly acceptable to use those lower-level components directly.
+ *
+ * We solve the equation
+ * div(D grad(u)) + Cu = f
+ * where D is a side-centered array and C is a cell-centered array.
+ * u and f are also cell-centered.
+ * Boundary conditions supported are Dirichlet, Neumann and mixed
+ * (Dirichlet on some faces and Neumann on others).
+ *
+ * This class is a wrapper, providing a single class that coordinates
+ * three major components: the FAC solver, the cell-centered Stokes
+ * FAC operator and a default Robin bc coefficient implelemtation.
+ * It is perfectly acceptable to use those classes outside of this
+ * class.
+ *
+ * The underlying solver is an FAC solver using cell-centered
+ * discretization. The difference scheme is second-order
+ * central-difference. On coarse-fine boundaries within the
+ * solution levels, the composite grid operator uses, by default,
+ * the discretization method of Ewing, Lazarov and Vassilevski
+ * ("Local Refinement Techniques for Elliptic Problems on
+ * Cell-Centered Grids, I. Error Analysis", Mathematics of
+ * Computation, Vol. 56, No. 194, April 1991, pp. 437-461).
+ *
+ * Typical use of this class is:
+ * -# Construct a CellStokesFACSolver object, providing it
+ * the hierarchy and range of levels participating in the solve.
+ * -# Set the parameters C and D using the functions named @c setC...
+ * and @c setD... By default, D=1 and C=0 everywhere.
+ * -# Call setBoundaries() to state the types boundary conditions,
+ * along with supplemental data for setting those boundary
+ * conditions.
+ * -# Call initializeSolverState() to set up information
+ * internal to the solver. This is step is not required
+ * but will save setup costs if you are making multiple
+ * solves. This commits the object to the current hierarchy state
+ * and the specific @em types of boundary conditions you selected,
+ * It does NOT commit to the specific @em values of the boundary
+ * condition. A hierarchy change (through adaption or other means)
+ * invalidates the state, thus you must reinitialize or
+ * deallocateSolverState() the state before another solve.
+ * -# Solve the equation with solveSystem(). You provide the
+ * patch data indices for the solution u and the right hand
+ * side f. u must have at least one ghost cell and where
+ * a Dirichlet boundary condition applies, those cells
+ * must be set to the value on the boundary. If only Neumann
+ * boundary conditions are used, the ghost cell values
+ * do not matter.
+ * -# Call deallocateSolverState() to free up internal resources,
+ * if initializeSolverState() was called before the solve.
+ *
+ * After the solve, information on the solve can be obtained
+ * by calling one of these functions:
+ * - getNumberOfIterations() gives the number of FAC cycles used.
+ * - getConvergenceFactors() gives the average and final convergence
+ * factors for the solve.
+ * - getResidualNorm() gives the final residual
+ *
+ * Finer solver controls can be set using the functions in this class.
+ *
+ * Object of this class can be set using input databases.
+ * The following parameters can be set. Each is shown with its
+ * default value in the case where hypre is used.
+ * @verbatim
+ * enable_logging = TRUE // Bool flag to switch logging on/off
+ * max_cycles = 10 // Integer number of max FAC cycles to use
+ * residual_tol = 1.e-6 // Residual tolerance to solve for
+ * num_pre_sweeps = 1 // Number of presmoothing sweeps to use
+ * num_post_sweeps = 1 // Number of postsmoothing sweeps to use
+ * coarse_fine_discretization = "Ewing" // Name of coarse-fine discretization
+ * prolongation_method = "CONSTANT_REFINE" // Name of prolongation method
+ * coarse_solver_choice = "hypre" // Name of coarse level solver
+ * coarse_solver_tolerance = 1e-10 // Coarse level tolerance
+ * coarse_solver_max_iterations = 20 // Coarse level max iterations
+ * use_smg = "FALSE" // Whether to use hypre's smg solver
+ * // (alternative is the pfmg solver)
+ * @endverbatim
+ *
+ */
+class CellStokesFACSolver
+{
+
+public:
+ /*!
+ * @brief Construct a solver.
+ *
+ * If the database is not NULL, initial settings will be set
+ * using the database.
+ * The solver is uninitialized until initializeSolverState()
+ * is called.
+ *
+ * @param object_name Name of object used in outputs
+ * @param database tbox::Database for initialization (may be NULL)
+ */
+ CellStokesFACSolver(
+ const tbox::Dimension& dim,
+ const std::string& object_name,
+ tbox::Pointer<tbox::Database> database =
+ tbox::Pointer<tbox::Database>());
+
+ /*!
+ * @brief Destructor.
+ */
+ ~CellStokesFACSolver(
+ void);
+
+ /*!
+ * @brief Enable logging.
+ *
+ * To disable, pass in @c false.
+ */
+ void
+ enableLogging(
+ bool logging);
+
+ /*!
+ * @brief Solve Stokes's equation, assuming an uninitialized
+ * solver state.
+ *
+ * Here, u is the "solution" patch data index and f is the
+ * right hand side patch data index.
+ * The return value is true if the solver converged and false otherwise.
+ *
+ * This function is a wrapper.
+ * It simply initializes the solver state, call the
+ * solveSystem(const int,const int) for the initialized solver then
+ * deallocates the solver state.
+ *
+ * Upon return from this function,
+ * solution will contain the result of the solve.
+ *
+ * See initializeSolverState() for opportunities to save overhead
+ * when using multiple consecutive solves.
+ *
+ * @see solveSystem(const int,const int)
+ *
+ * @param solution hier::Patch data index for solution u
+ * @param rhs hier::Patch data index for right hand side f
+ * @param hierarchy The patch hierarchy to solve on
+ * @param coarse_ln The coarsest level in the solve.
+ * @param fine_ln The finest level in the solve.
+ *
+ * @return whether solver converged to specified level
+ *
+ * @see initializeSolverState
+ */
+ bool
+ solveSystem(
+ const int solution,
+ const int rhs,
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ int coarse_ln = -1,
+ int fine_ln = -1);
+
+ /*!
+ * @brief Solve Stokes's equation using the current solver state
+ * set by initializeSolverState().
+ *
+ * When the solver state has been initialized, this function may
+ * be called repeadedly with different values on the rhs.
+ * There is some cost savings for multiple solves when this
+ * is done.
+ *
+ * Before calling this function, the solution and
+ * right-hand-side quantities should be set properly by the user
+ * on all patch interiors on the range of levels covered by the
+ * FAC iteration. All data for these patch data index should be allocated.
+ * Thus, the user is responsible for managing the
+ * storage for the solution and right-hand-side.
+ *
+ * @return whether solver converged to specified level
+ *
+ * @see solveSystem( const int, const int, tbox::Pointer< hier::PatchHierarchy >, int, int);
+ */
+ bool
+ solveSystem(
+ const int solution,
+ const int rhs);
+
+ /*!
+ * @brief Specify the boundary conditions that are to be used at the
+ * physical domain boundary.
+ *
+ * This method is used to set up the default SimpleCellRobinBcCoefs
+ * object for specifying boundary conditions. Note that you may
+ * alternatively provide your own implementation of the Robin
+ * boundary condition coefficients using the setBcObject() method.
+ *
+ * The boundary conditions specified as the
+ * std::string argument "boundary_type." The boundary type argument can be
+ * "Dirichlet", "Neumann", or "Mixed".
+ *
+ * If using Dirichlet boundary conditions, then before the solver is
+ * called, the storage for the unknown u
+ * must have a mapped_box_level of ghost cells at least one cell wide that includes
+ * the Dirichlet boundary values.
+ *
+ * If using Neumann boundary conditions, then before the solver is called,
+ * the outerface boundary flux data must be set for the Neumann conditions.
+ * The fluxes argument gives the patch data index of this flux
+ * data.
+ *
+ * The mixed boundary type is for a mixture of Dirichlet and Neumann
+ * boundary conditions are used at the physical domain boundary.
+ * The fluxes argument gives the patch data index of the outerface data
+ * that specifies the flux data for the Neumann conditions. The flags
+ * array is an outerface data array of integer flags that specifies whether
+ * Dirichlet (flag == zero) or Neumann (flag == one) conditions are to be
+ * used at a particular cell boundary face. Note that the flag data must
+ * be set before the matrix entries can be computed and the flux data
+ * must be set before the solver is called. The bdry_types argument can
+ * be used if the boundary conditions are mixed but one or more of the
+ * faces of the physical boundary are entirely either Dirichlet or
+ * Neumann boundaries. The bdry_types argument should be an array of
+ * 2*DIM integers, specifying the boundary conditions on each side of
+ * the physical domain. It should be ordered {x_lo, x_hi, y_lo, y_hi,
+ * z_lo, z_hi}, with the values for each face being 0 for Dirichlet
+ * conditions, 1 for Neumann conditions, and 2 for mixed boundary
+ * conditions. The bdry_type argument is never required, but if used
+ * it can sometimes make the StokesHYPRESolver class more efficient.
+ */
+
+ void
+ setBoundaries(
+ const std::string& boundary_type,
+ const int fluxes = -1,
+ const int flags = -1,
+ int* bdry_types = NULL);
+
+ /*!
+ * @brief Override internal implementation to set boundary condition
+ * coefficients with user-provided implementation.
+ *
+ * This function is used to override the default internal
+ * object for setting Robin boundary condition coefficients.
+ * You should override when you need to avoid the limitations
+ * of the SimpleCellRobinBcCoefs class or you prefer to
+ * use your own implementation.
+ *
+ * Note that an important limitation of the SimpleCellRobinBcCoefs
+ * class is the inability to support linear interpolation in
+ * the prolongation step.
+ *
+ * Once the boundary condition object is overwritten by this
+ * method, you must no longer call the setBoundaries() method.
+ */
+ void
+ setBcObject(
+ const RobinBcCoefStrategy* bc_object);
+
+ //!@{ @name Specifying PDE parameters
+
+ /*!
+ * @brief Set the patch data index for variable D.
+ *
+ * In addition, disregard any previous D
+ * specified by setDConstant().
+ */
+ void
+ setDPatchDataId(
+ int id);
+
+ /*!
+ * @brief Set the scalar value variable D.
+ *
+ * In addition, disregard any previous D
+ * specified by setDPatchDataId().
+ */
+ void
+ setDConstant(
+ double scalar);
+
+ /*!
+ * @brief Set the scalar value variable C.
+ *
+ * In addition, disregard any previous C
+ * specified by setCConstant().
+ */
+ void
+ setCPatchDataId(
+ int id);
+
+ /*!
+ * @brief Set the patch data index for variable C.
+ *
+ * In addition, disregard any previous C
+ * specified by setCConstant().
+ */
+ void
+ setCConstant(
+ double scalar);
+
+ //@}
+
+ //@{ @name Functions for setting solver mathematic algorithm controls
+
+ /*!
+ * @brief Set coarse level solver.
+ *
+ * Select from these:
+ * - @c "redblack"
+ * - @c "hypre" (only if the HYPRE library is available).
+ */
+ void
+ setCoarsestLevelSolverChoice(
+ const std::string& choice);
+
+ /*!
+ * @brief Set tolerance for coarse level solve.
+ *
+ * If the coarse level solver requires a tolerance
+ * (currently, they all do), the specified value is used.
+ */
+ void
+ setCoarsestLevelSolverTolerance(
+ double tol);
+
+ /*!
+ * @brief Set max iterations for coarse level solve.
+ *
+ * If the coarse level solver requires a max iteration limit
+ * (currently, they all do), the specified value is used.
+ */
+ void
+ setCoarsestLevelSolverMaxIterations(
+ int max_iterations);
+
+#ifdef HAVE_HYPRE
+ /*!
+ * @brief Set whether to use HYPRe's PFMG algorithm instead of the
+ * SMG algorithm.
+ *
+ * The flag is used to select which of HYPRE's linear solver algorithms
+ * to use if true, the semicoarsening multigrid algorithm is used, and if
+ * false, the ``PF'' multigrid algorithm is used.
+ * By default, the SMG algorithm is used.
+ *
+ * This setting has effect only when HYPRe is chosen for the coarsest
+ * level solver. See setCoarsestLevelSolverChoice().
+ *
+ * Changing the algorithm must be done before setting up the matrix
+ * coefficients.
+ */
+ void
+ setUseSMG(
+ bool use_smg);
+#endif
+
+ /*!
+ * @brief Set the coarse-fine boundary discretization method.
+ *
+ * Specify the @c op_name std::string which will be passed to
+ * xfer::Geometry::lookupRefineOperator() to get the operator
+ * for setting fine grid ghost cells from the coarse grid.
+ * Note that chosing this operator implicitly choses the
+ * discretization method at the coarse-fine boundary.
+ *
+ * There is one important instance where this std::string is
+ * @em not passed to xfer::Geometry::lookupRefineOperator().
+ * If this variable is set to "Ewing", a constant refinement
+ * method is used along with Ewing's correction.
+ * For a reference to the correction method, see
+ * "Local Refinement Techniques for Elliptic Problems on Cell-Centered
+ * Grids, I. Error Analysis", Mathematics of Computation, Vol. 56, No. 194,
+ * April 1991, pp. 437-461.
+ *
+ * @param coarsefine_method String selecting the coarse-fine discretization method.
+ */
+ void
+ setCoarseFineDiscretization(
+ const std::string& coarsefine_method);
+
+ /*!
+ * @brief Set the name of the prolongation method.
+ *
+ * Specify the @c op_name std::string which will be passed to
+ * xfer::Geometry::lookupRefineOperator() to get the operator
+ * for prolonging the coarse-grid correction.
+ *
+ * By default, "CONSTANT_REFINE" is used. "LINEAR_REFINE" seems to
+ * to lead to faster convergence, but it does NOT satisfy the Galerkin
+ * condition.
+ *
+ * Prolonging using linear refinement requires a Robin bc
+ * coefficient implementation that is capable of delivering
+ * coefficients for non-hierarchy data, because linear refinement
+ * requires boundary conditions to be set on temporary levels.
+ *
+ * @param prolongation_method String selecting the coarse-fine discretization method.
+ */
+ void
+ setProlongationMethod(
+ const std::string& prolongation_method);
+
+ /*!
+ * @brief Set the number of pre-smoothing sweeps during
+ * FAC iteration process.
+ *
+ * Presmoothing is applied during the fine-to-coarse phase of the
+ * iteration. The default is to use one sweep.
+ *
+ * @param num_pre_sweeps Number of presmoothing sweeps
+ */
+ void
+ setPresmoothingSweeps(
+ int num_pre_sweeps);
+
+ /*!
+ * @brief Set the number of post-smoothing sweeps during
+ * FAC iteration process.
+ *
+ * Postsmoothing is applied during the coarse-to-fine phase of the
+ * iteration. The default is to use one sweep.
+ *
+ * @param num_post_sweeps Number of postsmoothing sweeps
+ */
+ void
+ setPostsmoothingSweeps(
+ int num_post_sweeps);
+
+ /*!
+ * @brief Set the max number of iterations (cycles) to use per solve.
+ */
+ void
+ setMaxCycles(
+ int max_cycles);
+
+ /*!
+ * @brief Set the residual tolerance for stopping.
+ *
+ * If you want the prescribed maximum number of cycles to always be taken,
+ * set the residual tolerance to a negative number.
+ */
+ void
+ setResidualTolerance(
+ double residual_tol);
+
+ //@}
+
+ /*!
+ * @brief Prepare the solver's internal state for solving
+ *
+ * In the interest of efficiency, this class may prepare and
+ * cache some hierarchy-dependent objects. Though it is not required,
+ * initializing the solver state makes for greater efficiency
+ * when you are doing multiple solves on the same system of
+ * equation. If you do not initialize the state, it is initialized
+ * and deallocated each time you call solveSystem(const int, const int).
+ * The state must be reinitialized if the hierarchy or a boundary
+ * condition type changes.
+ *
+ * To unset the data set in this function,
+ * see deallocateSolverState().
+ *
+ * The @c solution and @c rhs patch data indices in the argument
+ * list are used to determine the @em form of the data you
+ * plan to use in the solve. They need not be the same data
+ * you solve on, but they should be similar. Both must represent
+ * cell-centered double data. The solution must have at least one
+ * ghost cell width, though this is not checked in the initialize
+ * phase, because data is not required yet.
+ *
+ * @param solution solution patch data index for u
+ * @param rhs right hand side patch data index for f
+ * @param hierarchy The patch hierarchy to solve on
+ * @param coarse_level The coarsest level in the solve
+ * @param fine_level The finest level in the solve
+ */
+ void
+ initializeSolverState(
+ const int solution,
+ const int rhs,
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ const int coarse_level = -1,
+ const int fine_level = -1);
+
+ /*!
+ * @brief Remove the solver's internal state data
+ *
+ * Remove all hierarchy-dependent data set by initializeSolverState.
+ * It is safe to call deallocateSolverState() even state is already
+ * deallocated, but nothing is done in that case.
+ *
+ * @see initializeSolverState()
+ */
+ void
+ deallocateSolverState();
+
+ //@{
+ //! @name Functions to get data on last solve.
+
+ /*!
+ * @brief Return FAC iteration count from last (or current
+ * if there is one) FAC iteration process.
+ */
+ int
+ getNumberOfIterations() const;
+
+ /*!
+ * @brief Get average convergance rate and convergence rate of
+ * the last (or current if there is one) FAC solve.
+ *
+ * @param avg_factor average convergence factor over current FAC cycles
+ * @param final_factor convergence factor of the last FAC cycle
+ */
+ void
+ getConvergenceFactors(
+ double& avg_factor,
+ double& final_factor) const;
+
+ /*!
+ * @brief Return residual norm from the just-completed FAC iteration.
+ *
+ * The norm return value is computed as the maximum norm over all
+ * patch levels involved in the solve. The value corresponds to the
+ * norm applied in the user-defined residual computation.
+ *
+ * The latest computed norm is the one returned.
+ */
+ double
+ getResidualNorm() const;
+
+ //@}
+
+private:
+ /*!
+ * @brief Set state using database
+ *
+ * See the class description for the parameters that can be set
+ * from a database.
+ *
+ * @param database Input database. If a NULL pointer is given,
+ * nothing is done.
+ */
+ void
+ getFromInput(
+ tbox::Pointer<tbox::Database> database);
+
+ /*
+ * @brief Set @c d_uv and @c d_fv to vectors wrapping the data
+ * specified by patch data indices u and f.
+ */
+ void
+ createVectorWrappers(
+ int u,
+ int f);
+
+ /*
+ * @brief Destroy vector wrappers referenced to by @c d_uv and @c d_fv.
+ */
+ void
+ destroyVectorWrappers();
+
+ /*
+ * @brief Initialize static members
+ */
+ static void
+ initializeStatics();
+
+ const tbox::Dimension d_dim;
+
+ /*!
+ * @brief Object name.
+ */
+ std::string d_object_name;
+
+ /*!
+ * @brief Object holding the specifications of the Stokes equation.
+ */
+ StokesSpecifications d_stokes_spec;
+
+ /*!
+ * @brief FAC operator implementation corresponding to cell-centered
+ * Stokes discretization.
+ */
+ CellStokesFACOps d_fac_ops;
+
+ /*!
+ * @brief FAC preconditioner algorithm.
+ */
+ FACPreconditioner d_fac_precond;
+
+ /*!
+ * @brief Robin bc object in use.
+ */
+ const RobinBcCoefStrategy* d_bc_object;
+
+ /*
+ * @brief Default implementation of RobinBcCoefStrategy
+ */
+ SimpleCellRobinBcCoefs d_simple_bc;
+
+ tbox::Pointer<hier::PatchHierarchy> d_hierarchy;
+ int d_ln_min;
+ int d_ln_max;
+
+ /*!
+ * @brief Context for all internally maintained data.
+ */
+ tbox::Pointer<hier::VariableContext> d_context;
+ /*
+ * @brief Vector wrapper for solution.
+ * @see createVectorWrappers(), destroyVectorWrappers()
+ */
+ tbox::Pointer<SAMRAIVectorReal<double> > d_uv;
+ /*
+ * @brief Vector wrapper for source.
+ * @see createVectorWrappers(), destroyVectorWrappers()
+ */
+ tbox::Pointer<SAMRAIVectorReal<double> > d_fv;
+
+ bool d_solver_is_initialized;
+ bool d_enable_logging;
+
+ static bool s_initialized;
+ static int s_weight_id[SAMRAI::tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+ static int s_instance_counter[SAMRAI::tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+};
+
+}
+}
+
+#ifdef SAMRAI_INLINE
+#include "StokesFACSolver.I"
+#endif
+
+#endif // included_solv_CellStokesFACSolver
diff -r a44a82f15794 -r fe2a9230921b StokesHypreSolver.C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesHypreSolver.C Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,1590 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: Hypre solver interface for diffusion-like elliptic problems.
+ *
+ ************************************************************************/
+#ifndef included_solv_StokesHypreSolver_C
+#define included_solv_StokesHypreSolver_C
+
+#include "StokesHypreSolver.h"
+
+#ifdef HAVE_HYPRE
+
+#include "SAMRAI/geom/CartesianPatchGeometry.h"
+#include "SAMRAI/geom/CartesianGridGeometry.h"
+#include "SAMRAI/math/ArrayDataBasicOps.h"
+#include "SAMRAI/math/PatchSideDataBasicOps.h"
+#include "SAMRAI/pdat/ArrayData.h"
+#include "SAMRAI/pdat/CellIndex.h"
+#include "SAMRAI/pdat/CellIterator.h"
+#include "SAMRAI/pdat/FaceIndex.h"
+#include "SAMRAI/pdat/SideData.h"
+#include "SAMRAI/pdat/SideIndex.h"
+#include "SAMRAI/pdat/SideVariable.h"
+#include "SAMRAI/pdat/OuterfaceData.h"
+#include "SAMRAI/pdat/OutersideData.h"
+#include "SAMRAI/hier/BoundaryBoxUtils.h"
+#include "SAMRAI/hier/VariableDatabase.h"
+#include "SAMRAI/tbox/MathUtilities.h"
+#include "SAMRAI/tbox/SAMRAI_MPI.h"
+#include "SAMRAI/tbox/SAMRAIManager.h"
+#include "SAMRAI/tbox/PIO.h"
+#include "SAMRAI/tbox/Timer.h"
+#include "SAMRAI/tbox/TimerManager.h"
+#include "SAMRAI/tbox/StartupShutdownManager.h"
+#include "SAMRAI/tbox/Utilities.h"
+
+#include <cstdlib>
+
+#ifndef SAMRAI_INLINE
+#include "StokesHypreSolver.I"
+#endif
+
+extern "C" {
+
+#ifdef __INTEL_COMPILER
+#pragma warning (disable:1419)
+#endif
+
+void F77_FUNC(compdiagvariablec2d, COMPDIAGVARIABLEC2D) (
+ double* diag,
+ const double* c,
+ const double* offdiagi,
+ const double* offdiagj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* cscale,
+ const double* dscale);
+void F77_FUNC(compdiagscalarc2d, COMPDIAGSCALARC2D) (
+ double* diag,
+ const double* c,
+ const double* offdiagi,
+ const double* offdiagj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* cscale,
+ const double* dscale);
+void F77_FUNC(compdiagzeroc2d, COMPDIAGZEROC2D) (
+ double* diag,
+ const double* offdiagi,
+ const double* offdiagj,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const double* cscale,
+ const double* dscale);
+void F77_FUNC(adjbdry2d, ADJBDRY2D) (
+ double* diag,
+ const double* offdiagi,
+ const double* offdiagj,
+ const int* pifirst, const int* pilast,
+ const int* pjfirst, const int* pjlast,
+ const double* acoef,
+ const double* bcoef,
+ const int* aifirst, const int* ailast,
+ const int* ajfirst, const int* ajlast,
+ const double* Ak0,
+ const int* kifirst, const int* kilast,
+ const int* kjfirst, const int* kjlast,
+ const int* lower, const int* upper,
+ const int* location,
+ const double* h);
+void F77_FUNC(adjbdryconstoffdiags2d, ADJBDRYCONSTOFFDIAGS2D) (
+ double* diag,
+ const double* offdiag,
+ const int* pifirst,
+ const int* pilast,
+ const int* pjfirst,
+ const int* pjlast,
+ const double* acoef,
+ const int* aifirst,
+ const int* ailast,
+ const int* ajfirst,
+ const int* ajlast,
+ const double* Ak0,
+ const int* kifirst,
+ const int* kilast,
+ const int* kjfirst,
+ const int* kjlast,
+ const int* lower, const int* upper,
+ const int* location,
+ const double* h);
+void F77_FUNC(adjustrhs2d, ADJUSTRHS2D) (double* rhs,
+ const int* rifirst,
+ const int* rilast,
+ const int* rjfirst,
+ const int* rjlast,
+ const double* Ak0,
+ const int* kifirst,
+ const int* kilast,
+ const int* kjfirst,
+ const int* kjlast,
+ const double* gcoef,
+ const int* aifirst,
+ const int* ailast,
+ const int* ajfirst,
+ const int* ajlast,
+ const int* lower, const int* upper,
+ const int* location);
+
+void F77_FUNC(compdiagvariablec3d, COMPDIAGVARIABLEC3D) (
+ double* diag,
+ const double* c,
+ const double* offdiagi,
+ const double* offdiagj,
+ const double* offdiagk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* cscale,
+ const double* dscale);
+void F77_FUNC(compdiagscalarc3d, COMPDIAGSCALARC3D) (
+ double* diag,
+ const double* c,
+ const double* offdiagi,
+ const double* offdiagj,
+ const double* offdiagk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* cscale,
+ const double* dscale);
+void F77_FUNC(compdiagzeroc3d, COMPDIAGZEROC3D) (
+ double* diag,
+ const double* offdiagi,
+ const double* offdiagj,
+ const double* offdiagk,
+ const int* ifirst,
+ const int* ilast,
+ const int* jfirst,
+ const int* jlast,
+ const int* kfirst,
+ const int* klast,
+ const double* cscale,
+ const double* dscale);
+void F77_FUNC(adjbdry3d, ADJBDRY3D) (
+ double* diag,
+ const double* offdiagi,
+ const double* offdiagj,
+ const double* offdiagk,
+ const int* pifirst,
+ const int* pilast,
+ const int* pjfirst,
+ const int* pjlast,
+ const int* pkfirst,
+ const int* pklast,
+ const double* acoef,
+ const double* bcoef,
+ const int* aifirst,
+ const int* ailast,
+ const int* ajfirst,
+ const int* ajlast,
+ const int* akfirst,
+ const int* aklast,
+ const double* Ak0,
+ const int* kifirst,
+ const int* kilast,
+ const int* kjfirst,
+ const int* kjlast,
+ const int* kkfirst,
+ const int* kklast,
+ const int* lower, const int* upper,
+ const int* location,
+ const double* h);
+void F77_FUNC(adjbdryconstoffdiags3d, ADJBDRYCONSTOFFDIAGS3D) (
+ double* diag,
+ const double* offdiag,
+ const int* pifirst,
+ const int* pilast,
+ const int* pjfirst,
+ const int* pjlast,
+ const int* pkfirst,
+ const int* pklast,
+ const double* acoef,
+ const int* aifirst,
+ const int* ailast,
+ const int* ajfirst,
+ const int* ajlast,
+ const int* akfirst,
+ const int* aklast,
+ const double* Ak0,
+ const int* kifirst,
+ const int* kilast,
+ const int* kjfirst,
+ const int* kjlast,
+ const int* kkfirst,
+ const int* kklast,
+ const int* lower, const int* upper,
+ const int* location,
+ const double* h);
+void F77_FUNC(adjustrhs3d, ADJUSTRHS3D) (double* rhs,
+ const int* rifirst,
+ const int* rilast,
+ const int* rjfirst,
+ const int* rjlast,
+ const int* rkfirst,
+ const int* rklast,
+ const double* Ak0,
+ const int* kifirst,
+ const int* kilast,
+ const int* kjfirst,
+ const int* kjlast,
+ const int* kkfirst,
+ const int* kklast,
+ const double* gcoef,
+ const int* aifirst,
+ const int* ailast,
+ const int* ajfirst,
+ const int* ajlast,
+ const int* akfirst,
+ const int* aklast,
+ const int* lower, const int* upper,
+ const int* location);
+
+}
+
+namespace SAMRAI {
+namespace solv {
+
+tbox::Pointer<pdat::OutersideVariable<double> >
+CellStokesHypreSolver::s_Ak0_var[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+
+tbox::StartupShutdownManager::Handler CellStokesHypreSolver::s_finalize_handler(
+ 0,
+ 0,
+ 0,
+ CellStokesHypreSolver::finalizeCallback,
+ tbox::StartupShutdownManager::priorityVariables);
+
+/*
+ *************************************************************************
+ * Constructor *
+ *************************************************************************
+ */
+
+CellStokesHypreSolver::CellStokesHypreSolver(
+ const tbox::Dimension& dim,
+ const std::string& object_name,
+ tbox::Pointer<tbox::Database> database):
+ d_dim(dim),
+ d_object_name(object_name),
+ d_hierarchy(NULL),
+ d_ln(-1),
+ d_context(hier::VariableDatabase::getDatabase()->
+ getContext(object_name + "::context")),
+ d_cf_boundary(),
+ d_physical_bc_coef_strategy(&d_physical_bc_simple_case),
+ d_physical_bc_variable(NULL),
+ d_physical_bc_simple_case(dim, d_object_name + "::simple bc"),
+ d_cf_bc_coef(dim, object_name + "::coarse-fine bc coefs"),
+ d_coarsefine_bc_variable(NULL),
+ d_Ak0_id(-1),
+ d_soln_depth(0),
+ d_rhs_depth(0),
+ d_max_iterations(10),
+ d_relative_residual_tol(1e-10),
+ d_number_iterations(-1),
+ d_num_pre_relax_steps(1),
+ d_num_post_relax_steps(1),
+ d_relative_residual_norm(-1.0),
+ d_use_smg(false),
+ d_grid(NULL),
+ d_stencil(NULL),
+ d_matrix(NULL),
+ d_linear_rhs(NULL),
+ d_linear_sol(NULL),
+ d_mg_data(NULL),
+ d_print_solver_info(false)
+{
+ if (d_dim == tbox::Dimension(1) || d_dim > tbox::Dimension(3)) {
+ TBOX_ERROR(" CellStokesHypreSolver : DIM == 1 or > 3 not implemented");
+ }
+
+ t_solve_system = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesHypreSolver::solveSystem()");
+ t_set_matrix_coefficients = tbox::TimerManager::getManager()->
+ getTimer("solv::CellStokesHypreSolver::setMatrixCoefficients()");
+
+ hier::VariableDatabase* vdb = hier::VariableDatabase::getDatabase();
+ if (s_Ak0_var[d_dim.getValue() - 1].isNull()) {
+ s_Ak0_var[d_dim.getValue() - 1] = new
+ pdat::OutersideVariable<double>(d_dim, d_object_name + "::Ak0", 1);
+ }
+ d_Ak0_id =
+ vdb->registerVariableAndContext(s_Ak0_var[d_dim.getValue() - 1],
+ d_context,
+ hier::IntVector::getZero(d_dim));
+ if (database) {
+ getFromInput(database);
+ }
+}
+
+/*
+ ********************************************************************
+ * Set state from database *
+ ********************************************************************
+ */
+
+void CellStokesHypreSolver::getFromInput(
+ tbox::Pointer<tbox::Database> database)
+{
+ if (database) {
+ d_print_solver_info = database->getBoolWithDefault("print_solver_info",
+ d_print_solver_info);
+ d_max_iterations = database->getIntegerWithDefault("max_iterations",
+ d_max_iterations);
+ d_relative_residual_tol = database->getDoubleWithDefault(
+ "relative_residual_tol",
+ d_relative_residual_tol);
+ if (database->isDouble("residual_tol")) {
+ TBOX_ERROR("CellStokesHypreSolver input error.\n"
+ << "The parameter 'residual_tol' has been replaced\n"
+ << "by 'relative_residual_tol' to be more descriptive.\n"
+ << "Please change the parameter name in the input database.");
+ }
+ d_num_pre_relax_steps =
+ database->getIntegerWithDefault("num_pre_relax_steps",
+ d_num_pre_relax_steps);
+ if (d_num_pre_relax_steps < 0) {
+ TBOX_ERROR(d_object_name << ": Number of relaxation steps must be\n"
+ << "non-negative.\n");
+ }
+ d_num_post_relax_steps =
+ database->getIntegerWithDefault("num_post_relax_steps",
+ d_num_post_relax_steps);
+ if (d_num_post_relax_steps < 0) {
+ TBOX_ERROR(d_object_name << ": Number of relaxation steps must be\n"
+ << "non-negative.\n");
+ }
+ if (database->isBool("use_smg")) {
+ bool use_smg = database->getBool("use_smg");
+ if (use_smg != d_use_smg) {
+ setUseSMG(use_smg);
+ }
+ }
+ }
+}
+
+/*
+ ********************************************************************
+ * Initialize internal data for a given hierarchy level *
+ * After setting internal data, propagate the information *
+ * to the major algorithm objects. Allocate data for *
+ * storing boundary condition-dependent quantities for *
+ * adding to souce term before solving. *
+ ********************************************************************
+ */
+
+void CellStokesHypreSolver::initializeSolverState(
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ int ln)
+{
+ TBOX_ASSERT(!hierarchy.isNull());
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS1(d_dim, *hierarchy);
+
+ deallocateSolverState();
+
+ d_hierarchy = hierarchy;
+ d_ln = ln;
+
+ hier::IntVector max_gcw(d_dim, 1);
+ d_cf_boundary = new hier::CoarseFineBoundary(*d_hierarchy, d_ln, max_gcw);
+
+ d_physical_bc_simple_case.setHierarchy(d_hierarchy, d_ln, d_ln);
+
+ d_number_iterations = -1;
+ d_relative_residual_norm = -1.0;
+
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
+ level->allocatePatchData(d_Ak0_id);
+ allocateHypreData();
+}
+
+/*
+ ********************************************************************
+ * Deallocate data initialized by initializeSolverState *
+ ********************************************************************
+ */
+
+void CellStokesHypreSolver::deallocateSolverState()
+{
+ if (d_hierarchy.isNull()) return;
+
+ d_cf_boundary->clear();
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
+ level->deallocatePatchData(d_Ak0_id);
+ deallocateHypreData();
+ d_hierarchy.setNull();
+ d_ln = -1;
+}
+
+/*
+ *************************************************************************
+ * *
+ * Allocate the HYPRE data structures that depend only on the level *
+ * and will not change (grid, stencil, matrix, and vectors). *
+ * *
+ *************************************************************************
+ */
+void CellStokesHypreSolver::allocateHypreData()
+{
+ tbox::SAMRAI_MPI::Comm communicator = d_hierarchy->getDomainMappedBoxLevel().getMPI().getCommunicator();
+
+ /*
+ * Set up the grid data - only set grid data for local boxes
+ */
+
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
+ tbox::Pointer<geom::CartesianGridGeometry> grid_geometry =
+ d_hierarchy->getGridGeometry();
+ const hier::IntVector ratio = level->getRatioToLevelZero();
+ hier::IntVector periodic_shift =
+ grid_geometry->getPeriodicShift(ratio);
+
+ int periodic_flag[tbox::Dimension::MAXIMUM_DIMENSION_VALUE];
+ int d;
+ bool is_periodic = false;
+ for (d = 0; d < d_dim.getValue(); ++d) {
+ periodic_flag[d] = periodic_shift[d] != 0;
+ is_periodic = is_periodic || periodic_flag[d];
+ }
+
+ HYPRE_StructGridCreate(communicator, d_dim.getValue(), &d_grid);
+ for (hier::PatchLevel::Iterator p(level); p; p++) {
+ const hier::Box& box = (*p)->getBox();
+ hier::Index lower = box.lower();
+ hier::Index upper = box.upper();
+ HYPRE_StructGridSetExtents(d_grid, &lower[0], &upper[0]);
+ }
+
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (is_periodic) {
+ const hier::BoxArray& level_domain = level->getPhysicalDomain();
+ hier::Box domain_bound(level_domain[0]);
+ for (int i = 1; i < level_domain.size(); ++i) {
+ domain_bound.lower().min(level_domain[i].lower());
+ domain_bound.upper().max(level_domain[i].upper());
+ }
+ for (d = 0; d < d_dim.getValue(); ++d) {
+ if (periodic_flag[d] == true) {
+ int tmpi = 1;
+ unsigned int p_of_two;
+ for (p_of_two = 0; p_of_two < 8 * sizeof(p_of_two) - 1;
+ ++p_of_two) {
+ if (tmpi == domain_bound.numberCells(d)) {
+ break;
+ }
+ if (tmpi > domain_bound.numberCells(d)) {
+ TBOX_ERROR(
+ d_object_name << ": Hypre currently requires\n"
+ <<
+ "that grid size in periodic directions be\n"
+ <<
+ "powers of two. (This requirement may go\n"
+ <<
+ "away in future versions of hypre.)\n"
+ << "Size problem in direction "
+ << d << "\n"
+ << "Domain bound is "
+ << domain_bound << ",\n"
+ << "Size of "
+ << domain_bound.numberCells() << "\n");
+ }
+ tmpi = tmpi ? tmpi << 1 : 1;
+ }
+ }
+ }
+ }
+#endif
+
+ HYPRE_StructGridSetPeriodic(d_grid, &periodic_shift[0]);
+ HYPRE_StructGridAssemble(d_grid);
+
+ {
+ /*
+ * Allocate stencil data and set stencil offsets
+ */
+
+ if (d_dim == tbox::Dimension(1)) {
+ const int stencil_size = 2;
+ int stencil_offsets[2][1] = {
+ { -1 }, { 0 }
+ };
+ HYPRE_StructStencilCreate(d_dim.getValue(), stencil_size, &d_stencil);
+ for (int s = 0; s < stencil_size; s++) {
+ HYPRE_StructStencilSetElement(d_stencil, s,
+ stencil_offsets[s]);
+ }
+ } else if (d_dim == tbox::Dimension(2)) {
+ const int stencil_size = 3;
+ int stencil_offsets[3][2] = {
+ { -1, 0 }, { 0, -1 }, { 0, 0 }
+ };
+ HYPRE_StructStencilCreate(d_dim.getValue(), stencil_size, &d_stencil);
+ for (int s = 0; s < stencil_size; s++) {
+ HYPRE_StructStencilSetElement(d_stencil, s,
+ stencil_offsets[s]);
+ }
+ } else if (d_dim == tbox::Dimension(3)) {
+ const int stencil_size = 4;
+ int stencil_offsets[4][3] = {
+ { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 }, { 0, 0, 0 }
+ };
+ HYPRE_StructStencilCreate(d_dim.getValue(), stencil_size, &d_stencil);
+ for (int s = 0; s < stencil_size; s++) {
+ HYPRE_StructStencilSetElement(d_stencil, s,
+ stencil_offsets[s]);
+ }
+ }
+ }
+
+ {
+ int full_ghosts1[2 * 3] = { 1, 1, 0, 0, 0, 0 };
+ int no_ghosts1[2 * 3] = { 0, 0, 0, 0, 0, 0 };
+
+ int full_ghosts2[2 * 3] = { 1, 1, 1, 1, 0, 0 };
+ int no_ghosts2[2 * 3] = { 0, 0, 0, 0, 0, 0 };
+
+ int full_ghosts3[2 * 3] = { 1, 1, 1, 1, 1, 1 };
+ int no_ghosts3[2 * 3] = { 0, 0, 0, 0, 0, 0 };
+
+ /*
+ * Allocate the structured matrix
+ */
+
+ int* full_ghosts = NULL;
+ int* no_ghosts = NULL;
+
+ if (d_dim == tbox::Dimension(1)) {
+ full_ghosts = full_ghosts1;
+ no_ghosts = no_ghosts1;
+ } else if (d_dim == tbox::Dimension(2)) {
+ full_ghosts = full_ghosts2;
+ no_ghosts = no_ghosts2;
+ } else if (d_dim == tbox::Dimension(3)) {
+ full_ghosts = full_ghosts3;
+ no_ghosts = no_ghosts3;
+ } else {
+ TBOX_ERROR(
+ "CellStokesHypreSolver does not yet support dimension " << d_dim);
+ }
+
+ HYPRE_StructMatrixCreate(communicator,
+ d_grid,
+ d_stencil,
+ &d_matrix);
+ HYPRE_StructMatrixSetNumGhost(d_matrix, full_ghosts);
+ HYPRE_StructMatrixSetSymmetric(d_matrix, 1);
+ HYPRE_StructMatrixInitialize(d_matrix);
+
+ HYPRE_StructVectorCreate(communicator,
+ d_grid,
+ &d_linear_rhs);
+ HYPRE_StructVectorSetNumGhost(d_linear_rhs, no_ghosts);
+ HYPRE_StructVectorInitialize(d_linear_rhs);
+
+ HYPRE_StructVectorCreate(communicator,
+ d_grid,
+ &d_linear_sol);
+ HYPRE_StructVectorSetNumGhost(d_linear_sol, full_ghosts);
+ HYPRE_StructVectorInitialize(d_linear_sol);
+ }
+}
+
+/*
+ *************************************************************************
+ * *
+ * The destructor deallocates solver data. *
+ * *
+ *************************************************************************
+ */
+
+CellStokesHypreSolver::~CellStokesHypreSolver()
+{
+ deallocateHypreData();
+
+ if (!d_hierarchy.isNull()) {
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(0);
+ level->deallocatePatchData(d_Ak0_id);
+ }
+ hier::VariableDatabase* vdb =
+ hier::VariableDatabase::getDatabase();
+ vdb->removePatchDataIndex(d_Ak0_id);
+}
+
+/*
+ *************************************************************************
+ * *
+ * Deallocate HYPRE data and solver. HYPRE requires that we *
+ * check whether HYPRE has already deallocated this data. *
+ * Note that the HYPRE solver, d_mg_data, was created at *
+ * the end of setMatrixCoefficients. *
+ * *
+ *************************************************************************
+ */
+
+void CellStokesHypreSolver::deallocateHypreData()
+{
+ if (d_stencil) {
+ HYPRE_StructStencilDestroy(d_stencil);
+ d_stencil = NULL;
+ }
+ if (d_grid) {
+ HYPRE_StructGridDestroy(d_grid);
+ d_grid = NULL;
+ }
+ if (d_matrix) {
+ HYPRE_StructMatrixDestroy(d_matrix);
+ d_matrix = NULL;
+ }
+ if (d_linear_rhs) {
+ HYPRE_StructVectorDestroy(d_linear_rhs);
+ d_linear_rhs = NULL;
+ }
+ if (d_linear_sol) {
+ HYPRE_StructVectorDestroy(d_linear_sol);
+ d_linear_sol = NULL;
+ }
+ destroyHypreSolver();
+}
+
+/*
+ *************************************************************************
+ * *
+ * Copy data into the HYPRE vector structures. *
+ * *
+ *************************************************************************
+ */
+
+void CellStokesHypreSolver::copyToHypre(
+ HYPRE_StructVector vector,
+ pdat::CellData<double>& src,
+ int depth,
+ const hier::Box& box)
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS2(d_dim, src, box);
+
+ for (pdat::CellIterator c(box); c; c++) {
+ hier::IntVector ic = c();
+ HYPRE_StructVectorSetValues(vector, &ic[0], src(c(), depth));
+ }
+}
+
+/*
+ *************************************************************************
+ * *
+ * Copy data out of the HYPRE vector structures. *
+ * *
+ *************************************************************************
+ */
+
+void CellStokesHypreSolver::copyFromHypre(
+ pdat::CellData<double>& dst,
+ int depth,
+ HYPRE_StructVector vector,
+ const hier::Box box)
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS2(d_dim, dst, box);
+
+ for (pdat::CellIterator c(box); c; c++) {
+ double value;
+ hier::IntVector ic = c();
+ HYPRE_StructVectorGetValues(vector, &ic[0], &value);
+ dst(c(), depth) = value;
+ }
+}
+
+/*
+ *************************************************************************
+ * *
+ * Set the matrix coefficients for the linear system. *
+ * The matrix coefficients are dependent on the problem *
+ * specification described by the StokesSpecificiations *
+ * object and by the boundary condition. *
+ * *
+ *************************************************************************
+ */
+
+void CellStokesHypreSolver::setMatrixCoefficients(
+ const StokesSpecifications& spec)
+{
+ if (d_physical_bc_coef_strategy == NULL) {
+ TBOX_ERROR(
+ d_object_name << ": No BC coefficient strategy object!\n"
+ <<
+ "Use either setBoundaries or setPhysicalBcCoefObject\n"
+ <<
+ "to specify the boundary conidition. Do it before\n"
+ << "calling setMatrixCoefficients.");
+ }
+
+ t_set_matrix_coefficients->start();
+
+ int i = 0;
+
+ tbox::Pointer<pdat::CellData<double> > C_data;
+ tbox::Pointer<pdat::SideData<double> > D_data;
+
+ /*
+ * Some computations can be done using high-level math objects.
+ * Define the math objects.
+ */
+ math::ArrayDataBasicOps<double> array_math;
+ math::PatchSideDataBasicOps<double> patch_side_math;
+
+ /*
+ * The value of the ghost cell based on the Robin boundary condition
+ * can be written as the sum of a constant, k0, plus a multiple of the
+ * internal cell value, k1*ui. k1*ui depends on the value of u so it
+ * contributes to the product Au,
+ * while the constant k0 contributes the right hand side f.
+ * We save Ak0 = A*k0(a) to add to f when solving.
+ * We assume unit g here because we will multiply it in just before
+ * solving, thus allowing everything that does not affect A to change
+ * from solve to solve.
+ */
+ tbox::Pointer<pdat::OutersideData<double> > Ak0;
+
+ /*
+ * Loop over patches and set matrix entries for each patch.
+ */
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
+ const hier::IntVector no_ghosts(d_dim, 0);
+ for (hier::PatchLevel::Iterator pi(*level); pi; pi++) {
+
+ hier::Patch& patch = **pi;
+
+ tbox::Pointer<geom::CartesianPatchGeometry> pg =
+ patch.getPatchGeometry();
+
+ const double* h = pg->getDx();
+
+ const hier::Box patch_box = patch.getBox();
+ const hier::Index patch_lo = patch_box.lower();
+ const hier::Index patch_up = patch_box.upper();
+
+ if (!spec.cIsZero() && !spec.cIsConstant()) {
+ C_data = patch.getPatchData(spec.getCPatchDataId());
+ if (C_data.isNull()) {
+ TBOX_ERROR(d_object_name << ": Invalid cell variable index "
+ << spec.getCPatchDataId()
+ << " for the C parameter. It is not\n"
+ << "cell-centered double data.");
+ }
+ }
+
+ if (!spec.dIsConstant()) {
+ D_data = patch.getPatchData(spec.getDPatchDataId());
+ if (D_data.isNull()) {
+ TBOX_ERROR(d_object_name << ": Invalid cell variable index "
+ << spec.getDPatchDataId()
+ <<
+ " for diffusion coefficient. It is not\n"
+ << "side-centered double data.");
+ }
+ }
+
+ Ak0 = patch.getPatchData(d_Ak0_id);
+
+ Ak0->fillAll(0.0);
+
+ pdat::CellData<double> diagonal(patch_box, 1, no_ghosts);
+
+ /*
+ * Set diagonals to zero so we can accumulate to it.
+ * Accumulation is used at boundaries to shift weights
+ * for ghost cells onto the diagonal.
+ */
+ diagonal.fillAll(0.0);
+
+ const tbox::Pointer<geom::CartesianPatchGeometry>
+ geometry = patch.getPatchGeometry();
+
+ const hier::Index ifirst = patch_box.lower();
+ const hier::Index ilast = patch_box.upper();
+
+ /*
+ * Storage for off-diagonal entries,
+ * which can be variable or constant.
+ */
+ pdat::SideData<double> off_diagonal(patch_box, 1, no_ghosts);
+
+ /*
+ * Compute all off-diagonal entries with no regard to BCs.
+ * These off-diagonal entries are simply D/(h*h), according
+ * to our central difference formula.
+ */
+ if (spec.dIsConstant()) {
+ for (i = 0; i < d_dim.getValue(); ++i) {
+ double dhh = spec.getDConstant() / (h[i] * h[i]);
+ pdat::ArrayData<double>& off_diag_array(off_diagonal.getArrayData(i));
+ off_diag_array.fill(dhh);
+ }
+ } else {
+ for (i = 0; i < d_dim.getValue(); ++i) {
+ hier::Box sbox(patch_box);
+ sbox.growUpper(i, 1);
+ array_math.scale(off_diagonal.getArrayData(i),
+ 1.0 / (h[i] * h[i]),
+ D_data->getArrayData(i),
+ sbox);
+ }
+ }
+
+ /*
+ * Compute diagonal entries using off-diagonal contributions.
+ */
+ if (spec.cIsZero()) {
+ computeDiagonalEntries(diagonal,
+ off_diagonal,
+ patch_box);
+ } else if (spec.cIsConstant()) {
+ computeDiagonalEntries(diagonal,
+ spec.getCConstant(),
+ off_diagonal,
+ patch_box);
+ } else {
+ computeDiagonalEntries(diagonal,
+ *C_data,
+ off_diagonal,
+ patch_box);
+ }
+
+ /*
+ * Walk physical domain boundaries and adjust off-diagonals
+ * before computation of diagonal entries.
+ * The exterior cell's value is
+ * uo = ( h*gamma + ui*(beta-h*alpha/2) )/( beta+h*alpha/2 )
+ * = k0 + k1*ui
+ * where k0 = h*gamma/( beta+h*alpha/2 )
+ * k1 = ( beta-h*alpha/2 )/( beta+h*alpha/2 )
+ * Split coupling between interior-exterior cells
+ * into two parts: interior-interior coupling (k1)
+ * and rhs contribution (k0).
+ */
+ {
+ const tbox::Array<hier::BoundaryBox>& surface_boxes =
+ pg->getCodimensionBoundaries(1);
+ const int n_bdry_boxes = surface_boxes.getSize();
+ for (int n = 0; n < n_bdry_boxes; ++n) {
+
+ const hier::BoundaryBox& boundary_box = surface_boxes[n];
+ if (boundary_box.getBoundaryType() != 1) {
+ TBOX_ERROR(
+ d_object_name << ": Illegal boundary type in "
+ <<
+ "CellStokesHypreSolver::setMatrixCoefficients\n");
+ }
+ const hier::BoundaryBoxUtils bbu(boundary_box);
+ const int location_index = boundary_box.getLocationIndex();
+ const hier::BoundaryBox trimmed_boundary_box =
+ bbu.trimBoundaryBox(patch.getBox());
+ const hier::Box bccoef_box =
+ bbu.getSurfaceBoxFromBoundaryBox();
+ tbox::Pointer<pdat::ArrayData<double> >
+ acoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
+ tbox::Pointer<pdat::ArrayData<double> >
+ bcoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
+ tbox::Pointer<pdat::ArrayData<double> >
+ gcoef_data(NULL);
+ static const double fill_time = 0.0;
+ d_physical_bc_coef_strategy->setBcCoefs(acoef_data,
+ bcoef_data,
+ gcoef_data,
+ d_physical_bc_variable,
+ patch,
+ boundary_box,
+ fill_time);
+ pdat::ArrayData<double>& Ak0_data =
+ Ak0->getArrayData(location_index / 2,
+ location_index % 2);
+ adjustBoundaryEntries(diagonal,
+ off_diagonal,
+ patch_box,
+ *acoef_data,
+ *bcoef_data,
+ bccoef_box,
+ Ak0_data,
+ trimmed_boundary_box,
+ h);
+ }
+ }
+
+ /*
+ * Walk coarse-fine boundaries and adjust off-diagonals
+ * according data in ghost cells.
+ */
+ if (d_ln > 0) {
+ /*
+ * There are potentially coarse-fine boundaries to deal with.
+ */
+
+ tbox::Array<hier::BoundaryBox> surface_boxes;
+
+ if (d_dim == tbox::Dimension(2)) {
+ surface_boxes = d_cf_boundary->getEdgeBoundaries(pi->getGlobalId());
+ } else if (d_dim == tbox::Dimension(3)) {
+ surface_boxes = d_cf_boundary->getFaceBoundaries(pi->getGlobalId());
+ }
+
+ const int n_bdry_boxes = surface_boxes.getSize();
+ for (int n = 0; n < n_bdry_boxes; ++n) {
+
+ const hier::BoundaryBox& boundary_box = surface_boxes[n];
+ if (boundary_box.getBoundaryType() != 1) {
+ TBOX_ERROR(
+ d_object_name << ": Illegal boundary type in "
+ <<
+ "CellStokesHypreSolver::setMatrixCoefficients\n");
+ }
+ const int location_index = boundary_box.getLocationIndex();
+ const hier::BoundaryBoxUtils bbu(boundary_box);
+ const hier::BoundaryBox trimmed_boundary_box =
+ bbu.trimBoundaryBox(patch.getBox());
+ const hier::Box bccoef_box =
+ bbu.getSurfaceBoxFromBoundaryBox();
+ tbox::Pointer<pdat::ArrayData<double> >
+ acoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
+ tbox::Pointer<pdat::ArrayData<double> >
+ bcoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
+ tbox::Pointer<pdat::ArrayData<double> >
+ gcoef_data(NULL);
+ static const double fill_time = 0.0;
+ /*
+ * Reset invalid ghost data id to help detect use in setBcCoefs.
+ */
+ d_cf_bc_coef.setGhostDataId(-1, hier::IntVector::getZero(d_dim));
+ d_cf_bc_coef.setBcCoefs(acoef_data,
+ bcoef_data,
+ gcoef_data,
+ d_coarsefine_bc_variable,
+ patch,
+ boundary_box,
+ fill_time);
+ pdat::ArrayData<double>& Ak0_data =
+ Ak0->getArrayData(location_index / 2,
+ location_index % 2);
+ adjustBoundaryEntries(diagonal,
+ off_diagonal,
+ patch_box,
+ *acoef_data,
+ *bcoef_data,
+ bccoef_box,
+ Ak0_data,
+ trimmed_boundary_box,
+ h);
+ }
+ }
+
+ /*
+ * Copy matrix entries to HYPRE matrix structure. Note that
+ * we translate our temporary diagonal/off-diagonal storage into the
+ * HYPRE symmetric storage scheme for the stencil specified earlier.
+ */
+ const int stencil_size = d_dim.getValue() + 1;
+ int stencil_indices[stencil_size];
+ double mat_entries[stencil_size];
+
+ for (i = 0; i < stencil_size; i++) stencil_indices[i] = i;
+
+ pdat::CellIterator ic(patch_box);
+
+ /*
+ * To do: This loop uses inefficient high-level syntax.
+ * See if it can be replaced by a Fortran loop or if we
+ * can set matrix entries for an entire box at once.
+ */
+ for ( ; ic; ic++) {
+
+ hier::IntVector icell = ic();
+ pdat::SideIndex ixlower(ic(),
+ pdat::SideIndex::X,
+ pdat::SideIndex::Lower);
+ mat_entries[0] = (off_diagonal)(ixlower);
+
+ if (d_dim > tbox::Dimension(1)) {
+ pdat::SideIndex iylower(ic(),
+ pdat::SideIndex::Y,
+ pdat::SideIndex::Lower);
+ mat_entries[1] = (off_diagonal)(iylower);
+ }
+
+ if (d_dim > tbox::Dimension(2)) {
+ pdat::SideIndex izlower(ic(),
+ pdat::SideIndex::Z,
+ pdat::SideIndex::Lower);
+ // The "funny" indexing prevents a warning when compiling for
+ // DIM < 2. This code is only reached if DIM > 2 when
+ // executing.
+ mat_entries[d_dim.getValue() > 2 ? 2 : 0] = (off_diagonal)(izlower);
+ }
+
+ mat_entries[d_dim.getValue()] = (diagonal)(ic());
+ HYPRE_StructMatrixSetValues(d_matrix, &icell[0],
+ stencil_size, stencil_indices,
+ mat_entries);
+ } // end cell loop
+
+ } // end patch loop
+
+ if (d_print_solver_info) {
+ HYPRE_StructMatrixPrint("mat_bA.out", d_matrix, 1);
+ }
+
+ HYPRE_StructMatrixAssemble(d_matrix);
+
+ if (d_print_solver_info) {
+ HYPRE_StructMatrixPrint("mat_aA.out", d_matrix, 1);
+ }
+
+ t_set_matrix_coefficients->stop();
+
+ setupHypreSolver();
+}
+
+/*
+ **********************************************************************
+ * Add g*A*k0(a) from physical boundaries to rhs. *
+ * This operation is done for physical as well as cf boundaries, *
+ * so it is placed in a function. *
+ **********************************************************************
+ */
+
+void CellStokesHypreSolver::add_gAk0_toRhs(
+ const hier::Patch& patch,
+ const tbox::Array<hier::BoundaryBox>& bdry_boxes,
+ const RobinBcCoefStrategy* robin_bc_coef,
+ pdat::CellData<double>& rhs)
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS2(d_dim, patch, rhs);
+
+ /*
+ * g*A*k0(a) is the storage for adjustments to be made to the rhs
+ * when we solve. This is the value of the weight of the ghost cell
+ * value for the interior cell, times k0. It is independent of u,
+ * and so is moved to the rhs. Before solving, g*A*k0(a) is added
+ * to rhs.
+ */
+ tbox::Pointer<pdat::OutersideData<double> > Ak0;
+
+ tbox::Pointer<geom::CartesianPatchGeometry> pg =
+ patch.getPatchGeometry();
+
+ Ak0 = patch.getPatchData(d_Ak0_id);
+
+ const int n_bdry_boxes = bdry_boxes.getSize();
+ for (int n = 0; n < n_bdry_boxes; ++n) {
+
+ const hier::BoundaryBox& boundary_box = bdry_boxes[n];
+#ifdef DEBUG_CHECK_ASSERTIONS
+ if (boundary_box.getBoundaryType() != 1) {
+ TBOX_ERROR(d_object_name << ": Illegal boundary type in "
+ << "CellStokesHypreSolver::add_gAk0_toRhs\n");
+ }
+#endif
+ const int location_index = boundary_box.getLocationIndex();
+ const hier::BoundaryBoxUtils bbu(boundary_box);
+ const hier::BoundaryBox trimmed_boundary_box =
+ bbu.trimBoundaryBox(patch.getBox());
+ const hier::Index& lower = trimmed_boundary_box.getBox().lower();
+ const hier::Index& upper = trimmed_boundary_box.getBox().upper();
+ const hier::Box& rhsbox = rhs.getArrayData().getBox();
+ const hier::Box& Ak0box = Ak0->getArrayData(location_index / 2,
+ location_index % 2).getBox();
+ const hier::Box bccoef_box = bbu.getSurfaceBoxFromBoundaryBox();
+ tbox::Pointer<pdat::ArrayData<double> >
+ acoef_data(NULL);
+ tbox::Pointer<pdat::ArrayData<double> >
+ bcoef_data(NULL);
+ tbox::Pointer<pdat::ArrayData<double> >
+ gcoef_data(new pdat::ArrayData<double>(bccoef_box, 1));
+ static const double fill_time = 0.0;
+ robin_bc_coef->setBcCoefs(acoef_data,
+ bcoef_data,
+ gcoef_data,
+ d_physical_bc_variable,
+ patch,
+ boundary_box,
+ fill_time);
+ /*
+ * Nomenclature for indices: cel=first-cell, gho=ghost,
+ * beg=beginning, end=ending.
+ */
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(adjustrhs2d, ADJUSTRHS2D) (rhs.getPointer(d_rhs_depth),
+ &rhsbox.lower()[0],
+ &rhsbox.upper()[0],
+ &rhsbox.lower()[1],
+ &rhsbox.upper()[1],
+ Ak0->getPointer(location_index / 2, location_index % 2),
+ &Ak0box.lower()[0],
+ &Ak0box.upper()[0],
+ &Ak0box.lower()[1],
+ &Ak0box.upper()[1],
+ gcoef_data->getPointer(),
+ &bccoef_box.lower()[0],
+ &bccoef_box.upper()[0],
+ &bccoef_box.lower()[1],
+ &bccoef_box.upper()[1],
+ &lower[0], &upper[0],
+ &location_index);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(adjustrhs3d, ADJUSTRHS3D) (rhs.getPointer(d_rhs_depth),
+ &rhsbox.lower()[0],
+ &rhsbox.upper()[0],
+ &rhsbox.lower()[1],
+ &rhsbox.upper()[1],
+ &rhsbox.lower()[2],
+ &rhsbox.upper()[2],
+ Ak0->getPointer(location_index / 2, location_index % 2),
+ &Ak0box.lower()[0],
+ &Ak0box.upper()[0],
+ &Ak0box.lower()[1],
+ &Ak0box.upper()[1],
+ &Ak0box.lower()[2],
+ &Ak0box.upper()[2],
+ gcoef_data->getPointer(),
+ &bccoef_box.lower()[0],
+ &bccoef_box.upper()[0],
+ &bccoef_box.lower()[1],
+ &bccoef_box.upper()[1],
+ &bccoef_box.lower()[2],
+ &bccoef_box.upper()[2],
+ &lower[0], &upper[0],
+ &location_index);
+ }
+ }
+}
+
+/*
+ *************************************************************************
+ * Create the hypre solver and set it according to the current state. *
+ *************************************************************************
+ */
+void CellStokesHypreSolver::setupHypreSolver()
+{
+ TBOX_ASSERT(d_mg_data == NULL);
+
+ tbox::SAMRAI_MPI::Comm communicator = d_hierarchy->getDomainMappedBoxLevel().getMPI().getCommunicator();
+
+ if (d_use_smg) {
+ HYPRE_StructSMGCreate(communicator, &d_mg_data);
+ HYPRE_StructSMGSetMemoryUse(d_mg_data, 0);
+ HYPRE_StructSMGSetMaxIter(d_mg_data, d_max_iterations);
+ HYPRE_StructSMGSetTol(d_mg_data, d_relative_residual_tol);
+ HYPRE_StructSMGSetLogging(d_mg_data, 1);
+ HYPRE_StructSMGSetNumPreRelax(d_mg_data,
+ d_num_pre_relax_steps);
+ HYPRE_StructSMGSetNumPostRelax(d_mg_data,
+ d_num_post_relax_steps);
+ HYPRE_StructSMGSetup(d_mg_data,
+ d_matrix,
+ d_linear_rhs,
+ d_linear_sol);
+ } else {
+ HYPRE_StructPFMGCreate(communicator, &d_mg_data);
+ HYPRE_StructPFMGSetMaxIter(d_mg_data, d_max_iterations);
+ HYPRE_StructPFMGSetTol(d_mg_data, d_relative_residual_tol);
+ HYPRE_StructPFMGSetLogging(d_mg_data, 1);
+ HYPRE_StructPFMGSetNumPreRelax(d_mg_data,
+ d_num_pre_relax_steps);
+ HYPRE_StructPFMGSetNumPostRelax(d_mg_data,
+ d_num_post_relax_steps);
+ HYPRE_StructPFMGSetup(d_mg_data,
+ d_matrix,
+ d_linear_rhs,
+ d_linear_sol);
+ }
+}
+
+void CellStokesHypreSolver::destroyHypreSolver()
+{
+ if (d_mg_data != NULL) {
+ if (d_use_smg) {
+ HYPRE_StructSMGDestroy(d_mg_data);
+ } else {
+ HYPRE_StructPFMGDestroy(d_mg_data);
+ }
+ d_mg_data = NULL;
+ }
+}
+
+/*
+ *************************************************************************
+ * *
+ * Solve the linear system. This routine assumes that the boundary *
+ * conditions and the matrix coefficients have been specified. *
+ * *
+ *************************************************************************
+ */
+
+int CellStokesHypreSolver::solveSystem(
+ const int u,
+ const int f,
+ bool homogeneous_bc)
+{
+ if (d_physical_bc_coef_strategy == NULL) {
+ TBOX_ERROR(
+ d_object_name << ": No BC coefficient strategy object!\n"
+ <<
+ "Use either setBoundaries or setPhysicalBcCoefObject\n"
+ <<
+ "to specify the boundary conidition. Do it before\n"
+ << "calling solveSystem.");
+ }
+ // Tracer t("CellStokesHypreSolver::solveSystem");
+
+ t_solve_system->start();
+
+ tbox::Pointer<hier::PatchLevel> level = d_hierarchy->getPatchLevel(d_ln);
+#ifdef DEBUG_CHECK_ASSERTIONS
+ TBOX_ASSERT(u >= 0);
+ TBOX_ASSERT(
+ u < level->getPatchDescriptor()->getMaxNumberRegisteredComponents());
+ TBOX_ASSERT(f >= 0);
+ TBOX_ASSERT(
+ f < level->getPatchDescriptor()->getMaxNumberRegisteredComponents());
+#endif
+
+ if (d_physical_bc_coef_strategy == &d_physical_bc_simple_case) {
+ /*
+ * If we are using the simple bc implementation, the final piece
+ * of information it requires is the Dirichlet boundary value
+ * set in the ghost cells. Now that we have the ghost cell data,
+ * we can complete the boundary condition setup.
+ */
+ d_physical_bc_simple_case.cacheDirichletData(u);
+ }
+
+ /*
+ * Modify right-hand-side to account for boundary conditions and
+ * copy solution and right-hand-side to HYPRE structures.
+ */
+
+ const hier::IntVector no_ghosts(d_dim, 0);
+ const hier::IntVector ghosts(d_dim, 1);
+
+ /*
+ * At coarse-fine boundaries, we expect ghost cells to have correct
+ * values to be used in our bc, so u provides the ghost cell data.
+ * Assume that the user only provided data for the immediate first
+ * ghost cell, so pass zero for the number of extensions fillable.
+ */
+ d_cf_bc_coef.setGhostDataId(u, hier::IntVector::getZero(d_dim));
+
+ for (hier::PatchLevel::Iterator p(level); p; p++) {
+ tbox::Pointer<hier::Patch> patch = *p;
+
+ const hier::Box box = patch->getBox();
+
+ /*
+ * Set up variable data needed to prepare linear system solver.
+ */
+ tbox::Pointer<pdat::CellData<double> > u_data_ = patch->getPatchData(u);
+#ifdef DEBUG_CHECK_ASSERTIONS
+ TBOX_ASSERT(!u_data_.isNull());
+#endif
+ pdat::CellData<double>& u_data = *u_data_;
+ pdat::CellData<double> rhs_data(box, 1, no_ghosts);
+
+ /*
+ * Copy rhs and solution from the hierarchy into HYPRE structures.
+ * For rhs, add in the contribution from boundary conditions, if
+ * needed. If boundary condition is homogenous, this only adds
+ * zero, so we skip it.
+ */
+ copyToHypre(d_linear_sol, u_data, d_soln_depth, box);
+ rhs_data.copy(*(patch->getPatchData(f)));
+ if (!homogeneous_bc) {
+ /*
+ * Add g*A*k0(a) from physical and coarse-fine boundaries to rhs.
+ */
+ add_gAk0_toRhs(*patch,
+ patch->getPatchGeometry()->getCodimensionBoundaries(1),
+ d_physical_bc_coef_strategy,
+ rhs_data);
+ add_gAk0_toRhs(*patch,
+ d_cf_boundary->getBoundaries(patch->getGlobalId(), 1),
+ &d_cf_bc_coef,
+ rhs_data);
+ }
+ copyToHypre(d_linear_rhs, rhs_data, d_rhs_depth, box);
+
+ } // end patch loop
+
+ /*
+ * Reset invalid ghost data id to help detect erroneous further use.
+ */
+ d_cf_bc_coef.setGhostDataId(-1, hier::IntVector::getZero(d_dim));
+
+ /*
+ * Finish assembly of the vectors
+ */
+ HYPRE_StructVectorAssemble(d_linear_sol);
+
+ HYPRE_StructVectorAssemble(d_linear_rhs);
+
+ /*
+ * Solve the system - zero means convergence
+ * Solve takes the same arguments as Setup
+ */
+
+ if (d_print_solver_info) {
+ HYPRE_StructVectorPrint("sol0.out", d_linear_sol, 1);
+ HYPRE_StructMatrixPrint("mat0.out", d_matrix, 1);
+ HYPRE_StructVectorPrint("rhs.out", d_linear_rhs, 1);
+ }
+
+ if (d_use_smg) {
+ // HYPRE_StructSMGSetMaxIter(d_mg_data, d_max_iterations);
+ HYPRE_StructSMGSetTol(d_mg_data, d_relative_residual_tol);
+ /* converge = */ HYPRE_StructSMGSolve(d_mg_data,
+ d_matrix,
+ d_linear_rhs,
+ d_linear_sol);
+ } else {
+ // HYPRE_StructPFMGSetMaxIter(d_mg_data, d_max_iterations);
+ HYPRE_StructPFMGSetTol(d_mg_data, d_relative_residual_tol);
+ /* converge = */ HYPRE_StructPFMGSolve(d_mg_data,
+ d_matrix,
+ d_linear_rhs,
+ d_linear_sol);
+ }
+
+ if (d_print_solver_info) {
+ HYPRE_StructMatrixPrint("mat.out", d_matrix, 1);
+ HYPRE_StructVectorPrint("sol.out", d_linear_sol, 1);
+ }
+
+ if (d_use_smg) {
+ HYPRE_StructSMGGetNumIterations(d_mg_data,
+ &d_number_iterations);
+ HYPRE_StructSMGGetFinalRelativeResidualNorm(d_mg_data,
+ &d_relative_residual_norm);
+ } else {
+ HYPRE_StructPFMGGetNumIterations(d_mg_data,
+ &d_number_iterations);
+ HYPRE_StructPFMGGetFinalRelativeResidualNorm(d_mg_data,
+ &d_relative_residual_norm);
+ }
+
+ /*
+ * Pull the solution vector out of the HYPRE structures
+ */
+ for (hier::PatchLevel::Iterator ip(level); ip; ip++) {
+ tbox::Pointer<hier::Patch> patch = *ip;
+ tbox::Pointer<pdat::CellData<double> > u_data_ = patch->getPatchData(u);
+ pdat::CellData<double>& u_data = *u_data_;
+ copyFromHypre(u_data,
+ d_soln_depth,
+ d_linear_sol,
+ patch->getBox());
+ }
+
+ t_solve_system->stop();
+
+ return d_relative_residual_norm <= d_relative_residual_tol;
+}
+
+void CellStokesHypreSolver::computeDiagonalEntries(
+ pdat::CellData<double>& diagonal,
+ const pdat::CellData<double>& C_data,
+ const pdat::SideData<double>& off_diagonal,
+ const hier::Box& patch_box)
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS4(d_dim,
+ diagonal,
+ C_data,
+ off_diagonal,
+ patch_box);
+
+ const hier::Index patch_lo = patch_box.lower();
+ const hier::Index patch_up = patch_box.upper();
+ const double c = 1.0, d = 1.0;
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compdiagvariablec2d, COMPDIAGVARIABLEC2D) (diagonal.getPointer(),
+ C_data.getPointer(),
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &c, &d);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compdiagvariablec3d, COMPDIAGVARIABLEC3D) (diagonal.getPointer(),
+ C_data.getPointer(),
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ off_diagonal.getPointer(2),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &patch_lo[2], &patch_up[2],
+ &c, &d);
+ }
+}
+
+void CellStokesHypreSolver::computeDiagonalEntries(
+ pdat::CellData<double>& diagonal,
+ const double C,
+ const pdat::SideData<double>& off_diagonal,
+ const hier::Box& patch_box)
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS3(d_dim, diagonal, off_diagonal, patch_box);
+
+ const hier::Index patch_lo = patch_box.lower();
+ const hier::Index patch_up = patch_box.upper();
+ const double c = 1.0, d = 1.0;
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compdiagscalarc2d, COMPDIAGSCALARC2D) (diagonal.getPointer(),
+ &C,
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &c, &d);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compdiagscalarc3d, COMPDIAGSCALARC3D) (diagonal.getPointer(),
+ &C,
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ off_diagonal.getPointer(2),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &patch_lo[2], &patch_up[2],
+ &c, &d);
+ } else {
+ TBOX_ERROR("CellStokesHypreSolver error...\n"
+ << "DIM > 3 not supported." << std::endl);
+ }
+}
+
+void CellStokesHypreSolver::computeDiagonalEntries(
+ pdat::CellData<double>& diagonal,
+ const pdat::SideData<double>& off_diagonal,
+ const hier::Box& patch_box)
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS3(d_dim, diagonal, off_diagonal, patch_box);
+
+ const hier::Index patch_lo = patch_box.lower();
+ const hier::Index patch_up = patch_box.upper();
+ const double c = 1.0, d = 1.0;
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(compdiagzeroc2d, COMPDIAGZEROC2D) (diagonal.getPointer(),
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &c, &d);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(compdiagzeroc3d, COMPDIAGZEROC3D) (diagonal.getPointer(),
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ off_diagonal.getPointer(2),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &patch_lo[2], &patch_up[2],
+ &c, &d);
+ } else {
+ TBOX_ERROR("CellStokesHypreSolver error...\n"
+ << "DIM > 3 not supported." << std::endl);
+ }
+}
+
+void CellStokesHypreSolver::adjustBoundaryEntries(
+ pdat::CellData<double>& diagonal,
+ const pdat::SideData<double>& off_diagonal,
+ const hier::Box& patch_box,
+ const pdat::ArrayData<double>& acoef_data,
+ const pdat::ArrayData<double>& bcoef_data,
+ const hier::Box bccoef_box,
+ pdat::ArrayData<double>& Ak0_data,
+ const hier::BoundaryBox& trimmed_boundary_box,
+ const double h[tbox::Dimension::MAXIMUM_DIMENSION_VALUE])
+{
+ TBOX_DIM_ASSERT_CHECK_DIM_ARGS8(d_dim, diagonal, off_diagonal, patch_box,
+ acoef_data, bcoef_data,
+ bccoef_box, Ak0_data, trimmed_boundary_box);
+
+ const hier::Index patch_lo = patch_box.lower();
+ const hier::Index patch_up = patch_box.upper();
+ const int location_index = trimmed_boundary_box.getLocationIndex();
+ const hier::Index& lower = trimmed_boundary_box.getBox().lower();
+ const hier::Index& upper = trimmed_boundary_box.getBox().upper();
+ const hier::Box& Ak0_box = Ak0_data.getBox();
+ if (d_dim == tbox::Dimension(2)) {
+ F77_FUNC(adjbdry2d, ADJBDRY2D) (diagonal.getPointer(),
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ acoef_data.getPointer(),
+ bcoef_data.getPointer(),
+ &bccoef_box.lower()[0],
+ &bccoef_box.upper()[0],
+ &bccoef_box.lower()[1],
+ &bccoef_box.upper()[1],
+ Ak0_data.getPointer(),
+ &Ak0_box.lower()[0],
+ &Ak0_box.upper()[0],
+ &Ak0_box.lower()[1],
+ &Ak0_box.upper()[1],
+ &lower[0], &upper[0],
+ &location_index, h);
+ } else if (d_dim == tbox::Dimension(3)) {
+ F77_FUNC(adjbdry3d, ADJBDRY3D) (diagonal.getPointer(),
+ off_diagonal.getPointer(0),
+ off_diagonal.getPointer(1),
+ off_diagonal.getPointer(2),
+ &patch_lo[0], &patch_up[0],
+ &patch_lo[1], &patch_up[1],
+ &patch_lo[2], &patch_up[2],
+ acoef_data.getPointer(),
+ bcoef_data.getPointer(),
+ &bccoef_box.lower()[0],
+ &bccoef_box.upper()[0],
+ &bccoef_box.lower()[1],
+ &bccoef_box.upper()[1],
+ &bccoef_box.lower()[2],
+ &bccoef_box.upper()[2],
+ Ak0_data.getPointer(),
+ &Ak0_box.lower()[0],
+ &Ak0_box.upper()[0],
+ &Ak0_box.lower()[1],
+ &Ak0_box.upper()[1],
+ &Ak0_box.lower()[2],
+ &Ak0_box.upper()[2],
+ &lower[0], &upper[0],
+ &location_index, h);
+ } else {
+ TBOX_ERROR("CellStokesHypreSolver error...\n"
+ << "DIM > 3 not supported." << std::endl);
+ }
+}
+
+void
+CellStokesHypreSolver::finalizeCallback()
+{
+ for (int d = 0; d < tbox::Dimension::MAXIMUM_DIMENSION_VALUE; ++d) {
+ s_Ak0_var[d].setNull();
+ }
+}
+
+}
+}
+
+#endif
+#endif
diff -r a44a82f15794 -r fe2a9230921b StokesHypreSolver.I
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesHypreSolver.I Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,121 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: Level solver for diffusion-like elliptic problems.
+ *
+ ************************************************************************/
+namespace SAMRAI {
+namespace solv {
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setSolnIdDepth(
+ const int depth) {
+ d_soln_depth = depth;
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setRhsIdDepth(
+ const int depth) {
+ d_rhs_depth = depth;
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setUseSMG(
+ bool use_smg) {
+ d_use_smg = use_smg;
+}
+
+/*
+ ********************************************************************
+ * Specify bc using the default internal bc coefficient object. *
+ * Clear up data supporting external bc coefficient setter. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setBoundaries(
+ const std::string& boundary_type,
+ const int fluxes,
+ const int flags,
+ int* bdry_types)
+{
+ d_physical_bc_simple_case.setBoundaries(boundary_type,
+ fluxes,
+ flags,
+ bdry_types);
+ d_physical_bc_coef_strategy = &d_physical_bc_simple_case;
+ d_physical_bc_variable.setNull();
+}
+
+/*
+ ********************************************************************
+ * Set the physical boundary condition object. *
+ ********************************************************************
+ */
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setPhysicalBcCoefObject(
+ const RobinBcCoefStrategy* physical_bc_coef_strategy,
+ const tbox::Pointer<hier::Variable> variable)
+{
+ d_physical_bc_coef_strategy = physical_bc_coef_strategy;
+ d_physical_bc_variable = variable;
+}
+
+SAMRAI_INLINE_KEYWORD
+int CellStokesHypreSolver::getNumberOfIterations() const
+{
+ return d_number_iterations;
+}
+
+SAMRAI_INLINE_KEYWORD
+double CellStokesHypreSolver::getRelativeResidualNorm() const
+{
+ return d_relative_residual_norm;
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setNumPreRelaxSteps(
+ const int steps)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ TBOX_ASSERT(!d_hierarchy.isNull());
+#endif
+ d_num_pre_relax_steps = steps;
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setNumPostRelaxSteps(
+ const int steps)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ TBOX_ASSERT(!d_hierarchy.isNull());
+#endif
+ d_num_post_relax_steps = steps;
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setPrintSolverInfo(
+ const bool print)
+{
+ d_print_solver_info = print;
+}
+
+SAMRAI_INLINE_KEYWORD
+void CellStokesHypreSolver::setStoppingCriteria(
+ const int max_iterations,
+ const double residual_tol)
+{
+#ifdef DEBUG_CHECK_ASSERTIONS
+ TBOX_ASSERT(max_iterations >= 0);
+ TBOX_ASSERT(residual_tol >= 0.0);
+#endif
+ d_max_iterations = max_iterations;
+ d_relative_residual_tol = residual_tol;
+}
+
+}
+}
diff -r a44a82f15794 -r fe2a9230921b StokesHypreSolver.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StokesHypreSolver.h Fri Dec 31 12:10:26 2010 -0800
@@ -0,0 +1,617 @@
+/*************************************************************************
+ *
+ * This file is part of the SAMRAI distribution. For full copyright
+ * information, see COPYRIGHT and COPYING.LESSER.
+ *
+ * Copyright: (c) 1997-2010 Lawrence Livermore National Security, LLC
+ * Description: Hypre solver interface for diffusion-like elliptic problems.
+ *
+ ************************************************************************/
+#ifndef included_solv_StokesHypreSolver
+#define included_solv_StokesHypreSolver
+
+#include "SAMRAI/SAMRAI_config.h"
+
+#ifdef HAVE_HYPRE
+
+#ifndef included_HYPRE_struct_ls
+/*
+ * This might break things if F77_FUNC_ is different for hypre vs
+ * SAMRAI autoconf detection. But then C/C++ macros are totally
+ * broken due to namespace collision as this example highlights so
+ * resorting to hacks are necessary.
+ */
+#ifdef F77_FUNC_
+#undef F77_FUNC_
+#endif
+#include "HYPRE_struct_ls.h"
+#define included_HYPRE_struct_ls
+#endif
+
+#include "SAMRAI/solv/GhostCellRobinBcCoefs.h"
+#include "SAMRAI/solv/RobinBcCoefStrategy.h"
+#include "StokesSpecifications.h"
+#include "SAMRAI/solv/SimpleCellRobinBcCoefs.h"
+#include "SAMRAI/pdat/CellData.h"
+#include "SAMRAI/pdat/SideData.h"
+#include "SAMRAI/pdat/OutersideVariable.h"
+#include "SAMRAI/hier/BoxList.h"
+#include "SAMRAI/hier/CoarseFineBoundary.h"
+#include "SAMRAI/hier/PatchHierarchy.h"
+#include "SAMRAI/hier/PatchLevel.h"
+#include "SAMRAI/hier/VariableContext.h"
+#include "SAMRAI/tbox/Database.h"
+#include "SAMRAI/tbox/Pointer.h"
+
+#include <string>
+
+namespace SAMRAI {
+namespace solv {
+
+/*!
+ * @brief Use the HYPRE preconditioner library to solve (the cell-centered)
+ * Stokes's equation on a single level in a hierarchy.
+ *
+ * Class CellStokesHypreSolver uses the HYPRE preconditioner library
+ * to solve linear equations of the form
+ * @f$ \nabla ( D \nabla u ) + C u = f @f$, where
+ * C is a cell-centered array, D is a face-centered array,
+ * and u and f are cell-centered arrays
+ * (see StokesSpecifications).
+ * The discretization is the standard second order
+ * finite difference stencil.
+ *
+ * Robin boundary conditions are used through the
+ * interface class RobinBcCoefStrategy.
+ * Periodic boundary conditions are not supported yet.
+ *
+ * The user must perform the following steps to use
+ * CellStokesHypreSolver:
+ * - Create a CellStokesHypreSolver object.
+ * - Initialize CellStokesHypreSolver object with a patch hierarchy,
+ * using the function initializeSolverState().
+ * - Use the functions setPhysicalBcCoefObject()
+ * to provide implementations of RobinBcCoefStrategy.
+ * (For most problems you can probably find a suitable
+ * implementation to use without implementing the
+ * strategy yourself. See for example
+ * SimpleCellRobinBcCoefs and GhostCellRobinBcCoefs.)
+ * - Set the matrix coefficients in the linear system,
+ * using the function setMatrixCoefficients().
+ * - Specify the stopping criteria using setStoppingCriteria().
+ * - Solve the linear system, passing in u and f as the patch
+ * indices of the solution and the right hand side, respectively.
+ *
+ * Sample parameters for initialization from database (and their
+ * default values):
+ * @verbatim
+ * print_solver_info = FALSE // Whether to print some data for debugging
+ * max_iterations = 10 // Max iterations used by Hypre
+ * relative_residual_tol = 1.0e-8 // Residual tolerance used by Hypre
+ * num_pre_relax_steps = 1 // # of presmoothing steps used by Hypre
+ * num_post_relax_steps = 1 // # of postsmoothing steps used by Hypre
+ * use_smg = FALSE // Whether to use hypre's smg solver
+ * // (alternative is the pfmg solver)
+ * @endverbatim
+ */
+
+class CellStokesHypreSolver
+{
+public:
+ /*!
+ * @brief Constructor.
+ *
+ * @param object_name Name of object.
+ * @param database tbox::Database for input.
+ */
+ CellStokesHypreSolver(
+ const tbox::Dimension& dim,
+ const std::string& object_name,
+ tbox::Pointer<tbox::Database> database =
+ tbox::Pointer<tbox::Database>(NULL));
+
+ /*!
+ * The Stokes destructor releases all internally managed data.
+ */
+ ~CellStokesHypreSolver();
+
+ /*!
+ * @brief Initialize to a given hierarchy.
+ *
+ * Initializer Stokes solver for a patch level in a hierarchy.
+ *
+ * @param hierarchy Hierarchy
+ * @param ln Level number
+ */
+ void
+ initializeSolverState(
+ tbox::Pointer<hier::PatchHierarchy> hierarchy,
+ int ln = 0);
+
+ /*!
+ * @brief Reset to an uninitialized state.
+ */
+ void
+ deallocateSolverState();
+
+ /*!
+ * @brief Set the matrix coefficients
+ *
+ * For information describing the Stokes equation parameters,
+ * see the light-weight StokesSpecifications class where
+ * you set the values of C and D.
+ *
+ * This method must be called before solveSystem().
+ */
+ void
+ setMatrixCoefficients(
+ const StokesSpecifications& spec);
+
+ /*!
+ * @brief Set default depth of the solution data involved in the solve.
+ *
+ * If the solution data has multiple depths,
+ * the solver uses just one depth at a time.
+ * The default depth is the first depth.
+ * Use this function to change it.
+ * This is not used to set the depth of the data (which is not
+ * controled by this class) but the depth used in the solve.
+ *
+ * Changing the depth after setting up the matrix is permissible,
+ * as the solution data does not affect the matrix.
+ */
+ void
+ setSolnIdDepth(
+ const int depth);
+
+ /*!
+ * @brief Set default depth of the rhs data involved in the solve.
+ *
+ * If the rhs data has multiple depths,
+ * the solver uses just one depth at a time.
+ * The default depth is the first depth.
+ * Use this function to change it.
+ * This is not used to set the depth of the data (which is not
+ * controled by this class) but the depth used in the solve.
+ *
+ * Changing the depth after setting up the matrix is permissible,
+ * as the rhs data does not affect the matrix.
+ */
+ void
+ setRhsIdDepth(
+ const int depth);
+
+ /*!
+ * @brief Set the stopping criteria (max iterations and residual
+ * tolerance) for the linear solver.
+ *
+ * @param max_iterations gives the maximum number of iterations
+ * @param relative_residual_tol the maximum error tolerance
+ */
+ void
+ setStoppingCriteria(
+ const int max_iterations = 10,
+ const double relative_residual_tol = 1.0e-6);
+
+ /*!
+ * @brief Solve the linear system Au=f.
+ *
+ * The solution u and the right hand side f are
+ * specified via patch indices on the patch hierarchy.
+ *
+ * Member functions getNumberOfIterations() return the iterations
+ * from the solver.
+ * Note that the matrix coefficients and boundary condition object
+ * must have been set up before this function is called.
+ * As long as the matrix coefficients do not change,
+ * this routine may be called repeatedly to solve any number of linear
+ * systems (with the right-hand side varying).
+ * If the boundary conditions or matrix coefficients are changed
+ * then function setMatrixCoefficients() must be called again.
+ *
+ * When computing the matrix coefficients in setMatrixCoefficients(),
+ * the inhomogeneous portion of the boundary condition (constant
+ * terms, independent of u and thus having no effect on the matrix)
+ * are saved and added to the source term, f,
+ * before performing the matrix solve. In some situations, it may be
+ * useful to not add the inhomogeneous portion to f. The flag argument
+ * @c homoegneous_bc is used for this. (This is a sort of optimization,
+ * to avoid having to re-call setMatrixCoefficients() to change the
+ * inhomogeneous portion.)
+ *
+ * @param u Descriptor of cell-centered unknown variable.
+ * @param f Descriptor of cell-centered source variable.
+ * @param homogeneous_bc Whether homogeneous boundary conditions
+ * are assumed.
+ *
+ * @return whether solver converged to specified level
+ */
+ int
+ solveSystem(
+ const int u,
+ const int f,
+ bool homogeneous_bc = false);
+
+ /*!
+ * @brief Return the number of iterations taken by the solver to converge.
+ *
+ * @return number of iterations taken by the solver to converge
+ */
+ int
+ getNumberOfIterations() const;
+
+ /*!
+ * @brief Set the number of pre-relax steps used by the Hypre solve.
+ */
+ void
+ setNumPreRelaxSteps(
+ const int steps);
+
+ /*!
+ * @brief Set the number of post-relax steps used by the Hypre solve.
+ */
+ void
+ setNumPostRelaxSteps(
+ const int steps);
+
+ /*!
+ * @brief Return the final residual norm returned by the Hypre solve.
+ * @return final residual norm returned by the Hypre solve.
+ */
+ double
+ getRelativeResidualNorm() const;
+
+ /*!
+ * @brief Set whether to use Hypre's PFMG algorithm instead of the
+ * SMG algorithm.
+ *
+ * The flag is used to select which of HYPRE's linear solver algorithms
+ * to use if true, the semicoarsening multigrid algorithm is used, and if
+ * false, the "PF" multigrid algorithm is used.
+ * By default, the SMG algorithm is used.
+ *
+ * Changing the algorithm must be done before setting up the matrix
+ * coefficients.
+ */
+ void
+ setUseSMG(
+ bool use_smg);
+
+ /*!
+ * @brief Specify boundary condition directly, without using
+ * a RobinBcCoefStrategy object.
+ *
+ * Use @em either setBoundaries() @em or setPhysicalBcCoefObject(),
+ * but not both.
+ *
+ * A SimpleCelBcCoef object is used to interpret and implement
+ * the specified boundary conditions.
+ * See SimpleCellRobinBcCoefs::setBoundaries()
+ * for an explanation of the arguments.
+ */
+ void
+ setBoundaries(
+ const std::string& boundary_type,
+ const int fluxes = -1,
+ const int flags = -1,
+ int* bdry_types = NULL);
+
+ /*!
+ * @brief Specify boundary condition through the use of a
+ * Robin boundary condition object.
+ *
+ * Use @em either setBoundaries() @em or setPhysicalBcCoefObject(),
+ * but not both.
+ *
+ * The Robin boundary condition object is used when setting
+ * the matrix coefficient and when solving the system.
+ * If your boundary conditions are fixed values at ghost
+ * cell centers, use the GhostCellRobinBcCoefs
+ * implementation of the RobinBcCoefStrategy strategy.
+ *
+ * @param physical_bc_coef_strategy tbox::Pointer a concrete
+ * implementation of the Robin bc strategy.
+ * @param variable hier::Variable pointer to be passed
+ * to RobinBcCoefStrategy::setBcCoefs(),
+ * but otherwise unused by this class.
+ */
+ void
+ setPhysicalBcCoefObject(
+ const RobinBcCoefStrategy* physical_bc_coef_strategy,
+ const tbox::Pointer<hier::Variable> variable =
+ tbox::Pointer<hier::Variable>(NULL));
+
+ /*!
+ * @brief Set the flag for printing solver information.
+ *
+ * This optional function is used primarily for debugging.
+ *
+ * If set true, it will print the HYPRE matrix information
+ * to the following files:
+ *
+ * - mat_bA.out - before setting matrix coefficients in matrix assemble
+ * - mat_aA.out - after setting matrix coefficients in matrix assemble
+ * - sol0.out - u before solve (i.e. for system Au = b)
+ * - sol.out - u after solve
+ * - mat0.out - A before solve
+ * - mat.out - A after solve
+ * - rhs.out - b before and after solve
+ *
+ * If this method is not called, or the flag is set false, no printing
+ * will occur.
+ */
+ void
+ setPrintSolverInfo(
+ const bool print);
+
+private:
+ /*!
+ * @brief Set state using database
+ *
+ * See the class description for the parameters that can be set
+ * from a database.
+ *
+ * @param database Input database. If a NULL pointer is given,
+ * nothing is done.
+ */
+ void
+ getFromInput(
+ tbox::Pointer<tbox::Database> database);
+
+ void
+ setupHypreSolver();
+ void
+ destroyHypreSolver();
+ void
+ allocateHypreData();
+ void
+ deallocateHypreData();
+
+ void
+ copyToHypre(
+ HYPRE_StructVector vector,
+ pdat::CellData<double>& src,
+ int depth,
+ const hier::Box& box);
+ void
+ copyFromHypre(
+ pdat::CellData<double>& dst,
+ int depth,
+ HYPRE_StructVector vector,
+ const hier::Box box);
+
+ /*!
+ * @brief Add g*A*k0(a) from boundaries to rhs.
+ *
+ * Move the constant portion of the boundary condition
+ * contribution to the right hand side and add it to the existing rhs.
+ * This operation is done for physical as well as cf boundaries,
+ * so it is placed in a function.
+ *
+ * The boundary boxes given must be to either the physical
+ * boundary or coarse-fine boundary for the patch. The
+ * bc coefficient implementation should correspond to the
+ * boundary being worked on.
+ */
+ void
+ add_gAk0_toRhs(
+ const hier::Patch& patch,
+ const tbox::Array<hier::BoundaryBox>& bdry_boxes,
+ const RobinBcCoefStrategy* robin_bc_coef,
+ pdat::CellData<double>& rhs);
+
+ //@{
+
+ /*!
+ * @name Dimension-independent functions to organize Fortran interface.
+ */
+
+ //! @brief Compute diagonal entries of the matrix when C is variable.
+ void
+ computeDiagonalEntries(
+ pdat::CellData<double>& diagonal,
+ const pdat::CellData<double>& C_data,
+ const pdat::SideData<double>& variable_off_diagonal,
+ const hier::Box& patch_box);
+ //! @brief Compute diagonal entries of the matrix when C is constant.
+ void
+ computeDiagonalEntries(
+ pdat::CellData<double>& diagonal,
+ const double C,
+ const pdat::SideData<double>& variable_off_diagonal,
+ const hier::Box& patch_box);
+ //! @brief Compute diagonal entries of the matrix when C is zero.
+ void
+ computeDiagonalEntries(
+ pdat::CellData<double>& diagonal,
+ const pdat::SideData<double>& variable_off_diagonal,
+ const hier::Box& patch_box);
+ /*!
+ * @brief Adjust boundary entries for variable off-diagonals.
+ *
+ * At the same time, save information that are needed to adjust
+ * the rhs.
+ */
+ void
+ adjustBoundaryEntries(
+ pdat::CellData<double>& diagonal,
+ const pdat::SideData<double>& variable_off_diagonal,
+ const hier::Box& patch_box,
+ const pdat::ArrayData<double>& acoef_data,
+ const pdat::ArrayData<double>& bcoef_data,
+ const hier::Box bccoef_box,
+ pdat::ArrayData<double>& Ak0_data,
+ const hier::BoundaryBox& trimmed_boundary_box,
+ const double h[tbox::Dimension::MAXIMUM_DIMENSION_VALUE]);
+
+ //@}
+
+ //! @brief Free static variables at shutdown time.
+ static void
+ finalizeCallback();
+
+ /*!
+ * @brief Object dimension.
+ */
+ const tbox::Dimension d_dim;
+
+ /*!
+ * @brief Object name.
+ */
+ std::string d_object_name;
+
+ /*!
+ * @brief Associated hierarchy.
+ */
+ tbox::Pointer<hier::PatchHierarchy> d_hierarchy;
+
+ /*!
+ * @brief Associated level number.
+ *
+ * Currently, this must be level number 0.
+ */
+ int d_ln;
+
+ /*!
+ * @brief Scratch context for this object.
+ */
+ tbox::Pointer<hier::VariableContext> d_context;
+
+ //@{ @name Boundary condition handling
+
+ /*!
+ * @brief The coarse-fine boundary description for level d_ln.
+ *
+ * The coarse-fine boundary is computed when the operator
+ * state is initialized. It is used to allow solves on
+ * levels that are not the coarsest in the hierarchy.
+ */
+ tbox::Pointer<hier::CoarseFineBoundary> d_cf_boundary;
+
+ /*!
+ * @brief Robin boundary coefficient object for physical
+ * boundaries.
+ *
+ * If d_physical_bc_coef_strategy is set, use it, otherwise,
+ * use d_physical_bc_simple_case.
+ */
+ const RobinBcCoefStrategy* d_physical_bc_coef_strategy;
+ tbox::Pointer<hier::Variable> d_physical_bc_variable;
+
+ /*!
+ * @brief Implementation of Robin boundary conefficients
+ * for the case of simple boundary conditions.
+ */
+ SimpleCellRobinBcCoefs d_physical_bc_simple_case;
+
+ /*!
+ * @brief Robin boundary coefficient object for coarse-fine
+ * boundaries.
+ *
+ * This is a GhostCellRobinBcCoefs object because we
+ * expect the users to have the correct ghost cell values
+ * in the coarse-fine boundaries before solving.
+ */
+ GhostCellRobinBcCoefs d_cf_bc_coef;
+ tbox::Pointer<hier::Variable> d_coarsefine_bc_variable;
+
+ //@}
+
+ /*!
+ * @brief hier::Patch index of A*k0(a) quantity
+ *
+ * A*k0(a) is the quantity that is saved for
+ * later adding to the rhs.
+ *
+ * The Robin bc is expressed by the coefficients a and g
+ * on the boundary (see RobinBcCoefStrategy).
+ * This class uses a central difference approximation of
+ * the Robin bc, which results in the value at a ghost cell,
+ * uo, being writen as uo = g*k0(a) + k1(a)*ui, where ui is
+ * the first interior cell value, k0 and k1 depend on a as
+ * indicated.
+ *
+ * In setting up the Au=f system, the contribution of k1(a)*ui
+ * is incorporated into the product Au. The contribution of
+ * A*g*k0(a) should be moved to the right hand side and saved for
+ * later adding to f. However, the value of g is not provided
+ * until solve time. Therefore, we save just A*k0(a) at the
+ * patch data index d_Ak0_id.
+ */
+ int d_Ak0_id;
+
+ static tbox::Pointer<pdat::OutersideVariable<double> > s_Ak0_var[tbox::
+ Dimension::
+ MAXIMUM_DIMENSION_VALUE];
+
+ /*!
+ * @brief Depth of the solution variable.
+ */
+ int d_soln_depth;
+
+ /*!
+ * @brief Depth of the rhs variable.
+ */
+ int d_rhs_depth;
+
+ int d_max_iterations;
+ double d_relative_residual_tol;
+
+ int d_number_iterations; // iterations in solver
+ int d_num_pre_relax_steps; // pre-relax steps in solver
+ int d_num_post_relax_steps; // post-relax steps in solver
+ double d_relative_residual_norm; // norm from solver
+
+ /*@
+ * @brief Flag to use SMG or PFMG (default)
+ */
+ bool d_use_smg;
+
+ //@{
+ //! @name Hypre object
+ //! @brief HYPRE grid
+ HYPRE_StructGrid d_grid;
+ //! @brief HYPRE stencil
+ HYPRE_StructStencil d_stencil;
+ //! @brief HYPRE structured matrix
+ HYPRE_StructMatrix d_matrix;
+ //! @brief Hypre RHS vector for linear solves
+ HYPRE_StructVector d_linear_rhs;
+ //! @brief Hypre solution vector
+ HYPRE_StructVector d_linear_sol;
+ //! @brief Hypre SMG solver data
+ HYPRE_StructSolver d_mg_data;
+ //@}
+
+ //@{
+
+ //! @name Variables for debugging and analysis.
+
+ /*!
+ * @brief Flag to print solver info
+ *
+ * See setPrintSolverInfo().
+ */
+ bool d_print_solver_info;
+
+ //@}
+
+ /*!
+ * @brief Timers for performance measurement.
+ */
+ tbox::Pointer<tbox::Timer> t_solve_system;
+ tbox::Pointer<tbox::Timer> t_set_matrix_coefficients;
+
+ static tbox::StartupShutdownManager::Handler s_finalize_handler;
+};
+
+}
+} // namespace SAMRAI
+
+#ifdef SAMRAI_INLINE
+#include "StokesHypreSolver.I"
+#endif
+
+#endif
+
+#endif
More information about the CIG-COMMITS
mailing list