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");
411 DebugOut().fmt(
"Read initial condition\n");
415 LocDofVec l_indices = dh_cell.get_loc_dof_indices();
422 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
424 eq_data_->p_edge_solution.add(l_indices[i], init_value/n_sides_of_edge);
428 eq_data_->p_edge_solution.ghost_to_local_begin();
429 eq_data_->p_edge_solution.ghost_to_local_end();
430 eq_data_->p_edge_solution.local_to_ghost_begin();
431 eq_data_->p_edge_solution.local_to_ghost_end();
454 eq_data_->p_edge_solution.zero_entries();
456 if (
eq_data_->use_steady_assembly_) {
457 MessageOut() <<
"Flow zero time step - steady case\n";
461 MessageOut() <<
"Flow zero time step - unsteady case\n";
489 eq_data_->full_solution.local_to_ghost_begin();
490 eq_data_->full_solution.local_to_ghost_end();
499 bool jump_time =
eq_fields_->storativity.is_jump_time();
500 if (! zero_time_term_from_left) {
501 MessageOut() <<
"Flow time step - unsteady case\n";
506 eq_data_->use_steady_assembly_ =
false;
512 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
521 if (! zero_time_term_from_left && ! jump_time && output)
529 if (zero_time_term_from_right) {
530 MessageOut() <<
"Flow time step - steady case\n";
532 eq_data_->use_steady_assembly_ =
true;
537 }
else if (! zero_time_term_from_left && jump_time) {
538 WarningOut() <<
"Discontinuous time term not supported yet.\n";
549 return (
eq_fields_->storativity.input_list_size() == 0);
562 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
565 int is_linear_common;
570 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
571 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
572 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
574 if (! is_linear_common) {
580 while (nonlinear_iteration_ < this->
min_n_it_ ||
581 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
583 convergence_history.push_back(residual_norm);
587 if (convergence_history.size() >= 5 &&
588 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
589 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
595 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
599 if (! is_linear_common){
601 eq_data_->p_edge_solution_previous.local_to_ghost_begin();
602 eq_data_->p_edge_solution_previous.local_to_ghost_end();
606 MessageOut().fmt(
"[schur solver] lin. it: {}, reason: {}, residual: {}\n",
612 if (is_linear_common){
615 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
622 VecAXPBY(
eq_data_->p_edge_solution.petsc_vec(), (1-alpha), alpha,
eq_data_->p_edge_solution_previous.petsc_vec());
629 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
649 eq_data_->p_edge_solution_previous_time.copy_from(
eq_data_->p_edge_solution);
650 eq_data_->p_edge_solution_previous_time.local_to_ghost_begin();
651 eq_data_->p_edge_solution_previous_time.local_to_ghost_end();
673 return eq_data_->lin_sys_schur->get_solution_precision();
685 START_TIMER(
"DarcyLMH::assembly_steady_mh_matrix");
698 unsigned int dim = dh_cell.dim();
699 assembler[dim-1]->assemble(dh_cell);
715 double zeros[100000];
716 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
719 tmp_rows.reserve(200);
722 dofs.reserve(
eq_data_->dh_cr_->max_elem_dofs());
723 dofs_ngh.reserve(
eq_data_->dh_cr_->max_elem_dofs());
729 const uint ndofs = dh_cell.n_dofs();
730 dofs.resize(dh_cell.n_dofs());
731 dh_cell.get_dof_indices(dofs);
733 int* dofs_ptr = dofs.
data();
740 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
748 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
749 dofs_ngh.resize(ndofs_ngh);
753 tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
763 for(
auto &isec : isec_list ) {
767 const uint ndofs_slave = dh_cell_slave.
n_dofs();
768 dofs_ngh.resize(ndofs_slave);
772 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->n_sides(); i_side++) {
773 tmp_rows.push_back( dofs_ngh[i_side] );
913 eq_data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*
eq_data_->dh_cr_->distr()) );
986 eq_data_->full_solution.zero_entries();
987 eq_data_->p_edge_solution.zero_entries();
991 THROW( ExcUnknownSolver() );
1002 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1004 eq_data_->full_solution.zero_entries();
1005 eq_data_->p_edge_solution.local_to_ghost_begin();
1006 eq_data_->p_edge_solution.local_to_ghost_end();
1013 unsigned int dim = dh_cell.dim();
1014 assembler[dim-1]->assemble_reconstruct(dh_cell);
1017 eq_data_->full_solution.local_to_ghost_begin();
1018 eq_data_->full_solution.local_to_ghost_end();
1026 START_TIMER(
"DarcyFlowMH::assembly_linear_system");
1029 eq_data_->p_edge_solution.local_to_ghost_begin();
1030 eq_data_->p_edge_solution.local_to_ghost_end();
1064 std::string output_file;
1067 double d_max = std::numeric_limits<double>::max();
1068 double h1 = d_max, h2 = d_max, h3 = d_max;
1069 double he2 = d_max, he3 = d_max;
1072 case 1: h1 = std::min(h1,ele.measure());
break;
1073 case 2: h2 = std::min(h2,ele.measure());
break;
1074 case 3: h3 = std::min(h3,ele.measure());
break;
1077 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1079 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1080 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1084 if(h1 == d_max) h1 = 0;
1085 if(h2 == d_max) h2 = 0;
1086 if(h3 == d_max) h3 = 0;
1087 if(he2 == d_max) he2 = 0;
1088 if(he3 == d_max) he3 = 0;
1091 file = fopen(output_file.c_str(),
"a");
1093 fprintf(file,
"nB = %d;\n",
eq_data_->dh_->mesh()->get_el_ds()->size());
1095 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1096 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1102 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1103 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1104 MatView( *
const_cast<Mat*
>(
lin_sys_schur().get_matrix()), viewer);
1105 VecView( *
const_cast<Vec*
>(
lin_sys_schur().get_rhs()), viewer);
1106 VecView( *
const_cast<Vec*
>(&(
lin_sys_schur().get_solution())), viewer);
1107 VecView( *
const_cast<Vec*
>(&(
eq_data_->full_solution.petsc_vec())), viewer);
1304 if(
time_ !=
nullptr)
1311 ASSERT_LT(component, 3).error(
"Invalid component!");
1312 unsigned int i, n_dofs, min, max;
1316 n_dofs = dh_cell.get_dof_indices(dof_indices);
1318 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);