16 #include "solver/runge_kutta.h"
17 #include "discrete_problem/discrete_problem.h"
18 #include "projections/ogprojection.h"
28 template<
typename Scalar>
29 RungeKutta<Scalar>::RungeKutta(WeakFormSharedPtr<Scalar> wf, std::vector<SpaceSharedPtr<Scalar> > spaces, ButcherTable* bt)
30 : wf(wf), bt(bt), num_stages(bt->get_size()), stage_wf_right(new WeakForm<Scalar>(bt->get_size() * spaces.size())),
31 stage_wf_left(new WeakForm<Scalar>(spaces.size())), start_from_zero_K_vector(false), block_diagonal_jacobian(false), residual_as_vector(true), iteration(0),
32 freeze_jacobian(false), newton_tol(1e-6), newton_max_iter(20), newton_damping_coeff(1.0), newton_max_allowed_residual_norm(1e10)
34 for (
unsigned char i = 0; i < spaces.size(); i++)
36 this->spaces.push_back(spaces.at(i));
37 this->spaces_seqs.push_back(spaces.at(i)->get_seq());
41 throw Exceptions::NullException(2);
43 matrix_right = create_matrix<Scalar>();
44 matrix_left = create_matrix<Scalar>();
45 vector_right = create_vector<Scalar>();
47 solver = create_linear_solver(matrix_right, vector_right);
59 this->stage_dp_left =
nullptr;
60 this->stage_dp_right =
nullptr;
63 template<
typename Scalar>
64 RungeKutta<Scalar>::RungeKutta(WeakFormSharedPtr<Scalar> wf, SpaceSharedPtr<Scalar> space, ButcherTable* bt)
65 : wf(wf), bt(bt), num_stages(bt->get_size()), stage_wf_right(new WeakForm<Scalar>(bt->get_size())),
66 stage_wf_left(new WeakForm<Scalar>(1)), start_from_zero_K_vector(false), block_diagonal_jacobian(false), residual_as_vector(true), iteration(0),
67 freeze_jacobian(false), newton_tol(1e-6), newton_max_iter(20), newton_damping_coeff(1.0), newton_max_allowed_residual_norm(1e10)
69 this->spaces.push_back(space);
70 this->spaces_seqs.push_back(space->get_seq());
72 if (bt ==
nullptr)
throw Exceptions::NullException(2);
74 matrix_right = create_matrix<Scalar>();
75 matrix_left = create_matrix<Scalar>();
76 vector_right = create_vector<Scalar>();
78 solver = create_linear_solver(matrix_right, vector_right);
90 this->stage_dp_left =
nullptr;
91 this->stage_dp_right =
nullptr;
94 template<
typename Scalar>
95 void RungeKutta<Scalar>::set_spaces(std::vector<SpaceSharedPtr<Scalar> > spaces)
97 bool delete_K_vector =
false;
98 for (
unsigned char i = 0; i < spaces.size(); i++)
100 if (spaces[i]->get_seq() != this->spaces_seqs[i])
101 delete_K_vector =
true;
104 this->spaces = spaces;
105 this->spaces_seqs.clear();
106 for (
unsigned char i = 0; i < spaces.size(); i++)
107 this->spaces_seqs.push_back(spaces.at(i)->get_seq());
113 this->info(
"\tRunge-Kutta: K vectors are being set to zero, as the spaces changed during computation.");
114 memset(K_vector, 0, num_stages * Space<Scalar>::get_num_dofs(this->spaces) *
sizeof(Scalar));
118 delete[] vector_left;
121 if (this->stage_dp_left !=
nullptr)
122 this->stage_dp_left->set_spaces(this->spaces);
125 template<
typename Scalar>
126 void RungeKutta<Scalar>::set_space(SpaceSharedPtr<Scalar> space)
128 bool delete_K_vector =
false;
129 if (space->get_seq() != this->spaces_seqs[0])
130 delete_K_vector =
true;
132 this->spaces.clear();
133 this->spaces.push_back(space);
134 this->spaces_seqs.clear();
135 this->spaces_seqs.push_back(space->get_seq());
141 this->info(
"\tRunge-Kutta: K vector is being set to zero, as the spaces changed during computation.");
142 memset(K_vector, 0, num_stages * Space<Scalar>::get_num_dofs(this->spaces) *
sizeof(Scalar));
146 delete[] vector_left;
149 if (this->stage_dp_left !=
nullptr)
150 this->stage_dp_left->set_space(space);
153 template<
typename Scalar>
154 std::vector<SpaceSharedPtr<Scalar> > RungeKutta<Scalar>::get_spaces()
159 template<
typename Scalar>
160 void RungeKutta<Scalar>::init()
162 this->create_stage_wf(spaces.size(), block_diagonal_jacobian);
164 if (this->get_verbose_output())
166 this->stage_wf_left->set_verbose_output(
true);
167 this->stage_wf_right->set_verbose_output(
true);
171 this->stage_wf_left->set_verbose_output(
true);
172 this->stage_wf_right->set_verbose_output(
true);
182 this->stage_dp_left =
new DiscreteProblem<Scalar>(stage_wf_left, spaces);
185 std::vector<SpaceSharedPtr<Scalar> > stage_spaces_vector;
189 for (
unsigned int i = 0; i < num_stages; i++)
190 for (
unsigned int space_i = 0; space_i < spaces.size(); space_i++)
191 stage_spaces_vector.push_back(spaces[space_i]);
193 this->stage_dp_right =
new DiscreteProblem<Scalar>(stage_wf_right, stage_spaces_vector);
196 if (!residual_as_vector)
197 for (
unsigned int i = 0; i < num_stages; i++)
198 for (
unsigned int sln_i = 0; sln_i < spaces.size(); sln_i++)
199 residuals_vector.push_back(
new Solution<Scalar>(spaces[sln_i]->get_mesh()));
202 template<
typename Scalar>
203 void RungeKutta<Scalar>::set_start_from_zero_K_vector()
205 this->start_from_zero_K_vector =
true;
208 template<
typename Scalar>
209 void RungeKutta<Scalar>::set_residual_as_solutions()
211 this->residual_as_vector =
false;
214 template<
typename Scalar>
215 void RungeKutta<Scalar>::set_block_diagonal_jacobian()
217 this->block_diagonal_jacobian =
true;
220 template<
typename Scalar>
221 void RungeKutta<Scalar>::set_freeze_jacobian()
223 this->freeze_jacobian =
true;
225 template<
typename Scalar>
226 void RungeKutta<Scalar>::set_tolerance(
double newton_tol)
228 this->newton_tol = newton_tol;
230 template<
typename Scalar>
231 void RungeKutta<Scalar>::set_max_allowed_iterations(
int newton_max_iter)
233 this->newton_max_iter = newton_max_iter;
235 template<
typename Scalar>
236 void RungeKutta<Scalar>::set_newton_damping_coeff(
double newton_damping_coeff)
238 this->newton_damping_coeff = newton_damping_coeff;
240 template<
typename Scalar>
241 void RungeKutta<Scalar>::set_newton_max_allowed_residual_norm(
double newton_max_allowed_residual_norm)
243 this->newton_max_allowed_residual_norm = newton_max_allowed_residual_norm;
246 template<
typename Scalar>
247 RungeKutta<Scalar>::~RungeKutta()
249 if (stage_dp_left !=
nullptr)
250 delete stage_dp_left;
251 if (stage_dp_right !=
nullptr)
252 delete stage_dp_right;
259 delete[] vector_left;
262 template<
typename Scalar>
263 void RungeKutta<Scalar>::multiply_as_diagonal_block_matrix(SparseMatrix<Scalar>* matrix,
int num_blocks,
264 Scalar* source_vec, Scalar* target_vec)
266 int size = matrix->get_size();
267 for (
int i = 0; i < num_blocks; i++)
269 Scalar* temp = target_vec + i * size;
270 Scalar** temp_for_pass = &temp;
271 matrix->multiply_with_vector(source_vec + i*size, *temp_for_pass,
true);
275 template<
typename Scalar>
276 void RungeKutta<Scalar>::rk_time_step_newton(MeshFunctionSharedPtr<Scalar> sln_time_prev,
277 MeshFunctionSharedPtr<Scalar> sln_time_new, MeshFunctionSharedPtr<Scalar> error_fn)
279 std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev = std::vector<MeshFunctionSharedPtr<Scalar> >();
280 slns_time_prev.push_back(sln_time_prev);
281 std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_new = std::vector<MeshFunctionSharedPtr<Scalar> >();
282 slns_time_new.push_back(sln_time_new);
283 std::vector<MeshFunctionSharedPtr<Scalar> > error_fns = std::vector<MeshFunctionSharedPtr<Scalar> >();
284 error_fns.push_back(error_fn);
285 return rk_time_step_newton(slns_time_prev, slns_time_new,
289 template<
typename Scalar>
290 void RungeKutta<Scalar>::rk_time_step_newton(std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev,
291 std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_new,
292 std::vector<MeshFunctionSharedPtr<Scalar> > error_fns)
298 if (this->stage_dp_left ==
nullptr)
302 update_stage_wf(slns_time_prev);
305 if (error_fns != std::vector<MeshFunctionSharedPtr<Scalar> >() && bt->is_embedded() ==
false)
306 throw Hermes::Exceptions::Exception(
"rk_time_step_newton(): R-K method must be embedded if temporal error estimate is requested.");
308 info(
"\tRunge-Kutta: time step, time: %f, time step: %f", this->
time, this->time_step);
311 for (
unsigned int stage_i = 0; stage_i < num_stages; stage_i++)
312 Space<Scalar>::update_essential_bc_values(spaces, this->
time + bt->get_C(stage_i)*this->time_step);
315 std::vector<SpaceSharedPtr<Scalar> > stage_spaces_vector;
318 for (
unsigned int i = 0; i < num_stages; i++)
320 for (
unsigned int space_i = 0; space_i < spaces.size(); space_i++)
322 typename Space<Scalar>::ReferenceSpaceCreator ref_space_creator(spaces[space_i], spaces[space_i]->get_mesh(), 0);
323 stage_spaces_vector.push_back(ref_space_creator.create_ref_space());
326 this->stage_dp_right->set_spaces(stage_spaces_vector);
329 if (start_from_zero_K_vector || !iteration)
330 memset(K_vector, 0, num_stages * ndof *
sizeof(Scalar));
331 memset(u_ext_vec, 0, num_stages * ndof *
sizeof(Scalar));
332 memset(vector_left, 0, num_stages * ndof *
sizeof(Scalar));
339 stage_dp_left->assemble(matrix_left);
343 double residual_norm;
351 if (this->filters_to_reinit.size() > 0)
355 for (
unsigned int filters_i = 0; filters_i < this->filters_to_reinit.size(); filters_i++)
356 filters_to_reinit.at(filters_i)->reinit();
360 multiply_as_diagonal_block_matrix(matrix_left, num_stages, K_vector, vector_left);
364 stage_dp_right->set_RK(spaces.size(),
true, this->bt);
365 stage_dp_right->assemble(u_ext_vec,
nullptr, vector_right);
368 vector_right->add_vector(vector_left);
372 vector_right->change_sign();
373 if (this->output_rhsOn && (this->output_rhsIterations == -1 || this->output_rhsIterations >= it))
375 char* fileName =
new char[this->RhsFilename.length() + 5];
376 sprintf(fileName,
"%s%i", this->RhsFilename.c_str(), it);
377 vector_right->export_to_file(fileName, this->RhsVarname.c_str(), this->RhsFormat, this->rhs_number_format);
381 if (residual_as_vector)
383 residual_norm = get_l2_norm(vector_right);
387 std::vector<bool> add_dir_lift_vector;
388 add_dir_lift_vector.reserve(1);
389 add_dir_lift_vector.push_back(
false);
390 Solution<Scalar>::vector_to_solutions_common_dir_lift(vector_right, stage_dp_right->get_spaces(), residuals_vector,
false);
392 std::vector<MeshFunctionSharedPtr<Scalar> > meshFns;
393 for (
unsigned short i = 0; i < residuals_vector.size(); i++)
394 meshFns.push_back(residuals_vector[i]);
396 DefaultNormCalculator<Scalar, HERMES_L2_NORM> errorCalculator(meshFns.size());
397 residual_norm = errorCalculator.calculate_norms(meshFns);
402 this->info(
"\tRunge-Kutta: Newton initial residual norm: %g", residual_norm);
404 this->info(
"\tRunge-Kutta: Newton iteration %d, residual norm: %g", it - 1, residual_norm);
407 if (residual_norm > newton_max_allowed_residual_norm)
409 throw Exceptions::ValueException(
"residual norm", residual_norm, newton_max_allowed_residual_norm);
414 if ((residual_norm < newton_tol || it > newton_max_iter) && it > 1)
417 bool rhs_only = (freeze_jacobian && it > 1);
423 stage_dp_right->set_RK(spaces.size(),
true, this->bt);
424 stage_dp_right->assemble(u_ext_vec, matrix_right,
nullptr);
428 matrix_right->add_sparse_to_diagonal_blocks(num_stages, matrix_left);
430 if (this->output_matrixOn && (this->output_matrixIterations == -1 || this->output_matrixIterations >= it))
432 char* fileName =
new char[this->matrixFilename.length() + 5];
433 sprintf(fileName,
"%s%i", this->matrixFilename.c_str(), it);
434 matrix_right->export_to_file(fileName, this->matrixVarname.c_str(), this->matrixFormat, this->matrix_number_format);
437 matrix_right->finish();
440 solver->set_reuse_scheme(HERMES_REUSE_MATRIX_STRUCTURE_COMPLETELY);
446 for (
unsigned int i = 0; i < num_stages*ndof; i++)
447 K_vector[i] += newton_damping_coeff * solver->get_sln_vector()[i];
454 if (it >= newton_max_iter)
457 this->info(
"\tRunge-Kutta: time step duration: %f s.\n", this->last());
458 throw Exceptions::ValueException(
"Newton iterations", it, newton_max_iter);
466 Scalar* coeff_vec =
new Scalar[ndof];
470 for (
int i = 0; i < ndof; i++)
471 for (
unsigned int j = 0; j < num_stages; j++)
472 coeff_vec[i] += this->time_step * bt->get_B(j) * K_vector[j * ndof + i];
478 if (error_fns != std::vector<MeshFunctionSharedPtr<Scalar> >())
480 for (
int i = 0; i < ndof; i++)
483 for (
unsigned int j = 0; j < num_stages; j++)
484 coeff_vec[i] += (bt->get_B(j) - bt->get_B2(j)) * K_vector[j * ndof + i];
485 coeff_vec[i] *= this->time_step;
487 Solution<Scalar>::vector_to_solutions_common_dir_lift(coeff_vec, spaces, error_fns);
495 this->info(
"\tRunge-Kutta: time step duration: %f s.\n", this->last());
498 template<
typename Scalar>
499 void RungeKutta<Scalar>::rk_time_step_newton(std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev,
500 std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_new)
502 return rk_time_step_newton(slns_time_prev, slns_time_new,
503 std::vector<MeshFunctionSharedPtr<Scalar> >());
506 template<
typename Scalar>
507 void RungeKutta<Scalar>::rk_time_step_newton(MeshFunctionSharedPtr<Scalar> sln_time_prev, MeshFunctionSharedPtr<Scalar> sln_time_new)
509 std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev;
510 slns_time_prev.push_back(sln_time_prev);
511 std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_new;
512 slns_time_new.push_back(sln_time_new);
513 std::vector<MeshFunctionSharedPtr<Scalar> > error_fns;
514 return rk_time_step_newton(slns_time_prev, slns_time_new, error_fns);
517 template<
typename Scalar>
518 void RungeKutta<Scalar>::set_filters_to_reinit(std::vector<Filter<Scalar>*> filters_to_reinit)
520 for (
unsigned short i = 0; i < filters_to_reinit.size(); i++)
521 this->filters_to_reinit.push_back(filters_to_reinit.at(i));
524 template<
typename Scalar>
525 void RungeKutta<Scalar>::create_stage_wf(
unsigned int size,
bool block_diagonal_jacobian)
528 stage_wf_left->delete_all();
529 stage_wf_right->delete_all();
531 int spaces_size = stage_wf_right->original_neq = spaces.size();
534 for (
unsigned int component_i = 0; component_i < size; component_i++)
536 if (spaces[component_i]->get_type() == HERMES_H1_SPACE
537 || spaces[component_i]->get_type() == HERMES_L2_SPACE)
539 MatrixDefaultNormFormVol<Scalar>* proj_form =
new MatrixDefaultNormFormVol<Scalar>(component_i, component_i, HERMES_L2_NORM);
540 proj_form->areas.push_back(HERMES_ANY);
541 proj_form->scaling_factor = 1.0;
542 proj_form->u_ext_offset = 0;
543 stage_wf_left->add_matrix_form(proj_form);
545 if (spaces[component_i]->get_type() == HERMES_HDIV_SPACE
546 || spaces[component_i]->get_type() == HERMES_HCURL_SPACE)
548 MatrixDefaultNormFormVol<Scalar>* proj_form =
new MatrixDefaultNormFormVol<Scalar>(component_i, component_i, HERMES_HCURL_NORM);
549 proj_form->areas.push_back(HERMES_ANY);
550 proj_form->scaling_factor = 1.0;
551 proj_form->u_ext_offset = 0;
552 stage_wf_left->add_matrix_form(proj_form);
563 std::vector<MatrixFormVol<Scalar> *> mfvol_base = wf->mfvol;
564 std::vector<MatrixFormSurf<Scalar> *> mfsurf_base = wf->mfsurf;
565 std::vector<VectorFormVol<Scalar> *> vfvol_base = wf->vfvol;
566 std::vector<VectorFormSurf<Scalar> *> vfsurf_base = wf->vfsurf;
573 for (
unsigned int m = 0; m < mfvol_base.size(); m++)
575 for (
unsigned int i = 0; i < num_stages; i++)
577 for (
unsigned int j = 0; j < num_stages; j++)
579 if (block_diagonal_jacobian && i != j)
continue;
581 MatrixFormVol<Scalar>* mfv_ij = mfvol_base[m]->clone();
583 mfv_ij->i = mfv_ij->i + i * spaces_size;
584 mfv_ij->j = mfv_ij->j + j * spaces_size;
586 mfv_ij->u_ext_offset = i * spaces_size;
590 stage_wf_right->add_matrix_form(mfv_ij);
598 for (
unsigned int m = 0; m < mfsurf_base.size(); m++)
600 for (
unsigned int i = 0; i < num_stages; i++)
602 for (
unsigned int j = 0; j < num_stages; j++)
604 if (block_diagonal_jacobian && i != j)
continue;
606 MatrixFormSurf<Scalar>* mfs_ij = mfsurf_base[m]->clone();
608 mfs_ij->i = mfs_ij->i + i * spaces_size;
609 mfs_ij->j = mfs_ij->j + j * spaces_size;
611 mfs_ij->u_ext_offset = i * spaces_size;
615 stage_wf_right->add_matrix_form_surf(mfs_ij);
623 for (
unsigned int m = 0; m < vfvol_base.size(); m++)
625 for (
unsigned int i = 0; i < num_stages; i++)
627 VectorFormVol<Scalar>* vfv_i = vfvol_base[m]->clone();
629 vfv_i->i = vfv_i->i + i * spaces_size;
631 vfv_i->scaling_factor = -1.0;
632 vfv_i->u_ext_offset = i * spaces_size;
636 stage_wf_right->add_vector_form(vfv_i);
643 for (
unsigned int m = 0; m < vfsurf_base.size(); m++)
645 for (
unsigned int i = 0; i < num_stages; i++)
647 VectorFormSurf<Scalar>* vfs_i = vfsurf_base[m]->clone();
649 vfs_i->i = vfs_i->i + i * spaces_size;
651 vfs_i->scaling_factor = -1.0;
652 vfs_i->u_ext_offset = i * spaces_size;
656 stage_wf_right->add_vector_form_surf(vfs_i);
661 template<
typename Scalar>
662 void RungeKutta<Scalar>::update_stage_wf(std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev)
664 if (this->wf->global_integration_order_set)
666 this->stage_wf_left->set_global_integration_order(this->wf->global_integration_order);
667 this->stage_wf_right->set_global_integration_order(this->wf->global_integration_order);
672 std::vector<MatrixFormVol<Scalar> *> mfvol = stage_wf_right->mfvol;
673 std::vector<MatrixFormSurf<Scalar> *> mfsurf = stage_wf_right->mfsurf;
674 std::vector<VectorFormVol<Scalar> *> vfvol = stage_wf_right->vfvol;
675 std::vector<VectorFormSurf<Scalar> *> vfsurf = stage_wf_right->vfsurf;
677 stage_wf_right->ext.clear();
679 for (
unsigned int slns_time_prev_i = 0; slns_time_prev_i < slns_time_prev.size(); slns_time_prev_i++)
680 stage_wf_right->ext.push_back(slns_time_prev[slns_time_prev_i]);
687 for (
unsigned int m = 0; m < mfvol.size(); m++)
689 MatrixFormVol<Scalar> *mfv_ij = mfvol[m];
690 mfv_ij->scaling_factor = -this->time_step * bt->get_A(mfv_ij->i / spaces.size(), mfv_ij->j / spaces.size());
691 mfv_ij->set_current_stage_time(this->
time + bt->get_C(mfv_ij->i / spaces.size()) * this->time_step);
697 for (
unsigned int m = 0; m < mfsurf.size(); m++)
699 MatrixFormSurf<Scalar> *mfs_ij = mfsurf[m];
700 mfs_ij->scaling_factor = -this->time_step * bt->get_A(mfs_ij->i / spaces.size(), mfs_ij->j / spaces.size());
701 mfs_ij->set_current_stage_time(this->
time + bt->get_C(mfs_ij->i / spaces.size()) * this->time_step);
707 for (
unsigned int m = 0; m < vfvol.size(); m++)
709 VectorFormVol<Scalar>* vfv_i = vfvol[m];
710 vfv_i->set_current_stage_time(this->
time + bt->get_C(vfv_i->i / spaces.size())*this->time_step);
716 for (
unsigned int m = 0; m < vfsurf.size(); m++)
718 VectorFormSurf<Scalar>* vfs_i = vfsurf[m];
719 vfs_i->set_current_stage_time(this->
time + bt->get_C(vfs_i->i / spaces.size())*this->time_step);
723 template<
typename Scalar>
724 void RungeKutta<Scalar>::prepare_u_ext_vec()
727 for (
unsigned int stage_i = 0; stage_i < num_stages; stage_i++)
729 unsigned int running_space_ndofs = 0;
730 for (
unsigned int space_i = 0; space_i < spaces.size(); space_i++)
732 for (
int idx = 0; idx < spaces[space_i]->get_num_dofs(); idx++)
734 Scalar increment = 0;
735 for (
unsigned int stage_j = 0; stage_j < num_stages; stage_j++)
736 increment += bt->get_A(stage_i, stage_j) * K_vector[stage_j * ndof + running_space_ndofs + idx];
737 u_ext_vec[stage_i * ndof + running_space_ndofs + idx] = this->time_step * increment;
739 running_space_ndofs += spaces[space_i]->get_num_dofs();
743 template class HERMES_API RungeKutta < double > ;
744 template class HERMES_API RungeKutta < std::complex<double> > ;
::xsd::cxx::tree::time< char, simple_type > time
C++ type corresponding to the time XML Schema built-in type.
int get_num_dofs() const
Returns the number of basis functions contained in the space.
static void vector_to_solutions(const Scalar *solution_vector, std::vector< SpaceSharedPtr< Scalar > > spaces, std::vector< MeshFunctionSharedPtr< Scalar > > solutions, std::vector< bool > add_dir_lift=std::vector< bool >(), std::vector< int > start_indices=std::vector< int >())
Passes solution components calculated from solution vector as Solutions.
virtual int assign_dofs(int first_dof=0)
Builds basis functions and assigns DOF numbers to them.
static void project_global(SpaceSharedPtr< Scalar > space, MatrixFormVol< Scalar > *custom_projection_jacobian, VectorFormVol< Scalar > *custom_projection_residual, Scalar *target_vec)
This method allows to specify your own OG-projection form.