Flow123d  jenkins-Flow123d-windows32-release-multijob-51
dual_por_exchange.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <stdlib.h>
3 #include <math.h>
4 
5 #include "reaction/reaction.hh"
7 #include "system/system.hh"
8 #include "system/sys_profiler.hh"
9 #include <petscmat.h>
10 
11 #include "la/distribution.hh"
12 #include "mesh/mesh.h"
13 #include "mesh/elements.h"
14 #include "mesh/region.hh"
16 
17 #include "reaction/sorption.hh"
21 
22 using namespace Input::Type;
23 using namespace std;
24 
25 
27  = EqData().output_fields.make_output_field_selection("DualPorosity_Output")
28  .close();
29 
31  = Record("DualPorosity",
32  "Dual porosity model in transport problems.\n"
33  "Provides computing the concentration of substances in mobile and immobile zone.\n"
34  )
36  .declare_key("input_fields", Array(DualPorosity::EqData().make_field_descriptor_type("DualPorosity")), Default::obligatory(),
37  "Containes region specific data necessary to construct dual porosity model.")
38  .declare_key("scheme_tolerance", Double(0.0), Default("1e-3"),
39  "Tolerance according to which the explicit Euler scheme is used or not."
40  "Set 0.0 to use analytic formula only (can be slower).")
41 
42  .declare_key("reaction_mobile", ReactionTerm::input_type, Default::optional(), "Reaction model in mobile zone.")
43  .declare_key("reaction_immobile", ReactionTerm::input_type, Default::optional(), "Reaction model in immobile zone.")
44 
45  .declare_key("output_fields", Array(EqData::output_selection),
46  Default("conc_immobile"), "List of fields to write to output stream.");
47 
49 {
50  *this += diffusion_rate_immobile
51  .name("diffusion_rate_immobile")
52  .description("Diffusion coefficient of non-equilibrium linear exchange between mobile and immobile zone.")
53  .input_default("0")
54  .units( UnitSI().s(-1) );
55 
56  *this += porosity_immobile
57  .name("porosity_immobile")
58  .description("Porosity of the immobile zone.")
59  .input_default("0")
60  .units( UnitSI::dimensionless() );
61 
62  *this += init_conc_immobile
63  .name("init_conc_immobile")
64  .description("Initial concentration of substances in the immobile zone.")
65  .units( UnitSI().kg().m(-3) );
66 
67  //creating field for porosity that is set later from the governing equation (transport)
68  *this +=porosity
69  .name("porosity")
70  .units( UnitSI::dimensionless() )
71  .flags( FieldFlag::input_copy );
72 
73  output_fields += *this;
74  output_fields += conc_immobile.name("conc_immobile").units( UnitSI().kg().m(-3) );
75 }
76 
78  : ReactionTerm(init_mesh, in_rec)
79 {
80  //set pointer to equation data fieldset
81  this->eq_data_ = &data_;
82 
83  //reads input and creates possibly other reaction terms
85  //read value from input
86  scheme_tolerance_ = input_record_.val<double>("scheme_tolerance");
87 }
88 
90 {
91  if(reaction_mobile != nullptr) delete reaction_mobile;
92  if(reaction_immobile != nullptr) delete reaction_immobile;
93 
94  VecScatterDestroy(&(vconc_out_scatter));
95  VecDestroy(vconc_immobile);
96  VecDestroy(vconc_immobile_out);
97 
98  for (unsigned int sbi = 0; sbi < names_.size(); sbi++)
99  {
100  //no mpi vectors
101  xfree(conc_immobile[sbi]);
102  xfree(conc_immobile_out[sbi]);
103  }
104 
107 }
108 
109 
112  if ( reactions_it )
113  {
114  if (reactions_it->type() == LinearReaction::input_type ) {
115  reaction_mobile = new LinearReaction(*mesh_, *reactions_it);
116 
117  } else
118  if (reactions_it->type() == PadeApproximant::input_type) {
119  reaction_mobile = new PadeApproximant(*mesh_, *reactions_it);
120  } else
121  if (reactions_it->type() == SorptionMob::input_type ) {
122  reaction_mobile = new SorptionMob(*mesh_, *reactions_it);
123  } else
124  if (reactions_it->type() == DualPorosity::input_type ) {
125  xprintf(UsrErr, "Dual porosity model cannot have another descendant dual porosity model.\n");
126  } else
127  if (reactions_it->type() == Semchem_interface::input_type )
128  {
129  xprintf(UsrErr, "Semchem chemistry model is not supported at current time.\n");
130  } else
131  {
132  xprintf(UsrErr, "Wrong reaction type in DualPorosity model.\n");
133  }
134  } else
135  {
136  reaction_mobile = nullptr;
137  }
138 
139  reactions_it = input_record_.find<Input::AbstractRecord>("reaction_immobile");
140  if ( reactions_it )
141  {
142  if (reactions_it->type() == LinearReaction::input_type ) {
143  reaction_immobile = new LinearReaction(*mesh_, *reactions_it);
144 
145  } else
146  if (reactions_it->type() == PadeApproximant::input_type) {
147  reaction_immobile = new PadeApproximant(*mesh_, *reactions_it);
148  } else
149  if (reactions_it->type() == SorptionImmob::input_type ) {
150  reaction_immobile = new SorptionImmob(*mesh_, *reactions_it);
151  } else
152  if (reactions_it->type() == DualPorosity::input_type ) {
153  xprintf(UsrErr, "Dual porosity model cannot have another descendant dual porosity model.\n");
154  } else
155  if (reactions_it->type() == Semchem_interface::input_type )
156  {
157  xprintf(UsrErr, "Semchem chemistry model is not supported at current time.\n");
158  } else
159  {
160  xprintf(UsrErr, "Unknown reactions type in DualPorosity model.\n");
161  }
162  } else
163  {
164  reaction_immobile = nullptr;
165  }
166 
167 }
168 
170 {
171  ASSERT(distribution_ != nullptr, "Distribution has not been set yet.\n");
172  ASSERT(time_ != nullptr, "Time governor has not been set yet.\n");
173  ASSERT(output_stream_,"Null output stream.");
174  ASSERT_LESS(0, names_.size());
175 
176  //allocating memory for immobile concentration matrix
177  conc_immobile = (double**) xmalloc(names_.size() * sizeof(double*));
178  conc_immobile_out = (double**) xmalloc(names_.size() * sizeof(double*));
179  for (unsigned int sbi = 0; sbi < names_.size(); sbi++)
180  {
181  conc_immobile[sbi] = (double*) xmalloc(distribution_->lsize() * sizeof(double));
182  conc_immobile_out[sbi] = (double*) xmalloc(distribution_->size() * sizeof(double));
183  }
185 
187 
188  if(reaction_mobile != nullptr)
189  {
195  }
196 
197  if(reaction_immobile != nullptr)
198  {
204  }
205 
206 }
207 
209 {
210  //setting fields in data
211  data_.set_n_components(names_.size());
212 
213  //setting fields that are set from input file
216 
217  data_.set_mesh(*mesh_);
219 
220  //initialization of output
221  output_array = input_record_.val<Input::Array>("output_fields");
222 
223  //initialization of output
227 
228  for (unsigned int sbi=0; sbi<names_.size(); sbi++)
229  {
230  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
231  std::shared_ptr<FieldElementwise<3, FieldValue<3>::Scalar> > output_field_ptr(
233  data_.conc_immobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
234  }
237 }
238 
239 
241 {
242  ASSERT(distribution_ != nullptr, "Distribution has not been set yet.\n");
243  ASSERT(time_ != nullptr, "Time governor has not been set yet.\n");
244  ASSERT(output_stream_,"Null output stream.");
245  ASSERT_LESS(0, names_.size());
246 
247  //coupling - passing fields
248  if(reaction_mobile)
249  if (typeid(*reaction_mobile) == typeid(SorptionMob))
250  {
251  reaction_mobile->data().set_field("porosity", data_["porosity"]);
252  reaction_mobile->data().set_field("porosity_immobile", data_["porosity_immobile"]);
253  }
255  if (typeid(*reaction_immobile) == typeid(SorptionImmob))
256  {
257  reaction_immobile->data().set_field("porosity", data_["porosity"]);
258  reaction_immobile->data().set_field("porosity_immobile", data_["porosity_immobile"]);
259  }
260 
261  data_.set_time(*time_);
263 
264  // write initial condition
268 
269  if(reaction_mobile != nullptr)
271 
272  if(reaction_immobile != nullptr)
274 }
275 
277 {
278  //setting initial condition for immobile concentration matrix
279  for (unsigned int loc_el = 0; loc_el < distribution_->lsize(); loc_el++)
280  {
281  unsigned int index = el_4_loc_[loc_el];
282  ElementAccessor<3> ele_acc = mesh_->element_accessor(index);
283  arma::vec value = data_.init_conc_immobile.value(ele_acc.centre(), ele_acc);
284 
285  for (unsigned int sbi=0; sbi < names_.size(); sbi++)
286  {
287  conc_immobile[sbi][loc_el] = value(sbi);
288  }
289  }
290 }
291 
293 {
294  data_.set_time(*time_);
295 
296  START_TIMER("dual_por_exchange_step");
297  for (unsigned int loc_el = 0; loc_el < distribution_->lsize(); loc_el++)
298  {
300  }
301  END_TIMER("dual_por_exchange_step");
302 
305 }
306 
307 
308 double **DualPorosity::compute_reaction(double **concentrations, int loc_el)
309 {
310  unsigned int sbi;
311  double conc_average, // weighted (by porosity) average of concentration
312  conc_mob, conc_immob, // new mobile and immobile concentration
313  previous_conc_mob, previous_conc_immob, // mobile and immobile concentration in previous time step
314  conc_max, //difference between concentration and average concentration
315  por_mob, por_immob; // mobile and immobile porosity
316 
317  // get data from fields
318  ElementFullIter ele = mesh_->element(el_4_loc_[loc_el]);
319  por_mob = data_.porosity.value(ele->centre(),ele->element_accessor());
320  por_immob = data_.porosity_immobile.value(ele->centre(),ele->element_accessor());
321  arma::Col<double> diff_vec = data_.diffusion_rate_immobile.value(ele->centre(), ele->element_accessor());
322 
323  // if porosity_immobile == 0 then mobile concentration stays the same
324  // and immobile concentration cannot change
325  if (por_immob == 0.0) return conc_immobile;
326 
327  double exponent,
328  temp_exponent = (por_mob + por_immob) / (por_mob * por_immob) * time_->dt();
329 
330  for (sbi = 0; sbi < names_.size(); sbi++) //over all substances
331  {
332  exponent = diff_vec[sbi] * temp_exponent;
333  //previous values
334  previous_conc_mob = concentration_matrix_[sbi][loc_el];
335  previous_conc_immob = conc_immobile[sbi][loc_el];
336 
337  // ---compute average concentration------------------------------------------
338  conc_average = ((por_mob * previous_conc_mob) + (por_immob * previous_conc_immob))
339  / (por_mob + por_immob);
340 
341  conc_max = std::max(previous_conc_mob-conc_average, previous_conc_immob-conc_average);
342 
343  if( conc_max <= (2*scheme_tolerance_/(exponent*exponent)*conc_average) ) // forward euler
344  {
345  double temp = diff_vec[sbi]*(previous_conc_immob - previous_conc_mob) * time_->dt();
346  // ---compute concentration in mobile area
347  conc_mob = temp / por_mob + previous_conc_mob;
348 
349  // ---compute concentration in immobile area
350  conc_immob = -temp / por_immob + previous_conc_immob;
351  }
352  else //analytic solution
353  {
354  double temp = exp(-exponent);
355  // ---compute concentration in mobile area
356  conc_mob = (previous_conc_mob - conc_average) * temp + conc_average;
357 
358  // ---compute concentration in immobile area
359  conc_immob = (previous_conc_immob - conc_average) * temp + conc_average;
360  }
361 
362  concentration_matrix_[sbi][loc_el] = conc_mob;
363  conc_immobile[sbi][loc_el] = conc_immob;
364  }
365 
366  return conc_immobile;
367 }
368 
369 
371 {
372  int sbi, n_subst;
373  n_subst = names_.size();
374 
375  vconc_immobile = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
376  vconc_immobile_out = (Vec*) xmalloc(n_subst * (sizeof(Vec))); // extend to all
377 
378 
379  for (sbi = 0; sbi < n_subst; sbi++) {
380  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, distribution_->lsize(), mesh_->n_elements(), conc_immobile[sbi],
381  &vconc_immobile[sbi]);
382  VecZeroEntries(vconc_immobile[sbi]);
383 
384  // if(rank == 0)
385  VecCreateSeqWithArray(PETSC_COMM_SELF,1, mesh_->n_elements(), conc_immobile_out[sbi], &vconc_immobile_out[sbi]);
386  VecZeroEntries(vconc_immobile_out[sbi]);
387  }
388 
389  // create output vector scatter
390  IS is;
391  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el_, PETSC_COPY_VALUES, &is); //WithArray
392  VecScatterCreate(vconc_immobile[0], is, vconc_immobile_out[0], PETSC_NULL, &vconc_out_scatter);
393  ISDestroy(&(is));
394 }
395 
396 
398 {
399  unsigned int sbi;
400 
401  for (sbi = 0; sbi < names_.size(); sbi++) {
402  VecScatterBegin(vconc_out_scatter, vconc_immobile[sbi], vconc_immobile_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
403  VecScatterEnd(vconc_out_scatter, vconc_immobile[sbi], vconc_immobile_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
404  }
405 }
406 
407 
409 {
411 
412  // Register fresh output data
415 
418 }
419 
FieldSet & data()
Definition: equation.hh:188
void output_type(OutputTime::DiscreteSpace rt)
Definition: field_set.hh:194
unsigned int size() const
get global size
void set_input_list(Input::Array input_list)
Definition: field_set.hh:164
static Input::Type::Record input_type
Definition: sorption.hh:78
Sorption model in immobile zone in case dual porosity is considered.
Definition: sorption.hh:97
virtual void zero_time_step()
Definition: equation.hh:97
ReactionTerm & output_stream(OutputTime &ostream)
Sets the output stream which is given from transport class.
Definition: reaction.hh:50
FieldSet * eq_data_
Definition: equation.hh:227
void set_limit_side(LimitSide side)
Definition: field_set.hh:171
OutputTime * output_stream_
Pointer to a transport output stream.
Definition: reaction.hh:112
void set_initial_condition()
Sets initial condition from input.
VecScatter vconc_out_scatter
Output vector scatter.
void init(const vector< string > &names)
Definition: field.impl.hh:473
Accessor to input data conforming to declared Array.
Definition: accessors.hh:521
virtual void output_data(void)
Output method.
Definition: reaction.hh:75
void output_data(void) override
Main output routine.
double ** concentration_matrix_
Definition: reaction.hh:95
virtual void initialize()
Initialize fields.
Definition: equation.hh:114
MultiField< 3, FieldValue< 3 >::Scalar > conc_immobile
Calculated concentrations in the immobile zone.
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:39
FieldSet output_fields
Fields indended for output, i.e. all input fields plus those representing solution.
vector< string > names_
Names belonging to substances.
Definition: reaction.hh:109
static Default obligatory()
Definition: type_record.hh:87
???
static Input::Type::Record input_type
Definition: sorption.hh:100
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:361
void zero_time_step() override
static Input::Type::Record input_type
Definition: mesh.h:108
Field< 3, FieldValue< 3 >::Scalar > porosity_immobile
Immobile porosity field.
Iterator< Ret > find(const string &key) const
int * row_4_el_
Indices of rows belonging to elements.
Definition: reaction.hh:100
~DualPorosity(void)
Destructor.
Record & derive_from(AbstractRecord &parent)
Definition: type_record.cc:169
Field< 3, FieldValue< 3 >::Vector > diffusion_rate_immobile
Mass transfer coefficients between mobile and immobile pores.
const RegionDB & region_db() const
Definition: mesh.h:148
ElementAccessor< 3 > element_accessor(unsigned int idx, bool boundary=false)
Definition: mesh.cc:638
void allocate_output_mpi(void)
Allocates petsc vectors, prepares them for output and creates output vector scatter.
Class for declaration of inputs sequences.
Definition: type_base.hh:230
void update_solution(void) override
Input::Array output_array
static Input::Type::AbstractRecord input_type
Definition: reaction.hh:24
double scheme_tolerance_
Dual porosity computational scheme tolerance.
static Default optional()
Definition: type_record.hh:100
void make_reactions()
Resolves construction of following reactions.
unsigned int n_elements() const
Definition: mesh.h:137
void initialize() override
Prepares the object to usage.
#define ASSERT(...)
Definition: global_defs.h:121
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:376
static Input::Type::Record input_type
Distribution * distribution_
Pointer to reference to distribution of elements between processors.
Definition: reaction.hh:103
static constexpr Mask input_copy
A field that is input of its equation and cna not read from input, thus muzt be set by copy...
Definition: field_flag.hh:29
static Input::Type::Selection output_selection
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:100
#define ASSERT_LESS(a, b)
Definition: global_defs.h:164
#define START_TIMER(tag)
Starts a timer with specified tag.
void initialize_fields()
Initializes field sets.
Mesh * mesh_
Definition: equation.hh:218
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:399
void set_field(const std::string &dest_field_name, FieldCommon &source)
Definition: field_set.cc:94
EqData()
Collect all fields.
static Input::Type::Record input_type
static Input::Type::AbstractRecord input_type
void * xmalloc(size_t size)
Memory allocation with checking.
Definition: system.cc:209
void set_time(const TimeGovernor &time)
Definition: field_set.hh:186
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:423
double ** conc_immobile
virtual void set_time_governor(TimeGovernor &time)
Definition: equation.cc:80
Definition: system.hh:72
Support classes for parallel programing.
void set_n_components(unsigned int n_comp)
Definition: field_set.hh:151
ReactionTerm * reaction_immobile
Reaction running in immobile zone.
Sorption model in mobile zone in case dual porosity is considered.
Definition: sorption.hh:75
void output_vector_gather(void) override
Gathers all the parallel vectors to enable them to be output.
Field< 3, FieldValue< 3 >::Vector > init_conc_immobile
Initial concentrations in the immobile zone.
double ** conc_immobile_out
concentration array output for immobile phase (gathered - sequential)
virtual void update_solution()
Definition: equation.hh:105
void output(OutputTime *stream)
Definition: field_set.cc:136
const Selection & close() const
Input::Record input_record_
Definition: equation.hh:220
int * el_4_loc_
Indices of elements belonging to local dofs.
Definition: reaction.hh:98
double dt() const
void add_admissible_field_names(const Input::Array &in_array, const Input::Type::Selection &in_sel)
Registers names of output fields that can be written using this stream.
Definition: output.cc:231
double ** compute_reaction(double **concentrations, int loc_el) override
ReactionTerm & names(const std::vector< string > &names)
Sets the names of substances considered in transport.
Definition: reaction.hh:46
#define END_TIMER(tag)
Ends a timer with specified tag.
arma::vec::fixed< spacedim > centre() const
Definition: accessors.hh:81
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:157
ReactionTerm * reaction_mobile
Reaction running in mobile zone.
Record type proxy class.
Definition: type_record.hh:161
Field< 3, FieldValue< 3 >::Scalar > porosity
Porosity field.
#define xfree(p)
Definition: system.hh:108
Class for representation SI units of Fields.
Definition: unit_si.hh:31
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:44
DualPorosity data.
Vec * vconc_immobile
PETSC concentration vector for immobile phase (parallel).
Vec * vconc_immobile_out
PETSC concentration vector output for immobile phase (gathered - sequential)
ReactionTerm & concentration_matrix(double **concentration, Distribution *conc_distr, int *el_4_loc, int *row_4_el)
Definition: reaction.hh:57
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:520
Template for classes storing finite set of named values.
TimeGovernor * time_
Definition: equation.hh:219
FieldSet input_data_set_
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:198
unsigned int lsize(int proc) const
get local size
Record & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:386