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