28 #include "petscviewer.h"
29 #include "petscerror.h"
87 .
add_value(
MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
95 "Homogeneous Neumann boundary condition\n(zero normal flux over the boundary).")
97 "Dirichlet boundary condition. "
98 "Specify the pressure head through the ``bc_pressure`` field "
99 "or the piezometric head through the ``bc_piezo_head`` field.")
100 .
add_value(
total_flux,
"total_flux",
"Flux boundary condition (combines Neumann and Robin type). "
101 "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). "
102 "Specify the water inflow by the ``bc_flux`` field, the transition coefficient by ``bc_robin_sigma`` "
103 "and the reference pressure head or piezometric head through ``bc_pressure`` or ``bc_piezo_head`` respectively.")
105 "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow "
106 "is described by the pair of inequalities: "
107 "(($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. "
108 "Caution: setting (($q_d^N$)) strictly negative "
109 "may lead to an ill posed problem since a positive outflow is enforced. "
110 "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."
113 "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: "
114 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: "
115 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, "
116 " ``bc_sigma``, ``bc_flux``."
127 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
129 "Boundary switch piezometric head for BC types: seepage, river." )
131 "Initial condition for the pressure given as the piezometric head." )
133 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.")
160 "Vector of the gravity force. Dimensionless.")
163 "Input fields of the equation defined by user.")
165 "Input data for Darcy flow model.")
167 "Non-linear solver for MH problem.")
169 "Output stream settings.\n Specify file format, precision etc.")
172 IT::Default(
"{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
173 "Specification of output fields and output times.")
175 "Output settings specific to Darcy flow model.\n"
176 "Includes raw output and some experimental functionality.")
178 "Settings for computing mass balance.")
180 "Number of Schur complements to perform when solving MH system.")
182 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
188 Input::register_class< DarcyMH, Mesh &, const Input::Record >(
equation_name_) +
195 *
this += field_ele_pressure.name(
"pressure_p0")
198 .description(
"Pressure solution - P0 interpolation.");
200 *
this += field_edge_pressure.name(
"pressure_edge")
203 .description(
"Pressure solution - Crouzeix-Raviart interpolation.");
205 *
this += field_ele_piezo_head.name(
"piezo_head_p0")
208 .description(
"Piezo head solution - P0 interpolation.");
210 *
this += field_ele_velocity.name(
"velocity_p0")
211 .units(
UnitSI().m().s(-1))
213 .description(
"Velocity solution - P0 interpolation.");
215 *
this += flux.name(
"flux")
216 .units(
UnitSI().m().s(-1))
218 .description(
"Darcy flow flux.");
220 *
this += anisotropy.name(
"anisotropy")
221 .description(
"Anisotropy of the conductivity tensor.")
222 .input_default(
"1.0")
225 *
this += cross_section.name(
"cross_section")
226 .description(
"Complement dimension parameter (cross section for 1D, thickness for 2D).")
227 .input_default(
"1.0")
228 .units(
UnitSI().m(3).md() );
230 *
this += conductivity.name(
"conductivity")
231 .description(
"Isotropic conductivity scalar.")
232 .input_default(
"1.0")
233 .units(
UnitSI().m().s(-1) )
236 *
this += sigma.name(
"sigma")
237 .description(
"Transition coefficient between dimensions.")
238 .input_default(
"1.0")
241 *
this += water_source_density.name(
"water_source_density")
242 .description(
"Water source density.")
243 .input_default(
"0.0")
246 *
this += bc_type.name(
"bc_type")
247 .description(
"Boundary condition type.")
248 .input_selection( get_bc_type_selection() )
249 .input_default(
"\"none\"")
253 .disable_where(bc_type, {
none, seepage} )
255 .description(
"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. "
256 "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.")
257 .input_default(
"0.0")
261 .disable_where(bc_type, {
none, dirichlet} )
263 .description(
"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.")
264 .input_default(
"0.0")
265 .units(
UnitSI().m().s(-1) );
267 *
this += bc_robin_sigma
268 .disable_where(bc_type, {
none, dirichlet, seepage} )
269 .name(
"bc_robin_sigma")
270 .description(
"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.")
271 .input_default(
"0.0")
274 *
this += bc_switch_pressure
275 .disable_where(bc_type, {
none, dirichlet, total_flux} )
276 .name(
"bc_switch_pressure")
277 .description(
"Critical switch pressure for ``seepage`` and ``river`` boundary conditions.")
278 .input_default(
"0.0")
283 *
this += init_pressure.name(
"init_pressure")
284 .description(
"Initial condition for pressure in time dependent problems.")
285 .input_default(
"0.0")
288 *
this += storativity.name(
"storativity")
289 .description(
"Storativity (in time dependent problems).")
290 .input_default(
"0.0")
293 *
this += extra_storativity.name(
"extra_storativity")
294 .description(
"Storativity added from upstream equation.")
296 .input_default(
"0.0")
297 .flags( input_copy );
299 *
this += extra_source.name(
"extra_water_source_density")
300 .description(
"Water source density added from upstream equation.")
301 .input_default(
"0.0")
303 .flags( input_copy );
305 *
this += gravity_field.name(
"gravity")
306 .description(
"Gravity vector.")
307 .input_default(
"0.0")
310 *
this += bc_gravity.name(
"bc_gravity")
311 .description(
"Boundary gravity vector.")
312 .input_default(
"0.0")
315 *
this += init_piezo_head.name(
"init_piezo_head")
317 .input_default(
"0.0")
318 .description(
"Init piezo head.");
320 *
this += bc_piezo_head.name(
"bc_piezo_head")
322 .input_default(
"0.0")
323 .description(
"Boundary piezo head.");
325 *
this += bc_switch_piezo_head.name(
"bc_switch_piezo_head")
327 .input_default(
"0.0")
328 .description(
"Boundary switch piezo head.");
378 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
418 return next_t * (1 - 2*std::numeric_limits<double>::epsilon());
440 gravity_array.copy_to(gvec);
446 auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
447 field_algo->set_value(gvalue);
448 eq_fields_->gravity_field.set(field_algo, 0.0);
466 eq_fields_->set_user_fields_map(user_fields_arr);
473 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
486 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
487 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
488 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
489 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
490 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
491 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
492 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
493 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
494 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
495 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
496 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
498 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
504 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
505 eq_data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
516 uint rt_component = 0;
518 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
eq_data_->dh_, &
eq_data_->full_solution, rt_component);
523 uint p_ele_component = 1;
524 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_ele_component);
525 eq_fields_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
527 uint p_edge_component = 2;
528 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_edge_component);
529 eq_fields_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
538 uint p_edge_component = 2;
539 eq_data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
eq_data_->dh_,p_edge_component);
544 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
545 eq_data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
546 eq_data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
556 .val<Input::AbstractRecord>(
"linear_solver");
605 if (zero_time_term_from_right) {
606 MessageOut() <<
"Flow zero time step - steady case\n";
615 MessageOut() <<
"Flow zero time step - unsteady case\n";
627 eq_data_->full_solution.local_to_ghost_begin();
628 eq_data_->full_solution.local_to_ghost_end();
645 eq_data_->full_solution.local_to_ghost_begin();
646 eq_data_->full_solution.local_to_ghost_end();
656 bool jump_time =
eq_fields_->storativity.is_jump_time();
657 if (! zero_time_term_from_left) {
658 MessageOut() <<
"Flow time step - unsteady case\n";
668 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
677 if (! zero_time_term_from_left && ! jump_time && output)
output_data();
683 if (zero_time_term_from_right) {
684 MessageOut() <<
"Flow time step - steady case\n";
689 }
else if (! zero_time_term_from_left && jump_time) {
690 WarningOut() <<
"Discontinuous time term not supported yet.\n";
702 return (
eq_fields_->storativity.input_list_size() == 0);
715 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
718 int is_linear_common;
723 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
724 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
725 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
727 if (! is_linear_common) {
735 while (nonlinear_iteration_ < this->
min_n_it_ ||
736 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
738 convergence_history.push_back(residual_norm);
741 if (convergence_history.size() >= 5 &&
742 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
743 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
749 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
753 if (! is_linear_common)
759 if (is_linear_common){
762 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
776 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
779 chkerr(VecDestroy(&save_solution));
803 if(
eq_data_->mortar_method_ != MortarMethod::NoMortar){
804 auto multidim_assembler = AssemblyFlowBase::create< AssemblyMH >(
eq_fields_,
eq_data_);
806 unsigned int dim = dh_cell.dim();
807 multidim_assembler[dim-1]->fix_velocity(dh_cell);
874 unsigned int dim = dh_cell.dim();
875 assembler[dim-1]->assemble(dh_cell);
893 double zeros[100000];
894 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
897 tmp_rows.reserve(200);
900 dofs.reserve(
eq_data_->dh_->max_elem_dofs());
901 dofs_ngh.reserve(
eq_data_->dh_->max_elem_dofs());
906 const uint ndofs = dh_cell.n_dofs();
908 dh_cell.get_dof_indices(dofs);
917 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
925 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
926 dofs_ngh.resize(ndofs_ngh);
932 const unsigned int t = dh_neighb_cell.
n_dofs() - (dh_neighb_cell.
dim()+1) + neighb_side.side().side_idx();
933 tmp_rows.push_back(dofs_ngh[t]);
947 for(
auto &isec : isec_list ) {
951 const uint ndofs_slave = dh_cell_slave.
n_dofs();
952 dofs_ngh.resize(ndofs_slave);
956 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->
n_sides(); i_side++) {
958 tmp_rows.push_back( dofs_ngh[(ndofs_slave+1)/2+i_side] );
968 edge_rows = dofs.
data() + nsides +1;
1007 const uint ndofs = dh_cell.n_dofs();
1008 global_dofs.resize(ndofs);
1009 dh_cell.get_dof_indices(global_dofs);
1014 double source = ele.
measure() * cs *
1021 {dh_cell.get_loc_dof_indices()[ndofs/2]}, {0}, {source});
1041 #ifdef FLOW123D_HAVE_BDDCML
1042 WarningOut() <<
"For BDDC no Schur complements are used.";
1055 THROW( ExcBddcmlNotSupported() );
1056 #endif // FLOW123D_HAVE_BDDCML
1061 WarningOut() <<
"Invalid number of Schur Complements. Using 2.";
1074 ls->LinSys::set_from_input(in_rec);
1083 ISCreateGeneral(PETSC_COMM_SELF, side_dofs_vec.size(), &(side_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1098 const PetscInt *b_indices;
1099 ISGetIndices(ls->
IsB, &b_indices);
1101 for(
uint i_b=0, i_bb=0; i_b < b_size && i_bb < elem_dofs_vec.size(); i_b++) {
1102 if (b_indices[i_b] == elem_dofs_vec[i_bb])
1103 elem_dofs_vec[i_bb++] = i_b + ds->
begin();
1105 ISRestoreIndices(ls->
IsB, &b_indices);
1108 ISCreateGeneral(PETSC_COMM_SELF, elem_dofs_vec.size(), &(elem_dofs_vec[0]), PETSC_COPY_VALUES, &is);
1136 THROW( ExcUnknownSolver() );
1148 START_TIMER(
"DarcyFlowMH_Steady::assembly_linear_system");
1205 std::string output_file;
1217 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1218 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1230 double d_max = std::numeric_limits<double>::max();
1231 double h1 = d_max, h2 = d_max, h3 = d_max;
1232 double he2 = d_max, he3 = d_max;
1235 case 1: h1 = std::min(h1,ele.measure());
break;
1236 case 2: h2 = std::min(h2,ele.measure());
break;
1237 case 3: h3 = std::min(h3,ele.measure());
break;
1240 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1242 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1243 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1247 if(h1 == d_max) h1 = 0;
1248 if(h2 == d_max) h2 = 0;
1249 if(h3 == d_max) h3 = 0;
1250 if(he2 == d_max) he2 = 0;
1251 if(he3 == d_max) he3 = 0;
1254 file = fopen(output_file.c_str(),
"a");
1256 fprintf(file,
"nB = %d;\n",
eq_data_->dh_->mesh()->get_el_ds()->size());
1258 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1259 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1277 START_TIMER(
"DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1305 dh_cell.get_dof_indices(cell_dofs_global);
1307 inet.insert(inet.end(), cell_dofs_global.begin(), cell_dofs_global.end());
1308 uint n_inet = cell_dofs_global.size();
1311 uint dim = dh_cell.elm().dim();
1312 elDimMax = std::max( elDimMax, dim );
1313 elDimMin = std::min( elDimMin, dim );
1317 isegn.push_back( dh_cell.elm_idx());
1320 for (
unsigned int si=0; si<dh_cell.elm()->n_sides(); si++) {
1321 arma::vec3 coord = dh_cell.elm().side(si)->centre();
1324 localDofMap.insert( std::make_pair( cell_dofs_global[si], coord ) );
1326 localDofMap.insert( std::make_pair( cell_dofs_global[si+dim+2], coord ) );
1329 arma::vec3 elm_centre = dh_cell.elm().centre();
1330 localDofMap.insert( std::make_pair( cell_dofs_global[dim+1], elm_centre ) );
1334 for(
DHCellSide side : dh_cell.neighb_sides()) {
1335 uint neigh_dim = side.cell().elm().dim();
1336 side.cell().get_dof_indices(cell_dofs_global);
1337 int edge_row = cell_dofs_global[neigh_dim+2+side.side_idx()];
1338 localDofMap.insert( std::make_pair( edge_row, side.centre() ) );
1339 inet.push_back( edge_row );
1342 nnet.push_back(n_inet);
1347 double conduct =
eq_fields_->conductivity.value( elm_centre , dh_cell.elm() );
1348 auto aniso =
eq_fields_->anisotropy.value( elm_centre , dh_cell.elm() );
1352 for (
int i = 0; i < 3; i++) {
1353 coef = coef + aniso.at(i,i);
1356 coef = conduct*coef / 3;
1358 ASSERT_GT( coef, 0. ).error(
"Zero coefficient of hydrodynamic resistance. \n");
1359 element_permeability.push_back( 1. / coef );
1369 auto distr =
eq_data_->dh_->distr();
1378 int numNodeSub = localDofMap.size();
1389 for ( ; itB != localDofMap.end(); ++itB ) {
1390 isngn[ind] = itB -> first;
1393 for (
int j = 0; j < 3; j++ ) {
1394 xyz[ j*numNodeSub + ind ] = coord[j];
1399 localDofMap.clear();
1407 Global2LocalMap_ global2LocalNodeMap;
1408 for (
unsigned ind = 0; ind < isngn.size(); ++ind ) {
1409 global2LocalNodeMap.insert( std::make_pair(
static_cast<unsigned>( isngn[ind] ), ind ) );
1414 for (
unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1415 int nne = nnet[ iEle ];
1416 for (
int ien = 0; ien < nne; ien++ ) {
1418 int indGlob = inet[indInet];
1420 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1421 ASSERT( pos != global2LocalNodeMap.end() )(indGlob).error(
"Cannot remap node global index to local indices.\n");
1422 int indLoc =
static_cast<int> ( pos -> second );
1425 inet[ indInet++ ] = indLoc;
1429 int numNodes =
size;
1430 int numDofsInt =
size;
1432 int meshDim = elDimMax;
1444 bddc_ls -> load_mesh( LinSys_BDDC::BDDCMatrixType::SPD_VIA_SYMMETRICGENERAL, spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1466 if(
time_ !=
nullptr)
1516 LocDofVec loc_dofs = dh_cell.get_loc_dof_indices();
1517 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
1521 eq_data_->full_solution.add(loc_dofs[edge_dof], init_value/n_sides_of_edge);
1525 eq_data_->full_solution.ghost_to_local_begin();
1526 eq_data_->full_solution.ghost_to_local_end();
1527 eq_data_->full_solution.local_to_ghost_begin();
1528 eq_data_->full_solution.local_to_ghost_end();
1534 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1537 unsigned int dim = dh_cell.dim();
1538 assembler[dim-1]->assemble_reconstruct(dh_cell);
1541 eq_data_->full_solution.local_to_ghost_begin();
1542 eq_data_->full_solution.local_to_ghost_end();
1553 PetscScalar *local_diagonal;
1561 dofs.reserve(
eq_data_->dh_->max_elem_dofs());
1565 dofs.resize(dh_cell.n_dofs());
1566 dh_cell.get_dof_indices(dofs);
1569 const uint p_ele_dof = dh_cell.n_dofs() / 2;
1575 local_diagonal[dh_cell.get_loc_dof_indices()[p_ele_dof]]= - diagonal_coeff /
time_->
dt();
1578 {dh_cell.get_loc_dof_indices()[p_ele_dof]},
1579 {diagonal_coeff}, 0.0);
1581 VecRestoreArray(new_diagonal,& local_diagonal);
1582 MatDiagonalSet(*( schur0->get_matrix() ), new_diagonal, ADD_VALUES);
1584 schur0->set_matrix_changed();
1586 balance_->finish_mass_assembly(eq_data_->water_balance_idx);
1593 if (scale_factor != 1.0) {
1614 void dofs_range(
unsigned int n_dofs,
unsigned int &min,
unsigned int &max,
unsigned int component) {
1618 }
else if (component==1) {
1629 ASSERT_LT(component, 3).error(
"Invalid component!");
1630 unsigned int i, n_dofs, min, max;
1634 n_dofs = dh_cell.get_dof_indices(dof_indices);
1636 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);