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