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