Flow123d  release_2.2.0-41-g0958a8d
richards_lmh.cc
Go to the documentation of this file.
1 /*
2  * richards_lmh.cc
3  *
4  * Created on: Sep 16, 2015
5  * Author: jb
6  */
7 
8 
9 #include "system/global_defs.h"
10 #include "system/sys_profiler.hh"
11 
12 
13 #include "input/input_type.hh"
14 #include "input/factory.hh"
15 #include "flow/richards_lmh.hh"
17 #include "tools/time_governor.hh"
18 
19 #include "petscmat.h"
20 #include "petscviewer.h"
21 #include "petscerror.h"
22 #include <armadillo>
23 
24 #include "la/schur.hh"
25 
26 #include "coupling/balance.hh"
27 
28 #include "fields/vec_seq_double.hh"
29 
30 // in the third_party/FADBAD++ dir, namespace "fadbad"
31 #include "fadbad.h"
32 #include "badiff.h"
33 #include "fadiff.h"
34 
35 #include "flow/assembly_lmh.hh"
36 
37 
38 FLOW123D_FORCE_LINK_IN_CHILD(richards_lmh);
39 
40 
41 namespace it=Input::Type;
42 
43 
45 {
46  string desc;
47 
48  desc = R"(
49 Saturated water content (($ \theta_s $)).
50 Relative volume of water in a reference volume of a saturated porous media.
51 )" ;
52  ADD_FIELD(water_content_saturated, desc, "0.0");
54 
55  desc = R"(
56 Residual water content (($ \theta_r $)).
57 Relative volume of water in a reference volume of an ideally dry porous media.
58 )";
59  ADD_FIELD(water_content_residual, desc, "0.0");
61 
62  desc = R"(
63 The van Genuchten pressure head scaling parameter (($ \alpha $)).
64 Related to the inverse of the air entry pressure, i.e. the pressure where the relative water content starts to decrease below 1.
65 )";
66  ADD_FIELD(genuchten_p_head_scale, desc, "0.0");
68 
70  "The van Genuchten exponent parameter (($ n $)).", "2.0");
72 
73 }
74 
75 
77  it::Record field_descriptor = it::Record("RichardsLMH_Data",FieldCommon::field_descriptor_record_description("RichardsLMH_Data"))
79  .copy_keys( RichardsLMH::EqData().make_field_descriptor_type("RichardsLMH_Data_aux") )
80  .close();
81 
82  auto model_selection = it::Selection("Soil_Model_Type", "")
83  .add_value(SoilModelBase::van_genuchten, "van_genuchten", "Van Genuchten soil model with cutting near zero.")
84  .add_value(SoilModelBase::irmay, "irmay", "Irmay model for conductivity, Van Genuchten model for the water content. Suitable for bentonite.")
85  .close();
86 
87  auto soil_rec = it::Record("SoilModel", "Soil model settings.")
88  .allow_auto_conversion("model_type")
89  .declare_key("model_type", model_selection, it::Default("\"van_genuchten\""),
90  "Selection of the globally applied soil model. In future we replace this key by a field for selection of the model."
91  "That will allow usage of different soil model in a single simulation.")
92  .declare_key("cut_fraction", it::Double(0.0,1.0), it::Default("0.999"),
93  "Fraction of the water content where we cut and rescale the curve.")
94  .close();
95 
96  return it::Record("Flow_Richards_LMH", "Lumped Mixed-Hybrid solver for unsteady unsaturated Darcy flow.")
99  .declare_key("input_fields", it::Array( field_descriptor ), it::Default::obligatory(),
100  "Input data for Darcy flow model.")
101  .declare_key("soil_model", soil_rec, it::Default("\"van_genuchten\""),
102  "Soil model settings.")
103  .close();
104 }
105 
106 
107 const int RichardsLMH::registrar =
108  Input::register_class< RichardsLMH, Mesh &, const Input::Record >("Flow_Richards_LMH") +
110 
111 
112 
114  : DarcyMH(mesh_in, in_rec)
115 {
116  data_ = make_shared<EqData>();
119  //data_->edge_new_local_4_mesh_idx_ = &(this->edge_new_local_4_mesh_idx_);
120 }
121 
123 
124  auto model_rec = input_record_.val<Input::Record>("soil_model");
125  auto model_type = model_rec.val<SoilModelBase::SoilModelType>("model_type");
126  double fraction= model_rec.val<double>("cut_fraction");
127  if (model_type == SoilModelBase::van_genuchten)
128  data_->soil_model_ = std::make_shared<SoilModel_VanGenuchten>(fraction);
129  else if (model_type == SoilModelBase::irmay)
130  data_->soil_model_ = std::make_shared<SoilModel_Irmay>(fraction);
131  else
132  ASSERT(false);
133 
134  // create edge vectors
135  unsigned int n_local_edges = mh_dh.edge_new_local_4_mesh_idx_.size();
136  unsigned int n_local_sides = mh_dh.side_ds->lsize();
137  data_->phead_edge_.resize( n_local_edges);
138  data_->water_content_previous_it.resize(n_local_sides);
139  data_->water_content_previous_time.resize(n_local_sides);
140  data_->capacity.resize(n_local_sides);
141 
142  Distribution ds_split_edges(n_local_edges, PETSC_COMM_WORLD);
143  vector<int> local_edge_rows(n_local_edges);
144 
145  IS is_loc;
146  for(auto item : mh_dh.edge_new_local_4_mesh_idx_) {
147  local_edge_rows[item.second]=mh_dh.row_4_edge[item.first];
148  }
149  ISCreateGeneral(PETSC_COMM_SELF, local_edge_rows.size(),
150  &(local_edge_rows[0]), PETSC_COPY_VALUES, &(is_loc));
151 
152  VecScatterCreate(schur0->get_solution(), is_loc,
153  data_->phead_edge_.petsc_vec(), PETSC_NULL, &solution_2_edge_scatter_);
154  ISDestroy(&is_loc);
155 
156 }
157 
158 
160 {
161 
162 }
163 
164 
166 {
167  // apply initial condition
168  // cycle over local element rows
169  double init_value;
170 
171  for (unsigned int i_loc_el = 0; i_loc_el < mh_dh.el_ds->lsize(); i_loc_el++) {
172  auto ele_ac = mh_dh.accessor(i_loc_el);
173 
174  init_value = data_->init_pressure.value(ele_ac.centre(), ele_ac.element_accessor());
175 
176  FOR_ELEMENT_SIDES(ele_ac.full_iter(),i) {
177  int edge_row = ele_ac.edge_row(i);
178  uint n_sides_of_edge = ele_ac.full_iter()->side(i)->edge()->n_sides;
179  VecSetValue(schur0->get_solution(),edge_row, init_value/n_sides_of_edge, ADD_VALUES);
180  }
181  VecSetValue(schur0->get_solution(),ele_ac.ele_row(), init_value,ADD_VALUES);
182  }
183  VecAssemblyBegin(schur0->get_solution());
184  VecAssemblyEnd(schur0->get_solution());
185 
186  // set water_content
187  // pretty ugly since postprocess change fluxes, which cause bad balance, so we must set them back
188  VecCopy(schur0->get_solution(), previous_solution); // store solution vector
189  postprocess();
190  VecSwap(schur0->get_solution(), previous_solution); // restore solution vector
191 
192  //DebugOut() << "init sol:\n";
193  //VecView( schur0->get_solution(), PETSC_VIEWER_STDOUT_WORLD);
194  //DebugOut() << "init water content:\n";
195  //VecView( data_->water_content_previous_it.petsc_vec(), PETSC_VIEWER_STDOUT_WORLD);
196 
198 }
199 
200 
202 {
204  data_->water_content_previous_time.copy(data_->water_content_previous_it);
205  //VecCopy(schur0->get_solution(), previous_solution);
206 }
207 
208 bool RichardsLMH::zero_time_term(bool time_global) {
209  if (time_global) {
210  return (data_->storativity.input_list_size() == 0)
211  && (data_->water_content_saturated.input_list_size() == 0);
212 
213  } else {
214  return (data_->storativity.field_result(mesh_->region_db().get_region_set("BULK"))
215  == result_zeros)
216  && (data_->water_content_saturated.field_result(mesh_->region_db().get_region_set("BULK"))
217  == result_zeros);
218  }
219 }
220 
221 
223 {
224 
225  START_TIMER("RicharsLMH::assembly_linear_system");
226 
227  VecScatterBegin(solution_2_edge_scatter_, schur0->get_solution(), data_->phead_edge_.petsc_vec() , INSERT_VALUES, SCATTER_FORWARD);
228  VecScatterEnd(solution_2_edge_scatter_, schur0->get_solution(), data_->phead_edge_.petsc_vec() , INSERT_VALUES, SCATTER_FORWARD);
229 
230  is_linear_ = data_->genuchten_p_head_scale.field_result(mesh_->region_db().get_region_set("BULK")) == result_zeros;
231 
232  bool is_steady = zero_time_term();
233  //DebugOut() << "Assembly linear system\n";
234  START_TIMER("full assembly");
235  if (typeid(*schur0) != typeid(LinSys_BDDC)) {
236  schur0->start_add_assembly(); // finish allocation and create matrix
237  }
238  data_->time_step_ = time_->dt();
239  auto multidim_assembler = AssemblyBase::create< AssemblyLMH >(data_);
240 
241 
244 
245  balance_->start_source_assembly(water_balance_idx_);
246  balance_->start_mass_assembly(water_balance_idx_);
247 
248  assembly_mh_matrix( multidim_assembler ); // fill matrix
249 
250  balance_->finish_source_assembly(water_balance_idx_);
251  balance_->finish_mass_assembly(water_balance_idx_);
252  //MatView( *const_cast<Mat*>(schur0->get_matrix()), PETSC_VIEWER_STDOUT_WORLD );
253  //VecView( *const_cast<Vec*>(schur0->get_rhs()), PETSC_VIEWER_STDOUT_WORLD);
254 
257 
258 
259  if (! is_steady) {
260  START_TIMER("fix time term");
261  //DebugOut() << "setup time term\n";
262  // assembly time term and rhs
264  }
265 }
266 
267 
268 
270 {
271  FEAL_ASSERT(false).error("Shold not be called.");
272 }
273 
274 
275 
276 
277 
279 
280  // update structures for balance of water volume
282 
283 
284 
285  int side_rows[4];
286  double values[4];
287 
288 
289  VecScatterBegin(solution_2_edge_scatter_, schur0->get_solution(), data_->phead_edge_.petsc_vec() , INSERT_VALUES, SCATTER_FORWARD);
290  VecScatterEnd(solution_2_edge_scatter_, schur0->get_solution(), data_->phead_edge_.petsc_vec() , INSERT_VALUES, SCATTER_FORWARD);
291 
292 
293  // modify side fluxes in parallel
294  // for every local edge take time term on digonal and add it to the corresponding flux
295  //PetscScalar *loc_prev_sol;
296  auto multidim_assembler = AssemblyBase::create< AssemblyLMH >(data_);
297 
298  //VecGetArray(previous_solution, &loc_prev_sol);
299  for (unsigned int i_loc = 0; i_loc < mh_dh.el_ds->lsize(); i_loc++) {
300  auto ele_ac = mh_dh.accessor(i_loc);
301  multidim_assembler[ele_ac.dim()-1]->update_water_content(ele_ac);
302 
303  double ele_scale = ele_ac.measure() *
304  data_->cross_section.value(ele_ac.centre(), ele_ac.element_accessor()) / ele_ac.n_sides();
305  double ele_source = data_->water_source_density.value(ele_ac.centre(), ele_ac.element_accessor());
306  //double storativity = data_->storativity.value(ele_ac.centre(), ele_ac.element_accessor());
307 
308  FOR_ELEMENT_SIDES(ele_ac.full_iter(),i) {
309  //unsigned int loc_edge_row = ele_ac.edge_local_row(i);
310  side_rows[i] = ele_ac.side_row(i);
311  double water_content = data_->water_content_previous_it[ele_ac.side_local_idx(i)];
312  double water_content_previous_time = data_->water_content_previous_time[ele_ac.side_local_idx(i)];
313 
314  values[i] = ele_scale * ele_source - ele_scale * (water_content - water_content_previous_time) / time_->dt();
315  }
316  VecSetValues(schur0->get_solution(), ele_ac.n_sides(), side_rows, values, ADD_VALUES);
317  }
318 
319 
320  VecAssemblyBegin(schur0->get_solution());
321  //VecRestoreArray(previous_solution, &loc_prev_sol);
322  VecAssemblyEnd(schur0->get_solution());
323 
324 }
void initialize_specific() override
FieldSet * eq_data_
Definition: equation.hh:232
Distribution * side_ds
Output class for darcy_flow_mh model.
void assembly_mh_matrix(MultidimAssembler ma)
unsigned int uint
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:598
int is_linear_
void postprocess() override
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
virtual void start_add_assembly()
Definition: linsys.hh:297
virtual PetscErrorCode mat_zero_entries()
Definition: linsys.hh:239
bool zero_time_term(bool time_global=false) override
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:328
Definition: mesh.h:97
static const Input::Type::Record & type_field_descriptor()
Distribution * el_ds
#define FOR_ELEMENT_SIDES(i, j)
Definition: elements.h:188
virtual void finish_assembly()=0
const RegionDB & region_db() const
Definition: mesh.h:155
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
static const std::string field_descriptor_record_description(const string &record_name)
Definition: field_common.cc:68
#define ADD_FIELD(name,...)
Definition: field_set.hh:269
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
bool solution_changed_for_scatter
std::shared_ptr< EqData > data_
FLOW123D_FORCE_LINK_IN_CHILD(richards_lmh)
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
Basic time management class.
Class for declaration of inputs sequences.
Definition: type_base.hh:345
std::unordered_map< unsigned int, unsigned int > edge_new_local_4_mesh_idx_
void prepare_new_time_step() override
postprocess velocity field (add sources)
Assembly explicit Schur complement for the given linear system. Provides method for resolution of the...
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
VecScatter solution_2_edge_scatter_
PETSC scatter from the solution vector to the parallel edge vector with ghost values.
Global macros to enhance readability and debugging, general constants.
virtual Record & allow_auto_conversion(const string &from_key)
Allows shorter input of the Record providing only value of the from_key given as the parameter...
Definition: type_record.cc:132
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:540
void setup_time_term() override
std::shared_ptr< Balance > balance_
const Vec & get_solution()
Definition: linsys.hh:257
Field< 3, FieldValue< 3 >::Scalar > water_content_saturated
Definition: richards_lmh.hh:57
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
#define START_TIMER(tag)
Starts a timer with specified tag.
Mesh * mesh_
Definition: equation.hh:223
Selection & add_value(const int value, const std::string &key, const std::string &description="", TypeBase::attribute_map attributes=TypeBase::attribute_map())
Adds one new value with name given by key to the Selection.
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:490
static Input::Type::Abstract & get_input_type()
LinSys * schur0
virtual PetscErrorCode rhs_zero_entries()
Definition: linsys.hh:248
std::shared_ptr< EqData > data_
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:215
Field< 3, FieldValue< 3 >::Scalar > genuchten_p_head_scale
Definition: richards_lmh.hh:59
MH_DofHandler mh_dh
Field< 3, FieldValue< 3 >::Scalar > water_content_residual
Definition: richards_lmh.hh:58
const Selection & close() const
Close the Selection, no more values can be added.
Input::Record input_record_
Definition: equation.hh:225
static const Input::Type::Record & get_input_type()
Definition: richards_lmh.cc:76
double dt() const
LocalElementAccessorBase< 3 > accessor(uint local_ele_idx)
unsigned int water_balance_idx_
index of water balance within the Balance object.
Field< 3, FieldValue< 3 >::Scalar > genuchten_n_exponent
Definition: richards_lmh.hh:60
void read_initial_condition() override
void assembly_linear_system() override
void set_matrix_changed()
Definition: linsys.hh:187
Record type proxy class.
Definition: type_record.hh:182
static const int registrar
Registrar of class to factory.
Definition: richards_lmh.hh:85
Class for representation SI units of Fields.
Definition: unit_si.hh:40
RichardsLMH(Mesh &mesh, const Input::Record in_rec)
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
Vec previous_solution
Template for classes storing finite set of named values.
Input::Type::Record make_field_descriptor_type(const std::string &equation_name) const
Definition: field_set.cc:61
static const Input::Type::Record & get_input_type()
TimeGovernor * time_
Definition: equation.hh:224
void assembly_source_term() override
Source term is implemented differently in LMH version.
#define FEAL_ASSERT(expr)
Definition of assert for debug and release mode.
Definition: asserts.hh:279
Mixed-hybrid of steady Darcy flow with sources and variable density.
unsigned int lsize(int proc) const
get local size