MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
pmaxwell.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 Maxwell parallel example
13//
14// Compile with: make pmaxwell
15//
16// sample run
17// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
18// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
19// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
20// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
21// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2 -pmg
22// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
23// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
24
25// AMR run. Note that this is a computationally intensive sample run.
26// We recommend trying it on a large machine with more mpi ranks
27// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
28
29// Description:
30// This example code demonstrates the use of MFEM to define and solve
31// the "ultraweak" (UW) DPG formulation for the Maxwell problem
32
33// ∇×(1/μ ∇×E) - ω² ϵ E = Ĵ , in Ω
34// E×n = E₀ , on ∂Ω
35
36// It solves the following kinds of problems
37// 1) Known exact solutions with error convergence rates
38// a) A manufactured solution problem where E is a plane beam
39// 2) Fichera "microwave" problem
40// 3) PML problems
41// a) Generic PML problem with point source given by the load
42// b) Plane wave scattering from a square
43// c) PML problem with a point source prescribed on the boundary
44
45// The DPG UW deals with the First Order System
46// i ω μ H + ∇ × E = 0, in Ω
47// -i ω ϵ E + ∇ × H = J, in Ω
48// E × n = E₀, on ∂Ω
49// Note: Ĵ = -iωJ
50
51// The ultraweak-DPG formulation is obtained by integration by parts of both
52// equations and the introduction of trace unknowns on the mesh skeleton
53
54// in 2D
55// E is vector valued and H is scalar.
56// (∇ × E, F) = (E, ∇ × F) + < n × E , F>
57// or (∇ ⋅ AE , F) = (AE, ∇ F) + < AE ⋅ n, F>
58// where A = [0 1; -1 0];
59
60// E ∈ (L²(Ω))² , H ∈ L²(Ω)
61// Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ)
62// i ω μ (H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹
63// -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
64// Ê = E₀ on ∂Ω
65// -------------------------------------------------------------------------
66// | | E | H | Ê | Ĥ | RHS |
67// -------------------------------------------------------------------------
68// | F | (E,∇ × F) | i ω μ (H,F) | < Ê, F > | | |
69// | | | | | | |
70// | G | -i ω ϵ (E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) |
71// where (F,G) ∈ H¹ × H(curl,Ω)
72
73// in 3D
74// E,H ∈ (L^2(Ω))³
75// Ê ∈ H\_0^1/2(Ω)(curl, Γₕ), Ĥ ∈ H^-1/2(curl, Γₕ)
76// i ω μ (H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω)
77// -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
78// Ê × n = E₀ on ∂Ω
79// -------------------------------------------------------------------------
80// | | E | H | Ê | Ĥ | RHS |
81// -------------------------------------------------------------------------
82// | F | (E,∇ × F) | i ω μ (H,F) | < n × Ê, F > | | |
83// | | | | | | |
84// | G | -i ω ϵ (E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) |
85// where (F,G) ∈ H(curl,Ω) × H(curl,Ω)
86
87// Here we use the "Adjoint Graph" norm on the test space i.e.,
88// ||(F,G)||²ᵥ = ||A^*(F,G)||² + ||(F,G)||² where A is the
89// maxwell operator defined by (1)
90
91// The PML formulation is
92
93// ∇×(1/μ α ∇×E) - ω² ϵ β E = Ĵ , in Ω
94// E×n = E₀ , on ∂Ω
95
96// where α = |J|⁻¹ Jᵀ J (in 2D it's the scalar |J|⁻¹),
97// β = |J| J⁻¹ J⁻ᵀ, J is the Jacobian of the stretching map
98// and |J| its determinant.
99
100// The first order system reads
101// i ω μ α⁻¹ H + ∇ × E = 0, in Ω
102// -i ω ϵ β E + ∇ × H = J, in Ω
103// E × n = E₀, on ∂Ω
104
105// and the ultraweak formulation is
106
107// in 2D
108// E ∈ (L²(Ω))² , H ∈ L²(Ω)
109// Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ)
110// i ω μ (α⁻¹ H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹
111// -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
112// Ê = E₀ on ∂Ω
113// ---------------------------------------------------------------------------------
114// | | E | H | Ê | Ĥ | RHS |
115// ---------------------------------------------------------------------------------
116// | F | (E,∇ × F) | i ω μ (α⁻¹ H,F) | < Ê, F > | | |
117// | | | | | | |
118// | G | -i ω ϵ (β E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) |
119
120// where (F,G) ∈ H¹ × H(curl,Ω)
121
122//
123// in 3D
124// E,H ∈ (L^2(Ω))³
125// Ê ∈ H_0^1/2(Ω)(curl, Γₕ), Ĥ ∈ H^-1/2(curl, Γₕ)
126// i ω μ (α⁻¹ H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω)
127// -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
128// Ê × n = E₀ on ∂Ω
129// -------------------------------------------------------------------------------
130// | | E | H | Ê | Ĥ | RHS |
131// -------------------------------------------------------------------------------
132// | F | ( E,∇ × F) | i ω μ (α⁻¹ H,F) | < n × Ê, F > | | |
133// | | | | | | |
134// | G | -iωϵ (β E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) |
135// where (F,G) ∈ H(curl,Ω) × H(curl,Ω)
136
137// For more information see https://doi.org/10.1016/j.camwa.2021.01.017
138
139#include "mfem.hpp"
141#include "util/pml.hpp"
144#include <fstream>
145#include <iostream>
146
147using namespace std;
148using namespace mfem;
149using namespace mfem::common;
150
151
152void E_exact_r(const Vector &x, Vector & E_r);
153void E_exact_i(const Vector &x, Vector & E_i);
154
155void H_exact_r(const Vector &x, Vector & H_r);
156void H_exact_i(const Vector &x, Vector & H_i);
157
158void rhs_func_r(const Vector &x, Vector & J_r);
159void rhs_func_i(const Vector &x, Vector & J_i);
160
161void curlE_exact_r(const Vector &x, Vector &curlE_r);
162void curlE_exact_i(const Vector &x, Vector &curlE_i);
163void curlH_exact_r(const Vector &x,Vector &curlH_r);
164void curlH_exact_i(const Vector &x,Vector &curlH_i);
165
166void curlcurlE_exact_r(const Vector &x, Vector & curlcurlE_r);
167void curlcurlE_exact_i(const Vector &x, Vector & curlcurlE_i);
168
169void hatE_exact_r(const Vector & X, Vector & hatE_r);
170void hatE_exact_i(const Vector & X, Vector & hatE_i);
171
172void hatH_exact_r(const Vector & X, Vector & hatH_r);
173void hatH_exact_i(const Vector & X, Vector & hatH_i);
174
177
178void maxwell_solution(const Vector & X,
179 std::vector<complex<real_t>> &E);
180
181void maxwell_solution_curl(const Vector & X,
182 std::vector<complex<real_t>> &curlE);
183
184void maxwell_solution_curlcurl(const Vector & X,
185 std::vector<complex<real_t>> &curlcurlE);
186
187void source_function(const Vector &x, Vector & f);
188
189int dim;
192real_t mu = 1.0;
194
203
204static const char *enum_str[] =
205{
206 "plane_wave",
207 "fichera_oven",
208 "pml_general",
209 "pml_plane_wave_scatter",
210 "pml_pointsource"
211};
212
214
215int main(int argc, char *argv[])
216{
217 Mpi::Init();
218 int myid = Mpi::WorldRank();
219 Hypre::Init();
220
221 const char *mesh_file = "../../data/inline-quad.mesh";
222 int order = 1;
223 int delta_order = 1;
224 real_t rnum=1.0;
225 real_t theta = 0.0;
226 bool pmg = false;
227 int pmg_levels = -1;
228 real_t relax_factor = 2.0/3;
229 bool static_cond = false;
230 int iprob = 0;
231 int sr = 0;
232 int pr = 1;
233 bool exact_known = false;
234 bool with_pml = false;
235 bool visualization = true;
236 int visport = 19916;
237 bool paraview = false;
238
239 OptionsParser args(argc, argv);
240 args.AddOption(&mesh_file, "-m", "--mesh",
241 "Mesh file to use.");
242 args.AddOption(&order, "-o", "--order",
243 "Finite element order (polynomial degree)");
244 args.AddOption(&rnum, "-rnum", "--number-of-wavelengths",
245 "Number of wavelengths");
246 args.AddOption(&mu, "-mu", "--permeability",
247 "Permeability of free space (or 1/(spring constant)).");
248 args.AddOption(&epsilon, "-eps", "--permittivity",
249 "Permittivity of free space (or mass constant).");
250 args.AddOption(&iprob, "-prob", "--problem", "Problem case"
251 " 0: plane wave, 1: Fichera 'oven', "
252 " 2: Generic PML problem with point source given as a load "
253 " 3: Scattering of a plane wave, "
254 " 4: Point source given on the boundary");
255 args.AddOption(&delta_order, "-do", "--delta-order",
256 "Order enrichment for DPG test space.");
257 args.AddOption(&theta, "-theta", "--theta",
258 "Theta parameter for AMR");
259 args.AddOption(&sr, "-sref", "--serial-ref",
260 "Number of parallel refinements.");
261 args.AddOption(&pr, "-pref", "--parallel-ref",
262 "Number of parallel refinements.");
263 args.AddOption(&pmg, "-pmg", "--p-refinement-multigrid", "-no-pmg",
264 "--no-p-refinement-multigrid", "Enable P-Refinement Multigrid.");
265 args.AddOption(&pmg_levels, "-pmgl","--p-refinement-multigrid-levels",
266 "Number of levels for P-Refinement Multigrid.");
267 args.AddOption(&relax_factor, "-rf", "--relaxation-factor",
268 "Relaxation factor for the p-multigrid smoother.");
269 args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
270 "--no-static-condensation", "Enable static condensation.");
271 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
272 "--no-visualization",
273 "Enable or disable GLVis visualization.");
274 args.AddOption(&paraview, "-paraview", "--paraview", "-no-paraview",
275 "--no-paraview",
276 "Enable or disable ParaView visualization.");
277 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
278 args.Parse();
279 if (!args.Good())
280 {
281 if (myid == 0)
282 {
283 args.PrintUsage(cout);
284 }
285 return 1;
286 }
287
288 if (iprob > 4) { iprob = 0; }
289 prob = (prob_type)iprob;
290 omega = 2.*M_PI*rnum;
291
292 if (prob == 0)
293 {
294 exact_known = true;
295 }
296 else if (prob == 1)
297 {
298 mesh_file = "meshes/fichera-waveguide.mesh";
299 omega = 5.0;
300 rnum = omega/(2.*M_PI);
301 }
302 else if (prob == 2)
303 {
304 with_pml = true;
305 }
306 else
307 {
308 with_pml = true;
309 mesh_file = "meshes/scatter.mesh";
310 }
311
312 if (myid == 0)
313 {
314 args.PrintOptions(cout);
315 }
316
317 Mesh mesh(mesh_file, 1, 1);
318 dim = mesh.Dimension();
319 MFEM_VERIFY(dim > 1, "Dimension = 1 is not supported in this example");
320
321 dimc = (dim == 3) ? 3 : 1;
322
323 for (int i = 0; i<sr; i++)
324 {
325 mesh.UniformRefinement();
326 }
327 mesh.EnsureNCMesh(false);
328
329 CartesianPML * pml = nullptr;
330 if (with_pml)
331 {
332 Array2D<real_t> length(dim, 2); length = 0.25;
333 pml = new CartesianPML(&mesh,length);
334 pml->SetOmega(omega);
336 }
337
338 ParMesh pmesh(MPI_COMM_WORLD, mesh);
339 mesh.Clear();
340
341 // PML element attribute marker
342 Array<int> attr;
343 Array<int> attrPML;
344 if (pml) { pml->SetAttributes(&pmesh, &attr, &attrPML); }
345
346 // Define spaces
347 enum TrialSpace
348 {
349 E_space = 0,
350 H_space = 1,
351 hatE_space = 2,
352 hatH_space = 3
353 };
354 enum TestSpace
355 {
356 F_space = 0,
357 G_space = 1
358 };
359 // L2 space for E
360 FiniteElementCollection *E_fec = new L2_FECollection(order-1,dim);
361 ParFiniteElementSpace *E_fes = new ParFiniteElementSpace(&pmesh,E_fec,dim);
362
363 // Vector L2 space for H
364 FiniteElementCollection *H_fec = new L2_FECollection(order-1,dim);
365 ParFiniteElementSpace *H_fes = new ParFiniteElementSpace(&pmesh,H_fec, dimc);
366
367 // H^-1/2 (curl) space for Ê
368 FiniteElementCollection * hatE_fec = nullptr;
369 FiniteElementCollection * hatH_fec = nullptr;
370 FiniteElementCollection * F_fec = nullptr;
371 int test_order = order+delta_order;
372 if (dim == 3)
373 {
374 hatE_fec = new ND_Trace_FECollection(order,dim);
375 hatH_fec = new ND_Trace_FECollection(order,dim);
376 F_fec = new ND_FECollection(test_order, dim);
377 }
378 else
379 {
380 hatE_fec = new RT_Trace_FECollection(order-1,dim);
381 hatH_fec = new H1_Trace_FECollection(order,dim);
382 F_fec = new H1_FECollection(test_order, dim);
383 }
384 ParFiniteElementSpace *hatE_fes = new ParFiniteElementSpace(&pmesh,hatE_fec);
385 ParFiniteElementSpace *hatH_fes = new ParFiniteElementSpace(&pmesh,hatH_fec);
386 FiniteElementCollection * G_fec = new ND_FECollection(test_order, dim);
387
390 trial_fes.Append(E_fes);
391 trial_fes.Append(H_fes);
392 trial_fes.Append(hatE_fes);
393 trial_fes.Append(hatH_fes);
394 test_fec.Append(F_fec);
395 test_fec.Append(G_fec);
396
397 // Bilinear form coefficients
398 ConstantCoefficient one(1.0);
402 ConstantCoefficient negepsomeg(-epsilon*omega);
404 ConstantCoefficient negmuomeg(-mu*omega);
405 // for the 2D case
406 DenseMatrix rot_mat(2);
407 rot_mat(0,0) = 0.; rot_mat(0,1) = 1.;
408 rot_mat(1,0) = -1.; rot_mat(1,1) = 0.;
409 MatrixConstantCoefficient rot(rot_mat);
410 ScalarMatrixProductCoefficient epsrot(epsomeg,rot);
411 ScalarMatrixProductCoefficient negepsrot(negepsomeg,rot);
412
413 Coefficient * epsomeg_cf = nullptr;
414 Coefficient * negepsomeg_cf = nullptr;
415 Coefficient * eps2omeg2_cf = nullptr;
416 Coefficient * muomeg_cf = nullptr;
417 Coefficient * negmuomeg_cf = nullptr;
418 Coefficient * mu2omeg2_cf = nullptr;
419 MatrixCoefficient *epsrot_cf = nullptr;
420 MatrixCoefficient *negepsrot_cf = nullptr;
421
422 if (pml)
423 {
424 epsomeg_cf = new RestrictedCoefficient(epsomeg,attr);
425 negepsomeg_cf = new RestrictedCoefficient(negepsomeg,attr);
426 eps2omeg2_cf = new RestrictedCoefficient(eps2omeg2,attr);
427 muomeg_cf = new RestrictedCoefficient(muomeg,attr);
428 negmuomeg_cf = new RestrictedCoefficient(negmuomeg,attr);
429 mu2omeg2_cf = new RestrictedCoefficient(mu2omeg2,attr);
430 epsrot_cf = new MatrixRestrictedCoefficient(epsrot,attr);
431 negepsrot_cf = new MatrixRestrictedCoefficient(negepsrot,attr);
432 }
433 else
434 {
435 epsomeg_cf = &epsomeg;
436 negepsomeg_cf = &negepsomeg;
437 eps2omeg2_cf = &eps2omeg2;
438 muomeg_cf = &muomeg;
439 negmuomeg_cf = &negmuomeg;
440 mu2omeg2_cf = &mu2omeg2;
441 epsrot_cf = &epsrot;
442 negepsrot_cf = &negepsrot;
443 }
444
445 // PML coefficients;
448 PmlCoefficient abs_detJ_2(abs_detJ_2_function,pml);
452
453 ProductCoefficient negmuomeg_detJ_r(negmuomeg,detJ_r);
454 ProductCoefficient negmuomeg_detJ_i(negmuomeg,detJ_i);
455 ProductCoefficient muomeg_detJ_r(muomeg,detJ_r);
456 ProductCoefficient mu2omeg2_detJ_2(mu2omeg2,abs_detJ_2);
457 ScalarMatrixProductCoefficient epsomeg_detJ_Jt_J_inv_i(epsomeg,
458 detJ_Jt_J_inv_i);
459 ScalarMatrixProductCoefficient epsomeg_detJ_Jt_J_inv_r(epsomeg,
460 detJ_Jt_J_inv_r);
461 ScalarMatrixProductCoefficient negepsomeg_detJ_Jt_J_inv_r(negepsomeg,
462 detJ_Jt_J_inv_r);
463 ScalarMatrixProductCoefficient muomeg_detJ_Jt_J_inv_r(muomeg,detJ_Jt_J_inv_r);
464 ScalarMatrixProductCoefficient negmuomeg_detJ_Jt_J_inv_i(negmuomeg,
465 detJ_Jt_J_inv_i);
466 ScalarMatrixProductCoefficient negmuomeg_detJ_Jt_J_inv_r(negmuomeg,
467 detJ_Jt_J_inv_r);
468 ScalarMatrixProductCoefficient mu2omeg2_detJ_Jt_J_inv_2(mu2omeg2,
469 abs_detJ_Jt_J_inv_2);
470 ScalarMatrixProductCoefficient eps2omeg2_detJ_Jt_J_inv_2(eps2omeg2,
471 abs_detJ_Jt_J_inv_2);
472
473 RestrictedCoefficient negmuomeg_detJ_r_restr(negmuomeg_detJ_r,attrPML);
474 RestrictedCoefficient negmuomeg_detJ_i_restr(negmuomeg_detJ_i,attrPML);
475 RestrictedCoefficient muomeg_detJ_r_restr(muomeg_detJ_r,attrPML);
476 RestrictedCoefficient mu2omeg2_detJ_2_restr(mu2omeg2_detJ_2,attrPML);
477 MatrixRestrictedCoefficient epsomeg_detJ_Jt_J_inv_i_restr(
478 epsomeg_detJ_Jt_J_inv_i,attrPML);
479 MatrixRestrictedCoefficient epsomeg_detJ_Jt_J_inv_r_restr(
480 epsomeg_detJ_Jt_J_inv_r,attrPML);
481 MatrixRestrictedCoefficient negepsomeg_detJ_Jt_J_inv_r_restr(
482 negepsomeg_detJ_Jt_J_inv_r,attrPML);
483 MatrixRestrictedCoefficient muomeg_detJ_Jt_J_inv_r_restr(muomeg_detJ_Jt_J_inv_r,
484 attrPML);
485 MatrixRestrictedCoefficient negmuomeg_detJ_Jt_J_inv_i_restr(
486 negmuomeg_detJ_Jt_J_inv_i,attrPML);
487 MatrixRestrictedCoefficient negmuomeg_detJ_Jt_J_inv_r_restr(
488 negmuomeg_detJ_Jt_J_inv_r,attrPML);
489 MatrixRestrictedCoefficient mu2omeg2_detJ_Jt_J_inv_2_restr(
490 mu2omeg2_detJ_Jt_J_inv_2,attrPML);
491 MatrixRestrictedCoefficient eps2omeg2_detJ_Jt_J_inv_2_restr(
492 eps2omeg2_detJ_Jt_J_inv_2,attrPML);
493
494 MatrixProductCoefficient * epsomeg_detJ_Jt_J_inv_i_rot = nullptr;
495 MatrixProductCoefficient * epsomeg_detJ_Jt_J_inv_r_rot = nullptr;
496 MatrixProductCoefficient * negepsomeg_detJ_Jt_J_inv_r_rot = nullptr;
497 MatrixRestrictedCoefficient * epsomeg_detJ_Jt_J_inv_i_rot_restr = nullptr;
498 MatrixRestrictedCoefficient * epsomeg_detJ_Jt_J_inv_r_rot_restr = nullptr;
499 MatrixRestrictedCoefficient * negepsomeg_detJ_Jt_J_inv_r_rot_restr = nullptr;
500
501 if (pml && dim == 2)
502 {
503 epsomeg_detJ_Jt_J_inv_i_rot = new MatrixProductCoefficient(
504 epsomeg_detJ_Jt_J_inv_i, rot);
505 epsomeg_detJ_Jt_J_inv_r_rot = new MatrixProductCoefficient(
506 epsomeg_detJ_Jt_J_inv_r, rot);
507 negepsomeg_detJ_Jt_J_inv_r_rot = new MatrixProductCoefficient(
508 negepsomeg_detJ_Jt_J_inv_r, rot);
509 epsomeg_detJ_Jt_J_inv_i_rot_restr = new MatrixRestrictedCoefficient(
510 *epsomeg_detJ_Jt_J_inv_i_rot, attrPML);
511 epsomeg_detJ_Jt_J_inv_r_rot_restr = new MatrixRestrictedCoefficient(
512 *epsomeg_detJ_Jt_J_inv_r_rot, attrPML);
513 negepsomeg_detJ_Jt_J_inv_r_rot_restr = new MatrixRestrictedCoefficient(
514 *negepsomeg_detJ_Jt_J_inv_r_rot, attrPML);
515 }
516
517 ParComplexDPGWeakForm * a = new ParComplexDPGWeakForm(trial_fes,test_fec);
518 a->StoreMatrices(); // needed for AMR
519
520 // (E,∇ × F)
521 a->AddTrialIntegrator(new TransposeIntegrator(new MixedCurlIntegrator(one)),
522 nullptr,TrialSpace::E_space, TestSpace::F_space);
523 // -i ω ϵ (E , G) = i (- ω ϵ E, G)
524 a->AddTrialIntegrator(nullptr,
525 new TransposeIntegrator(new VectorFEMassIntegrator(*negepsomeg_cf)),
526 TrialSpace::E_space,TestSpace::G_space);
527 // (H,∇ × G)
528 a->AddTrialIntegrator(new TransposeIntegrator(new MixedCurlIntegrator(one)),
529 nullptr,TrialSpace::H_space, TestSpace::G_space);
530 // < n×Ĥ ,G>
531 a->AddTrialIntegrator(new TangentTraceIntegrator,nullptr,
532 TrialSpace::hatH_space, TestSpace::G_space);
533 // test integrators
534 // (∇×G ,∇× δG)
535 a->AddTestIntegrator(new CurlCurlIntegrator(one),nullptr,
536 TestSpace::G_space,TestSpace::G_space);
537 // (G,δG)
538 a->AddTestIntegrator(new VectorFEMassIntegrator(one),nullptr,
539 TestSpace::G_space,TestSpace::G_space);
540
541 if (dim == 3)
542 {
543 // i ω μ (H, F)
544 a->AddTrialIntegrator(nullptr, new TransposeIntegrator(
545 new VectorFEMassIntegrator(*muomeg_cf)),
546 TrialSpace::H_space,TestSpace::F_space);
547 // < n×Ê,F>
548 a->AddTrialIntegrator(new TangentTraceIntegrator,nullptr,
549 TrialSpace::hatE_space, TestSpace::F_space);
550
551 // test integrators
552 // (∇×F,∇×δF)
553 a->AddTestIntegrator(new CurlCurlIntegrator(one),nullptr,
554 TestSpace::F_space, TestSpace::F_space);
555 // (F,δF)
556 a->AddTestIntegrator(new VectorFEMassIntegrator(one),nullptr,
557 TestSpace::F_space,TestSpace::F_space);
558 // μ^2 ω^2 (F,δF)
559 a->AddTestIntegrator(new VectorFEMassIntegrator(*mu2omeg2_cf),nullptr,
560 TestSpace::F_space, TestSpace::F_space);
561 // -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G)
562 a->AddTestIntegrator(nullptr,new MixedVectorWeakCurlIntegrator(*negmuomeg_cf),
563 TestSpace::F_space, TestSpace::G_space);
564 // -i ω ϵ (∇ × F, δG)
565 a->AddTestIntegrator(nullptr,new MixedVectorCurlIntegrator(*negepsomeg_cf),
566 TestSpace::F_space, TestSpace::G_space);
567 // i ω μ (∇ × G,δF)
568 a->AddTestIntegrator(nullptr,new MixedVectorCurlIntegrator(*muomeg_cf),
569 TestSpace::G_space, TestSpace::F_space);
570 // i ω ϵ (G, ∇ × δF )
571 a->AddTestIntegrator(nullptr,new MixedVectorWeakCurlIntegrator(*epsomeg_cf),
572 TestSpace::G_space, TestSpace::F_space);
573 // ϵ^2 ω^2 (G,δG)
574 a->AddTestIntegrator(new VectorFEMassIntegrator(*eps2omeg2_cf),nullptr,
575 TestSpace::G_space, TestSpace::G_space);
576 }
577 else
578 {
579 // i ω μ (H, F)
580 a->AddTrialIntegrator(nullptr,new MixedScalarMassIntegrator(*muomeg_cf),
581 TrialSpace::H_space, TestSpace::F_space);
582 // < n×Ê,F>
583 a->AddTrialIntegrator(new TraceIntegrator,nullptr,
584 TrialSpace::hatE_space, TestSpace::F_space);
585 // test integrators
586 // (∇F,∇δF)
587 a->AddTestIntegrator(new DiffusionIntegrator(one),nullptr,
588 TestSpace::F_space, TestSpace::F_space);
589 // (F,δF)
590 a->AddTestIntegrator(new MassIntegrator(one),nullptr,
591 TestSpace::F_space, TestSpace::F_space);
592 // μ^2 ω^2 (F,δF)
593 a->AddTestIntegrator(new MassIntegrator(*mu2omeg2_cf),nullptr,
594 TestSpace::F_space, TestSpace::F_space);
595 // -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G)
596 a->AddTestIntegrator(nullptr,
597 new TransposeIntegrator(new MixedCurlIntegrator(*negmuomeg_cf)),
598 TestSpace::F_space, TestSpace::G_space);
599 // -i ω ϵ (∇ × F, δG) = i (- ω ϵ A ∇ F,δG), A = [0 1; -1; 0]
600 a->AddTestIntegrator(nullptr,new MixedVectorGradientIntegrator(*negepsrot_cf),
601 TestSpace::F_space, TestSpace::G_space);
602 // i ω μ (∇ × G,δF) = i (ω μ ∇ × G, δF )
603 a->AddTestIntegrator(nullptr,new MixedCurlIntegrator(*muomeg_cf),
604 TestSpace::G_space, TestSpace::F_space);
605 // i ω ϵ (G, ∇ × δF ) = i (ω ϵ G, A ∇ δF) = i ( G , ω ϵ A ∇ δF)
606 a->AddTestIntegrator(nullptr,
608 new MixedVectorGradientIntegrator(*epsrot_cf)),
609 TestSpace::G_space, TestSpace::F_space);
610 // ϵ^2 ω^2 (G, δG)
611 a->AddTestIntegrator(new VectorFEMassIntegrator(*eps2omeg2_cf),nullptr,
612 TestSpace::G_space, TestSpace::G_space);
613 }
614 if (pml)
615 {
616 //trial integrators
617 // -i ω ϵ (β E , G) = -i ω ϵ ((β_re + i β_im) E, G)
618 // = (ω ϵ β_im E, G) + i (- ω ϵ β_re E, G)
619 a->AddTrialIntegrator(
621 epsomeg_detJ_Jt_J_inv_i_restr)),
623 negepsomeg_detJ_Jt_J_inv_r_restr)),
624 TrialSpace::E_space,TestSpace::G_space);
625 if (dim == 3)
626 {
627 //trial integrators
628 // i ω μ (α^-1 H, F) = i ω μ ( (α^-1_re + i α^-1_im) H, F)
629 // = (- ω μ α^-1_im, H,F) + i *(ω μ α^-1_re H, F)
630 a->AddTrialIntegrator(
632 negmuomeg_detJ_Jt_J_inv_i_restr)),
634 muomeg_detJ_Jt_J_inv_r_restr)),
635 TrialSpace::H_space, TestSpace::F_space);
636 // test integrators
637 // μ^2 ω^2 (|α|^-2 F,δF)
638 a->AddTestIntegrator(
639 new VectorFEMassIntegrator(mu2omeg2_detJ_Jt_J_inv_2_restr),nullptr,
640 TestSpace::F_space, TestSpace::F_space);
641 // -i ω μ (α^-* F,∇ × δG) = i (F, - ω μ α^-1 ∇ × δ G)
642 // = i (F, - ω μ (α^-1_re + i α^-1_im) ∇ × δ G)
643 // = (F, - ω μ α^-1_im ∇ × δ G) + i (F, - ω μ α^-1_re ∇×δG)
644 a->AddTestIntegrator(new MixedVectorWeakCurlIntegrator(
645 negmuomeg_detJ_Jt_J_inv_i_restr),
646 new MixedVectorWeakCurlIntegrator(negmuomeg_detJ_Jt_J_inv_r_restr),
647 TestSpace::F_space,TestSpace::G_space);
648 // -i ω ϵ (β ∇ × F, δG) = -i ω ϵ ((β_re + i β_im) ∇ × F, δG)
649 // = (ω ϵ β_im ∇ × F, δG) + i (- ω ϵ β_re ∇ × F, δG)
650 a->AddTestIntegrator(new MixedVectorCurlIntegrator(
651 epsomeg_detJ_Jt_J_inv_i_restr),
652 new MixedVectorCurlIntegrator(negepsomeg_detJ_Jt_J_inv_r_restr),
653 TestSpace::F_space,TestSpace::G_space);
654 // i ω μ (α^-1 ∇ × G,δF) = i ω μ ((α^-1_re + i α^-1_im) ∇ × G,δF)
655 // = (- ω μ α^-1_im ∇ × G,δF) + i (ω μ α^-1_re ∇ × G,δF)
656 a->AddTestIntegrator(new MixedVectorCurlIntegrator(
657 negmuomeg_detJ_Jt_J_inv_i_restr),
658 new MixedVectorCurlIntegrator(muomeg_detJ_Jt_J_inv_r_restr),
659 TestSpace::G_space, TestSpace::F_space);
660 // i ω ϵ (β^* G, ∇×δF) = i ω ϵ ( (β_re - i β_im) G, ∇×δF)
661 // = (ω ϵ β_im G, ∇×δF) + i ( ω ϵ β_re G, ∇×δF)
662 a->AddTestIntegrator(new MixedVectorWeakCurlIntegrator(
663 epsomeg_detJ_Jt_J_inv_i_restr),
664 new MixedVectorWeakCurlIntegrator(epsomeg_detJ_Jt_J_inv_r_restr),
665 TestSpace::G_space, TestSpace::F_space);
666 // ϵ^2 ω^2 (|β|^2 G,δG)
667 a->AddTestIntegrator(new VectorFEMassIntegrator(
668 eps2omeg2_detJ_Jt_J_inv_2_restr),nullptr,
669 TestSpace::G_space, TestSpace::G_space);
670 }
671 else
672 {
673 //trial integrators
674 // i ω μ (α^-1 H, F) = i ω μ ( (α^-1_re + i α^-1_im) H, F)
675 // = (- ω μ α^-1_im, H,F) + i *(ω μ α^-1_re H, F)
676 a->AddTrialIntegrator(
677 new MixedScalarMassIntegrator(negmuomeg_detJ_i_restr),
678 new MixedScalarMassIntegrator(muomeg_detJ_r_restr),
679 TrialSpace::H_space, TestSpace::F_space);
680 // test integrators
681 // μ^2 ω^2 (|α|^-2 F,δF)
682 a->AddTestIntegrator(new MassIntegrator(mu2omeg2_detJ_2_restr),nullptr,
683 TestSpace::F_space, TestSpace::F_space);
684 // -i ω μ (α^-* F,∇ × δG) = (F, ω μ α^-1 ∇ × δ G)
685 // =(F, - ω μ α^-1_im ∇ × δ G) + i (F, - ω μ α^-1_re ∇×δG)
686 a->AddTestIntegrator(
687 new TransposeIntegrator(new MixedCurlIntegrator(negmuomeg_detJ_i_restr)),
688 new TransposeIntegrator(new MixedCurlIntegrator(negmuomeg_detJ_r_restr)),
689 TestSpace::F_space, TestSpace::G_space);
690 // -i ω ϵ (β ∇ × F, δG) = i (- ω ϵ β A ∇ F,δG), A = [0 1; -1; 0]
691 // = (ω ϵ β_im A ∇ F, δG) + i (- ω ϵ β_re A ∇ F, δG)
692 a->AddTestIntegrator(new MixedVectorGradientIntegrator(
693 *epsomeg_detJ_Jt_J_inv_i_rot_restr),
694 new MixedVectorGradientIntegrator(*negepsomeg_detJ_Jt_J_inv_r_rot_restr),
695 TestSpace::F_space, TestSpace::G_space);
696 // i ω μ (α^-1 ∇ × G,δF) = i (ω μ α^-1 ∇ × G, δF )
697 // = (- ω μ α^-1_im ∇ × G,δF) + i (ω μ α^-1_re ∇ × G,δF)
698 a->AddTestIntegrator(new MixedCurlIntegrator(negmuomeg_detJ_i_restr),
699 new MixedCurlIntegrator(muomeg_detJ_r_restr),
700 TestSpace::G_space, TestSpace::F_space);
701 // i ω ϵ (β^* G, ∇ × δF ) = i ( G , ω ϵ β A ∇ δF)
702 // = ( G , ω ϵ β_im A ∇ δF) + i ( G , ω ϵ β_re A ∇ δF)
703 a->AddTestIntegrator(
705 *epsomeg_detJ_Jt_J_inv_i_rot_restr)),
707 *epsomeg_detJ_Jt_J_inv_r_rot_restr)),
708 TestSpace::G_space, TestSpace::F_space);
709 // ϵ^2 ω^2 (|β|^2 G,δG)
710 a->AddTestIntegrator(new VectorFEMassIntegrator(
711 eps2omeg2_detJ_Jt_J_inv_2_restr),nullptr,
712 TestSpace::G_space, TestSpace::G_space);
713 }
714 }
715 // RHS
719 if (prob == 0)
720 {
721 a->AddDomainLFIntegrator(new VectorFEDomainLFIntegrator(f_rhs_r),
722 new VectorFEDomainLFIntegrator(f_rhs_i),
723 TestSpace::G_space);
724 }
725 else if (prob == 2)
726 {
727 a->AddDomainLFIntegrator(new VectorFEDomainLFIntegrator(f_source),nullptr,
728 TestSpace::G_space);
729 }
730
733
734 socketstream E_out_r;
735 socketstream H_out_r;
736 if (myid == 0)
737 {
738 std::cout << "\n Ref |"
739 << " Dofs |"
740 << " ω |" ;
741 if (exact_known)
742 {
743 std::cout << " L2 Error |"
744 << " Rate |" ;
745 }
746 std::cout << " Residual |"
747 << " Rate |"
748 << " PCG it |" << endl;
749 std::cout << std::string((exact_known) ? 82 : 60,'-')
750 << endl;
751 }
752
753 real_t res0 = 0.;
754 real_t err0 = 0.;
755 int dof0 = 0; // init to suppress gcc warning
756
757 Array<int> elements_to_refine;
758
759 ParGridFunction E_r, E_i, H_r, H_i;
760
761 ParaViewDataCollection * paraview_dc = nullptr;
762
763 if (paraview)
764 {
765 paraview_dc = new ParaViewDataCollection(enum_str[prob], &pmesh);
766 paraview_dc->SetPrefixPath("ParaView/Maxwell");
767 paraview_dc->SetLevelsOfDetail(order);
768 paraview_dc->SetCycle(0);
769 paraview_dc->SetDataFormat(VTKFormat::BINARY);
770 paraview_dc->SetHighOrderOutput(true);
771 paraview_dc->SetTime(0.0); // set the time
772 paraview_dc->RegisterField("E_r",&E_r);
773 paraview_dc->RegisterField("E_i",&E_i);
774 paraview_dc->RegisterField("H_r",&H_r);
775 paraview_dc->RegisterField("H_i",&H_i);
776 }
777
778 if (static_cond) { a->EnableStaticCondensation(); }
779 for (int it = 0; it<=pr; it++)
780 {
781 a->Assemble();
782
784 Array<int> ess_bdr;
785 if (pmesh.bdr_attributes.Size())
786 {
787 ess_bdr.SetSize(pmesh.bdr_attributes.Max());
788 ess_bdr = 1;
789 hatE_fes->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
790 if (pml)
791 {
792 ess_bdr = 0;
793 ess_bdr[1] = 1;
794 }
795 }
796
797 // shift the ess_tdofs
798 for (int j = 0; j < ess_tdof_list.Size(); j++)
799 {
800 ess_tdof_list[j] += E_fes->GetTrueVSize() + H_fes->GetTrueVSize();
801 }
802
803 Array<int> offsets(5);
804 offsets[0] = 0;
805 offsets[1] = E_fes->GetVSize();
806 offsets[2] = H_fes->GetVSize();
807 offsets[3] = hatE_fes->GetVSize();
808 offsets[4] = hatH_fes->GetVSize();
809 offsets.PartialSum();
810
811 Vector x(2*offsets.Last());
812 x = 0.;
813
814 if (prob != 2)
815 {
816 ParGridFunction hatE_gf_r(hatE_fes, x, offsets[2]);
817 ParGridFunction hatE_gf_i(hatE_fes, x, offsets.Last() + offsets[2]);
818 if (dim == 3)
819 {
820 hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr);
821 hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr);
822 }
823 else
824 {
825 hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr);
826 hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr);
827 }
828 }
829
830 OperatorPtr Ah;
831 Vector X,B;
832 a->FormLinearSystem(ess_tdof_list,x,Ah, X,B);
833
834 ComplexOperator * Ahc = Ah.As<ComplexOperator>();
835 BlockOperator * BlockA_r = dynamic_cast<BlockOperator *>(&Ahc->real());
836
838 if (static_cond)
839 {
840 a->GetTraceFESpaces(prec_fes);
841 }
842 else
843 {
844 prec_fes = trial_fes;
845 }
846 Solver * cprec = nullptr;
847 if (pmg)
848 {
849#ifdef MFEM_USE_MUMPS
850 bool mumps_coarse_solver = true;
851#else
852 bool mumps_coarse_solver = false;
853#endif
854 std::vector<Array<int>> ess_bdr_marker(prec_fes.Size());
855 for (int b = 0; b<prec_fes.Size(); b++)
856 {
857 if (pmesh.bdr_attributes.Size())
858 {
859 ess_bdr_marker[b].SetSize(pmesh.bdr_attributes.Max());
860 int ess_block = (static_cond) ? 0 : 2;
861 if (b == ess_block) // hatE
862 {
863 ess_bdr_marker[b] = ess_bdr;
864 }
865 else
866 {
867 ess_bdr_marker[b] = 0;
868 }
869 }
870 }
871 cprec = new ComplexPRefinementMultigrid(prec_fes, ess_bdr_marker, *Ahc,
872 pmg_levels, relax_factor, mumps_coarse_solver);
873 }
874 else
875 {
877 BlockA_r->RowOffsets());
878 real_prec->owns_blocks = 1;
879 for (int i = 0; i<BlockA_r->NumRowBlocks(); i++)
880 {
881 auto prec = MakeFESpaceDefaultSolver(prec_fes[i],0);
882 prec->SetOperator(BlockA_r->GetBlock(i,i));
883 real_prec->SetDiagonalBlock(i,prec);
884 }
885 cprec = new ComplexPreconditioner(real_prec, true);
886 }
887
888 CGSolver cg(MPI_COMM_WORLD);
889 cg.SetRelTol(1e-6);
890 cg.SetMaxIter(10000);
891 cg.SetPrintLevel(0);
892 cg.SetOperator(*Ahc);
893 cg.SetPreconditioner(*cprec);
894 cg.Mult(B, X);
895
896 delete cprec;
897
898 int num_iter = cg.GetNumIterations();
899
900 a->RecoverFEMSolution(X,x);
901
902 Vector & residuals = a->ComputeResidual(x);
903
904 real_t residual = residuals.Norml2();
905 real_t maxresidual = residuals.Max();
906 real_t globalresidual = residual * residual;
907 MPI_Allreduce(MPI_IN_PLACE, &maxresidual, 1, MPITypeMap<real_t>::mpi_type,
908 MPI_MAX, MPI_COMM_WORLD);
909 MPI_Allreduce(MPI_IN_PLACE, &globalresidual, 1,
910 MPITypeMap<real_t>::mpi_type, MPI_SUM, MPI_COMM_WORLD);
911
912 globalresidual = sqrt(globalresidual);
913
914 E_r.MakeRef(E_fes,x, 0);
915 E_i.MakeRef(E_fes,x, offsets.Last());
916
917 H_r.MakeRef(H_fes,x, offsets[1]);
918 H_i.MakeRef(H_fes,x, offsets.Last()+offsets[1]);
919
920 int dofs = 0;
921 for (int i = 0; i<trial_fes.Size(); i++)
922 {
923 dofs += trial_fes[i]->GlobalTrueVSize();
924 }
925
926 real_t L2Error = 0.0;
927 real_t rate_err = 0.0;
928
929 if (exact_known)
930 {
935 real_t E_err_r = E_r.ComputeL2Error(E_ex_r);
936 real_t E_err_i = E_i.ComputeL2Error(E_ex_i);
937 real_t H_err_r = H_r.ComputeL2Error(H_ex_r);
938 real_t H_err_i = H_i.ComputeL2Error(H_ex_i);
939 L2Error = sqrt( E_err_r*E_err_r + E_err_i*E_err_i
940 + H_err_r*H_err_r + H_err_i*H_err_i );
941 rate_err = (it) ? dim*log(err0/L2Error)/log((real_t)dof0/dofs) : 0.0;
942 err0 = L2Error;
943 }
944
945 real_t rate_res = (it) ? dim*log(res0/globalresidual)/log((
946 real_t)dof0/dofs) : 0.0;
947
948 res0 = globalresidual;
949 dof0 = dofs;
950
951 if (myid == 0)
952 {
953 std::ios oldState(nullptr);
954 oldState.copyfmt(std::cout);
955 std::cout << std::right << std::setw(5) << it << " | "
956 << std::setw(10) << dof0 << " | "
957 << std::setprecision(1) << std::fixed
958 << std::setw(4) << 2.0*rnum << " π | "
959 << std::setprecision(3);
960 if (exact_known)
961 {
962 std::cout << std::setw(10) << std::scientific << err0 << " | "
963 << std::setprecision(2)
964 << std::setw(6) << std::fixed << rate_err << " | " ;
965 }
966 std::cout << std::setprecision(3)
967 << std::setw(10) << std::scientific << res0 << " | "
968 << std::setprecision(2)
969 << std::setw(6) << std::fixed << rate_res << " | "
970 << std::setw(6) << std::fixed << num_iter << " | "
971 << std::endl;
972 std::cout.copyfmt(oldState);
973 }
974
975 if (visualization)
976 {
977 const char * keys = (it == 0 && dim == 2) ? "jRcml\n" : nullptr;
978 char vishost[] = "localhost";
979 VisualizeField(E_out_r,vishost, visport, E_r,
980 "Numerical Electric field (real part)", 0, 0, 500, 500, keys);
981 VisualizeField(H_out_r,vishost, visport, H_r,
982 "Numerical Magnetic field (real part)", 501, 0, 500, 500, keys);
983 }
984
985 if (paraview)
986 {
987 paraview_dc->SetCycle(it);
988 paraview_dc->SetTime((real_t)it);
989 paraview_dc->Save();
990 }
991
992 if (it == pr)
993 {
994 break;
995 }
996
997 if (theta > 0.0)
998 {
999 elements_to_refine.SetSize(0);
1000 for (int iel = 0; iel<pmesh.GetNE(); iel++)
1001 {
1002 if (residuals[iel] > theta * maxresidual)
1003 {
1004 elements_to_refine.Append(iel);
1005 }
1006 }
1007 pmesh.GeneralRefinement(elements_to_refine,1,1);
1008 }
1009 else
1010 {
1011 pmesh.UniformRefinement();
1012 }
1013 if (pml) { pml->SetAttributes(&pmesh); }
1014 for (int i =0; i<trial_fes.Size(); i++)
1015 {
1016 trial_fes[i]->Update(false);
1017 }
1018 a->Update();
1019 }
1020
1021 if (pml && dim == 2)
1022 {
1023 delete epsomeg_detJ_Jt_J_inv_i_rot;
1024 delete epsomeg_detJ_Jt_J_inv_r_rot;
1025 delete negepsomeg_detJ_Jt_J_inv_r_rot;
1026 delete epsomeg_detJ_Jt_J_inv_i_rot_restr;
1027 delete epsomeg_detJ_Jt_J_inv_r_rot_restr;
1028 delete negepsomeg_detJ_Jt_J_inv_r_rot_restr;
1029 }
1030
1031 if (paraview)
1032 {
1033 delete paraview_dc;
1034 }
1035
1036 delete a;
1037 delete F_fec;
1038 delete G_fec;
1039 delete hatH_fes;
1040 delete hatH_fec;
1041 delete hatE_fes;
1042 delete hatE_fec;
1043 delete H_fec;
1044 delete E_fec;
1045 delete H_fes;
1046 delete E_fes;
1047
1048 return 0;
1049}
1050
1051void E_exact_r(const Vector &x, Vector & E_r)
1052{
1053 std::vector<std::complex<real_t>> E;
1054 maxwell_solution(x,E);
1055 E_r.SetSize(E.size());
1056 for (unsigned i = 0; i < E.size(); i++)
1057 {
1058 E_r[i]= E[i].real();
1059 }
1060}
1061
1062void E_exact_i(const Vector &x, Vector & E_i)
1063{
1064 std::vector<std::complex<real_t>> E;
1065 maxwell_solution(x, E);
1066 E_i.SetSize(E.size());
1067 for (unsigned i = 0; i < E.size(); i++)
1068 {
1069 E_i[i]= E[i].imag();
1070 }
1071}
1072
1073void curlE_exact_r(const Vector &x, Vector &curlE_r)
1074{
1075 std::vector<std::complex<real_t>> curlE;
1076 maxwell_solution_curl(x, curlE);
1077 curlE_r.SetSize(curlE.size());
1078 for (unsigned i = 0; i < curlE.size(); i++)
1079 {
1080 curlE_r[i]= curlE[i].real();
1081 }
1082}
1083
1084void curlE_exact_i(const Vector &x, Vector &curlE_i)
1085{
1086 std::vector<std::complex<real_t>> curlE;
1087 maxwell_solution_curl(x, curlE);
1088 curlE_i.SetSize(curlE.size());
1089 for (unsigned i = 0; i < curlE.size(); i++)
1090 {
1091 curlE_i[i]= curlE[i].imag();
1092 }
1093}
1094
1095void curlcurlE_exact_r(const Vector &x, Vector & curlcurlE_r)
1096{
1097 std::vector<std::complex<real_t>> curlcurlE;
1098 maxwell_solution_curlcurl(x, curlcurlE);
1099 curlcurlE_r.SetSize(curlcurlE.size());
1100 for (unsigned i = 0; i < curlcurlE.size(); i++)
1101 {
1102 curlcurlE_r[i]= curlcurlE[i].real();
1103 }
1104}
1105
1106void curlcurlE_exact_i(const Vector &x, Vector & curlcurlE_i)
1107{
1108 std::vector<std::complex<real_t>> curlcurlE;
1109 maxwell_solution_curlcurl(x, curlcurlE);
1110 curlcurlE_i.SetSize(curlcurlE.size());
1111 for (unsigned i = 0; i < curlcurlE.size(); i++)
1112 {
1113 curlcurlE_i[i]= curlcurlE[i].imag();
1114 }
1115}
1116
1117
1118void H_exact_r(const Vector &x, Vector & H_r)
1119{
1120 // H = i ∇ × E / ω μ
1121 // H_r = - ∇ × E_i / ω μ
1122 Vector curlE_i;
1123 curlE_exact_i(x,curlE_i);
1124 H_r.SetSize(dimc);
1125 for (int i = 0; i<dimc; i++)
1126 {
1127 H_r(i) = - curlE_i(i) / (omega * mu);
1128 }
1129}
1130
1131void H_exact_i(const Vector &x, Vector & H_i)
1132{
1133 // H = i ∇ × E / ω μ
1134 // H_i = ∇ × E_r / ω μ
1135 Vector curlE_r;
1136 curlE_exact_r(x,curlE_r);
1137 H_i.SetSize(dimc);
1138 for (int i = 0; i<dimc; i++)
1139 {
1140 H_i(i) = curlE_r(i) / (omega * mu);
1141 }
1142}
1143
1144void curlH_exact_r(const Vector &x,Vector &curlH_r)
1145{
1146 // ∇ × H_r = - ∇ × ∇ × E_i / ω μ
1147 Vector curlcurlE_i;
1148 curlcurlE_exact_i(x,curlcurlE_i);
1149 curlH_r.SetSize(dim);
1150 for (int i = 0; i<dim; i++)
1151 {
1152 curlH_r(i) = -curlcurlE_i(i) / (omega * mu);
1153 }
1154}
1155
1156void curlH_exact_i(const Vector &x,Vector &curlH_i)
1157{
1158 // ∇ × H_i = ∇ × ∇ × E_r / ω μ
1159 Vector curlcurlE_r;
1160 curlcurlE_exact_r(x,curlcurlE_r);
1161 curlH_i.SetSize(dim);
1162 for (int i = 0; i<dim; i++)
1163 {
1164 curlH_i(i) = curlcurlE_r(i) / (omega * mu);
1165 }
1166}
1167
1168void hatE_exact_r(const Vector & x, Vector & hatE_r)
1169{
1170 if (dim == 3)
1171 {
1172 E_exact_r(x,hatE_r);
1173 }
1174 else
1175 {
1176 Vector E_r;
1177 E_exact_r(x,E_r);
1178 hatE_r.SetSize(hatE_r.Size());
1179 // rotate E_hat
1180 hatE_r[0] = E_r[1];
1181 hatE_r[1] = -E_r[0];
1182 }
1183}
1184
1185void hatE_exact_i(const Vector & x, Vector & hatE_i)
1186{
1187 if (dim == 3)
1188 {
1189 E_exact_i(x,hatE_i);
1190 }
1191 else
1192 {
1193 Vector E_i;
1194 E_exact_i(x,E_i);
1195 hatE_i.SetSize(hatE_i.Size());
1196 // rotate E_hat
1197 hatE_i[0] = E_i[1];
1198 hatE_i[1] = -E_i[0];
1199 }
1200}
1201
1202void hatH_exact_r(const Vector & x, Vector & hatH_r)
1203{
1204 H_exact_r(x,hatH_r);
1205}
1206
1207void hatH_exact_i(const Vector & x, Vector & hatH_i)
1208{
1209 H_exact_i(x,hatH_i);
1210}
1211
1213{
1214 Vector hatH_r;
1215 H_exact_r(x,hatH_r);
1216 return hatH_r[0];
1217}
1218
1220{
1221 Vector hatH_i;
1222 H_exact_i(x,hatH_i);
1223 return hatH_i[0];
1224}
1225
1226// J = -i ω ϵ E + ∇ × H
1227// J_r + iJ_i = -i ω ϵ (E_r + i E_i) + ∇ × (H_r + i H_i)
1228void rhs_func_r(const Vector &x, Vector & J_r)
1229{
1230 // J_r = ω ϵ E_i + ∇ × H_r
1231 Vector E_i, curlH_r;
1232 E_exact_i(x,E_i);
1233 curlH_exact_r(x,curlH_r);
1234 J_r.SetSize(dim);
1235 for (int i = 0; i<dim; i++)
1236 {
1237 J_r(i) = omega * epsilon * E_i(i) + curlH_r(i);
1238 }
1239}
1240
1241void rhs_func_i(const Vector &x, Vector & J_i)
1242{
1243 // J_i = - ω ϵ E_r + ∇ × H_i
1244 Vector E_r, curlH_i;
1245 E_exact_r(x,E_r);
1246 curlH_exact_i(x,curlH_i);
1247 J_i.SetSize(dim);
1248 for (int i = 0; i<dim; i++)
1249 {
1250 J_i(i) = -omega * epsilon * E_r(i) + curlH_i(i);
1251 }
1252}
1253
1254void maxwell_solution(const Vector & X, std::vector<complex<real_t>> &E)
1255{
1256 complex<real_t> zi = complex<real_t>(0., 1.);
1257 E.resize(dim);
1258 for (int i = 0; i < dim; ++i)
1259 {
1260 E[i] = 0.0;
1261 }
1262 switch (prob)
1263 {
1264 case plane_wave:
1265 {
1266 E[0] = exp(zi * omega * (X.Sum()));
1267 }
1268 break;
1270 {
1271 E[1] = exp(zi * omega * (X(0)));
1272 }
1273 break;
1274 case fichera_oven:
1275 {
1276 if (abs(X(2) - 3.0) < 1e-10)
1277 {
1278 E[0] = sin(M_PI*X(1));
1279 }
1280 }
1281 break;
1282 case pml_pointsource:
1283 {
1284 Vector shift(dim);
1285 real_t k = omega * sqrt(epsilon * mu);
1286 shift = -0.5;
1287
1288 if (dim == 2)
1289 {
1290 real_t x0 = X(0) + shift(0);
1291 real_t x1 = X(1) + shift(1);
1292 real_t r = sqrt(x0 * x0 + x1 * x1);
1293 real_t beta = k * r;
1294
1295 // Bessel functions
1296 complex<real_t> Ho, Ho_r, Ho_rr;
1297 Ho = real_t(jn(0, beta)) + zi * real_t(yn(0, beta));
1298 Ho_r = -k * real_t(jn(1, beta)) + zi * real_t(yn(1, beta));
1299 Ho_rr = -k * k * (1_r / beta *
1300 (real_t(jn(1, beta)) + zi * real_t(yn(1, beta))) -
1301 (real_t(jn(2, beta)) + zi * real_t(yn(2, beta))));
1302
1303 // First derivatives
1304 real_t r_x = x0 / r;
1305 real_t r_y = x1 / r;
1306 real_t r_xy = -(r_x / r) * r_y;
1307 real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
1308
1309 complex<real_t> val, val_xx, val_xy;
1310 val = 0.25_r * zi * Ho;
1311 val_xx = 0.25_r * zi * (r_xx * Ho_r + r_x * r_x * Ho_rr);
1312 val_xy = 0.25_r * zi * (r_xy * Ho_r + r_x * r_y * Ho_rr);
1313 E[0] = zi / k * (k * k * val + val_xx);
1314 E[1] = zi / k * val_xy;
1315 }
1316 else
1317 {
1318 real_t x0 = X(0) + shift(0);
1319 real_t x1 = X(1) + shift(1);
1320 real_t x2 = X(2) + shift(2);
1321 real_t r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
1322
1323 real_t r_x = x0 / r;
1324 real_t r_y = x1 / r;
1325 real_t r_z = x2 / r;
1326 real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
1327 real_t r_yx = -(r_y / r) * r_x;
1328 real_t r_zx = -(r_z / r) * r_x;
1329
1330 complex<real_t> val, val_r, val_rr;
1331 val = exp(zi * k * r) / r;
1332 val_r = val / r * (zi * k * r - 1_r);
1333 val_rr = val / (r * r) * (-k * k * r * r
1334 - 2_r * zi * k * r + 2_r);
1335
1336 complex<real_t> val_xx, val_yx, val_zx;
1337 val_xx = val_rr * r_x * r_x + val_r * r_xx;
1338 val_yx = val_rr * r_x * r_y + val_r * r_yx;
1339 val_zx = val_rr * r_x * r_z + val_r * r_zx;
1340 complex<real_t> alpha = zi * k / 4_r / real_t(M_PI) / k / k;
1341 E[0] = alpha * (k * k * val + val_xx);
1342 E[1] = alpha * val_yx;
1343 E[2] = alpha * val_zx;
1344 }
1345 }
1346 break;
1347
1348 default:
1349 MFEM_ABORT("Should be unreachable");
1350 break;
1351 }
1352}
1353
1355 std::vector<complex<real_t>> &curlE)
1356{
1357 complex<real_t> zi = complex<real_t>(0., 1.);
1358 curlE.resize(dimc);
1359 for (int i = 0; i < dimc; ++i)
1360 {
1361 curlE[i] = 0.0;
1362 }
1363 switch (prob)
1364 {
1365 case plane_wave:
1366 {
1367 std::complex<real_t> pw = exp(zi * omega * (X.Sum()));
1368 if (dim == 3)
1369 {
1370 curlE[0] = 0.0;
1371 curlE[1] = zi * omega * pw;
1372 curlE[2] = -zi * omega * pw;
1373 }
1374 else
1375 {
1376 curlE[0] = -zi * omega * pw;
1377 }
1378 }
1379 break;
1381 {
1382 std::complex<real_t> pw = exp(zi * omega * (X(0)));
1383 curlE[0] = zi * omega * pw;
1384 }
1385 break;
1386 default:
1387 MFEM_ABORT("Should be unreachable");
1388 break;
1389 }
1390}
1391
1393 std::vector<complex<real_t>> &curlcurlE)
1394{
1395 complex<real_t> zi = complex<real_t>(0., 1.);
1396 curlcurlE.resize(dim);
1397 for (int i = 0; i < dim; ++i)
1398 {
1399 curlcurlE[i] = 0.0;
1400 }
1401 switch (prob)
1402 {
1403 case plane_wave:
1404 {
1405 std::complex<real_t> pw = exp(zi * omega * (X.Sum()));
1406 if (dim == 3)
1407 {
1408 curlcurlE[0] = 2_r * omega * omega * pw;
1409 curlcurlE[1] = - omega * omega * pw;
1410 curlcurlE[2] = - omega * omega * pw;
1411 }
1412 else
1413 {
1414 curlcurlE[0] = omega * omega * pw;
1415 curlcurlE[1] = -omega * omega * pw;
1416 }
1417 }
1418 break;
1420 {
1421 std::complex<real_t> pw = exp(zi * omega * (X(0)));
1422 curlcurlE[1] = omega * omega * pw;
1423 }
1424 break;
1425 default:
1426 MFEM_ABORT("Should be unreachable");
1427 break;
1428 }
1429}
1430
1432{
1433 Vector center(dim);
1434 center = 0.5;
1435 real_t r = 0.0;
1436 for (int i = 0; i < dim; ++i)
1437 {
1438 r += pow(x[i] - center[i], 2.);
1439 }
1440 real_t n = 5.0 * omega * sqrt(epsilon * mu) / M_PI;
1441 real_t coeff = pow(n, 2) / M_PI;
1442 real_t alpha = -pow(n, 2) * r;
1443 f = 0.0;
1444 f[0] = -omega * coeff * exp(alpha)/omega;
1445}
Dynamic 2D array using row-major layout.
Definition array.hpp:459
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
T & Last()
Return the last element in the array.
Definition array.hpp:974
A class to handle Block diagonal preconditioners in a matrix-free implementation.
void SetDiagonalBlock(int iblock, Operator *op)
Add a square block op in the block-entry (iblock, iblock).
A class to handle Block systems in a matrix-free implementation.
Conjugate gradient method.
Definition solvers.hpp:627
Class for setting up a simple Cartesian PML region.
Definition pml.hpp:19
void SetEpsilonAndMu(real_t epsilon_, real_t mu_)
Definition pml.hpp:65
void SetAttributes(Mesh *mesh_, Array< int > *attrNonPML=nullptr, Array< int > *attrPML=nullptr)
Mark element in the PML region.
Definition pml.cpp:73
void SetOmega(real_t omega_)
Definition pml.hpp:64
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
Mimic the action of a complex operator using two real operators.
virtual Operator & real()
Real or imaginary part accessor methods.
Creates a p-refinement multigrid preconditioner for a given set of parallel finite element spaces and...
A coefficient that is constant across space and time.
Integrator for for Nedelec elements.
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.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
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
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
A matrix coefficient that is constant in space and time.
Matrix coefficient defined as the product of two matrices.
Derived matrix coefficient that has the value of the parent matrix coefficient where it is active and...
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
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:11781
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:12125
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).
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:526
Arbitrary order H(curl)-trace finite elements defined on the interface between mesh elements (faces,...
Definition fe_coll.hpp:575
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.
Class representing the parallel weak formulation. (Convenient for DPG Equations)
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
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:365
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 MakeRef(FiniteElementSpace *f, real_t *v) override
Make the ParGridFunction reference external data on a new FiniteElementSpace.
void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, const Array< int > &bdr_attr) override
Project the tangential components of the given VectorCoefficient on the boundary.
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)
Scalar coefficient defined as the product of two scalar coefficients or a scalar and a scalar coeffic...
Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the interface between mesh elem...
Definition fe_coll.hpp:492
Derived coefficient that takes the value of the parent coefficient for the active attributes and is z...
Matrix coefficient defined as a product of a scalar coefficient and a matrix coefficient.
Base class for solvers.
Definition operator.hpp:855
for VectorFiniteElements (Nedelec, Raviart-Thomas)
Definition lininteg.hpp:365
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
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
real_t Sum() const
Return the sum of the vector entries.
Definition vector.cpp:1246
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
const int * ess_tdof_list
const real_t alpha
Definition ex15.cpp:369
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 detJ_r_function(const Vector &x, CartesianPML *pml)
PML stretching functions: See https://doi.org/10.1006/jcph.1994.1159.
Definition pml.cpp:163
Solver * MakeFESpaceDefaultSolver(const ParFiniteElementSpace *pfespace, int print_level)
Creates a default solver for a given parallel FE space. The default solvers are the following:
void detJ_Jt_J_inv_r_function(const Vector &x, CartesianPML *pml, DenseMatrix &M)
Definition pml.cpp:245
float real_t
Definition config.hpp:46
real_t abs_detJ_2_function(const Vector &x, CartesianPML *pml)
Definition pml.cpp:183
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
real_t detJ_i_function(const Vector &x, CartesianPML *pml)
Definition pml.cpp:173
void abs_detJ_Jt_J_inv_2_function(const Vector &x, CartesianPML *pml, DenseMatrix &M)
Definition pml.cpp:279
void detJ_Jt_J_inv_i_function(const Vector &x, CartesianPML *pml, DenseMatrix &M)
Definition pml.cpp:262
const char vishost[]
STL namespace.
void curlE_exact_i(const Vector &x, Vector &curlE_i)
void H_exact_i(const Vector &x, Vector &H_i)
real_t omega
Definition pmaxwell.cpp:191
void curlcurlE_exact_r(const Vector &x, Vector &curlcurlE_r)
int dimc
Definition pmaxwell.cpp:190
void source_function(const Vector &x, Vector &f)
void hatH_exact_r(const Vector &X, Vector &hatH_r)
void hatE_exact_r(const Vector &X, Vector &hatE_r)
void H_exact_r(const Vector &x, Vector &H_r)
real_t hatH_exact_scalar_i(const Vector &X)
void curlH_exact_r(const Vector &x, Vector &curlH_r)
real_t hatH_exact_scalar_r(const Vector &X)
int dim
Definition pmaxwell.cpp:189
real_t mu
Definition pmaxwell.cpp:192
void rhs_func_r(const Vector &x, Vector &J_r)
void hatH_exact_i(const Vector &X, Vector &hatH_i)
void rhs_func_i(const Vector &x, Vector &J_i)
real_t epsilon
Definition pmaxwell.cpp:193
void curlcurlE_exact_i(const Vector &x, Vector &curlcurlE_i)
void E_exact_r(const Vector &x, Vector &E_r)
void maxwell_solution_curlcurl(const Vector &X, std::vector< complex< real_t > > &curlcurlE)
void E_exact_i(const Vector &x, Vector &E_i)
void hatE_exact_i(const Vector &X, Vector &hatE_i)
prob_type prob
Definition pmaxwell.cpp:213
void maxwell_solution_curl(const Vector &X, std::vector< complex< real_t > > &curlE)
prob_type
Definition pmaxwell.cpp:196
@ fichera_oven
Definition pmaxwell.cpp:198
@ plane_wave
Definition pmaxwell.cpp:197
@ pml_plane_wave_scatter
Definition pmaxwell.cpp:200
@ pml_pointsource
Definition pmaxwell.cpp:201
@ pml_general
Definition pmaxwell.cpp:199
void maxwell_solution(const Vector &X, std::vector< complex< real_t > > &E)
void curlE_exact_r(const Vector &x, Vector &curlE_r)
void curlH_exact_i(const Vector &x, Vector &curlH_i)
MFEM_HOST_DEVICE Complex exp(const Complex &q)
MFEM_HOST_DEVICE real_t abs(const Complex &z)
Helper struct to convert a C++ type to an MPI type.