Flow123d
dual_por_exchange.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstring>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <boost/foreach.hpp>
6 
7 #include "reaction/reaction.hh"
9 #include "system/system.hh"
10 #include "system/sys_profiler.hh"
11 #include <petscmat.h>
12 
13 #include "la/distribution.hh"
14 #include "mesh/mesh.h"
15 #include "mesh/elements.h"
16 #include "mesh/region.hh"
18 
21 #include "reaction/sorption_mob.hh"
25 
26 using namespace Input::Type;
27 using namespace std;
28 
29 
30 //it is currently switched of (by "0") until the reference tests are created
31 const double DualPorosity::min_dt = 0;
32 
34  = EqData().output_fields.make_output_field_selection("DualPorosity_Output")
35  .close();
36 
38  = Record("DualPorosity",
39  "Dual porosity model in transport problems.\n"
40  "Provides computing the concentration of substances in mobile and immobile zone.\n"
41  )
43  .declare_key("input_fields", Array(DualPorosity::EqData().make_field_descriptor_type("DualPorosity")), Default::obligatory(),
44  "Containes region specific data necessary to construct dual porosity model.")
45 
46  .declare_key("reaction_mobile", ReactionTerm::input_type, Default::optional(), "Reaction model in mobile zone.")
47  .declare_key("reaction_immobile", ReactionTerm::input_type, Default::optional(), "Reaction model in immobile zone.")
48 
49  .declare_key("output_fields", Array(EqData::output_selection),
50  Default("conc_immobile"), "List of fields to write to output stream.");
51 
53 {
54  *this += diffusion_rate_immobile
55  .name("diffusion_rate_immobile")
56  .desc("Diffusion coefficient of non-equilibrium linear exchange between mobile and immobile zone.")
57  .input_default("0")
58  .units("");
59 
60  *this += porosity_immobile
61  .name("porosity_immobile")
62  .desc("Porosity of the immobile zone.")
63  .input_default("0")
64  .units("1");
65 
66  *this += init_conc_immobile
67  .name("init_conc_immobile")
68  .desc("Initial concentration of substances in the immobile zone.")
69  .units("M/L^3");
70 
71  //creating field for porosity that is set later from the governing equation (transport)
72  *this +=porosity
73  .name("porosity")
74  .units("1")
75  .just_copy();
76 
77  output_fields += *this;
78  output_fields += conc_immobile.name("conc_immobile").units("M/L^3");
79 }
80 
82  : ReactionTerm(init_mesh, in_rec)
83 {
85 }
86 
88 {
89  if(reaction_mobile != nullptr) delete reaction_mobile;
90  if(reaction_immobile != nullptr) delete reaction_immobile;
91 
92 // if(!output_rec.is_empty())
93  {
94  VecDestroy(vconc_immobile);
95  VecDestroy(vconc_immobile_out);
96  }
97 
98  for (unsigned int sbi = 0; sbi < names_.size(); sbi++)
99  {
100  //no mpi vectors
101  xfree(conc_immobile[sbi]);
102  }
103 
105 }
106 
107 
109 {
110  data_.set_field(data_.porosity.name(),por_m);
111 
112 
113 }
114 
117  if ( reactions_it )
118  {
119  if (reactions_it->type() == Linear_reaction::input_type ) {
120  reaction_mobile = new Linear_reaction(*mesh_, *reactions_it);
121 
122  } else
123  if (reactions_it->type() == Pade_approximant::input_type) {
124  reaction_mobile = new Pade_approximant(*mesh_, *reactions_it);
125  } else
126  if (reactions_it->type() == SorptionMob::input_type ) {
127  reaction_mobile = new SorptionMob(*mesh_, *reactions_it);
128  } else
129  if (reactions_it->type() == DualPorosity::input_type ) {
130  xprintf(UsrErr, "Dual porosity model cannot have another descendant dual porosity model.\n");
131  } else
132  if (reactions_it->type() == Semchem_interface::input_type )
133  {
134  xprintf(UsrErr, "Semchem chemistry model is not supported at current time.\n");
135  } else
136  {
137  xprintf(UsrErr, "Wrong reaction type in DualPorosity model.\n");
138  }
139  } else
140  {
141  reaction_mobile = nullptr;
142  }
143 
144  reactions_it = input_record_.find<Input::AbstractRecord>("reaction_immobile");
145  if ( reactions_it )
146  {
147  if (reactions_it->type() == Linear_reaction::input_type ) {
148  reaction_immobile = new Linear_reaction(*mesh_, *reactions_it);
149 
150  } else
151  if (reactions_it->type() == Pade_approximant::input_type) {
152  reaction_immobile = new Pade_approximant(*mesh_, *reactions_it);
153  } else
154  if (reactions_it->type() == SorptionImmob::input_type ) {
155  reaction_immobile = new SorptionImmob(*mesh_, *reactions_it);
156  } else
157  if (reactions_it->type() == DualPorosity::input_type ) {
158  xprintf(UsrErr, "Dual porosity model cannot have another descendant dual porosity model.\n");
159  } else
160  if (reactions_it->type() == Semchem_interface::input_type )
161  {
162  xprintf(UsrErr, "Semchem chemistry model is not supported at current time.\n");
163  } else
164  {
165  xprintf(UsrErr, "Unknown reactions type in DualPorosity model.\n");
166  }
167  } else
168  {
169  reaction_immobile = nullptr;
170  }
171 
172 }
173 
175 {
176  //DBGMSG("DualPorosity - initialize.\n");
177  ASSERT(distribution != nullptr, "Distribution has not been set yet.\n");
178  ASSERT(time_ != nullptr, "Time governor has not been set yet.\n");
179  ASSERT(output_stream_,"Null output stream.");
180  ASSERT_LESS(0, names_.size());
181 
184 
185  //setting fields that are set from input file
188 
189 
190 
191  data_.set_mesh(*mesh_);
192  data_.set_limit_side(LimitSide::right);
193  output_array = input_record_.val<Input::Array>("output_fields");
194 
195 
196  //DBGMSG("dual_por init_from_input\n");
197 
198 
199 
200  data_.set_time(*time_);
201 
202  //allocating memory for immobile concentration matrix
203  conc_immobile = (double**) xmalloc(names_.size() * sizeof(double*));
204  conc_immobile_out = (double**) xmalloc(names_.size() * sizeof(double*));
205  for (unsigned int sbi = 0; sbi < names_.size(); sbi++)
206  {
207  conc_immobile[sbi] = (double*) xmalloc(distribution->lsize() * sizeof(double));
208  conc_immobile_out[sbi] = (double*) xmalloc(distribution->size() * sizeof(double));
209  }
210 
211  //DBGMSG("DualPorosity - init_conc_immobile.\n");
212  //setting initial condition for immobile concentration matrix
213  for (unsigned int loc_el = 0; loc_el < distribution->lsize(); loc_el++)
214  {
215  unsigned int index = el_4_loc[loc_el];
216  ElementAccessor<3> ele_acc = mesh_->element_accessor(index);
217  arma::vec value = data_.init_conc_immobile.value(ele_acc.centre(), ele_acc);
218 
219  for (int sbi=0; sbi < names_.size(); sbi++)
220  {
221  conc_immobile[sbi][loc_el] = value(sbi);
222  }
223  }
224 
225  //initialization of output
230 
231  for (int sbi=0; sbi<names_.size(); sbi++)
232  {
233  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
234  std::shared_ptr<FieldElementwise<3, FieldValue<3>::Scalar> > output_field_ptr(
236  data_.conc_immobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
237  }
238  data_.output_fields.set_limit_side(LimitSide::right);
240 
241  // write initial condition
245 
246  // creating reactions from input and setting their parameters
248 
249  // assign porosities to reactions
250  SorptionMob *sorption_mob = dynamic_cast<SorptionMob *>(reaction_mobile);
251  SorptionImmob *sorption_immob = dynamic_cast<SorptionImmob *>(reaction_immobile);
252 
253  if (sorption_mob != nullptr)
254  {
255  sorption_mob->set_porosity(data_.porosity);
257  }
258  if (sorption_immob != nullptr)
259  {
260  sorption_immob->set_porosity(data_.porosity);
262  }
263 
264 
265  if(reaction_mobile != nullptr)
266  {
271  .zero_time_step();
272  }
273 
274  if(reaction_immobile != nullptr)
275  {
280  .zero_time_step();
281  }
282 
283 }
284 
285 
287 {
288  //DBGMSG("DualPorosity - update solution\n");
289  data_.set_time(*time_);
290 
291  START_TIMER("dual_por_exchange_step");
292  for (unsigned int loc_el = 0; loc_el < distribution->lsize(); loc_el++)
293  {
295  }
296  END_TIMER("dual_por_exchange_step");
297 
300 }
301 
302 
303 double **DualPorosity::compute_reaction(double **concentrations, int loc_el)
304 {
305  double conc_avg = 0.0;
306  unsigned int sbi, sbi_loc;
307  double cm, pcm, ci, pci, por_m, por_imm, temp_exp;
308 
309  ElementFullIter ele = mesh_->element(el_4_loc[loc_el]);
310  por_m = data_.porosity.value(ele->centre(),ele->element_accessor());
311  por_imm = data_.porosity_immobile.value(ele->centre(),ele->element_accessor());
312  arma::Col<double> diff_vec = data_.diffusion_rate_immobile.value(ele->centre(), ele->element_accessor());
313 
314  if(time_->dt() >= min_dt)
315  {
316  //TODO:
317  //for (sbi = 0; sbi < n_substances_; sbi++) //over substances involved in dual porosity model
318  for (sbi = 0; sbi < names_.size(); sbi++) //over all substances
319  {
320  //sbi_loc = substance_id[sbi]; //mapping to global substance index
321  //previous values
322  pcm = concentration_matrix_[sbi][loc_el];
323  pci = conc_immobile[sbi][loc_el];
324 
325  // ---compute average concentration------------------------------------------
326  conc_avg = ((por_m * pcm) + (por_imm * pci)) / (por_m + por_imm);
327 
328  if ((conc_avg != 0.0) && (por_imm != 0.0)) {
329  temp_exp = exp(-diff_vec[sbi] * ((por_m + por_imm) / (por_m * por_imm)) * time_->dt());
330  // ---compute concentration in mobile area-----------------------------------
331  cm = (pcm - conc_avg) * temp_exp + conc_avg;
332 
333  // ---compute concentration in immobile area---------------------------------
334  ci = (pci - conc_avg) * temp_exp + conc_avg;
335  // --------------------------------------------------------------------------
336 // DBGMSG("cm: %f ci: %f pcm: %f pci: %f conc_avg: %f diff: %f por_m: %f por_imm: %f time_dt: %f\n",
337 // cm, ci, pcm, pci, conc_avg, diff_vec[sbi], por_m, por_imm, time_->dt());
338  concentration_matrix_[sbi][loc_el] = cm;
339  conc_immobile[sbi][loc_el] = ci;
340  }
341  }
342  }
343  else{
344 
345  for (sbi = 0; sbi < names_.size(); sbi++) {
346  //previous values
347  pcm = concentration_matrix_[sbi][loc_el];
348  pci = conc_immobile[sbi][loc_el];
349 
350  if (por_imm != 0.0) {
351  temp_exp = diff_vec[sbi]*(pci - pcm) * time_->dt();
352  // ---compute concentration in mobile area-----------------------------------
353  cm = temp_exp / por_m + pcm;
354 
355  // ---compute concentration in immobile area---------------------------------
356  ci = -temp_exp / por_imm + pci;
357  // --------------------------------------------------------------------------
358 
359  concentration_matrix_[sbi][loc_el] = cm;
360  conc_immobile[sbi][loc_el] = ci;
361  }
362  }
363  }
364  return conc_immobile;
365 }
366 
367 
369 {
370  //DBGMSG("DualPorosity - allocate_output_mpi.\n");
371  int sbi, n_subst, ierr, rank, np; //, i, j, ph;
372  n_subst = names_.size();
373 
374  vconc_immobile = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
375  vconc_immobile_out = (Vec*) xmalloc(n_subst * (sizeof(Vec))); // extend to all
376 
377 
378  for (sbi = 0; sbi < n_subst; sbi++) {
379  ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1, distribution->lsize(), mesh_->n_elements(), conc_immobile[sbi],
380  &vconc_immobile[sbi]);
381  VecZeroEntries(vconc_immobile[sbi]);
382 
383  // if(rank == 0)
384  ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1, mesh_->n_elements(), conc_immobile_out[sbi], &vconc_immobile_out[sbi]);
385  VecZeroEntries(vconc_immobile_out[sbi]);
386  }
387 }
388 
389 
391 {
392  //DBGMSG("DualPorosity - output_vector_gather.\n");
393  unsigned int sbi/*, rank, np*/;
394  IS is;
395  VecScatter vconc_out_scatter;
396  //PetscViewer inviewer;
397 
398 // MPI_Barrier(PETSC_COMM_WORLD);
399 // MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
400 // MPI_Comm_size(PETSC_COMM_WORLD, &np);
401 
402 
403  //ISCreateStride(PETSC_COMM_SELF,mesh_->n_elements(),0,1,&is);
404  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el, PETSC_COPY_VALUES, &is); //WithArray
405  VecScatterCreate(vconc_immobile[0], is, vconc_immobile_out[0], PETSC_NULL, &vconc_out_scatter);
406  for (sbi = 0; sbi < names_.size(); sbi++) {
407  VecScatterBegin(vconc_out_scatter, vconc_immobile[sbi], vconc_immobile_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
408  VecScatterEnd(vconc_out_scatter, vconc_immobile[sbi], vconc_immobile_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
409  }
410  //VecView(transport->vconc[0],PETSC_VIEWER_STDOUT_WORLD);
411  //VecView(transport->vconc_out[0],PETSC_VIEWER_STDOUT_WORLD);
412  VecScatterDestroy(&(vconc_out_scatter));
413  ISDestroy(&(is));
414 }
415 
416 
418 {
419  //DBGMSG("DualPorosity output\n");
421 
422  // Register fresh output data
425 
428 }
429