Flow123d
transport.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  *
17  * You should have received a copy of the GNU General Public License along with this program; if not,
18  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
19  *
20  *
21  * $Id$
22  * $Revision$
23  * $LastChangedBy$
24  * $LastChangedDate$
25  *
26  * @file
27  * @ingroup transport
28  * @brief Transport
29  *
30  *
31  */
32 
33 
34 #include <memory>
35 
36 #include "system/system.hh"
37 #include "system/sys_profiler.hh"
38 
39 #include "mesh/mesh.h"
40 #include "mesh/partitioning.hh"
41 #include "transport/transport.h"
42 
43 #include "io/output.h"
44 
45 //#include "ppfcs.h"
46 //#include "btc.h" XX
47 //#include "reaction.h" XX
48 
49 #include "la/distribution.hh"
50 
51 #include "la/sparse_graph.hh"
52 #include <iostream>
53 #include <iomanip>
54 #include <string>
55 
56 // TODO: move partitioning into mesh_ and remove this include
57 #include "flow/darcy_flow_mh.hh"
58 #include "flow/old_bcd.hh"
59 #include "input/accessors.hh"
60 #include "input/input_type.hh"
61 
63 
64 #include "fields/field_base.hh"
65 #include "fields/field_values.hh"
67 #include "reaction/isotherm.hh" // SorptionType enum
68 
69 namespace IT = Input::Type;
70 
72  .add_value(none,"none","No sorption considered")
73  .add_value(Isotherm::linear,"linear","Linear isotherm described sorption considered.")
74  .add_value(Isotherm::freundlich,"freundlich","Freundlich isotherm described sorption considered")
75  .add_value(Isotherm::langmuir,"langmuir","Langmuir isotherm described sorption considered")
76  .close();
77 
78 
80  EqData().output_fields.make_output_field_selection("ConvectionTransport_Output")
81  .close();
82 
83 
85 {
86  ADD_FIELD(bc_conc, "Boundary conditions for concentrations.", "0.0");
87  ADD_FIELD(init_conc, "Initial concentrations.", "0.0");
88 
90 
91  output_fields += *this;
92  output_fields += conc_mobile.name("conc").units("M/L^3");
93 }
94 
95 /*
96 RegionSet ConvectionTransport::EqData::read_descriptor_hook(Input::Record rec) {
97  // Base method EqDataBase::read_boundary_list_item must be called first!
98  RegionSet domain = EqDataBase::read_boundary_list_item(rec);
99  FilePath bcd_file;
100 
101  // read transport boundary conditions using old file format .tbc
102  if (rec.opt_val("old_boundary_file", bcd_file) )
103  OldBcdInput::instance()->read_transport(bcd_file, bc_conc);
104 
105  return domain;
106 }*/
107 
108 
109 
111 : TransportBase(init_mesh, in_rec)
112 {
113  this->eq_data_ = &data_;
114 
115  //mark type of the equation of convection transport (created in EquationBase constructor) and it is fixed
116  time_ = new TimeGovernor(in_rec.val<Input::Record>("time"));
118 
119  //output_mark_type = this->mark_type() | TimeGovernor::marks().type_fixed_time() | time_->marks().type_output();
120  //time_->marks().add_time_marks(0.0,
121  // in_rec.val<Input::Record>("output_stream").val<double>("time_step"),
122  // time_->end_time(), output_mark_type );
123 
125 
126  in_rec.val<Input::Array>("substances").copy_to(subst_names_);
127  n_subst_ = subst_names_.size();
128  INPUT_CHECK(n_subst_ >= 1 ,"Number of substances must be positive.\n");
129 
130  Input::Iterator<Input::Record> it = in_rec.find<Input::Record>("mass_balance");
131  if (it) mass_balance_ = new MassBalance(this, *it);
132 
138  data_.set_mesh(init_mesh);
139  data_.set_input_list( in_rec.val<Input::Array>("input_fields") );
140  data_.set_limit_side(LimitSide::right);
141  //data_.set_time(*time_);
142 
143 
144  sub_problem = 0;
145 
149  transport_matrix_time = -1.0; // or -infty
151  need_time_rescaling=true;
152 
153  // register output vectors
154  output_rec = in_rec.val<Input::Record>("output_stream");
158 
159  for (int sbi=0; sbi<n_subst_; sbi++)
160  {
161  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
162  std::shared_ptr<FieldElementwise<3, FieldValue<3>::Scalar> > output_field_ptr(new FieldElementwise<3, FieldValue<3>::Scalar>(out_conc[MOBILE][sbi], n_subst_, mesh_->n_elements()));
163  data_.conc_mobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
164  }
165  data_.output_fields.set_limit_side(LimitSide::right);
169 
170 }
171 
172 
173 //=============================================================================
174 // MAKE TRANSPORT
175 //=============================================================================
177 
178  F_ENTRY;
179 
180  //int rank, np, i, j, k, row_MH, a;
181  //struct DarcyFlowMH *water=transport->problem->water;
182 /*
183  SparseGraph *ele_graph = new SparseGraphMETIS(mesh_->n_elements()); // graph for partitioning
184  Distribution init_ele_ds = ele_graph->get_distr(); // initial distr.
185  int *loc_part = new int[init_ele_ds.lsize()]; // partitionig in initial distribution
186 
187  make_element_connection_graph(mesh_, ele_graph, true);
188  WARN_ASSERT(ele_graph->is_symmetric(),"Attention graph for partitioning is not symmetric!\n");
189 
190  ele_graph->partition(loc_part);
191 
192  delete ele_graph;
193 */
194  int * id_4_old = new int[mesh_->n_elements()];
195  int i = 0;
196  FOR_ELEMENTS(mesh_, ele) id_4_old[i++] = ele.index();
198  delete[] id_4_old;
199 
200  // TODO: make output of partitioning is usefull but makes outputs different
201  // on different number of processors, which breaks tests.
202  //
203  // Possible solution:
204  // - have flag in ini file to turn this output ON
205  // - possibility to have different ref_output for different num of proc.
206  // - or do not test such kind of output
207  //
208  //FOR_ELEMENTS(mesh_, ele) {
209  // ele->pid=el_ds->get_proc(row_4_el[ele.index()]);
210  //}
211 
212 }
213 
214 
215 
217 {
218  unsigned int sbi, ph;
219 
220  if (mass_balance_ != NULL)
221  delete mass_balance_;
222 
223  //Destroy mpi vectors at first
224  VecDestroy(&v_sources_corr);
225  MatDestroy(&tm);
226 
227  VecDestroy(vconc);
228  VecDestroy(bcvcorr);
229  VecDestroy(vpconc);
230  VecDestroy(vcumulative_corr);
231  VecDestroy(vconc_out);
232 
233  for (sbi = 0; sbi < n_subst_; sbi++) {
234  //no mpi vectors
235  xfree(sources_density[sbi]);
236  xfree(sources_conc[sbi]);
237  xfree(sources_sigma[sbi]);
238  xfree(cumulative_corr[sbi]);
239  }
240 
241 
243 
248 
249  delete output_stream_;
250 
251  /*
252  for (ph = 0; ph < MAX_PHASES; ph++) {
253  if ((sub_problem & ph) == ph) {
254  for (sbi = 0; sbi < n_subst_; sbi++) {
255  xfree(conc[ph][sbi]);
256  xfree(out_conc[ph][sbi]);
257  }
258  xfree(conc[ph]);
259  xfree(out_conc[ph]);
260  }
261  }
262 
263  DBGMSG("inner conc vecs freed\n");
264 
265  xfree(conc);
266  xfree(out_conc);
267  //*/
268 }
269 
270 /*
271 //=============================================================================
272 // GET REACTION
273 //=============================================================================
274 void ConvectionTransport::get_reaction(int i,oReaction *reaction) {
275  react[i] = *reaction;
276 }
277 */
278 //=============================================================================
279 // RECOMPUTE MATRICES
280 //=============================================================================
281 
282 /*
283 void ConvectionTransport::set_flow_field_vector(const MH_DofHandler &dh){
284  // DBGMSG("set_flow_fieldvec\n");
285  mh_dh = &dh;
286  create_transport_matrix_mpi();
287 };
288 */
289 /*
290 void ConvectionTransport::set_cross_section_field(const Field< 3, FieldValue<3>::Scalar > &cross_section) {
291  data_.cross_section.copy_from(cross_section);
292 }
293 */
294 
295 
296 
298 {
299  FOR_ELEMENTS(mesh_, elem)
300  {
301  if (!el_ds->is_local(row_4_el[elem.index()])) continue;
302 
303  unsigned int index = row_4_el[elem.index()] - el_ds->begin();
304  ElementAccessor<3> ele_acc = mesh_->element_accessor(elem.index());
305  arma::vec value = data_.init_conc.value(elem->centre(), ele_acc);
306 
307  for (int sbi=0; sbi<n_subst_; sbi++)
308  {
309  conc[MOBILE][sbi][index] = value(sbi);
310  //pconc[MOBILE][sbi][index] = value(sbi);
311  }
312  }
313 
314 }
315 
316 //=============================================================================
317 // ALLOCATE OF TRANSPORT VARIABLES (ELEMENT & NODES)
318 //=============================================================================
320 
321  int i, sbi, n_subst, ph; //, j;
322  //ElementIter elm;
323  n_subst = n_subst_;
324 
325 
326  // printf("%d\t\n",n_substances);
327  // getchar();
328 
329  sources_corr = new double[el_ds->lsize()];
330  sources_density = (double**) xmalloc(n_subst * sizeof(double*));
331  sources_conc = (double**) xmalloc(n_subst * sizeof(double*));
332  sources_sigma = (double**) xmalloc(n_subst * sizeof(double*));
333 
334  cumulative_corr = (double**) xmalloc(n_subst * sizeof(double*));
335  for (sbi = 0; sbi < n_subst; sbi++) {
336  sources_density[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
337  sources_conc[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
338  sources_sigma[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
339  cumulative_corr[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
340  }
341 
342  conc = (double***) xmalloc(MAX_PHASES * sizeof(double**));
343  //pconc = (double***) xmalloc(MAX_PHASES * sizeof(double**));
344  out_conc = (double***) xmalloc(MAX_PHASES * sizeof(double**));
345  //transport->node_conc = (double****) xmalloc(MAX_PHASES * sizeof(double***));
346  for (ph = 0; ph < MAX_PHASES; ph++) {
347  if ((sub_problem & ph) == ph) {
348  conc[ph] = (double**) xmalloc(n_subst * sizeof(double*)); //(MAX_PHASES * sizeof(double*));
349  //pconc[ph] = (double**) xmalloc(n_subst * sizeof(double*));
350  out_conc[ph] = (double**) xmalloc(n_subst * sizeof(double*));
351  // transport->node_conc[sbi] = (double***) xmalloc(MAX_PHASES * sizeof(double**));
352  //}
353  //}
354  for (sbi = 0; sbi < n_subst; sbi++) {
355  conc[ph][sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
356  //pconc[ph][sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
357  out_conc[ph][sbi] = (double*) xmalloc(el_ds->size() * sizeof(double));
358  // transport->node_conc[sbi][ph] = (double**)xmalloc((mesh__->n_elements() ) * sizeof(double*));
359  for (i = 0; i < el_ds->lsize(); i++) {
360  conc[ph][sbi][i] = 0.0;
361  //pconc[ph][sbi][i] = 0.0;
362 
363  }
364  for (i = 0; i < el_ds->size(); i++) {
365  out_conc[ph][sbi][i] = 0.0;
366  }
367  /*
368  i = 0;
369  FOR_ELEMENTS(elm){
370  transport->node_conc[sbi][ph][i++]=(double*)xmalloc((elm->n_nodes) * sizeof(double));
371  for(j = 0 ;j < elm->n_nodes ; j++)
372  transport->node_conc[sbi][ph][i-1][j] = 0.0;
373  }*/
374  }
375  } else {
376  conc[ph] = NULL;
377  //pconc[ph] = NULL;
378  out_conc[ph] = NULL;
379  //transport->node_conc[sbi][ph] = NULL;
380  }
381  }
382 }
383 
384 //=============================================================================
385 // ALLOCATION OF TRANSPORT VECTORS (MPI)
386 //=============================================================================
388 
389  int sbi, n_subst, ierr, rank, np; //, i, j, ph;
390  //ElementIter elm;
391  n_subst = n_subst_;
392 
393  MPI_Barrier(PETSC_COMM_WORLD);
394  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
395  MPI_Comm_size(PETSC_COMM_WORLD, &np);
396 
397  bcvcorr = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
398  vconc = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
399  vpconc = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
400  vcumulative_corr = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
401 
402 
403  // if( rank == 0)
404  vconc_out = (Vec*) xmalloc(n_subst * (sizeof(Vec))); // extend to all
405 
406 
407  ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), PETSC_DECIDE,
409 
410  for (sbi = 0; sbi < n_subst; sbi++) {
411  ierr = VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &bcvcorr[sbi]);
412  VecZeroEntries(bcvcorr[sbi]);
413  ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(), conc[MOBILE][sbi],
414  &vconc[sbi]);
415 
416 // ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(),
417 // pconc[MOBILE][sbi], &vpconc[sbi]);
418  ierr = VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &vpconc[sbi]);
419  VecZeroEntries(vconc[sbi]);
420  VecZeroEntries(vpconc[sbi]);
421 
422  // SOURCES
423  ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
424  cumulative_corr[sbi],&vcumulative_corr[sbi]);
425 
426  // if(rank == 0)
427  ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1, mesh_->n_elements(), out_conc[MOBILE][sbi], &vconc_out[sbi]);
428 
429  VecZeroEntries(vcumulative_corr[sbi]);
430  VecZeroEntries(vconc_out[sbi]);
431  }
432 
433 
434  ierr = MatCreateAIJ(PETSC_COMM_WORLD, el_ds->lsize(), el_ds->lsize(), mesh_->n_elements(),
435  mesh_->n_elements(), 16, PETSC_NULL, 4, PETSC_NULL, &tm);
436 
437 }
438 
439 
441 {
443 
444  unsigned int sbi, loc_el;
445 
446  // Assembly bcvcorr vector
447  for(sbi=0; sbi < n_subst_; sbi++) VecZeroEntries(bcvcorr[sbi]);
448 
449 
450  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
451  elm = mesh_->element(el_4_loc[loc_el]);
452  if (elm->boundary_idx_ != NULL) {
453  unsigned int new_i = row_4_el[elm.index()];
454  double csection = data_.cross_section.value(elm->centre(), elm->element_accessor());
455  double por_m = data_.porosity.value(elm->centre(), elm->element_accessor());
456 
457  FOR_ELEMENT_SIDES(elm,si) {
458  Boundary *b = elm->side(si)->cond();
459  if (b != NULL) {
460  double flux = mh_dh->side_flux( *(elm->side(si)) );
461  if (flux < 0.0) {
462  double aij = -(flux / (elm->measure() * csection * por_m) );
463 
464  arma::vec value = data_.bc_conc.value( b->element()->centre(), b->element_accessor() );
465  for (sbi=0; sbi<n_subst_; sbi++)
466  VecSetValue(bcvcorr[sbi], new_i, value[sbi] * aij, ADD_VALUES);
467  }
468  }
469  }
470 
471  }
472  }
473 
474  for (sbi=0; sbi<n_subst_; sbi++) VecAssemblyBegin(bcvcorr[sbi]);
475  for (sbi=0; sbi<n_subst_; sbi++) VecAssemblyEnd(bcvcorr[sbi]);
476 
477 
478  //VecView(bcvcorr[0],PETSC_VIEWER_STDOUT_SELF);
479  //exit(0);
480 }
481 
482 
483 //=============================================================================
484 // COMPUTE SOURCES
485 //=============================================================================
487 
488  //temporary variables
489  unsigned int loc_el;
490  double conc_diff, csection;
491  ElementAccessor<3> ele_acc;
492  arma::vec3 p;
493 
494  //TODO: would it be possible to check the change in data for chosen substance? (may be in multifields?)
495 
496  //checking if the data were changed
497  if( (data_.sources_density.changed() )
498  || (data_.sources_conc.changed() )
499  || (data_.sources_sigma.changed() )
500  || (data_.cross_section.changed()))
501  {
502  START_TIMER("sources_reinit");
503  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
504  {
505  ele_acc = mesh_->element_accessor(el_4_loc[loc_el]);
506  p = ele_acc.centre();
507 
508  csection = data_.cross_section.value(p, ele_acc);
509 
510  //if(data_.sources_density.changed_during_set_time)
511  sources_density[sbi][loc_el] = data_.sources_density.value(p, ele_acc)(sbi)*csection;
512 
513  //if(data_.sources_conc.changed_during_set_time)
514  sources_conc[sbi][loc_el] = data_.sources_conc.value(p, ele_acc)(sbi);
515 
516  //if(data_.sources_sigma.changed_during_set_time)
517  sources_sigma[sbi][loc_el] = data_.sources_sigma.value(p, ele_acc)(sbi)*csection;
518  }
519  }
520 
521  //now computing source concentrations: density - sigma (source_conc - actual_conc)
522  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
523  {
524  conc_diff = sources_conc[sbi][loc_el] - conc[MOBILE][sbi][loc_el];
525  if ( conc_diff > 0.0)
526  sources_corr[loc_el] = ( sources_density[sbi][loc_el]
527  + conc_diff * sources_sigma[sbi][loc_el] )
528  * time_->dt();
529  else
530  sources_corr[loc_el] = sources_density[sbi][loc_el] * time_->dt();
531  }
532 }
533 
535 
536  //temporary variables
537  unsigned int loc_el;
538  double conc_diff, csection;
539  ElementAccessor<3> ele_acc;
540  arma::vec3 p;
541 
542  double *pconc;
543  VecGetArray(vpconc[sbi], &pconc);
544 
545  //TODO: would it be possible to check the change in data for chosen substance? (may be in multifields?)
546 
547  //checking if the data were changed
548  if( (data_.sources_density.changed() )
549  || (data_.sources_conc.changed() )
550  || (data_.sources_sigma.changed() )
551  || (data_.cross_section.changed()))
552  {
553  START_TIMER("sources_reinit");
554  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
555  {
556  ele_acc = mesh_->element_accessor(el_4_loc[loc_el]);
557  p = ele_acc.centre();
558 
559  csection = data_.cross_section.value(p, ele_acc);
560 
561  //if(data_.sources_density.changed_during_set_time)
562  sources_density[sbi][loc_el] = data_.sources_density.value(p, ele_acc)(sbi)*csection;
563 
564  //if(data_.sources_conc.changed_during_set_time)
565  sources_conc[sbi][loc_el] = data_.sources_conc.value(p, ele_acc)(sbi);
566 
567  //if(data_.sources_sigma.changed_during_set_time)
568  sources_sigma[sbi][loc_el] = data_.sources_sigma.value(p, ele_acc)(sbi)*csection;
569  }
570  }
571 
572  //now computing source concentrations: density - sigma (source_conc - actual_conc)
573  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
574  {
575  conc_diff = sources_conc[sbi][loc_el] - pconc[loc_el];
576  if ( conc_diff > 0.0)
577  sources_corr[loc_el] = sources_density[sbi][loc_el] + conc_diff * sources_sigma[sbi][loc_el];
578  else
579  sources_corr[loc_el] = sources_density[sbi][loc_el];
580  }
581 }
582 
583 
585 {
586  ASSERT_EQUAL(time_->tlevel(), 0);
587 
589  data_.set_time(*time_);
590 
592 
593 
594  // write initial condition
595  output_data();
596 }
597 
598 
599 
601 
602  START_TIMER("convection-one step");
603 
604  unsigned int loc_el,sbi;
605 
606  START_TIMER("data reinit");
607  data_.set_time(*time_); // set to the last computed time
608 
609  ASSERT(mh_dh, "Null MH object.\n" );
610  // update matrix and sources if neccessary
611 
612 
615 
616  // need new fixation of the time step
617 
620 
622  // scale boundary sources
623  for (sbi=0; sbi<n_subst_; sbi++) VecScale(bcvcorr[sbi], time_->estimate_dt());
624 
625  need_time_rescaling = true;
626  } else {
627  // possibly read boundary conditions
628  if (data_.bc_conc.changed() ) {
630  // scale boundary sources
631  for (sbi=0; sbi<n_subst_; sbi++) VecScale(bcvcorr[sbi], time_->estimate_dt());
632  }
633  }
634 
635  if (need_time_rescaling) {
637  // rescale matrix
638  //for (unsigned int sbi=0; sbi<n_substances; sbi++) VecScale(bcvcorr[sbi], time_->dt()/time_->estimate_dt());
639  MatShift(tm, -1.0);
640  MatScale(tm, time_->estimate_dt()/time_->dt() );
641  MatShift(tm, 1.0);
642 
643  for (sbi=0; sbi<n_subst_; sbi++) VecScale(bcvcorr[sbi], time_->estimate_dt()/time_->dt());
644 
645  } else {
646  // scale fresh convection term matrix
647  //for (unsigned int sbi=0; sbi<n_substances; sbi++) VecScale(bcvcorr[sbi], time_->estimate_dt());
648  MatScale(tm, time_->estimate_dt());
649  MatShift(tm, 1.0);
651 
652  }
653  need_time_rescaling = false;
654  }
655 
656  // update source vectors
657 // for (unsigned int sbi = 0; sbi < n_substances; sbi++) {
658 // MatMult(bcm, bcv[sbi], bcvcorr[sbi]);
659 // VecView(bcv[sbi],PETSC_VIEWER_STDOUT_SELF);
660 // getchar();
661 // VecView(bcvcorr[sbi],PETSC_VIEWER_STDOUT_SELF);
662 // getchar();
663 // }
664 
665 
666  END_TIMER("data reinit");
667 
668 
669  // proceed to actually computed time
670  //time_->view("CONVECTION");
671  time_->next_time(); // explicit scheme use values from previous time and then set then new time
672 
673 
674  for (sbi = 0; sbi < n_subst_; sbi++) {
675  // one step in MOBILE phase
676 
677  START_TIMER("compute_concentration_sources");
678  //sources update
680 
681  //vcumulative_corr[sbi] = 1.0 * bcvcorr[sbi] + v_sources_corr;
682  VecWAXPY(vcumulative_corr[sbi],1.0,bcvcorr[sbi],v_sources_corr);
683  END_TIMER("compute_concentration_sources");
684 
685  START_TIMER("mat mult");
686  VecCopy(vconc[sbi], vpconc[sbi]); // pconc = conc
687  MatMultAdd(tm, vpconc[sbi], vcumulative_corr[sbi], vconc[sbi]); // conc=tm*pconc + bc
688  //VecView(vconc[sbi],PETSC_VIEWER_STDOUT_SELF);
689  END_TIMER("mat mult");
690  }
691  //}
692 
693  /*
694  // DELETE
695  //START_TIMER("dual porosity/old-sorption");
696 
697 // if(sorption == true) for(int loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
698 // {
699 // for(int i_subst = 0; i_subst < n_subst_; i_subst++)
700 // {
701 // //following conditional print is here for comparison of old and new type of sorption input concentrations
702 // if(i_subst < (n_subst_ - 1)) cout << conc[MOBILE][i_subst][loc_el] << ", ";
703 // else cout << conc[MOBILE][i_subst][loc_el] << endl;
704 // }
705 // }
706 // for (sbi = 0; sbi < n_subst_; sbi++) {
707 
708 
709  START_TIMER("old_sorp_step");
710  if ((dual_porosity == true) || (sorption == true) )
711  // cycle over local elements only in any order
712  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
713 
714  if (dual_porosity == true)
715  transport_dual_porosity(loc_el, mesh_->element(el_4_loc[loc_el]), sbi);
716  if (sorption == true)
717  transport_sorption(loc_el, mesh_->element(el_4_loc[loc_el]), sbi);
718 
719  }
720  // transport_node_conc(mesh_,sbi,problem->transport_sub_problem); // vyresit prepocet
721  //END_TIMER("dual porosity/old-sorption");
722  }
723  END_TIMER("old_sorp_step");
724  */
725 
726  END_TIMER("convection-one step");
727 }
728 
729 
730 void ConvectionTransport::set_target_time(double target_time)
731 {
732 
733  //sets target_mark_type (it is fixed) to be met in next_time()
734  time_->marks().add(TimeMark(target_time, target_mark_type));
735 
736  // make new time step fixation, invalidate scaling
737  // same is done when matrix has changed in compute_one_step
739 
740  // fixing convection time governor till next target_mark_type (got from TOS or other)
741  // may have marks for data changes
743  need_time_rescaling = true;
744 
745 }
746 
747 /*
748 void ConvectionTransport::preallocate_transport_matrix() {
749 
750  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
751  elm = mesh_->element(el_4_loc[loc_el]);
752  new_i = row_4_el[elm.index()];
753 
754  n_on_proc=1; n_off_proc=0;
755  FOR_ELEMENT_SIDES(elm,si) {
756  if (elm->side(si)->cond() == NULL) {
757  edg = elm->side(si)->edge();
758  FOR_EDGE_SIDES(edg,s) {
759  j = ELEMENT_FULL_ITER(mesh_, edg->side(s)->element()).index();
760  new_j = row_4_el[j];
761  if (el_ds->is_local(new_j)) n_on_proc++;
762  else n_off_proc++;
763  }
764  n_on_proc--; // do not count diagonal entry more then once
765  }
766  }
767 
768  FOR_ELM_NEIGHS_VB(elm,n) // comp model
769  {
770  el2 = ELEMENT_FULL_ITER(mesh_, elm->neigh_vb[n]->side()->element() ); // higher dim. el.
771  ASSERT( el2 != elm, "Elm. same\n");
772  if (flux > 0.0) {
773  // volume source - out-flow from higher dimension
774  j = el2.index();
775  new_j = row_4_el[j];
776  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
777  // out flow from higher dim. already accounted
778  }
779  if (flux < 0.0) {
780  // volume drain - in-flow to higher dimension
781  aij = (-flux) / (el2->measure() *
782  data_.cross_section->value(el2->centre(), el2->element_accessor()) *
783  data_.porosity.value(el2->centre(), el2->element_accessor()));
784  new_j = row_4_el[el2.index()];
785  MatSetValue(tm, new_j, new_i, aij, INSERT_VALUES);
786 
787  // diagonal drain
788  aii -= (-flux) / (elm->measure() * csection * por_m);
789  }
790 
791  //} // end comp model
792  }
793  } // END ELEMENTS
794 
795 }*/
796 
797 //=============================================================================
798 // CREATE TRANSPORT MATRIX
799 //=============================================================================
801 
802  START_TIMER("convection_matrix_assembly");
803 
806  struct Edge *edg;
807  //struct Neighbour *ngh;
808  //struct Transport *transport;
809  int n, s, j, np, rank, new_j, new_i; //, i;
810  double max_sum, aij, aii; //, *solution;
811  /*
812  DarcyFlow *water;
813 
814  water = problem->water;
815  solution = water.solution();
816  id = water
817 */
818 
819  /*
820  FOR_ELEMENTS(elm)
821  FOR_ELEMENT_SIDES(elm,i){
822  printf("id: %d side: %d flux: %f\n",elm->id, i,elm->side(i)->flux);
823  getchar();
824  }
825 
826  getchar();
827  */
828 
829 
830  MatZeroEntries(tm);
831 // MatZeroEntries(bcm);
832 
833 
834  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
835  MPI_Comm_size(PETSC_COMM_WORLD, &np);
836 
837  double flux, flux2, edg_flux;
838 
839 
840  vector<double> edge_flow(mesh_->n_edges(),0.0);
841  for(unsigned int i=0; i < mesh_->n_edges() ; i++) { // calculate edge Qv
842  Edge &edg = mesh_->edges[i];
843  for( int s=0; s < edg.n_sides; s++) {
844  flux = mh_dh->side_flux( *(edg.side(s)) );
845  if ( flux > 0) edge_flow[i]+= flux;
846  }
847  }
848 
849  max_sum = 0.0;
850  aii = 0.0;
851 
852  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
853  elm = mesh_->element(el_4_loc[loc_el]);
854  new_i = row_4_el[elm.index()];
855 
856  double csection = data_.cross_section.value(elm->centre(), elm->element_accessor());
857  double por_m = data_.porosity.value(elm->centre(), elm->element_accessor());
858 
859  FOR_ELEMENT_SIDES(elm,si) {
860  // same dim
861  flux = mh_dh->side_flux( *(elm->side(si)) );
862  if (elm->side(si)->cond() == NULL) {
863  edg = elm->side(si)->edge();
864  edg_flux = edge_flow[ elm->side(si)->edge_idx() ];
865  FOR_EDGE_SIDES(edg,s)
866  // this test should also eliminate sides facing to lower dim. elements in comp. neighboring
867  // These edges on these sides should have just one side
868  if (edg->side(s) != elm->side(si)) {
869  j = ELEMENT_FULL_ITER(mesh_, edg->side(s)->element()).index();
870  new_j = row_4_el[j];
871 
872  flux2 = mh_dh->side_flux( *(edg->side(s)));
873  if ( flux2 > 0.0 && flux <0.0)
874  aij = -(flux * flux2 / ( edg_flux * elm->measure() * csection * por_m) );
875  else aij =0;
876  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
877  }
878  if (flux > 0.0)
879  aii -= (flux / (elm->measure() * csection * por_m) );
880  } else {
881 // if (flux < 0.0) {
882 // aij = -(flux / (elm->measure() * csection * por_m) );
883 // j = elm->side(si)->cond_idx() ;
884  // DBGMSG("BCM, i: %d j:%d\n", new_i , j);
885 // MatSetValue(bcm, new_i, j, aij, INSERT_VALUES);
886  // vyresit BC matrix !!!!
887  // printf("side in elm:%d value:%f\n ",elm->id,svector->val[j-1]);
888  // printf("%d\t%d\n",elm->id,id2pos(problem,elm->side(si)->id,problem->spos_id,BC));
889 
890 // }
891  if (flux > 0.0)
892  aii -= (flux / (elm->measure() * csection * por_m) );
893  }
894  } // end same dim //ELEMENT_SIDES
895 
896  FOR_ELM_NEIGHS_VB(elm,n) // comp model
897  //FOR_NEIGH_ELEMENTS(elm->neigh_vb[n],s)
898  {
899  el2 = ELEMENT_FULL_ITER(mesh_, elm->neigh_vb[n]->side()->element() ); // higher dim. el.
900  ASSERT( el2 != elm, "Elm. same\n");
901  new_j = row_4_el[el2.index()];
902  flux = mh_dh->side_flux( *(elm->neigh_vb[n]->side()) );
903 
904  // volume source - out-flow from higher dimension
905  if (flux > 0.0) aij = flux / (elm->measure() * csection * por_m);
906  else aij=0;
907  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
908  // out flow from higher dim. already accounted
909 
910  // volume drain - in-flow to higher dimension
911  if (flux < 0.0) {
912  aii -= (-flux) / (elm->measure() * csection * por_m); // diagonal drain
913  aij = (-flux) / (el2->measure() *
914  data_.cross_section.value(el2->centre(), el2->element_accessor()) *
915  data_.porosity.value(el2->centre(), el2->element_accessor()));
916  } else aij=0;
917  MatSetValue(tm, new_j, new_i, aij, INSERT_VALUES);
918  }
919 
920  MatSetValue(tm, new_i, new_i, aii, INSERT_VALUES);
921 
922  if (fabs(aii) > max_sum)
923  max_sum = fabs(aii);
924  aii = 0.0;
925  // i++;
926  } // END ELEMENTS
927 
928  double glob_max_sum;
929 
930  MPI_Allreduce(&max_sum,&glob_max_sum,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD);
931  //xprintf(Msg,"CFL: glob_max_sum=%f\n",glob_max_sum);
932  cfl_max_step = 1 / glob_max_sum;
933  //time_step = 0.9 / glob_max_sum;
934 
935  MatAssemblyBegin(tm, MAT_FINAL_ASSEMBLY);
936 // MatAssemblyBegin(bcm, MAT_FINAL_ASSEMBLY);
937 
938 
939  MatAssemblyEnd(tm, MAT_FINAL_ASSEMBLY);
940 // MatAssemblyEnd(bcm, MAT_FINAL_ASSEMBLY);
941 
942 
943  // MPI_Barrier(PETSC_COMM_WORLD);
944 
945  //MatView(tm,PETSC_VIEWER_STDOUT_SELF);
946 
947 
949  END_TIMER("convection_matrix_assembly");
950 
952 }
953 
954 
955 //=============================================================================
956 // COMPUTE CONCENTRATIONS IN THE NODES FROM THE ELEMENTS
957 //=============================================================================
958 /*
959  void transport_node_conc(struct Transport *transport)
960  {
961  TNode* nod;
962  mesh_* mesh_ = transport->mesh_;
963  int i;
964  double P,N,scale, *pi;
965  int min_elm_dim;
966  int sbi,sub;
967  pi = transport_aloc_pi(mesh_);
968 
969  FOR_NODES(nod)
970  {
971  P = N = 0;
972  min_elm_dim=3;
973  FOR_NODE_ELEMENTS(nod,i)
974  {
975  if (nod->element[i]->dim < min_elm_dim)
976  min_elm_dim = nod->element[i]->dim;
977  }
978  //printf("%d %d %d\n",nod->id,i,min_elm_dim);
979  FOR_NODE_ELEMENTS(nod,i)
980  {
981  if (nod->element[i]->dim == min_elm_dim)
982  {
983  pi[ i ] = sqrt( SQUARE(nod->x - nod->element[i]->centre[0]) +
984  SQUARE(nod->y - nod->element[i]->centre[1]) +
985  SQUARE(nod->z - nod->element[i]->centre[2]) );
986  if (pi[i] > ZERO)
987  P += 1 / pi[ i ]; // { P += pi[ i ]; N++;}
988  }
989  //else printf("vynechano %d ",i);
990 
991  }
992 
993  //node_init(nod,sbi,sub);
994 
995  FOR_NODE_ELEMENTS(nod,i) {
996  if ((nod->element[i]->dim == min_elm_dim) && (P != 0)) {
997  if (pi[i] > ZERO) { // if ((pi[i]> ZERO) && (N!=1)){
998  scale = 1 / (pi[i] * P); // scale = (1 - (pi[ i ] / P)) / (N - 1);
999  nod->conc[sbi] += nod->element[i]->conc[sbi] * scale;
1000  if ((sub & 1) == 1)
1001  nod->conc_immobile[sbi]
1002  += nod->element[i]->conc_immobile[sbi] * scale;
1003  if ((sub & 2) == 2)
1004  nod->conc_sorb[sbi] += nod->element[i]->conc_sorb[sbi]
1005  * scale;
1006  if ((sub & 3) == 3)
1007  nod->conc_immobile_sorb[sbi]
1008  += nod->element[i]->conc_immobile_sorb[sbi]
1009  * scale;
1010  } else {
1011  nod->conc[sbi] = nod->element[i]->conc[sbi];
1012  if ((sub & 1) == 1)
1013  nod->conc_immobile[sbi]
1014  = nod->element[i]->conc_immobile[sbi];
1015  if ((sub & 2) == 2)
1016  nod->conc_sorb[sbi] = nod->element[i]->conc_sorb[sbi];
1017  if ((sub & 3) == 3)
1018  nod->conc_immobile_sorb[sbi]
1019  = nod->element[i]->conc_immobile_sorb[sbi];
1020  break;
1021  }
1022  }
1023  } //for node elm
1024  }
1025  xfree( pi );
1026  }
1027  */
1028 
1029 /*
1030 //DELETE
1031 //=============================================================================
1032 // COMPUTE DUAL POROSITY ( ANALYTICAL EQUATION )
1033 //
1034 // assume: elm_pos - position of values of pconc and conc vectors corresponding to a mesh_ element
1035 // sbi - matter index
1036 // material - material on corresponding mesh_ element
1037 //=============================================================================
1038 void ConvectionTransport::transport_dual_porosity( int elm_pos, ElementFullIter elem, int sbi) {
1039 
1040  double conc_avg = 0.0;
1041  unsigned int loc_el;
1042  //int id;
1043  //double ***conc = transport->conc;
1044  //double ***pconc = transport->pconc;
1045  double cm, pcm, ci, pci, por_m, por_imm, alpha;
1046 
1047  por_m = data_.porosity.value(elem->centre(), elem->element_accessor());
1048  por_imm = data_.por_imm.value(elem->centre(), elem->element_accessor());
1049  alpha = data_.alpha.value(elem->centre(), elem->element_accessor())(sbi);
1050  pcm = conc[MOBILE][sbi][elm_pos];
1051  pci = conc[IMMOBILE][sbi][elm_pos];
1052  // ---compute average concentration------------------------------------------
1053  conc_avg = ((por_m * pcm) + (por_imm * pci)) / (por_m + por_imm);
1054 
1055  if ((conc_avg != 0.0) && (por_imm != 0.0)) {
1056  // ---compute concentration in mobile area-----------------------------------
1057  cm = (pcm - conc_avg) * exp(-alpha * ((por_m + por_imm) / (por_m * por_imm)) * time_->dt()) + conc_avg;
1058 
1059  // ---compute concentration in immobile area---------------------------------
1060  ci = (pci - conc_avg) * exp(-alpha * ((por_m + por_imm) / (por_m * por_imm)) * time_->dt()) + conc_avg;
1061  // --------------------------------------------------------------------------
1062  //printf("\n%f\t%f\t%f",conc_avg,cm,ci);
1063 // DBGMSG("cm: %f ci: %f pcm: %f pci: %f conc_avg: %f alpha: %f por_m: %f por_imm: %f time_dt: %f\n",
1064 // cm, ci, pcm, pci, conc_avg, alpha, por_m, por_imm, time_->dt());
1065  //getchar();
1066 
1067  conc[MOBILE][sbi][elm_pos] = cm;
1068  conc[IMMOBILE][sbi][elm_pos] = ci;
1069  }
1070 
1071 }
1072 
1073 
1074 //=============================================================================
1075 // TRANSPORT SORPTION
1076 //=============================================================================
1077 void ConvectionTransport::transport_sorption( int elm_pos, ElementFullIter elem, int sbi) {
1078 
1079  double conc_avg = 0.0;
1080  double conc_avg_imm = 0.0;
1081  double n, Nm, Nimm;
1082  //int id;
1083  double phi = data_.phi.value(elem->centre(), elem->element_accessor());
1084  double por_m = data_.porosity.value(elem->centre(), elem->element_accessor());
1085  double por_imm = data_.por_imm.value(elem->centre(), elem->element_accessor());
1086  arma::Col<unsigned int> sorp_type = data_.sorp_type.value(elem->centre(), elem->element_accessor());
1087  arma::vec sorp_coef0 = data_.sorp_coef0.value(elem->centre(), elem->element_accessor());
1088  arma::vec sorp_coef1 = data_.sorp_coef1.value(elem->centre(), elem->element_accessor());
1089 
1090  n = 1 - (por_m + por_imm);
1091  Nm = por_m;
1092  Nimm = por_imm;
1093 
1094  conc_avg = conc[MOBILE][sbi][elm_pos] + conc[MOBILE_SORB][sbi][elm_pos] * n / Nm; // cela hmota do poru
1095 
1096  //cout << "input concentration for old sorption is " << conc[MOBILE][sbi][elm_pos] << endl;
1097  if (conc_avg != 0) {
1098  compute_sorption(conc_avg, sorp_coef0[sbi], sorp_coef1[sbi], sorp_type[sbi], &conc[MOBILE][sbi][elm_pos],
1099  &conc[MOBILE_SORB][sbi][elm_pos], Nm / n, n * phi / Nm);
1100 
1101  }
1102  //printf("\n%f\t%f\t",n * phi / Nm,n * phi / Nm);
1103  //printf("\n%f\t%f\t",n * phi / Nimm,n * (1 - phi) / Nimm);
1104  // getchar();
1105 
1106  if ((dual_porosity == true) && (por_imm != 0)) {
1107  conc_avg_imm = conc[IMMOBILE][sbi][elm_pos] + conc[IMMOBILE_SORB][sbi][elm_pos] * n / Nimm; // cela hmota do poru
1108 
1109  if (conc_avg_imm != 0) {
1110  compute_sorption(conc_avg_imm, sorp_coef0[sbi], sorp_coef1[sbi], sorp_type[sbi], &conc[IMMOBILE][sbi][elm_pos],
1111  &conc[IMMOBILE_SORB][sbi][elm_pos], Nimm / n, n * (1 - phi) / Nimm);
1112  }
1113  }
1114 
1115 }
1116 //=============================================================================
1117 // COMPUTE SORPTION
1118 //=============================================================================
1119 void ConvectionTransport::compute_sorption(double conc_avg, double sorp_coef0, double sorp_coef1, unsigned int sorp_type, double *concx, double *concx_sorb, double Nv,
1120  double N) {
1121  double Kx = sorp_coef0 * N;
1122  double parameter;
1123  double NR, pNR, cz, tcz;
1124 
1125  double ad = 1e4;
1126  double tolerence = 1e-8;
1127  int i;
1128 
1129  pNR = 0;
1130 
1131  //if(conc_avg > 1e-20)
1132  switch (sorp_type) {
1133  case Isotherm::linear: //linear
1134  *concx = conc_avg / (1 + Kx);
1135  // *concx_sorb = (conc_avg - *concx) * Nv; // s = Kd *c [kg/m^3]
1136  break;
1137  case Isotherm::freundlich: //freundlich
1138  parameter = sorp_coef1;
1139  cz = pow(ad / (Kx * parameter), 1 / (parameter - 1));
1140  tcz = ad / parameter;
1141  NR = cz;
1142  for (i = 0; i < 20; i++) //Newton Raphson iteration cycle
1143  {
1144  NR -= (NR + ((NR > cz) ? Kx * pow(NR, parameter) : tcz * NR) - conc_avg) / (1 + ((NR > cz) ? parameter * Kx * pow(NR,
1145  parameter - 1) : tcz));
1146  if ((NR <= cz) || (fabs(NR - pNR) < tolerence * NR ) )
1147  break;
1148  pNR = NR;
1149  // if(NR < 0) printf("\n%f\t",NR);
1150  }
1151  *concx = NR;
1152  break;
1153  case Isotherm::langmuir: // langmuir
1154  parameter = sorp_coef1;
1155  NR = 0;
1156  //Kx = sorp_coef0/N;
1157  for (i = 0; i < 5; i++) //Newton Raphson iteration cycle
1158  {
1159  //NR -= (NR + (NR * Kx * parameter) / (1 + NR * Kx) - conc_avg) / (1 + Kx * parameter / pow(1 + NR * Kx, 2));
1160  NR -= (NR + (N * NR * parameter * sorp_coef0)/( 1 + NR * sorp_coef0 ) - conc_avg)/(1 + N * sorp_coef0 * parameter/pow((1 + NR * sorp_coef0), 2));
1161  if (fabs(NR - pNR) < tolerence *NR)
1162  break;
1163  pNR = NR;
1164  }
1165  *concx = NR;
1166  // *concx_sorb = (conc_avg - *concx) * Nv;
1167  break;
1168  }
1169 
1170  *concx_sorb = (conc_avg - *concx) * Nv;
1171 }
1172 //*/
1173 
1174 //=============================================================================
1175 // TIME STEP (RECOMPUTE)
1176 //=============================================================================
1177 //void ConvectionTransport::compute_time_step() {
1178 // double problem_save_step = OptGetDbl("Global", "Save_step", "1.0");
1179 // double problem_stop_time = OptGetDbl("Global", "Stop_time", "1.0");
1180 // save_step = (int) ceil(problem_save_step / time_step); // transport rev
1181 // time_step = problem_save_step / save_step;
1182 // steps = save_step * (int) floor(problem_stop_time / problem_save_step);
1183 //
1184 //}
1185 //=============================================================================
1186 // TRANSPORT ONE STEP
1187 //=============================================================================
1188 
1189 #if 0
1190 //=============================================================================
1191 // TRANSPORT UNTIL TIME
1192 //=============================================================================
1193 void ConvectionTransport::transport_until_time(double time_interval) {
1194  int step = 0;
1195  register int t;
1196  /*Distribution *distribution;
1197  int *el_4_loc;
1198 
1199  // Chemistry initialization
1200  Linear_reaction *decayRad = new Linear_reaction(time_step,mesh_,n_substances,dual_porosity);
1201  this->get_par_info(el_4_loc, distribution);
1202  decayRad->set_concentration_matrix(pconc, distribution, el_4_loc);
1203  Semchem_interface *Semchem_reactions = new Semchem_interface(time_step,mesh_,n_substances,dual_porosity);
1204  Semchem_reactions->set_el_4_loc(el_4_loc);
1205  Semchem_reactions->set_concentration_matrix(pconc, distribution, el_4_loc);*/
1206 
1207  for (t = 1; t <= steps; t++) {
1208  time += time_step;
1209  // SET_TIMER_SUBFRAMES("TRANSPORT",t); // should be in destructor as soon as we have class iteration counter
1210  START_TIMER("transport_step");
1211  update_solution();
1212  END_TIMER("transport_step");
1213 
1214  /*/ Calling linear reactions and Semchem together
1215  for (int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
1216  START_TIMER("decay_step");
1217  (*decayRad).compute_reaction(pconc[MOBILE], loc_el);
1218  if (dual_porosity == true) {
1219  (*decayRad).compute_reaction(pconc[IMMOBILE], loc_el);
1220  }
1221  END_TIMER("decay_step");
1222  START_TIMER("semchem_step");
1223  if(Semchem_reactions->semchem_on == true){
1224  Semchem_reactions->set_timestep(time_step);
1225  //Semchem_reactions->compute_reaction(dual_porosity, mesh_->element(el_4_loc[loc_el]), loc_el, pconc[MOBILE], pconc[IMMOBILE]);
1226  Semchem_reactions->compute_reaction(dual_porosity, mesh_->element(el_4_loc[loc_el]), loc_el, pconc);
1227  }
1228  END_TIMER("semchem_step");
1229  }*/
1230 
1231  step++;
1232  //&& ((ConstantDB::getInstance()->getInt("Problem_type") != PROBLEM_DENSITY)
1233  if ((save_step == step) || (write_iterations)) {
1234  xprintf( Msg, "Output\n");
1236 
1237  // Register concentrations data on elements
1238  for(int subst_id=0; subst_id<n_subst_; subst_id++) {
1239  output_time->register_elem_data(subst_names_[subst_id], "", out_conc[MOBILE][subst_id], mesh_->n_elements());
1240  }
1241  output_time->write_data(time);
1242  // if (ConstantDB::getInstance()->getInt("Problem_type") != STEADY_SATURATED)
1243  // output_time(problem, t * time_step); // time variable flow field
1244  step = 0;
1245  }
1246  }
1247 }
1248 
1249 #endif
1250 
1251 //=============================================================================
1252 // OUTPUT VECTOR GATHER
1253 //=============================================================================
1255 
1256  unsigned int sbi/*, rank, np*/;
1257  IS is;
1258  //PetscViewer inviewer;
1259 
1260  // MPI_Barrier(PETSC_COMM_WORLD);
1261 /* MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
1262  MPI_Comm_size(PETSC_COMM_WORLD, &np);*/
1263 
1264 
1265  //ISCreateStride(PETSC_COMM_SELF,mesh_->n_elements(),0,1,&is);
1266  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el, PETSC_COPY_VALUES, &is); //WithArray
1267  VecScatterCreate(vconc[0], is, vconc_out[0], PETSC_NULL, &vconc_out_scatter);
1268  for (sbi = 0; sbi < n_subst_; sbi++) {
1269  VecScatterBegin(vconc_out_scatter, vconc[sbi], vconc_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
1270  VecScatterEnd(vconc_out_scatter, vconc[sbi], vconc_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
1271  }
1272  //VecView(transport->vconc[0],PETSC_VIEWER_STDOUT_WORLD);
1273  //VecView(transport->vconc_out[0],PETSC_VIEWER_STDOUT_WORLD);
1274  VecScatterDestroy(&(vconc_out_scatter));
1275  ISDestroy(&(is));
1276 }
1277 
1278 
1280  return conc;
1281 }
1282 
1283 void ConvectionTransport::get_par_info(int * &el_4_loc_out, Distribution * &el_distribution_out){
1284  el_4_loc_out = this->el_4_loc;
1285  el_distribution_out = this->el_ds;
1286  return;
1287 }
1288 
1290  return el_4_loc;
1291 }
1292 
1294  return row_4_el;
1295 }
1296 
1297 /*
1298 int ConvectionTransport::get_n_substances() {
1299  return n_subst_;
1300 }
1301 */
1302 
1303 
1304 void ConvectionTransport::calc_fluxes(vector<vector<double> > &bcd_balance, vector<vector<double> > &bcd_plus_balance, vector<vector<double> > &bcd_minus_balance)
1305 {
1306  double mass_flux[n_substances()];
1307  double *pconc[n_substances()];
1308 
1309  for (int sbi=0; sbi<n_substances(); sbi++)
1310  VecGetArray(vpconc[sbi], &pconc[sbi]);
1311 
1312  FOR_BOUNDARIES(mesh_, bcd) {
1313 
1314  // !! there can be more sides per one boundary
1315  int index = row_4_el[bcd->side()->element().index()];
1316  if (!el_ds->is_local(index)) continue;
1317  int loc_index = index-el_ds->begin();
1318 
1319  double por_m = data_.porosity.value(bcd->side()->element()->centre(), bcd->side()->element()->element_accessor() );
1320  double water_flux = mh_dh->side_flux(*(bcd->side()));
1321  if (water_flux < 0) {
1322  arma::vec bc_conc = data_.bc_conc.value( bcd->element()->centre(), bcd->element_accessor() );
1323  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
1324  mass_flux[sbi] = water_flux*bc_conc[sbi]*por_m;
1325  } else {
1326  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
1327  mass_flux[sbi] = water_flux*pconc[sbi][loc_index]*por_m;
1328  }
1329 
1330  Region r = bcd->region();
1331  if (! r.is_valid()) xprintf(Msg, "Invalid region, ele % d, edg: % d\n", bcd->bc_ele_idx_, bcd->edge_idx_);
1332  unsigned int bc_region_idx = r.boundary_idx();
1333 
1334  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
1335  {
1336  bcd_balance[sbi][bc_region_idx] += mass_flux[sbi];
1337 
1338  if (water_flux > 0) bcd_plus_balance[sbi][bc_region_idx] += mass_flux[sbi];
1339  else bcd_minus_balance[sbi][bc_region_idx] += mass_flux[sbi];
1340  }
1341  }
1342 
1343 }
1344 
1346 {
1347  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
1348  {
1350  double *sources = sources_corr;
1351 
1352  FOR_ELEMENTS(mesh_,elem)
1353  {
1354  int index = row_4_el[elem.index()];
1355  if (!el_ds->is_local(index)) continue;
1356  ElementAccessor<3> ele_acc = elem->element_accessor();
1357  double por_m = data_.porosity.value(elem->centre(), ele_acc);
1358  double csection = data_.cross_section.value(elem->centre(), ele_acc);
1359  int loc_index = index - el_ds->begin();
1360  //double sum_sol_phases = 0;
1361 
1362  //temporary fix - mass balance works only when no reaction term is present
1363  //for (int ph=0; ph<MAX_PHASES; ph++)
1364  //{
1365  // if ((sub_problem & ph) == ph)
1366  double sum_sol_phases = conc[0][sbi][loc_index];
1367  //}
1368 
1369  mass[sbi][ele_acc.region().bulk_idx()] += por_m*csection*sum_sol_phases*elem->measure();
1370  src_balance[sbi][ele_acc.region().bulk_idx()] += sources[loc_index]*elem->measure();
1371  }
1372  }
1373 }
1374 
1375 
1376 
1378 
1379  if (time_->is_current( time_->marks().type_output() )) {
1381 
1384 
1385 
1387 
1388  //for synchronization when measuring time by Profiler
1389  //MPI_Barrier(MPI_COMM_WORLD);
1390  }
1391 }