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