Flow123d  jenkins-Flow123d-windows32-release-multijob-51
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 "la/distribution.hh"
46 
47 #include "la/sparse_graph.hh"
48 #include <iostream>
49 #include <iomanip>
50 #include <string>
51 
52 // TODO: move partitioning into mesh_ and remove this include
53 #include "flow/darcy_flow_mh.hh"
54 #include "flow/old_bcd.hh"
55 #include "input/accessors.hh"
56 #include "input/input_type.hh"
57 
59 
61 #include "fields/field_values.hh"
63 #include "reaction/isotherm.hh" // SorptionType enum
64 
65 namespace IT = Input::Type;
66 
68  .add_value(none,"none","No sorption considered")
69  .add_value(Isotherm::linear,"linear","Linear isotherm described sorption considered.")
70  .add_value(Isotherm::freundlich,"freundlich","Freundlich isotherm described sorption considered")
71  .add_value(Isotherm::langmuir,"langmuir","Langmuir isotherm described sorption considered")
72  .close();
73 
74 
76  EqData().output_fields.make_output_field_selection("ConvectionTransport_Output")
77  .close();
78 
79 
81 {
82  ADD_FIELD(bc_conc, "Boundary conditions for concentrations.", "0.0");
84  bc_conc.units( UnitSI().kg().m(-3) );
85  ADD_FIELD(init_conc, "Initial concentrations.", "0.0");
86  init_conc.units( UnitSI().kg().m(-3) );
87 
88  output_fields += *this;
89  output_fields += conc_mobile.name("conc").units( UnitSI().kg().m(-3) );
90 }
91 
92 
94 : TransportBase(init_mesh, in_rec)
95 {
96  this->eq_data_ = &data_;
97 
98  //mark type of the equation of convection transport (created in EquationBase constructor) and it is fixed
99  time_ = new TimeGovernor(in_rec.val<Input::Record>("time"));
101 
103 
104  in_rec.val<Input::Array>("substances").copy_to(subst_names_);
105  n_subst_ = subst_names_.size();
106  INPUT_CHECK(n_subst_ >= 1 ,"Number of substances must be positive.\n");
107 
108  Input::Iterator<Input::Record> it = in_rec.find<Input::Record>("mass_balance");
109  if (it) mass_balance_ = new MassBalance(this, *it);
110 
112  data_.set_mesh(init_mesh);
113  data_.set_input_list( in_rec.val<Input::Array>("input_fields") );
115 
116 
117  sub_problem = 0;
118 
122  transport_matrix_time = -1.0; // or -infty
124  need_time_rescaling=true;
125 
126  // register output vectors
127  output_rec = in_rec.val<Input::Record>("output_stream");
131 
132  for (unsigned int sbi=0; sbi<n_subst_; sbi++)
133  {
134  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
135  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()));
136  data_.conc_mobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
137  }
142 
143 }
144 
145 
146 //=============================================================================
147 // MAKE TRANSPORT
148 //=============================================================================
150 
151  int * id_4_old = new int[mesh_->n_elements()];
152  int i = 0;
153  FOR_ELEMENTS(mesh_, ele) id_4_old[i++] = ele.index();
155  delete[] id_4_old;
156 
157  // TODO: make output of partitioning is usefull but makes outputs different
158  // on different number of processors, which breaks tests.
159  //
160  // Possible solution:
161  // - have flag in ini file to turn this output ON
162  // - possibility to have different ref_output for different num of proc.
163  // - or do not test such kind of output
164  //
165  //FOR_ELEMENTS(mesh_, ele) {
166  // ele->pid=el_ds->get_proc(row_4_el[ele.index()]);
167  //}
168 
169 }
170 
171 
172 
174 {
175  unsigned int sbi;
176 
177  if (mass_balance_ != NULL)
178  delete mass_balance_;
179 
180  //Destroy mpi vectors at first
181  VecDestroy(&v_sources_corr);
182  MatDestroy(&tm);
183 
184  VecDestroy(vconc);
185  VecDestroy(bcvcorr);
186  VecDestroy(vpconc);
187  VecDestroy(vcumulative_corr);
188  VecDestroy(vconc_out);
189 
190  for (sbi = 0; sbi < n_subst_; sbi++) {
191  //no mpi vectors
192  xfree(sources_density[sbi]);
193  xfree(sources_conc[sbi]);
194  xfree(sources_sigma[sbi]);
195  xfree(cumulative_corr[sbi]);
196  }
197 
198 
200 
205 
206  delete output_stream_;
207 
208 }
209 
210 
211 
212 
213 
215 {
216  FOR_ELEMENTS(mesh_, elem)
217  {
218  if (!el_ds->is_local(row_4_el[elem.index()])) continue;
219 
220  unsigned int index = row_4_el[elem.index()] - el_ds->begin();
221  ElementAccessor<3> ele_acc = mesh_->element_accessor(elem.index());
222  arma::vec value = data_.init_conc.value(elem->centre(), ele_acc);
223 
224  for (unsigned int sbi=0; sbi<n_subst_; sbi++)
225  conc[MOBILE][sbi][index] = value(sbi);
226  }
227 
228 }
229 
230 //=============================================================================
231 // ALLOCATE OF TRANSPORT VARIABLES (ELEMENT & NODES)
232 //=============================================================================
234 
235  unsigned int i;
236  int sbi, n_subst, ph;
237  n_subst = n_subst_;
238 
239 
240  sources_corr = new double[el_ds->lsize()];
241  sources_density = (double**) xmalloc(n_subst * sizeof(double*));
242  sources_conc = (double**) xmalloc(n_subst * sizeof(double*));
243  sources_sigma = (double**) xmalloc(n_subst * sizeof(double*));
244 
245  cumulative_corr = (double**) xmalloc(n_subst * sizeof(double*));
246  for (sbi = 0; sbi < n_subst; sbi++) {
247  sources_density[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
248  sources_conc[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
249  sources_sigma[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
250  cumulative_corr[sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
251  }
252 
253  conc = (double***) xmalloc(MAX_PHASES * sizeof(double**));
254  out_conc = (double***) xmalloc(MAX_PHASES * sizeof(double**));
255  for (ph = 0; ph < MAX_PHASES; ph++) {
256  if ((sub_problem & ph) == ph) {
257  conc[ph] = (double**) xmalloc(n_subst * sizeof(double*));
258  out_conc[ph] = (double**) xmalloc(n_subst * sizeof(double*));
259  for (sbi = 0; sbi < n_subst; sbi++) {
260  conc[ph][sbi] = (double*) xmalloc(el_ds->lsize() * sizeof(double));
261  out_conc[ph][sbi] = (double*) xmalloc(el_ds->size() * sizeof(double));
262  for (i = 0; i < el_ds->lsize(); i++) {
263  conc[ph][sbi][i] = 0.0;
264  }
265  for (i = 0; i < el_ds->size(); i++) {
266  out_conc[ph][sbi][i] = 0.0;
267  }
268  }
269  } else {
270  conc[ph] = NULL;
271  out_conc[ph] = NULL;
272  }
273  }
274 }
275 
276 //=============================================================================
277 // ALLOCATION OF TRANSPORT VECTORS (MPI)
278 //=============================================================================
280 
281  int sbi, n_subst, rank, np;
282  n_subst = n_subst_;
283 
284  MPI_Barrier(PETSC_COMM_WORLD);
285  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
286  MPI_Comm_size(PETSC_COMM_WORLD, &np);
287 
288  bcvcorr = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
289  vconc = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
290  vpconc = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
291  vcumulative_corr = (Vec*) xmalloc(n_subst * (sizeof(Vec)));
292 
293 
294  vconc_out = (Vec*) xmalloc(n_subst * (sizeof(Vec))); // extend to all
295 
296 
297  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), PETSC_DECIDE,
299 
300  for (sbi = 0; sbi < n_subst; sbi++) {
301  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &bcvcorr[sbi]);
302  VecZeroEntries(bcvcorr[sbi]);
303  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(), conc[MOBILE][sbi],
304  &vconc[sbi]);
305 
306  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &vpconc[sbi]);
307  VecZeroEntries(vconc[sbi]);
308  VecZeroEntries(vpconc[sbi]);
309 
310  // SOURCES
311  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
312  cumulative_corr[sbi],&vcumulative_corr[sbi]);
313 
314  VecCreateSeqWithArray(PETSC_COMM_SELF,1, mesh_->n_elements(), out_conc[MOBILE][sbi], &vconc_out[sbi]);
315 
316  VecZeroEntries(vcumulative_corr[sbi]);
317  VecZeroEntries(vconc_out[sbi]);
318  }
319 
320 
321  MatCreateAIJ(PETSC_COMM_WORLD, el_ds->lsize(), el_ds->lsize(), mesh_->n_elements(),
322  mesh_->n_elements(), 16, PETSC_NULL, 4, PETSC_NULL, &tm);
323 
324 }
325 
326 
328 {
330 
331  unsigned int sbi, loc_el;
332 
333  // Assembly bcvcorr vector
334  for(sbi=0; sbi < n_subst_; sbi++) VecZeroEntries(bcvcorr[sbi]);
335 
336 
337  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
338  elm = mesh_->element(el_4_loc[loc_el]);
339  if (elm->boundary_idx_ != NULL) {
340  unsigned int new_i = row_4_el[elm.index()];
341  double csection = data_.cross_section.value(elm->centre(), elm->element_accessor());
342  double por_m = data_.porosity.value(elm->centre(), elm->element_accessor());
343 
344  FOR_ELEMENT_SIDES(elm,si) {
345  Boundary *b = elm->side(si)->cond();
346  if (b != NULL) {
347  double flux = mh_dh->side_flux( *(elm->side(si)) );
348  if (flux < 0.0) {
349  double aij = -(flux / (elm->measure() * csection * por_m) );
350 
351  arma::vec value = data_.bc_conc.value( b->element()->centre(), b->element_accessor() );
352  for (sbi=0; sbi<n_subst_; sbi++)
353  VecSetValue(bcvcorr[sbi], new_i, value[sbi] * aij, ADD_VALUES);
354  }
355  }
356  }
357 
358  }
359  }
360 
361  for (sbi=0; sbi<n_subst_; sbi++) VecAssemblyBegin(bcvcorr[sbi]);
362  for (sbi=0; sbi<n_subst_; sbi++) VecAssemblyEnd(bcvcorr[sbi]);
363 
364 }
365 
366 
367 //=============================================================================
368 // COMPUTE SOURCES
369 //=============================================================================
371 
372  //temporary variables
373  unsigned int loc_el;
374  double conc_diff, csection;
375  ElementAccessor<3> ele_acc;
376  arma::vec3 p;
377 
378  //TODO: would it be possible to check the change in data for chosen substance? (may be in multifields?)
379 
380  //checking if the data were changed
381  if( (data_.sources_density.changed() )
382  || (data_.sources_conc.changed() )
383  || (data_.sources_sigma.changed() )
384  || (data_.cross_section.changed()))
385  {
386  START_TIMER("sources_reinit");
387  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
388  {
389  ele_acc = mesh_->element_accessor(el_4_loc[loc_el]);
390  p = ele_acc.centre();
391 
392  csection = data_.cross_section.value(p, ele_acc);
393 
394  //if(data_.sources_density.changed_during_set_time)
395  sources_density[sbi][loc_el] = data_.sources_density.value(p, ele_acc)(sbi)*csection;
396 
397  //if(data_.sources_conc.changed_during_set_time)
398  sources_conc[sbi][loc_el] = data_.sources_conc.value(p, ele_acc)(sbi);
399 
400  //if(data_.sources_sigma.changed_during_set_time)
401  sources_sigma[sbi][loc_el] = data_.sources_sigma.value(p, ele_acc)(sbi)*csection;
402  }
403  }
404 
405  //now computing source concentrations: density - sigma (source_conc - actual_conc)
406  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
407  {
408  conc_diff = sources_conc[sbi][loc_el] - conc[MOBILE][sbi][loc_el];
409  if ( conc_diff > 0.0)
410  sources_corr[loc_el] = ( sources_density[sbi][loc_el]
411  + conc_diff * sources_sigma[sbi][loc_el] )
412  * time_->dt();
413  else
414  sources_corr[loc_el] = sources_density[sbi][loc_el] * time_->dt();
415  }
416 }
417 
419 
420  //temporary variables
421  unsigned int loc_el;
422  double conc_diff, csection;
423  ElementAccessor<3> ele_acc;
424  arma::vec3 p;
425 
426  double *pconc;
427  VecGetArray(vpconc[sbi], &pconc);
428 
429  //TODO: would it be possible to check the change in data for chosen substance? (may be in multifields?)
430 
431  //checking if the data were changed
432  if( (data_.sources_density.changed() )
433  || (data_.sources_conc.changed() )
434  || (data_.sources_sigma.changed() )
435  || (data_.cross_section.changed()))
436  {
437  START_TIMER("sources_reinit");
438  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
439  {
440  ele_acc = mesh_->element_accessor(el_4_loc[loc_el]);
441  p = ele_acc.centre();
442 
443  csection = data_.cross_section.value(p, ele_acc);
444 
445  //if(data_.sources_density.changed_during_set_time)
446  sources_density[sbi][loc_el] = data_.sources_density.value(p, ele_acc)(sbi)*csection;
447 
448  //if(data_.sources_conc.changed_during_set_time)
449  sources_conc[sbi][loc_el] = data_.sources_conc.value(p, ele_acc)(sbi);
450 
451  //if(data_.sources_sigma.changed_during_set_time)
452  sources_sigma[sbi][loc_el] = data_.sources_sigma.value(p, ele_acc)(sbi)*csection;
453  }
454  }
455 
456  //now computing source concentrations: density - sigma (source_conc - actual_conc)
457  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
458  {
459  conc_diff = sources_conc[sbi][loc_el] - pconc[loc_el];
460  if ( conc_diff > 0.0)
461  sources_corr[loc_el] = sources_density[sbi][loc_el] + conc_diff * sources_sigma[sbi][loc_el];
462  else
463  sources_corr[loc_el] = sources_density[sbi][loc_el];
464  }
465 }
466 
467 
469 {
470  ASSERT_EQUAL(time_->tlevel(), 0);
471 
473  data_.set_time(*time_);
474 
476 
477 
478  // write initial condition
479  output_data();
480 }
481 
482 
483 
485 
486  START_TIMER("convection-one step");
487 
488  unsigned int sbi;
489 
490  START_TIMER("data reinit");
491  data_.set_time(*time_); // set to the last computed time
492 
493  ASSERT(mh_dh, "Null MH object.\n" );
494  // update matrix and sources if neccessary
495 
496 
500 
501  // need new fixation of the time step
502 
505 
507  // scale boundary sources
508  for (sbi=0; sbi<n_subst_; sbi++) VecScale(bcvcorr[sbi], time_->estimate_dt());
509 
510  need_time_rescaling = true;
511  } else {
512  // possibly read boundary conditions
513  if (data_.bc_conc.changed() ) {
515  // scale boundary sources
516  for (sbi=0; sbi<n_subst_; sbi++) VecScale(bcvcorr[sbi], time_->dt());
517  }
518  }
519 
520  if (need_time_rescaling) {
522  // rescale matrix
523  MatShift(tm, -1.0);
524  MatScale(tm, time_->estimate_dt()/time_->dt() );
525  MatShift(tm, 1.0);
526 
527  for (sbi=0; sbi<n_subst_; sbi++) VecScale(bcvcorr[sbi], time_->estimate_dt()/time_->dt());
528 
529  } else {
530  // scale fresh convection term matrix
531  MatScale(tm, time_->estimate_dt());
532  MatShift(tm, 1.0);
534 
535  }
536  need_time_rescaling = false;
537  }
538 
539  END_TIMER("data reinit");
540 
541 
542  // proceed to actually computed time
543  time_->next_time(); // explicit scheme use values from previous time and then set then new time
544 
545 
546  for (sbi = 0; sbi < n_subst_; sbi++) {
547  // one step in MOBILE phase
548 
549  START_TIMER("compute_concentration_sources");
550  //sources update
552 
553  //vcumulative_corr[sbi] = 1.0 * bcvcorr[sbi] + v_sources_corr;
554  VecWAXPY(vcumulative_corr[sbi],1.0,bcvcorr[sbi],v_sources_corr);
555  END_TIMER("compute_concentration_sources");
556 
557  START_TIMER("mat mult");
558  VecCopy(vconc[sbi], vpconc[sbi]); // pconc = conc
559  MatMultAdd(tm, vpconc[sbi], vcumulative_corr[sbi], vconc[sbi]); // conc=tm*pconc + bc
560  END_TIMER("mat mult");
561  }
562 
563  END_TIMER("convection-one step");
564 }
565 
566 
567 void ConvectionTransport::set_target_time(double target_time)
568 {
569 
570  //sets target_mark_type (it is fixed) to be met in next_time()
571  time_->marks().add(TimeMark(target_time, target_mark_type));
572 
573  // make new time step fixation, invalidate scaling
574  // same is done when matrix has changed in compute_one_step
576 
577  // fixing convection time governor till next target_mark_type (got from TOS or other)
578  // may have marks for data changes
580  need_time_rescaling = true;
581 
582 }
583 
584 
585 //=============================================================================
586 // CREATE TRANSPORT MATRIX
587 //=============================================================================
589 
590  START_TIMER("convection_matrix_assembly");
591 
594  struct Edge *edg;
595  unsigned int n;
596  int s, j, np, rank, new_j, new_i;
597  double max_sum, aij, aii;
598 
599  MatZeroEntries(tm);
600 
601  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
602  MPI_Comm_size(PETSC_COMM_WORLD, &np);
603 
604  double flux, flux2, edg_flux;
605 
606 
607  vector<double> edge_flow(mesh_->n_edges(),0.0);
608  for(unsigned int i=0; i < mesh_->n_edges() ; i++) { // calculate edge Qv
609  Edge &edg = mesh_->edges[i];
610  for( int s=0; s < edg.n_sides; s++) {
611  flux = mh_dh->side_flux( *(edg.side(s)) );
612  if ( flux > 0) edge_flow[i]+= flux;
613  }
614  }
615 
616  max_sum = 0.0;
617  aii = 0.0;
618 
619  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
620  elm = mesh_->element(el_4_loc[loc_el]);
621  new_i = row_4_el[elm.index()];
622 
623  double csection = data_.cross_section.value(elm->centre(), elm->element_accessor());
624  double por_m = data_.porosity.value(elm->centre(), elm->element_accessor());
625 
626  FOR_ELEMENT_SIDES(elm,si) {
627  // same dim
628  flux = mh_dh->side_flux( *(elm->side(si)) );
629  if (elm->side(si)->cond() == NULL) {
630  edg = elm->side(si)->edge();
631  edg_flux = edge_flow[ elm->side(si)->edge_idx() ];
632  FOR_EDGE_SIDES(edg,s)
633  // this test should also eliminate sides facing to lower dim. elements in comp. neighboring
634  // These edges on these sides should have just one side
635  if (edg->side(s) != elm->side(si)) {
636  j = ELEMENT_FULL_ITER(mesh_, edg->side(s)->element()).index();
637  new_j = row_4_el[j];
638 
639  flux2 = mh_dh->side_flux( *(edg->side(s)));
640  if ( flux2 > 0.0 && flux <0.0)
641  aij = -(flux * flux2 / ( edg_flux * elm->measure() * csection * por_m) );
642  else aij =0;
643  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
644  }
645  if (flux > 0.0)
646  aii -= (flux / (elm->measure() * csection * por_m) );
647  } else {
648  if (flux > 0.0)
649  aii -= (flux / (elm->measure() * csection * por_m) );
650  }
651  } // end same dim //ELEMENT_SIDES
652 
653  FOR_ELM_NEIGHS_VB(elm,n) // comp model
654  {
655  el2 = ELEMENT_FULL_ITER(mesh_, elm->neigh_vb[n]->side()->element() ); // higher dim. el.
656  ASSERT( el2 != elm, "Elm. same\n");
657  new_j = row_4_el[el2.index()];
658  flux = mh_dh->side_flux( *(elm->neigh_vb[n]->side()) );
659 
660  // volume source - out-flow from higher dimension
661  if (flux > 0.0) aij = flux / (elm->measure() * csection * por_m);
662  else aij=0;
663  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
664  // out flow from higher dim. already accounted
665 
666  // volume drain - in-flow to higher dimension
667  if (flux < 0.0) {
668  aii -= (-flux) / (elm->measure() * csection * por_m); // diagonal drain
669  aij = (-flux) / (el2->measure() *
670  data_.cross_section.value(el2->centre(), el2->element_accessor()) *
671  data_.porosity.value(el2->centre(), el2->element_accessor()));
672  } else aij=0;
673  MatSetValue(tm, new_j, new_i, aij, INSERT_VALUES);
674  }
675 
676  MatSetValue(tm, new_i, new_i, aii, INSERT_VALUES);
677 
678  if (fabs(aii) > max_sum)
679  max_sum = fabs(aii);
680  aii = 0.0;
681  } // END ELEMENTS
682 
683  double glob_max_sum;
684 
685  MPI_Allreduce(&max_sum,&glob_max_sum,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD);
686  cfl_max_step = 1 / glob_max_sum;
687 
688  MatAssemblyBegin(tm, MAT_FINAL_ASSEMBLY);
689  MatAssemblyEnd(tm, MAT_FINAL_ASSEMBLY);
690 
692  END_TIMER("convection_matrix_assembly");
693 
695 }
696 
697 
698 
699 
700 
701 //=============================================================================
702 // OUTPUT VECTOR GATHER
703 //=============================================================================
705 
706  unsigned int sbi;
707  IS is;
708 
709  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el, PETSC_COPY_VALUES, &is); //WithArray
710  VecScatterCreate(vconc[0], is, vconc_out[0], PETSC_NULL, &vconc_out_scatter);
711  for (sbi = 0; sbi < n_subst_; sbi++) {
712  VecScatterBegin(vconc_out_scatter, vconc[sbi], vconc_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
713  VecScatterEnd(vconc_out_scatter, vconc[sbi], vconc_out[sbi], INSERT_VALUES, SCATTER_FORWARD);
714  }
715  VecScatterDestroy(&(vconc_out_scatter));
716  ISDestroy(&(is));
717 }
718 
719 
721  return conc;
722 }
723 
724 void ConvectionTransport::get_par_info(int * &el_4_loc_out, Distribution * &el_distribution_out){
725  el_4_loc_out = this->el_4_loc;
726  el_distribution_out = this->el_ds;
727  return;
728 }
729 
731  return el_4_loc;
732 }
733 
735  return row_4_el;
736 }
737 
738 
739 
740 void ConvectionTransport::calc_fluxes(vector<vector<double> > &bcd_balance, vector<vector<double> > &bcd_plus_balance, vector<vector<double> > &bcd_minus_balance)
741 {
742  double mass_flux[n_substances()];
743  double *pconc[n_substances()];
744 
745  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
746  VecGetArray(vpconc[sbi], &pconc[sbi]);
747 
748  FOR_BOUNDARIES(mesh_, bcd) {
749 
750  // !! there can be more sides per one boundary
751  int index = row_4_el[bcd->side()->element().index()];
752  if (!el_ds->is_local(index)) continue;
753  int loc_index = index-el_ds->begin();
754 
755  double por_m = data_.porosity.value(bcd->side()->element()->centre(), bcd->side()->element()->element_accessor() );
756  double water_flux = mh_dh->side_flux(*(bcd->side()));
757  if (water_flux < 0) {
758  arma::vec bc_conc = data_.bc_conc.value( bcd->element()->centre(), bcd->element_accessor() );
759  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
760  mass_flux[sbi] = water_flux*bc_conc[sbi]*por_m;
761  } else {
762  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
763  mass_flux[sbi] = water_flux*pconc[sbi][loc_index]*por_m;
764  }
765 
766  Region r = bcd->region();
767  if (! r.is_valid()) xprintf(Msg, "Invalid region, ele % d, edg: % d\n", bcd->bc_ele_idx_, bcd->edge_idx_);
768  unsigned int bc_region_idx = r.boundary_idx();
769 
770  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
771  {
772  bcd_balance[sbi][bc_region_idx] += mass_flux[sbi];
773 
774  if (water_flux > 0) bcd_plus_balance[sbi][bc_region_idx] += mass_flux[sbi];
775  else bcd_minus_balance[sbi][bc_region_idx] += mass_flux[sbi];
776  }
777  }
778 
779 }
780 
782 {
783  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
784  {
786  double *sources = sources_corr;
787 
788  FOR_ELEMENTS(mesh_,elem)
789  {
790  int index = row_4_el[elem.index()];
791  if (!el_ds->is_local(index)) continue;
792  ElementAccessor<3> ele_acc = elem->element_accessor();
793  double por_m = data_.porosity.value(elem->centre(), ele_acc);
794  double csection = data_.cross_section.value(elem->centre(), ele_acc);
795  int loc_index = index - el_ds->begin();
796 
797  //temporary fix - mass balance works only when no reaction term is present
798  double sum_sol_phases = conc[0][sbi][loc_index];
799 
800  mass[sbi][ele_acc.region().bulk_idx()] += por_m*csection*sum_sol_phases*elem->measure();
801  src_balance[sbi][ele_acc.region().bulk_idx()] += sources[loc_index]*elem->measure();
802  }
803  }
804 }
805 
806 
807 
809 
810  if (time_->is_current( time_->marks().type_output() )) {
812 
815 
816 
818 
819  }
820 }
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
void compute_concentration_sources(unsigned int sbi)
Definition: transport.cc:370
FieldSet * eq_data_
Definition: equation.hh:227
void set_limit_side(LimitSide side)
Definition: field_set.hh:171
double *** get_concentration_matrix()
Definition: transport.cc:720
double time_changed() const
double * sources_corr
Definition: transport.h:232
void init(const vector< string > &names)
Definition: field.impl.hh:473
Header: The functions for all outputs.
void update_solution() override
Definition: transport.cc:484
Accessor to input data conforming to declared Array.
Definition: accessors.hh:521
double end_time() const
End time.
Definition: system.hh:72
double transport_matrix_time
Definition: transport.h:253
int tlevel() const
Field< 3, FieldValue< 3 >::Scalar > cross_section
Pointer to DarcyFlow field cross_section.
void id_maps(int n_ids, int *id_4_old, Distribution *&new_ds, int *&id_4_loc, int *&new_4_id)
double *** conc
Concentrations for phase, substance, element.
Definition: transport.h:258
#define FOR_EDGE_SIDES(i, j)
Definition: edges.h:53
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:357
void alloc_transport_vectors()
Definition: transport.cc:233
double ** sources_sigma
Definition: transport.h:237
BCField< 3, FieldValue< 3 >::Vector > bc_conc
Definition: transport.h:101
FieldBasePtr(* read_field_descriptor_hook)(Input::Record rec, const FieldCommon &field)
Definition: field.hh:71
double fix_dt_until_mark()
Fixing time step until fixed time mark.
MultiField< 3, FieldValue< 3 >::Scalar > conc_mobile
Calculated concentrations in the mobile zone.
Definition: transport.h:106
void next_time()
Proceed to the next time according to current estimated time step.
TimeMark::Type target_mark_type
TimeMark type for time marks denoting end of every time interval where transport matrix remains const...
Definition: transport.h:241
TimeMark::Type type_output()
Definition: time_marks.hh:192
void set_initial_condition()
Definition: transport.cc:214
???
void set_boundary_conditions()
Definition: transport.cc:327
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:361
const MH_DofHandler * mh_dh
MassBalance * mass_balance_
object for calculation and writing the mass balance to file.
#define ELEMENT_FULL_ITER(_mesh_, i)
Definition: mesh.h:365
Definition: mesh.h:108
Field< 3, FieldValue< 3 >::Vector > sources_conc
Iterator< Ret > find(const string &key) const
#define FOR_ELEMENT_SIDES(i, j)
Definition: elements.h:151
int index() const
Definition: sys_vector.hh:88
bool is_current(const TimeMark::Type &mask) const
int n_sides
Definition: edges.h:48
Field< 3, FieldValue< 3 >::Scalar > porosity
Mobile porosity.
Definition: edges.h:38
const RegionDB & region_db() const
Definition: mesh.h:148
ElementAccessor< 3 > element_accessor(unsigned int idx, bool boundary=false)
Definition: mesh.cc:638
virtual ~ConvectionTransport()
Definition: transport.cc:173
double t() const
void get_par_info(int *&el_4_loc, Distribution *&el_ds)
Definition: transport.cc:724
#define ADD_FIELD(name,...)
Definition: field_set.hh:260
Basic time management functionality for unsteady (and steady) solvers (class Equation).
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
Partitioning * get_part()
Definition: mesh.cc:162
void zero_time_step() override
Definition: transport.cc:468
static TimeMarks & marks()
void output_vector_gather()
Definition: transport.cc:704
Basic time management class.
Specification of transport model interface.
double estimate_dt() const
Estimate choice of next time step according to actual setting of constraints.
OutputTime * output_stream_
Definition: transport.h:272
static FieldBaseVector trans_conc_hook(Input::Record rec, const FieldCommon &field)
Definition: old_bcd.hh:117
ConvectionTransport(Mesh &init_mesh, const Input::Record &in_rec)
Definition: transport.cc:93
unsigned int boundary_idx() const
Returns index of the region in the boundary set.
Definition: region.hh:75
void compute_concentration_sources_for_mass_balance(unsigned int sbi)
Definition: transport.cc:418
void add(const TimeMark &mark)
Definition: time_marks.cc:77
#define MOBILE
unsigned int n_elements() const
Definition: mesh.h:137
#define ASSERT(...)
Definition: global_defs.h:121
bool is_local(unsigned int idx) const
identify local index
static OutputTime * create_output_stream(const Input::Record &in_rec)
This method write all registered data to output streams.
Definition: output.cc:171
double *** out_conc
Definition: transport.h:267
static Input::Type::Selection sorption_type_selection
Definition: transport.h:87
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:136
Input::Record output_rec
Record with output specification.
Definition: transport.h:270
void calc_fluxes(vector< vector< double > > &bcd_balance, vector< vector< double > > &bcd_plus_balance, vector< vector< double > > &bcd_minus_balance)
Definition: transport.cc:740
TimeMark::Type equation_fixed_mark_type() const
unsigned int begin(int proc) const
get starting local index
Selection & add_value(const int value, const std::string &key, const std::string &description="")
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 START_TIMER(tag)
Starts a timer with specified tag.
void output(double time)
Write computed fields to file.
Mesh * mesh_
Definition: equation.hh:218
Element * element()
Definition: boundaries.cc:47
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:399
void mark_input_times(TimeMark::Type mark_type)
Definition: field_set.hh:201
unsigned int n_subst_
Number of transported substances.
void mark_output_times(const TimeGovernor &tg)
Definition: output.cc:331
#define MPI_Comm_size
Definition: mpi.h:235
#define MPI_DOUBLE
Definition: mpi.h:156
Vec * vconc
Concentration vectors for mobile phase.
Definition: transport.h:256
void * xmalloc(size_t size)
Memory allocation with checking.
Definition: system.cc:209
#define INPUT_CHECK(i,...)
Debugging macros.
Definition: global_defs.h:61
void set_time(const TimeGovernor &time)
Definition: field_set.hh:186
Region region() const
Definition: accessors.hh:88
void calc_elem_sources(vector< vector< double > > &mass, vector< vector< double > > &src_balance)
Definition: transport.cc:781
#define MPI_Comm_rank
Definition: mpi.h:236
std::vector< string > subst_names_
Names of transported substances.
FieldSet output_fields
Fields indended for output, i.e. all input fields plus those representing solution.
Definition: transport.h:109
void create_transport_matrix_mpi()
Definition: transport.cc:588
Support classes for parallel programing.
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
Definition: mpi.h:612
Field< 3, FieldValue< 3 >::Vector > sources_sigma
Concentration sources - Robin type, in_flux = sources_sigma * (sources_conc - mobile_conc) ...
void alloc_transport_structs_mpi()
Definition: transport.cc:279
void set_n_components(unsigned int n_comp)
Definition: field_set.hh:151
double side_flux(const Side &side) const
temporary replacement for DofHandler accessor, flux through given side
bool is_convection_matrix_scaled
Definition: transport.h:224
#define ELEMENT_FULL_ITER_NULL(_mesh_)
Definition: mesh.h:371
static Input::Type::Selection output_selection
Definition: transport.h:89
#define MAX_PHASES
Definition: transport.h:64
void output(OutputTime *stream)
Definition: field_set.cc:136
const Selection & close() const
ElementFullIter element() const
Definition: side_impl.hh:41
int set_upper_constraint(double upper)
Sets upper constraint for the next time step estimating.
Field< 3, FieldValue< 3 >::Vector > sources_density
Concentration sources - density of substance source, only positive part is used.
VecScatter vconc_out_scatter
Definition: transport.h:247
double ** sources_density
temporary arrays to store constant values of fields over time interval
Definition: transport.h:237
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
arma::vec3 centre() const
Definition: elements.cc:130
virtual void output_data() override
Write computed fields.
Definition: transport.cc:808
std::vector< Edge > edges
Vector of MH edges, this should not be part of the geometrical mesh.
Definition: mesh.h:209
Distributed sparse graphs, partitioning.
#define FOR_BOUNDARIES(_mesh_, i)
Definition: mesh.h:375
void set_target_time(double target_time)
Definition: transport.cc:567
unsigned int bulk_idx() const
Returns index of the region in the bulk set.
Definition: region.hh:80
FieldCommon & name(const string &name)
Definition: field_common.hh:71
#define END_TIMER(tag)
Ends a timer with specified tag.
arma::vec::fixed< spacedim > centre() const
Definition: accessors.hh:81
#define FOR_ELM_NEIGHS_VB(i, j)
Definition: elements.h:152
#define MPI_MAX
Definition: mpi.h:197
double ** cumulative_corr
Definition: transport.h:264
mixed-hybrid model of linear Darcy flow, possibly unsteady.
bool changed() const
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:157
Class used for marking specified times at which some events occur.
Definition: time_marks.hh:44
unsigned int n_substances() override
Returns number of trnasported substances.
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:67
unsigned int n_edges() const
Definition: mesh.h:145
#define xfree(p)
Definition: system.hh:108
Class for representation SI units of Fields.
Definition: unit_si.hh:31
#define MPI_Barrier(comm)
Definition: mpi.h:531
Distribution * el_ds
Definition: transport.h:277
SideIter side(const unsigned int i) const
Definition: edges.h:43
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:520
Template for classes storing finite set of named values.
Field< 3, FieldValue< 3 >::Vector > init_conc
Initial concentrations.
Definition: transport.h:104
ElementAccessor< 3 > element_accessor()
Definition: boundaries.cc:55
void make_transport_partitioning()
Definition: transport.cc:149
friend class MassBalance
Definition: mass_balance.hh:62
TimeGovernor * time_
Definition: equation.hh:219
double ** sources_conc
Definition: transport.h:237
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:198
unsigned int lsize(int proc) const
get local size