939 lines
30 KiB
C++
939 lines
30 KiB
C++
// MFEM Example 5
|
|
//
|
|
// Compile with: make ex5
|
|
//
|
|
// Sample runs: ex5 -m ../data/square-disc.mesh
|
|
// ex5 -m ../data/star.mesh
|
|
// ex5 -m ../data/star.mesh -pa
|
|
// ex5 -m ../data/beam-tet.mesh
|
|
// ex5 -m ../data/beam-hex.mesh
|
|
// ex5 -m ../data/beam-hex.mesh -pa
|
|
// ex5 -m ../data/escher.mesh
|
|
// ex5 -m ../data/fichera.mesh
|
|
//
|
|
// Device sample runs:
|
|
// ex5 -m ../data/star.mesh -pa -d cuda
|
|
// ex5 -m ../data/star.mesh -pa -d raja-cuda
|
|
// ex5 -m ../data/star.mesh -pa -d raja-omp
|
|
// ex5 -m ../data/beam-hex.mesh -pa -d cuda
|
|
//
|
|
// Description: This example code solves a simple 2D coupled Maxwell + compression
|
|
// wave interaction problem in the mixed formulation corresponding to
|
|
// the system
|
|
//
|
|
// du/dt + grad n = sigma0 * n * E
|
|
// div u + dn/dt = 0
|
|
// dE/dt - curl B = -sigma0 * n * E
|
|
// dB/dt + curl E = 0
|
|
//
|
|
// with natural boundary condition n = <given density> and/or
|
|
// essential (RT) / natural (DG) boundary condition u.n = <given
|
|
// velocity>. Similarly, essential boundary condition Exnxn =
|
|
// <given electric field> can be set or natural boundary condition
|
|
// for the magnetic field. Multiple problems are offered:
|
|
// 1) material wave - compression wave in medium (left u b.c.)
|
|
// 2) Maxwell - electromagnetic wave (left E b.c.)
|
|
// 3) excitation - electromagnetic wave exciting the medium (left
|
|
// E b.c.)
|
|
// 4) scaterring - interaction of electromagnetic and compression
|
|
// Gaussian beams (bottom u and left E b.c.)
|
|
// The waves are harmonic in time with the given frequency. We
|
|
// discretize the problem with normally continuous or broken
|
|
// Raviart-Thomas, or piecewise discontinuous finite elements the
|
|
// velocity u; piecewise discontinuous polynomials the density n;
|
|
// tangentially continuous Nedelec the electric field; and
|
|
// piecewise discountinuous polynomials the magnetic field B.
|
|
//
|
|
// The example demonstrates the use of the DarcyForm class, as
|
|
// well as hybridization of mixed systems and the collective saving
|
|
// of several grid functions in VisIt (visit.llnl.gov) and ParaView
|
|
// (paraview.org) formats.
|
|
//
|
|
// We recommend viewing examples 1-4 before viewing this example.
|
|
|
|
#include "mfem.hpp"
|
|
#include "coupledop.hpp"
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
using namespace std;
|
|
using namespace mfem;
|
|
|
|
// Define the analytical solution and forcing terms / boundary conditions
|
|
typedef std::function<real_t(const Vector &, real_t)> TFunc;
|
|
typedef std::function<void(const Vector &, Vector &)> VecFunc;
|
|
typedef std::function<void(const Vector &, real_t, Vector &)> VecTFunc;
|
|
typedef std::function<real_t(real_t f, const Vector &x)> KFunc;
|
|
|
|
enum Problem
|
|
{
|
|
MaterialWave = 1,
|
|
Maxwell,
|
|
Excitation,
|
|
Scattering,
|
|
};
|
|
|
|
constexpr real_t epsilon = numeric_limits<real_t>::epsilon();
|
|
|
|
TFunc GetSigFun(Problem prob, real_t f, real_t s0);
|
|
TFunc GetNFun(Problem prob, real_t t_0, real_t k, real_t c);
|
|
VecTFunc GetUFun(Problem prob, real_t f, real_t a0);
|
|
VecTFunc GetEFun(Problem prob, real_t f);
|
|
TFunc GetFFun(Problem prob, real_t t_0, real_t k, real_t c);
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
StopWatch chrono;
|
|
|
|
// 1. Parse command-line options.
|
|
const char *mesh_file = "";
|
|
int nx = 0;
|
|
int ny = 0;
|
|
real_t sx = 1.;
|
|
real_t sy = 1.;
|
|
int order = 1;
|
|
bool dg = false;
|
|
bool brt = false;
|
|
int iproblem = Problem::MaterialWave;
|
|
real_t tf = 1.;
|
|
int nt = 0;
|
|
int ode = 1;
|
|
real_t k = 1.;
|
|
real_t c = 1.;
|
|
real_t freq = 1.;
|
|
real_t s0 = 1.;
|
|
real_t a0 = 1e-3;
|
|
real_t td = 0.5;
|
|
bool bc_neumann = false;
|
|
//bool reduction = false;
|
|
bool hybridization = false;
|
|
/*bool nonlinear = false;
|
|
bool nonlinear_conv = false;
|
|
bool nonlinear_diff = false;
|
|
int hdg_scheme = 1;
|
|
int solver_type = (int)DarcyOperator::SolverType::Default;
|
|
bool pa = false;*/
|
|
const char *device_config = "cpu";
|
|
bool mfem = false;
|
|
bool visit = false;
|
|
bool paraview = false;
|
|
bool visualization = true;
|
|
bool analytic = false;
|
|
|
|
OptionsParser args(argc, argv);
|
|
args.AddOption(&mesh_file, "-m", "--mesh",
|
|
"Mesh file to use.");
|
|
args.AddOption(&nx, "-nx", "--ncells-x",
|
|
"Number of cells in x.");
|
|
args.AddOption(&ny, "-ny", "--ncells-y",
|
|
"Number of cells in y.");
|
|
args.AddOption(&sx, "-sx", "--size-x",
|
|
"Size along x axis.");
|
|
args.AddOption(&sy, "-sy", "--size-y",
|
|
"Size along y axis.");
|
|
args.AddOption(&order, "-o", "--order",
|
|
"Finite element order (polynomial degree).");
|
|
args.AddOption(&dg, "-dg", "--discontinuous", "-no-dg",
|
|
"--no-discontinuous", "Enable DG elements for fluxes.");
|
|
args.AddOption(&brt, "-brt", "--broken-RT", "-no-brt",
|
|
"--no-broken-RT", "Enable broken RT elements for fluxes.");
|
|
args.AddOption(&iproblem, "-p", "--problem",
|
|
"Problem to solve:\n\t\t"
|
|
"1=dumping\n\t\t"
|
|
"2=Maxwell\n\t\t");
|
|
args.AddOption(&tf, "-tf", "--time-final",
|
|
"Final time.");
|
|
args.AddOption(&nt, "-nt", "--ntimesteps",
|
|
"Number of time steps.");
|
|
args.AddOption(&ode, "-ode", "--ode-solver",
|
|
"ODE time solver (1=Bacward Euler, 2=RK23L, 3=RK23A, 4=RK34).");
|
|
args.AddOption(&k, "-k", "--kappa",
|
|
"Heat conductivity");
|
|
args.AddOption(&c, "-c", "--velocity",
|
|
"Convection velocity");
|
|
args.AddOption(&freq, "-f", "--frequency",
|
|
"Harmonic frequency");
|
|
args.AddOption(&s0, "-s0", "--sigma0",
|
|
"Coupling factor");
|
|
args.AddOption(&a0, "-a0", "--amplitude0",
|
|
"Amplitude factor");
|
|
args.AddOption(&td, "-td", "--stab_diff",
|
|
"Diffusion stabilization factor (1/2=default)");
|
|
args.AddOption(&bc_neumann, "-bcn", "--bc-neumann", "-no-bcn",
|
|
"--no-bc-neumann", "Enable Neumann outflow boundary condition.");
|
|
//args.AddOption(&reduction, "-rd", "--reduction", "-no-rd",
|
|
// "--no-reduction", "Enable reduction.");
|
|
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
|
|
"--no-hybridization", "Enable hybridization.");
|
|
/*args.AddOption(&nonlinear, "-nl", "--nonlinear", "-no-nl",
|
|
"--no-nonlinear", "Enable non-linear regime.");
|
|
args.AddOption(&nonlinear_conv, "-nlc", "--nonlinear-convection", "-no-nlc",
|
|
"--no-nonlinear-convection", "Enable non-linear convection regime.");
|
|
args.AddOption(&nonlinear_diff, "-nld", "--nonlinear-diffusion", "-no-nld",
|
|
"--no-nonlinear-diffusion", "Enable non-linear diffusion regime.");
|
|
args.AddOption(&hdg_scheme, "-hdg", "--hdg_scheme",
|
|
"HDG scheme (1=HDG-I, 2=HDG-II, 3=Rusanov, 4=Godunov).");
|
|
args.AddOption(&solver_type, "-nls", "--nonlinear-solver",
|
|
"Nonlinear solver type (1=LBFGS, 2=LBB, 3=Newton, 4=KINSol).");
|
|
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
|
"--no-partial-assembly", "Enable Partial Assembly.");*/
|
|
args.AddOption(&device_config, "-d", "--device",
|
|
"Device configuration string, see Device::Configure().");
|
|
args.AddOption(&mfem, "-mfem", "--mfem", "-no-mfem",
|
|
"--no-mfem",
|
|
"Enable or disable MFEM output.");
|
|
args.AddOption(&visit, "-visit", "--visit", "-no-visit",
|
|
"--no-visit",
|
|
"Enable or disable Visit output.");
|
|
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
|
"--no-paraview",
|
|
"Enable or disable ParaView output.");
|
|
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
|
"--no-visualization",
|
|
"Enable or disable GLVis visualization.");
|
|
args.AddOption(&analytic, "-anal", "--analytic", "-no-anal",
|
|
"--no-analytic",
|
|
"Enable or disable analytic solution.");
|
|
|
|
args.Parse();
|
|
if (!args.Good())
|
|
{
|
|
args.PrintUsage(cout);
|
|
return 1;
|
|
}
|
|
args.PrintOptions(cout);
|
|
|
|
// Set the problem options
|
|
Problem problem = (Problem)iproblem;
|
|
bool btime = false;
|
|
switch (problem)
|
|
{
|
|
case Problem::MaterialWave:
|
|
case Problem::Maxwell:
|
|
case Problem::Excitation:
|
|
case Problem::Scattering:
|
|
btime = true;
|
|
break;
|
|
default:
|
|
cerr << "Unknown problem" << endl;
|
|
return 1;
|
|
}
|
|
|
|
/*if (bnldiff && reduction)
|
|
{
|
|
cerr << "Reduction is not possible with non-linear diffusion" << endl;
|
|
return 1;
|
|
}
|
|
|
|
if (!bconv && !bnlconv && upwinded)
|
|
{
|
|
cerr << "Upwinded scheme cannot work without advection" << endl;
|
|
return 1;
|
|
}
|
|
|
|
if (bnlconv && !nonlinear)
|
|
{
|
|
cerr << "Nonlinear convection can only work in the nonlinear regime" << endl;
|
|
return 1;
|
|
}*/
|
|
|
|
if (btime && nt <= 0)
|
|
{
|
|
cerr << "You must specify the number of time steps for time evolving problems"
|
|
<< endl;
|
|
return 1;
|
|
}
|
|
|
|
// 2. Enable hardware devices such as GPUs, and programming models such as
|
|
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
|
Device device(device_config);
|
|
device.Print();
|
|
|
|
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
|
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
|
// the same code.
|
|
if (ny <= 0)
|
|
{
|
|
ny = nx;
|
|
}
|
|
|
|
Mesh *mesh = NULL;
|
|
if (strlen(mesh_file) > 0)
|
|
{
|
|
mesh = new Mesh(mesh_file, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
mesh = new Mesh(Mesh::MakeCartesian2D(nx, ny, Element::QUADRILATERAL, false,
|
|
sx, sy));
|
|
}
|
|
|
|
int dim = mesh->Dimension();
|
|
|
|
// Mark boundary conditions
|
|
Array<int> bdr_u_is_dirichlet(mesh->bdr_attributes.Max());
|
|
Array<int> bdr_u_is_neumann(bdr_u_is_dirichlet.Size());
|
|
Array<int> bdr_E_is_neumann(bdr_u_is_dirichlet.Size());
|
|
bdr_u_is_dirichlet = 0;
|
|
bdr_u_is_neumann = 0;
|
|
bdr_E_is_neumann = 0;
|
|
|
|
switch (problem)
|
|
{
|
|
case Problem::MaterialWave:
|
|
bdr_u_is_neumann[3] = -1;//inflow
|
|
if (bc_neumann)
|
|
{
|
|
bdr_u_is_neumann[0] = -1;//outflow
|
|
bdr_u_is_neumann[2] = -1;//outflow
|
|
}
|
|
break;
|
|
case Problem::Maxwell:
|
|
case Problem::Excitation:
|
|
bdr_u_is_dirichlet = -1;
|
|
bdr_u_is_neumann[3] = -1;
|
|
bdr_E_is_neumann[3] = -1;//inflow
|
|
if (bc_neumann)
|
|
{
|
|
bdr_E_is_neumann[0] = -1;//outflow
|
|
bdr_E_is_neumann[2] = -1;//outflow
|
|
}
|
|
break;
|
|
case Problem::Scattering:
|
|
bdr_u_is_dirichlet = -1;
|
|
bdr_u_is_neumann[0] = -1;//inflow
|
|
bdr_E_is_neumann[3] = -1;//inflow
|
|
if (bc_neumann)
|
|
{
|
|
bdr_u_is_neumann[1] = -1;//outflow
|
|
bdr_u_is_neumann[3] = -1;//outflow
|
|
bdr_E_is_neumann[0] = -1;//outflow
|
|
bdr_E_is_neumann[2] = -1;//outflow
|
|
}
|
|
break;
|
|
}
|
|
|
|
// 4. Refine the mesh to increase the resolution. In this example we do
|
|
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
|
// largest number that gives a final mesh with no more than 10,000
|
|
// elements.
|
|
if (strlen(mesh_file) > 0)
|
|
{
|
|
int ref_levels =
|
|
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
|
|
for (int l = 0; l < ref_levels; l++)
|
|
{
|
|
mesh->UniformRefinement();
|
|
}
|
|
}
|
|
|
|
// 5. Define a finite element space on the mesh. Here we use the
|
|
// Raviart-Thomas finite elements of the specified order.
|
|
FiniteElementCollection *V_coll, *V_coll_dg = NULL;
|
|
if (dg)
|
|
{
|
|
// In the case of LDG formulation, we chose a closed basis as it
|
|
// is customary for HDG to match trace DOFs, but an open basis can
|
|
// be used instead.
|
|
V_coll = new L2_FECollection(order, dim, BasisType::GaussLobatto);
|
|
}
|
|
else if (brt)
|
|
{
|
|
V_coll = new BrokenRT_FECollection(order, dim);
|
|
V_coll_dg = new L2_FECollection(order+1, dim);
|
|
}
|
|
else
|
|
{
|
|
V_coll = new RT_FECollection(order, dim);
|
|
}
|
|
FiniteElementCollection *W_coll = new L2_FECollection(order, dim,
|
|
BasisType::GaussLobatto);
|
|
FiniteElementCollection *E_coll = new ND_FECollection(order, dim);
|
|
FiniteElementCollection *B_coll = new L2_FECollection(order, dim, 0,
|
|
FiniteElement::INTEGRAL);
|
|
|
|
FiniteElementSpace *V_space = new FiniteElementSpace(mesh, V_coll,
|
|
(dg)?(dim):(1));
|
|
FiniteElementSpace *V_space_dg = (V_coll_dg)?(new FiniteElementSpace(
|
|
mesh, V_coll_dg, dim)):(NULL);
|
|
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, W_coll);
|
|
FiniteElementSpace *E_space = new FiniteElementSpace(mesh, E_coll);
|
|
FiniteElementSpace *B_space = new FiniteElementSpace(mesh, B_coll);
|
|
|
|
FiniteElementCollection *trace_coll = NULL;
|
|
FiniteElementSpace *trace_space = NULL;
|
|
|
|
if (hybridization)
|
|
{
|
|
trace_coll = new DG_Interface_FECollection(order, dim);
|
|
trace_space = new FiniteElementSpace(mesh, trace_coll);
|
|
}
|
|
|
|
// 6. Define the coefficients, analytical solution, and rhs of the PDE.
|
|
const real_t t_0 = 1.; //base density
|
|
|
|
ConstantCoefficient kcoeff(k); //conductivity
|
|
ConstantCoefficient ikcoeff(1./k); //inverse conductivity
|
|
|
|
auto sigFun = GetSigFun(problem, freq, s0);
|
|
FunctionCoefficient sigcoeff(sigFun); //coupling
|
|
|
|
auto nFun = GetNFun(problem, t_0, k, c);
|
|
FunctionCoefficient ncoeff(nFun); //density
|
|
SumCoefficient gcoeff(0., ncoeff, 1., -1.); //boundary velocity rhs
|
|
ProductCoefficient ghcoeff(0.5, gcoeff);
|
|
|
|
auto fFun = GetFFun(problem, t_0, k, c);
|
|
FunctionCoefficient fcoeff(fFun); //density rhs
|
|
|
|
auto uFun = GetUFun(problem, freq, a0);
|
|
VectorFunctionCoefficient ucoeff(dim, uFun); //velocity
|
|
ConstantCoefficient one;
|
|
|
|
auto Efun = GetEFun(problem, freq);
|
|
VectorFunctionCoefficient Ecoeff(dim, Efun); //electric field
|
|
|
|
// 7. Assemble the finite element matrices for the Darcy operator
|
|
//
|
|
// D = [ M B^T ]
|
|
// [ B 0 ]
|
|
// where:
|
|
//
|
|
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in V_h
|
|
// B = -\int_\Omega \div u_h u_h d\Omega u_h \in V_h, w_h \in W_h
|
|
|
|
// 8. Define the BlockStructure of the problem, i.e. define the array of
|
|
// offsets for each variable. The last component of the Array is the sum
|
|
// of the dimensions of each block.
|
|
const Array<int> block_offsets(CoupledOperator::ConstructOffsets(V_space,
|
|
W_space, E_space, B_space, trace_space));
|
|
|
|
std::cout << "***********************************************************\n";
|
|
std::cout << "dim(V) = " << block_offsets[1] - block_offsets[0] << "\n";
|
|
std::cout << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
|
|
if (hybridization)
|
|
{
|
|
std::cout << "dim(M) = " << block_offsets[3] - block_offsets[2] << "\n";
|
|
std::cout << "dim(E) = " << block_offsets[4] - block_offsets[3] << "\n";
|
|
std::cout << "dim(B) = " << block_offsets[5] - block_offsets[4] << "\n";
|
|
std::cout << "dim(V+W+M+E+B) = " << block_offsets.Last() << "\n";
|
|
}
|
|
else
|
|
{
|
|
std::cout << "dim(E) = " << block_offsets[3] - block_offsets[2] << "\n";
|
|
std::cout << "dim(B) = " << block_offsets[4] - block_offsets[3] << "\n";
|
|
std::cout << "dim(V+W+E+B) = " << block_offsets.Last() << "\n";
|
|
}
|
|
std::cout << "***********************************************************\n";
|
|
|
|
// 9. Allocate memory (x, rhs) for the analytical solution and the right hand
|
|
// side. Define the GridFunction q,t for the finite element solution and
|
|
// linear forms fform and gform for the right hand side. The data
|
|
// allocated by x and rhs are passed as a reference to the grid functions
|
|
// (q,t) and the linear forms (fform, gform).
|
|
MemoryType mt = device.GetMemoryType();
|
|
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
|
|
|
|
x = 0.;
|
|
GridFunction u_h, n_h, tr_h, E_h, B_h;
|
|
int i = 0;
|
|
u_h.MakeRef(V_space, x.GetBlock(i++), 0);
|
|
n_h.MakeRef(W_space, x.GetBlock(i++), 0);
|
|
if (trace_space)
|
|
{
|
|
tr_h.MakeRef(trace_space, x.GetBlock(i++), 0);
|
|
}
|
|
E_h.MakeRef(E_space, x.GetBlock(i++), 0);
|
|
B_h.MakeRef(B_space, x.GetBlock(i++), 0);
|
|
|
|
if (btime)
|
|
{
|
|
n_h.ProjectCoefficient(ncoeff); //initial condition
|
|
}
|
|
|
|
if (!dg && !brt)
|
|
{
|
|
u_h.ProjectBdrCoefficientNormal(ucoeff,
|
|
bdr_u_is_neumann); //essential Neumann BC
|
|
}
|
|
|
|
LinearForm *gform(new LinearForm);
|
|
gform->Update(V_space, rhs.GetBlock(0), 0);
|
|
if (dg)
|
|
{
|
|
gform->AddBdrFaceIntegrator(new VectorBoundaryFluxLFIntegrator(gcoeff),
|
|
bdr_u_is_dirichlet);
|
|
if (!hybridization)
|
|
{
|
|
gform->AddBdrFaceIntegrator(new VectorBoundaryFluxLFIntegrator(
|
|
gcoeff, 0.5), bdr_u_is_neumann);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (brt)
|
|
{
|
|
gform->AddBdrFaceIntegrator(new VectorFEBoundaryFluxLFIntegrator(gcoeff),
|
|
bdr_u_is_dirichlet);
|
|
if (!hybridization)
|
|
{
|
|
gform->AddBdrFaceIntegrator(new VectorFEBoundaryFluxLFIntegrator(
|
|
ghcoeff), bdr_u_is_neumann);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(gcoeff),
|
|
bdr_u_is_dirichlet);
|
|
}
|
|
}
|
|
|
|
LinearForm *fform(new LinearForm);
|
|
fform->Update(W_space, rhs.GetBlock(1), 0);
|
|
fform->AddDomainIntegrator(new DomainLFIntegrator(fcoeff));
|
|
|
|
//Neumann
|
|
if (!hybridization && (dg || brt))
|
|
{
|
|
fform->AddBdrFaceIntegrator(new BoundaryFlowIntegrator(one, ucoeff, +1., 0.),
|
|
bdr_u_is_neumann);
|
|
}
|
|
|
|
//prepare (reduced) solution and rhs vectors
|
|
|
|
LinearForm *hform = NULL;
|
|
|
|
//Neumann BC for the hybridized system
|
|
|
|
if (hybridization)
|
|
{
|
|
hform = new LinearForm();
|
|
hform->Update(trace_space, rhs.GetBlock(2), 0);
|
|
//note that Neumann BC must be applied only for the velocity
|
|
//and not the total flux for stability reasons
|
|
hform->AddBoundaryIntegrator(new BoundaryNormalLFIntegrator(ucoeff, 2),
|
|
bdr_u_is_neumann);
|
|
}
|
|
|
|
//construct the operator
|
|
|
|
Array<LinearForm*> lfs({gform, fform, hform, (LinearForm*)NULL, (LinearForm*)NULL});
|
|
|
|
Array<Coefficient*> coeffs({(Coefficient*)&gcoeff,
|
|
(Coefficient*)&fcoeff,
|
|
(Coefficient*)&ucoeff});
|
|
|
|
CoupledOperator op(bdr_u_is_neumann, bdr_E_is_neumann, &sigcoeff, lfs, coeffs,
|
|
V_space, W_space, E_space, B_space, trace_space, td);
|
|
|
|
//construct the time solver
|
|
|
|
ODESolver *ode_solver;
|
|
|
|
switch (ode)
|
|
{
|
|
case 1: ode_solver = new BackwardEulerSolver(); break;
|
|
case 2: ode_solver = new SDIRK23Solver(2); break;
|
|
case 3: ode_solver = new SDIRK23Solver(); break;
|
|
case 4: ode_solver = new SDIRK34Solver(); break;
|
|
default:
|
|
MFEM_ABORT("Unknown solver");
|
|
return 1;
|
|
}
|
|
|
|
ode_solver->Init(op);
|
|
|
|
//iterate in time
|
|
|
|
if (!btime) { nt = 1; }
|
|
|
|
const real_t dt = tf / nt; //time step
|
|
|
|
for (int ti = 0; ti < nt; ti++)
|
|
{
|
|
//set current time
|
|
|
|
real_t t = tf * ti / nt;
|
|
|
|
if (!dg && !brt)
|
|
{
|
|
ucoeff.SetTime(t);
|
|
u_h.ProjectBdrCoefficientNormal(ucoeff,
|
|
bdr_u_is_neumann); //essential Neumann BC
|
|
}
|
|
|
|
Ecoeff.SetTime(t);
|
|
E_h.ProjectBdrCoefficientTangent(Ecoeff, bdr_E_is_neumann);
|
|
|
|
//perform time step
|
|
|
|
real_t dt_ = dt;//<---ignore time step changes
|
|
ode_solver->Step(x, t, dt_);
|
|
|
|
// 12. Compute the L2 error norms.
|
|
|
|
int order_quad = max(2, 2*order+1);
|
|
const IntegrationRule *irs[Geometry::NumGeom];
|
|
for (int i=0; i < Geometry::NumGeom; ++i)
|
|
{
|
|
irs[i] = &(IntRules.Get(i, order_quad));
|
|
}
|
|
|
|
real_t err_u = u_h.ComputeL2Error(ucoeff, irs);
|
|
real_t norm_u = ComputeLpNorm(2., ucoeff, *mesh, irs);
|
|
real_t err_n = n_h.ComputeL2Error(ncoeff, irs);
|
|
real_t norm_n = ComputeLpNorm(2., ncoeff, *mesh, irs);
|
|
|
|
if (btime)
|
|
{
|
|
cout << "iter:\t" << ti
|
|
<< "\ttime:\t" << t
|
|
<< "\tq_err:\t" << err_u / norm_u
|
|
<< "\tt_err:\t" << err_n / norm_n
|
|
<< endl;
|
|
}
|
|
else
|
|
{
|
|
cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n";
|
|
cout << "|| n_h - n_ex || / || n_ex || = " << err_n / norm_n << "\n";
|
|
}
|
|
|
|
// Project the broken space
|
|
|
|
GridFunction u_v;
|
|
if (V_space_dg)
|
|
{
|
|
VectorGridFunctionCoefficient coeff(&u_h);
|
|
u_v.SetSpace(V_space_dg);
|
|
u_v.ProjectCoefficient(coeff);
|
|
}
|
|
else
|
|
{
|
|
u_v.MakeRef(V_space, u_h, 0);
|
|
}
|
|
|
|
// Project the analytic solution
|
|
|
|
static GridFunction u_a, n_a, c_gf;
|
|
|
|
u_a.SetSpace(V_space);
|
|
u_a.ProjectCoefficient(ucoeff);
|
|
|
|
n_a.SetSpace(W_space);
|
|
n_a.ProjectCoefficient(ncoeff);
|
|
|
|
// 13. Save the mesh and the solution. This output can be viewed later using
|
|
// GLVis: "glvis -m ex5.mesh -g sol_q.gf" or "glvis -m ex5.mesh -g
|
|
// sol_t.gf".
|
|
if (mfem)
|
|
{
|
|
stringstream ss;
|
|
ss.str("");
|
|
ss << "mesh";
|
|
if (btime) { ss << "_" << ti; }
|
|
ss << ".mesh";
|
|
ofstream mesh_ofs(ss.str());
|
|
mesh_ofs.precision(8);
|
|
mesh->Print(mesh_ofs);
|
|
|
|
ss.str("");
|
|
ss << "sol_u";
|
|
if (btime) { ss << "_" << ti; }
|
|
ss << ".gf";
|
|
ofstream u_ofs(ss.str());
|
|
u_ofs.precision(8);
|
|
u_v.Save(u_ofs);
|
|
|
|
ss.str("");
|
|
ss << "sol_n";
|
|
if (btime) { ss << "_" << ti; }
|
|
ss << ".gf";
|
|
ofstream n_ofs(ss.str());
|
|
n_ofs.precision(8);
|
|
n_h.Save(n_ofs);
|
|
|
|
ss.str("");
|
|
ss << "sol_E";
|
|
if (btime) { ss << "_" << ti; }
|
|
ss << ".gf";
|
|
ofstream E_ofs(ss.str());
|
|
E_ofs.precision(8);
|
|
E_h.Save(E_ofs);
|
|
|
|
ss.str("");
|
|
ss << "sol_B";
|
|
if (btime) { ss << "_" << ti; }
|
|
ss << ".gf";
|
|
ofstream B_ofs(ss.str());
|
|
B_ofs.precision(8);
|
|
B_h.Save(B_ofs);
|
|
}
|
|
|
|
// 14. Save data in the VisIt format
|
|
if (visit)
|
|
{
|
|
static VisItDataCollection visit_dc("Example5", mesh);
|
|
if (ti == 0)
|
|
{
|
|
visit_dc.RegisterField("velocity", &u_h);
|
|
visit_dc.RegisterField("density", &n_h);
|
|
if (analytic)
|
|
{
|
|
visit_dc.RegisterField("velocity analytic", &u_a);
|
|
visit_dc.RegisterField("density analytic", &n_a);
|
|
}
|
|
}
|
|
visit_dc.SetCycle(ti);
|
|
visit_dc.SetTime(t); // set the time
|
|
visit_dc.Save();
|
|
}
|
|
|
|
// 15. Save data in the ParaView format
|
|
if (paraview)
|
|
{
|
|
static ParaViewDataCollection paraview_dc("Example5", mesh);
|
|
if (ti == 0)
|
|
{
|
|
paraview_dc.SetPrefixPath("ParaView");
|
|
paraview_dc.SetLevelsOfDetail(order);
|
|
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
|
paraview_dc.SetHighOrderOutput(true);
|
|
paraview_dc.RegisterField("velocity",&u_h);
|
|
paraview_dc.RegisterField("density",&n_h);
|
|
if (analytic)
|
|
{
|
|
paraview_dc.RegisterField("velocity analytic", &u_a);
|
|
paraview_dc.RegisterField("density analytic", &n_a);
|
|
}
|
|
}
|
|
paraview_dc.SetCycle(ti);
|
|
paraview_dc.SetTime(t); // set the time
|
|
paraview_dc.Save();
|
|
}
|
|
|
|
// 16. Send the solution by socket to a GLVis server.
|
|
if (visualization)
|
|
{
|
|
const char vishost[] = "localhost";
|
|
const int visport = 19916;
|
|
static socketstream u_sock(vishost, visport);
|
|
u_sock.precision(8);
|
|
u_sock << "solution\n" << *mesh << u_v << endl;
|
|
if (ti == 0)
|
|
{
|
|
u_sock << "window_title 'Velocity'" << endl;
|
|
u_sock << "keys Rljvvvvvmmc" << endl;
|
|
}
|
|
static socketstream n_sock(vishost, visport);
|
|
n_sock.precision(8);
|
|
n_sock << "solution\n" << *mesh << n_h << endl;
|
|
if (ti == 0)
|
|
{
|
|
n_sock << "window_title 'Density'" << endl;
|
|
n_sock << "keys Rljmmc" << endl;
|
|
}
|
|
static socketstream E_sock(vishost, visport);
|
|
E_sock.precision(8);
|
|
E_sock << "solution\n" << *mesh << E_h << endl;
|
|
if (ti == 0)
|
|
{
|
|
E_sock << "window_title 'Electric field'" << endl;
|
|
E_sock << "keys Rljvvvvvmmc" << endl;
|
|
}
|
|
static socketstream B_sock(vishost, visport);
|
|
B_sock.precision(8);
|
|
B_sock << "solution\n" << *mesh << B_h << endl;
|
|
if (ti == 0)
|
|
{
|
|
B_sock << "window_title 'Magnetic field'" << endl;
|
|
B_sock << "keys Rljmmc" << endl;
|
|
}
|
|
if (analytic)
|
|
{
|
|
static socketstream qa_sock(vishost, visport);
|
|
qa_sock.precision(8);
|
|
qa_sock << "solution\n" << *mesh << u_a << endl;
|
|
if (ti == 0)
|
|
{
|
|
qa_sock << "window_title 'Velocity analytic'" << endl;
|
|
qa_sock << "keys Rljvvvvvmmc" << endl;
|
|
}
|
|
static socketstream ta_sock(vishost, visport);
|
|
ta_sock.precision(8);
|
|
ta_sock << "solution\n" << *mesh << n_a << endl;
|
|
if (ti == 0)
|
|
{
|
|
ta_sock << "window_title 'Density analytic'" << endl;
|
|
ta_sock << "keys Rljmmc" << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 17. Free the used memory.
|
|
|
|
delete ode_solver;
|
|
delete fform;
|
|
delete gform;
|
|
delete hform;
|
|
delete W_space;
|
|
delete V_space;
|
|
delete V_space_dg;
|
|
delete E_space;
|
|
delete B_space;
|
|
delete trace_space;
|
|
delete W_coll;
|
|
delete V_coll;
|
|
delete V_coll_dg;
|
|
delete E_coll;
|
|
delete B_coll;
|
|
delete trace_coll;
|
|
delete mesh;
|
|
|
|
return 0;
|
|
}
|
|
|
|
TFunc GetSigFun(Problem prob, real_t f, real_t s0)
|
|
{
|
|
switch (prob)
|
|
{
|
|
case Problem::MaterialWave:
|
|
case Problem::Maxwell:
|
|
return [=](const Vector &x, real_t) -> real_t
|
|
{
|
|
return 0.;
|
|
};
|
|
case Problem::Excitation:
|
|
case Problem::Scattering:
|
|
return [=](const Vector &x, real_t) -> real_t
|
|
{
|
|
constexpr real_t x0 = 0.5;
|
|
constexpr real_t y0 = 0.5;
|
|
constexpr real_t w = 0.5;
|
|
const real_t r = hypot(x(0) - x0, x(1) - y0) / w;
|
|
return exp(-r*r) * s0;
|
|
};
|
|
}
|
|
return TFunc();
|
|
}
|
|
|
|
TFunc GetNFun(Problem prob, real_t t_0, real_t k, real_t c)
|
|
{
|
|
switch (prob)
|
|
{
|
|
case Problem::MaterialWave:
|
|
case Problem::Maxwell:
|
|
case Problem::Scattering:
|
|
return [=](const Vector &x, real_t) -> real_t
|
|
{
|
|
return 0.;
|
|
};
|
|
case Problem::Excitation:
|
|
return [=](const Vector &x, real_t) -> real_t
|
|
{
|
|
return 1.;
|
|
};
|
|
}
|
|
return TFunc();
|
|
}
|
|
|
|
VecTFunc GetUFun(Problem prob, real_t f, real_t a0)
|
|
{
|
|
switch (prob)
|
|
{
|
|
case Problem::MaterialWave:
|
|
return [=](const Vector &x, real_t t, Vector &v)
|
|
{
|
|
const int vdim = x.Size();
|
|
v.SetSize(vdim);
|
|
|
|
v = 0.;
|
|
constexpr real_t w = 0.25;
|
|
constexpr real_t y0 = 0.5;
|
|
const real_t dy = (x(1) - y0) / w;
|
|
v(0) = exp(-dy*dy) * sin(M_PI * f * t) * cos(M_PI * x(0));
|
|
};
|
|
case Problem::Maxwell:
|
|
case Problem::Excitation:
|
|
return [=](const Vector &x, real_t t, Vector &v)
|
|
{
|
|
const int vdim = x.Size();
|
|
v.SetSize(vdim);
|
|
v = 0.;
|
|
};
|
|
case Problem::Scattering:
|
|
return [=](const Vector &x, real_t t, Vector &v)
|
|
{
|
|
const int vdim = x.Size();
|
|
v.SetSize(vdim);
|
|
|
|
v = 0.;
|
|
constexpr real_t w = 0.15;
|
|
constexpr real_t r0 = 0.5;
|
|
const real_t r = x(0) - r0;
|
|
const real_t rw = r / w;
|
|
constexpr real_t zR = 0.5;
|
|
constexpr real_t z0 = 0.5;
|
|
const real_t dz = x(1) - z0;
|
|
const real_t R = dz / (dz*dz + zR*zR);
|
|
v(1) = exp(-rw*rw) * sin(M_PI * (f * t - r*r / R)) * cos(M_PI * x(1)) * a0;
|
|
};
|
|
}
|
|
return VecTFunc();
|
|
}
|
|
|
|
VecTFunc GetEFun(Problem prob, real_t f)
|
|
{
|
|
switch (prob)
|
|
{
|
|
case Problem::MaterialWave:
|
|
case Problem::Maxwell:
|
|
case Problem::Excitation:
|
|
return [=](const Vector &x, real_t t, Vector &v)
|
|
{
|
|
const int vdim = x.Size();
|
|
v.SetSize(vdim);
|
|
|
|
v = 0.;
|
|
constexpr real_t w = 0.25;
|
|
constexpr real_t y0 = 0.5;
|
|
const real_t dy = (x(1) - y0) / w;
|
|
v(1) = exp(-dy*dy) * sin(M_PI * f * t) * cos(M_PI * x(0));
|
|
};
|
|
case Problem::Scattering:
|
|
return [=](const Vector &x, real_t t, Vector &v)
|
|
{
|
|
const int vdim = x.Size();
|
|
v.SetSize(vdim);
|
|
|
|
v = 0.;
|
|
constexpr real_t w = 0.15;
|
|
const real_t r = x(1) - 0.5;
|
|
const real_t rw = r / w;
|
|
constexpr real_t zR = 0.5;
|
|
constexpr real_t z0 = 0.5;
|
|
const real_t dz = x(0) - z0;
|
|
const real_t R = dz / (dz*dz + zR*zR);
|
|
v(1) = exp(-rw*rw) * sin(M_PI * (f * t - r*r / R)) * cos(M_PI * x(0));
|
|
};
|
|
}
|
|
return VecTFunc();
|
|
}
|
|
|
|
TFunc GetFFun(Problem prob, real_t t_0, real_t k, real_t c)
|
|
{
|
|
switch (prob)
|
|
{
|
|
case Problem::MaterialWave:
|
|
case Problem::Maxwell:
|
|
case Problem::Excitation:
|
|
case Problem::Scattering:
|
|
return [=](const Vector &x, real_t) -> real_t
|
|
{
|
|
return 0.;
|
|
};
|
|
}
|
|
return TFunc();
|
|
}
|