-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Low storage runge kutta #259
base: master
Are you sure you want to change the base?
Changes from all commits
4f19280
93f71f1
01d72b3
ca60d55
555565c
8cb35d8
303cbf6
d858fe7
35170cc
15ad87c
820d80c
e758b4a
ee073a4
7acd254
40d4e00
659719b
4a99eac
ac2b446
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,188 @@ | ||||||
#include "low_storage_runge_kutta_ode_solver.h" | ||||||
|
||||||
namespace PHiLiP { | ||||||
namespace ODE { | ||||||
|
||||||
template <int dim, typename real, int n_rk_stages, typename MeshType> | ||||||
LowStorageRungeKuttaODESolver<dim,real,n_rk_stages, MeshType>::LowStorageRungeKuttaODESolver(std::shared_ptr< DGBase<dim, real, MeshType> > dg_input, | ||||||
std::shared_ptr<LowStorageRKTableauBase<dim,real,MeshType>> rk_tableau_input, | ||||||
std::shared_ptr<EmptyRRKBase<dim,real,MeshType>> RRK_object_input) | ||||||
: ODESolverBase<dim,real,MeshType>(dg_input) | ||||||
, butcher_tableau(rk_tableau_input) | ||||||
, relaxation_runge_kutta(RRK_object_input) | ||||||
, solver(dg_input) | ||||||
{ epsilon[0] = 1.0; | ||||||
epsilon[1] = 1.0; | ||||||
epsilon[2] = 1.0; | ||||||
} | ||||||
|
||||||
template <int dim, typename real, int n_rk_stages, typename MeshType> | ||||||
void LowStorageRungeKuttaODESolver<dim,real,n_rk_stages, MeshType>::step_in_time (real dt, const bool pseudotime) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This way you don't have to call (void) pseudotime. |
||||||
{ | ||||||
this->original_time_step = dt; | ||||||
this->solution_update = this->dg->solution; //storing u_n | ||||||
(void) pseudotime; | ||||||
|
||||||
dealii::LinearAlgebra::distributed::Vector<double> storage_register_2; | ||||||
storage_register_2.reinit(this->solution_update); | ||||||
storage_register_2*=0; | ||||||
dealii::LinearAlgebra::distributed::Vector<double> storage_register_1; | ||||||
storage_register_1.reinit(this->solution_update); | ||||||
storage_register_1 = this->dg->solution; | ||||||
dealii::LinearAlgebra::distributed::Vector<double> storage_register_3 = storage_register_1; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you move the initialization of these vectors to In order to do that, you would need to make all of the storage registers member variables of the LowStorageRungeKuttaODESolver, then just do the allocation steps in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just be careful to reinitialize the vectors if that needs to be done! |
||||||
|
||||||
dealii::LinearAlgebra::distributed::Vector<double> rhs = storage_register_1; | ||||||
|
||||||
dealii::LinearAlgebra::distributed::Vector<double> storage_register_4; | ||||||
|
||||||
if (this->butcher_tableau->get_b_hat(0) != 0.0){ | ||||||
storage_register_4 = storage_register_1; | ||||||
} | ||||||
|
||||||
double sum_delta = 0; | ||||||
|
||||||
//double atol = 0.001; | ||||||
//double rtol = 0.001; | ||||||
double error = 0.0; | ||||||
w = 0.0; | ||||||
|
||||||
for (int i = 1; i < n_rk_stages +1; i++ ){ | ||||||
// storage_register_2 = storage_register_2 + delta[i-1] * storage_register_1; | ||||||
storage_register_2.add(this->butcher_tableau->get_delta(i-1) , storage_register_1); | ||||||
this->dg->solution = rhs; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this might be possible to do without the extra vector |
||||||
this->dg->assemble_residual(); | ||||||
this->dg->apply_inverse_global_mass_matrix(this->dg->right_hand_side, rhs); | ||||||
// storage_register_1 = gamma[i][0] * storage_register_1 + gamma[i][1] * storage_register_2 + gamma[i][2] * storage_register_3 + beta[i] * dt * rhs; | ||||||
storage_register_1 *= this->butcher_tableau->get_gamma(i, 0); | ||||||
storage_register_1.add(this->butcher_tableau->get_gamma(i, 1), storage_register_2); | ||||||
storage_register_1.add(this->butcher_tableau->get_gamma(i, 2), storage_register_3); | ||||||
rhs *= dt; | ||||||
storage_register_1.add(this->butcher_tableau->get_beta(i), rhs); | ||||||
if (this->butcher_tableau->get_b_hat(i) != 0.0){ | ||||||
storage_register_4.add(this->butcher_tableau->get_b_hat(i-1), rhs); | ||||||
} | ||||||
//this->pcout << std::endl; | ||||||
// Check bhat (i) | ||||||
// rhs = dt * f(S1) | ||||||
rhs = storage_register_1; | ||||||
} | ||||||
// std::abort(); | ||||||
// storage_register_2 = (storage_register_2 + delta[m] * storage_register_1 + delta[m+1] * storage_register_3) / sum_delta; | ||||||
if (this->butcher_tableau->get_b_hat(1) == 0){ | ||||||
for (int i = 0; i < num_delta; i++){ //change n_rk_stages+2 to num_delta on this line | ||||||
sum_delta = sum_delta + this->butcher_tableau->get_delta(i); | ||||||
} | ||||||
storage_register_2.add(this->butcher_tableau->get_delta(n_rk_stages), storage_register_1); | ||||||
storage_register_2.add(this->butcher_tableau->get_delta(n_rk_stages+1), storage_register_3); | ||||||
storage_register_2 /= sum_delta; | ||||||
// u_hat = s2 | ||||||
} | ||||||
|
||||||
|
||||||
// need to calculate rhs of s1 | ||||||
else if (this->butcher_tableau->get_b_hat(n_rk_stages) != 0){ | ||||||
this->dg->solution = rhs; | ||||||
this->dg->assemble_residual(); | ||||||
this->dg->apply_inverse_global_mass_matrix(this->dg->right_hand_side, rhs); | ||||||
rhs *= dt; | ||||||
storage_register_4.add(this->butcher_tableau->get_b_hat(n_rk_stages), rhs); | ||||||
//this->pcout << " b_hat_fsal " << this->butcher_tableau->get_b_hat(n_rk_stages); | ||||||
|
||||||
} | ||||||
this->dg->solution = storage_register_1; | ||||||
|
||||||
double global_size = dealii::Utilities::MPI::sum(storage_register_1.local_size(), this->mpi_communicator); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would probably be better to do in |
||||||
|
||||||
if (this->butcher_tableau->get_b_hat(1) == 0){ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be easier to read if you made a Also, I think the computation of |
||||||
// loop sums elements at each mpi processor | ||||||
for (dealii::LinearAlgebra::distributed::Vector<double>::size_type i = 0; i < storage_register_1.local_size(); ++i) { | ||||||
error = storage_register_1.local_element(i) - storage_register_2.local_element(i); | ||||||
w = w + pow(error / (atol + rtol * std::max(std::abs(storage_register_1.local_element(i)), std::abs(storage_register_2.local_element(i)))), 2); | ||||||
} | ||||||
} | ||||||
else if (this->butcher_tableau->get_b_hat(1) != 0){ | ||||||
// loop sums elements at each mpi processor | ||||||
for (dealii::LinearAlgebra::distributed::Vector<double>::size_type i = 0; i < storage_register_1.local_size(); ++i) { | ||||||
error = storage_register_1.local_element(i) - storage_register_4.local_element(i); | ||||||
w = w + pow(error / (atol + rtol * std::max(std::abs(storage_register_1.local_element(i)), std::abs(storage_register_4.local_element(i)))), 2); | ||||||
} | ||||||
} | ||||||
this->pcout << std::endl; | ||||||
|
||||||
// sum over all elements | ||||||
w = dealii::Utilities::MPI::sum(w, this->mpi_communicator); | ||||||
|
||||||
w = pow(w / global_size, 0.5); | ||||||
|
||||||
this->pcout << std::endl; | ||||||
// std::cout << "w " << w; | ||||||
|
||||||
++(this->current_iteration); | ||||||
this->current_time += dt; | ||||||
this->pcout << " Time is: " << this->current_time <<std::endl; | ||||||
this->pcout << "dt" << dt; | ||||||
} | ||||||
|
||||||
|
||||||
template <int dim, typename real, int n_rk_stages, typename MeshType> | ||||||
double LowStorageRungeKuttaODESolver<dim,real,n_rk_stages, MeshType>::err_time_step (real dt, const bool pseudotime) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use a name similar to the ones used in flow solver for consistency? Maybe |
||||||
{ | ||||||
(void) pseudotime; | ||||||
//int q_hat = 2; | ||||||
//int k = q_hat +1; | ||||||
double beta_controller[3] = {0.70, -0.23, 0}; | ||||||
|
||||||
// error based step size | ||||||
|
||||||
epsilon[2] = epsilon[1]; | ||||||
epsilon[1] = epsilon[0]; | ||||||
epsilon[0] = 1.0 / w; | ||||||
//dt = pow(epsilon[0], 1.0 * beta_controller[0]/k) * pow(epsilon[1], 1.0 * beta_controller[1]/k) * pow(epsilon[2], 1.0 * beta_controller[2]/k) * dt; | ||||||
dt = pow(epsilon[0], 1.0 * beta_controller[0]/rk_order) * pow(epsilon[1], 1.0 * beta_controller[1]/rk_order) * pow(epsilon[2], 1.0 * beta_controller[2]/rk_order) * dt; | ||||||
this->pcout << std::endl; | ||||||
//this->pcout << "dt" << dt; | ||||||
return dt; | ||||||
} | ||||||
|
||||||
|
||||||
template <int dim, typename real, int n_rk_stages, typename MeshType> | ||||||
void LowStorageRungeKuttaODESolver<dim,real,n_rk_stages, MeshType>::allocate_ode_system () | ||||||
{ | ||||||
this->pcout << "Allocating ODE system..." << std::flush; | ||||||
this->solution_update.reinit(this->dg->right_hand_side); | ||||||
if(this->all_parameters->use_inverse_mass_on_the_fly == false) { | ||||||
this->pcout << " evaluating inverse mass matrix..." << std::flush; | ||||||
this->dg->evaluate_mass_matrices(true); // creates and stores global inverse mass matrix | ||||||
//RRK needs both mass matrix and inverse mass matrix | ||||||
using ODEEnum = Parameters::ODESolverParam::ODESolverEnum; | ||||||
ODEEnum ode_type = this->ode_param.ode_solver_type; | ||||||
if (ode_type == ODEEnum::rrk_explicit_solver){ | ||||||
this->dg->evaluate_mass_matrices(false); // creates and stores global mass matrix | ||||||
} | ||||||
} | ||||||
|
||||||
this->pcout << std::endl; | ||||||
|
||||||
this->butcher_tableau->set_tableau(); | ||||||
} | ||||||
|
||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,1, dealii::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,2, dealii::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,3, dealii::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,4, dealii::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,5, dealii::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,1, dealii::parallel::shared::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,2, dealii::parallel::shared::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,3, dealii::parallel::shared::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,4, dealii::parallel::shared::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,5, dealii::parallel::shared::Triangulation<PHILIP_DIM> >; | ||||||
#if PHILIP_DIM != 1 | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,1, dealii::parallel::distributed::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,2, dealii::parallel::distributed::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,3, dealii::parallel::distributed::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,4, dealii::parallel::distributed::Triangulation<PHILIP_DIM> >; | ||||||
template class LowStorageRungeKuttaODESolver<PHILIP_DIM, double,5, dealii::parallel::distributed::Triangulation<PHILIP_DIM> >; | ||||||
#endif | ||||||
|
||||||
} // ODESolver namespace | ||||||
} // PHiLiP namespace |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#ifndef __LOW_STORAGE_RUNGE_KUTTA_ODESOLVER__ | ||
#define __LOW_STORAGE_RUNGE_KUTTA_ODESOLVER__ | ||
|
||
#include "JFNK_solver/JFNK_solver.h" | ||
#include "dg/dg_base.hpp" | ||
#include "ode_solver_base.h" | ||
#include "runge_kutta_methods/low_storage_rk_tableau_base.h" | ||
#include "relaxation_runge_kutta/empty_RRK_base.h" | ||
|
||
namespace PHiLiP { | ||
namespace ODE { | ||
|
||
/// Runge-Kutta ODE solver (explicit or implicit) derived from ODESolver. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add the reference to the article we are using? Any reference style is okay, so long as it has year, authors, title, etc. Also add a link to that github page which has the correct coefficients. |
||
#if PHILIP_DIM==1 | ||
template <int dim, typename real, int n_rk_stages, typename MeshType = dealii::Triangulation<dim>> | ||
#else | ||
template <int dim, typename real, int n_rk_stages, typename MeshType = dealii::parallel::distributed::Triangulation<dim>> | ||
#endif | ||
class LowStorageRungeKuttaODESolver: public ODESolverBase <dim, real, MeshType> | ||
{ | ||
public: | ||
LowStorageRungeKuttaODESolver(std::shared_ptr< DGBase<dim, real, MeshType> > dg_input, | ||
std::shared_ptr<LowStorageRKTableauBase<dim,real,MeshType>> rk_tableau_input, | ||
std::shared_ptr<EmptyRRKBase<dim,real,MeshType>> RRK_object_input); ///< Constructor. | ||
|
||
/// Function to evaluate solution update | ||
double err_time_step(real dt, const bool pseudotime); | ||
|
||
void step_in_time(real dt, const bool pseudotime); | ||
|
||
/// Function to allocate the ODE system | ||
void allocate_ode_system (); | ||
|
||
protected: | ||
/// Stores Butcher tableau a and b, which specify the RK method | ||
std::shared_ptr<LowStorageRKTableauBase<dim,real,MeshType>> butcher_tableau; | ||
|
||
/// Stores functions related to relaxation Runge-Kutta (RRK). | ||
/// Functions are empty by default. | ||
std::shared_ptr<EmptyRRKBase<dim,real,MeshType>> relaxation_runge_kutta; | ||
|
||
/// Implicit solver for diagonally-implicit RK methods, using Jacobian-free Newton-Krylov | ||
/** This is initialized for any RK method, but solution-sized vectors are | ||
* only initialized if there is an implicit solve | ||
*/ | ||
JFNKSolver<dim,real,MeshType> solver; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this can be removed since we will never have implicit for this type of low-storage algorithm. You can remove it from the header here and also from line 13 of the cpp file. |
||
|
||
/// Storage for the derivative at each Runge-Kutta stage | ||
std::vector<dealii::LinearAlgebra::distributed::Vector<double>> rk_stage; | ||
|
||
/// Indicator for zero diagonal elements; used to toggle implicit solve. | ||
std::vector<bool> butcher_tableau_aii_is_zero; | ||
/* | ||
std::vector<dealii::LinearAlgebra::distributed::Vector<double>> storage_register_2; | ||
std::vector<dealii::LinearAlgebra::distributed::Vector<double>> storage_register_1; | ||
std::vector<dealii::LinearAlgebra::distributed::Vector<double>> storage_register_3; | ||
std::vector<dealii::LinearAlgebra::distributed::Vector<double>> storage_register_4; | ||
std::vector<dealii::LinearAlgebra::distributed::Vector<double>> rhs; | ||
*/ | ||
|
||
real w; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add comments for all new variables/functions? The syntax can be copied from above. |
||
|
||
double epsilon[3]; | ||
int num_delta; | ||
int rk_order; | ||
double atol; | ||
double rtol; | ||
//double beta_controller[3]; | ||
}; | ||
|
||
} // ODE namespace | ||
} // PHiLiP namespace | ||
|
||
#endif | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add another parameter which controls whether you use the error-adaptive time stepping? Then this structure would change to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the best place for that parameter would be in the flow solver section.