54 return Selection(
"DG_variant",
"Type of penalty term.")
55 .
add_value(non_symmetric,
"non-symmetric",
"non-symmetric weighted interior penalty DG method")
56 .
add_value(incomplete,
"incomplete",
"incomplete weighted interior penalty DG method")
57 .
add_value(symmetric,
"symmetric",
"symmetric weighted interior penalty DG method")
80 std::string equation_name = std::string(Model::ModelEqData::name()) +
"_DG";
81 return Model::get_input_type(
"DG",
"Discontinuous Galerkin (DG) solver")
83 "Solver for the linear system.")
86 .make_field_descriptor_type(equation_name)),
88 "Input fields of the equation.")
90 "Variant of the interior penalty discontinuous Galerkin method.")
92 "Polynomial order for the finite element in DG method (order 0 is suitable if there is no diffusion/dispersion).")
94 EqData().output_fields.make_output_type(equation_name,
""),
95 IT::Default(
"{ \"fields\": [ " + Model::ModelEqData::default_output_field() +
"] }"),
96 "Specification of output fields and output times.")
100 template<
class Model>
102 Input::register_class< TransportDG<Model>,
Mesh &,
const Input::Record>(std::string(Model::ModelEqData::name()) +
"_DG") +
110 unsigned int q_order;
112 q_order = 2*fe_order;
131 ds_ = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe0_, fe1_, fe2_, fe3_);
132 dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
134 dh_->distribute_dofs(ds_);
178 template<
class Model>
182 .
name(
"fracture_sigma")
184 "Coefficient of diffusive transfer through fractures (for each substance).")
192 "Penalty parameter influencing the discontinuity of the solution (for each substance). "
193 "Its default value 1 is sufficient in most cases. Higher value diminishes the inter-element jumps.")
206 .
description(
"Subdomain ids of the domain decomposition.");
214 template<
class Model>
216 : Model(init_mesh, in_rec),
230 data_.set_mesh(init_mesh);
239 Model::init_from_input(in_rec);
248 template<
class Model>
251 data_.set_components(Model::substances_.names());
252 data_.set_input_list( input_rec.val<
Input::Array>(
"input_fields"), *(Model::time_) );
255 gamma.resize(Model::n_substances());
256 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
257 gamma[sbi].resize(Model::mesh_->boundary_.size());
260 int qsize = max(feo->q<0>()->size(), max(feo->q<1>()->size(), max(feo->q<2>()->size(), feo->q<3>()->size())));
261 int max_edg_sides = max(Model::mesh_->max_edge_sides(1), max(Model::mesh_->max_edge_sides(2), Model::mesh_->max_edge_sides(3)));
262 mm_coef.resize(qsize);
263 ret_coef.resize(Model::n_substances());
264 ret_sources.resize(Model::n_substances());
265 ret_sources_prev.resize(Model::n_substances());
266 ad_coef.resize(Model::n_substances());
267 dif_coef.resize(Model::n_substances());
268 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
270 ret_coef[sbi].resize(qsize);
271 ad_coef[sbi].resize(qsize);
272 dif_coef[sbi].resize(qsize);
274 ad_coef_edg.resize(max_edg_sides);
275 dif_coef_edg.resize(max_edg_sides);
276 for (
int sd=0; sd<max_edg_sides; sd++)
278 ad_coef_edg[sd].resize(Model::n_substances());
279 dif_coef_edg[sd].resize(Model::n_substances());
280 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
282 ad_coef_edg[sd][sbi].resize(qsize);
283 dif_coef_edg[sd][sbi].resize(qsize);
287 output_vec.resize(Model::n_substances());
288 data_.output_field.set_components(Model::substances_.names());
289 data_.output_field.set_mesh(*Model::mesh_);
292 data_.output_field.setup_components();
293 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
297 output_vec[sbi] = output_field_ptr->set_fe_data(feo->dh());
298 data_.output_field[sbi].set_field(Model::mesh_->region_db().get_region_set(
"ALL"), output_field_ptr, 0);
302 data_.output_fields.initialize(Model::output_stream_, Model::mesh_, input_rec.val<
Input::Record>(
"output"), this->time());
305 std::string petsc_default_opts;
306 if (feo->dh()->distr()->np() == 1)
307 petsc_default_opts =
"-ksp_type bcgs -pc_type ilu -pc_factor_levels 2 -ksp_diagonal_scale_fix -pc_factor_fill 6.0";
309 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";
312 ls =
new LinSys*[Model::n_substances()];
313 ls_dt =
new LinSys*[Model::n_substances()];
314 solution_elem_ =
new double*[Model::n_substances()];
316 stiffness_matrix.resize(Model::n_substances(),
nullptr);
317 mass_matrix.resize(Model::n_substances(),
nullptr);
318 rhs.resize(Model::n_substances(),
nullptr);
319 mass_vec.resize(Model::n_substances(),
nullptr);
320 ret_vec.resize(Model::n_substances(),
nullptr);
322 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++) {
323 ls[sbi] =
new LinSys_PETSC(feo->dh()->distr().get(), petsc_default_opts);
325 ls[sbi]->set_solution(output_vec[sbi].petsc_vec());
327 ls_dt[sbi] =
new LinSys_PETSC(feo->dh()->distr().get(), petsc_default_opts);
329 solution_elem_[sbi] =
new double[Model::mesh_->get_el_ds()->lsize()];
331 VecDuplicate(ls[sbi]->get_solution(), &ret_vec[sbi]);
336 Model::balance_->allocate(feo->dh()->distr()->lsize(),
337 max(feo->fe<1>()->n_dofs(), max(feo->fe<2>()->n_dofs(), feo->fe<3>()->n_dofs())));
342 template<
class Model>
347 if (gamma.size() > 0) {
350 for (
unsigned int i=0; i<Model::n_substances(); i++)
353 delete[] solution_elem_[i];
356 if (stiffness_matrix[i])
357 chkerr(MatDestroy(&stiffness_matrix[i]));
359 chkerr(MatDestroy(&mass_matrix[i]));
361 chkerr(VecDestroy(&rhs[i]));
363 chkerr(VecDestroy(&mass_vec[i]));
365 chkerr(VecDestroy(&ret_vec[i]));
368 delete[] solution_elem_;
382 template<
class Model>
386 data_.mark_input_times( *(Model::time_) );
388 std::stringstream ss;
395 set_initial_condition();
396 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++)
397 ( (
LinSys_PETSC *)ls[sbi] )->set_initial_guess_nonzero();
400 if (!allocation_done) preallocate();
403 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
405 Model::balance_->calculate_instant(Model::subst_idx[sbi], ls[sbi]->get_solution());
408 ret_sources_prev[sbi] = 0;
415 template<
class Model>
419 for (
unsigned int i=0; i<Model::n_substances(); i++)
422 ls[i]->start_allocation();
423 stiffness_matrix[i] = NULL;
427 ls_dt[i]->start_allocation();
428 mass_matrix[i] = NULL;
429 VecZeroEntries(ret_vec[i]);
431 assemble_stiffness_matrix();
432 assemble_mass_matrix();
434 set_boundary_conditions();
435 for (
unsigned int i=0; i<Model::n_substances(); i++)
437 VecAssemblyBegin(ret_vec[i]);
438 VecAssemblyEnd(ret_vec[i]);
441 allocation_done =
true;
446 template<
class Model>
451 Model::time_->next_time();
452 Model::time_->view(
"TDG");
461 for (
unsigned int i=0; i<Model::n_substances(); i++)
463 ls_dt[i]->start_add_assembly();
464 ls_dt[i]->mat_zero_entries();
465 VecZeroEntries(ret_vec[i]);
467 assemble_mass_matrix();
468 for (
unsigned int i=0; i<Model::n_substances(); i++)
470 ls_dt[i]->finish_assembly();
471 VecAssemblyBegin(ret_vec[i]);
472 VecAssemblyEnd(ret_vec[i]);
474 if (mass_matrix[i] == NULL)
476 VecDuplicate(ls[i]->get_solution(), &mass_vec[i]);
477 MatMult(*(ls_dt[i]->get_matrix()), ls[i]->get_solution(), mass_vec[i]);
478 MatConvert(*( ls_dt[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &mass_matrix[i]);
481 MatCopy(*( ls_dt[i]->get_matrix() ), mass_matrix[i], DIFFERENT_NONZERO_PATTERN);
486 if (stiffness_matrix[0] == NULL
488 || Model::flux_changed)
492 for (
unsigned int i=0; i<Model::n_substances(); i++)
494 ls[i]->start_add_assembly();
495 ls[i]->mat_zero_entries();
497 assemble_stiffness_matrix();
498 for (
unsigned int i=0; i<Model::n_substances(); i++)
500 ls[i]->finish_assembly();
502 if (stiffness_matrix[i] == NULL)
503 MatConvert(*( ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &stiffness_matrix[i]);
505 MatCopy(*( ls[i]->get_matrix() ), stiffness_matrix[i], DIFFERENT_NONZERO_PATTERN);
512 || Model::flux_changed)
514 for (
unsigned int i=0; i<Model::n_substances(); i++)
516 ls[i]->start_add_assembly();
517 ls[i]->rhs_zero_entries();
520 set_boundary_conditions();
521 for (
unsigned int i=0; i<Model::n_substances(); i++)
523 ls[i]->finish_assembly();
525 if (rhs[i] ==
nullptr) VecDuplicate(*( ls[i]->get_rhs() ), &rhs[i]);
526 VecCopy(*( ls[i]->get_rhs() ), rhs[i]);
530 Model::flux_changed =
false;
551 for (
unsigned int i=0; i<Model::n_substances(); i++)
553 MatConvert(stiffness_matrix[i], MATSAME, MAT_INITIAL_MATRIX, &m);
554 MatAXPY(m, 1./Model::time_->dt(), mass_matrix[i], SUBSET_NONZERO_PATTERN);
555 ls[i]->set_matrix(m, DIFFERENT_NONZERO_PATTERN);
557 VecDuplicate(rhs[i], &w);
558 VecWAXPY(w, 1./Model::time_->dt(), mass_vec[i], rhs[i]);
567 MatMult(*(ls_dt[i]->get_matrix()), ls[i]->get_solution(), mass_vec[i]);
571 calculate_cumulative_balance();
577 template<
class Model>
581 unsigned int i_cell=0;
582 for (
auto cell : feo->dh()->own_range() )
589 n_dofs = feo->fe<1>()->n_dofs();
592 n_dofs = feo->fe<2>()->n_dofs();
595 n_dofs = feo->fe<3>()->n_dofs();
600 cell.get_dof_indices(dof_indices);
602 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
604 solution_elem_[sbi][i_cell] = 0;
606 for (
unsigned int j=0; j<n_dofs; ++j)
607 solution_elem_[sbi][i_cell] += ls[sbi]->get_solution_array()[dof_indices[j]-feo->dh()->distr()->begin()];
609 solution_elem_[sbi][i_cell] = max(solution_elem_[sbi][i_cell]/n_dofs, 0.);
618 template<
class Model>
629 data_.output_fields.output(this->
time().step());
631 Model::output_data();
634 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
635 Model::balance_->calculate_instant(Model::subst_idx[sbi], ls[sbi]->get_solution());
636 Model::balance_->output();
643 template<
class Model>
646 if (Model::balance_->cumulative())
648 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
650 Model::balance_->calculate_cumulative(Model::subst_idx[sbi], ls[sbi]->get_solution());
653 VecDot(ret_vec[sbi], ls[sbi]->get_solution(), &ret_sources[sbi]);
655 Model::balance_->add_cumulative_source(Model::subst_idx[sbi], (ret_sources[sbi]-ret_sources_prev[sbi])/Model::time_->dt());
656 ret_sources_prev[sbi] = ret_sources[sbi];
662 template<
class Model>
666 Model::balance_->start_mass_assembly(Model::subst_idx);
667 assemble_mass_matrix<1>();
668 assemble_mass_matrix<2>();
669 assemble_mass_matrix<3>();
670 Model::balance_->finish_mass_assembly(Model::subst_idx);
675 template<
class Model>
template<
unsigned int dim>
679 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
681 PetscScalar local_mass_matrix[ndofs*ndofs], local_retardation_balance_vector[ndofs];
685 for (
auto cell : feo->dh()->own_range() )
687 if (cell.dim() != dim)
continue;
690 fe_values.reinit(elm);
691 cell.get_dof_indices(dof_indices);
693 Model::compute_mass_matrix_coefficient(fe_values.point_list(), elm, mm_coef);
694 Model::compute_retardation_coefficient(fe_values.point_list(), elm, ret_coef);
696 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
699 for (
unsigned int i=0; i<ndofs; i++)
701 for (
unsigned int j=0; j<ndofs; j++)
703 local_mass_matrix[i*ndofs+j] = 0;
704 for (
unsigned int k=0; k<qsize; k++)
705 local_mass_matrix[i*ndofs+j] += (mm_coef[k]+ret_coef[sbi][k])*fe_values.shape_value(j,k)*fe_values.shape_value(i,k)*fe_values.JxW(k);
709 for (
unsigned int i=0; i<ndofs; i++)
711 local_mass_balance_vector[i] = 0;
712 local_retardation_balance_vector[i] = 0;
713 for (
unsigned int k=0; k<qsize; k++)
715 local_mass_balance_vector[i] += mm_coef[k]*fe_values.shape_value(i,k)*fe_values.JxW(k);
716 local_retardation_balance_vector[i] -= ret_coef[sbi][k]*fe_values.shape_value(i,k)*fe_values.JxW(k);
720 Model::balance_->add_mass_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_mass_balance_vector);
721 ls_dt[sbi]->mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_mass_matrix);
722 VecSetValues(ret_vec[sbi], ndofs, &(dof_indices[0]), local_retardation_balance_vector, ADD_VALUES);
730 template<
class Model>
735 assemble_volume_integrals<1>();
736 assemble_volume_integrals<2>();
737 assemble_volume_integrals<3>();
741 assemble_fluxes_boundary<1>();
742 assemble_fluxes_boundary<2>();
743 assemble_fluxes_boundary<3>();
747 assemble_fluxes_element_element<1>();
748 assemble_fluxes_element_element<2>();
749 assemble_fluxes_element_element<3>();
753 assemble_fluxes_element_side<1>();
754 assemble_fluxes_element_side<2>();
755 assemble_fluxes_element_side<3>();
762 template<
class Model>
763 template<
unsigned int dim>
766 FEValues<dim,3> fv_rt(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe_rt<dim>(),
768 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
770 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
774 PetscScalar local_matrix[ndofs*ndofs];
777 for (
auto cell : feo->dh()->own_range() )
779 if (cell.dim() != dim)
continue;
784 cell.get_dof_indices(dof_indices);
786 calculate_velocity(elm, velocity, fv_rt);
787 Model::compute_advection_diffusion_coefficients(fe_values.
point_list(), velocity, elm, ad_coef, dif_coef);
788 Model::compute_sources_sigma(fe_values.
point_list(), elm, sources_sigma);
791 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
793 for (
unsigned int i=0; i<ndofs; i++)
794 for (
unsigned int j=0; j<ndofs; j++)
795 local_matrix[i*ndofs+j] = 0;
797 for (
unsigned int k=0; k<qsize; k++)
799 for (
unsigned int i=0; i<ndofs; i++)
802 double ad_dot_grad_i = arma::dot(ad_coef[sbi][k], fe_values.
shape_grad(i,k));
804 for (
unsigned int j=0; j<ndofs; j++)
805 local_matrix[i*ndofs+j] += (arma::dot(Kt_grad_i, fe_values.
shape_grad(j,k))
810 ls[sbi]->mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_matrix);
816 template<
class Model>
820 Model::balance_->start_source_assembly(Model::subst_idx);
824 Model::balance_->finish_source_assembly(Model::subst_idx);
828 template<
class Model>
829 template<
unsigned int dim>
832 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
834 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
839 PetscScalar local_rhs[ndofs];
844 for (
auto cell : feo->dh()->own_range() )
846 if (cell.dim() != dim)
continue;
849 fe_values.reinit(elm);
850 cell.get_dof_indices(dof_indices);
852 Model::compute_source_coefficients(fe_values.point_list(), elm, sources_conc, sources_density, sources_sigma);
855 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
857 fill_n(local_rhs, ndofs, 0);
858 local_source_balance_vector.assign(ndofs, 0);
859 local_source_balance_rhs.assign(ndofs, 0);
862 for (
unsigned int k=0; k<qsize; k++)
864 source = (sources_density[sbi][k] + sources_conc[sbi][k]*sources_sigma[sbi][k])*fe_values.JxW(k);
866 for (
unsigned int i=0; i<ndofs; i++)
867 local_rhs[i] += source*fe_values.shape_value(i,k);
869 ls[sbi]->rhs_set_values(ndofs, &(dof_indices[0]), local_rhs);
871 for (
unsigned int i=0; i<ndofs; i++)
873 for (
unsigned int k=0; k<qsize; k++)
874 local_source_balance_vector[i] -= sources_sigma[sbi][k]*fe_values.shape_value(i,k)*fe_values.JxW(k);
876 local_source_balance_rhs[i] += local_rhs[i];
878 Model::balance_->add_source_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_source_balance_vector);
879 Model::balance_->add_source_vec_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_source_balance_rhs);
886 template<
class Model>
887 template<
unsigned int dim>
893 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size(),
894 n_max_sides = ad_coef_edg.size();
896 PetscScalar local_matrix[ndofs*ndofs];
899 double gamma_l, omega[2], transport_flux;
901 for (
unsigned int sid=0; sid<n_max_sides; sid++)
904 fe_values.push_back(
new FESideValues<dim,3>(*feo->mapping<dim>(), *feo->q<dim-1>(), *feo->fe<dim>(),
909 for (
unsigned int iedg=0; iedg<feo->dh()->n_loc_edges(); iedg++)
911 Edge *edg = &Model::mesh_->edges[feo->dh()->edge_index(iedg)];
914 for (
int sid=0; sid<edg->
n_sides; sid++)
916 auto dh_cell = feo->dh()->cell_accessor_from_element( edg->
side(sid)->
element().
idx() );
918 dh_cell.get_dof_indices(side_dof_indices[sid]);
919 fe_values[sid]->reinit(cell, edg->
side(sid)->
side_idx());
921 calculate_velocity(cell, side_velocity[sid], fsv_rt);
922 Model::compute_advection_diffusion_coefficients(fe_values[sid]->point_list(), side_velocity[sid], cell, ad_coef_edg[sid], dif_coef_edg[sid]);
923 dg_penalty[sid].resize(Model::n_substances());
924 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
925 dg_penalty[sid][sbi] = data_.dg_penalty[sbi].value(cell.
centre(), cell);
929 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
932 for (
int sid=0; sid<edg->
n_sides; sid++)
935 for (
unsigned int k=0; k<qsize; k++)
936 fluxes[sid] += arma::dot(ad_coef_edg[sid][sbi][k], fe_values[sid]->normal_vector(k))*fe_values[sid]->JxW(k);
940 for (
int s1=0; s1<edg->
n_sides; s1++)
942 for (
int s2=s1+1; s2<edg->
n_sides; s2++)
946 && !feo->dh()->el_is_local( edg->
side(s2)->
element().
idx() ))
continue;
948 arma::vec3 nv = fe_values[s1]->normal_vector(0);
951 set_DG_parameters_edge(*edg, s1, s2, qsize, dif_coef_edg[s1][sbi], dif_coef_edg[s2][sbi], fluxes, fe_values[0]->normal_vector(0), dg_penalty[s1][sbi], dg_penalty[s2][sbi], gamma_l, omega, transport_flux);
957 #define AVERAGE(i,k,side_id) (fe_values[sd[side_id]]->shape_value(i,k)*0.5)
958 #define WAVERAGE(i,k,side_id) (arma::dot(dif_coef_edg[sd[side_id]][sbi][k]*fe_values[sd[side_id]]->shape_grad(i,k),nv)*omega[side_id])
959 #define JUMP(i,k,side_id) ((side_id==0?1:-1)*fe_values[sd[side_id]]->shape_value(i,k))
962 for (
int n=0; n<2; n++)
964 if (!feo->dh()->el_is_local( edg->
side(sd[n])->
element().
idx() ))
continue;
966 for (
int m=0; m<2; m++)
968 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
969 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
970 local_matrix[i*fe_values[sd[m]]->n_dofs()+j] = 0;
972 for (
unsigned int k=0; k<qsize; k++)
974 double flux_times_JxW = transport_flux*fe_values[0]->JxW(k);
975 double gamma_times_JxW = gamma_l*fe_values[0]->JxW(k);
977 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
979 double flux_JxW_jump_i = flux_times_JxW*
JUMP(i,k,n);
980 double gamma_JxW_jump_i = gamma_times_JxW*
JUMP(i,k,n);
981 double JxW_jump_i = fe_values[0]->JxW(k)*
JUMP(i,k,n);
982 double JxW_var_wavg_i = fe_values[0]->JxW(k)*
WAVERAGE(i,k,n)*dg_variant;
984 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
986 int index = i*fe_values[sd[m]]->n_dofs()+j;
989 local_matrix[index] += flux_JxW_jump_i*
AVERAGE(j,k,m);
992 local_matrix[index] += gamma_JxW_jump_i*
JUMP(j,k,m);
995 local_matrix[index] -=
WAVERAGE(j,k,m)*JxW_jump_i;
996 local_matrix[index] -=
JUMP(j,k,m)*JxW_var_wavg_i;
1000 ls[sbi]->mat_set_values(fe_values[sd[n]]->n_dofs(), &(side_dof_indices[sd[n]][0]), fe_values[sd[m]]->n_dofs(), &(side_dof_indices[sd[m]][0]), local_matrix);
1011 for (
unsigned int i=0; i<n_max_sides; i++)
1013 delete fe_values[i];
1018 template<
class Model>
1019 template<
unsigned int dim>
1022 FESideValues<dim,3> fe_values_side(*feo->mapping<dim>(), *feo->q<dim-1>(), *feo->fe<dim>(),
1026 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size();
1028 PetscScalar local_matrix[ndofs*ndofs];
1035 for (
unsigned int iedg=0; iedg<feo->dh()->n_loc_edges(); iedg++)
1037 Edge *edg = &Model::mesh_->edges[feo->dh()->edge_index(iedg)];
1038 if (edg->
n_sides > 1)
continue;
1040 if (edg->
side(0)->
dim() != dim-1)
continue;
1042 if (edg->
side(0)->
cond() == NULL)
continue;
1045 auto cell = feo->dh()->cell_accessor_from_element( side->
element().
idx() );
1047 cell.get_dof_indices(side_dof_indices);
1051 calculate_velocity(elm_acc, side_velocity, fsv_rt);
1052 Model::compute_advection_diffusion_coefficients(fe_values_side.
point_list(), side_velocity, elm_acc, ad_coef, dif_coef);
1055 data_.cross_section.value_list(fe_values_side.
point_list(), elm_acc, csection);
1057 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1059 for (
unsigned int i=0; i<ndofs; i++)
1060 for (
unsigned int j=0; j<ndofs; j++)
1061 local_matrix[i*ndofs+j] = 0;
1065 double side_flux = 0;
1066 for (
unsigned int k=0; k<qsize; k++)
1067 side_flux += arma::dot(ad_coef[sbi][k], fe_values_side.
normal_vector(k))*fe_values_side.
JxW(k);
1068 double transport_flux = side_flux/side->
measure();
1073 set_DG_parameters_boundary(side, qsize, dif_coef[sbi], transport_flux, fe_values_side.
normal_vector(0), data_.dg_penalty[sbi].value(elm_acc.
centre(), elm_acc), gamma_l);
1074 gamma[sbi][side->
cond_idx()] = gamma_l;
1075 transport_flux += gamma_l;
1079 for (
unsigned int k=0; k<qsize; k++)
1081 double flux_times_JxW;
1085 flux_times_JxW = csection[k]*robin_sigma[k]*fe_values_side.
JxW(k);
1090 flux_times_JxW = (transport_flux + csection[k]*robin_sigma[k])*fe_values_side.
JxW(k);
1095 flux_times_JxW = transport_flux*fe_values_side.
JxW(k);
1097 for (
unsigned int i=0; i<ndofs; i++)
1099 for (
unsigned int j=0; j<ndofs; j++)
1102 local_matrix[i*ndofs+j] += flux_times_JxW*fe_values_side.
shape_value(i,k)*fe_values_side.
shape_value(j,k);
1108 )*fe_values_side.
JxW(k);
1113 ls[sbi]->mat_set_values(ndofs, &(side_dof_indices[0]), ndofs, &(side_dof_indices[0]), local_matrix);
1119 template<
class Model>
1120 template<
unsigned int dim>
1124 if (dim == 1)
return;
1125 FEValues<dim-1,3> fe_values_vb(*feo->mapping<dim-1>(), *feo->q<dim-1>(), *feo->
fe<dim-1>(),
1131 FEValues<dim-1,3> fv_rt(*feo->mapping<dim-1>(), *feo->q<dim-1>(), *feo->fe_rt<dim-1>(),
1135 const unsigned int ndofs = feo->fe<dim>()->n_dofs();
1136 const unsigned int qsize = feo->q<dim-1>()->size();
1137 int side_dof_indices[2*ndofs];
1139 unsigned int n_dofs[2], n_indices;
1143 PetscScalar local_matrix[4*ndofs*ndofs];
1144 double comm_flux[2][2];
1148 fv_sb[0] = &fe_values_vb;
1149 fv_sb[1] = &fe_values_side;
1152 for (
unsigned int inb=0; inb<feo->dh()->n_loc_nb(); inb++)
1154 Neighbour *nb = &Model::mesh_->vb_neighbours_[feo->dh()->nb_index(inb)];
1158 auto dh_cell_sub = feo->dh()->cell_accessor_from_element( nb->
element().
idx() );
1160 n_indices = dh_cell_sub.get_dof_indices(indices);
1161 for(
unsigned int i=0; i<n_indices; ++i) {
1162 side_dof_indices[i] = indices[i];
1164 fe_values_vb.
reinit(cell_sub);
1165 n_dofs[0] = fv_sb[0]->n_dofs();
1167 auto dh_cell = feo->dh()->cell_accessor_from_element( nb->
side()->
element().
idx() );
1169 n_indices = dh_cell.get_dof_indices(indices);
1170 for(
unsigned int i=0; i<n_indices; ++i) {
1171 side_dof_indices[i+n_dofs[0]] = indices[i];
1174 n_dofs[1] = fv_sb[1]->n_dofs();
1178 element_id[0] = cell_sub.
idx();
1179 element_id[1] = cell.
idx();
1183 calculate_velocity(cell, velocity_higher, fsv_rt);
1184 calculate_velocity(cell_sub, velocity_lower, fv_rt);
1185 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_lower, cell_sub, ad_coef_edg[0], dif_coef_edg[0]);
1186 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_higher, cell, ad_coef_edg[1], dif_coef_edg[1]);
1187 data_.cross_section.value_list(fe_values_vb.
point_list(), cell_sub, csection_lower);
1188 data_.cross_section.value_list(fe_values_vb.
point_list(), cell, csection_higher);
1190 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1192 for (
unsigned int i=0; i<n_dofs[0]+n_dofs[1]; i++)
1193 for (
unsigned int j=0; j<n_dofs[0]+n_dofs[1]; j++)
1194 local_matrix[i*(n_dofs[0]+n_dofs[1])+j] = 0;
1196 data_.fracture_sigma[sbi].value_list(fe_values_vb.
point_list(), cell_sub, frac_sigma);
1199 for (
unsigned int k=0; k<qsize; k++)
1209 double sigma = frac_sigma[k]*arma::dot(dif_coef_edg[0][sbi][k]*fe_values_side.
normal_vector(k),fe_values_side.
normal_vector(k))*
1210 2*csection_higher[k]*csection_higher[k]/(csection_lower[k]*csection_lower[k]);
1212 double transport_flux = arma::dot(ad_coef_edg[1][sbi][k], fe_values_side.
normal_vector(k));
1214 comm_flux[0][0] = (sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1215 comm_flux[0][1] = -(sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1216 comm_flux[1][0] = -(sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1217 comm_flux[1][1] = (sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1219 for (
int n=0; n<2; n++)
1221 if (!feo->dh()->el_is_local(element_id[n]))
continue;
1223 for (
unsigned int i=0; i<n_dofs[n]; i++)
1224 for (
int m=0; m<2; m++)
1225 for (
unsigned int j=0; j<n_dofs[m]; j++)
1226 local_matrix[(i+n*n_dofs[0])*(n_dofs[0]+n_dofs[1]) + m*n_dofs[0] + j] +=
1227 comm_flux[m][n]*fv_sb[m]->shape_value(j,k)*fv_sb[n]->shape_value(i,k);
1230 ls[sbi]->mat_set_values(n_dofs[0]+n_dofs[1], side_dof_indices, n_dofs[0]+n_dofs[1], side_dof_indices, local_matrix);
1241 template<
class Model>
1245 Model::balance_->start_flux_assembly(Model::subst_idx);
1246 set_boundary_conditions<1>();
1247 set_boundary_conditions<2>();
1248 set_boundary_conditions<3>();
1249 Model::balance_->finish_flux_assembly(Model::subst_idx);
1254 template<
class Model>
1255 template<
unsigned int dim>
1258 FESideValues<dim,3> fe_values_side(*feo->mapping<dim>(), *feo->q<dim-1>(), *feo->fe<dim>(),
1262 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size();
1264 double local_rhs[ndofs];
1266 PetscScalar local_flux_balance_rhs;
1270 bc_ref_values(qsize);
1274 for (
auto cell : feo->dh()->own_range() )
1276 if (cell.elm()->boundary_idx_ ==
nullptr)
continue;
1278 for (
unsigned int si=0; si<cell.elm()->n_sides(); si++)
1281 if (edg->
n_sides > 1)
continue;
1283 if (edg->
side(0)->
cond() == NULL)
continue;
1286 if (edg->
side(0)->
dim() != dim-1)
continue;
1293 Model::get_bc_type(ele_acc, bc_type);
1295 fe_values_side.reinit(elm, side->
side_idx());
1296 fsv_rt.reinit(elm, side->
side_idx());
1297 calculate_velocity(elm, velocity, fsv_rt);
1299 Model::compute_advection_diffusion_coefficients(fe_values_side.point_list(), velocity, side->
element(), ad_coef, dif_coef);
1300 data_.cross_section.value_list(fe_values_side.point_list(), side->
element(), csection);
1302 auto dh_cell = feo->dh()->cell_accessor_from_element( side->
element().
idx() );
1303 dh_cell.get_dof_indices(side_dof_indices);
1305 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1307 fill_n(local_rhs, ndofs, 0);
1308 local_flux_balance_vector.assign(ndofs, 0);
1309 local_flux_balance_rhs = 0;
1313 data_.bc_dirichlet_value[sbi].value_list(fe_values_side.point_list(), ele_acc, bc_values);
1315 double side_flux = 0;
1316 for (
unsigned int k=0; k<qsize; k++)
1317 side_flux += arma::dot(ad_coef[sbi][k], fe_values_side.normal_vector(k))*fe_values_side.JxW(k);
1318 double transport_flux = side_flux/side->
measure();
1322 for (
unsigned int k=0; k<qsize; k++)
1324 double bc_term = -transport_flux*bc_values[k]*fe_values_side.JxW(k);
1325 for (
unsigned int i=0; i<ndofs; i++)
1326 local_rhs[i] += bc_term*fe_values_side.shape_value(i,k);
1328 for (
unsigned int i=0; i<ndofs; i++)
1329 local_flux_balance_rhs -= local_rhs[i];
1333 for (
unsigned int k=0; k<qsize; k++)
1335 double bc_term = gamma[sbi][side->
cond_idx()]*bc_values[k]*fe_values_side.JxW(k);
1336 arma::vec3 bc_grad = -bc_values[k]*fe_values_side.JxW(k)*dg_variant*(arma::trans(dif_coef[sbi][k])*fe_values_side.normal_vector(k));
1337 for (
unsigned int i=0; i<ndofs; i++)
1338 local_rhs[i] += bc_term*fe_values_side.shape_value(i,k)
1339 + arma::dot(bc_grad,fe_values_side.shape_grad(i,k));
1341 for (
unsigned int k=0; k<qsize; k++)
1343 for (
unsigned int i=0; i<ndofs; i++)
1345 local_flux_balance_vector[i] += (arma::dot(ad_coef[sbi][k], fe_values_side.normal_vector(k))*fe_values_side.shape_value(i,k)
1346 - arma::dot(dif_coef[sbi][k]*fe_values_side.shape_grad(i,k),fe_values_side.normal_vector(k))
1347 + gamma[sbi][side->
cond_idx()]*fe_values_side.shape_value(i,k))*fe_values_side.JxW(k);
1350 if (Model::time_->tlevel() > 0)
1351 for (
unsigned int i=0; i<ndofs; i++)
1352 local_flux_balance_rhs -= local_rhs[i];
1356 Model::get_flux_bc_data(sbi, fe_values_side.point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1357 for (
unsigned int k=0; k<qsize; k++)
1359 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.JxW(k);
1360 for (
unsigned int i=0; i<ndofs; i++)
1361 local_rhs[i] += bc_term*fe_values_side.shape_value(i,k);
1364 for (
unsigned int i=0; i<ndofs; i++)
1366 for (
unsigned int k=0; k<qsize; k++)
1367 local_flux_balance_vector[i] += csection[k]*bc_sigma[k]*fe_values_side.JxW(k)*fe_values_side.shape_value(i,k);
1368 local_flux_balance_rhs -= local_rhs[i];
1373 Model::get_flux_bc_data(sbi, fe_values_side.point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1374 for (
unsigned int k=0; k<qsize; k++)
1376 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.JxW(k);
1377 for (
unsigned int i=0; i<ndofs; i++)
1378 local_rhs[i] += bc_term*fe_values_side.shape_value(i,k);
1381 for (
unsigned int i=0; i<ndofs; i++)
1383 for (
unsigned int k=0; k<qsize; k++)
1384 local_flux_balance_vector[i] += csection[k]*(arma::dot(ad_coef[sbi][k], fe_values_side.normal_vector(k)) + bc_sigma[k])*fe_values_side.JxW(k)*fe_values_side.shape_value(i,k);
1385 local_flux_balance_rhs -= local_rhs[i];
1390 for (
unsigned int k=0; k<qsize; k++)
1392 for (
unsigned int i=0; i<ndofs; i++)
1393 local_flux_balance_vector[i] += arma::dot(ad_coef[sbi][k], fe_values_side.normal_vector(k))*fe_values_side.JxW(k)*fe_values_side.shape_value(i,k);
1396 ls[sbi]->rhs_set_values(ndofs, &(side_dof_indices[0]), local_rhs);
1398 Model::balance_->add_flux_matrix_values(Model::subst_idx[sbi], side, side_dof_indices, local_flux_balance_vector);
1399 Model::balance_->add_flux_vec_value(Model::subst_idx[sbi], side, local_flux_balance_rhs);
1407 template<
class Model>
1408 template<
unsigned int dim>
1413 OLD_ASSERT(cell->
dim() == dim,
"Element dimension mismatch!");
1417 for (
unsigned int k=0; k<fv.
n_points(); k++)
1419 velocity[k].zeros();
1420 for (
unsigned int sid=0; sid<cell->
n_sides(); sid++)
1421 for (
unsigned int c=0; c<3; ++c)
1430 double h_max = 0, h_min = numeric_limits<double>::infinity();
1431 for (
unsigned int i=0; i<e->
n_nodes(); i++)
1432 for (
unsigned int j=i+1; j<e->
n_nodes(); j++)
1442 template<
class Model>
1451 const double alpha1,
1452 const double alpha2,
1455 double &transport_flux)
1459 double local_alpha = 0;
1471 for (
unsigned int i=0; i<s->
n_nodes(); i++)
1472 for (
unsigned int j=i+1; j<s->
n_nodes(); j++)
1473 h = max(h, s->
node(i)->distance(*s->
node(j).node()));
1481 double pflux = 0, nflux = 0;
1482 for (
int i=0; i<edg.
n_sides; i++)
1491 if (fluxes[s2] > 0 && fluxes[s1] < 0 && s1 < s2)
1492 transport_flux = fluxes[s1]*fabs(fluxes[s2]/pflux);
1493 else if (fluxes[s2] < 0 && fluxes[s1] > 0 && s1 < s2)
1494 transport_flux = fluxes[s1]*fabs(fluxes[s2]/nflux);
1496 transport_flux = fluxes[s1];
1500 gamma = 0.5*fabs(transport_flux);
1504 local_alpha = max(alpha1, alpha2);
1512 for (
int k=0; k<K_size; k++)
1513 delta[0] += dot(K1[k]*normal_vector,normal_vector);
1516 gamma += local_alpha/h*aniso1*aniso2*delta[0];
1522 for (
int k=0; k<K_size; k++)
1524 delta[0] += dot(K1[k]*normal_vector,normal_vector);
1525 delta[1] += dot(K2[k]*normal_vector,normal_vector);
1530 double delta_sum = delta[0] + delta[1];
1533 if (fabs(delta_sum) > 0)
1535 omega[0] = delta[1]/delta_sum;
1536 omega[1] = delta[0]/delta_sum;
1537 gamma += local_alpha/h*aniso1*aniso2*(delta[0]*delta[1]/delta_sum);
1540 for (
int i=0; i<2; i++) omega[i] = 0;
1549 template<
class Model>
1558 double delta = 0, h = 0;
1561 if (side->
dim() == 0)
1567 for (
unsigned int i=0; i<side->
n_nodes(); i++)
1568 for (
unsigned int j=i+1; j<side->
n_nodes(); j++)
1569 h = max(h, side->
node(i)->distance( *side->
node(j).node() ));
1573 for (
int k=0; k<K_size; k++)
1574 delta += dot(K[k]*normal_vector,normal_vector);
1584 template<
class Model>
1588 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1589 ls[sbi]->start_allocation();
1590 prepare_initial_condition<1>();
1591 prepare_initial_condition<2>();
1592 prepare_initial_condition<3>();
1594 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1595 ls[sbi]->start_add_assembly();
1596 prepare_initial_condition<1>();
1597 prepare_initial_condition<2>();
1598 prepare_initial_condition<3>();
1600 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1602 ls[sbi]->finish_assembly();
1608 template<
class Model>
1609 template<
unsigned int dim>
1612 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
1614 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
1616 double matrix[ndofs*ndofs], rhs[ndofs];
1619 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1620 init_values[sbi].resize(qsize);
1622 for (
auto cell : feo->dh()->own_range() )
1624 if (cell.dim() != dim)
continue;
1627 cell.get_dof_indices(dof_indices);
1630 Model::compute_init_cond(fe_values.
point_list(), elem, init_values);
1632 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1634 for (
unsigned int i=0; i<ndofs; i++)
1637 for (
unsigned int j=0; j<ndofs; j++)
1638 matrix[i*ndofs+j] = 0;
1641 for (
unsigned int k=0; k<qsize; k++)
1643 double rhs_term = init_values[sbi][k]*fe_values.
JxW(k);
1645 for (
unsigned int i=0; i<ndofs; i++)
1647 for (
unsigned int j=0; j<ndofs; j++)
1653 ls[sbi]->set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), matrix, rhs);
1659 template<
class Model>
1662 el_4_loc = Model::mesh_->get_el_4_loc();
1663 el_ds = Model::mesh_->get_el_ds();
1667 template<
class Model>
1670 if (solution_changed)
1672 unsigned int i_cell=0;
1673 for (
auto cell : feo->dh()->own_range() )
1676 unsigned int n_dofs;
1680 n_dofs = feo->fe<1>()->n_dofs();
1683 n_dofs = feo->fe<2>()->n_dofs();
1686 n_dofs = feo->fe<3>()->n_dofs();
1691 cell.get_dof_indices(dof_indices);
1693 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1695 double old_average = 0;
1696 for (
unsigned int j=0; j<n_dofs; ++j)
1697 old_average += ls[sbi]->get_solution_array()[dof_indices[j]-feo->dh()->distr()->begin()];
1698 old_average /= n_dofs;
1700 for (
unsigned int j=0; j<n_dofs; ++j)
1701 ls[sbi]->get_solution_array()[dof_indices[j]-feo->dh()->distr()->begin()] += solution_elem_[sbi][i_cell] - old_average;
1707 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1708 MatMult(*(ls_dt[sbi]->get_matrix()), ls[sbi]->get_solution(), mass_vec[sbi]);
1711 template<
class Model>
1714 return Model::mesh_->get_row_4_el();