Flow123d  JS_before_hm-1755-g6249b9fc1
dual_porosity.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 dual_porosity.cc
15  * @brief
16  */
17 
18 #include <iostream>
19 #include <stdlib.h>
20 #include <math.h>
21 
24 #include "system/system.hh"
25 #include "system/sys_profiler.hh"
26 
27 #include "la/distribution.hh"
28 #include "mesh/mesh.h"
29 #include "mesh/elements.h"
30 #include "mesh/region.hh"
31 #include "mesh/accessors.hh"
32 #include "fields/field_fe.hh"
34 
35 #include "reaction/sorption.hh"
38 #include "input/factory.hh"
39 
40 FLOW123D_FORCE_LINK_IN_CHILD(dualPorosity)
41 
42 
43 using namespace Input::Type;
44 
45 
46 
48  return Record("DualPorosity",
49  "Dual porosity model in transport problems.\n"
50  "Provides computing the concentration of substances in mobile and immobile zone.\n"
51  )
53  .declare_key("input_fields", Array(DualPorosity::EqData().make_field_descriptor_type("DualPorosity")), Default::obligatory(),
54  "Containes region specific data necessary to construct dual porosity model.")
55  .declare_key("scheme_tolerance", Double(0.0), Default("1e-3"),
56  "Tolerance according to which the explicit Euler scheme is used or not."
57  "Set 0.0 to use analytic formula only (can be slower).")
58 
59  .declare_key("reaction_mobile", ReactionTerm::it_abstract_mobile_term(), Default::optional(), "Reaction model in mobile zone.")
60  .declare_key("reaction_immobile", ReactionTerm::it_abstract_immobile_term(), Default::optional(), "Reaction model in immobile zone.")
61  .declare_key("output",
62  EqData().output_fields.make_output_type("DualPorosity", ""),
63  IT::Default("{ \"fields\": [ \"conc_immobile\" ] }"),
64  "Setting of the fields output.")
65  .close();
66 }
67 
68 const int DualPorosity::registrar =
69  Input::register_class< DualPorosity, Mesh &, Input::Record >("DualPorosity") +
71 
73 {
74  *this += diffusion_rate_immobile
75  .name("diffusion_rate_immobile")
76  .description("Diffusion coefficient of non-equilibrium linear exchange between mobile and immobile zone.")
77  .input_default("0")
78  .units( UnitSI().s(-1) );
79 
80  *this += porosity_immobile
81  .name("porosity_immobile")
82  .description("Porosity of the immobile zone.")
83  .input_default("0")
84  .units( UnitSI::dimensionless() )
85  .set_limits(0.0);
86 
87  *this += init_conc_immobile
88  .name("init_conc_immobile")
89  .description("Initial concentration of substances in the immobile zone.")
90  .units( UnitSI().kg().m(-3) );
91 
92  //creating field for porosity that is set later from the governing equation (transport)
93  *this +=porosity
94  .name("porosity")
95  .description("Concentration solution in the mobile phase.")
96  .units( UnitSI::dimensionless() )
97  .flags( FieldFlag::input_copy )
98  .set_limits(0.0);
99 
100  *this += conc_immobile
101  .name("conc_immobile")
102  .units( UnitSI().kg().m(-3) )
104 
105  output_fields += *this;
106 
107 }
108 
110  : ReactionTerm(init_mesh, in_rec)
111 {
112  //set pointer to equation data fieldset
113  this->eq_fieldset_ = &data_;
114 
115  //reads input and creates possibly other reaction terms
116  make_reactions();
117  //read value from input
118  scheme_tolerance_ = input_record_.val<double>("scheme_tolerance");
119 }
120 
122 {
123 }
124 
125 
128  if ( reactions_it )
129  {
130  // TODO: allowed instances in this case are only
131  // FirstOrderReaction, RadioactiveDecay and SorptionMob
132  reaction_mobile = (*reactions_it).factory< ReactionTerm, Mesh &, Input::Record >(*mesh_, *reactions_it);
133  } else
134  {
135  reaction_mobile = nullptr;
136  }
137 
138  reactions_it = input_record_.find<Input::AbstractRecord>("reaction_immobile");
139  if ( reactions_it )
140  {
141  // TODO: allowed instances in this case are only
142  // FirstOrderReaction, RadioactiveDecay and SorptionImmob
143  reaction_immobile = (*reactions_it).factory< ReactionTerm, Mesh &, Input::Record >(*mesh_, *reactions_it);
144  } else
145  {
146  reaction_immobile = nullptr;
147  }
148 
149 }
150 
152 {
153  ASSERT(time_ != nullptr).error("Time governor has not been set yet.\n");
154  ASSERT_LT(0, substances_.size()).error("No substances for rection term.\n");
155  ASSERT(output_stream_ != nullptr).error("Null output stream.\n");
156 
158 
159  if(reaction_mobile)
160  {
161  reaction_mobile->substances(substances_)
162  .output_stream(output_stream_)
163  .concentration_fields(conc_mobile_fe)
164  .set_time_governor(*time_);
165  reaction_mobile->initialize();
166  }
167 
169  {
170  reaction_immobile->substances(substances_)
171  .output_stream(output_stream_)
172  .concentration_fields(data_.conc_immobile_fe)
173  .set_time_governor(*time_);
174  reaction_immobile->initialize();
175  }
176 
177 }
178 
180 {
182  //setting fields that are set from input file
185 
186  //setting fields in data
187  data_.set_mesh(*mesh_);
188 
189  //initialization of output
194 
195 
196  //creating field fe and output multifield for sorbed concentrations
198  for (unsigned int sbi = 0; sbi < substances_.size(); sbi++)
199  {
200  // create shared pointer to a FieldFE and push this Field to output_field on all regions
201  data_.conc_immobile_fe[sbi] = create_field_fe< 3, FieldValue<3>::Scalar >(dof_handler_);
203  }
204 
206 }
207 
208 
210 {
211  ASSERT(time_ != nullptr).error("Time governor has not been set yet.\n");
212  ASSERT_LT(0, substances_.size()).error("No substances for rection term.\n");
213  ASSERT(output_stream_ != nullptr).error("Null output stream.\n");
214 
215  //coupling - passing fields
216  if(reaction_mobile)
217  if (typeid(*reaction_mobile) == typeid(SorptionMob))
218  {
219  reaction_mobile->eq_fieldset().set_field("porosity", data_["porosity"]);
220  reaction_mobile->eq_fieldset().set_field("porosity_immobile", data_["porosity_immobile"]);
221  }
223  if (typeid(*reaction_immobile) == typeid(SorptionImmob))
224  {
225  reaction_immobile->eq_fieldset().set_field("porosity", data_["porosity"]);
226  reaction_immobile->eq_fieldset().set_field("porosity_immobile", data_["porosity_immobile"]);
227  }
228 
230  std::stringstream ss; // print warning message with table of uninitialized fields
231  if ( FieldCommon::print_message_table(ss, "dual porosity") ) {
232  WarningOut() << ss.str();
233  }
235 
236  output_data();
237 
238  if(reaction_mobile)
239  reaction_mobile->zero_time_step();
240 
242  reaction_immobile->zero_time_step();
243 
244 }
245 
247 {
248  for ( DHCellAccessor dh_cell : dof_handler_->own_range() ) {
249  IntIdx dof_p0 = dh_cell.get_loc_dof_indices()[0];
250  const ElementAccessor<3> ele = dh_cell.elm();
251 
252  //setting initial solid concentration for substances involved in adsorption
253  for (unsigned int sbi = 0; sbi < substances_.size(); sbi++)
254  {
255  data_.conc_immobile_fe[sbi]->vec().set( dof_p0, data_.init_conc_immobile[sbi].value(ele.centre(), ele) );
256  }
257  }
258 }
259 
261 {
263 
264  START_TIMER("dual_por_exchange_step");
265  for ( DHCellAccessor dh_cell : dof_handler_->own_range() )
266  {
267  compute_reaction(dh_cell);
268  }
269  END_TIMER("dual_por_exchange_step");
270 
271  if(reaction_mobile) reaction_mobile->update_solution();
272  if(reaction_immobile) reaction_immobile->update_solution();
273 }
274 
275 
277 {
278  unsigned int sbi;
279  double conc_average, // weighted (by porosity) average of concentration
280  conc_mob, conc_immob, // new mobile and immobile concentration
281  previous_conc_mob, previous_conc_immob, // mobile and immobile concentration in previous time step
282  conc_max, //difference between concentration and average concentration
283  por_mob, por_immob; // mobile and immobile porosity
284 
285  // get data from fields
286  ElementAccessor<3> ele = dh_cell.elm();
287  IntIdx dof_p0 = dh_cell.get_loc_dof_indices()[0];
288  por_mob = data_.porosity.value(ele.centre(),ele);
289  por_immob = data_.porosity_immobile.value(ele.centre(),ele);
290  arma::Col<double> diff_vec(substances_.size());
291  for (sbi=0; sbi<substances_.size(); sbi++) // Optimize: SWAP LOOPS
292  diff_vec[sbi] = data_.diffusion_rate_immobile[sbi].value(ele.centre(), ele);
293 
294  // if porosity_immobile == 0 then mobile concentration stays the same
295  // and immobile concentration cannot change
296  if (por_immob == 0.0) return;
297 
298  double exponent,
299  temp_exponent = (por_mob + por_immob) / (por_mob * por_immob) * time_->dt();
300 
301  for (sbi = 0; sbi < substances_.size(); sbi++) //over all substances
302  {
303  exponent = diff_vec[sbi] * temp_exponent;
304  //previous values
305  previous_conc_mob = conc_mobile_fe[sbi]->vec().get(dof_p0);
306  previous_conc_immob = data_.conc_immobile_fe[sbi]->vec().get(dof_p0);
307 
308  // ---compute average concentration------------------------------------------
309  conc_average = ((por_mob * previous_conc_mob) + (por_immob * previous_conc_immob))
310  / (por_mob + por_immob);
311 
312  conc_max = std::max(previous_conc_mob-conc_average, previous_conc_immob-conc_average);
313 
314  // the following 2 conditions guarantee:
315  // 1) stability of forward Euler's method
316  // 2) the error of forward Euler's method will not be large
317  if(time_->dt() <= por_mob*por_immob/(max(diff_vec)*(por_mob+por_immob)) &&
318  conc_max <= (2*scheme_tolerance_/(exponent*exponent)*conc_average)) // forward euler
319  {
320  double temp = diff_vec[sbi]*(previous_conc_immob - previous_conc_mob) * time_->dt();
321  // ---compute concentration in mobile area
322  conc_mob = temp / por_mob + previous_conc_mob;
323 
324  // ---compute concentration in immobile area
325  conc_immob = -temp / por_immob + previous_conc_immob;
326  }
327  else //analytic solution
328  {
329  double temp = exp(-exponent);
330  // ---compute concentration in mobile area
331  conc_mob = (previous_conc_mob - conc_average) * temp + conc_average;
332 
333  // ---compute concentration in immobile area
334  conc_immob = (previous_conc_immob - conc_average) * temp + conc_average;
335  }
336 
337  conc_mobile_fe[sbi]->vec().set(dof_p0, conc_mob);
338  data_.conc_immobile_fe[sbi]->vec().set(dof_p0, conc_immob);
339  }
340 }
341 
342 
344 {
346 
347  // Register fresh output data
349 
350  if (time_->tlevel() !=0) {
351  // zero_time_step call zero_time_Step of subreactions which performs its own output
352  if (reaction_mobile) reaction_mobile->output_data();
353  if (reaction_immobile) reaction_immobile->output_data();
354  }
355 }
356 
357 
358 bool DualPorosity::evaluate_time_constraint(double &time_constraint)
359 {
360  bool cfl_changed = false;
361  if (reaction_mobile)
362  {
363  if (reaction_mobile->evaluate_time_constraint(time_constraint))
364  cfl_changed = true;
365  }
366  if (reaction_immobile)
367  {
368  double cfl_immobile;
369  if (reaction_immobile->evaluate_time_constraint(cfl_immobile))
370  {
371  time_constraint = std::min(time_constraint, cfl_immobile);
372  cfl_changed = true;
373  }
374  }
375 
376  return cfl_changed;
377 }
LimitSide::right
@ right
ReactionTerm::output_stream_
std::shared_ptr< OutputTime > output_stream_
Pointer to a transport output stream.
Definition: reaction_term.hh:124
EquationBase::mesh_
Mesh * mesh_
Definition: equation.hh:218
DualPorosity::registrar
static const int registrar
Registrar of class to factory.
Definition: dual_porosity.hh:149
MultiField::setup_components
void setup_components()
Definition: multi_field.impl.hh:266
DualPorosity::initialize
void initialize() override
Prepares the object to usage.
Definition: dual_porosity.cc:151
TimeGovernor::dt
double dt() const
Definition: time_governor.hh:558
UnitSI::dimensionless
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
ReactionTerm::it_abstract_immobile_term
static Input::Type::Abstract & it_abstract_immobile_term()
Definition: reaction_term.cc:37
DualPorosity::EqData::conc_immobile_fe
FieldFEScalarVec conc_immobile_fe
Underlaying FieldFE for each substance of conc_immobile.
Definition: dual_porosity.hh:76
factory.hh
FieldSet::set_time
bool set_time(const TimeStep &time, LimitSide limit_side)
Definition: field_set.cc:164
ReactionTerm::ReactionTerm
ReactionTerm(Mesh &init_mesh, Input::Record in_rec)
Constructor.
Definition: reaction_term.cc:51
DualPorosity::scheme_tolerance_
double scheme_tolerance_
Dual porosity computational scheme tolerance.
Definition: dual_porosity.hh:145
EquationOutput::initialize
void initialize(std::shared_ptr< OutputTime > stream, Mesh *mesh, Input::Record in_rec, const TimeGovernor &tg)
Definition: equation_output.cc:109
SubstanceList::size
unsigned int size() const
Definition: substance.hh:87
ASSERT
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:347
EquationBase::time_
TimeGovernor * time_
Definition: equation.hh:219
MultiField::set
void set(std::vector< typename Field< spacedim, Value >::FieldBasePtr > field_vec, double time, std::vector< std::string > region_set_names={"ALL"})
Definition: multi_field.impl.hh:403
distribution.hh
Support classes for parallel programing.
Input::Record::val
const Ret val(const string &key) const
Definition: accessors_impl.hh:31
IntIdx
int IntIdx
Definition: index_types.hh:25
EquationBase::time
TimeGovernor & time()
Definition: equation.hh:149
FieldSet::set_input_list
void set_input_list(Input::Array input_list, const TimeGovernor &tg)
Definition: field_set.hh:282
FieldSet::output_type
void output_type(OutputTime::DiscreteSpace rt)
Definition: field_set.hh:303
Input::Type::Double
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:534
DualPorosity::data_
EqData data_
Definition: dual_porosity.hh:131
DualPorosity::compute_reaction
void compute_reaction(const DHCellAccessor &dh_cell) override
Compute reaction on a single element.
Definition: dual_porosity.cc:276
DualPorosity::update_solution
void update_solution(void) override
Definition: dual_porosity.cc:260
FLOW123D_FORCE_LINK_IN_CHILD
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:157
DualPorosity::DualPorosity
DualPorosity()
ElementAccessor< 3 >
system.hh
OutputTime::ELEM_DATA
@ ELEM_DATA
Definition: output_time.hh:111
field_fe.hh
ReactionTerm::dof_handler_
std::shared_ptr< DOFHandlerMultiDim > dof_handler_
Pointer to DOF handler used through the reaction tree.
Definition: reaction_term.hh:127
DualPorosity::make_reactions
void make_reactions()
Resolves construction of following reactions.
Definition: dual_porosity.cc:126
ASSERT_LT
#define ASSERT_LT(a, b)
Definition of comparative assert macro (Less Than)
Definition: asserts.hh:296
DualPorosity::input_data_set_
FieldSet input_data_set_
Definition: dual_porosity.hh:136
ReactionTerm::conc_mobile_fe
FieldFEScalarVec conc_mobile_fe
FieldFEs representing P0 interpolation of mobile concentration (passed from transport).
Definition: reaction_term.hh:115
SubstanceList::names
const std::vector< std::string > & names()
Definition: substance.hh:85
Input::Iterator
Definition: accessors.hh:143
SorptionImmob
Sorption model in immobile zone in case dual porosity is considered.
Definition: sorption.hh:132
Input::Type::Record::size
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:602
Input::Type::Default
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
Input::Type::Record::derive_from
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:196
SorptionMob
Sorption model in mobile zone in case dual porosity is considered.
Definition: sorption.hh:106
FieldSet::set_components
void set_components(const std::vector< string > &names)
Definition: field_set.hh:268
accessors.hh
Input::Record
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
FieldFlag::equation_result
static constexpr Mask equation_result
Match result fields. These are never given by input or copy of input.
Definition: field_flag.hh:55
elements.h
sys_profiler.hh
DualPorosity::EqData
DualPorosity data.
Definition: dual_porosity.hh:61
TimeGovernor::tlevel
int tlevel() const
Definition: time_governor.hh:600
TimeGovernor::step
const TimeStep & step(int index=-1) const
Definition: time_governor.cc:753
DualPorosity::reaction_mobile
std::shared_ptr< ReactionTerm > reaction_mobile
Reaction running in mobile zone.
Definition: dual_porosity.hh:138
DualPorosity::EqData::diffusion_rate_immobile
MultiField< 3, FieldValue< 3 >::Scalar > diffusion_rate_immobile
Mass transfer coefficients between mobile and immobile pores.
Definition: dual_porosity.hh:68
sorption.hh
This file contains classes representing sorption model. Sorption model can be computed both in case t...
DHCellAccessor::elm
const ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
Definition: dh_cell_accessor.hh:71
Input::AbstractRecord
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:458
Input::Type::Default::obligatory
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
FieldCommon::print_message_table
static bool print_message_table(ostream &stream, std::string equation_name)
Definition: field_common.cc:96
UnitSI
Class for representation SI units of Fields.
Definition: unit_si.hh:40
EquationBase::input_record_
Input::Record input_record_
Definition: equation.hh:220
DualPorosity::EqData::porosity_immobile
Field< 3, FieldValue< 3 >::Scalar > porosity_immobile
Immobile porosity field.
Definition: dual_porosity.hh:69
DualPorosity::~DualPorosity
~DualPorosity(void)
Destructor.
Definition: dual_porosity.cc:121
first_order_reaction.hh
Input::Type::Record::declare_key
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
mesh.h
ReactionTerm::substances_
SubstanceList substances_
Names belonging to substances.
Definition: reaction_term.hh:121
DualPorosity::set_initial_condition
void set_initial_condition()
Sets initial condition from input.
Definition: dual_porosity.cc:246
Input::Record::find
Iterator< Ret > find(const string &key) const
Definition: accessors_impl.hh:91
FieldFlag::input_copy
static constexpr Mask input_copy
Definition: field_flag.hh:44
Input::Type::Record::close
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Input::Type
Definition: balance.hh:41
DualPorosity::evaluate_time_constraint
bool evaluate_time_constraint(double &time_constraint) override
Computes a constraint for time step.
Definition: dual_porosity.cc:358
Input::Type::Record
Record type proxy class.
Definition: type_record.hh:182
Field::value
virtual const Value::return_type & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:452
DualPorosity::reaction_immobile
std::shared_ptr< ReactionTerm > reaction_immobile
Reaction running in immobile zone.
Definition: dual_porosity.hh:139
EquationOutput::output
void output(TimeStep step)
Definition: equation_output.cc:199
DualPorosity::output_data
void output_data(void) override
Main output routine.
Definition: dual_porosity.cc:343
Mesh
Definition: mesh.h:77
Input::Type::Array
Class for declaration of inputs sequences.
Definition: type_base.hh:339
dual_porosity.hh
Class Dual_por_exchange implements the model of dual porosity.
DualPorosity::zero_time_step
void zero_time_step() override
Definition: dual_porosity.cc:209
DHCellAccessor
Cell accessor allow iterate over DOF handler cells.
Definition: dh_cell_accessor.hh:43
DualPorosity::get_input_type
static const Input::Type::Record & get_input_type()
Definition: dual_porosity.cc:47
Input::Array
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
FieldSet::set_mesh
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:274
WarningOut
#define WarningOut()
Macro defining 'warning' record of log.
Definition: logger.hh:270
DualPorosity::EqData::EqData
EqData()
Collect all fields.
Definition: dual_porosity.cc:72
ReactionTerm::it_abstract_term
static Input::Type::Abstract & it_abstract_term()
Definition: reaction_term.cc:25
fe_value_handler.hh
DualPorosity::EqData::conc_immobile
MultiField< 3, FieldValue< 3 >::Scalar > conc_immobile
Calculated concentrations in the immobile zone.
Definition: dual_porosity.hh:75
DualPorosity::EqData::init_conc_immobile
MultiField< 3, FieldValue< 3 >::Scalar > init_conc_immobile
Initial concentrations in the immobile zone.
Definition: dual_porosity.hh:71
DHCellAccessor::get_loc_dof_indices
LocDofVec get_loc_dof_indices() const
Returns the local indices of dofs associated to the cell on the local process.
Definition: dh_cell_accessor.hh:88
region.hh
EquationBase::eq_fieldset_
FieldSet * eq_fieldset_
Definition: equation.hh:227
DualPorosity::initialize_fields
void initialize_fields()
Initializes field sets.
Definition: dual_porosity.cc:179
DualPorosity::EqData::output_fields
EquationOutput output_fields
Fields indended for output, i.e. all input fields plus those representing solution.
Definition: dual_porosity.hh:79
reaction_term.hh
Class ReactionTerm is an abstract class representing reaction term in transport.
ReactionTerm::it_abstract_mobile_term
static Input::Type::Abstract & it_abstract_mobile_term()
Definition: reaction_term.cc:31
ReactionTerm
Definition: reaction_term.hh:45
radioactive_decay.hh
Input::Type::Default::optional
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:124
START_TIMER
#define START_TIMER(tag)
Starts a timer with specified tag.
Definition: sys_profiler.hh:115
DualPorosity::EqData::porosity
Field< 3, FieldValue< 3 >::Scalar > porosity
Porosity field.
Definition: dual_porosity.hh:73
END_TIMER
#define END_TIMER(tag)
Ends a timer with specified tag.
Definition: sys_profiler.hh:149
ElementAccessor::centre
arma::vec::fixed< spacedim > centre() const
Computes the barycenter.
Definition: accessors_impl.hh:112