Flow123d  DF_patch_fe_darcy_complete-579fe1e
assembly_flow_output.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 assembly_flow_output.hh
15  * @brief
16  */
17 
18 #ifndef ASSEMBLY_FLOW_OUTPUT_HH_
19 #define ASSEMBLY_FLOW_OUTPUT_HH_
20 
21 #include <fstream>
22 
26 #include "flow/darcy_flow_lmh.hh"
27 #include "fem/element_cache_map.hh"
28 #include "fields/field_fe.hh"
29 
30 #include "mesh/mesh.h"
31 #include "mesh/accessors.hh"
32 #include "fem/fe_p.hh"
33 #include "fem/fe_rt.hh"
34 #include "fem/fe_system.hh"
36 
37 
38 /**
39  * Calculate approximation of L2 norm for:
40  * 1) difference between regularized pressure and analytical solution (using FunctionPython)
41  * 2) difference between RT velocities and analytical solution
42  * 3) difference of divergence
43  *
44  * TODO:
45  * 1) implement field objects
46  * 2) implement DG_P2 finite elements
47  * 3) implement pressure postprocessing (result is DG_P2 field)
48  * 4) implement calculation of L2 norm for two field (compute the norm and values on individual elements as P0 field)
49  *
50  */
51 template <unsigned int dim, class TEqData>
53 {
54 public:
55  typedef typename TEqData::EqFields EqFields;
56  typedef TEqData EqData;
57 
58  static constexpr const char * name() { return "Output_L2Difference_Assembly"; }
59 
60  /// Constructor.
61  L2DifferenceAssembly(EqData *eq_data, AssemblyInternals *asm_internals)
62  : AssemblyBasePatch<dim>(2, asm_internals), eq_fields_(eq_data->eq_fields_.get()), eq_data_(eq_data),
64  JxW_( output_integral_->JxW() ),
65  pt_coords_( output_integral_->coords() ),
66  vec_shape_rt_( output_integral_->vector_shape(0) ) {
67  this->used_fields_ += eq_fields_->conductivity;
68  this->used_fields_ += eq_fields_->cross_section;
69  this->used_fields_ += eq_fields_->ref_pressure;
70  this->used_fields_ += eq_fields_->ref_velocity;
71  this->used_fields_ += eq_fields_->ref_divergence;
72  }
73 
74  /// Destructor.
75  virtual ~L2DifferenceAssembly() {}
76 
77  /// Initialize auxiliary vectors and other data members
78  void initialize() {
79  fluxes_.resize(dim+1);
80  }
81 
82 
83  /// Assemble integral over element
84  inline void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
85  {
86  ASSERT_EQ(cell.dim(), dim).error("Dimension of element mismatch!");
87 
88  ElementAccessor<3> ele = cell.elm();
89 
90  // get coefficients on the current element
91  for (unsigned int li = 0; li < ele->n_sides(); li++) {
92  fluxes_[li] = eq_data_->flow_data_->full_solution.get( cell.get_loc_dof_indices()[li] );
93  //pressure_traces[li] = diff_eq_data_->dh->side_scalar( *(ele->side( li ) ) );
94  }
95  // TODO: replace with DHCell getter when available for FESystem component
96  double pressure_mean = eq_data_->flow_data_->full_solution.get( cell.get_loc_dof_indices()[ cell.n_dofs()/2 ] );
97 
98  double velocity_diff=0, divergence_diff=0, pressure_diff=0, diff;
99 
100  // 1d: mean_x_squared = 1/6 (v0^2 + v1^2 + v0*v1)
101  // 2d: mean_x_squared = 1/12 (v0^2 + v1^2 +v2^2 + v0*v1 + v0*v2 + v1*v2)
102  double mean_x_squared=0;
103  for(unsigned int i_node=0; i_node < ele->n_nodes(); i_node++ )
104  for(unsigned int j_node=0; j_node < ele->n_nodes(); j_node++ )
105  {
106  mean_x_squared += (i_node == j_node ? 2.0 : 1.0) / ( 6 * dim ) // multiply by 2 on diagonal
107  * arma::dot( *ele.node(i_node), *ele.node(j_node));
108  }
109 
110  unsigned int oposite_node;
111  for (auto p : output_integral_->points(element_patch_idx) )
112  {
113  q_point_ = pt_coords_(p);
114 
115  conductivity_ = eq_fields_->conductivity(p);
116  cross_ = eq_fields_->cross_section(p);
117  ref_pressure_ = eq_fields_->ref_pressure(p);
118  ref_flux_ = eq_fields_->ref_velocity(p);
119  ref_divergence_ = eq_fields_->ref_divergence(p);
120 
121  // compute postprocesed pressure
122  diff = 0;
123  for(unsigned int i_shape=0; i_shape < ele->n_sides(); i_shape++) {
124  oposite_node = RefElement<dim>::oposite_node(i_shape);
125 
126  diff += fluxes_[ i_shape ] *
127  ( arma::dot( q_point_, q_point_ )/ 2
128  - mean_x_squared / 2
129  - arma::dot( q_point_, *ele.node(oposite_node) )
130  + arma::dot( ele.centre(), *ele.node(oposite_node) )
131  );
132  }
133 
134  diff = - (1.0 / conductivity_) * diff / dim / ele.measure() / cross_ + pressure_mean ;
135  diff = ( diff - ref_pressure_);
136  pressure_diff += diff * diff * JxW_(p);
137 
138  // velocity difference
139  flux_in_q_point_.zeros();
140  for(unsigned int i_shape=0; i_shape < ele->n_sides(); i_shape++) {
141  flux_in_q_point_ += fluxes_[ i_shape ]
142  * vec_shape_rt_.shape(i_shape)(p)
143  / cross_;
144  }
145 
147  velocity_diff += dot(flux_in_q_point_, flux_in_q_point_) * JxW_(p);
148 
149  // divergence diff
150  diff = 0;
151  for(unsigned int i_shape=0; i_shape < ele->n_sides(); i_shape++) diff += fluxes_[ i_shape ];
152  diff = ( diff / ele.measure() / cross_ - ref_divergence_);
153  divergence_diff += diff * diff * JxW_(p);
154  }
155 
156  // DHCell constructed with diff fields DH, get DOF indices of actual element
157  DHCellAccessor sub_dh_cell = cell.cell_with_other_dh(eq_data_->dh_.get());
158  IntIdx idx = sub_dh_cell.get_loc_dof_indices()[0];
159 
160  auto velocity_data = eq_data_->vel_diff_ptr->vec();
161  velocity_data.set( idx, sqrt(velocity_diff) );
162  eq_data_->velocity_error[dim-1] += velocity_diff;
163  if (dim == 2 && eq_data_->velocity_mask.size() != 0 ) {
164  eq_data_->mask_vel_error += (eq_data_->velocity_mask[ ele.idx() ])? 0 : velocity_diff;
165  }
166 
167  auto pressure_data = eq_data_->pressure_diff_ptr->vec();
168  pressure_data.set( idx, sqrt(pressure_diff) );
169  eq_data_->pressure_error[dim-1] += pressure_diff;
170 
171  auto div_data = eq_data_->div_diff_ptr->vec();
172  div_data.set( idx, sqrt(divergence_diff) );
173  eq_data_->div_error[dim-1] += divergence_diff;
174  }
175 
176  /// Implements @p AssemblyBase::begin.
177  void begin() override
178  {
179  DebugOut() << "l2 norm output\n";
180 
181  eq_data_->mask_vel_error=0;
182  for(unsigned int j=0; j<3; j++){
183  eq_data_->pressure_error[j] = 0;
184  eq_data_->velocity_error[j] = 0;
185  eq_data_->div_error[j] = 0;
186  }
187  }
188 
189  /// Implements @p AssemblyBase::end.
190  void end() override
191  {
192  ofstream os( FilePath("solution_error", FilePath::output_file) );
193 
194  // square root for L2 norm
195  for(unsigned int j=0; j<3; j++){
196  eq_data_->pressure_error[j] = sqrt(eq_data_->pressure_error[j]);
197  eq_data_->velocity_error[j] = sqrt(eq_data_->velocity_error[j]);
198  eq_data_->div_error[j] = sqrt(eq_data_->div_error[j]);
199  }
200  eq_data_->mask_vel_error = sqrt(eq_data_->mask_vel_error);
201 
202  os << "l2 norm output\n\n"
203  << "pressure error 1d: " << eq_data_->pressure_error[0] << endl
204  << "pressure error 2d: " << eq_data_->pressure_error[1] << endl
205  << "pressure error 3d: " << eq_data_->pressure_error[2] << endl
206  << "velocity error 1d: " << eq_data_->velocity_error[0] << endl
207  << "velocity error 2d: " << eq_data_->velocity_error[1] << endl
208  << "velocity error 3d: " << eq_data_->velocity_error[2] << endl
209  << "masked velocity error 2d: " << eq_data_->mask_vel_error <<endl
210  << "div error 1d: " << eq_data_->div_error[0] << endl
211  << "div error 2d: " << eq_data_->div_error[1] << endl
212  << "div error 3d: " << eq_data_->div_error[2];
213  }
214 
215 
216 protected:
217  /// Sub field set contains fields used in calculation.
219 
220  /// Data objects shared with Flow equation
223 
224  /// following is used for calculation of postprocessed pressure difference
225  /// and comparison to analytical solution
226  std::vector<double> fluxes_; ///< Precomputed fluxes on element sides.
227  arma::vec3 flux_in_q_point_; ///< Precomputed flux in quadrature point.
228  arma::vec3 q_point_; ///< Local coords of quadrature point.
229  arma::vec3 ref_flux_; ///< Field result.
230  double ref_pressure_, ref_divergence_, conductivity_, cross_; ///< Field results.
231 
232  std::shared_ptr<BulkIntegralAcc<dim>> output_integral_; ///< Integral accessor of assembly class
233 
234  /// Following data members represent Element quantities and FE quantities
238 
239  template < template<IntDim...> class DimAssembly>
240  friend class GenericAssembly;
241 
242 };
243 
244 
245 /**
246  * Compute output of internal flow data.
247  */
248 template <unsigned int dim, class TEqData>
250 {
251 public:
252  typedef typename TEqData::EqFields EqFields;
253  typedef TEqData EqData;
254 
255  static constexpr const char * name() { return "Output_InternalFlow_Assembly"; }
256 
257  /// Constructor.
259  : AssemblyBase<dim>(0, asm_internals), eq_fields_(eq_data->eq_fields_.get()), eq_data_(eq_data),
261  this->used_fields_ += eq_fields_->field_ele_velocity;
262  }
263 
264  /// Destructor.
266 
267  /// Initialize auxiliary vectors and other data members
268  void initialize() {}
269 
270 
271  /// Assemble integral over element
272  inline void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
273  {
274  ASSERT_EQ(cell.dim(), dim).error("Dimension of element mismatch!");
275 
276  ElementAccessor<3> ele = cell.elm();
277  LocDofVec indices = cell.get_loc_dof_indices();
278 
279  std::stringstream ss;
280  // pressure
281  ss << fmt::format("{} {} ", cell.elm().input_id(), eq_data_->flow_data_->full_solution.get(indices[ele->n_sides()]));
282 
283  // velocity at element center
284  auto p = *( output_integral_->points(element_patch_idx).begin() );
285  flux_in_center_ = eq_fields_->field_ele_velocity(p);
286  for (unsigned int i = 0; i < 3; i++)
287  ss << flux_in_center_[i] << " ";
288 
289  // number of sides
290  ss << ele->n_sides() << " ";
291 
292  // use node permutation to permute sides
293  auto &new_to_old_node = ele.orig_nodes_order();
294  std::vector<uint> old_to_new_side(ele->n_sides());
295  for (unsigned int i = 0; i < ele->n_sides(); i++) {
296  // According to RefElement<dim>::opposite_node()
297  uint new_opp_node = ele->n_sides() - i - 1;
298  uint old_opp_node = new_to_old_node[new_opp_node];
299  uint old_iside = ele->n_sides() - old_opp_node - 1;
300  old_to_new_side[old_iside] = i;
301  }
302 
303  // pressure on edges
304  // unsigned int lid = ele->n_sides() + 1;
305  for (unsigned int i = 0; i < ele->n_sides(); i++) {
306  uint new_lid = ele->n_sides() + 1 + old_to_new_side[i];
307  ss << eq_data_->flow_data_->full_solution.get(indices[new_lid]) << " ";
308  }
309  // fluxes on sides
310  for (unsigned int i = 0; i < ele->n_sides(); i++) {
311  uint new_iside = old_to_new_side[i];
312  ss << eq_data_->flow_data_->full_solution.get(indices[new_iside]) << " ";
313  }
314 
315  // remove last white space
316  string line = ss.str();
317  eq_data_->raw_output_strings_[cell.elm_idx()] = line.substr(0, line.size()-1);
318  }
319 
320  /// Implements @p AssemblyBase::begin.
321  void begin() override
322  {
323  DebugOut() << "Internal flow data output\n";
324 
325  eq_data_->raw_output_strings_.resize( eq_data_->flow_data_->dh_->n_own_cells() );
326  }
327 
328  /// Implements @p AssemblyBase::end.
329  void end() override
330  {
331  //char dbl_fmt[ 16 ]= "%.8g ";
332  // header
333  eq_data_->raw_output_file << "// fields:\n//ele_id ele_presure flux_in_barycenter[3] n_sides side_pressures[n] side_fluxes[n]\n";
334  eq_data_->raw_output_file << fmt::format("$FlowField\nT={}\n", eq_data_->time_->t());
335  eq_data_->raw_output_file << fmt::format("{}\n" , eq_data_->flow_data_->dh_->mesh()->n_elements() );
336 
337  auto permutation_vec = eq_data_->flow_data_->dh_->mesh()->element_permutations();
338  for (unsigned int i_elem=0; i_elem<eq_data_->flow_data_->dh_->n_own_cells(); ++i_elem) {
339  eq_data_->raw_output_file << eq_data_->raw_output_strings_[ permutation_vec[i_elem] ] << endl;
340  }
341 
342  eq_data_->raw_output_file << "$EndFlowField\n" << endl;
343  }
344 
345 
346 protected:
347  /// Sub field set contains fields used in calculation.
349 
350  /// Data objects shared with Flow equation
353 
355 
356  std::shared_ptr<BulkIntegralAcc<dim>> output_integral_; ///< Integral accessor of assembly class
357 
358  template < template<IntDim...> class DimAssembly>
359  friend class GenericAssembly;
360 
361 };
362 
363 
364 #endif /* ASSEMBLY_FLOW_OUTPUT_HH_ */
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
Quadrature * quad_
Quadrature used in assembling methods.
std::shared_ptr< BulkIntegralAcc< dim > > create_bulk_integral(Quadrature *quad)
Cell accessor allow iterate over DOF handler cells.
unsigned int n_dofs() const
Return number of dofs on given cell.
LocDofVec get_loc_dof_indices() const
Returns the local indices of dofs associated to the cell on the local process.
DHCellAccessor cell_with_other_dh(const DOFHandlerMultiDim *dh) const
Create new accessor with same local idx and given DOF handler. Actual and given DOF handler must be c...
unsigned int dim() const
Return dimension of element appropriate to cell.
unsigned int elm_idx() const
Return serial idx to element of loc_ele_idx_.
ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
auto & orig_nodes_order() const
Definition: accessors.hh:240
unsigned int input_id() const
Return the element ID in the input mesh. Should be only used for special output.
Definition: accessors.hh:220
NodeAccessor< 3 > node(unsigned int ni) const
Definition: accessors.hh:230
double measure() const
Computes the measure of the element.
unsigned int idx() const
We need this method after replacing Region by RegionIdx, and movinf RegionDB instance into particular...
Definition: accessors.hh:215
arma::vec::fixed< spacedim > centre() const
Computes the barycenter.
unsigned int n_sides() const
Definition: elements.h:131
unsigned int n_nodes() const
Definition: elements.h:125
Container for various descendants of FieldCommonBase.
Definition: field_set.hh:159
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
@ output_file
Definition: file_path.hh:69
Generic class of assemblation.
std::shared_ptr< BulkIntegralAcc< dim > > output_integral_
Integral accessor of assembly class.
static constexpr const char * name()
void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
Assemble integral over element.
arma::vec3 flux_in_q_point_
Precomputed flux in quadrature point.
std::vector< double > fluxes_
Precomputed fluxes on element sides.
arma::vec3 q_point_
Local coords of quadrature point.
FieldSet used_fields_
Sub field set contains fields used in calculation.
FeQ< Scalar > JxW_
Following data members represent Element quantities and FE quantities.
void initialize()
Initialize auxiliary vectors and other data members.
EqFields * eq_fields_
Data objects shared with Flow equation.
double cross_
Field results.
virtual ~L2DifferenceAssembly()
Destructor.
void end() override
Implements AssemblyBase::end.
arma::vec3 ref_flux_
Field result.
L2DifferenceAssembly(EqData *eq_data, AssemblyInternals *asm_internals)
Constructor.
TEqData::EqFields EqFields
FeQArray< Vector > vec_shape_rt_
void begin() override
Implements AssemblyBase::begin.
std::shared_ptr< BulkIntegralAcc< dim > > output_integral_
Integral accessor of assembly class.
virtual ~OutputInternalFlowAssembly()
Destructor.
EqFields * eq_fields_
Data objects shared with Flow equation.
void end() override
Implements AssemblyBase::end.
OutputInternalFlowAssembly(EqData *eq_data, AssemblyInternals *asm_internals)
Constructor.
static constexpr const char * name()
void cell_integral(DHCellAccessor cell, unsigned int element_patch_idx)
Assemble integral over element.
void initialize()
Initialize auxiliary vectors and other data members.
void begin() override
Implements AssemblyBase::begin.
FieldSet used_fields_
Sub field set contains fields used in calculation.
static unsigned int oposite_node(unsigned int sid)
Definition: ref_element.cc:210
Lumped mixed-hybrid model of linear Darcy flow, possibly unsteady.
Output class for darcy_flow_mh model.
Definitions of basic Lagrangean finite elements with polynomial shape functions.
Definitions of Raviart-Thomas finite elements.
Class FESystem for compound finite elements.
int IntIdx
Definition: index_types.hh:25
arma::Col< IntIdx > LocDofVec
Definition: index_types.hh:28
#define DebugOut()
Macro defining 'debug' record of log.
Definition: logger.hh:284
unsigned int uint
unsigned int IntDim
A dimension index type.
Definition: mixed.hh:19
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3141
Definitions of particular quadrature rules on simplices.
Holds common data shared between GenericAssemblz and Assembly<dim> classes.