28 #include "petscviewer.h"
29 #include "petscerror.h"
86 .
add_value(
MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
94 "Homogeneous Neumann boundary condition\n(zero normal flux over the boundary).")
96 "Dirichlet boundary condition. "
97 "Specify the pressure head through the ``bc_pressure`` field "
98 "or the piezometric head through the ``bc_piezo_head`` field.")
99 .
add_value(
total_flux,
"total_flux",
"Flux boundary condition (combines Neumann and Robin type). "
100 "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). "
101 "Specify the water inflow by the ``bc_flux`` field, the transition coefficient by ``bc_robin_sigma`` "
102 "and the reference pressure head or piezometric head through ``bc_pressure`` or ``bc_piezo_head`` respectively.")
104 "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow "
105 "is described by the pair of inequalities: "
106 "(($h_d \\le h_d^D$)) and (($ -\\boldsymbol q_d\\cdot\\boldsymbol n \\le \\delta q_d^N$)), where the equality holds in at least one of them. "
107 "Caution: setting (($q_d^N$)) strictly negative "
108 "may lead to an ill posed problem since a positive outflow is enforced. "
109 "Parameters (($h_d^D$)) and (($q_d^N$)) are given by the fields ``bc_switch_pressure`` (or ``bc_switch_piezo_head``) and ``bc_flux`` respectively."
112 "River boundary condition. For the water level above the bedrock, (($H_d > H_d^S$)), the Robin boundary condition is used with the inflow given by: "
113 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: "
114 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, "
115 " ``bc_sigma``, ``bc_flux``."
126 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
128 "Boundary switch piezometric head for BC types: seepage, river." )
130 "Initial condition for the pressure given as the piezometric head." )
132 return field_descriptor;
139 "Linear solver for MH problem.")
141 "Residual tolerance.")
143 "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria "
144 "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution."
145 "If greater then 'max_it' the value is set to 'max_it'.")
147 "Maximum number of iterations (linear solutions) of the non-linear solver.")
149 "If a stagnation of the nonlinear solver is detected the solver stops. "
150 "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver "
151 "ends with convergence success on stagnation, but it reports warning about it.")
156 return it::Record(
"Flow_Darcy_MH",
"Mixed-Hybrid solver for saturated Darcy flow.")
160 "Vector of the gravity force. Dimensionless.")
162 "Input data for Darcy flow model.")
164 "Non-linear solver for MH problem.")
166 "Output stream settings.\n Specify file format, precision etc.")
169 IT::Default(
"{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
170 "Specification of output fields and output times.")
172 "Output settings specific to Darcy flow model.\n"
173 "Includes raw output and some experimental functionality.")
175 "Settings for computing mass balance.")
177 "Number of Schur complements to perform when solving MH system.")
179 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
185 Input::register_class< DarcyMH, Mesh &, const Input::Record >(
"Flow_Darcy_MH") +
194 *
this += field_ele_pressure.name(
"pressure_p0")
197 .description(
"Pressure solution - P0 interpolation.");
199 *
this += field_edge_pressure.name(
"pressure_edge")
202 .description(
"Pressure solution - Crouzeix-Raviart interpolation.");
204 *
this += field_ele_piezo_head.name(
"piezo_head_p0")
207 .description(
"Piezo head solution - P0 interpolation.");
209 *
this += field_ele_velocity.name(
"velocity_p0")
210 .units(
UnitSI().m().s(-1))
212 .description(
"Velocity solution - P0 interpolation.");
214 *
this += flux.name(
"flux")
215 .units(
UnitSI().m().s(-1))
217 .description(
"Darcy flow flux.");
219 *
this += anisotropy.name(
"anisotropy")
220 .description(
"Anisotropy of the conductivity tensor.")
221 .input_default(
"1.0")
224 *
this += cross_section.name(
"cross_section")
225 .description(
"Complement dimension parameter (cross section for 1D, thickness for 2D).")
226 .input_default(
"1.0")
227 .units(
UnitSI().m(3).md() );
229 *
this += conductivity.name(
"conductivity")
230 .description(
"Isotropic conductivity scalar.")
231 .input_default(
"1.0")
232 .units(
UnitSI().m().s(-1) )
235 *
this += sigma.name(
"sigma")
236 .description(
"Transition coefficient between dimensions.")
237 .input_default(
"1.0")
240 *
this += water_source_density.name(
"water_source_density")
241 .description(
"Water source density.")
242 .input_default(
"0.0")
245 *
this += bc_type.name(
"bc_type")
246 .description(
"Boundary condition type.")
247 .input_selection( get_bc_type_selection() )
248 .input_default(
"\"none\"")
252 .disable_where(bc_type, {
none, seepage} )
254 .description(
"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. "
255 "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.")
256 .input_default(
"0.0")
260 .disable_where(bc_type, {
none, dirichlet} )
262 .description(
"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.")
263 .input_default(
"0.0")
264 .units(
UnitSI().m().s(-1) );
266 *
this += bc_robin_sigma
267 .disable_where(bc_type, {
none, dirichlet, seepage} )
268 .name(
"bc_robin_sigma")
269 .description(
"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.")
270 .input_default(
"0.0")
273 *
this += bc_switch_pressure
274 .disable_where(bc_type, {
none, dirichlet, total_flux} )
275 .name(
"bc_switch_pressure")
276 .description(
"Critical switch pressure for ``seepage`` and ``river`` boundary conditions.")
277 .input_default(
"0.0")
282 *
this += init_pressure.name(
"init_pressure")
283 .description(
"Initial condition for pressure in time dependent problems.")
284 .input_default(
"0.0")
287 *
this += storativity.name(
"storativity")
288 .description(
"Storativity (in time dependent problems).")
289 .input_default(
"0.0")
292 *
this += extra_storativity.name(
"extra_storativity")
293 .description(
"Storativity added from upstream equation.")
295 .input_default(
"0.0")
296 .flags( input_copy );
298 *
this += extra_source.name(
"extra_water_source_density")
299 .description(
"Water source density added from upstream equation.")
300 .input_default(
"0.0")
302 .flags( input_copy );
304 *
this += gravity_field.name(
"gravity")
305 .description(
"Gravity vector.")
306 .input_default(
"0.0")
351 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
358 data_ = make_shared<EqData>();
361 data_->is_linear=
true;
391 gravity_array.copy_to(gvec);
394 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
397 auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
398 field_algo->set_value(gvalue);
399 data_->gravity_field.set(field_algo, 0.0);
401 data_->bc_pressure.add_factory(
403 (
data_->gravity_,
"bc_piezo_head") );
404 data_->bc_switch_pressure.add_factory(
406 (
data_->gravity_,
"bc_switch_piezo_head") );
407 data_->init_pressure.add_factory(
409 (
data_->gravity_,
"init_piezo_head") );
417 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
430 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
431 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
432 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
433 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
434 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
435 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
436 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
437 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
438 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
439 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
440 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
442 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
448 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
449 data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
450 data_->dh_->distribute_dofs(ds);
454 this->
data_->multidim_assembler = AssemblyBase::create< AssemblyMH >(
data_);
457 data_->add_coords_field();
460 uint rt_component = 0;
461 data_->full_solution =
data_->dh_->create_vector();
462 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
data_->dh_, &
data_->full_solution, rt_component);
463 data_->flux.set(ele_flux_ptr, 0.0);
467 uint p_ele_component = 1;
468 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_ele_component);
469 data_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
471 uint p_edge_component = 2;
472 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_edge_component);
473 data_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
475 data_->field_ele_piezo_head.set(
482 uint p_edge_component = 2;
483 data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_edge_component);
488 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
489 data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
490 data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
500 .val<Input::AbstractRecord>(
"linear_solver");
510 VecCreateMPI(PETSC_COMM_WORLD,
data_->dh_->distr()->lsize(),PETSC_DETERMINE,&(
steady_diagonal));
519 data_->water_balance_idx =
balance_->add_quantity(
"water_volume");
549 if (zero_time_term_from_right) {
580 data_->full_solution.local_to_ghost_begin();
581 data_->full_solution.local_to_ghost_end();
591 bool jump_time =
data_->storativity.is_jump_time();
592 if (! zero_time_term_from_left) {
602 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
611 if (! zero_time_term_from_left && ! jump_time && output)
output_data();
617 if (zero_time_term_from_right) {
622 }
else if (! zero_time_term_from_left && jump_time) {
623 WarningOut() <<
"Discontinuous time term not supported yet.\n";
635 return (
data_->storativity.input_list_size() == 0);
648 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
651 int is_linear_common;
656 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
657 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
658 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
660 if (! is_linear_common) {
668 while (nonlinear_iteration_ < this->
min_n_it_ ||
669 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
671 convergence_history.push_back(residual_norm);
674 if (convergence_history.size() >= 5 &&
675 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
676 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
682 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
686 if (! is_linear_common)
692 if (is_linear_common){
695 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
709 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
712 chkerr(VecDestroy(&save_solution));
736 if(
data_->mortar_method_ != MortarMethod::NoMortar){
737 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(
data_);
739 unsigned int dim = dh_cell.dim();
740 multidim_assembler[dim-1]->fix_velocity(dh_cell);
807 unsigned int dim = dh_cell.dim();
808 assembler[dim-1]->assemble(dh_cell);
826 double zeros[100000];
827 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
830 tmp_rows.reserve(200);
833 dofs.reserve(
data_->dh_->max_elem_dofs());
834 dofs_ngh.reserve(
data_->dh_->max_elem_dofs());
839 const uint ndofs = dh_cell.n_dofs();
841 dh_cell.get_dof_indices(dofs);
850 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
858 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
859 dofs_ngh.resize(ndofs_ngh);
865 const unsigned int t = dh_neighb_cell.
n_dofs() - (dh_neighb_cell.
dim()+1) + neighb_side.side().side_idx();
866 tmp_rows.push_back(dofs_ngh[t]);
880 for(
auto &isec : isec_list ) {
884 const uint ndofs_slave = dh_cell_slave.
n_dofs();
885 dofs_ngh.resize(ndofs_slave);
889 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->
n_sides(); i_side++) {
891 tmp_rows.push_back( dofs_ngh[(ndofs_slave+1)/2+i_side] );
901 edge_rows = dofs.
data() + nsides +1;
940 const uint ndofs = dh_cell.n_dofs();
941 global_dofs.resize(ndofs);
942 dh_cell.get_dof_indices(global_dofs);
944 double cs =
data_->cross_section.value(ele.
centre(), ele);
947 double source = ele.
measure() * cs *
948 (
data_->water_source_density.value(ele.
centre(), ele)
954 {dh_cell.get_loc_dof_indices()[ndofs/2]}, {0}, {source});
974 #ifdef FLOW123D_HAVE_BDDCML
975 WarningOut() <<
"For BDDC no Schur complements are used.";
988 THROW( ExcBddcmlNotSupported() );
989 #endif // FLOW123D_HAVE_BDDCML
994 WarningOut() <<
"Invalid number of Schur Complements. Using 2.";
1007 ls->LinSys::set_from_input(in_rec);
1016 ISCreateGeneral(PETSC_COMM_SELF, side_dofs_vec.size(), &(side_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1031 const PetscInt *b_indices;
1032 ISGetIndices(ls->
IsB, &b_indices);
1034 for(
uint i_b=0, i_bb=0; i_b < b_size && i_bb < elem_dofs_vec.size(); i_b++) {
1035 if (b_indices[i_b] == elem_dofs_vec[i_bb])
1036 elem_dofs_vec[i_bb++] = i_b + ds->
begin();
1038 ISRestoreIndices(ls->
IsB, &b_indices);
1041 ISCreateGeneral(PETSC_COMM_SELF, elem_dofs_vec.size(), &(elem_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1069 THROW( ExcUnknownSolver() );
1081 START_TIMER(
"DarcyFlowMH_Steady::assembly_linear_system");
1083 data_->is_linear=
true;
1138 std::string output_file;
1150 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1151 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1163 double d_max = std::numeric_limits<double>::max();
1164 double h1 = d_max, h2 = d_max, h3 = d_max;
1165 double he2 = d_max, he3 = d_max;
1168 case 1: h1 = std::min(h1,ele.measure());
break;
1169 case 2: h2 = std::min(h2,ele.measure());
break;
1170 case 3: h3 = std::min(h3,ele.measure());
break;
1173 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1175 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1176 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1180 if(h1 == d_max) h1 = 0;
1181 if(h2 == d_max) h2 = 0;
1182 if(h3 == d_max) h3 = 0;
1183 if(he2 == d_max) he2 = 0;
1184 if(he3 == d_max) he3 = 0;
1187 file = fopen(output_file.c_str(),
"a");
1188 fprintf(file,
"nA = %d;\n",
data_->dh_cr_disc_->distr()->size());
1189 fprintf(file,
"nB = %d;\n",
data_->dh_->mesh()->get_el_ds()->size());
1190 fprintf(file,
"nBF = %d;\n",
data_->dh_cr_->distr()->size());
1191 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1192 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1210 START_TIMER(
"DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1238 dh_cell.get_dof_indices(cell_dofs_global);
1240 inet.insert(inet.end(), cell_dofs_global.begin(), cell_dofs_global.end());
1241 uint n_inet = cell_dofs_global.size();
1244 uint dim = dh_cell.elm().dim();
1245 elDimMax = std::max( elDimMax, dim );
1246 elDimMin = std::min( elDimMin, dim );
1250 isegn.push_back( dh_cell.elm_idx());
1253 for (
unsigned int si=0; si<dh_cell.elm()->n_sides(); si++) {
1254 arma::vec3 coord = dh_cell.elm().side(si)->centre();
1257 localDofMap.insert( std::make_pair( cell_dofs_global[si], coord ) );
1259 localDofMap.insert( std::make_pair( cell_dofs_global[si+dim+2], coord ) );
1262 arma::vec3 elm_centre = dh_cell.elm().centre();
1263 localDofMap.insert( std::make_pair( cell_dofs_global[dim+1], elm_centre ) );
1267 for(
DHCellSide side : dh_cell.neighb_sides()) {
1268 uint neigh_dim = side.cell().elm().dim();
1269 side.cell().get_dof_indices(cell_dofs_global);
1270 int edge_row = cell_dofs_global[neigh_dim+2+side.side_idx()];
1271 localDofMap.insert( std::make_pair( edge_row, side.centre() ) );
1272 inet.push_back( edge_row );
1275 nnet.push_back(n_inet);
1280 double conduct =
data_->conductivity.value( elm_centre , dh_cell.elm() );
1281 auto aniso =
data_->anisotropy.value( elm_centre , dh_cell.elm() );
1285 for (
int i = 0; i < 3; i++) {
1286 coef = coef + aniso.at(i,i);
1289 coef = conduct*coef / 3;
1292 "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1293 element_permeability.push_back( 1. / coef );
1303 auto distr =
data_->dh_->distr();
1312 int numNodeSub = localDofMap.size();
1323 for ( ; itB != localDofMap.end(); ++itB ) {
1324 isngn[ind] = itB -> first;
1327 for (
int j = 0; j < 3; j++ ) {
1328 xyz[ j*numNodeSub + ind ] = coord[j];
1333 localDofMap.clear();
1341 Global2LocalMap_ global2LocalNodeMap;
1342 for (
unsigned ind = 0; ind < isngn.size(); ++ind ) {
1343 global2LocalNodeMap.insert( std::make_pair(
static_cast<unsigned>( isngn[ind] ), ind ) );
1348 for (
unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1349 int nne = nnet[ iEle ];
1350 for (
int ien = 0; ien < nne; ien++ ) {
1352 int indGlob = inet[indInet];
1354 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1355 OLD_ASSERT( pos != global2LocalNodeMap.end(),
1356 "Cannot remap node index %d to local indices. \n ", indGlob );
1357 int indLoc =
static_cast<int> ( pos -> second );
1360 inet[ indInet++ ] = indLoc;
1364 int numNodes =
size;
1365 int numDofsInt =
size;
1367 int meshDim = elDimMax;
1379 bddc_ls -> load_mesh( LinSys_BDDC::BDDCMatrixType::SPD_VIA_SYMMETRICGENERAL, spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1401 if(
time_ !=
nullptr)
1454 const IntIdx p_ele_dof = dh_cell.get_loc_dof_indices()[dh_cell.n_dofs()/2];
1455 local_sol[p_ele_dof] =
data_->init_pressure.value(ele.
centre(),ele);
1466 PetscScalar *local_diagonal;
1474 dofs.reserve(
data_->dh_->max_elem_dofs());
1478 dofs.resize(dh_cell.n_dofs());
1479 dh_cell.get_dof_indices(dofs);
1482 const uint p_ele_dof = dh_cell.n_dofs() / 2;
1484 double diagonal_coeff =
data_->cross_section.value(ele.
centre(), ele)
1486 +
data_->extra_storativity.value(ele.
centre(), ele))
1488 local_diagonal[dh_cell.get_loc_dof_indices()[p_ele_dof]]= - diagonal_coeff /
time_->
dt();
1490 balance_->add_mass_values(
data_->water_balance_idx, dh_cell,
1491 {dh_cell.get_loc_dof_indices()[p_ele_dof]},
1492 {diagonal_coeff}, 0.0);
1494 VecRestoreArray(new_diagonal,& local_diagonal);
1495 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1497 schur0->set_matrix_changed();
1499 balance_->finish_mass_assembly(data_->water_balance_idx);
1506 if (scale_factor != 1.0) {
1527 void dofs_range(
unsigned int n_dofs,
unsigned int &min,
unsigned int &max,
unsigned int component) {
1531 }
else if (component==1) {
1543 unsigned int i, n_dofs, min, max;
1547 n_dofs = dh_cell.get_dof_indices(dof_indices);
1549 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);