Flow123d
darcy_flow_mh_output.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  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id: darcy_flow_mh.hh 877 2011-02-04 13:13:25Z jakub.sistek $
21  * $Revision: 877 $
22  * $LastChangedBy: jakub.sistek $
23  * $LastChangedDate: 2011-02-04 14:13:25 +0100 (Fri, 04 Feb 2011) $
24  *
25  * @file
26  * @brief Output class for darcy_flow_mh model.
27  * @ingroup flow
28  *
29  * @author Jan Brezina
30  *
31  */
32 
33 
34 #include <vector>
35 #include <iostream>
36 #include <sstream>
37 #include <string>
38 
39 #include <system/global_defs.h>
40 
41 #include "flow/mh_fe_values.hh"
42 #include "flow/darcy_flow_mh.hh"
44 #include "system/system.hh"
45 #include "system/sys_profiler.hh"
46 #include "system/xio.h"
47 
48 #include "fem/dofhandler.hh"
49 #include "fields/field_fe.hh"
50 
51 #include "io/output.h"
52 #include "mesh/partitioning.hh"
53 
54 
55 
56 namespace it = Input::Type;
57 
59  = DarcyFlowMH::EqData().make_output_field_selection("DarcyMHOutput_Selection", "Selection of fields available for output.")
60  .copy_values(OutputFields().make_output_field_selection("").close())
61  .close();
62 
64  = it::Record("DarcyMHOutput", "Parameters of MH output.")
66  "Parameters of output stream.")
67  .declare_key("output_fields", it::Array(OutputFields::output_selection),
68  it::Default::obligatory(), "List of fields to write to output file.")
69  .declare_key("balance_output", it::FileName::output(), it::Default("water_balance.txt"),
70  "Output file for water balance table.")
71  .declare_key("compute_errors", it::Bool(), it::Default("false"),
72  "SPECIAL PURPOSE. Computing errors pro non-compatible coupling.")
74  "Output file with raw data form MH module.");
75 
76 
78 {
79 // *this += darcy_flow->get_data();
80  *this += field_ele_pressure.name("pressure_p0").units("L");
81  *this += field_node_pressure.name("pressure_p1").units("L");
82  *this += field_ele_piezo_head.name("piezo_head_p0").units("L");
83  *this += field_ele_flux.name("velocity_p0").units("L/T");
84  *this += subdomain.name("subdomain").units("0");
85 
86  fields_for_output += *this;
87 
88  *this += pressure_diff.name("pressure_diff").units("0");
89  *this += velocity_diff.name("velocity_diff").units("0");
90  *this += div_diff.name("div_diff").units("0");
91 
92 }
93 
94 
96 : darcy_flow(flow),
97  mesh_(&darcy_flow->mesh()),
98  in_rec_(in_rec),
99  balance_output_file(NULL),
100  raw_output_file(NULL)
101 {
102 
103  int ierr, rank;
104  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
105  ASSERT(ierr == 0, "Error in MPI test of rank.");
106 
107 
108  // we need to add data from the flow equation at this point, not in constructor of OutputFields
111 
112  //VecCreateSeqWithArray(PETSC_COMM_SELF, 1, dh->n_global_dofs(), corner_pressure, &vec_corner_pressure);
113 
114  // create shared pointer to a FieldElementwise and push this Field to output_field on all regions
115  ele_pressure.resize(mesh_->n_elements());
116  auto ele_pressure_ptr=make_shared< FieldElementwise<3, FieldValue<3>::Scalar> >(ele_pressure, 1);
118 
119  dh = new DOFHandlerMultiDim(*mesh_);
121  corner_pressure.resize(dh->n_global_dofs());
122  VecCreateSeqWithArray(PETSC_COMM_SELF, 1, dh->n_global_dofs(), &(corner_pressure[0]), &vec_corner_pressure);
123 
124  auto corner_ptr = make_shared< FieldFE<3, FieldValue<3>::Scalar> >();
125  corner_ptr->set_fe_data(dh, &map1, &map2, &map3, &vec_corner_pressure);
126 
129 
130  ele_piezo_head.resize(mesh_->n_elements());
132  make_shared< FieldElementwise<3, FieldValue<3>::Scalar> >(ele_piezo_head, 1));
133 
134  ele_flux.resize(3*mesh_->n_elements());
136  make_shared< FieldElementwise<3, FieldValue<3>::VectorFixed> >(ele_flux, 3));
137 
138  auto &vec_int_sub = mesh_->get_part()->seq_output_partition();
139  subdomains.resize(vec_int_sub.size());
140  for(unsigned int i=0; i<subdomains.size();i++)
141  subdomains[i]=vec_int_sub[i];
143  make_shared< FieldElementwise<3, FieldValue<3>::Integer> >(subdomains, 1));
144 
145  output_fields.set_limit_side(LimitSide::right);
146 
147 
151  //DBGMSG("output stream: %p\n", output_stream);
152 
153 
154  if (rank == 0) {
155  // temporary solution for balance output
156  balance_output_file = xfopen( in_rec.val<FilePath>("balance_output"), "wt");
157 
158  // optionally open raw output file
159  FilePath raw_output_file_path;
160  if (in_rec.opt_val("raw_flow_output", raw_output_file_path)) {
161  xprintf(Msg, "Opening raw output: %s\n", string(raw_output_file_path).c_str() );
162  raw_output_file = xfopen(raw_output_file_path, "wt");
163  }
164 
165  }
166 }
167 
168 
169 
171  //if (output_writer != NULL) delete output_writer;
172 
175  //delete [] ele_pressure;
176  //delete [] node_pressure;
177  //delete [] ele_flux;
178  VecDestroy(&vec_corner_pressure);
179  //delete [] corner_pressure;
180  //delete [] ele_piezo_head;
181  delete output_stream;
182 
183  delete dh;
184 };
185 
186 
187 
188 
189 
190 //=============================================================================
191 // CONVERT SOLUTION, CALCULATE BALANCES, ETC...
192 //=============================================================================
193 
194 
196 {
197  START_TIMER("Darcy output");
198 
199 // std::string eleVectorName = "velocity_elements";
200 // std::string eleVectorUnit = "L/T";
201 
202  //cout << "DMHO_output: rank: " << rank << "\t output_writer: " << output_writer << endl;
203 
204  // skip initial output for steady solver
205  //darcy_flow->time().view("Darcy output output");
206 
207  //if (darcy_flow->time().is_steady() && darcy_flow->time().tlevel() ==0) return;
208 
209  //DBGVAR( darcy_flow->time().is_current( TimeGovernor::marks().type_output() ) );
210  if (darcy_flow->time().is_current( TimeGovernor::marks().type_output() )) {
211 
214 
216 
217  water_balance();
218 
219  if (in_rec_.val<bool>("compute_errors")) compute_l2_difference();
220 
221  double time = darcy_flow->solved_time();
222 
223 
227 
229 
230  }
231 
232 }
233 
234 
235 //=============================================================================
236 // FILL TH "SCALAR" FIELD FOR ALL ELEMENTS IN THE MESH
237 //=============================================================================
238 
240  unsigned int sol_size;
241  double *sol;
242 
243  darcy_flow->get_solution_vector(sol, sol_size);
244  unsigned int soi = mesh_->n_sides();
245  unsigned int i = 0;
246  FOR_ELEMENTS(mesh_,ele) {
247  ele_pressure[i] = sol[ soi];
248  ele_piezo_head[i] = sol[soi ] + ele->centre()[Mesh::z_coord];
249  i++; soi++;
250  }
251 }
252 
253 
254 
255 /****
256  * compute Darcian velocity in centre of elements
257  *
258  */
261  MHFEValues fe_values;
262 
263  int i_side=0;
264  FOR_ELEMENTS(mesh_, ele) {
265  arma::vec3 flux_in_centre;
266  flux_in_centre.zeros();
267 
268  fe_values.update(ele,
272 
273  for (unsigned int li = 0; li < ele->n_sides(); li++) {
274  flux_in_centre += dh.side_flux( *(ele->side( li ) ) )
275  * fe_values.RT0_value( ele, ele->centre(), li )
276  / darcy_flow->data_.cross_section.value(ele->centre(), ele->element_accessor() );
277  }
278 
279  for(unsigned int j=0; j<3; j++)
280  ele_flux[3*i_side+j]=flux_in_centre[j];
281 
282  i_side++;
283  }
284 
285 }
286 
287 
289 {
290  unsigned int ndofs = max(dh->fe<1>()->n_dofs(), max(dh->fe<2>()->n_dofs(), dh->fe<3>()->n_dofs()));
291  unsigned int indices[ndofs];
292  int i_node;
293  FOR_ELEMENTS(mesh_, ele)
294  {
295  dh->get_dof_indices(ele, indices);
296  FOR_ELEMENT_NODES(ele, i_node)
297  {
298  corner_pressure[indices[i_node]] = node_scalar[mesh_->node_vector.index(ele->node[i_node])];
299  }
300  }
301 }
302 
303 
304 //=============================================================================
305 // pressure interpolation
306 //
307 // some sort of weighted average over elements and sides/edges of an node
308 //
309 // TODO:
310 // questions:
311 // - explain details of averaging and motivation for this type
312 // - edge scalars are stronger since thay are computed twice by each side
313 // - why division by (nod.aux-1)
314 // - ?implement without TED, TSD global arrays with single loop over elements, sides and one loop over nodes for normalization
315 //
316 //=============================================================================
317 
319 
320  vector<double> scalars(mesh_->n_nodes());
321 
322  double dist; //!< tmp variable for storing particular distance node --> element, node --> side*/
323 
324  /** Iterators */
325  const Node * node;
326  //ElementIter ele;
327  //struct Side* side;
328 
329  int n_nodes = mesh_->node_vector.size(); //!< number of nodes in the mesh */
330  int node_index = 0; //!< index of each node */
331 
332  int* sum_elements = new int [n_nodes]; //!< sum elements joined to node */
333  int* sum_sides = new int [n_nodes]; //!< sum sides joined to node */
334  double* sum_ele_dist = new double [n_nodes]; //!< sum distances to all joined elements */
335  double* sum_side_dist = new double [n_nodes]; //!< Sum distances to all joined sides */
336 
337  /** tmp variables, will be replaced by ini keys
338  * TODO include them into ini file*/
339  bool count_elements = true; //!< scalar is counted via elements*/
340  bool count_sides = true; //!< scalar is counted via sides */
341 
342 
344 
345  /** init arrays */
346  for (int i = 0; i < n_nodes; i++){
347  sum_elements[i] = 0;
348  sum_sides[i] = 0;
349  sum_ele_dist[i] = 0.0;
350  sum_side_dist[i] = 0.0;
351  scalars[i] = 0.0;
352  };
353 
354  /**first pass - calculate sums (weights)*/
355  if (count_elements){
356  FOR_ELEMENTS(mesh_, ele)
357  for (unsigned int li = 0; li < ele->n_nodes(); li++) {
358  node = ele->node[li]; //!< get Node pointer from element */
359  node_index = mesh_->node_vector.index(node); //!< get nod index from mesh */
360 
361  dist = sqrt(
362  ((node->getX() - ele->centre()[ 0 ])*(node->getX() - ele->centre()[ 0 ])) +
363  ((node->getY() - ele->centre()[ 1 ])*(node->getY() - ele->centre()[ 1 ])) +
364  ((node->getZ() - ele->centre()[ 2 ])*(node->getZ() - ele->centre()[ 2 ]))
365  );
366  sum_ele_dist[node_index] += dist;
367  sum_elements[node_index]++;
368  }
369  }
370  if (count_sides){
371  FOR_SIDES(mesh_, side) {
372  for (unsigned int li = 0; li < side->n_nodes(); li++) {
373  node = side->node(li);//!< get Node pointer from element */
374  node_index = mesh_->node_vector.index(node); //!< get nod index from mesh */
375  dist = sqrt(
376  ((node->getX() - side->centre()[ 0 ])*(node->getX() - side->centre()[ 0 ])) +
377  ((node->getY() - side->centre()[ 1 ])*(node->getY() - side->centre()[ 1 ])) +
378  ((node->getZ() - side->centre()[ 2 ])*(node->getZ() - side->centre()[ 2 ]))
379  );
380 
381  sum_side_dist[node_index] += dist;
382  sum_sides[node_index]++;
383  }
384  }
385  }
386 
387  /**second pass - calculate scalar */
388  if (count_elements){
389  FOR_ELEMENTS(mesh_, ele)
390  for (unsigned int li = 0; li < ele->n_nodes(); li++) {
391  node = ele->node[li];//!< get Node pointer from element */
392  node_index = mesh_->node_vector.index(node); //!< get nod index from mesh */
393 
394  /**TODO - calculate it again or store it in prior pass*/
395  dist = sqrt(
396  ((node->getX() - ele->centre()[ 0 ])*(node->getX() - ele->centre()[ 0 ])) +
397  ((node->getY() - ele->centre()[ 1 ])*(node->getY() - ele->centre()[ 1 ])) +
398  ((node->getZ() - ele->centre()[ 2 ])*(node->getZ() - ele->centre()[ 2 ]))
399  );
400  scalars[node_index] += ele_pressure[ele.index()] *
401  (1 - dist / (sum_ele_dist[node_index] + sum_side_dist[node_index])) /
402  (sum_elements[node_index] + sum_sides[node_index] - 1);
403  }
404  }
405  if (count_sides) {
406  FOR_SIDES(mesh_, side) {
407  for (unsigned int li = 0; li < side->n_nodes(); li++) {
408  node = side->node(li);//!< get Node pointer from element */
409  node_index = mesh_->node_vector.index(node); //!< get nod index from mesh */
410 
411  /**TODO - calculate it again or store it in prior pass*/
412  dist = sqrt(
413  ((node->getX() - side->centre()[ 0 ])*(node->getX() - side->centre()[ 0 ])) +
414  ((node->getY() - side->centre()[ 1 ])*(node->getY() - side->centre()[ 1 ])) +
415  ((node->getZ() - side->centre()[ 2 ])*(node->getZ() - side->centre()[ 2 ]))
416  );
417 
418 
419  scalars[node_index] += dh.side_scalar( *side ) *
420  (1 - dist / (sum_ele_dist[node_index] + sum_side_dist[node_index])) /
421  (sum_sides[node_index] + sum_elements[node_index] - 1);
422  }
423  }
424  }
425 
426 // xprintf(Msg, "**********************************************************************************************\n");
427 // for (int i =0; i<n_nodes; i++){
428 // xprintf(Msg, "make_node_scalar_param id: %i, %f\n", i, scalars[i]);
429 // };
430 // xprintf(Msg, "**********************************************************************************************\n");
431 
432  /** free memory */
433  delete [] sum_elements;
434  delete [] sum_sides;
435  delete [] sum_ele_dist;
436  delete [] sum_side_dist;
437 
438  make_corner_scalar(scalars);
439 }
440 
441 
442 /*
443 void DarcyFlowMHOutput::make_node_scalar() {
444  int li;
445  NodeIter nod;
446  struct Side *sde;
447  double dist;
448  int max_side_id = 0;
449 
450  double **TED;
451  double **TSD;
452 
453 
454  TED = (double **) xmalloc((mesh_->element.size() + 1) * sizeof (double *));
455 
456  FOR_SIDES(mesh_, sde)
457  if (max_side_id <= sde->id)
458  max_side_id = sde->id;
459 
460  TSD = (double **) xmalloc((max_side_id + 1) * sizeof (double *));
461 
462  FOR_ELEMENTS(mesh_, ele)
463  TED[ele.index()] = (double*) xmalloc(ele->n_nodes * sizeof (double));
464  FOR_SIDES(mesh_, sde)
465  TSD[sde->id] = (double*) xmalloc(sde->n_nodes * sizeof (double));
466 
467  FOR_NODES(mesh_, nod ) {
468  nod->scalar = 0.0;
469  nod->faux = 0.0;
470  nod->aux = 0;
471  }
472  FOR_ELEMENTS(mesh_, ele)
473  for (li = 0; li < ele->n_nodes; li++) {
474  nod = ele->node[li];
475 
476  dist = sqrt(
477  ((nod->getX() - ele->centre()[ 0 ])*(nod->getX() - ele->centre()[ 0 ])) +
478  ((nod->getY() - ele->centre()[ 1 ])*(nod->getY() - ele->centre()[ 1 ])) +
479  ((nod->getZ() - ele->centre()[ 2 ])*(nod->getZ() - ele->centre()[ 2 ]))
480  );
481 
482  TED[ele.index()][li] = dist;
483  nod->faux += dist; // nod->faux += 1 / dist;
484  nod->aux++;
485  }
486 
487  FOR_SIDES(mesh_, sde) {
488  for (li = 0; li < sde->n_nodes; li++) {
489  nod = sde->node[li];
490 
491  dist = sqrt(
492  ((nod->getX() - sde->centre()[ 0 ])*(nod->getX() - sde->centre()[ 0 ])) +
493  ((nod->getY() - sde->centre()[ 1 ])*(nod->getY() - sde->centre()[ 1 ])) +
494  ((nod->getZ() - sde->centre()[ 2 ])*(nod->getZ() - sde->centre()[ 2 ]))
495  );
496 
497  TSD[sde->id][li] = dist;
498  nod->faux += dist; // nod->faux += 1 / dist;
499  nod->aux++;
500  }
501  }
502  FOR_ELEMENTS(mesh_, ele)
503  for (li = 0; li < ele->n_nodes; li++) {
504  nod = ele->node[li];
505  nod->scalar += ele->scalar * (1 - TED[ele.index()][li] / nod->faux)
506  / (nod->aux - 1); // 1 / (dist * nod->faux);
507  }
508  FOR_SIDES(mesh_, sde)
509  for (li = 0; li < sde->n_nodes; li++) {
510  nod = sde->node[li];
511  nod->scalar += sde->scalar * (1 - TSD[sde->id][li] / nod->faux)
512  / (nod->aux - 1); // 1 / (dist * nod->faux);
513  }
514  xfree(TED);
515  xfree(TSD);
516 }
517 */
518 /*
519 //=============================================================================
520 //
521 //=============================================================================
522 void make_node_vector(Mesh* mesh)
523 {
524  int ni;
525  int nei;
526  TNode* nod;
527  ElementIter ele;
528  double cnt;
529 
530  for( ni = 0; ni < mesh->n_nodes; ni++ ) {
531  nod = mesh->node + ni;
532  nod->vector[ 0 ] = 0.0;
533  nod->vector[ 1 ] = 0.0;
534  cnt = 0.0;
535  for( nei = 0; nei < nod->n_elements(); nei++ ) {
536  ele = nod->element[ nei ];
537  nod->vector[ 0 ] += ele->vector[ 0 ];
538  nod->vector[ 1 ] += ele->vector[ 1 ];
539  cnt += 1.0;
540  }
541  nod->vector[ 0 ] /= cnt;
542  nod->vector[ 1 ] /= cnt;
543 
544  }
545 }
546  */
547 //=============================================================================
548 // FILL TH "FLUX" FIELD FOR ALL VV NEIGHBOURS IN THE MESH
549 //=============================================================================
550 /*
551 void DarcyFlowMHOutput::make_neighbour_flux() {
552  struct Neighbour *ngh;
553 
554  FOR_NEIGHBOURS(mesh_, ngh) {
555  if (ngh->type != VV_2E)
556  continue;
557 
558  ngh->flux = ngh->sigma * ngh->geom_factor * (ngh->element[1]->scalar - ngh->element[0]->scalar);
559  continue;
560  }
561 }*/
562 
563 //=============================================================================
564 //
565 //=============================================================================
566 
568  F_ENTRY;
570  if (balance_output_file == NULL) return;
571 
572  //BOUNDARY
573  //struct Boundary *bcd;
574  std::vector<double> bcd_balance( mesh_->region_db().boundary_size(), 0.0 );
575  std::vector<double> bcd_plus_balance( mesh_->region_db().boundary_size(), 0.0 );
576  std::vector<double> bcd_minus_balance( mesh_->region_db().boundary_size(), 0.0 );
577 
578  using namespace std;
579  //printing the head of water balance file
580  unsigned int c = 5; //column number without label
581  unsigned int w = 14; //column width
582  unsigned int wl = 2*(w-5)+7; //label column width
583  stringstream s; //helpful stringstream
584  string bc_head_format = "# %-*s%-*s%-*s%-*s%-*s%-*s\n",
585  bc_format = "%*s%-*d%-*s %-*g%-*g%-*g%-*g\n",
586  bc_total_format = "# %-*s%-*g%-*g%-*g\n\n\n";
587  s << setw((w*c+wl-15)/2) << setfill('-') << "-"; //drawing half line
588  fprintf(balance_output_file,"# %s WATER BALANCE %s\n",s.str().c_str(), s.str().c_str());
589  fprintf(balance_output_file,"# Time of computed water balance: %f\n\n\n",darcy_flow->time().t());
590 
591  fprintf(balance_output_file,"# Boundary water balance:\n");
592  fprintf(balance_output_file,bc_head_format.c_str(),w,"[boundary_id]",wl,"[label]",
593  w,"[total_balance]",w,"[total_outflow]",w,"[total_inflow]",w,"[time]");
594  s.clear();
595  s.str(std::string());
596  s << setw(w*c+wl) << setfill('-') << "-";
597  fprintf(balance_output_file,"# %s\n",s.str().c_str()); //drawing long line
598 
599  //computing water balance over boundaries
600  FOR_BOUNDARIES(mesh_, bcd) {
601  // !! there can be more sides per one boundary
602  double flux = dh.side_flux( *(bcd->side()) );
603 
604  Region r = bcd->region();
605  //DBGMSG("flux: %f side: %d %d reg: %s\n", flux, bcd->side()->element()->index(), bcd->side()->el_idx(), r.label().c_str() );
606  if (! r.is_valid()) xprintf(Msg, "Invalid region, ele % d, edg: % d\n", bcd->bc_ele_idx_, bcd->edge_idx_);
607  unsigned int bc_region_idx = r.boundary_idx();
608  bcd_balance[bc_region_idx] += flux;
609 
610  if (flux > 0) bcd_plus_balance[bc_region_idx] += flux;
611  else bcd_minus_balance[bc_region_idx] += flux;
612  }
613  //printing water balance over boundaries
614  //DBGMSG("DB[boundary] size: %u\n", mesh_->region_db().boundary_size());
615  const RegionSet & b_set = mesh_->region_db().get_region_set("BOUNDARY");
616  double total_balance = 0, // for computing total balance on boundary
617  total_inflow = 0,
618  total_outflow = 0;
619  for( RegionSet::const_iterator reg = b_set.begin(); reg != b_set.end(); ++reg) {
620  //DBGMSG("writing reg->idx() and id() and boundary_idx(): %d\t%d\t%d\n", reg->idx(), reg->id(), reg->boundary_idx());
621  total_balance += bcd_balance[reg->boundary_idx()];
622  total_outflow += bcd_plus_balance[reg->boundary_idx()];
623  total_inflow += bcd_minus_balance[reg->boundary_idx()];
624  fprintf(balance_output_file, bc_format.c_str(),2,"",w,reg->id(),wl,reg->label().c_str(),
625  w, bcd_balance[reg->boundary_idx()], w, bcd_plus_balance[reg->boundary_idx()],
626  w, bcd_minus_balance[reg->boundary_idx()], w, darcy_flow->time().t());
627  }
628  //total boundary balance
629  fprintf(balance_output_file,"# %s\n",s.str().c_str()); // drawing long line
630  fprintf(balance_output_file, bc_total_format.c_str(),w+wl+2,"total boundary balance",
631  w,total_balance, w, total_outflow, w, total_inflow);
632 
633  //SOURCES
634  string src_head_format = "# %-*s%-*s%-*s%-*s%-*s\n",
635  src_format = "%*s%-*d%-*s %-*g%-*s%-*g\n",
636  src_total_format = "# %-*s%-*g\n\n\n";
637  //computing water balance of sources
638  fprintf(balance_output_file,"# Source fluxes over material subdomains:\n"); //head
639  fprintf(balance_output_file,src_head_format.c_str(),w,"[region_id]",wl,"[label]",
640  w,"[total_balance]",2*w,"",w,"[time]");
641  fprintf(balance_output_file,"# %s\n",s.str().c_str()); //long line
642  std::vector<double> src_balance( mesh_->region_db().bulk_size(), 0.0 ); // initialize by zero
643  FOR_ELEMENTS(mesh_, elm) {
644  //DBGMSG("writing reg->idx() and id() and bulk_idx(): %d\t%d\t%d\n",
645  // elm->element_accessor().region().idx(),
646  // elm->element_accessor().region().id(),
647  // elm->element_accessor().region().bulk_idx());
648  src_balance[elm->element_accessor().region().bulk_idx()] += elm->measure() *
649  darcy_flow->data_.cross_section.value(elm->centre(), elm->element_accessor()) *
650  darcy_flow->data_.water_source_density.value(elm->centre(), elm->element_accessor());
651  }
652 
653  total_balance = 0;
654  //printing water balance of sources
655  //DBGMSG("DB[bulk] size: %u\n", mesh_->region_db().bulk_size());
656  const RegionSet & bulk_set = mesh_->region_db().get_region_set("BULK");
657  for( RegionSet::const_iterator reg = bulk_set.begin(); reg != bulk_set.end(); ++reg)
658  {
659  total_balance += src_balance[reg->bulk_idx()];
660  //"%*s%-*d%-*s %-*g%-*s%-*g\n";
661  fprintf(balance_output_file, src_format.c_str(), 2,"", w, reg->id(), wl,
662  reg->label().c_str(), w, src_balance[reg->bulk_idx()],2*w,"", w,darcy_flow->time().t());
663  }
664  //total sources balance
665  fprintf(balance_output_file,"# %s\n",s.str().c_str()); //drawing long line
666  fprintf(balance_output_file, src_total_format.c_str(),w+wl+2,"total sources balance",
667  w,total_balance);
668 }
669 
670 //=============================================================================
671 // UNUSED FUNCTION
672 //=============================================================================
673 /*
674 double calc_water_balance(Mesh* mesh, int c_water) {
675  double rc;
676  struct Boundary *bcd;
677 
678  rc = 0.0;
679 
680  return rc;
681 }
682 */
683 
684 /*
685  * Output of internal flow data.
686  */
687 
689 {
691 
692  if (raw_output_file == NULL) return;
693 
694  char dbl_fmt[ 16 ]= "%.8g ";
695  // header
696  xfprintf( raw_output_file, "// fields:\n//ele_id ele_presure flux_in_barycenter[3] n_sides side_pressures[n] side_fluxes[n]\n");
697  xfprintf( raw_output_file, "$FlowField\nT=");
698  xfprintf( raw_output_file, dbl_fmt, darcy_flow->time().t());
699  xfprintf( raw_output_file, "\n%d\n", mesh_->n_elements() );
700 
701  unsigned int i;
702  int cit = 0;
703  FOR_ELEMENTS( mesh_, ele ) {
704  //xfprintf( raw_output_file, "%d ", cit);
705  xfprintf( raw_output_file, "%d ", ele.id());
706  xfprintf( raw_output_file, dbl_fmt, ele_pressure[cit]);
707  for (i = 0; i < 3; i++)
708  xfprintf( raw_output_file, dbl_fmt, ele_flux[3*cit+i]);
709 
710  xfprintf( raw_output_file, " %d ", ele->n_sides());
711  for (i = 0; i < ele->n_sides(); i++)
712  xfprintf( raw_output_file, dbl_fmt, dh.side_scalar( *(ele->side(i) ) ) );
713  for (i = 0; i < ele->n_sides(); i++)
714  xfprintf( raw_output_file, dbl_fmt, dh.side_flux( *(ele->side(i) ) ) );
715 
716  //xfprintf( raw_output_file, "%d ", ele->n_neighs_vv);
717  //for (i = 0; i < ele->n_neighs_vv; i++)
718  // xfprintf( raw_output_file, "%d ", ele->neigh_vv[i]->id);
719 
720  xfprintf( raw_output_file, "\n" );
721  cit ++;
722  }
723  xfprintf( raw_output_file, "$EndFlowField\n\n" );
724 }
725 
726 
728 #include "fem/fe_p.hh"
729 #include "fem/fe_values.hh"
730 #include "fem/mapping_p1.hh"
731 //#include "functions/function_python.hh"
732 #include "fields/field_python.hh"
733 #include "fields/field_values.hh"
734 
736 
737 /*
738 * Calculate approximation of L2 norm for:
739  * 1) difference between regularized pressure and analytical solution (using FunctionPython)
740  * 2) difference between RT velocities and analytical solution
741  * 3) difference of divergence
742  * */
743 
744 struct DiffData {
745  double pressure_error[2], velocity_error[2], div_error[2];
749 
750  double * solution;
751  const MH_DofHandler * dh;
753 
754  //double *ele_flux;
755 
758 };
759 
760 template <int dim>
761 void l2_diff_local(ElementFullIter &ele, FEValues<dim,3> &fe_values, ExactSolution &anal_sol, DiffData &result) {
762 
763  fe_values.reinit(ele);
764  result.fe_values.update(ele,
765  result.data_->anisotropy,
766  result.data_->cross_section,
767  result.data_->conductivity);
768  double conductivity = result.data_->conductivity.value(ele->centre(), ele->element_accessor() );
769  double cross = result.data_->cross_section.value(ele->centre(), ele->element_accessor() );
770 
771 
772  // get coefficients on the current element
773  vector<double> fluxes(dim+1);
774  vector<double> pressure_traces(dim+1);
775 
776  for (unsigned int li = 0; li < ele->n_sides(); li++) {
777  fluxes[li] = result.dh->side_flux( *(ele->side( li ) ) );
778  pressure_traces[li] = result.dh->side_scalar( *(ele->side( li ) ) );
779  }
780  double pressure_mean = result.dh->element_scalar(ele);
781 
782  arma::vec analytical(5);
783  arma::vec3 flux_in_q_point;
784  arma::vec3 anal_flux;
785 
786  double velocity_diff=0, divergence_diff=0, pressure_diff=0, diff;
787 
788  // 1d: mean_x_squared = 1/6 (v0^2 + v1^2 + v0*v1)
789  // 2d: mean_x_squared = 1/12 (v0^2 + v1^2 +v2^2 + v0*v1 + v0*v2 + v1*v2)
790  double mean_x_squared=0;
791  for(unsigned int i_node=0; i_node < ele->n_nodes(); i_node++ )
792  for(unsigned int j_node=0; j_node < ele->n_nodes(); j_node++ )
793  {
794  mean_x_squared += (i_node == j_node ? 2.0 : 1.0) / ( 6 * dim ) // multiply by 2 on diagonal
795  * arma::dot( ele->node[i_node]->point(), ele->node[j_node]->point());
796  }
797 
798  for(unsigned int i_point=0; i_point < fe_values.n_points(); i_point++) {
799  arma::vec3 q_point = fe_values.point(i_point);
800 
801 
802  analytical = anal_sol.value(q_point, ele->element_accessor() );
803  for(unsigned int i=0; i< 3; i++) anal_flux[i] = analytical[i+1];
804 
805  // compute postprocesed pressure
806  diff = 0;
807  for(unsigned int i_shape=0; i_shape < ele->n_sides(); i_shape++) {
808  unsigned int oposite_node = (i_shape + dim) % (dim + 1);
809 
810  diff += fluxes[ i_shape ] *
811  ( arma::dot( q_point, q_point )/ 2
812  - mean_x_squared / 2
813  - arma::dot( q_point, ele->node[oposite_node]->point() )
814  + arma::dot( ele->centre(), ele->node[oposite_node]->point() )
815  );
816  }
817 
818  diff = - (1.0 / conductivity) * diff / dim / ele->measure() / cross + pressure_mean ;
819  diff = ( diff - analytical[0]);
820  pressure_diff += diff * diff * fe_values.JxW(i_point);
821 
822 
823  // velocity difference
824  flux_in_q_point.zeros();
825  for(unsigned int i_shape=0; i_shape < ele->n_sides(); i_shape++) {
826  flux_in_q_point += fluxes[ i_shape ]
827  * result.fe_values.RT0_value( ele, q_point, i_shape )
828  / cross;
829  }
830 
831  flux_in_q_point -= anal_flux;
832  velocity_diff += dot(flux_in_q_point, flux_in_q_point) * fe_values.JxW(i_point);
833 
834  // divergence diff
835  diff = 0;
836  for(unsigned int i_shape=0; i_shape < ele->n_sides(); i_shape++) diff += fluxes[ i_shape ];
837  diff = ( diff / ele->measure() / cross - analytical[4]);
838  divergence_diff += diff * diff * fe_values.JxW(i_point);
839 
840  }
841 
842 
843  result.velocity_diff[ele.index()] = velocity_diff;
844  result.velocity_error[dim-1] += velocity_diff;
845 
846  result.pressure_diff[ele.index()] = pressure_diff;
847  result.pressure_error[dim-1] += pressure_diff;
848 
849  result.div_diff[ele.index()] = divergence_diff;
850  result.div_error[dim-1] += divergence_diff;
851 
852 }
853 
854 
855 
856 
857 
858 
860  DBGMSG("l2 norm output\n");
861  ofstream os( FilePath("solution_error", FilePath::output_file) );
862 
863  const unsigned int order = 4; // order of Gauss quadrature
864 
865  // we create trivial Dofhandler , for P0 elements, to get access to, FEValues on individual elements
866  // this we use to integrate our own functions - difference of postprocessed pressure and analytical solution
867  FE_P_disc<0,1,3> fe_1d;
868  FE_P_disc<0,2,3> fe_2d;
869 
870  QGauss<1> quad_1d( order );
871  QGauss<2> quad_2d( order );
872 
873  MappingP1<1,3> mapp_1d;
874  MappingP1<2,3> mapp_2d;
875 
876  FEValues<1,3> fe_values_1d(mapp_1d, quad_1d, fe_1d, update_JxW_values | update_quadrature_points);
877  FEValues<2,3> fe_values_2d(mapp_2d, quad_2d, fe_2d, update_JxW_values | update_quadrature_points);
878 
879  FilePath source_file( "analytical_module.py", FilePath::input_file);
880  ExactSolution anal_sol_1d(5); // components: pressure, flux vector 3d, divergence
881  anal_sol_1d.set_python_field_from_file( source_file, "all_values_1d");
882 
883  ExactSolution anal_sol_2d(5);
884  anal_sol_2d.set_python_field_from_file( source_file, "all_values_2d");
885 
886 
887  static DiffData result;
888 
889  result.pressure_diff.resize( mesh_->n_elements() );
890  result.velocity_diff.resize( mesh_->n_elements() );
891  result.div_diff.resize( mesh_->n_elements() );
892 
893  result.pressure_error[0] = 0;
894  result.velocity_error[0] = 0;
895  result.div_error[0] = 0;
896  result.pressure_error[1] = 0;
897  result.velocity_error[1] = 0;
898  result.div_error[1] = 0;
899 
900  //result.ele_flux = &(ele_flux[0]);
901 
902  //output_writer->register_elem_data(mesh_, "pressure_diff", "0", in_rec_.val<Input::Record>("output_stream") ,result.pressure_diff);
903  //output_writer->register_elem_data(mesh_, "velocity_diff", "0", in_rec_.val<Input::Record>("output_stream"),result.pressure_diff);
904  //output_writer->register_elem_data(mesh_, "div_diff", "0", in_rec_.val<Input::Record>("output_stream"),result.pressure_diff);
905 
906 
907 
908  auto vel_diff_ptr = std::make_shared< FieldElementwise<3, FieldValue<3>::Scalar> >(&(result.velocity_diff[0]), 1, mesh_->n_elements());
910  auto pressure_diff_ptr = std::make_shared< FieldElementwise<3, FieldValue<3>::Scalar> >(&(result.pressure_diff[0]), 1, mesh_->n_elements());
911  output_fields.pressure_diff.set_field(mesh_->region_db().get_region_set("ALL"), pressure_diff_ptr, 0);
912  auto div_diff_ptr = std::make_shared< FieldElementwise<3, FieldValue<3>::Scalar> >(&(result.div_diff[0]), 1, mesh_->n_elements());
913  output_fields.div_diff.set_field(mesh_->region_db().get_region_set("ALL"), div_diff_ptr, 0);
914 
916 
917  unsigned int solution_size;
918  darcy_flow->get_solution_vector(result.solution, solution_size);
919 
920  result.dh = &( darcy_flow->get_mh_dofhandler());
921  result.darcy = darcy_flow;
922  result.data_ = &(darcy_flow->data_);
923 
924  FOR_ELEMENTS( mesh_, ele) {
925 
926  switch (ele->dim()) {
927  case 1:
928 
929  l2_diff_local<1>( ele, fe_values_1d, anal_sol_1d, result);
930  break;
931  case 2:
932  l2_diff_local<2>( ele, fe_values_2d, anal_sol_2d, result);
933  break;
934  }
935  }
936 
937  os << "l2 norm output\n\n"
938  << "pressure error 1d: " << sqrt(result.pressure_error[0]) << endl
939  << "pressure error 2d: " << sqrt(result.pressure_error[1]) << endl
940  << "velocity error 1d: " << sqrt(result.velocity_error[0]) << endl
941  << "velocity error 2d: " << sqrt(result.velocity_error[1]) << endl
942  << "div error 1d: " << sqrt(result.div_error[0]) << endl
943  << "div error 2d: " << sqrt(result.div_error[1]);
944 }
945