32 #include <boost/foreach.hpp>
53 using namespace Input::Type;
57 =
Selection(
"DG_variant",
"Type of penalty term.")
58 .
add_value(non_symmetric,
"non-symmetric",
"non-symmetric weighted interior penalty DG method")
59 .
add_value(incomplete,
"incomplete",
"incomplete weighted interior penalty DG method")
60 .
add_value(symmetric,
"symmetric",
"symmetric weighted interior penalty DG method");
65 .
add_value(inflow,
"inflow",
"Dirichlet BC on inflow and homogeneous Neumann BC on outflow.")
72 Model::ModelEqData::get_output_selection_input_type(
"DG",
"DG solver")
73 .copy_values(EqData().output_fields.make_output_field_selection(
"").close())
78 = Model::get_input_type(
"DG",
"DG solver")
80 "Linear solver for MH problem.")
83 "Variant of interior penalty discontinuous Galerkin method.")
85 "Polynomial order for finite element in DG method (order 0 is suitable if there is no diffusion/dispersion).")
86 .declare_key(
"output_fields",
Array(EqData::output_selection),
87 Default(Model::ModelEqData::default_output_field()),
88 "List of fields to write to output file.");
127 xprintf(
PrgErr,
"Unsupported polynomial order %d for finite elements in TransportDG ", fe_order);
147 dh_->distribute_dofs(*fe1_, *fe2_, *fe3_);
193 template<
class Model>
197 ADD_FIELD(
dg_penalty,
"Penalty parameter influencing the discontinuity of the solution (for each substance). "
198 "Its default value 1 is sufficient in most cases. Higher value diminishes the inter-element jumps.",
"1.0");
200 ADD_FIELD(
bc_type,
"Boundary condition type, possible values: inflow, dirichlet, neumann, robin.",
"\"inflow\"" );
210 this->output_fields += *
this;
215 template<
class Model>
222 static_assert(std::is_base_of<AdvectionDiffusionModel, Model>::value,
"");
238 data_.set_mesh(init_mesh);
246 data_.set_limit_side(LimitSide::left);
254 for (
int sbi=0; sbi<
n_subst_; sbi++)
261 DBGMSG(
"TDG: solution size %d\n", feo->dh()->n_global_dofs());
264 int qsize = max(feo->q<0>()->size(), max(feo->q<1>()->size(), max(feo->q<2>()->size(), feo->q<3>()->size())));
269 for (
int sbi=0; sbi<
n_subst_; sbi++)
276 for (
int sd=0; sd<max_edg_sides; sd++)
280 for (
int sbi=0; sbi<
n_subst_; sbi++)
291 for (
int sbi=0; sbi<
n_subst_; sbi++)
301 for (
int sbi=0; sbi<
n_subst_; sbi++)
305 output_field_ptr->set_fe_data(feo->dh(), feo->mapping<1>(), feo->mapping<2>(), feo->mapping<3>(), &
output_vec[sbi]);
308 data_.output_fields.set_limit_side(LimitSide::left);
322 for (
int sbi = 0; sbi <
n_subst_; sbi++) {
332 template<
class Model>
338 if (feo->dh()->el_ds()->myp() == 0)
342 VecDestroy(&output_vec[i]);
343 delete[] output_solution[i];
350 MatDestroy(&stiffness_matrix[i]);
354 delete[] stiffness_matrix;
361 delete output_stream;
365 template<
class Model>
369 VecScatter output_scatter;
371 for (
int sbi=0; sbi<
n_subst_; sbi++)
374 ISCreateBlock(PETSC_COMM_SELF, ls[sbi]->size(), 1, idx, PETSC_COPY_VALUES, &is);
375 VecScatterCreate(ls[sbi]->get_solution(), is, output_vec[sbi], PETSC_NULL, &output_scatter);
376 VecScatterBegin(output_scatter, ls[sbi]->get_solution(), output_vec[sbi], INSERT_VALUES, SCATTER_FORWARD);
377 VecScatterEnd(output_scatter, ls[sbi]->get_solution(), output_vec[sbi], INSERT_VALUES, SCATTER_FORWARD);
378 VecScatterDestroy(&(output_scatter));
385 template<
class Model>
388 data_.set_time(*
time_);
391 set_initial_condition();
392 for (
int sbi = 0; sbi <
n_subst_; sbi++)
393 ( (
LinSys_PETSC *)ls[sbi] )->set_initial_guess_nonzero();
399 template<
class Model>
408 data_.set_time(*
time_);
412 if (!allocation_done)
415 ls_dt->start_allocation();
416 assemble_mass_matrix();
422 ls[i]->start_allocation();
423 stiffness_matrix[i] = NULL;
426 assemble_stiffness_matrix();
428 set_boundary_conditions();
430 allocation_done =
true;
434 if (mass_matrix == NULL ||
435 mass_matrix_changed())
437 ls_dt->start_add_assembly();
438 ls_dt->mat_zero_entries();
439 assemble_mass_matrix();
440 ls_dt->finish_assembly();
441 mass_matrix = ls_dt->get_matrix();
445 if (stiffness_matrix[0] == NULL ||
446 stiffness_matrix_changed())
452 ls[i]->start_add_assembly();
453 ls[i]->mat_zero_entries();
455 assemble_stiffness_matrix();
458 ls[i]->finish_assembly();
460 if (stiffness_matrix[i] == NULL)
461 MatConvert(ls[i]->get_matrix(), MATSAME, MAT_INITIAL_MATRIX, &stiffness_matrix[i]);
463 MatCopy(ls[i]->get_matrix(), stiffness_matrix[i], DIFFERENT_NONZERO_PATTERN);
468 if (rhs[0] == NULL ||
473 ls[i]->start_add_assembly();
474 ls[i]->rhs_zero_entries();
477 set_boundary_conditions();
480 ls[i]->finish_assembly();
482 VecDuplicate(ls[i]->get_rhs(), &rhs[i]);
483 VecCopy(ls[i]->get_rhs(), rhs[i]);
487 Model::flux_changed =
false;
510 MatConvert(stiffness_matrix[i], MATSAME, MAT_INITIAL_MATRIX, &m);
511 MatAXPY(m, 1./
time_->
dt(), mass_matrix, SUBSET_NONZERO_PATTERN);
512 ls[i]->set_matrix(m, DIFFERENT_NONZERO_PATTERN);
514 VecDuplicate(rhs[i], &y);
515 VecDuplicate(rhs[i], &w);
516 MatMult(mass_matrix, ls[i]->get_solution(), y);
517 VecWAXPY(w, 1./
time_->
dt(), y, rhs[i]);
536 template<
class Model>
541 template<
class Model>
546 template<
class Model>
553 Model::flux_changed =
true;
558 template<
class Model>
562 unsigned int dof_indices[max(feo->fe<1>()->n_dofs(), max(feo->fe<2>()->n_dofs(), feo->fe<3>()->n_dofs()))];
569 output_vector_gather();
570 data_.output_fields.set_time(*
time_);
571 data_.output_fields.output(output_stream);
572 output_stream->write_time_frame();
581 template<
class Model>
585 assemble_mass_matrix<1>();
586 assemble_mass_matrix<2>();
587 assemble_mass_matrix<3>();
592 template<
class Model>
template<
unsigned int dim>
596 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
597 unsigned int dof_indices[ndofs];
598 PetscScalar local_mass_matrix[ndofs*ndofs];
601 for (
int i_cell=0; i_cell<feo->dh()->el_ds()->lsize(); i_cell++)
604 if (cell->dim() != dim)
continue;
606 fe_values.reinit(cell);
607 feo->dh()->get_dof_indices(cell, dof_indices);
610 Model::compute_mass_matrix_coefficient(fe_values.point_list(), ele_acc, mm_coef);
613 for (
unsigned int i=0; i<ndofs; i++)
615 for (
unsigned int j=0; j<ndofs; j++)
617 local_mass_matrix[i*ndofs+j] = 0;
618 for (
unsigned int k=0; k<qsize; k++)
619 local_mass_matrix[i*ndofs+j] += mm_coef[k]*fe_values.shape_value(j,k)*fe_values.shape_value(i,k)*fe_values.JxW(k);
623 ls_dt->mat_set_values(ndofs, (
int *)dof_indices, ndofs, (
int *)dof_indices, local_mass_matrix);
630 template<
class Model>
635 assemble_volume_integrals<1>();
636 assemble_volume_integrals<2>();
637 assemble_volume_integrals<3>();
641 assemble_fluxes_boundary<1>();
642 assemble_fluxes_boundary<2>();
643 assemble_fluxes_boundary<3>();
647 assemble_fluxes_element_element<1>();
648 assemble_fluxes_element_element<2>();
649 assemble_fluxes_element_element<3>();
653 assemble_fluxes_element_side<1>();
654 assemble_fluxes_element_side<2>();
655 assemble_fluxes_element_side<3>();
662 template<
class Model>
663 template<
unsigned int dim>
666 FEValues<dim,3> fv_rt(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe_rt<dim>(),
668 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
670 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
671 unsigned int dof_indices[ndofs];
674 PetscScalar local_matrix[ndofs*ndofs];
677 for (
int i_cell=0; i_cell<feo->dh()->el_ds()->lsize(); i_cell++)
680 if (cell->dim() != dim)
continue;
685 feo->dh()->get_dof_indices(cell, dof_indices);
687 calculate_velocity(cell, velocity, fv_rt);
688 Model::compute_advection_diffusion_coefficients(fe_values.
point_list(), velocity, ele_acc, ad_coef, dif_coef);
689 Model::compute_sources_sigma(fe_values.
point_list(), ele_acc, sources_sigma);
692 for (
int sbi=0; sbi<
n_subst_; sbi++)
694 for (
unsigned int i=0; i<ndofs; i++)
695 for (
unsigned int j=0; j<ndofs; j++)
696 local_matrix[i*ndofs+j] = 0;
698 for (
unsigned int k=0; k<qsize; k++)
700 for (
unsigned int i=0; i<ndofs; i++)
703 double ad_dot_grad_i = arma::dot(ad_coef[sbi][k], fe_values.
shape_grad(i,k));
705 for (
unsigned int j=0; j<ndofs; j++)
706 local_matrix[i*ndofs+j] += (arma::dot(Kt_grad_i, fe_values.
shape_grad(j,k))
711 ls[sbi]->mat_set_values(ndofs, (
int *)dof_indices, ndofs, (
int *)dof_indices, local_matrix);
717 template<
class Model>
727 template<
class Model>
728 template<
unsigned int dim>
731 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
733 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
734 vector<arma::vec> sources_conc(qsize), sources_density(qsize), sources_sigma(qsize);
735 unsigned int dof_indices[ndofs];
736 PetscScalar local_rhs[ndofs];
740 for (
int i_cell=0; i_cell<feo->dh()->el_ds()->lsize(); i_cell++)
743 if (cell->dim() != dim)
continue;
745 fe_values.reinit(cell);
746 feo->dh()->get_dof_indices(cell, dof_indices);
748 Model::compute_source_coefficients(fe_values.point_list(), cell->element_accessor(), sources_conc, sources_density, sources_sigma);
751 for (
int sbi=0; sbi<
n_subst_; sbi++)
753 for (
unsigned int i=0; i<ndofs; i++)
757 for (
unsigned int k=0; k<qsize; k++)
759 source = (sources_density[k][sbi] + sources_conc[k][sbi]*sources_sigma[k][sbi])*fe_values.JxW(k);
761 for (
unsigned int i=0; i<ndofs; i++)
762 local_rhs[i] += source*fe_values.shape_value(i,k);
764 ls[sbi]->rhs_set_values(ndofs, (
int *)dof_indices, local_rhs);
771 template<
class Model>
772 template<
unsigned int dim>
778 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size(),
779 n_max_sides = ad_coef_edg.size();
781 PetscScalar local_matrix[ndofs*ndofs];
784 double gamma_l, omega[2], transport_flux;
786 for (
int sid=0; sid<n_max_sides; sid++)
788 side_dof_indices.push_back(
new unsigned int[ndofs]);
789 fe_values.push_back(
new FESideValues<dim,3>(*feo->mapping<dim>(), *feo->q<dim-1>(), *feo->fe<dim>(),
794 for (
int iedg=0; iedg<feo->dh()->n_loc_edges(); iedg++)
799 for (
int sid=0; sid<edg->
n_sides; sid++)
803 feo->dh()->get_dof_indices(cell, side_dof_indices[sid]);
804 fe_values[sid]->reinit(cell, edg->
side(sid)->
el_idx());
806 calculate_velocity(cell, side_velocity[sid], fsv_rt);
807 Model::compute_advection_diffusion_coefficients(fe_values[sid]->point_list(), side_velocity[sid], ele_acc, ad_coef_edg[sid], dif_coef_edg[sid]);
808 dg_penalty[sid] = data_.dg_penalty.value(cell->centre(), ele_acc);
812 for (
int sbi=0; sbi<
n_subst_; sbi++)
815 for (
unsigned int sid=0; sid<edg->
n_sides; sid++)
818 for (
unsigned int k=0; k<qsize; k++)
819 fluxes[sid] += arma::dot(ad_coef_edg[sid][sbi][k], fe_values[sid]->normal_vector(k))*fe_values[sid]->JxW(k);
823 for (
int s1=0; s1<edg->
n_sides; s1++)
825 for (
int s2=s1+1; s2<edg->
n_sides; s2++)
831 arma::vec3 nv = fe_values[s1]->normal_vector(0);
834 set_DG_parameters_edge(*edg, s1, s2, qsize, dif_coef_edg[s1][sbi], dif_coef_edg[s2][sbi], fluxes, fe_values[0]->normal_vector(0), dg_penalty[s1][sbi], dg_penalty[s2][sbi], gamma_l, omega, transport_flux);
840 #define AVERAGE(i,k,side_id) (fe_values[sd[side_id]]->shape_value(i,k)*0.5)
841 #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])
842 #define JUMP(i,k,side_id) ((side_id==0?1:-1)*fe_values[sd[side_id]]->shape_value(i,k))
845 for (
int n=0; n<2; n++)
849 for (
int m=0; m<2; m++)
851 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
852 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
853 local_matrix[i*fe_values[sd[m]]->n_dofs()+j] = 0;
855 for (
unsigned int k=0; k<qsize; k++)
857 double flux_times_JxW = transport_flux*fe_values[0]->JxW(k);
858 double gamma_times_JxW = gamma_l*fe_values[0]->JxW(k);
860 for (
unsigned int i=0; i<fe_values[sd[n]]->n_dofs(); i++)
862 double flux_JxW_jump_i = flux_times_JxW*
JUMP(i,k,n);
863 double gamma_JxW_jump_i = gamma_times_JxW*JUMP(i,k,n);
864 double JxW_jump_i = fe_values[0]->JxW(k)*JUMP(i,k,n);
865 double JxW_var_wavg_i = fe_values[0]->JxW(k)*
WAVERAGE(i,k,n)*dg_variant;
867 for (
unsigned int j=0; j<fe_values[sd[m]]->n_dofs(); j++)
869 int index = i*fe_values[sd[m]]->n_dofs()+j;
872 local_matrix[index] += flux_JxW_jump_i*
AVERAGE(j,k,m);
875 local_matrix[index] += gamma_JxW_jump_i*JUMP(j,k,m);
878 local_matrix[index] -=
WAVERAGE(j,k,m)*JxW_jump_i;
879 local_matrix[index] -= JUMP(j,k,m)*JxW_var_wavg_i;
883 ls[sbi]->mat_set_values(fe_values[sd[n]]->n_dofs(), (
int *)side_dof_indices[sd[n]], fe_values[sd[m]]->n_dofs(), (
int *)side_dof_indices[sd[m]], local_matrix);
894 for (
unsigned int i=0; i<n_max_sides; i++)
897 delete[] side_dof_indices[i];
902 template<
class Model>
903 template<
unsigned int dim>
906 FESideValues<dim,3> fe_values_side(*feo->mapping<dim>(), *feo->q<dim-1>(), *feo->fe<dim>(),
910 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size();
911 unsigned int side_dof_indices[ndofs];
912 PetscScalar local_matrix[ndofs*ndofs];
915 arma::vec dg_penalty;
919 for (
int iedg=0; iedg<feo->dh()->n_loc_edges(); iedg++)
922 if (edg->
n_sides > 1)
continue;
924 if (edg->
side(0)->
dim() != dim-1)
continue;
926 if (edg->
side(0)->
cond() == NULL)
continue;
931 feo->dh()->get_dof_indices(cell, side_dof_indices);
935 calculate_velocity(cell, side_velocity, fsv_rt);
936 Model::compute_advection_diffusion_coefficients(fe_values_side.
point_list(), side_velocity, ele_acc, ad_coef, dif_coef);
937 dg_penalty = data_.dg_penalty.value(cell->centre(), ele_acc);
941 for (
int sbi=0; sbi<
n_subst_; sbi++)
943 for (
unsigned int i=0; i<ndofs; i++)
944 for (
unsigned int j=0; j<ndofs; j++)
945 local_matrix[i*ndofs+j] = 0;
949 double side_flux = 0;
950 for (
unsigned int k=0; k<qsize; k++)
951 side_flux += arma::dot(ad_coef[sbi][k], fe_values_side.
normal_vector(k))*fe_values_side.
JxW(k);
952 double transport_flux = side_flux/side->
measure();
954 if ((bc_type[sbi] == EqData::dirichlet) || (bc_type[sbi] == EqData::inflow ))
957 set_DG_parameters_boundary(side, qsize, dif_coef[sbi], transport_flux, fe_values_side.
normal_vector(0), dg_penalty[sbi], gamma_l);
958 gamma[sbi][side->
cond_idx()] = gamma_l;
959 if (bc_type[sbi] == EqData::dirichlet || side_flux < -mh_dh->precision())
960 transport_flux += gamma_l;
964 for (
unsigned int k=0; k<qsize; k++)
966 double flux_times_JxW;
967 if (bc_type[sbi] == EqData::robin)
968 flux_times_JxW = (transport_flux + robin_sigma[k][sbi])*fe_values_side.
JxW(k);
970 flux_times_JxW = transport_flux*fe_values_side.
JxW(k);
972 for (
unsigned int i=0; i<ndofs; i++)
973 for (
unsigned int j=0; j<ndofs; j++)
976 local_matrix[i*ndofs+j] += flux_times_JxW*fe_values_side.
shape_value(i,k)*fe_values_side.
shape_value(j,k);
979 if (bc_type[sbi] == EqData::dirichlet || (bc_type[sbi] == EqData::inflow && side_flux < -mh_dh->precision()))
982 )*fe_values_side.
JxW(k);
985 ls[sbi]->mat_set_values(ndofs, (
int *)side_dof_indices, ndofs, (
int *)side_dof_indices, local_matrix);
991 template<
class Model>
992 template<
unsigned int dim>
996 if (dim == 1)
return;
997 FEValues<dim-1,3> fe_values_vb(*feo->mapping<dim-1>(), *feo->q<dim-1>(), *feo->
fe<dim-1>(),
1003 FEValues<dim-1,3> fv_rt(*feo->mapping<dim-1>(), *feo->q<dim-1>(), *feo->fe_rt<dim-1>(),
1007 const unsigned int ndofs = feo->fe<dim>()->n_dofs();
1008 const unsigned int qsize = feo->q<dim-1>()->size();
1009 unsigned int side_dof_indices[2*ndofs], n_dofs[2];
1012 vector<double> csection_lower(qsize), csection_higher(qsize), mm_coef_lower(qsize), mm_coef_higher(qsize);
1013 PetscScalar local_matrix[4*ndofs*ndofs];
1014 double comm_flux[2][2];
1018 fv_sb[0] = &fe_values_vb;
1019 fv_sb[1] = &fe_values_side;
1022 for (
int inb=0; inb<feo->dh()->n_loc_nb(); inb++)
1029 feo->dh()->get_dof_indices(cell_sub, side_dof_indices);
1030 fe_values_vb.
reinit(cell_sub);
1031 n_dofs[0] = fv_sb[0]->n_dofs();
1034 feo->dh()->get_dof_indices(cell, side_dof_indices+n_dofs[0]);
1036 n_dofs[1] = fv_sb[1]->n_dofs();
1040 element_id[0] = cell_sub.
index();
1041 element_id[1] = cell.
index();
1045 calculate_velocity(cell, velocity_higher, fsv_rt);
1046 calculate_velocity(cell_sub, velocity_lower, fv_rt);
1047 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_lower, cell_sub->element_accessor(), ad_coef_edg[0], dif_coef_edg[0]);
1048 Model::compute_advection_diffusion_coefficients(fe_values_vb.
point_list(), velocity_higher, cell->element_accessor(), ad_coef_edg[1], dif_coef_edg[1]);
1049 Model::compute_mass_matrix_coefficient(fe_values_vb.
point_list(), cell_sub->element_accessor(), mm_coef_lower);
1050 Model::compute_mass_matrix_coefficient(fe_values_vb.
point_list(), cell->element_accessor(), mm_coef_higher);
1051 data_.cross_section.value_list(fe_values_vb.
point_list(), cell_sub->element_accessor(), csection_lower);
1052 data_.cross_section.value_list(fe_values_vb.
point_list(), cell->element_accessor(), csection_higher);
1053 data_.fracture_sigma.value_list(fe_values_vb.
point_list(), cell_sub->element_accessor(), frac_sigma);
1055 for (
int sbi=0; sbi<
n_subst_; sbi++)
1057 for (
unsigned int i=0; i<n_dofs[0]+n_dofs[1]; i++)
1058 for (
unsigned int j=0; j<n_dofs[0]+n_dofs[1]; j++)
1059 local_matrix[i*(n_dofs[0]+n_dofs[1])+j] = 0;
1062 for (
unsigned int k=0; k<qsize; k++)
1072 double sigma = frac_sigma[k][sbi]*arma::dot(dif_coef_edg[0][sbi][k]*fe_values_side.
normal_vector(k),fe_values_side.
normal_vector(k))*
1073 2*csection_higher[k]*csection_higher[k]/(csection_lower[k]*csection_lower[k]);
1076 double transport_flux = arma::dot(ad_coef_edg[1][sbi][k], fe_values_side.
normal_vector(k));
1077 double por_lower_over_higher = mm_coef_lower[k]*csection_higher[k]/(mm_coef_higher[k]*csection_lower[k]);
1079 comm_flux[0][0] = (sigma-min(0.,transport_flux*por_lower_over_higher))*fv_sb[0]->JxW(k);
1080 comm_flux[0][1] = -(sigma-min(0.,transport_flux*por_lower_over_higher))*fv_sb[0]->JxW(k);
1081 comm_flux[1][0] = -(sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1082 comm_flux[1][1] = (sigma+max(0.,transport_flux))*fv_sb[0]->JxW(k);
1084 for (
int n=0; n<2; n++)
1086 if (!feo->dh()->el_is_local(element_id[n]))
continue;
1088 for (
unsigned int i=0; i<n_dofs[n]; i++)
1089 for (
int m=0; m<2; m++)
1090 for (
unsigned int j=0; j<n_dofs[m]; j++)
1091 local_matrix[(i+n*n_dofs[0])*(n_dofs[0]+n_dofs[1]) + m*n_dofs[0] + j] +=
1092 comm_flux[m][n]*fv_sb[m]->shape_value(j,k)*fv_sb[n]->shape_value(i,k);
1095 ls[sbi]->mat_set_values(n_dofs[0]+n_dofs[1], (
int *)side_dof_indices, n_dofs[0]+n_dofs[1], (
int *)side_dof_indices, local_matrix);
1106 template<
class Model>
1110 set_boundary_conditions<1>();
1111 set_boundary_conditions<2>();
1112 set_boundary_conditions<3>();
1117 template<
class Model>
1118 template<
unsigned int dim>
1121 FESideValues<dim,3> fe_values_side(*feo->mapping<dim>(), *feo->q<dim-1>(), *feo->fe<dim>(),
1125 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size();
1126 unsigned int side_dof_indices[ndofs];
1127 double local_rhs[ndofs];
1131 for (
int i=0; i<qsize; i++)
1133 bc_values[i].resize(n_subst_);
1134 bc_fluxes[i].resize(n_subst_);
1135 bc_sigma[i].resize(n_subst_);
1138 for (
int iedg=0; iedg<feo->dh()->n_loc_edges(); iedg++)
1141 if (edg->
n_sides > 1)
continue;
1142 if (edg->
side(0)->
dim() != dim-1)
continue;
1144 if (edg->
side(0)->
cond() == NULL)
continue;
1150 arma::uvec bc_type = data_.bc_type.value(side->
cond()->
element()->
centre(), ele_acc);
1152 fe_values_side.reinit(cell, side->
el_idx());
1153 fsv_rt.reinit(cell, side->
el_idx());
1154 calculate_velocity(cell, velocity, fsv_rt);
1156 Model::compute_advection_diffusion_coefficients(fe_values_side.point_list(), velocity, side->
element()->element_accessor(), ad_coef, dif_coef);
1157 Model::compute_dirichlet_bc(fe_values_side.point_list(), ele_acc, bc_values);
1158 data_.bc_flux.value_list(fe_values_side.point_list(), ele_acc, bc_fluxes);
1159 data_.bc_robin_sigma.value_list(fe_values_side.point_list(), ele_acc, bc_sigma);
1161 feo->dh()->get_dof_indices(cell, side_dof_indices);
1163 for (
int sbi=0; sbi<
n_subst_; sbi++)
1165 for (
unsigned int i=0; i<ndofs; i++) local_rhs[i] = 0;
1167 for (
unsigned int k=0; k<qsize; k++)
1173 || (bc_type[sbi] == EqData::dirichlet))
1175 bc_term = gamma[sbi][side->
cond_idx()]*bc_values[k][sbi]*fe_values_side.JxW(k);
1176 bc_grad = -bc_values[k][sbi]*fe_values_side.JxW(k)*dg_variant*(arma::trans(dif_coef[sbi][k])*fe_values_side.normal_vector(k));
1178 else if (bc_type[sbi] == EqData::neumann)
1180 bc_term = bc_fluxes[k][sbi]*fe_values_side.JxW(k);
1182 else if (bc_type[sbi] == EqData::robin)
1184 bc_term = bc_sigma[k][sbi]*bc_values[k][sbi]*fe_values_side.JxW(k);
1187 for (
unsigned int i=0; i<ndofs; i++)
1188 local_rhs[i] += bc_term*fe_values_side.shape_value(i,k)
1189 + arma::dot(bc_grad,fe_values_side.shape_grad(i,k));
1191 ls[sbi]->rhs_set_values(ndofs, (
int *)side_dof_indices, local_rhs);
1203 template<
class Model>
1204 template<
unsigned int dim>
1208 for (
unsigned int i=0; i<cell->n_nodes(); i++)
1209 node_nums[cell->node[i]] = i;
1213 for (
unsigned int k=0; k<fv.
n_points(); k++)
1215 velocity[k].zeros();
1216 for (
unsigned int sid=0; sid<cell->n_sides(); sid++)
1218 if (cell->side(sid)->dim() != dim-1)
continue;
1219 int num = dim*(dim+1)/2;
1220 for (
unsigned int i=0; i<cell->side(sid)->n_nodes(); i++)
1221 num -= node_nums[cell->side(sid)->node(i)];
1231 template<
class Model>
1240 const double alpha1,
1241 const double alpha2,
1244 double &transport_flux)
1248 double local_alpha = 0;
1260 for (
unsigned int i=0; i<s->n_nodes(); i++)
1261 for (
unsigned int j=i+1; j<s->n_nodes(); j++)
1262 h = max(h, s->node(i)->distance(*s->node(j)));
1266 double pflux = 0, nflux = 0;
1267 for (
int i=0; i<edg.
n_sides; i++)
1276 if (fluxes[s2] > 0 && fluxes[s1] < 0 && s1 < s2)
1277 transport_flux = fluxes[s1]*fabs(fluxes[s2]/pflux);
1278 else if (fluxes[s2] < 0 && fluxes[s1] > 0 && s1 < s2)
1279 transport_flux = fluxes[s1]*fabs(fluxes[s2]/nflux);
1281 transport_flux = fluxes[s1];
1285 gamma = 0.5*fabs(transport_flux);
1289 local_alpha = max(alpha1, alpha2);
1297 for (
unsigned int k=0; k<K_size; k++)
1298 delta[0] += dot(K1[k]*normal_vector,normal_vector);
1301 gamma += local_alpha/h*(delta[0]);
1307 for (
unsigned int k=0; k<K_size; k++)
1309 delta[0] += dot(K1[k]*normal_vector,normal_vector);
1310 delta[1] += dot(K2[k]*normal_vector,normal_vector);
1315 double delta_sum = delta[0] + delta[1];
1319 omega[0] = delta[1]/delta_sum;
1320 omega[1] = delta[0]/delta_sum;
1321 gamma += local_alpha/h*(delta[0]*delta[1]/delta_sum);
1324 for (
int i=0; i<2; i++) omega[i] = 0;
1333 template<
class Model>
1342 double delta = 0, h = 0;
1345 if (side->
dim() == 0)
1351 for (
unsigned int i=0; i<side->
n_nodes(); i++)
1352 for (
unsigned int j=i+1; j<side->
n_nodes(); j++)
1357 for (
unsigned int k=0; k<K_size; k++)
1358 delta += dot(K[k]*normal_vector,normal_vector);
1361 gamma = 0.5*fabs(flux) + alpha/h*delta;
1368 template<
class Model>
1372 for (
int sbi=0; sbi<
n_subst_; sbi++)
1373 ls[sbi]->start_allocation();
1374 prepare_initial_condition<1>();
1375 prepare_initial_condition<2>();
1376 prepare_initial_condition<3>();
1378 for (
int sbi=0; sbi<
n_subst_; sbi++)
1379 ls[sbi]->start_add_assembly();
1380 prepare_initial_condition<1>();
1381 prepare_initial_condition<2>();
1382 prepare_initial_condition<3>();
1384 for (
int sbi=0; sbi<
n_subst_; sbi++)
1386 ls[sbi]->finish_assembly();
1392 template<
class Model>
1393 template<
unsigned int dim>
1396 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
1398 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
1399 unsigned int dof_indices[ndofs];
1400 double matrix[ndofs*ndofs], rhs[ndofs];
1403 for (
int i=0; i<qsize; i++)
1404 init_values[i].resize(n_subst_);
1406 for (
int i_cell=0; i_cell<feo->dh()->el_ds()->lsize(); i_cell++)
1409 if (elem->dim() != dim)
continue;
1412 feo->dh()->get_dof_indices(elem, dof_indices);
1415 Model::compute_init_cond(fe_values.
point_list(), ele_acc, init_values);
1417 for (
int sbi=0; sbi<
n_subst_; sbi++)
1419 for (
unsigned int i=0; i<ndofs; i++)
1422 for (
unsigned int j=0; j<ndofs; j++)
1423 matrix[i*ndofs+j] = 0;
1426 for (
unsigned int k=0; k<qsize; k++)
1428 double rhs_term = init_values[k](sbi)*fe_values.
JxW(k);
1430 for (
unsigned int i=0; i<ndofs; i++)
1432 for (
unsigned int j=0; j<ndofs; j++)
1438 ls[sbi]->set_values(ndofs, (
int *)dof_indices, ndofs, (
int *)dof_indices, matrix, rhs);
1444 template<
class Model>
1447 calc_fluxes<1>(bcd_balance, bcd_plus_balance, bcd_minus_balance);
1448 calc_fluxes<2>(bcd_balance, bcd_plus_balance, bcd_minus_balance);
1449 calc_fluxes<3>(bcd_balance, bcd_plus_balance, bcd_minus_balance);
1452 template<
class Model>
1453 template<
unsigned int dim>
1460 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim-1>()->size();
1461 unsigned int dof_indices[ndofs];
1466 for (
int i=0; i<qsize; i++)
1467 bc_values[i].resize(n_subst_);
1469 for (
int iedg=0; iedg<feo->dh()->n_loc_edges(); iedg++)
1472 if (edg->
n_sides > 1)
continue;
1473 if (edg->
side(0)->
dim() != dim-1)
continue;
1475 if (edg->
side(0)->
cond() == NULL)
continue;
1484 fe_values.reinit(cell, side->
el_idx());
1485 fsv_rt.reinit(cell, side->
el_idx());
1486 feo->dh()->get_dof_indices(cell, dof_indices);
1487 calculate_velocity(cell, side_velocity, fsv_rt);
1488 Model::compute_advection_diffusion_coefficients(fe_values.point_list(), side_velocity, ele_acc, ad_coef, dif_coef);
1489 Model::compute_dirichlet_bc(fe_values.point_list(), side->
cond()->
element_accessor(), bc_values);
1492 for (
int sbi=0; sbi<
n_subst_; sbi++)
1494 double mass_flux = 0;
1495 double water_flux = 0;
1496 for (
unsigned int k=0; k<qsize; k++)
1497 water_flux += arma::dot(ad_coef[sbi][k], fe_values.normal_vector(k))*fe_values.JxW(k);
1498 water_flux /= side->
measure();
1500 for (
unsigned int k=0; k<qsize; k++)
1504 for (
unsigned int i=0; i<ndofs; i++)
1506 conc += fe_values.shape_value(i,k)*ls[sbi]->get_solution_array()[dof_indices[i]-feo->dh()->loffset()];
1507 conc_grad += fe_values.shape_grad(i,k)*ls[sbi]->get_solution_array()[dof_indices[i]-feo->dh()->loffset()];
1511 mass_flux += water_flux*conc*fe_values.JxW(k);
1513 if (bc_type[sbi] == EqData::dirichlet || (bc_type[sbi] == EqData::inflow && water_flux*side->
measure() < -
mh_dh->
precision()))
1516 mass_flux -= arma::dot(dif_coef[sbi][k]*conc_grad,fe_values.normal_vector(k))*fe_values.JxW(k);
1519 mass_flux -= gamma[sbi][side->
cond_idx()]*(bc_values[k][sbi] - conc)*fe_values.JxW(k);
1523 bcd_balance[sbi][bc_region_idx] += mass_flux;
1524 if (mass_flux >= 0) bcd_plus_balance[sbi][bc_region_idx] += mass_flux;
1525 else bcd_minus_balance[sbi][bc_region_idx] += mass_flux;
1531 template<
class Model>
1534 calc_elem_sources<1>(mass, src_balance);
1535 calc_elem_sources<2>(mass, src_balance);
1536 calc_elem_sources<3>(mass, src_balance);
1539 template<
class Model>
1540 template<
unsigned int dim>
1543 FEValues<dim,3> fe_values(*feo->mapping<dim>(), *feo->q<dim>(), *feo->fe<dim>(),
1545 const unsigned int ndofs = feo->fe<dim>()->n_dofs(), qsize = feo->q<dim>()->size();
1546 unsigned int dof_indices[ndofs];
1547 vector<arma::vec> sources_conc(qsize), sources_density(qsize), sources_sigma(qsize);
1548 double mass_sum, sources_sum, conc, conc_diff;
1550 for (
int i_cell=0; i_cell<feo->dh()->el_ds()->lsize(); i_cell++)
1553 if (elem->dim() != dim)
continue;
1555 Region r = elem->element_accessor().region();
1557 unsigned int region_idx = r.
bulk_idx();
1560 fe_values.reinit(elem);
1561 feo->dh()->get_dof_indices(elem, dof_indices);
1563 Model::compute_mass_matrix_coefficient(fe_values.point_list(), ele_acc, mm_coef);
1564 Model::compute_source_coefficients(fe_values.point_list(), ele_acc, sources_conc, sources_density, sources_sigma);
1566 for (
int sbi=0; sbi<
n_subst_; sbi++)
1571 for (
unsigned int k=0; k<qsize; k++)
1574 for (
unsigned int i=0; i<ndofs; i++)
1575 conc += fe_values.shape_value(i,k)*ls[sbi]->get_solution_array()[dof_indices[i]-feo->dh()->loffset()];
1577 mass_sum += mm_coef[k]*conc*fe_values.JxW(k);
1579 conc_diff = sources_conc[k][sbi] - conc;
1580 sources_sum += (sources_density[k][sbi] + conc_diff*sources_sigma[k][sbi])*fe_values.JxW(k);
1583 mass[sbi][region_idx] += mass_sum;
1584 src_balance[sbi][region_idx] += sources_sum;