Flow123d  jenkins-Flow123d-windows32-release-multijob-28
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("");
55 
56  *this += porosity_immobile
57  .name("porosity_immobile")
58  .description("Porosity of the immobile zone.")
59  .input_default("0")
60  .units("1");
61 
62  *this += init_conc_immobile
63  .name("init_conc_immobile")
64  .description("Initial concentration of substances in the immobile zone.")
65  .units("M/L^3");
66 
67  //creating field for porosity that is set later from the governing equation (transport)
68  *this +=porosity
69  .name("porosity")
70  .units("1")
71  .flags( FieldFlag::input_copy );
72 
73  output_fields += *this;
74  output_fields += conc_immobile.name("conc_immobile").units("M/L^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  //DBGMSG("DualPorosity - initialize.\n");
172  ASSERT(distribution_ != nullptr, "Distribution has not been set yet.\n");
173  ASSERT(time_ != nullptr, "Time governor has not been set yet.\n");
174  ASSERT(output_stream_,"Null output stream.");
175  ASSERT_LESS(0, names_.size());
176 
177  //allocating memory for immobile concentration matrix
178  conc_immobile = (double**) xmalloc(names_.size() * sizeof(double*));
179  conc_immobile_out = (double**) xmalloc(names_.size() * sizeof(double*));
180  for (unsigned int sbi = 0; sbi < names_.size(); sbi++)
181  {
182  conc_immobile[sbi] = (double*) xmalloc(distribution_->lsize() * sizeof(double));
183  conc_immobile_out[sbi] = (double*) xmalloc(distribution_->size() * sizeof(double));
184  }
186 
188 
189  if(reaction_mobile != nullptr)
190  {
196  }
197 
198  if(reaction_immobile != nullptr)
199  {
205  }
206 
207 }
208 
210 {
211  //setting fields in data
212  data_.set_n_components(names_.size());
213 
214  //setting fields that are set from input file
217 
218  data_.set_mesh(*mesh_);
220 
221  //initialization of output
222  output_array = input_record_.val<Input::Array>("output_fields");
223 
224  //initialization of output
228 
229  for (unsigned int sbi=0; sbi<names_.size(); sbi++)
230  {
231  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
232  std::shared_ptr<FieldElementwise<3, FieldValue<3>::Scalar> > output_field_ptr(
234  data_.conc_immobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
235  }
238 }
239 
240 
242 {
243  //DBGMSG("DualPorosity - zero_time_step.\n");
244  ASSERT(distribution_ != nullptr, "Distribution has not been set yet.\n");
245  ASSERT(time_ != nullptr, "Time governor has not been set yet.\n");
246  ASSERT(output_stream_,"Null output stream.");
247  ASSERT_LESS(0, names_.size());
248 
249  //coupling - passing fields
250  if(reaction_mobile)
251  if (typeid(*reaction_mobile) == typeid(SorptionMob))
252  {
253  reaction_mobile->data().set_field("porosity", data_["porosity"]);
254  reaction_mobile->data().set_field("porosity_immobile", data_["porosity_immobile"]);
255  }
257  if (typeid(*reaction_immobile) == typeid(SorptionImmob))
258  {
259  reaction_immobile->data().set_field("porosity", data_["porosity"]);
260  reaction_immobile->data().set_field("porosity_immobile", data_["porosity_immobile"]);
261  }
262 
263  data_.set_time(*time_);
265 
266  // write initial condition
270 
271  if(reaction_mobile != nullptr)
273 
274  if(reaction_immobile != nullptr)
276 }
277 
279 {
280  //DBGMSG("DualPorosity - init_conc_immobile.\n");
281  //setting initial condition for immobile concentration matrix
282  for (unsigned int loc_el = 0; loc_el < distribution_->lsize(); loc_el++)
283  {
284  unsigned int index = el_4_loc_[loc_el];
285  ElementAccessor<3> ele_acc = mesh_->element_accessor(index);
286  arma::vec value = data_.init_conc_immobile.value(ele_acc.centre(), ele_acc);
287 
288  for (unsigned int sbi=0; sbi < names_.size(); sbi++)
289  {
290  conc_immobile[sbi][loc_el] = value(sbi);
291  }
292  }
293 }
294 
296 {
297  //DBGMSG("DualPorosity - update solution\n");
298  data_.set_time(*time_);
299 
300  START_TIMER("dual_por_exchange_step");
301  for (unsigned int loc_el = 0; loc_el < distribution_->lsize(); loc_el++)
302  {
304  }
305  END_TIMER("dual_por_exchange_step");
306 
309 }
310 
311 
312 double **DualPorosity::compute_reaction(double **concentrations, int loc_el)
313 {
314  unsigned int sbi;
315  double conc_average, // weighted (by porosity) average of concentration
316  conc_mob, conc_immob, // new mobile and immobile concentration
317  previous_conc_mob, previous_conc_immob, // mobile and immobile concentration in previous time step
318  conc_max, //difference between concentration and average concentration
319  por_mob, por_immob; // mobile and immobile porosity
320 
321  // get data from fields
322  ElementFullIter ele = mesh_->element(el_4_loc_[loc_el]);
323  por_mob = data_.porosity.value(ele->centre(),ele->element_accessor());
324  por_immob = data_.porosity_immobile.value(ele->centre(),ele->element_accessor());
325  arma::Col<double> diff_vec = data_.diffusion_rate_immobile.value(ele->centre(), ele->element_accessor());
326 
327 // OLD CODE:
328 // for (sbi = 0; sbi < names_.size(); sbi++) //over all substances
329 // {
330 // //sbi_loc = substance_id[sbi]; //mapping to global substance index
331 // //previous values
332 // previous_conc_mob = concentration_matrix_[sbi][loc_el];
333 // previous_conc_immob = conc_immobile[sbi][loc_el];
334 //
335 // // ---compute average concentration------------------------------------------
336 // conc_average = ((por_mob * previous_conc_mob) + (por_immob * previous_conc_immob)) / (por_mob + por_immob);
337 //
338 // if ((conc_average != 0.0) && (por_immob != 0.0)) {
339 // temp_exp = exp(-diff_vec[sbi] * ((por_mob + por_immob) / (por_mob * por_immob)) * time_->dt());
340 // // ---compute concentration in mobile area-----------------------------------
341 // conc_mob = (previous_conc_mob - conc_average) * temp_exp + conc_average;
342 //
343 // // ---compute concentration in immobile area---------------------------------
344 // conc_immob = (previous_conc_immob - conc_average) * temp_exp + conc_average;
345 // // --------------------------------------------------------------------------
346 // // DBGMSG("conc_mob: %f conc_immob: %f previous_conc_mob: %f previous_conc_immob: %f conc_average: %f diff: %f por_mob: %f por_immob: %f time_dt: %f\n",
347 // // conc_mob, conc_immob, previous_conc_mob, previous_conc_immob, conc_average, diff_vec[sbi], por_mob, por_immob, time_->dt());
348 // concentration_matrix_[sbi][loc_el] = conc_mob;
349 // conc_immobile[sbi][loc_el] = conc_immob;
350 // }
351 // }
352 
353 
354  // if porosity_immobile == 0 then mobile concentration stays the same
355  // and immobile concentration cannot change
356  if (por_immob == 0.0) return conc_immobile;
357 
358  double exponent,
359  temp_exponent = (por_mob + por_immob) / (por_mob * por_immob) * time_->dt();
360 
361  for (sbi = 0; sbi < names_.size(); sbi++) //over all substances
362  {
363  exponent = diff_vec[sbi] * temp_exponent;
364  //previous values
365  previous_conc_mob = concentration_matrix_[sbi][loc_el];
366  previous_conc_immob = conc_immobile[sbi][loc_el];
367 
368  // ---compute average concentration------------------------------------------
369  conc_average = ((por_mob * previous_conc_mob) + (por_immob * previous_conc_immob))
370  / (por_mob + por_immob);
371 
372  conc_max = std::max(previous_conc_mob-conc_average, previous_conc_immob-conc_average);
373 
374  if( conc_max <= (2*scheme_tolerance_/(exponent*exponent)*conc_average) ) // forward euler
375  {
376  //DBGMSG("forward euler\n");
377  double temp = diff_vec[sbi]*(previous_conc_immob - previous_conc_mob) * time_->dt();
378  // ---compute concentration in mobile area
379  conc_mob = temp / por_mob + previous_conc_mob;
380 
381  // ---compute concentration in immobile area
382  conc_immob = -temp / por_immob + previous_conc_immob;
383  }
384  else //analytic solution
385  {
386  //DBGMSG("analytic\n");
387  double temp = exp(-exponent);
388  // ---compute concentration in mobile area
389  conc_mob = (previous_conc_mob - conc_average) * temp + conc_average;
390 
391  // ---compute concentration in immobile area
392  conc_immob = (previous_conc_immob - conc_average) * temp + conc_average;
393 
394 // DBGMSG("conc_mob: %f conc_immob: %f previous_conc_mob: %f previous_conc_immob: %f conc_average: %f diff: %f por_mob: %f por_immob: %f time_dt: %f\n",
395 // conc_mob, conc_immob, previous_conc_mob, previous_conc_immob, conc_average, diff_vec[sbi], por_mob, por_immob, time_->dt());
396  }
397 
398  concentration_matrix_[sbi][loc_el] = conc_mob;
399  conc_immobile[sbi][loc_el] = conc_immob;
400  }
401  //*/
402 
403  return conc_immobile;
404 }
405 
406 
408 {
409  //DBGMSG("DualPorosity - allocate_output_mpi.\n");
410  int sbi, n_subst, ierr;
411  n_subst = names_.size();
412 
413  vconc_immobile = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
414  vconc_immobile_out = (Vec*) xmalloc(n_subst * (sizeof(Vec))); // extend to all
415 
416 
417  for (sbi = 0; sbi < n_subst; sbi++) {
418  ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1, distribution_->lsize(), mesh_->n_elements(), conc_immobile[sbi],
419  &vconc_immobile[sbi]);
420  VecZeroEntries(vconc_immobile[sbi]);
421 
422  // if(rank == 0)
423  ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1, mesh_->n_elements(), conc_immobile_out[sbi], &vconc_immobile_out[sbi]);
424  VecZeroEntries(vconc_immobile_out[sbi]);
425  }
426 
427  // create output vector scatter
428  IS is;
429  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el_, PETSC_COPY_VALUES, &is); //WithArray
430  VecScatterCreate(vconc_immobile[0], is, vconc_immobile_out[0], PETSC_NULL, &vconc_out_scatter);
431  ISDestroy(&(is));
432 }
433 
434 
436 {
437  //DBGMSG("DualPorosity - output_vector_gather.\n");
438  unsigned int sbi;
439 
440  //PetscViewer inviewer;
441 
442  for (sbi = 0; sbi < names_.size(); sbi++) {
443  VecScatterBegin(vconc_out_scatter, vconc_immobile[sbi], vconc_immobile_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
444  VecScatterEnd(vconc_out_scatter, vconc_immobile[sbi], vconc_immobile_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
445  }
446  //VecView(transport->vconc[0],PETSC_VIEWER_STDOUT_WORLD);
447  //VecView(transport->vconc_out[0],PETSC_VIEWER_STDOUT_WORLD);
448 }
449 
450 
452 {
453  //DBGMSG("DualPorosity output\n");
455 
456  // Register fresh output data
459 
462 }
463 
FieldSet & data()
Definition: equation.hh:197
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:237
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:487
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:365
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:172
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:733
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:120
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:104
#define ASSERT_LESS(a, b)
Definition: global_defs.h:163
#define START_TIMER(tag)
Starts a timer with specified tag.
void initialize_fields()
Initializes field sets.
Mesh * mesh_
Definition: equation.hh:227
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:95
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:218
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:75
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:137
const Selection & close() const
Input::Record input_record_
Definition: equation.hh:230
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:112
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:534
Template for classes storing finite set of named values.
TimeGovernor * time_
Definition: equation.hh:228
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:390