28 #include "petscviewer.h" 29 #include "petscerror.h" 78 const
it::Selection &
DarcyLMH::get_mh_mortar_selection() {
80 .
add_value(NoMortar,
"None",
"No Mortar method is applied.")
81 .
add_value(MortarP0,
"P0",
"Mortar space: P0 on elements of lower dimension.")
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]);
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
arma::Col< IntIdx > LocDofVec
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.
virtual unsigned int n_elements() const
Returns count of boundary or bulk elements.
BCMesh * get_bc_mesh()
Create boundary mesh if doesn't exist and return it.
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.
unsigned int n_elements() const override
Returns count of boundary elements of parent mesh.
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
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.
#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
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.
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.