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