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());
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)));
263 ret_coef.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++)
276 for (
int sd=0; sd<max_edg_sides; sd++)
280 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
291 unsigned int output_vector_size= (rank==0)?
feo->
dh()->n_global_dofs():0;
292 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
298 data_.output_field.set_components(Model::substances_.names());
299 data_.output_field.set_mesh(*Model::mesh_);
302 data_.output_field.setup_components();
303 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
307 output_field_ptr->set_fe_data(
feo->
dh()->sequential(), 0, &
output_vec[sbi]);
308 data_.output_field[sbi].set_field(Model::mesh_->region_db().get_region_set(
"ALL"), output_field_ptr, 0);
315 std::string petsc_default_opts;
316 if (
feo->
dh()->distr()->np() == 1)
317 petsc_default_opts =
"-ksp_type bcgs -pc_type ilu -pc_factor_levels 2 -ksp_diagonal_scale_fix -pc_factor_fill 6.0";
319 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";
322 ls =
new LinSys*[Model::n_substances()];
327 mass_matrix.resize(Model::n_substances(),
nullptr);
328 rhs.resize(Model::n_substances(),
nullptr);
329 mass_vec.resize(Model::n_substances(),
nullptr);
330 ret_vec.resize(Model::n_substances(),
nullptr);
332 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++) {
339 solution_elem_[sbi] =
new double[Model::mesh_->get_el_ds()->lsize()];
346 Model::balance_->allocate(
feo->
dh()->distr()->lsize(),
347 max(
feo->
fe<1>()->n_dofs(), max(
feo->
fe<2>()->n_dofs(),
feo->
fe<3>()->n_dofs())));
352 template<
class Model>
357 if (
gamma.size() > 0) {
360 for (
unsigned int i=0; i<Model::n_substances(); i++)
392 template<
class Model>
395 VecScatter output_scatter;
396 VecScatterCreateToZero(
ls[0]->
get_solution(), &output_scatter, PETSC_NULL);
397 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
400 VecScatterBegin(output_scatter,
ls[sbi]->
get_solution(), (
output_vec[sbi]).petsc_vec(), INSERT_VALUES, SCATTER_FORWARD);
401 VecScatterEnd(output_scatter,
ls[sbi]->
get_solution(), (
output_vec[sbi]).petsc_vec(), INSERT_VALUES, SCATTER_FORWARD);
403 chkerr(VecScatterDestroy(&(output_scatter)));
409 template<
class Model>
413 data_.mark_input_times( *(Model::time_) );
415 std::stringstream ss;
423 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++)
430 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
432 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
442 template<
class Model>
446 for (
unsigned int i=0; i<Model::n_substances(); i++)
462 for (
unsigned int i=0; i<Model::n_substances(); i++)
473 template<
class Model>
478 Model::time_->next_time();
479 Model::time_->view(
"TDG");
488 for (
unsigned int i=0; i<Model::n_substances(); i++)
495 for (
unsigned int i=0; i<Model::n_substances(); i++)
505 MatConvert(*(
ls_dt[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
mass_matrix[i]);
508 MatCopy(*(
ls_dt[i]->get_matrix() ),
mass_matrix[i], DIFFERENT_NONZERO_PATTERN);
515 || Model::flux_changed)
519 for (
unsigned int i=0; i<Model::n_substances(); i++)
525 for (
unsigned int i=0; i<Model::n_substances(); i++)
530 MatConvert(*(
ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
stiffness_matrix[i]);
539 || Model::flux_changed)
541 for (
unsigned int i=0; i<Model::n_substances(); i++)
548 for (
unsigned int i=0; i<Model::n_substances(); i++)
552 if (
rhs[i] ==
nullptr) VecDuplicate(*(
ls[i]->get_rhs() ), &
rhs[i]);
553 VecCopy(*(
ls[i]->get_rhs() ),
rhs[i]);
557 Model::flux_changed =
false;
578 for (
unsigned int i=0; i<Model::n_substances(); i++)
581 MatAXPY(m, 1./Model::time_->dt(),
mass_matrix[i], SUBSET_NONZERO_PATTERN);
584 VecDuplicate(
rhs[i], &w);
585 VecWAXPY(w, 1./Model::time_->dt(),
mass_vec[i],
rhs[i]);
604 template<
class Model>
608 unsigned int i_cell=0;
609 for (
auto cell :
feo->
dh()->own_range() )
616 n_dofs =
feo->
fe<1>()->n_dofs();
619 n_dofs =
feo->
fe<2>()->n_dofs();
622 n_dofs =
feo->
fe<3>()->n_dofs();
627 cell.get_dof_indices(dof_indices);
629 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
633 for (
unsigned int j=0; j<n_dofs; ++j)
634 solution_elem_[sbi][i_cell] +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
645 template<
class Model>
659 Model::output_data();
662 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
663 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
664 Model::balance_->output();
671 template<
class Model>
674 if (Model::balance_->cumulative())
676 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
678 Model::balance_->calculate_cumulative(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
690 template<
class Model>
694 Model::balance_->start_mass_assembly(Model::subst_idx);
695 assemble_mass_matrix<1>();
696 assemble_mass_matrix<2>();
697 assemble_mass_matrix<3>();
698 Model::balance_->finish_mass_assembly(Model::subst_idx);
703 template<
class Model>
template<
unsigned int dim>
707 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
709 PetscScalar local_mass_matrix[ndofs*ndofs], local_retardation_balance_vector[ndofs];
713 for (
auto cell :
feo->
dh()->own_range() )
715 if (cell.dim() != dim)
continue;
719 cell.get_dof_indices(dof_indices);
724 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
727 for (
unsigned int i=0; i<ndofs; i++)
729 for (
unsigned int j=0; j<ndofs; j++)
731 local_mass_matrix[i*ndofs+j] = 0;
732 for (
unsigned int k=0; k<qsize; k++)
737 for (
unsigned int i=0; i<ndofs; i++)
739 local_mass_balance_vector[i] = 0;
740 local_retardation_balance_vector[i] = 0;
741 for (
unsigned int k=0; k<qsize; k++)
748 Model::balance_->add_mass_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_mass_balance_vector);
749 ls_dt[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_mass_matrix);
750 VecSetValues(
ret_vec[sbi], ndofs, &(dof_indices[0]), local_retardation_balance_vector, ADD_VALUES);
758 template<
class Model>
763 assemble_volume_integrals<1>();
764 assemble_volume_integrals<2>();
765 assemble_volume_integrals<3>();
769 assemble_fluxes_boundary<1>();
770 assemble_fluxes_boundary<2>();
771 assemble_fluxes_boundary<3>();
775 assemble_fluxes_element_element<1>();
776 assemble_fluxes_element_element<2>();
777 assemble_fluxes_element_element<3>();
781 assemble_fluxes_element_side<1>();
782 assemble_fluxes_element_side<2>();
783 assemble_fluxes_element_side<3>();
790 template<
class Model>
791 template<
unsigned int dim>
798 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
802 PetscScalar local_matrix[ndofs*ndofs];
805 for (
auto cell :
feo->
dh()->own_range() )
807 if (cell.dim() != dim)
continue;
812 cell.get_dof_indices(dof_indices);
816 Model::compute_sources_sigma(fe_values.
point_list(), elm, sources_sigma);
819 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
821 for (
unsigned int i=0; i<ndofs; i++)
822 for (
unsigned int j=0; j<ndofs; j++)
823 local_matrix[i*ndofs+j] = 0;
825 for (
unsigned int k=0; k<qsize; k++)
827 for (
unsigned int i=0; i<ndofs; i++)
830 double ad_dot_grad_i = arma::dot(ad_coef[sbi][k], fe_values.
shape_grad(i,k));
832 for (
unsigned int j=0; j<ndofs; j++)
833 local_matrix[i*ndofs+j] += (arma::dot(Kt_grad_i, fe_values.
shape_grad(j,k))
838 ls[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_matrix);
844 template<
class Model>
848 Model::balance_->start_source_assembly(Model::subst_idx);
852 Model::balance_->finish_source_assembly(Model::subst_idx);
856 template<
class Model>
857 template<
unsigned int dim>
862 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
867 PetscScalar local_rhs[ndofs];
872 for (
auto cell :
feo->
dh()->own_range() )
874 if (cell.dim() != dim)
continue;
878 cell.get_dof_indices(dof_indices);
880 Model::compute_source_coefficients(fe_values.
point_list(), elm, sources_conc, sources_density, sources_sigma);
883 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
885 fill_n(local_rhs, ndofs, 0);
886 local_source_balance_vector.assign(ndofs, 0);
887 local_source_balance_rhs.assign(ndofs, 0);
890 for (
unsigned int k=0; k<qsize; k++)
892 source = (sources_density[sbi][k] + sources_conc[sbi][k]*sources_sigma[sbi][k])*fe_values.
JxW(k);
894 for (
unsigned int i=0; i<ndofs; i++)
899 for (
unsigned int i=0; i<ndofs; i++)
901 for (
unsigned int k=0; k<qsize; k++)
902 local_source_balance_vector[i] -= sources_sigma[sbi][k]*fe_values.
shape_value(i,k)*fe_values.
JxW(k);
904 local_source_balance_rhs[i] += local_rhs[i];
906 Model::balance_->add_source_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_source_balance_vector);
907 Model::balance_->add_source_vec_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_source_balance_rhs);
914 template<
class Model>
915 template<
unsigned int dim>
921 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size(),
924 PetscScalar local_matrix[ndofs*ndofs];
927 double gamma_l, omega[2], transport_flux;
929 for (
unsigned int sid=0; sid<n_max_sides; sid++)
937 for (
unsigned int iedg=0; iedg<
feo->
dh()->n_loc_edges(); iedg++)
939 Edge *edg = &Model::mesh_->edges[
feo->
dh()->edge_index(iedg)];
942 for (
int sid=0; sid<edg->
n_sides; sid++)
946 dh_cell.get_dof_indices(side_dof_indices[sid]);
947 fe_values[sid]->reinit(cell, edg->
side(sid)->
side_idx());
950 Model::compute_advection_diffusion_coefficients(fe_values[sid]->point_list(), side_velocity[sid], cell,
ad_coef_edg[sid],
dif_coef_edg[sid]);
951 dg_penalty[sid].resize(Model::n_substances());
952 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
957 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
960 for (
int sid=0; sid<edg->
n_sides; sid++)
963 for (
unsigned int k=0; k<qsize; k++)
964 fluxes[sid] += arma::dot(
ad_coef_edg[sid][sbi][k], fe_values[sid]->normal_vector(k))*fe_values[sid]->JxW(k);
968 for (
int s1=0; s1<edg->
n_sides; s1++)
970 for (
int s2=s1+1; s2<edg->
n_sides; s2++)
976 arma::vec3 nv = fe_values[s1]->normal_vector(0);
979 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);
985 #define AVERAGE(i,k,side_id) (fe_values[sd[side_id]]->shape_value(i,k)*0.5) 986 #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]) 987 #define JUMP(i,k,side_id) ((side_id==0?1:-1)*fe_values[sd[side_id]]->shape_value(i,k)) 990 for (
int n=0; n<2; n++)
994 for (
int m=0; m<2; m++)
996 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
997 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
998 local_matrix[i*fe_values[sd[m]]->n_dofs()+j] = 0;
1000 for (
unsigned int k=0; k<qsize; k++)
1002 double flux_times_JxW = transport_flux*fe_values[0]->JxW(k);
1003 double gamma_times_JxW = gamma_l*fe_values[0]->JxW(k);
1005 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1007 double flux_JxW_jump_i = flux_times_JxW*
JUMP(i,k,n);
1008 double gamma_JxW_jump_i = gamma_times_JxW*
JUMP(i,k,n);
1009 double JxW_jump_i = fe_values[0]->JxW(k)*
JUMP(i,k,n);
1012 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1014 int index = i*fe_values[sd[m]]->n_dofs()+j;
1017 local_matrix[index] += flux_JxW_jump_i*
AVERAGE(j,k,m);
1020 local_matrix[index] += gamma_JxW_jump_i*
JUMP(j,k,m);
1023 local_matrix[index] -=
WAVERAGE(j,k,m)*JxW_jump_i;
1024 local_matrix[index] -=
JUMP(j,k,m)*JxW_var_wavg_i;
1028 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);
1039 for (
unsigned int i=0; i<n_max_sides; i++)
1041 delete fe_values[i];
1046 template<
class Model>
1047 template<
unsigned int dim>
1054 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1056 PetscScalar local_matrix[ndofs*ndofs];
1063 for (
unsigned int iedg=0; iedg<
feo->
dh()->n_loc_edges(); iedg++)
1065 Edge *edg = &Model::mesh_->edges[
feo->
dh()->edge_index(iedg)];
1066 if (edg->
n_sides > 1)
continue;
1068 if (edg->
side(0)->
dim() != dim-1)
continue;
1070 if (edg->
side(0)->
cond() == NULL)
continue;
1073 auto cell =
feo->
dh()->cell_accessor_from_element( side->
element().
idx() );
1075 cell.get_dof_indices(side_dof_indices);
1080 Model::compute_advection_diffusion_coefficients(fe_values_side.
point_list(), side_velocity, elm_acc,
ad_coef,
dif_coef);
1083 data_.cross_section.value_list(fe_values_side.
point_list(), elm_acc, csection);
1085 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1087 for (
unsigned int i=0; i<ndofs; i++)
1088 for (
unsigned int j=0; j<ndofs; j++)
1089 local_matrix[i*ndofs+j] = 0;
1093 double side_flux = 0;
1094 for (
unsigned int k=0; k<qsize; k++)
1095 side_flux += arma::dot(ad_coef[sbi][k], fe_values_side.
normal_vector(k))*fe_values_side.
JxW(k);
1096 double transport_flux = side_flux/side->
measure();
1103 transport_flux += gamma_l;
1107 for (
unsigned int k=0; k<qsize; k++)
1109 double flux_times_JxW;
1113 flux_times_JxW = csection[k]*robin_sigma[k]*fe_values_side.
JxW(k);
1118 flux_times_JxW = (transport_flux + csection[k]*robin_sigma[k])*fe_values_side.
JxW(k);
1123 flux_times_JxW = transport_flux*fe_values_side.
JxW(k);
1125 for (
unsigned int i=0; i<ndofs; i++)
1127 for (
unsigned int j=0; j<ndofs; j++)
1130 local_matrix[i*ndofs+j] += flux_times_JxW*fe_values_side.
shape_value(i,k)*fe_values_side.
shape_value(j,k);
1136 )*fe_values_side.
JxW(k);
1141 ls[sbi]->
mat_set_values(ndofs, &(side_dof_indices[0]), ndofs, &(side_dof_indices[0]), local_matrix);
1147 template<
class Model>
1148 template<
unsigned int dim>
1152 if (dim == 1)
return;
1163 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs();
1164 const unsigned int qsize =
feo->
q<dim-1>()->size();
1165 int side_dof_indices[2*ndofs];
1167 unsigned int n_dofs[2], n_indices;
1171 PetscScalar local_matrix[4*ndofs*ndofs];
1172 double comm_flux[2][2];
1176 fv_sb[0] = &fe_values_vb;
1177 fv_sb[1] = &fe_values_side;
1180 for (
unsigned int inb=0; inb<
feo->
dh()->n_loc_nb(); inb++)
1182 Neighbour *nb = &Model::mesh_->vb_neighbours_[
feo->
dh()->nb_index(inb)];
1186 auto dh_cell_sub =
feo->
dh()->cell_accessor_from_element( nb->
element().
idx() );
1188 n_indices = dh_cell_sub.get_dof_indices(indices);
1189 for(
unsigned int i=0; i<n_indices; ++i) {
1190 side_dof_indices[i] = indices[i];
1192 fe_values_vb.
reinit(cell_sub);
1193 n_dofs[0] = fv_sb[0]->n_dofs();
1197 n_indices = dh_cell.get_dof_indices(indices);
1198 for(
unsigned int i=0; i<n_indices; ++i) {
1199 side_dof_indices[i+n_dofs[0]] = indices[i];
1202 n_dofs[1] = fv_sb[1]->n_dofs();
1206 element_id[0] = cell_sub.
idx();
1207 element_id[1] = cell.
idx();
1214 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_higher, cell, ad_coef_edg[1],
dif_coef_edg[1]);
1215 data_.cross_section.value_list(fe_values_vb.
point_list(), cell_sub, csection_lower);
1216 data_.cross_section.value_list(fe_values_vb.
point_list(), cell, csection_higher);
1218 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1220 for (
unsigned int i=0; i<n_dofs[0]+n_dofs[1]; i++)
1221 for (
unsigned int j=0; j<n_dofs[0]+n_dofs[1]; j++)
1222 local_matrix[i*(n_dofs[0]+n_dofs[1])+j] = 0;
1227 for (
unsigned int k=0; k<qsize; k++)
1238 2*csection_higher[k]*csection_higher[k]/(csection_lower[k]*csection_lower[k]);
1240 double transport_flux = arma::dot(ad_coef_edg[1][sbi][k], fe_values_side.
normal_vector(k));
1242 comm_flux[0][0] = (sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1243 comm_flux[0][1] = -(sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1244 comm_flux[1][0] = -(sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1245 comm_flux[1][1] = (sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1247 for (
int n=0; n<2; n++)
1249 if (!
feo->
dh()->el_is_local(element_id[n]))
continue;
1251 for (
unsigned int i=0; i<n_dofs[n]; i++)
1252 for (
int m=0; m<2; m++)
1253 for (
unsigned int j=0; j<n_dofs[m]; j++)
1254 local_matrix[(i+n*n_dofs[0])*(n_dofs[0]+n_dofs[1]) + m*n_dofs[0] + j] +=
1255 comm_flux[m][n]*fv_sb[m]->shape_value(j,k)*fv_sb[n]->shape_value(i,k);
1258 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);
1269 template<
class Model>
1273 Model::balance_->start_flux_assembly(Model::subst_idx);
1274 set_boundary_conditions<1>();
1275 set_boundary_conditions<2>();
1276 set_boundary_conditions<3>();
1277 Model::balance_->finish_flux_assembly(Model::subst_idx);
1282 template<
class Model>
1283 template<
unsigned int dim>
1290 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1292 unsigned int loc_b=0;
1293 double local_rhs[ndofs];
1295 PetscScalar local_flux_balance_rhs;
1299 bc_ref_values(qsize);
1303 for (
auto cell :
feo->
dh()->own_range() )
1305 if (cell.elm()->boundary_idx_ ==
nullptr)
continue;
1307 for (
unsigned int si=0; si<cell.elm()->n_sides(); si++)
1310 if (edg->
n_sides > 1)
continue;
1312 if (edg->
side(0)->
cond() == NULL)
continue;
1314 if (edg->
side(0)->
dim() != dim-1)
1316 if (edg->
side(0)->
cond() !=
nullptr) ++loc_b;
1325 Model::get_bc_type(ele_acc, bc_type);
1334 auto dh_cell =
feo->
dh()->cell_accessor_from_element( side->
element().
idx() );
1335 dh_cell.get_dof_indices(side_dof_indices);
1337 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1339 fill_n(local_rhs, ndofs, 0);
1340 local_flux_balance_vector.assign(ndofs, 0);
1341 local_flux_balance_rhs = 0;
1345 data_.bc_dirichlet_value[sbi].value_list(fe_values_side.
point_list(), ele_acc, bc_values);
1347 double side_flux = 0;
1348 for (
unsigned int k=0; k<qsize; k++)
1350 double transport_flux = side_flux/side->
measure();
1354 for (
unsigned int k=0; k<qsize; k++)
1356 double bc_term = -transport_flux*bc_values[k]*fe_values_side.
JxW(k);
1357 for (
unsigned int i=0; i<ndofs; i++)
1358 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1360 for (
unsigned int i=0; i<ndofs; i++)
1361 local_flux_balance_rhs -= local_rhs[i];
1365 for (
unsigned int k=0; k<qsize; k++)
1367 double bc_term =
gamma[sbi][side->
cond_idx()]*bc_values[k]*fe_values_side.
JxW(k);
1369 for (
unsigned int i=0; i<ndofs; i++)
1370 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k)
1371 + arma::dot(bc_grad,fe_values_side.
shape_grad(i,k));
1373 for (
unsigned int k=0; k<qsize; k++)
1375 for (
unsigned int i=0; i<ndofs; i++)
1382 if (Model::time_->tlevel() > 0)
1383 for (
unsigned int i=0; i<ndofs; i++)
1384 local_flux_balance_rhs -= local_rhs[i];
1388 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1389 for (
unsigned int k=0; k<qsize; k++)
1391 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1392 for (
unsigned int i=0; i<ndofs; i++)
1393 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1396 for (
unsigned int i=0; i<ndofs; i++)
1398 for (
unsigned int k=0; k<qsize; k++)
1399 local_flux_balance_vector[i] += csection[k]*bc_sigma[k]*fe_values_side.
JxW(k)*fe_values_side.
shape_value(i,k);
1400 local_flux_balance_rhs -= local_rhs[i];
1405 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1406 for (
unsigned int k=0; k<qsize; k++)
1408 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1409 for (
unsigned int i=0; i<ndofs; i++)
1410 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1413 for (
unsigned int i=0; i<ndofs; i++)
1415 for (
unsigned int k=0; k<qsize; k++)
1416 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);
1417 local_flux_balance_rhs -= local_rhs[i];
1422 for (
unsigned int k=0; k<qsize; k++)
1424 for (
unsigned int i=0; i<ndofs; i++)
1430 Model::balance_->add_flux_matrix_values(Model::subst_idx[sbi], loc_b, side_dof_indices, local_flux_balance_vector);
1431 Model::balance_->add_flux_vec_value(Model::subst_idx[sbi], loc_b, local_flux_balance_rhs);
1440 template<
class Model>
1441 template<
unsigned int dim>
1446 OLD_ASSERT(cell->
dim() == dim,
"Element dimension mismatch!");
1450 for (
unsigned int k=0; k<fv.
n_points(); k++)
1452 velocity[k].zeros();
1453 for (
unsigned int sid=0; sid<cell->
n_sides(); sid++)
1454 for (
unsigned int c=0; c<3; ++c)
1463 double h_max = 0, h_min = numeric_limits<double>::infinity();
1464 for (
unsigned int i=0; i<e->
n_nodes(); i++)
1465 for (
unsigned int j=i+1; j<e->
n_nodes(); j++)
1475 template<
class Model>
1484 const double alpha1,
1485 const double alpha2,
1488 double &transport_flux)
1492 double local_alpha = 0;
1504 for (
unsigned int i=0; i<s->n_nodes(); i++)
1505 for (
unsigned int j=i+1; j<s->n_nodes(); j++)
1506 h = max(h, s->node(i)->distance(*s->node(j).node()));
1514 double pflux = 0, nflux = 0;
1515 for (
int i=0; i<edg.
n_sides; i++)
1524 if (fluxes[s2] > 0 && fluxes[s1] < 0 && s1 < s2)
1525 transport_flux = fluxes[s1]*fabs(fluxes[s2]/pflux);
1526 else if (fluxes[s2] < 0 && fluxes[s1] > 0 && s1 < s2)
1527 transport_flux = fluxes[s1]*fabs(fluxes[s2]/nflux);
1529 transport_flux = fluxes[s1];
1533 gamma = 0.5*fabs(transport_flux);
1537 local_alpha = max(alpha1, alpha2);
1545 for (
int k=0; k<K_size; k++)
1546 delta[0] += dot(K1[k]*normal_vector,normal_vector);
1549 gamma += local_alpha/h*aniso1*aniso2*delta[0];
1555 for (
int k=0; k<K_size; k++)
1557 delta[0] += dot(K1[k]*normal_vector,normal_vector);
1558 delta[1] += dot(K2[k]*normal_vector,normal_vector);
1563 double delta_sum = delta[0] + delta[1];
1566 if (fabs(delta_sum) > 0)
1568 omega[0] = delta[1]/delta_sum;
1569 omega[1] = delta[0]/delta_sum;
1570 gamma += local_alpha/h*aniso1*aniso2*(delta[0]*delta[1]/delta_sum);
1573 for (
int i=0; i<2; i++) omega[i] = 0;
1582 template<
class Model>
1591 double delta = 0, h = 0;
1594 if (side->
dim() == 0)
1600 for (
unsigned int i=0; i<side->
n_nodes(); i++)
1601 for (
unsigned int j=i+1; j<side->
n_nodes(); j++)
1602 h = max(h, side->
node(i)->distance( *side->
node(j).node() ));
1606 for (
int k=0; k<K_size; k++)
1607 delta += dot(K[k]*normal_vector,normal_vector);
1617 template<
class Model>
1621 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1622 ls[sbi]->start_allocation();
1623 prepare_initial_condition<1>();
1624 prepare_initial_condition<2>();
1625 prepare_initial_condition<3>();
1627 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1628 ls[sbi]->start_add_assembly();
1629 prepare_initial_condition<1>();
1630 prepare_initial_condition<2>();
1631 prepare_initial_condition<3>();
1633 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1641 template<
class Model>
1642 template<
unsigned int dim>
1647 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
1649 double matrix[ndofs*ndofs],
rhs[ndofs];
1652 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1653 init_values[sbi].resize(qsize);
1655 for (
auto cell :
feo->
dh()->own_range() )
1657 if (cell.dim() != dim)
continue;
1660 cell.get_dof_indices(dof_indices);
1663 Model::compute_init_cond(fe_values.
point_list(), elem, init_values);
1665 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1667 for (
unsigned int i=0; i<ndofs; i++)
1670 for (
unsigned int j=0; j<ndofs; j++)
1671 matrix[i*ndofs+j] = 0;
1674 for (
unsigned int k=0; k<qsize; k++)
1676 double rhs_term = init_values[sbi][k]*fe_values.
JxW(k);
1678 for (
unsigned int i=0; i<ndofs; i++)
1680 for (
unsigned int j=0; j<ndofs; j++)
1686 ls[sbi]->
set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), matrix, rhs);
1692 template<
class Model>
1695 el_4_loc = Model::mesh_->get_el_4_loc();
1696 el_ds = Model::mesh_->get_el_ds();
1700 template<
class Model>
1703 if (solution_changed)
1705 unsigned int i_cell=0;
1706 for (
auto cell :
feo->
dh()->own_range() )
1709 unsigned int n_dofs;
1713 n_dofs =
feo->
fe<1>()->n_dofs();
1716 n_dofs =
feo->
fe<2>()->n_dofs();
1719 n_dofs =
feo->
fe<3>()->n_dofs();
1724 cell.get_dof_indices(dof_indices);
1726 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1728 double old_average = 0;
1729 for (
unsigned int j=0; j<n_dofs; ++j)
1730 old_average +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
1731 old_average /= n_dofs;
1733 for (
unsigned int j=0; j<n_dofs; ++j)
1734 ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()] +=
solution_elem_[sbi][i_cell] - old_average;
1740 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1744 template<
class Model>
1747 return Model::mesh_->get_row_4_el();
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
const Edge * edge() const
Input::Record input_rec
Record with input specification.
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell...
double JxW(const unsigned int point_no)
Return the product of Jacobian determinant and the quadrature weight at given quadrature point...
static auto subdomain(Mesh &mesh) -> IndexField
void assemble_fluxes_element_element()
Assembles the fluxes between elements of the same dimension.
void set_sources()
Assembles the right hand side due to volume sources.
FiniteElement< dim > * fe()
void set_boundary_conditions()
Assembles the r.h.s. components corresponding to the Dirichlet boundary conditions.
void get_par_info(LongIdx *&el_4_loc, Distribution *&el_ds)
unsigned int n_nodes() const
Transformed quadrature weight for cell sides.
vector< double > mm_coef
Mass matrix coefficients.
void assemble_fluxes_element_side()
Assembles the fluxes between elements of different dimensions.
static constexpr Mask in_main_matrix
A field is part of main "stiffness matrix" of the equation.
void reinit(ElementAccessor< 3 > &cell, unsigned int sid)
Update cell-dependent data (gradients, Jacobians etc.)
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
unsigned int side_idx() const
void calculate_concentration_matrix()
Transport with dispersion implemented using discontinuous Galerkin method.
FieldCommon & flags_add(FieldFlag::Flags::Mask mask)
double distance(const Node &n2) const
void set_from_input(const Input::Record in_rec) override
virtual void start_add_assembly()
void assemble_mass_matrix()
Assembles the mass matrix.
void output(TimeStep step)
virtual PetscErrorCode mat_zero_entries()
vector< VectorMPI > output_vec
Array for storing the output solution data.
virtual void rhs_set_values(int nrow, int *rows, double *vals)=0
void update_solution() override
Computes the solution in one time instant.
int dg_variant
DG variant ((non-)symmetric/incomplete.
void prepare_initial_condition()
Assembles the auxiliary linear system to calculate the initial solution as L^2-projection of the pres...
Fields computed from the mesh data.
virtual void start_allocation()
void set_initial_condition()
Sets the initial condition.
Class FEValues calculates finite element data on the actual cells such as shape function values...
void chkerr(unsigned int ierr)
Replacement of new/delete operator in the spirit of xmalloc.
virtual void finish_assembly()=0
vector< vector< arma::vec3 > > ad_coef
Advection coefficients.
SideIter side(const unsigned int loc_index)
#define AVERAGE(i, k, side_id)
std::shared_ptr< DOFHandlerMultiDim > dh()
void assemble_stiffness_matrix()
Assembles the stiffness matrix.
vector< vector< vector< arma::mat33 > > > dif_coef_edg
Diffusion coefficients on edges.
Discontinuous Galerkin method for equation of transport with dispersion.
const Vec & get_solution(unsigned int sbi)
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
ElementAccessor< 3 > element() const
vector< double > ret_sources_prev
MultiField< 3, FieldValue< 3 >::Scalar > dg_penalty
Penalty enforcing inter-element continuity of solution (for each substance).
static const Input::Type::Selection & get_dg_variant_selection_input_type()
Input type for the DG variant selection.
unsigned int n_points()
Returns the number of quadrature points.
EquationOutput output_fields
std::vector< Mat > mass_matrix
The mass matrix.
void calculate_cumulative_balance()
void assemble_fluxes_boundary()
Assembles the fluxes on the boundary.
static constexpr bool value
Symmetric Gauss-Legendre quadrature formulae on simplices.
#define WAVERAGE(i, k, side_id)
TransportDG(Mesh &init_mesh, const Input::Record in_rec)
Constructor.
vector< vector< double > > ret_coef
Retardation coefficient due to sorption.
arma::vec::fixed< spacedim > centre() const
Computes the barycenter.
arma::vec::fixed< spacedim > normal_vector(unsigned int point_no)
Returns the normal vector to a side at given quadrature point.
ElementAccessor< 3 > element()
void initialize() override
vector< vector< vector< arma::vec3 > > > ad_coef_edg
Advection coefficients on edges.
Transformed quadrature points.
void output_data()
Postprocesses the solution and writes to output file.
virtual PetscErrorCode set_rhs(Vec &rhs)
MultiField< 3, FieldValue< 3 >::Scalar > fracture_sigma
Transition parameter for diffusive transfer on fractures (for each substance).
vector< vector< arma::mat33 > > dif_coef
Diffusion coefficients.
FEObjects * feo
Finite element objects.
static constexpr Mask in_time_term
A field is part of time term of the equation.
FieldCommon & input_default(const string &input_default)
const Vec & get_solution()
Raviart-Thomas element of order 0.
Definitions of basic Lagrangean finite elements with polynomial shape functions.
static constexpr Mask equation_external_output
Match an output field, that can be also copy of other field.
Field< 3, FieldValue< 3 >::Scalar > subdomain
unsigned int n_sides() const
static auto region_id(Mesh &mesh) -> IndexField
#define START_TIMER(tag)
Starts a timer with specified tag.
std::vector< Vec > rhs
Vector of right hand side.
Field< 3, FieldValue< 3 >::Scalar > region_id
double elem_anisotropy(ElementAccessor< 3 > e)
unsigned int dg_order
Polynomial order of finite elements.
void output_vector_gather()
static constexpr Mask in_rhs
A field is part of the right hand side of the equation.
Shape function gradients.
FLOW123D_FORCE_LINK_IN_CHILD(concentrationTransportModel)
void set_solution(double *sol_array)
NodeAccessor< 3 > node(unsigned int i) const
double shape_value(const unsigned int function_no, const unsigned int point_no)
Return the value of the function_no-th shape function at the point_no-th quadrature point...
virtual PetscErrorCode rhs_zero_entries()
Discontinuous Galerkin method for equation of transport with dispersion.
double ** solution_elem_
Element averages of solution (the array is passed to reactions in operator splitting).
std::vector< Mat > stiffness_matrix
The stiffness matrix.
FieldCommon & description(const string &description)
void set_values(int nrow, int *rows, int ncol, int *cols, PetscScalar *mat_vals, PetscScalar *rhs_vals)
Set values in the system matrix and values in the right-hand side vector on corresponding rows...
EqData data_
Field data for model parameters.
bool allocation_done
Indicates whether matrices have been preallocated.
unsigned int cond_idx() const
std::vector< std::vector< double > > gamma
Penalty parameters.
static const Input::Type::Record & get_input_type()
Declare input record type for the equation TransportDG.
void initialize(std::shared_ptr< OutputTime > stream, Mesh *mesh, Input::Record in_rec, const TimeGovernor &tg)
Discontinuous Galerkin method for equation of transport with dispersion.
void update_after_reactions(bool solution_changed)
MappingP1< dim, 3 > * mapping()
std::vector< Vec > ret_vec
Auxiliary vectors for calculation of sources in balance due to retardation (e.g. sorption).
double shape_value_component(const unsigned int function_no, const unsigned int point_no, const unsigned int comp) const
Return the value of the function_no-th shape function at the point_no-th quadrature point...
vector< double > ret_sources
Temporary values of increments due to retardation (e.g. sorption)
bool set_time(const TimeStep &time, LimitSide limit_side)
arma::vec::fixed< spacedim > shape_grad(const unsigned int function_no, const unsigned int point_no)
Return the gradient of the function_no-th shape function at the point_no-th quadrature point...
unsigned int bulk_idx() const
Returns index of the region in the bulk set.
Definitions of particular quadrature rules on simplices.
#define WarningOut()
Macro defining 'warning' record of log.
FieldCommon & name(const string &name)
virtual SolveInfo solve()=0
#define END_TIMER(tag)
Ends a timer with specified tag.
Discontinuous Galerkin method for equation of transport with dispersion.
void calculate_velocity(const ElementAccessor< 3 > &cell, std::vector< arma::vec3 > &velocity, FEValuesBase< dim, 3 > &fv)
Calculates the velocity field on a given dim dimensional cell.
vector< arma::vec::fixed< spacedim > > & point_list()
Return coordinates of all quadrature points in the actual cell system.
static const Input::Type::Record & get_input_type()
virtual PetscErrorCode set_matrix(Mat &matrix, MatStructure str)
std::vector< Vec > mass_vec
Mass from previous time instant (necessary when coefficients of mass matrix change in time)...
void assemble_volume_integrals()
Assembles the volume integrals into the stiffness matrix.
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
FieldCommon & flags(FieldFlag::Flags::Mask mask)
Base class for FEValues and FESideValues.
static UnitSI & dimensionless()
Returns dimensionless unit.
static bool print_message_table(ostream &stream, std::string equation_name)
~TransportDG()
Destructor.
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
LinSys ** ls
Linear algebra system for the transport equation.
FiniteElement< dim > * fe_rt()
void set_DG_parameters_edge(const Edge &edg, const int s1, const int s2, const int K_size, const std::vector< arma::mat33 > &K1, const std::vector< arma::mat33 > &K2, const std::vector< double > &fluxes, const arma::vec3 &normal_vector, const double alpha1, const double alpha2, double &gamma, double *omega, double &transport_flux)
Calculates the dispersivity (diffusivity) tensor from the velocity field.
SideIter side(const unsigned int i) const
LinSys ** ls_dt
Linear algebra system for the time derivative (actually it is used only for handling the matrix struc...
#define JUMP(i, k, side_id)
void set_DG_parameters_boundary(const SideIter side, const int K_size, const std::vector< arma::mat33 > &K, const double flux, const arma::vec3 &normal_vector, const double alpha, double &gamma)
Sets up parameters of the DG method on a given boundary edge.
Definitions of Raviart-Thomas finite elements.
ElementAccessor< 3 > element_accessor()
void zero_time_step() override
Initialize solution in the zero time.
FEObjects(Mesh *mesh_, unsigned int fe_order)
void reinit(ElementAccessor< 3 > &cell)
Update cell-dependent data (gradients, Jacobians etc.)
unsigned int n_nodes() const
Transformed quadrature weights.
Calculates finite element data on a side.
const Node * node(unsigned int ni) const