94int main(
int argc,
char *argv[])
101 const char *mesh_file =
"../../data/beam-tri.mesh";
104 bool visualization =
false;
106 bool reorder_space =
true;
107 const char *device_config =
"cpu";
109 bool sub_solve =
false;
110 bool componentwise_action =
false;
113 args.
AddOption(&mesh_file,
"-m",
"--mesh",
114 "Mesh file to use.");
116 "Finite element order (polynomial degree).");
117 args.
AddOption(&amg_elast,
"-elast",
"--amg-for-elasticity",
"-sys",
119 "Use the special AMG elasticity solver (GM/LN approaches), "
120 "or standard AMG for systems (unknown approach).");
121 args.
AddOption(&sub_solve,
"-ss",
"--sub-solve",
"-no-ss",
123 "Blocks are solved with a few CG iterations instead of a single AMG application.");
124 args.
AddOption(&pa,
"-pa",
"--partial-assembly",
"-no-pa",
125 "--no-partial-assembly",
"Enable Partial Assembly.");
126 args.
AddOption(&reorder_space,
"-nodes",
"--by-nodes",
"-vdim",
"--by-vdim",
127 "Use byNODES ordering of vector space instead of byVDIM");
128 args.
AddOption(&device_config,
"-d",
"--device",
129 "Device configuration string, see Device::Configure().");
130 args.
AddOption(&ref_levels,
"-l",
"--reflevels",
131 "How many mesh refinements to perform.");
132 args.
AddOption(&componentwise_action,
"-ca",
"--component-action",
"-no-ca",
133 "--no-component-action",
134 "Uses partial assembly with a block operator of components instead of the monolithic vector integrator.");
135 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
136 "--no-visualization",
137 "Enable or disable ParaView and GLVis output.");
142 Device device(device_config);
147 Mesh mesh(mesh_file, 1, 1);
154 cerr <<
"\nInput mesh should have at least two materials and "
155 <<
"two boundary attributes! (See schematic in ex2.cpp)\n"
162 for (
int l = 0; l < ref_levels; l++)
168 ParMesh pmesh(MPI_COMM_WORLD, mesh);
179 unique_ptr<ParLORDiscretization> lor_disc;
180 unique_ptr<ParFiniteElementSpace> scalar_lor_fespace;
181 if (pa || componentwise_action)
187 scalar_lor_fespace.reset(
193 cout <<
"Number of finite element unknowns: " << size << endl
194 <<
"Assembling: " << flush;
215 for (
int i = 0; i <
dim-1; i++)
222 pull_force(1) = -1.0e-2;
230 cout <<
"r.h.s. ... " << flush;
245 lambda(0) = lambda(1)*50;
254 if (pa || componentwise_action)
257 AssemblyLevel::PARTIAL);
259 a.AddDomainIntegrator(&integrator);
260 a.UseExternalIntegrators();
266 if (
Mpi::Root()) { cout <<
"matrix ... " << flush; }
269 assembly_timer.
Start();
274 Operator *a_lhs = componentwise_action ? nullptr : &
a;
275 if (!componentwise_action)
281 cout <<
"done." << endl;
282 cout <<
"Size of linear system: " << fespace.
GlobalTrueVSize() << endl;
286 block_offsets[0] = 0;
288 unique_ptr<Solver> prec =
nullptr;
294 vector<unique_ptr<ParBilinearForm>> bilinear_forms;
295 vector<unique_ptr<HypreParMatrix>> lor_block;
297 vector<unique_ptr<HypreBoomerAMG>> amg_blocks;
299 vector<unique_ptr<CGSolver>> cg_blocks;
302 vector<unique_ptr<ParBilinearForm>> ho_bilinear_form_blocks;
303 vector<unique_ptr<ConstrainedOperator>> diag_ho;
306 vector<unique_ptr<ParBilinearForm>> pa_components;
307 vector<const FiniteElementSpace*> fespaces;
311 ess_bdr_block_ho = 0;
312 ess_bdr_block_ho[0] = 1;
314 if (pa || componentwise_action)
317 lor_integrator.
AssemblePA(lor_disc->GetParFESpace());
318 for (
int j = 0; j <
dim; j++)
321 lor_integrator, j, j);
323 bilinear_forms.emplace_back(
new ParBilinearForm(scalar_lor_fespace.get()));
324 bilinear_forms[j]->SetAssemblyLevel(AssemblyLevel::FULL);
326 bilinear_forms[j]->AddDomainIntegrator(block);
327 bilinear_forms[j]->Assemble();
332 ess_bdr_block[0] = 1;
333 scalar_lor_fespace->GetEssentialTrueDofs(ess_bdr_block, ess_tdof_list_block);
334 lor_block.emplace_back(bilinear_forms[j]->ParallelAssemble());
335 lor_block[j]->EliminateBC(ess_tdof_list_block,
336 Operator::DiagonalPolicy::DIAG_ONE);
338 amg_blocks[j]->SetStrengthThresh(0.25);
339 amg_blocks[j]->SetRelaxType(16);
340 amg_blocks[j]->SetOperator(*lor_block[j]);
341 block_offsets[j+1] = amg_blocks[j]->Height();
343 if (componentwise_action)
345 for (
int i = 0; i <
dim; i++)
351 fespaces.emplace_back(&scalar_fespace);
354 pa_components[i +
dim*j]->SetAssemblyLevel(pa ? AssemblyLevel::PARTIAL :
355 AssemblyLevel::FULL);
357 pa_components[i +
dim*j]->AddDomainIntegrator(action_block);
358 pa_components[i +
dim*j]->Assemble();
367 for (
int i = 0; i <
dim; i++)
372 ho_bilinear_form_blocks.emplace_back(
new ParBilinearForm(&scalar_fespace));
373 ho_bilinear_form_blocks[i]->SetAssemblyLevel(AssemblyLevel::PARTIAL);
374 ho_bilinear_form_blocks[i]->AddDomainIntegrator(block);
375 ho_bilinear_form_blocks[i]->Assemble();
377 auto *rap =
new RAPOperator(*prolong, *ho_bilinear_form_blocks[i], *prolong);
379 Operator::DiagonalPolicy::DIAG_ONE));
382 for (
int i = 0; i <
dim; i++)
384 cg_blocks.emplace_back(
new CGSolver(MPI_COMM_WORLD));
385 cg_blocks[i]->iterative_mode =
false;
386 cg_blocks[i]->SetOperator(*diag_ho[i]);
387 cg_blocks[i]->SetPreconditioner(*amg_blocks[i]);
388 cg_blocks[i]->SetMaxIter(30);
389 cg_blocks[i]->SetRelTol(1e-8);
393 for (
int i = 0; i <
dim; i++)
404 prec.reset(blockDiag);
410 if (amg_elast && !
a.StaticCondensationIsEnabled())
412 amg->SetElasticityOptions(&fespace);
416 amg->SetSystemsOptions(
dim, reorder_space);
421 unique_ptr<Operator> A_components =
nullptr;
422 unique_ptr<BlockFESpaceOperator> pa_blocks;
423 if (componentwise_action)
426 for (
int j = 0; j <
dim; j++)
428 for (
int i = 0; i <
dim; i++)
430 pa_blocks->SetBlock(i,j,pa_components[i +
dim*j].get());
434 pa_blocks->FormLinearSystem(ess_tdof_list, x,
b, A_temp, X, B);
435 A_components.reset(A_temp);
436 a_lhs = pa_blocks.get();
438 assembly_timer.
Stop();
446 solver.
SetOperator(A_components ? *A_components : *A);
449 linear_solve_timer.
Start();
451 linear_solve_timer.
Stop();
459 cout <<
"Elapsed Times\n";
460 cout <<
"Assembly (s) = " << assembly_timer.
RealTime() << endl;
461 cout <<
"Linear Solve (s) = " << linear_solve_timer.
RealTime() << endl;
462 cout <<
"Total Solve (s) " << total_timer.
RealTime() << endl;
486 ostringstream mesh_name, sol_name;
487 mesh_name <<
"mesh." << setfill(
'0') << setw(6) <<
Mpi::WorldRank();
488 sol_name <<
"sol." << setfill(
'0') << setw(6) <<
Mpi::WorldRank();
490 ofstream mesh_ofs(mesh_name.str().c_str());
491 mesh_ofs.precision(8);
492 pmesh.
Print(mesh_ofs);
494 ofstream sol_ofs(sol_name.str().c_str());
495 sol_ofs.precision(8);
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
A class to handle Block diagonal preconditioners in a matrix-free implementation.
void SetDiagonalBlock(int iblock, Operator *op)
Add a square block op in the block-entry (iblock, iblock).
Operator for block systems arising from different arbitrarily many finite element spaces.
Conjugate gradient method.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the Conjugate Gradient method.
A coefficient that is constant across space and time.
Square Operator for imposing essential boundary conditions using only the action, Mult(),...
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection.
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
void SetTime(real_t t)
Set physical time (for time-dependent simulations)
void SetPrefixPath(const std::string &prefix)
Set the path where the DataCollection will be saved.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
static bool IsEnabled()
Return true if any backend other than Backend::CPU is enabled.
Integrator that computes the PA action of one of the blocks in an ElasticityIntegrator,...
virtual void AssemblePA(const FiniteElementSpace &fes)
Method defining partial assembly.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
const FiniteElementCollection * FEColl() const
Class for grid function - Vector with associated FE space.
Arbitrary order H1-conforming (continuous) finite elements.
The BoomerAMG solver in hypre.
Wrapper for hypre's ParCSR matrix class.
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
void SetRelTol(real_t rtol)
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
void SetMaxIter(int max_it)
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
int Dimension() const
Dimension of the reference space used within the elements.
void GetNodes(Vector &node_coord) const
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Array< int > attributes
A list of all unique element attributes used by the Mesh.
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldRank()
Return the MPI rank in 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 FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, Operator *&A, Vector &X, Vector &B, int copy_interior=0)
Form a constrained linear system using a matrix-free approach.
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
Reconstruct a solution vector x (e.g. a GridFunction) from the solution X of a constrained linear sys...
void ParseCheck(std::ostream &out=mfem::out)
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.
Abstract parallel finite element space.
void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const override
HYPRE_BigInt GlobalTrueVSize() const
const Operator * GetProlongationMatrix() const override
The returned Operator is owned by the FiniteElementSpace.
ParMesh * GetParMesh() const
Class for parallel grid function.
void Save(std::ostream &out) const override
Create and assemble a low-order refined version of a ParBilinearForm.
Class for parallel meshes.
void SetNodalFESpace(FiniteElementSpace *nfes) override
void Print(std::ostream &out=mfem::out, const std::string &comments="") const override
Helper class for ParaView visualization data.
void SetHighOrderOutput(bool high_order_output_)
void SetLevelsOfDetail(int levels_of_detail_)
virtual void Save() override
void SetDataFormat(VTKFormat fmt)
The operator x -> R*A*P*x constructed through the actions of R^T, A and P.
double RealTime()
Return the number of real seconds elapsed since the stopwatch was started.
void Start()
Start the stopwatch. The elapsed time is not cleared.
void Stop()
Stop the stopwatch.
Vector coefficient defined by an array of scalar coefficients. Coefficients that are not set will eva...
Vector & Set(const real_t a, const Vector &x)
(*this) = a * x
std::function< real_t(const Vector &)> f(real_t mass_coeff)