50 using namespace
Input::Type;
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++)
130 dh_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
132 dh_->distribute_dofs(
ds_);
145 for (
unsigned int dim = 0; dim < 4; dim++)
delete q_[dim];
169 template<
class Model>
173 .
name(
"fracture_sigma")
175 "Coefficient of diffusive transfer through fractures (for each substance).")
183 "Penalty parameter influencing the discontinuity of the solution (for each substance). " 184 "Its default value 1 is sufficient in most cases. Higher value diminishes the inter-element jumps.")
197 .
description(
"Subdomain ids of the domain decomposition.");
205 template<
class Model>
207 : Model(init_mesh, in_rec),
221 data_.set_mesh(init_mesh);
230 Model::init_from_input(in_rec);
239 template<
class Model>
242 data_.set_components(Model::substances_.names());
246 gamma.resize(Model::n_substances());
247 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
248 gamma[sbi].resize(Model::mesh_->boundary_.size());
252 int max_edg_sides = max(Model::mesh_->max_edge_sides(1), max(Model::mesh_->max_edge_sides(2), Model::mesh_->max_edge_sides(3)));
254 ret_coef.resize(Model::n_substances());
257 ad_coef.resize(Model::n_substances());
258 dif_coef.resize(Model::n_substances());
259 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
267 for (
int sd=0; sd<max_edg_sides; sd++)
271 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
279 data_.output_field.set_components(Model::substances_.names());
280 data_.output_field.set_mesh(*Model::mesh_);
283 data_.output_field.setup_components();
284 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
289 data_.output_field[sbi].set_field(Model::mesh_->region_db().get_region_set(
"ALL"), output_field_ptr, 0);
296 std::string petsc_default_opts;
297 if (
feo->
dh()->distr()->np() == 1)
298 petsc_default_opts =
"-ksp_type bcgs -pc_type ilu -pc_factor_levels 2 -ksp_diagonal_scale_fix -pc_factor_fill 6.0";
300 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";
303 ls =
new LinSys*[Model::n_substances()];
308 mass_matrix.resize(Model::n_substances(),
nullptr);
309 rhs.resize(Model::n_substances(),
nullptr);
310 mass_vec.resize(Model::n_substances(),
nullptr);
311 ret_vec.resize(Model::n_substances(),
nullptr);
313 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++) {
320 solution_elem_[sbi] =
new double[Model::mesh_->get_el_ds()->lsize()];
327 Model::balance_->allocate(
feo->
dh()->distr()->lsize(),
328 max(
feo->
fe<1>()->n_dofs(), max(
feo->
fe<2>()->n_dofs(),
feo->
fe<3>()->n_dofs())));
333 template<
class Model>
338 if (
gamma.size() > 0) {
341 for (
unsigned int i=0; i<Model::n_substances(); i++)
373 template<
class Model>
377 data_.mark_input_times( *(Model::time_) );
379 std::stringstream ss;
387 for (
unsigned int sbi = 0; sbi < Model::n_substances(); sbi++)
394 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
396 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
406 template<
class Model>
410 for (
unsigned int i=0; i<Model::n_substances(); i++)
426 for (
unsigned int i=0; i<Model::n_substances(); i++)
437 template<
class Model>
442 Model::time_->next_time();
443 Model::time_->view(
"TDG");
452 for (
unsigned int i=0; i<Model::n_substances(); i++)
459 for (
unsigned int i=0; i<Model::n_substances(); i++)
469 MatConvert(*(
ls_dt[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
mass_matrix[i]);
472 MatCopy(*(
ls_dt[i]->get_matrix() ),
mass_matrix[i], DIFFERENT_NONZERO_PATTERN);
479 || Model::flux_changed)
483 for (
unsigned int i=0; i<Model::n_substances(); i++)
489 for (
unsigned int i=0; i<Model::n_substances(); i++)
494 MatConvert(*(
ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &
stiffness_matrix[i]);
503 || Model::flux_changed)
505 for (
unsigned int i=0; i<Model::n_substances(); i++)
512 for (
unsigned int i=0; i<Model::n_substances(); i++)
516 if (
rhs[i] ==
nullptr) VecDuplicate(*(
ls[i]->get_rhs() ), &
rhs[i]);
517 VecCopy(*(
ls[i]->get_rhs() ),
rhs[i]);
521 Model::flux_changed =
false;
542 for (
unsigned int i=0; i<Model::n_substances(); i++)
545 MatAXPY(m, 1./Model::time_->dt(),
mass_matrix[i], SUBSET_NONZERO_PATTERN);
548 VecDuplicate(
rhs[i], &w);
549 VecWAXPY(w, 1./Model::time_->dt(),
mass_vec[i],
rhs[i]);
568 template<
class Model>
572 unsigned int i_cell=0;
573 for (
auto cell :
feo->
dh()->own_range() )
576 unsigned int n_dofs = 0;
580 n_dofs =
feo->
fe<1>()->n_dofs();
583 n_dofs =
feo->
fe<2>()->n_dofs();
586 n_dofs =
feo->
fe<3>()->n_dofs();
591 cell.get_dof_indices(dof_indices);
593 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
597 for (
unsigned int j=0; j<n_dofs; ++j)
598 solution_elem_[sbi][i_cell] +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
609 template<
class Model>
622 Model::output_data();
625 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
626 Model::balance_->calculate_instant(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
627 Model::balance_->output();
634 template<
class Model>
637 if (Model::balance_->cumulative())
639 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
641 Model::balance_->calculate_cumulative(Model::subst_idx[sbi],
ls[sbi]->
get_solution());
653 template<
class Model>
657 Model::balance_->start_mass_assembly(Model::subst_idx);
658 assemble_mass_matrix<1>();
659 assemble_mass_matrix<2>();
660 assemble_mass_matrix<3>();
661 Model::balance_->finish_mass_assembly(Model::subst_idx);
666 template<
class Model>
template<
unsigned int dim>
670 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
672 PetscScalar local_mass_matrix[ndofs*ndofs], local_retardation_balance_vector[ndofs];
676 for (
auto cell :
feo->
dh()->own_range() )
678 if (cell.dim() != dim)
continue;
682 cell.get_dof_indices(dof_indices);
687 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
690 for (
unsigned int i=0; i<ndofs; i++)
692 for (
unsigned int j=0; j<ndofs; j++)
694 local_mass_matrix[i*ndofs+j] = 0;
695 for (
unsigned int k=0; k<qsize; k++)
700 for (
unsigned int i=0; i<ndofs; i++)
702 local_mass_balance_vector[i] = 0;
703 local_retardation_balance_vector[i] = 0;
704 for (
unsigned int k=0; k<qsize; k++)
711 Model::balance_->add_mass_matrix_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), dof_indices, local_mass_balance_vector);
712 ls_dt[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_mass_matrix);
713 VecSetValues(
ret_vec[sbi], ndofs, &(dof_indices[0]), local_retardation_balance_vector, ADD_VALUES);
721 template<
class Model>
726 assemble_volume_integrals<1>();
727 assemble_volume_integrals<2>();
728 assemble_volume_integrals<3>();
732 assemble_fluxes_boundary<1>();
733 assemble_fluxes_boundary<2>();
734 assemble_fluxes_boundary<3>();
738 assemble_fluxes_element_element<1>();
739 assemble_fluxes_element_element<2>();
740 assemble_fluxes_element_element<3>();
744 assemble_fluxes_element_side<1>();
745 assemble_fluxes_element_side<2>();
746 assemble_fluxes_element_side<3>();
753 template<
class Model>
754 template<
unsigned int dim>
761 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
765 PetscScalar local_matrix[ndofs*ndofs];
768 for (
auto cell :
feo->
dh()->local_range() )
770 if (!cell.is_own())
continue;
771 if (cell.dim() != dim)
continue;
776 cell.get_dof_indices(dof_indices);
780 Model::compute_sources_sigma(fe_values.
point_list(), elm, sources_sigma);
783 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
785 for (
unsigned int i=0; i<ndofs; i++)
786 for (
unsigned int j=0; j<ndofs; j++)
787 local_matrix[i*ndofs+j] = 0;
789 for (
unsigned int k=0; k<qsize; k++)
791 for (
unsigned int i=0; i<ndofs; i++)
796 for (
unsigned int j=0; j<ndofs; j++)
802 ls[sbi]->
mat_set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), local_matrix);
808 template<
class Model>
812 Model::balance_->start_source_assembly(Model::subst_idx);
816 Model::balance_->finish_source_assembly(Model::subst_idx);
820 template<
class Model>
821 template<
unsigned int dim>
826 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
832 PetscScalar local_rhs[ndofs];
837 for (
auto cell :
feo->
dh()->own_range() )
839 if (cell.dim() != dim)
continue;
843 cell.get_dof_indices(dof_indices);
844 cell.get_loc_dof_indices(loc_dof_indices);
846 Model::compute_source_coefficients(fe_values.
point_list(), elm, sources_conc, sources_density, sources_sigma);
849 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
851 fill_n(local_rhs, ndofs, 0);
852 local_source_balance_vector.assign(ndofs, 0);
853 local_source_balance_rhs.assign(ndofs, 0);
856 for (
unsigned int k=0; k<qsize; k++)
858 source = (sources_density[sbi][k] + sources_conc[sbi][k]*sources_sigma[sbi][k])*fe_values.
JxW(k);
860 for (
unsigned int i=0; i<ndofs; i++)
865 for (
unsigned int i=0; i<ndofs; i++)
867 for (
unsigned int k=0; k<qsize; k++)
868 local_source_balance_vector[i] -= sources_sigma[sbi][k]*fe_values.
shape_value(i,k)*fe_values.
JxW(k);
870 local_source_balance_rhs[i] += local_rhs[i];
872 Model::balance_->add_source_values(Model::subst_idx[sbi], elm.
region().
bulk_idx(), loc_dof_indices,
873 local_source_balance_vector, local_source_balance_rhs);
883 double h_max = 0, h_min = numeric_limits<double>::infinity();
884 for (
unsigned int i=0; i<e->
n_nodes(); i++)
885 for (
unsigned int j=i+1; j<e->
n_nodes(); j++)
895 template<
class Model>
896 template<
unsigned int dim>
902 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size(),
905 PetscScalar local_matrix[ndofs*ndofs];
908 double gamma_l, omega[2], transport_flux, delta[2], delta_sum;
909 double aniso1, aniso2;
911 for (
unsigned int sid=0; sid<n_max_sides; sid++)
921 if (dh_cell.dim() != dim)
continue;
922 for(
DHCellSide cell_side : dh_cell.side_range() )
924 if (cell_side.n_edge_sides() < 2)
continue;
925 bool unique_edge = (cell_side.edge_sides().begin()->element().idx() != dh_cell.elm_idx());
926 if ( unique_edge )
continue;
930 auto dh_edge_cell =
feo->
dh()->cell_accessor_from_element( edge_side.elem_idx() );
932 dh_edge_cell.get_dof_indices(side_dof_indices[sid]);
933 fe_values[sid]->reinit(cell, edge_side.side_idx());
934 fsv_rt.
reinit(cell, edge_side.side_idx());
936 Model::compute_advection_diffusion_coefficients(fe_values[sid]->point_list(), side_velocity[sid], cell,
ad_coef_edg[sid],
dif_coef_edg[sid]);
937 dg_penalty[sid].resize(Model::n_substances());
938 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
942 arma::vec3 normal_vector = fe_values[0]->normal_vector(0);
945 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
948 double pflux = 0, nflux = 0;
953 for (
unsigned int k=0; k<qsize; k++)
954 fluxes[sid] +=
arma::dot(
ad_coef_edg[sid][sbi][k], fe_values[sid]->normal_vector(k))*fe_values[sid]->JxW(k);
955 fluxes[sid] /= edge_side.measure();
957 pflux += fluxes[sid];
959 nflux += fluxes[sid];
970 if (s2<=s1)
continue;
971 ASSERT(edge_side1.is_valid()).error(
"Invalid side of edge.");
973 arma::vec3 nv = fe_values[s1]->normal_vector(0);
977 if (fluxes[s2] > 0 && fluxes[s1] < 0)
978 transport_flux = fluxes[s1]*fabs(fluxes[s2]/pflux);
979 else if (fluxes[s2] < 0 && fluxes[s1] > 0)
980 transport_flux = fluxes[s1]*fabs(fluxes[s2]/nflux);
984 gamma_l = 0.5*fabs(transport_flux);
988 for (
unsigned int k=0; k<qsize; k++)
996 delta_sum = delta[0] + delta[1];
999 if (fabs(delta_sum) > 0)
1001 omega[0] = delta[1]/delta_sum;
1002 omega[1] = delta[0]/delta_sum;
1003 double local_alpha = max(dg_penalty[s1][sbi], dg_penalty[s2][sbi]);
1004 double h = edge_side1.diameter();
1007 gamma_l += local_alpha/h*aniso1*aniso2*(delta[0]*delta[1]/delta_sum);
1010 for (
int i=0; i<2; i++) omega[i] = 0;
1013 int sd[2];
bool is_side_own[2];
1014 sd[0] = s1; is_side_own[0] = edge_side1.cell().is_own();
1015 sd[1] = s2; is_side_own[1] = edge_side2.cell().is_own();
1017 #define AVERAGE(i,k,side_id) (fe_values[sd[side_id]]->shape_value(i,k)*0.5) 1018 #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]) 1019 #define JUMP(i,k,side_id) ((side_id==0?1:-1)*fe_values[sd[side_id]]->shape_value(i,k)) 1022 for (
int n=0; n<2; n++)
1024 if (!is_side_own[n])
continue;
1026 for (
int m=0; m<2; m++)
1028 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1029 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1030 local_matrix[i*fe_values[sd[m]]->n_dofs()+j] = 0;
1032 for (
unsigned int k=0; k<qsize; k++)
1034 double flux_times_JxW = transport_flux*fe_values[0]->JxW(k);
1035 double gamma_times_JxW = gamma_l*fe_values[0]->JxW(k);
1037 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
1039 double flux_JxW_jump_i = flux_times_JxW*
JUMP(i,k,n);
1040 double gamma_JxW_jump_i = gamma_times_JxW*
JUMP(i,k,n);
1041 double JxW_jump_i = fe_values[0]->JxW(k)*
JUMP(i,k,n);
1044 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
1046 int index = i*fe_values[sd[m]]->n_dofs()+j;
1049 local_matrix[index] += flux_JxW_jump_i*
AVERAGE(j,k,m);
1052 local_matrix[index] += gamma_JxW_jump_i*
JUMP(j,k,m);
1055 local_matrix[index] -=
WAVERAGE(j,k,m)*JxW_jump_i;
1056 local_matrix[index] -=
JUMP(j,k,m)*JxW_var_wavg_i;
1060 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);
1073 for (
unsigned int i=0; i<n_max_sides; i++)
1075 delete fe_values[i];
1080 template<
class Model>
1081 template<
unsigned int dim>
1088 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1090 PetscScalar local_matrix[ndofs*ndofs];
1097 for (
auto cell :
feo->
dh()->local_range() )
1099 if (!cell.is_own())
continue;
1100 for(
DHCellSide cell_side : cell.side_range() )
1102 Side side = cell_side.side();
1105 if (side.
dim() != dim-1)
continue;
1110 cell.get_dof_indices(side_dof_indices);
1115 Model::compute_advection_diffusion_coefficients(fe_values_side.
point_list(), side_velocity, elm_acc,
ad_coef,
dif_coef);
1118 data_.cross_section.value_list(fe_values_side.
point_list(), elm_acc, csection);
1120 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1122 for (
unsigned int i=0; i<ndofs; i++)
1123 for (
unsigned int j=0; j<ndofs; j++)
1124 local_matrix[i*ndofs+j] = 0;
1128 double side_flux = 0;
1129 for (
unsigned int k=0; k<qsize; k++)
1131 double transport_flux = side_flux/side.
measure();
1138 transport_flux += gamma_l;
1142 for (
unsigned int k=0; k<qsize; k++)
1144 double flux_times_JxW;
1148 flux_times_JxW = csection[k]*robin_sigma[k]*fe_values_side.
JxW(k);
1153 flux_times_JxW = (transport_flux + csection[k]*robin_sigma[k])*fe_values_side.
JxW(k);
1158 flux_times_JxW = transport_flux*fe_values_side.
JxW(k);
1160 for (
unsigned int i=0; i<ndofs; i++)
1162 for (
unsigned int j=0; j<ndofs; j++)
1165 local_matrix[i*ndofs+j] += flux_times_JxW*fe_values_side.
shape_value(i,k)*fe_values_side.
shape_value(j,k);
1171 )*fe_values_side.
JxW(k);
1176 ls[sbi]->
mat_set_values(ndofs, &(side_dof_indices[0]), ndofs, &(side_dof_indices[0]), local_matrix);
1183 template<
class Model>
1184 template<
unsigned int dim>
1188 if (dim == 1)
return;
1199 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs();
1200 const unsigned int qsize =
feo->
q<dim-1>()->size();
1201 int side_dof_indices[2*ndofs];
1203 unsigned int n_dofs[2], n_indices;
1207 PetscScalar local_matrix[4*ndofs*ndofs];
1208 double comm_flux[2][2];
1212 fv_sb[0] = &fe_values_vb;
1213 fv_sb[1] = &fe_values_side;
1217 for(
DHCellSide neighb_side : cell_lower_dim.neighb_sides() )
1220 if (cell_lower_dim.elm().dim() != dim-1)
continue;
1223 n_indices = cell_lower_dim.get_dof_indices(indices);
1224 for(
unsigned int i=0; i<n_indices; ++i) {
1225 side_dof_indices[i] = indices[i];
1227 fe_values_vb.
reinit(elm_lower_dim);
1228 n_dofs[0] = fv_sb[0]->n_dofs();
1230 DHCellAccessor cell_higher_dim =
feo->
dh()->cell_accessor_from_element( neighb_side.element().idx() );
1233 for(
unsigned int i=0; i<n_indices; ++i) {
1234 side_dof_indices[i+n_dofs[0]] = indices[i];
1236 fe_values_side.
reinit(elm_higher_dim, neighb_side.side_idx());
1237 n_dofs[1] = fv_sb[1]->n_dofs();
1240 bool own_element_id[2];
1241 own_element_id[0] = cell_lower_dim.is_own();
1242 own_element_id[1] = cell_higher_dim.
is_own();
1244 fsv_rt.
reinit(elm_higher_dim, neighb_side.side_idx());
1245 fv_rt.
reinit(elm_lower_dim);
1249 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_higher, elm_higher_dim, ad_coef_edg[1],
dif_coef_edg[1]);
1250 data_.cross_section.value_list(fe_values_vb.
point_list(), elm_lower_dim, csection_lower);
1251 data_.cross_section.value_list(fe_values_vb.
point_list(), elm_higher_dim, csection_higher);
1253 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1255 for (
unsigned int i=0; i<n_dofs[0]+n_dofs[1]; i++)
1256 for (
unsigned int j=0; j<n_dofs[0]+n_dofs[1]; j++)
1257 local_matrix[i*(n_dofs[0]+n_dofs[1])+j] = 0;
1262 for (
unsigned int k=0; k<qsize; k++)
1273 2*csection_higher[k]*csection_higher[k]/(csection_lower[k]*csection_lower[k]);
1277 comm_flux[0][0] = (sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1278 comm_flux[0][1] = -(sigma-min(0.,transport_flux))*fv_sb[0]->JxW(k);
1279 comm_flux[1][0] = -(sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1280 comm_flux[1][1] = (sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1282 for (
int n=0; n<2; n++)
1284 if (!own_element_id[n])
continue;
1286 for (
unsigned int i=0; i<n_dofs[n]; i++)
1287 for (
int m=0; m<2; m++)
1288 for (
unsigned int j=0; j<n_dofs[m]; j++)
1289 local_matrix[(i+n*n_dofs[0])*(n_dofs[0]+n_dofs[1]) + m*n_dofs[0] + j] +=
1290 comm_flux[m][n]*fv_sb[m]->shape_value(j,k)*fv_sb[n]->shape_value(i,k);
1293 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);
1304 template<
class Model>
1308 Model::balance_->start_flux_assembly(Model::subst_idx);
1309 set_boundary_conditions<1>();
1310 set_boundary_conditions<2>();
1311 set_boundary_conditions<3>();
1312 Model::balance_->finish_flux_assembly(Model::subst_idx);
1317 template<
class Model>
1318 template<
unsigned int dim>
1325 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim-1>()->size();
1327 double local_rhs[ndofs];
1329 PetscScalar local_flux_balance_rhs;
1333 bc_ref_values(qsize);
1337 for (
auto cell :
feo->
dh()->own_range() )
1339 if (cell.elm()->boundary_idx_ ==
nullptr)
continue;
1341 for (
unsigned int si=0; si<cell.elm()->n_sides(); si++)
1344 if (edg.
n_sides() > 1)
continue;
1349 if (edg.
side(0)->
dim() != dim-1)
continue;
1357 Model::get_bc_type(ele_acc, bc_type);
1366 auto dh_cell =
feo->
dh()->cell_accessor_from_element( side.
element().
idx() );
1367 dh_cell.get_dof_indices(side_dof_indices);
1369 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1371 fill_n(local_rhs, ndofs, 0);
1372 local_flux_balance_vector.assign(ndofs, 0);
1373 local_flux_balance_rhs = 0;
1377 data_.bc_dirichlet_value[sbi].value_list(fe_values_side.
point_list(), ele_acc, bc_values);
1379 double side_flux = 0;
1380 for (
unsigned int k=0; k<qsize; k++)
1382 double transport_flux = side_flux/side.
measure();
1386 for (
unsigned int k=0; k<qsize; k++)
1388 double bc_term = -transport_flux*bc_values[k]*fe_values_side.
JxW(k);
1389 for (
unsigned int i=0; i<ndofs; i++)
1390 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1392 for (
unsigned int i=0; i<ndofs; i++)
1393 local_flux_balance_rhs -= local_rhs[i];
1397 for (
unsigned int k=0; k<qsize; k++)
1399 double bc_term =
gamma[sbi][side.
cond_idx()]*bc_values[k]*fe_values_side.
JxW(k);
1401 for (
unsigned int i=0; i<ndofs; i++)
1402 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k)
1405 for (
unsigned int k=0; k<qsize; k++)
1407 for (
unsigned int i=0; i<ndofs; i++)
1414 if (Model::time_->tlevel() > 0)
1415 for (
unsigned int i=0; i<ndofs; i++)
1416 local_flux_balance_rhs -= local_rhs[i];
1420 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1421 for (
unsigned int k=0; k<qsize; k++)
1423 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1424 for (
unsigned int i=0; i<ndofs; i++)
1425 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1428 for (
unsigned int i=0; i<ndofs; i++)
1430 for (
unsigned int k=0; k<qsize; k++)
1431 local_flux_balance_vector[i] += csection[k]*bc_sigma[k]*fe_values_side.
JxW(k)*fe_values_side.
shape_value(i,k);
1432 local_flux_balance_rhs -= local_rhs[i];
1437 Model::get_flux_bc_data(sbi, fe_values_side.
point_list(), ele_acc, bc_fluxes, bc_sigma, bc_ref_values);
1438 for (
unsigned int k=0; k<qsize; k++)
1440 double bc_term = csection[k]*(bc_sigma[k]*bc_ref_values[k]+bc_fluxes[k])*fe_values_side.
JxW(k);
1441 for (
unsigned int i=0; i<ndofs; i++)
1442 local_rhs[i] += bc_term*fe_values_side.
shape_value(i,k);
1445 for (
unsigned int i=0; i<ndofs; i++)
1447 for (
unsigned int k=0; k<qsize; k++)
1449 local_flux_balance_rhs -= local_rhs[i];
1454 for (
unsigned int k=0; k<qsize; k++)
1456 for (
unsigned int i=0; i<ndofs; i++)
1462 Model::balance_->add_flux_matrix_values(Model::subst_idx[sbi], side, side_dof_indices, local_flux_balance_vector);
1463 Model::balance_->add_flux_vec_value(Model::subst_idx[sbi], side, local_flux_balance_rhs);
1471 template<
class Model>
1472 template<
unsigned int dim>
1477 OLD_ASSERT(cell->
dim() == dim,
"Element dimension mismatch!");
1481 for (
unsigned int k=0; k<fv.
n_points(); k++)
1483 velocity[k].zeros();
1484 for (
unsigned int sid=0; sid<cell->
n_sides(); sid++)
1485 for (
unsigned int c=0; c<3; ++c)
1492 template<
class Model>
1501 double delta = 0, h = 0;
1504 if (side.
dim() == 0)
1510 for (
unsigned int i=0; i<side.
n_nodes(); i++)
1511 for (
unsigned int j=i+1; j<side.
n_nodes(); j++)
1512 h = max(h, side.
node(i)->distance( *side.
node(j).node() ));
1516 for (
int k=0; k<K_size; k++)
1517 delta +=
dot(K[k]*normal_vector,normal_vector);
1527 template<
class Model>
1531 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1532 ls[sbi]->start_allocation();
1533 prepare_initial_condition<1>();
1534 prepare_initial_condition<2>();
1535 prepare_initial_condition<3>();
1537 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1538 ls[sbi]->start_add_assembly();
1539 prepare_initial_condition<1>();
1540 prepare_initial_condition<2>();
1541 prepare_initial_condition<3>();
1543 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1551 template<
class Model>
1552 template<
unsigned int dim>
1557 const unsigned int ndofs =
feo->
fe<dim>()->n_dofs(), qsize =
feo->
q<dim>()->size();
1559 double matrix[ndofs*ndofs],
rhs[ndofs];
1562 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1563 init_values[sbi].resize(qsize);
1565 for (
auto cell :
feo->
dh()->own_range() )
1567 if (cell.dim() != dim)
continue;
1570 cell.get_dof_indices(dof_indices);
1573 Model::compute_init_cond(fe_values.
point_list(), elem, init_values);
1575 for (
unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
1577 for (
unsigned int i=0; i<ndofs; i++)
1580 for (
unsigned int j=0; j<ndofs; j++)
1581 matrix[i*ndofs+j] = 0;
1584 for (
unsigned int k=0; k<qsize; k++)
1586 double rhs_term = init_values[sbi][k]*fe_values.
JxW(k);
1588 for (
unsigned int i=0; i<ndofs; i++)
1590 for (
unsigned int j=0; j<ndofs; j++)
1596 ls[sbi]->
set_values(ndofs, &(dof_indices[0]), ndofs, &(dof_indices[0]), matrix, rhs);
1602 template<
class Model>
1605 el_4_loc = Model::mesh_->get_el_4_loc();
1606 el_ds = Model::mesh_->get_el_ds();
1610 template<
class Model>
1613 if (solution_changed)
1615 unsigned int i_cell=0;
1616 for (
auto cell :
feo->
dh()->own_range() )
1619 unsigned int n_dofs = 0;
1623 n_dofs =
feo->
fe<1>()->n_dofs();
1626 n_dofs =
feo->
fe<2>()->n_dofs();
1629 n_dofs =
feo->
fe<3>()->n_dofs();
1634 cell.get_dof_indices(dof_indices);
1636 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1638 double old_average = 0;
1639 for (
unsigned int j=0; j<n_dofs; ++j)
1640 old_average +=
ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()];
1641 old_average /= n_dofs;
1643 for (
unsigned int j=0; j<n_dofs; ++j)
1644 ls[sbi]->get_solution_array()[dof_indices[j]-
feo->
dh()->distr()->begin()] +=
solution_elem_[sbi][i_cell] - old_average;
1650 for (
unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
1654 template<
class Model>
1657 return Model::mesh_->get_row_4_el();
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Input::Record input_rec
Record with input specification.
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell...
unsigned int n_sides() const
Returns number of sides aligned with the edge.
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)
FiniteElement< 2 > * fe_rt2_
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.
MappingP1< 3, 3 > * map3_
virtual PetscErrorCode set_matrix(Mat &, MatStructure)
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
Returns local index of the side on the element.
void calculate_concentration_matrix()
Transport with dispersion implemented using discontinuous Galerkin method.
Edge edge() const
Returns pointer to the edge connected to the side.
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
Returns iterator to the element of the side.
vector< double > ret_sources_prev
MultiField< 3, FieldValue< 3 >::Scalar > dg_penalty
Penalty enforcing inter-element continuity of solution (for each substance).
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.
FiniteElement< 0 > * fe0_
Finite elements for the solution of the advection-diffusion equation.
MultiField< 3, FieldValue< 3 >::Scalar > fracture_sigma
Transition parameter for diffusive transfer on fractures (for each substance).
unsigned int dim() const
Returns dimension of the side, that is dimension of the element minus one.
vector< vector< arma::mat33 > > dif_coef
Diffusion coefficients.
FEObjects * feo
Finite element objects.
bool is_boundary() const
Returns true for side on the boundary.
FiniteElement< 2 > * fe2_
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.
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::shared_ptr< DiscreteSpace > ds_
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.
NodeAccessor< 3 > node(unsigned int i) const
Returns node for given local index i on the side.
FiniteElement< 1 > * fe_rt1_
Finite elements for the water velocity field.
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.
MappingP1< 2, 3 > * map2_
virtual PetscErrorCode rhs_zero_entries()
void set_solution(Vec sol_vec)
virtual PetscErrorCode set_rhs(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).
Quadrature * q_[4]
Quadratures used in assembling methods.
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
Returns global index of the prescribed boundary condition.
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)
FiniteElement< 1 > * fe1_
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)
FiniteElement< 3 > * fe3_
FiniteElement< 3 > * fe_rt3_
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()
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.
unsigned int size() const
Returns number of quadrature points.
static UnitSI & dimensionless()
Returns dimensionless unit.
static bool print_message_table(ostream &stream, std::string equation_name)
MappingP1< 1, 3 > * map1_
Auxiliary mappings of reference elements.
~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
Gets side iterator of the i -th side.
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.
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
ElementAccessor< 3 > element_accessor()
std::shared_ptr< DOFHandlerMultiDim > dh_
Object for distribution of dofs.
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
Returns number of nodes of the side.
Transformed quadrature weights.
Calculates finite element data on a side.
const Node * node(unsigned int ni) const