8 #ifndef SRC_ASSEMBLY_LMH_HH_ 9 #define SRC_ASSEMBLY_LMH_HH_ 46 velocity_interpolation_quad_(dim, 0),
55 auto fe = ad_->dh_->ds()->fe()[
Dim<dim>{}];
57 loc_side_dofs = fe_system->
fe_dofs(0);
58 loc_ele_dof = fe_system->
fe_dofs(1)[0];
59 loc_edge_dofs = fe_system->
fe_dofs(2);
62 .error(
"Mortar methods are not supported in Lumped Mixed-Hybrid Method.");
71 schur_offset_ = loc_edge_dofs[0];
72 reconstructed_solution_.zeros(schur_offset_);
97 arma::vec schur_solution = ad_->p_edge_solution.get_subvec(loc_schur_.row_dofs);
99 loc_system_.reconstruct_solution_schur(schur_offset_, schur_solution, reconstructed_solution_);
104 ad_->full_solution.set_subvec(loc_system_.row_dofs.head(schur_offset_), reconstructed_solution_);
105 ad_->full_solution.set_subvec(loc_system_.row_dofs.tail(loc_schur_.row_dofs.n_elem), schur_solution);
111 save_local_system_ =
false;
112 bc_fluxes_reconstruted =
false;
116 loc_system_.compute_schur_complement(schur_offset_, loc_schur_,
true);
120 loc_schur_.eliminate_solution();
121 ad_->lin_sys_schur->set_local_system(loc_schur_, ad_->dh_cr_->get_local_to_global_map());
157 if(bc_fluxes_reconstruted)
161 auto ls = ad_->seepage_bc_systems.find(dh_cell.
elm_idx());
162 if (ls != ad_->seepage_bc_systems.end())
164 arma::vec schur_solution = ad_->p_edge_solution.get_subvec(loc_schur_.row_dofs);
166 ls->second.reconstruct_solution_schur(schur_offset_, schur_solution, reconstructed_solution_);
170 bc_fluxes_reconstruted =
true;
180 if(save_local_system_)
181 ad_->seepage_bc_systems[dh_cell.
elm_idx()] = loc_system_;
215 const unsigned int p =
size()+i;
217 const unsigned int t = dh_neighb_cell.
n_dofs() - dh_neighb_cr_cell.
n_dofs() + neighb_side.side().side_idx();
221 const unsigned int tt = dh_cr_cell.
n_dofs()+i;
223 [neighb_side.side().side_idx()];
227 loc_system_.reset(dofs, dofs);
228 loc_schur_.reset(dofs_schur, dofs_schur);
235 dirichlet_edge.resize(ele->
n_sides());
237 unsigned int sidx = dh_side.side_idx();
238 dirichlet_edge[sidx] = 0;
241 if (dh_side.side().is_boundary()) {
242 double cross_section = ad_->cross_section.value(ele.
centre(), ele);
245 ad_->balance->add_flux_values(ad_->water_balance_idx, dh_side,
246 {loc_system_.row_dofs[loc_side_dofs[sidx]]},
251 loc_system_.add_value(loc_side_dofs[sidx], loc_edge_dofs[sidx], 1.0);
252 loc_system_.add_value(loc_edge_dofs[sidx], loc_side_dofs[sidx], 1.0);
259 const unsigned int sidx = side.
side_idx();
260 const unsigned int side_row = loc_side_dofs[sidx];
261 const unsigned int edge_row = loc_edge_dofs[sidx];
269 double bc_pressure = ad_->bc_pressure.value(b_ele.
centre(), b_ele);
270 loc_schur_.set_solution(sidx, bc_pressure);
271 dirichlet_edge[sidx] = 1;
275 double bc_flux = -ad_->bc_flux.value(b_ele.
centre(), b_ele);
276 double bc_pressure = ad_->bc_pressure.value(b_ele.
centre(), b_ele);
277 double bc_sigma = ad_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
279 dirichlet_edge[sidx] = 2;
280 loc_system_.add_value(edge_row, edge_row,
281 -b_ele.
measure() * bc_sigma * cross_section,
282 (bc_flux - bc_sigma * bc_pressure) * b_ele.
measure() * cross_section);
285 ad_->is_linear=
false;
287 char & switch_dirichlet = ad_->bc_switch_dirichlet[b_ele.
idx()];
288 double bc_pressure = ad_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
289 double bc_flux = -ad_->bc_flux.value(b_ele.
centre(), b_ele);
290 double side_flux = bc_flux * b_ele.
measure() * cross_section;
293 if(use_dirichlet_switch){
294 if (switch_dirichlet) {
301 double solution_flux = reconstructed_solution_[side_row];
303 if ( solution_flux < side_flux) {
318 double solution_head = ad_->p_edge_solution.get(loc_schur_.row_dofs[sidx]);
320 if ( solution_head > bc_pressure) {
327 save_local_system_ = (bool) switch_dirichlet;
331 if (switch_dirichlet || ad_->force_no_neumann_bc ) {
333 loc_schur_.set_solution(sidx, bc_pressure);
334 dirichlet_edge[sidx] = 1;
337 loc_system_.add_value(edge_row, side_flux);
341 ad_->is_linear=
false;
343 double bc_pressure = ad_->bc_pressure.value(b_ele.
centre(), b_ele);
344 double bc_switch_pressure = ad_->bc_switch_pressure.value(b_ele.
centre(), b_ele);
345 double bc_flux = -ad_->bc_flux.value(b_ele.
centre(), b_ele);
346 double bc_sigma = ad_->bc_robin_sigma.value(b_ele.
centre(), b_ele);
348 double solution_head = ad_->p_edge_solution.get(loc_schur_.row_dofs[sidx]);
351 if (solution_head > bc_switch_pressure || ad_->force_no_neumann_bc) {
354 loc_system_.add_value(edge_row, edge_row,
355 -b_ele.
measure() * bc_sigma * cross_section,
356 b_ele.
measure() * cross_section * (bc_flux - bc_sigma * bc_pressure) );
360 double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
362 loc_system_.add_value(edge_row, bc_total_flux * b_ele.
measure() * cross_section);
374 double cs = ad_->cross_section.value(ele.
centre(), ele);
375 double conduct = ad_->conductivity.value(ele.
centre(), ele);
376 double scale = 1 / cs /conduct;
384 auto ele = dh_cell.
elm();
391 for (
unsigned int k=0; k<qsize; k++)
392 for (
unsigned int i=0; i<ndofs; i++){
394 arma::dot(gravity_vec,velocity.value(i,k))
396 loc_system_.add_value(i, rhs_val);
398 for (
unsigned int j=0; j<ndofs; j++){
400 arma::dot(velocity.value(i,k),
401 (ad_->anisotropy.value(ele.centre(), ele)).i()
402 * velocity.value(j,k))
405 loc_system_.add_value(i, j, mat_val);
436 for(
unsigned int side = 0; side < loc_side_dofs.size(); side++){
437 loc_system_.add_value(loc_ele_dof, loc_side_dofs[side], -1.0);
438 loc_system_.add_value(loc_side_dofs[side], loc_ele_dof, -1.0);
453 double alpha = 1.0 / ele->
n_sides();
454 double cross_section = ad_->cross_section.value(ele.
centre(), ele);
455 double coef = alpha * ele.
measure() * cross_section;
457 double source = ad_->water_source_density.value(ele.
centre(), ele)
458 + ad_->extra_source.value(ele.
centre(), ele);
459 double source_term = coef * source;
462 double storativity = 0.0;
463 double time_term_diag = 0.0, time_term = 0.0, time_term_rhs = 0.0;
465 if(! ad_->use_steady_assembly_)
467 storativity = ad_->storativity.value(ele.
centre(), ele)
468 + ad_->extra_storativity.value(ele.
centre(), ele);
469 time_term = coef * storativity;
472 for (
unsigned int i=0; i<ele->
n_sides(); i++)
474 if(! ad_->use_steady_assembly_)
476 time_term_diag = time_term / ad_->time_step_;
477 time_term_rhs = time_term_diag * ad_->p_edge_solution_previous_time.get(loc_schur_.row_dofs[i]);
479 ad_->balance->add_mass_values(ad_->water_balance_idx, dh_cell,
480 {loc_system_.row_dofs[loc_edge_dofs[i]]}, {time_term}, 0);
483 this->loc_system_.add_value(loc_edge_dofs[i], loc_edge_dofs[i],
485 -source_term - time_term_rhs);
487 ad_->balance->add_source_values(ad_->water_balance_idx, ele.
region().
bulk_idx(),
488 {loc_system_.row_dofs[loc_edge_dofs[i]]}, {0},{source_term});
506 unsigned int p =
size()+i;
509 ngh_values_.fe_side_values_.reinit(neighb_side.side());
510 nv = ngh_values_.fe_side_values_.normal_vector(0);
512 double value = ad_->sigma.value( ele.
centre(), ele) *
513 2*ad_->conductivity.value( ele.
centre(), ele) *
514 arma::dot(ad_->anisotropy.value( ele.
centre(), ele)*nv, nv) *
515 ad_->cross_section.value( neighb_side.centre(), ele_higher ) *
516 ad_->cross_section.value( neighb_side.centre(), ele_higher ) /
517 ad_->cross_section.value( ele.
centre(), ele ) *
518 neighb_side.measure();
520 loc_system_.add_value(loc_ele_dof, loc_ele_dof, -value);
521 loc_system_.add_value(loc_ele_dof, p, value);
522 loc_system_.add_value(p,loc_ele_dof, value);
523 loc_system_.add_value(p,p, -value);
540 double edge_scale = ele.
measure()
541 * ad_->cross_section.value(ele.
centre(), ele)
544 double edge_source_term = edge_scale *
545 ( ad_->water_source_density.value(ele.
centre(), ele)
546 + ad_->extra_source.value(ele.
centre(), ele));
552 double edge_scale,
double edge_source_term)
556 double storativity = ad_->storativity.value(ele.
centre(), ele)
557 + ad_->extra_storativity.value(ele.
centre(), ele);
558 double new_pressure, old_pressure, time_term = 0.0;
560 for (
unsigned int i=0; i<ele->
n_sides(); i++) {
562 if( ! ad_->use_steady_assembly_)
564 new_pressure = ad_->p_edge_solution.get(loc_schur_.row_dofs[i]);
565 old_pressure = ad_->p_edge_solution_previous_time.get(loc_schur_.row_dofs[i]);
566 time_term = edge_scale * storativity / ad_->time_step_ * (new_pressure - old_pressure);
568 solution[loc_side_dofs[i]] += edge_source_term - time_term;
580 QGauss velocity_interpolation_quad_;
584 AssemblyDataPtrLMH ad_;
596 unsigned int loc_ele_dof;
601 unsigned int schur_offset_;
608 bool save_local_system_;
611 bool bc_fluxes_reconstruted;
virtual void assemble_sides(const DHCellAccessor &dh_cell)
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell...
void assemble_local_system(const DHCellAccessor &dh_cell, bool use_dirichlet_switch)
Range< DHCellSide > side_range() const
Returns range of cell sides.
static unsigned int size()
#define ASSERT_EQ_DBG(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
const FEValuesViews::Vector< spacedim > & vector_view(unsigned int i) const
Accessor to vector values of multicomponent FE.
unsigned int elm_idx() const
Return serial idx to element of loc_ele_idx_.
arma::Col< IntIdx > LocDofVec
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
void save_local_system(const DHCellAccessor &dh_cell)
unsigned int dim() const
Return dimension of element appropriate to cell.
Lumped mixed-hybrid model of linear Darcy flow, possibly unsteady.
unsigned int n_dofs() const
Returns the number of shape functions.
Cell accessor allow iterate over DOF handler cells.
Class FEValues calculates finite element data on the actual cells such as shape function values...
Class FESystem for compound finite elements.
LocDofVec get_loc_dof_indices() const
Returns the local indices of dofs associated to the cell on the local process.
unsigned int side_idx() const
unsigned int n_dofs() const
Return number of dofs on given cell.
void reinit(const ElementAccessor< spacedim > &cell)
Update cell-dependent data (gradients, Jacobians etc.)
static constexpr bool value
Symmetric Gauss-Legendre quadrature formulae on simplices.
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
arma::vec::fixed< spacedim > centre() const
Computes the barycenter.
void load_local_system(const DHCellAccessor &dh_cell)
std::shared_ptr< DarcyLMH::EqData > AssemblyDataPtrLMH
virtual void assemble_source_term(const DHCellAccessor &dh_cell)
Transformed quadrature points.
void assemble_side_bc(const DHCellSide &side, double cross_section, bool use_dirichlet_switch)
const ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
Compound finite element on dim dimensional simplex.
void assemble(const DHCellAccessor &dh_cell) override
Raviart-Thomas element of order 0.
Definitions of basic Lagrangean finite elements with polynomial shape functions.
std::vector< unsigned int > fe_dofs(unsigned int fe_index)
Return dof indices belonging to given sub-FE.
unsigned int n_sides() const
RangeConvert< DHNeighbSide, DHCellSide > neighb_sides() const
Returns range of neighbour cell of lower dimension corresponding to cell of higher dimension...
void initialize(Quadrature &_quadrature, FiniteElement< DIM > &_fe, UpdateFlags _flags)
Initialize structures and calculates cell-independent data.
void assembly_dim_connections(const DHCellAccessor &dh_cell)
void assemble_element(FMT_UNUSED const DHCellAccessor &dh_cell)
double measure() const
Computes the measure of the element.
Shape function gradients.
const DHCellAccessor & cell() const
Return DHCellAccessor appropriate to the side.
virtual void postprocess_velocity_specific(const DHCellAccessor &dh_cell, arma::vec &solution, double edge_scale, double edge_source_term)
void fix_velocity(const DHCellAccessor &) override
void assemble_bc(const DHCellAccessor &dh_cell, bool use_dirichlet_switch)
unsigned int bulk_idx() const
Returns index of the region in the bulk set.
Definitions of particular quadrature rules on simplices.
Calculates finite element data on the actual cell.
void set_dofs(const DHCellAccessor &dh_cell)
DHCellAccessor cell_with_other_dh(const DOFHandlerMultiDim *dh) const
Create new accessor with same local idx and given DOF handler. Actual and given DOF handler must be c...
double JxW(const unsigned int point_no)
Return the product of Jacobian determinant and the quadrature weight at given quadrature point...
unsigned int n_neighs_vb() const
Return number of neighbours.
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
void postprocess_velocity(const DHCellAccessor &dh_cell, arma::vec &solution)
void assemble_reconstruct(const DHCellAccessor &dh_cell) override
unsigned int n_points() const
Returns the number of quadrature points.
Definitions of Raviart-Thomas finite elements.
Side accessor allows to iterate over sides of DOF handler cell.
void update_water_content(const DHCellAccessor &) override
Updates water content in Richards.
ElementAccessor< 3 > element_accessor()
#define FEAL_ASSERT(expr)
Definition of assert for debug and release mode.
Transformed quadrature weights.
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
void assemble_sides_scale(const DHCellAccessor &dh_cell, double scale)