Flow123d  release_1.8.2-1603-g0109a2b
transport.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file transport.cc
15  * @ingroup transport
16  * @brief Transport
17  */
18 
19 #include <memory>
20 
21 #include "system/system.hh"
22 #include "system/sys_profiler.hh"
23 
24 #include "mesh/mesh.h"
25 #include "mesh/partitioning.hh"
26 #include "transport/transport.h"
27 
28 #include "la/distribution.hh"
29 
30 #include "la/sparse_graph.hh"
31 #include <iostream>
32 #include <iomanip>
33 #include <string>
34 
35 #include "io/output_time.hh"
36 #include "tools/time_governor.hh"
37 #include "coupling/balance.hh"
38 #include "input/accessors.hh"
39 #include "input/input_type.hh"
40 
42 #include "fields/field_values.hh"
44 #include "fields/generic_field.hh"
45 
46 #include "reaction/isotherm.hh" // SorptionType enum
47 
48 
49 FLOW123D_FORCE_LINK_IN_CHILD(convectionTransport);
50 
51 
52 namespace IT = Input::Type;
53 
54 
56  Input::register_class< ConvectionTransport, Mesh &, const Input::Record >("Convection_FV") +
58 
60 {
61  return IT::Record("Convection_FV", "Explicit in time finite volume method for solute transport.")
63  .declare_key("input_fields", IT::Array(
64  EqData().make_field_descriptor_type("Convection_FV")),
66  "")
67 
68  .declare_key("output_fields",
69  IT::Array(
70  ConvectionTransport::EqData().output_fields
71  .make_output_field_selection(
72  "ConvectionTransport_output_fields",
73  "Selection of output fields for Convection Solute Transport model.")
74  .close()),
75  IT::Default("\"conc\""),
76  "List of fields to write to output file.")
77  .close();
78 }
79 
80 
84  "ConvectionTransport_output_fields",
85  "Selection of output fields for Convection Solute Transport model.")
86  .close();
87 
88 }
89 
90 
92 {
93  ADD_FIELD(bc_conc, "Boundary conditions for concentrations.", "0.0");
94  bc_conc.units( UnitSI().kg().m(-3) );
95  ADD_FIELD(init_conc, "Initial concentrations.", "0.0");
96  init_conc.units( UnitSI().kg().m(-3) );
97 
98  output_fields += *this;
100  output_fields += region_id.name("region_id")
103 }
104 
105 
107 : ConcentrationTransportBase(init_mesh, in_rec),
108  is_mass_diag_changed(false),
109  input_rec(in_rec),
110  mh_dh(nullptr)
111 {
112  START_TIMER("ConvectionTransport");
113  this->eq_data_ = &data_;
114 
115  transport_matrix_time = -1.0; // or -infty
116  transport_bc_time = -1.0;
118  is_src_term_scaled = false;
119  is_bc_term_scaled = false;
120 }
121 
123 {
125 
127 
129  data_.set_input_list( input_rec.val<Input::Array>("input_fields") );
130  data_.set_mesh(*mesh_);
131 
135 
136  // register output vectors
142  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
143  {
144  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
145  auto output_field_ptr = out_conc[sbi].create_field<3, FieldValue<3>::Scalar>(n_substances());
146  data_.conc_mobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
147  }
148  output_stream_->add_admissible_field_names(input_rec.val<Input::Array>("output_fields"));
149  output_stream_->mark_output_times(*time_);
150 
151  if (balance_ != nullptr)
152  balance_->allocate(el_ds->lsize(), 1);
153 }
154 
155 
156 //=============================================================================
157 // MAKE TRANSPORT
158 //=============================================================================
160 
161 // int * id_4_old = new int[mesh_->n_elements()];
162 // int i = 0;
163 // FOR_ELEMENTS(mesh_, ele) id_4_old[i++] = ele.index();
164 // mesh_->get_part()->id_maps(mesh_->n_elements(), id_4_old, el_ds, el_4_loc, row_4_el);
165 // delete[] id_4_old;
166  el_ds = mesh_->get_el_ds();
169 
170  // TODO: make output of partitioning is usefull but makes outputs different
171  // on different number of processors, which breaks tests.
172  //
173  // Possible solution:
174  // - have flag in ini file to turn this output ON
175  // - possibility to have different ref_output for different num of proc.
176  // - or do not test such kind of output
177  //
178  //FOR_ELEMENTS(mesh_, ele) {
179  // ele->pid=el_ds->get_proc(row_4_el[ele.index()]);
180  //}
181 
182 }
183 
184 
185 
187 {
188  unsigned int sbi;
189 
190  //Destroy mpi vectors at first
191  MatDestroy(&tm);
192  VecDestroy(&mass_diag);
193  VecDestroy(&vpmass_diag);
194  VecDestroy(&vcfl_flow_);
195  VecDestroy(&vcfl_source_);
196  delete cfl_flow_;
197  delete cfl_source_;
198 
199  for (sbi = 0; sbi < n_substances(); sbi++) {
200  // mpi vectors
201  VecDestroy(&(vconc[sbi]));
202  VecDestroy(&(vpconc[sbi]));
203  VecDestroy(&(bcvcorr[sbi]));
204  VecDestroy(&(vcumulative_corr[sbi]));
205  VecDestroy(&(v_tm_diag[sbi]));
206  VecDestroy(&(v_sources_corr[sbi]));
207 
208  // arrays of arrays
209  delete conc[sbi];
210  delete cumulative_corr[sbi];
211  delete tm_diag[sbi];
212  delete sources_corr[sbi];
213  }
214 
215  // arrays of mpi vectors
216  delete vconc;
217  delete vpconc;
218  delete bcvcorr;
219  delete vcumulative_corr;
220  delete v_tm_diag;
221  delete v_sources_corr;
222 
223  // arrays of arrays
224  delete conc;
225  delete cumulative_corr;
226  delete tm_diag;
227  delete sources_corr;
228 }
229 
230 
231 
232 
233 
235 {
236  FOR_ELEMENTS(mesh_, elem)
237  {
238  if (!el_ds->is_local(row_4_el[elem.index()])) continue;
239 
240  unsigned int index = row_4_el[elem.index()] - el_ds->begin();
241  ElementAccessor<3> ele_acc = mesh_->element_accessor(elem.index());
242  arma::vec value = data_.init_conc.value(elem->centre(), ele_acc);
243 
244  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
245  conc[sbi][index] = value(sbi);
246  }
247 
248 }
249 
250 //=============================================================================
251 // ALLOCATE OF TRANSPORT VARIABLES (ELEMENT & NODES)
252 //=============================================================================
254 
255  unsigned int i, sbi, n_subst;
256  n_subst = n_substances();
257 
258  sources_corr = new double*[n_subst];
259  tm_diag = new double*[n_subst];
260  cumulative_corr = new double*[n_subst];
261  for (sbi = 0; sbi < n_subst; sbi++) {
262  cumulative_corr[sbi] = new double[el_ds->lsize()];
263  sources_corr[sbi] = new double[el_ds->lsize()];
264  tm_diag[sbi] = new double[el_ds->lsize()];
265  }
266 
267  conc = new double*[n_subst];
268  out_conc.clear();
269  out_conc.resize(n_subst);
270  for (sbi = 0; sbi < n_subst; sbi++) {
271  conc[sbi] = new double[el_ds->lsize()];
272  out_conc[sbi].resize( el_ds->size() );
273  for (i = 0; i < el_ds->lsize(); i++) {
274  conc[sbi][i] = 0.0;
275  }
276  }
277 
278  cfl_flow_ = new double[el_ds->lsize()];
279  cfl_source_ = new double[el_ds->lsize()];
280 }
281 
282 //=============================================================================
283 // ALLOCATION OF TRANSPORT VECTORS (MPI)
284 //=============================================================================
286 
287  int sbi, n_subst, rank, np;
288  n_subst = n_substances();
289 
290  MPI_Barrier(PETSC_COMM_WORLD);
291  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
292  MPI_Comm_size(PETSC_COMM_WORLD, &np);
293 
294  vconc = new Vec[n_subst];
295  vpconc = new Vec[n_subst];
296  bcvcorr = new Vec[n_subst];
297  vcumulative_corr = new Vec[n_subst];
298  v_tm_diag = new Vec[n_subst];
299  v_sources_corr = new Vec[n_subst];
300 
301 
302  for (sbi = 0; sbi < n_subst; sbi++) {
303  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &bcvcorr[sbi]);
304  VecZeroEntries(bcvcorr[sbi]);
305  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(), conc[sbi],
306  &vconc[sbi]);
307 
308  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &vpconc[sbi]);
309  VecZeroEntries(vconc[sbi]);
310  VecZeroEntries(vpconc[sbi]);
311 
312  // SOURCES
313  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
314  cumulative_corr[sbi],&vcumulative_corr[sbi]);
315 
316  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
317  sources_corr[sbi],&v_sources_corr[sbi]);
318 
319  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
320  tm_diag[sbi],&v_tm_diag[sbi]);
321 
322  VecZeroEntries(vcumulative_corr[sbi]);
323  VecZeroEntries(out_conc[sbi].get_data_petsc());
324  }
325 
326 
327  MatCreateAIJ(PETSC_COMM_WORLD, el_ds->lsize(), el_ds->lsize(), mesh_->n_elements(),
328  mesh_->n_elements(), 16, PETSC_NULL, 4, PETSC_NULL, &tm);
329 
330  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &mass_diag);
331  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &vpmass_diag);
332 
333  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
335  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
337 }
338 
339 
341 {
342  START_TIMER ("set_boundary_conditions");
343 
345 
346  unsigned int sbi, loc_el, loc_b = 0;
347 
348  // Assembly bcvcorr vector
349  for(sbi=0; sbi < n_substances(); sbi++) VecZeroEntries(bcvcorr[sbi]);
350 
351  if (balance_ != nullptr)
352  balance_->start_flux_assembly(subst_idx);
353 
354  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
355  elm = mesh_->element(el_4_loc[loc_el]);
356  if (elm->boundary_idx_ != NULL) {
357  unsigned int new_i = row_4_el[elm.index()];
358 
359  FOR_ELEMENT_SIDES(elm,si) {
360  Boundary *b = elm->side(si)->cond();
361  if (b != NULL) {
362  double flux = mh_dh->side_flux( *(elm->side(si)) );
363  if (flux < 0.0) {
364  double aij = -(flux / elm->measure() );
365 
366  arma::vec value = data_.bc_conc.value( b->element()->centre(), b->element_accessor() );
367  for (sbi=0; sbi<n_substances(); sbi++)
368  VecSetValue(bcvcorr[sbi], new_i, value[sbi] * aij, ADD_VALUES);
369 
370  if (balance_ != nullptr)
371  {
372  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
373  {
374  // CAUTION: It seems that PETSc possibly optimize allocated space during assembly.
375  // So we have to add also values that may be non-zero in future due to changing velocity field.
376  balance_->add_flux_matrix_values(subst_idx[sbi], loc_b, {row_4_el[el_4_loc[loc_el]]}, {0.});
377  balance_->add_flux_vec_value(subst_idx[sbi], loc_b, flux*value[sbi]);
378  }
379  }
380  } else {
381  for (sbi=0; sbi<n_substances(); sbi++)
382  VecSetValue(bcvcorr[sbi], new_i, 0, ADD_VALUES);
383 
384  if (balance_ != nullptr)
385  {
386  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
387  {
388  balance_->add_flux_matrix_values(subst_idx[sbi], loc_b, {row_4_el[el_4_loc[loc_el]]}, {flux});
389  balance_->add_flux_vec_value(subst_idx[sbi], loc_b, 0);
390  }
391  }
392  }
393  ++loc_b;
394  }
395  }
396 
397  }
398  }
399 
400  if (balance_ != nullptr)
401  balance_->finish_flux_assembly(subst_idx);
402 
403  for (sbi=0; sbi<n_substances(); sbi++) VecAssemblyBegin(bcvcorr[sbi]);
404  for (sbi=0; sbi<n_substances(); sbi++) VecAssemblyEnd(bcvcorr[sbi]);
405 
406  // we are calling set_boundary_conditions() after next_time() and
407  // we are using data from t() before, so we need to set corresponding bc time
409 }
410 
411 
412 //=============================================================================
413 // COMPUTE SOURCES
414 //=============================================================================
416 
417  //temporary variables
418  unsigned int loc_el, sbi;
419  double csection, source, diag;
420 
421  Element *ele;
422  ElementAccessor<3> ele_acc;
423  arma::vec3 p;
424  arma::vec src_density(n_substances()), src_conc(n_substances()), src_sigma(n_substances());
425 
426  //TODO: would it be possible to check the change in data for chosen substance? (may be in multifields?)
427 
428  //checking if the data were changed
429  if( (data_.sources_density.changed() )
430  || (data_.sources_conc.changed() )
431  || (data_.sources_sigma.changed() )
432  || (data_.cross_section.changed()))
433  {
434  START_TIMER("sources_reinit");
435  if (balance_ != nullptr) balance_->start_source_assembly(subst_idx);
436 
437  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
438  {
439  ele = mesh_->element(el_4_loc[loc_el]);
440  ele_acc = ele->element_accessor();
441  p = ele_acc.centre();
442  csection = data_.cross_section.value(p, ele_acc);
443 
444  // read for all substances
445  src_density = data_.sources_density.value(p, ele_acc);
446  src_conc = data_.sources_conc.value(p, ele_acc);
447  src_sigma = data_.sources_sigma.value(p, ele_acc);
448 
449  double max_cfl=0;
450  for (sbi = 0; sbi < n_substances(); sbi++)
451  {
452  source = csection * (src_density(sbi) + src_sigma(sbi) * src_conc(sbi));
453  // addition to RHS
454  sources_corr[sbi][loc_el] = source;
455  // addition to diagonal of the transport matrix
456  diag = src_sigma(sbi) * csection;
457  tm_diag[sbi][loc_el] = - diag;
458 
459  // compute maximal cfl condition over all substances
460  max_cfl = std::max(max_cfl, fabs(diag));
461 
462  if (balance_ != nullptr)
463  {
464  balance_->add_source_matrix_values(sbi, ele_acc.region().bulk_idx(), {row_4_el[el_4_loc[loc_el]]},
465  {- src_sigma(sbi) * ele->measure() * csection});
466  balance_->add_source_rhs_values(sbi, ele_acc.region().bulk_idx(), {row_4_el[el_4_loc[loc_el]]},
467  {source * ele->measure()});
468  }
469  }
470 
471  cfl_source_[loc_el] = max_cfl;
472  }
473 
474  if (balance_ != nullptr) balance_->finish_source_assembly(subst_idx);
475 
476  END_TIMER("sources_reinit");
477  }
478 }
479 
480 
481 
483 {
485 
488 
491 
492  if (balance_ != nullptr)
493  {
494  START_TIMER("Convection balance zero time step");
495 
499 
501  }
502 
503  // write initial condition
504  output_data();
505 }
506 
507 
509 {
510  OLD_ASSERT(mh_dh, "Null MH object.\n" );
511  data_.set_time(time_->step(), LimitSide::right); // set to the last computed time
512 
513  START_TIMER("data reinit");
514 
515  bool cfl_changed = false;
516 
517  // if FLOW or DATA changed ---------------------> recompute transport matrix
519  {
522  cfl_changed = true;
523  DBGMSG("CFL changed - flow.\n");
524  }
525 
527  {
529  cfl_changed = true;
530  DBGMSG("CFL changed - mass matrix.\n");
531  }
532 
533  // if DATA changed ---------------------> recompute concentration sources (rhs and matrix diagonal)
536  {
538  is_src_term_scaled = false;
539  cfl_changed = true;
540  DBGMSG("CFL changed - source.\n");
541  }
542 
543  // now resolve the CFL condition
544  if(cfl_changed)
545  {
546  // find maximum of sum of contribution from flow and sources: MAX(vcfl_flow_ + vcfl_source_)
547  Vec cfl;
548  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(),PETSC_DETERMINE, &cfl);
549  VecWAXPY(cfl, 1.0, vcfl_flow_, vcfl_source_);
550  VecMaxPointwiseDivide(cfl,mass_diag, &cfl_max_step);
551  // get a reciprocal value as a time constraint
553  }
554 
555  // although it does not influence CFL, compute BC so the full system is assembled
557  || data_.porosity.changed()
558  || data_.bc_conc.changed() )
559  {
561  is_bc_term_scaled = false;
562  }
563 
564  END_TIMER("data reinit");
565 
566  // return time constraint
567  time_constraint = cfl_max_step;
568  return cfl_changed;
569 }
570 
572 
573  START_TIMER("convection-one step");
574 
575  // proceed to next time - which we are about to compute
576  // explicit scheme looks one step back and uses data from previous time
577  // (data time set previously in assess_time_constraint())
578  time_->next_time();
579 
580  double dt_new = time_->dt(), // current time step we are about to compute
581  dt_scaled = dt_new / time_->last_dt(); // scaling ratio to previous time step
582 
583  START_TIMER("time step rescaling");
584 
585  // if FLOW or DATA or BC or DT changed ---------------------> rescale boundary condition
587  {
588  DBGMSG("BC - rescale dt.\n");
589  //choose between fresh scaling with new dt or rescaling to a new dt
590  double dt = (!is_bc_term_scaled) ? dt_new : dt_scaled;
591  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
592  VecScale(bcvcorr[sbi], dt);
593  is_bc_term_scaled = true;
594  }
595 
596 
597  // if DATA or TIME STEP changed -----------------------> rescale source term
599  DBGMSG("SRC - rescale dt.\n");
600  //choose between fresh scaling with new dt or rescaling to a new dt
601  double dt = (!is_src_term_scaled) ? dt_new : dt_scaled;
602  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
603  {
604  VecScale(v_sources_corr[sbi], dt);
605  VecScale(v_tm_diag[sbi], dt);
606  }
607  is_src_term_scaled = true;
608  }
609 
610  // if DATA or TIME STEP changed -----------------------> rescale transport matrix
612  DBGMSG("TM - rescale dt.\n");
613  //choose between fresh scaling with new dt or rescaling to a new dt
614  double dt = (!is_convection_matrix_scaled) ? dt_new : dt_scaled;
615 
616  MatScale(tm, dt);
618  }
619 
620  END_TIMER("time step rescaling");
621 
622 
623  data_.set_time(time_->step(), LimitSide::right); // set to the last computed time
625  {
626  VecCopy(mass_diag, vpmass_diag);
628  } else is_mass_diag_changed = false;
629 
630 
631  // Compute new concentrations for every substance.
632 
633  for (unsigned int sbi = 0; sbi < n_substances(); sbi++) {
634  // one step in MOBILE phase
635  START_TIMER("mat mult");
636 
637  // tm_diag is a diagonal part of transport matrix, which depends on substance data (sources_sigma)
638  // Wwe need keep transport matrix independent of substance, therefore we keep this diagonal part
639  // separately in a vector tm_diag.
640  // Computation: first, we compute this diagonal addition D*pconc and save it temporaly into RHS
641 
642  // RHS = D*pconc, where D is diagonal matrix represented by a vector
643  VecPointwiseMult(vcumulative_corr[sbi], v_tm_diag[sbi], vconc[sbi]); //w = x.*y
644 
645  // Then we add boundary terms ans other source terms into RHS.
646  // RHS = 1.0 * bcvcorr + 1.0 * v_sources_corr + 1.0 * rhs
647  VecAXPBYPCZ(vcumulative_corr[sbi], 1.0, 1.0, 1.0, bcvcorr[sbi], v_sources_corr[sbi]); //z = ax + by + cz
648 
649  // Then we set the new previous concentration.
650  VecCopy(vconc[sbi], vpconc[sbi]); // pconc = conc
651  // And finally proceed with transport matrix multiplication.
652  if (is_mass_diag_changed) {
653  VecPointwiseMult(vconc[sbi], vconc[sbi], vpmass_diag); // vconc*=vpmass_diag
654  MatMultAdd(tm, vpconc[sbi], vconc[sbi], vconc[sbi]); // vconc+=tm*vpconc
655  VecAXPY(vconc[sbi], 1, vcumulative_corr[sbi]); // vconc+=vcumulative_corr
656  VecPointwiseDivide(vconc[sbi], vconc[sbi], mass_diag); // vconc/=mass_diag
657  } else {
658  MatMultAdd(tm, vpconc[sbi], vcumulative_corr[sbi], vconc[sbi]); // vconc =tm*vpconc+vcumulative_corr
659  VecPointwiseDivide(vconc[sbi], vconc[sbi], mass_diag); // vconc/=mass_diag
660  VecAXPY(vconc[sbi], 1, vpconc[sbi]); // vconc+=vpconc
661  }
662 
663  END_TIMER("mat mult");
664  }
665 
666  if (balance_ != nullptr)
668 
669  END_TIMER("convection-one step");
670 }
671 
672 
673 void ConvectionTransport::set_target_time(double target_time)
674 {
675 
676  //sets target_mark_type (it is fixed) to be met in next_time()
677  time_->marks().add(TimeMark(target_time, target_mark_type));
678 
679  // This is done every time TOS calls update_solution.
680  // If CFL condition is changed, time fixation will change later from TOS.
681 
682  // Set the same constraint as was set last time.
683 
684  // TODO: fix this hack, remove this method completely, leaving just the first line at the calling point
685  // in TransportOperatorSplitting::update_solution()
686  // doing this directly leads to choose of large time step violationg CFL condition
687  if (cfl_max_step > time_->dt()*1e-10)
688  time_->set_upper_constraint(cfl_max_step, "CFL condition used from previous step.");
689 
690  // fixing convection time governor till next target_mark_type (got from TOS or other)
691  // may have marks for data changes
693 }
694 
695 
697 {
699 
700  VecZeroEntries(mass_diag);
701 
702  if (balance_ != nullptr)
703  balance_->start_mass_assembly(subst_idx);
704 
705  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
706  elm = mesh_->element(el_4_loc[loc_el]);
707 
708  double csection = data_.cross_section.value(elm->centre(), elm->element_accessor());
709  double por_m = data_.porosity.value(elm->centre(), elm->element_accessor());
710 
711  if (balance_ != nullptr)
712  {
713  for (unsigned int sbi=0; sbi<n_substances(); ++sbi)
714  balance_->add_mass_matrix_values(subst_idx[sbi], elm->region().bulk_idx(), {row_4_el[el_4_loc[loc_el]]}, {csection*por_m*elm->measure()} );
715  }
716 
717  VecSetValue(mass_diag, row_4_el[elm.index()], csection*por_m, INSERT_VALUES);
718  }
719 
720  if (balance_ != nullptr)
721  balance_->finish_mass_assembly(subst_idx);
722 
723  VecAssemblyBegin(mass_diag);
724  VecAssemblyEnd(mass_diag);
725 
726  is_mass_diag_changed = true;
727 }
728 
729 
730 //=============================================================================
731 // CREATE TRANSPORT MATRIX
732 //=============================================================================
734 
735  START_TIMER("convection_matrix_assembly");
736 
739  struct Edge *edg;
740  unsigned int n;
741  int s, j, np, rank, new_j, new_i;
742  double aij, aii;
743 
744  MatZeroEntries(tm);
745 
746  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
747  MPI_Comm_size(PETSC_COMM_WORLD, &np);
748 
749  double flux, flux2, edg_flux;
750 
751  aii = 0.0;
752 
753  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
754  elm = mesh_->element(el_4_loc[loc_el]);
755  new_i = row_4_el[elm.index()];
756 
757  FOR_ELEMENT_SIDES(elm,si) {
758  // same dim
759  flux = mh_dh->side_flux( *(elm->side(si)) );
760  if (elm->side(si)->cond() == NULL) {
761  edg = elm->side(si)->edge();
762  edg_flux = 0;
763  for( int s=0; s < edg->n_sides; s++) {
764  flux2 = mh_dh->side_flux( *(edg->side(s)) );
765  if ( flux2 > 0) edg_flux+= flux2;
766  }
767  FOR_EDGE_SIDES(edg,s)
768  // this test should also eliminate sides facing to lower dim. elements in comp. neighboring
769  // These edges on these sides should have just one side
770  if (edg->side(s) != elm->side(si)) {
771  j = ELEMENT_FULL_ITER(mesh_, edg->side(s)->element()).index();
772  new_j = row_4_el[j];
773 
774  flux2 = mh_dh->side_flux( *(edg->side(s)));
775  if ( flux2 > 0.0 && flux <0.0)
776  aij = -(flux * flux2 / ( edg_flux * elm->measure() ) );
777  else aij =0;
778  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
779  }
780  }
781  if (flux > 0.0)
782  aii -= (flux / elm->measure() );
783  } // end same dim //ELEMENT_SIDES
784 
785  FOR_ELM_NEIGHS_VB(elm,n) // comp model
786  {
787  el2 = ELEMENT_FULL_ITER(mesh_, elm->neigh_vb[n]->side()->element() ); // higher dim. el.
788  OLD_ASSERT( el2 != elm, "Elm. same\n");
789  new_j = row_4_el[el2.index()];
790  flux = mh_dh->side_flux( *(elm->neigh_vb[n]->side()) );
791 
792  // volume source - out-flow from higher dimension
793  if (flux > 0.0) aij = flux / elm->measure();
794  else aij=0;
795  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
796  // out flow from higher dim. already accounted
797 
798  // volume drain - in-flow to higher dimension
799  if (flux < 0.0) {
800  aii -= (-flux) / elm->measure(); // diagonal drain
801  aij = (-flux) / el2->measure();
802  } else aij=0;
803  MatSetValue(tm, new_j, new_i, aij, INSERT_VALUES);
804  }
805 
806  MatSetValue(tm, new_i, new_i, aii, INSERT_VALUES);
807 
808  cfl_flow_[loc_el] = fabs(aii);
809  aii = 0.0;
810  } // END ELEMENTS
811 
812  MatAssemblyBegin(tm, MAT_FINAL_ASSEMBLY);
813  MatAssemblyEnd(tm, MAT_FINAL_ASSEMBLY);
814 
816  END_TIMER("convection_matrix_assembly");
817 
819 }
820 
821 
822 
823 
824 
825 //=============================================================================
826 // OUTPUT VECTOR GATHER
827 //=============================================================================
829 
830  unsigned int sbi;
831  IS is;
832 
833  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el, PETSC_COPY_VALUES, &is); //WithArray
834  VecScatterCreate(vconc[0], is, out_conc[0].get_data_petsc(), PETSC_NULL, &vconc_out_scatter);
835  for (sbi = 0; sbi < n_substances(); sbi++) {
836  VecScatterBegin(vconc_out_scatter, vconc[sbi], out_conc[sbi].get_data_petsc(), INSERT_VALUES, SCATTER_FORWARD);
837  VecScatterEnd(vconc_out_scatter, vconc[sbi], out_conc[sbi].get_data_petsc(), INSERT_VALUES, SCATTER_FORWARD);
838  }
839  VecScatterDestroy(&(vconc_out_scatter));
840  ISDestroy(&(is));
841 }
842 
843 
845  return conc;
846 }
847 
848 void ConvectionTransport::get_par_info(int * &el_4_loc_out, Distribution * &el_distribution_out){
849  el_4_loc_out = this->el_4_loc;
850  el_distribution_out = this->el_ds;
851  return;
852 }
853 
854 //int *ConvectionTransport::get_el_4_loc(){
855 // return el_4_loc;
856 //}
857 
859  return row_4_el;
860 }
861 
862 
863 
865 {
866  for (unsigned int sbi=0; sbi<n_substances(); ++sbi)
867  {
868  balance_->calculate_cumulative_sources(sbi, vpconc[sbi], time_->dt());
869  balance_->calculate_cumulative_fluxes(sbi, vpconc[sbi], time_->dt());
870  }
871 }
872 
873 
875 {
876  for (unsigned int sbi=0; sbi<n_substances(); ++sbi)
877  {
878  balance_->calculate_mass(sbi, vconc[sbi]);
879  balance_->calculate_source(sbi, vconc[sbi]);
880  balance_->calculate_flux(sbi, vconc[sbi]);
881  }
882 }
883 
884 
886 
887  if (time_->is_current( time_->marks().type_output() )) {
889 
892 
893  }
894 }
895 
896 void ConvectionTransport::set_balance_object(boost::shared_ptr<Balance> balance)
897 {
898  balance_ = balance;
899  subst_idx = balance_->add_quantities(substances_.names());
900 }
void output_type(OutputTime::DiscreteSpace rt)
Definition: field_set.hh:203
static const IT::Selection & get_output_selection()
Definition: transport.cc:81
unsigned int size() const
get global size
void set_input_list(Input::Array input_list)
Definition: field_set.hh:180
void calculate_instant_balance() override
Definition: transport.cc:874
void set_balance_object(boost::shared_ptr< Balance > balance) override
Definition: transport.cc:896
FieldSet * eq_data_
Definition: equation.hh:230
#define DBGMSG(...)
Definition: global_defs.h:229
#define ADD_FIELD(name,...)
Definition: field_set.hh:275
std::vector< VectorSeqDouble > out_conc
Definition: transport.h:304
bool is_mass_diag_changed
Flag indicates that porosity or cross_section changed during last time.
Definition: transport.h:265
double measure() const
Definition: elements.cc:89
double time_changed() const
void update_solution() override
Definition: transport.cc:571
Accessor to input data conforming to declared Array.
Definition: accessors.hh:552
double end_time() const
End time.
double transport_matrix_time
Definition: transport.h:290
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:578
int tlevel() const
const std::vector< std::string > & names()
Definition: substance.hh:85
#define FOR_EDGE_SIDES(i, j)
Definition: edges.h:41
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:50
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:408
void alloc_transport_vectors()
Definition: transport.cc:253
unsigned int n_substances() override
Returns number of transported substances.
Definition: transport.h:199
void set_time(const TimeStep &time, LimitSide limit_side)
Definition: field_set.hh:195
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:88
void create_mass_matrix()
Definition: transport.cc:696
void next_time()
Proceed to the next time according to current estimated time step.
void initialize() override
Definition: transport.cc:122
std::shared_ptr< OutputTime > output_stream_
Definition: transport.h:309
TimeMark::Type target_mark_type
TimeMark type for time marks denoting end of every time interval where transport matrix remains const...
Definition: transport.h:272
TimeMark::Type type_output()
Definition: time_marks.hh:190
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:99
void set_initial_condition()
Definition: transport.cc:234
double transport_bc_time
Time of the last update of the boundary condition terms.
Definition: transport.h:291
double * cfl_flow_
Definition: transport.h:277
MultiField< 3, FieldValue< 3 >::Scalar > sources_density
Concentration sources - density of substance source, only positive part is used.
void set_boundary_conditions()
Definition: transport.cc:340
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:321
#define ELEMENT_FULL_ITER(_mesh_, i)
Definition: mesh.h:416
Definition: mesh.h:99
Fields computed from the mesh data.
double ** sources_corr
Definition: transport.h:268
#define FOR_ELEMENT_SIDES(i, j)
Definition: elements.h:140
MultiField< 3, FieldValue< 3 >::Scalar > sources_conc
int index() const
Definition: sys_vector.hh:78
BCMultiField< 3, FieldValue< 3 >::Scalar > bc_conc
Definition: transport.h:82
bool is_current(const TimeMark::Type &mask) const
int * get_el_4_loc() const
Definition: mesh.h:171
int n_sides
Definition: edges.h:36
Definition: edges.h:26
const RegionDB & region_db() const
Definition: mesh.h:156
ElementAccessor< 3 > element_accessor(unsigned int idx, bool boundary=false)
Definition: mesh.cc:700
double ** conc
Concentrations for phase, substance, element.
Definition: transport.h:296
const TimeStep & step(int index=-1) const
virtual ~ConvectionTransport()
Definition: transport.cc:186
static Input::Type::Abstract & get_input_type()
Common specification of the input record for secondary equations.
MultiField< 3, FieldValue< 3 >::Scalar > init_conc
Initial concentrations.
Definition: transport.h:85
double t() const
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
void zero_time_step() override
Definition: transport.cc:482
static TimeMarks & marks()
void output_vector_gather()
Definition: transport.cc:828
Basic time management class.
Class for declaration of inputs sequences.
Definition: type_base.hh:316
const Input::Record input_rec
Record with input specification.
Definition: transport.h:307
double last_t() const
const MH_DofHandler * mh_dh
Definition: transport.h:324
static const Input::Type::Record & get_input_type()
Definition: transport.cc:59
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:193
#define OLD_ASSERT(...)
Definition: global_defs.h:128
void setup_components()
void add(const TimeMark &mark)
Definition: time_marks.cc:74
unsigned int n_elements() const
Definition: mesh.h:142
bool is_local(unsigned int idx) const
identify local index
static constexpr Mask equation_result
Match result fields. These are never given by input or copy of input.
Definition: field_flag.hh:49
TimeMark::Type equation_fixed_mark_type() const
MultiField< 3, FieldValue< 3 >::Scalar > sources_sigma
Concentration sources - Robin type, in_flux = sources_sigma * (sources_conc - mobile_conc) ...
static constexpr Mask equation_external_output
Match an output field, that can be also copy of other field.
Definition: field_flag.hh:52
unsigned int begin(int proc) const
get starting local index
Accessor to the data with type Type::Record.
Definition: accessors.hh:277
const Ret val(const string &key) const
static auto region_id(Mesh &mesh) -> IndexField
ConvectionTransport(Mesh &init_mesh, const Input::Record in_rec)
Definition: transport.cc:106
static const int registrar
Registrar of class to factory.
Definition: transport.h:249
bool is_changed_dt() const
#define START_TIMER(tag)
Starts a timer with specified tag.
SubstanceList substances_
Transported substances.
Definition: transport.h:317
Mesh * mesh_
Definition: equation.hh:221
Element * element()
Definition: boundaries.cc:35
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:337
double ** get_concentration_matrix() override
Getter for array of concentrations per element.
Definition: transport.cc:844
Field< 3, FieldValue< 3 >::Scalar > porosity
Mobile porosity.
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:459
void calculate_cumulative_balance() override
Definition: transport.cc:864
const Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:271
vector< unsigned int > subst_idx
List of indices used to call balance methods for a set of quantities.
Definition: transport.h:327
Distribution * get_el_ds() const
Definition: mesh.h:165
#define MPI_Comm_size
Definition: mpi.h:235
Vec * vconc
Concentration vectors for mobile phase.
Definition: transport.h:294
Region region() const
Definition: accessors.hh:98
#define MPI_Comm_rank
Definition: mpi.h:236
void mark_input_times(const TimeGovernor &tg)
Definition: field_set.hh:210
FieldSet output_fields
Fields indended for output, i.e. all input fields plus those representing solution.
Definition: transport.h:92
Field< 3, FieldValue< 3 >::Integer > region_id
Definition: transport.h:87
void create_transport_matrix_mpi()
Definition: transport.cc:733
Support classes for parallel programing.
void alloc_transport_structs_mpi()
Definition: transport.cc:285
int set_upper_constraint(double upper, std::string message)
Sets upper constraint for the next time step estimating.
double side_flux(const Side &side) const
temporary replacement for DofHandler accessor, flux through given side
bool is_convection_matrix_scaled
Definition: transport.h:262
FLOW123D_FORCE_LINK_IN_CHILD(convectionTransport)
double * cfl_source_
Definition: transport.h:277
#define ELEMENT_FULL_ITER_NULL(_mesh_)
Definition: mesh.h:422
virtual MultiFieldValue::return_type value(const Point &p, const ElementAccessor< spacedim > &elm) const
const Selection & close() const
Close the Selection, no more values can be added.
void output(std::shared_ptr< OutputTime > stream)
Definition: field_set.cc:169
void set_components(const std::vector< string > &names)
Definition: field_set.hh:167
ElementFullIter element() const
Definition: side_impl.hh:51
void compute_concentration_sources()
Assembles concentration sources for each substance. note: the source of concentration is multiplied b...
Definition: transport.cc:415
bool evaluate_time_constraint(double &time_constraint) override
Definition: transport.cc:508
VecScatter vconc_out_scatter
Definition: transport.h:280
double dt() const
Vec vcfl_flow_
Parallel vector for flow contribution to CFL condition.
Definition: transport.h:275
arma::vec3 centre() const
Definition: elements.cc:120
void set_target_time(double target_time) override
Definition: transport.cc:673
int * get_row_4_el() const
Definition: mesh.h:168
double ** tm_diag
Definition: transport.h:285
virtual void output_data() override
Write computed fields.
Definition: transport.cc:885
Distributed sparse graphs, partitioning.
Vec vcfl_source_
Parallel vector for source term contribution to CFL condition.
Definition: transport.h:275
unsigned int bulk_idx() const
Returns index of the region in the bulk set.
Definition: region.hh:90
int * get_row_4_el() override
Return global array of order of elements within parallel vector.
Definition: transport.cc:858
FieldCommon & name(const string &name)
Definition: field_common.hh:83
#define END_TIMER(tag)
Ends a timer with specified tag.
arma::vec::fixed< spacedim > centre() const
Definition: accessors.hh:91
boost::shared_ptr< Balance > balance_
object for calculation and writing the mass balance to file.
Definition: equation.hh:233
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:130
#define FOR_ELM_NEIGHS_VB(i, j)
Definition: elements.h:141
ElementAccessor< 3 > element_accessor() const
Gets ElementAccessor of this element.
Definition: elements.cc:148
double ** cumulative_corr
Definition: transport.h:302
bool changed() const
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:173
Class used for marking specified times at which some events occur.
Definition: time_marks.hh:36
Record type proxy class.
Definition: type_record.hh:171
void get_par_info(int *&el_4_loc, Distribution *&el_ds) override
Return array of indices of local elements and parallel distribution of elements.
Definition: transport.cc:848
FieldCommon & flags(FieldFlag::Flags::Mask mask)
Field< 3, FieldValue< 3 >::Scalar > cross_section
Pointer to DarcyFlow field cross_section.
Class for representation SI units of Fields.
Definition: unit_si.hh:40
#define MPI_Barrier(comm)
Definition: mpi.h:531
double last_dt() const
Input::Type::Selection make_output_field_selection(const string &name, const string &desc)
Definition: field_set.cc:95
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:53
Other possible transformation of coordinates:
Distribution * el_ds
Definition: transport.h:314
SideIter side(const unsigned int i) const
Definition: edges.h:31
Template for classes storing finite set of named values.
ElementAccessor< 3 > element_accessor()
Definition: boundaries.cc:43
void make_transport_partitioning()
Definition: transport.cc:159
double cfl_max_step
Time step constraint coming from CFL condition.
Definition: transport.h:273
TimeGovernor * time_
Definition: equation.hh:222
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:225
unsigned int lsize(int proc) const
get local size