MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
nurbs_ex3.cpp
Go to the documentation of this file.
1// MFEM Example 3 -- modified for NURBS FE
2//
3// Compile with: make nurbs_ex3
4//
5// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
6// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
7// nurbs_ex3 -m ../../data/cube-nurbs.mesh
8//
9// Description: This example code solves a simple electromagnetic diffusion
10// problem corresponding to the second order definite Maxwell
11// equation curl curl E + E = f with boundary condition
12// E x n = <given tangential field>. Here, we use a given exact
13// solution E and compute the corresponding r.h.s. f.
14// We discretize with Nedelec finite elements in 2D or 3D.
15//
16// The example demonstrates the use of H(curl) finite element
17// spaces with the curl-curl and the (vector finite element) mass
18// bilinear form, as well as the computation of discretization
19// error when the exact solution is known. Static condensation is
20// also illustrated.
21//
22// NURBS-based H(curl) spaces only implemented for meshes
23// consisting of a single patch.
24//
25// We recommend viewing examples 1-2 before viewing this example.
26
27#include "mfem.hpp"
28#include <fstream>
29#include <iostream>
30
31using namespace std;
32using namespace mfem;
33
34// Exact solution, E, and r.h.s., f. See below for implementation.
35void E_exact(const Vector &, Vector &);
36void f_exact(const Vector &, Vector &);
38int dim;
39
40int main(int argc, char *argv[])
41{
42 // 1. Parse command-line options.
43 const char *mesh_file = "../../data/square-nurbs.mesh";
44 int ref_levels = -1;
45 bool NURBS = true;
46 int order = 1;
47 bool static_cond = false;
48 bool pa = false;
49 const char *device_config = "cpu";
50 int visport = 19916;
51 bool visualization = 1;
52
53 OptionsParser args(argc, argv);
54 args.AddOption(&mesh_file, "-m", "--mesh",
55 "Mesh file to use.");
56 args.AddOption(&ref_levels, "-r", "--refine",
57 "Number of times to refine the mesh uniformly, -1 for auto.");
58 args.AddOption(&order, "-o", "--order",
59 "Finite element order (polynomial degree).");
60 args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
61 "NURBS.");
62 args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
63 " solution.");
64 args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
65 "--no-static-condensation", "Enable static condensation.");
66 args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
67 "--no-partial-assembly", "Enable Partial Assembly.");
68 args.AddOption(&device_config, "-d", "--device",
69 "Device configuration string, see Device::Configure().");
70 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
71 "--no-visualization",
72 "Enable or disable GLVis visualization.");
73 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
74 args.Parse();
75 if (!args.Good())
76 {
77 args.PrintUsage(cout);
78 return 1;
79 }
80 args.PrintOptions(cout);
81 kappa = freq * M_PI;
82
83 // 2. Enable hardware devices such as GPUs, and programming models such as
84 // CUDA, OCCA, RAJA and OpenMP based on command line options.
85 Device device(device_config);
86 device.Print();
87
88 // 3. Read the mesh from the given mesh file. We can handle triangular,
89 // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
90 // the same code.
91 Mesh *mesh = new Mesh(mesh_file, 1, 1);
92 dim = mesh->Dimension();
93 int sdim = mesh->SpaceDimension();
94
95 // 4. Refine the mesh to increase the resolution. In this example we do
96 // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
97 // largest number that gives a final mesh with no more than 50,000
98 // elements.
99 {
100 if (ref_levels < 0)
101 {
102 ref_levels =
103 (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
104 }
105 for (int l = 0; l < ref_levels; l++)
106 {
107 mesh->UniformRefinement();
108 }
109 }
110
111 // 5. Define a finite element space on the mesh. Here we use the
112 // Raviart-Thomas finite elements of the specified order.
113 FiniteElementCollection *fec = nullptr;
114 NURBSExtension *NURBSext = nullptr;
115
116 if (mesh->NURBSext && NURBS)
117 {
118 fec = new NURBS_HCurlFECollection(order,dim);
119 NURBSext = new NURBSExtension(mesh->NURBSext, order);
120 mfem::out<<"Create NURBS fec and ext"<<std::endl;
121 }
122 else
123 {
124 NURBS = false;
125 fec = new ND_FECollection(order, dim);
126 mfem::out<<"Create Normal fec"<<std::endl;
127 }
128
129 FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
130 cout << "Number of finite element unknowns: "
131 << fespace->GetTrueVSize() << endl;
132
133 // 6. Determine the list of true (i.e. conforming) essential boundary dofs.
134 // In this example, the boundary conditions are defined by marking all
135 // the boundary attributes from the mesh as essential (Dirichlet) and
136 // converting them to a list of true dofs.
137 Array<int> ess_tdof_list;
138 if (mesh->bdr_attributes.Size())
139 {
140 Array<int> ess_bdr(mesh->bdr_attributes.Max());
141 ess_bdr = 1;
142 fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
143 }
144 cout << "Number of knowns in essential BCs: "
145 << ess_tdof_list.Size() << endl;
146
147 // 7. Set up the linear form b(.) which corresponds to the right-hand side
148 // of the FEM linear system, which in this case is (f,phi_i) where f is
149 // given by the function f_exact and phi_i are the basis functions in the
150 // finite element fespace.
152 LinearForm *b = new LinearForm(fespace);
153 b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
154 b->Assemble();
155
156 // 8. Define the solution vector x as a finite element grid function
157 // corresponding to fespace. Initialize x by projecting the exact
158 // solution. Note that only values from the boundary edges will be used
159 // when eliminating the non-homogeneous boundary condition to modify the
160 // r.h.s. vector b.
161 GridFunction x(fespace);
164
165 // 9. Set up the bilinear form corresponding to the EM diffusion operator
166 // curl muinv curl + sigma I, by adding the curl-curl and the mass domain
167 // integrators.
168 Coefficient *muinv = new ConstantCoefficient(1.0);
170 BilinearForm *a = new BilinearForm(fespace);
171 if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
172 a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
173 a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
174
175 // 10. Assemble the bilinear form and the corresponding linear system,
176 // applying any necessary transformations such as: eliminating boundary
177 // conditions, applying conforming constraints for non-conforming AMR,
178 // static condensation, etc.
179 if (static_cond) { a->EnableStaticCondensation(); }
180 a->Assemble();
181
182 OperatorPtr A;
183 Vector B, X;
184 a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
185
186 cout << "Size of linear system: " << A->Height() << endl;
187
188 // 11. Solve the linear system A X = B.
189 if (pa) // Jacobi preconditioning in partial assembly mode
190 {
191 OperatorJacobiSmoother M(*a, ess_tdof_list);
192 PCG(*A, M, B, X, 1, 1000, 1e-12, 0.0);
193 }
194 else
195 {
196#ifndef MFEM_USE_SUITESPARSE
197 // 11. Define a simple symmetric Gauss-Seidel preconditioner and use it to
198 // solve the system Ax=b with PCG.
199 GSSmoother M((SparseMatrix&)(*A));
200 PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
201#else
202 // 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
203 // system.
204 UMFPackSolver umf_solver;
205 umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
206 umf_solver.SetOperator(*A);
207 umf_solver.Mult(B, X);
208#endif
209 }
210
211 // 12. Recover the solution as a finite element grid function.
212 a->RecoverFEMSolution(X, *b, x);
213
214 // 13. Compute and print the L^2 norm of the error.
215 cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl;
216
217 // 14. Save the refined mesh and the solution. This output can be viewed
218 // later using GLVis: "glvis -m refined.mesh -g sol.gf".
219 {
220 ofstream mesh_ofs("refined.mesh");
221 mesh_ofs.precision(8);
222 mesh->Print(mesh_ofs);
223 ofstream sol_ofs("sol.gf");
224 sol_ofs.precision(8);
225 x.Save(sol_ofs);
226 }
227
228 // 15. Send the solution by socket to a GLVis server.
229 if (visualization)
230 {
231 char vishost[] = "localhost";
232 socketstream sol_sock(vishost, visport);
233 sol_sock.precision(8);
234 sol_sock << "solution\n" << *mesh << x << flush;
235 }
236
237 // 16. Create output in visit format
238 VisItDataCollection visit_dc("Example3", mesh);
239 visit_dc.RegisterField("x", &x);
240 visit_dc.Save();
241
242 // 17. Free the used memory.
243 delete a;
244 delete sigma;
245 delete muinv;
246 delete b;
247 delete fespace;
248 delete fec;
249 delete mesh;
250
251 return 0;
252}
253
254
255void E_exact(const Vector &x, Vector &E)
256{
257 if (dim == 3)
258 {
259 E(0) = sin(kappa * x(1));
260 E(1) = sin(kappa * x(2));
261 E(2) = sin(kappa * x(0));
262 }
263 else
264 {
265 E(0) = sin(kappa * x(1));
266 E(1) = sin(kappa * x(0));
267 if (x.Size() == 3) { E(2) = 0.0; }
268 }
269}
270
271void f_exact(const Vector &x, Vector &f)
272{
273 if (dim == 3)
274 {
275 f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
276 f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
277 f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
278 }
279 else
280 {
281 f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
282 f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
283 if (x.Size() == 3) { f(2) = 0.0; }
284 }
285}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
int Size() const
Return the logical size of the array.
Definition array.hpp:147
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
A coefficient that is constant across space and time.
Integrator for for Nedelec elements.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:123
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:297
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:244
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:851
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const
Get a list of essential true dofs, ess_tdof_list, corresponding to the boundary attributes marked in ...
Definition fespace.cpp:658
Data type for Gauss-Seidel smoother of sparse matrix.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const
Returns ||exsol - u_h||_L2 for scalar or vector H1 or L2 elements.
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Vector with associated FE space and LinearFormIntegrators.
Mesh data type.
Definition mesh.hpp:64
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:290
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:298
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2433
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1219
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11295
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:482
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
Definition nurbs.hpp:449
Arbitrary order H(curl) NURBS finite elements.
Definition fe_coll.hpp:810
Pointer to an Operator of a specified type.
Definition handle.hpp:34
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:333
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
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...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Data type sparse matrix.
Definition sparsemat.hpp:51
Direct sparse solver using UMFPACK.
Definition solvers.hpp:1121
real_t Control[UMFPACK_CONTROL]
Definition solvers.hpp:1131
void SetOperator(const Operator &op) override
Factorize the given Operator op which must be a SparseMatrix.
Definition solvers.cpp:3218
void Mult(const Vector &b, Vector &x) const override
Direct solution of the linear system using UMFPACK.
Definition solvers.cpp:3313
for VectorFiniteElements (Nedelec, Raviart-Thomas)
Definition lininteg.hpp:344
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
Data collection with VisIt I/O routines.
void Save() override
Save the collection and a VisIt root file.
void RegisterField(const std::string &field_name, GridFunction *gf) override
Add a grid function to the collection and update the root file.
real_t sigma(const Vector &x)
Definition maxwell.cpp:102
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
void PCG(const Operator &A, Solver &B, const Vector &b, Vector &x, int print_iter, int max_num_iter, real_t RTOLERANCE, real_t ATOLERANCE)
Preconditioned conjugate gradient method. (tolerances are squared)
Definition solvers.cpp:949
float real_t
Definition config.hpp:43
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
const char vishost[]
real_t kappa
Definition nurbs_ex3.cpp:37
int dim
Definition nurbs_ex3.cpp:38
void E_exact(const Vector &, Vector &)
void f_exact(const Vector &, Vector &)
real_t freq
Definition nurbs_ex3.cpp:37