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