diff --git a/MathLib/Integration/GaussLegendreTri.cpp b/MathLib/Integration/GaussLegendreTri.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b62888c78f92fab60f8de07617c2af6ba997daa6 --- /dev/null +++ b/MathLib/Integration/GaussLegendreTri.cpp @@ -0,0 +1,29 @@ +/** + * \file + * \author Norihiro Watanabe + * \date 2013-08-13 + * \brief + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "GaussLegendreTri.h" + +namespace MathLib +{ + +template <> const std::array<std::array<double, 2>, GaussLegendreTri<1>::NPoints> GaussLegendreTri<1>::X = {{{{1./3., 1./3.}}}}; +template <> double const GaussLegendreTri<1>::W[1] = {1.0}; + +const std::array<std::array<double, 2>, GaussLegendreTri<2>::NPoints> GaussLegendreTri<2>::X = {{{{1./6., 1./6.}}, {{2./3., 1./6.}}, {{1./6., 2./3.}}}}; +double const GaussLegendreTri<2>::W[3] = {1./3., 1./3., 1./3.}; + +const std::array<std::array<double, 2>, GaussLegendreTri<3>::NPoints> GaussLegendreTri<3>::X = {{{{1./3., 1./3.}}, {{1./5., 3./5.}}, {{1./5., 1./5.}}, {{3./5., 1./5.}}}}; +double const GaussLegendreTri<3>::W[4] = {-27./48., 25./48., 25./48., 25./48.}; + +} diff --git a/MathLib/Integration/GaussLegendreTri.h b/MathLib/Integration/GaussLegendreTri.h new file mode 100644 index 0000000000000000000000000000000000000000..4dea7a9869ca497079b086a7ae99ee067ad3f556 --- /dev/null +++ b/MathLib/Integration/GaussLegendreTri.h @@ -0,0 +1,52 @@ +/** + * \file + * \author Norihiro Watanabe + * \date 2013-08-13 + * \brief + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef GAUSSLEGENDRETRI_H_ +#define GAUSSLEGENDRETRI_H_ + +#include <array> + +namespace MathLib +{ + +/// Gauss-Legendre quadrature on triangles +/// +/// \tparam ORDER integration order. +template <unsigned ORDER> +struct GaussLegendreTri { + static const unsigned Order = ORDER; + static const unsigned NPoints = ORDER; + static const std::array<std::array<double, 2>, NPoints> X; + static const double W[NPoints]; +}; + +template <> +struct GaussLegendreTri<2> { + static const unsigned Order = 2; + static const unsigned NPoints = 3; + static const std::array<std::array<double, 2>, NPoints> X; + static const double W[NPoints]; +}; + +template <> +struct GaussLegendreTri<3> { + static const unsigned Order = 3; + static const unsigned NPoints = 4; + static const std::array<std::array<double, 2>, NPoints> X; + static const double W[NPoints]; +}; + +} + +#endif //GAUSSLEGENDRETRI_H_ diff --git a/NumLib/Fem/FiniteElement/C0IsoparametricElements.h b/NumLib/Fem/FiniteElement/C0IsoparametricElements.h index 68fb04d38e5a5ea927bc194c9200972f136540be..0b18ed706c237cc6ab34ae99d6c0daea14b02c18 100644 --- a/NumLib/Fem/FiniteElement/C0IsoparametricElements.h +++ b/NumLib/Fem/FiniteElement/C0IsoparametricElements.h @@ -15,12 +15,15 @@ #define C0ISOPARAMETRICELEMENTS_H_ #include "MeshLib/Elements/Line.h" +#include "MeshLib/Elements/Tri.h" #include "MeshLib/Elements/Quad.h" #include "MeshLib/Elements/Hex.h" #include "NumLib/Fem/ShapeFunction/ShapeLine2.h" +#include "NumLib/Fem/ShapeFunction/ShapeTri3.h" #include "NumLib/Fem/ShapeFunction/ShapeQuad4.h" #include "NumLib/Fem/ShapeFunction/ShapeHex8.h" #include "NumLib/Fem/Integration/IntegrationGaussRegular.h" +#include "NumLib/Fem/Integration/IntegrationGaussTri.h" #include "TemplateIsoparametric.h" @@ -33,6 +36,12 @@ struct FeLINE2 typedef TemplateIsoparametric<MeshLib::Line, ShapeLine2, IntegrationGaussRegular<1>, T_SHAPE_VECTOR, T_DSHAPE_MATRIX, T_JACOBIAN_MATRIX> type; }; +template <class T_SHAPE_VECTOR, class T_DSHAPE_MATRIX, class T_JACOBIAN_MATRIX> +struct FeTRI3 +{ + typedef TemplateIsoparametric<MeshLib::Tri, ShapeTri3, IntegrationGaussTri, T_SHAPE_VECTOR, T_DSHAPE_MATRIX, T_JACOBIAN_MATRIX> type; +}; + template <class T_SHAPE_VECTOR, class T_DSHAPE_MATRIX, class T_JACOBIAN_MATRIX> struct FeQUAD4 { diff --git a/NumLib/Fem/Integration/IntegrationGaussTri.h b/NumLib/Fem/Integration/IntegrationGaussTri.h new file mode 100644 index 0000000000000000000000000000000000000000..52d3f9d6334926cecb927007a8c463a6a22dca8e --- /dev/null +++ b/NumLib/Fem/Integration/IntegrationGaussTri.h @@ -0,0 +1,129 @@ +/** + * \file + * \author Norihiro Watanabe + * \date 2013-08-13 + * \brief + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef INTEGRATIONGAUSSTRI_H_ +#define INTEGRATIONGAUSSTRI_H_ + +#include "MathLib/Integration/GaussLegendreTri.h" + +namespace NumLib +{ + +/** + * \brief Gauss quadrature rule for triangles + * + * Gauss quadrature rule for triangles is originally given as + * \f[ + * \int F(x,y) dx dy = \int F(x(r, s), y(r, s)) j(r,s) dr ds \approx \frac{1}{2} \sum_i ( F(x(r_i, s_i), y(r_i, s_i)) w_i ) + * \f] + * + * To make it consistent with other elements, we rewrite the above formula as + * \f[ + * \int F(x,y) dx dy \approx \sum_i ( F(x(r_i, s_i), y(r_i, s_i)) w'_i ) + * \f] + * by defining the new weight \f$ w'=\frac{1}{2} w \f$. + */ +class IntegrationGaussTri +{ + typedef typename MathLib::TemplateWeightedPoint<double, double, 2> + WeightedPoint; +public: + /** + * Construct this object with the given integration order + * + * @param order integration order (default 2) + */ + explicit IntegrationGaussTri(std::size_t order = 2) + : _order(order), _n_sampl_pt(0) + { + this->setIntegrationOrder(order); + } + + /// Change the integration order. + void setIntegrationOrder(std::size_t order) + { + _order = order; + _n_sampl_pt = getNPoints(order); + } + + /// return current integration order. + std::size_t getIntegrationOrder() const {return _order;} + + /// return the number of sampling points + std::size_t getNPoints() const {return _n_sampl_pt;} + + /** + * get coordinates of a integration point + * + * @param igp The integration point index + * @return a weighted point + */ + WeightedPoint getWeightedPoint(std::size_t igp) + { + return getWeightedPoint(getIntegrationOrder(), igp); + } + + /** + * get coordinates of a integration point + * + * @param order the number of integration points + * @param pt_id the sampling point id + * @return weight + */ + static WeightedPoint + getWeightedPoint(std::size_t order, std::size_t igp) + { + switch (order) + { + case 1: return getWeightedPoint<MathLib::GaussLegendreTri<1> >(igp); + case 2: return getWeightedPoint<MathLib::GaussLegendreTri<2> >(igp); + case 3: return getWeightedPoint<MathLib::GaussLegendreTri<3> >(igp); + } + return WeightedPoint(std::array<double, 2>(), 0); + } + + template <typename Method> + static WeightedPoint + getWeightedPoint(std::size_t igp) + { + return WeightedPoint(Method::X[igp], 0.5 * Method::W[igp]); + } + + + /** + * get the number of integration points + * + * @param order the number of integration points + * @return the number of points + */ + static std::size_t + getNPoints(std::size_t order) + { + switch (order) + { + case 1: return MathLib::GaussLegendreTri<1>::NPoints; + case 2: return MathLib::GaussLegendreTri<2>::NPoints; + case 3: return MathLib::GaussLegendreTri<3>::NPoints; + } + return 0; + } + +private: + std::size_t _order; + std::size_t _n_sampl_pt; +}; + +} + +#endif //INTEGRATIONGAUSSTRI_H_ diff --git a/NumLib/Fem/ShapeFunction/ShapeTri3-impl.h b/NumLib/Fem/ShapeFunction/ShapeTri3-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..1ddda9a86a78357911b0570477ee23736e080c4c --- /dev/null +++ b/NumLib/Fem/ShapeFunction/ShapeTri3-impl.h @@ -0,0 +1,40 @@ +/** + * \file + * \author Norihiro Watanabe + * \date 2013-08-13 + * \brief + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +namespace NumLib +{ + +template <class T_X, class T_N> +void ShapeTri3::computeShapeFunction(const T_X &r, T_N &N) +{ + N[0] = 1. - r[0] - r[1]; + N[1] = r[0]; + N[2] = r[1]; +} + +template <class T_X, class T_N> +void ShapeTri3::computeGradShapeFunction(const T_X &/*r*/, T_N &dN) +{ + //dN/dr + dN[0] = -1.0; + dN[1] = 1.0; + dN[2] = 0.0; + //dN/ds + dN[3] = -1.0; + dN[4] = 0.0; + dN[5] = 1.0; +} + +} + diff --git a/NumLib/Fem/ShapeFunction/ShapeTri3.h b/NumLib/Fem/ShapeFunction/ShapeTri3.h new file mode 100644 index 0000000000000000000000000000000000000000..523d039b63d3fab31e707bcbded89989b79e3994 --- /dev/null +++ b/NumLib/Fem/ShapeFunction/ShapeTri3.h @@ -0,0 +1,58 @@ +/** + * \file + * \author Norihiro Watanabe + * \date 2013-08-13 + * \brief + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef SHAPETRI3_H_ +#define SHAPETRI3_H_ + +namespace NumLib +{ + +/** + * Shape function for a triangle element of three nodes in natural coordinates + * + * 3 (0,1) + * * + * s | \ + * | \ + * | \ + * *––––––* r + * 1 (0,0) 2 (1,0) + */ +class ShapeTri3 +{ +public: + /** + * Evaluate the shape function at the given point + * + * @param [in] r point coordinates + * @param [out] N a vector of calculated shape function. + */ + template <class T_X, class T_N> + static void computeShapeFunction(const T_X &r, T_N &N3); + + /** + * Evaluate derivatives of the shape function at the given point + * + * @param [in] r point coordinates + * @param [out] dN a matrix of the derivatives + */ + template <class T_X, class T_N> + static void computeGradShapeFunction(const T_X &/*r*/, T_N &dN6); +}; + +} + +#include "ShapeTri3-impl.h" + +#endif //SHAPETRI3_H_ diff --git a/Tests/NumLib/CoordinatesMappingTestData/TestTri3.h b/Tests/NumLib/CoordinatesMappingTestData/TestTri3.h new file mode 100644 index 0000000000000000000000000000000000000000..6223fceb42e3a2e0968e8bc718d200b9da4c5928 --- /dev/null +++ b/Tests/NumLib/CoordinatesMappingTestData/TestTri3.h @@ -0,0 +1,99 @@ +/** + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/LICENSE.txt + */ + +#ifndef COORDINATESMAPPINGTESTDATA_TESTTRI3_H_ +#define COORDINATESMAPPINGTESTDATA_TESTTRI3_H_ + +#include "MeshLib/Elements/Tri.h" +#include "NumLib/Fem/ShapeFunction/ShapeTri3.h" + +namespace CoordinatesMappingTestData +{ + +class TestTri3 +{ + public: + // Element information + typedef MeshLib::Tri ElementType; + typedef NumLib::ShapeTri3 ShapeFunctionType; + static const unsigned dim = 2; //ElementType::dimension; + static const unsigned e_nnodes = ElementType::n_all_nodes; + // Coordinates where shape functions are evaluated + static const double r[dim]; + // Expected results for natural shape + static const double nat_exp_N[e_nnodes]; + static const double nat_exp_dNdr[e_nnodes*dim]; + // Expected results for irregular shape + static const double ir_exp_J[dim*dim]; + static const double ir_exp_invJ[dim*dim]; + static const double ir_exp_detJ; + static const double ir_exp_dNdx[e_nnodes*dim]; + // Expected results for clock-wise node ordering + static const double cl_exp_J[dim*dim]; + // Expected results for zero volume + static const double cl_exp_detJ; + static const double ze_exp_J[dim*dim]; + + // element having shape identical to that in natural coordinates + MeshLib::Tri* createNaturalShape() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node( 0.0, 0.0, 0.0); + nodes[1] = new MeshLib::Node( 1.0, 0.0, 0.0); + nodes[2] = new MeshLib::Node( 0.0, 1.0, 0.0); + return new MeshLib::Tri(nodes); + } + + // element having irregular or skew shape + MeshLib::Tri* createIrregularShape() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node( 0.1, 0.1, 0.0); + nodes[1] = new MeshLib::Node( 2.0, -0.6, 0.0); + nodes[2] = new MeshLib::Node( 1.5, 0.4, 0.0); + return new MeshLib::Tri(nodes); + } + + // invalid case: clock wise node ordering + MeshLib::Tri* createClockWise() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node( 0.0, 0.0, 0.0); + nodes[2] = new MeshLib::Node( 1.0, 0.0, 0.0); + nodes[1] = new MeshLib::Node( 0.0, 1.0, 0.0); + return new MeshLib::Tri(nodes); + } + + // invalid case: zero area + MeshLib::Tri* createZeroVolume() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node( 0.0, 0.0, 0.0); + nodes[1] = new MeshLib::Node( 1.0, 0.0, 0.0); + nodes[2] = new MeshLib::Node( 1.0, 0.0, 0.0); + return new MeshLib::Tri(nodes); + } +}; + +const double TestTri3::r[dim] = {0.5, 0.5}; +const double TestTri3::nat_exp_N[e_nnodes] = {0.0, 0.5, 0.5}; +const double TestTri3::nat_exp_dNdr[e_nnodes*dim] = {-1, 1, 0, -1, 0, 1}; +const double TestTri3::ir_exp_J[dim*dim] = {1.9, -0.7, 1.4, 0.3}; +const double TestTri3::ir_exp_detJ = 1.55; +const double TestTri3::ir_exp_invJ[dim*dim] + = {0.19354838709677424, 0.45161290322580649, -0.90322580645161299, 1.2258064516129032}; +const double TestTri3::ir_exp_dNdx[dim*e_nnodes] + = {-0.6451612903225807, 0.1935483870967742, 0.4516129032258065, + -0.3225806451612903, -0.903225806451613, 1.225806451612903}; +const double TestTri3::cl_exp_J[dim*dim] = {0.0, 1.0, 1.0, 0.0}; +const double TestTri3::cl_exp_detJ = -1.; +const double TestTri3::ze_exp_J[dim*dim] = {1.0, 0.0, 1.0, 0.0}; + +} + +#endif diff --git a/Tests/NumLib/FeTestData/TestFeTRI3.h b/Tests/NumLib/FeTestData/TestFeTRI3.h new file mode 100644 index 0000000000000000000000000000000000000000..077dd815adde7358e28379276b01190593c969cf --- /dev/null +++ b/Tests/NumLib/FeTestData/TestFeTRI3.h @@ -0,0 +1,77 @@ +/** + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef TESTFETRI3_H_ +#define TESTFETRI3_H_ + +#include "MeshLib/Elements/Tri.h" +#include "NumLib/Fem/FiniteElement/C0IsoparametricElements.h" + +#include "MatrixTools.h" + +namespace FeTestData +{ + +// Test case for TRI3 +class TestFeTRI3 +{ +public: + // Fe type information + template <class T_MATRIX_TYPES> + struct FeType + { + typedef NumLib::FeTRI3<typename T_MATRIX_TYPES::NodalVectorType, typename T_MATRIX_TYPES::DimNodalMatrixType, typename T_MATRIX_TYPES::DimMatrixType> type; + }; + typedef MeshLib::Tri MeshElementType; + static const unsigned dim = 2; //MeshElementType::dimension; + static const unsigned e_nnodes = MeshElementType::n_all_nodes; + static const unsigned n_sample_pt_order2 = 3; + static const unsigned n_sample_pt_order3 = 4; + + /// create a mesh element + MeshElementType* createMeshElement() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node( 0.0, 0.0, 0.0); + nodes[1] = new MeshLib::Node( 1.0, 0.0, 0.0); + nodes[2] = new MeshLib::Node( 0.0, 1.0, 0.0); + return new MeshLib::Tri(nodes); + } + + /// set an expected mass matrix for 1m x 1m + template <class T_MATRIX> + void setExpectedMassMatrix(T_MATRIX &m) + { + // set upper triangle entries + m(0,0) = 1.0; m(0,1) = 1./2; m(0,2) = 1./2; + m(1,1) = 1.0; m(1,2) = 1./2; + m(2,2) = 1.0; + // make symmetric + copyUpperToLower(e_nnodes, m); + m *= 1./6.*0.5; + } + + /// set an expected laplace matrix for 1m x 1m + template <class T_MATRIX> + void setExpectedLaplaceMatrix(double k, T_MATRIX &m) + { + // set upper triangle entries + m(0,0) = 2.0; m(0,1) = -1.0; m(0,2) = -1.0; + m(1,1) = 1.0; m(1,2) = 0.0; + m(2,2) = 1.0; + // make symmetric + copyUpperToLower(e_nnodes, m); + m *= k*0.5; + } +}; + +} // namespace + +#endif + diff --git a/Tests/NumLib/TestCoordinatesMapping.cpp b/Tests/NumLib/TestCoordinatesMapping.cpp index f4a5bf67f8985269b7a3478f84992a79418810e8..a3766ae222fb0a7d4216aa273207e913af12be5a 100644 --- a/Tests/NumLib/TestCoordinatesMapping.cpp +++ b/Tests/NumLib/TestCoordinatesMapping.cpp @@ -20,6 +20,7 @@ #include "NumLib/Fem/CoordinatesMapping/NaturalCoordinatesMapping.h" #include "CoordinatesMappingTestData/TestLine2.h" +#include "CoordinatesMappingTestData/TestTri3.h" #include "CoordinatesMappingTestData/TestQuad4.h" #include "CoordinatesMappingTestData/TestHex8.h" @@ -35,6 +36,7 @@ namespace // Element types to be tested typedef ::testing::Types< TestLine2, + TestTri3, TestQuad4, TestHex8 > TestTypes; diff --git a/Tests/NumLib/TestFe.cpp b/Tests/NumLib/TestFe.cpp index 13b9fd48cf976f0ac91d7eb5d61b951184f86960..76c569bb06ead9a2f9dcc57b06d4696031219da4 100644 --- a/Tests/NumLib/TestFe.cpp +++ b/Tests/NumLib/TestFe.cpp @@ -19,6 +19,7 @@ #include "NumLib/Fem/FiniteElement/C0IsoparametricElements.h" #include "FeTestData/TestFeLINE2.h" +#include "FeTestData/TestFeTRI3.h" #include "FeTestData/TestFeQUAD4.h" #include "FeTestData/TestFeHEX8.h" @@ -60,10 +61,12 @@ struct TestCase typedef ::testing::Types< TestCase<TestFeLINE2>, + TestCase<TestFeTRI3>, TestCase<TestFeQUAD4>, TestCase<TestFeHEX8> #ifdef OGS_USE_EIGEN ,TestCase<TestFeLINE2, EigenFixedMatrixTypes<TestFeLINE2> > + ,TestCase<TestFeTRI3, EigenFixedMatrixTypes<TestFeTRI3> > ,TestCase<TestFeQUAD4, EigenFixedMatrixTypes<TestFeQUAD4> > ,TestCase<TestFeHEX8, EigenFixedMatrixTypes<TestFeHEX8> > #endif