Flow123d  JS_before_hm-887-g601087d
hm_iterative.cc
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 hm_iterative.cc
15  * @brief
16  * @author Jan Stebel
17  */
18 
19 #include "hm_iterative.hh"
20 #include "system/sys_profiler.hh"
21 #include "input/input_type.hh"
22 #include "flow/richards_lmh.hh"
23 #include "fields/field_fe.hh" // for create_field_fe()
24 
25 
26 FLOW123D_FORCE_LINK_IN_CHILD(coupling_iterative)
27 
28 
29 namespace it = Input::Type;
30 
31 
32 const it::Record & HM_Iterative::get_input_type() {
33  return it::Record("Coupling_Iterative",
34  "Record with data for iterative coupling of flow and mechanics.\n")
37  .declare_key("flow_equation", RichardsLMH::get_input_type(),
39  "Flow equation, provides the velocity field as a result.")
40  .declare_key("mechanics_equation", Elasticity::get_input_type(),
41  "Mechanics, provides the displacement field.")
42  .declare_key("input_fields", it::Array(
44  .make_field_descriptor_type("Coupling_Iterative")),
46  "Input fields of the HM coupling.")
47  .declare_key( "iteration_parameter", it::Double(), it::Default("1"),
48  "Tuning parameter for iterative splitting. Its default value"
49  "corresponds to a theoretically optimal value with fastest convergence." )
50  .declare_key( "max_it", it::Integer(0), it::Default("100"),
51  "Maximal count of HM iterations." )
52  .declare_key( "min_it", it::Integer(0), it::Default("1"),
53  "Minimal count of HM iterations." )
54  .declare_key( "a_tol", it::Double(0), it::Default("0"),
55  "Absolute tolerance for difference in HM iteration." )
56  .declare_key( "r_tol", it::Double(0), it::Default("1e-7"),
57  "Relative tolerance for difference in HM iteration." )
58  .close();
59 }
60 
61 
62 const int HM_Iterative::registrar = Input::register_class< HM_Iterative, Mesh &, const Input::Record >("Coupling_Iterative")
64 
65 
67 {
68  *this += alpha.name("biot_alpha")
69  .units(UnitSI().dimensionless())
70  .input_default("0.0")
72 
73  *this += density.name("fluid_density")
74  .units(UnitSI().kg().m(-3))
75  .input_default("0.0")
77 
78  *this += gravity.name("gravity")
79  .units(UnitSI().m().s(-2))
80  .input_default("9.81")
82 
83  *this += beta.name("relaxation_beta")
84  .units(UnitSI().dimensionless())
86 
87  *this += pressure_potential.name("pressure_potential")
88  .units(UnitSI().m())
90 
91  *this += flow_source.name("extra_flow_source")
92  .units(UnitSI().s(-1))
94 }
95 
96 
98 {
99  // initialize coupling fields with FieldFE
100  set_mesh(mesh);
101 
102  potential_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(mesh, MixedPtr<FE_CR>());
103  pressure_potential.set_field(mesh.region_db().get_region_set("ALL"), potential_ptr_);
104 
105  beta_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(mesh, MixedPtr<FE_P_disc>(0));
106  beta.set_field(mesh.region_db().get_region_set("ALL"), beta_ptr_);
107 
108  flow_source_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(beta_ptr_->get_dofhandler());
109  flow_source.set_field(mesh.region_db().get_region_set("ALL"), flow_source_ptr_);
110 
111  old_pressure_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(beta_ptr_->get_dofhandler());
112  old_iter_pressure_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(beta_ptr_->get_dofhandler());
113  div_u_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(beta_ptr_->get_dofhandler());
114  old_div_u_ptr_ = create_field_fe<3, FieldValue<3>::Scalar>(beta_ptr_->get_dofhandler());
115 }
116 
117 
118 
120 : DarcyFlowInterface(mesh, in_record)
121 {
122  START_TIMER("HM constructor");
123  using namespace Input;
124 
125  time_ = new TimeGovernor(in_record.val<Record>("time"));
126  ASSERT( time_->is_default() == false ).error("Missing key 'time' in Coupling_Iterative.");
127 
128  // setup flow equation
129  Record flow_rec = in_record.val<Record>("flow_equation");
130  // Need explicit template types here, since reference is used (automatically passing by value)
131  flow_ = std::make_shared<RichardsLMH>(*mesh_, flow_rec, time_);
132  flow_->initialize();
133  std::stringstream ss; // print warning message with table of uninitialized fields
134  if ( FieldCommon::print_message_table(ss, "flow") )
135  WarningOut() << ss.str();
136 
137  // setup mechanics
138  Record mech_rec = in_record.val<Record>("mechanics_equation");
139  mechanics_ = std::make_shared<Elasticity>(*mesh_, mech_rec, this->time_);
140  mechanics_->data()["cross_section"].copy_from(flow_->data()["cross_section"]);
141  mechanics_->initialize();
142 
143  // read parameters controlling the iteration
144  beta_ = in_record.val<double>("iteration_parameter");
145  min_it_ = in_record.val<unsigned int>("min_it");
146  max_it_ = in_record.val<unsigned int>("max_it");
147  a_tol_ = in_record.val<double>("a_tol");
148  r_tol_ = in_record.val<double>("r_tol");
149 
150  this->eq_data_ = &data_;
151 
152  // setup input fields
153  data_.set_input_list( in_record.val<Input::Array>("input_fields"), time() );
154 
155  data_.initialize(*mesh_);
156  mechanics_->set_potential_load(data_.pressure_potential);
157 }
158 
159 
161 {
162 }
163 
164 
165 template<int dim, class Value>
166 void copy_field(const FieldCommon &from_field_common, FieldFE<dim, Value> &to_field)
167 {
168  auto dh = to_field.get_dofhandler();
169  auto vec = to_field.get_data_vec();
170  Field<dim,Value> from_field;
171  from_field.copy_from(from_field_common);
172 
173  for ( auto cell : dh->own_range() )
174  vec[cell.local_idx()] = from_field.value(cell.elm().centre(), cell.elm());
175 
176 // vec.local_to_ghost_begin();
177 // vec.local_to_ghost_end();
178 }
179 
180 
181 
183 {
185  std::stringstream ss;
186  if ( FieldCommon::print_message_table(ss, "coupling_iterative") )
187  WarningOut() << ss.str();
188 
189  flow_->zero_time_step();
191  mechanics_->zero_time_step();
192 
193  copy_field(*flow_->data().field("pressure_p0"), *data_.old_pressure_ptr_);
194  copy_field(*flow_->data().field("pressure_p0"), *data_.old_iter_pressure_ptr_);
195  copy_field(mechanics_->data().output_divergence, *data_.div_u_ptr_);
196 }
197 
198 
200 {
201  unsigned it = 0;
202  double difference = 0;
203  double norm = 1;
204 
205  time_->next_time();
206  time_->view("HM");
208 
209  while (it < min_it_ ||
210  (it < max_it_ && difference > a_tol_ && difference/norm > r_tol_)
211  )
212  {
213  it++;
214 
215  // pass displacement (divergence) to flow
216  // and solve flow problem
218  flow_->solve_time_step(false);
219 
220  // pass pressure to mechanics and solve mechanics
222  mechanics_->solve_linear_system();
223 
224  // update displacement divergence
225  mechanics_->update_output_fields();
226  copy_field(mechanics_->data().output_divergence, *data_.div_u_ptr_);
227 
228  // TODO: compute difference of iterates
229  compute_iteration_error(difference, norm);
230 
231  MessageOut().fmt("HM Iteration {} abs. difference: {} rel. difference: {}\n"
232  "--------------------------------------------------------",
233  it, difference, difference/norm);
234  copy_field(*flow_->data().field("pressure_p0"), *data_.old_iter_pressure_ptr_);
235  }
236 
237  flow_->accept_time_step();
238  flow_->output_data();
239  mechanics_->output_data();
240 
241  copy_field(*flow_->data().field("pressure_p0"), *data_.old_pressure_ptr_);
242  copy_field(mechanics_->data().output_divergence, *data_.old_div_u_ptr_);
243 }
244 
245 
247 {
248  auto potential_vec_ = data_.potential_ptr_->get_data_vec();
249  auto dh = data_.potential_ptr_->get_dofhandler();
250  Field<3, FieldValue<3>::Scalar> field_edge_pressure;
251  field_edge_pressure.copy_from(*flow_->data().field("pressure_edge"));
252  for ( auto ele : dh->local_range() )
253  {
254  auto elm = ele.elm();
255  LocDofVec dof_indices = ele.get_loc_dof_indices();
256  for ( auto side : ele.side_range() )
257  {
258  double alpha = data_.alpha.value(side.centre(), elm);
259  double density = data_.density.value(side.centre(), elm);
260  double gravity = data_.gravity.value(side.centre(), elm);
261  double pressure = field_edge_pressure.value(side.centre(), elm);
262  double potential = -alpha*density*gravity*pressure;
263 
264  potential_vec_[dof_indices[side.side_idx()]] = potential;
265  }
266  }
267 
269  mechanics_->set_potential_load(data_.pressure_potential);
270 }
271 
272 
274 {
275  auto beta_vec = data_.beta_ptr_->get_data_vec();
276  auto src_vec = data_.flow_source_ptr_->get_data_vec();
277  auto dh = data_.beta_ptr_->get_dofhandler();
278  Field<3,FieldValue<3>::Scalar> field_ele_pressure;
279  field_ele_pressure.copy_from(*flow_->data().field("pressure_p0"));
280  for ( auto ele : dh->local_range() )
281  {
282  auto elm = ele.elm();
283 
284  double alpha = data_.alpha.value(elm.centre(), elm);
285  double young = mechanics_->data().young_modulus.value(elm.centre(), elm);
286  double poisson = mechanics_->data().poisson_ratio.value(elm.centre(), elm);
287  double beta = beta_ * 0.5*alpha*alpha/(2*lame_mu(young, poisson)/elm.dim() + lame_lambda(young, poisson));
288 
289  double old_p = data_.old_pressure_ptr_->value(elm.centre(), elm);
290  double p = field_ele_pressure.value(elm.centre(), elm);
291  double div_u = data_.div_u_ptr_->value(elm.centre(), elm);
292  double old_div_u = data_.old_div_u_ptr_->value(elm.centre(), elm);
293  double src = (beta*(p-old_p) + alpha*(old_div_u - div_u)) / time_->dt();
294 
295  beta_vec[ele.local_idx()] = beta;
296  src_vec[ele.local_idx()] = src;
297  }
298 
301  flow_->set_extra_storativity(data_.beta);
302  flow_->set_extra_source(data_.flow_source);
303 }
304 
305 
306 void HM_Iterative::compute_iteration_error(double& difference, double& norm)
307 {
308  auto dh = data_.beta_ptr_->get_dofhandler();
309  double p_dif2 = 0, p_norm2 = 0;
310  Field<3,FieldValue<3>::Scalar> field_ele_pressure;
311  field_ele_pressure.copy_from(*flow_->data().field("pressure_p0"));
312  for (auto cell : dh->own_range())
313  {
314  auto elm = cell.elm();
315  double new_p = field_ele_pressure.value(elm.centre(), elm);
316  double old_p = data_.old_iter_pressure_ptr_->value(elm.centre(), elm);
317  p_dif2 += pow(new_p - old_p, 2)*elm.measure();
318  p_norm2 += pow(old_p, 2)*elm.measure();
319  }
320 
321  double send_data[] = { p_dif2, p_norm2 };
322  double recv_data[2];
323  MPI_Allreduce(&send_data, &recv_data, 2, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD);
324  difference = sqrt(recv_data[0]);
325  norm = sqrt(recv_data[1]);
326 }
327 
328 
329 
331 {
332  return flow_->last_t();
333 }
334 
335 
337  flow_.reset();
338  mechanics_.reset();
339 }
340 
341 
342 
TimeGovernor & time()
Definition: equation.hh:151
FieldSet * eq_data_
Definition: equation.hh:229
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:75
Accessor to input data conforming to declared Array.
Definition: accessors.hh:567
unsigned int max_it_
Maximal number of iterations.
arma::Col< IntIdx > LocDofVec
Definition: index_types.hh:28
ArmaVec< double, N > vec
Definition: armor.hh:861
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > old_div_u_ptr_
Definition: hm_iterative.hh:69
Class for solution of fully coupled flow and mechanics using fixed-stress iterative splitting...
Definition: hm_iterative.hh:43
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:602
double beta_
Tuning parameter for iterative splitting.
double r_tol_
Relative tolerance for difference between two succeeding iterations.
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
static const int registrar
Definition: hm_iterative.hh:90
FieldCommon & flags_add(FieldFlag::Flags::Mask mask)
#define MessageOut()
Macro defining &#39;message&#39; record of log.
Definition: logger.hh:255
void update_potential()
Abstract linear system class.
Definition: balance.hh:40
VectorMPI get_data_vec() const
Definition: field_fe.hh:146
Class template representing a field with values dependent on: point, element, and region...
Definition: field.hh:92
void initialize(Mesh &mesh)
Definition: hm_iterative.cc:97
void next_time()
Proceed to the next time according to current estimated time step.
static const Input::Type::Record & get_input_type()
Declare input record type for the equation TransportDG.
Definition: elasticity.cc:43
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
#define MPI_SUM
Definition: mpi.h:196
Definition: mesh.h:78
void update_flow_fields()
double lame_mu(double young, double poisson)
Definition: elasticity.cc:128
void zero_time_step() override
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:347
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > potential_ptr_
FieldFE for pressure_potential field.
Definition: hm_iterative.hh:63
const TimeStep & step(int index=-1) const
Class for declaration of the integral input data.
Definition: type_base.hh:490
Basic time management functionality for unsteady (and steady) solvers (class Equation).
double a_tol_
Absolute tolerance for difference between two succeeding iterations.
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
static const Input::Type::Record & get_input_type()
Define input record.
Definition: hm_iterative.cc:32
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Class for declaration of inputs sequences.
Definition: type_base.hh:346
void view(const char *name="") const
static Input::Type::Record & record_template()
Template Record with common keys for derived equations.
Definition: equation.cc:36
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > old_pressure_ptr_
Definition: hm_iterative.hh:66
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > div_u_ptr_
Definition: hm_iterative.hh:68
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:196
void update_solution() override
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:541
static constexpr Mask equation_result
Match result fields. These are never given by input or copy of input.
Definition: field_flag.hh:55
Mesh & mesh()
Definition: equation.hh:179
Field< 3, FieldValue< 3 >::Scalar > pressure_potential
Potential -alpha*pressure whose gradient is passed to mechanics as additional load.
Definition: hm_iterative.hh:59
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > flow_source_ptr_
Definition: hm_iterative.hh:65
FieldCommon & input_default(const string &input_default)
static constexpr Mask equation_external_output
Match an output field, that can be also copy of other field.
Definition: field_flag.hh:58
void set_time_result_changed()
Manually mark flag that the field has been changed.
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
Field< 3, FieldValue< 3 >::Scalar > alpha
Biot coefficient.
Definition: hm_iterative.hh:53
const Ret val(const string &key) const
std::shared_ptr< Elasticity > mechanics_
solute transport with chemistry through operator splitting
Definition: hm_iterative.hh:96
#define START_TIMER(tag)
Starts a timer with specified tag.
Mesh * mesh_
Definition: equation.hh:220
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:431
Field< 3, FieldValue< 3 >::Scalar > gravity
Standard gravity.
Definition: hm_iterative.hh:55
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:503
static Input::Type::Abstract & get_input_type()
static constexpr Mask in_rhs
A field is part of the right hand side of the equation.
Definition: field_flag.hh:51
Field< 3, FieldValue< 3 >::Scalar > flow_source
Definition: hm_iterative.hh:60
void initialize() override
Field< 3, FieldValue< 3 >::Scalar > beta
Definition: hm_iterative.hh:56
#define MPI_DOUBLE
Definition: mpi.h:156
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:216
std::shared_ptr< DOFHandlerMultiDim > get_dofhandler() const
Definition: field_fe.hh:142
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
Definition: mpi.h:612
void set_input_list(Input::Array input_list, const TimeGovernor &tg)
Definition: field_set.hh:193
unsigned int min_it_
Minimal number of iterations to perform.
static const Input::Type::Record & get_input_type()
Definition: richards_lmh.cc:79
double dt() const
void set_field(const RegionSet &domain, FieldBasePtr field, double time=0.0)
Definition: field.impl.hh:229
HM_Iterative(Mesh &mesh, Input::Record in_record)
bool set_time(const TimeStep &time, LimitSide limit_side)
Definition: field_set.cc:157
double lame_lambda(double young, double poisson)
Definition: elasticity.cc:134
void copy_field(const FieldCommon &from_field_common, FieldFE< dim, Value > &to_field)
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:258
FieldCommon & name(const string &name)
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:186
Record type proxy class.
Definition: type_record.hh:182
FieldCommon & flags(FieldFlag::Flags::Mask mask)
void copy_from(const FieldCommon &other) override
Definition: field.impl.hh:347
Class for representation SI units of Fields.
Definition: unit_si.hh:40
std::shared_ptr< RichardsLMH > flow_
steady or unsteady water flow simulator based on MH scheme
Definition: hm_iterative.hh:93
void compute_iteration_error(double &difference, double &norm)
static bool print_message_table(ostream &stream, std::string equation_name)
Definition: field_common.cc:96
double last_t() override
Return last time of TimeGovernor.
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > old_iter_pressure_ptr_
Definition: hm_iterative.hh:67
Field< 3, FieldValue< 3 >::Scalar > density
Density of fluid.
Definition: hm_iterative.hh:54
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:180
std::shared_ptr< FieldFE< 3, FieldValue< 3 >::Scalar > > beta_ptr_
Definition: hm_iterative.hh:64
TimeGovernor * time_
Definition: equation.hh:221
Definition: field.hh:60