28 #include "petscviewer.h" 29 #include "petscerror.h" 77 const
it::Selection &
DarcyLMH::get_mh_mortar_selection() {
79 .
add_value(NoMortar,
"None",
"No Mortar method is applied.")
80 .
add_value(MortarP0,
"P0",
"Mortar space: P0 on elements of lower dimension.")
81 .
add_value(MortarP1,
"P1",
"Mortar space: P1 on intersections, using non-conforming pressures.")
91 "Boundary piezometric head for BC types: dirichlet, robin, and river." )
93 "Boundary switch piezometric head for BC types: seepage, river." )
95 "Initial condition for the pressure given as the piezometric head." )
97 return field_descriptor;
104 "Linear solver for MH problem.")
106 "Residual tolerance.")
108 "Minimum number of iterations (linear solutions) to use.\nThis is usefull if the convergence criteria " 109 "does not characterize your goal well enough so it converges prematurely, possibly even without a single linear solution." 110 "If greater then 'max_it' the value is set to 'max_it'.")
112 "Maximum number of iterations (linear solutions) of the non-linear solver.")
114 "If a stagnation of the nonlinear solver is detected the solver stops. " 115 "A divergence is reported by default, forcing the end of the simulation. By setting this flag to 'true', the solver " 116 "ends with convergence success on stagnation, but it reports warning about it.")
121 return it::Record(
"Flow_Darcy_LMH",
"Lumped Mixed-Hybrid solver for saturated Darcy flow.")
125 "Vector of the gravity force. Dimensionless.")
127 "Input data for Darcy flow model.")
129 "Non-linear solver for MH problem.")
131 "Output stream settings.\n Specify file format, precision etc.")
134 IT::Default(
"{ \"fields\": [ \"pressure_p0\", \"velocity_p0\" ] }"),
135 "Specification of output fields and output times.")
137 "Output settings specific to Darcy flow model.\n" 138 "Includes raw output and some experimental functionality.")
140 "Settings for computing mass balance.")
142 "Method for coupling Darcy flow between dimensions on incompatible meshes. [Experimental]" )
148 Input::register_class< DarcyLMH, Mesh &, const Input::Record >(
"Flow_Darcy_LMH") +
193 MessageOut() <<
"Duplicate key 'time', time in flow equation is already initialized from parent class!";
200 data_ = make_shared<EqData>();
203 data_->is_linear=
true;
232 gravity_array.copy_to(gvec);
235 data_->gravity_vec_ =
data_->gravity_.subvec(0,2);
237 data_->bc_pressure.add_factory(
239 (
data_->gravity_,
"bc_piezo_head") );
240 data_->bc_switch_pressure.add_factory(
242 (
data_->gravity_,
"bc_switch_piezo_head") );
243 data_->init_pressure.add_factory(
245 (
data_->gravity_,
"init_piezo_head") );
253 MessageOut() <<
"Missing the key 'time', obligatory for the transient problems." << endl;
264 std::shared_ptr< FiniteElement<1> > fe1_rt = std::make_shared<FE_RT0_disc<1>>();
265 std::shared_ptr< FiniteElement<2> > fe2_rt = std::make_shared<FE_RT0_disc<2>>();
266 std::shared_ptr< FiniteElement<3> > fe3_rt = std::make_shared<FE_RT0_disc<3>>();
267 std::shared_ptr< FiniteElement<0> > fe0_disc = std::make_shared<FE_P_disc<0>>(0);
268 std::shared_ptr< FiniteElement<1> > fe1_disc = std::make_shared<FE_P_disc<1>>(0);
269 std::shared_ptr< FiniteElement<2> > fe2_disc = std::make_shared<FE_P_disc<2>>(0);
270 std::shared_ptr< FiniteElement<3> > fe3_disc = std::make_shared<FE_P_disc<3>>(0);
271 std::shared_ptr< FiniteElement<0> > fe0_cr = std::make_shared<FE_CR<0>>();
272 std::shared_ptr< FiniteElement<1> > fe1_cr = std::make_shared<FE_CR<1>>();
273 std::shared_ptr< FiniteElement<2> > fe2_cr = std::make_shared<FE_CR<2>>();
274 std::shared_ptr< FiniteElement<3> > fe3_cr = std::make_shared<FE_CR<3>>();
276 FESystem<0> fe0_sys( {fe0_disc, fe0_disc, fe0_cr} );
282 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_sys);
283 data_->dh_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
284 data_->dh_->distribute_dofs(ds);
291 uint rt_component = 0;
292 ele_flux_ptr = create_field_fe<3, FieldValue<3>::VectorFixed>(
data_->dh_, rt_component);
293 auto ele_velocity_ptr = std::make_shared< FieldDivide<3, FieldValue<3>::VectorFixed> >(
ele_flux_ptr,
data_->cross_section);
295 data_->full_solution = ele_flux_ptr->get_data_vec();
297 uint p_ele_component = 0;
298 auto ele_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, p_ele_component, &
data_->full_solution);
301 uint p_edge_component = 1;
302 auto edge_pressure_ptr = create_field_fe<3, FieldValue<3>::Scalar>(
data_->dh_, p_edge_component, &
data_->full_solution);
305 arma::vec4 gravity = (-1) *
data_->gravity_;
311 uint p_element_component = 1;
312 data_->dh_p_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_element_component);
316 uint p_edge_component = 2;
317 data_->dh_cr_ = std::make_shared<SubDOFHandlerMultiDim>(
data_->dh_,p_edge_component);
322 std::shared_ptr<DiscreteSpace> ds_cr_disc = std::make_shared<EqualOrderDiscreteSpace>(
mesh_, fe_cr_disc);
323 data_->dh_cr_disc_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
324 data_->dh_cr_disc_->distribute_dofs(ds_cr_disc);
331 data_->p_edge_solution =
data_->dh_cr_->create_vector();
332 data_->p_edge_solution_previous =
data_->dh_cr_->create_vector();
333 data_->p_edge_solution_previous_time =
data_->dh_cr_->create_vector();
342 .val<Input::AbstractRecord>(
"linear_solver");
354 data_->water_balance_idx =
balance_->add_quantity(
"water_volume");
363 data_->multidim_assembler = AssemblyBase::create< AssemblyLMH >(
data_);
395 DebugOut().fmt(
"Read initial condition\n");
399 LocDofVec p_indices = dh_cell.cell_with_other_dh(
data_->dh_p_.get()).get_loc_dof_indices();
401 LocDofVec l_indices = dh_cell.cell_with_other_dh(
data_->dh_cr_.get()).get_loc_dof_indices();
405 double init_value =
data_->init_pressure.value(ele.
centre(),ele);
406 unsigned int p_idx =
data_->dh_p_->parent_indices()[p_indices[0]];
407 data_->full_solution[p_idx] = init_value;
409 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
411 unsigned int l_idx =
data_->dh_cr_->parent_indices()[l_indices[i]];
412 data_->full_solution[l_idx] += init_value/n_sides_of_edge;
414 data_->p_edge_solution[l_indices[i]] += init_value/n_sides_of_edge;
418 data_->full_solution.ghost_to_local_begin();
419 data_->full_solution.ghost_to_local_end();
421 data_->p_edge_solution.ghost_to_local_begin();
422 data_->p_edge_solution.ghost_to_local_end();
423 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
445 data_->p_edge_solution.zero_entries();
447 if (
data_->use_steady_assembly_) {
466 data_->full_solution.copy_from(temp);
494 bool jump_time =
data_->storativity.is_jump_time();
495 if (! zero_time_term_from_left) {
500 data_->use_steady_assembly_ =
false;
506 WarningOut() <<
"Output of solution discontinuous in time not supported yet.\n";
515 if (! zero_time_term_from_left && ! jump_time && output)
522 if (zero_time_term_from_right) {
524 data_->use_steady_assembly_ =
true;
529 }
else if (! zero_time_term_from_left && jump_time) {
530 WarningOut() <<
"Discontinuous time term not supported yet.\n";
541 return (
data_->storativity.input_list_size() == 0);
554 MessageOut().fmt(
"[nonlinear solver] norm of initial residual: {}\n", residual_norm);
557 int is_linear_common;
562 this->
max_n_it_ = nl_solver_rec.
val<
unsigned int>(
"max_it");
563 this->
min_n_it_ = nl_solver_rec.
val<
unsigned int>(
"min_it");
564 if (this->min_n_it_ > this->max_n_it_) this->min_n_it_ = this->
max_n_it_;
566 if (! is_linear_common) {
572 while (nonlinear_iteration_ < this->min_n_it_ ||
573 (residual_norm > this->tolerance_ && nonlinear_iteration_ < this->max_n_it_ )) {
575 convergence_history.push_back(residual_norm);
579 if (convergence_history.size() >= 5 &&
580 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 2] > 0.9 &&
581 convergence_history[ convergence_history.size() - 1]/convergence_history[ convergence_history.size() - 5] > 0.8) {
587 THROW(ExcSolverDiverge() << EI_Reason(
"Stagnation."));
591 if (! is_linear_common){
592 data_->p_edge_solution_previous.copy_from(
data_->p_edge_solution);
593 data_->p_edge_solution_previous.local_to_ghost_begin();
594 data_->p_edge_solution_previous.local_to_ghost_end();
598 MessageOut().fmt(
"[schur solver] lin. it: {}, reason: {}, residual: {}\n",
604 if (is_linear_common){
607 MessageOut().fmt(
"[nonlinear solver] lin. it: {}, reason: {}, residual: {}\n",
614 VecAXPBY(
data_->p_edge_solution.petsc_vec(), (1-alpha), alpha,
data_->p_edge_solution_previous.petsc_vec());
621 MessageOut().fmt(
"[nonlinear solver] it: {} lin. it: {}, reason: {}, residual: {}\n",
641 data_->p_edge_solution_previous_time.copy_from(
data_->p_edge_solution);
642 data_->p_edge_solution_previous_time.local_to_ghost_begin();
643 data_->p_edge_solution_previous_time.local_to_ghost_end();
657 balance_->calculate_cumulative(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
658 balance_->calculate_instant(
data_->water_balance_idx,
data_->full_solution.petsc_vec());
665 return data_->lin_sys_schur->get_solution_precision();
677 START_TIMER(
"DarcyLMH::assembly_steady_mh_matrix");
690 unsigned int dim = dh_cell.dim();
691 assembler[dim-1]->assemble(dh_cell);
707 double zeros[100000];
708 for(
int i=0; i<100000; i++) zeros[i] = 0.0;
711 tmp_rows.reserve(200);
714 dofs.reserve(
data_->dh_cr_->max_elem_dofs());
715 dofs_ngh.reserve(
data_->dh_cr_->max_elem_dofs());
721 const uint ndofs = dh_cell.n_dofs();
722 dofs.resize(dh_cell.n_dofs());
723 dh_cell.get_dof_indices(dofs);
725 int* dofs_ptr = dofs.
data();
732 for (
DHCellSide neighb_side : dh_cell.neighb_sides() ) {
740 const uint ndofs_ngh = dh_neighb_cell.
n_dofs();
741 dofs_ngh.resize(ndofs_ngh);
745 tmp_rows.push_back(dofs_ngh[neighb_side.side().side_idx()]);
755 for(
auto &isec : isec_list ) {
759 const uint ndofs_slave = dh_cell_slave.
n_dofs();
760 dofs_ngh.resize(ndofs_slave);
764 for(
unsigned int i_side=0; i_side < dh_cell_slave.
elm()->
n_sides(); i_side++) {
765 tmp_rows.push_back( dofs_ngh[i_side] );
905 data_->lin_sys_schur = std::make_shared<LinSys_PETSC>( &(*
data_->dh_cr_->distr()) );
978 data_->full_solution.zero_entries();
979 data_->p_edge_solution.zero_entries();
983 xprintf(
Err,
"Unknown solver type. Internal error.\n");
994 START_TIMER(
"DarcyFlowMH::reconstruct_solution_from_schur");
996 data_->full_solution.zero_entries();
997 data_->p_edge_solution.local_to_ghost_begin();
998 data_->p_edge_solution.local_to_ghost_end();
1005 unsigned int dim = dh_cell.dim();
1006 assembler[dim-1]->assemble_reconstruct(dh_cell);
1009 data_->full_solution.local_to_ghost_begin();
1010 data_->full_solution.local_to_ghost_end();
1018 START_TIMER(
"DarcyFlowMH::assembly_linear_system");
1021 data_->p_edge_solution.local_to_ghost_begin();
1022 data_->p_edge_solution.local_to_ghost_end();
1024 data_->is_linear=
true;
1056 std::string output_file;
1059 double d_max = std::numeric_limits<double>::max();
1060 double h1 = d_max, h2 = d_max, h3 = d_max;
1061 double he2 = d_max, he3 = d_max;
1064 case 1: h1 = std::min(h1,ele.measure());
break;
1065 case 2: h2 = std::min(h2,ele.measure());
break;
1066 case 3: h3 = std::min(h3,ele.measure());
break;
1069 for (
unsigned int j=0; j<ele->n_sides(); j++) {
1071 case 2: he2 = std::min(he2, ele.side(j)->measure());
break;
1072 case 3: he3 = std::min(he3, ele.side(j)->measure());
break;
1076 if(h1 == d_max) h1 = 0;
1077 if(h2 == d_max) h2 = 0;
1078 if(h3 == d_max) h3 = 0;
1079 if(he2 == d_max) he2 = 0;
1080 if(he3 == d_max) he3 = 0;
1083 file = fopen(output_file.c_str(),
"a");
1084 fprintf(file,
"nA = %d;\n",
data_->dh_cr_disc_->distr()->size());
1085 fprintf(file,
"nB = %d;\n",
data_->dh_->mesh()->get_el_ds()->size());
1086 fprintf(file,
"nBF = %d;\n",
data_->dh_cr_->distr()->size());
1087 fprintf(file,
"h1 = %e;\nh2 = %e;\nh3 = %e;\n", h1, h2, h3);
1088 fprintf(file,
"he2 = %e;\nhe3 = %e;\n", he2, he3);
1094 PetscViewerASCIIOpen(PETSC_COMM_WORLD, output_file.c_str(), &viewer);
1095 PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);
1096 MatView( *const_cast<Mat*>(
lin_sys_schur().get_matrix()), viewer);
1097 VecView( *const_cast<Vec*>(
lin_sys_schur().get_rhs()), viewer);
1098 VecView( *const_cast<Vec*>(&(
lin_sys_schur().get_solution())), viewer);
1099 VecView( *const_cast<Vec*>(&(
data_->full_solution.petsc_vec())), viewer);
1298 if(
time_ !=
nullptr)
1311 unsigned int i, n_dofs, min, max;
1315 n_dofs = dh_cell.get_dof_indices(dof_indices);
1317 for (i=min; i<max; ++i) dof_vec.push_back(dof_indices[i]);
unsigned int n_sides() const
Returns number of sides aligned with the edge.
virtual bool zero_time_term(bool time_global=false)
static const Input::Type::Record & get_input_type()
Main balance input record type.
Output class for darcy_flow_mh model.
RegionSet get_region_set(const std::string &set_name) const
void set_symmetric(bool flag=true)
Classes with algorithms for computation of intersections of meshes.
static const int registrar
Registrar of class to factory.
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
virtual void set_from_input(const Input::Record in_rec)
MixedMeshIntersections & mixed_intersections()
static const Input::Type::Record & get_input_type()
The specification of output stream.
Common base for intersection object.
unsigned int get_dof_indices(std::vector< LongIdx > &indices) const
Fill vector of the global indices of dofs associated to the cell.
Edge edge() const
Returns pointer to the edge connected to the side.
static const Input::Type::Record & get_input_type()
virtual void initialize_specific()
#define MessageOut()
Macro defining 'message' record of log.
virtual void start_add_assembly()
void assembly_mh_matrix(MultidimAssembly &assembler)
virtual PetscErrorCode mat_zero_entries()
Wrappers for linear systems based on MPIAIJ and MATIS format.
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
void next_time()
Proceed to the next time according to current estimated time step.
void zero_time_step() override
void create_linear_system(Input::AbstractRecord rec)
void solve_time_step(bool output=true)
Solve the problem without moving to next time and without output.
Lumped mixed-hybrid model of linear Darcy flow, possibly unsteady.
friend class DarcyFlowMHOutput
std::vector< int > get_component_indices_vec(unsigned int component) const
Get vector of all DOF indices of given component (0..side, 1..element, 2..edge)
virtual void start_allocation()
Cell accessor allow iterate over DOF handler cells.
virtual void finish_assembly()=0
std::vector< std::vector< ILpair > > element_intersections_
static const Input::Type::Instance & get_input_type(FieldSet &eq_data, const std::string &equation_name)
SideIter side(const unsigned int loc_index)
const RegionDB & region_db() const
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
const TimeStep & step(int index=-1) const
static const Input::Type::Selection & get_mh_mortar_selection()
Selection for enum MortarMethod.
Mixed-hybrid model of linear Darcy flow, possibly unsteady.
static const std::string field_descriptor_record_description(const string &record_name)
virtual void initial_condition_postprocess()
Basic time management functionality for unsteady (and steady) solvers (class Equation).
unsigned int bulk_ele_idx() const
Returns index of bulk element.
unsigned int n_dofs() const
Return number of dofs on given cell.
Basic time management class.
virtual void set_tolerances(double r_tol, double a_tol, unsigned int max_it)=0
DarcyFlowMHOutput * output_object
void view(const char *name="") const
static Input::Type::Record & record_template()
Template Record with common keys for derived equations.
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
void initialize() override
arma::vec::fixed< spacedim > centre() const
Computes the barycenter.
void print_matlab_matrix(string matlab_file)
Print darcy flow matrix in matlab format into a file.
void copy_from(VectorMPI &other)
virtual void postprocess()
const ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
void read_initial_condition()
static const Input::Type::Instance & get_input_type_specific()
Compound finite element on dim dimensional simplex.
void allocate_mh_matrix()
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args)
Definitions of basic Lagrangean finite elements with polynomial shape functions.
unsigned int n_sides() const
virtual void output_data() override
Write computed fields.
#define START_TIMER(tag)
Starts a timer with specified tag.
static Input::Type::Abstract & get_input_type()
virtual Range< ElementAccessor< 3 > > elements_range() const
Returns range of bulk elements.
virtual ~DarcyLMH() override
unsigned int n_sides() const
std::shared_ptr< EqData > data_
unsigned int nonlinear_iteration_
virtual PetscErrorCode rhs_zero_entries()
virtual void accept_time_step()
postprocess velocity field (add sources)
void set_solution(Vec sol_vec)
Dedicated class for storing path to input and output files.
Support classes for parallel programing.
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
int set_upper_constraint(double upper, std::string message)
Sets upper constraint for the next time step estimating.
void solve_nonlinear()
Solve method common to zero_time_step and update solution.
void update_solution() override
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
LinSys & lin_sys_schur()
Getter for the linear system of the 2. Schur complement.
Input::Record input_record_
std::shared_ptr< Balance > balance_
virtual void assembly_linear_system()
#define WarningOut()
Macro defining 'warning' record of log.
virtual SolveInfo solve()=0
virtual double solution_precision() const
#define END_TIMER(tag)
Ends a timer with specified tag.
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::VectorFixed > > get_velocity_field() override
#define OLD_ASSERT_EQUAL(a, b)
void set_matrix_changed()
static const Input::Type::Record & get_input_type()
void dofs_range(unsigned int n_dofs, unsigned int &min, unsigned int &max, unsigned int component)
Helper method fills range (min and max) of given component.
void set_positive_definite(bool flag=true)
static const Input::Type::Record & type_field_descriptor()
static Input::Type::Abstract & get_input_type()
virtual void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)=0
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::VectorFixed > > ele_flux_ptr
Field of flux in barycenter of every element.
unsigned int n_edges() const
Class for representation SI units of Fields.
void reconstruct_solution_from_schur(MultidimAssembly &assembler)
MortarMethod
Type of experimental Mortar-like method for non-compatible 1d-2d interaction.
unsigned int n_neighs_vb() const
Return number of neighbours.
#define DebugOut()
Macro defining 'debug' record of log.
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
arma::Col< Idx > LocDofVec
virtual double compute_residual()=0
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Implementation of range helper class.
Side accessor allows to iterate over sides of DOF handler cell.
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
DarcyLMH(Mesh &mesh, const Input::Record in_rec, TimeGovernor *tm=nullptr)
CREATE AND FILL GLOBAL MH MATRIX OF THE WATER MODEL.
void output()
Calculate values for output.
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Mixed-hybrid model of linear Darcy flow, possibly unsteady.