Flow123d  release_3.0.0-1165-gffc6a5f
balance.hh
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.hh
15  * @brief
16  */
17 
18 #ifndef BALANCE_HH_
19 #define BALANCE_HH_
20 
21 
22 #include <iosfwd> // for ofstream
23 #include <string> // for string
24 #include <vector> // for vector
25 #include <unordered_map> // for unordered_map
26 #include "mesh/side_impl.hh" // for SideIter
27 #include "tools/unit_si.hh" // for UnitSI
28 #include "input/accessors.hh" // for Record
29 #include "petscmat.h" // for Mat, _p_Mat
30 #include "petscvec.h" // for Vec, _p_Vec
31 #include "system/file_path.hh" // for FilePath
32 #include "tools/time_marks.hh" // for TimeMark, TimeMark::Type
33 #include "mesh/long_idx.hh" // for LongIdx
34 
35 class Mesh;
36 class TimeGovernor;
37 namespace Input {
38  namespace Type {
39  class Record;
40  class Selection;
41  }
42 }
43 
44 
45 
46 
47 
48 /**
49  * Design of balance class - serves as storage and writer.
50  * Equations themselves call methods of Balance that add/modify mass, source and flux
51  * of various quantities and generate output.
52  *
53  * One instance of Balance can handle several conservative quantities of the same type
54  * (e.g. mass of several substances or their phases).
55  *
56  * The mass, flux and source are calculated as follows:
57  *
58  * m(q,r) = ( M'(q) * solution + mv(q) )[r]
59  * f(q,r) = -( R' * ( F(q) * solution + fv(q) ) )[r]
60  * s(q,r) = ( S'(q) * solution + sv(q) )[r]
61  *
62  * where M' stands for matrix transpose,
63  *
64  * m(q,r)...mass of q-th substance in region r
65  * f(q,r)...incoming flux of q-th substance in region r
66  * s(q,r)...source of q-th substance in region r
67  *
68  * and
69  *
70  * M(q)...region_mass_matrix_ n_dofs x n_bulk_regions
71  * F(q)...be_flux_matrix_ n_boundary_edges x n_dofs
72  * S(q)...region_source_matrix_ n_dofs x n_bulk_regions
73  * SV(q)..region_source_rhs_ n_dofs x n_bulk_regions
74  * mv(q)..region_mass_vec_ n_bulk_regions
75  * fv(q)..be_flux_vec_ n_boundary_edges
76  * sv(q)..region_source_vec_ n_bulk_regions
77  * R......region_be_matrix_ n_boundary_edges x n_boundary_regions
78  *
79  * Remark: Matrix F and the vector fv are such that F*solution+fv produces _outcoming_ fluxes per boundary edge.
80  * However we write to output _incoming_ flux due to users' convention and consistently with input interface.
81  *
82  * Note that it holds:
83  *
84  * sv(q) = column sum of SV(q)
85  *
86  * Except for that, we also provide information on positive/negative flux and source:
87  *
88  * fp(q,r) = ( R' * EFP(q) )[r], EFP(q)[e] = max{ 0, ( F(q) * solution + fv(q) )[e] }
89  * fn(q,r) = ( R' * EFN(q) )[r], EFN(q)[e] = min{ 0, ( F(q) * solution + fv(q) )[e] }
90  * sp(q,r) = sum_{i in DOFS } max{ 0, ( S(q)[i,r] * solution[i] + SV(q)[i,r] ) }
91  * sn(q,r) = sum_{i in DOFS } min{ 0, ( S(q)[i,r] * solution[i] + SV(q)[i,r] ) }
92  *
93  * where
94  *
95  * fp(q,r)...positive (inward) flux of q-th quantity in region r
96  * fn(q,r)...negative (outward) flux of q-th quantity in region r
97  * sp(q,r)...positive source (spring) of q-th quantity in region r
98  * sn(q,r)...negative source (sink) of q-th quantity in region r
99  *
100  * Remark: The matrix R is needed only for calculation of signed fluxes.
101  * The reason is that to determine sign, we decompose flux to sum of local contributions
102  * per each boundary element and check its sign. It is not possible to decompose flux
103  * using shape functions, since their normal derivatives may have any sign.
104  *
105  *
106  *
107  * Output values (if not relevant, zero is supplied):
108  *
109  * #time bulk_region quantity 0 0 0 mass source source_in source_out 0 0 0
110  * #time boundary_region quantity flux flux_in flux_out 0 0 0 0 0 0 0
111  * #time ALL quantity flux flux_in flux_out mass source source_in source_out integrated_flux integrated_source error
112  *
113  * error = current_mass - (initial_mass + integrated_source - integrated_flux)
114  *
115  */
116 class Balance {
117 public:
118 
119  /**
120  * Class for storing internal data about conservative quantities handled by the Balance object.
121  * In the future we may store additional data or support definition of derived quantities
122  * (e.g. linear combinations of quantities).
123  */
124  class Quantity {
125  public:
126 
127  Quantity(const unsigned int index, const string &name)
128  : name_(name),
129  index_(index)
130  {}
131 
132  /// Name of quantity (for output).
133  string name_;
134 
135  /// Internal index within list of quantities.
136  const unsigned int index_;
137 
138  };
139 
140  /**
141  * Possible formats of output file.
142  */
144  {
145  legacy,//!< legacy
146  txt, //!< csv
147  gnuplot//!< gnuplot
148  };
149 
150  /// Main balance input record type.
151  static const Input::Type::Record & get_input_type();
152 
153  /// Input selection for file format.
154  static const Input::Type::Selection & get_format_selection_input_type();
155 
156  /// Set global variable to output balance files into YAML format (in addition to the table format).
157  static void set_yaml_output();
158 
159  /**
160  * Constructor.
161  * @param file_prefix Prefix of output file name.
162  * @param mesh Mesh.
163  */
164  Balance(const std::string &file_prefix, const Mesh *mesh);
165 
166  /**
167  * Destructor.
168  */
169  ~Balance();
170 
171 
172  /**
173  * Initialize the balance object according to the input.
174  * The balance output time marks are set according to the already existing output time marks of the same equation.
175  * So, this method must be called after Output::
176  *
177  * @param in_rec Input record of balance.
178  * @param tg TimeGovernor of the equation. We need just equation mark type.
179  *
180  */
181  void init_from_input(const Input::Record &in_rec, TimeGovernor &tg);
182 
183  /// Setter for units of conserved quantities.
184  void units(const UnitSI &unit);
185 
186  /// Getter for cumulative_.
187  inline bool cumulative() const { return cumulative_; }
188 
189 
190  /**
191  * Define a single conservative quantity.
192  * @param name Name of the quantity.
193  * @return Quantity's internal index.
194  */
195  unsigned int add_quantity(const string &name);
196 
197  /**
198  * Define a set of conservative quantities.
199  * @param names List of quantities' names.
200  * @return List of quantities' indices.
201  */
202  std::vector<unsigned int> add_quantities(const std::vector<string> &names);
203 
204  /**
205  * Allocates matrices and vectors for balance.
206  * @param n_loc_dofs Number of solution dofs on the local process.
207  * @param max_dofs_per_boundary Number of dofs contributing to one boundary edge.
208  */
209  void allocate(unsigned int n_loc_dofs,
210  unsigned int max_dofs_per_boundary);
211 
212 
213  /// Returns true if the current time step is marked for the balance output.
214  bool is_current();
215 
216  /**
217  * This method must be called before assembling the matrix for computing mass.
218  * It actually erases the matrix.
219  */
220  void start_mass_assembly(unsigned int quantity_idx);
221 
222  /// Variant of the start_mass_assembly() method for a set of quantities.
224  {
225  for (auto idx : q_idx_vec)
226  start_mass_assembly(idx);
227  }
228 
229  /**
230  * This method must be called before assembling the matrix and vector for fluxes.
231  * It actually erases the matrix and vector.
232  */
233  void start_flux_assembly(unsigned int quantity_idx);
234 
235  /// Variant of the start_flux_assembly() method for a set of quantities.
237  {
238  for (auto idx : q_idx_vec)
239  start_flux_assembly(idx);
240  }
241 
242  /**
243  * This method must be called before assembling the matrix and vectors for sources.
244  * It actually erases the matrix and vectors.
245  */
246  void start_source_assembly(unsigned int quantity_idx);
247 
248  /// Variant of the start_source_assembly() method for a set of quantities.
250  {
251  for (auto idx : q_idx_vec)
252  start_source_assembly(idx);
253  }
254 
255  /**
256  * Adds elements into matrix for computing mass.
257  * @param quantity_idx Index of quantity.
258  * @param region_idx Index of bulk region.
259  * @param dof_indices Dof indices to be added.
260  * @param values Values to be added.
261  */
262  void add_mass_matrix_values(unsigned int quantity_idx,
263  unsigned int region_idx,
264  const std::vector<LongIdx> &dof_indices,
265  const std::vector<double> &values);
266 
267  /**
268  * Adds elements into matrix for computing (outgoing) flux.
269  * @param quantity_idx Index of quantity.
270  * @param side Element side iterator.
271  * @param dof_indices Dof indices (to the solution vector) to be added.
272  * @param values Values to be added.
273  *
274  * TODO: Instead of SideIter and dof_indices, use DHCellSide,
275  * when it is available in all equations.
276  */
277  void add_flux_matrix_values(unsigned int quantity_idx,
278  SideIter side,
279  const std::vector<LongIdx> &dof_indices,
280  const std::vector<double> &values);
281 
282  /**
283  * Adds element into vector for computing mass.
284  * @param quantity_idx Index of quantity.
285  * @param region_idx Index of bulk region.
286  * @param value Value to be added.
287  */
288  void add_mass_vec_value(unsigned int quantity_idx,
289  unsigned int region_idx,
290  double value);
291 
292  /**
293  * Adds elements into matrix and vector for computing source.
294  * @param quantity_idx Index of quantity.
295  * @param region_idx Index of bulk region.
296  * @param dof_indices Local dof indices to be added.
297  * @param mat_values Values to be added into matrix.
298  * @param vec_values Values to be added into vector.
299  */
300  void add_source_values(unsigned int quantity_idx,
301  unsigned int region_idx,
302  const std::vector<LongIdx> &loc_dof_indices,
303  const std::vector<double> &mat_values,
304  const std::vector<double> &vec_values);
305 
306  /**
307  * Adds element into vector for computing (outgoing) flux.
308  * @param quantity_idx Index of quantity.
309  * @param side Element side iterator.
310  * @param value Value to be added.
311  *
312  */
313  void add_flux_vec_value(unsigned int quantity_idx,
314  SideIter side,
315  double value);
316 
317  /// This method must be called after assembling the matrix for computing mass.
318  void finish_mass_assembly(unsigned int quantity_idx);
319 
320  /// Variant of the finish_mass_assembly() method for a set of quantities.
322  {
323  for (auto idx : q_idx_vec)
324  finish_mass_assembly(idx);
325  }
326 
327  /// This method must be called after assembling the matrix and vector for computing flux.
328  void finish_flux_assembly(unsigned int quantity_idx);
329 
330  /// Variant of the finish_flux_assembly() method for a set of quantities.
332  {
333  for (auto idx : q_idx_vec)
334  finish_flux_assembly(idx);
335  }
336 
337  /// This method must be called after assembling the matrix and vectors for computing source.
338  void finish_source_assembly(unsigned int quantity_idx);
339 
340  /// Variant of the finish_source_assembly() method for a set of quantities.
342  {
343  for (auto idx : q_idx_vec)
344  finish_source_assembly(idx);
345  }
346 
347  /**
348  * Updates cumulative quantities for balance.
349  * This method can be called in substeps even if no output is generated.
350  * It calculates the sum of source and sum of (incoming) flux over time interval.
351  * @param quantity_idx Index of quantity.
352  * @param solution Solution vector.
353  */
354  void calculate_cumulative(unsigned int quantity_idx,
355  const Vec &solution);
356 
357  /**
358  * Calculates actual mass and save it to given vector.
359  * @param quantity_idx Index of quantity.
360  * @param solution Solution vector.
361  * @param output_array Vector of output masses per region.
362  */
363  void calculate_mass(unsigned int quantity_idx,
364  const Vec &solution,
365  vector<double> &output_array);
366 
367  /**
368  * Calculates actual mass, incoming flux and source.
369  * @param quantity_idx Index of quantity.
370  * @param solution Solution vector.
371  */
372  void calculate_instant(unsigned int quantity_idx,
373  const Vec &solution);
374 
375  /**
376  * Adds provided values to the cumulative sources.
377  * @param quantity_idx Index of quantity.
378  * @param sources Sources per region.
379  * @param dt Actual time step.
380  */
381  void add_cumulative_source(unsigned int quantity_idx, double source);
382 
383  /// Perform output to file for given time instant.
384  void output();
385 
386 private:
387  /// Size of column in output (used if delimiter is space)
388  static const unsigned int output_column_width = 20;
389  /**
390  * Postponed allocation and initialization to allow calling setters in arbitrary order.
391  * In particular we need to perform adding of output times after the output time marks are set.
392  * On the other hand we need to read the input before we make the allocation.
393  *
394  * The initialization is done during the first call of any start_*_assembly method.
395  */
396  void lazy_initialize();
397 
398  /// Perform output in old format (for compatibility)
399  void output_legacy(double time);
400 
401  /// Perform output in csv format
402  void output_csv(double time, char delimiter, const std::string& comment_string, unsigned int repeat = 0);
403 
404  /// Perform output in yaml format
405  void output_yaml(double time);
406 
407  /// Return part of output represented by zero values. Count of zero values is given by cnt parameter.
408  std::string csv_zero_vals(unsigned int cnt, char delimiter);
409 
410  /// Print output header
411  void format_csv_output_header(char delimiter, const std::string& comment_string);
412 
413  /// Format string value of csv output. Wrap string into quotes and if delimiter is space, align text to column.
414  std::string format_csv_val(std::string val, char delimiter, bool initial = false);
415 
416  /// Format double value of csv output. If delimiter is space, align text to column.
417  std::string format_csv_val(double val, char delimiter, bool initial = false);
418 
419  /** Computes unique id of local boundary edge from local element index and element side index
420  *
421  * @param side is a side of locally owned element
422  */
424  { return 4*side->elem_idx() + side->side_idx();} // 4 is maximum of sides per element
425 
426  //**********************************************
427 
428  static bool do_yaml_output_;
429 
430  /// Allocation parameters. Set by the allocate method used in the lazy_initialize.
431  unsigned int n_loc_dofs_;
433 
434 
435  /// Save prefix passed in in constructor.
436  std::string file_prefix_;
437 
438  /// File path for output_ stream.
440 
441  /// Handle for file for output in given OutputFormat of balance and total fluxes over individual regions and region sets.
442  ofstream output_;
443 
444  // The same as the previous case, but for output in YAML format.
445  ofstream output_yaml_;
446 
447  /// Format of output file.
449 
450  /// Names of conserved quantities.
452 
453  const Mesh *mesh_;
454 
455  /// Units of conserved quantities.
457 
458 
459  /// Matrices for calculation of mass (n_dofs x n_bulk_regions).
461 
462  /// Matrices for calculation of flux (n_boundary_edges x n_dofs).
464 
465  /// Matrices for calculation of source (n_dofs x n_bulk_regions).
467 
468  /// Matrices for calculation of signed source (n_dofs x n_bulk_regions).
470 
471  /// Vectors for calculation of flux (n_boundary_edges).
473 
474  /// Vectors for calculation of mass (n_bulk_regions).
476 
477  /** Maps unique identifier of (local bulk element idx, side idx) returned by @p get_boundary_edge_uid(side)
478  * to local boundary edge.
479  * Example usage:
480  * be_id = be_id_map_[get_boundary_edge_uid(side)]
481  */
482  std::unordered_map<LongIdx, unsigned int> be_id_map_;
483 
484  /// Maps local boundary edge to its region boundary index.
486 
487  /// Offset for local part of vector of boundary edges.
489 
490 
491  // Vectors storing mass and balances of fluxes and volumes.
492  // substance, phase, region
499 
500  // Sums of the above vectors over phases and regions
509 
510  // time integrated quantities
515 
516  /// time of last calculated balance
517  double last_time_;
518 
519  /// TimeMark type for balance output of particular equation.
521 
522  /// TimeMark type for output of particular equation.
524 
525  /// true before calculating the mass at initial time, otherwise false
526  bool initial_;
527 
528  /// if true then cumulative balance is computed
530 
531  /// true before allocating necessary internal structures (Petsc matrices etc.)
533 
534  /// If the balance is on. Balance is off in the case of no balance output time marks.
536 
537  /// Add output time marks to balance output time marks.
539 
540 
541  /// MPI rank.
542  int rank_;
543 
544  /// hold count of line printed into output_
545  unsigned int output_line_counter_;
546 
547  /// marks whether YAML output has printed header
549 
550  /// Record for current balance
552 
554 
555 
556 };
557 
558 
559 
560 
561 
562 #endif // BALANCE_HH_
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
UnitSI units_
Units of conserved quantities.
Definition: balance.hh:456
std::vector< double > integrated_sources_
Definition: balance.hh:511
std::vector< double > sum_fluxes_out_
Definition: balance.hh:503
LongIdx get_boundary_edge_uid(SideIter side)
Definition: balance.hh:423
TimeMark::Type output_mark_type_
TimeMark type for output of particular equation.
Definition: balance.hh:523
TimeMark::Type balance_output_type_
TimeMark type for balance output of particular equation.
Definition: balance.hh:520
unsigned int side_idx() const
Definition: side_impl.hh:82
bool initial_
true before calculating the mass at initial time, otherwise false
Definition: balance.hh:526
Abstract linear system class.
Definition: balance.hh:37
void start_mass_assembly(std::vector< unsigned int > q_idx_vec)
Variant of the start_mass_assembly() method for a set of quantities.
Definition: balance.hh:223
std::vector< std::vector< double > > sources_in_
Definition: balance.hh:497
void finish_mass_assembly(std::vector< unsigned int > q_idx_vec)
Variant of the finish_mass_assembly() method for a set of quantities.
Definition: balance.hh:321
std::vector< std::vector< double > > fluxes_in_
Definition: balance.hh:494
std::vector< double > sum_fluxes_in_
Definition: balance.hh:502
std::vector< std::vector< double > > fluxes_out_
Definition: balance.hh:495
const TimeGovernor * time_
Definition: balance.hh:553
Mat * region_source_rhs_
Matrices for calculation of signed source (n_dofs x n_bulk_regions).
Definition: balance.hh:469
Definition: mesh.h:76
Input::Record input_record_
Record for current balance.
Definition: balance.hh:551
ofstream output_
Handle for file for output in given OutputFormat of balance and total fluxes over individual regions ...
Definition: balance.hh:442
bool cumulative() const
Getter for cumulative_.
Definition: balance.hh:187
bool allocation_done_
true before allocating necessary internal structures (Petsc matrices etc.)
Definition: balance.hh:532
Basic time management functionality for unsteady (and steady) solvers (class Equation).
std::vector< double > sum_fluxes_
Definition: balance.hh:501
string name_
Name of quantity (for output).
Definition: balance.hh:133
bool balance_on_
If the balance is on. Balance is off in the case of no balance output time marks. ...
Definition: balance.hh:535
static constexpr bool value
Definition: json.hpp:87
std::vector< double > increment_sources_
Definition: balance.hh:514
const unsigned int index_
Internal index within list of quantities.
Definition: balance.hh:136
Vec * be_flux_vec_
Vectors for calculation of flux (n_boundary_edges).
Definition: balance.hh:472
std::vector< double > integrated_fluxes_
Definition: balance.hh:512
std::vector< Quantity > quantities_
Names of conserved quantities.
Definition: balance.hh:451
std::vector< std::vector< double > > sources_out_
Definition: balance.hh:498
Mat * be_flux_matrix_
Matrices for calculation of flux (n_boundary_edges x n_dofs).
Definition: balance.hh:463
double last_time_
time of last calculated balance
Definition: balance.hh:517
std::vector< std::vector< double > > fluxes_
Definition: balance.hh:493
void finish_flux_assembly(std::vector< unsigned int > q_idx_vec)
Variant of the finish_flux_assembly() method for a set of quantities.
Definition: balance.hh:331
int rank_
MPI rank.
Definition: balance.hh:542
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
void start_flux_assembly(std::vector< unsigned int > q_idx_vec)
Variant of the start_flux_assembly() method for a set of quantities.
Definition: balance.hh:236
Mat * region_mass_matrix_
Matrices for calculation of mass (n_dofs x n_bulk_regions).
Definition: balance.hh:460
std::vector< double > sum_sources_out_
Definition: balance.hh:507
unsigned int max_dofs_per_boundary_
Definition: balance.hh:432
bool cumulative_
if true then cumulative balance is computed
Definition: balance.hh:529
Mat * region_source_matrix_
Matrices for calculation of source (n_dofs x n_bulk_regions).
Definition: balance.hh:466
std::vector< double > increment_fluxes_
Definition: balance.hh:513
void finish_source_assembly(std::vector< unsigned int > q_idx_vec)
Variant of the finish_source_assembly() method for a set of quantities.
Definition: balance.hh:341
static bool do_yaml_output_
Definition: balance.hh:428
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
const Mesh * mesh_
Definition: balance.hh:453
std::vector< double > sum_sources_
Definition: balance.hh:505
std::vector< double > initial_mass_
Definition: balance.hh:508
Quantity(const unsigned int index, const string &name)
Definition: balance.hh:127
std::vector< unsigned int > be_regions_
Maps local boundary edge to its region boundary index.
Definition: balance.hh:485
ofstream output_yaml_
Definition: balance.hh:445
OutputFormat output_format_
Format of output file.
Definition: balance.hh:448
std::unordered_map< LongIdx, unsigned int > be_id_map_
Definition: balance.hh:482
int be_offset_
Offset for local part of vector of boundary edges.
Definition: balance.hh:488
std::vector< std::vector< double > > masses_
Definition: balance.hh:496
void start_source_assembly(std::vector< unsigned int > q_idx_vec)
Variant of the start_source_assembly() method for a set of quantities.
Definition: balance.hh:249
unsigned int elem_idx() const
Definition: side_impl.hh:87
Record type proxy class.
Definition: type_record.hh:182
std::vector< double > sum_masses_
Definition: balance.hh:504
Vec * region_mass_vec_
Vectors for calculation of mass (n_bulk_regions).
Definition: balance.hh:475
unsigned int output_line_counter_
hold count of line printed into output_
Definition: balance.hh:545
bool add_output_times_
Add output time marks to balance output time marks.
Definition: balance.hh:538
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:431
OutputFormat
Definition: balance.hh:143
Template for classes storing finite set of named values.
FilePath balance_output_file_
File path for output_ stream.
Definition: balance.hh:439
std::string file_prefix_
Save prefix passed in in constructor.
Definition: balance.hh:436
bool output_yaml_header_
marks whether YAML output has printed header
Definition: balance.hh:548
std::vector< double > sum_sources_in_
Definition: balance.hh:506