MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
pconvection-diffusion.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// MFEM Ultraweak DPG parallel example for convection-diffusion
13//
14// Compile with: make pconvection-diffusion
15//
16// sample runs
17// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
18// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
19// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
20
21// AMR runs
22// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
23// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
24// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
25
26// Description:
27// This example code demonstrates the use of MFEM to define and solve a parallel
28// "ultraweak" (UW) DPG formulation for the convection-diffusion problem
29
30// - εΔu + ∇⋅(βu) = f, in Ω
31// u = u₀ , on ∂Ω
32
33// It solves the following kinds of problems
34// (a) A manufactured solution where u_exact = sin(π * (x + y + z)).
35// (b) The 2D Erickson-Johnson problem
36// (c) Internal layer problem
37// (d) Boundary layer problem
38
39// The DPG UW deals with the First Order System
40// - ∇⋅σ + ∇⋅(βu) = f, in Ω
41// 1/ε σ - ∇u = 0, in Ω
42// u = u₀ , on ∂Ω
43
44// Ultraweak-DPG is obtained by integration by parts of both equations and the
45// introduction of trace unknowns on the mesh skeleton
46//
47// u ∈ L²(Ω), σ ∈ (L²(Ω))ᵈⁱᵐ
48// û ∈ H^1/2, f̂ ∈ H^-1/2
49// -(βu , ∇v) + (σ , ∇v) + < f̂ , v > = (f,v), ∀ v ∈ H¹(Ω)
50// (u , ∇⋅τ) + 1/ε (σ , τ) + < û , τ⋅n > = 0, ∀ τ ∈ H(div,Ω)
51// û = u₀ on ∂Ω
52
53// Note:
54// f̂ := βu - σ, û := -u on the mesh skeleton
55
56// -------------------------------------------------------------
57// | | u | σ | û | f̂ | RHS |
58// -------------------------------------------------------------
59// | v |-(βu , ∇v) | (σ , ∇v) | | < f̂ ,v > | (f,v) |
60// | | | | | | |
61// | τ | (u ,∇⋅τ) | 1/ε(σ , τ)| <û,τ⋅n> | | 0 |
62
63// where (v,τ) ∈ H¹(Ωₕ) × H(div,Ωₕ)
64
65// For more information see https://doi.org/10.1016/j.camwa.2013.06.010
66
67#include "mfem.hpp"
68#include "util/pweakform.hpp"
70#include <fstream>
71#include <iostream>
72
73
74using namespace mfem;
75using namespace mfem::common;
76
78{
80 EJ, // see https://doi.org/10.1016/j.camwa.2013.06.010
81 curved_streamlines, // see https://doi.org/10.1515/cmam-2018-0207
82 bdr_layer // see https://doi.org/10.1002/num.20640
83};
84
85static const char *enum_str[] =
86{
87 "sinusoidal",
88 "EJ",
89 "curved_streamlines",
90 "bdr_layer"
91};
92
96
97real_t exact_u(const Vector & X);
98void exact_gradu(const Vector & X, Vector & du);
100real_t exact_u(const Vector & X);
101void exact_sigma(const Vector & X, Vector & sigma);
102real_t exact_hatu(const Vector & X);
103void exact_hatf(const Vector & X, Vector & hatf);
104real_t f_exact(const Vector & X);
105real_t bdr_data(const Vector &X);
106void beta_function(const Vector & X, Vector & beta_val);
108
109int main(int argc, char *argv[])
110{
111 Mpi::Init();
112 int myid = Mpi::WorldRank();
113 Hypre::Init();
114
115 // 1. Parse command-line options.
116 const char *mesh_file = "../../data/inline-quad.mesh";
117 int order = 1;
118 int delta_order = 1;
119 int ref = 1;
120 int iprob = 0;
121 real_t theta = 0.7;
122 bool static_cond = false;
123 epsilon = 1e0;
124
125 bool visualization = true;
126 int visport = 19916;
127 bool paraview = false;
128
129 OptionsParser args(argc, argv);
130 args.AddOption(&mesh_file, "-m", "--mesh",
131 "Mesh file to use.");
132 args.AddOption(&order, "-o", "--order",
133 "Finite element order (polynomial degree).");
134 args.AddOption(&delta_order, "-do", "--delta-order",
135 "Order enrichment for DPG test space.");
136 args.AddOption(&epsilon, "-eps", "--epsilon",
137 "Epsilon coefficient");
138 args.AddOption(&ref, "-ref", "--num-refinements",
139 "Number of uniform refinements");
140 args.AddOption(&theta, "-theta", "--theta",
141 "Theta parameter for AMR");
142 args.AddOption(&iprob, "-prob", "--problem", "Problem case"
143 " 0: lshape, 1: General");
144 args.AddOption(&beta, "-beta", "--beta",
145 "Vector Coefficient beta");
146 args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
147 "--no-static-condensation", "Enable static condensation.");
148 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
149 "--no-visualization",
150 "Enable or disable GLVis visualization.");
151 args.AddOption(&paraview, "-paraview", "--paraview", "-no-paraview",
152 "--no-paraview",
153 "Enable or disable ParaView visualization.");
154 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
155 args.Parse();
156 if (!args.Good())
157 {
158 if (myid == 0)
159 {
160 args.PrintUsage(std::cout);
161 }
162 return 1;
163 }
164
165 if (iprob > 3) { iprob = 3; }
166 prob = (prob_type)iprob;
167
168 if (prob == prob_type::EJ || prob == prob_type::curved_streamlines ||
169 prob == prob_type::bdr_layer)
170 {
171 mesh_file = "../../data/inline-quad.mesh";
172 }
173
174 Mesh mesh(mesh_file, 1, 1);
175 int dim = mesh.Dimension();
176 MFEM_VERIFY(dim > 1, "Dimension = 1 is not supported in this example");
177
178 bool exact_known = true;
179 switch (prob)
180 {
181 case sinusoidal:
182 case EJ:
183 {
184 if (beta.Size() == 0)
185 {
187 beta = 0.0;
188 beta[0] = 1.;
189 }
190 break;
191 }
192 case bdr_layer:
193 {
195 beta[0] = 1.;
196 beta[1] = 2.;
197 exact_known = false;
198 }
199 break;
200 default:
201 // do nothing; beta is defined as a FunctionCoefficient
202 break;
203 }
204
205 if (myid == 0)
206 {
207 args.PrintOptions(std::cout);
208 }
209
210 mesh.EnsureNCMesh(true);
211
212 ParMesh pmesh(MPI_COMM_WORLD, mesh);
213 mesh.Clear();
214
215 // Define spaces
216 enum TrialSpace
217 {
218 u_space = 0,
219 sigma_space = 1,
220 hatu_space = 2,
221 hatf_space = 3
222 };
223 enum TestSpace
224 {
225 v_space = 0,
226 tau_space = 1
227 };
228 // L2 space for u
229 FiniteElementCollection *u_fec = new L2_FECollection(order-1,dim);
230 ParFiniteElementSpace *u_fes = new ParFiniteElementSpace(&pmesh,u_fec);
231
232 // Vector L2 space for σ
233 FiniteElementCollection *sigma_fec = new L2_FECollection(order-1,dim);
234 ParFiniteElementSpace *sigma_fes = new ParFiniteElementSpace(&pmesh,sigma_fec,
235 dim);
236
237 // H^1/2 space for û
238 FiniteElementCollection * hatu_fec = new H1_Trace_FECollection(order,dim);
239 ParFiniteElementSpace *hatu_fes = new ParFiniteElementSpace(&pmesh,hatu_fec);
240
241 // H^-1/2 space for σ̂
242 FiniteElementCollection * hatf_fec = new RT_Trace_FECollection(order-1,dim);
243 ParFiniteElementSpace *hatf_fes = new ParFiniteElementSpace(&pmesh,hatf_fec);
244
245 // testspace fe collections
246 int test_order = order+delta_order;
247 FiniteElementCollection * v_fec = new H1_FECollection(test_order, dim);
248 FiniteElementCollection * tau_fec = new RT_FECollection(test_order-1, dim);
249
250 // Coefficients
251 ConstantCoefficient one(1.0);
252 ConstantCoefficient negone(-1.0);
255 ConstantCoefficient negeps1(-1./epsilon);
258
260 ScalarVectorProductCoefficient negbetacoeff(-1.0,betacoeff);
261 OuterProductCoefficient bbtcoeff(betacoeff,betacoeff);
262
263 // Normal equation weak formulation
266
267 trial_fes.Append(u_fes);
268 trial_fes.Append(sigma_fes);
269 trial_fes.Append(hatu_fes);
270 trial_fes.Append(hatf_fes);
271 test_fec.Append(v_fec);
272 test_fec.Append(tau_fec);
273
274 ParDPGWeakForm * a = new ParDPGWeakForm(trial_fes,test_fec);
275 a->StoreMatrices(true);
276
277 //-(βu , ∇v)
278 a->AddTrialIntegrator(new MixedScalarWeakDivergenceIntegrator(betacoeff),
279 TrialSpace::u_space, TestSpace::v_space);
280
281 // (σ,∇ v)
282 a->AddTrialIntegrator(new TransposeIntegrator(new GradientIntegrator(one)),
283 TrialSpace::sigma_space, TestSpace::v_space);
284
285 // (u ,∇⋅τ)
286 a->AddTrialIntegrator(new MixedScalarWeakGradientIntegrator(negone),
287 TrialSpace::u_space, TestSpace::tau_space);
288
289 // 1/ε (σ,τ)
290 a->AddTrialIntegrator(new TransposeIntegrator(new VectorFEMassIntegrator(eps1)),
291 TrialSpace::sigma_space, TestSpace::tau_space);
292
293 // <û,τ⋅n>
294 a->AddTrialIntegrator(new NormalTraceIntegrator,
295 TrialSpace::hatu_space, TestSpace::tau_space);
296
297 // <f̂ ,v>
298 a->AddTrialIntegrator(new TraceIntegrator,
299 TrialSpace::hatf_space, TestSpace::v_space);
300
301
302 FiniteElementCollection *coeff_fec = new L2_FECollection(0,dim);
303 ParFiniteElementSpace *coeff_fes = new ParFiniteElementSpace(&pmesh,coeff_fec);
304 ParGridFunction c1_gf, c2_gf;
305 GridFunctionCoefficient c1_coeff(&c1_gf);
306 GridFunctionCoefficient c2_coeff(&c2_gf);
307
308 c1_gf.SetSpace(coeff_fes);
309 c2_gf.SetSpace(coeff_fes);
310 setup_test_norm_coeffs(c1_gf,c2_gf);
311
312 // c1 (v,δv)
313 a->AddTestIntegrator(new MassIntegrator(c1_coeff),
314 TestSpace::v_space, TestSpace::v_space);
315 // ε (∇v,∇δv)
316 a->AddTestIntegrator(new DiffusionIntegrator(eps),
317 TestSpace::v_space, TestSpace::v_space);
318 // (β⋅∇v, β⋅∇δv)
319 a->AddTestIntegrator(new DiffusionIntegrator(bbtcoeff),
320 TestSpace::v_space, TestSpace::v_space);
321 // c2 (τ,δτ)
322 a->AddTestIntegrator(new VectorFEMassIntegrator(c2_coeff),
323 TestSpace::tau_space, TestSpace::tau_space);
324 // (∇⋅τ,∇⋅δτ)
325 a->AddTestIntegrator(new DivDivIntegrator(one),
326 TestSpace::tau_space, TestSpace::tau_space);
327
329 if (prob == prob_type::sinusoidal ||
330 prob == prob_type::curved_streamlines)
331 {
332 a->AddDomainLFIntegrator(new DomainLFIntegrator(f),TestSpace::v_space);
333 }
334
337 Array<int> elements_to_refine;
340
341 ParGridFunction hatu_gf;
342 ParGridFunction hatf_gf;
343
344 socketstream u_out;
345 socketstream sigma_out;
346
347 real_t res0 = 0.;
348 real_t err0 = 0.;
349 int dof0 = 0; // init to suppress gcc warning
350 if (myid == 0)
351 {
352 std::cout << " Ref |"
353 << " Dofs |" ;
354 if (exact_known)
355 {
356 std::cout << " L2 Error |"
357 << " Rate |";
358 }
359 std::cout << " Residual |"
360 << " Rate |"
361 << " CG it |" << std::endl;
362 std::cout << std::string((exact_known) ? 72 : 50,'-')
363 << std::endl;
364 }
365
366 if (static_cond) { a->EnableStaticCondensation(); }
367
368 ParGridFunction u_gf(u_fes); u_gf = 0.0;
369 ParGridFunction sigma_gf(sigma_fes); sigma_gf = 0.0;
370
371 ParaViewDataCollection * paraview_dc = nullptr;
372
373 if (paraview)
374 {
375 paraview_dc = new ParaViewDataCollection(enum_str[prob], &pmesh);
376 paraview_dc->SetPrefixPath("ParaView/Convection-Diffusion");
377 paraview_dc->SetLevelsOfDetail(order);
378 paraview_dc->SetCycle(0);
379 paraview_dc->SetDataFormat(VTKFormat::BINARY);
380 paraview_dc->SetHighOrderOutput(true);
381 paraview_dc->SetTime(0.0); // set the time
382 paraview_dc->RegisterField("u",&u_gf);
383 paraview_dc->RegisterField("sigma",&sigma_gf);
384 }
385
386 for (int it = 0; it<=ref; it++)
387 {
388 a->Assemble();
389
390 Array<int> ess_tdof_list_uhat;
391 Array<int> ess_tdof_list_fhat;
392 Array<int> ess_bdr_uhat;
393 Array<int> ess_bdr_fhat;
394 if (pmesh.bdr_attributes.Size())
395 {
396 ess_bdr_uhat.SetSize(pmesh.bdr_attributes.Max());
397 ess_bdr_fhat.SetSize(pmesh.bdr_attributes.Max());
398
399 if (prob == prob_type::EJ)
400 {
401 ess_bdr_uhat = 0;
402 ess_bdr_fhat = 1;
403 ess_bdr_uhat[1] = 1;
404 ess_bdr_fhat[1] = 0;
405 }
406 else
407 {
408 ess_bdr_uhat = 1;
409 ess_bdr_fhat = 0;
410 }
411
412 hatu_fes->GetEssentialTrueDofs(ess_bdr_uhat, ess_tdof_list_uhat);
413 hatf_fes->GetEssentialTrueDofs(ess_bdr_fhat, ess_tdof_list_fhat);
414 }
415
416 // shift the ess_tdofs
417 int n = ess_tdof_list_uhat.Size();
418 int m = ess_tdof_list_fhat.Size();
419 Array<int> ess_tdof_list(n+m);
420 for (int j = 0; j < n; j++)
421 {
422 ess_tdof_list[j] = ess_tdof_list_uhat[j]
423 + u_fes->GetTrueVSize()
424 + sigma_fes->GetTrueVSize();
425 }
426 for (int j = 0; j < m; j++)
427 {
428 ess_tdof_list[j+n] = ess_tdof_list_fhat[j]
429 + u_fes->GetTrueVSize()
430 + sigma_fes->GetTrueVSize()
431 + hatu_fes->GetTrueVSize();
432 }
433
434 Array<int> offsets(5);
435 offsets[0] = 0;
436 offsets[1] = u_fes->GetVSize();
437 offsets[2] = sigma_fes->GetVSize();
438 offsets[3] = hatu_fes->GetVSize();
439 offsets[4] = hatf_fes->GetVSize();
440 offsets.PartialSum();
441 BlockVector x(offsets);
442 x = 0.0;
443 hatu_gf.MakeRef(hatu_fes,x.GetBlock(2),0);
445 hatu_gf.ProjectBdrCoefficient(bdr_cf,ess_bdr_uhat);
446
447 hatf_gf.MakeRef(hatf_fes,x.GetBlock(3),0);
448 hatf_gf.ProjectBdrCoefficientNormal(hatfex,ess_bdr_fhat);
449
450 OperatorPtr Ah;
451 Vector X,B;
452 a->FormLinearSystem(ess_tdof_list,x,Ah,X,B);
453
454 BlockOperator * A = Ah.As<BlockOperator>();
455
457 M.owns_blocks = 1;
458 int skip = 0;
459 if (!static_cond)
460 {
461 HypreBoomerAMG * amg0 = new HypreBoomerAMG((HypreParMatrix &)A->GetBlock(0,0));
462 HypreBoomerAMG * amg1 = new HypreBoomerAMG((HypreParMatrix &)A->GetBlock(1,1));
463 amg0->SetPrintLevel(0);
464 amg1->SetPrintLevel(0);
465 M.SetDiagonalBlock(0,amg0);
466 M.SetDiagonalBlock(1,amg1);
467 skip = 2;
468 }
470 skip));
471 amg2->SetPrintLevel(0);
472 M.SetDiagonalBlock(skip,amg2);
473
474 HypreSolver * prec;
475 if (dim == 2)
476 {
477 // AMS preconditioner for 2D H(div) (trace) space
478 prec = new HypreAMS((HypreParMatrix &)A->GetBlock(skip+1,skip+1), hatf_fes);
479 }
480 else
481 {
482 // ADS preconditioner for 3D H(div) (trace) space
483 prec = new HypreADS((HypreParMatrix &)A->GetBlock(skip+1,skip+1), hatf_fes);
484 }
485 M.SetDiagonalBlock(skip+1,prec);
486
487 CGSolver cg(MPI_COMM_WORLD);
488 cg.SetRelTol(1e-12);
489 cg.SetMaxIter(2000);
490 cg.SetPrintLevel(0);
491 cg.SetPreconditioner(M);
492 cg.SetOperator(*A);
493 cg.Mult(B, X);
494 int num_iter = cg.GetNumIterations();
495
496 a->RecoverFEMSolution(X,x);
497 Vector & residuals = a->ComputeResidual(x);
498
499 real_t residual = residuals.Norml2();
500 real_t maxresidual = residuals.Max();
501
502 real_t gresidual = residual * residual;
503
504 MPI_Allreduce(MPI_IN_PLACE, &maxresidual, 1, MPITypeMap<real_t>::mpi_type,
505 MPI_MAX, MPI_COMM_WORLD);
506 MPI_Allreduce(MPI_IN_PLACE, &gresidual, 1, MPITypeMap<real_t>::mpi_type,
507 MPI_SUM, MPI_COMM_WORLD);
508
509 gresidual = sqrt(gresidual);
510
511 elements_to_refine.SetSize(0);
512 for (int iel = 0; iel<pmesh.GetNE(); iel++)
513 {
514 if (residuals[iel] > theta * maxresidual)
515 {
516 elements_to_refine.Append(iel);
517 }
518 }
519
520 u_gf.MakeRef(u_fes,x.GetBlock(0),0);
521 sigma_gf.MakeRef(sigma_fes,x.GetBlock(1),0);
522
523 int dofs = u_fes->GlobalTrueVSize()
524 + sigma_fes->GlobalTrueVSize()
525 + hatu_fes->GlobalTrueVSize()
526 + hatf_fes->GlobalTrueVSize();
527
528 real_t L2Error = 0.0;
529 real_t rate_err = 0.0;
530 if (exact_known)
531 {
532 real_t u_err = u_gf.ComputeL2Error(uex);
533 real_t sigma_err = sigma_gf.ComputeL2Error(sigmaex);
534 L2Error = sqrt(u_err*u_err + sigma_err*sigma_err);
535 rate_err = (it) ? dim*log(err0/L2Error)/log((real_t)dof0/dofs) : 0.0;
536 err0 = L2Error;
537 }
538 real_t rate_res = (it) ? dim*log(res0/gresidual)/log((real_t)dof0/dofs) : 0.0;
539
540 res0 = gresidual;
541 dof0 = dofs;
542
543 if (myid == 0)
544 {
545 std::ios oldState(nullptr);
546 oldState.copyfmt(std::cout);
547 std::cout << std::right << std::setw(5) << it << " | "
548 << std::setw(10) << dof0 << " | ";
549 if (exact_known)
550 {
551 std::cout << std::setprecision(3) << std::setw(10)
552 << std::scientific << err0 << " | "
553 << std::setprecision(2)
554 << std::setw(6) << std::fixed << rate_err << " | " ;
555 }
556 std::cout << std::setprecision(3)
557 << std::setw(10) << std::scientific << res0 << " | "
558 << std::setprecision(2)
559 << std::setw(6) << std::fixed << rate_res << " | "
560 << std::setw(6) << std::fixed << num_iter << " | "
561 << std::endl;
562 std::cout.copyfmt(oldState);
563 }
564
565 if (visualization)
566 {
567 const char * keys = (it == 0 && dim == 2) ? "cgRjmlk\n" : nullptr;
568 char vishost[] = "localhost";
569 VisualizeField(u_out,vishost, visport, u_gf,
570 "Numerical u", 0,0, 500, 500, keys);
571 VisualizeField(sigma_out,vishost, visport, sigma_gf,
572 "Numerical flux", 501,0,500, 500, keys);
573 }
574
575 if (paraview)
576 {
577 paraview_dc->SetCycle(it);
578 paraview_dc->SetTime((real_t)it);
579 paraview_dc->Save();
580 }
581
582 if (it == ref)
583 {
584 break;
585 }
586
587 pmesh.GeneralRefinement(elements_to_refine,1,1);
588 for (int i =0; i<trial_fes.Size(); i++)
589 {
590 trial_fes[i]->Update(false);
591 }
592 a->Update();
593
594 coeff_fes->Update();
595 c1_gf.Update();
596 c2_gf.Update();
597 setup_test_norm_coeffs(c1_gf,c2_gf);
598 }
599
600 if (paraview)
601 {
602 delete paraview_dc;
603 }
604
605 delete coeff_fes;
606 delete coeff_fec;
607 delete a;
608 delete tau_fec;
609 delete v_fec;
610 delete hatf_fes;
611 delete hatf_fec;
612 delete hatu_fes;
613 delete hatu_fec;
614 delete sigma_fec;
615 delete sigma_fes;
616 delete u_fec;
617 delete u_fes;
618
619 return 0;
620}
621
623{
624 real_t x = X[0];
625 real_t y = X[1];
626 real_t z = 0.;
627 if (X.Size() == 3) { z = X[2]; }
628 switch (prob)
629 {
630 case sinusoidal:
631 {
632 real_t alpha = M_PI * (x + y + z);
633 return sin(alpha);
634 }
635 break;
636 case EJ:
637 {
638 real_t alpha = sqrt(1. + 4. * epsilon * epsilon * M_PI * M_PI);
639 real_t r1 = (1. + alpha) / (2.*epsilon);
640 real_t r2 = (1. - alpha) / (2.*epsilon);
641 real_t denom = exp(-r2) - exp(-r1);
642
643 real_t g1 = exp(r2*(x-1.));
644 real_t g2 = exp(r1*(x-1.));
645 real_t g = g1-g2;
646 return g * cos(M_PI * y)/denom;
647 }
648 break;
650 {
651 real_t r = sqrt(x*x+y*y);
652 return atan((1.0-r)/epsilon);
653 }
654 break;
655 default:
656 MFEM_ABORT("Wrong code path");
657 return 1;
658 break;
659 }
660}
661
662void exact_gradu(const Vector & X, Vector & du)
663{
664 real_t x = X[0];
665 real_t y = X[1];
666 real_t z = 0.;
667 if (X.Size() == 3) { z = X[2]; }
668 du.SetSize(X.Size());
669
670 switch (prob)
671 {
672 case sinusoidal:
673 {
674 real_t alpha = M_PI * (x + y + z);
675 for (int i = 0; i<du.Size(); i++)
676 {
677 du[i] = M_PI * cos(alpha);
678 }
679 }
680 break;
681 case EJ:
682 {
683 real_t alpha = sqrt(1. + 4. * epsilon * epsilon * M_PI * M_PI);
684 real_t r1 = (1. + alpha) / (2.*epsilon);
685 real_t r2 = (1. - alpha) / (2.*epsilon);
686 real_t denom = exp(-r2) - exp(-r1);
687
688 real_t g1 = exp(r2*(x-1.));
689 real_t g1_x = r2*g1;
690 real_t g2 = exp(r1*(x-1.));
691 real_t g2_x = r1*g2;
692 real_t g = g1-g2;
693 real_t g_x = g1_x - g2_x;
694
695 real_t u_x = g_x * cos(M_PI * y)/denom;
696 real_t u_y = -M_PI * g * sin(M_PI*y)/denom;
697 du[0] = u_x;
698 du[1] = u_y;
699 }
700 break;
702 {
703 real_t r = sqrt(x*x+y*y);
704 real_t alpha = -2.0*r + r*r + epsilon*epsilon + 1;
705 real_t denom = r*alpha;
706 du[0] = - x* epsilon / denom;
707 du[1] = - y* epsilon / denom;
708 }
709 break;
710 default:
711 MFEM_ABORT("Wrong code path");
712 break;
713 }
714}
715
717{
718 real_t x = X[0];
719 real_t y = X[1];
720 real_t z = 0.;
721 if (X.Size() == 3) { z = X[2]; }
722 switch (prob)
723 {
724 case sinusoidal:
725 {
726 real_t alpha = M_PI * (x + y + z);
727 real_t u = sin(alpha);
728 return - M_PI*M_PI * u * X.Size();
729 }
730 break;
731 case EJ:
732 {
733 real_t alpha = sqrt(1. + 4. * epsilon * epsilon * M_PI * M_PI);
734 real_t r1 = (1. + alpha) / (2.*epsilon);
735 real_t r2 = (1. - alpha) / (2.*epsilon);
736 real_t denom = exp(-r2) - exp(-r1);
737
738 real_t g1 = exp(r2*(x-1.));
739 real_t g1_x = r2*g1;
740 real_t g1_xx = r2*g1_x;
741 real_t g2 = exp(r1*(x-1.));
742 real_t g2_x = r1*g2;
743 real_t g2_xx = r1*g2_x;
744 real_t g = g1-g2;
745 real_t g_xx = g1_xx - g2_xx;
746
747 real_t u = g * cos(M_PI * y)/denom;
748 real_t u_xx = g_xx * cos(M_PI * y)/denom;
749 real_t u_yy = -M_PI * M_PI * u;
750 return u_xx + u_yy;
751 }
752 break;
754 {
755 real_t r = sqrt(x*x+y*y);
756 real_t alpha = -2.0*r + r*r + epsilon*epsilon + 1;
757 return epsilon * (r*r - epsilon*epsilon - 1.0) / (r*alpha*alpha);
758 }
759 break;
760 default:
761 MFEM_ABORT("Wrong code path");
762 return 1;
763 break;
764 }
765}
766
767void exact_sigma(const Vector & X, Vector & sigma)
768{
769 // σ = ε ∇ u
771 sigma *= epsilon;
772}
773
775{
776 return -exact_u(X);
777}
778
779void exact_hatf(const Vector & X, Vector & hatf)
780{
782 Vector beta_val;
783 beta_function(X,beta_val);
785 real_t u = exact_u(X);
786 hatf.SetSize(X.Size());
787 for (int i = 0; i<hatf.Size(); i++)
788 {
789 hatf[i] = beta_val[i] * u - sigma[i];
790 }
791}
792
794{
795 // f = - εΔu + ∇⋅(βu)
796 Vector du;
797 exact_gradu(X,du);
798 real_t d2u = exact_laplacian_u(X);
799
800 Vector beta_val;
801 beta_function(X,beta_val);
802
803 real_t s = 0;
804 for (int i = 0; i<du.Size(); i++)
805 {
806 s += beta_val[i] * du[i];
807 }
808 return -epsilon * d2u + s;
809}
810
812{
813 if (prob == prob_type::bdr_layer)
814 {
815 real_t x = X(0);
816 real_t y = X(1);
817
818 if (y==0.0)
819 {
820 return -(1.0-x);
821 }
822 else if (x == 0.0)
823 {
824 return -(1.0-y);
825 }
826 else
827 {
828 return 0.0;
829 }
830 }
831 else
832 {
833 return exact_hatu(X);
834 }
835}
836
837void beta_function(const Vector & X, Vector & beta_val)
838{
839 beta_val.SetSize(2);
840 if (prob == prob_type::curved_streamlines)
841 {
842 real_t x = X(0);
843 real_t y = X(1);
844 beta_val(0) = exp(x)*sin(y);
845 beta_val(1) = exp(x)*cos(y);
846 }
847 else
848 {
849 beta_val = beta;
850 }
851}
852
854{
855 Array<int> vdofs;
856 ParFiniteElementSpace * fes = c1_gf.ParFESpace();
857 ParMesh * pmesh = fes->GetParMesh();
858 for (int i = 0; i < pmesh->GetNE(); i++)
859 {
860 real_t volume = pmesh->GetElementVolume(i);
861 real_t c1 = std::min(epsilon/volume, (real_t) 1.);
862 real_t c2 = std::min(1./epsilon, 1./volume);
863 fes->GetElementDofs(i,vdofs);
864 c1_gf.SetSubVector(vdofs,c1);
865 c2_gf.SetSubVector(vdofs,c2);
866 }
867}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:758
int Size() const
Return the logical size of the array.
Definition array.hpp:147
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition array.cpp:103
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:830
A class to handle Block diagonal preconditioners in a matrix-free implementation.
A class to handle Block systems in a matrix-free implementation.
Array< int > & RowOffsets()
Return the row offsets for block starts.
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
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.
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.
for Raviart-Thomas elements
Class for domain integration .
Definition lininteg.hpp:106
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:848
A general function coefficient.
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff, const Array< int > &bdr_attr)
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:275
Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the interface between mesh elem...
Definition fe_coll.hpp:338
The Auxiliary-space Divergence Solver in hypre.
Definition hypre.hpp:1948
The Auxiliary-space Maxwell Solver in hypre.
Definition hypre.hpp:1871
The BoomerAMG solver in hypre.
Definition hypre.hpp:1717
void SetPrintLevel(int print_level)
Definition hypre.hpp:1797
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:408
Abstract class for hypre's solvers and preconditioners.
Definition hypre.hpp:1188
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
void SetRelTol(real_t rtol)
Definition solvers.hpp:229
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:174
int GetNumIterations() const
Returns the number of iterations taken during the last call to Mult()
Definition solvers.hpp:280
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
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:290
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:10883
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:761
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
real_t GetElementVolume(int i)
Definition mesh.cpp:121
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:10951
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.
Definition handle.hpp:34
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
Definition handle.hpp:104
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.
Matrix coefficient defined as the outer product of two vector coefficients.
Class representing the parallel weak formulation. (Convenient for DPG Equations)
Definition pweakform.hpp:26
Abstract parallel finite element space.
Definition pfespace.hpp:29
void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const override
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:346
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:350
void GetElementDofs(int i, Array< int > &dofs, DofTransformation &doftrans) const override
The same as GetElementDofs(), but with a user-allocated DofTransformation object. doftrans must be al...
Definition pfespace.cpp:561
ParMesh * GetParMesh() const
Definition pfespace.hpp:338
void Update(bool want_transform=true) override
Class for parallel grid function.
Definition pgridfunc.hpp:50
real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const override
Returns ||u_ex - u_h||_L2 in parallel for H1 or L2 elements.
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff, const Array< int > &attr)
ParFiniteElementSpace * ParFESpace() const
void MakeRef(FiniteElementSpace *f, real_t *v) override
Make the ParGridFunction reference external data on a new FiniteElementSpace.
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition pgridfunc.cpp:91
void SetSpace(FiniteElementSpace *f) override
Associate a new FiniteElementSpace with the ParGridFunction.
Definition pgridfunc.cpp:97
Class for parallel meshes.
Definition pmesh.hpp:34
Helper class for ParaView visualization data.
void SetHighOrderOutput(bool high_order_output_)
void SetLevelsOfDetail(int levels_of_detail_)
void SetDataFormat(VTKFormat fmt)
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
Definition fe_coll.hpp:403
Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the interface between mesh elem...
Definition fe_coll.hpp:462
Vector coefficient defined as a product of scalar and vector coefficients.
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:679
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:931
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1164
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
real_t sigma(const Vector &x)
Definition maxwell.cpp:102
const real_t alpha
Definition ex15.cpp:369
int dim
Definition ex24.cpp:53
bool exact_known
Definition ex25.cpp:144
prob_type
Definition ex25.cpp:149
int main()
real_t a
Definition lissajous.cpp:41
void VisualizeField(socketstream &sock, const char *vishost, int visport, GridFunction &gf, const char *title, int x, int y, int w, int h, const char *keys, bool vec)
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
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[]
Vector beta
real_t exact_hatu(const Vector &X)
real_t exact_laplacian_u(const Vector &X)
void exact_gradu(const Vector &X, Vector &du)
real_t bdr_data(const Vector &X)
real_t epsilon
void exact_hatf(const Vector &X, Vector &hatf)
real_t exact_u(const Vector &X)
void beta_function(const Vector &X, Vector &beta_val)
void exact_sigma(const Vector &X, Vector &sigma)
prob_type prob
@ curved_streamlines
real_t f_exact(const Vector &X)
void setup_test_norm_coeffs(ParGridFunction &c1_gf, ParGridFunction &c2_gf)
Helper struct to convert a C++ type to an MPI type.