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