You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi everyone, since there's no example for problems with time-dependent (especially nonzero) Dirichlet boundary conditions, I try to write one based on ex23. A special nature of ex23 is that wave equation has 2nd-order time derivatives. The code is as follow and I cannot guarantee it's correctness yet. Hope this can offer some help to people with similar needs.
ex23 applys a zero dirichlet boundary condtion, which doesn't need eliminating the rhs at all. Here I try a testcase here. In the $[0,1]^2$ region, the boundary conditions are $u(x,t)=sin(4\pi t), \frac{du}{dt}(x,t)=4\pi cos(4\pi t), \frac{d^2u}{dt^2}(x,t)=-16\pi^2 sin(4\pi t)$, when $x=0, 1/6 < y < 5/6$, and 0 otherwise. In this case I need to set dirichlet BC for both $u, \frac{du}{dt}, \frac{d^2u}{dt^2}$.
For Newmark method, the wave equation is discretized as $[M+\beta(\Delta t)^2K]\frac{d^2u(t+\Delta t)}{dt^2} = -K[u(t)+\Delta t\frac{du(t)}{dt}+(\frac{1}{2}-\beta)(\Delta t)^2\frac{d^2u(t)}{dt^2}]$. Following @v-dobrev's suggestion #1720 , I derive the solution d2udt2 at t+dt after elimination as
The u or dudt in photo represents u(t), du(t)/dt. I and B represents DoFs on interior region and boundary, respectively.
I have some quesitons about improving it
Is the ImplicitSolve() correct about eliminating the Dirichlet BC contributions?
I cannot access dt and beta inside ImplicitSolve, but I need dt and 0.5-beta to eliminate rhs. The current code calculates dt first, and then compute beta based on the input variable fac0=beta*dt*dt. Clearly it's only limit to the Newmark ODESolver. How to improve it for more general solvers?
Is there a better method to set boudnary value for solution vector, when the boundary value dependent on coordinate? Current method seems not robust, only limit to serial codes:
#include"mfem.hpp"
#include<fstream>
#include<iostream>usingnamespacestd;usingnamespacemfem;doubleInitialSolution(const Vector &x)
{
return0.0;
}
doubleInitialRate(const Vector &x)
{
return0.0;
}
doubleBoundaryValue_u(const Vector &x, double time)
{
if (time <= 0.5 && x(0) <= 1e-7 && x(1) < 5.0/6.0 && x(1) > 1.0/6.0)
returnsin(4*M_PI*time);
elsereturn0.;
}
doubleBoundaryValue_dudt(const Vector &x, double time)
{
if (time <= 0.5 && x(0) <= 1e-7 && x(1) < 5.0/6.0 && x(1) > 1.0/6.0)
return4 * M_PI * cos(4*M_PI*time);
elsereturn0.;
}
doubleBoundaryValue_d2udt2(const Vector &x, double time)
{
if (time <= 0.5 && x(0) <= 1e-7 && x(1) < 5.0/6.0 && x(1) > 1.0/6.0)
return -16 * M_PI * M_PI * sin(4*M_PI*time);
elsereturn0.;
}
/** After spatial discretization, the conduction model can be written as: * * d^2u/dt^2 = M^{-1}(-Ku) * * where u is the vector representing the temperature, M is the mass matrix, * and K is the diffusion operator with diffusivity depending on u: * (\kappa + \alpha u). * * Class WaveOperator represents the right-hand side of the above ODE.*/classWaveOperator : publicSecondOrderTimeDependentOperator
{
protected:
FiniteElementSpace &fespace;
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
Array<int> ess_bdr;
BilinearForm *M;
BilinearForm *K;
SparseMatrix Mmat, Kmat, Kmat0;
SparseMatrix *T; // T = M + dt Kdouble previous_time;
double current_time;
double current_dt;
UMFPackSolver M_solver;
CGSolver T_solver; // Implicit solver for T = M + fac0*K
DSmoother T_prec; // Preconditioner for the implicit solver
Coefficient *c2;
FunctionCoefficient *u_bdr;
FunctionCoefficient *dudt_bdr;
FunctionCoefficient *d2udt2_bdr;
mutable Vector z; // auxiliary vectorpublic:WaveOperator(FiniteElementSpace &f, Array<int> &ess_bdr,
double speed, double init_time);
using SecondOrderTimeDependentOperator::Mult;
virtualvoidMult(const Vector &u, const Vector &du_dt,
Vector &d2udt2) const;
/** Solve the Backward-Euler equation: d2udt2 = f(u + fac0*d2udt2,dudt + fac1*d2udt2, t), for the unknown d2udt2. */using SecondOrderTimeDependentOperator::ImplicitSolve;
virtualvoidImplicitSolve(constdouble fac0, constdouble fac1,
const Vector &u, const Vector &dudt, Vector &d2udt2);
///voidSetParameters(const Vector &u);
virtual~WaveOperator();
};
WaveOperator::WaveOperator(FiniteElementSpace &f,
Array<int> &ess_bdr, double speed, double init_time)
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL),
K(NULL),
T(NULL), current_dt(1.0e-2), z(height), previous_time(init_time), current_time(0.)
{
constdouble rel_tol = 1e-8;
this->ess_bdr = ess_bdr;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
c2 = newConstantCoefficient(speed*speed);
K = newBilinearForm(&fespace);
K->AddDomainIntegrator(newDiffusionIntegrator(*c2));
K->Assemble();
Array<int> dummy;
K->FormSystemMatrix(dummy, Kmat0);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M = newBilinearForm(&fespace);
M->AddDomainIntegrator(newMassIntegrator());
M->Assemble();
M->FormSystemMatrix(ess_tdof_list, Mmat);
M_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
M_solver.SetOperator(Mmat);
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
T = NULL;
u_bdr = newFunctionCoefficient(BoundaryValue_u);
dudt_bdr = newFunctionCoefficient(BoundaryValue_dudt);
d2udt2_bdr = newFunctionCoefficient(BoundaryValue_d2udt2);
cout << "WaveOperator initialized" << endl;
}
voidWaveOperator::Mult(const Vector &u, const Vector &du_dt,
Vector &d2udt2) const
{
// Compute:// d2udt2 = M^{-1}*-K(u)// for d2udt2// Kmat.Mult(u, z);// z.Neg(); // z = -z// M_solver.Mult(z, d2udt2);
GridFunction d2udt2_gf(&fespace);
d2udt2_gf = 0.;
d2udt2_bdr->SetTime(previous_time);
Array<int> ess_bdr_ = this->ess_bdr;
d2udt2_gf.ProjectBdrCoefficient(*d2udt2_bdr, ess_bdr_);
for (int i = 0; i < ess_tdof_list.Size(); i++)
{
d2udt2[ess_tdof_list[i]] = d2udt2_gf[ess_tdof_list[i]]; // is this correct ?
}
}
voidWaveOperator::ImplicitSolve(constdouble fac0, constdouble fac1,
const Vector &u, const Vector &dudt, Vector &d2udt2)
{
if (!T)
{
T = Add(1.0, Mmat, fac0, Kmat);
T_solver.SetOperator(*T);
}
// Get current_dt
current_time = this->GetTime();
current_dt = current_time - previous_time;
// Kmat0.Mult(z, )
Kmat.Mult(u, z);
z.Neg();
// Eliminate -K_{IB}(u_B + dt dudt_B + (0.5-beta)(dt)^2 d2udt2_B) at t
GridFunction u_gf(&fespace);
u_bdr->SetTime(previous_time);
u_gf = 0.;
u_gf.ProjectBdrCoefficient(*u_bdr, this->ess_bdr);
GridFunction dudt_gf(&fespace);
dudt_bdr->SetTime(previous_time);
dudt_gf = 0.;
dudt_gf.ProjectBdrCoefficient(*dudt_bdr, this->ess_bdr);
GridFunction d2udt2_gf(&fespace);
d2udt2_bdr->SetTime(previous_time);
d2udt2_gf = 0.;
d2udt2_gf.ProjectBdrCoefficient(*d2udt2_bdr, this->ess_bdr);
// u_B
K->EliminateVDofsInRHS(ess_tdof_list, u_gf, z);
// dt*dudt_B
K->SpMatElim().AddMult(dudt_gf, z, -current_dt);
K->SpMat().PartMult(ess_tdof_list, dudt_gf, z);
// (0.5 - beta) * (dt)^2double beta = fac0 / (current_dt * current_dt);
double fac_d2udt2 = (0.5 - beta) *(current_dt * current_dt);
K->SpMatElim().AddMult(d2udt2_gf, z, -fac_d2udt2);
K->SpMat().PartMult(ess_tdof_list, d2udt2_gf, z);
// Eliminate -T_{IB}*d2udt2_B at t+dt// T = M + beta*(dt)^2*K
d2udt2_bdr->SetTime(current_time);
d2udt2_gf = 0.;
d2udt2_gf.ProjectBdrCoefficient(*d2udt2_bdr, this->ess_bdr);
M->EliminateVDofsInRHS(ess_tdof_list, d2udt2_gf, z);
K->SpMatElim().AddMult(d2udt2_gf, z, -fac0);
K->SpMat().PartMult(ess_tdof_list, d2udt2_gf, z);
T_solver.Mult(z, d2udt2);
// set Dirichlet BC for u, dudt, d2udt2 here// d2udt2:for (int i = 0; i < ess_tdof_list.Size(); i++)
{
d2udt2[ess_tdof_list[i]] = d2udt2_gf[ess_tdof_list[i]]; // is this correct ?
}
previous_time = current_time;
}
voidWaveOperator::SetParameters(const Vector &u)
{
if (0) // disable since dt is constant, so T never change
{
delete T;
T = NULL; // re-compute T on the next ImplicitSolve
}
}
WaveOperator::~WaveOperator()
{
delete T;
delete M;
delete K;
delete c2;
}
intmain(int argc, char *argv[])
{
// 1. Parse command-line options.constchar *mesh_file = "../data/star.mesh";
constchar *ref_dir = "";
int ref_levels = 2;
int order = 2;
int ode_solver_type = 10;
double t_final = 0.5;
double dt = 1.0e-2;
double speed = 1.0;
bool visualization = true;
bool visit = true;
bool dirichlet = true;
int vis_steps = 1;
int precision = 8;
cout.precision(precision);
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: [0--10] - GeneralizedAlpha(0.1 * s),\n\t""\t 11 - Average Acceleration, 12 - Linear Acceleration\n""\t 13 - CentralDifference, 14 - FoxGoodwin");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step.");
args.AddOption(&speed, "-c", "--speed",
"Wave speed.");
args.AddOption(&dirichlet, "-dir", "--dirichlet", "-neu",
"--neumann",
"BC switch.");
args.AddOption(&ref_dir, "-r", "--ref",
"Reference directory for checking final solution.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
"--no-visit-datafiles",
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,// quadrilateral, tetrahedral and hexahedral meshes with the same code.
Mesh *mesh = newMesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Define the ODE solver used for time integration. Several second order// time integrators are available.
SecondOrderODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit methodscase0: ode_solver = newGeneralizedAlpha2Solver(0.0); break;
case1: ode_solver = newGeneralizedAlpha2Solver(0.1); break;
case2: ode_solver = newGeneralizedAlpha2Solver(0.2); break;
case3: ode_solver = newGeneralizedAlpha2Solver(0.3); break;
case4: ode_solver = newGeneralizedAlpha2Solver(0.4); break;
case5: ode_solver = newGeneralizedAlpha2Solver(0.5); break;
case6: ode_solver = newGeneralizedAlpha2Solver(0.6); break;
case7: ode_solver = newGeneralizedAlpha2Solver(0.7); break;
case8: ode_solver = newGeneralizedAlpha2Solver(0.8); break;
case9: ode_solver = newGeneralizedAlpha2Solver(0.9); break;
case10: ode_solver = newGeneralizedAlpha2Solver(1.0); break;
case11: ode_solver = newAverageAccelerationSolver(); break;
case12: ode_solver = newLinearAccelerationSolver(); break;
case13: ode_solver = newCentralDifferenceSolver(); break;
case14: ode_solver = newFoxGoodwinSolver(); break;
case15: ode_solver = newNewmarkSolver(); break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return3;
}
// 4. Refine the mesh to increase the resolution. In this example we do// 'ref_levels' of uniform refinement, where 'ref_levels' is a// command-line parameter.for (int lev = 0; lev < ref_levels; lev++)
{
mesh->UniformRefinement();
}
cout << "Number of elements = " << mesh->GetNE() << endl;
// 5. Define the vector finite element space representing the current and the// initial temperature, u_ref.
H1_FECollection fe_coll(order, dim);
FiniteElementSpace fespace(mesh, &fe_coll);
int fe_size = fespace.GetTrueVSize();
cout << "Number of temperature unknowns: " << fe_size << endl;
GridFunction u_gf(&fespace);
GridFunction dudt_gf(&fespace);
// 6. Set the initial conditions for u. All boundaries are considered// natural.
FunctionCoefficient u_0(InitialSolution);
u_gf.ProjectCoefficient(u_0);
Vector u;
u_gf.GetTrueDofs(u);
FunctionCoefficient dudt_0(InitialRate);
dudt_gf.ProjectCoefficient(dudt_0);
Vector dudt;
dudt_gf.GetTrueDofs(dudt);
// 7. Initialize the conduction operator and the visualization.
Array<int> ess_bdr;
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
if (dirichlet)
{
ess_bdr = 1;
cout << "Size of ess_bdr = " << ess_bdr.Size() << endl;
}
else
{
ess_bdr = 0;
}
}
u_gf.SetFromTrueDofs(u);
{
ofstream omesh("ex23.mesh");
omesh.precision(precision);
mesh->Print(omesh);
ofstream osol("ex23-init.gf");
osol.precision(precision);
u_gf.Save(osol);
dudt_gf.Save(osol);
}
VisItDataCollection visit_dc("Example23", mesh);
visit_dc.RegisterField("solution", &u_gf);
visit_dc.RegisterField("rate", &dudt_gf);
if (visit)
{
visit_dc.SetCycle(0);
visit_dc.SetTime(0.0);
visit_dc.Save();
}
socketstream sout;
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
sout.open(vishost, visport);
if (!sout)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
visualization = false;
cout << "GLVis visualization disabled.\n";
}
else
{
sout.precision(precision);
// sout << "solution\n" << *mesh << dudt_gf;
sout << "solution\n" << *mesh << u_gf;
sout << "pause\n";
sout << flush;
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
// 8. Perform time-integration (looping over the time iterations, ti, with a// time-step dt).double t = 0.0;
WaveOperator oper(fespace, ess_bdr, speed, /*init_time*/t);
ode_solver->Init(oper);
bool last_step = false;
Array<int> ess_tdof_list_main; // For DBC of u and dudt
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list_main);
FunctionCoefficient u_bdr(BoundaryValue_u);
FunctionCoefficient dudt_bdr(BoundaryValue_dudt);
for (int ti = 1; !last_step; ti++)
{
if (t + dt >= t_final - dt/2)
{
last_step = true;
}
// Assign DBC for u and dudt
u_bdr.SetTime(t);
u_gf.ProjectBdrCoefficient(u_bdr, ess_bdr);
dudt_bdr.SetTime(t);
dudt_gf.ProjectBdrCoefficient(dudt_bdr, ess_bdr);
for (int dofi = 0; dofi < ess_tdof_list_main.Size(); dofi++)
{
// I think directly set u is not legal
u[ess_tdof_list_main[dofi]] = u_gf[ess_tdof_list_main[dofi]];
dudt[ess_tdof_list_main[dofi]] = dudt_gf[ess_tdof_list_main[dofi]];
}
// Initial DBC for d2udt2 should set in f->Mult(x, dxdt, d2xdt2)
ode_solver->Step(u, dudt, t, dt);
if (last_step || (ti % vis_steps) == 0)
{
cout << "step " << ti << ", t = " << t << endl;
// Assign DBC at t+dt
u_bdr.SetTime(t);
u_gf.ProjectBdrCoefficient(u_bdr, ess_bdr);
dudt_bdr.SetTime(t);
dudt_gf.ProjectBdrCoefficient(dudt_bdr, ess_bdr);
for (int dofi = 0; dofi < ess_tdof_list_main.Size(); dofi++)
{
// I think directly set u is not legal
u[ess_tdof_list_main[dofi]] = u_gf[ess_tdof_list_main[dofi]];
dudt[ess_tdof_list_main[dofi]] = dudt_gf[ess_tdof_list_main[dofi]];
}
u_gf.SetFromTrueDofs(u);
dudt_gf.SetFromTrueDofs(dudt);
if (visualization)
{
sout << "solution\n" << *mesh << u_gf << flush;
}
if (visit)
{
visit_dc.SetCycle(ti);
visit_dc.SetTime(t);
visit_dc.Save();
}
}
oper.SetParameters(u);
}
// 9. Save the final solution. This output can be viewed later using GLVis:// "glvis -m ex23.mesh -g ex23-final.gf".
{
ofstream osol("ex23-final.gf");
osol.precision(precision);
u_gf.Save(osol);
dudt_gf.Save(osol);
}
// 10. Free the used memory.delete ode_solver;
delete mesh;
return0;
}
I use mesh uniform refined 7 times just like the example, but result seems differ.
The text was updated successfully, but these errors were encountered:
Wayne901
changed the title
A example of wave equation with time-dependent inhomogeneous Dirichlet boundary condition
An example of wave equation with time-dependent inhomogeneous Dirichlet boundary condition
Mar 9, 2024
Hi everyone, since there's no example for problems with time-dependent (especially nonzero) Dirichlet boundary conditions, I try to write one based on
ex23
. A special nature ofex23
is that wave equation has 2nd-order time derivatives. The code is as follow and I cannot guarantee it's correctness yet. Hope this can offer some help to people with similar needs.ex23
applys a zero dirichlet boundary condtion, which doesn't need eliminating the rhs at all. Here I try a testcase here. In theFor Newmark method, the wave equation is discretized as$[M+\beta(\Delta t)^2K]\frac{d^2u(t+\Delta t)}{dt^2} = -K[u(t)+\Delta t\frac{du(t)}{dt}+(\frac{1}{2}-\beta)(\Delta t)^2\frac{d^2u(t)}{dt^2}]$ . Following @v-dobrev's suggestion #1720 , I derive the solution
d2udt2
att+dt
after elimination asThe
u
ordudt
in photo representsu(t)
,du(t)/dt
.I
andB
represents DoFs on interior region and boundary, respectively.I have some quesitons about improving it
dt
andbeta
inside ImplicitSolve, but I needdt
and0.5-beta
to eliminate rhs. The current code calculatesdt
first, and then computebeta
based on the input variablefac0=beta*dt*dt
. Clearly it's only limit to the Newmark ODESolver. How to improve it for more general solvers?The whole code.
I use mesh uniform refined 7 times just like the example, but result seems differ.
The text was updated successfully, but these errors were encountered: