Flow123d  JS_before_hm-1801-ga009cfea3
balance.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 balance.cc
15  * @ingroup transport
16  * @brief Mass balance
17  */
18 
19 #include <iostream>
20 #include <iomanip>
21 #include <unordered_map>
22 
23 #include "system/system.hh"
24 #include "system/sys_profiler.hh"
25 #include "system/index_types.hh"
26 
27 #include <petscmat.h>
28 #include "mesh/mesh.h"
29 #include "mesh/accessors.hh"
30 #include "io/output_time_set.hh"
31 #include "coupling/balance.hh"
32 #include "tools/unit_si.hh"
33 #include "tools/time_governor.hh"
34 #include "la/distribution.hh"
35 #include "fem/dofhandler.hh"
36 #include "fem/dh_cell_accessor.hh"
37 
38 using namespace Input::Type;
39 
40 bool Balance::do_yaml_output_ = true;
41 
43  return Selection("Balance_output_format", "Format of output file for balance.")
44  .add_value(Balance::legacy, "legacy", "Legacy format used by previous program versions.")
45  .add_value(Balance::txt, "txt", "Excel format with tab delimiter.")
46  .add_value(Balance::gnuplot, "gnuplot", "Format compatible with GnuPlot datafile with fixed column width.")
47  .close();
48 }
49 
51  return Record("Balance", "Balance of a conservative quantity, boundary fluxes and sources.")
52  .declare_key("times", OutputTimeSet::get_input_type(), Default("[]"), "" )
53  .declare_key("add_output_times", Bool(), Default("true"), "Add all output times of the balanced equation to the balance output times set. "
54  "Note that this is not the time set of the output stream.")
55  //.declare_key("balance_on", Bool(), Default("true"), "Balance is computed if the value is true.")
56  .declare_key("format", Balance::get_format_selection_input_type(), Default("\"txt\""), "Format of output file.")
57  .declare_key("cumulative", Bool(), Default("false"), "Compute cumulative balance over time. "
58  "If true, then balance is calculated at each computational time step, which can slow down the program.")
59  .declare_key("file", FileName::output(), Default::read_time("File name generated from the balanced quantity: <quantity_name>_balance.*"), "File name for output of balance.")
60  .close();
61 }
62 
65 }
66 
67 /*
68 std::shared_ptr<Balance> Balance::make_balance(
69  const std::string &file_prefix,
70  const Mesh *mesh,
71  const Input::Record &in_rec,
72  TimeGovernor &tg)
73 {
74  auto ptr = make_shared<Balance>(file_prefix, mesh, in_rec, tg);
75  auto &marks = TimeGovernor::marks();
76  auto balance_output_type = tg.equation_mark_type() | TimeGovernor::marks().type_balance_output();
77  if (marks.begin(balance_output_type) == marks.end(balance_output_type) ) {
78  // no balance output time => force balance off
79  ptr.reset();
80  }
81  return ptr;
82 }*/
83 
84 
85 
86 Balance::Balance(const std::string &file_prefix, const Mesh *mesh)
87  : file_prefix_(file_prefix),
88  mesh_(mesh),
89  last_time_(),
90  initial_(true),
91  allocation_done_(false),
92  balance_on_(true),
93  output_line_counter_(0),
94  output_yaml_header_(false)
95 
96 {
97  MPI_Comm_rank(PETSC_COMM_WORLD, &rank_);
99 }
100 
101 
102 
104 {
105  if (rank_ == 0) {
106  output_.close();
107  if (do_yaml_output_) output_yaml_.close();
108  }
109  if (! allocation_done_) return;
110 
111  for (unsigned int c=0; c<quantities_.size(); ++c)
112  {
113  chkerr(MatDestroy(&(region_mass_matrix_[c])));
114  chkerr(MatDestroy(&(be_flux_matrix_[c])));
115  chkerr(MatDestroy(&(region_source_matrix_[c])));
116  chkerr(MatDestroy(&(region_source_rhs_[c])));
117  chkerr(VecDestroy(&(be_flux_vec_[c])));
118  chkerr(VecDestroy(&(region_mass_vec_[c])));
119  }
120  delete[] region_mass_matrix_;
121  delete[] be_flux_matrix_;
122  delete[] be_flux_vec_;
123  delete[] region_source_matrix_;
124  delete[] region_source_rhs_;
125  delete[] region_mass_vec_;
126 }
127 
128 
130  const Input::Record &in_rec,
131  TimeGovernor &tg)
132 {
134 
135  time_ = &tg;
136 
137  auto &marks = TimeGovernor::marks();
138 
139  output_mark_type_ = tg.equation_mark_type() | marks.type_output(),
140  balance_output_type_ = tg.equation_fixed_mark_type() | marks.type_balance_output();
141 
142  cumulative_ = in_rec.val<bool>("cumulative");
143  output_format_ = in_rec.val<OutputFormat>("format");
144 
145  OutputTimeSet time_set;
146  time_set.read_from_input( in_rec.val<Input::Array>("times"), tg, balance_output_type_);
147  add_output_times_ = in_rec.val<bool>("add_output_times");
148 
149  input_record_ = in_rec;
150 
151 }
152 
153 
154 void Balance::units(const UnitSI &unit)
155 {
157 
158  units_ = unit;
159  units_.undef(false);
160 }
161 
162 unsigned int Balance::add_quantity(const string &name)
163 {
165 
166  Quantity q(quantities_.size(), name);
167  quantities_.push_back(q);
168 
169  return q.index_;
170 }
171 
172 
174 {
175  vector<unsigned int> indices;
176  for (auto name : names)
177  indices.push_back(add_quantity(name));
178  return indices;
179 }
180 
181 
182 void Balance::allocate(unsigned int n_loc_dofs,
183  unsigned int max_dofs_per_boundary)
184 {
186  n_loc_dofs_seq_ = n_loc_dofs;
187  n_loc_dofs_par_ = n_loc_dofs;
188  max_dofs_per_boundary_ = max_dofs_per_boundary;
189 }
190 
191 void Balance::allocate(const std::shared_ptr<DOFHandlerMultiDim>& dh,
192  unsigned int max_dofs_per_boundary)
193 {
195  // for sequential matrices, we need to include ghost values
196  n_loc_dofs_seq_ = dh->get_local_to_global_map().size();
197  // for parallel matrices, we use the local size from dof distribution
198  n_loc_dofs_par_ = dh->distr()->lsize();
199  max_dofs_per_boundary_ = max_dofs_per_boundary;
200 }
201 
203 {
204  if (allocation_done_) return;
205 
206  auto &marks = TimeGovernor::marks();
207  if (add_output_times_){
208  marks.add_to_type_all(output_mark_type_, balance_output_type_);
209  // add balance output time mark to init time
210  // due to balance output when there are no output fields
211  marks.add( TimeMark(time_->init_time(), balance_output_type_) );
212  }
213  // if there are no balance marks turn balance off
214  if (marks.begin(balance_output_type_) == marks.end(balance_output_type_) )
215  {
216  balance_on_ = false;
217  cumulative_ = false;
218  return;
219  }
220 
221  // Max. number of regions to which a single dof can contribute.
222  // TODO: estimate or compute this number directly (from mesh or dof handler).
223  const int n_bulk_regs_per_dof = min(10, (int)mesh_->region_db().bulk_size());
224  const unsigned int n_quant = quantities_.size();
225  const unsigned int n_bdr_reg = mesh_->region_db().boundary_size();
226  const unsigned int n_blk_reg = mesh_->region_db().bulk_size();
227 
228 
229  // enumerate boundary edges by unique id and
230  // create map: (local bulk ele idx, side idx) -> boundary edge id
231  // create vector that maps: boundary edge id -> region boundary index
232  unsigned int be_id = 0;
233  for (unsigned int loc_el = 0; loc_el < mesh_->get_el_ds()->lsize(); loc_el++)
234  {
236  if (elm->boundary_idx_ != nullptr)
237  {
238  for(unsigned int si=0; si<elm->n_sides(); si++)
239  {
240  if (elm.side(si)->is_boundary()){
241  Boundary bcd = elm.side(si)->cond();
242  LongIdx ele_side_uid = get_boundary_edge_uid(elm.side(si));
243  be_id_map_[ele_side_uid] = be_id;
244  be_regions_.push_back(bcd.region().boundary_idx());
245  be_id++;
246  }
247  }
248  }
249  }
250 
251 
252  fluxes_ .resize(n_quant, vector<double>(n_bdr_reg, 0));
253  fluxes_in_ .resize(n_quant, vector<double>(n_bdr_reg, 0));
254  fluxes_out_.resize(n_quant, vector<double>(n_bdr_reg, 0));
255 
256  masses_ .resize(n_quant, vector<double>(n_blk_reg, 0));
257  sources_in_ .resize(n_quant, vector<double>(n_blk_reg, 0));
258  sources_out_.resize(n_quant, vector<double>(n_blk_reg, 0));
259 
260  sum_fluxes_ .resize(n_quant, 0);
261  sum_fluxes_in_ .resize(n_quant, 0);
262  sum_fluxes_out_ .resize(n_quant, 0);
263  sum_masses_ .resize(n_quant, 0);
264  sum_sources_ .resize(n_quant, 0);
265  sum_sources_in_ .resize(n_quant, 0);
266  sum_sources_out_.resize(n_quant, 0);
267 
268  if (cumulative_)
269  {
270  initial_mass_ .resize(n_quant, 0);
271  integrated_fluxes_ .resize(n_quant, 0);
272  integrated_sources_.resize(n_quant, 0);
273  increment_sources_.resize(n_quant, 0);
274  increment_fluxes_.resize(n_quant, 0);
275  }
276 
277 
278 
279  region_mass_matrix_ = new Mat[n_quant];
280  be_flux_matrix_ = new Mat[n_quant];
281  region_source_matrix_ = new Mat[n_quant];
282  region_source_rhs_ = new Mat[n_quant];
283  region_mass_vec_ = new Vec[n_quant];
284  be_flux_vec_ = new Vec[n_quant];
285 
286 
287  for (unsigned int c=0; c<n_quant; ++c)
288  {
289  chkerr(MatCreateAIJ(PETSC_COMM_WORLD,
291  (rank_==0)?mesh_->region_db().bulk_size():0,
292  PETSC_DECIDE,
293  PETSC_DECIDE,
294  (rank_==0)?n_bulk_regs_per_dof:0,
295  0,
296  (rank_==0)?0:n_bulk_regs_per_dof,
297  0,
298  &(region_mass_matrix_[c])));
299 
300  chkerr(MatCreateSeqAIJ(PETSC_COMM_SELF,
303  n_bulk_regs_per_dof,
304  NULL,
305  &(region_source_matrix_[c])));
306 
307  chkerr(MatCreateSeqAIJ(PETSC_COMM_SELF,
310  n_bulk_regs_per_dof,
311  NULL,
312  &(region_source_rhs_[c])));
313 
314  chkerr(MatCreateAIJ(PETSC_COMM_WORLD,
315  be_regions_.size(), // n local rows, number of local boundary edges
316  n_loc_dofs_par_, // n local cols (local rows of multiplying vector)
317  PETSC_DECIDE, // n global rows
318  PETSC_DECIDE, // n global cols
319  max_dofs_per_boundary_, // allocation, local poriton
320  0,
321  0,
322  0,
323  &(be_flux_matrix_[c])));
324 
325  chkerr(VecCreateMPI(PETSC_COMM_WORLD,
326  (rank_==0)?mesh_->region_db().bulk_size():0,
327  PETSC_DECIDE,
328  &(region_mass_vec_[c])));
329 
330  chkerr(VecCreateMPI(PETSC_COMM_WORLD,
331  be_regions_.size(),
332  PETSC_DECIDE,
333  &(be_flux_vec_[c])));
334  }
335 
336  // set be_offset_, used in add_flux_matrix_values()
337  chkerr(VecGetOwnershipRange(be_flux_vec_[0], &be_offset_, NULL));
338 
339  if (rank_ == 0) {
340  // set default value by output_format_
341  std::string default_file_name;
342  switch (output_format_)
343  {
344  case txt:
345  default_file_name = file_prefix_ + "_balance.txt";
346  break;
347  case gnuplot:
348  default_file_name = file_prefix_ + "_balance.dat";
349  break;
350  case legacy:
351  default_file_name = file_prefix_ + "_balance.txt";
352  break;
353  }
354 
356  try {
358  } INPUT_CATCH(FilePath::ExcFileOpen, FilePath::EI_Address_String, input_record_)
359 
360 
361  // set file name of YAML output
362  if (do_yaml_output_) {
363  string yaml_file_name = file_prefix_ + "_balance.yaml";
365  }
366  }
367 
368  allocation_done_ = true;
369 }
370 
371 
372 
374 {
375  if (! balance_on_) return false;
376 
377  auto &marks = TimeGovernor::marks();
378  bool res = marks.current(time_->step(), balance_output_type_) != marks.end(balance_output_type_);
379 
380  //cout << "flag: " << res << " time: " << step.end() << " type:" << hex << balance_output_type_ << endl;
381  return res;
382 }
383 
384 void Balance::start_mass_assembly(unsigned int quantity_idx)
385 {
386  lazy_initialize();
387  if (! balance_on_) return;
388  chkerr(MatZeroEntries(region_mass_matrix_[quantity_idx]));
389  chkerr(VecZeroEntries(region_mass_vec_[quantity_idx]));
390 }
391 
392 
393 void Balance::start_flux_assembly(unsigned int quantity_idx)
394 {
395  lazy_initialize();
396  if (! balance_on_) return;
397  chkerr(MatZeroEntries(be_flux_matrix_[quantity_idx]));
398  chkerr(VecZeroEntries(be_flux_vec_[quantity_idx]));
399 }
400 
401 
402 void Balance::start_source_assembly(unsigned int quantity_idx)
403 {
404  lazy_initialize();
405  if (! balance_on_) return;
406  chkerr(MatZeroEntries(region_source_matrix_[quantity_idx]));
407  chkerr(MatZeroEntries(region_source_rhs_[quantity_idx]));
408 }
409 
410 
411 void Balance::finish_mass_assembly(unsigned int quantity_idx)
412 {
414  if (! balance_on_) return;
415 
416  chkerr(MatAssemblyBegin(region_mass_matrix_[quantity_idx], MAT_FINAL_ASSEMBLY));
417  chkerr(MatAssemblyEnd(region_mass_matrix_[quantity_idx], MAT_FINAL_ASSEMBLY));
418  chkerr(VecAssemblyBegin(region_mass_vec_[quantity_idx]));
419  chkerr(VecAssemblyEnd(region_mass_vec_[quantity_idx]));
420 }
421 
422 void Balance::finish_flux_assembly(unsigned int quantity_idx)
423 {
425  if (! balance_on_) return;
426 
427  chkerr(MatAssemblyBegin(be_flux_matrix_[quantity_idx], MAT_FINAL_ASSEMBLY));
428  chkerr(MatAssemblyEnd(be_flux_matrix_[quantity_idx], MAT_FINAL_ASSEMBLY));
429  chkerr(VecAssemblyBegin(be_flux_vec_[quantity_idx]));
430  chkerr(VecAssemblyEnd(be_flux_vec_[quantity_idx]));
431 }
432 
433 void Balance::finish_source_assembly(unsigned int quantity_idx)
434 {
436  if (! balance_on_) return;
437 
438  chkerr(MatAssemblyBegin(region_source_matrix_[quantity_idx], MAT_FINAL_ASSEMBLY));
439  chkerr(MatAssemblyEnd(region_source_matrix_[quantity_idx], MAT_FINAL_ASSEMBLY));
440  chkerr(MatAssemblyBegin(region_source_rhs_[quantity_idx], MAT_FINAL_ASSEMBLY));
441  chkerr(MatAssemblyEnd(region_source_rhs_[quantity_idx], MAT_FINAL_ASSEMBLY));
442 }
443 
444 
445 void Balance::add_mass_values(unsigned int quantity_idx,
446  const DHCellAccessor &dh_cell,
447  const LocDofVec &loc_dof_indices,
448  const std::vector<double> &mat_values,
449  double vec_value)
450 {
452  if (! balance_on_) return;
453 
454  // map local dof indices to global
455  uint m = mat_values.size();
456  int row_dofs[m];
457  for (uint i=0; i<m; i++)
458  row_dofs[i]= dh_cell.dh()->get_local_to_global_map()[loc_dof_indices[i]];
459 
460  PetscInt reg_array[1] = { (int)dh_cell.elm().region_idx().bulk_idx() };
461 
462  chkerr_assert(MatSetValues(region_mass_matrix_[quantity_idx],
463  m,
464  row_dofs,
465  1,
466  reg_array,
467  &(mat_values[0]),
468  ADD_VALUES));
469 
470  chkerr_assert(VecSetValue(region_mass_vec_[quantity_idx],
471  dh_cell.elm().region_idx().bulk_idx(),
472  vec_value,
473  ADD_VALUES));
474 }
475 
476 void Balance::add_flux_values(unsigned int quantity_idx,
477  const DHCellSide &side,
478  const LocDofVec &loc_dof_indices,
479  const std::vector<double> &mat_values,
480  double vec_value)
481 {
483  if (! balance_on_) return;
484 
485  // filling row elements corresponding to a boundary edge
486 
487  // map local dof indices to global
488  uint m = mat_values.size();
489  int col_dofs[m];
490  for (uint i=0; i<m; i++)
491  col_dofs[i]= side.cell().dh()->get_local_to_global_map()[loc_dof_indices[i]];
492 
493  SideIter s = SideIter(side.side());
494  PetscInt glob_be_idx[1] = { int(be_offset_ + be_id_map_[get_boundary_edge_uid(s)]) };
495 
496  chkerr_assert(MatSetValues(be_flux_matrix_[quantity_idx],
497  1,
498  glob_be_idx,
499  m,
500  col_dofs,
501  &(mat_values[0]),
502  ADD_VALUES));
503 
504  chkerr_assert(VecSetValue(be_flux_vec_[quantity_idx],
505  glob_be_idx[0],
506  vec_value,
507  ADD_VALUES));
508 }
509 
510 void Balance::add_source_values(unsigned int quantity_idx,
511  unsigned int region_idx,
512  const LocDofVec &loc_dof_indices,
513  const vector<double> &mult_mat_values,
514  const vector<double> &add_mat_values)
515 {
517  if (! balance_on_) return;
518 
519  PetscInt reg_array[1] = { (int)region_idx };
520 
521  chkerr_assert(MatSetValues(region_source_matrix_[quantity_idx],
522  loc_dof_indices.size(),
523  loc_dof_indices.memptr(),
524  1,
525  reg_array,
526  &(mult_mat_values[0]),
527  ADD_VALUES));
528 
529  chkerr_assert(MatSetValues(region_source_rhs_[quantity_idx],
530  loc_dof_indices.size(),
531  loc_dof_indices.memptr(),
532  1,
533  reg_array,
534  &(add_mat_values[0]),
535  ADD_VALUES));
536 }
537 
538 
539 void Balance::add_cumulative_source(unsigned int quantity_idx, double source)
540 {
542  if (!cumulative_) return;
543 
544  if (rank_ == 0)
545  increment_sources_[quantity_idx] += source;
546 }
547 
548 
549 void Balance::calculate_cumulative(unsigned int quantity_idx,
550  const Vec &solution)
551 {
553  if (!cumulative_) return;
554  if (time_->tlevel() <= 0) return;
555 
556  // sources
557  double temp_source = 0;
558  int lsize, n_cols_mat, n_cols_rhs;
559  //const int *cols;
560  const double *vals_mat, *vals_rhs, *sol_array;
561  // chkerr(VecGetLocalSize(solution, &lsize));
562  // chkerr(ISLocalToGlobalMappingGetSize(solution->mapping, &lsize); // cannot do for const
563  lsize = n_loc_dofs_seq_;
564  chkerr(VecGetArrayRead(solution, &sol_array));
565 
566  // computes transpose multiplication and sums region_source_rhs_ over dofs
567  // resulting in a vector of sources for each region
568  // transpose(region_source_matrix_) * solution + region_source_rhs_*ones(n_blk_reg)
569  // the region vector is then summed up to temp_source
570  for (int i=0; i<lsize; ++i){
571  chkerr(MatGetRow(region_source_matrix_[quantity_idx], i, &n_cols_mat, NULL, &vals_mat));
572  chkerr(MatGetRow(region_source_rhs_[quantity_idx], i, &n_cols_rhs, NULL, &vals_rhs));
573 
574  ASSERT_DBG(n_cols_mat == n_cols_rhs);
575 
576  for (int j=0; j<n_cols_mat; ++j)
577  temp_source += vals_mat[j]*sol_array[i] + vals_rhs[j];
578 
579  chkerr(MatRestoreRow(region_source_matrix_[quantity_idx], i, &n_cols_mat, NULL, &vals_mat));
580  chkerr(MatRestoreRow(region_source_rhs_[quantity_idx], i, &n_cols_rhs, NULL, &vals_rhs));
581  }
582  chkerr(VecRestoreArrayRead(solution, &sol_array));
583 
584  increment_sources_[quantity_idx] += temp_source*time_->dt();
585 
586 
587  // fluxes
588  Vec temp;
589  chkerr(VecCreateMPI(PETSC_COMM_WORLD,
590  be_regions_.size(),
591  PETSC_DECIDE,
592  &temp));
593 
594  chkerr(MatMultAdd(be_flux_matrix_[quantity_idx], solution, be_flux_vec_[quantity_idx], temp));
595 
596  double sum_fluxes;
597  chkerr(VecSum(temp, &sum_fluxes));
598  chkerr(VecDestroy(&temp));
599 
600  if (rank_ == 0)
601  // sum fluxes in one step
602  // Since internally we keep outgoing fluxes, we change sign
603  // to write to output _incoming_ fluxes.
604  increment_fluxes_[quantity_idx] += -1.0 * sum_fluxes*time_->dt();
605 }
606 
607 
608 void Balance::calculate_mass(unsigned int quantity_idx,
609  const Vec &solution,
610  vector<double> &output_array)
611 {
613  if (! balance_on_) return;
614 
615  Vec bulk_vec;
616 
617  chkerr(VecCreateMPIWithArray(PETSC_COMM_WORLD,
618  1,
619  (rank_==0)?mesh_->region_db().bulk_size():0,
620  PETSC_DECIDE,
621  &(output_array[0]),
622  &bulk_vec));
623 
624  // compute mass on regions: M'.u
625  chkerr(VecZeroEntries(bulk_vec));
626  chkerr(MatMultTransposeAdd(region_mass_matrix_[quantity_idx],
627  solution,
628  region_mass_vec_[quantity_idx],
629  bulk_vec));
630  chkerr(VecDestroy(&bulk_vec));
631 }
632 
633 void Balance::calculate_instant(unsigned int quantity_idx, const Vec& solution)
634 {
635  if ( !is_current() ) return;
636 
637  calculate_mass(quantity_idx, solution, masses_[quantity_idx]);
638 
639  // compute positive/negative sources
640  for (unsigned int r=0; r<mesh_->region_db().bulk_size(); ++r)
641  {
642  sources_in_[quantity_idx][r] = 0;
643  sources_out_[quantity_idx][r] = 0;
644  }
645 
646  int lsize, n_cols_mat, n_cols_rhs;
647  const int *cols; // the columns must be same - matrices created and filled in the same way
648  const double *vals_mat, *vals_rhs, *sol_array;
649  // chkerr(VecGetLocalSize(solution, &lsize));
650  // chkerr(ISLocalToGlobalMappingGetSize(solution->mapping, &lsize); // cannot do for const
651  lsize = n_loc_dofs_seq_;
652  chkerr(VecGetArrayRead(solution, &sol_array));
653 
654  // computes transpose multiplication and sums region_source_rhs_ over dofs
655  // resulting in a vector of sources for each region, one positive, one negative
656  // transpose(region_source_matrix_) * solution + region_source_rhs_*ones(n_blk_reg)
657  for (int i=0; i<lsize; ++i)
658  {
659  int row = i;
660  chkerr(MatGetRow(region_source_matrix_[quantity_idx], row, &n_cols_mat, &cols, &vals_mat));
661  chkerr(MatGetRow(region_source_rhs_[quantity_idx], row, &n_cols_rhs, NULL, &vals_rhs));
662 
663  ASSERT_DBG(n_cols_mat == n_cols_rhs);
664 
665  for (int j=0; j<n_cols_mat; ++j)
666  {
667  int col = cols[j];
668 
669  double f = vals_mat[j]*sol_array[i] + vals_rhs[j];
670  if (f > 0) sources_in_[quantity_idx][col] += f;
671  else sources_out_[quantity_idx][col] += f;
672  }
673  }
674  chkerr(VecRestoreArrayRead(solution, &sol_array));
675 
676  // calculate flux
677  Vec temp;
678  chkerr(VecCreateMPI(PETSC_COMM_WORLD,
679  be_regions_.size(),
680  PETSC_DECIDE,
681  &temp));
682 
683  chkerr(MatMultAdd(be_flux_matrix_[quantity_idx], solution, be_flux_vec_[quantity_idx], temp));
684  // Since internally we keep outgoing fluxes, we change sign
685  // to write to output _incoming_ fluxes.
686  chkerr(VecScale(temp, -1));
687 
688  // compute positive/negative fluxes
689  fluxes_in_[quantity_idx].assign(mesh_->region_db().boundary_size(), 0);
690  fluxes_out_[quantity_idx].assign(mesh_->region_db().boundary_size(), 0);
691  const double *flux_array;
692 // int lsize;
693  chkerr(VecGetArrayRead(temp, &flux_array));
694  chkerr(VecGetLocalSize(temp, &lsize));
695  for (int e=0; e<lsize; ++e)
696  {
697  if (flux_array[e] < 0)
698  fluxes_out_[quantity_idx][be_regions_[e]] += flux_array[e];
699  else
700  fluxes_in_[quantity_idx][be_regions_[e]] += flux_array[e];
701  }
702  chkerr(VecRestoreArrayRead(temp, &flux_array));
703  chkerr(VecDestroy(&temp));
704 }
705 
706 
707 
708 
709 
711 {
713  if (! balance_on_) return;
714  if (! is_current() ) return;
715 
716  // gather results from processes and sum them up
717  const unsigned int n_quant = quantities_.size();
718  const unsigned int n_blk_reg = mesh_->region_db().bulk_size();
719  const unsigned int n_bdr_reg = mesh_->region_db().boundary_size();
720  const int buf_size = n_quant*2*n_blk_reg + n_quant*2*n_bdr_reg + n_quant;
721  double sendbuffer[buf_size], recvbuffer[buf_size];
722  for (unsigned int qi=0; qi<n_quant; qi++)
723  {
724  for (unsigned int ri=0; ri<n_blk_reg; ri++)
725  {
726  sendbuffer[qi*2*n_blk_reg + + ri] = sources_in_[qi][ri];
727  sendbuffer[qi*2*n_blk_reg + n_blk_reg + ri] = sources_out_[qi][ri];
728  }
729  for (unsigned int ri=0; ri<n_bdr_reg; ri++)
730  {
731  sendbuffer[n_quant*2*n_blk_reg + qi*2*n_bdr_reg + + ri] = fluxes_in_[qi][ri];
732  sendbuffer[n_quant*2*n_blk_reg + qi*2*n_bdr_reg + n_bdr_reg + ri] = fluxes_out_[qi][ri];
733  }
734  if (cumulative_)
735  {
736  sendbuffer[n_quant*2*n_blk_reg + n_quant*2*n_bdr_reg + qi] = increment_sources_[qi];
737  }
738  }
739 
740  MPI_Reduce(&sendbuffer,recvbuffer,buf_size,MPI_DOUBLE,MPI_SUM,0,PETSC_COMM_WORLD);
741  // for other than 0th process update last_time and finish,
742  // on process #0 sum balances over all regions and calculate
743  // cumulative balance over time.
744  if (rank_ == 0)
745  {
746  // update balance vectors
747  for (unsigned int qi=0; qi<n_quant; qi++)
748  {
749  for (unsigned int ri=0; ri<n_blk_reg; ri++)
750  {
751  sources_in_[qi][ri] = recvbuffer[qi*2*n_blk_reg + + ri];
752  sources_out_[qi][ri] = recvbuffer[qi*2*n_blk_reg + n_blk_reg + ri];
753  }
754  for (unsigned int ri=0; ri<n_bdr_reg; ri++)
755  {
756  fluxes_in_[qi][ri] = recvbuffer[n_quant*2*n_blk_reg + qi*2*n_bdr_reg + + ri];
757  fluxes_out_[qi][ri] = recvbuffer[n_quant*2*n_blk_reg + qi*2*n_bdr_reg + n_bdr_reg + ri];
758  }
759  if (cumulative_)
760  {
761  increment_sources_[qi] = recvbuffer[n_quant*2*n_blk_reg + n_quant*2*n_bdr_reg + qi];
762  }
763  }
764  }
765 
766 
767  // The convention for input/output of fluxes is that positive means inward.
768  // Therefore in the following code we switch sign of fluxes.
769  if (rank_ == 0)
770  {
771  sum_fluxes_.assign(n_quant, 0);
772  sum_fluxes_in_.assign(n_quant, 0);
773  sum_fluxes_out_.assign(n_quant, 0);
774  sum_masses_.assign(n_quant, 0);
775  sum_sources_.assign(n_quant, 0);
776  sum_sources_in_.assign(n_quant, 0);
777  sum_sources_out_.assign(n_quant, 0);
778 
779  // sum all boundary fluxes
780  const RegionSet & b_set = mesh_->region_db().get_region_set(".BOUNDARY");
781  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg)
782  {
783  for (unsigned int qi=0; qi<n_quant; qi++)
784  {
785  sum_fluxes_[qi] += fluxes_in_ [qi][reg->boundary_idx()] + fluxes_out_[qi][reg->boundary_idx()];
786  sum_fluxes_in_[qi] += fluxes_in_ [qi][reg->boundary_idx()];
787  sum_fluxes_out_[qi] += fluxes_out_[qi][reg->boundary_idx()];
788  }
789  }
790 
791  // sum all volume sources
792  const RegionSet & bulk_set = mesh_->region_db().get_region_set("BULK");
793  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
794  {
795  for (unsigned int qi=0; qi<n_quant; qi++)
796  {
797  sum_masses_[qi] += masses_[qi][reg->bulk_idx()];
798  sum_sources_[qi] += sources_in_[qi][reg->bulk_idx()] + sources_out_[qi][reg->bulk_idx()];
799  sum_sources_in_[qi] += sources_in_[qi][reg->bulk_idx()];
800  sum_sources_out_[qi] += sources_out_[qi][reg->bulk_idx()];
801  }
802  }
803 
804  // cumulative balance over time
805  if (cumulative_)
806  {
807  // save initial time and mass
808  if (initial_)
809  {
811  for (unsigned int qi=0; qi<n_quant; qi++)
812  initial_mass_[qi] = sum_masses_[qi];
813  initial_ = false;
814  }
815 
816  for (unsigned int qi=0; qi<n_quant; qi++)
817  {
820  }
821  }
822  }
823 
824  last_time_ = time_->t();
825 
826 
827  // perform actual output
828  switch (output_format_)
829  {
830  case txt:
831  output_csv(time_->t(), '\t', "");
832  break;
833  case gnuplot:
834  output_csv(time_->t(), ' ', "#", 30);
835  break;
836  case legacy:
837  output_legacy(time_->t());
838  break;
839  }
840  // output in YAML format
841  output_yaml(time_->t());
842 
843  if (rank_ == 0)
844  {
845  sum_fluxes_.assign(n_quant, 0);
846  sum_sources_.assign(n_quant, 0);
847  increment_fluxes_.assign(n_quant, 0);
848  }
849  increment_sources_.assign(n_quant, 0);
850 }
851 
852 
853 void Balance::output_legacy(double time)
854 {
855  // write output only on process #0
856  if (rank_ != 0) return;
857 
858  const unsigned int n_quant = quantities_.size();
859 
860  // print the head of mass balance file
861  unsigned int c = 6; //column number without label
862  unsigned int w = 14; //column width
863  unsigned int wl = 2*(w-5)+7; //label column width
864  string bc_head_format = "# %-*s%-*s%-*s%-*s%-*s%-*s\n",
865  bc_format = "%*s%-*d%-*s%-*s%-*g%-*g%-*g\n",
866  bc_total_format = "# %-*s%-*s%-*g%-*g%-*g\n";
867 
868  output_ << "# " << setw((w*c+wl-14)/2) << setfill('-') << "--"
869  << " MASS BALANCE "
870  << setw((w*c+wl-14)/2) << setfill('-') << "" << endl
871  << "# Time: " << (time / time_->get_coef())
872  << "[" << time_->get_unit_conversion()->get_unit_string() << "]\n\n\n";
873 
874  // header for table of boundary fluxes
875  output_ << "# Mass flux through boundary [M/T]:\n# "
876  << setiosflags(ios::left) << setfill(' ')
877  << setw(w) << "[boundary_id]"
878  << setw(wl) << "[label]"
879  << setw(w) << "[substance]"
880  << setw(w) << "[total flux]"
881  << setw(w) << "[outward flux]"
882  << setw(w) << "[inward flux]"
883  << endl;
884 
885  // draw long line
886  output_ << "# " << setw(w*c+wl) << setfill('-') << "" << setfill(' ') << endl;
887 
888  // print mass fluxes over boundaries
889  const RegionSet & b_set = mesh_->region_db().get_region_set(".BOUNDARY");
890  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg) {
891  for (unsigned int qi=0; qi<n_quant; qi++) {
892  output_ << setw(2) << ""
893  << setw(w) << (int)reg->id()
894  << setw(wl) << reg->label().c_str()
895  << setw(w) << quantities_[qi].name_.c_str()
896  << setw(w) << fluxes_in_[qi][reg->boundary_idx()] + fluxes_out_[qi][reg->boundary_idx()]
897  << setw(w) << fluxes_out_[qi][reg->boundary_idx()]
898  << setw(w) << fluxes_in_[qi][reg->boundary_idx()]
899  << endl;
900  }
901  }
902 
903  // draw long line
904  output_ << "# " << setw(w*c+wl) << setfill('-') << "" << setfill(' ') << endl;
905 
906  // total boundary balance
907  for (unsigned int qi=0; qi<n_quant; qi++)
908  output_ << "# " << setiosflags(ios::left)
909  << setw(w+wl) << "Total mass flux of substance [M/T]"
910  << setw(w) << quantities_[qi].name_.c_str()
911  << setw(w) << sum_fluxes_[qi]
912  << setw(w) << sum_fluxes_out_[qi]
913  << setw(w) << sum_fluxes_in_[qi]
914  << endl;
915  output_ << "\n\n";
916 
917 
918  // header for table of volume sources and masses
919  string src_head_format = "# %-*s%-*s%-*s%-*s%-*s\n",
920  src_format = "%*s%-*d%-*s%-*s%-*g%-*g\n",
921  src_total_format = "# %-*s%-*s%-*g%-*g\n";
922  output_ << "# Mass [M] and sources [M/T] on regions:\n"
923  << "# " << setiosflags(ios::left)
924  << setw(w) << "[region_id]"
925  << setw(wl) << "[label]"
926  << setw(w) << "[substance]"
927  << setw(w) << "[total_mass]"
928  << setw(w) << "[total_source]"
929  << endl;
930 
931  // draw long line
932  output_ << "# " << setw(w*c+wl) << setfill('-') << "" << setfill(' ') << endl;
933 
934  // print balance of volume sources and masses
935  const RegionSet & bulk_set = mesh_->region_db().get_region_set("BULK");
936  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
937  {
938  for (unsigned int qi=0; qi<n_quant; qi++)
939  {
940  output_ << setw(2) << ""
941  << setw(w) << (int)reg->id()
942  << setw(wl) << reg->label().c_str()
943  << setw(w) << quantities_[qi].name_.c_str()
944  << setw(w) << masses_[qi][reg->bulk_idx()]
945  << setw(w) << sources_in_[qi][reg->bulk_idx()] + sources_out_[qi][reg->bulk_idx()]
946  << endl;
947  }
948  }
949 
950  // draw long line
951  output_ << "# " << setw(w*c+wl) << setfill('-') << "" << setfill(' ') << endl;
952 
953  // total sources balance
954  for (unsigned int qi=0; qi<n_quant; qi++)
955  output_ << "# " << setiosflags(ios::left) << setw(w+wl) << "Total mass [M] and sources [M/T]"
956  << setw(w) << quantities_[qi].name_.c_str()
957  << setw(w) << sum_masses_[qi]
958  << setw(w) << sum_sources_[qi]
959  << endl;
960 
961  if (cumulative_)
962  {
963  // Print cumulative sources
964  output_ << "\n\n# Cumulative mass balance on time interval ["
965  << setiosflags(ios::left) << time_->init_time() << ","
966  << setiosflags(ios::left) << time << "]\n"
967  << "# Initial mass [M] + sources integrated over time [M] - flux integrated over time [M] = current mass [M]\n"
968  << "# " << setiosflags(ios::left)
969  << setw(w) << "[substance]"
970  << setw(w) << "[A=init. mass]"
971  << setw(w) << "[B=source]"
972  << setw(w) << "[C=flux]"
973  << setw(w) << "[A+B-C]"
974  << setw(w) << "[D=curr. mass]"
975  << setw(w) << "[A+B-C-D=err.]"
976  << setw(w) << "[rel. error]"
977  << endl;
978 
979  for (unsigned int qi=0; qi<n_quant; qi++)
980  {
981  double denominator = max(fabs(initial_mass_[qi]+integrated_sources_[qi]-integrated_fluxes_[qi]),fabs(sum_masses_[qi]));
982  output_ << " " << setiosflags(ios::left)
983  << setw(w) << quantities_[qi].name_.c_str()
984  << setw(w) << initial_mass_[qi]
985  << setw(w) << integrated_sources_[qi]
986  << setw(w) << integrated_fluxes_[qi]
987  << setw(w) << initial_mass_[qi]+integrated_sources_[qi]-integrated_fluxes_[qi]
988  << setw(w) << sum_masses_[qi]
990  << setw(w) << fabs(initial_mass_[qi]+integrated_sources_[qi]+integrated_fluxes_[qi]-sum_masses_[qi])/(denominator==0?1:denominator)
991  << endl;
992  }
993  }
994 
995  output_ << endl << endl;
996 }
997 
998 
999 std::string Balance::csv_zero_vals(unsigned int cnt, char delimiter)
1000 {
1001  std::stringstream ss;
1002  for (unsigned int i=0; i<cnt; i++) ss << format_csv_val(0, delimiter);
1003  return ss.str();
1004 }
1005 
1006 
1007 void Balance::output_csv(double time, char delimiter, const std::string& comment_string, unsigned int repeat)
1008 {
1009  // write output only on process #0
1010  if (rank_ != 0) return;
1011 
1012  const unsigned int n_quant = quantities_.size();
1013 
1014  // print data header only on first line
1015  if (repeat==0 && output_line_counter_==0) format_csv_output_header(delimiter, comment_string);
1016 
1017  // print sources and masses over bulk regions
1018  const RegionSet & bulk_set = mesh_->region_db().get_region_set("BULK");
1019  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
1020  {
1021  for (unsigned int qi=0; qi<n_quant; qi++)
1022  {
1023  // print data header (repeat header after every "repeat" lines)
1024  if (repeat && (output_line_counter_%repeat == 0)) format_csv_output_header(delimiter, comment_string);
1025 
1026  output_ << format_csv_val(time / time_->get_coef(), delimiter, true)
1027  << format_csv_val(reg->label(), delimiter)
1028  << format_csv_val(quantities_[qi].name_, delimiter)
1029  << csv_zero_vals(3, delimiter)
1030  << format_csv_val(masses_[qi][reg->bulk_idx()], delimiter)
1031  << format_csv_val(sources_in_[qi][reg->bulk_idx()] + sources_out_[qi][reg->bulk_idx()], delimiter)
1032  << format_csv_val(sources_in_[qi][reg->bulk_idx()], delimiter)
1033  << format_csv_val(sources_out_[qi][reg->bulk_idx()], delimiter)
1034  << csv_zero_vals(5, delimiter) << endl;
1036  }
1037  }
1038 
1039  // print mass fluxes over boundaries
1040  const RegionSet & b_set = mesh_->region_db().get_region_set(".BOUNDARY");
1041  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg)
1042  {
1043  for (unsigned int qi=0; qi<n_quant; qi++) {
1044  // print data header (repeat header after every "repeat" lines)
1045  if (repeat && (output_line_counter_%repeat == 0)) format_csv_output_header(delimiter, comment_string);
1046 
1047  output_ << format_csv_val(time / time_->get_coef(), delimiter, true)
1048  << format_csv_val(reg->label(), delimiter)
1049  << format_csv_val(quantities_[qi].name_, delimiter)
1050  << format_csv_val(fluxes_in_[qi][reg->boundary_idx()] + fluxes_out_[qi][reg->boundary_idx()], delimiter)
1051  << format_csv_val(fluxes_in_[qi][reg->boundary_idx()], delimiter)
1052  << format_csv_val(fluxes_out_[qi][reg->boundary_idx()], delimiter)
1053  << csv_zero_vals(9, delimiter) << endl;
1055  }
1056  }
1057 
1058  if (cumulative_)
1059  {
1060  for (unsigned int qi=0; qi<n_quant; qi++)
1061  {
1062  // print data header (repeat header after every "repeat" lines)
1063  if (repeat && (output_line_counter_%repeat == 0)) format_csv_output_header(delimiter, comment_string);
1064 
1065  double error = sum_masses_[qi] - (initial_mass_[qi] + integrated_sources_[qi] + integrated_fluxes_[qi]);
1066  output_ << format_csv_val(time / time_->get_coef(), delimiter, true)
1067  << format_csv_val("ALL", delimiter)
1068  << format_csv_val(quantities_[qi].name_, delimiter)
1069  << format_csv_val(sum_fluxes_[qi], delimiter)
1070  << format_csv_val(sum_fluxes_in_[qi], delimiter)
1071  << format_csv_val(sum_fluxes_out_[qi], delimiter)
1072  << format_csv_val(sum_masses_[qi], delimiter)
1073  << format_csv_val(sum_sources_[qi], delimiter)
1074  << format_csv_val(sum_sources_in_[qi], delimiter)
1075  << format_csv_val(sum_sources_out_[qi], delimiter)
1076  << format_csv_val(increment_fluxes_[qi], delimiter)
1077  << format_csv_val(increment_sources_[qi], delimiter)
1078  << format_csv_val(integrated_fluxes_[qi], delimiter)
1079  << format_csv_val(integrated_sources_[qi], delimiter)
1080  << format_csv_val(error, delimiter) << endl;
1082  }
1083  }
1084 
1085 }
1086 
1087 
1088 void Balance::format_csv_output_header(char delimiter, const std::string& comment_string)
1089 {
1090  std::stringstream ss;
1091  if (delimiter == ' ') {
1092  ss << setw(output_column_width-comment_string.size())
1093  << "\"time [" << time_->get_unit_conversion()->get_unit_string() << "]\"";
1094  } else {
1095  ss << "\"time [" << time_->get_unit_conversion()->get_unit_string() << "]\"";
1096  }
1097 
1098  output_ << comment_string << ss.str()
1099  << format_csv_val("region", delimiter)
1100  << format_csv_val("quantity [" + units_.format_text() + "]", delimiter)
1101  << format_csv_val("flux", delimiter)
1102  << format_csv_val("flux_in", delimiter)
1103  << format_csv_val("flux_out", delimiter)
1104  << format_csv_val("mass", delimiter)
1105  << format_csv_val("source", delimiter)
1106  << format_csv_val("source_in", delimiter)
1107  << format_csv_val("source_out", delimiter)
1108  << format_csv_val("flux_increment", delimiter)
1109  << format_csv_val("source_increment", delimiter)
1110  << format_csv_val("flux_cumulative", delimiter)
1111  << format_csv_val("source_cumulative", delimiter)
1112  << format_csv_val("error", delimiter)
1113  << endl;
1114 }
1115 
1116 std::string Balance::format_csv_val(std::string val, char delimiter, bool initial)
1117 {
1118  std::stringstream ss;
1119  std::replace( val.begin(), val.end(), '\"', '\'');
1120 
1121  if (!initial) ss << delimiter;
1122  if (delimiter == ' ') {
1123  std::stringstream sval;
1124  sval << "\"" << val << "\"";
1125  ss << " " << setw(output_column_width-1) << sval.str();
1126  } else {
1127  ss << "\"" << val << "\"";
1128  }
1129 
1130  return ss.str();
1131 }
1132 
1133 std::string Balance::format_csv_val(double val, char delimiter, bool initial)
1134 {
1135  std::stringstream ss;
1136 
1137  if (!initial) ss << delimiter;
1138  if (delimiter == ' ') {
1139  ss << " " << setw(output_column_width-1) << val;
1140  } else {
1141  ss << val;
1142  }
1143  return ss.str();
1144 }
1145 
1146 void Balance::output_yaml(double time)
1147 {
1148 
1149  // write output only on process #0
1150  if (!do_yaml_output_ || rank_ != 0) return;
1151 
1152  const unsigned int n_quant = quantities_.size();
1153 
1154  // print data header only once
1155  if (!output_yaml_header_) {
1156  output_yaml_ << "column_names: [ flux, flux_in, flux_out, mass, source, source_in, source_out, flux_increment, "
1157  << "source_increment, flux_cumulative, source_cumulative, error ]" << endl;
1158  output_yaml_ << "data:" << endl;
1159  output_yaml_header_ = true;
1160  }
1161 
1162  output_yaml_ << setfill(' ');
1163 
1164  // print sources and masses over bulk regions
1165  const RegionSet & bulk_set = mesh_->region_db().get_region_set("BULK");
1166  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
1167  {
1168  for (unsigned int qi=0; qi<n_quant; qi++)
1169  {
1170  output_yaml_ << " - time: " << (time / time_->get_coef()) << endl;
1171  output_yaml_ << setw(4) << "" << "region: " << reg->label() << endl;
1172  output_yaml_ << setw(4) << "" << "quantity: " << quantities_[qi].name_ << endl;
1173  output_yaml_ << setw(4) << "" << "data: " << "[ 0, 0, 0, " << masses_[qi][reg->bulk_idx()] << ", "
1174  << sources_in_[qi][reg->bulk_idx()] + sources_out_[qi][reg->bulk_idx()] << ", "
1175  << sources_in_[qi][reg->bulk_idx()] << ", " << sources_out_[qi][reg->bulk_idx()]
1176  << ", 0, 0, 0, 0, 0 ]" << endl;
1177  }
1178  }
1179 
1180  // print mass fluxes over boundaries
1181  const RegionSet & b_set = mesh_->region_db().get_region_set(".BOUNDARY");
1182  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg)
1183  {
1184  for (unsigned int qi=0; qi<n_quant; qi++) {
1185  output_yaml_ << " - time: " << (time / time_->get_coef()) << endl;
1186  output_yaml_ << setw(4) << "" << "region: " << reg->label() << endl;
1187  output_yaml_ << setw(4) << "" << "quantity: " << quantities_[qi].name_ << endl;
1188  output_yaml_ << setw(4) << "" << "data: " << "[ "
1189  << fluxes_in_[qi][reg->boundary_idx()] + fluxes_out_[qi][reg->boundary_idx()] << ", "
1190  << fluxes_in_[qi][reg->boundary_idx()] << ", " << fluxes_out_[qi][reg->boundary_idx()]
1191  << ", 0, 0, 0, 0, 0, 0, 0, 0, 0 ]" << endl;
1192  }
1193  }
1194 
1195  if (cumulative_)
1196  {
1197  for (unsigned int qi=0; qi<n_quant; qi++)
1198  {
1199  double error = sum_masses_[qi] - (initial_mass_[qi] + integrated_sources_[qi] + integrated_fluxes_[qi]);
1200  output_yaml_ << " - time: " << (time / time_->get_coef()) << endl;
1201  output_yaml_ << setw(4) << "" << "region: ALL" << endl;
1202  output_yaml_ << setw(4) << "" << "quantity: " << quantities_[qi].name_ << endl;
1203  output_yaml_ << setw(4) << "" << "data: " << "[ " << sum_fluxes_[qi] << ", "
1204  << sum_fluxes_in_[qi] << ", " << sum_fluxes_out_[qi] << ", "
1205  << sum_masses_[qi] << ", " << sum_sources_[qi] << ", "
1206  << sum_sources_in_[qi] << ", " << sum_sources_out_[qi] << ", "
1207  << increment_fluxes_[qi] << ", " << increment_sources_[qi] << ", "
1208  << integrated_fluxes_[qi] << ", " << integrated_sources_[qi] << ", "
1209  << error << " ]" << endl;
1210  }
1211  }
1212 }
1213 
1214 
1215 
1216 
1217 
1218 
Balance::mesh_
const Mesh * mesh_
Definition: balance.hh:457
LocDofVec
arma::Col< IntIdx > LocDofVec
Definition: index_types.hh:28
Mesh::get_el_ds
Distribution * get_el_ds() const
Definition: mesh.h:198
Balance::calculate_instant
void calculate_instant(unsigned int quantity_idx, const Vec &solution)
Definition: balance.cc:633
Input::Type::Bool
Class for declaration of the input of type Bool.
Definition: type_base.hh:452
Balance::allocate
void allocate(const std::shared_ptr< DOFHandlerMultiDim > &dh, unsigned int max_dofs_per_boundary)
Definition: balance.cc:191
Boundary
Definition: accessors.hh:363
Balance::Quantity
Definition: balance.hh:127
Balance::output_column_width
static const unsigned int output_column_width
Size of column in output (used if delimiter is space)
Definition: balance.hh:391
Balance::be_regions_
std::vector< unsigned int > be_regions_
Maps local boundary edge to its region boundary index.
Definition: balance.hh:489
TimeGovernor::dt
double dt() const
Definition: time_governor.hh:558
DHCellSide::side
Side side() const
Return Side of given cell and side_idx.
Definition: dh_cell_accessor.hh:198
DHCellAccessor::dh
const DOFHandlerMultiDim * dh() const
Return DOF handler.
Definition: dh_cell_accessor.hh:106
Balance::lazy_initialize
void lazy_initialize()
Definition: balance.cc:202
Balance::n_loc_dofs_seq_
unsigned int n_loc_dofs_seq_
Definition: balance.hh:435
Balance::sum_fluxes_out_
std::vector< double > sum_fluxes_out_
Definition: balance.hh:507
Balance::Balance
Balance(const std::string &file_prefix, const Mesh *mesh)
Definition: balance.cc:86
time_governor.hh
Basic time management class.
Balance::units_
UnitSI units_
Units of conserved quantities.
Definition: balance.hh:460
DOFHandlerMultiDim::get_local_to_global_map
const std::vector< LongIdx > & get_local_to_global_map() const
Get the map between local dof indices and the global ones.
Definition: dofhandler.hh:258
UnitSI::format_text
std::string format_text() const
Definition: unit_si.cc:127
Balance::time_
const TimeGovernor * time_
Definition: balance.hh:557
TimeGovernor::get_unit_conversion
std::shared_ptr< TimeUnitConversion > get_unit_conversion() const
Getter for time unit conversion object.
Definition: time_governor.cc:807
ASSERT
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:347
Balance::csv_zero_vals
std::string csv_zero_vals(unsigned int cnt, char delimiter)
Return part of output represented by zero values. Count of zero values is given by cnt parameter.
Definition: balance.cc:999
Balance::Quantity::index_
const unsigned int index_
Internal index within list of quantities.
Definition: balance.hh:139
Balance::txt
@ txt
csv
Definition: balance.hh:149
Balance::add_quantity
unsigned int add_quantity(const string &name)
Definition: balance.cc:162
Balance::balance_output_type_
TimeMark::Type balance_output_type_
TimeMark type for balance output of particular equation.
Definition: balance.hh:524
TimeGovernor::equation_fixed_mark_type
TimeMark::Type equation_fixed_mark_type() const
Definition: time_governor.hh:474
distribution.hh
Support classes for parallel programing.
Balance::integrated_sources_
std::vector< double > integrated_sources_
Definition: balance.hh:515
Side::is_boundary
bool is_boundary() const
Returns true for side on the boundary.
Definition: accessors_impl.hh:202
Input::Record::val
const Ret val(const string &key) const
Definition: accessors_impl.hh:31
Balance::format_csv_output_header
void format_csv_output_header(char delimiter, const std::string &comment_string)
Print output header.
Definition: balance.cc:1088
Input::Type::Selection::close
const Selection & close() const
Close the Selection, no more values can be added.
Definition: type_selection.cc:65
Balance::sum_sources_
std::vector< double > sum_sources_
Definition: balance.hh:509
Balance::finish_source_assembly
void finish_source_assembly(unsigned int quantity_idx)
This method must be called after assembling the matrix and vectors for computing source.
Definition: balance.cc:433
FilePath
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
Balance::rank_
int rank_
MPI rank.
Definition: balance.hh:546
ASSERT_DBG
#define ASSERT_DBG(expr)
Definition: include_fadbad.hh:28
chkerr
void chkerr(unsigned int ierr)
Replacement of new/delete operator in the spirit of xmalloc.
Definition: system.hh:142
Balance::output_yaml_header_
bool output_yaml_header_
marks whether YAML output has printed header
Definition: balance.hh:552
MPI_DOUBLE
#define MPI_DOUBLE
Definition: mpi.h:156
Balance::start_flux_assembly
void start_flux_assembly(unsigned int quantity_idx)
Definition: balance.cc:393
std::vector< unsigned int >
Balance::increment_fluxes_
std::vector< double > increment_fluxes_
Definition: balance.hh:517
Input::Type::Default::read_time
static Default read_time(const std::string &description)
The factory function to make an default value that will be specified at the time when a key will be r...
Definition: type_record.hh:97
ElementAccessor< 3 >
Input::Type::FileName::output
static FileName output()
The factory function for declaring type FileName for input files.
Definition: type_base.cc:531
system.hh
Balance::init_from_input
void init_from_input(const Input::Record &in_rec, TimeGovernor &tg)
Definition: balance.cc:129
Balance::do_yaml_output_
static bool do_yaml_output_
Definition: balance.hh:431
dofhandler.hh
Declaration of class which handles the ordering of degrees of freedom (dof) and mappings between loca...
uint
unsigned int uint
Definition: mh_dofhandler.hh:101
Side::cond
Boundary cond() const
Definition: accessors_impl.hh:225
Balance::quantities_
std::vector< Quantity > quantities_
Names of conserved quantities.
Definition: balance.hh:455
FilePath::open_stream
void open_stream(Stream &stream) const
Definition: file_path.cc:211
Balance::units
void units(const UnitSI &unit)
Setter for units of conserved quantities.
Definition: balance.cc:154
Balance::add_flux_values
void add_flux_values(unsigned int quantity_idx, const DHCellSide &side, const LocDofVec &loc_dof_indices, const std::vector< double > &mat_values, double vec_value)
Definition: balance.cc:476
index_types.hh
MPI_Comm_rank
#define MPI_Comm_rank
Definition: mpi.h:236
RegionDB::boundary_size
unsigned int boundary_size() const
Definition: region.cc:261
Balance::start_mass_assembly
void start_mass_assembly(unsigned int quantity_idx)
Definition: balance.cc:384
Balance::region_mass_vec_
Vec * region_mass_vec_
Vectors for calculation of mass (n_bulk_regions).
Definition: balance.hh:479
Balance::be_flux_matrix_
Mat * be_flux_matrix_
Matrices for calculation of flux (n_boundary_edges x n_dofs).
Definition: balance.hh:467
Balance::finish_mass_assembly
void finish_mass_assembly(unsigned int quantity_idx)
This method must be called after assembling the matrix for computing mass.
Definition: balance.cc:411
Input::Type::Default
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
DHCellSide
Side accessor allows to iterate over sides of DOF handler cell.
Definition: dh_cell_accessor.hh:176
TimeMark
Class used for marking specified times at which some events occur.
Definition: time_marks.hh:45
dh_cell_accessor.hh
accessors.hh
Balance::output_
std::ofstream output_
Handle for file for output in given OutputFormat of balance and total fluxes over individual regions ...
Definition: balance.hh:446
Balance::output_yaml
void output_yaml(double time)
Perform output in yaml format.
Definition: balance.cc:1146
DHCellSide::cell
const DHCellAccessor & cell() const
Return DHCellAccessor appropriate to the side.
Definition: dh_cell_accessor.hh:204
Input::Record
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
Balance::region_mass_matrix_
Mat * region_mass_matrix_
Matrices for calculation of mass (n_dofs x n_bulk_regions).
Definition: balance.hh:464
sys_profiler.hh
Balance::legacy
@ legacy
legacy
Definition: balance.hh:148
TimeGovernor::tlevel
int tlevel() const
Definition: time_governor.hh:600
Balance::balance_on_
bool balance_on_
If the balance is on. Balance is off in the case of no balance output time marks.
Definition: balance.hh:539
RegionDB::bulk_size
unsigned int bulk_size() const
Definition: region.cc:268
Balance::cumulative_
bool cumulative_
if true then cumulative balance is computed
Definition: balance.hh:533
Balance::~Balance
~Balance()
Definition: balance.cc:103
Balance::masses_
std::vector< std::vector< double > > masses_
Definition: balance.hh:500
INPUT_CATCH
#define INPUT_CATCH(ExceptionType, AddressEITag, input_accessor)
Definition: accessors.hh:63
TimeGovernor
Basic time management functionality for unsteady (and steady) solvers (class Equation).
Definition: time_governor.hh:310
TimeGovernor::step
const TimeStep & step(int index=-1) const
Definition: time_governor.cc:753
Balance::be_flux_vec_
Vec * be_flux_vec_
Vectors for calculation of flux (n_boundary_edges).
Definition: balance.hh:476
DHCellAccessor::elm
const ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
Definition: dh_cell_accessor.hh:71
chkerr_assert
void chkerr_assert(unsigned int ierr)
Definition: system.hh:153
Balance::sum_fluxes_in_
std::vector< double > sum_fluxes_in_
Definition: balance.hh:506
UnitSI
Class for representation SI units of Fields.
Definition: unit_si.hh:40
Mesh::region_db
const RegionDB & region_db() const
Definition: mesh.h:187
Balance::sum_masses_
std::vector< double > sum_masses_
Definition: balance.hh:508
Balance::fluxes_
std::vector< std::vector< double > > fluxes_
Definition: balance.hh:497
RegionDB::get_region_set
RegionSet get_region_set(const std::string &set_name) const
Definition: region.cc:328
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
MPI_Reduce
#define MPI_Reduce(sendbuf, recvbuf, count, datatype, op, root, comm)
Definition: mpi.h:608
Balance::gnuplot
@ gnuplot
gnuplot
Definition: balance.hh:150
Balance::output_line_counter_
unsigned int output_line_counter_
hold count of line printed into output_
Definition: balance.hh:549
Balance::output
void output()
Perform output to file for given time instant.
Definition: balance.cc:710
Balance::initial_mass_
std::vector< double > initial_mass_
Definition: balance.hh:512
Balance::add_output_times_
bool add_output_times_
Add output time marks to balance output time marks.
Definition: balance.hh:542
Balance::calculate_mass
void calculate_mass(unsigned int quantity_idx, const Vec &solution, vector< double > &output_array)
Definition: balance.cc:608
mesh.h
output_time_set.hh
Input::Type::Selection
Template for classes storing finite set of named values.
Definition: type_selection.hh:65
Input::Type::Record::close
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
OutputTimeSet::read_from_input
void read_from_input(Input::Array in_array, const TimeGovernor &tg)
Definition: output_time_set.cc:35
Input::Type
Definition: balance.hh:41
Input::Type::Record
Record type proxy class.
Definition: type_record.hh:182
MPI_SUM
#define MPI_SUM
Definition: mpi.h:196
Balance::region_source_matrix_
Mat * region_source_matrix_
Matrices for calculation of source (n_dofs x n_bulk_regions).
Definition: balance.hh:470
Balance::is_current
bool is_current()
Returns true if the current time step is marked for the balance output.
Definition: balance.cc:373
Balance::format_csv_val
std::string format_csv_val(std::string val, char delimiter, bool initial=false)
Format string value of csv output. Wrap string into quotes and if delimiter is space,...
Definition: balance.cc:1116
LongIdx
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: index_types.hh:24
Balance::calculate_cumulative
void calculate_cumulative(unsigned int quantity_idx, const Vec &solution)
Definition: balance.cc:549
Balance::output_format_
OutputFormat output_format_
Format of output file.
Definition: balance.hh:452
Balance::fluxes_in_
std::vector< std::vector< double > > fluxes_in_
Definition: balance.hh:498
Balance::be_offset_
int be_offset_
Offset for local part of vector of boundary edges.
Definition: balance.hh:492
Mesh
Definition: mesh.h:98
Balance::sources_in_
std::vector< std::vector< double > > sources_in_
Definition: balance.hh:501
Balance::add_source_values
void add_source_values(unsigned int quantity_idx, unsigned int region_idx, const LocDofVec &loc_dof_indices, const std::vector< double > &mult_mat_values, const std::vector< double > &add_mat_values)
Definition: balance.cc:510
UnitSI::undef
void undef(bool val=true)
Definition: unit_si.cc:197
Balance::sum_fluxes_
std::vector< double > sum_fluxes_
Definition: balance.hh:505
Balance::increment_sources_
std::vector< double > increment_sources_
Definition: balance.hh:518
Balance::file_prefix_
std::string file_prefix_
Save prefix passed in in constructor.
Definition: balance.hh:440
Element::n_sides
unsigned int n_sides() const
Definition: elements.h:138
Balance::last_time_
double last_time_
time of last calculated balance
Definition: balance.hh:521
OutputTimeSet::get_input_type
static const Input::Type::Array get_input_type()
Definition: output_time_set.cc:17
TimeGovernor::marks
static TimeMarks & marks()
Definition: time_governor.hh:331
Balance::set_yaml_output
static void set_yaml_output()
Set global variable to output balance files into YAML format (in addition to the table format).
Definition: balance.cc:63
DHCellAccessor
Cell accessor allow iterate over DOF handler cells.
Definition: dh_cell_accessor.hh:43
Balance::output_csv
void output_csv(double time, char delimiter, const std::string &comment_string, unsigned int repeat=0)
Perform output in csv format.
Definition: balance.cc:1007
Balance::fluxes_out_
std::vector< std::vector< double > > fluxes_out_
Definition: balance.hh:499
Input::Array
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
Balance::get_format_selection_input_type
static const Input::Type::Selection & get_format_selection_input_type()
Input selection for file format.
Definition: balance.cc:42
unit_si.hh
TimeGovernor::get_coef
double get_coef() const
Definition: time_governor.cc:802
Balance::get_boundary_edge_uid
LongIdx get_boundary_edge_uid(SideIter side)
Definition: balance.hh:426
Balance::n_loc_dofs_par_
unsigned int n_loc_dofs_par_
Allocation parameters. Set by the allocate method used in the lazy_initialize.
Definition: balance.hh:434
RegionIdx::boundary_idx
unsigned int boundary_idx() const
Returns index of the region in the boundary set.
Definition: region.hh:86
Balance::input_record_
Input::Record input_record_
Record for current balance.
Definition: balance.hh:555
Balance::output_mark_type_
TimeMark::Type output_mark_type_
TimeMark type for output of particular equation.
Definition: balance.hh:527
TimeGovernor::equation_mark_type
TimeMark::Type equation_mark_type() const
Definition: time_governor.hh:468
Balance::start_source_assembly
void start_source_assembly(unsigned int quantity_idx)
Definition: balance.cc:402
FilePath::output_file
@ output_file
Definition: file_path.hh:69
balance.hh
Balance::sum_sources_in_
std::vector< double > sum_sources_in_
Definition: balance.hh:510
Balance::allocation_done_
bool allocation_done_
true before allocating necessary internal structures (Petsc matrices etc.)
Definition: balance.hh:536
Balance::sum_sources_out_
std::vector< double > sum_sources_out_
Definition: balance.hh:511
Balance::balance_output_file_
FilePath balance_output_file_
File path for output_ stream.
Definition: balance.hh:443
Balance::output_yaml_
std::ofstream output_yaml_
Definition: balance.hh:449
Balance::initial_
bool initial_
true before calculating the mass at initial time, otherwise false
Definition: balance.hh:530
Balance::max_dofs_per_boundary_
unsigned int max_dofs_per_boundary_
Definition: balance.hh:436
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
Balance::add_mass_values
void add_mass_values(unsigned int quantity_idx, const DHCellAccessor &dh_cell, const LocDofVec &loc_dof_indices, const std::vector< double > &mat_values, double vec_value)
Definition: balance.cc:445
Balance::add_cumulative_source
void add_cumulative_source(unsigned int quantity_idx, double source)
Definition: balance.cc:539
OutputTimeSet
Definition: output_time_set.hh:28
ASSERT_PTR
#define ASSERT_PTR(ptr)
Definition of assert macro checking non-null pointer (PTR)
Definition: asserts.hh:336
ElementAccessor::side
SideIter side(const unsigned int loc_index)
Definition: accessors_impl.hh:139
Balance::finish_flux_assembly
void finish_flux_assembly(unsigned int quantity_idx)
This method must be called after assembling the matrix and vector for computing flux.
Definition: balance.cc:422
Mesh::element_accessor
virtual ElementAccessor< 3 > element_accessor(unsigned int idx) const
Create and return ElementAccessor to element of given idx.
Definition: mesh.cc:817
Balance::integrated_fluxes_
std::vector< double > integrated_fluxes_
Definition: balance.hh:516
RegionIdx::bulk_idx
unsigned int bulk_idx() const
Returns index of the region in the bulk set.
Definition: region.hh:91
TimeGovernor::init_time
double init_time() const
Definition: time_governor.hh:529
Boundary::region
Region region()
Definition: accessors_impl.hh:259
Balance::region_source_rhs_
Mat * region_source_rhs_
Matrices for calculation of signed source (n_dofs x n_bulk_regions).
Definition: balance.hh:473
Balance::sources_out_
std::vector< std::vector< double > > sources_out_
Definition: balance.hh:502
SideIter
Definition: accessors.hh:504
Element::boundary_idx_
unsigned int * boundary_idx_
Definition: elements.h:82
Balance::be_id_map_
std::unordered_map< LongIdx, unsigned int > be_id_map_
Definition: balance.hh:486
Balance::get_input_type
static const Input::Type::Record & get_input_type()
Main balance input record type.
Definition: balance.cc:50
Balance::output_legacy
void output_legacy(double time)
Perform output in old format (for compatibility)
Definition: balance.cc:853
ElementAccessor::region_idx
RegionIdx region_idx() const
Definition: accessors.hh:204
Balance::OutputFormat
OutputFormat
Definition: balance.hh:146
Balance::add_quantities
std::vector< unsigned int > add_quantities(const std::vector< string > &names)
Definition: balance.cc:173
Mesh::get_el_4_loc
LongIdx * get_el_4_loc() const
Definition: mesh.h:204
TimeGovernor::t
double t() const
Definition: time_governor.hh:535