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