Flow123d
darcy_flow_mh.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id$
21  * $Revision$
22  * $LastChangedBy$
23  * $LastChangedDate$
24  *
25  * @file
26  * @brief mixed-hybrid model of linear Darcy flow, possibly unsteady.
27  *
28  * Main object for mixed-hybrid discretization of the linear elliptic PDE (Laplace)
29  * on a multidimensional domain. Discretization of saturated Darcy flow using
30  * RT0 approximation for the velocity
31  *
32  *
33  *
34  * @author Jan Brezina
35  *
36  */
37 
38 /*
39  * list of files dependent on this one:
40  *
41  * posprocess.cc
42  * problem.cc
43  * main.hh
44  * transport.cc
45  */
46 
47 
48 #ifndef DARCY_FLOW_MH_HH
49 #define DARCY_FLOW_MH_HH
50 
51 #include <memory>
52 #include "input/input_type.hh"
53 
54 #include <petscmat.h>
55 #include "system/sys_vector.hh"
56 #include "coupling/equation.hh"
57 #include "flow/mh_dofhandler.hh"
58 #include "input/input_type.hh"
59 #include "la/linsys_BDDC.hh"
60 #include "la/linsys_PETSC.hh"
61 
62 #include "fields/field.hh"
63 #include "fields/field_set.hh"
65 #include "flow/old_bcd.hh"
66 
67 
68 /// external types:
69 class LinSys;
70 struct Solver;
71 class Mesh;
72 class SchurComplement;
73 class Distribution;
74 class SparseGraph;
75 class LocalToGlobalMap;
76 class DarcyFlowMHOutput;
77 
78 
79 /**
80  * @brief Mixed-hybrid model of linear Darcy flow, possibly unsteady.
81  *
82  * Abstract class for various implementations of Darcy flow. In future there should be
83  * one further level of abstraction for general time dependent problem.
84  *
85  * maybe TODO:
86  * split compute_one_step to :
87  * 1) prepare_next_timestep
88  * 2) actualize_solution - this is for iterative nonlinear solvers
89  *
90  */
91 
92 class DarcyFlowMH : public EquationBase {
93 public:
94  enum MortarMethod {
95  NoMortar = 0,
96  MortarP0 = 1,
98  };
99 
100  /** @brief Data for Darcy flow equation.
101  *
102  */
103  class EqData : public FieldSet {
104  public:
105 
106  /**
107  * For compatibility with old BCD file we have to assign integer codes starting from 1.
108  */
109  enum BC_Type {
110  none=0,
113  robin=3,
115  };
117 
118  /// Collect all fields
119  EqData();
120 
121 
122  /**
123  * Hook for processing "bc_piezo_head" key.
124  */
125  inline static std::shared_ptr< FieldBase<3, FieldValue<3>::Scalar> >
127  {
128  auto field_ptr = OldBcdInput::flow_pressure_hook(rec, field);
129  Input::AbstractRecord field_a_rec;
130  if (! field_ptr && rec.opt_val("bc_piezo_head", field_a_rec)) {
131  return std::make_shared< FieldAddPotential<3, FieldValue<3>::Scalar > >( gravity_, field_a_rec);
132  } else {
133  return field_ptr;
134  }
135  }
136 
142 
143  BCField<3, FieldValue<3>::Enum > bc_type; // Discrete need Selection for initialization
147 
148  //TODO: these belong to Unsteady flow classes
149  //as long as Unsteady is descendant from Steady, these cannot be transfered..
152 
153  /**
154  * Gravity vector and constant shift of pressure potential. Used to convert piezometric head
155  * to pressure head and vice versa.
156  *
157  * TODO: static method bc_piezo_head_hook needs static @p gravity_ vector. Other solution is to
158  * introduce some kind of context pointer into @p FieldCommonBase.
159  */
160  static arma::vec4 gravity_;
161 
165  };
166 
167 
168  /**
169  * Model for transition coefficients due to Martin, Jaffre, Roberts (see manual for full reference)
170  *
171  * TODO:
172  * - how we can reuse values computed during assembly
173  * we want to make this class see values in
174  *
175  */
177  : EquationBase(mesh, in_rec)
178  {}
179 
185 
186  void get_velocity_seq_vector(Vec &velocity_vec)
187  { velocity_vec = velocity_vector; }
188 
190  double *array;
191  unsigned int size;
192  get_solution_vector(array, size);
193 
194  // here assume that velocity field is extended as constant
195  // to the previous time, so here we set left bound of the interval where the velocity
196  // has current value; this may not be good for every transport !!
197  // we can resolve this when we use FieldFE to store computed velocities in few last steps and
198  // let every equation set time according to nature of the time scheme
199 
200  // in particular this setting is necessary to prevent ConvectinTransport to recreate the transport matrix
201  // every timestep ( this may happen for unsteady flow if we would use time->t() here since it returns infinity.
203  return mh_dh;
204  }
205 
206  virtual void get_partitioning_vector(int * &elem_part, unsigned &lelem_part){};
207 
208  virtual void set_concentration_vector(Vec &vc){};
209 
210 
211 protected:
213  double *velocity_array;
214  unsigned int size;
215 
216  get_solution_vector(velocity_array, size);
217  VecCreateSeqWithArray(PETSC_COMM_SELF, 1, mesh_->n_sides(), velocity_array, &velocity_vector);
218 
219  }
220 
221  //virtual void postprocess() =0;
222 
223  virtual double solution_precision() const = 0;
224 
225  //virtual void balance();
226  //virtual void integrate_sources();
227 
228 
231  MH_DofHandler mh_dh; // provides access to seq. solution fluxes and pressures on sides
232 
234 };
235 
236 
237 /**
238  * @brief Mixed-hybrid of steady Darcy flow with sources and variable density.
239  *
240  * solve equations:
241  * @f[
242  * q= -{\mathbf{K}} \nabla h -{\mathbf{K}} R \nabla z
243  * @f]
244  * @f[
245  * \mathrm{div} q = f
246  * @f]
247  *
248  * where
249  * - @f$ q @f$ is flux @f$[ms^{-1}]@f$ for 3d, @f$[m^2s^{-1}]@f$ for 2d and @f$[m^3s^{-1}]@f$ for 1d.
250  * - @f$ \mathbf{K} @f$ is hydraulic tensor ( its orientation for 2d, 1d case is questionable )
251  * - @f$ h = \frac{\pi}{\rho_0 g}+z @f$ is pressure head, @f$ \pi, \rho_0, g @f$ are the pressure, water density, and acceleration of gravity , respectively.
252  * Assumes gravity force acts counter to the direction of the @f$ z @f$ axis.
253  * - @f$ R @f$ is destity or gravity variability coefficient. For density driven flow it should be
254  * @f[
255  * R = \frac{\rho}{\rho_0} -1 = \rho_0^{-1}\sum_{i=1}^s c_i
256  * @f]
257  * where @f$ c_i @f$ is concentration in @f$ kg m^{-3} @f$.
258  *
259  *
260  * TODO:
261  * - consider create auxiliary classes for creation of inverse of block A
262  */
264 {
265 public:
266 
267  class EqData : public DarcyFlowMH::EqData {
268  public:
269 
271  {}
272  };
273 
274  DarcyFlowMH_Steady(Mesh &mesh, const Input::Record in_rec, bool make_tg=true);
275 
277 
278  virtual void update_solution();
279  virtual void get_solution_vector(double * &vec, unsigned int &vec_size);
280  virtual void get_parallel_solution_vector(Vec &vector);
281  void get_partitioning_vector(int * &elem_part, unsigned &lelem_part);
282 
283  /// postprocess velocity field (add sources)
284  virtual void postprocess();
285  virtual void output_data() override;
286 
288 
289 
290 protected:
291  void make_serial_scatter();
292  virtual void modify_system()
293  { ASSERT(0, "Modify system called for Steady darcy.\n"); };
294  virtual void setup_time_term()
295  { ASSERT(0, "Setup time term called for Steady darcy.\n"); };
296 
297 
298  //void set_R() {};
299  void prepare_parallel( const Input::AbstractRecord in_rec);
300  void make_row_numberings();
301 
302  /**
303  * Create and preallocate MH linear system (including matrix, rhs and solution vectors)
304  */
305  void create_linear_system();
306 
307  /**
308  * Read initial condition into solution vector.
309  * Must be called after create_linear_system.
310  *
311  */
312  virtual void read_init_condition() {};
313 
314  /**
315  * Abstract assembly method used for both assembly and preallocation.
316  * Assembly only steady part of the equation.
317  * TODO:
318  * - use general preallocation methods in DofHandler
319  * - include alos time term
320  * - add support for Robin type sources
321  * - support for nonlinear solvers - assembly either residual vector, matrix, or both (using FADBAD++)
322  *
323  */
325 
326  /**
327  * Assembly or update whole linear system.
328  */
329  void assembly_linear_system();
330 
331  void set_mesh_data_for_bddc(LinSys_BDDC * bddc_ls);
332  double solution_precision() const;
333 
334 
336 
337  int size; // global size of MH matrix
338  int n_schur_compls; // number of shur complements to make
339  double *solution; // sequantial scattered solution vector
340 
341 
342  LinSys *schur0; //< whole MH Linear System
343  //LinSys_PETSC *schur1; //< first schur compl.
344  //LinSys_PETSC *schur2; //< second ..
345 
346 
347  // parallel
348  Distribution *edge_ds; //< optimal distribution of edges
349  Distribution *el_ds; //< optimal distribution of elements
350  Distribution *side_ds; //< optimal distribution of elements
351  boost::shared_ptr<Distribution> rows_ds; //< final distribution of rows of MH matrix
352 
353  int *el_4_loc; //< array of idexes of local elements (in ordering matching the optimal global)
354  int *row_4_el; //< element index to matrix row
355  int *side_id_4_loc; //< array of ids of local sides
356  int *side_row_4_id; //< side id to matrix row
357  int *edge_4_loc; //< array of indexes of local edges
358  int *row_4_edge; //< edge index to matrix row
359 
360  // MATIS related arrays
361  std::vector<double> solution_; //< sequantial scattered solution vector
362  std::vector<unsigned> solver_indices_; //< renumbering of unknowns in the global vector
363  boost::shared_ptr<LocalToGlobalMap> global_row_4_sub_row; //< global dof index for subdomain index
364 
365  // gather of the solution
366  Vec sol_vec; //< vector over solution array
367  VecScatter par_to_all;
368 
370 
371  friend class DarcyFlowMHOutput;
372  friend class P0_CouplingAssembler;
373  friend class P1_CouplingAssembler;
374 };
375 
376 
378 public:
380  : darcy_(darcy),
381  master_list_(darcy.mesh_->master_elements),
382  intersections_(darcy.mesh_->intersections),
383  master_(nullptr),
384  tensor_average(2)
385  {
386  arma::mat master_map(1,2), slave_map(1,3);
387  master_map.fill(1.0 / 2);
388  slave_map.fill(1.0 / 3);
389 
390  tensor_average[0].push_back( trans( master_map ) * master_map );
391  tensor_average[0].push_back( trans( master_map ) * slave_map );
392  tensor_average[1].push_back( trans( slave_map ) * master_map );
393  tensor_average[1].push_back( trans( slave_map ) * slave_map );
394  }
395 
396  void assembly(LinSys &ls);
397  void pressure_diff(int i_ele,
398  vector<int> &dofs,
399  unsigned int &ele_type,
400  double &delta,
401  arma::vec &dirichlet);
402 private:
404 
406 
409 
411  const Element *master_;
412 
413  /// Row matrices to compute element pressure as average of boundary pressures
415  /// measure of master element, should be sum of intersection measures
416  double delta_0;
417 };
418 
419 
420 
422 public:
424  : darcy_(darcy),
425  intersections_(darcy.mesh_->intersections),
426  rhs(5),
427  dofs(5),
428  dirichlet(5)
429  {
430  rhs.zeros();
431  }
432 
433  void assembly(LinSys &ls);
434  void add_sides(const Element * ele, unsigned int shift, vector<int> &dofs, vector<double> &dirichlet);
435 private:
436 
439 
440  arma::vec rhs;
443 };
444 
445 
446 
447 //void make_element_connection_graph(Mesh *mesh, SparseGraph * &graph,bool neigh_on = false);
448 //void id_maps(int n_ids, int *id_4_old, const Distribution &old_ds,
449 // int *loc_part, Distribution * &new_ds, int * &id_4_loc, int * &new_4_id);
450 void mat_count_off_proc_values(Mat m, Vec v);
451 
452 
453 
454 /**
455  * @brief Mixed-hybrid solution of unsteady Darcy flow.
456  *
457  * Standard discretization with time term and sources picewise constant
458  * on the element. This leads to violation of the discrete maximum principle for
459  * non-acute meshes or to too small timesteps. For simplicial meshes this can be solved by lumping to the edges. See DarcyFlowLMH_Unsteady.
460  */
461 
463 {
464 public:
465 
466  /* TODO: this can be applied when Unstedy is no longer descendant from Steady
467  class EqData : public DarcyFlowMH::EqData{
468  public:
469  EqData();
470 
471  Field<3, FieldValue<3>::Scalar > init_pressure;
472  Field<3, FieldValue<3>::Scalar > storativity;
473  };
474  //*/
475 
478 
479  //returns reference to equation data
480  //virtual DarcyFlowMH::DarcyFlowMH::EqData &get_data()
481  //{return data;}
482 
484 protected:
485  void read_init_condition() override;
486  void modify_system() override;
487  void setup_time_term();
488 
489 private:
494 
495 };
496 
497 /**
498  * @brief Edge lumped mixed-hybrid solution of unsteady Darcy flow.
499  *
500  * The time term and sources are evenly distributed form an element to its edges.
501  * This applies directly to the second Schur complement. After this system for pressure traces is solved we reconstruct pressures and side flows as follows:
502  *
503  * -# Element pressure is average of edge pressure. This is in fact same as the MH for steady case so we let SchurComplement class do its job.
504  *
505  * -# We let SchurComplement to reconstruct fluxes and then account time term and sources which are evenly distributed from an element to its sides.
506  * It can be proved, that this keeps continuity of the fluxes over the edges.
507  *
508  * This lumping technique preserves discrete maximum principle for any time step provided one use acute mesh. But in practice even worse meshes are tractable.
509  */
511 {
512 public:
513 
514  /* TODO: this can be applied when Unstedy is no longer descendant from Steady
515  class EqData : public DarcyFlowMH::EqData{
516  public:
517 
518  EqData();
519 
520  Field<3, FieldValue<3>::Scalar > init_pressure;
521  Field<3, FieldValue<3>::Scalar > storativity;
522  };
523  //*/
524 
527 
529 protected:
530  void read_init_condition() override;
531  void modify_system() override;
532  void setup_time_term();
533  virtual void postprocess();
534 private:
539  //Vec time_term;
540 };
541 
542 #endif //DARCY_FLOW_MH_HH
543 //-----------------------------------------------------------------------------
544 // vim: set cindent:
545