From c4d4ad6726ee6c60fa410ab33c0971451ddfcfde Mon Sep 17 00:00:00 2001 From: Norihiro Watanabe <norihiro.watanabe@ufz.de> Date: Thu, 23 Apr 2015 12:57:28 +0200 Subject: [PATCH] add ElementCoordinatesMappingLocal class --- MeshLib/ElementCoordinatesMappingLocal.cpp | 97 +++++++ MeshLib/ElementCoordinatesMappingLocal.h | 79 +++++ Tests/MeshLib/TestCoordinatesMappingLocal.cpp | 270 ++++++++++++++++++ 3 files changed, 446 insertions(+) create mode 100644 MeshLib/ElementCoordinatesMappingLocal.cpp create mode 100644 MeshLib/ElementCoordinatesMappingLocal.h create mode 100644 Tests/MeshLib/TestCoordinatesMappingLocal.cpp diff --git a/MeshLib/ElementCoordinatesMappingLocal.cpp b/MeshLib/ElementCoordinatesMappingLocal.cpp new file mode 100644 index 00000000000..c6a5c513d76 --- /dev/null +++ b/MeshLib/ElementCoordinatesMappingLocal.cpp @@ -0,0 +1,97 @@ +/** + * \copyright + * Copyright (c) 2012-2015, 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 "ElementCoordinatesMappingLocal.h" + +#include <limits> +#include <cassert> + +#include "GeoLib/AnalyticalGeometry.h" + +#include "MathLib/MathTools.h" +#include "MeshLib/Node.h" + +namespace MeshLib +{ + +ElementCoordinatesMappingLocal::ElementCoordinatesMappingLocal( + const Element& e, + const CoordinateSystem &global_coords) +: _coords(global_coords) +{ + assert(e.getDimension() <= global_coords.getDimension()); + for(size_t i = 0; i < e.getNNodes(); i++) + _point_vec.push_back(MeshLib::Node(*(e.getNode(i)))); + + getRotationMatrixToGlobal(e, global_coords, _point_vec, _matR2global); + rotateToLocal(e, global_coords, _point_vec, _matR2global.transpose(), _point_vec); +} + +void ElementCoordinatesMappingLocal::rotateToLocal( + const Element &ele, + const CoordinateSystem &global_coords, + const std::vector<MeshLib::Node> &vec_pt, + const RotationMatrix &matR2local, + std::vector<MeshLib::Node> &local_pt) const +{ + // rotate the point coordinates + const std::size_t global_dim = global_coords.getDimension(); + Eigen::VectorXd dx = Eigen::VectorXd::Zero(global_dim); + Eigen::VectorXd x_new = Eigen::VectorXd::Zero(3); + for(std::size_t i = 0; i < ele.getNNodes(); i++) + { + for (std::size_t j=0; j<global_dim; j++) + dx[j] = vec_pt[i].getCoords()[j]; + + x_new.head(global_dim) = matR2local * dx; + local_pt[i] = MeshLib::Node(x_new.data()); + } +}; + +void ElementCoordinatesMappingLocal::getRotationMatrixToGlobal( + const Element &e, + const CoordinateSystem &global_coords, + const std::vector<MeshLib::Node> &vec_pt, + RotationMatrix &matR) const +{ + const std::size_t global_dim = global_coords.getDimension(); + + // compute R in x=R*x' where x is original coordinates and x' is local coordinates + matR = RotationMatrix::Zero(global_dim, global_dim); + if (global_dim == e.getDimension()) { + matR = RotationMatrix::Identity(global_dim, global_dim); + } else if (e.getDimension() == 1) { + MathLib::Vector3 xx(vec_pt[0], vec_pt[1]); + xx.normalize(); + if (global_dim == 2) + GeoLib::compute2DRotationMatrixToX(xx, matR); + else + GeoLib::compute3DRotationMatrixToX(xx, matR); + matR.transposeInPlace(); + } else if (global_dim == 3 && e.getDimension() == 2) { + std::vector<MathLib::Point3d*> pnts; + for (auto& p : vec_pt) + pnts.push_back(const_cast<MeshLib::Node*>(&p)); + + // get plane normal + MathLib::Vector3 plane_normal; + double d; + GeoLib::getNewellPlane (pnts, plane_normal, d); + //std::cout << "pn=" << plane_normal << std::endl; + // compute a rotation matrix to XY + MathLib::DenseMatrix<double> matToXY(3,3,0.0); + GeoLib::computeRotationMatrixToXY(plane_normal, matToXY); + // set a transposed matrix + for (size_t i=0; i<global_dim; ++i) + for (size_t j=0; j<global_dim; ++j) + matR(i, j) = matToXY(j,i); + } + +} + +} // MeshLib diff --git a/MeshLib/ElementCoordinatesMappingLocal.h b/MeshLib/ElementCoordinatesMappingLocal.h new file mode 100644 index 00000000000..974ce68c009 --- /dev/null +++ b/MeshLib/ElementCoordinatesMappingLocal.h @@ -0,0 +1,79 @@ +/** + * \copyright + * Copyright (c) 2012-2015, 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 ELEMENTCOORDINATESMAPPINGLOCAL_H_ +#define ELEMENTCOORDINATESMAPPINGLOCAL_H_ + +#include <vector> + +#ifdef OGS_USE_EIGEN +#include <Eigen/Eigen> +#endif + +#include "MathLib/Vector3.h" + +#include "MeshLib/Elements/Element.h" +#include "MeshLib/CoordinateSystem.h" + +namespace MeshLib +{ + +#ifdef OGS_USE_EIGEN +typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> RotationMatrix; +#endif + +/** + * This class maps node coordinates on intrinsic coordinates of the given element. + */ +class ElementCoordinatesMappingLocal +{ +public: + /** + * Constructor + * \param e Mesh element whose node coordinates are mapped + * \param global_coord_system Global coordinate system + */ + ElementCoordinatesMappingLocal(const Element &e, const CoordinateSystem &global_coord_system); + + /// Destructor + virtual ~ElementCoordinatesMappingLocal() {} + + /// return the global coordinate system + const CoordinateSystem getGlobalCoordinateSystem() const { return _coords; } + + /// return mapped coordinates of the node + const MeshLib::Node* getMappedCoordinates(size_t node_id) const + { + return &_point_vec[node_id]; + } + + /// return a rotation matrix converting to global coordinates + const RotationMatrix& getRotationMatrixToGlobal() const {return _matR2global;}; + +private: + /// rotate points to local coordinates + void rotateToLocal( + const Element &e, const CoordinateSystem &coordinate_system, + const std::vector<MeshLib::Node> &vec_pt, const RotationMatrix &matR2local, + std::vector<MeshLib::Node> &local_pt) const; + + /// get a rotation matrix to the global coordinates + /// it computes R in x=R*x' where x is original coordinates and x' is local coordinates + void getRotationMatrixToGlobal( + const Element &e, const CoordinateSystem &coordinate_system, + const std::vector<MeshLib::Node> &vec_pt, RotationMatrix &matR2original) const; + +private: + const CoordinateSystem _coords; + std::vector<MeshLib::Node> _point_vec; + RotationMatrix _matR2global; +}; + +} + +#endif // ELEMENTCOORDINATESMAPPINGLOCAL_H_ diff --git a/Tests/MeshLib/TestCoordinatesMappingLocal.cpp b/Tests/MeshLib/TestCoordinatesMappingLocal.cpp new file mode 100644 index 00000000000..30e223f2b95 --- /dev/null +++ b/Tests/MeshLib/TestCoordinatesMappingLocal.cpp @@ -0,0 +1,270 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/LICENSE.txt + */ + +#include <gtest/gtest.h> + +#include <limits> +#include <algorithm> +#include <vector> +#include <cmath> + +#ifdef OGS_USE_EIGEN +#include <Eigen/Eigen> +#endif + +#include "GeoLib/AnalyticalGeometry.h" +#include "MathLib/LinAlg/Dense/DenseMatrix.h" + +#include "MeshLib/Node.h" +#include "MeshLib/Elements/Element.h" +#include "MeshLib/Elements/Line.h" +#include "MeshLib/Elements/Quad.h" +#include "MeshLib/ElementCoordinatesMappingLocal.h" + +#include "../TestTools.h" + + +namespace +{ + +class TestLine2 +{ +public: + typedef MeshLib::Line ElementType; + static const unsigned dim = ElementType::dimension; + static const unsigned e_nnodes = ElementType::n_all_nodes; + + static MeshLib::Line* createY() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node(0.0, -1.0, 0.0); + nodes[1] = new MeshLib::Node(0.0, 1.0, 0.0); + return new MeshLib::Line(nodes); + } + + static MeshLib::Line* createZ() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node(0.0, 0.0, -1.0); + nodes[1] = new MeshLib::Node(0.0, 0.0, 1.0); + return new MeshLib::Line(nodes); + } + + static MeshLib::Line* createXY() + { + // 45degree inclined + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node(0.0, 0.0, 0.0); + nodes[1] = new MeshLib::Node(2./sqrt(2), 2./sqrt(2), 0.0); + return new MeshLib::Line(nodes); + } + + static MeshLib::Line* createXYZ() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node(0.0, 0.0, 0.0); + nodes[1] = new MeshLib::Node(2./sqrt(3), 2./sqrt(3), 2./sqrt(3)); + return new MeshLib::Line(nodes); + } + +}; + +class TestQuad4 +{ + public: + // Element information + typedef MeshLib::Quad ElementType; + static const unsigned dim = 2; //ElementType::dimension; + static const unsigned e_nnodes = ElementType::n_all_nodes; + + // 2.5D case: inclined + static MeshLib::Quad* createXYZ() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + // rotate 40 degree around x axis + nodes[0] = new MeshLib::Node( 1.0, 0.7071067811865475, 0.7071067811865475); + nodes[1] = new MeshLib::Node(-1.0, 0.7071067811865475, 0.7071067811865475); + nodes[2] = new MeshLib::Node(-1.0, -0.7071067811865475, -0.7071067811865475); + nodes[3] = new MeshLib::Node( 1.0, -0.7071067811865475, -0.7071067811865475); + return new MeshLib::Quad(nodes); + } + + // 2.5D case: inclined + static MeshLib::Quad* createXZ() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node( 1.0, 0.0, 1.0); + nodes[1] = new MeshLib::Node(-1.0, 0.0, 1.0); + nodes[2] = new MeshLib::Node(-1.0, 0.0, -1.0); + nodes[3] = new MeshLib::Node( 1.0, 0.0, -1.0); + return new MeshLib::Quad(nodes); + } + + // 2.5D case: inclined + static MeshLib::Quad* createYZ() + { + MeshLib::Node** nodes = new MeshLib::Node*[e_nnodes]; + nodes[0] = new MeshLib::Node(0.0, 1.0, 1.0); + nodes[1] = new MeshLib::Node(0.0, -1.0, 1.0); + nodes[2] = new MeshLib::Node(0.0, -1.0, -1.0); + nodes[3] = new MeshLib::Node(0.0, 1.0, -1.0); + return new MeshLib::Quad(nodes); + } + +}; + +void debugOutput(MeshLib::Element *ele, MeshLib::ElementCoordinatesMappingLocal &mapping) +{ + std::cout.precision(12); + std::cout << "original" << std::endl; + for (unsigned i=0; i<ele->getNNodes(); i++) + std::cout << *ele->getNode(i) << std::endl; + std::cout << "local coords=" << std::endl; + for (unsigned i=0; i<ele->getNNodes(); i++) + std::cout << *mapping.getMappedCoordinates(i) << std::endl; + std::cout << "R=\n" << mapping.getRotationMatrixToGlobal() << std::endl; + auto matR(mapping.getRotationMatrixToGlobal()); + std::cout << "global coords=" << std::endl; + for (unsigned i=0; i<ele->getNNodes(); i++) { + double* raw = const_cast<double*>(&(*mapping.getMappedCoordinates(i))[0]); + Eigen::Map<Eigen::Vector3d> v(raw); + std::cout << (matR*v).transpose() << std::endl; + } +} + +// check if using the rotation matrix results in the original coordinates +#define CHECK_COORDS(ele, mapping)\ + for (unsigned ii=0; ii<ele->getNNodes(); ii++) {\ + Eigen::Map<Eigen::Vector3d> local(const_cast<double*>(&(*mapping.getMappedCoordinates(ii))[0]));\ + Eigen::Vector3d global(matR*local);\ + const double eps(std::numeric_limits<double>::epsilon());\ + ASSERT_ARRAY_NEAR(&(*ele->getNode(ii))[0], global.data(), 3u, eps);\ + } + +} //namespace + +TEST(MeshLib, CoordinatesMappingLocalLowerDimLineY) +{ + auto ele = TestLine2::createY(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(MeshLib::CoordinateSystemType::Y)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + double exp_R[2*2] = {0, -1, + 1, 0}; //row major + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + +TEST(MeshLib, CoordinatesMappingLocalLowerDimLineZ) +{ + auto ele = TestLine2::createZ(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, + MeshLib::CoordinateSystem(MeshLib::CoordinateSystemType::Z)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + double exp_R[3*3] = {0, 0, -1, 0, 1, 0, 1, 0, 0}; //row major + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + +TEST(MeshLib, CoordinatesMappingLocalLowerDimLineXY) +{ + auto ele = TestLine2::createXY(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + double exp_R[2*2] = {0.70710678118654757, -0.70710678118654757, + 0.70710678118654757, 0.70710678118654757}; //row major + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + +TEST(MeshLib, CoordinatesMappingLocalLowerDimLineXYZ) +{ + auto ele = TestLine2::createXYZ(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + double exp_R[3*3] = {0.57735026918962584, -0.81649658092772626, 0, + 0.57735026918962584, 0.40824829046386313, -0.70710678118654757, + 0.57735026918962584, 0.40824829046386313, 0.70710678118654757}; //row major + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + +TEST(MeshLib, CoordinatesMappingLocalLowerDimQuadXZ) +{ + auto ele = TestQuad4::createXZ(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + // results when using GeoLib::ComputeRotationMatrixToXY() + double exp_R[3*3] = { 1, 0, 0, + 0, 0, -1, + 0, 1, 0}; //row major +// // results when using GeoLib::ComputeRotationMatrixToXY2() +// double exp_R[3*3] = { -1, 0, 0, +// 0, 0, -1, +// 0, -1, 0}; //row major + + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + +TEST(MeshLib, CoordinatesMappingLocalLowerDimQuadYZ) +{ + auto ele = TestQuad4::createYZ(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + // results when using GeoLib::ComputeRotationMatrixToXY() + double exp_R[3*3] = { 0, 0, 1, + 0, 1, 0, + -1, 0, 0}; //row major +// // results when using GeoLib::ComputeRotationMatrixToXY2() +// double exp_R[3*3] = { 0, 0, 1, +// -1, 0, 0, +// 0, -1, 0}; //row major + + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + +TEST(MeshLib, CoordinatesMappingLocalLowerDimQuadXYZ) +{ + auto ele = TestQuad4::createXYZ(); + MeshLib::ElementCoordinatesMappingLocal mapping(*ele, MeshLib::CoordinateSystem(*ele)); + auto matR(mapping.getRotationMatrixToGlobal()); + //debugOutput(ele, mapping); + + // results when using GeoLib::ComputeRotationMatrixToXY() + double exp_R[3*3] = { 1, 0, 0, + 0, 0.70710678118654757, -0.70710678118654757, + 0, 0.70710678118654757, 0.70710678118654757}; //row major +// // results when using GeoLib::ComputeRotationMatrixToXY2() +// double exp_R[3*3] = { -1, 0, 0, +// 0, -0.70710678118654757, -0.70710678118654757, +// 0, -0.70710678118654757, 0.70710678118654757}; //row major + + const double eps(std::numeric_limits<double>::epsilon()); + ASSERT_ARRAY_NEAR(exp_R, matR.data(), matR.size(), eps); + CHECK_COORDS(ele,mapping); +} + -- GitLab