57 return arma::dot(velocity, diff.i()*velocity) * diam / arma::norm(velocity);
64 return Selection(
"DG_variant",
"Type of penalty term.")
65 .
add_value(non_symmetric,
"non-symmetric",
"non-symmetric weighted interior penalty DG method")
66 .
add_value(incomplete,
"incomplete",
"incomplete weighted interior penalty DG method")
67 .
add_value(symmetric,
"symmetric",
"symmetric weighted interior penalty DG method")
90 std::string equation_name = std::string(Model::ModelEqData::name()) +
"_DG";
91 return Model::get_input_type(
"DG",
"Discontinuous Galerkin (DG) solver")
94 "Solver for the linear system.")
97 .make_field_descriptor_type(equation_name)),
99 "Input fields of the equation.")
101 "Variant of the interior penalty discontinuous Galerkin method.")
103 "Polynomial order for the finite element in DG method (order 0 is suitable if there is no diffusion/dispersion).")
105 "If true, use DG projection of the initial condition field."
106 "Otherwise, evaluate initial condition field directly (well suited for reading native data).")
108 EqFields().output_fields.make_output_type(equation_name,
""),
109 IT::Default(
"{ \"fields\": [ " + Model::ModelEqData::default_output_field() +
"] }"),
110 "Specification of output fields and output times.")
114 template<
class Model>
116 Input::register_class< TransportDG<Model>,
Mesh &,
const Input::Record>(std::string(Model::ModelEqData::name()) +
"_DG") +
121 template<
class Model>
125 .
name(
"fracture_sigma")
127 "Coefficient of diffusive transfer through fractures (for each substance).")
135 "Penalty parameter influencing the discontinuity of the solution (for each substance). "
136 "Its default value 1 is sufficient in most cases. Higher value diminishes the inter-element jumps.")
144 .
description(
"Local Peclet number (ratio of advection to diffusion).");
154 .
description(
"Subdomain ids of the domain decomposition.");
170 this->add_coords_field();
171 this->set_default_fieldset();
177 template<
class Model>
180 double h_max = 0, h_min = numeric_limits<double>::infinity();
181 for (
unsigned int i=0; i<e->
n_nodes(); i++)
182 for (
unsigned int j=i+1; j<e->
n_nodes(); j++)
184 double dist = arma::norm(*e.
node(i) - *e.
node(j));
185 h_max = max(h_max, dist);
186 h_min = min(h_min, dist);
193 template<
class Model>
202 double delta = 0, h = 0;
211 for (
unsigned int i=0; i<side.
n_nodes(); i++)
212 for (
unsigned int j=i+1; j<side.
n_nodes(); j++) {
213 double dist = arma::norm(*side.
node(i) - *side.
node(j));
220 for (
int k=0; k<K_size; k++)
221 delta += dot(K[k]*normal_vector,normal_vector);
224 gamma = 0.5*fabs(flux) + alpha/h*delta*elem_anisotropy(side.
element());
229 template<
typename Model>
231 :
Model(init_mesh, in_rec),
245 Model::init_balance(in_rec);
257 eq_data_->dg_order = in_rec.
val<
unsigned int>(
"dg_order");
259 Model::init_from_input(in_rec);
262 shared_ptr<DiscreteSpace> ds = make_shared<EqualOrderDiscreteSpace>(Model::mesh_, fe);
263 eq_data_->dh_ = make_shared<DOFHandlerMultiDim>(*Model::mesh_);
270 template<
class TModel>
273 eq_fields_->set_components(eq_data_->substances_.names());
274 eq_fields_->set_input_list( input_rec.val<
Input::Array>(
"input_fields"), *(TModel::time_) );
275 eq_data_->set_time_governor(TModel::time_);
276 eq_data_->balance_ = this->balance();
277 eq_fields_->initialize(input_rec);
280 eq_data_->gamma.resize(eq_data_->n_substances());
281 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
282 eq_data_->gamma[sbi].resize(TModel::mesh_->boundary_.size());
285 eq_data_->max_edg_sides = max(TModel::mesh_->max_edge_sides(1), max(TModel::mesh_->max_edge_sides(2), TModel::mesh_->max_edge_sides(3)));
286 ret_sources.resize(eq_data_->n_substances());
287 ret_sources_prev.resize(eq_data_->n_substances());
290 if (input_rec.opt_val(
"user_fields", user_fields_arr)) {
291 this->init_user_fields(user_fields_arr, eq_fields_->output_fields);
294 eq_data_->output_vec.resize(eq_data_->n_substances());
295 eq_fields_->output_field.set_components(eq_data_->substances_.names());
296 eq_fields_->output_field.set_mesh(*TModel::mesh_);
297 eq_fields_->output_fields.set_mesh(*TModel::mesh_);
300 eq_fields_->output_field.setup_components();
301 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
304 auto output_field_ptr = create_field_fe< 3, FieldValue<3>::Scalar >(eq_data_->dh_);
305 eq_fields_->output_field[sbi].set(output_field_ptr, 0);
306 eq_data_->output_vec[sbi] = output_field_ptr->vec();
309 eq_fields_->peclet_number.set(
311 fn_peclet_number(), eq_fields_->diffusion_coef, eq_fields_->advection_coef, eq_fields_->elem_diameter
315 eq_fields_->peclet_number.setup_component_names();
318 eq_fields_->output_fields.initialize(TModel::output_stream_, TModel::mesh_, input_rec.val<
Input::Record>(
"output"), this->time());
321 std::string petsc_default_opts;
322 if (eq_data_->dh_->distr()->np() == 1)
323 petsc_default_opts =
"-ksp_type bcgs -pc_type ilu -pc_factor_levels 2 -ksp_diagonal_scale_fix -pc_factor_fill 6.0";
325 petsc_default_opts =
"-ksp_type bcgs -ksp_diagonal_scale_fix -pc_type asm -pc_asm_overlap 4 -sub_pc_type ilu -sub_pc_factor_levels 3 -sub_pc_factor_fill 6.0";
328 eq_data_->ls =
new LinSys*[eq_data_->n_substances()];
329 eq_data_->ls_dt =
new LinSys*[eq_data_->n_substances()];
330 eq_data_->conc_fe.resize(eq_data_->n_substances());
333 shared_ptr<DiscreteSpace> ds = make_shared<EqualOrderDiscreteSpace>(TModel::mesh_, fe);
334 eq_data_->dh_p0 = make_shared<DOFHandlerMultiDim>(*TModel::mesh_);
335 eq_data_->dh_p0->distribute_dofs(ds);
337 stiffness_matrix.resize(eq_data_->n_substances(),
nullptr);
338 mass_matrix.resize(eq_data_->n_substances(),
nullptr);
339 rhs.resize(eq_data_->n_substances(),
nullptr);
340 mass_vec.resize(eq_data_->n_substances(),
nullptr);
341 eq_data_->ret_vec.resize(eq_data_->n_substances(),
nullptr);
343 for (
unsigned int sbi = 0; sbi < eq_data_->n_substances(); sbi++) {
344 eq_data_->ls[sbi] =
new LinSys_PETSC(eq_data_->dh_->distr().get(), petsc_default_opts);
346 eq_data_->ls[sbi]->set_solution(eq_data_->output_vec[sbi].petsc_vec());
348 eq_data_->ls_dt[sbi] =
new LinSys_PETSC(eq_data_->dh_->distr().get(), petsc_default_opts);
351 eq_data_->conc_fe[sbi] = create_field_fe< 3, FieldValue<3>::Scalar >(eq_data_->dh_p0);
353 VecDuplicate(eq_data_->ls[sbi]->get_solution(), &eq_data_->ret_vec[sbi]);
357 init_projection = input_rec.val<
bool>(
"init_projection");
371 TModel::balance_->allocate(eq_data_->dh_->distr()->lsize(), mass_assembly_->eval_points()->max_size());
373 int qsize = mass_assembly_->eval_points()->max_size();
374 eq_data_->dif_coef.resize(eq_data_->n_substances());
375 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
377 eq_data_->dif_coef[sbi].resize(qsize);
380 eq_fields_->init_condition.setup_components();
381 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
388 template<
class Model>
393 if (eq_data_->gamma.size() > 0) {
396 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
398 if (eq_data_->ls !=
nullptr) {
399 delete eq_data_->ls[i];
400 delete eq_data_->ls_dt[i];
403 if (stiffness_matrix.size() > 0) {
404 if (stiffness_matrix[i])
405 chkerr(MatDestroy(&stiffness_matrix[i]));
407 chkerr(MatDestroy(&mass_matrix[i]));
409 chkerr(VecDestroy(&rhs[i]));
411 chkerr(VecDestroy(&mass_vec[i]));
412 if (eq_data_->ret_vec[i])
413 chkerr(VecDestroy(&eq_data_->ret_vec[i]));
416 if (eq_data_->ls !=
nullptr) {
417 delete[] eq_data_->ls;
418 delete[] eq_data_->ls_dt;
419 eq_data_->ls =
nullptr;
427 if (mass_assembly_ !=
nullptr) {
428 delete mass_assembly_;
429 delete stiffness_assembly_;
430 delete sources_assembly_;
431 delete bdr_cond_assembly_;
432 delete init_assembly_;
440 template<
class Model>
444 eq_fields_->mark_input_times( *(Model::time_) );
446 std::stringstream ss;
453 set_initial_condition();
454 for (
unsigned int sbi = 0; sbi < eq_data_->n_substances(); sbi++)
455 ( (
LinSys_PETSC *)eq_data_->ls[sbi] )->set_initial_guess_nonzero();
458 if (!allocation_done) preallocate();
461 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); ++sbi)
463 Model::balance_->calculate_instant(eq_data_->subst_idx_[sbi], eq_data_->ls[sbi]->get_solution());
466 ret_sources_prev[sbi] = 0;
473 template<
class Model>
477 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
480 eq_data_->ls[i]->start_allocation();
481 stiffness_matrix[i] = NULL;
485 eq_data_->ls_dt[i]->start_allocation();
486 mass_matrix[i] = NULL;
487 VecZeroEntries(eq_data_->ret_vec[i]);
490 mass_assembly_->assemble(eq_data_->dh_);
491 sources_assembly_->assemble(eq_data_->dh_);
492 bdr_cond_assembly_->assemble(eq_data_->dh_);
493 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
495 ((
LinSys_PETSC*)eq_data_->ls[i])->preallocate_matrix(*eq_data_->dh_);
496 VecAssemblyBegin(eq_data_->ret_vec[i]);
497 VecAssemblyEnd(eq_data_->ret_vec[i]);
500 allocation_done =
true;
505 template<
class Model>
510 Model::time_->next_time();
511 Model::time_->view(
"TDG");
520 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
522 eq_data_->ls_dt[i]->start_add_assembly();
523 eq_data_->ls_dt[i]->mat_zero_entries();
524 VecZeroEntries(eq_data_->ret_vec[i]);
526 mass_assembly_->assemble(eq_data_->dh_);
527 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
529 eq_data_->ls_dt[i]->finish_assembly();
530 VecAssemblyBegin(eq_data_->ret_vec[i]);
531 VecAssemblyEnd(eq_data_->ret_vec[i]);
533 if (mass_matrix[i] == NULL)
535 VecDuplicate(eq_data_->ls[i]->get_solution(), &mass_vec[i]);
536 MatMult(*(eq_data_->ls_dt[i]->get_matrix()), eq_data_->ls[i]->get_solution(), mass_vec[i]);
537 MatConvert(*( eq_data_->ls_dt[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &mass_matrix[i]);
540 MatCopy(*( eq_data_->ls_dt[i]->get_matrix() ), mass_matrix[i], DIFFERENT_NONZERO_PATTERN);
545 if (stiffness_matrix[0] == NULL
547 || eq_fields_->flow_flux.changed())
551 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
553 eq_data_->ls[i]->start_add_assembly();
554 eq_data_->ls[i]->mat_zero_entries();
556 stiffness_assembly_->assemble(eq_data_->dh_);
557 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
559 eq_data_->ls[i]->finish_assembly();
561 if (stiffness_matrix[i] == NULL)
562 MatConvert(*( eq_data_->ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &stiffness_matrix[i]);
564 MatCopy(*( eq_data_->ls[i]->get_matrix() ), stiffness_matrix[i], DIFFERENT_NONZERO_PATTERN);
571 || eq_fields_->flow_flux.changed())
573 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
575 eq_data_->ls[i]->start_add_assembly();
576 eq_data_->ls[i]->rhs_zero_entries();
578 sources_assembly_->assemble(eq_data_->dh_);
579 bdr_cond_assembly_->assemble(eq_data_->dh_);
580 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
582 eq_data_->ls[i]->finish_assembly();
584 if (rhs[i] ==
nullptr) VecDuplicate(*( eq_data_->ls[i]->get_rhs() ), &rhs[i]);
585 VecCopy(*( eq_data_->ls[i]->get_rhs() ), rhs[i]);
607 for (
unsigned int i=0; i<eq_data_->n_substances(); i++)
609 MatConvert(stiffness_matrix[i], MATSAME, MAT_INITIAL_MATRIX, &m);
610 MatAXPY(m, 1./Model::time_->dt(), mass_matrix[i], SUBSET_NONZERO_PATTERN);
611 eq_data_->ls[i]->set_matrix(m, DIFFERENT_NONZERO_PATTERN);
613 VecDuplicate(rhs[i], &w);
614 VecWAXPY(w, 1./Model::time_->dt(), mass_vec[i], rhs[i]);
615 eq_data_->ls[i]->set_rhs(w);
620 eq_data_->ls[i]->solve();
623 MatMult(*(eq_data_->ls_dt[i]->get_matrix()), eq_data_->ls[i]->get_solution(), mass_vec[i]);
634 calculate_cumulative_balance();
640 template<
class Model>
644 for (
auto cell : eq_data_->dh_->own_range() )
646 LocDofVec loc_dof_indices = cell.get_loc_dof_indices();
647 unsigned int n_dofs=loc_dof_indices.n_rows;
649 DHCellAccessor dh_p0_cell = eq_data_->dh_p0->cell_accessor_from_element(cell.elm_idx());
652 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); ++sbi)
654 eq_data_->conc_fe[sbi]->vec().set(dof_p0, 0);
656 for (
unsigned int j=0; j<n_dofs; ++j)
657 eq_data_->conc_fe[sbi]->vec().add( dof_p0, eq_data_->ls[sbi]->get_solution_array()[loc_dof_indices[j]] );
659 eq_data_->conc_fe[sbi]->vec().set( dof_p0, max(eq_data_->conc_fe[sbi]->vec().get(dof_p0)/n_dofs, 0.) );
667 template<
class Model>
676 eq_fields_->output_fields.set_time( this->time().step(),
LimitSide::left);
678 eq_fields_->output_fields.output(this->time().step());
680 Model::output_data();
683 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); ++sbi)
684 Model::balance_->calculate_instant(eq_data_->subst_idx_[sbi], eq_data_->ls[sbi]->get_solution());
685 Model::balance_->output();
692 template<
class Model>
695 if (Model::balance_->cumulative())
697 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); ++sbi)
699 Model::balance_->calculate_cumulative(eq_data_->subst_idx_[sbi], eq_data_->ls[sbi]->get_solution());
702 VecDot(eq_data_->ret_vec[sbi], eq_data_->ls[sbi]->get_solution(), &ret_sources[sbi]);
704 Model::balance_->add_cumulative_source(eq_data_->subst_idx_[sbi], (ret_sources[sbi]-ret_sources_prev[sbi])/Model::time_->dt());
705 ret_sources_prev[sbi] = ret_sources[sbi];
713 template<
class Model>
718 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
719 eq_data_->ls[sbi]->start_allocation();
721 init_assembly_->assemble(eq_data_->dh_);
723 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
724 eq_data_->ls[sbi]->start_add_assembly();
726 init_assembly_->assemble(eq_data_->dh_);
728 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); sbi++)
730 eq_data_->ls[sbi]->finish_assembly();
731 eq_data_->ls[sbi]->solve();
735 init_assembly_->assemble(eq_data_->dh_);
739 template<
class Model>
742 if (solution_changed)
744 for (
auto cell : eq_data_->dh_->own_range() )
746 LocDofVec loc_dof_indices = cell.get_loc_dof_indices();
747 unsigned int n_dofs=loc_dof_indices.n_rows;
749 DHCellAccessor dh_p0_cell = eq_data_->dh_p0->cell_accessor_from_element(cell.elm_idx());
752 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); ++sbi)
754 double old_average = 0;
755 for (
unsigned int j=0; j<n_dofs; ++j)
756 old_average += eq_data_->ls[sbi]->get_solution_array()[loc_dof_indices[j]];
757 old_average /= n_dofs;
759 for (
unsigned int j=0; j<n_dofs; ++j)
760 eq_data_->ls[sbi]->get_solution_array()[loc_dof_indices[j]]
761 += eq_data_->conc_fe[sbi]->vec().get(dof_p0) - old_average;
766 for (
unsigned int sbi=0; sbi<eq_data_->n_substances(); ++sbi)
767 MatMult(*(eq_data_->ls_dt[sbi]->get_matrix()), eq_data_->ls[sbi]->get_solution(), mass_vec[sbi]);