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;
122 for (
unsigned int dim = 0; dim < 4; dim++)
123 q_[dim] =
new QGauss(dim, q_order);
129 ds_ = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe0_, fe1_, fe2_, fe3_);
130 dh_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
132 dh_->distribute_dofs(ds_);
145 for (
unsigned int dim = 0; dim < 4; dim++)
delete q_[dim];
168 template<
class Model>
172 .
name(
"fracture_sigma")
174 "Coefficient of diffusive transfer through fractures (for each substance).")
182 "Penalty parameter influencing the discontinuity of the solution (for each substance). " 183 "Its default value 1 is sufficient in most cases. Higher value diminishes the inter-element jumps.")
196 .
description(
"Subdomain ids of the domain decomposition.");
204 template<
class Model>
206 : Model(init_mesh, in_rec),
220 data_.set_mesh(init_mesh);
229 Model::init_from_input(in_rec);
238 template<
class Model>
241 data_.set_components(Model::substances_.names());
245 gamma.resize(Model::n_substances());
246 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
247 gamma[sbi].resize(Model::mesh_->boundary_.size());
251 int max_edg_sides = max(Model::mesh_->max_edge_sides(1), max(Model::mesh_->max_edge_sides(2), Model::mesh_->max_edge_sides(3)));
253 ret_coef.resize(Model::n_substances());
256 ad_coef.resize(Model::n_substances());
257 dif_coef.resize(Model::n_substances());
258 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
266 for (
int sd=0; sd<max_edg_sides; sd++)
270 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
278 data_.output_field.set_components(Model::substances_.names());
279 data_.output_field.set_mesh(*Model::mesh_);
282 data_.output_field.setup_components();
283 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
288 data_.output_field[sbi].set_field(Model::mesh_->region_db().get_region_set(
"ALL"), output_field_ptr, 0);
295 std::string petsc_default_opts;
296 if (
feo->
dh()->distr()->np() == 1)
297 petsc_default_opts =
"-ksp_type bcgs -pc_type ilu -pc_factor_levels 2 -ksp_diagonal_scale_fix -pc_factor_fill 6.0";
299 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";
302 ls =
new LinSys*[Model::n_substances()];
307 mass_matrix.resize(Model::n_substances(),
nullptr);
308 rhs.resize(Model::n_substances(),
nullptr);
309 mass_vec.resize(Model::n_substances(),
nullptr);
310 ret_vec.resize(Model::n_substances(),
nullptr);
312 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++) {
319 solution_elem_[sbi] =
new double[Model::mesh_->get_el_ds()->lsize()];
326 Model::balance_->allocate(
feo->
dh()->distr()->lsize(),
327 max(
feo->
fe<1>()->n_dofs(), max(
feo->
fe<2>()->n_dofs(),
feo->
fe<3>()->n_dofs())));
332 template<
class Model>
337 if (
gamma.size() > 0) {
340 for (
unsigned int i=0; i<Model::n_substances(); i++)
372 template<
class Model>
376 data_.mark_input_times( *(Model::time_) );
378 std::stringstream ss;
386 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++)
393 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
395 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
405 template<
class Model>
409 for (
unsigned int i=0; i<Model::n_substances(); i++)
425 for (
unsigned int i=0; i<Model::n_substances(); i++)
436 template<
class Model>
441 Model::time_->next_time();
442 Model::time_->view(
"TDG");
451 for (
unsigned int i=0; i<Model::n_substances(); i++)
458 for (
unsigned int i=0; i<Model::n_substances(); i++)
468 MatConvert(*(
ls_dt[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
mass_matrix[i]);
471 MatCopy(*(
ls_dt[i]->get_matrix() ),
mass_matrix[i], DIFFERENT_NONZERO_PATTERN);
478 || Model::flux_changed)
482 for (
unsigned int i=0; i<Model::n_substances(); i++)
488 for (
unsigned int i=0; i<Model::n_substances(); i++)
493 MatConvert(*(
ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
stiffness_matrix[i]);
502 || Model::flux_changed)
504 for (
unsigned int i=0; i<Model::n_substances(); i++)
511 for (
unsigned int i=0; i<Model::n_substances(); i++)
515 if (
rhs[i] ==
nullptr) VecDuplicate(*(
ls[i]->get_rhs() ), &
rhs[i]);
516 VecCopy(*(
ls[i]->get_rhs() ),
rhs[i]);
520 Model::flux_changed =
false;
541 for (
unsigned int i=0; i<Model::n_substances(); i++)
544 MatAXPY(m, 1./Model::time_->dt(),
mass_matrix[i], SUBSET_NONZERO_PATTERN);
547 VecDuplicate(
rhs[i], &w);
548 VecWAXPY(w, 1./Model::time_->dt(),
mass_vec[i],
rhs[i]);
567 template<
class Model>
571 unsigned int i_cell=0;
572 for (
auto cell :
feo->
dh()->own_range() )
579 n_dofs =
feo->
fe<1>()->n_dofs();
582 n_dofs =
feo->
fe<2>()->n_dofs();
585 n_dofs =
feo->
fe<3>()->n_dofs();
590 cell.get_dof_indices(dof_indices);
592 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
596 for (
unsigned int j=0; j<n_dofs; ++j)
597 solution_elem_[sbi][i_cell] +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
608 template<
class Model>
621 Model::output_data();
624 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
625 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
626 Model::balance_->output();
633 template<
class Model>
636 if (Model::balance_->cumulative())
638 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
640 Model::balance_->calculate_cumulative(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
652 template<
class Model>
656 Model::balance_->start_mass_assembly(Model::subst_idx);
657 assemble_mass_matrix<1>();
658 assemble_mass_matrix<2>();
659 assemble_mass_matrix<3>();
660 Model::balance_->finish_mass_assembly(Model::subst_idx);
665 template<
class Model>
template<
unsigned int dim>
669 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
671 PetscScalar local_mass_matrix[ndofs*ndofs], local_retardation_balance_vector[ndofs];
675 for (
auto cell :
feo->
dh()->own_range() )
677 if (cell.dim() != dim)
continue;
681 cell.get_dof_indices(dof_indices);
686 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
689 for (
unsigned int i=0; i<ndofs; i++)
691 for (
unsigned int j=0; j<ndofs; j++)
693 local_mass_matrix[i*ndofs+j] = 0;
694 for (
unsigned int k=0; k<qsize; k++)
699 for (
unsigned int i=0; i<ndofs; i++)
701 local_mass_balance_vector[i] = 0;
702 local_retardation_balance_vector[i] = 0;
703 for (
unsigned int k=0; k<qsize; k++)
710 Model::balance_->add_mass_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_mass_balance_vector);
711 ls_dt[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_mass_matrix);
712 VecSetValues(
ret_vec[sbi], ndofs, &(dof_indices[0]), local_retardation_balance_vector, ADD_VALUES);
720 template<
class Model>
725 assemble_volume_integrals<1>();
726 assemble_volume_integrals<2>();
727 assemble_volume_integrals<3>();
731 assemble_fluxes_boundary<1>();
732 assemble_fluxes_boundary<2>();
733 assemble_fluxes_boundary<3>();
737 assemble_fluxes_element_element<1>();
738 assemble_fluxes_element_element<2>();
739 assemble_fluxes_element_element<3>();
743 assemble_fluxes_element_side<1>();
744 assemble_fluxes_element_side<2>();
745 assemble_fluxes_element_side<3>();
752 template<
class Model>
753 template<
unsigned int dim>
760 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
764 PetscScalar local_matrix[ndofs*ndofs];
767 for (
auto cell :
feo->
dh()->local_range() )
769 if (!cell.is_own())
continue;
770 if (cell.dim() != dim)
continue;
775 cell.get_dof_indices(dof_indices);
779 Model::compute_sources_sigma(fe_values.
point_list(), elm, sources_sigma);
782 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
784 for (
unsigned int i=0; i<ndofs; i++)
785 for (
unsigned int j=0; j<ndofs; j++)
786 local_matrix[i*ndofs+j] = 0;
788 for (
unsigned int k=0; k<qsize; k++)
790 for (
unsigned int i=0; i<ndofs; i++)
795 for (
unsigned int j=0; j<ndofs; j++)
801 ls[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_matrix);
807 template<
class Model>
811 Model::balance_->start_source_assembly(Model::subst_idx);
815 Model::balance_->finish_source_assembly(Model::subst_idx);
819 template<
class Model>
820 template<
unsigned int dim>
825 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
831 PetscScalar local_rhs[ndofs];
836 for (
auto cell :
feo->
dh()->own_range() )
838 if (cell.dim() != dim)
continue;
842 cell.get_dof_indices(dof_indices);
843 cell.get_loc_dof_indices(loc_dof_indices);
845 Model::compute_source_coefficients(fe_values.
point_list(), elm, sources_conc, sources_density, sources_sigma);
848 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
850 fill_n(local_rhs, ndofs, 0);
851 local_source_balance_vector.assign(ndofs, 0);
852 local_source_balance_rhs.assign(ndofs, 0);
855 for (
unsigned int k=0; k<qsize; k++)
857 source = (sources_density[sbi][k] + sources_conc[sbi][k]*sources_sigma[sbi][k])*fe_values.
JxW(k);
859 for (
unsigned int i=0; i<ndofs; i++)
864 for (
unsigned int i=0; i<ndofs; i++)
866 for (
unsigned int k=0; k<qsize; k++)
867 local_source_balance_vector[i] -= sources_sigma[sbi][k]*fe_values.
shape_value(i,k)*fe_values.
JxW(k);
869 local_source_balance_rhs[i] += local_rhs[i];
871 Model::balance_->add_source_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), loc_dof_indices,
872 local_source_balance_vector, local_source_balance_rhs);
882 double h_max = 0, h_min = numeric_limits<double>::infinity();
883 for (
unsigned int i=0; i<e->
n_nodes(); i++)
884 for (
unsigned int j=i+1; j<e->
n_nodes(); j++)
894 template<
class Model>
895 template<
unsigned int dim>
901 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size(),
904 PetscScalar local_matrix[ndofs*ndofs];
907 double gamma_l, omega[2], transport_flux, delta[2], delta_sum;
908 double aniso1, aniso2;
910 for (
unsigned int sid=0; sid<n_max_sides; sid++)
920 if (dh_cell.dim() != dim)
continue;
921 for(
DHCellSide cell_side : dh_cell.side_range() )
923 if (cell_side.n_edge_sides() < 2)
continue;
924 bool unique_edge = (cell_side.edge_sides().begin()->element().idx() != dh_cell.elm_idx());
925 if ( unique_edge )
continue;
929 auto dh_edge_cell =
feo->
dh()->cell_accessor_from_element( edge_side.elem_idx() );
931 dh_edge_cell.get_dof_indices(side_dof_indices[sid]);
932 fe_values[sid]->reinit(cell, edge_side.side_idx());
933 fsv_rt.
reinit(cell, edge_side.side_idx());
935 Model::compute_advection_diffusion_coefficients(fe_values[sid]->point_list(), side_velocity[sid], cell,
ad_coef_edg[sid],
dif_coef_edg[sid]);
936 dg_penalty[sid].resize(Model::n_substances());
937 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
941 arma::vec3 normal_vector = fe_values[0]->normal_vector(0);
944 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
947 double pflux = 0, nflux = 0;
952 for (
unsigned int k=0; k<qsize; k++)
953 fluxes[sid] +=
arma::dot(
ad_coef_edg[sid][sbi][k], fe_values[sid]->normal_vector(k))*fe_values[sid]->JxW(k);
954 fluxes[sid] /= edge_side.measure();
956 pflux += fluxes[sid];
958 nflux += fluxes[sid];
969 if (s2<=s1)
continue;
970 ASSERT(edge_side1.is_valid()).error(
"Invalid side of edge.");
972 arma::vec3 nv = fe_values[s1]->normal_vector(0);
976 if (fluxes[s2] > 0 && fluxes[s1] < 0)
977 transport_flux = fluxes[s1]*fabs(fluxes[s2]/pflux);
978 else if (fluxes[s2] < 0 && fluxes[s1] > 0)
979 transport_flux = fluxes[s1]*fabs(fluxes[s2]/nflux);
983 gamma_l = 0.5*fabs(transport_flux);
987 for (
unsigned int k=0; k<qsize; k++)
995 delta_sum = delta[0] + delta[1];
998 if (fabs(delta_sum) > 0)
1000 omega[0] = delta[1]/delta_sum;
1001 omega[1] = delta[0]/delta_sum;
1002 double local_alpha = max(dg_penalty[s1][sbi], dg_penalty[s2][sbi]);
1003 double h = edge_side1.diameter();
1006 gamma_l += local_alpha/h*aniso1*aniso2*(delta[0]*delta[1]/delta_sum);
1009 for (
int i=0; i<2; i++) omega[i] = 0;
1012 int sd[2];
bool is_side_own[2];
1013 sd[0] = s1; is_side_own[0] = edge_side1.cell().is_own();
1014 sd[1] = s2; is_side_own[1] = edge_side2.cell().is_own();
1016 #define AVERAGE(i,k,side_id) (fe_values[sd[side_id]]->shape_value(i,k)*0.5) 1017 #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]) 1018 #define JUMP(i,k,side_id) ((side_id==0?1:-1)*fe_values[sd[side_id]]->shape_value(i,k)) 1021 for (
int n=0; n<2; n++)
1023 if (!is_side_own[n])
continue;
1025 for (
int m=0; m<2; m++)
1027 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1028 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1029 local_matrix[i*fe_values[sd[m]]->n_dofs()+j] = 0;
1031 for (
unsigned int k=0; k<qsize; k++)
1033 double flux_times_JxW = transport_flux*fe_values[0]->JxW(k);
1034 double gamma_times_JxW = gamma_l*fe_values[0]->JxW(k);
1036 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1038 double flux_JxW_jump_i = flux_times_JxW*
JUMP(i,k,n);
1039 double gamma_JxW_jump_i = gamma_times_JxW*
JUMP(i,k,n);
1040 double JxW_jump_i = fe_values[0]->JxW(k)*
JUMP(i,k,n);
1043 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1045 int index = i*fe_values[sd[m]]->n_dofs()+j;
1048 local_matrix[index] += flux_JxW_jump_i*
AVERAGE(j,k,m);
1051 local_matrix[index] += gamma_JxW_jump_i*
JUMP(j,k,m);
1054 local_matrix[index] -=
WAVERAGE(j,k,m)*JxW_jump_i;
1055 local_matrix[index] -=
JUMP(j,k,m)*JxW_var_wavg_i;
1059 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);
1072 for (
unsigned int i=0; i<n_max_sides; i++)
1074 delete fe_values[i];
1079 template<
class Model>
1080 template<
unsigned int dim>
1087 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1089 PetscScalar local_matrix[ndofs*ndofs];
1096 for (
auto cell :
feo->
dh()->local_range() )
1098 if (!cell.is_own())
continue;
1099 for(
DHCellSide cell_side : cell.side_range() )
1101 Side side = cell_side.side();
1104 if (side.
dim() != dim-1)
continue;
1106 if (side.
cond() == NULL)
continue;
1109 cell.get_dof_indices(side_dof_indices);
1114 Model::compute_advection_diffusion_coefficients(fe_values_side.
point_list(), side_velocity, elm_acc,
ad_coef,
dif_coef);
1117 data_.cross_section.value_list(fe_values_side.
point_list(), elm_acc, csection);
1119 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1121 for (
unsigned int i=0; i<ndofs; i++)
1122 for (
unsigned int j=0; j<ndofs; j++)
1123 local_matrix[i*ndofs+j] = 0;
1127 double side_flux = 0;
1128 for (
unsigned int k=0; k<qsize; k++)
1130 double transport_flux = side_flux/side.
measure();
1137 transport_flux += gamma_l;
1141 for (
unsigned int k=0; k<qsize; k++)
1143 double flux_times_JxW;
1147 flux_times_JxW = csection[k]*robin_sigma[k]*fe_values_side.
JxW(k);
1152 flux_times_JxW = (transport_flux + csection[k]*robin_sigma[k])*fe_values_side.
JxW(k);
1157 flux_times_JxW = transport_flux*fe_values_side.
JxW(k);
1159 for (
unsigned int i=0; i<ndofs; i++)
1161 for (
unsigned int j=0; j<ndofs; j++)
1164 local_matrix[i*ndofs+j] += flux_times_JxW*fe_values_side.
shape_value(i,k)*fe_values_side.
shape_value(j,k);
1170 )*fe_values_side.
JxW(k);
1175 ls[sbi]->
mat_set_values(ndofs, &(side_dof_indices[0]), ndofs, &(side_dof_indices[0]), local_matrix);
1182 template<
class Model>
1183 template<
unsigned int dim>
1187 if (dim == 1)
return;
1198 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs();
1199 const unsigned int qsize =
feo->
q<dim-1>()->size();
1200 int side_dof_indices[2*ndofs];
1202 unsigned int n_dofs[2], n_indices;
1206 PetscScalar local_matrix[4*ndofs*ndofs];
1207 double comm_flux[2][2];
1211 fv_sb[0] = &fe_values_vb;
1212 fv_sb[1] = &fe_values_side;
1216 for(
DHCellSide neighb_side : cell_lower_dim.neighb_sides() )
1219 if (cell_lower_dim.elm().dim() != dim-1)
continue;
1222 n_indices = cell_lower_dim.get_dof_indices(indices);
1223 for(
unsigned int i=0; i<n_indices; ++i) {
1224 side_dof_indices[i] = indices[i];
1226 fe_values_vb.
reinit(elm_lower_dim);
1227 n_dofs[0] = fv_sb[0]->n_dofs();
1229 DHCellAccessor cell_higher_dim =
feo->
dh()->cell_accessor_from_element( neighb_side.element().idx() );
1232 for(
unsigned int i=0; i<n_indices; ++i) {
1233 side_dof_indices[i+n_dofs[0]] = indices[i];
1235 fe_values_side.
reinit(elm_higher_dim, neighb_side.side_idx());
1236 n_dofs[1] = fv_sb[1]->n_dofs();
1239 bool own_element_id[2];
1240 own_element_id[0] = cell_lower_dim.is_own();
1241 own_element_id[1] = cell_higher_dim.
is_own();
1243 fsv_rt.
reinit(elm_higher_dim, neighb_side.side_idx());
1244 fv_rt.
reinit(elm_lower_dim);
1248 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_higher, elm_higher_dim, ad_coef_edg[1],
dif_coef_edg[1]);
1249 data_.cross_section.value_list(fe_values_vb.
point_list(), elm_lower_dim, csection_lower);
1250 data_.cross_section.value_list(fe_values_vb.
point_list(), elm_higher_dim, csection_higher);
1252 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1254 for (
unsigned int i=0; i<n_dofs[0]+n_dofs[1]; i++)
1255 for (
unsigned int j=0; j<n_dofs[0]+n_dofs[1]; j++)
1256 local_matrix[i*(n_dofs[0]+n_dofs[1])+j] = 0;
1261 for (
unsigned int k=0; k<qsize; k++)
1272 2*csection_higher[k]*csection_higher[k]/(csection_lower[k]*csection_lower[k]);
1276 comm_flux[0][0] = (sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1277 comm_flux[0][1] = -(sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1278 comm_flux[1][0] = -(sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1279 comm_flux[1][1] = (sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1281 for (
int n=0; n<2; n++)
1283 if (!own_element_id[n])
continue;
1285 for (
unsigned int i=0; i<n_dofs[n]; i++)
1286 for (
int m=0; m<2; m++)
1287 for (
unsigned int j=0; j<n_dofs[m]; j++)
1288 local_matrix[(i+n*n_dofs[0])*(n_dofs[0]+n_dofs[1]) + m*n_dofs[0] + j] +=
1289 comm_flux[m][n]*fv_sb[m]->shape_value(j,k)*fv_sb[n]->shape_value(i,k);
1292 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);
1303 template<
class Model>
1307 Model::balance_->start_flux_assembly(Model::subst_idx);
1308 set_boundary_conditions<1>();
1309 set_boundary_conditions<2>();
1310 set_boundary_conditions<3>();
1311 Model::balance_->finish_flux_assembly(Model::subst_idx);
1316 template<
class Model>
1317 template<
unsigned int dim>
1324 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1326 double local_rhs[ndofs];
1328 PetscScalar local_flux_balance_rhs;
1332 bc_ref_values(qsize);
1336 for (
auto cell :
feo->
dh()->own_range() )
1338 if (cell.elm()->boundary_idx_ ==
nullptr)
continue;
1340 for (
unsigned int si=0; si<cell.elm()->n_sides(); si++)
1343 if (edg->
n_sides > 1)
continue;
1345 if (edg->
side(0)->
cond() == NULL)
continue;
1348 if (edg->
side(0)->
dim() != dim-1)
continue;
1356 Model::get_bc_type(ele_acc, bc_type);
1365 auto dh_cell =
feo->
dh()->cell_accessor_from_element( side.
element().
idx() );
1366 dh_cell.get_dof_indices(side_dof_indices);
1368 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1370 fill_n(local_rhs, ndofs, 0);
1371 local_flux_balance_vector.assign(ndofs, 0);
1372 local_flux_balance_rhs = 0;
1376 data_.bc_dirichlet_value[sbi].value_list(fe_values_side.
point_list(), ele_acc, bc_values);
1378 double side_flux = 0;
1379 for (
unsigned int k=0; k<qsize; k++)
1381 double transport_flux = side_flux/side.
measure();
1385 for (
unsigned int k=0; k<qsize; k++)
1387 double bc_term = -transport_flux*bc_values[k]*fe_values_side.
JxW(k);
1388 for (
unsigned int i=0; i<ndofs; i++)
1389 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1391 for (
unsigned int i=0; i<ndofs; i++)
1392 local_flux_balance_rhs -= local_rhs[i];
1396 for (
unsigned int k=0; k<qsize; k++)
1398 double bc_term =
gamma[sbi][side.
cond_idx()]*bc_values[k]*fe_values_side.
JxW(k);
1400 for (
unsigned int i=0; i<ndofs; i++)
1401 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k)
1404 for (
unsigned int k=0; k<qsize; k++)
1406 for (
unsigned int i=0; i<ndofs; i++)
1413 if (Model::time_->tlevel() > 0)
1414 for (
unsigned int i=0; i<ndofs; i++)
1415 local_flux_balance_rhs -= local_rhs[i];
1419 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1420 for (
unsigned int k=0; k<qsize; k++)
1422 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1423 for (
unsigned int i=0; i<ndofs; i++)
1424 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1427 for (
unsigned int i=0; i<ndofs; i++)
1429 for (
unsigned int k=0; k<qsize; k++)
1430 local_flux_balance_vector[i] += csection[k]*bc_sigma[k]*fe_values_side.
JxW(k)*fe_values_side.
shape_value(i,k);
1431 local_flux_balance_rhs -= local_rhs[i];
1436 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1437 for (
unsigned int k=0; k<qsize; k++)
1439 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1440 for (
unsigned int i=0; i<ndofs; i++)
1441 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1444 for (
unsigned int i=0; i<ndofs; i++)
1446 for (
unsigned int k=0; k<qsize; k++)
1448 local_flux_balance_rhs -= local_rhs[i];
1453 for (
unsigned int k=0; k<qsize; k++)
1455 for (
unsigned int i=0; i<ndofs; i++)
1461 Model::balance_->add_flux_matrix_values(Model::subst_idx[sbi], side, side_dof_indices, local_flux_balance_vector);
1462 Model::balance_->add_flux_vec_value(Model::subst_idx[sbi], side, local_flux_balance_rhs);
1470 template<
class Model>
1471 template<
unsigned int dim>
1476 OLD_ASSERT(cell->
dim() == dim,
"Element dimension mismatch!");
1480 for (
unsigned int k=0; k<fv.
n_points(); k++)
1482 velocity[k].zeros();
1483 for (
unsigned int sid=0; sid<cell->
n_sides(); sid++)
1484 for (
unsigned int c=0; c<3; ++c)
1491 template<
class Model>
1500 double delta = 0, h = 0;
1503 if (side.
dim() == 0)
1509 for (
unsigned int i=0; i<side.
n_nodes(); i++)
1510 for (
unsigned int j=i+1; j<side.
n_nodes(); j++)
1511 h = max(h, side.
node(i)->distance( *side.
node(j).node() ));
1515 for (
int k=0; k<K_size; k++)
1516 delta +=
dot(K[k]*normal_vector,normal_vector);
1526 template<
class Model>
1530 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1531 ls[sbi]->start_allocation();
1532 prepare_initial_condition<1>();
1533 prepare_initial_condition<2>();
1534 prepare_initial_condition<3>();
1536 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1537 ls[sbi]->start_add_assembly();
1538 prepare_initial_condition<1>();
1539 prepare_initial_condition<2>();
1540 prepare_initial_condition<3>();
1542 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1550 template<
class Model>
1551 template<
unsigned int dim>
1556 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
1558 double matrix[ndofs*ndofs],
rhs[ndofs];
1561 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1562 init_values[sbi].resize(qsize);
1564 for (
auto cell :
feo->
dh()->own_range() )
1566 if (cell.dim() != dim)
continue;
1569 cell.get_dof_indices(dof_indices);
1572 Model::compute_init_cond(fe_values.
point_list(), elem, init_values);
1574 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1576 for (
unsigned int i=0; i<ndofs; i++)
1579 for (
unsigned int j=0; j<ndofs; j++)
1580 matrix[i*ndofs+j] = 0;
1583 for (
unsigned int k=0; k<qsize; k++)
1585 double rhs_term = init_values[sbi][k]*fe_values.
JxW(k);
1587 for (
unsigned int i=0; i<ndofs; i++)
1589 for (
unsigned int j=0; j<ndofs; j++)
1595 ls[sbi]->
set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), matrix, rhs);
1601 template<
class Model>
1604 el_4_loc = Model::mesh_->get_el_4_loc();
1605 el_ds = Model::mesh_->get_el_ds();
1609 template<
class Model>
1612 if (solution_changed)
1614 unsigned int i_cell=0;
1615 for (
auto cell :
feo->
dh()->own_range() )
1618 unsigned int n_dofs;
1622 n_dofs =
feo->
fe<1>()->n_dofs();
1625 n_dofs =
feo->
fe<2>()->n_dofs();
1628 n_dofs =
feo->
fe<3>()->n_dofs();
1633 cell.get_dof_indices(dof_indices);
1635 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1637 double old_average = 0;
1638 for (
unsigned int j=0; j<n_dofs; ++j)
1639 old_average +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
1640 old_average /= n_dofs;
1642 for (
unsigned int j=0; j<n_dofs; ++j)
1643 ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()] +=
solution_elem_[sbi][i_cell] - old_average;
1649 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1653 template<
class Model>
1656 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...
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.
#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 > shape_grad(const unsigned int function_no, const unsigned int point_no) override
Return the gradient of the function_no-th shape function at the point_no-th 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()
double JxW(const unsigned int point_no) override
Return the product of Jacobian determinant and the quadrature weight at given quadrature point...
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.
const unsigned int size() const
Returns number of quadrature points.
Field< 3, FieldValue< 3 >::Scalar > subdomain
unsigned int n_sides() const
static auto region_id(Mesh &mesh) -> IndexField
Type dot(const Mat< Type, nRows, nCols > &a, const Mat< Type, nRows, nCols > &b)
#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.
arma::vec::fixed< spacedim > normal_vector(unsigned int point_no) override
Returns the normal vector to a side at given 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.
double shape_value(const unsigned int function_no, const unsigned int point_no) override
Return the value of the function_no-th shape function at the point_no-th quadrature point...
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)
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.
void set_DG_parameters_boundary(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.
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