28 #include "petscviewer.h"
29 #include "petscerror.h"
82 .
add_value(
MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
90 "Homogeneous Neumann boundary condition\n(zero normal flux over the boundary).")
92 "Dirichlet boundary condition. "
93 "Specify the pressure head through the ``bc_pressure`` field "
94 "or the piezometric head through the ``bc_piezo_head`` field.")
95 .
add_value(
total_flux,
"total_flux",
"Flux boundary condition (combines Neumann and Robin type). "
96 "Water inflow equal to (($ \\delta_d(q_d^N + \\sigma_d (h_d^R - h_d) )$)). "
97 "Specify the water inflow by the ``bc_flux`` field, the transition coefficient by ``bc_robin_sigma`` "
98 "and the reference pressure head or piezometric head through ``bc_pressure`` or ``bc_piezo_head`` respectively.")
100 "Seepage face boundary condition. Pressure and inflow bounded from above. Boundary with potential seepage flow "
101 "is described by the pair of inequalities: "
102 "(($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. "
103 "Caution: setting (($q_d^N$)) strictly negative "
104 "may lead to an ill posed problem since a positive outflow is enforced. "
105 "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."
108 "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: "
109 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d) )$)). For the water level under the bedrock, constant infiltration is used: "
110 "(( $ \\delta_d(q_d^N + \\sigma_d(H_d^D - H_d^S) )$)). Parameters: ``bc_pressure``, ``bc_switch_pressure``, "
111 " ``bc_sigma``, ``bc_flux``."
122 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
124 "Boundary switch piezometric head for BC types: seepage, river." )
126 "Initial condition for the pressure given as the piezometric head." )
128 return field_descriptor;
135 "Linear solver for MH problem.")
137 "Residual tolerance.")
139 "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria "
140 "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution."
141 "If greater then 'max_it' the value is set to 'max_it'.")
143 "Maximum number of iterations (linear solutions) of the non-linear solver.")
145 "If a stagnation of the nonlinear solver is detected the solver stops. "
146 "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver "
147 "ends with convergence success on stagnation, but it reports warning about it.")
150 return it::Record(
"Flow_Darcy_MH",
"Mixed-Hybrid solver for saturated Darcy flow.")
153 "Vector of the gravity force. Dimensionless.")
155 "Input data for Darcy flow model.")
157 "Non-linear solver for MH problem.")
159 "Output stream settings.\n Specify file format, precision etc.")
162 "Specification of output fields and output times.")
164 "Output settings specific to Darcy flow model.\n"
165 "Includes raw output and some experimental functionality.")
167 "Settings for computing mass balance.")
169 "Time governor settings for the unsteady Darcy flow model.")
171 "Number of Schur complements to perform when solving MH system.")
173 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
179 Input::register_class< DarcyMH, Mesh &, const Input::Record >(
"Flow_Darcy_MH") +
188 *
this += anisotropy.name(
"anisotropy")
189 .description(
"Anisotropy of the conductivity tensor.")
190 .input_default(
"1.0")
193 *
this += cross_section.name(
"cross_section")
194 .description(
"Complement dimension parameter (cross section for 1D, thickness for 2D).")
195 .input_default(
"1.0")
196 .units(
UnitSI().m(3).md() );
198 *
this += conductivity.name(
"conductivity")
199 .description(
"Isotropic conductivity scalar.")
200 .input_default(
"1.0")
201 .units(
UnitSI().m().s(-1) )
204 *
this += sigma.name(
"sigma")
205 .description(
"Transition coefficient between dimensions.")
206 .input_default(
"1.0")
209 *
this += water_source_density.name(
"water_source_density")
210 .description(
"Water source density.")
211 .input_default(
"0.0")
214 *
this += bc_type.name(
"bc_type")
215 .description(
"Boundary condition type.")
216 .input_selection( get_bc_type_selection() )
217 .input_default(
"\"none\"")
221 .disable_where(bc_type, {
none, seepage} )
223 .description(
"Prescribed pressure value on the boundary. Used for all values of ``bc_type`` except ``none`` and ``seepage``. "
224 "See documentation of ``bc_type`` for exact meaning of ``bc_pressure`` in individual boundary condition types.")
225 .input_default(
"0.0")
229 .disable_where(bc_type, {
none, dirichlet} )
231 .description(
"Incoming water boundary flux. Used for bc_types : ``total_flux``, ``seepage``, ``river``.")
232 .input_default(
"0.0")
233 .units(
UnitSI().m().s(-1) );
235 *
this += bc_robin_sigma
236 .disable_where(bc_type, {
none, dirichlet, seepage} )
237 .name(
"bc_robin_sigma")
238 .description(
"Conductivity coefficient in the ``total_flux`` or the ``river`` boundary condition type.")
239 .input_default(
"0.0")
242 *
this += bc_switch_pressure
243 .disable_where(bc_type, {
none, dirichlet, total_flux} )
244 .name(
"bc_switch_pressure")
245 .description(
"Critical switch pressure for ``seepage`` and ``river`` boundary conditions.")
246 .input_default(
"0.0")
251 *
this += init_pressure.name(
"init_pressure")
252 .description(
"Initial condition for pressure in time dependent problems.")
253 .input_default(
"0.0")
256 *
this += storativity.name(
"storativity")
257 .description(
"Storativity (in time dependent problems).")
258 .input_default(
"0.0")
304 data_ = make_shared<EqData>();
307 data_->is_linear=
true;
338 gravity_array.copy_to(gvec);
340 data_->gravity_ = arma::vec(gvec);
341 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
343 data_->bc_pressure.add_factory(
345 (
data_->gravity_,
"bc_piezo_head") );
346 data_->bc_switch_pressure.add_factory(
348 (
data_->gravity_,
"bc_switch_piezo_head") );
349 data_->init_pressure.add_factory(
351 (
data_->gravity_,
"init_piezo_head") );
359 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
381 .val<Input::AbstractRecord>(
"linear_solver");
400 data_->water_balance_idx =
balance_->add_quantity(
"water_volume");
430 if (zero_time_term_from_right) {
461 bool jump_time =
data_->storativity.is_jump_time();
462 if (! zero_time_term_from_left) {
472 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
481 if (! zero_time_term_from_left && ! jump_time)
output_data();
487 if (zero_time_term_from_right) {
492 }
else if (! zero_time_term_from_left && jump_time) {
493 WarningOut() <<
"Discontinuous time term not supported yet.\n";
504 return (
data_->storativity.input_list_size() == 0);
517 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
520 int is_linear_common;
525 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
526 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
527 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
529 if (! is_linear_common) {
537 while (nonlinear_iteration_ < this->
min_n_it_ ||
538 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
540 convergence_history.push_back(residual_norm);
543 if (convergence_history.size() >= 5 &&
544 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
545 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
551 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
555 if (! is_linear_common)
561 if (is_linear_common){
564 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
586 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
589 chkerr(VecDestroy(&save_solution));
616 if(
data_->mortar_method_ != MortarMethod::NoMortar){
617 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(
data_);
620 unsigned int dim = ele_ac.
dim();
621 multidim_assembler[dim-1]->fix_velocity(ele_ac);
679 vec_size = this->
size;
680 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
686 OLD_ASSERT(vec != NULL,
"Requested solution is not allocated!\n");
698 START_TIMER(
"DarcyFlowMH_Steady::assembly_steady_mh_matrix");
711 unsigned int dim = ele_ac.
dim();
712 assembler[dim-1]->assemble(ele_ac);
723 START_TIMER(
"DarcyFlowMH_Steady::allocate_mh_matrix");
734 double zeros[100000];
735 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
738 tmp_rows.reserve(200);
740 unsigned int nsides, loc_size;
747 loc_size = 1 + 2*nsides;
748 unsigned int i_side = 0;
750 for (; i_side < nsides; i_side++) {
751 local_dofs[i_side] = ele_ac.side_row(i_side);
752 local_dofs[i_side+nsides] = ele_ac.edge_row(i_side);
754 local_dofs[i_side+nsides] = ele_ac.ele_row();
755 int * edge_rows = local_dofs + nsides;
759 ls->
mat_set_values(loc_size, local_dofs, loc_size, local_dofs, zeros);
763 unsigned int n_neighs = ele_ac.element_accessor()->n_neighs_vb();
764 for (
unsigned int i = 0; i < n_neighs; i++) {
767 Neighbour *ngh = ele_ac.element_accessor()->neigh_vb[i];
769 tmp_rows.push_back(neigh_edge_row);
782 for(
auto &isec : isec_list ) {
786 for(
unsigned int i_side=0; i_side < slave_ele->
n_sides(); i_side++) {
833 double cs =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor());
836 double source = ele_ac.measure() * cs *
837 data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
840 balance_->add_source_vec_values(
data_->water_balance_idx, ele_ac.region().bulk_idx(), {(LongIdx) ele_ac.ele_row()}, {source});
860 #ifdef FLOW123D_HAVE_BDDCML
861 WarningOut() <<
"For BDDC no Schur complements are used.";
876 xprintf(
Err,
"Flow123d was not build with BDDCML support.\n");
877 #endif // FLOW123D_HAVE_BDDCML
882 WarningOut() <<
"Invalid number of Schur Complements. Using 2.";
895 ls->LinSys::set_from_input(in_rec);
941 xprintf(
Err,
"Unknown solver type. Internal error.\n");
955 START_TIMER(
"DarcyFlowMH_Steady::assembly_linear_system");
957 data_->is_linear=
true;
974 auto multidim_assembler = AssemblyBase::create< AssemblyMH >(
data_);
1011 std::string output_file;
1023 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1024 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1034 double d_max = std::numeric_limits<double>::max();
1035 double h1 = d_max, h2 = d_max, h3 = d_max;
1036 double he2 = d_max, he3 = d_max;
1039 case 1: h1 = std::min(h1,ele.measure());
break;
1040 case 2: h2 = std::min(h2,ele.measure());
break;
1041 case 3: h3 = std::min(h3,ele.measure());
break;
1044 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1046 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1047 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1051 if(h1 == d_max) h1 = 0;
1052 if(h2 == d_max) h2 = 0;
1053 if(h3 == d_max) h3 = 0;
1054 if(he2 == d_max) he2 = 0;
1055 if(he3 == d_max) he3 = 0;
1058 file = fopen(output_file.c_str(),
"a");
1062 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1063 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1069 START_TIMER(
"DarcyFlowMH_Steady::set_mesh_data_for_bddc");
1090 for (
unsigned int i_loc = 0; i_loc <
mh_dh.
el_ds->
lsize(); i_loc++ ) {
1094 elDimMax = std::max( elDimMax, ele_ac.dim() );
1095 elDimMin = std::min( elDimMin, ele_ac.dim() );
1097 isegn.push_back( ele_ac.ele_global_idx() );
1100 for (
unsigned int si=0; si<ele_ac.element_accessor()->n_sides(); si++) {
1102 int side_row = ele_ac.side_row(si);
1103 arma::vec3 coord = ele_ac.side(si)->centre();
1105 localDofMap.insert( std::make_pair( side_row, coord ) );
1106 inet.push_back( side_row );
1111 int el_row = ele_ac.ele_row();
1113 localDofMap.insert( std::make_pair( el_row, coord ) );
1114 inet.push_back( el_row );
1117 for (
unsigned int si=0; si<ele_ac.element_accessor()->n_sides(); si++) {
1119 int edge_row = ele_ac.edge_row(si);
1120 arma::vec3 coord = ele_ac.side(si)->centre();
1122 localDofMap.insert( std::make_pair( edge_row, coord ) );
1123 inet.push_back( edge_row );
1128 for (
unsigned int i_neigh = 0; i_neigh < ele_ac.element_accessor()->n_neighs_vb(); i_neigh++) {
1129 int edge_row =
mh_dh.
row_4_edge[ ele_ac.element_accessor()->neigh_vb[i_neigh]->edge_idx() ];
1130 arma::vec3 coord = ele_ac.element_accessor()->neigh_vb[i_neigh]->edge()->side(0)->centre();
1132 localDofMap.insert( std::make_pair( edge_row, coord ) );
1133 inet.push_back( edge_row );
1137 nnet.push_back( nne );
1142 double conduct =
data_->conductivity.value( centre , ele_ac.element_accessor() );
1143 auto aniso =
data_->anisotropy.value( centre, ele_ac.element_accessor() );
1147 for (
int i = 0; i < 3; i++) {
1148 coef = coef + aniso.at(i,i);
1151 coef = conduct*coef / 3;
1154 "Zero coefficient of hydrodynamic resistance %f . \n ", coef );
1155 element_permeability.push_back( 1. / coef );
1159 int numNodeSub = localDofMap.size();
1170 for ( ; itB != localDofMap.end(); ++itB ) {
1171 isngn[ind] = itB -> first;
1174 for (
int j = 0; j < 3; j++ ) {
1175 xyz[ j*numNodeSub + ind ] = coord[j];
1180 localDofMap.clear();
1188 Global2LocalMap_ global2LocalNodeMap;
1189 for (
unsigned ind = 0; ind < isngn.size(); ++ind ) {
1190 global2LocalNodeMap.insert( std::make_pair(
static_cast<unsigned>( isngn[ind] ), ind ) );
1195 for (
unsigned int iEle = 0; iEle < isegn.size(); iEle++ ) {
1196 int nne = nnet[ iEle ];
1197 for (
int ien = 0; ien < nne; ien++ ) {
1199 int indGlob = inet[indInet];
1201 Global2LocalMap_::iterator pos = global2LocalNodeMap.find( indGlob );
1202 OLD_ASSERT( pos != global2LocalNodeMap.end(),
1203 "Cannot remap node index %d to local indices. \n ", indGlob );
1204 int indLoc =
static_cast<int> ( pos -> second );
1207 inet[ indInet++ ] = indLoc;
1211 int numNodes =
size;
1212 int numDofsInt =
size;
1214 int meshDim = elDimMax;
1216 bddc_ls -> load_mesh( spaceDim, numNodes, numDofsInt, inet, nnet, nndf, isegn, isngn, isngn, xyz, element_permeability, meshDim );
1244 if(
time_ !=
nullptr)
1264 VecCreateSeqWithArray(PETSC_COMM_SELF,1,
size,
solution,
1269 loc_idx =
new int [
size];
1272 for (
unsigned int si=0; si<ele->n_sides(); si++) {
1279 for(
unsigned int i_edg=0; i_edg <
mesh_->
n_edges(); i_edg++) {
1282 OLD_ASSERT( i==
size,
"Size of array does not match number of fills.\n");
1284 ISCreateGeneral(PETSC_COMM_SELF,
size, loc_idx, PETSC_COPY_VALUES, &(is_loc));
1288 chkerr(ISDestroy(&(is_loc)));
1340 for (
unsigned int i_loc_el = 0; i_loc_el <
mh_dh.
el_ds->
lsize(); i_loc_el++) {
1343 local_sol[ele_ac.ele_local_row()] =
data_->init_pressure.value(ele_ac.centre(),ele_ac.element_accessor());
1357 PetscScalar *local_diagonal;
1365 for (
unsigned int i_loc_el = 0; i_loc_el <
mh_dh.
el_ds->
lsize(); i_loc_el++) {
1369 double diagonal_coeff =
data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor())
1370 *
data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor())
1372 local_diagonal[ele_ac.ele_local_row()]= - diagonal_coeff /
time_->
dt();
1376 ele_ac.region().bulk_idx(), { LongIdx(ele_ac.ele_row()) }, {diagonal_coeff});
1391 if (scale_factor != 1.0) {