COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
utest-mesh-lagrangep1-triag3d.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2013 von Karman Institute for Fluid Dynamics, Belgium
2 //
3 // This software is distributed under the terms of the
4 // GNU Lesser General Public License version 3 (LGPLv3).
5 // See doc/lgpl.txt and doc/gpl.txt for the license text.
6 
7 #define BOOST_TEST_DYN_LINK
8 #define BOOST_TEST_MODULE "Test module for the ETYPE shapefunction"
9 
10 #include <boost/assign/list_of.hpp>
11 #include <boost/test/unit_test.hpp>
12 
13 #include "common/Log.hpp"
14 
15 #include "math/Consts.hpp"
16 #include "math/Functions.hpp"
17 
18 #include "common/Table.hpp"
21 #include "mesh/ElementData.hpp"
22 
23 
25 
26 using namespace boost::assign;
27 using namespace cf3;
28 using namespace cf3::common;
29 using namespace cf3::math;
30 using namespace cf3::math::Consts;
31 using namespace cf3::mesh;
32 using namespace cf3::mesh::Integrators;
33 using namespace cf3::mesh::LagrangeP1;
34 using namespace cf3::Tools::Testing;
35 
37 
38 typedef Triag3D ETYPE;
39 
41 {
44  LagrangeP1Triag3DFixture() : mapped_coords(0.1, 0.8), nodes((NodesT() << 0.5, 0.3, 0.,
45  1.1, 1.2, 0.5,
46  0.8, 2.1, 1.).finished())
47  {
48  }
49 
52  {
53  }
54 
56  void create_cylinder(Table<Real>& coordinates, Table<Uint>& connectivity, const Real radius, const Uint u_segments, const Uint v_segments, const Real height, const Real start_angle = 0., const Real end_angle = 2.*Consts::pi())
57  {
58  const Uint dim = ETYPE::dimension;
59  const Uint nb_nodes = ETYPE::nb_nodes;
60  const bool closed = std::abs(std::abs(end_angle - start_angle) - 2.0*Consts::pi()) < eps();
61 
62  coordinates.set_row_size(dim);
63  Table<Real>::ArrayT& coord_array = coordinates.array();
64  coord_array.resize(boost::extents[(u_segments + (!closed)) * (v_segments+1)][dim]);
65 
66  connectivity.set_row_size(nb_nodes);
67  Table<Uint>::ArrayT& conn_array = connectivity.array();
68  conn_array.resize(boost::extents[2 * u_segments * v_segments][nb_nodes]);
69  const Real v_step = height / v_segments;
70 
71  if(!closed)
72  {
73  for(Uint v = 0; v <= v_segments; ++v)
74  {
75  const Real z_coord = v_step * static_cast<Real>(v);
76  for(Uint u = 0; u <= u_segments; ++u)
77  {
78  const Real theta = start_angle + (end_angle - start_angle) * (static_cast<Real>(u) / static_cast<Real>(u_segments));
79  Table<Real>::Row coord_row = coord_array[v*(u_segments+1) + u];
80 
81  coord_row[XX] = radius * cos(theta);
82  coord_row[YY] = radius * sin(theta);
83  coord_row[ZZ] = z_coord;
84  }
85  }
86 
87  for(Uint v = 0; v != v_segments; ++v)
88  {
89  //const Real z_coord = v_step * static_cast<Real>(v);
90  for(Uint u = 0; u != u_segments; ++u)
91  {
92  const Uint node0 = v*(u_segments+1) + u;
93  const Uint node1 = node0 + 1;
94  const Uint node3 = (v+1)*(u_segments+1) + u;
95  const Uint node2 = node3 + 1;
96 
97  Table<Uint>::Row nodes1 = conn_array[2*(v*u_segments + u)];
98  Table<Uint>::Row nodes2 = conn_array[2*(v*u_segments + u) + 1];
99 
100  nodes1[0] = node0;
101  nodes1[1] = node1;
102  nodes1[2] = node2;
103 
104  nodes2[0] = node2;
105  nodes2[1] = node3;
106  nodes2[2] = node0;
107  }
108  }
109  }
110  else // closed loop
111  {
112  for(Uint v = 0; v <= v_segments; ++v)
113  {
114  const Real z_coord = v_step * static_cast<Real>(v);
115  for(Uint u = 0; u != u_segments; ++u)
116  {
117  const Real theta = start_angle + (end_angle - start_angle) * (static_cast<Real>(u) / static_cast<Real>(u_segments));
118  Table<Real>::Row coord_row = coord_array[v*u_segments + u];
119 
120  coord_row[XX] = radius * cos(theta);
121  coord_row[YY] = radius * sin(theta);
122  coord_row[ZZ] = z_coord;
123  }
124  }
125 
126  for(Uint v = 0; v != v_segments; ++v)
127  {
128  //const Real z_coord = v_step * static_cast<Real>(v);
129  for(Uint u = 0; u != u_segments; ++u)
130  {
131  const Uint node0 = v*u_segments + u;
132  const Uint node1 = node0 + 1;
133  const Uint node3 = (v+1)*u_segments + u;
134  const Uint node2 = node3 + 1;
135 
136  Table<Uint>::Row nodes1 = conn_array[2*(v*u_segments + u)];
137  Table<Uint>::Row nodes2 = conn_array[2*(v*u_segments + u) + 1];
138 
139  nodes1[0] = node0;
140  nodes1[1] = node1;
141  nodes1[2] = node2;
142 
143  nodes2[0] = node2;
144  nodes2[1] = node3;
145  nodes2[2] = node0;
146  }
147  conn_array[2 * (v*u_segments + u_segments-1)][1] = v*u_segments;
148  conn_array[2 * (v*u_segments + u_segments-1)][2] = (v+1)*u_segments;
149  conn_array[2 * (v*u_segments + u_segments-1) + 1][0] = (v+1)*u_segments;
150  }
151  }
152  }
153 
155  const NodesT nodes;
156 
158  {
159  ConstFunctor(const NodesT& node_list) : m_nodes(node_list) {}
160 
161  Real operator()() const
162  {
163  ETYPE::CoordsT result;
164  ETYPE::normal(mapped_coords, m_nodes, result);
165  return result.norm();
166  }
168  private:
169  const NodesT& m_nodes;
170  };
171 
174 
175  Real operator()(const RealVector& mapped_coords, const NodesT& nodes)
176  {
177  ETYPE::CoordsT result;
178  ETYPE::normal(mapped_coords, nodes, result);
179  return result.norm();
180  }
181 
182  };
183 
186 
187  ConstVectorField(const RealVector& vector) : m_vector(vector) {}
188 
189  Real operator()(const RealVector& mapped_coords, const NodesT& nodes)
190  {
192  ETYPE::normal(mapped_coords, nodes, normal);
193  return Functions::inner_product(normal, m_vector);
194  }
195 
196  private:
198 
199  };
200 
204  {
205 
206  RotatingCylinderPressure(const Real radius, const Real circulation, const Real U) :
207  m_radius(radius), m_circulation(circulation), m_u(U) {}
208 
209  ETYPE::CoordsT operator()(const RealVector& mapped_coords, const NodesT& nodes)
210  {
211  // The pressures to interpolate
212  RealVector3 nodal_p;
213  nodal_p[0] = pressure(theta(nodes.row(0)));
214  nodal_p[1] = pressure(theta(nodes.row(1)));
215  nodal_p[2] = pressure(theta(nodes.row(2)));
216 
217  // The local normal
219  ETYPE::normal(mapped_coords, nodes, normal);
220 
221  // Interpolate the pressure
222  ETYPE::SF::ValueT sf_mat;
223  ETYPE::SF::compute_value(mapped_coords, sf_mat);
224 
225  return normal * (sf_mat * nodal_p);
226  }
227 
228  private:
229  const Real m_radius;
230  const Real m_circulation;
231  const Real m_u;
232  static const Real m_rho;
233 
234  // Reconstruct the value of theta, based on the coordinates
236  {
237  return atan2(coords[YY], coords[XX]);
238  }
239 
240  // Pressure in function of theta
241  Real pressure(const Real theta)
242  {
243  Real tmp = (2. * m_u * sin(theta) + m_circulation / (2. * Consts::pi() * m_radius));
244  return 0.5 * m_rho * tmp * tmp;
245  }
246  };
247 };
248 
250 
251 template<typename ResultT, typename FunctorT>
252 void integrate_region(ResultT& result, FunctorT functor, const Table<Real>& coordinates, const Table<Uint>& connectivity)
253 {
254  const Uint nb_elems = connectivity.array().size();
255  for(Uint elem_idx = 0; elem_idx != nb_elems; ++ elem_idx)
256  {
257  //const Table<Uint>::ConstRow& r = connectivity.array()[elem_idx];
258  typename ETYPE::NodesT nodes;
259  fill(nodes, coordinates, connectivity.array()[elem_idx]);
260  integrate_element(result, functor, nodes);
261  }
262 }
263 
264 template<typename ResultT, typename FunctorT, typename NodesT>
265 void integrate_element(ResultT& result, FunctorT functor, const NodesT& nodes)
266 {
267  static const double mu = 0.3333333333333333333333333;
268  static const double w = 0.5;
269  static const ETYPE::MappedCoordsT mapped_coords(mu, mu);
270  result += w * functor(mapped_coords, nodes);
271 }
272 
274 
275 BOOST_FIXTURE_TEST_SUITE( LagrangeP1Triag3DSuite, LagrangeP1Triag3DFixture )
276 
277 
280 {
281  NodesT nodes_triag3D;
282  nodes_triag3D <<
283  0.0, 0.0, 0.0,
284  1.0, 0.0, 1.0,
285  1.0, 1.0, 1.0;
286  BOOST_CHECK_EQUAL(ETYPE::area(nodes_triag3D), std::sqrt(2.)/2.);
287 }
288 
290 {
291  const ETYPE::SF::ValueT reference_result(0.1, 0.1, 0.8);
292  ETYPE::SF::ValueT result;
293  ETYPE::SF::compute_value(mapped_coords, result);
295  cf3::Tools::Testing::vector_test(result, reference_result, accumulator);
296  BOOST_CHECK_LT(boost::accumulators::max(accumulator.ulps), 10); // Maximal difference can't be greater than 10 times the least representable unit
297 }
298 
299 BOOST_AUTO_TEST_CASE( MappedGradient )
300 {
301  ETYPE::SF::GradientT expected;
302  expected(0,0) = -1.;
303  expected(1,0) = -1.;
304  expected(0,1) = 1.;
305  expected(1,1) = 0.;
306  expected(0,2) = 0.;
307  expected(1,2) = 1.;
308  ETYPE::SF::GradientT result;
309  ETYPE::SF::compute_gradient(mapped_coords, result);
311  cf3::Tools::Testing::vector_test(result, expected, accumulator);
312  BOOST_CHECK_LT(boost::accumulators::max(accumulator.ulps), 2);
313 }
314 
316 {
317  ETYPE::JacobianT expected;
318  expected(KSI,XX) = 0.6;
319  expected(KSI,YY) = 0.9;
320  expected(KSI,ZZ) = 0.5;
321 
322  expected(ETA,XX) = 0.3;
323  expected(ETA,YY) = 1.8;
324  expected(ETA,ZZ) = 1.;
325 
326  ETYPE::JacobianT result;
327  ETYPE::compute_jacobian(mapped_coords, nodes, result);
329  cf3::Tools::Testing::vector_test(result, expected, accumulator);
330  BOOST_CHECK_LT(boost::accumulators::max(accumulator.ulps), 15);
331 }
332 
333 BOOST_AUTO_TEST_CASE( IntegrateConst )
334 {
335  ConstFunctor ftor(nodes);
336  const Real area = ETYPE::area(nodes);
337 
338  Real result = 0.0;
339 
340  gauss_integrate<1, GeoShape::TRIAG>(ftor, ftor.mapped_coords, result);
341 
342  BOOST_CHECK_CLOSE(result, area, 0.001);
343 }
344 
349 BOOST_AUTO_TEST_CASE( SurfaceIntegral )
350 {
351  // Create an approximation of a circle
352  const Real radius = 1.;
353  const Uint u_segments = 100;
354  const Uint v_segments = 24;
355  const Real height = 3.;
356 
357  // complete circle
358  boost::shared_ptr< Table<Real> > coordinates(common::allocate_component< Table<Real> >(mesh::Tags::coordinates()));
359  boost::shared_ptr< Table<Uint> > connectivity(common::allocate_component< Table<Uint> >("connectivity"));
360  create_cylinder(*coordinates, *connectivity, radius, u_segments, v_segments, height);
361 
362  // Check the area
363  Real area = 0.;
364  integrate_region(area, NormalVectorNorm(), *coordinates, *connectivity);
365  BOOST_CHECK_CLOSE(area, 2.*Consts::pi()*radius*height, 0.1);
366 
367  // Flux from a constant vector field through a closed surface should be 0
368  Real zero_flux = 0.;
369  const ETYPE::CoordsT field_vector(0.35, 1.25, 0.);
370  integrate_region(zero_flux, ConstVectorField(field_vector), *coordinates, *connectivity);
371  BOOST_CHECK_SMALL(zero_flux, 1e-14);
372 }
373 
374 BOOST_AUTO_TEST_CASE( ArcIntegral )
375 {
376  // half cylinder arc
377  boost::shared_ptr< Table<Real> > arc_coordinates(common::allocate_component< Table<Real> >(mesh::Tags::coordinates()));
378  boost::shared_ptr< Table<Uint> > arc_connectivity(common::allocate_component< Table<Uint> >("connectivity"));
379  create_cylinder(*arc_coordinates, *arc_connectivity, 1., 100, 24, 3., 0., Consts::pi());
380  Real arc_flux = 0.;
381  const ETYPE::CoordsT y_vector(0., 1., 0.);
382  integrate_region(arc_flux, ConstVectorField(y_vector), *arc_coordinates, *arc_connectivity);
383  BOOST_CHECK_CLOSE(arc_flux, 6., 0.01);
384 }
385 
387 BOOST_AUTO_TEST_CASE( RotatingCylinder )
388 {
389  // Create an approximation of a circle
390  const Real radius = 1.;
391  const Uint u_segments = 1000;
392  const Uint v_segments = 100;
393  const Real height = 3.;
394 
395  // complete cylinder
396  boost::shared_ptr< Table<Real> > coordinates(common::allocate_component< Table<Real> >(mesh::Tags::coordinates()));
397  boost::shared_ptr< Table<Uint> > connectivity(common::allocate_component< Table<Uint> >("connectivity"));
398  create_cylinder(*coordinates, *connectivity, radius, u_segments, v_segments, height);
399 
400  // Rotating cylinder in uniform flow
401  const Real u = 300.;
402  const Real circulation = 975.;
403  ETYPE::CoordsT force;
404  force.setZero();
405  integrate_region(force, RotatingCylinderPressure(radius, circulation, u), *coordinates, *connectivity);
406  BOOST_CHECK_CLOSE(force[YY], height * 1.225*u*circulation, 0.001); // lift according to theory
407  BOOST_CHECK_SMALL(force[XX], 1e-8); // Drag should be zero
408  BOOST_CHECK_SMALL(force[ZZ], 1e-8);
409 }
410 
412 
413 BOOST_AUTO_TEST_SUITE_END()
414 
415 
BOOST_AUTO_TEST_CASE(Area)
Real operator()(const RealVector &mapped_coords, const NodesT &nodes)
boost::proto::terminal< SFOp< NormalOp > >::type const normal
void integrate_region(ResultT &result, FunctorT functor, const Table< Real > &coordinates, const Table< Uint > &connectivity)
ArrayT & array()
Definition: Table.hpp:92
Basic Classes for Mathematical applications used by COOLFluiD.
static void compute_jacobian(const MappedCoordsT &mapped_coord, const NodesT &nodes, MatrixType &jacobian)
3D Lagrange P1 Triangular Element type This class provides the lagrangian shape function describing t...
Definition: Triag3D.hpp:36
ETYPE::CoordsT operator()(const RealVector &mapped_coords, const NodesT &nodes)
~LagrangeP1Triag3DFixture()
common tear-down for each test case
Real max(const Real a, const Real b)
Maximum between two scalars.
Definition: Terminals.hpp:228
Real e()
Definition of the Unit charge [C].
Definition: Consts.hpp:30
boost::proto::terminal< SFOp< NodesOp > >::type const nodes
Definition: Defs.hpp:17
void integrate_element(ResultT &result, FunctorT functor, const NodesT &nodes)
Static functions for mathematical constants.
Definition: Consts.hpp:25
const ETYPE::MappedCoordsT mapped_coords
Definition: Defs.hpp:17
Eigen::Matrix< Real, nb_nodes, Hexa3D_traits::dimension > NodesT
Real pi()
Definition of the Pi constant.
Definition: Consts.hpp:48
boost::accumulators::accumulator_set< Real, boost::accumulators::stats< boost::accumulators::tag::min, boost::accumulators::tag::mean, boost::accumulators::tag::max, boost::accumulators::tag::median, boost::accumulators::tag::lazy_variance > > ulps
Stores statistics for comparisons of inexact (floating-point) types using Units in the Last Place (UL...
Definition: Difference.hpp:55
Basic Classes for Mesh applications used by COOLFluiD.
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealVector
Dynamic sized column vector.
Definition: MatrixTypes.hpp:25
namespace holding LagrangeP1 shape functions and elements
static Real area(const NodesT &nodes)
Definition: Hexa3D.cpp:331
RotatingCylinderPressure(const Real radius, const Real circulation, const Real U)
Top-level namespace for coolfluid.
Definition: Action.cpp:18
void create_cylinder(Table< Real > &coordinates, Table< Uint > &connectivity, const Real radius, const Uint u_segments, const Uint v_segments, const Real height, const Real start_angle=0., const Real end_angle=2.*Consts::pi())
Fills the given coordinate and connectivity data to create a cylinder along the Z-axis, consisting of ETYPE elements.
void fill(NodeValuesT &to_fill, const common::Table< Real > &data_array, const RowT &element_row, const Uint start=0)
Fill STL-vector like per-node data storage.
Definition: ElementData.hpp:28
Returns the norm of the normal vector to the curve or surface element (equal to tangent in the case o...
Returns the scalar product of a constant vector field and the local element normal.
Eigen::Matrix< Real, Hexa3D_traits::dimension, 1 > CoordsT
Functions to provide integration over elements.
Definition: Gauss.hpp:26
boost::proto::terminal< SFOp< CoordinatesOp > >::type const coordinates
LagrangeP1Triag3DFixture()
common setup for each test case
void set_row_size(const Uint nb_cols)
Definition: Table.hpp:78
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
Definition: Defs.hpp:17
void vector_test(const VectorT &A, const VectorT &B, Accumulator &Result)
Compares vector-like sequences.
Definition: Difference.hpp:139
Eigen::Matrix< Real, Hexa3D_traits::SF::dimensionality, Hexa3D_traits::dimension > JacobianT
Real inner_product(const T1 &v1, const T2 &v2)
Definition: Functions.hpp:197
Real operator()(const RealVector &mapped_coords, const NodesT &nodes)
Most basic kernel library.
Definition: Action.cpp:19
boost::shared_ptr< T > allocate_component(const std::string &name)
Stand-alone function to allocate components of a given type.
Definition: Component.hpp:55
Eigen::Matrix< Real, 3, 1 > RealVector3
Fixed size 3x1 column vector.
Definition: MatrixTypes.hpp:41
Stores the results of the difference::test() function.
Definition: Difference.hpp:49
virtual void resize(const Uint nb_rows)
Definition: Table.hpp:85
Send comments to:
COOLFluiD Web Admin