Flow123d  master-2fe7782
assembly_lmh.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file assembly_lmh.hh
15  * @brief
16  */
17 
18 #ifndef ASSEMBLY_LMH_HH_
19 #define ASSEMBLY_LMH_HH_
20 
23 #include "flow/darcy_flow_lmh.hh"
24 #include "fem/element_cache_map.hh"
25 
26 #include "system/index_types.hh"
27 #include "mesh/mesh.h"
28 #include "mesh/accessors.hh"
29 #include "mesh/neighbours.h"
30 #include "fem/fe_p.hh"
31 #include "fem/fe_rt.hh"
32 #include "fem/fe_system.hh"
33 #include "fem/patch_op_impl.hh"
35 
36 #include "la/linsys_PETSC.hh"
37 #include "la/schur.hh"
38 #include "la/local_system.hh"
39 #include "la/local_constraint.hh"
40 
41 #include "coupling/balance.hh"
42 
43 
44 template <unsigned int dim, class TEqData>
46 {
47 public:
48  typedef typename TEqData::EqFields EqFields;
49  typedef TEqData EqData;
50 
51  static constexpr const char * name() { return "Darcy_ReadInitCond_Assembly"; }
52 
53  /// Constructor.
54  ReadInitCondAssemblyLMH(EqData *eq_data, PatchInternals *patch_internals)
55  : AssemblyBasePatch<dim>(0, patch_internals), eq_fields_(eq_data->eq_fields_.get()), eq_data_(eq_data),
56  bulk_integral_( this->create_bulk_integral(this->quad_) ) {
57  this->used_fields_ += eq_fields_->init_pressure;
58  }
59 
60  /// Destructor.
62 
63  /// Initialize auxiliary vectors and other data members
64  void initialize() {}
65 
66 
67  /// Assemble integral over element
68  inline void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
69  {
70  ASSERT_EQ(cell.dim(), dim).error("Dimension of element mismatch!");
71 
73  ASSERT(l_indices_.n_elem == cell.elm().element()->n_sides());
74 
75  // set initial condition
76  auto p = *( bulk_integral_->points(element_patch_idx).begin() );
77  double init_value = eq_fields_->init_pressure(p);
78 
79  for (unsigned int i=0; i<cell.elm()->n_sides(); i++) {
80  double init_value_on_edge = init_value / cell.elm().side(i)->edge().n_sides();
81  eq_data_->p_edge_solution.add(l_indices_[i], init_value_on_edge);
82  }
83  }
84 
85  /// Implements @p AssemblyBase::end.
86  void end() override
87  {
88  eq_data_->p_edge_solution.ghost_to_local_begin();
89  eq_data_->p_edge_solution.ghost_to_local_end();
90  eq_data_->p_edge_solution.local_to_ghost_begin();
91  eq_data_->p_edge_solution.local_to_ghost_end();
92  }
93 
94 
95 
96 protected:
97  /// Sub field set contains fields used in calculation.
99 
100  /// Data objects shared with Flow equation
103 
104  /// Vector of pre-computed local DOF indices
106 
107  std::shared_ptr<BulkIntegralAcc<dim>> bulk_integral_; ///< Bulk integral of assembly class
108 
109  template < template<IntDim...> class DimAssembly>
110  friend class GenericAssembly;
111 
112 };
113 
114 template <unsigned int dim, class TEqData>
116 {
117 public:
118  typedef typename TEqData::EqFields EqFields;
119  typedef TEqData EqData;
120 
121  DECLARE_EXCEPTION( ExcBCNotSupported, << "BC type not supported.\n" );
122 
123  static constexpr const char * name() { return "Darcy_MHMatrix_Assembly"; }
124 
125  /// Constructor.
126  MHMatrixAssemblyLMH(EqData *eq_data, PatchInternals *patch_internals)
127  : AssemblyBasePatch<dim>(0, patch_internals), eq_fields_(eq_data->eq_fields_.get()), eq_data_(eq_data), quad_rt_(dim, 2),
128  bulk_integral_( this->create_bulk_integral(this->quad_)) ,
132  JxW_( asm_sides_integral_->JxW() ),
133  velocity_( asm_sides_integral_->vector_shape(0) ),
134  normal_join_( coupling_integral_->normal_vector() ) {
135  this->used_fields_ += eq_fields_->cross_section;
136  this->used_fields_ += eq_fields_->conductivity;
137  this->used_fields_ += eq_fields_->anisotropy;
138  this->used_fields_ += eq_fields_->sigma;
139  this->used_fields_ += eq_fields_->water_source_density;
140  this->used_fields_ += eq_fields_->water_source_sigma;
141  this->used_fields_ += eq_fields_->water_source_ref_pressure;
142  this->used_fields_ += eq_fields_->extra_source;
143  this->used_fields_ += eq_fields_->storativity;
144  this->used_fields_ += eq_fields_->extra_storativity;
145  this->used_fields_ += eq_fields_->bc_type;
146  this->used_fields_ += eq_fields_->bc_pressure;
147  this->used_fields_ += eq_fields_->bc_flux;
148  this->used_fields_ += eq_fields_->bc_robin_sigma;
149  this->used_fields_ += eq_fields_->bc_switch_pressure;
150  }
151 
152  /// Destructor.
153  virtual ~MHMatrixAssemblyLMH() {}
154 
155  /// Initialize auxiliary vectors and other data members
156  void initialize() {
157  //this->balance_ = eq_data_->balance_;
158 
159  // local numbering of dofs for MH system
160  // note: this shortcut supposes that the fe_system is the same on all elements
161  // TODO the function should be DiscreteSpace.fe(ElementAccessor)
162  // and correct form fe(ad_->dh_->own_range().begin()->elm()) (see documentation of DiscreteSpace::fe)
163  auto fe = eq_data_->dh_->ds()->fe()[Dim<dim>{}];
164  FESystem<dim>* fe_system = dynamic_cast<FESystem<dim>*>(fe.get());
165  eq_data_->loc_side_dofs[dim-1] = fe_system->fe_dofs(0);
166  eq_data_->loc_ele_dof[dim-1] = fe_system->fe_dofs(1)[0];
167  eq_data_->loc_edge_dofs[dim-1] = fe_system->fe_dofs(2);
168 
169  // reconstructed vector for the velocity and pressure
170  // length = local Schur complement offset in LocalSystem
171  eq_data_->schur_offset_[dim-1] = eq_data_->loc_edge_dofs[dim-1][0];
172  reconstructed_solution_.zeros(eq_data_->schur_offset_[dim-1]);
173 
174  n_dofs_ = this->patch_internals_->fe_values_.template fe_comp<dim>(this->patch_internals_->fe_values_.template fe_dim<dim>(), 0)->n_dofs();
175  }
176 
177 
178  /**
179  * Integral over element.
180  *
181  * Override in descendants.
182  */
183  inline void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
184  {
185  ASSERT_EQ(cell.dim(), dim).error("Dimension of element mismatch!");
186 
187  // evaluation point
188  auto p = *( bulk_integral_->points(element_patch_idx).begin() );
189  bulk_local_idx_ = cell.local_idx();
190 
191  this->asm_sides(p, eq_fields_->conductivity(p), element_patch_idx);
192  this->asm_element();
193  this->asm_source_term_darcy(cell, p);
194  }
195 
196 
197  /**
198  * Assembles between boundary element and corresponding side on bulk element.
199  *
200  * Override in descendants.
201  */
202  inline void boundary_side_integral(DHCellSide cell_side)
203  {
204  ASSERT_EQ(cell_side.dim(), dim).error("Dimension of element mismatch!");
205  if (!cell_side.cell().is_own()) return;
206 
207  auto p_side = *( bdr_integral_->points(cell_side).begin() );
208  auto p_bdr = p_side.point_bdr(cell_side.cond().element_accessor() );
209  ElementAccessor<3> b_ele = cell_side.side().cond().element_accessor(); // ??
210 
211  precompute_boundary_side(cell_side, p_side, p_bdr);
212 
214  this->use_dirichlet_switch(cell_side, b_ele, p_bdr);
215  }
216 
217  this->boundary_side_integral_in(cell_side, b_ele, p_bdr);
218  }
219 
220 
221  /**
222  * Assembles the fluxes between elements of different dimensions.
223  *
224  * Common in all descendants.
225  */
226  inline void dimjoin_intergral(DHCellAccessor cell_lower_dim, DHCellSide neighb_side) {
227  if (dim == 3) return;
228  ASSERT_EQ(cell_lower_dim.dim(), dim).error("Dimension of element mismatch!");
229 
230  unsigned int neigh_idx = ngh_idx(cell_lower_dim, neighb_side); // TODO use better evaluation of neighbour_idx
231  unsigned int loc_dof_higher = (2*(cell_lower_dim.dim()+1) + 1) + neigh_idx; // loc dof of higher ele edge
232  bulk_local_idx_ = cell_lower_dim.local_idx();
233 
234  // Evaluation points
235  auto p_high = *( coupling_integral_->points(neighb_side).begin() );
236  auto p_low = p_high.lower_dim(cell_lower_dim);
237 
238  nv_ = normal_join_(p_high);
239 
240  ngh_value_ = eq_fields_->sigma(p_low) *
241  2*eq_fields_->conductivity(p_low) *
242  arma::dot(eq_fields_->anisotropy(p_low)*nv_, nv_) *
243  eq_fields_->cross_section(p_high) * // cross-section of higher dim. (2d)
244  eq_fields_->cross_section(p_high) /
245  eq_fields_->cross_section(p_low) * // crossection of lower dim.
246  neighb_side.measure();
247 
248  eq_data_->loc_system_[bulk_local_idx_].add_value(eq_data_->loc_ele_dof[dim-1], eq_data_->loc_ele_dof[dim-1], -ngh_value_);
249  eq_data_->loc_system_[bulk_local_idx_].add_value(eq_data_->loc_ele_dof[dim-1], loc_dof_higher, ngh_value_);
250  eq_data_->loc_system_[bulk_local_idx_].add_value(loc_dof_higher, eq_data_->loc_ele_dof[dim-1], ngh_value_);
251  eq_data_->loc_system_[bulk_local_idx_].add_value(loc_dof_higher, loc_dof_higher, -ngh_value_);
252 
253 // // update matrix for weights in BDDCML
254 // if ( typeid(*eq_data_->lin_sys) == typeid(LinSys_BDDC) ) {
255 // int ind = eq_data_->loc_system_[bulk_local_idx_].row_dofs[p];
256 // // there is -value on diagonal in block C!
257 // static_cast<LinSys_BDDC*>(eq_data_->lin_sys)->diagonal_weights_set_value( ind, -value );
258 // }
259  }
260 
261 
262  /// Implements @p AssemblyBase::begin.
263  void begin() override
264  {
265  this->begin_mh_matrix();
266  }
267 
268 
269  /// Implements @p AssemblyBase::end.
270  void end() override
271  {
272  this->end_mh_matrix();
273  }
274 
275 protected:
276  /// Common code of begin method of MH matrix assembly (Darcy and Richards)
278  {
279  // DebugOut() << "assembly_mh_matrix \n";
280  // set auxiliary flag for switchting Dirichlet like BC
281  eq_data_->force_no_neumann_bc = eq_data_->use_steady_assembly_ && (eq_data_->nonlinear_iteration_ == 0);
282 
283  eq_data_->reset();
284 
285  eq_data_->balance_->start_flux_assembly(eq_data_->water_balance_idx);
286  eq_data_->balance_->start_source_assembly(eq_data_->water_balance_idx);
287  eq_data_->balance_->start_mass_assembly(eq_data_->water_balance_idx);
288 
289  this->set_dofs();
290  }
291 
292 
293  /// Common code of end method of MH matrix assembly (Darcy and Richards)
295  {
296  std::sort(eq_data_->loc_constraint_.begin(), eq_data_->loc_constraint_.end());
297  eq_data_->loc_constraint_.emplace_back(uint(-1), 0, 0.0); // add constraint of invalid element to end of vector
298  unsigned int i_constr = 0;
299  for ( DHCellAccessor dh_cell : eq_data_->dh_cr_->own_range() ) {
300  this->set_loc_schur(dh_cell);
301  while (eq_data_->loc_constraint_[i_constr].i_element() == dh_cell.local_idx()) {
302  this->loc_schur_.set_solution(eq_data_->loc_constraint_[i_constr]);
303  i_constr++;
304  }
305  eq_data_->loc_system_[dh_cell.local_idx()].compute_schur_complement(
306  eq_data_->schur_offset_[dh_cell.dim()-1], this->loc_schur_, true);
307 
308  // for seepage BC, save local system
309  if (eq_data_->save_local_system_[dh_cell.local_idx()])
310  eq_data_->seepage_bc_systems[dh_cell.elm_idx()] = eq_data_->loc_system_[dh_cell.local_idx()];
311 
313  eq_data_->lin_sys_schur->set_local_system(this->loc_schur_, eq_data_->dh_cr_->get_local_to_global_map());
314 
315  // TODO:
316  // if (mortar_assembly)
317  // mortar_assembly->assembly(dh_cell);
318  }
319 
320  eq_data_->balance_->finish_mass_assembly(eq_data_->water_balance_idx);
321  eq_data_->balance_->finish_source_assembly(eq_data_->water_balance_idx);
322  eq_data_->balance_->finish_flux_assembly(eq_data_->water_balance_idx);
323 
324  eq_data_->loc_constraint_.clear();
325  }
326 
327 
328  /// Common code of begin method of Reconstruct Schur assembly (Darcy and Richards)
330  {
331  this->eq_data_->full_solution.zero_entries();
332  this->eq_data_->p_edge_solution.local_to_ghost_begin();
333  this->eq_data_->p_edge_solution.local_to_ghost_end();
334  }
335 
336 
337  /// Common code of end method of Reconstruct Schur assembly (Darcy and Richards)
339  {
340  for ( DHCellAccessor dh_cell : this->eq_data_->dh_cr_->own_range() ) {
341  this->bulk_local_idx_ = dh_cell.local_idx();
342  this->set_loc_schur(dh_cell);
343  arma::vec schur_solution = this->eq_data_->p_edge_solution.get_subvec(this->loc_schur_.row_dofs);
344  // reconstruct the velocity and pressure
345  this->eq_data_->loc_system_[this->bulk_local_idx_].reconstruct_solution_schur(this->eq_data_->schur_offset_[dh_cell.dim()-1],
346  schur_solution, this->reconstructed_solution_);
347 
348  this->reconstructed_solution_ += this->eq_data_->postprocess_solution_[this->bulk_local_idx_];
349 
350  this->eq_data_->full_solution.set_subvec(this->eq_data_->loc_system_[this->bulk_local_idx_].row_dofs.head(
351  this->eq_data_->schur_offset_[dh_cell.dim()-1]), this->reconstructed_solution_);
352  this->eq_data_->full_solution.set_subvec(this->eq_data_->loc_system_[this->bulk_local_idx_].row_dofs.tail(
353  this->loc_schur_.row_dofs.n_elem), schur_solution);
354  }
355 
356  this->eq_data_->full_solution.local_to_ghost_begin();
357  this->eq_data_->full_solution.local_to_ghost_end();
358 
359  eq_data_->loc_constraint_.clear();
360  }
361 
362  /// Part of cell_integral method, common in all descendants
363  inline void asm_sides(BulkPoint &p, double conductivity, unsigned int element_patch_idx)
364  {
365  double scale_sides = 1 / eq_fields_->cross_section(p) / conductivity;
366  arma::mat33 aniso_inv = (eq_fields_->anisotropy(p)).i();
367 
368  for (auto p_rt : asm_sides_integral_->points(element_patch_idx) ) {
369  for (unsigned int i=0; i<n_dofs_; i++){
370  double rhs_val = arma::dot( eq_data_->gravity_vec_, velocity_.shape(i)(p_rt) )
371  * JxW_(p_rt);
372  eq_data_->loc_system_[bulk_local_idx_].add_value(i, rhs_val);
373 
374  for (unsigned int j=0; j<n_dofs_; j++){
375  double mat_val =
376  arma::dot( velocity_.shape(i)(p_rt), aniso_inv * velocity_.shape(j)(p_rt) )
377  * scale_sides * JxW_(p_rt);
378 
379  eq_data_->loc_system_[bulk_local_idx_].add_value(i, j, mat_val);
380  }
381  }
382  }
383 
384  // assemble matrix for weights in BDDCML
385  // approximation to diagonal of
386  // S = -C - B*inv(A)*B'
387  // as
388  // diag(S) ~ - diag(C) - 1./diag(A)
389  // the weights form a partition of unity to average a discontinuous solution from neighbouring subdomains
390  // to a continuous one
391  // it is important to scale the effect - if conductivity is low for one subdomain and high for the other,
392  // trust more the one with low conductivity - it will be closer to the truth than an arithmetic average
393 // if ( typeid(*ad_->lin_sys) == typeid(LinSys_BDDC) ) {
394 // const arma::mat& local_matrix = loc_system_.get_matrix();
395 // for(unsigned int i=0; i < ndofs; i++) {
396 // double val_side = local_matrix(i,i);
397 // double val_edge = -1./local_matrix(i,i);
398 //
399 // unsigned int side_row = loc_system_.row_dofs[loc_side_dofs[i]];
400 // unsigned int edge_row = loc_system_.row_dofs[loc_edge_dofs[i]];
401 // static_cast<LinSys_BDDC*>(ad_->lin_sys)->diagonal_weights_set_value( side_row, val_side );
402 // static_cast<LinSys_BDDC*>(ad_->lin_sys)->diagonal_weights_set_value( edge_row, val_edge );
403 // }
404 // }
405  }
406 
407  /// Part of cell_integral method, common in all descendants
408  inline void asm_element()
409  {
410  // set block B, B': element-side, side-element
411 
412  for(unsigned int side = 0; side < eq_data_->loc_side_dofs[dim-1].size(); side++){
413  eq_data_->loc_system_[bulk_local_idx_].add_value(eq_data_->loc_ele_dof[dim-1], eq_data_->loc_side_dofs[dim-1][side], -1.0);
414  eq_data_->loc_system_[bulk_local_idx_].add_value(eq_data_->loc_side_dofs[dim-1][side], eq_data_->loc_ele_dof[dim-1], -1.0);
415  }
416 
417 // if ( typeid(*ad_->lin_sys) == typeid(LinSys_BDDC) ) {
418 // double val_ele = 1.;
419 // static_cast<LinSys_BDDC*>(ad_->lin_sys)->
420 // diagonal_weights_set_value( loc_system_.row_dofs[loc_ele_dof], val_ele );
421 // }
422  }
423 
424  /// Part of cell_integral method, specialized in Darcy equation
425  inline void asm_source_term_darcy(const DHCellAccessor& cell, BulkPoint &p)
426  {
427  // compute lumped source
428  uint n_sides = cell.elm()->n_sides();
429  coef_ = (1.0 / n_sides) * cell.elm().measure() * eq_fields_->cross_section(p);
430  source_term_ = coef_ * (eq_fields_->water_source_density(p) +
431  eq_fields_->water_source_sigma(p)*eq_fields_->water_source_ref_pressure(p) +
432  eq_fields_->extra_source(p));
433  double source_term_diag_ = coef_ * eq_fields_->water_source_sigma(p);
434 
435  // in unsteady, compute time term
436  time_term_diag_ = 0.0;
437  time_term_ = 0.0;
438  time_term_rhs_ = 0.0;
439 
440  if(! eq_data_->use_steady_assembly_)
441  {
442  time_term_ = coef_ * (eq_fields_->storativity(p) + eq_fields_->extra_storativity(p));
443  }
444 
445  const DHCellAccessor cr_cell = cell.cell_with_other_dh(eq_data_->dh_cr_.get());
446  auto loc_dof_vec = cr_cell.get_loc_dof_indices();
447 
448  for (unsigned int i=0; i<n_sides; i++)
449  {
450  if(! eq_data_->use_steady_assembly_)
451  {
452  time_term_diag_ = time_term_ / eq_data_->time_step_;
453  time_term_rhs_ = time_term_diag_ * eq_data_->p_edge_solution_previous_time.get(loc_dof_vec[i]);
454 
455  eq_data_->balance_->add_mass_values(eq_data_->water_balance_idx, cell,
456  {eq_data_->loc_system_[bulk_local_idx_].row_dofs[eq_data_->loc_edge_dofs[dim-1][i]]}, {time_term_}, 0);
457  }
458  else
459  {
460  // Add zeros explicitely to keep the sparsity pattern.
461  // Otherwise Petsc would compress out the zeros in FinishAssembly.
462  eq_data_->balance_->add_mass_values(eq_data_->water_balance_idx, cell,
463  {eq_data_->loc_system_[bulk_local_idx_].row_dofs[eq_data_->loc_edge_dofs[dim-1][i]]}, {0}, 0);
464  }
465 
466  eq_data_->loc_system_[bulk_local_idx_].add_value(eq_data_->loc_edge_dofs[dim-1][i], eq_data_->loc_edge_dofs[dim-1][i],
467  -source_term_diag_ - time_term_diag_,
469 
470  eq_data_->balance_->add_source_values(eq_data_->water_balance_idx, cell.elm().region().bulk_idx(),
471  {eq_data_->loc_system_[bulk_local_idx_].row_dofs[eq_data_->loc_edge_dofs[dim-1][i]]}, {-source_term_diag_}, {source_term_});
472  }
473  }
474 
475  /// Precompute values used in boundary side integral on given DHCellSide
476  inline void precompute_boundary_side(DHCellSide &cell_side, BoundaryPoint &p_side, BulkPoint &p_bdr)
477  {
478  bulk_local_idx_ = cell_side.cell().local_idx();
479 
480  cross_section_ = eq_fields_->cross_section(p_side);
481  type_ = (DarcyLMH::EqFields::BC_Type)eq_fields_->bc_type(p_bdr);
482 
483  sidx_ = cell_side.side_idx();
484  side_row_ = eq_data_->loc_side_dofs[dim-1][sidx_]; //local
485  edge_row_ = eq_data_->loc_edge_dofs[dim-1][sidx_]; //local
486  }
487 
488  /// Update BC switch dirichlet in MH matrix assembly if BC type is seepage
489  inline void use_dirichlet_switch(DHCellSide &cell_side, const ElementAccessor<3> &b_ele, BulkPoint &p_bdr)
490  {
491  char & switch_dirichlet = eq_data_->bc_switch_dirichlet[b_ele.idx()];
492  if (switch_dirichlet) {
493  // check and possibly switch to flux BC
494  // The switch raise error on the corresponding edge row.
495  // Magnitude of the error is abs(solution_flux - side_flux).
496 
497  // try reconstructing local system for seepage BC
498  auto reconstr_solution = this->load_local_system(cell_side.cell());
499  double side_flux = -eq_fields_->bc_flux(p_bdr) * b_ele.measure() * cross_section_;
500 
501  if ( reconstr_solution[side_row_] < side_flux) {
502  //DebugOut().fmt("x: {}, to neum, p: {} f: {} -> f: {}\n", b_ele.centre()[0], bc_pressure, reconstructed_solution_[side_row_], side_flux);
503  switch_dirichlet = 0;
504  }
505  } else {
506  // check and possibly switch to pressure BC
507  // TODO: What is the appropriate DOF in not local?
508  // The switch raise error on the corresponding side row.
509  // Magnitude of the error is abs(solution_head - bc_pressure)
510  // Since usually K is very large, this error would be much
511  // higher then error caused by the inverse switch, this
512  // cause that a solution with the flux violating the
513  // flux inequality leading may be accepted, while the error
514  // in pressure inequality is always satisfied.
515 
516  const DHCellAccessor cr_cell = cell_side.cell().cell_with_other_dh(eq_data_->dh_cr_.get());
517  auto loc_dof_vec = cr_cell.get_loc_dof_indices();
518  double solution_head = eq_data_->p_edge_solution.get(loc_dof_vec[sidx_]);
519  double bc_pressure = eq_fields_->bc_switch_pressure(p_bdr);
520 
521  if ( solution_head > bc_pressure) {
522  //DebugOut().fmt("x: {}, to dirich, p: {} -> p: {} f: {}\n",b_ele.centre()[0], solution_head, bc_pressure, bc_flux);
523  switch_dirichlet=1;
524  }
525  }
526  }
527 
528  /**
529  * Common code of boundary_side_integral.
530  */
531  inline void boundary_side_integral_in(DHCellSide cell_side, const ElementAccessor<3> &b_ele, BulkPoint &p_bdr)
532  {
533  if ( type_ == DarcyLMH::EqFields::none) {
534  // homogeneous neumann
535  } else if ( type_ == DarcyLMH::EqFields::dirichlet ) {
536  eq_data_->loc_constraint_.emplace_back( bulk_local_idx_, sidx_, eq_fields_->bc_pressure(p_bdr) );
537 
538  } else if ( type_ == DarcyLMH::EqFields::total_flux) {
539  // internally we work with outward flux
540  eq_data_->loc_system_[bulk_local_idx_].add_value(edge_row_, edge_row_,
541  -b_ele.measure() * eq_fields_->bc_robin_sigma(p_bdr) * cross_section_,
542  (-eq_fields_->bc_flux(p_bdr) - eq_fields_->bc_robin_sigma(p_bdr) * eq_fields_->bc_pressure(p_bdr)) * b_ele.measure() * cross_section_);
543  } else if (type_==DarcyLMH::EqFields::seepage) {
544  eq_data_->is_linear=false;
545 
546  double bc_pressure = eq_fields_->bc_switch_pressure(p_bdr);
547  double side_flux = -eq_fields_->bc_flux(p_bdr) * b_ele.measure() * cross_section_;
548 
549  eq_data_->save_local_system_[bulk_local_idx_] = (bool) eq_data_->bc_switch_dirichlet[b_ele.idx()];
550 
551  // ** Apply BCUpdate BC type. **
552  // Force Dirichlet type during the first iteration of the unsteady case.
553  if (eq_data_->save_local_system_[bulk_local_idx_] || eq_data_->force_no_neumann_bc ) {
554  //DebugOut().fmt("x: {}, dirich, bcp: {}\n", b_ele.centre()[0], bc_pressure);
555  eq_data_->loc_constraint_.emplace_back(bulk_local_idx_, sidx_, bc_pressure);
556  } else {
557  //DebugOut()("x: {}, neuman, q: {} bcq: {}\n", b_ele.centre()[0], side_flux, bc_flux);
558  eq_data_->loc_system_[bulk_local_idx_].add_value(edge_row_, side_flux);
559  }
560 
561  } else if (type_==DarcyLMH::EqFields::river) {
562  eq_data_->is_linear=false;
563 
564  double bc_pressure = eq_fields_->bc_pressure(p_bdr);
565  double bc_switch_pressure = eq_fields_->bc_switch_pressure(p_bdr);
566  double bc_flux = -eq_fields_->bc_flux(p_bdr);
567  double bc_sigma = eq_fields_->bc_robin_sigma(p_bdr);
568 
569  const DHCellAccessor cr_cell = cell_side.cell().cell_with_other_dh(eq_data_->dh_cr_.get());
570  auto loc_dof_vec = cr_cell.get_loc_dof_indices();
571  double solution_head = eq_data_->p_edge_solution.get(loc_dof_vec[sidx_]);
572 
573  // Force Robin type during the first iteration of the unsteady case.
574  if (solution_head > bc_switch_pressure || eq_data_->force_no_neumann_bc) {
575  // Robin BC
576  //DebugOut().fmt("x: {}, robin, bcp: {}\n", b_ele.centre()[0], bc_pressure);
577  eq_data_->loc_system_[bulk_local_idx_].add_value(edge_row_, edge_row_,
578  -b_ele.measure() * bc_sigma * cross_section_,
579  b_ele.measure() * cross_section_ * (bc_flux - bc_sigma * bc_pressure) );
580  } else {
581  // Neumann BC
582  //DebugOut().fmt("x: {}, neuman, q: {} bcq: {}\n", b_ele.centre()[0], bc_switch_pressure, bc_pressure);
583  double bc_total_flux = bc_flux + bc_sigma*(bc_switch_pressure - bc_pressure);
584 
585  eq_data_->loc_system_[bulk_local_idx_].add_value(edge_row_, bc_total_flux * b_ele.measure() * cross_section_);
586  }
587  }
588  else {
589  THROW( ExcBCNotSupported() );
590  }
591 
592  eq_data_->balance_->add_flux_values(eq_data_->water_balance_idx, cell_side,
593  {eq_data_->loc_system_[bulk_local_idx_].row_dofs[eq_data_->loc_side_dofs[dim-1][sidx_]]},
594  {1}, 0);
595  }
596 
597  /// Precompute loc_system and loc_schur data members.
598  void set_dofs() {
599  unsigned int size, loc_size, elm_dim;;
600  for ( DHCellAccessor dh_cell : eq_data_->dh_->local_range() ) {
601  const ElementAccessor<3> ele = dh_cell.elm();
602 
603  elm_dim = ele.dim();
604  size = (elm_dim+1) + 1 + (elm_dim+1); // = n_sides + 1 + n_sides
605  loc_size = size + ele->n_neighs_vb();
606  LocDofVec dofs(loc_size);
607 
608  // add full vec indices
609  dofs.head(dh_cell.n_dofs()) = dh_cell.get_loc_dof_indices();
610 
611  if(ele->n_neighs_vb() != 0)
612  {
613  //D, E',E block: compatible connections: element-edge
614  unsigned int i = 0;
615 
616  for ( DHCellSide neighb_side : dh_cell.neighb_sides() ) {
617 
618  // read neighbor dofs (dh dofhandler)
619  // neighbor cell owning neighb_side
620  DHCellAccessor dh_neighb_cell = neighb_side.cell();
621 
622  // read neighbor dofs (dh_cr dofhandler)
623  // neighbor cell owning neighb_side
624  DHCellAccessor dh_neighb_cr_cell = dh_neighb_cell.cell_with_other_dh(eq_data_->dh_cr_.get());
625 
626  // local index of pedge dof in local system
627  const unsigned int p = size+i;
628  // local index of pedge dof on neighboring cell
629  const unsigned int t = dh_neighb_cell.n_dofs() - dh_neighb_cr_cell.n_dofs() + neighb_side.side().side_idx();
630  dofs[p] = dh_neighb_cell.get_loc_dof_indices()[t];
631  i++;
632  }
633  }
634  eq_data_->loc_system_[dh_cell.local_idx()].reset(dofs, dofs);
635 
636  // Set side-edge (flux-lambda) terms
637  for (DHCellSide dh_side : dh_cell.side_range()) {
638  unsigned int sidx = dh_side.side_idx();
639  // side-edge (flux-lambda) terms
640  eq_data_->loc_system_[dh_cell.local_idx()].add_value(eq_data_->loc_side_dofs[elm_dim-1][sidx], eq_data_->loc_edge_dofs[elm_dim-1][sidx], 1.0);
641  eq_data_->loc_system_[dh_cell.local_idx()].add_value(eq_data_->loc_edge_dofs[elm_dim-1][sidx], eq_data_->loc_side_dofs[elm_dim-1][sidx], 1.0);
642  }
643  }
644  }
645 
646 
647  /// Precompute loc_schur data member of given cell.
648  void set_loc_schur(const DHCellAccessor dh_cr_cell) {
649  const ElementAccessor<3> ele = dh_cr_cell.elm();
650 
651  unsigned int loc_size_schur = ele->n_sides() + ele->n_neighs_vb();
652  LocDofVec dofs_schur(loc_size_schur);
653 
654  // add schur vec indices
655  dofs_schur.head(dh_cr_cell.n_dofs()) = dh_cr_cell.get_loc_dof_indices();
656 
657  if(ele->n_neighs_vb() != 0)
658  {
659  //D, E',E block: compatible connections: element-edge
660  unsigned int i = 0;
661 
662  for ( DHCellSide neighb_side : dh_cr_cell.neighb_sides() ) {
663 
664  // read neighbor dofs (dh dofhandler)
665  // neighbor cell owning neighb_side
666  DHCellAccessor dh_neighb_cr_cell = neighb_side.cell();
667 
668  // local index of pedge dof in local schur system
669  const unsigned int tt = dh_cr_cell.n_dofs()+i;
670  dofs_schur[tt] = dh_neighb_cr_cell.get_loc_dof_indices()[neighb_side.side().side_idx()];
671  i++;
672  }
673  }
674 
675 
676  loc_schur_.reset(dofs_schur, dofs_schur);
677  }
678 
679 
680  /// Temporary method find neighbour index in higher-dim cell
681  inline unsigned int ngh_idx(DHCellAccessor &dh_cell, DHCellSide &neighb_side) {
682  for (uint n_i=0; n_i<dh_cell.elm()->n_neighs_vb(); ++n_i) {
683  auto side = dh_cell.elm()->neigh_vb[n_i]->side();
684  if ( (side->elem_idx() == neighb_side.elem_idx()) && (side->side_idx() == neighb_side.side_idx()) ) return n_i;
685  }
686  ASSERT_PERMANENT(false)(dh_cell.elm_idx())(neighb_side.side_idx()).error("Side is not a part of neighbour!\n");
687  return 0;
688  }
689 
690 
691  /** Loads the local system from a map: element index -> LocalSystem,
692  * if it exits, or if the full solution is not yet reconstructed,
693  * and reconstructs the full solution on the element.
694  * Currently used only for seepage BC.
695  */
697  {
698  // possibly find the corresponding local system
699  auto ls = eq_data_->seepage_bc_systems.find(dh_cell.elm_idx());
700  if (ls != eq_data_->seepage_bc_systems.end())
701  {
702  const DHCellAccessor cr_cell = dh_cell.cell_with_other_dh(eq_data_->dh_cr_.get());
703  auto loc_dof_vec = cr_cell.get_loc_dof_indices();
704  arma::vec schur_solution = eq_data_->p_edge_solution.get_subvec(loc_dof_vec);
705  // reconstruct the velocity and pressure
706  ls->second.reconstruct_solution_schur(eq_data_->schur_offset_[dim-1], schur_solution, reconstructed_solution_);
707 
708  unsigned int pos_in_cache = this->patch_internals_->element_cache_map_.position_in_cache(dh_cell.elm_idx());
709  auto p = *( bulk_integral_->points(pos_in_cache).begin() );
710  postprocess_velocity_darcy(dh_cell, p, reconstructed_solution_);
711 
712  eq_data_->bc_fluxes_reconstruted[bulk_local_idx_] = true;
713  }
714 
715  return reconstructed_solution_;
716  }
717 
718 
719  /**
720  * Precompute edge_scale and edge_source_term.
721  *
722  * This method must be calls in methods postprocess_velocity_darcy and postprocess_velocity_richards
723  */
725  {
726  edge_scale_ = dh_cell.elm().measure()
727  * eq_fields_->cross_section(p)
728  / dh_cell.elm()->n_sides();
729 
730  edge_source_term_ = edge_scale_ *
731  ( eq_fields_->water_source_density(p)
732  + eq_fields_->water_source_sigma(p)*eq_fields_->water_source_ref_pressure(p)
733  + eq_fields_->extra_source(p));
734  }
735 
736 
737  /// Postprocess velocity during loading of local system and after calculating of cell integral.
738  void postprocess_velocity_darcy(const DHCellAccessor& dh_cell, BulkPoint &p, arma::vec& solution)
739  {
740  postprocess_velocity(dh_cell, p);
741 
742  time_term_ = 0.0;
743  const DHCellAccessor cr_cell = dh_cell.cell_with_other_dh(eq_data_->dh_cr_.get());
744  auto loc_dof_vec = cr_cell.get_loc_dof_indices();
745 
746  for (unsigned int i=0; i<dh_cell.elm()->n_sides(); i++) {
747 
748  double new_pressure = eq_data_->p_edge_solution.get(loc_dof_vec[i]);
749  if( ! eq_data_->use_steady_assembly_)
750  {
751  double old_pressure = eq_data_->p_edge_solution_previous_time.get(loc_dof_vec[i]);
752  time_term_ = edge_scale_ * (eq_fields_->storativity(p) + eq_fields_->extra_storativity(p))
753  / eq_data_->time_step_ * (new_pressure - old_pressure);
754  }
755  solution[eq_data_->loc_side_dofs[dim-1][i]] += edge_source_term_ - time_term_ - edge_scale_ * eq_fields_->water_source_sigma(p)*new_pressure;
756  }
757  }
758 
759 
760  /// Sub field set contains fields used in calculation.
762 
763  /// Data objects shared with DarcyFlow
766 
767  /// Assembly volume integrals
769 
770  /// Vector for reconstructed solution (velocity and pressure on element) from Schur complement.
772 
773  double coef_, source_term_; ///< Variables used in compute lumped source.
774  double time_term_diag_, time_term_, time_term_rhs_; ///< Variables used in compute time term (unsteady)
775  double cross_section_; ///< Precomputed cross-section value
776  unsigned int bulk_local_idx_; ///< Local idx of bulk element
777  unsigned int sidx_, side_row_, edge_row_; ///< Helper indices in boundary assembly
778  DarcyLMH::EqFields::BC_Type type_; ///< Type of boundary condition
779  arma::vec3 nv_; ///< Normal vector
780  double ngh_value_; ///< Precomputed ngh value
781  double edge_scale_, edge_source_term_; ///< Precomputed values in postprocess_velocity
782 
784  unsigned int n_dofs_; ///< Number of DOFs of fe_rt component
785 
786  std::shared_ptr<BulkIntegralAcc<dim>> bulk_integral_; ///< Bulk integral of assembly class
787  std::shared_ptr<BulkIntegralAcc<dim>> asm_sides_integral_; ///< Bulk integral defined on quadrature of higher order
788  std::shared_ptr<BoundaryIntegralAcc<dim>> bdr_integral_; ///< Boundary integral of assembly class
789  std::shared_ptr<CouplingIntegralAcc<dim>> coupling_integral_; ///< Coupling integral of assembly class
790 
791  /// Following data members represent Element quantities and FE quantities
795 
796  template < template<IntDim...> class DimAssembly>
797  friend class GenericAssembly;
798 
799 };
800 
801 template <unsigned int dim, class TEqData>
803 {
804 public:
805  typedef typename TEqData::EqFields EqFields;
806  typedef TEqData EqData;
807 
808  static constexpr const char * name() { return "Darcy_ReconstructSchur_Assembly"; }
809 
810  /// Constructor.
812  : MHMatrixAssemblyLMH<dim, TEqData>(eq_data, patch_internals) {}
813 
814  /// Integral over element.
815  inline void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
816  {
817  ASSERT_EQ(cell.dim(), dim).error("Dimension of element mismatch!");
818 
819  // evaluation point
820  auto p = *( this->bulk_integral_->points(element_patch_idx).begin() );
821  this->bulk_local_idx_ = cell.local_idx();
822 
823  { // postprocess the velocity
824  this->eq_data_->postprocess_solution_[this->bulk_local_idx_].zeros(this->eq_data_->schur_offset_[dim-1]);
825  this->postprocess_velocity_darcy(cell, p, this->eq_data_->postprocess_solution_[this->bulk_local_idx_]);
826  }
827  }
828 
829 
830  /// Assembles between boundary element and corresponding side on bulk element.
832  {}
833 
834  inline void dimjoin_intergral(FMT_UNUSED DHCellAccessor cell_lower_dim, FMT_UNUSED DHCellSide neighb_side)
835  {}
836 
837 
838  /// Implements @p AssemblyBase::begin.
839  void begin() override
840  {
841  this->begin_reconstruct_schur();
842  }
843 
844 
845  /// Implements @p AssemblyBase::end.
846  void end() override
847  {
848  this->end_reconstruct_schur();
849  }
850 
851 };
852 
853 #endif /* ASSEMBLY_LMH_HH_ */
854 
#define ASSERT(expr)
Definition: asserts.hh:351
#define ASSERT_PERMANENT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:348
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
std::shared_ptr< CouplingIntegralAcc< dim > > create_coupling_integral(Quadrature *quad)
PatchInternals * patch_internals_
Holds shared internals data with GeneriAssembly.
std::shared_ptr< BulkIntegralAcc< dim > > create_bulk_integral(Quadrature *quad)
Quadrature * quad_low_
Quadrature used in assembling methods (dim-1).
Quadrature * quad_
Quadrature used in assembling methods.
std::shared_ptr< BoundaryIntegralAcc< dim > > create_boundary_integral(Quadrature *quad)
Point accessor allow iterate over quadrature points of given side defined in local element coordinate...
ElementAccessor< 3 > element_accessor()
Base point accessor class.
Cell accessor allow iterate over DOF handler cells.
unsigned int n_dofs() const
Return number of dofs on given cell.
RangeConvert< DHNeighbSide, DHCellSide > neighb_sides() const
Returns range of neighbour cell of lower dimension corresponding to cell of higher dimension.
bool is_own() const
Return true if accessor represents own element (false for ghost element)
LocDofVec get_loc_dof_indices() const
Returns the local indices of dofs associated to the cell on the local process.
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...
unsigned int dim() const
Return dimension of element appropriate to cell.
unsigned int elm_idx() const
Return serial idx to element of loc_ele_idx_.
ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
unsigned int local_idx() const
Return local index to element (index of DOF handler).
Side accessor allows to iterate over sides of DOF handler cell.
unsigned int elem_idx() const
Side side() const
Return Side of given cell and side_idx.
Boundary cond() const
const DHCellAccessor & cell() const
Return DHCellAccessor appropriate to the side.
unsigned int dim() const
Return dimension of element appropriate to the side.
double measure() const
unsigned int side_idx() const
unsigned int n_sides() const
Returns number of sides aligned with the edge.
Definition: accessors.hh:329
double measure() const
Computes the measure of the element.
SideIter side(const unsigned int loc_index)
unsigned int idx() const
We need this method after replacing Region by RegionIdx, and movinf RegionDB instance into particular...
Definition: accessors.hh:215
unsigned int dim() const
Definition: accessors.hh:188
const Element * element() const
Definition: accessors.hh:193
Neighbour ** neigh_vb
Definition: elements.h:83
unsigned int n_neighs_vb() const
Return number of neighbours.
Definition: elements.h:65
unsigned int n_sides() const
Definition: elements.h:131
Compound finite element on dim dimensional simplex.
Definition: fe_system.hh:102
std::vector< unsigned int > fe_dofs(unsigned int fe_index)
Return dof indices belonging to given sub-FE.
Definition: fe_system.cc:267
Container for various descendants of FieldCommonBase.
Definition: field_set.hh:161
Generic class of assemblation.
void set_solution(uint loc_dof, double solution, double diag=0.0)
Set the position and value of known solution. E.g. Dirichlet boundary condition.
Definition: local_system.cc:82
void eliminate_solution()
LocDofVec row_dofs
Definition: local_system.hh:54
double time_term_rhs_
Variables used in compute time term (unsteady)
void asm_sides(BulkPoint &p, double conductivity, unsigned int element_patch_idx)
Part of cell_integral method, common in all descendants.
unsigned int n_dofs_
Number of DOFs of fe_rt component.
arma::vec load_local_system(const DHCellAccessor &dh_cell)
unsigned int edge_row_
Helper indices in boundary assembly.
LocalSystem loc_schur_
void begin_mh_matrix()
Common code of begin method of MH matrix assembly (Darcy and Richards)
void end_reconstruct_schur()
Common code of end method of Reconstruct Schur assembly (Darcy and Richards)
void begin_reconstruct_schur()
Common code of begin method of Reconstruct Schur assembly (Darcy and Richards)
virtual ~MHMatrixAssemblyLMH()
Destructor.
FieldSet used_fields_
Sub field set contains fields used in calculation.
TEqData::EqFields EqFields
void set_dofs()
Precompute loc_system and loc_schur data members.
unsigned int bulk_local_idx_
Local idx of bulk element.
void begin() override
Implements AssemblyBase::begin.
ElQ< Vector > normal_join_
void postprocess_velocity_darcy(const DHCellAccessor &dh_cell, BulkPoint &p, arma::vec &solution)
Postprocess velocity during loading of local system and after calculating of cell integral.
void initialize()
Initialize auxiliary vectors and other data members.
arma::vec reconstructed_solution_
Vector for reconstructed solution (velocity and pressure on element) from Schur complement.
static constexpr const char * name()
void set_loc_schur(const DHCellAccessor dh_cr_cell)
Precompute loc_schur data member of given cell.
double cross_section_
Precomputed cross-section value.
EqFields * eq_fields_
Data objects shared with DarcyFlow.
void boundary_side_integral_in(DHCellSide cell_side, const ElementAccessor< 3 > &b_ele, BulkPoint &p_bdr)
QGauss quad_rt_
Assembly volume integrals.
void asm_element()
Part of cell_integral method, common in all descendants.
DarcyLMH::EqFields::BC_Type type_
Type of boundary condition.
void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
double source_term_
Variables used in compute lumped source.
void end() override
Implements AssemblyBase::end.
std::shared_ptr< CouplingIntegralAcc< dim > > coupling_integral_
Coupling integral of assembly class.
void asm_source_term_darcy(const DHCellAccessor &cell, BulkPoint &p)
Part of cell_integral method, specialized in Darcy equation.
arma::vec3 nv_
Normal vector.
void dimjoin_intergral(DHCellAccessor cell_lower_dim, DHCellSide neighb_side)
void boundary_side_integral(DHCellSide cell_side)
DECLARE_EXCEPTION(ExcBCNotSupported,<< "BC type not supported.\n")
double ngh_value_
Precomputed ngh value.
MHMatrixAssemblyLMH(EqData *eq_data, PatchInternals *patch_internals)
Constructor.
unsigned int ngh_idx(DHCellAccessor &dh_cell, DHCellSide &neighb_side)
Temporary method find neighbour index in higher-dim cell.
FeQ< Scalar > JxW_
Following data members represent Element quantities and FE quantities.
void end_mh_matrix()
Common code of end method of MH matrix assembly (Darcy and Richards)
std::shared_ptr< BulkIntegralAcc< dim > > bulk_integral_
Bulk integral of assembly class.
void use_dirichlet_switch(DHCellSide &cell_side, const ElementAccessor< 3 > &b_ele, BulkPoint &p_bdr)
Update BC switch dirichlet in MH matrix assembly if BC type is seepage.
std::shared_ptr< BoundaryIntegralAcc< dim > > bdr_integral_
Boundary integral of assembly class.
FeQArray< Vector > velocity_
void precompute_boundary_side(DHCellSide &cell_side, BoundaryPoint &p_side, BulkPoint &p_bdr)
Precompute values used in boundary side integral on given DHCellSide.
void postprocess_velocity(const DHCellAccessor &dh_cell, BulkPoint &p)
std::shared_ptr< BulkIntegralAcc< dim > > asm_sides_integral_
Bulk integral defined on quadrature of higher order.
SideIter side() const
Definition: neighbours.h:147
unsigned int n_dofs() const
Returns the number of shape functions.
Symmetric Gauss-Legendre quadrature formulae on simplices.
static constexpr const char * name()
Definition: assembly_lmh.hh:51
void initialize()
Initialize auxiliary vectors and other data members.
Definition: assembly_lmh.hh:64
virtual ~ReadInitCondAssemblyLMH()
Destructor.
Definition: assembly_lmh.hh:61
FieldSet used_fields_
Sub field set contains fields used in calculation.
Definition: assembly_lmh.hh:98
void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
Assemble integral over element.
Definition: assembly_lmh.hh:68
ReadInitCondAssemblyLMH(EqData *eq_data, PatchInternals *patch_internals)
Constructor.
Definition: assembly_lmh.hh:54
std::shared_ptr< BulkIntegralAcc< dim > > bulk_integral_
Bulk integral of assembly class.
LocDofVec l_indices_
Vector of pre-computed local DOF indices.
EqFields * eq_fields_
Data objects shared with Flow equation.
void end() override
Implements AssemblyBase::end.
Definition: assembly_lmh.hh:86
TEqData::EqFields EqFields
Definition: assembly_lmh.hh:48
ReconstructSchurAssemblyLMH(EqData *eq_data, PatchInternals *patch_internals)
Constructor.
void dimjoin_intergral(FMT_UNUSED DHCellAccessor cell_lower_dim, FMT_UNUSED DHCellSide neighb_side)
static constexpr const char * name()
void begin() override
Implements AssemblyBase::begin.
void boundary_side_integral(FMT_UNUSED DHCellSide cell_side)
Assembles between boundary element and corresponding side on bulk element.
void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
Integral over element.
void end() override
Implements AssemblyBase::end.
TEqData::EqFields EqFields
Boundary cond() const
Edge edge() const
Returns pointer to the edge connected to the side.
Lumped mixed-hybrid model of linear Darcy flow, possibly unsteady.
Definitions of basic Lagrangean finite elements with polynomial shape functions.
Definitions of Raviart-Thomas finite elements.
Class FESystem for compound finite elements.
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
arma::Col< IntIdx > LocDofVec
Definition: index_types.hh:28
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
unsigned int uint
unsigned int IntDim
A dimension index type.
Definition: mixed.hh:19
ArmaVec< double, N > vec
Definition: armor.hh:933
Store finite element reinit functions.
#define FMT_UNUSED
Definition: posix.h:75
Definitions of particular quadrature rules on simplices.
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
Definition: mixed.hh:25
Holds common data shared between GenericAssemblz and Assembly<dim> classes.
PatchFEValues< 3 > fe_values_
Common FEValues object over all dimensions.