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!";
415 return next_t * (1 - 2*std::numeric_limits<double>::epsilon());
437 gravity_array.copy_to(gvec);
443 auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
444 field_algo->set_value(gvalue);
445 eq_fields_->gravity_field.set(field_algo, 0.0);
464 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
477 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
478 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
479 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
480 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
481 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
482 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
483 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
484 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
485 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
486 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
487 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
489 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
495 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
496 eq_data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
507 uint rt_component = 0;
509 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
eq_data_->dh_, &
eq_data_->full_solution, rt_component);
514 uint p_ele_component = 1;
515 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_ele_component);
516 eq_fields_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
518 uint p_edge_component = 2;
519 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_edge_component);
520 eq_fields_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
529 uint p_edge_component = 2;
530 eq_data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
eq_data_->dh_,p_edge_component);
535 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
536 eq_data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
537 eq_data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
547 .val<Input::AbstractRecord>(
"linear_solver");
596 if (zero_time_term_from_right) {
597 MessageOut() <<
"Flow zero time step - steady case\n";
606 MessageOut() <<
"Flow zero time step - unsteady case\n";
618 eq_data_->full_solution.local_to_ghost_begin();
619 eq_data_->full_solution.local_to_ghost_end();
636 eq_data_->full_solution.local_to_ghost_begin();
637 eq_data_->full_solution.local_to_ghost_end();
647 bool jump_time =
eq_fields_->storativity.is_jump_time();
648 if (! zero_time_term_from_left) {
649 MessageOut() <<
"Flow time step - unsteady case\n";
659 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
668 if (! zero_time_term_from_left && ! jump_time && output)
output_data();
674 if (zero_time_term_from_right) {
675 MessageOut() <<
"Flow time step - steady case\n";
680 }
else if (! zero_time_term_from_left && jump_time) {
681 WarningOut() <<
"Discontinuous time term not supported yet.\n";
693 return (
eq_fields_->storativity.input_list_size() == 0);
706 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
709 int is_linear_common;
714 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
715 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
716 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
718 if (! is_linear_common) {
726 while (nonlinear_iteration_ < this->
min_n_it_ ||
727 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
729 convergence_history.push_back(residual_norm);
732 if (convergence_history.size() >= 5 &&
733 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
734 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
740 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
744 if (! is_linear_common)
750 if (is_linear_common){
753 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
767 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
770 chkerr(VecDestroy(&save_solution));
794 if(
eq_data_->mortar_method_ != MortarMethod::NoMortar){
795 auto multidim_assembler = AssemblyFlowBase::create< AssemblyMH >(
eq_fields_,
eq_data_);
797 unsigned int dim = dh_cell.dim();
798 multidim_assembler[dim-1]->fix_velocity(dh_cell);
865 unsigned int dim = dh_cell.dim();
866 assembler[dim-1]->assemble(dh_cell);
884 double zeros[100000];
885 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
888 tmp_rows.reserve(200);
891 dofs.reserve(
eq_data_->dh_->max_elem_dofs());
892 dofs_ngh.reserve(
eq_data_->dh_->max_elem_dofs());
897 const uint ndofs = dh_cell.n_dofs();
899 dh_cell.get_dof_indices(dofs);
908 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
916 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
917 dofs_ngh.resize(ndofs_ngh);
923 const unsigned int t = dh_neighb_cell.
n_dofs() - (dh_neighb_cell.
dim()+1) + neighb_side.side().side_idx();
924 tmp_rows.push_back(dofs_ngh[t]);
938 for(
auto &isec : isec_list ) {
942 const uint ndofs_slave = dh_cell_slave.
n_dofs();
943 dofs_ngh.resize(ndofs_slave);
947 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->
n_sides(); i_side++) {
949 tmp_rows.push_back( dofs_ngh[(ndofs_slave+1)/2+i_side] );
959 edge_rows = dofs.
data() + nsides +1;
998 const uint ndofs = dh_cell.n_dofs();
999 global_dofs.resize(ndofs);
1000 dh_cell.get_dof_indices(global_dofs);
1005 double source = ele.
measure() * cs *
1012 {dh_cell.get_loc_dof_indices()[ndofs/2]}, {0}, {source});
1032 #ifdef FLOW123D_HAVE_BDDCML
1033 WarningOut() <<
"For BDDC no Schur complements are used.";
1046 THROW( ExcBddcmlNotSupported() );
1047 #endif // FLOW123D_HAVE_BDDCML
1052 WarningOut() <<
"Invalid number of Schur Complements. Using 2.";
1065 ls->LinSys::set_from_input(in_rec);
1074 ISCreateGeneral(PETSC_COMM_SELF, side_dofs_vec.size(), &(side_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1089 const PetscInt *b_indices;
1090 ISGetIndices(ls->
IsB, &b_indices);
1092 for(
uint i_b=0, i_bb=0; i_b < b_size && i_bb < elem_dofs_vec.size(); i_b++) {
1093 if (b_indices[i_b] == elem_dofs_vec[i_bb])
1094 elem_dofs_vec[i_bb++] = i_b + ds->
begin();
1096 ISRestoreIndices(ls->
IsB, &b_indices);
1099 ISCreateGeneral(PETSC_COMM_SELF, elem_dofs_vec.size(), &(elem_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1127 THROW( ExcUnknownSolver() );
1139 START_TIMER(
"DarcyFlowMH_Steady::assembly_linear_system");
1196 std::string output_file;
1208 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1209 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1221 double d_max = std::numeric_limits<double>::max();
1222 double h1 = d_max, h2 = d_max, h3 = d_max;
1223 double he2 = d_max, he3 = d_max;
1226 case 1: h1 = std::min(h1,ele.measure());
break;
1227 case 2: h2 = std::min(h2,ele.measure());
break;
1228 case 3: h3 = std::min(h3,ele.measure());
break;
1231 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1233 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1234 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1238 if(h1 == d_max) h1 = 0;
1239 if(h2 == d_max) h2 = 0;
1240 if(h3 == d_max) h3 = 0;
1241 if(he2 == d_max) he2 = 0;
1242 if(he3 == d_max) he3 = 0;
1245 file = fopen(output_file.c_str(),
"a");
1247 fprintf(file,
"nB = %d;\n",
eq_data_->dh_->mesh()->get_el_ds()->size());
1249 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1250 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1268 START_TIMER(
"DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1296 dh_cell.get_dof_indices(cell_dofs_global);
1298 inet.insert(inet.end(), cell_dofs_global.begin(), cell_dofs_global.end());
1299 uint n_inet = cell_dofs_global.size();
1302 uint dim = dh_cell.elm().dim();
1303 elDimMax = std::max( elDimMax, dim );
1304 elDimMin = std::min( elDimMin, dim );
1308 isegn.push_back( dh_cell.elm_idx());
1311 for (
unsigned int si=0; si<dh_cell.elm()->n_sides(); si++) {
1312 arma::vec3 coord = dh_cell.elm().side(si)->centre();
1315 localDofMap.insert( std::make_pair( cell_dofs_global[si], coord ) );
1317 localDofMap.insert( std::make_pair( cell_dofs_global[si+dim+2], coord ) );
1320 arma::vec3 elm_centre = dh_cell.elm().centre();
1321 localDofMap.insert( std::make_pair( cell_dofs_global[dim+1], elm_centre ) );
1325 for(
DHCellSide side : dh_cell.neighb_sides()) {
1326 uint neigh_dim = side.cell().elm().dim();
1327 side.cell().get_dof_indices(cell_dofs_global);
1328 int edge_row = cell_dofs_global[neigh_dim+2+side.side_idx()];
1329 localDofMap.insert( std::make_pair( edge_row, side.centre() ) );
1330 inet.push_back( edge_row );
1333 nnet.push_back(n_inet);
1338 double conduct =
eq_fields_->conductivity.value( elm_centre , dh_cell.elm() );
1339 auto aniso =
eq_fields_->anisotropy.value( elm_centre , dh_cell.elm() );
1343 for (
int i = 0; i < 3; i++) {
1344 coef = coef + aniso.at(i,i);
1347 coef = conduct*coef / 3;
1350 "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1351 element_permeability.push_back( 1. / coef );
1361 auto distr =
eq_data_->dh_->distr();
1370 int numNodeSub = localDofMap.size();
1381 for ( ; itB != localDofMap.end(); ++itB ) {
1382 isngn[ind] = itB -> first;
1385 for (
int j = 0; j < 3; j++ ) {
1386 xyz[ j*numNodeSub + ind ] = coord[j];
1391 localDofMap.clear();
1399 Global2LocalMap_ global2LocalNodeMap;
1400 for (
unsigned ind = 0; ind < isngn.size(); ++ind ) {
1401 global2LocalNodeMap.insert( std::make_pair(
static_cast<unsigned>( isngn[ind] ), ind ) );
1406 for (
unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1407 int nne = nnet[ iEle ];
1408 for (
int ien = 0; ien < nne; ien++ ) {
1410 int indGlob = inet[indInet];
1412 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1413 OLD_ASSERT( pos != global2LocalNodeMap.end(),
1414 "Cannot remap node index %d to local indices. \n ", indGlob );
1415 int indLoc =
static_cast<int> ( pos -> second );
1418 inet[ indInet++ ] = indLoc;
1422 int numNodes =
size;
1423 int numDofsInt =
size;
1425 int meshDim = elDimMax;
1437 bddc_ls -> load_mesh( LinSys_BDDC::BDDCMatrixType::SPD_VIA_SYMMETRICGENERAL, spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1459 if(
time_ !=
nullptr)
1509 LocDofVec loc_dofs = dh_cell.get_loc_dof_indices();
1510 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
1514 eq_data_->full_solution.add(loc_dofs[edge_dof], init_value/n_sides_of_edge);
1518 eq_data_->full_solution.ghost_to_local_begin();
1519 eq_data_->full_solution.ghost_to_local_end();
1520 eq_data_->full_solution.local_to_ghost_begin();
1521 eq_data_->full_solution.local_to_ghost_end();
1527 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1530 unsigned int dim = dh_cell.dim();
1531 assembler[dim-1]->assemble_reconstruct(dh_cell);
1534 eq_data_->full_solution.local_to_ghost_begin();
1535 eq_data_->full_solution.local_to_ghost_end();
1546 PetscScalar *local_diagonal;
1554 dofs.reserve(
eq_data_->dh_->max_elem_dofs());
1558 dofs.resize(dh_cell.n_dofs());
1559 dh_cell.get_dof_indices(dofs);
1562 const uint p_ele_dof = dh_cell.n_dofs() / 2;
1568 local_diagonal[dh_cell.get_loc_dof_indices()[p_ele_dof]]= - diagonal_coeff /
time_->
dt();
1571 {dh_cell.get_loc_dof_indices()[p_ele_dof]},
1572 {diagonal_coeff}, 0.0);
1574 VecRestoreArray(new_diagonal,& local_diagonal);
1575 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1577 schur0->set_matrix_changed();
1579 balance_->finish_mass_assembly(eq_data_->water_balance_idx);
1586 if (scale_factor != 1.0) {
1607 void dofs_range(
unsigned int n_dofs,
unsigned int &min,
unsigned int &max,
unsigned int component) {
1611 }
else if (component==1) {
1623 unsigned int i, n_dofs, min, max;
1627 n_dofs = dh_cell.get_dof_indices(dof_indices);
1629 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);