Flow123d  release_2.2.0-914-gf1a3a4f
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 const string _equation_name = "Solute_Advection_FV";
55 
57  Input::register_class< ConvectionTransport, Mesh &, const Input::Record >(_equation_name) +
59 
61 {
62  return IT::Record(_equation_name, "Explicit in time finite volume method for advection only solute transport.")
64  .declare_key("input_fields", IT::Array(
65  EqData().make_field_descriptor_type(_equation_name)),
67  "")
68  .declare_key("output",
69  EqData().output_fields.make_output_type(_equation_name, ""),
70  IT::Default("{ \"fields\": [ \"conc\" ] }"),
71  "Setting of the fields output.")
72  .close();
73 }
74 
75 
77 {
78  ADD_FIELD(bc_conc, "Boundary conditions for concentrations.", "0.0");
79  bc_conc.units( UnitSI().kg().m(-3) );
80  ADD_FIELD(init_conc, "Initial concentrations.", "0.0");
81  init_conc.units( UnitSI().kg().m(-3) );
82 
83  output_fields += *this;
84  output_fields += conc_mobile.name("conc")
85  .units( UnitSI().kg().m(-3) )
87  output_fields += region_id.name("region_id")
90  output_fields += subdomain.name("subdomain")
93 }
94 
95 
97 : ConcentrationTransportBase(init_mesh, in_rec),
98  is_mass_diag_changed(false),
99  input_rec(in_rec),
100  mh_dh(nullptr),
101  sources_corr(nullptr)
102 {
103  START_TIMER("ConvectionTransport");
104  this->eq_data_ = &data_;
105 
106  transport_matrix_time = -1.0; // or -infty
107  transport_bc_time = -1.0;
109  is_src_term_scaled = false;
110  is_bc_term_scaled = false;
111 }
112 
114 {
116 
118 
120  data_.set_input_list( input_rec.val<Input::Array>("input_fields") );
121  data_.set_mesh(*mesh_);
122 
126 
127  // register output vectors
134  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
135  {
136  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
137  auto output_field_ptr = out_conc[sbi].create_field<3, FieldValue<3>::Scalar>(n_substances());
138  data_.conc_mobile[sbi].set_field(mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
139  }
140  //output_stream_->add_admissible_field_names(input_rec.val<Input::Array>("output_fields"));
141  //output_stream_->mark_output_times(*time_);
142 
144  //cout << "Transport." << endl;
145  //cout << time().marks();
146 
147  balance_->allocate(el_ds->lsize(), 1);
148 
149 }
150 
151 
152 //=============================================================================
153 // MAKE TRANSPORT
154 //=============================================================================
156 
157 // int * id_4_old = new int[mesh_->n_elements()];
158 // int i = 0;
159 // FOR_ELEMENTS(mesh_, ele) id_4_old[i++] = ele.index();
160 // mesh_->get_part()->id_maps(mesh_->n_elements(), id_4_old, el_ds, el_4_loc, row_4_el);
161 // delete[] id_4_old;
162  el_ds = mesh_->get_el_ds();
165 
166  // TODO: make output of partitioning is usefull but makes outputs different
167  // on different number of processors, which breaks tests.
168  //
169  // Possible solution:
170  // - have flag in ini file to turn this output ON
171  // - possibility to have different ref_output for different num of proc.
172  // - or do not test such kind of output
173  //
174  //FOR_ELEMENTS(mesh_, ele) {
175  // ele->pid=el_ds->get_proc(row_4_el[ele.index()]);
176  //}
177 
178 }
179 
180 
181 
183 {
184  unsigned int sbi;
185 
186  if (sources_corr) {
187  //Destroy mpi vectors at first
188  MatDestroy(&tm);
189  VecDestroy(&mass_diag);
190  VecDestroy(&vpmass_diag);
191  VecDestroy(&vcfl_flow_);
192  VecDestroy(&vcfl_source_);
193  delete cfl_flow_;
194  delete cfl_source_;
195 
196  for (sbi = 0; sbi < n_substances(); sbi++) {
197  // mpi vectors
198  VecDestroy(&(vconc[sbi]));
199  VecDestroy(&(vpconc[sbi]));
200  VecDestroy(&(bcvcorr[sbi]));
201  VecDestroy(&(vcumulative_corr[sbi]));
202  VecDestroy(&(v_tm_diag[sbi]));
203  VecDestroy(&(v_sources_corr[sbi]));
204 
205  // arrays of arrays
206  delete conc[sbi];
207  delete cumulative_corr[sbi];
208  delete tm_diag[sbi];
209  delete sources_corr[sbi];
210  }
211 
212  // arrays of mpi vectors
213  delete vconc;
214  delete vpconc;
215  delete bcvcorr;
216  delete vcumulative_corr;
217  delete v_tm_diag;
218  delete v_sources_corr;
219 
220  // arrays of arrays
221  delete conc;
222  delete cumulative_corr;
223  delete tm_diag;
224  delete sources_corr;
225  }
226 }
227 
228 
229 
230 
231 
233 {
234  FOR_ELEMENTS(mesh_, elem)
235  {
236  if (!el_ds->is_local(row_4_el[elem.index()])) continue;
237 
238  IdxInt index = row_4_el[elem.index()] - el_ds->begin();
239  ElementAccessor<3> ele_acc = mesh_->element_accessor(elem.index());
240 
241  for (unsigned int sbi=0; sbi<n_substances(); sbi++) // Optimize: SWAP LOOPS
242  conc[sbi][index] = data_.init_conc[sbi].value(elem->centre(), ele_acc);
243  }
244 
245 }
246 
247 //=============================================================================
248 // ALLOCATE OF TRANSPORT VARIABLES (ELEMENT & NODES)
249 //=============================================================================
251 
252  unsigned int i, sbi, n_subst;
253  n_subst = n_substances();
254 
255  sources_corr = new double*[n_subst];
256  tm_diag = new double*[n_subst];
257  cumulative_corr = new double*[n_subst];
258  for (sbi = 0; sbi < n_subst; sbi++) {
259  cumulative_corr[sbi] = new double[el_ds->lsize()];
260  sources_corr[sbi] = new double[el_ds->lsize()];
261  tm_diag[sbi] = new double[el_ds->lsize()];
262  }
263 
264  conc = new double*[n_subst];
265  out_conc.clear();
266  out_conc.resize(n_subst);
267  for (sbi = 0; sbi < n_subst; sbi++) {
268  conc[sbi] = new double[el_ds->lsize()];
269  out_conc[sbi].resize( el_ds->size() );
270  for (i = 0; i < el_ds->lsize(); i++) {
271  conc[sbi][i] = 0.0;
272  }
273  }
274 
275  cfl_flow_ = new double[el_ds->lsize()];
276  cfl_source_ = new double[el_ds->lsize()];
277 }
278 
279 //=============================================================================
280 // ALLOCATION OF TRANSPORT VECTORS (MPI)
281 //=============================================================================
283 
284  int sbi, n_subst, rank, np;
285  n_subst = n_substances();
286 
287  MPI_Barrier(PETSC_COMM_WORLD);
288  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
289  MPI_Comm_size(PETSC_COMM_WORLD, &np);
290 
291  vconc = new Vec[n_subst];
292  vpconc = new Vec[n_subst];
293  bcvcorr = new Vec[n_subst];
294  vcumulative_corr = new Vec[n_subst];
295  v_tm_diag = new Vec[n_subst];
296  v_sources_corr = new Vec[n_subst];
297 
298 
299  for (sbi = 0; sbi < n_subst; sbi++) {
300  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &bcvcorr[sbi]);
301  VecZeroEntries(bcvcorr[sbi]);
302  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(), conc[sbi],
303  &vconc[sbi]);
304 
305  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &vpconc[sbi]);
306  VecZeroEntries(vconc[sbi]);
307  VecZeroEntries(vpconc[sbi]);
308 
309  // SOURCES
310  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
311  cumulative_corr[sbi],&vcumulative_corr[sbi]);
312 
313  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
314  sources_corr[sbi],&v_sources_corr[sbi]);
315 
316  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
317  tm_diag[sbi],&v_tm_diag[sbi]);
318 
319  VecZeroEntries(vcumulative_corr[sbi]);
320  VecZeroEntries(out_conc[sbi].get_data_petsc());
321  }
322 
323 
324  MatCreateAIJ(PETSC_COMM_WORLD, el_ds->lsize(), el_ds->lsize(), mesh_->n_elements(),
325  mesh_->n_elements(), 16, PETSC_NULL, 4, PETSC_NULL, &tm);
326 
327  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &mass_diag);
328  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(), mesh_->n_elements(), &vpmass_diag);
329 
330  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
332  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, el_ds->lsize(), mesh_->n_elements(),
334 }
335 
336 
338 {
339  START_TIMER ("set_boundary_conditions");
340 
342 
343  unsigned int sbi, loc_el, loc_b = 0;
344 
345  // Assembly bcvcorr vector
346  for(sbi=0; sbi < n_substances(); sbi++) VecZeroEntries(bcvcorr[sbi]);
347 
348  balance_->start_flux_assembly(subst_idx);
349 
350  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
351  elm = mesh_->element(el_4_loc[loc_el]);
352  if (elm->boundary_idx_ != NULL) {
353  IdxInt new_i = row_4_el[elm.index()];
354 
355  FOR_ELEMENT_SIDES(elm,si) {
356  Boundary *b = elm->side(si)->cond();
357  if (b != NULL) {
358  double flux = mh_dh->side_flux( *(elm->side(si)) );
359  if (flux < 0.0) {
360  double aij = -(flux / elm->measure() );
361 
362  for (sbi=0; sbi<n_substances(); sbi++)
363  {
364  double value = data_.bc_conc[sbi].value( b->element()->centre(), b->element_accessor() );
365 
366  VecSetValue(bcvcorr[sbi], new_i, value * aij, ADD_VALUES);
367 
368  // CAUTION: It seems that PETSc possibly optimize allocated space during assembly.
369  // So we have to add also values that may be non-zero in future due to changing velocity field.
370  balance_->add_flux_matrix_values(subst_idx[sbi], loc_b, {row_4_el[el_4_loc[loc_el]]}, {0.});
371  balance_->add_flux_vec_value(subst_idx[sbi], loc_b, flux*value);
372  }
373  } else {
374  for (sbi=0; sbi<n_substances(); sbi++)
375  VecSetValue(bcvcorr[sbi], new_i, 0, ADD_VALUES);
376 
377  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
378  {
379  balance_->add_flux_matrix_values(subst_idx[sbi], loc_b, {row_4_el[el_4_loc[loc_el]]}, {flux});
380  balance_->add_flux_vec_value(subst_idx[sbi], loc_b, 0);
381  }
382  }
383  ++loc_b;
384  }
385  }
386 
387  }
388  }
389 
390  balance_->finish_flux_assembly(subst_idx);
391 
392  for (sbi=0; sbi<n_substances(); sbi++) VecAssemblyBegin(bcvcorr[sbi]);
393  for (sbi=0; sbi<n_substances(); sbi++) VecAssemblyEnd(bcvcorr[sbi]);
394 
395  // we are calling set_boundary_conditions() after next_time() and
396  // we are using data from t() before, so we need to set corresponding bc time
398 }
399 
400 
401 //=============================================================================
402 // COMPUTE SOURCES
403 //=============================================================================
405 
406  //temporary variables
407  unsigned int loc_el, sbi;
408  double csection, source, diag;
409 
410  Element *ele;
411  ElementAccessor<3> ele_acc;
412  arma::vec3 p;
413 
414  //TODO: would it be possible to check the change in data for chosen substance? (may be in multifields?)
415 
416  //checking if the data were changed
417  if( (data_.sources_density.changed() )
418  || (data_.sources_conc.changed() )
419  || (data_.sources_sigma.changed() )
420  || (data_.cross_section.changed()))
421  {
422  START_TIMER("sources_reinit");
423  balance_->start_source_assembly(subst_idx);
424 
425  for (loc_el = 0; loc_el < el_ds->lsize(); loc_el++)
426  {
427  ele = mesh_->element(el_4_loc[loc_el]);
428  ele_acc = ele->element_accessor();
429  p = ele_acc.centre();
430  csection = data_.cross_section.value(p, ele_acc);
431 
432  // read for all substances
433  double max_cfl=0;
434  for (sbi = 0; sbi < n_substances(); sbi++)
435  {
436  double src_sigma = data_.sources_sigma[sbi].value(p, ele_acc);
437 
438  source = csection * (data_.sources_density[sbi].value(p, ele_acc) + src_sigma * data_.sources_conc[sbi].value(p, ele_acc));
439  // addition to RHS
440  sources_corr[sbi][loc_el] = source;
441  // addition to diagonal of the transport matrix
442  diag = src_sigma * csection;
443  tm_diag[sbi][loc_el] = - diag;
444 
445  // compute maximal cfl condition over all substances
446  max_cfl = std::max(max_cfl, fabs(diag));
447 
448  balance_->add_source_matrix_values(sbi, ele_acc.region().bulk_idx(), {row_4_el[el_4_loc[loc_el]]},
449  {- src_sigma * ele->measure() * csection});
450  balance_->add_source_vec_values(sbi, ele_acc.region().bulk_idx(), {row_4_el[el_4_loc[loc_el]]},
451  {source * ele->measure()});
452  }
453 
454  cfl_source_[loc_el] = max_cfl;
455  }
456 
457  balance_->finish_source_assembly(subst_idx);
458 
459  END_TIMER("sources_reinit");
460  }
461 }
462 
463 
464 
466 {
468 
471  std::stringstream ss; // print warning message with table of uninitialized fields
472  if ( FieldCommon::print_message_table(ss, "convection transport") ) {
473  WarningOut() << ss.str();
474  }
475 
478 
479  START_TIMER("Convection balance zero time step");
480 
484 
485  // write initial condition
486  output_data();
487 }
488 
489 
491 {
492  OLD_ASSERT(mh_dh, "Null MH object.\n" );
493  data_.set_time(time_->step(), LimitSide::right); // set to the last computed time
494 
495  START_TIMER("data reinit");
496 
497  bool cfl_changed = false;
498 
499  // if FLOW or DATA changed ---------------------> recompute transport matrix
501  {
504  cfl_changed = true;
505  DebugOut() << "CFL changed - flow.\n";
506  }
507 
509  {
511  cfl_changed = true;
512  DebugOut() << "CFL changed - mass matrix.\n";
513  }
514 
515  // if DATA changed ---------------------> recompute concentration sources (rhs and matrix diagonal)
518  {
520  is_src_term_scaled = false;
521  cfl_changed = true;
522  DebugOut() << "CFL changed - source.\n";
523  }
524 
525  // now resolve the CFL condition
526  if(cfl_changed)
527  {
528  // find maximum of sum of contribution from flow and sources: MAX(vcfl_flow_ + vcfl_source_)
529  Vec cfl;
530  VecCreateMPI(PETSC_COMM_WORLD, el_ds->lsize(),PETSC_DETERMINE, &cfl);
531  VecWAXPY(cfl, 1.0, vcfl_flow_, vcfl_source_);
532  VecMaxPointwiseDivide(cfl,mass_diag, &cfl_max_step);
533  // get a reciprocal value as a time constraint
535  DebugOut().fmt("CFL constraint (transport): {}\n", cfl_max_step);
536  }
537 
538  // although it does not influence CFL, compute BC so the full system is assembled
540  || data_.porosity.changed()
542  || data_.bc_conc.changed() )
543  {
545  is_bc_term_scaled = false;
546  }
547 
548  END_TIMER("data reinit");
549 
550  // return time constraint
551  time_constraint = cfl_max_step;
552  return cfl_changed;
553 }
554 
556 
557  START_TIMER("convection-one step");
558 
559  // proceed to next time - which we are about to compute
560  // explicit scheme looks one step back and uses data from previous time
561  // (data time set previously in assess_time_constraint())
562  time_->next_time();
563 
564  double dt_new = time_->dt(), // current time step we are about to compute
565  dt_scaled = dt_new / time_->last_dt(); // scaling ratio to previous time step
566 
567  START_TIMER("time step rescaling");
568 
569  // if FLOW or DATA or BC or DT changed ---------------------> rescale boundary condition
571  {
572  DebugOut() << "BC - rescale dt.\n";
573  //choose between fresh scaling with new dt or rescaling to a new dt
574  double dt = (!is_bc_term_scaled) ? dt_new : dt_scaled;
575  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
576  VecScale(bcvcorr[sbi], dt);
577  is_bc_term_scaled = true;
578  }
579 
580 
581  // if DATA or TIME STEP changed -----------------------> rescale source term
583  DebugOut() << "SRC - rescale dt.\n";
584  //choose between fresh scaling with new dt or rescaling to a new dt
585  double dt = (!is_src_term_scaled) ? dt_new : dt_scaled;
586  for (unsigned int sbi=0; sbi<n_substances(); sbi++)
587  {
588  VecScale(v_sources_corr[sbi], dt);
589  VecScale(v_tm_diag[sbi], dt);
590  }
591  is_src_term_scaled = true;
592  }
593 
594  // if DATA or TIME STEP changed -----------------------> rescale transport matrix
596  DebugOut() << "TM - rescale dt.\n";
597  //choose between fresh scaling with new dt or rescaling to a new dt
598  double dt = (!is_convection_matrix_scaled) ? dt_new : dt_scaled;
599 
600  MatScale(tm, dt);
602  }
603 
604  END_TIMER("time step rescaling");
605 
606 
607  data_.set_time(time_->step(), LimitSide::right); // set to the last computed time
609  {
610  VecCopy(mass_diag, vpmass_diag);
612  } else is_mass_diag_changed = false;
613 
614 
615  // Compute new concentrations for every substance.
616 
617  for (unsigned int sbi = 0; sbi < n_substances(); sbi++) {
618  // one step in MOBILE phase
619  START_TIMER("mat mult");
620 
621  // tm_diag is a diagonal part of transport matrix, which depends on substance data (sources_sigma)
622  // Wwe need keep transport matrix independent of substance, therefore we keep this diagonal part
623  // separately in a vector tm_diag.
624  // Computation: first, we compute this diagonal addition D*pconc and save it temporaly into RHS
625 
626  // RHS = D*pconc, where D is diagonal matrix represented by a vector
627  VecPointwiseMult(vcumulative_corr[sbi], v_tm_diag[sbi], vconc[sbi]); //w = x.*y
628 
629  // Then we add boundary terms ans other source terms into RHS.
630  // RHS = 1.0 * bcvcorr + 1.0 * v_sources_corr + 1.0 * rhs
631  VecAXPBYPCZ(vcumulative_corr[sbi], 1.0, 1.0, 1.0, bcvcorr[sbi], v_sources_corr[sbi]); //z = ax + by + cz
632 
633  // Then we set the new previous concentration.
634  VecCopy(vconc[sbi], vpconc[sbi]); // pconc = conc
635  // And finally proceed with transport matrix multiplication.
636  if (is_mass_diag_changed) {
637  VecPointwiseMult(vconc[sbi], vconc[sbi], vpmass_diag); // vconc*=vpmass_diag
638  MatMultAdd(tm, vpconc[sbi], vconc[sbi], vconc[sbi]); // vconc+=tm*vpconc
639  VecAXPY(vconc[sbi], 1, vcumulative_corr[sbi]); // vconc+=vcumulative_corr
640  VecPointwiseDivide(vconc[sbi], vconc[sbi], mass_diag); // vconc/=mass_diag
641  } else {
642  MatMultAdd(tm, vpconc[sbi], vcumulative_corr[sbi], vconc[sbi]); // vconc =tm*vpconc+vcumulative_corr
643  VecPointwiseDivide(vconc[sbi], vconc[sbi], mass_diag); // vconc/=mass_diag
644  VecAXPY(vconc[sbi], 1, vpconc[sbi]); // vconc+=vpconc
645  }
646 
647  END_TIMER("mat mult");
648  }
649 
650  for (unsigned int sbi=0; sbi<n_substances(); ++sbi)
651  balance_->calculate_cumulative(sbi, vpconc[sbi]);
652 
653  END_TIMER("convection-one step");
654 }
655 
656 
657 void ConvectionTransport::set_target_time(double target_time)
658 {
659 
660  //sets target_mark_type (it is fixed) to be met in next_time()
661  time_->marks().add(TimeMark(target_time, target_mark_type));
662 
663  // This is done every time TOS calls update_solution.
664  // If CFL condition is changed, time fixation will change later from TOS.
665 
666  // Set the same constraint as was set last time.
667 
668  // TODO: fix this hack, remove this method completely, leaving just the first line at the calling point
669  // in TransportOperatorSplitting::update_solution()
670  // doing this directly leads to choose of large time step violationg CFL condition
671  if (cfl_max_step > time_->dt()*1e-10)
672  time_->set_upper_constraint(cfl_max_step, "CFL condition used from previous step.");
673 
674  // fixing convection time governor till next target_mark_type (got from TOS or other)
675  // may have marks for data changes
677 }
678 
679 
681 {
683 
684  VecZeroEntries(mass_diag);
685 
686  balance_->start_mass_assembly(subst_idx);
687 
688  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
689  elm = mesh_->element(el_4_loc[loc_el]);
690 
691  double csection = data_.cross_section.value(elm->centre(), elm->element_accessor());
692  //double por_m = data_.porosity.value(elm->centre(), elm->element_accessor());
693  double por_m = data_.water_content.value(elm->centre(), elm->element_accessor());
694 
695  for (unsigned int sbi=0; sbi<n_substances(); ++sbi)
696  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()} );
697 
698  VecSetValue(mass_diag, row_4_el[elm.index()], csection*por_m, INSERT_VALUES);
699  }
700 
701  balance_->finish_mass_assembly(subst_idx);
702 
703  VecAssemblyBegin(mass_diag);
704  VecAssemblyEnd(mass_diag);
705 
706  is_mass_diag_changed = true;
707 }
708 
709 
710 //=============================================================================
711 // CREATE TRANSPORT MATRIX
712 //=============================================================================
714 
715  START_TIMER("convection_matrix_assembly");
716 
719  struct Edge *edg;
720  unsigned int n;
721  int s, j, np, rank;
722  IdxInt new_j, new_i;
723  double aij, aii;
724 
725  MatZeroEntries(tm);
726 
727  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
728  MPI_Comm_size(PETSC_COMM_WORLD, &np);
729 
730  double flux, flux2, edg_flux;
731 
732  aii = 0.0;
733 
734  for (unsigned int loc_el = 0; loc_el < el_ds->lsize(); loc_el++) {
735  elm = mesh_->element(el_4_loc[loc_el]);
736  new_i = row_4_el[elm.index()];
737 
738  FOR_ELEMENT_SIDES(elm,si) {
739  // same dim
740  flux = mh_dh->side_flux( *(elm->side(si)) );
741  if (elm->side(si)->cond() == NULL) {
742  edg = elm->side(si)->edge();
743  edg_flux = 0;
744  for( int s=0; s < edg->n_sides; s++) {
745  flux2 = mh_dh->side_flux( *(edg->side(s)) );
746  if ( flux2 > 0) edg_flux+= flux2;
747  }
748  FOR_EDGE_SIDES(edg,s)
749  // this test should also eliminate sides facing to lower dim. elements in comp. neighboring
750  // These edges on these sides should have just one side
751  if (edg->side(s) != elm->side(si)) {
752  j = ELEMENT_FULL_ITER(mesh_, edg->side(s)->element()).index();
753  new_j = row_4_el[j];
754 
755  flux2 = mh_dh->side_flux( *(edg->side(s)));
756  if ( flux2 > 0.0 && flux <0.0)
757  aij = -(flux * flux2 / ( edg_flux * elm->measure() ) );
758  else aij =0;
759  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
760  }
761  }
762  if (flux > 0.0)
763  aii -= (flux / elm->measure() );
764  } // end same dim //ELEMENT_SIDES
765 
766  FOR_ELM_NEIGHS_VB(elm,n) // comp model
767  {
768  el2 = ELEMENT_FULL_ITER(mesh_, elm->neigh_vb[n]->side()->element() ); // higher dim. el.
769  OLD_ASSERT( el2 != elm, "Elm. same\n");
770  new_j = row_4_el[el2.index()];
771  flux = mh_dh->side_flux( *(elm->neigh_vb[n]->side()) );
772 
773  // volume source - out-flow from higher dimension
774  if (flux > 0.0) aij = flux / elm->measure();
775  else aij=0;
776  MatSetValue(tm, new_i, new_j, aij, INSERT_VALUES);
777  // out flow from higher dim. already accounted
778 
779  // volume drain - in-flow to higher dimension
780  if (flux < 0.0) {
781  aii -= (-flux) / elm->measure(); // diagonal drain
782  aij = (-flux) / el2->measure();
783  } else aij=0;
784  MatSetValue(tm, new_j, new_i, aij, INSERT_VALUES);
785  }
786 
787  MatSetValue(tm, new_i, new_i, aii, INSERT_VALUES);
788 
789  cfl_flow_[loc_el] = fabs(aii);
790  aii = 0.0;
791  } // END ELEMENTS
792 
793  MatAssemblyBegin(tm, MAT_FINAL_ASSEMBLY);
794  MatAssemblyEnd(tm, MAT_FINAL_ASSEMBLY);
795 
797  END_TIMER("convection_matrix_assembly");
798 
800 }
801 
802 
803 
804 
805 
806 //=============================================================================
807 // OUTPUT VECTOR GATHER
808 //=============================================================================
810 
811  unsigned int sbi;
812  IS is;
813 
814  ISCreateGeneral(PETSC_COMM_SELF, mesh_->n_elements(), row_4_el, PETSC_COPY_VALUES, &is); //WithArray
815  VecScatterCreate(vconc[0], is, out_conc[0].get_data_petsc(), PETSC_NULL, &vconc_out_scatter);
816  for (sbi = 0; sbi < n_substances(); sbi++) {
817  VecScatterBegin(vconc_out_scatter, vconc[sbi], out_conc[sbi].get_data_petsc(), INSERT_VALUES, SCATTER_FORWARD);
818  VecScatterEnd(vconc_out_scatter, vconc[sbi], out_conc[sbi].get_data_petsc(), INSERT_VALUES, SCATTER_FORWARD);
819  }
820  VecScatterDestroy(&(vconc_out_scatter));
821  ISDestroy(&(is));
822 }
823 
824 
826  return conc;
827 }
828 
829 void ConvectionTransport::get_par_info(IdxInt * &el_4_loc_out, Distribution * &el_distribution_out){
830  el_4_loc_out = this->el_4_loc;
831  el_distribution_out = this->el_ds;
832  return;
833 }
834 
835 //int *ConvectionTransport::get_el_4_loc(){
836 // return el_4_loc;
837 //}
838 
840  return row_4_el;
841 }
842 
843 
844 
846 
848  //if ( data_.output_fields.is_field_output_time(data_.conc_mobile, time().step()) ) {
850  //}
851 
852  data_.output_fields.output(time().step());
853 
854  START_TIMER("TOS-balance");
855  for (unsigned int sbi=0; sbi<n_substances(); ++sbi)
856  balance_->calculate_instant(sbi, vconc[sbi]);
857  balance_->output();
858  END_TIMER("TOS-balance");
859 }
860 
861 void ConvectionTransport::set_balance_object(std::shared_ptr<Balance> balance)
862 {
863  balance_ = balance;
864  subst_idx = balance_->add_quantities(substances_.names());
865 }
TimeGovernor & time()
Definition: equation.hh:148
void output_type(OutputTime::DiscreteSpace rt)
Definition: field_set.hh:201
unsigned int size() const
get global size
void set_input_list(Input::Array input_list)
Definition: field_set.hh:180
FieldSet * eq_data_
Definition: equation.hh:232
int IdxInt
Define integers that are indices into large arrays (elements, nodes, dofs etc.)
Definition: mesh.h:85
static auto subdomain(Mesh &mesh) -> IndexField
std::vector< VectorSeqDouble > out_conc
Definition: transport.h:294
bool is_mass_diag_changed
Flag indicates that porosity or cross_section changed during last time.
Definition: transport.h:255
double measure() const
Computes the measure of the element.
Definition: elements.cc:90
double time_changed() const
void update_solution() override
Definition: transport.cc:555
Accessor to input data conforming to declared Array.
Definition: accessors.hh:567
double end_time() const
End time.
double transport_matrix_time
Definition: transport.h:280
void get_par_info(IdxInt *&el_4_loc, Distribution *&el_ds) override
Return array of indices of local elements and parallel distribution of elements.
Definition: transport.cc:829
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:598
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:61
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:480
void alloc_transport_vectors()
Definition: transport.cc:250
unsigned int n_substances() override
Returns number of transported substances.
Definition: transport.h:189
void output(TimeStep step)
double fix_dt_until_mark()
Fixing time step until fixed time mark.
IdxInt * get_el_4_loc() const
Definition: mesh.h:195
MultiField< 3, FieldValue< 3 >::Scalar > conc_mobile
Calculated concentrations in the mobile zone.
Definition: transport.h:90
void create_mass_matrix()
Definition: transport.cc:680
void next_time()
Proceed to the next time according to current estimated time step.
void initialize() override
Definition: transport.cc:113
std::shared_ptr< OutputTime > output_stream_
Definition: transport.h:299
TimeMark::Type target_mark_type
TimeMark type for time marks denoting end of every time interval where transport matrix remains const...
Definition: transport.h:262
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
void set_initial_condition()
Definition: transport.cc:232
double transport_bc_time
Time of the last update of the boundary condition terms.
Definition: transport.h:281
double * cfl_flow_
Definition: transport.h:267
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:337
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:328
#define ELEMENT_FULL_ITER(_mesh_, i)
Definition: mesh.h:488
Definition: mesh.h:99
Fields computed from the mesh data.
EquationOutput output_fields
Fields indended for output, i.e. all input fields plus those representing solution.
Definition: transport.h:94
double ** sources_corr
Definition: transport.h:258
#define FOR_ELEMENT_SIDES(i, j)
Definition: elements.h:157
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:83
int n_sides
Definition: edges.h:36
Definition: edges.h:26
const RegionDB & region_db() const
Definition: mesh.h:170
void set_balance_object(std::shared_ptr< Balance > balance) override
Definition: transport.cc:861
ElementAccessor< 3 > element_accessor(unsigned int idx, bool boundary=false)
Definition: mesh.cc:668
double ** conc
Concentrations for phase, substance, element.
Definition: transport.h:286
const TimeStep & step(int index=-1) const
virtual ~ConvectionTransport()
Definition: transport.cc:182
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:86
double t() const
#define ADD_FIELD(name,...)
Definition: field_set.hh:269
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
void zero_time_step() override
Definition: transport.cc:465
static TimeMarks & marks()
void output_vector_gather()
Definition: transport.cc:809
Basic time management class.
Class for declaration of inputs sequences.
Definition: type_base.hh:345
const Input::Record input_rec
Record with input specification.
Definition: transport.h:297
static constexpr bool value
Definition: json.hpp:87
const string _equation_name
Definition: transport.cc:54
double last_t() const
const MH_DofHandler * mh_dh
Definition: transport.h:314
static const Input::Type::Record & get_input_type()
Definition: transport.cc:60
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
#define OLD_ASSERT(...)
Definition: global_defs.h:131
void setup_components()
unsigned int n_elements() const
Definition: mesh.h:156
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:55
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:58
unsigned int begin(int proc) const
get starting local index
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
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:96
static const int registrar
Registrar of class to factory.
Definition: transport.h:239
bool is_changed_dt() const
#define START_TIMER(tag)
Starts a timer with specified tag.
SubstanceList substances_
Transported substances.
Definition: transport.h:307
Mesh * mesh_
Definition: equation.hh:223
Element * element()
Definition: boundaries.cc:39
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:368
double ** get_concentration_matrix() override
Getter for array of concentrations per element.
Definition: transport.cc:825
Field< 3, FieldValue< 3 >::Scalar > porosity
Mobile porosity - usually saturated water content in the case of unsaturated flow model...
std::shared_ptr< Balance > balance_
object for calculation and writing the mass balance to file.
Definition: equation.hh:235
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:490
vector< unsigned int > subst_idx
List of indices used to call balance methods for a set of quantities.
Definition: transport.h:317
Distribution * get_el_ds() const
Definition: mesh.h:189
#define MPI_Comm_size
Definition: mpi.h:235
Field< 3, FieldValue< 3 >::Scalar > water_content
Water content - result of unsaturated water flow model or porosity.
Vec * vconc
Concentration vectors for mobile phase.
Definition: transport.h:284
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:208
TimeMark add(const TimeMark &mark)
Definition: time_marks.cc:81
Field< 3, FieldValue< 3 >::Integer > region_id
Definition: transport.h:88
void create_transport_matrix_mpi()
Definition: transport.cc:713
Support classes for parallel programing.
void alloc_transport_structs_mpi()
Definition: transport.cc:282
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:252
FLOW123D_FORCE_LINK_IN_CHILD(convectionTransport)
IdxInt * get_row_4_el() override
Return global array of order of elements within parallel vector.
Definition: transport.cc:839
double * cfl_source_
Definition: transport.h:267
#define ELEMENT_FULL_ITER_NULL(_mesh_)
Definition: mesh.h:494
void initialize(std::shared_ptr< OutputTime > stream, Mesh *mesh, Input::Record in_rec, const TimeGovernor &tg)
void set_components(const std::vector< string > &names)
Definition: field_set.hh:167
ElementFullIter element() const
Definition: side_impl.hh:52
void compute_concentration_sources()
Assembles concentration sources for each substance. note: the source of concentration is multiplied b...
Definition: transport.cc:404
bool evaluate_time_constraint(double &time_constraint) override
Definition: transport.cc:490
VecScatter vconc_out_scatter
Definition: transport.h:270
double dt() const
Vec vcfl_flow_
Parallel vector for flow contribution to CFL condition.
Definition: transport.h:265
arma::vec3 centre() const
Computes the barycenter.
Definition: elements.cc:130
void set_target_time(double target_time) override
Definition: transport.cc:657
double ** tm_diag
Definition: transport.h:275
virtual void output_data() override
Write computed fields.
Definition: transport.cc:845
bool set_time(const TimeStep &time, LimitSide limit_side)
Definition: field_set.cc:157
Distributed sparse graphs, partitioning.
Vec vcfl_source_
Parallel vector for source term contribution to CFL condition.
Definition: transport.h:265
unsigned int bulk_idx() const
Returns index of the region in the bulk set.
Definition: region.hh:90
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:246
FieldCommon & name(const string &name)
Definition: field_common.hh:97
#define END_TIMER(tag)
Ends a timer with specified tag.
arma::vec::fixed< spacedim > centre() const
Definition: accessors.hh:91
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
#define FOR_ELM_NEIGHS_VB(i, j)
Definition: elements.h:158
ElementAccessor< 3 > element_accessor() const
Gets ElementAccessor of this element.
Definition: elements.cc:158
double ** cumulative_corr
Definition: transport.h:292
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:45
Record type proxy class.
Definition: type_record.hh:182
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
Field< 3, FieldValue< 3 >::Integer > subdomain
Definition: transport.h:89
#define MPI_Barrier(comm)
Definition: mpi.h:531
double last_dt() const
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
#define DebugOut()
Macro defining &#39;debug&#39; record of log.
Definition: logger.hh:252
static bool print_message_table(ostream &stream, std::string equation_name)
Definition: field_common.cc:91
Other possible transformation of coordinates:
Distribution * el_ds
Definition: transport.h:304
SideIter side(const unsigned int i) const
Definition: edges.h:31
IdxInt * get_row_4_el() const
Definition: mesh.h:192
ElementAccessor< 3 > element_accessor()
Definition: boundaries.cc:47
void make_transport_partitioning()
Definition: transport.cc:155
double cfl_max_step
Time step constraint coming from CFL condition.
Definition: transport.h:263
TimeGovernor * time_
Definition: equation.hh:224
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:260
unsigned int lsize(int proc) const
get local size