Flow123d  JS_before_hm-1003-g4e68d2c
transport_dg.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_dg.cc
15 * @brief Discontinuous Galerkin method for equation of transport with dispersion.
16 * @author Jan Stebel
17 */
18 
19 #include "system/index_types.hh"
20 #include "system/sys_profiler.hh"
22 
23 #include "io/output_time.hh"
25 #include "fem/fe_values.hh"
26 #include "fem/fe_p.hh"
27 #include "fem/fe_rt.hh"
28 #include "fem/dh_cell_accessor.hh"
29 #include "fields/field_fe.hh"
31 #include "la/linsys_PETSC.hh"
32 #include "coupling/balance.hh"
35 #include "transport/heat_model.hh"
36 #include "transport/assembly_dg.hh"
37 
38 #include "fields/multi_field.hh"
39 #include "fields/generic_field.hh"
40 #include "input/factory.hh"
42 #include "mesh/accessors.hh"
43 
44 FLOW123D_FORCE_LINK_IN_CHILD(concentrationTransportModel)
46 
47 
48 
49 using namespace Input::Type;
50 
51 template<class Model>
52 const Selection & TransportDG<Model>::get_dg_variant_selection_input_type() {
53  return Selection("DG_variant", "Type of penalty term.")
54  .add_value(non_symmetric, "non-symmetric", "non-symmetric weighted interior penalty DG method")
55  .add_value(incomplete, "incomplete", "incomplete weighted interior penalty DG method")
56  .add_value(symmetric, "symmetric", "symmetric weighted interior penalty DG method")
57  .close();
58 }
59 
60 /*
61 * Should be removed
62 template<class Model>
63 const Selection & TransportDG<Model>::EqData::get_output_selection() {
64  return Model::ModelEqData::get_output_selection_input_type(
65  "DG",
66  "Implicit in time Discontinuous Galerkin solver")
67  .copy_values(EqData().make_output_field_selection("").close())
68  ConvectionTransport::EqData().output_fields
69  .make_output_field_selection(
70  "ConvectionTransport_output_fields",
71  "Selection of output fields for Convection Solute Transport model.")
72  .close()),
73  .close();
74 }
75 */
76 
77 template<class Model>
79  std::string equation_name = std::string(Model::ModelEqData::name()) + "_DG";
80  return Model::get_input_type("DG", "Discontinuous Galerkin (DG) solver")
82  "Solver for the linear system.")
83  .declare_key("input_fields", Array(
85  .make_field_descriptor_type(equation_name)),
87  "Input fields of the equation.")
89  "Variant of the interior penalty discontinuous Galerkin method.")
90  .declare_key("dg_order", Integer(0,3), Default("1"),
91  "Polynomial order for the finite element in DG method (order 0 is suitable if there is no diffusion/dispersion).")
92  .declare_key("output",
93  EqData().output_fields.make_output_type(equation_name, ""),
94  IT::Default("{ \"fields\": [ " + Model::ModelEqData::default_output_field() + "] }"),
95  "Specification of output fields and output times.")
96  .close();
97 }
98 
99 template<class Model>
101  Input::register_class< TransportDG<Model>, Mesh &, const Input::Record>(std::string(Model::ModelEqData::name()) + "_DG") +
103 
104 
105 
106 template<class Model>
108 {
109  *this+=fracture_sigma
110  .name("fracture_sigma")
111  .description(
112  "Coefficient of diffusive transfer through fractures (for each substance).")
114  .input_default("1.0")
116 
117  *this+=dg_penalty
118  .name("dg_penalty")
119  .description(
120  "Penalty parameter influencing the discontinuity of the solution (for each substance). "
121  "Its default value 1 is sufficient in most cases. Higher value diminishes the inter-element jumps.")
123  .input_default("1.0")
125 
126  *this += region_id.name("region_id")
129  .description("Region ids.");
130 
131  *this += subdomain.name("subdomain")
134  .description("Subdomain ids of the domain decomposition.");
135 
136 
137  // add all input fields to the output list
138  output_fields += *this;
139 
140 }
141 
142 
143 
144 // return the ratio of longest and shortest edge
145 template<class Model>
147 {
148  double h_max = 0, h_min = numeric_limits<double>::infinity();
149  for (unsigned int i=0; i<e->n_nodes(); i++)
150  for (unsigned int j=i+1; j<e->n_nodes(); j++)
151  {
152  double dist = arma::norm(*e.node(i) - *e.node(j));
153  h_max = max(h_max, dist);
154  h_min = min(h_min, dist);
155  }
156  return h_max/h_min;
157 }
158 
159 
160 
161 template<class Model>
163  const int K_size,
164  const vector<arma::mat33> &K,
165  const double flux,
166  const arma::vec3 &normal_vector,
167  const double alpha,
168  double &gamma)
169 {
170  double delta = 0, h = 0;
171 
172  // calculate the side diameter
173  if (side.dim() == 0)
174  {
175  h = 1;
176  }
177  else
178  {
179  for (unsigned int i=0; i<side.n_nodes(); i++)
180  for (unsigned int j=i+1; j<side.n_nodes(); j++) {
181  double dist = arma::norm(*side.node(i) - *side.node(j));
182  h = max(h, dist);
183  }
184 
185  }
186 
187  // delta is set to the average value of Kn.n on the side
188  for (int k=0; k<K_size; k++)
189  delta += dot(K[k]*normal_vector,normal_vector);
190  delta /= K_size;
191 
192  gamma = 0.5*fabs(flux) + alpha/h*delta*elem_anisotropy(side.element());
193 }
194 
195 
196 
197 template<typename Model>
199  : Model(init_mesh, in_rec),
200  input_rec(in_rec),
201  allocation_done(false)
202 {
203  // Can not use name() + "constructor" here, since START_TIMER only accepts const char *
204  // due to constexpr optimization.
205  START_TIMER(Model::ModelEqData::name());
206  // Check that Model is derived from AdvectionDiffusionModel.
208 
209  data_ = make_shared<EqData>();
210  this->eq_data_ = data_.get();
211 
212 
213  // Set up physical parameters.
214  data_->set_mesh(init_mesh);
215  data_->region_id = GenericField<3>::region_id(*Model::mesh_);
216  data_->subdomain = GenericField<3>::subdomain(*Model::mesh_);
217 
218 
219  // DG variant and order
220  data_->dg_variant = in_rec.val<DGVariant>("dg_variant");
221  data_->dg_order = in_rec.val<unsigned int>("dg_order");
222 
223  Model::init_from_input(in_rec);
224 
225  // create assemblation object, finite element structures and distribute DOFs
227  data_->stiffness_assembly_ = new GenericAssembly< StiffnessAssemblyDim >(data_.get(),
232 
233  MixedPtr<FE_P_disc> fe(data_->dg_order);
234  shared_ptr<DiscreteSpace> ds = make_shared<EqualOrderDiscreteSpace>(Model::mesh_, fe);
235  data_->dh_ = make_shared<DOFHandlerMultiDim>(*Model::mesh_);
236  data_->dh_->distribute_dofs(ds);
237  //DebugOut().fmt("TDG: solution size {}\n", data_->dh_->n_global_dofs());
238 
239 }
240 
241 
242 template<class Model>
244 {
245  data_->set_components(Model::substances_.names());
246  data_->set_input_list( input_rec.val<Input::Array>("input_fields"), *(Model::time_) );
247 
248  // DG stabilization parameters on boundary edges
249  data_->gamma.resize(Model::n_substances());
250  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
251  data_->gamma[sbi].resize(Model::mesh_->boundary_.size());
252 
253  // Resize coefficient arrays
254  int qsize = data_->mass_assembly_->eval_points()->max_size();
255  int max_edg_sides = max(Model::mesh_->max_edge_sides(1), max(Model::mesh_->max_edge_sides(2), Model::mesh_->max_edge_sides(3)));
256  ret_sources.resize(Model::n_substances());
257  ret_sources_prev.resize(Model::n_substances());
258  data_->ad_coef.resize(Model::n_substances());
259  data_->dif_coef.resize(Model::n_substances());
260  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
261  {
262  data_->ad_coef[sbi].resize(qsize);
263  data_->dif_coef[sbi].resize(qsize);
264  }
265  data_->ad_coef_edg.resize(max_edg_sides);
266  data_->dif_coef_edg.resize(max_edg_sides);
267  for (int sd=0; sd<max_edg_sides; sd++)
268  {
269  data_->ad_coef_edg[sd].resize(Model::n_substances());
270  data_->dif_coef_edg[sd].resize(Model::n_substances());
271  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
272  {
273  data_->ad_coef_edg[sd][sbi].resize(qsize);
274  data_->dif_coef_edg[sd][sbi].resize(qsize);
275  }
276  }
277 
278  output_vec.resize(Model::n_substances());
279  data_->output_field.set_components(Model::substances_.names());
280  data_->output_field.set_mesh(*Model::mesh_);
281  data_->output_type(OutputTime::CORNER_DATA);
282 
283  data_->output_field.setup_components();
284  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
285  {
286  // create shared pointer to a FieldFE, pass FE data and push this FieldFE to output_field on all regions
287  auto output_field_ptr = create_field_fe< 3, FieldValue<3>::Scalar >(data_->dh_);
288  data_->output_field[sbi].set_field(Model::mesh_->region_db().get_region_set("ALL"), output_field_ptr, 0);
289  output_vec[sbi] = output_field_ptr->vec();
290  }
291 
292  // set time marks for writing the output
293  data_->output_fields.initialize(Model::output_stream_, Model::mesh_, input_rec.val<Input::Record>("output"), this->time());
294 
295  // equation default PETSc solver options
296  std::string petsc_default_opts;
297  if (data_->dh_->distr()->np() == 1)
298  petsc_default_opts = "-ksp_type bcgs -pc_type ilu -pc_factor_levels 2 -ksp_diagonal_scale_fix -pc_factor_fill 6.0";
299  else
300  petsc_default_opts = "-ksp_type bcgs -ksp_diagonal_scale_fix -pc_type asm -pc_asm_overlap 4 -sub_pc_type ilu -sub_pc_factor_levels 3 -sub_pc_factor_fill 6.0";
301 
302  // allocate matrix and vector structures
303  data_->ls = new LinSys*[Model::n_substances()];
304  data_->ls_dt = new LinSys*[Model::n_substances()];
305  data_->conc_fe.resize(Model::n_substances());
306 
307  MixedPtr<FE_P_disc> fe(0);
308  shared_ptr<DiscreteSpace> ds = make_shared<EqualOrderDiscreteSpace>(Model::mesh_, fe);
309  data_->dh_p0 = make_shared<DOFHandlerMultiDim>(*Model::mesh_);
310  data_->dh_p0->distribute_dofs(ds);
311 
312 
313  stiffness_matrix.resize(Model::n_substances(), nullptr);
314  mass_matrix.resize(Model::n_substances(), nullptr);
315  rhs.resize(Model::n_substances(), nullptr);
316  mass_vec.resize(Model::n_substances(), nullptr);
317  data_->ret_vec.resize(Model::n_substances(), nullptr);
318 
319  for (unsigned int sbi = 0; sbi < Model::n_substances(); sbi++) {
320  data_->ls[sbi] = new LinSys_PETSC(data_->dh_->distr().get(), petsc_default_opts);
321  ( (LinSys_PETSC *)data_->ls[sbi] )->set_from_input( input_rec.val<Input::Record>("solver") );
322  data_->ls[sbi]->set_solution(output_vec[sbi].petsc_vec());
323 
324  data_->ls_dt[sbi] = new LinSys_PETSC(data_->dh_->distr().get(), petsc_default_opts);
325  ( (LinSys_PETSC *)data_->ls_dt[sbi] )->set_from_input( input_rec.val<Input::Record>("solver") );
326 
327  data_->conc_fe[sbi] = create_field_fe< 3, FieldValue<3>::Scalar >(data_->dh_p0);
328 
329  VecDuplicate(data_->ls[sbi]->get_solution(), &data_->ret_vec[sbi]);
330  }
331 
332 
333  // initialization of balance object
334  Model::balance_->allocate(data_->dh_->distr()->lsize(), data_->mass_assembly_->eval_points()->max_size());
335 
336  // initialization of assembly object
337  data_->mass_assembly_->multidim_assembly()[1_d]->initialize(*this);
338  data_->mass_assembly_->multidim_assembly()[2_d]->initialize(*this);
339  data_->mass_assembly_->multidim_assembly()[3_d]->initialize(*this);
340  data_->stiffness_assembly_->multidim_assembly()[1_d]->initialize(*this);
341  data_->stiffness_assembly_->multidim_assembly()[2_d]->initialize(*this);
342  data_->stiffness_assembly_->multidim_assembly()[3_d]->initialize(*this);
343  data_->sources_assembly_->multidim_assembly()[1_d]->initialize(*this);
344  data_->sources_assembly_->multidim_assembly()[2_d]->initialize(*this);
345  data_->sources_assembly_->multidim_assembly()[3_d]->initialize(*this);
346  data_->bdr_cond_assembly_->multidim_assembly()[1_d]->initialize(*this);
347  data_->bdr_cond_assembly_->multidim_assembly()[2_d]->initialize(*this);
348  data_->bdr_cond_assembly_->multidim_assembly()[3_d]->initialize(*this);
349  data_->init_cond_assembly_->multidim_assembly()[1_d]->initialize(*this);
350  data_->init_cond_assembly_->multidim_assembly()[2_d]->initialize(*this);
351  data_->init_cond_assembly_->multidim_assembly()[3_d]->initialize(*this);
352 }
353 
354 
355 template<class Model>
357 {
358  delete Model::time_;
359 
360  if (data_->gamma.size() > 0) {
361  // initialize called
362 
363  for (unsigned int i=0; i<Model::n_substances(); i++)
364  {
365  delete data_->ls[i];
366  delete data_->ls_dt[i];
367 
368  if (stiffness_matrix[i])
369  chkerr(MatDestroy(&stiffness_matrix[i]));
370  if (mass_matrix[i])
371  chkerr(MatDestroy(&mass_matrix[i]));
372  if (rhs[i])
373  chkerr(VecDestroy(&rhs[i]));
374  if (mass_vec[i])
375  chkerr(VecDestroy(&mass_vec[i]));
376  if (data_->ret_vec[i])
377  chkerr(VecDestroy(&data_->ret_vec[i]));
378  }
379  delete[] data_->ls;
380  delete[] data_->ls_dt;
381  //delete[] stiffness_matrix;
382  //delete[] mass_matrix;
383  //delete[] rhs;
384  //delete[] mass_vec;
385  //delete[] ret_vec;
386 
387  delete data_->mass_assembly_;
388  delete data_->stiffness_assembly_;
389  delete data_->sources_assembly_;
390  delete data_->bdr_cond_assembly_;
391  delete data_->init_cond_assembly_;
392  }
393 
394 }
395 
396 
397 template<class Model>
399 {
400  START_TIMER(Model::ModelEqData::name());
401  data_->mark_input_times( *(Model::time_) );
402  data_->set_time(Model::time_->step(), LimitSide::left);
403  std::stringstream ss; // print warning message with table of uninitialized fields
404  if ( FieldCommon::print_message_table(ss, "transport DG") ) {
405  WarningOut() << ss.str();
406  }
407 
408 
409  // set initial conditions
411  for (unsigned int sbi = 0; sbi < Model::n_substances(); sbi++)
412  ( (LinSys_PETSC *)data_->ls[sbi] )->set_initial_guess_nonzero();
413 
414  // check first time assembly - needs preallocation
416 
417  // after preallocation we assemble the matrices and vectors required for mass balance
418  for (unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
419  {
420  Model::balance_->calculate_instant(Model::subst_idx[sbi], data_->ls[sbi]->get_solution());
421 
422  // add sources due to sorption
423  ret_sources_prev[sbi] = 0;
424  }
425 
426  output_data();
427 }
428 
429 
430 template<class Model>
432 {
433  // preallocate system matrix
434  for (unsigned int i=0; i<Model::n_substances(); i++)
435  {
436  // preallocate system matrix
437  data_->ls[i]->start_allocation();
438  stiffness_matrix[i] = NULL;
439  rhs[i] = NULL;
440 
441  // preallocate mass matrix
442  data_->ls_dt[i]->start_allocation();
443  mass_matrix[i] = NULL;
444  VecZeroEntries(data_->ret_vec[i]);
445  }
446  START_TIMER("assemble_stiffness");
447  data_->stiffness_assembly_->assemble(data_->dh_);
448  END_TIMER("assemble_stiffness");
449  START_TIMER("assemble_mass");
450  data_->mass_assembly_->assemble(data_->dh_);
451  END_TIMER("assemble_mass");
452  START_TIMER("assemble_sources");
453  data_->sources_assembly_->assemble(data_->dh_);
454  END_TIMER("assemble_sources");
455  START_TIMER("assemble_bc");
456  data_->bdr_cond_assembly_->assemble(data_->dh_);
457  END_TIMER("assemble_bc");
458  for (unsigned int i=0; i<Model::n_substances(); i++)
459  {
460  VecAssemblyBegin(data_->ret_vec[i]);
461  VecAssemblyEnd(data_->ret_vec[i]);
462  }
463 
464  allocation_done = true;
465 }
466 
467 
468 
469 template<class Model>
471 {
472  START_TIMER("DG-ONE STEP");
473 
474  Model::time_->next_time();
475  Model::time_->view("TDG");
476 
477  START_TIMER("data reinit");
478  data_->set_time(Model::time_->step(), LimitSide::left);
479  END_TIMER("data reinit");
480 
481  // assemble mass matrix
482  if (mass_matrix[0] == NULL || data_->subset(FieldFlag::in_time_term).changed() )
483  {
484  for (unsigned int i=0; i<Model::n_substances(); i++)
485  {
486  data_->ls_dt[i]->start_add_assembly();
487  data_->ls_dt[i]->mat_zero_entries();
488  VecZeroEntries(data_->ret_vec[i]);
489  }
490  START_TIMER("assemble_mass");
491  data_->mass_assembly_->assemble(data_->dh_);
492  END_TIMER("assemble_mass");
493  for (unsigned int i=0; i<Model::n_substances(); i++)
494  {
495  data_->ls_dt[i]->finish_assembly();
496  VecAssemblyBegin(data_->ret_vec[i]);
497  VecAssemblyEnd(data_->ret_vec[i]);
498  // construct mass_vec for initial time
499  if (mass_matrix[i] == NULL)
500  {
501  VecDuplicate(data_->ls[i]->get_solution(), &mass_vec[i]);
502  MatMult(*(data_->ls_dt[i]->get_matrix()), data_->ls[i]->get_solution(), mass_vec[i]);
503  MatConvert(*( data_->ls_dt[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &mass_matrix[i]);
504  }
505  else
506  MatCopy(*( data_->ls_dt[i]->get_matrix() ), mass_matrix[i], DIFFERENT_NONZERO_PATTERN);
507  }
508  }
509 
510  // assemble stiffness matrix
511  if (stiffness_matrix[0] == NULL
512  || data_->subset(FieldFlag::in_main_matrix).changed()
513  || data_->flow_flux.changed())
514  {
515  // new fluxes can change the location of Neumann boundary,
516  // thus stiffness matrix must be reassembled
517  for (unsigned int i=0; i<Model::n_substances(); i++)
518  {
519  data_->ls[i]->start_add_assembly();
520  data_->ls[i]->mat_zero_entries();
521  }
522  START_TIMER("assemble_stiffness");
523  data_->stiffness_assembly_->assemble(data_->dh_);
524  END_TIMER("assemble_stiffness");
525  for (unsigned int i=0; i<Model::n_substances(); i++)
526  {
527  data_->ls[i]->finish_assembly();
528 
529  if (stiffness_matrix[i] == NULL)
530  MatConvert(*( data_->ls[i]->get_matrix() ), MATSAME, MAT_INITIAL_MATRIX, &stiffness_matrix[i]);
531  else
532  MatCopy(*( data_->ls[i]->get_matrix() ), stiffness_matrix[i], DIFFERENT_NONZERO_PATTERN);
533  }
534  }
535 
536  // assemble right hand side (due to sources and boundary conditions)
537  if (rhs[0] == NULL
538  || data_->subset(FieldFlag::in_rhs).changed()
539  || data_->flow_flux.changed())
540  {
541  for (unsigned int i=0; i<Model::n_substances(); i++)
542  {
543  data_->ls[i]->start_add_assembly();
544  data_->ls[i]->rhs_zero_entries();
545  }
546  START_TIMER("assemble_sources");
547  data_->sources_assembly_->assemble(data_->dh_);
548  END_TIMER("assemble_sources");
549  START_TIMER("assemble_bc");
550  data_->bdr_cond_assembly_->assemble(data_->dh_);
551  END_TIMER("assemble_bc");
552  for (unsigned int i=0; i<Model::n_substances(); i++)
553  {
554  data_->ls[i]->finish_assembly();
555 
556  if (rhs[i] == nullptr) VecDuplicate(*( data_->ls[i]->get_rhs() ), &rhs[i]);
557  VecCopy(*( data_->ls[i]->get_rhs() ), rhs[i]);
558  }
559  }
560 
561 
562  /* Apply backward Euler time integration.
563  *
564  * Denoting A the stiffness matrix and M the mass matrix, the algebraic system at the k-th time level reads
565  *
566  * (1/dt M + A)u^k = f + 1/dt M.u^{k-1}
567  *
568  * Hence we modify at each time level the right hand side:
569  *
570  * f^k = f + 1/dt M u^{k-1},
571  *
572  * where f stands for the term stemming from the force and boundary conditions.
573  * Accordingly, we set
574  *
575  * A^k = A + 1/dt M.
576  *
577  */
578  Mat m;
579  START_TIMER("solve");
580  for (unsigned int i=0; i<Model::n_substances(); i++)
581  {
582  MatConvert(stiffness_matrix[i], MATSAME, MAT_INITIAL_MATRIX, &m);
583  MatAXPY(m, 1./Model::time_->dt(), mass_matrix[i], SUBSET_NONZERO_PATTERN);
584  data_->ls[i]->set_matrix(m, DIFFERENT_NONZERO_PATTERN);
585  Vec w;
586  VecDuplicate(rhs[i], &w);
587  VecWAXPY(w, 1./Model::time_->dt(), mass_vec[i], rhs[i]);
588  data_->ls[i]->set_rhs(w);
589 
590  VecDestroy(&w);
591  chkerr(MatDestroy(&m));
592 
593  data_->ls[i]->solve();
594 
595  // update mass_vec due to possible changes in mass matrix
596  MatMult(*(data_->ls_dt[i]->get_matrix()), data_->ls[i]->get_solution(), mass_vec[i]);
597  }
598  END_TIMER("solve");
599 
601 
602  END_TIMER("DG-ONE STEP");
603 }
604 
605 
606 template<class Model>
608 {
609  // calculate element averages of solution
610  for (auto cell : data_->dh_->own_range() )
611  {
612  LocDofVec loc_dof_indices = cell.get_loc_dof_indices();
613  unsigned int n_dofs=loc_dof_indices.n_rows;
614 
615  DHCellAccessor dh_p0_cell = data_->dh_p0->cell_accessor_from_element(cell.elm_idx());
616  IntIdx dof_p0 = dh_p0_cell.get_loc_dof_indices()[0];
617 
618  for (unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
619  {
620  data_->conc_fe[sbi]->vec()[dof_p0] = 0;
621 
622  for (unsigned int j=0; j<n_dofs; ++j)
623  data_->conc_fe[sbi]->vec()[dof_p0] += data_->ls[sbi]->get_solution_array()[loc_dof_indices[j]];
624 
625  data_->conc_fe[sbi]->vec()[dof_p0] = max(data_->conc_fe[sbi]->vec()[dof_p0]/n_dofs, 0.);
626  }
627  }
628 }
629 
630 
631 
632 
633 template<class Model>
635 {
636  //if (!Model::time_->is_current( Model::time_->marks().type_output() )) return;
637 
638 
639  START_TIMER("DG-OUTPUT");
640 
641  // gather the solution from all processors
642  data_->output_fields.set_time( this->time().step(), LimitSide::left);
643  //if (data_->output_fields.is_field_output_time(data_->output_field, this->time().step()) )
644  data_->output_fields.output(this->time().step());
645 
646  Model::output_data();
647 
648  START_TIMER("TOS-balance");
649  for (unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
650  Model::balance_->calculate_instant(Model::subst_idx[sbi], data_->ls[sbi]->get_solution());
651  Model::balance_->output();
652  END_TIMER("TOS-balance");
653 
654  END_TIMER("DG-OUTPUT");
655 }
656 
657 
658 template<class Model>
660 {
661  if (Model::balance_->cumulative())
662  {
663  for (unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
664  {
665  Model::balance_->calculate_cumulative(Model::subst_idx[sbi], data_->ls[sbi]->get_solution());
666 
667  // update source increment due to retardation
668  VecDot(data_->ret_vec[sbi], data_->ls[sbi]->get_solution(), &ret_sources[sbi]);
669 
670  Model::balance_->add_cumulative_source(Model::subst_idx[sbi], (ret_sources[sbi]-ret_sources_prev[sbi])/Model::time_->dt());
671  ret_sources_prev[sbi] = ret_sources[sbi];
672  }
673  }
674 }
675 
676 
677 
678 
679 template<class Model>
681 {
682  START_TIMER("set_init_cond");
683  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
684  data_->ls[sbi]->start_allocation();
685  data_->init_cond_assembly_->assemble(data_->dh_);
686 
687  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
688  data_->ls[sbi]->start_add_assembly();
689  data_->init_cond_assembly_->assemble(data_->dh_);
690 
691  for (unsigned int sbi=0; sbi<Model::n_substances(); sbi++)
692  {
693  data_->ls[sbi]->finish_assembly();
694  data_->ls[sbi]->solve();
695  }
696  END_TIMER("set_init_cond");
697 }
698 
699 
700 template<class Model>
702 {
703  el_4_loc = Model::mesh_->get_el_4_loc();
704  el_ds = Model::mesh_->get_el_ds();
705 }
706 
707 
708 template<class Model>
710 {
711  if (solution_changed)
712  {
713  for (auto cell : data_->dh_->own_range() )
714  {
715  LocDofVec loc_dof_indices = cell.get_loc_dof_indices();
716  unsigned int n_dofs=loc_dof_indices.n_rows;
717 
718  DHCellAccessor dh_p0_cell = data_->dh_p0->cell_accessor_from_element(cell.elm_idx());
719  IntIdx dof_p0 = dh_p0_cell.get_loc_dof_indices()[0];
720 
721  for (unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
722  {
723  double old_average = 0;
724  for (unsigned int j=0; j<n_dofs; ++j)
725  old_average += data_->ls[sbi]->get_solution_array()[loc_dof_indices[j]];
726  old_average /= n_dofs;
727 
728  for (unsigned int j=0; j<n_dofs; ++j)
729  data_->ls[sbi]->get_solution_array()[loc_dof_indices[j]]
730  += data_->conc_fe[sbi]->vec()[dof_p0] - old_average;
731  }
732  }
733  }
734  // update mass_vec for the case that mass matrix changes in next time step
735  for (unsigned int sbi=0; sbi<Model::n_substances(); ++sbi)
736  MatMult(*(data_->ls_dt[sbi]->get_matrix()), data_->ls[sbi]->get_solution(), mass_vec[sbi]);
737 }
738 
739 template<class Model>
741 {
742  return Model::mesh_->get_row_4_el();
743 }
744 
745 
746 
747 
748 
749 
751 template class TransportDG<HeatTransferModel>;
752 
753 
754 
755 
TimeGovernor & time()
Definition: equation.hh:149
Input::Record input_rec
Record with input specification.
FieldSet * eq_data_
Definition: equation.hh:227
static auto subdomain(Mesh &mesh) -> IndexField
void get_par_info(LongIdx *&el_4_loc, Distribution *&el_ds)
unsigned int n_nodes() const
Definition: elements.h:126
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
arma::Col< IntIdx > LocDofVec
Definition: index_types.hh:28
double elem_anisotropy(ElementAccessor< 3 > e) const
Compute and return anisotropy of given element.
std::vector< std::vector< double > > gamma
Penalty parameters.
static constexpr Mask in_main_matrix
A field is part of main "stiffness matrix" of the equation.
Definition: field_flag.hh:49
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
Transport with dispersion implemented using discontinuous Galerkin method.
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
FieldCommon & flags_add(FieldFlag::Flags::Mask mask)
void set_from_input(const Input::Record in_rec) override
int IntIdx
Definition: index_types.hh:25
Abstract linear system class.
Definition: balance.hh:40
vector< VectorMPI > output_vec
Array for storing the output solution data.
void update_solution() override
Computes the solution in one time instant.
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
Definition: mesh.h:78
Fields computed from the mesh data.
void set_initial_condition()
Calculates the dispersivity (diffusivity) tensor from the velocity field.
Cell accessor allow iterate over DOF handler cells.
Class FEValues calculates finite element data on the actual cells such as shape function values...
void chkerr(unsigned int ierr)
Replacement of new/delete operator in the spirit of xmalloc.
Definition: system.hh:148
LocDofVec get_loc_dof_indices() const
Returns the local indices of dofs associated to the cell on the local process.
Discontinuous Galerkin method for equation of transport with dispersion.
Class for declaration of the integral input data.
Definition: type_base.hh:483
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
ElementAccessor< 3 > element() const
Returns iterator to the element of the side.
vector< double > ret_sources_prev
MultiField< 3, FieldValue< 3 >::Scalar > dg_penalty
Penalty enforcing inter-element continuity of solution (for each substance).
NodeAccessor< 3 > node(unsigned int ni) const
Definition: accessors.hh:200
Class for declaration of inputs sequences.
Definition: type_base.hh:339
EquationOutput output_fields
std::vector< Mat > mass_matrix
The mass matrix.
void calculate_cumulative_balance()
static constexpr bool value
Definition: json.hpp:87
TransportDG(Mesh &init_mesh, const Input::Record in_rec)
Constructor.
LongIdx * get_row_4_el()
void initialize() override
void output_data()
Postprocesses the solution and writes to output file.
MultiField< 3, FieldValue< 3 >::Scalar > fracture_sigma
Transition parameter for diffusive transfer on fractures (for each substance).
void preallocate()
unsigned int dim() const
Returns dimension of the side, that is dimension of the element minus one.
void compute_p0_interpolation()
Compute P0 interpolation of the solution (used in reaction term).
static constexpr Mask in_time_term
A field is part of time term of the equation.
Definition: field_flag.hh:47
FieldCommon & input_default(const string &input_default)
Definitions of basic Lagrangean finite elements with polynomial shape functions.
static constexpr Mask equation_external_output
Match an output field, that can be also copy of other field.
Definition: field_flag.hh:58
Field< 3, FieldValue< 3 >::Scalar > subdomain
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
const Ret val(const string &key) const
static auto region_id(Mesh &mesh) -> IndexField
#define START_TIMER(tag)
Starts a timer with specified tag.
std::vector< Vec > rhs
Vector of right hand side.
Selection & add_value(const int value, const std::string &key, const std::string &description="", TypeBase::attribute_map attributes=TypeBase::attribute_map())
Adds one new value with name given by key to the Selection.
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:503
Field< 3, FieldValue< 3 >::Scalar > region_id
static constexpr Mask in_rhs
A field is part of the right hand side of the equation.
Definition: field_flag.hh:51
void set_DG_parameters_boundary(Side side, const int K_size, const std::vector< arma::mat33 > &K, const double flux, const arma::vec3 &normal_vector, const double alpha, double &gamma)
Sets up parameters of the DG method on a given boundary edge.
NodeAccessor< 3 > node(unsigned int i) const
Returns node for given local index i on the side.
Discontinuous Galerkin method for equation of transport with dispersion.
std::vector< Mat > stiffness_matrix
The stiffness matrix.
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: index_types.hh:24
FieldCommon & description(const string &description)
bool allocation_done
Indicates whether matrices have been preallocated.
static const Input::Type::Record & get_input_type()
Declare input record type for the equation TransportDG.
Definition: transport_dg.cc:78
Discontinuous Galerkin method for equation of transport with dispersion.
const Selection & close() const
Close the Selection, no more values can be added.
void update_after_reactions(bool solution_changed)
vector< double > ret_sources
Temporary values of increments due to retardation (e.g. sorption)
Generic class of assemblation.
Definition: assembly_dg.hh:64
Definitions of particular quadrature rules on simplices.
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:258
FieldCommon & name(const string &name)
#define END_TIMER(tag)
Ends a timer with specified tag.
Discontinuous Galerkin method for equation of transport with dispersion.
static const Input::Type::Record & get_input_type()
Definition: linsys_PETSC.cc:32
std::vector< Vec > mass_vec
Mass from previous time instant (necessary when coefficients of mass matrix change in time)...
Record type proxy class.
Definition: type_record.hh:182
FieldCommon & flags(FieldFlag::Flags::Mask mask)
~TransportDG() override
Destructor.
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
static bool print_message_table(ostream &stream, std::string equation_name)
Definition: field_common.cc:96
Template for classes storing finite set of named values.
std::shared_ptr< EqData > data_
Field data for model parameters.
Definitions of Raviart-Thomas finite elements.
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:180
void zero_time_step() override
Initialize solution in the zero time.
unsigned int n_nodes() const
Returns number of nodes of the side.
Definition: accessors.hh:407