Flow123d  jenkins-Flow123d-windows32-release-multijob-51
mass_balance.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  *
17  * You should have received a copy of the GNU General Public License along with this program; if not,
18  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
19  *
20  *
21  * $Id$
22  * $Revision$
23  * $LastChangedBy$
24  * $LastChangedDate$
25  *
26  * @file
27  * @ingroup transport
28  * @brief Mass balance
29  *
30  *
31  */
32 
33 #include <iostream>
34 #include <iomanip>
35 
36 #include "system/system.hh"
37 #include "system/sys_profiler.hh"
38 #include "system/xio.h"
39 
40 #include <petscmat.h>
41 #include "mesh/mesh.h"
42 
44 
45 using namespace Input::Type;
46 
48  = Record("MassBalance", "Balance of mass, boundary fluxes and sources for transport of substances.")
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("mass_balance.txt"), "File name for output of mass balance.")
52 ;
53 
54 
55 
57  : equation_(eq), initial_time(0), last_time(-1), initial(true)
58 {
59  balance_output_file = xfopen( in_rec.val<FilePath>("file"), "wt");
60 
61  cumulative = in_rec.val<bool>("cumulative");
62 
63  const int n_bcd_reg_ = equation_->region_db()->boundary_size();
64  const int n_blk_reg_ = equation_->region_db()->bulk_size();
65 
66  bcd_balance.resize(eq->n_substances(), vector<double>(n_bcd_reg_, 0));
67  bcd_plus_balance.resize(eq->n_substances(), vector<double>(n_bcd_reg_, 0));
68  bcd_minus_balance.resize(eq->n_substances(), vector<double>(n_bcd_reg_, 0));
69  mass.resize(eq->n_substances(), vector<double>(n_blk_reg_, 0));
70  src_balance.resize(eq->n_substances(), vector<double>(n_blk_reg_, 0));
71 
72  bcd_total_balance.resize(eq->n_substances(), 0.);
73  bcd_total_inflow.resize(eq->n_substances(), 0.);
74  bcd_total_outflow.resize(eq->n_substances(), 0.);
75  mass_total.resize(eq->n_substances(), 0.);
76  src_total_balance.resize(eq->n_substances(), 0.);
77 
78  initial_mass.resize(eq->n_substances(), 0.);
79  integrated_sources.resize(eq->n_substances(), 0.);
80  integrated_fluxes.resize(eq->n_substances(), 0.);
81 }
82 
84 {
86 }
87 
88 
89 void MassBalance::calculate(double time) {
90  // return if we already calculated at the given time
91  if (last_time == time) return;
92 
93  const int n_bcd_reg_ = equation_->region_db()->boundary_size();
94  const int n_blk_reg_ = equation_->region_db()->bulk_size();
95  const int n_subst = equation_->n_substances();
96 
97  for (int i=0; i<n_subst; i++)
98  {
99  for (int j=0; j<n_bcd_reg_; j++)
100  {
101  bcd_balance[i][j] = 0;
102  bcd_plus_balance[i][j] = 0;
103  bcd_minus_balance[i][j] = 0;
104  }
105  for (int j=0; j<n_blk_reg_; j++)
106  {
107  mass[i][j] = 0;
108  src_balance[i][j] = 0;
109  }
110  bcd_total_balance[i] = 0;
111  bcd_total_outflow[i] = 0;
112  bcd_total_inflow[i] = 0;
113  mass_total[i] = 0;
114  src_total_balance[i] = 0;
115  }
116 
117  // compute fluxes, mass and volume sources
120 
121 
122  // gather results from processes and sum them up
123  int buf_size = n_subst*(3*n_bcd_reg_ + 2*n_blk_reg_);
124  double sendbuffer[buf_size], recvbuffer[buf_size];
125  for (int i=0; i<n_subst; i++)
126  {
127  for (int j=0; j<n_bcd_reg_; j++)
128  {
129  sendbuffer[i*3*n_bcd_reg_+ j] = bcd_balance[i][j];
130  sendbuffer[i*3*n_bcd_reg_+ n_bcd_reg_+j] = bcd_plus_balance[i][j];
131  sendbuffer[i*3*n_bcd_reg_+2*n_bcd_reg_+j] = bcd_minus_balance[i][j];
132  }
133  for (int j=0; j<n_blk_reg_; j++)
134  {
135  sendbuffer[n_subst*3*n_bcd_reg_+i*2*n_blk_reg_ +j] = mass[i][j];
136  sendbuffer[n_subst*3*n_bcd_reg_+i*2*n_blk_reg_+n_blk_reg_+j] = src_balance[i][j];
137  }
138  }
139  MPI_Reduce(&sendbuffer,recvbuffer,buf_size,MPI_DOUBLE,MPI_SUM,0,PETSC_COMM_WORLD);
140 
141  int rank;
142  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
143 
144  // for other than 0th process update last_time and finish,
145  // on process #0 sum balances over all regions and calculate
146  // cumulative balance over time.
147  if (rank != 0)
148  {
149  last_time = time;
150  return;
151  }
152 
153 
154  // update balance vectors
155  for (int i=0; i<n_subst; i++)
156  {
157  for (int j=0; j<n_bcd_reg_; j++)
158  {
159  bcd_balance[i][j] = recvbuffer[i*3*n_bcd_reg_+ j];
160  bcd_plus_balance[i][j] = recvbuffer[i*3*n_bcd_reg_+ n_bcd_reg_+j];
161  bcd_minus_balance[i][j] = recvbuffer[i*3*n_bcd_reg_+2*n_bcd_reg_+j];
162  }
163  for (int j=0; j<n_blk_reg_; j++)
164  {
165  mass[i][j] = recvbuffer[n_subst*3*n_bcd_reg_+i*2*n_blk_reg_ +j];
166  src_balance[i][j] = recvbuffer[n_subst*3*n_bcd_reg_+i*2*n_blk_reg_+n_blk_reg_+j];
167  }
168  }
169 
170 
171  // sum all boundary fluxes
172  const RegionSet & b_set = equation_->region_db()->get_region_set("BOUNDARY");
173  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg) {
174  for (int sbi=0; sbi<n_subst; sbi++) {
175  bcd_total_balance[sbi] += bcd_balance[sbi][reg->boundary_idx()];
176  bcd_total_outflow[sbi] += bcd_plus_balance[sbi][reg->boundary_idx()];
177  bcd_total_inflow[sbi] += bcd_minus_balance[sbi][reg->boundary_idx()];
178  }
179  }
180 
181  // sum all volume sources
182  const RegionSet & bulk_set = equation_->region_db()->get_region_set("BULK");
183  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
184  {
185  for (int sbi=0; sbi<n_subst; sbi++)
186  {
187  mass_total[sbi] += mass[sbi][reg->bulk_idx()];
188  src_total_balance[sbi] += src_balance[sbi][reg->bulk_idx()];
189  }
190  }
191 
192  if (!cumulative) return;
193 
194  // cumulative balance over time
195 
196  // quantities need for the balance over time interval
197  static vector<double> last_sources(n_subst, 0.),
198  last_fluxes(n_subst, 0.);
199 
200  // save initial time and mass
201  if (initial)
202  {
203  initial_time = time;
205  for (int i=0; i<n_subst; i++)
206  initial_mass[i] = mass_total[i];
207  initial = false;
208  }
209 
210 
211  // sum sources and fluxes according to the time integration scheme
212  // TODO: Think if we really need TimeIntegrationScheme or the cummulative
213  // quantities can be calculated in the same way for both explicit and implicit
214  // methods.
215  switch (equation_->time_scheme())
216  {
218 // for (int i=0; i<n_subst; i++)
219 // {
220 // integrated_sources[i] += last_sources[i]*(time-last_time);
221 // integrated_fluxes[i] += last_fluxes[i]*(time-last_time);
222 // }
223 // break;
225  for (int i=0; i<n_subst; i++)
226  {
229  }
230  break;
232  for (int i=0; i<n_subst; i++)
233  {
234  integrated_sources[i] += (last_sources[i]+src_total_balance[i])*0.5*(time-last_time);
235  integrated_fluxes[i] += (last_fluxes[i]+bcd_total_balance[i])*0.5*(time-last_time);
236  }
237  break;
238  default:
239  break;
240  }
241 
242  last_time = time;
243  for (int i=0; i<n_subst; i++)
244  {
245  last_sources[i] = src_total_balance[i];
246  last_fluxes[i] = bcd_total_balance[i];
247  }
248 }
249 
250 
251 void MassBalance::output(double time)
252 {
253  // calculate balances for the given time
254  if (last_time != time) calculate(time);
255 
256  int rank;
257  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
258 
259  // write output only on process #0
260  if (rank != 0) return;
261 
262  const int n_subst = equation_->n_substances();
263 
264  // print the head of mass balance file
265  unsigned int c = 6; //column number without label
266  unsigned int w = 14; //column width
267  unsigned int wl = 2*(w-5)+7; //label column width
268  stringstream s; //helpful stringstream
269  string bc_head_format = "# %-*s%-*s%-*s%-*s%-*s%-*s\n",
270  bc_format = "%*s%-*d%-*s%-*s%-*g%-*g%-*g\n",
271  bc_total_format = "# %-*s%-*s%-*g%-*g%-*g\n";
272  s << setw((w*c+wl-14)/2) << setfill('-') << "--"; //drawing half line
273  fprintf(balance_output_file,"# %s MASS BALANCE %s\n",s.str().c_str(), s.str().c_str());
274  fprintf(balance_output_file,"# Time: %f\n\n\n",time);
275 
276  // header for table of boundary fluxes
277  fprintf(balance_output_file,"# Mass flux through boundary [M/T]:\n");
278  fprintf(balance_output_file,bc_head_format.c_str(),w,"[boundary_id]",wl,"[label]",
279  w,"[substance]",w,"[total flux]",w,"[outward flux]",w,"[inward flux]");
280  s.clear();
281  s.str(std::string());
282  s << setw(w*c+wl) << setfill('-') << "-";
283  fprintf(balance_output_file,"# %s\n",s.str().c_str()); //drawing long line
284 
285  // print mass fluxes over boundaries
286  const RegionSet & b_set = equation_->region_db()->get_region_set("BOUNDARY");
287  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg) {
288  for (int sbi=0; sbi<n_subst; sbi++) {
289  fprintf(balance_output_file, bc_format.c_str(),2,"",w,reg->id(),wl,reg->label().c_str(),
290  w, equation_->substance_names()[sbi].c_str(),w, bcd_balance[sbi][reg->boundary_idx()],
291  w, bcd_plus_balance[sbi][reg->boundary_idx()],
292  w, bcd_minus_balance[sbi][reg->boundary_idx()]);
293  }
294  }
295  // total boundary balance
296  fprintf(balance_output_file,"# %s\n",s.str().c_str()); // drawing long line
297  for (int sbi=0; sbi<n_subst; sbi++)
298  fprintf(balance_output_file, bc_total_format.c_str(),w+wl,"Total mass flux of substance [M/T]",
299  w,equation_->substance_names()[sbi].c_str(),w,bcd_total_balance[sbi], w, bcd_total_outflow[sbi], w, bcd_total_inflow[sbi]);
300  fprintf(balance_output_file, "\n\n");
301 
302 
303  // header for table of volume sources and masses
304  string src_head_format = "# %-*s%-*s%-*s%-*s%-*s\n",
305  src_format = "%*s%-*d%-*s%-*s%-*g%-*g\n",
306  src_total_format = "# %-*s%-*s%-*g%-*g\n";
307  fprintf(balance_output_file,"# Mass [M] and sources [M/T] on regions:\n"); //head
308  fprintf(balance_output_file,src_head_format.c_str(),w,"[region_id]",wl,"[label]",
309  w,"[substance]",w,"[total_mass]",w,"[total_source]");
310  fprintf(balance_output_file,"# %s\n",s.str().c_str()); //long line
311 
312  // print balance of volume sources and masses
313  const RegionSet & bulk_set = equation_->region_db()->get_region_set("BULK");
314  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
315  {
316  for (int sbi=0; sbi<n_subst; sbi++)
317  {
318  fprintf(balance_output_file, src_format.c_str(), 2,"", w, reg->id(), wl,
319  reg->label().c_str(), w, equation_->substance_names()[sbi].c_str(),
320  w,mass[sbi][reg->bulk_idx()],
321  w,src_balance[sbi][reg->bulk_idx()]);
322  }
323  }
324  // total sources balance
325  fprintf(balance_output_file,"# %s\n",s.str().c_str()); //drawing long line
326  for (int sbi=0; sbi<n_subst; sbi++)
327  fprintf(balance_output_file, src_total_format.c_str(),w+wl,"Total mass [M] and sources [M/T]",
328  w,equation_->substance_names()[sbi].c_str(),
329  w,mass_total[sbi],
330  w,src_total_balance[sbi]);
331 
332  if (cumulative)
333  {
334  // Print cumulative sources
335  fprintf(balance_output_file, "\n\n# Cumulative mass balance on time interval [%-g,%-g]\n"
336  "# Initial mass [M] + sources integrated over time [M] - flux integrated over time [M] = current mass [M]\n"
337  "# %-*s%-*s%-*s%-*s%-*s%-*s%-*s%-*s\n",
338  initial_time, time,
339  w,"[substance]",
340  w,"[A=init. mass]",
341  w,"[B=source]",
342  w,"[C=flux]",
343  w,"[A+B-C]",
344  w,"[D=curr. mass]",
345  w,"[A+B-C-D=err.]",
346  w,"[rel. error]");
347 
348  for (int i=0; i<n_subst; i++)
349  {
350  double denominator = max(fabs(initial_mass[i]+integrated_sources[i]-integrated_fluxes[i]),fabs(mass_total[i]));
351  fprintf(balance_output_file, " %-*s%-*g%-*g%-*g%-*g%-*g%-*g%-*g\n",
352  w,equation_->substance_names()[i].c_str(),
353  w,initial_mass[i],
354  w,integrated_sources[i],
355  w,integrated_fluxes[i],
356  w,initial_mass[i]+integrated_sources[i]-integrated_fluxes[i],
357  w,mass_total[i],
358  w,initial_mass[i]+integrated_sources[i]-integrated_fluxes[i]-mass_total[i],
359  w,fabs(initial_mass[i]+integrated_sources[i]-integrated_fluxes[i]-mass_total[i])/(denominator==0?1:denominator));
360  }
361  }
362 
363  fprintf(balance_output_file, "\n\n");
364 }
365 
366 
void calculate(double time)
Definition: mass_balance.cc:89
vector< double > src_total_balance
static Input::Type::Record input_type
unsigned int bulk_size() const
Definition: region.cc:252
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:39
Class for declaration of the input of type Bool.
Definition: type_base.hh:321
int xfclose(FILE *stream)
FCLOSE WITH ERROR HANDLING.
Definition: xio.cc:309
virtual void calc_elem_sources(vector< vector< double > > &mass, vector< vector< double > > &src_balance)=0
???
#define MPI_SUM
Definition: mpi.h:196
RegionSet get_region_set(const string &set_name) const
Definition: region.cc:361
vector< double > bcd_total_inflow
double initial_time
initial time
double last_time
time of last calculated balance
I/O functions with filename storing, able to track current line in opened file. All standard stdio fu...
#define MPI_Reduce(sendbuf, recvbuf, count, datatype, op, root, comm)
Definition: mpi.h:608
vector< vector< double > > bcd_plus_balance
FILE * balance_output_file
Handle for output file for output of balance and total fluxes over individual regions and region sets...
EquationForMassBalance * equation_
Pointer to the class which implements calculation of mass, sources and fluxes.
bool cumulative
if true then cumulative balance is computed
MassBalance(EquationForMassBalance *eq, const Input::Record &in_rec)
Definition: mass_balance.cc:56
vector< double > initial_mass
virtual unsigned int n_substances()=0
Returns number of trnasported substances.
vector< double > integrated_sources
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
virtual vector< string > & substance_names()=0
Returns reference to the vector of substnace names.
const Ret val(const string &key) const
vector< vector< double > > bcd_balance
void output(double time)
Write computed fields to file.
virtual TimeIntegrationScheme time_scheme()=0
Returns the time integration scheme of the equation.
virtual void calc_fluxes(vector< vector< double > > &bcd_balance, vector< vector< double > > &bcd_plus_balance, vector< vector< double > > &bcd_minus_balance)=0
#define MPI_DOUBLE
Definition: mpi.h:156
vector< vector< double > > bcd_minus_balance
#define MPI_Comm_rank
Definition: mpi.h:236
Dedicated class for storing path to input and output files.
Definition: file_path.hh:32
vector< vector< double > > src_balance
vector< double > bcd_total_balance
unsigned int boundary_size() const
Definition: region.cc:245
static FileName output()
Definition: type_base.hh:449
bool initial
true before calculating the mass at initial time, otherwise false
vector< double > bcd_total_outflow
vector< double > mass_total
Record type proxy class.
Definition: type_record.hh:161
virtual const RegionDB * region_db()=0
Returns the region database.
vector< vector< double > > mass
vector< double > integrated_fluxes
FILE * xfopen(const std::string &fname, const char *mode)
Definition: xio.cc:246
Record & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:386