Compare commits

...
2 Commits
Author SHA1 Message Date
Ben Southworth 05ee77fd58 Improve explanation of picard 2020-07-02 16:14:58 -07:00
Ben Southworth b1ab80e455 Added Picard iteraiton to ex16p 2020-07-02 16:03:32 -07:00
+48 -14
View File
@@ -65,7 +65,7 @@ protected:
HypreSmoother M_prec; // Preconditioner for the mass matrix M
CGSolver T_solver; // Implicit solver for T = M + dt K
HypreSmoother T_prec; // Preconditioner for the implicit solver
HypreBoomerAMG T_prec; // Preconditioner for the implicit solver
double alpha, kappa;
@@ -353,7 +353,6 @@ int main(int argc, char *argv[])
}
#endif
}
oper.SetParameters(u);
}
#ifdef MFEM_USE_ADIOS2
@@ -414,6 +413,7 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
T_prec.SetPrintLevel(0);
SetParameters(u);
}
@@ -430,19 +430,53 @@ void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
void ConductionOperator::ImplicitSolve(const double dt,
const Vector &u, Vector &du_dt)
{
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
if (!T)
{
T = Add(1.0, Mmat, dt, Kmat);
current_dt = dt;
// Here we use Picard iterations to solve a nonlinear equation
// for the Runge-Kutta stage vector k,
//
// M*k = N(u+dt*k) (1)
//
// for nonlinear operator N. We assume N can be written as
//
// N(u+dt*k) := L[u+dt*k](u+dt*k) + f(t)
//
// where L is a matrix-valued operator evaluated at u+dt*k and f(t)
// a (potentially zero) time-dependent forcing vector. (1) can be
// rewritten as a fixed-point equation
//
// x = (M - dt*L[x])^{-1} (Mu + f) (2)
//
// where x := u + dt*k, which can be solved using a Picard iteration,
// where a function G(x) = x is solved via iteraitons x_{k+1} = G(x_k).
double tol = 1e-6;
int maxiter = 100;
// Right-hand side for nonlinear iteration
Mmat.Mult(u, z); // Add forcing function if one exists
du_dt = u; // Set u as initial guess for x (2)
Vector temp(u); // Vector to measure error
temp = u;
double error = 1;
int iter = 0;
while (error > tol) {
iter ++;
this->SetParameters(du_dt); // Update nonlinear operator L[x]
T = Add(1.0, Mmat, dt, Kmat); // Form matrix (M - dt*L[x])
T_solver.SetOperator(*T);
T_solver.Mult(z, du_dt); // Apply (M - dt*L[x])^{-1}
temp -= du_dt; // Measure error
error = std::sqrt(InnerProduct(MPI_COMM_WORLD, temp, temp));
temp = du_dt;
if (iter >= maxiter) {
mfem_warning("Nonlinear iteration did not converge!");
break;
}
}
MFEM_VERIFY(dt == current_dt, ""); // SDIRK methods use the same dt
Kmat.Mult(u, z);
z.Neg();
T_solver.Mult(z, du_dt);
// Above we solved for x = u + dt*k, where k is the desired update
// Map du_dt -> k.
du_dt -= u;
du_dt /= dt;
}
void ConductionOperator::SetParameters(const Vector &u)
@@ -483,4 +517,4 @@ double InitialTemperature(const Vector &x)
{
return 1.0;
}
}
}