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++)
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++)
298 data_.output_field[sbi].set_field(Model::mesh_->region_db().get_region_set(
"ALL"), output_field_ptr, 0);
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()];
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++) {
329 solution_elem_[sbi] =
new double[Model::mesh_->get_el_ds()->lsize()];
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++)
382 template<
class Model>
386 data_.mark_input_times( *(Model::time_) );
388 std::stringstream ss;
396 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++)
403 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
405 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
415 template<
class Model>
419 for (
unsigned int i=0; i<Model::n_substances(); i++)
435 for (
unsigned int i=0; i<Model::n_substances(); i++)
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++)
468 for (
unsigned int i=0; i<Model::n_substances(); 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);
488 || Model::flux_changed)
492 for (
unsigned int i=0; i<Model::n_substances(); i++)
498 for (
unsigned int i=0; i<Model::n_substances(); i++)
503 MatConvert(*(
ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
stiffness_matrix[i]);
512 || Model::flux_changed)
514 for (
unsigned int i=0; i<Model::n_substances(); i++)
521 for (
unsigned int i=0; i<Model::n_substances(); i++)
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++)
554 MatAXPY(m, 1./Model::time_->dt(),
mass_matrix[i], SUBSET_NONZERO_PATTERN);
557 VecDuplicate(
rhs[i], &w);
558 VecWAXPY(w, 1./Model::time_->dt(),
mass_vec[i],
rhs[i]);
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)
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()];
618 template<
class Model>
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());
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;
691 cell.get_dof_indices(dof_indices);
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++)
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++)
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>
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()->local_range() )
779 if (!cell.is_own())
continue;
780 if (cell.dim() != dim)
continue;
785 cell.get_dof_indices(dof_indices);
789 Model::compute_sources_sigma(fe_values.
point_list(), elm, sources_sigma);
792 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
794 for (
unsigned int i=0; i<ndofs; i++)
795 for (
unsigned int j=0; j<ndofs; j++)
796 local_matrix[i*ndofs+j] = 0;
798 for (
unsigned int k=0; k<qsize; k++)
800 for (
unsigned int i=0; i<ndofs; i++)
803 double ad_dot_grad_i = arma::dot(ad_coef[sbi][k], fe_values.
shape_grad(i,k));
805 for (
unsigned int j=0; j<ndofs; j++)
806 local_matrix[i*ndofs+j] += (arma::dot(Kt_grad_i, fe_values.
shape_grad(j,k))
811 ls[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_matrix);
817 template<
class Model>
821 Model::balance_->start_source_assembly(Model::subst_idx);
825 Model::balance_->finish_source_assembly(Model::subst_idx);
829 template<
class Model>
830 template<
unsigned int dim>
835 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
840 PetscScalar local_rhs[ndofs];
845 for (
auto cell :
feo->
dh()->own_range() )
847 if (cell.dim() != dim)
continue;
851 cell.get_dof_indices(dof_indices);
853 Model::compute_source_coefficients(fe_values.
point_list(), elm, sources_conc, sources_density, sources_sigma);
856 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
858 fill_n(local_rhs, ndofs, 0);
859 local_source_balance_vector.assign(ndofs, 0);
860 local_source_balance_rhs.assign(ndofs, 0);
863 for (
unsigned int k=0; k<qsize; k++)
865 source = (sources_density[sbi][k] + sources_conc[sbi][k]*sources_sigma[sbi][k])*fe_values.
JxW(k);
867 for (
unsigned int i=0; i<ndofs; i++)
872 for (
unsigned int i=0; i<ndofs; i++)
874 for (
unsigned int k=0; k<qsize; k++)
875 local_source_balance_vector[i] -= sources_sigma[sbi][k]*fe_values.
shape_value(i,k)*fe_values.
JxW(k);
877 local_source_balance_rhs[i] += local_rhs[i];
879 Model::balance_->add_source_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_source_balance_vector);
880 Model::balance_->add_source_vec_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_source_balance_rhs);
890 double h_max = 0, h_min = numeric_limits<double>::infinity();
891 for (
unsigned int i=0; i<e->
n_nodes(); i++)
892 for (
unsigned int j=i+1; j<e->
n_nodes(); j++)
902 template<
class Model>
903 template<
unsigned int dim>
909 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size(),
912 PetscScalar local_matrix[ndofs*ndofs];
915 double gamma_l, omega[2], transport_flux, delta[2], delta_sum;
916 double aniso1, aniso2;
918 for (
unsigned int sid=0; sid<n_max_sides; sid++)
928 if (dh_cell.dim() != dim)
continue;
929 for(
DHCellSide cell_side : dh_cell.side_range() )
931 if (cell_side.n_edge_sides() < 2)
continue;
932 bool unique_edge = (cell_side.edge_sides().begin()->side()->element().idx() != dh_cell.elm_idx());
933 if ( unique_edge )
continue;
937 auto dh_edge_cell =
feo->
dh()->cell_accessor_from_element( edge_side.side()->elem_idx() );
939 dh_edge_cell.get_dof_indices(side_dof_indices[sid]);
940 fe_values[sid]->reinit(cell, edge_side.
side()->
side_idx());
943 Model::compute_advection_diffusion_coefficients(fe_values[sid]->point_list(), side_velocity[sid], cell,
ad_coef_edg[sid],
dif_coef_edg[sid]);
944 dg_penalty[sid].resize(Model::n_substances());
945 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
949 arma::vec3 normal_vector = fe_values[0]->normal_vector(0);
952 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
955 double pflux = 0, nflux = 0;
960 for (
unsigned int k=0; k<qsize; k++)
961 fluxes[sid] += arma::dot(
ad_coef_edg[sid][sbi][k], fe_values[sid]->normal_vector(k))*fe_values[sid]->JxW(k);
962 fluxes[sid] /= edge_side.side()->measure();
964 pflux += fluxes[sid];
966 nflux += fluxes[sid];
977 if (s2<=s1)
continue;
978 ASSERT(edge_side1.side()->valid()).error(
"Invalid side of edge.");
980 arma::vec3 nv = fe_values[s1]->normal_vector(0);
984 if (fluxes[s2] > 0 && fluxes[s1] < 0)
985 transport_flux = fluxes[s1]*fabs(fluxes[s2]/pflux);
986 else if (fluxes[s2] < 0 && fluxes[s1] > 0)
987 transport_flux = fluxes[s1]*fabs(fluxes[s2]/nflux);
991 gamma_l = 0.5*fabs(transport_flux);
995 for (
unsigned int k=0; k<qsize; k++)
997 delta[0] += dot(
dif_coef_edg[s1][sbi][k]*normal_vector,normal_vector);
998 delta[1] += dot(
dif_coef_edg[s2][sbi][k]*normal_vector,normal_vector);
1003 delta_sum = delta[0] + delta[1];
1006 if (fabs(delta_sum) > 0)
1008 omega[0] = delta[1]/delta_sum;
1009 omega[1] = delta[0]/delta_sum;
1010 double local_alpha = max(dg_penalty[s1][sbi], dg_penalty[s2][sbi]);
1011 double h = edge_side1.side()->diameter();
1014 gamma_l += local_alpha/h*aniso1*aniso2*(delta[0]*delta[1]/delta_sum);
1017 for (
int i=0; i<2; i++) omega[i] = 0;
1020 int sd[2];
bool is_side_own[2];
1021 sd[0] = s1; is_side_own[0] = edge_side1.cell().is_own();
1022 sd[1] = s2; is_side_own[1] = edge_side2.cell().is_own();
1024 #define AVERAGE(i,k,side_id) (fe_values[sd[side_id]]->shape_value(i,k)*0.5) 1025 #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]) 1026 #define JUMP(i,k,side_id) ((side_id==0?1:-1)*fe_values[sd[side_id]]->shape_value(i,k)) 1029 for (
int n=0; n<2; n++)
1031 if (!is_side_own[n])
continue;
1033 for (
int m=0; m<2; m++)
1035 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1036 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1037 local_matrix[i*fe_values[sd[m]]->n_dofs()+j] = 0;
1039 for (
unsigned int k=0; k<qsize; k++)
1041 double flux_times_JxW = transport_flux*fe_values[0]->JxW(k);
1042 double gamma_times_JxW = gamma_l*fe_values[0]->JxW(k);
1044 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1046 double flux_JxW_jump_i = flux_times_JxW*
JUMP(i,k,n);
1047 double gamma_JxW_jump_i = gamma_times_JxW*
JUMP(i,k,n);
1048 double JxW_jump_i = fe_values[0]->JxW(k)*
JUMP(i,k,n);
1051 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1053 int index = i*fe_values[sd[m]]->n_dofs()+j;
1056 local_matrix[index] += flux_JxW_jump_i*
AVERAGE(j,k,m);
1059 local_matrix[index] += gamma_JxW_jump_i*
JUMP(j,k,m);
1062 local_matrix[index] -=
WAVERAGE(j,k,m)*JxW_jump_i;
1063 local_matrix[index] -=
JUMP(j,k,m)*JxW_var_wavg_i;
1067 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);
1080 for (
unsigned int i=0; i<n_max_sides; i++)
1082 delete fe_values[i];
1087 template<
class Model>
1088 template<
unsigned int dim>
1095 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1097 PetscScalar local_matrix[ndofs*ndofs];
1104 for (
auto cell :
feo->
dh()->local_range() )
1106 if (!cell.is_own())
continue;
1107 for(
DHCellSide cell_side : cell.side_range() )
1109 const Side *side = cell_side.side();
1112 if (side->
dim() != dim-1)
continue;
1114 if (side->
cond() == NULL)
continue;
1117 cell.get_dof_indices(side_dof_indices);
1122 Model::compute_advection_diffusion_coefficients(fe_values_side.
point_list(), side_velocity, elm_acc,
ad_coef,
dif_coef);
1125 data_.cross_section.value_list(fe_values_side.
point_list(), elm_acc, csection);
1127 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1129 for (
unsigned int i=0; i<ndofs; i++)
1130 for (
unsigned int j=0; j<ndofs; j++)
1131 local_matrix[i*ndofs+j] = 0;
1135 double side_flux = 0;
1136 for (
unsigned int k=0; k<qsize; k++)
1137 side_flux += arma::dot(ad_coef[sbi][k], fe_values_side.
normal_vector(k))*fe_values_side.
JxW(k);
1138 double transport_flux = side_flux/side->
measure();
1145 transport_flux += gamma_l;
1149 for (
unsigned int k=0; k<qsize; k++)
1151 double flux_times_JxW;
1155 flux_times_JxW = csection[k]*robin_sigma[k]*fe_values_side.
JxW(k);
1160 flux_times_JxW = (transport_flux + csection[k]*robin_sigma[k])*fe_values_side.
JxW(k);
1165 flux_times_JxW = transport_flux*fe_values_side.
JxW(k);
1167 for (
unsigned int i=0; i<ndofs; i++)
1169 for (
unsigned int j=0; j<ndofs; j++)
1172 local_matrix[i*ndofs+j] += flux_times_JxW*fe_values_side.
shape_value(i,k)*fe_values_side.
shape_value(j,k);
1178 )*fe_values_side.
JxW(k);
1183 ls[sbi]->
mat_set_values(ndofs, &(side_dof_indices[0]), ndofs, &(side_dof_indices[0]), local_matrix);
1190 template<
class Model>
1191 template<
unsigned int dim>
1195 if (dim == 1)
return;
1206 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs();
1207 const unsigned int qsize =
feo->
q<dim-1>()->size();
1208 int side_dof_indices[2*ndofs];
1210 unsigned int n_dofs[2], n_indices;
1214 PetscScalar local_matrix[4*ndofs*ndofs];
1215 double comm_flux[2][2];
1219 fv_sb[0] = &fe_values_vb;
1220 fv_sb[1] = &fe_values_side;
1224 for(
DHCellSide neighb_side : cell_lower_dim.neighb_sides() )
1227 if (cell_lower_dim.elm().dim() != dim-1)
continue;
1230 n_indices = cell_lower_dim.get_dof_indices(indices);
1231 for(
unsigned int i=0; i<n_indices; ++i) {
1232 side_dof_indices[i] = indices[i];
1234 fe_values_vb.
reinit(elm_lower_dim);
1235 n_dofs[0] = fv_sb[0]->n_dofs();
1237 DHCellAccessor cell_higher_dim =
feo->
dh()->cell_accessor_from_element( neighb_side.side()->element().idx() );
1240 for(
unsigned int i=0; i<n_indices; ++i) {
1241 side_dof_indices[i+n_dofs[0]] = indices[i];
1244 n_dofs[1] = fv_sb[1]->n_dofs();
1247 bool own_element_id[2];
1248 own_element_id[0] = cell_lower_dim.is_own();
1249 own_element_id[1] = cell_higher_dim.
is_own();
1252 fv_rt.
reinit(elm_lower_dim);
1256 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_higher, elm_higher_dim, ad_coef_edg[1],
dif_coef_edg[1]);
1257 data_.cross_section.value_list(fe_values_vb.
point_list(), elm_lower_dim, csection_lower);
1258 data_.cross_section.value_list(fe_values_vb.
point_list(), elm_higher_dim, csection_higher);
1260 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1262 for (
unsigned int i=0; i<n_dofs[0]+n_dofs[1]; i++)
1263 for (
unsigned int j=0; j<n_dofs[0]+n_dofs[1]; j++)
1264 local_matrix[i*(n_dofs[0]+n_dofs[1])+j] = 0;
1269 for (
unsigned int k=0; k<qsize; k++)
1280 2*csection_higher[k]*csection_higher[k]/(csection_lower[k]*csection_lower[k]);
1282 double transport_flux = arma::dot(ad_coef_edg[1][sbi][k], fe_values_side.
normal_vector(k));
1284 comm_flux[0][0] = (sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1285 comm_flux[0][1] = -(sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1286 comm_flux[1][0] = -(sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1287 comm_flux[1][1] = (sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1289 for (
int n=0; n<2; n++)
1291 if (!own_element_id[n])
continue;
1293 for (
unsigned int i=0; i<n_dofs[n]; i++)
1294 for (
int m=0; m<2; m++)
1295 for (
unsigned int j=0; j<n_dofs[m]; j++)
1296 local_matrix[(i+n*n_dofs[0])*(n_dofs[0]+n_dofs[1]) + m*n_dofs[0] + j] +=
1297 comm_flux[m][n]*fv_sb[m]->shape_value(j,k)*fv_sb[n]->shape_value(i,k);
1300 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);
1311 template<
class Model>
1315 Model::balance_->start_flux_assembly(Model::subst_idx);
1316 set_boundary_conditions<1>();
1317 set_boundary_conditions<2>();
1318 set_boundary_conditions<3>();
1319 Model::balance_->finish_flux_assembly(Model::subst_idx);
1324 template<
class Model>
1325 template<
unsigned int dim>
1332 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1334 unsigned int loc_b=0;
1335 double local_rhs[ndofs];
1337 PetscScalar local_flux_balance_rhs;
1341 bc_ref_values(qsize);
1345 for (
auto cell :
feo->
dh()->own_range() )
1347 if (cell.elm()->boundary_idx_ ==
nullptr)
continue;
1349 for (
unsigned int si=0; si<cell.elm()->n_sides(); si++)
1352 if (edg->
n_sides > 1)
continue;
1354 if (edg->
side(0)->
cond() == NULL)
continue;
1356 if (edg->
side(0)->
dim() != dim-1)
1358 if (edg->
side(0)->
cond() !=
nullptr) ++loc_b;
1367 Model::get_bc_type(ele_acc, bc_type);
1376 auto dh_cell =
feo->
dh()->cell_accessor_from_element( side->
element().
idx() );
1377 dh_cell.get_dof_indices(side_dof_indices);
1379 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1381 fill_n(local_rhs, ndofs, 0);
1382 local_flux_balance_vector.assign(ndofs, 0);
1383 local_flux_balance_rhs = 0;
1387 data_.bc_dirichlet_value[sbi].value_list(fe_values_side.
point_list(), ele_acc, bc_values);
1389 double side_flux = 0;
1390 for (
unsigned int k=0; k<qsize; k++)
1392 double transport_flux = side_flux/side->
measure();
1396 for (
unsigned int k=0; k<qsize; k++)
1398 double bc_term = -transport_flux*bc_values[k]*fe_values_side.
JxW(k);
1399 for (
unsigned int i=0; i<ndofs; i++)
1400 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1402 for (
unsigned int i=0; i<ndofs; i++)
1403 local_flux_balance_rhs -= local_rhs[i];
1407 for (
unsigned int k=0; k<qsize; k++)
1409 double bc_term =
gamma[sbi][side->
cond_idx()]*bc_values[k]*fe_values_side.
JxW(k);
1411 for (
unsigned int i=0; i<ndofs; i++)
1412 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k)
1413 + arma::dot(bc_grad,fe_values_side.
shape_grad(i,k));
1415 for (
unsigned int k=0; k<qsize; k++)
1417 for (
unsigned int i=0; i<ndofs; i++)
1424 if (Model::time_->tlevel() > 0)
1425 for (
unsigned int i=0; i<ndofs; i++)
1426 local_flux_balance_rhs -= local_rhs[i];
1430 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1431 for (
unsigned int k=0; k<qsize; k++)
1433 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1434 for (
unsigned int i=0; i<ndofs; i++)
1435 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1438 for (
unsigned int i=0; i<ndofs; i++)
1440 for (
unsigned int k=0; k<qsize; k++)
1441 local_flux_balance_vector[i] += csection[k]*bc_sigma[k]*fe_values_side.
JxW(k)*fe_values_side.
shape_value(i,k);
1442 local_flux_balance_rhs -= local_rhs[i];
1447 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1448 for (
unsigned int k=0; k<qsize; k++)
1450 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1451 for (
unsigned int i=0; i<ndofs; i++)
1452 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1455 for (
unsigned int i=0; i<ndofs; i++)
1457 for (
unsigned int k=0; k<qsize; k++)
1458 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);
1459 local_flux_balance_rhs -= local_rhs[i];
1464 for (
unsigned int k=0; k<qsize; k++)
1466 for (
unsigned int i=0; i<ndofs; i++)
1472 Model::balance_->add_flux_matrix_values(Model::subst_idx[sbi], loc_b, side_dof_indices, local_flux_balance_vector);
1473 Model::balance_->add_flux_vec_value(Model::subst_idx[sbi], loc_b, local_flux_balance_rhs);
1482 template<
class Model>
1483 template<
unsigned int dim>
1488 OLD_ASSERT(cell->
dim() == dim,
"Element dimension mismatch!");
1492 for (
unsigned int k=0; k<fv.
n_points(); k++)
1494 velocity[k].zeros();
1495 for (
unsigned int sid=0; sid<cell->
n_sides(); sid++)
1496 for (
unsigned int c=0; c<3; ++c)
1503 template<
class Model>
1512 double delta = 0, h = 0;
1515 if (side->
dim() == 0)
1521 for (
unsigned int i=0; i<side->
n_nodes(); i++)
1522 for (
unsigned int j=i+1; j<side->
n_nodes(); j++)
1523 h = max(h, side->
node(i)->distance( *side->
node(j).node() ));
1527 for (
int k=0; k<K_size; k++)
1528 delta += dot(K[k]*normal_vector,normal_vector);
1538 template<
class Model>
1542 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1543 ls[sbi]->start_allocation();
1544 prepare_initial_condition<1>();
1545 prepare_initial_condition<2>();
1546 prepare_initial_condition<3>();
1548 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1549 ls[sbi]->start_add_assembly();
1550 prepare_initial_condition<1>();
1551 prepare_initial_condition<2>();
1552 prepare_initial_condition<3>();
1554 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1562 template<
class Model>
1563 template<
unsigned int dim>
1568 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
1570 double matrix[ndofs*ndofs],
rhs[ndofs];
1573 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1574 init_values[sbi].resize(qsize);
1576 for (
auto cell :
feo->
dh()->own_range() )
1578 if (cell.dim() != dim)
continue;
1581 cell.get_dof_indices(dof_indices);
1584 Model::compute_init_cond(fe_values.
point_list(), elem, init_values);
1586 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1588 for (
unsigned int i=0; i<ndofs; i++)
1591 for (
unsigned int j=0; j<ndofs; j++)
1592 matrix[i*ndofs+j] = 0;
1595 for (
unsigned int k=0; k<qsize; k++)
1597 double rhs_term = init_values[sbi][k]*fe_values.
JxW(k);
1599 for (
unsigned int i=0; i<ndofs; i++)
1601 for (
unsigned int j=0; j<ndofs; j++)
1607 ls[sbi]->
set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), matrix, rhs);
1613 template<
class Model>
1616 el_4_loc = Model::mesh_->get_el_4_loc();
1617 el_ds = Model::mesh_->get_el_ds();
1621 template<
class Model>
1624 if (solution_changed)
1626 unsigned int i_cell=0;
1627 for (
auto cell :
feo->
dh()->own_range() )
1630 unsigned int n_dofs;
1634 n_dofs =
feo->
fe<1>()->n_dofs();
1637 n_dofs =
feo->
fe<2>()->n_dofs();
1640 n_dofs =
feo->
fe<3>()->n_dofs();
1645 cell.get_dof_indices(dof_indices);
1647 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1649 double old_average = 0;
1650 for (
unsigned int j=0; j<n_dofs; ++j)
1651 old_average +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
1652 old_average /= n_dofs;
1654 for (
unsigned int j=0; j<n_dofs; ++j)
1655 ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()] +=
solution_elem_[sbi][i_cell] - old_average;
1661 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1665 template<
class Model>
1668 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.
Cell accessor allow iterate over DOF handler cells.
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 ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
#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)
bool is_own() const
Return true if accessor represents own element (false for ghost element)
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.
void set_DG_parameters_boundary(const Side *side, const int K_size, const std::vector< arma::mat33 > &K, const double flux, const arma::vec3 &normal_vector, const double alpha, double &gamma)
Calculates the dispersivity (diffusivity) tensor from the velocity field.
#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.
void initialize() override
vector< vector< vector< arma::vec3 > > > ad_coef_edg
Advection coefficients on edges.
Transformed quadrature points.
const ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
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.
RangeConvert< DHEdgeSide, DHCellSide > edge_sides() const
Returns range of all sides looped over common Edge.
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.
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)
NodeAccessor< 3 > node(unsigned int i) const
double measure() const
Calculate metrics of the side.
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()
void set_solution(Vec sol_vec)
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.
unsigned int get_dof_indices(std::vector< int > &indices) const
Fill vector of the global indices of dofs associated to the cell.
FiniteElement< dim > * fe_rt()
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)
Definitions of Raviart-Thomas finite elements.
Side accessor allows to iterate over sides of DOF handler cell.
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