Program Listing for File reference_frame.h¶
↰ Return to documentation for file (include/immersx/coupling/reference_frame.h)
// ---------------------------------------------------------------------
//
// Copyright (C) 2026 by Luca Heltai
//
// This file is part of the ImmersX application, based on the deal.II
// library.
//
// ---------------------------------------------------------------------
#ifndef immersx_reference_frame_h
#define immersx_reference_frame_h
#include <deal.II/base/exceptions.h>
#include <deal.II/base/tensor.h>
#include <cmath>
namespace ImmersX
{
namespace detail
{
template <int spacedim>
dealii::Tensor<2, spacedim>
reference_to_physical_rotation(const dealii::Tensor<1, spacedim> &tangent)
{
static_assert(spacedim == 2 || spacedim == 3,
"Reference-frame rotations support 2D and 3D only.");
AssertThrow(tangent.norm() > 0.,
dealii::ExcMessage(
"The physical frame direction must be non-zero."));
dealii::Tensor<1, spacedim> reference_vertical;
reference_vertical[spacedim - 1] = 1.;
const auto unit_tangent = tangent / tangent.norm();
dealii::Tensor<2, spacedim> rotation;
if constexpr (spacedim == 2)
{
// R(theta) e_y = (-sin(theta), cos(theta)).
const double cosine = reference_vertical * unit_tangent;
const double sine = -unit_tangent[0];
rotation[0][0] = cosine;
rotation[0][1] = -sine;
rotation[1][0] = sine;
rotation[1][1] = cosine;
}
else
{
auto axis =
dealii::cross_product_3d(reference_vertical, unit_tangent);
const auto sine = axis.norm();
const auto cosine = reference_vertical * unit_tangent;
constexpr double tolerance = 1.e-14;
if (sine > tolerance)
axis /= sine;
else if (cosine > 0.)
{
axis = 0.;
}
else
{
// e_z -> -e_z is a pi rotation about e_x. This choice is
// deterministic and keeps the transformation proper.
axis = 0.;
axis[0] = 1.;
}
for (unsigned int i = 0; i < spacedim; ++i)
for (unsigned int j = 0; j < spacedim; ++j)
rotation[i][j] =
(i == j ? cosine : 0.) + (1. - cosine) * axis[i] * axis[j];
if (sine > tolerance)
{
rotation[0][1] -= sine * axis[2];
rotation[0][2] += sine * axis[1];
rotation[1][0] += sine * axis[2];
rotation[1][2] -= sine * axis[0];
rotation[2][0] -= sine * axis[1];
rotation[2][1] += sine * axis[0];
}
}
return rotation;
}
} // namespace detail
} // namespace ImmersX
#endif // immersx_reference_frame_h