Skip to content
Snippets Groups Projects
Forked from ogs / ogs
898 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CoordinateSystem.h 4.16 KiB
/**
 * \file
 * \copyright
 * Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 */

#pragma once

#include <Eigen/Core>
#include <array>
#include <vector>

namespace ParameterLib
{
template <typename T>
struct Parameter;
class SpatialPosition;
}  // namespace ParameterLib

namespace ParameterLib
{
/**
 * \brief A local coordinate system used for tensor transformations.
 *
 * It offers a simple way for input of anisotropic tensors w.r.t. a coordinate
 * system.
 * The basis vectors form a transformation matrix \f$R = (e_0, e_1, e_2)\f$.
 * For a given anisotropic tensor \f$A\f$ parameter with the corresponding
 * \ref ogs_file_param__prj__parameters__parameter__use_local_coordinate_system
 * the tensor is rotated according to the formula: \f$A' = R\cdot A\cdot R^T\f$.
 *
 * For computations in transverse isotropic material models, we can create a
 * coordinate system with only one base, where the last base is explicitly
 * given. The other bases are set as implicit and computed from the given base
 * as follows:
 *  - For a 2D coordinate system, the unit vector orthogonal to
 *    the given base is used as the first base,
 *  - For a 3D coordinate system, the given base vector, \c unit_direction,
 *    is set as the third base,  \f${\vec e}_2\f$. An arbitrary unit vector
 *    orthogonal to \f${\vec e}_2\f$ is selected as the second base
 *    \f$e_1\f$, and the first  base \f${\vec e}_0\f$ is calculated as
 *    \f${\vec e}_0 = {\vec e}_1 \times {\vec e}_2\f$.
 */
struct CoordinateSystem final
{
    /**
     * It is used to create a local coordinate system with only one base, where
     * the last base is explicitly given as \c unit_direction.
     *
     * @param unit_direction The specified unit direction.
     */
    explicit CoordinateSystem(Parameter<double> const& unit_direction);

    CoordinateSystem(Parameter<double> const& e0, Parameter<double> const& e1);

    CoordinateSystem(Parameter<double> const& e0,
                     Parameter<double> const& e1,
                     Parameter<double> const& e2);

    template <int Dimension>
    Eigen::Matrix<double, Dimension, Dimension> transformation(
        SpatialPosition const& pos) const;

    Eigen::Matrix<double, 3, 3> transformation_3d(
        SpatialPosition const& pos) const;
    template <int Dimension>
    Eigen::Matrix<double, Dimension, Dimension> rotateTensor(
        std::vector<double> const& values, SpatialPosition const& pos) const;

    template <int Dimension, typename Derived>
    Eigen::Matrix<double, Dimension, Dimension> rotateTensor(
        Eigen::MatrixBase<Derived> const& tensor,
        SpatialPosition const& pos) const;

    template <int Dimension>
    Eigen::Matrix<double, Dimension, Dimension> rotateDiagonalTensor(
        std::vector<double> const& values, SpatialPosition const& pos) const;

private:
    std::array<Parameter<double> const*, 3> _base;
    bool _has_implicit_base;

    Eigen::Matrix<double, 3, 3> transformationFromSingleBase_3d(
        SpatialPosition const& pos) const;
};

template <int Dimension, typename Derived>
Eigen::Matrix<double, Dimension, Dimension> CoordinateSystem::rotateTensor(
    Eigen::MatrixBase<Derived> const& tensor, SpatialPosition const& pos) const
{
    auto const R = transformation<Dimension>(pos);
    return R * tensor * R.transpose();
}

extern template Eigen::Matrix<double, 2, 2> CoordinateSystem::rotateTensor<2>(
    std::vector<double> const& values, SpatialPosition const& pos) const;
extern template Eigen::Matrix<double, 3, 3> CoordinateSystem::rotateTensor<3>(
    std::vector<double> const& values, SpatialPosition const& pos) const;
extern template Eigen::Matrix<double, 2, 2>
CoordinateSystem::rotateDiagonalTensor<2>(std::vector<double> const& values,
                                          SpatialPosition const& pos) const;
extern template Eigen::Matrix<double, 3, 3>
CoordinateSystem::rotateDiagonalTensor<3>(std::vector<double> const& values,
                                          SpatialPosition const& pos) const;
}  // namespace ParameterLib