28 #include "petscviewer.h"
29 #include "petscerror.h"
84 .
add_value(
MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
94 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
96 "Boundary switch piezometric head for BC types: seepage, river." )
98 "Initial condition for the pressure given as the piezometric head." )
100 return field_descriptor;
107 "Linear solver for MH problem.")
109 "Residual tolerance.")
111 "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria "
112 "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution."
113 "If greater then 'max_it' the value is set to 'max_it'.")
115 "Maximum number of iterations (linear solutions) of the non-linear solver.")
117 "If a stagnation of the nonlinear solver is detected the solver stops. "
118 "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver "
119 "ends with convergence success on stagnation, but it reports warning about it.")
124 return it::Record(
"Flow_Darcy_LMH",
"Lumped Mixed-Hybrid solver for saturated Darcy flow.")
128 "Vector of the gravity force. Dimensionless.")
130 "Input data for Darcy flow model.")
132 "Non-linear solver for MH problem.")
134 "Output stream settings.\n Specify file format, precision etc.")
137 IT::Default(
"{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
138 "Specification of output fields and output times.")
140 "Output settings specific to Darcy flow model.\n"
141 "Includes raw output and some experimental functionality.")
143 "Settings for computing mass balance.")
145 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
151 Input::register_class< DarcyLMH, Mesh &, const Input::Record >(
"Flow_Darcy_LMH") +
196 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
203 data_ = make_shared<EqData>();
206 data_->is_linear=
true;
235 gravity_array.copy_to(gvec);
238 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
241 auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
242 field_algo->set_value(gvalue);
243 data_->gravity_field.set(field_algo, 0.0);
245 data_->bc_pressure.add_factory(
247 (
data_->gravity_,
"bc_piezo_head") );
248 data_->bc_switch_pressure.add_factory(
250 (
data_->gravity_,
"bc_switch_piezo_head") );
251 data_->init_pressure.add_factory(
253 (
data_->gravity_,
"init_piezo_head") );
261 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
272 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
273 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
274 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
275 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
276 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
277 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
278 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
279 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
280 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
281 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
282 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
284 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
290 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
291 data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
292 data_->dh_->distribute_dofs(ds);
298 data_->add_coords_field();
301 uint rt_component = 0;
302 data_->full_solution =
data_->dh_->create_vector();
303 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
data_->dh_, &
data_->full_solution, rt_component);
304 data_->flux.set(ele_flux_ptr, 0.0);
308 uint p_ele_component = 1;
309 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_ele_component);
310 data_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
312 uint p_edge_component = 2;
313 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_edge_component);
314 data_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
316 data_->field_ele_piezo_head.set(
323 uint p_element_component = 1;
324 data_->dh_p_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_element_component);
328 uint p_edge_component = 2;
329 data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_edge_component);
334 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
335 data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
336 data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
343 data_->p_edge_solution =
data_->dh_cr_->create_vector();
344 data_->p_edge_solution_previous =
data_->dh_cr_->create_vector();
345 data_->p_edge_solution_previous_time =
data_->dh_cr_->create_vector();
354 .val<Input::AbstractRecord>(
"linear_solver");
366 data_->water_balance_idx =
balance_->add_quantity(
"water_volume");
375 data_->multidim_assembler = AssemblyBase::create< AssemblyLMH >(
data_);
407 DebugOut().fmt(
"Read initial condition\n");
411 LocDofVec p_indices = dh_cell.cell_with_other_dh(
data_->dh_p_.get()).get_loc_dof_indices();
413 LocDofVec l_indices = dh_cell.cell_with_other_dh(
data_->dh_cr_.get()).get_loc_dof_indices();
417 double init_value =
data_->init_pressure.value(ele.
centre(),ele);
418 unsigned int p_idx =
data_->dh_p_->parent_indices()[p_indices[0]];
419 data_->full_solution.set(p_idx, init_value);
421 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
423 unsigned int l_idx =
data_->dh_cr_->parent_indices()[l_indices[i]];
424 data_->full_solution.add(l_idx, init_value/n_sides_of_edge);
426 data_->p_edge_solution.add(l_indices[i], init_value/n_sides_of_edge);
430 data_->full_solution.ghost_to_local_begin();
431 data_->full_solution.ghost_to_local_end();
433 data_->p_edge_solution.ghost_to_local_begin();
434 data_->p_edge_solution.ghost_to_local_end();
435 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
457 data_->p_edge_solution.zero_entries();
459 if (
data_->use_steady_assembly_) {
478 data_->full_solution.copy_from(temp);
500 data_->full_solution.local_to_ghost_begin();
501 data_->full_solution.local_to_ghost_end();
509 bool jump_time =
data_->storativity.is_jump_time();
510 if (! zero_time_term_from_left) {
515 data_->use_steady_assembly_ =
false;
521 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
530 if (! zero_time_term_from_left && ! jump_time && output)
537 if (zero_time_term_from_right) {
539 data_->use_steady_assembly_ =
true;
544 }
else if (! zero_time_term_from_left && jump_time) {
545 WarningOut() <<
"Discontinuous time term not supported yet.\n";
556 return (
data_->storativity.input_list_size() == 0);
569 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
572 int is_linear_common;
577 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
578 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
579 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
581 if (! is_linear_common) {
587 while (nonlinear_iteration_ < this->
min_n_it_ ||
588 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
590 convergence_history.push_back(residual_norm);
594 if (convergence_history.size() >= 5 &&
595 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
596 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
602 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
606 if (! is_linear_common){
607 data_->p_edge_solution_previous.copy_from(
data_->p_edge_solution);
608 data_->p_edge_solution_previous.local_to_ghost_begin();
609 data_->p_edge_solution_previous.local_to_ghost_end();
613 MessageOut().fmt(
"[schur solver] lin. it: {}, reason: {}, residual: {}\n",
619 if (is_linear_common){
622 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
629 VecAXPBY(
data_->p_edge_solution.petsc_vec(), (1-alpha), alpha,
data_->p_edge_solution_previous.petsc_vec());
636 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
656 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
657 data_->p_edge_solution_previous_time.local_to_ghost_begin();
658 data_->p_edge_solution_previous_time.local_to_ghost_end();
672 balance_->calculate_cumulative(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
673 balance_->calculate_instant(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
680 return data_->lin_sys_schur->get_solution_precision();
692 START_TIMER(
"DarcyLMH::assembly_steady_mh_matrix");
705 unsigned int dim = dh_cell.dim();
706 assembler[dim-1]->assemble(dh_cell);
722 double zeros[100000];
723 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
726 tmp_rows.reserve(200);
729 dofs.reserve(
data_->dh_cr_->max_elem_dofs());
730 dofs_ngh.reserve(
data_->dh_cr_->max_elem_dofs());
736 const uint ndofs = dh_cell.n_dofs();
737 dofs.resize(dh_cell.n_dofs());
738 dh_cell.get_dof_indices(dofs);
740 int* dofs_ptr = dofs.
data();
747 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
755 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
756 dofs_ngh.resize(ndofs_ngh);
760 tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
770 for(
auto &isec : isec_list ) {
774 const uint ndofs_slave = dh_cell_slave.
n_dofs();
775 dofs_ngh.resize(ndofs_slave);
779 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->n_sides(); i_side++) {
780 tmp_rows.push_back( dofs_ngh[i_side] );
920 data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*
data_->dh_cr_->distr()) );
993 data_->full_solution.zero_entries();
994 data_->p_edge_solution.zero_entries();
998 THROW( ExcUnknownSolver() );
1009 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1011 data_->full_solution.zero_entries();
1012 data_->p_edge_solution.local_to_ghost_begin();
1013 data_->p_edge_solution.local_to_ghost_end();
1020 unsigned int dim = dh_cell.dim();
1021 assembler[dim-1]->assemble_reconstruct(dh_cell);
1024 data_->full_solution.local_to_ghost_begin();
1025 data_->full_solution.local_to_ghost_end();
1033 START_TIMER(
"DarcyFlowMH::assembly_linear_system");
1036 data_->p_edge_solution.local_to_ghost_begin();
1037 data_->p_edge_solution.local_to_ghost_end();
1039 data_->is_linear=
true;
1071 std::string output_file;
1074 double d_max = std::numeric_limits<double>::max();
1075 double h1 = d_max, h2 = d_max, h3 = d_max;
1076 double he2 = d_max, he3 = d_max;
1079 case 1: h1 = std::min(h1,ele.measure());
break;
1080 case 2: h2 = std::min(h2,ele.measure());
break;
1081 case 3: h3 = std::min(h3,ele.measure());
break;
1084 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1086 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1087 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1091 if(h1 == d_max) h1 = 0;
1092 if(h2 == d_max) h2 = 0;
1093 if(h3 == d_max) h3 = 0;
1094 if(he2 == d_max) he2 = 0;
1095 if(he3 == d_max) he3 = 0;
1098 file = fopen(output_file.c_str(),
"a");
1099 fprintf(file,
"nA = %d;\n",
data_->dh_cr_disc_->distr()->size());
1100 fprintf(file,
"nB = %d;\n",
data_->dh_->mesh()->get_el_ds()->size());
1101 fprintf(file,
"nBF = %d;\n",
data_->dh_cr_->distr()->size());
1102 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1103 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1109 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1110 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1111 MatView( *
const_cast<Mat*
>(
lin_sys_schur().get_matrix()), viewer);
1112 VecView( *
const_cast<Vec*
>(
lin_sys_schur().get_rhs()), viewer);
1113 VecView( *
const_cast<Vec*
>(&(
lin_sys_schur().get_solution())), viewer);
1114 VecView( *
const_cast<Vec*
>(&(
data_->full_solution.petsc_vec())), viewer);
1313 if(
time_ !=
nullptr)
1321 unsigned int i, n_dofs, min, max;
1325 n_dofs = dh_cell.get_dof_indices(dof_indices);
1327 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);