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") +
192 *
this += field_ele_pressure.name(
"pressure_p0")
195 .description(
"Pressure solution - P0 interpolation.");
197 *
this += field_edge_pressure.name(
"pressure_edge")
200 .description(
"Pressure solution - Crouzeix-Raviart interpolation.");
202 *
this += field_ele_piezo_head.name(
"piezo_head_p0")
205 .description(
"Piezo head solution - P0 interpolation.");
207 *
this += field_ele_velocity.name(
"velocity_p0")
208 .units(
UnitSI().m().s(-1))
210 .description(
"Velocity solution - P0 interpolation.");
212 *
this += flux.name(
"flux")
213 .units(
UnitSI().m().s(-1))
215 .description(
"Darcy flow flux.");
217 *
this += anisotropy.name(
"anisotropy")
218 .description(
"Anisotropy of the conductivity tensor.")
219 .input_default(
"1.0")
222 *
this += cross_section.name(
"cross_section")
223 .description(
"Complement dimension parameter (cross section for 1D, thickness for 2D).")
224 .input_default(
"1.0")
225 .units(
UnitSI().m(3).md() );
227 *
this += conductivity.name(
"conductivity")
228 .description(
"Isotropic conductivity scalar.")
229 .input_default(
"1.0")
230 .units(
UnitSI().m().s(-1) )
233 *
this += sigma.name(
"sigma")
234 .description(
"Transition coefficient between dimensions.")
235 .input_default(
"1.0")
238 *
this += water_source_density.name(
"water_source_density")
239 .description(
"Water source density.")
240 .input_default(
"0.0")
243 *
this += bc_type.name(
"bc_type")
244 .description(
"Boundary condition type.")
245 .input_selection( get_bc_type_selection() )
246 .input_default(
"\"none\"")
250 .disable_where(bc_type, {
none, seepage} )
252 .description(
"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. "
253 "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.")
254 .input_default(
"0.0")
258 .disable_where(bc_type, {
none, dirichlet} )
260 .description(
"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.")
261 .input_default(
"0.0")
262 .units(
UnitSI().m().s(-1) );
264 *
this += bc_robin_sigma
265 .disable_where(bc_type, {
none, dirichlet, seepage} )
266 .name(
"bc_robin_sigma")
267 .description(
"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.")
268 .input_default(
"0.0")
271 *
this += bc_switch_pressure
272 .disable_where(bc_type, {
none, dirichlet, total_flux} )
273 .name(
"bc_switch_pressure")
274 .description(
"Critical switch pressure for ``seepage`` and ``river`` boundary conditions.")
275 .input_default(
"0.0")
280 *
this += init_pressure.name(
"init_pressure")
281 .description(
"Initial condition for pressure in time dependent problems.")
282 .input_default(
"0.0")
285 *
this += storativity.name(
"storativity")
286 .description(
"Storativity (in time dependent problems).")
287 .input_default(
"0.0")
290 *
this += extra_storativity.name(
"extra_storativity")
291 .description(
"Storativity added from upstream equation.")
293 .input_default(
"0.0")
294 .flags( input_copy );
296 *
this += extra_source.name(
"extra_water_source_density")
297 .description(
"Water source density added from upstream equation.")
298 .input_default(
"0.0")
300 .flags( input_copy );
302 *
this += gravity_field.name(
"gravity")
303 .description(
"Gravity vector.")
304 .input_default(
"0.0")
307 *
this += bc_gravity.name(
"bc_gravity")
308 .description(
"Boundary gravity vector.")
309 .input_default(
"0.0")
312 *
this += init_piezo_head.name(
"init_piezo_head")
314 .input_default(
"0.0")
315 .description(
"Init piezo head.");
317 *
this += bc_piezo_head.name(
"bc_piezo_head")
319 .input_default(
"0.0")
320 .description(
"Boundary piezo head.");
322 *
this += bc_switch_piezo_head.name(
"bc_switch_piezo_head")
324 .input_default(
"0.0")
325 .description(
"Boundary switch piezo head.");
375 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
416 gravity_array.copy_to(gvec);
422 auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
423 field_algo->set_value(gvalue);
424 eq_fields_->gravity_field.set(field_algo, 0.0);
443 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
456 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
457 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
458 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
459 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
460 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
461 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
462 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
463 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
464 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
465 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
466 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
468 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
474 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
475 eq_data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
486 uint rt_component = 0;
488 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
eq_data_->dh_, &
eq_data_->full_solution, rt_component);
493 uint p_ele_component = 1;
494 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_ele_component);
495 eq_fields_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
497 uint p_edge_component = 2;
498 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_edge_component);
499 eq_fields_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
508 uint p_edge_component = 2;
509 eq_data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
eq_data_->dh_,p_edge_component);
514 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
515 eq_data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
516 eq_data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
526 .val<Input::AbstractRecord>(
"linear_solver");
575 if (zero_time_term_from_right) {
606 eq_data_->full_solution.local_to_ghost_begin();
607 eq_data_->full_solution.local_to_ghost_end();
617 bool jump_time =
eq_fields_->storativity.is_jump_time();
618 if (! zero_time_term_from_left) {
628 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
637 if (! zero_time_term_from_left && ! jump_time && output)
output_data();
643 if (zero_time_term_from_right) {
648 }
else if (! zero_time_term_from_left && jump_time) {
649 WarningOut() <<
"Discontinuous time term not supported yet.\n";
661 return (
eq_fields_->storativity.input_list_size() == 0);
674 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
677 int is_linear_common;
682 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
683 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
684 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
686 if (! is_linear_common) {
694 while (nonlinear_iteration_ < this->
min_n_it_ ||
695 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
697 convergence_history.push_back(residual_norm);
700 if (convergence_history.size() >= 5 &&
701 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
702 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
708 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
712 if (! is_linear_common)
718 if (is_linear_common){
721 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
735 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
738 chkerr(VecDestroy(&save_solution));
762 if(
eq_data_->mortar_method_ != MortarMethod::NoMortar){
763 auto multidim_assembler = AssemblyFlowBase::create< AssemblyMH >(
eq_fields_,
eq_data_);
765 unsigned int dim = dh_cell.dim();
766 multidim_assembler[dim-1]->fix_velocity(dh_cell);
833 unsigned int dim = dh_cell.dim();
834 assembler[dim-1]->assemble(dh_cell);
852 double zeros[100000];
853 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
856 tmp_rows.reserve(200);
859 dofs.reserve(
eq_data_->dh_->max_elem_dofs());
860 dofs_ngh.reserve(
eq_data_->dh_->max_elem_dofs());
865 const uint ndofs = dh_cell.n_dofs();
867 dh_cell.get_dof_indices(dofs);
876 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
884 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
885 dofs_ngh.resize(ndofs_ngh);
891 const unsigned int t = dh_neighb_cell.
n_dofs() - (dh_neighb_cell.
dim()+1) + neighb_side.side().side_idx();
892 tmp_rows.push_back(dofs_ngh[t]);
906 for(
auto &isec : isec_list ) {
910 const uint ndofs_slave = dh_cell_slave.
n_dofs();
911 dofs_ngh.resize(ndofs_slave);
915 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->
n_sides(); i_side++) {
917 tmp_rows.push_back( dofs_ngh[(ndofs_slave+1)/2+i_side] );
927 edge_rows = dofs.
data() + nsides +1;
966 const uint ndofs = dh_cell.n_dofs();
967 global_dofs.resize(ndofs);
968 dh_cell.get_dof_indices(global_dofs);
973 double source = ele.
measure() * cs *
980 {dh_cell.get_loc_dof_indices()[ndofs/2]}, {0}, {source});
1000 #ifdef FLOW123D_HAVE_BDDCML
1001 WarningOut() <<
"For BDDC no Schur complements are used.";
1014 THROW( ExcBddcmlNotSupported() );
1015 #endif // FLOW123D_HAVE_BDDCML
1020 WarningOut() <<
"Invalid number of Schur Complements. Using 2.";
1033 ls->LinSys::set_from_input(in_rec);
1042 ISCreateGeneral(PETSC_COMM_SELF, side_dofs_vec.size(), &(side_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1057 const PetscInt *b_indices;
1058 ISGetIndices(ls->
IsB, &b_indices);
1060 for(
uint i_b=0, i_bb=0; i_b < b_size && i_bb < elem_dofs_vec.size(); i_b++) {
1061 if (b_indices[i_b] == elem_dofs_vec[i_bb])
1062 elem_dofs_vec[i_bb++] = i_b + ds->
begin();
1064 ISRestoreIndices(ls->
IsB, &b_indices);
1067 ISCreateGeneral(PETSC_COMM_SELF, elem_dofs_vec.size(), &(elem_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1095 THROW( ExcUnknownSolver() );
1107 START_TIMER(
"DarcyFlowMH_Steady::assembly_linear_system");
1164 std::string output_file;
1176 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1177 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1189 double d_max = std::numeric_limits<double>::max();
1190 double h1 = d_max, h2 = d_max, h3 = d_max;
1191 double he2 = d_max, he3 = d_max;
1194 case 1: h1 = std::min(h1,ele.measure());
break;
1195 case 2: h2 = std::min(h2,ele.measure());
break;
1196 case 3: h3 = std::min(h3,ele.measure());
break;
1199 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1201 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1202 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1206 if(h1 == d_max) h1 = 0;
1207 if(h2 == d_max) h2 = 0;
1208 if(h3 == d_max) h3 = 0;
1209 if(he2 == d_max) he2 = 0;
1210 if(he3 == d_max) he3 = 0;
1213 file = fopen(output_file.c_str(),
"a");
1215 fprintf(file,
"nB = %d;\n",
eq_data_->dh_->mesh()->get_el_ds()->size());
1217 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1218 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1236 START_TIMER(
"DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1264 dh_cell.get_dof_indices(cell_dofs_global);
1266 inet.insert(inet.end(), cell_dofs_global.begin(), cell_dofs_global.end());
1267 uint n_inet = cell_dofs_global.size();
1270 uint dim = dh_cell.elm().dim();
1271 elDimMax = std::max( elDimMax, dim );
1272 elDimMin = std::min( elDimMin, dim );
1276 isegn.push_back( dh_cell.elm_idx());
1279 for (
unsigned int si=0; si<dh_cell.elm()->n_sides(); si++) {
1280 arma::vec3 coord = dh_cell.elm().side(si)->centre();
1283 localDofMap.insert( std::make_pair( cell_dofs_global[si], coord ) );
1285 localDofMap.insert( std::make_pair( cell_dofs_global[si+dim+2], coord ) );
1288 arma::vec3 elm_centre = dh_cell.elm().centre();
1289 localDofMap.insert( std::make_pair( cell_dofs_global[dim+1], elm_centre ) );
1293 for(
DHCellSide side : dh_cell.neighb_sides()) {
1294 uint neigh_dim = side.cell().elm().dim();
1295 side.cell().get_dof_indices(cell_dofs_global);
1296 int edge_row = cell_dofs_global[neigh_dim+2+side.side_idx()];
1297 localDofMap.insert( std::make_pair( edge_row, side.centre() ) );
1298 inet.push_back( edge_row );
1301 nnet.push_back(n_inet);
1306 double conduct =
eq_fields_->conductivity.value( elm_centre , dh_cell.elm() );
1307 auto aniso =
eq_fields_->anisotropy.value( elm_centre , dh_cell.elm() );
1311 for (
int i = 0; i < 3; i++) {
1312 coef = coef + aniso.at(i,i);
1315 coef = conduct*coef / 3;
1318 "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1319 element_permeability.push_back( 1. / coef );
1329 auto distr =
eq_data_->dh_->distr();
1338 int numNodeSub = localDofMap.size();
1349 for ( ; itB != localDofMap.end(); ++itB ) {
1350 isngn[ind] = itB -> first;
1353 for (
int j = 0; j < 3; j++ ) {
1354 xyz[ j*numNodeSub + ind ] = coord[j];
1359 localDofMap.clear();
1367 Global2LocalMap_ global2LocalNodeMap;
1368 for (
unsigned ind = 0; ind < isngn.size(); ++ind ) {
1369 global2LocalNodeMap.insert( std::make_pair(
static_cast<unsigned>( isngn[ind] ), ind ) );
1374 for (
unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1375 int nne = nnet[ iEle ];
1376 for (
int ien = 0; ien < nne; ien++ ) {
1378 int indGlob = inet[indInet];
1380 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1381 OLD_ASSERT( pos != global2LocalNodeMap.end(),
1382 "Cannot remap node index %d to local indices. \n ", indGlob );
1383 int indLoc =
static_cast<int> ( pos -> second );
1386 inet[ indInet++ ] = indLoc;
1390 int numNodes =
size;
1391 int numDofsInt =
size;
1393 int meshDim = elDimMax;
1405 bddc_ls -> load_mesh( LinSys_BDDC::BDDCMatrixType::SPD_VIA_SYMMETRICGENERAL, spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1427 if(
time_ !=
nullptr)
1480 const IntIdx p_ele_dof = dh_cell.get_loc_dof_indices()[dh_cell.n_dofs()/2];
1492 PetscScalar *local_diagonal;
1500 dofs.reserve(
eq_data_->dh_->max_elem_dofs());
1504 dofs.resize(dh_cell.n_dofs());
1505 dh_cell.get_dof_indices(dofs);
1508 const uint p_ele_dof = dh_cell.n_dofs() / 2;
1514 local_diagonal[dh_cell.get_loc_dof_indices()[p_ele_dof]]= - diagonal_coeff /
time_->
dt();
1517 {dh_cell.get_loc_dof_indices()[p_ele_dof]},
1518 {diagonal_coeff}, 0.0);
1520 VecRestoreArray(new_diagonal,& local_diagonal);
1521 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1523 schur0->set_matrix_changed();
1525 balance_->finish_mass_assembly(eq_data_->water_balance_idx);
1532 if (scale_factor != 1.0) {
1553 void dofs_range(
unsigned int n_dofs,
unsigned int &min,
unsigned int &max,
unsigned int component) {
1557 }
else if (component==1) {
1569 unsigned int i, n_dofs, min, max;
1573 n_dofs = dh_cell.get_dof_indices(dof_indices);
1575 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);