28 #include "petscviewer.h"
29 #include "petscerror.h"
82 .
add_value(
MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
92 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
94 "Boundary switch piezometric head for BC types: seepage, river." )
96 "Initial condition for the pressure given as the piezometric head." )
98 return field_descriptor;
105 "Linear solver for MH problem.")
107 "Residual tolerance.")
109 "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria "
110 "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution."
111 "If greater then 'max_it' the value is set to 'max_it'.")
113 "Maximum number of iterations (linear solutions) of the non-linear solver.")
115 "If a stagnation of the nonlinear solver is detected the solver stops. "
116 "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver "
117 "ends with convergence success on stagnation, but it reports warning about it.")
122 return it::Record(
"Flow_Darcy_LMH",
"Lumped Mixed-Hybrid solver for saturated Darcy flow.")
126 "Vector of the gravity force. Dimensionless.")
128 "Input data for Darcy flow model.")
130 "Non-linear solver for MH problem.")
132 "Output stream settings.\n Specify file format, precision etc.")
135 IT::Default(
"{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
136 "Specification of output fields and output times.")
138 "Output settings specific to Darcy flow model.\n"
139 "Includes raw output and some experimental functionality.")
141 "Settings for computing mass balance.")
143 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
149 Input::register_class< DarcyLMH, Mesh &, const Input::Record >(
"Flow_Darcy_LMH") +
194 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
201 data_ = make_shared<EqData>();
204 data_->is_linear=
true;
233 gravity_array.copy_to(gvec);
236 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
238 data_->bc_pressure.add_factory(
240 (
data_->gravity_,
"bc_piezo_head") );
241 data_->bc_switch_pressure.add_factory(
243 (
data_->gravity_,
"bc_switch_piezo_head") );
244 data_->init_pressure.add_factory(
246 (
data_->gravity_,
"init_piezo_head") );
254 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
265 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
266 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
267 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
268 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
269 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
270 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
271 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
272 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
273 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
274 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
275 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
277 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
283 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
284 data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
285 data_->dh_->distribute_dofs(ds);
292 uint rt_component = 0;
293 data_->full_solution =
data_->dh_->create_vector();
294 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
data_->dh_, &
data_->full_solution, rt_component);
295 data_->flux.set(ele_flux_ptr, 0.0);
297 auto ele_velocity_ptr = std::make_shared< FieldDivide<3, FieldValue<3>::VectorFixed> >(ele_flux_ptr,
data_->cross_section);
298 data_->field_ele_velocity.set(ele_velocity_ptr, 0.0);
300 uint p_ele_component = 1;
301 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_ele_component);
302 data_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
304 uint p_edge_component = 2;
305 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_edge_component);
306 data_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
308 arma::vec4 gravity = (-1) *
data_->gravity_;
310 data_->field_ele_piezo_head.set(ele_piezo_head_ptr, 0.0);
314 uint p_element_component = 1;
315 data_->dh_p_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_element_component);
319 uint p_edge_component = 2;
320 data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_edge_component);
325 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
326 data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
327 data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
334 data_->p_edge_solution =
data_->dh_cr_->create_vector();
335 data_->p_edge_solution_previous =
data_->dh_cr_->create_vector();
336 data_->p_edge_solution_previous_time =
data_->dh_cr_->create_vector();
345 .val<Input::AbstractRecord>(
"linear_solver");
357 data_->water_balance_idx =
balance_->add_quantity(
"water_volume");
366 data_->multidim_assembler = AssemblyBase::create< AssemblyLMH >(
data_);
398 DebugOut().fmt(
"Read initial condition\n");
402 LocDofVec p_indices = dh_cell.cell_with_other_dh(
data_->dh_p_.get()).get_loc_dof_indices();
404 LocDofVec l_indices = dh_cell.cell_with_other_dh(
data_->dh_cr_.get()).get_loc_dof_indices();
408 double init_value =
data_->init_pressure.value(ele.
centre(),ele);
409 unsigned int p_idx =
data_->dh_p_->parent_indices()[p_indices[0]];
410 data_->full_solution.set(p_idx, init_value);
412 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
414 unsigned int l_idx =
data_->dh_cr_->parent_indices()[l_indices[i]];
415 data_->full_solution.add(l_idx, init_value/n_sides_of_edge);
417 data_->p_edge_solution.add(l_indices[i], init_value/n_sides_of_edge);
421 data_->full_solution.ghost_to_local_begin();
422 data_->full_solution.ghost_to_local_end();
424 data_->p_edge_solution.ghost_to_local_begin();
425 data_->p_edge_solution.ghost_to_local_end();
426 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
448 data_->p_edge_solution.zero_entries();
450 if (
data_->use_steady_assembly_) {
469 data_->full_solution.copy_from(temp);
491 data_->full_solution.local_to_ghost_begin();
492 data_->full_solution.local_to_ghost_end();
500 bool jump_time =
data_->storativity.is_jump_time();
501 if (! zero_time_term_from_left) {
506 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)
528 if (zero_time_term_from_right) {
530 data_->use_steady_assembly_ =
true;
535 }
else if (! zero_time_term_from_left && jump_time) {
536 WarningOut() <<
"Discontinuous time term not supported yet.\n";
547 return (
data_->storativity.input_list_size() == 0);
560 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
563 int is_linear_common;
568 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
569 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
570 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
572 if (! is_linear_common) {
578 while (nonlinear_iteration_ < this->
min_n_it_ ||
579 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
581 convergence_history.push_back(residual_norm);
585 if (convergence_history.size() >= 5 &&
586 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
587 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
593 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
597 if (! is_linear_common){
598 data_->p_edge_solution_previous.copy_from(
data_->p_edge_solution);
599 data_->p_edge_solution_previous.local_to_ghost_begin();
600 data_->p_edge_solution_previous.local_to_ghost_end();
604 MessageOut().fmt(
"[schur solver] lin. it: {}, reason: {}, residual: {}\n",
610 if (is_linear_common){
613 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
620 VecAXPBY(
data_->p_edge_solution.petsc_vec(), (1-alpha), alpha,
data_->p_edge_solution_previous.petsc_vec());
627 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
647 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
648 data_->p_edge_solution_previous_time.local_to_ghost_begin();
649 data_->p_edge_solution_previous_time.local_to_ghost_end();
663 balance_->calculate_cumulative(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
664 balance_->calculate_instant(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
671 return data_->lin_sys_schur->get_solution_precision();
683 START_TIMER(
"DarcyLMH::assembly_steady_mh_matrix");
696 unsigned int dim = dh_cell.dim();
697 assembler[dim-1]->assemble(dh_cell);
713 double zeros[100000];
714 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
717 tmp_rows.reserve(200);
720 dofs.reserve(
data_->dh_cr_->max_elem_dofs());
721 dofs_ngh.reserve(
data_->dh_cr_->max_elem_dofs());
727 const uint ndofs = dh_cell.n_dofs();
728 dofs.resize(dh_cell.n_dofs());
729 dh_cell.get_dof_indices(dofs);
731 int* dofs_ptr = dofs.
data();
738 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
746 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
747 dofs_ngh.resize(ndofs_ngh);
751 tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
761 for(
auto &isec : isec_list ) {
765 const uint ndofs_slave = dh_cell_slave.
n_dofs();
766 dofs_ngh.resize(ndofs_slave);
770 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->n_sides(); i_side++) {
771 tmp_rows.push_back( dofs_ngh[i_side] );
911 data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*
data_->dh_cr_->distr()) );
984 data_->full_solution.zero_entries();
985 data_->p_edge_solution.zero_entries();
989 THROW( ExcUnknownSolver() );
1000 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1002 data_->full_solution.zero_entries();
1003 data_->p_edge_solution.local_to_ghost_begin();
1004 data_->p_edge_solution.local_to_ghost_end();
1011 unsigned int dim = dh_cell.dim();
1012 assembler[dim-1]->assemble_reconstruct(dh_cell);
1015 data_->full_solution.local_to_ghost_begin();
1016 data_->full_solution.local_to_ghost_end();
1024 START_TIMER(
"DarcyFlowMH::assembly_linear_system");
1027 data_->p_edge_solution.local_to_ghost_begin();
1028 data_->p_edge_solution.local_to_ghost_end();
1030 data_->is_linear=
true;
1062 std::string output_file;
1065 double d_max = std::numeric_limits<double>::max();
1066 double h1 = d_max, h2 = d_max, h3 = d_max;
1067 double he2 = d_max, he3 = d_max;
1070 case 1: h1 = std::min(h1,ele.measure());
break;
1071 case 2: h2 = std::min(h2,ele.measure());
break;
1072 case 3: h3 = std::min(h3,ele.measure());
break;
1075 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1077 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1078 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1082 if(h1 == d_max) h1 = 0;
1083 if(h2 == d_max) h2 = 0;
1084 if(h3 == d_max) h3 = 0;
1085 if(he2 == d_max) he2 = 0;
1086 if(he3 == d_max) he3 = 0;
1089 file = fopen(output_file.c_str(),
"a");
1090 fprintf(file,
"nA = %d;\n",
data_->dh_cr_disc_->distr()->size());
1091 fprintf(file,
"nB = %d;\n",
data_->dh_->mesh()->get_el_ds()->size());
1092 fprintf(file,
"nBF = %d;\n",
data_->dh_cr_->distr()->size());
1093 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1094 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1100 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1101 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1102 MatView( *
const_cast<Mat*
>(
lin_sys_schur().get_matrix()), viewer);
1103 VecView( *
const_cast<Vec*
>(
lin_sys_schur().get_rhs()), viewer);
1104 VecView( *
const_cast<Vec*
>(&(
lin_sys_schur().get_solution())), viewer);
1105 VecView( *
const_cast<Vec*
>(&(
data_->full_solution.petsc_vec())), viewer);
1304 if(
time_ !=
nullptr)
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]);