COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
utest-mesh-lagrangep1-line2d.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 Line2D shapefunction"
9 
10 #include <boost/assign/list_of.hpp>
11 #include <boost/test/unit_test.hpp>
12 
13 #include "common/Log.hpp"
14 #include "common/Core.hpp"
16 
17 #include "math/Consts.hpp"
18 
19 #include "mesh/Connectivity.hpp"
20 #include "mesh/Dictionary.hpp"
21 #include "mesh/Field.hpp"
22 #include "mesh/ElementData.hpp"
23 #include "mesh/Elements.hpp"
24 #include "mesh/Space.hpp"
25 
27 
29 
30 
31 
34 
35 using namespace boost::assign;
36 using namespace cf3;
37 using namespace cf3::common;
38 using namespace cf3::math;
39 using namespace cf3::mesh;
40 using namespace cf3::mesh::Integrators;
41 using namespace cf3::mesh::LagrangeP1;
42 using namespace cf3::Tools::Testing;
43 using namespace cf3::Tools::MeshGeneration;
44 
46 
47 typedef Line2D ETYPE;
48 
50 {
51  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
52 
56  mapped_coords((ETYPE::MappedCoordsT() << .2).finished()),
57  nodes
58  (
59  (ETYPE::NodesT() << 5., 7.,
60  10., 3.).finished()
61  )
62  {
63  }
64 
67 
68  struct ConstFunctor
69  {
70  ConstFunctor(const ETYPE::NodesT& node_list) : m_nodes(node_list) {}
71 
72  Real operator()() const
73  {
74  ETYPE::JacobianT jac;
75  ETYPE::compute_jacobian(mapped_coords, m_nodes, jac);
76  return sqrt(jac[0]*jac[0] + jac[1]*jac[1]);
77  }
79  private:
81  };
82 
85  {
86  Real operator()(const ETYPE::MappedCoordsT& mapped_coords, const ETYPE::NodesT& nodes)
87  {
88  ETYPE::CoordsT result;
89  ETYPE::normal(mapped_coords, nodes, result);
90  return result.norm();
91  }
92  };
93 
96 
97  ConstVectorField(const ETYPE::CoordsT& vector) : m_vector(vector) {}
98 
99  Real operator()(const ETYPE::MappedCoordsT& mapped_coords, const ETYPE::NodesT& nodes)
100  {
102  ETYPE::normal(mapped_coords, nodes, normal);
103  return normal.dot(m_vector);
104  }
105 
106  private:
108 
109  };
110 
114 
115  RotatingCylinderPressure(const Real radius, const Real circulation, const Real U) :
116  m_radius(radius), m_circulation(circulation), m_u(U) {}
117 
118  ETYPE::CoordsT operator()(const ETYPE::MappedCoordsT& mapped_coords, const ETYPE::NodesT& nodes)
119  {
120  // The pressures to interpolate
121  ETYPE::CoordsT nodal_p;
122  nodal_p[0] = pressure(theta(nodes.row(0)));
123  nodal_p[1] = pressure(theta(nodes.row(1)));
124 
125  // The local normal
127  ETYPE::normal(mapped_coords, nodes, normal);
128 
129  // Interpolate the pressure
130  ETYPE::SF::ValueT sf_mat;
131  ETYPE::SF::compute_value(mapped_coords, sf_mat);
132 
133  return normal * (sf_mat * nodal_p);
134  }
135 
136  private:
137  const Real m_radius;
138  const Real m_circulation;
139  const Real m_u;
140  static const Real m_rho;
141 
142  // Reconstruct the value of theta, based on the coordinates
144  {
145  return atan2(coords[YY], coords[XX]);
146  }
147 
148  // Pressure in function of theta
149  Real pressure(const Real theta)
150  {
151  Real tmp = (2. * m_u * sin(theta) + m_circulation / (2. * Consts::pi() * m_radius));
152  return 0.5 * m_rho * tmp * tmp;
153  }
154 
155  };
156 };
157 
159 
161 template<typename ResultT, typename FunctorT>
162 void integrate_region(ResultT& result, FunctorT functor, const Table<Real>& coordinates, const Table<Uint>& connectivity)
163 {
164  const Uint nb_elems = connectivity.array().size();
165  for(Uint elem_idx = 0; elem_idx != nb_elems; ++ elem_idx)
166  {
168  fill(nodes, coordinates, connectivity.array()[elem_idx]);
169  integrate_element(result, functor, nodes);
170  }
171 }
172 
174 template<typename ResultT, typename FunctorT, typename NodesT>
175 void integrate_element(ResultT& result, FunctorT functor, const NodesT& nodes)
176 {
177  static const double mu = 0.;
178  static const double w = 2.;
179  static const ETYPE::MappedCoordsT mapped_coords((ETYPE::MappedCoordsT() << mu).finished());
180  result += w * functor(mapped_coords, nodes);
181 }
182 
184 
185 BOOST_FIXTURE_TEST_SUITE( Line2DSuite, LagrangeP1Line2DFixture )
186 
187 
190 {
191  ETYPE::NodesT nodes_line2D;
192  nodes_line2D(0, XX) = 2.0; nodes_line2D(0, YY) = 2.0;
193  nodes_line2D(1, XX) = 1.0; nodes_line2D(1, YY) = 1.0;
194  BOOST_CHECK_EQUAL(Line2D::area(nodes_line2D),std::sqrt(2.));
195 }
196 
198 {
199  const ETYPE::SF::ValueT reference_result(0.4, 0.6);
200  ETYPE::SF::ValueT result;
201  Line2D::SF::compute_value(mapped_coords, result);
202  Accumulator accumulator;
203  vector_test(result, reference_result, accumulator);
204  BOOST_CHECK_LT(boost::accumulators::max(accumulator.ulps), 10); // Maximal difference can't be greater than 10 times the least representable unit
205 }
206 
207 BOOST_AUTO_TEST_CASE( MappedGradient )
208 {
209  ETYPE::SF::GradientT result;
210  ETYPE::SF::GradientT expected;
211  expected(0,0) = -0.5;
212  expected(0,1) = 0.5;
213  Line2D::SF::compute_gradient(mapped_coords, result);
214  Accumulator accumulator;
215  vector_test(result, expected, accumulator);
216  BOOST_CHECK_LT(boost::accumulators::max(accumulator.ulps), 2);
217 }
218 
220 {
221  const ETYPE::JacobianT expected(2.5, -2.);
222  ETYPE::JacobianT result;
223  Line2D::compute_jacobian(mapped_coords, nodes, result);
224  Accumulator accumulator;
225  vector_test(result, expected, accumulator);
226  BOOST_CHECK_LT(boost::accumulators::max(accumulator.ulps), 2);
227 }
228 
229 BOOST_AUTO_TEST_CASE( IntegrateConst )
230 {
231  ConstFunctor ftor(nodes);
232  const Real vol = Line2D::area(nodes);
233 
234  Real result1 = 0.0;
235  Real result2 = 0.0;
236  Real result4 = 0.0;
237  Real result8 = 0.0;
238  Real result16 = 0.0;
239  Real result32 = 0.0;
240 
241  gauss_integrate<1, GeoShape::LINE>(ftor, ftor.mapped_coords, result1);
242  gauss_integrate<2, GeoShape::LINE>(ftor, ftor.mapped_coords, result2);
243  gauss_integrate<4, GeoShape::LINE>(ftor, ftor.mapped_coords, result4);
244  gauss_integrate<8, GeoShape::LINE>(ftor, ftor.mapped_coords, result8);
245  gauss_integrate<16, GeoShape::LINE>(ftor, ftor.mapped_coords, result16);
246  gauss_integrate<32, GeoShape::LINE>(ftor, ftor.mapped_coords, result32);
247 
248 
249  BOOST_CHECK_LT(boost::accumulators::max(test(result1, vol).ulps), 1);
250  BOOST_CHECK_LT(boost::accumulators::max(test(result2, vol).ulps), 5);
251  BOOST_CHECK_LT(boost::accumulators::max(test(result4, vol).ulps), 5);
252  BOOST_CHECK_LT(boost::accumulators::max(test(result8, vol).ulps), 5);
253  BOOST_CHECK_LT(boost::accumulators::max(test(result16, vol).ulps), 5);
254  BOOST_CHECK_LT(boost::accumulators::max(test(result32, vol).ulps), 5);
255 }
256 
261 BOOST_AUTO_TEST_CASE( SurfaceIntegral )
262 {
263  // Create an approximation of a circle
264  //const Real radius = 1.;
265  //const Uint segments = 100;
266 
267  // complete circle
268  Mesh& mesh = *Core::instance().root().create_component<Mesh>("surface_integral");
269  create_circle_2d(mesh, 1., 100);
270  Table<Real>& coordinates = find_component_recursively<Dictionary>(mesh).coordinates();
271  Table<Uint>& connectivity = find_component_recursively<Elements>(mesh).geometry_space().connectivity();
272 
273 
274  // Check the length, using the line integral of one times the norm of the tangent vector
275  Real length = 0.;
276  integrate_region(length, NormalVectorNorm(), coordinates, connectivity);
277  BOOST_CHECK_CLOSE(length, 2.*Consts::pi(), 0.1);
278 
279  // Flux from a constant vector field through a closed surface should be 0
280  Real zero_flux = 0.;
281  const ETYPE::CoordsT field_vector(0.35, 1.25);
282  integrate_region(zero_flux, ConstVectorField(field_vector), coordinates, connectivity);
283  BOOST_CHECK_SMALL(zero_flux, 1e-14);
284 }
285 
286 BOOST_AUTO_TEST_CASE( ArcIntegral )
287 {
288  // half circle arc, so the flux of a uniform field of unit vectors should equal the diameter
289  Mesh& mesh = *Core::instance().root().create_component<Mesh>("arc_integral");
290  create_circle_2d(mesh, 1., 100, 0., Consts::pi());
291  Table<Real>& arc_coordinates = find_component_recursively<Dictionary>(mesh).coordinates();
292  Table<Uint>& arc_connectivity = find_component_recursively<Elements>(mesh).geometry_space().connectivity();
293  Real arc_flux = 0.;
294  const ETYPE::CoordsT y_vector(0., 1.);
295  integrate_region(arc_flux, ConstVectorField(y_vector), arc_coordinates, arc_connectivity);
296  BOOST_CHECK_CLOSE(arc_flux, 2., 0.01);
297 }
298 
300 BOOST_AUTO_TEST_CASE( RotatingCylinder )
301 {
302  // Create an approximation of a circle
303  const Real radius = 1.;
304  const Uint segments = 10000;
305 
306  // complete circle
307  Mesh& mesh = *Core::instance().root().create_component<Mesh>("rotating_cylinder");
308  create_circle_2d(mesh, 1., segments);
309  Table<Real>& coordinates = find_component_recursively<Dictionary>(mesh).coordinates();
310  Table<Uint>& connectivity = find_component_recursively<Elements>(mesh).geometry_space().connectivity();
311 
312  // Rotating cylinder in uniform flow
313  const Real u = 300.;
314  const Real circulation = 975.;
315  ETYPE::CoordsT force(0.,0.);
316  integrate_region(force, RotatingCylinderPressure(radius, circulation, u), coordinates, connectivity);
317  BOOST_CHECK_CLOSE(force[YY], 1.225*u*circulation, 0.001); // lift according to theory
318  BOOST_CHECK_SMALL(force[XX], 1e-8); // Drag should be zero
319 }
320 
322 
323 BOOST_AUTO_TEST_SUITE_END()
324 
325 
cf3::Real result2[213]
boost::proto::terminal< SFOp< NormalOp > >::type const normal
ArrayT & array()
Definition: Table.hpp:92
void create_circle_2d(Mesh &mesh, const Real radius, const Uint segments, const Real start_angle, const Real end_angle)
Creates a 2D circular arc.
Basic Classes for Mathematical applications used by COOLFluiD.
RotatingCylinderPressure(const Real radius, const Real circulation, const Real U)
static void compute_jacobian(const MappedCoordsT &mapped_coord, const NodesT &nodes, MatrixType &jacobian)
Real operator()(const ETYPE::MappedCoordsT &mapped_coords, const ETYPE::NodesT &nodes)
BOOST_AUTO_TEST_CASE(Area)
cf3::Real result1[201]
Real operator()(const ETYPE::MappedCoordsT &mapped_coords, const ETYPE::NodesT &nodes)
void integrate_element(ResultT &result, FunctorT functor, const NodesT &nodes)
Integral for an element.
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
LagrangeP1Line2DFixture()
common setup for each test case
Definition: Defs.hpp:17
Eigen::Matrix< Real, nb_nodes, Hexa3D_traits::dimension > NodesT
Lagrange P1 Triangular Element type This class provides the lagrangian shape function describing the ...
Definition: Line2D.hpp:35
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.
namespace holding LagrangeP1 shape functions and elements
Returns the scalar product of a constant vector field and the local element normal.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW typedef ETYPE::NodesT NodesT
Returns the norm of the normal vector to the curve or surface element (equal to tangent in the case o...
Top-level namespace for coolfluid.
Definition: Action.cpp:18
void integrate_region(ResultT &result, FunctorT functor, const Table< Real > &coordinates, const Table< Uint > &connectivity)
Integral over a region.
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
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
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
ETYPE::CoordsT operator()(const ETYPE::MappedCoordsT &mapped_coords, const ETYPE::NodesT &nodes)
Most basic kernel library.
Definition: Action.cpp:19
2D Lagrange P1 Triangular Element type This class provides the lagrangian shape function describing t...
Definition: Hexa3D.hpp:36
Stores the results of the difference::test() function.
Definition: Difference.hpp:49
const ETYPE::MappedCoordsT mapped_coords
Send comments to:
COOLFluiD Web Admin