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