Plugins
navier_stokes_tools.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2015: G-CSC, Goethe University Frankfurt
3  * Author: Christian Wehner
4  *
5  * This file is part of UG4.
6  *
7  * UG4 is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License version 3 (as published by the
9  * Free Software Foundation) with the following additional attribution
10  * requirements (according to LGPL/GPL v3 §7):
11  *
12  * (1) The following notice must be displayed in the Appropriate Legal Notices
13  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14  *
15  * (2) The following notice must be displayed at a prominent place in the
16  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17  *
18  * (3) The following bibliography is recommended for citation and must be
19  * preserved in all covered files:
20  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21  * parallel geometric multigrid solver on hierarchically distributed grids.
22  * Computing and visualization in science 16, 4 (2013), 151-164"
23  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24  * flexible software system for simulating pde based models on high performance
25  * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU Lesser General Public License for more details.
31  */
32 
33 #ifndef __H__UG__PLUGINS__NAVIER_STOKES__INCOMPRESSIBLE__NAVIER_STOKES_TOOLS__
34 #define __H__UG__PLUGINS__NAVIER_STOKES__INCOMPRESSIBLE__NAVIER_STOKES_TOOLS__
35 
36 #include <vector>
38 #include "lib_grid/lg_base.h"
45 #include <iostream>
46 #include <fstream>
47 #include <vector>
48 #include <string>
49 
50 namespace ug{
51 
52 // Crouzeix-Raviart function is interpolated to Lagrange 1 function
53 template <typename TGridFunction>
54 void interpolateCRToLagrange(TGridFunction& uLagrange,TGridFunction& uCR){
56  typedef typename TGridFunction::domain_type domain_type;
57 
59  typedef typename domain_type::grid_type grid_type;
60 
62  static const int dim = domain_type::dim;
63 
64  // get grid
65  grid_type& grid = *uLagrange.domain()->grid();
66 
67  // position accessor type
69 
71  typedef typename TGridFunction::template dim_traits<dim>::grid_base_object elem_type;
72 
74  typedef typename elem_type::side side_type;
75 
76  // volume attachment
77  typedef PeriodicAttachmentAccessor<Vertex,ANumber > aVertexNumber;
78  aVertexNumber m_acVolume;
79  ANumber m_aVolume;
80 
82  typedef typename TGridFunction::template dim_traits<dim>::const_iterator ElemIterator;
83 
85  typedef typename TGridFunction::template traits<Vertex>::const_iterator VertexIterator;
86 
87  // get position accessor
89  position_accessor_type& posAcc = uLagrange.domain()->position_accessor();
90 
91  // scalar function or vector function
92  int spaceDim = uLagrange.num_fct();
93  if ((int)uLagrange.num_fct()==dim) spaceDim=dim;
94 
95  for (int i=0;i<spaceDim;i++){
96  if (uLagrange.local_finite_element_id(i) != LFEID(LFEID::LAGRANGE, TGridFunction::dim, 1)){
97  UG_THROW("First parameter must be of Lagrange 1 type.");
98  }
99  if (uCR.local_finite_element_id(i) != LFEID(LFEID::CROUZEIX_RAVIART, TGridFunction::dim, 1)){
100  UG_THROW("Second parameter must be of CR type.");
101  }
102  }
103 /* if (uLagrange.num_fct()==dim+1){
104  if (uLagrange.local_finite_element_id(dim) != LFEID(LFEID::PIECEWISE_CONSTANT, TGridFunction::dim, 0)){
105  UG_THROW("Parameter dim must be of piecewise type.");
106  }
107  }
108  if (uCR.num_fct()==dim+1){
109  if (uCR.local_finite_element_id(dim) != LFEID(LFEID::PIECEWISE_CONSTANT, TGridFunction::dim, 0)){
110  UG_THROW("Parameter dim must be of piecewise constant 1 type.");
111  }
112  }*/
113 
115 
116  grid.template attach_to<Vertex>(m_aVolume);
117  m_acVolume.access(grid,m_aVolume);
118 
119  SetAttachmentValues(m_acVolume,grid.template begin<Vertex>(), grid.template end<Vertex>(), 0);
120 
121  PeriodicBoundaryManager* pbm = grid.periodic_boundary_manager();
122 
123  // coord and vertex array
126 
127  // create Multiindex
128  std::vector<DoFIndex> multInd;
129 
130  static const size_t MaxNumSidesOfElem = 10;
131 
132  typedef MathVector<dim> MVD;
133  std::vector<MVD> uValue(MaxNumSidesOfElem);
134 
135  // set lagrange function to zero
136  for(int si = 0; si < uLagrange.num_subsets(); ++si){
137  // get iterators
138  VertexIterator iter = uLagrange.template begin<Vertex>(si);
139  VertexIterator iterEnd = uLagrange.template end<Vertex>(si);
140  for( ;iter !=iterEnd; ++iter){
141  Vertex* vrt = *iter;
142  if (pbm && pbm->is_slave(vrt)) continue;
143  for (int d=0;d<spaceDim;d++){
144  uLagrange.inner_dof_indices(vrt, d, multInd);
145  DoFRef(uLagrange,multInd[0])=0;
146  }
147  }
148  }
149 
150  for(int si = 0; si < uLagrange.num_subsets(); ++si)
151  {
152  // get iterators
153  ElemIterator iter = uLagrange.template begin<elem_type>(si);
154  ElemIterator iterEnd = uLagrange.template end<elem_type>(si);
155 
156  // loop elements of dimension
157  for( ;iter !=iterEnd; ++iter)
158  {
159  // get Elem
160  elem_type* elem = *iter;
161 
162  // reference object id
163  ReferenceObjectID roid = elem->reference_object_id();
164 
165  // get Crouzeix-Raviart trial space
166  const LocalShapeFunctionSet<dim>& crTrialSpace =
167  LocalFiniteElementProvider::get<dim>(roid, LFEID(LFEID::CROUZEIX_RAVIART, dim, 1));
168 
169  // get vertices and extract corner coordinates
170  const size_t numVertices = elem->num_vertices();
171  for(size_t i = 0; i < numVertices; ++i){
172  vVrt[i] = elem->vertex(i);
173  coCoord[i] = posAcc[vVrt[i]];
174  }
175 
176  typename grid_type::template traits<side_type>::secure_container sides;
177 
178  UG_ASSERT(dynamic_cast<elem_type*>(elem) != NULL, "Only elements of type elem_type are currently supported");
179 
180  grid.associated_elements_sorted(sides, static_cast<elem_type*>(elem) );
181 
182  size_t nofsides = sides.size();
183  for (size_t s=0;s < nofsides;s++)
184  {
185  for (int d=0;d<spaceDim;d++){
186  // get indices of function fct on vertex
187  uCR.inner_dof_indices(sides[s], d, multInd);
188  // read value of index from vector
189  uValue[s][d]=DoFRef(uCR,multInd[0]);
190  }
191  }
192 
193  // evaluate finite volume geometry
194  geo.update(elem, &(coCoord[0]), uLagrange.domain()->subset_handler().get());
195  for(size_t i = 0; i < numVertices; ++i){
196  const typename DimFV1Geometry<dim>::SCV& scv = geo.scv(i);
197  number scvVol = scv.volume();
198  m_acVolume[vVrt[i]]+=scvVol;
199  std::vector<number> vShape;
200  crTrialSpace.shapes(vShape, scv.local_ip());
201  MathVector<dim> localValue = 0;
202  for (size_t s=0;s<nofsides;s++)
203  for (int d=0;d<spaceDim;d++)
204  localValue[d]+=vShape[s]*uValue[s][d];
205  for (int d=0;d<spaceDim;d++){
206  uLagrange.inner_dof_indices(vVrt[i], d, multInd);
207  DoFRef(uLagrange,multInd[0])+=scvVol*localValue[d];
208  }
209  }
210  if (uLagrange.num_fct()==dim+1){
211  uLagrange.inner_dof_indices(elem,dim,multInd);
212  DoFRef(uLagrange,multInd[0])=DoFRef(uCR,multInd[0]);
213  }
214  }
215  }
216  // finish computation by averaging
217  for(int si = 0; si < uLagrange.num_subsets(); ++si){
218  // get iterators
219  VertexIterator iter = uLagrange.template begin<Vertex>(si);
220  VertexIterator iterEnd = uLagrange.template end<Vertex>(si);
221  for( ;iter !=iterEnd; ++iter){
222  Vertex* vrt = *iter;
223  if (pbm && pbm->is_slave(vrt)) continue;
224  for (int d=0;d<spaceDim;d++){
225  uLagrange.inner_dof_indices(vrt, d, multInd);
226  DoFRef(uLagrange,multInd[0])/=m_acVolume[vrt];
227  }
228  }
229  }
230 }
231 
232 // compute vorticity
233 // for velocity field (u,v,w) the vorticity is \partial_x v - \partial_y u
234 template <typename TGridFunction>
235 void vorticityFVCR(TGridFunction& vort,TGridFunction& u)
236 {
238  typedef typename TGridFunction::domain_type domain_type;
239 
241  typedef typename domain_type::grid_type grid_type;
242 
244  static const int dim = domain_type::dim;
245 
246  // get grid
247  grid_type& grid = *u.domain()->grid();
248 
249  // position accessor type
251 
253  typedef typename TGridFunction::template dim_traits<dim>::grid_base_object elem_type;
254 
256  typedef typename elem_type::side side_type;
257 
258  // volume attachment
260  aSideNumber m_acVolume;
261  ANumber m_aVolume;
262 
264  typedef typename TGridFunction::template dim_traits<dim>::const_iterator ElemIterator;
265 
267  typedef typename TGridFunction::template traits<side_type>::const_iterator SideIterator;
268 
269  // get position accessor
271  position_accessor_type& posAcc = u.domain()->position_accessor();
272 
274 
275  grid.template attach_to<side_type>(m_aVolume);
276  m_acVolume.access(grid,m_aVolume);
277 
278  SetAttachmentValues(m_acVolume,grid.template begin<side_type>(), grid.template end<side_type>(), 0);
279 
280  if (vort.local_finite_element_id(0) != LFEID(LFEID::CROUZEIX_RAVIART, dim, 1)){
281  UG_THROW("Component " << 0 << " in approximation space of parameter 1 must be of Crouzeix-Raviart type.");
282  }
283 
284  for (int d=0;d<dim;d++){
285  if (u.local_finite_element_id(d) != LFEID(LFEID::CROUZEIX_RAVIART, dim, 1)){
286  UG_THROW("Component " << d << " in approximation space of parameter 2 must be of Crouzeix-Raviart type.");
287  }
288  }
289 
290  PeriodicBoundaryManager* pbm = grid.periodic_boundary_manager();
291 
292  // coord and vertex array
295 
296  // create Multiindex
297  std::vector<DoFIndex> multInd;
298 
299  for(int si = 0; si < u.num_subsets(); ++si)
300  {
301  if (si>0) continue;
302  // get iterators
303  ElemIterator iter = u.template begin<elem_type>(si);
304  ElemIterator iterEnd = u.template end<elem_type>(si);
305 
306  // loop elements of dimension
307  for( ;iter !=iterEnd; ++iter)
308  {
309  // get Elem
310  elem_type* elem = *iter;
311  // get vertices and extract corner coordinates
312  const size_t numVertices = elem->num_vertices();
313  for(size_t i = 0; i < numVertices; ++i){
314  vVrt[i] = elem->vertex(i);
315  coCoord[i] = posAcc[vVrt[i]];
316  }
317  // evaluate finite volume geometry
318  geo.update(elem, &(coCoord[0]), u.domain()->subset_handler().get());
319 
320  size_t nofsides = geo.num_scv();
321 
322  typename grid_type::template traits<side_type>::secure_container sides;
323 
324  UG_ASSERT(dynamic_cast<elem_type*>(elem) != NULL, "Only elements of type elem_type are currently supported");
325 
326  grid.associated_elements_sorted(sides, static_cast<elem_type*>(elem) );
327 
328  static const size_t MaxNumSidesOfElem = 18;
329 
330  typedef MathVector<dim> MVD;
331  std::vector<MVD> uValue(MaxNumSidesOfElem);
332 
333  for (size_t s=0;s < nofsides;s++)
334  {
335  for (int d=0;d<dim;d++){
336  // get indices of function fct on vertex
337  u.dof_indices(sides[s], d, multInd);
338  // read value of index from vector
339  uValue[s][d]=DoFRef(u,multInd[0]);
340  }
341  }
342 
343  for (size_t s=0;s < nofsides;s++)
344  {
345  number localvort = 0;
346  const typename DimCRFVGeometry<dim>::SCV& scv = geo.scv(s);
347 
348  for(size_t sh = 0 ; sh < nofsides; ++sh){
349  localvort += uValue[sh][1] * scv.global_grad(sh)[0] - uValue[sh][0] * scv.global_grad(sh)[1];
350  };
351 
352  number vol = scv.volume();
353 
354  localvort*=vol;
355 
356  vort.dof_indices(sides[s], 0, multInd);
357  DoFRef(vort,multInd[0])+=localvort;
358  m_acVolume[sides[s]] += vol;
359  }
360  }
361  }
362  // average vorticity
363  number maxvort = 0;
364  for(int si = 0; si < u.num_subsets(); ++si)
365  {
366  SideIterator sideIter = vort.template begin<side_type>(si);
367  SideIterator sideIterEnd = vort.template end<side_type>(si);
368  for( ;sideIter !=sideIterEnd; sideIter++)
369  {
370  // get Elem
371  side_type* elem = *sideIter;
372  // if periodic slave continue
373  if (pbm && pbm->is_slave(elem)) continue;
374  vort.dof_indices(elem, 0, multInd);
375  DoFRef(vort,multInd[0])/=m_acVolume[elem];
376  //UG_LOG("[" << 0.5*(posAcc[elem->vertex(0)][0] + posAcc[elem->vertex(0)][0]) << "," <<
377  // 0.5*(posAcc[elem->vertex(0)][1] + posAcc[elem->vertex(0)][1]) << "]" << " " << DoFRef(vort,multInd[0]) << "\n");
378  if (DoFRef(vort,multInd[0])*DoFRef(vort,multInd[0])>maxvort*maxvort){
379  maxvort = DoFRef(vort,multInd[0]);
380  }
381  }
382  }
383  grid.template detach_from<side_type>(m_aVolume);
384 }
385 
386 template <typename TGridFunction>
387 void vorticityFV1(TGridFunction& vort,TGridFunction& u)
388 {
390  typedef typename TGridFunction::domain_type domain_type;
391 
393  typedef typename domain_type::grid_type grid_type;
394 
396  static const int dim = domain_type::dim;
397 
398  // get grid
399  grid_type& grid = *u.domain()->grid();
400 
401  // position accessor type
403 
405  typedef typename TGridFunction::template dim_traits<dim>::grid_base_object elem_type;
406 
407  // volume attachment
409  aSideNumber m_acVolume;
410  ANumber m_aVolume;
411 
413  typedef typename TGridFunction::template dim_traits<dim>::const_iterator ElemIterator;
414 
416  typedef typename TGridFunction::template traits<Vertex>::const_iterator VertexConstIterator;
417 
418  // get position accessor
420  position_accessor_type& posAcc = u.domain()->position_accessor();
421 
423 
424  grid.template attach_to<Vertex>(m_aVolume);
425  m_acVolume.access(grid,m_aVolume);
426 
427  SetAttachmentValues(m_acVolume,grid.template begin<Vertex>(), grid.template end<Vertex>(), 0);
428 
429  if (vort.local_finite_element_id(0) != LFEID(LFEID::LAGRANGE, dim, 1)){
430  UG_THROW("Component " << 0 << " in approximation space of parameter 1 must be of Crouzeix-Raviart type.");
431  }
432 
433  for (int d=0;d<dim;d++){
434  if (u.local_finite_element_id(d) != LFEID(LFEID::LAGRANGE, dim, 1)){
435  UG_THROW("Component " << d << " in approximation space of parameter 2 must be of Crouzeix-Raviart type.");
436  }
437  }
438 
439  PeriodicBoundaryManager* pbm = grid.periodic_boundary_manager();
440 
441  // coord and vertex array
444 
445  // create Multiindex
446  std::vector<DoFIndex> multInd;
447 
448  for(int si = 0; si < u.num_subsets(); ++si)
449  {
450  if (si>0) continue;
451  // get iterators
452  ElemIterator iter = u.template begin<elem_type>(si);
453  ElemIterator iterEnd = u.template end<elem_type>(si);
454 
455  // loop elements of dimension
456  for( ;iter !=iterEnd; ++iter)
457  {
458  // get Elem
459  elem_type* elem = *iter;
460  // get vertices and extract corner coordinates
461  const size_t numVertices = elem->num_vertices();
462  for(size_t i = 0; i < numVertices; ++i){
463  vVrt[i] = elem->vertex(i);
464  coCoord[i] = posAcc[vVrt[i]];
465  // UG_LOG("co_coord(" << i<< "+1,:)=" << coCoord[i] << "\n");
466  }
467  // evaluate finite volume geometry
468  geo.update(elem, &(coCoord[0]), u.domain()->subset_handler().get());
469 
470  static const size_t MaxNumSidesOfElem = 18;
471 
472  typedef MathVector<dim> MVD;
473  std::vector<MVD> uValue(MaxNumSidesOfElem);
474 
475  for (size_t co=0;co < numVertices;co++)
476  {
477  for (int d=0;d<dim;d++){
478  // get indices of function fct on vertex
479  u.dof_indices(elem->vertex(co), d, multInd);
480  // read value of index from vector
481  uValue[co][d]=DoFRef(u,multInd[0]);
482  }
483  }
484 
485  for (size_t co=0;co < numVertices;co++)
486  {
487  number localvort = 0;
488  const typename DimFV1Geometry<dim>::SCV& scv = geo.scv(co);
489 
490  for(size_t sh = 0 ; sh < scv.num_sh(); ++sh){
491  localvort += uValue[sh][1] * scv.global_grad(sh)[0] - uValue[sh][0] * scv.global_grad(sh)[1];
492  };
493 
494  number vol = scv.volume();
495 
496  localvort*=vol;
497 
498  vort.dof_indices(elem->vertex(co), 0, multInd);
499  DoFRef(vort,multInd[0])+=localvort;
500  m_acVolume[elem->vertex(co)] += vol;
501  }
502  }
503  }
504  // average vorticity
505  number maxvort = 0;
506  for(int si = 0; si < u.num_subsets(); ++si)
507  {
508  // average vorticity
509  VertexConstIterator vertexIter = vort.template begin<Vertex>(si);
510  VertexConstIterator vertexIterEnd = vort.template end<Vertex>(si);
511  for( ;vertexIter !=vertexIterEnd; vertexIter++)
512  {
513  // get Elem
514  Vertex* vrt = *vertexIter;
515  // if periodic slave continue
516  if (pbm && pbm->is_slave(vrt)) continue;
517  vort.dof_indices(vrt, 0, multInd);
518  DoFRef(vort,multInd[0])/=m_acVolume[vrt];
519  if (DoFRef(vort,multInd[0])*DoFRef(vort,multInd[0])>maxvort*maxvort){
520  maxvort = DoFRef(vort,multInd[0]);
521  }
522  }
523  }
524  grid.template detach_from<Vertex>(m_aVolume);
525 }
526 
527 template <typename TGridFunction>
528 void vorticity(TGridFunction& vort,TGridFunction& u){
529  if (vort.local_finite_element_id(0) == LFEID(LFEID::LAGRANGE, TGridFunction::dim, 1)){
530  vorticityFV1<TGridFunction>(vort,u);
531  } else
532  if (vort.local_finite_element_id(0) == LFEID(LFEID::CROUZEIX_RAVIART, TGridFunction::dim, 1)){
533  vorticityFVCR<TGridFunction>(vort,u);
534  } else {
535  UG_LOG("Function type " << vort.local_finite_element_id(0) << " not supported in vorticity computation.");
536  }
537 }
538 
539 template <typename TGridFunction>
540 void DrivenCavityEvalAtPoints(const std::vector<MathVector<2> >& vPos,
542  const number vReferenceValue[])
543 {
544 #ifndef UG_DIM_3
545  number maxdiff = 0, diffsum = 0;
547  table(0,0)<<"#"; table(0,1)<<"Position";table(0,2)<<"Measure";table(0,3)<<"Reference";table(0,4)<<"Difference";
548  for(size_t i = 0; i < vPos.size(); ++i)
549  {
550  number val;
551  const number ref = vReferenceValue[i];
552  GFEval.evaluate_global(val, vPos[i]);
553  const number localdiff = std::abs(ref-val);
554  maxdiff = std::max(localdiff, maxdiff);
555  diffsum += localdiff;
556 
557  table(i+1, 0) << std::setw(2) << i+1;
558  table(i+1, 1) << std::fixed << std::setprecision(4) << vPos[i];
559  table(i+1, 2) << std::fixed << std::setprecision(8) << val;
560  table(i+1, 3) << std::fixed << std::setprecision(7) << ref;
561  table(i+1, 4) << std::scientific << std::setprecision( 3 ) << localdiff;
562  }
563  std::cout << table;
564  UG_LOG("\t Max Diff: " << maxdiff << "\n")
565  UG_LOG("\t Average Diff: " << diffsum/vPos.size() << "\n\n");
566 #else
567  UG_LOG("DrivenCavityEvalAtPoints: Failed. Compile without dimension 3 to use this command.\n");
568 #endif
569 }
570 
571 template <typename TGridFunction>
572 void DrivenCavityLinesEval(SmartPtr<TGridFunction> u, std::vector<std::string> vVelCmp, size_t Re)
573 {
574  // data from Ghia paper, see also cast3m implementation
575  const size_t numGhiaPoints = 17;
576 
577  const number vertGhiaPosX = 0.5;
578  const number vertGhiaPosY[17]={0.0000,0.0547,0.0625,0.0703,0.1016,0.1719,0.2813,0.4531,0.5000,0.6172,0.7344,0.8516,0.9531,0.9609,0.9688,0.9766,1.0000};
579  const number vertGhia_100[17] ={0.,-0.03717,-0.04192,-0.04775,-0.06434,-0.10150,-0.15662,-0.2109,-0.20581,-0.13641,0.00332,0.23151,0.68717,0.73722,0.78871,0.84123,1.};
580  const number vertGhia_400[17] ={0.,-0.08186,-0.09266,-0.10338,-0.14612,-0.24299,-0.32726,-0.17119,-0.11477,0.02135,0.16256,0.29093,0.55892,0.61756,0.68439,0.75837,1.};
581  const number vertGhia_1000[17] ={0.,-0.18109,-0.20196,-0.22220,-0.29730,-0.38289,-0.27805,-0.10648,-0.06080,0.05702,0.18719,0.33304,0.46604,0.51117,0.57492,0.65928,1.};
582  const number vertGhia_3200[17] ={0.00000,-0.32407,-0.35344,-0.37827,-0.41933,-0.34323,-0.24427,-0.086636,-0.04272,0.07156,0.19791,0.34682,0.46101,0.46547,0.48296,0.53236,1.00000};
583  const number vertGhia_5000[17] ={0.00000,-0.41165,-0.42901,-0.43643,-0.40435,-0.33050,-0.22855,-0.07404,-0.03039,0.08183,0.20087,0.33556,0.46036,0.45992,0.46120,0.48223,1.00000};
584  const number vertGhia_7500[17] ={0.00000,-0.43154,-0.43590,-0.43025,-0.38324,-0.32393,-0.23176,-0.07503,-0.03800,0.08342,0.20591,0.34228,0.47167,0.47323,0.47048,0.47244,1.00000};
585  const number vertGhia_10000[17]={0.00000,-0.42735,-0.42537,-0.41657,-0.38000,-0.32709,-0.23186,-0.07540,-0.03111,0.08344,0.20673,0.34635,0.47804,0.48070,0.47783,0.47221,1.00000};
586 
587  const number horizGhiaPosX[17]= {0.0000,0.0625,0.0703,0.0781,0.0938,0.1563,0.2266,0.2344,0.5000,0.8047,0.8594,0.9063,0.9453,0.9531,0.9609,0.9688,1.0000};
588  const number horizGhiaPosY = 0.5;
589  const number horizGhia100[17] ={0.00000,0.09233,0.10091,0.10890,0.12317,0.16077,0.17507,0.17527,0.05454,-0.24533,-0.22445,-0.16914,-0.10313,-0.08864,-0.07391,-0.05906,0.00000};
590  const number horizGhia400[17] ={0.00000,0.18360,0.19713,0.20920,0.22965,0.28124,0.30203,0.30174,0.05186,-0.38598,-0.44993,-0.3827,-0.22847,-0.19254,-0.15663,-0.12146,0.00000};
591  const number horizGhia1000[17] ={0.00000,0.27485,0.29012,0.30353,0.32627,0.37095,0.33075,0.32235,0.02526,-0.31966,-0.42665,-0.51550,-0.39188,-0.33714,-0.27669,-0.21388,0.00000};
592  const number horizGhia3200[17] ={0.00000,0.39560,0.40917,0.41906,0.42768,0.37119,0.29030,0.28188,0.00999,-0.31184,-0.37401,-0.44307,-0.54053,-0.52357,-0.47425,-0.39017,0.00000};
593  const number horizGhia5000[17] ={0.00000,0.42447,0.43329,0.43648,0.42951,0.35368,0.28066,0.27280,0.00945,-0.30018,-0.36214,-0.41442,-0.52876,-0.55408,-0.55069,-0.49774,0.00000};
594  const number horizGhia7500[17] ={0.00000,0.43979,0.44030,0.43564,0.41824,0.35060,0.28117,0.27348,0.00824,-0.30448,-0.36213,-0.41050,-0.48590,-0.52347,-0.55216,-0.53858,0.00000};
595  const number horizGhia10000[17]={0.00000,0.43983,0.43733,0.43124,0.41487,0.35070,0.28003,0.27224,0.00831,-0.30719,-0.36737,-0.41496,-0.45863,-0.49099,-0.52987,-0.54302,0.00000};
596 
597  const number* vertGhia = NULL;
598  const number* horizGhia = NULL;
599  switch (Re)
600  {
601  case 100: vertGhia = vertGhia_100; horizGhia = horizGhia100; break;
602  case 400: vertGhia = vertGhia_400; horizGhia = horizGhia400; break;
603  case 1000: vertGhia = vertGhia_1000; horizGhia = horizGhia1000; break;
604  case 3200: vertGhia = vertGhia_3200; horizGhia = horizGhia3200; break;
605  case 5000: vertGhia = vertGhia_5000; horizGhia = horizGhia5000; break;
606  case 7500: vertGhia = vertGhia_7500; horizGhia = horizGhia7500; break;
607  case 10000: vertGhia = vertGhia_10000; horizGhia = horizGhia10000; break;
608  default: break;
609  }
610 
611  // Botella reference data for Re=1000
612  const number vertBotella_1000[17]={0.0000000 , -0.1812881 , -0.2023300 , -0.2228955 , -0.3004561 , -0.3885691 , -0.2803696 , -0.1081999 , -0.0620561 ,
613  0.0570178 , 0.1886747 , 0.3372212 , 0.4723329 , 0.5169277 , 0.5808359 , 0.6644227 , 1.0000000};
614  const number horizBotella_1000[17]={0.0000000 , 0.2807056 , 0.2962703 , 0.3099097 , 0.3330442 , 0.3769189 , 0.3339924 , 0.3253592 , 0.0257995 ,
615  -0.3202137 , -0.4264545 , -0.5264392 , -0.4103754 , -0.3553213 , -0.2936869 , -0.2279225 , 0.0000000};
616 
617  // ug4 fvcr / linear upwind/linear pressure reference data for Re=3200 (computed on level 6)
618  const number vertUG4_3200[17]={0, -3.565562e-01, -3.854442e-01,-4.083199e-01,-4.329174e-01, -3.455453e-01,-2.425736e-01,-8.123961e-02,-3.689807e-02,7.721821e-02,2.018428e-01,
619  3.482477e-01,4.618284e-01,4.654109e-01,4.811885e-01,5.280763e-01,1};
620  const number horizUG4_3200[17]={0,3.961922e-01,4.113146e-01,4.224736e-01,4.327940e-01,3.771819e-01,2.964934e-01,2.881224e-01,1.425516e-02,-3.136940e-01,
621  -3.787908e-01,-4.436374e-01,-5.672544e-01,-5.610925e-01,-5.200556e-01,-4.390652e-01,0};
622 
623  // data from Erturk, Corke, Gkcl paper
624  const size_t numErturkPoints = 23;
625  const number vertErturkPosX = 0.5;
626  const number vertErturkPosY[23]={1.00000,0.99000,0.98000,0.97000,0.96000,0.95000,0.94000,0.93000,0.92000,0.91000,0.90000,0.50000,0.20000,0.18000,0.16000,0.14000,0.12000,0.10000,0.08000,0.06000,0.04000,0.02000,0.00000};
627  const number horizErturkPosX[23]={1.00000,0.98500,0.97000,0.95500,0.94000,0.92500,0.91000,0.89500,0.88000,0.86500,0.85000,0.50000,0.15000,0.13500,0.12000,0.10500,0.09000,0.07500,0.06000,0.04500,0.03000,0.01500,0.00000};
628  const number horizErturkPosY = 0.5;
629  const number horizErturk_1000[23] ={0.00000,-0.09730,-0.21730,-0.34000,-0.44170,-0.50520,-0.52630,-0.51320,-0.48030,-0.44070,-0.40280,0.02580,0.37560,0.37050,0.36050,0.34600,0.32730,0.30410,0.27460,0.23490,0.17920,0.10190,0.00000};
630  const number horizErturk_2500[23] ={0.0000,-0.1675,-0.3725,-0.5192,-0.5603,-0.5268,-0.4741,-0.4321,-0.4042,-0.3843,-0.3671,0.0160,0.3918,0.4078,0.4187,0.4217,0.4142,0.3950,0.3649,0.3238,0.2633,0.1607,0.0000};
631  const number horizErturk_5000[23] ={0.0000,-0.2441,-0.5019,-0.5700,-0.5139,-0.4595,-0.4318,-0.4147,-0.3982,-0.3806,-0.3624,0.0117,0.3699,0.3878,0.4070,0.4260,0.4403,0.4426,0.4258,0.3868,0.3263,0.2160,0.0000};
632  const number horizErturk_7500[23] ={0.0000,-0.2991,-0.5550,-0.5434,-0.4748,-0.4443,-0.4283,-0.4118,-0.3938,-0.3755,-0.3574,0.0099,0.3616,0.3779,0.3950,0.4137,0.4337,0.4495,0.4494,0.4210,0.3608,0.2509,0.0000};
633  const number horizErturk_10000[23]={0.0000,-0.3419,-0.5712,-0.5124,-0.4592,-0.4411,-0.4256,-0.4078,-0.3895,-0.3715,-0.3538,0.0088,0.3562,0.3722,0.3885,0.4056,0.4247,0.4449,0.4566,0.4409,0.3844,0.2756,0.0000};
634  const number horizErturk_12500[23]={0.0000,-0.3762,-0.5694,-0.4899,-0.4534,-0.4388,-0.4221,-0.4040,-0.3859,-0.3682,-0.3508,0.0080,0.3519,0.3678,0.3840,0.4004,0.4180,0.4383,0.4563,0.4522,0.4018,0.2940,0.0000};
635  const number horizErturk_15000[23]={0.0000,-0.4041,-0.5593,-0.4754,-0.4505,-0.4361,-0.4186,-0.4005,-0.3828,-0.3654,-0.3481,0.0074,0.3483,0.3641,0.3801,0.3964,0.4132,0.4323,0.4529,0.4580,0.4152,0.3083,0.0000};
636  const number horizErturk_17500[23]={0.0000,-0.4269,-0.5460,-0.4664,-0.4482,-0.4331,-0.4153,-0.3975,-0.3800,-0.3627,-0.3457,0.0069,0.3452,0.3608,0.3767,0.3929,0.4093,0.4273,0.4484,0.4602,0.4254,0.3197,0.0000};
637  const number horizErturk_20000[23]={0.0000,-0.4457,-0.5321,-0.4605,-0.4459,-0.4300,-0.4122,-0.3946,-0.3774,-0.3603,-0.3434,0.0065,0.3423,0.3579,0.3736,0.3897,0.4060,0.4232,0.4438,0.4601,0.4332,0.3290,0.0000};
638  const number horizErturk_21000[23]={0.0000,-0.4522,-0.5266,-0.4588,-0.4449,-0.4287,-0.4110,-0.3936,-0.3764,-0.3593,-0.3425,0.0063,0.3413,0.3567,0.3725,0.3885,0.4048,0.4218,0.4420,0.4596,0.4357,0.3323,0.0000};
639  const number vertErturk_1000[23] ={1.00000,0.84860,0.70650,0.59170,0.51020,0.45820,0.42760,0.41010,0.39930,0.39130,0.38380,-0.06200,-0.37560,-0.38690,-0.38540,-0.36900,-0.33810,-0.29600,-0.24720,-0.19510,-0.13920,-0.07570,0.00000};
640  const number vertErturk_2500[23] ={1.0000,0.7704,0.5924,0.4971,0.4607,0.4506,0.4470,0.4424,0.4353,0.4256,0.4141,-0.0403,-0.3228,-0.3439,-0.3688,-0.3965,-0.4200,-0.4250,-0.3979,-0.3372,-0.2547,-0.1517,0.0000};
641  const number vertErturk_5000[23] ={1.0000,0.6866,0.5159,0.4749,0.4739,0.4738,0.4683,0.4582,0.4452,0.4307,0.4155,-0.0319,-0.3100,-0.3285,-0.3467,-0.3652,-0.3876,-0.4168,-0.4419,-0.4272,-0.3480,-0.2223,0.0000};
642  const number vertErturk_7500[23] ={1.0000,0.6300,0.4907,0.4817,0.4860,0.4824,0.4723,0.4585,0.4431,0.4275,0.4123,-0.0287,-0.3038,-0.3222,-0.3406,-0.3587,-0.3766,-0.3978,-0.4284,-0.4491,-0.3980,-0.2633,0.0000};
643  const number vertErturk_10000[23]={1.0000,0.5891,0.4837,0.4891,0.4917,0.4843,0.4711,0.4556,0.4398,0.4243,0.4095,-0.0268,-0.2998,-0.3179,-0.3361,-0.3543,-0.3721,-0.3899,-0.4142,-0.4469,-0.4259,-0.2907,0.0000};
644  const number vertErturk_12500[23]={1.0000,0.5587,0.4833,0.4941,0.4937,0.4833,0.4684,0.4523,0.4366,0.4216,0.4070,-0.0256,-0.2967,-0.3146,-0.3326,-0.3506,-0.3685,-0.3859,-0.4054,-0.4380,-0.4407,-0.3113,0.0000};
645  const number vertErturk_15000[23]={1.0000,0.5358,0.4850,0.4969,0.4937,0.4811,0.4653,0.4492,0.4338,0.4190,0.4047,-0.0247,-0.2942,-0.3119,-0.3297,-0.3474,-0.3652,-0.3827,-0.4001,-0.4286,-0.4474,-0.3278,0.0000};
646  const number vertErturk_17500[23]={1.0000,0.5183,0.4871,0.4982,0.4925,0.4784,0.4622,0.4463,0.4312,0.4166,0.4024,-0.0240,-0.2920,-0.3096,-0.3271,-0.3446,-0.3622,-0.3797,-0.3965,-0.4206,-0.4490,-0.3412,0.0000};
647  const number vertErturk_20000[23]={1.0000,0.5048,0.4889,0.4985,0.4906,0.4754,0.4592,0.4436,0.4287,0.4142,0.4001,-0.0234,-0.2899,-0.3074,-0.3248,-0.3422,-0.3595,-0.3769,-0.3936,-0.4143,-0.4475,-0.3523,0.0000};
648  const number vertErturk_21000[23]={1.0000,0.5003,0.4895,0.4983,0.4897,0.4742,0.4580,0.4425,0.4277,0.4132,0.3992,-0.0232,-0.2892,-0.3066,-0.3239,-0.3412,-0.3585,-0.3758,-0.3925,-0.4121,-0.4463,-0.3562,0.0000};
649 
650 
651  const number* horizErturk = NULL;
652  const number* vertErturk = NULL;
653  switch (Re)
654  {
655  case 1000: horizErturk = horizErturk_1000; vertErturk = vertErturk_1000; break;
656  case 2500: horizErturk = horizErturk_2500; vertErturk = vertErturk_2500; break;
657  case 5000: horizErturk = horizErturk_5000; vertErturk = vertErturk_5000; break;
658  case 7500: horizErturk = horizErturk_7500; vertErturk = vertErturk_7500; break;
659  case 10000: horizErturk = horizErturk_10000; vertErturk = vertErturk_10000; break;
660  case 15000: horizErturk = horizErturk_15000; vertErturk = vertErturk_15000; break;
661  case 12500: horizErturk = horizErturk_12500; vertErturk = vertErturk_12500; break;
662  case 17500: horizErturk = horizErturk_17500; vertErturk = vertErturk_17500; break;
663  case 20000: horizErturk = horizErturk_20000; vertErturk = vertErturk_20000; break;
664  case 21000: horizErturk = horizErturk_21000; vertErturk = vertErturk_21000; break;
665  default: break;
666  }
667 
668  // create Evaluation UserData
669  GlobalGridFunctionNumberData<TGridFunction> uGFEval(u, vVelCmp[0].c_str());
670  GlobalGridFunctionNumberData<TGridFunction> vGFEval(u, vVelCmp[1].c_str());
671  std::vector<MathVector<2> > vPos(numGhiaPoints);
672 
673  if(vertGhia != NULL && horizGhia != NULL)
674  {
675  UG_LOG(" ------ Ghia, Re = " << Re << ": u values on a vertical line through x = 0.5 ------\n");
676  for(size_t i = 0; i < numGhiaPoints; ++i) vPos[i] = MathVector<2>(vertGhiaPosX, vertGhiaPosY[i]);
677  DrivenCavityEvalAtPoints<TGridFunction>(vPos, uGFEval, vertGhia);
678 
679  UG_LOG(" ------ Ghia, Re = " << Re << ": v values on a horizontal line through y = 0.5 ------\n");
680  for(size_t i = 0; i < numGhiaPoints; ++i) vPos[i] = MathVector<2>(horizGhiaPosX[i], horizGhiaPosY);
681  DrivenCavityEvalAtPoints<TGridFunction>(vPos, vGFEval, horizGhia);
682  }
683 
684  if (Re==1000)
685  {
686  UG_LOG(" ------ Botella/Peyret, Re = " << Re << ": u values on a vertical line through x = 0.5 ------\n");
687  for(size_t i = 0; i < numGhiaPoints; ++i) vPos[i] = MathVector<2>(vertGhiaPosX, vertGhiaPosY[i]);
688  DrivenCavityEvalAtPoints<TGridFunction>(vPos, uGFEval, vertBotella_1000);
689 
690  UG_LOG(" ------ Botella/Peyret, Re = " << Re << ": v values on a horizontal line through y = 0.5 ------\n");
691  for(size_t i = 0; i < numGhiaPoints; ++i) vPos[i] = MathVector<2>(horizGhiaPosX[i], horizGhiaPosY);
692  DrivenCavityEvalAtPoints<TGridFunction>(vPos, vGFEval, horizBotella_1000);
693  }
694 
695  if (Re==3200)
696  {
697  UG_LOG(" ------ ug4, Re = " << Re << ": u values on a vertical line through x = 0.5 ------\n");
698  for(size_t i = 0; i < numGhiaPoints; ++i) vPos[i] = MathVector<2>(vertGhiaPosX, vertGhiaPosY[i]);
699  DrivenCavityEvalAtPoints<TGridFunction>(vPos, uGFEval, vertUG4_3200);
700 
701  UG_LOG(" ------ ug4, Re = " << Re << ": v values on a horizontal line through y = 0.5 ------\n");
702  for(size_t i = 0; i < numGhiaPoints; ++i) vPos[i] = MathVector<2>(horizGhiaPosX[i], horizGhiaPosY);
703  DrivenCavityEvalAtPoints<TGridFunction>(vPos, vGFEval, horizUG4_3200);
704  }
705 
706  if(horizErturk != NULL && vertErturk != NULL)
707  {
708  vPos.resize(numErturkPoints);
709  UG_LOG(" ------ Erturk, Re = " << Re << ": u values on a vertical line through x = 0.5 ------\n");
710  for(size_t i = 0; i < numErturkPoints; ++i) vPos[i] = MathVector<2>(vertErturkPosX, vertErturkPosY[i]);
711  DrivenCavityEvalAtPoints<TGridFunction>(vPos, uGFEval, vertErturk);
712 
713  UG_LOG(" ------ Erturk, Re = " << Re << ": v values on a horizontal line through y = 0.5 ------\n");
714  for(size_t i = 0; i < numErturkPoints; ++i) vPos[i] = MathVector<2>(horizErturkPosX[i], horizErturkPosY);
715  DrivenCavityEvalAtPoints<TGridFunction>(vPos, vGFEval, horizErturk);
716  }
717 }
718 
719 /*
720 // Computation of maximum CFL-number over elements
721 // General CFL number is given as |u|*deltaT/h where u is velocity, deltaT time step length
722 // and h mesh width.
723 // Here following approximation for element local CFL-number is used:
724 // In element compute interpolated velocity v_bary in barycenter
725 // go over all "edges" between Crouzeix-Raviart nodes c_i and c_j (middle of edge/face)
726 // approximate velocity between nodes is 1/|c_i-c_j|*|(c_i-c_j)*v_bary|
727 // step length is |c_i-c_j| Therefore overall local cfl number is
728 // 1/|c_i-c_j|^2*|(c_i-c_j)*v_bary|
729 // Function computes maximum over all elements.
730  */
731 template<typename TGridFunction>
732 void cflNumber(TGridFunction& u,number deltaT){
734  typedef typename TGridFunction::domain_type domain_type;
735 
737  static const int dim = domain_type::dim;
738 
740  typedef typename TGridFunction::template dim_traits<dim>::const_iterator ElemIterator;
741 
743  typedef typename TGridFunction::template dim_traits<dim>::grid_base_object elem_type;
744 
746  typedef typename elem_type::side side_type;
747 
749  typedef typename domain_type::grid_type grid_type;
750 
751  // cfl number
752  number maxCfl=0;
753  // get domain
754  domain_type& domain = *u.domain().get();
755 
757 
758  // create Multiindex
759  std::vector<DoFIndex > multInd;
760 
761  // coord and vertex array
764 
765  // get position accessor
767  const position_accessor_type& posAcc = domain.position_accessor();
768 
769  for(int si = 0; si < domain.subset_handler()->num_subsets(); ++si)
770  {
771  // get iterators
772  ElemIterator iter = u.template begin<elem_type>(si);
773  ElemIterator iterEnd = u.template end<elem_type>(si);
774 
775  // loop elements of dimension
776  for( ;iter !=iterEnd; ++iter)
777  {
778  // get Elem
779  elem_type* elem = *iter;
780  // get vertices and extract corner coordinates
781  const size_t numVertices = elem->num_vertices();
782  MathVector<dim> bary,localBary;
783  bary = 0;
784 
785  for(size_t i = 0; i < numVertices; ++i){
786  vVrt[i] = elem->vertex(i);
787  coCoord[i] = posAcc[vVrt[i]];
788  bary += coCoord[i];
789  };
790  bary /= numVertices;
791 
792  // reference object id
793  ReferenceObjectID roid = elem->reference_object_id();
794 
795  // get trial space
796  const LocalShapeFunctionSet<dim>& rTrialSpace =
797  LocalFiniteElementProvider::get<dim>(roid, LFEID(LFEID::CROUZEIX_RAVIART, dim, 1));
798 
799  // get Reference Mapping
800  DimReferenceMapping<dim, dim>& map = ReferenceMappingProvider::get<dim, dim>(roid, coCoord);
801 
802  map.global_to_local(localBary,bary);
803 
804  typename grid_type::template traits<side_type>::secure_container sides;
805 
806  UG_ASSERT(dynamic_cast<elem_type*>(elem) != NULL, "Only elements of type elem_type are currently supported");
807 
808  domain.grid()->associated_elements_sorted(sides, static_cast<elem_type*>(elem) );
809 
810  // memory for shapes
811  std::vector<number> vShape;
812 
813  // evaluate finite volume geometry
814  geo.update(elem, &(coCoord[0]), domain.subset_handler().get());
815 
816  rTrialSpace.shapes(vShape, localBary);
817 
818  size_t nofsides = geo.num_scv();
819 
820  MathVector<dim> baryV;
821  baryV = 0;
822  for (size_t s=0;s<nofsides;s++){
823  MathVector<dim> localbaryV;
824  for (int d=0;d<dim;d++){
825  u.dof_indices(sides[s], d, multInd);
826  localbaryV[d]=DoFRef(u,multInd[0]);
827  }
828  localbaryV *= vShape[s];
829  baryV += localbaryV;
830  }
831  for (size_t i=0;i<nofsides;i++){
832  const typename DimCRFVGeometry<dim>::SCV& scvi = geo.scv(i);
833  MathVector<dim> iCoord = scvi.global_ip();
834  for (size_t j=i+1;j<nofsides;j++){
835  const typename DimCRFVGeometry<dim>::SCV& scvj = geo.scv(j);
836  MathVector<dim> jCoord = scvj.global_ip();
837  MathVector<dim> subVec;
838  VecSubtract(subVec,iCoord,jCoord);
839  number localCfl=deltaT*(number)1.0/VecTwoNormSq(subVec)*std::abs(subVec*baryV);
840  if (localCfl>maxCfl) maxCfl=localCfl;
841  }
842  }
843  }
844  }
845  UG_LOG("Max CFL number is " << maxCfl << "\n");
846 }
847 
848 // Compute 1/|\Omega| \int_{\Omega} \hat{u_i} \hat{u_i} dx , where \Omega is the computational domain.
849 // Elementwise approximation of integral by interpolation to barycenter.
850 template<typename TGridFunction>
851 number kineticEnergy(TGridFunction& u){
852  // total kinetic energy
853  number totalE=0;
854  // total volume
855  number totalVol=0;
856 
858  typedef typename TGridFunction::domain_type domain_type;
859 
861  static const int dim = domain_type::dim;
862 
864  typedef typename TGridFunction::template dim_traits<dim>::const_iterator ElemIterator;
865 
867  typedef typename TGridFunction::template dim_traits<dim>::grid_base_object elem_type;
868 
870  typedef typename elem_type::side side_type;
871 
873  typedef typename domain_type::grid_type grid_type;
874 
875  // get domain of grid function
876  domain_type& domain = *u.domain().get();
878 
879  std::vector<DoFIndex> multInd;
880 
881  // coord and vertex array
884 
885  // get position accessor
887  const position_accessor_type& posAcc = domain.position_accessor();
888 
889  // assemble deformation tensor fluxes
890  for(int si = 0; si < domain.subset_handler()->num_subsets(); ++si)
891  {
892  // get iterators
893  ElemIterator iter = u.template begin<elem_type>(si);
894  ElemIterator iterEnd = u.template end<elem_type>(si);
895 
896  // loop elements of dimension
897  for( ;iter !=iterEnd; ++iter)
898  {
899  // get Elem
900  elem_type* elem = *iter;
901  // get vertices and extract corner coordinates
902  const size_t numVertices = elem->num_vertices();
903  MathVector<dim> bary,localBary;
904  bary = 0;
905 
906  for(size_t i = 0; i < numVertices; ++i){
907  vVrt[i] = elem->vertex(i);
908  coCoord[i] = posAcc[vVrt[i]];
909  bary += coCoord[i];
910  };
911  bary /= numVertices;
912 
913  // reference object id
914  ReferenceObjectID roid = elem->reference_object_id();
915 
916  // get trial space
917  const LocalShapeFunctionSet<dim>& rTrialSpace =
918  LocalFiniteElementProvider::get<dim>(roid, LFEID(LFEID::CROUZEIX_RAVIART, dim, 1));
919 
920  // get Reference Mapping
921  DimReferenceMapping<dim, dim>& map = ReferenceMappingProvider::get<dim, dim>(roid, coCoord);
922 
923  map.global_to_local(localBary,bary);
924 
925  typename grid_type::template traits<side_type>::secure_container sides;
926 
927  UG_ASSERT(dynamic_cast<elem_type*>(elem) != NULL, "Only elements of type elem_type are currently supported");
928 
929  domain.grid()->associated_elements_sorted(sides, static_cast<elem_type*>(elem) );
930 
931  // memory for shapes
932  std::vector<number> vShape;
933 
934  // evaluate finite volume geometry
935  geo.update(elem, &(coCoord[0]), domain.subset_handler().get());
936 
937  rTrialSpace.shapes(vShape, localBary);
938 
939  size_t nofsides = geo.num_scv();
940 
941  MathVector<dim> value;
942  value = 0;
943  number elementVolume = 0;
944  for (size_t s=0;s<nofsides;s++){
945  const typename DimCRFVGeometry<dim>::SCV& scv = geo.scv(s);
946  MathVector<dim> localValue;
947  for (int d=0;d<dim;d++){
948  u.dof_indices(sides[s], d, multInd);
949  localValue[d]=DoFRef(u,multInd[0]);
950  }
951  localValue *= vShape[s];
952  value += localValue;
953  elementVolume += scv.volume();
954  }
955  for (int d=0;d<dim;d++){
956  totalE += elementVolume*value[d]*value[d];
957  }
958 
959  totalVol+=elementVolume;
960  }
961  }
962  // average
963  totalE/=(number)totalVol;
964  UG_LOG("Total kinetic energy in domain is " << totalE << "\n");
965  return totalE;
966 }
967 
968 // clear file content
969 /* void clearFile(std::string filename){
970  std::fstream file(filename.c_str(), std::fstream::out | std::fstream::trunc);
971 }
972 */
973 // write numbers into file
974 /* void writeNumbers(std::string filename,const size_t step,const number t,const number data){
975  std::fstream file(filename.c_str(), std::fstream::out | std::fstream::app);
976  file << "t(" << step << ")=" << t << ";d(" << step << ")=" << data << ";" << std::endl;
977 }
978 */
979 
980 
981 template <typename TGridFunction>
982 std::vector<number> DragLift(SmartPtr<TGridFunction> spGridFct,
983  const char* vCmp,
984  const char* BndSubsets, const char* InnerSubsets,
985  number kinVisco, number density,
986  int quadOrder)
987 {
988  static const int dim = TGridFunction::dim;
989  static const int WorldDim = TGridFunction::dim;
990  typedef typename TGridFunction::template dim_traits<dim>::grid_base_object grid_base_object;
991  typedef typename TGridFunction::template dim_traits<dim>::const_iterator const_iterator;
992 
993 
994 // read subsets
995  SubsetGroup innerSSGrp(spGridFct->domain()->subset_handler());
996  if(InnerSubsets != NULL){
997  innerSSGrp.add(TokenizeString(InnerSubsets));
998  if(!SameDimensionsInAllSubsets(innerSSGrp))
999  UG_THROW("DragDrift: Subsets '"<<InnerSubsets<<"' do not have same dimension."
1000  "Can not integrate on subsets of different dimensions.");
1001  }
1002  else{
1003  innerSSGrp.add_all();
1004  RemoveLowerDimSubsets(innerSSGrp);
1005  }
1006 
1007 // read subsets
1008  SubsetGroup bndSSGrp(spGridFct->domain()->subset_handler());
1009  if(BndSubsets != NULL)
1010  bndSSGrp.add(TokenizeString(BndSubsets));
1011  else
1012  UG_THROW("DragDrift: No boundary subsets passed.");
1013 
1014 // get function group
1015  const FunctionGroup vFctID = spGridFct->fct_grp_by_name(vCmp);
1016  std::vector<LFEID> vLFEID;
1017  for(size_t fct = 0; fct < vFctID.size(); ++fct){
1018  vLFEID.push_back(spGridFct->lfeid(vFctID[fct]));
1019  }
1020 
1021 // reset the result
1022  number int_lift = 0;
1023  number int_drag = 0;
1024 
1025 // loop subsets
1026  for(size_t i = 0; i < innerSSGrp.size(); ++i)
1027  {
1028  // get subset index
1029  const int si = innerSSGrp[i];
1030 
1031  // skip empty subset
1032  if(innerSSGrp.dim(i) == DIM_SUBSET_EMPTY_GRID) continue;
1033 
1034  // check dimension
1035  if(innerSSGrp.dim(i) != dim)
1036  UG_THROW("DragDrift: Dimension of inner subset is "<<
1037  innerSSGrp.dim(i)<<", but only World Dimension "<<dim<<
1038  " subsets can be used for inner subsets.");
1039 
1040  // note: this iterator is for the base elements, e.g. Face and not
1041  // for the special type, e.g. Triangle, Quadrilateral
1042  const_iterator iterBegin = spGridFct->template begin<grid_base_object>(si);
1043  const_iterator iterEnd = spGridFct->template end<grid_base_object>(si);
1044  const_iterator iter = iterBegin;
1045 
1047  = spGridFct->domain()->position_accessor();
1048  const ISubsetHandler* ish = spGridFct->domain()->subset_handler().get();
1049  Grid& grid = *spGridFct->domain()->grid();
1050 
1051  // this is the base element type (e.g. Face). This is the type when the
1052  // iterators above are dereferenciated.
1053  typedef typename domain_traits<dim>::element_type Element;
1054  typedef typename domain_traits<dim>::side_type Side;
1055 
1056  // vector of corner coordinates of element corners (to be filled for each elem)
1057  std::vector<MathVector<WorldDim> > vCorner;
1058  std::vector<int> vSubsetIndex;
1059 
1060  // iterate over all elements
1061  for(; iter != iterEnd; ++iter)
1062  {
1063  // get element
1064  Element* pElem = *iter;
1065 
1066  // get all corner coordinates
1067  CollectCornerCoordinates(vCorner, *pElem, aaPos, true);
1068 
1069  // get reference object id
1070  const ReferenceObjectID elemRoid = pElem->reference_object_id();
1071 
1072  // get sides
1073  typename Grid::traits<Side>::secure_container vSide;
1074  grid.associated_elements_sorted(vSide, pElem);
1075  vSubsetIndex.resize(vSide.size());
1076  for(size_t i = 0; i < vSide.size(); ++i)
1077  vSubsetIndex[i] = ish->get_subset_index(vSide[i]);
1078 
1080  = ReferenceMappingProvider::get<dim, WorldDim>(elemRoid, vCorner);
1081 
1082  const DimReferenceElement<dim>& rRefElem
1083  = ReferenceElementProvider::get<dim>(elemRoid);
1084 
1085  // get element values
1086  std::vector<DoFIndex> vInd;
1087  std::vector<std::vector<number> > vvValue(vFctID.size());
1088  for(size_t fct = 0; fct < vvValue.size(); ++fct){
1089  spGridFct->dof_indices(pElem, vFctID[fct], vInd);
1090  vvValue[fct].resize(vInd.size());
1091  for(size_t sh = 0; sh < vInd.size(); ++sh)
1092  vvValue[fct][sh] = DoFRef(*spGridFct, vInd[sh]);
1093  }
1094  const static int _P_ = dim;
1095 
1096  // loop sub elements
1097  for(size_t side = 0; side < vSide.size(); ++side)
1098  {
1099  // check if side used
1100  if(!bndSSGrp.contains(vSubsetIndex[side])) continue;
1101 
1102  // get side
1103  Side* pSide = vSide[side];
1104 
1105  std::vector<MathVector<WorldDim> > vSideCorner(rRefElem.num(dim-1, side, 0));
1106  std::vector<MathVector<dim> > vLocalSideCorner(rRefElem.num(dim-1, side, 0));
1107  for(size_t co = 0; co < vSideCorner.size(); ++co){
1108  vSideCorner[co] = vCorner[rRefElem.id(dim-1, side, 0, co)];
1109  vLocalSideCorner[co] = rRefElem.corner(rRefElem.id(dim-1, side, 0, co));
1110  }
1111 
1112  // side quad rule
1113  const ReferenceObjectID sideRoid = pSide->reference_object_id();
1114  const QuadratureRule<dim-1>& rSideQuadRule
1115  = QuadratureRuleProvider<dim-1>::get(sideRoid, quadOrder);
1116 
1117  // normal
1118  MathVector<WorldDim> Normal;
1119  ElementNormal<WorldDim>(sideRoid, Normal, &vSideCorner[0]);
1120  VecNormalize(Normal, Normal);
1121  VecScale(Normal, Normal, -1); // inner normal
1122 
1123  // a tangental
1124  MathVector<WorldDim> Tangental(0.0);
1125  Tangental[0] = Normal[dim-1];
1126  Tangental[dim-1] = -Normal[0];
1127 
1128  // quadrature points
1129  const number* vWeight = rSideQuadRule.weights();
1130  const size_t nip = rSideQuadRule.size();
1131  std::vector<MathVector<dim> > vLocalIP(nip);
1132  std::vector<MathVector<dim> > vGlobalIP(nip);
1133 
1134  DimReferenceMapping<dim-1, dim>& map
1135  = ReferenceMappingProvider::get<dim-1, dim>(sideRoid, vLocalSideCorner);
1136 
1137  for(size_t ip = 0; ip < nip; ++ip)
1138  map.local_to_global(vLocalIP[ip], rSideQuadRule.point(ip));
1139 
1140  for(size_t ip = 0; ip < nip; ++ip)
1141  rMapping.local_to_global(vGlobalIP[ip], vLocalIP[ip]);
1142 
1143  // compute transformation matrices
1144  DimReferenceMapping<dim-1, dim>& map2
1145  = ReferenceMappingProvider::get<dim-1, dim>(sideRoid, vSideCorner);
1146  std::vector<MathMatrix<dim-1, WorldDim> > vJT(nip);
1147  map2.jacobian_transposed(&(vJT[0]), rSideQuadRule.points(), nip);
1148 
1149  std::vector<MathMatrix<dim, WorldDim> > vElemJT(nip);
1150  rMapping.jacobian_transposed(&(vElemJT[0]), &vLocalIP[0], nip);
1151 
1152  // loop integration points
1153  for(size_t ip = 0; ip < nip; ++ip)
1154  {
1155  // 1. Interpolate Functional Matrix of velocity at ip
1156  std::vector<MathVector<dim> > vvLocGradV[dim];
1157  std::vector<MathVector<dim> > vvGradV[dim];
1158  MathMatrix<dim, dim> JTInv;
1159  Inverse(JTInv, vElemJT[ip]);
1160  for(int d1 = 0; d1 < dim; ++d1){
1161  const LocalShapeFunctionSet<dim>& rTrialSpaceP =
1162  LocalFiniteElementProvider::get<dim>(elemRoid, vLFEID[d1]);
1163  rTrialSpaceP.grads(vvLocGradV[d1], vLocalIP[ip]);
1164 
1165  vvGradV[d1].resize(vvLocGradV[d1].size());
1166  for(size_t sh = 0; sh < vvGradV[d1].size(); ++sh)
1167  MatVecMult(vvGradV[d1][sh], JTInv, vvLocGradV[d1][sh]);
1168  }
1169 
1170  MathMatrix<dim, dim> gradVel;
1171  for(int d1 = 0; d1 < dim; ++d1){
1172  for(int d2 = 0; d2 <dim; ++d2){
1173  gradVel(d1, d2) = 0.0;
1174  for(size_t sh = 0; sh < vvValue[d1].size(); ++sh)
1175  gradVel(d1, d2) += vvValue[d1][sh] * vvGradV[d1][sh][d2];
1176  }
1177  }
1178 
1179  // 1. Interpolate pressure at ip
1180  const LocalShapeFunctionSet<dim>& rTrialSpaceP =
1181  LocalFiniteElementProvider::get<dim>(elemRoid, vLFEID[_P_]);
1182  std::vector<number> vShapeP;
1183  rTrialSpaceP.shapes(vShapeP, vLocalIP[ip]);
1184 
1185  number pressure = 0.0;
1186  for(size_t sh = 0; sh < vvValue[_P_].size(); ++sh)
1187  pressure += vShapeP[sh] * vvValue[_P_][sh];
1188 
1189  // 2. Compute flux
1190  MathVector<dim> diffFlux;
1191  MatVecMult(diffFlux, gradVel, Normal);
1192 
1193  // get quadrature weight
1194  const number weightIP = vWeight[ip];
1195 
1196  // get determinate of mapping
1197  const number det = SqrtGramDeterminant(vJT[ip]);
1198 
1199  // add contribution of integration point
1200  int_drag += weightIP * det *
1201  (kinVisco*density *VecDot(diffFlux, Tangental) * Normal[dim-1]
1202  - pressure * Normal[0]);
1203  int_lift -= weightIP * det *
1204  (kinVisco*density *VecDot(diffFlux, Tangental) * Normal[0]
1205  + pressure * Normal[dim-1]);
1206  }
1207  } // end bf
1208  } // end elem
1209  } // end subsets
1210 
1211 #ifdef UG_PARALLEL
1212  // sum over processes
1213  if(pcl::NumProcs() > 1)
1214  {
1216  number local = int_drag;
1217  com.allreduce(&local, &int_drag, 1, PCL_DT_DOUBLE, PCL_RO_SUM);
1218  local = int_lift;
1219  com.allreduce(&local, &int_lift, 1, PCL_DT_DOUBLE, PCL_RO_SUM);
1220  }
1221 #endif
1222 
1223 // return the summed integral contributions of all elements
1224  std::vector<number> vals(2);
1225  vals[0] = int_drag;
1226  vals[1] = int_lift;
1227  return vals;
1228 }
1229 
1230 
1231 } // end namespace ug
1232 
1233 #endif /* __H__UG__PLUGINS__NAVIER_STOKES__INCOMPRESSIBLE__NAVIER_STOKES_TOOLS__ */
TGridFunction * get()
size_t allreduce(const size_t &t, pcl::ReduceOperation op) const
const MathVector< worldDim > & global_grad(size_t sh) const
const MathVector< worldDim > & global_ip() const
const SCV & scv(size_t i) const
size_t num_scv() const
void update(GridObject *elem, const MathVector< worldDim > *vCornerCoords, const ISubsetHandler *ish=NULL)
size_t num_sh() const
const MathVector< dim > & local_ip() const
number volume() const
const MathVector< worldDim > & global_grad(size_t sh) const
const SCV & scv(size_t i) const
void update(GridObject *elem, const MathVector< worldDim > *vCornerCoords, const ISubsetHandler *ish=NULL)
const MathVector< dim, int > * corner() const
virtual void jacobian_transposed(MathMatrix< dim, worldDim > &JT, const MathVector< dim > &locPos) const=0
virtual void local_to_global(MathVector< worldDim > &globPos, const MathVector< dim > &locPos) const=0
virtual void global_to_local(MathVector< dim > &locPos, const MathVector< worldDim > &globPos, const size_t maxIter=1000, const number tol=1e-10) const=0
size_t size() const
void evaluate_global(number &value, const MathVector< dim > &x) const
int get_subset_index(const char *name) const
virtual void grads(std::vector< std::vector< grad_type > > &vvGrad, const std::vector< MathVector< dim > > &vLocPos) const=0
virtual void shapes(std::vector< std::vector< shape_type > > &vvShape, const std::vector< MathVector< dim > > &vLocPos) const=0
std::size_t size() const
bool is_slave(TElem *) const
size_t size() const
static const QuadratureRule< TDim > & get(ReferenceObjectID roid, size_t order, QuadType type=BEST)
size_t num(int dim) const
int id(int dim_i, size_t i, int dim_j, size_t j) const
static DimReferenceMapping< TDim, TWorldDim > & get(ReferenceObjectID roid)
bool contains(const char *name) const
void add(const char *name)
size_t size() const
int dim(size_t i) const
Grid::VertexAttachmentAccessor< position_attachment_type > position_accessor_type
SmartPtr< TGrid > grid()
void CollectCornerCoordinates(int base_object_id, std::vector< typename TDomain::position_type > &vCornerCoordsOut, GridObject &elem, const TDomain &domain, bool clearContainer)
static const int dim
TGrid grid_type
size_t num_subsets() const
void SetAttachmentValues(TAttachmentAccessor &aaVal, TIter elemsBegin, TIter elemsEnd, const TVal &val)
MathMatrix< N, M, T >::value_type Inverse(MathMatrix< N, M, T > &mOut, const MathMatrix< M, N, T > &m)
#define PCL_RO_SUM
#define PCL_DT_DOUBLE
int NumProcs()
StringTable s
StringTable & table()
vector< string > TokenizeString(const char *str, const char delimiter=',')
#define UG_ASSERT(expr, msg)
#define UG_THROW(msg)
#define UG_LOG(msg)
double number
void MatVecMult(vector_t_out &vOut, const matrix_t &m, const vector_t_in &v)
vector_t::value_type VecTwoNormSq(const vector_t &v)
void VecNormalize(vector_t &vOut, const vector_t &v)
void VecSubtract(vector_t &vOut, const vector_t &v, typename vector_t::value_type s)
void VecScale(vector_t &vOut, const vector_t &v, typename vector_t::value_type s)
vector_t::value_type VecDot(const vector_t &v1, const vector_t &v2)
int local(bglp_vertex_descriptor p)
const number & DoFRef(const TMatrix &mat, const DoFIndex &iInd, const DoFIndex &jInd)
ElementStorage< Vertex >::SectionContainer::iterator VertexIterator
ReferenceObjectID
std::vector< number > DragLift(SmartPtr< TGridFunction > spGridFct, const char *vCmp, const char *BndSubsets, const char *InnerSubsets, number kinVisco, number density, int quadOrder)
Definition: navier_stokes_tools.h:982
void vorticityFV1(TGridFunction &vort, TGridFunction &u)
Definition: navier_stokes_tools.h:387
bool SameDimensionsInAllSubsets(const SubsetGroup &subsetGroup)
void DrivenCavityLinesEval(SmartPtr< TGridFunction > u, std::vector< std::string > vVelCmp, size_t Re)
Definition: navier_stokes_tools.h:572
void DrivenCavityEvalAtPoints(const std::vector< MathVector< 2 > > &vPos, GlobalGridFunctionNumberData< TGridFunction > &GFEval, const number vReferenceValue[])
Definition: navier_stokes_tools.h:540
void vorticityFVCR(TGridFunction &vort, TGridFunction &u)
Definition: navier_stokes_tools.h:235
number kineticEnergy(TGridFunction &u)
Definition: navier_stokes_tools.h:851
void interpolateCRToLagrange(TGridFunction &uLagrange, TGridFunction &uCR)
Definition: navier_stokes_tools.h:54
void vorticity(TGridFunction &vort, TGridFunction &u)
Definition: navier_stokes_tools.h:528
void RemoveLowerDimSubsets(SubsetGroup &subsetGroup)
MathMatrix< 0, 0, T >::value_type SqrtGramDeterminant(const MathMatrix< 0, 0, T > &m)
void cflNumber(TGridFunction &u, number deltaT)
Definition: navier_stokes_tools.h:732
DIM_SUBSET_EMPTY_GRID
geometry_traits< TElem >::const_iterator const_iterator