Permalink
Fetching contributors…
Cannot retrieve contributors at this time
184 lines (168 sloc) 6.58 KB
// MFEM Example 14
//
// Compile with: make ex14
//
// Sample runs: ex14 -m ../data/inline-quad.mesh -o 0
// ex14 -m ../data/star.mesh -r 4 -o 2
// ex14 -m ../data/escher.mesh -s 1
// ex14 -m ../data/fichera.mesh -s 1 -k 1
// ex14 -m ../data/square-disc-p2.vtk -r 3 -o 2
// ex14 -m ../data/square-disc-p3.mesh -r 2 -o 3
// ex14 -m ../data/square-disc-nurbs.mesh -o 1
// ex14 -m ../data/disc-nurbs.mesh -r 3 -o 2 -s 1 -k 0
// ex14 -m ../data/pipe-nurbs.mesh -o 1
// ex14 -m ../data/inline-segment.mesh -r 5
// ex14 -m ../data/amr-quad.mesh -r 3
// ex14 -m ../data/amr-hex.mesh
// ex14 -m ../data/fichera-amr.mesh
//
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
// the Laplace problem -Delta u = 1 with homogeneous Dirichlet
// boundary conditions. Finite element spaces of any order,
// including zero on regular grids, are supported. The example
// highlights the use of discontinuous spaces and DG-specific face
// integrators.
//
// We recommend viewing examples 1 and 9 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ref_levels = -1;
int order = 1;
double sigma = -1.0;
double kappa = -1.0;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) >= 0.");
args.AddOption(&sigma, "-s", "--sigma",
"One of the two DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
args.AddOption(&kappa, "-k", "--kappa",
"One of the two DG penalty parameters, should be positive."
" Negative values are replaced with (order+1)^2.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
if (kappa < 0)
{
kappa = (order+1)*(order+1);
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
// NURBS meshes are projected to second order meshes.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. By default, or if ref_levels < 0,
// we choose it to be the largest number that gives a final mesh with no
// more than 50,000 elements.
{
if (ref_levels < 0)
{
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
if (mesh->NURBSext)
{
mesh->SetCurvature(max(order, 1));
}
// 4. Define a finite element space on the mesh. Here we use discontinuous
// finite elements of the specified order >= 0.
FiniteElementCollection *fec = new DG_FECollection(order, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of unknowns: " << fespace->GetVSize() << endl;
// 5. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(zero, one, sigma, kappa));
b->Assemble();
// 6. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero.
GridFunction x(fespace);
x = 0.0;
// 7. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator and the interior and boundary DG face integrators.
// Note that boundary conditions are imposed weakly in the form, so there
// is no need for dof elimination. After assembly and finalizing we
// extract the corresponding sparse matrix A.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
a->AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
a->Assemble();
a->Finalize();
const SparseMatrix &A = a->SpMat();
#ifndef MFEM_USE_SUITESPARSE
// 8. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG in the symmetric case, and GMRES in the
// non-symmetric one.
GSSmoother M(A);
if (sigma == -1.0)
{
PCG(A, M, *b, x, 1, 500, 1e-12, 0.0);
}
else
{
GMRES(A, M, *b, x, 1, 500, 10, 1e-12, 0.0);
}
#else
// 8. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(*b, x);
#endif
// 9. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 10. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 11. Free the used memory.
delete a;
delete b;
delete fespace;
delete fec;
delete mesh;
return 0;
}