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