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") +
203 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
242 return next_t * (1 - 2*std::numeric_limits<double>::epsilon());
264 gravity_array.copy_to(gvec);
270 auto field_algo=std::make_shared<FieldConstant<3, FieldValue<3>::VectorFixed>>();
271 field_algo->set_value(gvalue);
272 eq_fields_->gravity_field.set(field_algo, 0.0);
291 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
302 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
303 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
304 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
305 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
306 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
307 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
308 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
309 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
310 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
311 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
312 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
314 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
320 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
321 eq_data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
331 uint rt_component = 0;
333 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
eq_data_->dh_, &
eq_data_->full_solution, rt_component);
338 uint p_ele_component = 1;
339 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_ele_component);
340 eq_fields_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
342 uint p_edge_component = 2;
343 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
eq_data_->dh_, &
eq_data_->full_solution, p_edge_component);
344 eq_fields_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
353 uint p_element_component = 1;
354 eq_data_->dh_p_ = std::make_shared<SubDOFHandlerMultiDim>(
eq_data_->dh_,p_element_component);
358 uint p_edge_component = 2;
359 eq_data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
eq_data_->dh_,p_edge_component);
364 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
365 eq_data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
366 eq_data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
375 eq_data_->p_edge_solution_previous_time =
eq_data_->dh_cr_->create_vector();
384 .val<Input::AbstractRecord>(
"linear_solver");
410 DebugOut().fmt(
"Read initial condition\n");
414 LocDofVec l_indices = dh_cell.get_loc_dof_indices();
421 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
423 eq_data_->p_edge_solution.add(l_indices[i], init_value/n_sides_of_edge);
427 eq_data_->p_edge_solution.ghost_to_local_begin();
428 eq_data_->p_edge_solution.ghost_to_local_end();
429 eq_data_->p_edge_solution.local_to_ghost_begin();
430 eq_data_->p_edge_solution.local_to_ghost_end();
452 eq_data_->p_edge_solution.zero_entries();
454 if (
eq_data_->use_steady_assembly_) {
455 MessageOut() <<
"Flow zero time step - steady case\n";
459 MessageOut() <<
"Flow zero time step - unsteady case\n";
487 eq_data_->full_solution.local_to_ghost_begin();
488 eq_data_->full_solution.local_to_ghost_end();
496 bool jump_time =
eq_fields_->storativity.is_jump_time();
497 if (! zero_time_term_from_left) {
498 MessageOut() <<
"Flow time step - unsteady case\n";
503 eq_data_->use_steady_assembly_ =
false;
509 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
518 if (! zero_time_term_from_left && ! jump_time && output)
525 if (zero_time_term_from_right) {
526 MessageOut() <<
"Flow time step - steady case\n";
528 eq_data_->use_steady_assembly_ =
true;
533 }
else if (! zero_time_term_from_left && jump_time) {
534 WarningOut() <<
"Discontinuous time term not supported yet.\n";
545 return (
eq_fields_->storativity.input_list_size() == 0);
558 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
561 int is_linear_common;
566 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
567 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
568 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
570 if (! is_linear_common) {
576 while (nonlinear_iteration_ < this->
min_n_it_ ||
577 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
579 convergence_history.push_back(residual_norm);
583 if (convergence_history.size() >= 5 &&
584 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
585 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
591 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
595 if (! is_linear_common){
597 eq_data_->p_edge_solution_previous.local_to_ghost_begin();
598 eq_data_->p_edge_solution_previous.local_to_ghost_end();
602 MessageOut().fmt(
"[schur solver] lin. it: {}, reason: {}, residual: {}\n",
608 if (is_linear_common){
611 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
618 VecAXPBY(
eq_data_->p_edge_solution.petsc_vec(), (1-alpha), alpha,
eq_data_->p_edge_solution_previous.petsc_vec());
625 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
645 eq_data_->p_edge_solution_previous_time.copy_from(
eq_data_->p_edge_solution);
646 eq_data_->p_edge_solution_previous_time.local_to_ghost_begin();
647 eq_data_->p_edge_solution_previous_time.local_to_ghost_end();
669 return eq_data_->lin_sys_schur->get_solution_precision();
681 START_TIMER(
"DarcyLMH::assembly_steady_mh_matrix");
694 unsigned int dim = dh_cell.dim();
695 assembler[dim-1]->assemble(dh_cell);
711 double zeros[100000];
712 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
715 tmp_rows.reserve(200);
718 dofs.reserve(
eq_data_->dh_cr_->max_elem_dofs());
719 dofs_ngh.reserve(
eq_data_->dh_cr_->max_elem_dofs());
725 const uint ndofs = dh_cell.n_dofs();
726 dofs.resize(dh_cell.n_dofs());
727 dh_cell.get_dof_indices(dofs);
729 int* dofs_ptr = dofs.
data();
736 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
744 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
745 dofs_ngh.resize(ndofs_ngh);
749 tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
759 for(
auto &isec : isec_list ) {
763 const uint ndofs_slave = dh_cell_slave.
n_dofs();
764 dofs_ngh.resize(ndofs_slave);
768 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->n_sides(); i_side++) {
769 tmp_rows.push_back( dofs_ngh[i_side] );
909 eq_data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*
eq_data_->dh_cr_->distr()) );
982 eq_data_->full_solution.zero_entries();
983 eq_data_->p_edge_solution.zero_entries();
987 THROW( ExcUnknownSolver() );
998 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1000 eq_data_->full_solution.zero_entries();
1001 eq_data_->p_edge_solution.local_to_ghost_begin();
1002 eq_data_->p_edge_solution.local_to_ghost_end();
1009 unsigned int dim = dh_cell.dim();
1010 assembler[dim-1]->assemble_reconstruct(dh_cell);
1013 eq_data_->full_solution.local_to_ghost_begin();
1014 eq_data_->full_solution.local_to_ghost_end();
1022 START_TIMER(
"DarcyFlowMH::assembly_linear_system");
1025 eq_data_->p_edge_solution.local_to_ghost_begin();
1026 eq_data_->p_edge_solution.local_to_ghost_end();
1060 std::string output_file;
1063 double d_max = std::numeric_limits<double>::max();
1064 double h1 = d_max, h2 = d_max, h3 = d_max;
1065 double he2 = d_max, he3 = d_max;
1068 case 1: h1 = std::min(h1,ele.measure());
break;
1069 case 2: h2 = std::min(h2,ele.measure());
break;
1070 case 3: h3 = std::min(h3,ele.measure());
break;
1073 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1075 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1076 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1080 if(h1 == d_max) h1 = 0;
1081 if(h2 == d_max) h2 = 0;
1082 if(h3 == d_max) h3 = 0;
1083 if(he2 == d_max) he2 = 0;
1084 if(he3 == d_max) he3 = 0;
1087 file = fopen(output_file.c_str(),
"a");
1089 fprintf(file,
"nB = %d;\n",
eq_data_->dh_->mesh()->get_el_ds()->size());
1091 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1092 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1098 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1099 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1100 MatView( *
const_cast<Mat*
>(
lin_sys_schur().get_matrix()), viewer);
1101 VecView( *
const_cast<Vec*
>(
lin_sys_schur().get_rhs()), viewer);
1102 VecView( *
const_cast<Vec*
>(&(
lin_sys_schur().get_solution())), viewer);
1103 VecView( *
const_cast<Vec*
>(&(
eq_data_->full_solution.petsc_vec())), viewer);
1302 if(
time_ !=
nullptr)
1310 unsigned int i, n_dofs, min, max;
1314 n_dofs = dh_cell.get_dof_indices(dof_indices);
1316 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);