64using namespace blocksolvers;
101 DarcyProblem(
Mesh &mesh,
int num_refines,
int order,
const char *coef_file,
106 const Vector& GetRHS() {
return rhs_; }
107 const Vector& GetEssentialBC() {
return ess_data_; }
109 void ShowError(
const Vector &sol,
bool verbose);
110 void VisualizeSolution(
const Vector &sol, std::string tag);
115DarcyProblem::DarcyProblem(
Mesh &mesh,
int num_refs,
int order,
118 : mesh_(MPI_COMM_WORLD, mesh), ucoeff_(mesh.Dimension(),
u_exact),
119 pcoeff_(
p_exact), dfs_spaces_(order, num_refs, &mesh_, ess_bdr, dfs_param),
122 for (
int l = 0; l < num_refs; l++)
130 if (std::strcmp(coef_file,
""))
132 ifstream coef_str(coef_file);
133 coef_vector.Load(coef_str, mesh.
GetNE());
170 bVarf_->
SpMat() *= -1.0;
178 fform.ParallelAssemble(rhs_block0);
179 gform.ParallelAssemble(rhs_block1);
186 int order_quad = max(2, 2*order+1);
193void DarcyProblem::ShowError(
const Vector& sol,
bool verbose)
203 if (!verbose) {
return; }
204 mfem::out <<
"|| u_h - u_ex || / || u_ex || = " << err_u / norm_u <<
"\n";
205 mfem::out <<
"|| p_h - p_ex || / || p_ex || = " << err_p / norm_p <<
"\n";
208void DarcyProblem::VisualizeSolution(
const Vector& sol,
string tag)
211 MPI_Comm_size(mesh_.
GetComm(), &num_procs);
212 MPI_Comm_rank(mesh_.
GetComm(), &myid);
217 const char vishost[] =
"localhost";
220 u_sock <<
"parallel " << num_procs <<
" " << myid <<
"\n";
222 u_sock <<
"solution\n" << mesh_ << u_ <<
"window_title 'Velocity ("
223 << tag <<
" solver)'" << endl;
226 p_sock <<
"parallel " << num_procs <<
" " << myid <<
"\n";
228 p_sock <<
"solution\n" << mesh_ << p_ <<
"window_title 'Pressure ("
229 << tag <<
" solver)'" << endl;
234 for (
int attr : ess_bdr_attr) {
if (attr == 0) {
return false; } }
238int main(
int argc,
char *argv[])
240#ifdef HYPRE_USING_GPU
241 mfem::out <<
"\nAs of mfem-4.3 and hypre-2.22.0 (July 2021) this miniapp\n"
242 <<
"is NOT supported with the GPU version of hypre.\n\n";
243 return MFEM_SKIP_RETURN_VALUE;
253 const char *mesh_file =
"../../data/beam-hex.mesh";
254 const char *coef_file =
"";
255 const char *ess_bdr_attr_file =
"";
257 int ser_ref_levels = 1;
258 int par_ref_levels = 1;
259 bool show_error =
false;
260 bool visualization =
false;
266 args.
AddOption(&mesh_file,
"-m",
"--mesh",
267 "Mesh file to use.");
269 "Finite element order (polynomial degree).");
270 args.
AddOption(&ser_ref_levels,
"-rs",
"--refine-serial",
271 "Number of serial refinement steps.");
272 args.
AddOption(&par_ref_levels,
"-rp",
"--refine-parallel",
273 "Number of parallel refinement steps.");
274 args.
AddOption(&coef_file,
"-c",
"--coef",
275 "Coefficient file to use.");
276 args.
AddOption(&ess_bdr_attr_file,
"-eb",
"--ess-bdr",
277 "Essential boundary attribute file to use.");
278 args.
AddOption(&show_error,
"-se",
"--show-error",
"-no-se",
280 "Show or not show approximation error.");
281 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
282 "--no-visualization",
283 "Enable or disable GLVis visualization.");
289 mfem::out <<
"WARNING: DivFree solver is equivalent to BDPMinresSolver "
290 <<
"when par_ref_levels == 0.\n";
294 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
300 mfem::out <<
"Number of serial refinements: " << ser_ref_levels <<
"\n"
301 <<
"Number of parallel refinements: " << par_ref_levels <<
"\n";
304 for (
int i = 0; i < ser_ref_levels; ++i)
311 mfem::out <<
"\nWARNING: Number of processors is greater than the number of "
312 <<
"elements in the mesh.\n"
314 <<
"Number of elements: " << mesh->
GetNE() <<
"\n\n";
319 if (std::strcmp(ess_bdr_attr_file,
""))
321 ifstream ess_bdr_attr_str(ess_bdr_attr_file);
328 mfem::out <<
"\nSolution is not unique when Neumann boundary condition is "
329 <<
"imposed on the entire boundary. \nPlease provide a different "
330 <<
"boundary condition.\n";
336 string line =
"**********************************************************\n";
341 DarcyProblem darcy(*mesh, par_ref_levels, order, coef_file, ess_bdr, param);
344 const DFSData& DFS_data = darcy.GetDFSData();
350 mfem::out <<
"Dimension of the physical space: " <<
dim <<
"\n";
351 mfem::out <<
"Size of the discrete Darcy system: " << M.
M() + B.
M() <<
"\n";
352 if (par_ref_levels > 0)
354 mfem::out <<
"Dimension of the divergence free subspace: "
355 << DFS_data.
C.back().Ptr()->NumCols() <<
"\n\n";
360 std::map<const DarcySolver*, real_t> setup_time;
363 setup_time[&bdp] = chrono.
RealTime();
367 setup_time[&dfs_dm] = chrono.
RealTime();
372 setup_time[&dfs_cm] = chrono.
RealTime();
376 setup_time[&bp_bpcg] = chrono.
RealTime();
381 setup_time[&bp_pcg] = chrono.
RealTime();
383 std::map<const DarcySolver*, std::string> solver_to_name;
384 solver_to_name[&bdp] =
"Block-diagonal-preconditioned MINRES";
385 solver_to_name[&dfs_dm] =
"Divergence free (decoupled mode)";
386 solver_to_name[&dfs_cm] =
"Divergence free (coupled mode)";
387 solver_to_name[&bp_bpcg] =
"Bramble Pasciak CG (using BPCG)";
388 solver_to_name[&bp_pcg] =
"Bramble Pasciak CG (using regular PCG)";
391 for (
const auto& solver_pair : solver_to_name)
393 auto& solver = solver_pair.first;
394 auto& name = solver_pair.second;
396 Vector sol = darcy.GetEssentialBC();
399 solver->Mult(darcy.GetRHS(), sol);
404 mfem::out << line << name <<
" solver:\n Setup time: "
405 << setup_time[solver] <<
"s.\n Solve time: "
406 << chrono.
RealTime() <<
"s.\n Total time: "
407 << setup_time[solver] + chrono.
RealTime() <<
"s.\n"
408 <<
" Iteration count: " << solver->GetNumIterations() <<
"\n\n";
410 if (show_error && std::strcmp(coef_file,
"") == 0)
416 mfem::out <<
"Exact solution is unknown for coefficient '" << coef_file
417 <<
"'.\nApproximation error is computed in this case!\n\n";
420 if (visualization) { darcy.VisualizeSolution(sol, name); }
433 u(0) = - exp(xi)*sin(yi)*cos(zi);
434 u(1) = - exp(xi)*cos(yi)*cos(zi);
437 u(2) = exp(xi)*sin(yi)*sin(zi);
446 return exp(xi)*sin(yi)*cos(zi);
real_t p_exact(const Vector &x)
real_t g_exact(const Vector &x)
real_t natural_bc(const Vector &x)
void u_exact(const Vector &x, Vector &u)
void f_exact(const Vector &x, Vector &f)
bool IsAllNeumannBoundary(const Array< int > &ess_bdr_attr)
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
void Load(std::istream &in, int fmt=0)
Read an Array from the stream in using format fmt. The format fmt can be:
Class for domain integration .
A general function coefficient.
void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff, const Array< int > &bdr_attr)
Wrapper for hypre's ParCSR matrix class.
HYPRE_BigInt M() const
Returns the global number of rows.
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Class for an integration rule - an Array of IntegrationPoint.
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
int GetNE() const
Returns number of elements.
int Dimension() const
Dimension of the reference space used within the elements.
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldSize()
Return the size of MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
Pointer to an Operator of a specified type.
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
void ParseCheck(std::ostream &out=mfem::out)
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
A piecewise constant coefficient with the constants keyed off the element attribute numbers.
void UpdateConstants(Vector &c)
Update the constants with vector c.
Class for parallel grid function.
real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const override
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
void SetSpace(FiniteElementSpace *f) override
Associate a new FiniteElementSpace with the ParGridFunction.
void Distribute(const Vector *tv)
Class for parallel meshes.
double RealTime()
Return the number of real seconds elapsed since the stopwatch was started.
void Restart()
Clears and restarts the stopwatch. Equivalent to Clear() followed by Start().
void Stop()
Stop the stopwatch.
for VectorFiniteElements (Nedelec, Raviart-Thomas)
A general vector function coefficient.
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Wrapper for the block-diagonal-preconditioned MINRES employed in ex5p.cpp.
Bramble-Pasciak Solver for Darcy equation.
const DFSData & GetDFSData() const
ParFiniteElementSpace * GetHdivFES() const
ParFiniteElementSpace * GetL2FES() const
real_t u(const Vector &xvec)
real_t ComputeGlobalLpNorm(real_t p, Coefficient &coeff, ParMesh &pmesh, const IntegrationRule *irs[])
Compute the global Lp norm of a function f. .
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
std::function< real_t(const Vector &)> f(real_t mass_coeff)
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Parameters for the BramblePasciakSolver method.
Data for the divergence free solver.
std::vector< OperatorPtr > C
Parameters for the divergence free solver.