MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
nurbs_ex24.cpp
Go to the documentation of this file.
1// MFEM Example 24 -- modified for NURBS FE
2//
3// Compile with: make nurbs_ex24
4//
5// Sample runs: nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -o 2
6// nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -p 2
7// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -r 3
8// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 1 -r 3
9// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 2 -r 3
10// nurbs_ex24 -m ../../data/escher.mesh
11// nurbs_ex24 -m ../../data/escher.mesh -o 2
12// nurbs_ex24 -m ../../data/fichera.mesh
13// nurbs_ex24 -m ../../data/fichera-q2.vtk
14// nurbs_ex24 -m ../../data/fichera-q3.mesh
15// nurbs_ex24 -m ../../data/amr-quad.mesh -o 2
16// nurbs_ex24 -m ../../data/amr-hex.mesh
17//
18// Description: This example code illustrates usage of mixed finite element
19// spaces, with three variants:
20//
21// 0) (grad p, u) for p in H^1 tested against u in H(curl)
22// 1) (curl v, u) for v in H(curl) tested against u in H(div), 3D
23// 2) (div v, q) for v in H(div) tested against q in L_2
24//
25// Using different approaches, we project the gradient, curl, or
26// divergence to the appropriate space.
27//
28// NURBS-based H(curl) and H(div) spaces only implemented
29// for meshes consisting of a single patch.
30//
31// We recommend viewing examples 1, 3, and 5 before viewing this
32// example.
33
34#include "mfem.hpp"
35#include <fstream>
36#include <iostream>
37
38using namespace std;
39using namespace mfem;
40
41real_t p_exact(const Vector &x);
42void gradp_exact(const Vector &, Vector &);
44void v_exact(const Vector &x, Vector &v);
45void curlv_exact(const Vector &x, Vector &cv);
46
47int dim;
49
50int main(int argc, char *argv[])
51{
52 // 1. Parse command-line options.
53 const char *mesh_file = "../../data/cube-nurbs.mesh";
54 int ref_levels = -1;
55 int order = 1;
56 bool NURBS = true;
57 int prob = 0;
58 bool static_cond = false;
59 bool pa = false;
60 const char *device_config = "cpu";
61 int visport = 19916;
62 bool visualization = 1;
63
64 OptionsParser args(argc, argv);
65 args.AddOption(&mesh_file, "-m", "--mesh",
66 "Mesh file to use.");
67 args.AddOption(&ref_levels, "-r", "--refine",
68 "Number of times to refine the mesh uniformly, -1 for auto.");
69 args.AddOption(&order, "-o", "--order",
70 "Finite element order (polynomial degree).");
71 args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
72 "NURBS.");
73 args.AddOption(&prob, "-p", "--problem-type",
74 "Choose between 0: grad, 1: curl, 2: div");
75 args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
76 "--no-static-condensation", "Enable static condensation.");
77 args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
78 "--no-partial-assembly", "Enable Partial Assembly.");
79 args.AddOption(&device_config, "-d", "--device",
80 "Device configuration string, see Device::Configure().");
81 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
82 "--no-visualization",
83 "Enable or disable GLVis visualization.");
84
85 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
86 args.Parse();
87 if (!args.Good())
88 {
89 args.PrintUsage(cout);
90 return 1;
91 }
92 args.PrintOptions(cout);
93 kappa = freq * M_PI;
94
95 // 2. Enable hardware devices such as GPUs, and programming models such as
96 // CUDA, OCCA, RAJA and OpenMP based on command line options.
97 Device device(device_config);
98 device.Print();
99
100 // 3. Read the mesh from the given mesh file. We can handle triangular,
101 // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
102 // the same code.
103 Mesh *mesh = new Mesh(mesh_file, 1, 1);
104 dim = mesh->Dimension();
105 if ((prob == 1) &&(dim != 3))
106 {
107 MFEM_ABORT("The curl problem is only defined in 3D.");
108 }
109 int sdim = mesh->SpaceDimension();
110
111 // 4. Refine the mesh to increase the resolution. In this example we do
112 // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
113 // largest number that gives a final mesh with no more than 50,000
114 // elements.
115 {
116 if (ref_levels < 0)
117 {
118 ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
119 }
120 for (int l = 0; l < ref_levels; l++)
121 {
122 mesh->UniformRefinement();
123 }
124 }
125
126 // 5. Define a finite element space on the mesh. Here we use Nedelec or
127 // Raviart-Thomas finite elements of the specified order.
128 FiniteElementCollection *trial_fec = nullptr;
129 FiniteElementCollection *test_fec = nullptr;
130 NURBSExtension *NURBSext = nullptr;
131 if (mesh->NURBSext && NURBS)
132 {
133 NURBSext = new NURBSExtension(mesh->NURBSext, order);
134 if (prob == 0)
135 {
136 trial_fec = new NURBSFECollection(order);
137 test_fec = new NURBS_HCurlFECollection(order, dim);
138 }
139 else if (prob == 1)
140 {
141 trial_fec = new NURBS_HCurlFECollection(order, dim);
142 test_fec = new NURBS_HDivFECollection(order, dim);
143 }
144 else
145 {
146 trial_fec = new NURBS_HDivFECollection(order, dim);
147 test_fec = new NURBSFECollection(order);
148 }
149 mfem::out<<"Create NURBS fec and ext"<<std::endl;
150 }
151 else
152 {
153 if (prob == 0)
154 {
155 trial_fec = new H1_FECollection(order, dim);
156 test_fec = new ND_FECollection(order, dim);
157 }
158 else if (prob == 1)
159 {
160 trial_fec = new ND_FECollection(order, dim);
161 test_fec = new RT_FECollection(order-1, dim);
162 }
163 else
164 {
165 trial_fec = new RT_FECollection(order-1, dim);
166 test_fec = new L2_FECollection(order-1, dim);
167 }
168 }
169
170 FiniteElementSpace trial_fes(mesh, NURBSext, trial_fec);
171 FiniteElementSpace test_fes(mesh,trial_fes.StealNURBSext(), test_fec);
172
173 int trial_size = trial_fes.GetTrueVSize();
174 int test_size = test_fes.GetTrueVSize();
175
176 if (prob == 0)
177 {
178 cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
179 cout << "Number of H1 finite element unknowns: " << trial_size << endl;
180 }
181 else if (prob == 1)
182 {
183 cout << "Number of Nedelec finite element unknowns: " << trial_size << endl;
184 cout << "Number of Raviart-Thomas finite element unknowns: " << test_size <<
185 endl;
186 }
187 else
188 {
189 cout << "Number of Raviart-Thomas finite element unknowns: "
190 << trial_size << endl;
191 cout << "Number of L2 finite element unknowns: " << test_size << endl;
192 }
193
194 // 6. Define the solution vector as a finite element grid function
195 // corresponding to the trial fespace.
196 GridFunction gftest(&test_fes);
197 GridFunction gftrial(&trial_fes);
198 GridFunction x(&test_fes);
200 VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
202 VectorFunctionCoefficient curlv_coef(sdim, curlv_exact);
204
205 if (prob == 0)
206 {
207 gftrial.ProjectCoefficient(p_coef);
208 }
209 else if (prob == 1)
210 {
211 gftrial.ProjectCoefficient(v_coef);
212 }
213 else
214 {
215 gftrial.ProjectCoefficient(gradp_coef);
216 }
217
218 gftrial.SetTrueVector();
219 gftrial.SetFromTrueVector();
220
221 // 7. Set up the bilinear forms for L2 projection.
222 ConstantCoefficient one(1.0);
223 BilinearForm a(&test_fes);
224 MixedBilinearForm a_mixed(&trial_fes, &test_fes);
225 if (pa)
226 {
227 a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
228 a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
229 }
230
231 if (prob == 0)
232 {
233 a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
235 }
236 else if (prob == 1)
237 {
238 a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
240 }
241 else
242 {
243 a.AddDomainIntegrator(new MassIntegrator(one));
245 }
246
247 // 8. Assemble the bilinear form and the corresponding linear system,
248 // applying any necessary transformations such as: eliminating boundary
249 // conditions, applying conforming constraints for non-conforming AMR,
250 // static condensation, etc.
251 if (static_cond) { a.EnableStaticCondensation(); }
252
253 a.Assemble();
254 if (!pa) { a.Finalize(); }
255
256 a_mixed.Assemble();
257 if (!pa) { a_mixed.Finalize(); }
258
259 if (pa)
260 {
261 a_mixed.Mult(gftrial, x);
262 }
263 else
264 {
265 SparseMatrix& mixed = a_mixed.SpMat();
266 mixed.Mult(gftrial, x);
267 }
268
269 // 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
270 {
271 GridFunction rhs(&test_fes);
272 rhs = x;
273 x = 0.0;
274
275 CGSolver cg;
276 cg.SetRelTol(1e-12);
277 cg.SetMaxIter(1000);
278 cg.SetPrintLevel(1);
279 if (pa)
280 {
281 Array<int> ess_tdof_list; // empty
282 OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
283
284 cg.SetOperator(a);
285 cg.SetPreconditioner(Jacobi);
286 cg.Mult(rhs, x);
287 }
288 else
289 {
290 SparseMatrix& Amat = a.SpMat();
291 DSmoother Jacobi(Amat);
292
293 cg.SetOperator(Amat);
294 cg.SetPreconditioner(Jacobi);
295 cg.Mult(rhs, x);
296 }
297 }
298
299 // 10. Compute the projection of the exact field.
300 GridFunction exact_proj(&test_fes);
301 if (prob == 0)
302 {
303 exact_proj.ProjectCoefficient(gradp_coef);
304 }
305 else if (prob == 1)
306 {
307 exact_proj.ProjectCoefficient(curlv_coef);
308 }
309 else
310 {
311 exact_proj.ProjectCoefficient(divgradp_coef);
312 }
313
314 exact_proj.SetTrueVector();
315 exact_proj.SetFromTrueVector();
316
317 // 11. Compute and print the L_2 norm of the error.
318 if (prob == 0)
319 {
320 real_t errSol = x.ComputeL2Error(gradp_coef);
321 real_t errProj = exact_proj.ComputeL2Error(gradp_coef);
322
323 cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
324 "|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
325 cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
326 "||_{L_2} = " << errProj << '\n' << endl;
327 }
328 else if (prob == 1)
329 {
330 real_t errSol = x.ComputeL2Error(curlv_coef);
331 real_t errProj = exact_proj.ComputeL2Error(curlv_coef);
332
333 cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in H(div): "
334 "|| E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
335 cout << " Projection E_h of exact curl v in H(div): || E_h - curl v "
336 "||_{L_2} = " << errProj << '\n' << endl;
337 }
338 else
339 {
340 int order_quad = max(3, 2*order+1);
342 for (int i=0; i < Geometry::NumGeom; ++i)
343 {
344 irs[i] = &(IntRules.Get(i, order_quad));
345 }
346
347 real_t errSol = x.ComputeL2Error(divgradp_coef, irs);
348 real_t errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
349
350 cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
351 "|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
352
353 cout << " Projection f_h of exact div v in L_2: || f_h - div v "
354 "||_{L_2} = " << errProj << '\n' << endl;
355 }
356
357 // 12. Save the refined mesh and the solution. This output can be viewed
358 // later using GLVis: "glvis -m refined.mesh -g sol.gf".
359 ofstream mesh_ofs("refined.mesh");
360 mesh_ofs.precision(8);
361 mesh->Print(mesh_ofs);
362 ofstream sol_ofs("sol.gf");
363 sol_ofs.precision(8);
364 x.Save(sol_ofs);
365
366 // 13. Send the solution by socket to a GLVis server.
367 if (visualization)
368 {
369 char vishost[] = "localhost";
370 socketstream sol_sock(vishost, visport);
371 sol_sock.precision(8);
372 sol_sock << "solution\n" << *mesh << x << flush;
373 }
374
375 // 14. Free the used memory.
376 delete trial_fec;
377 delete test_fec;
378 delete mesh;
379
380 return 0;
381}
382
384{
385 if (dim == 3)
386 {
387 return sin(x(0)) * sin(x(1)) * sin(x(2));
388 }
389 else if (dim == 2)
390 {
391 return sin(x(0)) * sin(x(1));
392 }
393
394 return 0.0;
395}
396
397void gradp_exact(const Vector &x, Vector &f)
398{
399 if (dim == 3)
400 {
401 f(0) = cos(x(0)) * sin(x(1)) * sin(x(2));
402 f(1) = sin(x(0)) * cos(x(1)) * sin(x(2));
403 f(2) = sin(x(0)) * sin(x(1)) * cos(x(2));
404 }
405 else
406 {
407 f(0) = cos(x(0)) * sin(x(1));
408 f(1) = sin(x(0)) * cos(x(1));
409 if (x.Size() == 3) { f(2) = 0.0; }
410 }
411}
412
414{
415 if (dim == 3)
416 {
417 return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
418 }
419 else if (dim == 2)
420 {
421 return -2.0 * sin(x(0)) * sin(x(1));
422 }
423
424 return 0.0;
425}
426
427void v_exact(const Vector &x, Vector &v)
428{
429 if (dim == 3)
430 {
431 v(0) = sin(kappa * x(1));
432 v(1) = sin(kappa * x(2));
433 v(2) = sin(kappa * x(0));
434 }
435 else
436 {
437 v(0) = sin(kappa * x(1));
438 v(1) = sin(kappa * x(0));
439 if (x.Size() == 3) { v(2) = 0.0; }
440 }
441}
442
443void curlv_exact(const Vector &x, Vector &cv)
444{
445 if (dim == 3)
446 {
447 cv(0) = -kappa * cos(kappa * x(2));
448 cv(1) = -kappa * cos(kappa * x(0));
449 cv(2) = -kappa * cos(kappa * x(1));
450 }
451 else
452 {
453 cv = 0.0;
454 }
455}
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
Conjugate gradient method.
Definition solvers.hpp:627
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:869
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:640
A coefficient that is constant across space and time.
Data type for scaled Jacobi-type smoother of sparse matrix.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:124
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:317
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:208
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:829
NURBSExtension * StealNURBSext()
Definition fespace.cpp:2598
A general function coefficient.
static const int NumGeom
Definition geom.hpp:46
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:148
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.
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:154
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:178
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:76
void SetMaxIter(int max_it)
Definition solvers.hpp:240
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:350
Mesh data type.
Definition mesh.hpp:65
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:312
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Print the mesh to the given stream using the default MFEM mesh format.
Definition mesh.hpp:2567
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1309
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11637
void Assemble(int skip_zeros=1)
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY.
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level. The default is AssemblyLevel::LEGACY.
const SparseMatrix & SpMat() const
Returns a const reference to the sparse matrix: .
void Mult(const Vector &x, Vector &y) const override
Matrix multiplication: .
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds a domain integrator. Assumes ownership of bfi.
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:500
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
Definition nurbs.hpp:474
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition fe_coll.hpp:717
Arbitrary order H(curl) NURBS finite elements.
Definition fe_coll.hpp:828
Arbitrary order H(div) NURBS finite elements.
Definition fe_coll.hpp:776
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:422
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.
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
Definition fe_coll.hpp:407
Data type sparse matrix.
Definition sparsemat.hpp:51
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
prob_type prob
Definition ex25.cpp:156
int main()
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
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
const char vishost[]
real_t p_exact(const Vector &x)
real_t kappa
void curlv_exact(const Vector &x, Vector &cv)
int dim
void v_exact(const Vector &x, Vector &v)
real_t freq
void gradp_exact(const Vector &, Vector &)
real_t div_gradp_exact(const Vector &x)