65using namespace blocksolvers;
92 std::function<bool (
int)> refine_fn = [&](
int num_refs)
94 for (
int l = 0; l < num_refs; l++)
101 const bool dfs_refine_;
109 DarcyProblem(
Mesh &mesh,
int num_refines,
int order,
const char *coef_file,
114 const Vector& GetRHS() {
return rhs_; }
115 const Vector& GetEssentialBC() {
return ess_data_; }
117 void ShowError(
const Vector &sol,
bool verbose);
118 void VisualizeSolution(
const Vector &sol, std::string tag,
int visport = 19916);
123DarcyProblem::DarcyProblem(
Mesh &mesh,
int num_refs,
int order,
126 : mesh_(MPI_COMM_WORLD, mesh),
127 dfs_spaces_(order, num_refs, &mesh_, ess_bdr, dfs_param),
128 dfs_refine_(refine_fn(num_refs)),
129 mVarf_(dfs_spaces_.GetHdivFES()),
130 bVarf_(dfs_spaces_.GetHdivFES(), dfs_spaces_.GetL2FES()),
131 ucoeff_(mesh.Dimension(),
u_exact),
137 if (std::strcmp(coef_file,
""))
139 ifstream coef_str(coef_file);
140 coef_vector.Load(coef_str, mesh.
GetNE());
173 bVarf_.
SpMat() *= -1.0;
181 fform.ParallelAssemble(rhs_block0);
182 gform.ParallelAssemble(rhs_block1);
189 int order_quad = max(2, 2*order+1);
196void DarcyProblem::ShowError(
const Vector& sol,
bool verbose)
206 if (!verbose) {
return; }
207 mfem::out <<
"|| u_h - u_ex || / || u_ex || = " << err_u / norm_u <<
"\n";
208 mfem::out <<
"|| p_h - p_ex || / || p_ex || = " << err_p / norm_p <<
"\n";
211void DarcyProblem::VisualizeSolution(
const Vector& sol,
string tag,
215 MPI_Comm_size(mesh_.
GetComm(), &num_procs);
216 MPI_Comm_rank(mesh_.
GetComm(), &myid);
221 const char vishost[] =
"localhost";
223 u_sock <<
"parallel " << num_procs <<
" " << myid <<
"\n";
225 u_sock <<
"solution\n" << mesh_ << u_ <<
"window_title 'Velocity ("
226 << tag <<
" solver)'" << endl;
229 p_sock <<
"parallel " << num_procs <<
" " << myid <<
"\n";
231 p_sock <<
"solution\n" << mesh_ << p_ <<
"window_title 'Pressure ("
232 << tag <<
" solver)'" << endl;
237 for (
int attr : ess_bdr_attr) {
if (attr == 0) {
return false; } }
241int main(
int argc,
char *argv[])
243#ifdef HYPRE_USING_GPU
244 mfem::out <<
"\nAs of mfem-4.3 and hypre-2.22.0 (July 2021) this miniapp\n"
245 <<
"is NOT supported with the GPU version of hypre.\n\n";
246 return MFEM_SKIP_RETURN_VALUE;
256 const char *mesh_file =
"../../data/beam-hex.mesh";
257 const char *coef_file =
"";
258 const char *ess_bdr_attr_file =
"";
260 int ser_ref_levels = 1;
261 int par_ref_levels = 1;
262 bool show_error =
false;
263 bool visualization =
false;
270 args.
AddOption(&mesh_file,
"-m",
"--mesh",
271 "Mesh file to use.");
273 "Finite element order (polynomial degree).");
274 args.
AddOption(&ser_ref_levels,
"-rs",
"--refine-serial",
275 "Number of serial refinement steps.");
276 args.
AddOption(&par_ref_levels,
"-rp",
"--refine-parallel",
277 "Number of parallel refinement steps.");
278 args.
AddOption(&coef_file,
"-c",
"--coef",
279 "Coefficient file to use.");
280 args.
AddOption(&ess_bdr_attr_file,
"-eb",
"--ess-bdr",
281 "Essential boundary attribute file to use.");
282 args.
AddOption(&show_error,
"-se",
"--show-error",
"-no-se",
284 "Show or not show approximation error.");
285 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
286 "--no-visualization",
287 "Enable or disable GLVis visualization.");
288 args.
AddOption(&visport,
"-p",
"--send-port",
"Socket for GLVis.");
294 mfem::out <<
"WARNING: DivFree solver is equivalent to BDPMinresSolver "
295 <<
"when par_ref_levels == 0.\n";
299 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
305 mfem::out <<
"Number of serial refinements: " << ser_ref_levels <<
"\n"
306 <<
"Number of parallel refinements: " << par_ref_levels <<
"\n";
309 for (
int i = 0; i < ser_ref_levels; ++i)
316 mfem::out <<
"\nWARNING: Number of processors is greater than the number of "
317 <<
"elements in the mesh.\n"
319 <<
"Number of elements: " << mesh->
GetNE() <<
"\n\n";
324 if (std::strcmp(ess_bdr_attr_file,
""))
326 ifstream ess_bdr_attr_str(ess_bdr_attr_file);
333 mfem::out <<
"\nSolution is not unique when Neumann boundary condition is "
334 <<
"imposed on the entire boundary. \nPlease provide a different "
335 <<
"boundary condition.\n";
341 string line =
"**********************************************************\n";
346 DarcyProblem darcy(*mesh, par_ref_levels, order, coef_file, ess_bdr, param);
349 const DFSData& DFS_data = darcy.GetDFSData();
355 mfem::out <<
"Dimension of the physical space: " <<
dim <<
"\n";
356 mfem::out <<
"Size of the discrete Darcy system: " << M.
M() + B.
M() <<
"\n";
357 if (par_ref_levels > 0)
359 mfem::out <<
"Dimension of the divergence free subspace: "
360 << DFS_data.
C.back().Ptr()->NumCols() <<
"\n\n";
365 std::map<const DarcySolver*, real_t> setup_time;
368 setup_time[&bdp] = chrono.
RealTime();
372 setup_time[&dfs_dm] = chrono.
RealTime();
377 setup_time[&dfs_cm] = chrono.
RealTime();
381 setup_time[&bp_bpcg] = chrono.
RealTime();
386 setup_time[&bp_pcg] = chrono.
RealTime();
388 std::map<const DarcySolver*, std::string> solver_to_name;
389 solver_to_name[&bdp] =
"Block-diagonal-preconditioned MINRES";
390 solver_to_name[&dfs_dm] =
"Divergence free (decoupled mode)";
391 solver_to_name[&dfs_cm] =
"Divergence free (coupled mode)";
392 solver_to_name[&bp_bpcg] =
"Bramble Pasciak CG (using BPCG)";
393 solver_to_name[&bp_pcg] =
"Bramble Pasciak CG (using regular PCG)";
396 for (
const auto& solver_pair : solver_to_name)
398 auto& solver = solver_pair.first;
399 auto& name = solver_pair.second;
401 Vector sol = darcy.GetEssentialBC();
404 solver->Mult(darcy.GetRHS(), sol);
409 mfem::out << line << name <<
" solver:\n Setup time: "
410 << setup_time[solver] <<
"s.\n Solve time: "
411 << chrono.
RealTime() <<
"s.\n Total time: "
412 << setup_time[solver] + chrono.
RealTime() <<
"s.\n"
413 <<
" Iteration count: " << solver->GetNumIterations() <<
"\n\n";
415 if (show_error && std::strcmp(coef_file,
"") == 0)
421 mfem::out <<
"Exact solution is unknown for coefficient '" << coef_file
422 <<
"'.\nApproximation error is computed in this case!\n\n";
425 if (visualization) { darcy.VisualizeSolution(sol, name, visport); }
438 u(0) = -
exp(xi)*sin(yi)*cos(zi);
439 u(1) = -
exp(xi)*cos(yi)*cos(zi);
442 u(2) =
exp(xi)*sin(yi)*sin(zi);
451 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
Returns ||u_ex - u_h||_L2 in parallel for H1 or L2 elements.
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)
MFEM_HOST_DEVICE Complex exp(const Complex &q)
Parameters for the BramblePasciakSolver method.
Data for the divergence free solver.
std::vector< OperatorPtr > C
Parameters for the divergence free solver.