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);
244 data_->bc_gravity.set(field_algo, 0.0);
246 data_->bc_pressure.add_factory(
249 data_->bc_switch_pressure.add_factory(
252 data_->init_pressure.add_factory(
262 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
273 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
274 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
275 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
276 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
277 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
278 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
279 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
280 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
281 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
282 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
283 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
285 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
291 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
292 data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
293 data_->dh_->distribute_dofs(ds);
299 data_->add_coords_field();
302 uint rt_component = 0;
303 data_->full_solution =
data_->dh_->create_vector();
304 auto ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
data_->dh_, &
data_->full_solution, rt_component);
305 data_->flux.set(ele_flux_ptr, 0.0);
309 uint p_ele_component = 1;
310 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_ele_component);
311 data_->field_ele_pressure.set(ele_pressure_ptr, 0.0);
313 uint p_edge_component = 2;
314 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, &
data_->full_solution, p_edge_component);
315 data_->field_edge_pressure.set(edge_pressure_ptr, 0.0);
317 data_->field_ele_piezo_head.set(
324 uint p_element_component = 1;
325 data_->dh_p_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_element_component);
329 uint p_edge_component = 2;
330 data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_edge_component);
335 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
336 data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*
mesh_);
337 data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
344 data_->p_edge_solution =
data_->dh_cr_->create_vector();
345 data_->p_edge_solution_previous =
data_->dh_cr_->create_vector();
346 data_->p_edge_solution_previous_time =
data_->dh_cr_->create_vector();
355 .val<Input::AbstractRecord>(
"linear_solver");
367 data_->water_balance_idx =
balance_->add_quantity(
"water_volume");
376 data_->multidim_assembler = AssemblyBase::create< AssemblyLMH >(
data_);
408 DebugOut().fmt(
"Read initial condition\n");
412 LocDofVec p_indices = dh_cell.cell_with_other_dh(
data_->dh_p_.get()).get_loc_dof_indices();
414 LocDofVec l_indices = dh_cell.cell_with_other_dh(
data_->dh_cr_.get()).get_loc_dof_indices();
418 double init_value =
data_->init_pressure.value(ele.
centre(),ele);
419 unsigned int p_idx =
data_->dh_p_->parent_indices()[p_indices[0]];
420 data_->full_solution.set(p_idx, init_value);
422 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
424 unsigned int l_idx =
data_->dh_cr_->parent_indices()[l_indices[i]];
425 data_->full_solution.add(l_idx, init_value/n_sides_of_edge);
427 data_->p_edge_solution.add(l_indices[i], init_value/n_sides_of_edge);
431 data_->full_solution.ghost_to_local_begin();
432 data_->full_solution.ghost_to_local_end();
434 data_->p_edge_solution.ghost_to_local_begin();
435 data_->p_edge_solution.ghost_to_local_end();
436 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
458 data_->p_edge_solution.zero_entries();
460 if (
data_->use_steady_assembly_) {
479 data_->full_solution.copy_from(temp);
501 data_->full_solution.local_to_ghost_begin();
502 data_->full_solution.local_to_ghost_end();
510 bool jump_time =
data_->storativity.is_jump_time();
511 if (! zero_time_term_from_left) {
516 data_->use_steady_assembly_ =
false;
522 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
531 if (! zero_time_term_from_left && ! jump_time && output)
538 if (zero_time_term_from_right) {
540 data_->use_steady_assembly_ =
true;
545 }
else if (! zero_time_term_from_left && jump_time) {
546 WarningOut() <<
"Discontinuous time term not supported yet.\n";
557 return (
data_->storativity.input_list_size() == 0);
570 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
573 int is_linear_common;
578 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
579 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
580 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
582 if (! is_linear_common) {
588 while (nonlinear_iteration_ < this->
min_n_it_ ||
589 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->
max_n_it_ )) {
591 convergence_history.push_back(residual_norm);
595 if (convergence_history.size() >= 5 &&
596 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
597 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
603 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
607 if (! is_linear_common){
608 data_->p_edge_solution_previous.copy_from(
data_->p_edge_solution);
609 data_->p_edge_solution_previous.local_to_ghost_begin();
610 data_->p_edge_solution_previous.local_to_ghost_end();
614 MessageOut().fmt(
"[schur solver] lin. it: {}, reason: {}, residual: {}\n",
620 if (is_linear_common){
623 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
630 VecAXPBY(
data_->p_edge_solution.petsc_vec(), (1-alpha), alpha,
data_->p_edge_solution_previous.petsc_vec());
637 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
657 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
658 data_->p_edge_solution_previous_time.local_to_ghost_begin();
659 data_->p_edge_solution_previous_time.local_to_ghost_end();
673 balance_->calculate_cumulative(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
674 balance_->calculate_instant(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
681 return data_->lin_sys_schur->get_solution_precision();
693 START_TIMER(
"DarcyLMH::assembly_steady_mh_matrix");
706 unsigned int dim = dh_cell.dim();
707 assembler[dim-1]->assemble(dh_cell);
723 double zeros[100000];
724 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
727 tmp_rows.reserve(200);
730 dofs.reserve(
data_->dh_cr_->max_elem_dofs());
731 dofs_ngh.reserve(
data_->dh_cr_->max_elem_dofs());
737 const uint ndofs = dh_cell.n_dofs();
738 dofs.resize(dh_cell.n_dofs());
739 dh_cell.get_dof_indices(dofs);
741 int* dofs_ptr = dofs.
data();
748 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
756 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
757 dofs_ngh.resize(ndofs_ngh);
761 tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
771 for(
auto &isec : isec_list ) {
775 const uint ndofs_slave = dh_cell_slave.
n_dofs();
776 dofs_ngh.resize(ndofs_slave);
780 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->n_sides(); i_side++) {
781 tmp_rows.push_back( dofs_ngh[i_side] );
921 data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*
data_->dh_cr_->distr()) );
994 data_->full_solution.zero_entries();
995 data_->p_edge_solution.zero_entries();
999 THROW( ExcUnknownSolver() );
1010 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
1012 data_->full_solution.zero_entries();
1013 data_->p_edge_solution.local_to_ghost_begin();
1014 data_->p_edge_solution.local_to_ghost_end();
1021 unsigned int dim = dh_cell.dim();
1022 assembler[dim-1]->assemble_reconstruct(dh_cell);
1025 data_->full_solution.local_to_ghost_begin();
1026 data_->full_solution.local_to_ghost_end();
1034 START_TIMER(
"DarcyFlowMH::assembly_linear_system");
1037 data_->p_edge_solution.local_to_ghost_begin();
1038 data_->p_edge_solution.local_to_ghost_end();
1040 data_->is_linear=
true;
1072 std::string output_file;
1075 double d_max = std::numeric_limits<double>::max();
1076 double h1 = d_max, h2 = d_max, h3 = d_max;
1077 double he2 = d_max, he3 = d_max;
1080 case 1: h1 = std::min(h1,ele.measure());
break;
1081 case 2: h2 = std::min(h2,ele.measure());
break;
1082 case 3: h3 = std::min(h3,ele.measure());
break;
1085 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1087 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1088 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1092 if(h1 == d_max) h1 = 0;
1093 if(h2 == d_max) h2 = 0;
1094 if(h3 == d_max) h3 = 0;
1095 if(he2 == d_max) he2 = 0;
1096 if(he3 == d_max) he3 = 0;
1099 file = fopen(output_file.c_str(),
"a");
1100 fprintf(file,
"nA = %d;\n",
data_->dh_cr_disc_->distr()->size());
1101 fprintf(file,
"nB = %d;\n",
data_->dh_->mesh()->get_el_ds()->size());
1102 fprintf(file,
"nBF = %d;\n",
data_->dh_cr_->distr()->size());
1103 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1104 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1110 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1111 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1112 MatView( *
const_cast<Mat*
>(
lin_sys_schur().get_matrix()), viewer);
1113 VecView( *
const_cast<Vec*
>(
lin_sys_schur().get_rhs()), viewer);
1114 VecView( *
const_cast<Vec*
>(&(
lin_sys_schur().get_solution())), viewer);
1115 VecView( *
const_cast<Vec*
>(&(
data_->full_solution.petsc_vec())), viewer);
1314 if(
time_ !=
nullptr)
1322 unsigned int i, n_dofs, min, max;
1326 n_dofs = dh_cell.get_dof_indices(dof_indices);
1328 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);