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