Skip to content

Add Rotation class with docs and bindings#66

Open
chemiskyy wants to merge 18 commits intomasterfrom
feature/rotation
Open

Add Rotation class with docs and bindings#66
chemiskyy wants to merge 18 commits intomasterfrom
feature/rotation

Conversation

@chemiskyy
Copy link
Member

This pull request introduces a major enhancement to Simcoon 2.0 by adding a comprehensive new 3D rotation library centered around a Rotation class, with full Python bindings and extensive documentation. The changes improve both the C++ and Python APIs, update the documentation to reflect the new capabilities, and ensure the new class is tested and integrated throughout the build system.

Rotation Library Addition and Integration:

  • Introduced a new Rotation class for 3D rotations, using unit quaternions internally for stability and efficiency, with support for various representations (Euler angles, rotation matrices, quaternions, rotation vectors, axis-angle), composition, interpolation (SLERP), and Voigt notation transformations. The class is available in both C++ and Python APIs. [1] [2]
  • Registered the Rotation class in the Python bindings via pybind11, including the new wrapper source and header files in the build system for both C++ and Python modules. [1] [2] [3] [4]
  • Added unit tests for the new Rotation class to the test suite.

Documentation Updates:

  • Added a comprehensive new documentation page (doc_rotation.rst) detailing the Rotation class, its API, usage examples, and practical applications in continuum mechanics.
  • Updated the continuum mechanics and maths documentation to reference and describe the new rotation tools, and added the new page to the documentation index. [1] [2]
  • Updated the C++ API documentation to include the new rotation module, and provided a summary of new features in Simcoon 2.0, highlighting the enhanced rotation capabilities. [1] [2]Introduce a new Rotation subsystem: adds a C++ Rotation class (include/.../rotation_class.hpp and src/Simulation/Maths/rotation_class.cpp) implementing quaternion-based 3D rotations, Voigt operations, Euler conventions, SLERP, and apply methods for vectors/tensors. Add Python bindings (pybind11) and headers in simcoon-python-builder, update its CMake to build the rotation_class wrapper, and extend the python module registration. Add comprehensive documentation pages (continuum mechanics and C++ API) and index updates. Include a unit test (test/Libraries/Maths/TRotationClass.cpp) and adjust top-level CMakeLists where needed. This patch adds rotation functionality, docs, bindings, and tests to enable quaternion-based rotation operations from C++ and Python.

Introduce a new Rotation subsystem: adds a C++ Rotation class (include/.../rotation_class.hpp and src/Simulation/Maths/rotation_class.cpp) implementing quaternion-based 3D rotations, Voigt operations, Euler conventions, SLERP, and apply methods for vectors/tensors. Add Python bindings (pybind11) and headers in simcoon-python-builder, update its CMake to build the rotation_class wrapper, and extend the python module registration. Add comprehensive documentation pages (continuum mechanics and C++ API) and index updates. Include a unit test (test/Libraries/Maths/TRotationClass.cpp) and adjust top-level CMakeLists where needed. This patch adds rotation functionality, docs, bindings, and tests to enable quaternion-based rotation operations from C++ and Python.
@chemiskyy chemiskyy marked this pull request as draft February 4, 2026 17:04
Add input validation helpers in the Python wrapper (validate_vector_size, validate_matrix_size) and apply them to rotation bindings to ensure correct array shapes. Add SciPy interoperability: Rotation.from_scipy and to_scipy methods with docs and conversions via quaternions. Replace uses of legacy sim_pi/sim_iota with simcoon::pi and simcoon::iota across Rotation implementation and update tests accordingly to use the centralized constants. This improves robustness of the Python API and unifies constant usage in the core code and tests.
Expand rotation Python docs with Scipy interoperability, active vs passive rotation conventions, input validation guidance, and notes on quaternion equivalence. Fix cross‑references in C++ API docs to point to the correct continuum_mechanics doc pages. Rename test file to Trotation_class.cpp, update CMakeLists, and add comprehensive Rotation unit tests (tensor/stiffness/compliance behavior, factory methods, Euler conventions, round‑trip and gimbal‑lock cases) to improve coverage and verify correctness.
Rename ambiguous as_QS/as_QE to explicit as_voigt_stress_rotation/as_voigt_strain_rotation and add apply_localization_strain/apply_localization_stress to Rotation API. Update implementation, header, Python bindings, documentation and tests to use the new names and to expose rotation of localization tensors (QE·A·QS^T and QS·B·QE^T). Refactor callers (ellipsoid_multi, state_variables*, etc.) to use Rotation::from_euler and the new apply_* methods instead of ad-hoc rotate_* helpers; add necessary includes and input validation for 6×6 tensors. Add unit tests verifying consistency with existing fillQS/fillQE/rotateA/rotateB functions and update docs to reflect the new API and examples.
@chemiskyy chemiskyy marked this pull request as ready for review February 5, 2026 22:13
Remove default values for Euler convention and active/passive flags across rotation APIs and pybind bindings to force callers to specify convention and mode. Updated C++ headers (rotation.hpp, rotation_class.hpp) and Python wrappers to make conv and active mandatory, adjusted pybind registrations in python_module.cpp and rotation_class.cpp, and updated tests (Trotation.cpp) to pass explicit arguments. Also add simcoon_docs rotation docstrings (doc_rotation.hpp) and hook them into module definitions for improved Python documentation.
Docs updated to remove references to a "default" Euler convention and require the convention to be specified in examples. In rotation.cpp, the previous behavior of printing an error and falling back to default axes has been replaced with throwing std::invalid_argument when an invalid Euler convention is supplied (message lists supported conventions). This enforces explicit, valid conventions and prevents silent fallback. Affected files: docs/continuum_mechanics/functions/doc_rotation.rst, docs/cpp_api/simulation/rotation.rst, src/Simulation/Maths/rotation.cpp.
@chemiskyy chemiskyy added the enhancement New feature or request label Feb 6, 2026
Rename and reorganize rotation-related documentation to match updated API names and types. Key changes:
- Replace old function names with clearer ones: rotateL/rotateM -> rotate_stiffness/rotate_compliance; apply_localization_* -> apply_*_concentration; rotate_l2g_*/g2l_* functions replaced by *_R and *_angle variants.
- Update free-function autodoc/doxygen entries and Python autofunction names accordingly.
- Change C++ include references from rotation_class.hpp to rotation.hpp and document new Rotation construction functions (Rotation::from_euler, Rotation::from_axis_angle).
- Update examples to use Rotation::from_euler or pass a Rotation matrix to free functions.
These edits align the docs with the refactored rotation API and clarify naming (strain/stress concentration vs localization).
Rename and reorganize rotation-related Python wrappers and docs for clarity and vectorized usage. Replaced legacy fillR/fillQS/fillQE and rotateL/M/A/B/l2g/g2l APIs with clearer functions (rotate_stiffness_*, rotate_compliance_*, rotate_strain_concentration_*, rotate_stress_concentration_*, rotate_strain_*, rotate_stress_*), updated wrapper implementations to use descriptive variable names and support batched (ndim==2) inputs, and adjusted Rotation class method names (apply_localization_* -> apply_*_concentration). Also updated example docs to use simcoon.Rotation.from_axis_angle(...). Modified files: include/docs/Libraries/Maths/doc_rotation.hpp, include/simcoon/python_wrappers/Libraries/Maths/rotation.hpp, src/python_wrappers/Libraries/Maths/rotation.cpp, src/python_wrappers/Libraries/Maths/rotation_class.cpp, src/python_wrappers/python_module.cpp.
Introduce a unified Rotation class into rotation.hpp (merged from the removed rotation_class.hpp) providing quaternion-based factories, conversions, and apply methods for vectors, tensors and Voigt-notation quantities. Rename and refactor many legacy free functions (fillR / fillQS / fillQE / rotateL / rotateM / rotateA / rotateB / etc.) to clearer APIs (rotate_vec/rotate_mat, rotate_stress, rotate_strain, rotate_stiffness, rotate_compliance, rotate_strain_concentration, rotate_stress_concentration, etc.). Update the Python example to use sim.Rotation.from_axis_angle / from_euler and the new rotate_* function names. Remove the standalone rotation_class header and corresponding legacy sources to consolidate rotation functionality; this is a breaking API change that modernizes rotation handling and exposes richer functionality (quaternions, Euler, rotvec, Voigt helpers, slerp, composition, etc.).
Replace legacy rotation helpers with the new Rotation class methods across the codebase and tests. Updates include: using Rotation::from_euler / from_matrix and its apply_* helpers (apply_stiffness, apply_compliance, apply_strain/apply_stress, apply_strain_concentration/apply_stress_concentration) instead of free functions like rotateL, rotateM, rotateA, rotate_g2l_L, rotate_g2l_stress, rotate_l2g_A, fillR, fillQE/QS, etc. Remove includes of rotation_class.hpp where no longer needed. Adjusted unit tests to construct expected rotations via the Rotation API and to validate transformations by applying rotations to vectors/matrices rather than calling the old utility functions. Changes touch continuum mechanics, homogenization, micromechanics schemes, phase state variables, and math tests to unify on the new rotation interface and improve consistency.
Comment on lines 160 to 165
# This example uses both :func:`simcoon.rotate_stress_concentration_angle` and
# :func:`simcoon.rotate_stress_concentration_R`.

B6 = np.eye(6)
rotB1 = sim.rotateB_angle(B6, angle, axis, active, copy)
rotB2 = sim.rotateB_R(B6, Rmat, active, copy)
rotB1 = sim.rotate_stress_concentration_angle(B6, angle, axis, active, copy)
rotB2 = sim.rotate_stress_concentration_R(B6, Rmat, active, copy)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be updated too?

Comment on lines 194 to 195
L_rotate = sim.rotate_stiffness_R(L, rot_matrix)
L_rotate_angle = sim.rotate_stiffness_angle(L, alpha, axis=3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too?

Comment on lines 5 to 125
constexpr auto rotate_vec_R = R"pbdoc(
Rotate a 3D vector using a rotation matrix.

Parameters
----------
input : ndarray
3D vector to rotate.
R : ndarray
3x3 rotation matrix.
copy : bool, optional
If True (default), return a copy of the result.

Returns
-------
ndarray
Rotated 3D vector.

Examples
--------
.. code-block:: python

import numpy as np
import simcoon as sim

v = np.array([1.0, 0.0, 0.0])
R = sim.Rotation.from_axis_angle(np.pi/4, 3).as_matrix()
v_rot = sim.rotate_vec_R(v, R)
print(v_rot)
)pbdoc";

constexpr auto rotate_vec_angle = R"pbdoc(
Rotate a 3D vector by an angle around a given axis.

Parameters
----------
input : ndarray
3D vector to rotate.
angle : float
Rotation angle in radians.
axis : int
Axis of rotation: 1=x, 2=y, 3=z.
copy : bool, optional
If True (default), return a copy of the result.

Returns
-------
ndarray
Rotated 3D vector.

Examples
--------
.. code-block:: python

import numpy as np
import simcoon as sim

v = np.array([1.0, 0.0, 0.0])
v_rot = sim.rotate_vec_angle(v, np.pi/4, 3)
print(v_rot)
)pbdoc";

constexpr auto rotate_mat_R = R"pbdoc(
Rotate a 3x3 matrix using a rotation matrix.

Parameters
----------
input : ndarray
3x3 matrix to rotate.
R : ndarray
3x3 rotation matrix.
copy : bool, optional
If True (default), return a copy of the result.

Returns
-------
ndarray
Rotated 3x3 matrix: R * input * R^T.

Examples
--------
.. code-block:: python

import numpy as np
import simcoon as sim

m = np.eye(3)
R = sim.Rotation.from_axis_angle(np.pi/4, 3).as_matrix()
m_rot = sim.rotate_mat_R(m, R)
print(m_rot)
)pbdoc";

constexpr auto rotate_mat_angle = R"pbdoc(
Rotate a 3x3 matrix by an angle around a given axis.

Parameters
----------
input : ndarray
3x3 matrix to rotate.
angle : float
Rotation angle in radians.
axis : int
Axis of rotation: 1=x, 2=y, 3=z.
copy : bool, optional
If True (default), return a copy of the result.

Returns
-------
ndarray
Rotated 3x3 matrix.

Examples
--------
.. code-block:: python

import numpy as np
import simcoon as sim

m = np.eye(3)
m_rot = sim.rotate_mat_angle(m, np.pi/4, 3)
print(m_rot)
)pbdoc";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still up to date?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not!, will be removed in a next commit

Comment on lines 19 to 33
//These functions rotate a 6*6 stiffness matrix
pybind11::array_t<double> rotate_stiffness_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_stiffness_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);

//This function returns the 6*6 rotation arma::matrix of a arma::vector of type 'strain' from an angle and an axis
pybind11::array_t<double> fillQE_angle(const double &angle, const int &axis, const bool &active=true, const bool &copy=true);

//This function returns the 6*6 rotation arma::matrix of a arma::vector of type 'strain' from a rotation matrix
pybind11::array_t<double> fillQE_R(const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
//These functions rotate a 6*6 compliance matrix
pybind11::array_t<double> rotate_compliance_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_compliance_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);

//These functions rotates a 6*6 stiffness arma::matrix (L)
pybind11::array_t<double> rotateL_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotateL_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_l2g_L(const pybind11::array_t<double> &input, const double &, const double &, const double &, const bool &copy=true);
pybind11::array_t<double> rotate_g2l_L(const pybind11::array_t<double> &input, const double &, const double &, const double &, const bool &copy=true);

//These functions rotates a 6*6 compliance arma::matrix (M)
pybind11::array_t<double> rotateM_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotateM_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_l2g_M(const pybind11::array_t<double> &input, const double &psi, const double &theta, const double &phi, const bool &copy=true);
pybind11::array_t<double> rotate_g2l_M(const pybind11::array_t<double> &input, const double &psi, const double &theta, const double &phi, const bool &copy=true);

//These functions rotates a 6*6 strain concentration (A)
pybind11::array_t<double> rotateA_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotateA_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_l2g_A(const pybind11::array_t<double> &input, const double &psi, const double &theta, const double &phi, const bool &copy=true);
pybind11::array_t<double> rotate_g2l_A(const pybind11::array_t<double> &input, const double &psi, const double &theta, const double &phi, const bool &copy=true);

//These functions rotates a 6*6 stress concentration (B)
pybind11::array_t<double> rotateB_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotateB_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_l2g_B(const pybind11::array_t<double> &input, const double &psi, const double &theta, const double &phi, const bool &copy=true);
pybind11::array_t<double> rotate_g2l_B(const pybind11::array_t<double> &input, const double &psi, const double &theta, const double &phi, const bool &copy=true);

//These functions rotates strain arma::vectors
//These functions rotate a 6*6 strain concentration tensor (A)
pybind11::array_t<double> rotate_strain_concentration_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_strain_concentration_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);

//These functions rotate a 6*6 stress concentration tensor (B)
pybind11::array_t<double> rotate_stress_concentration_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_stress_concentration_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up-to-date?

Copy link
Member Author

@chemiskyy chemiskyy Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All file will be removed in a forthcoming commit

Comment on lines 36 to 41
pybind11::array_t<double> rotate_strain_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_strain_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_l2g_strain(const pybind11::array_t<double> &, const double &psi, const double &theta, const double &phi, const bool &copy=true);
pybind11::array_t<double> rotate_g2l_strain(const pybind11::array_t<double> &, const double &psi, const double &theta, const double &phi, const bool &copy=true);

//These functions rotates stress arma::vectors
//These functions rotate stress vectors - Can be used with stack of arrays (vectorized)
pybind11::array_t<double> rotate_stress_angle(const pybind11::array_t<double> &input, const double &angle, const int &axis, const bool &active=true, const bool &copy=true);
pybind11::array_t<double> rotate_stress_R(const pybind11::array_t<double> &input, const pybind11::array_t<double> &R, const bool &active=true, const bool &copy=true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up-to-date?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, all these functions should disappear, not more _R or _angle

Comment on lines 17 to 193
@@ -186,17 +149,17 @@ py::array_t<double> rotate_stress_R(const py::array_t<double> &input, const py::
//This function rotates strain vectors - Can be used with stack of arrays (vectorized)
py::array_t<double> rotate_strain_angle(const py::array_t<double> &input, const double &angle, const int &axis, const bool &active, const bool &copy) {
if (input.ndim()==1){
vec v = carma::arr_to_col(input);
vec rotated_strain = simcoon::rotate_strain(v,angle,axis,active);
vec strain = carma::arr_to_col(input);
vec rotated_strain = simcoon::rotate_strain(strain, angle, axis, active);
return carma::col_to_arr(rotated_strain, copy);
}
else if (input.ndim() == 2){
mat m = carma::arr_to_mat_view(input);
int nb_points = m.n_cols;
mat rotated_strain(6,nb_points);
mat strain_batch = carma::arr_to_mat_view(input);
int nb_points = strain_batch.n_cols;
mat rotated_strain(6, nb_points);
for (int pt = 0; pt < nb_points; pt++) {
vec v = m.unsafe_col(pt);
rotated_strain.col(pt) = simcoon::rotate_strain(v,angle,axis,active);
vec strain = strain_batch.unsafe_col(pt);
rotated_strain.col(pt) = simcoon::rotate_strain(strain, angle, axis, active);
}
return carma::mat_to_arr(rotated_strain, copy);
}
@@ -208,19 +171,19 @@ py::array_t<double> rotate_strain_angle(const py::array_t<double> &input, const
//This function rotates strain vectors - Can be used with stack of arrays (vectorized)
py::array_t<double> rotate_strain_R(const py::array_t<double> &input, const py::array_t<double> &R, const bool &active, const bool &copy) {
if (input.ndim()==1){
vec v = carma::arr_to_col(input);
vec strain = carma::arr_to_col(input);
mat R_cpp = carma::arr_to_mat(R);
vec rotated_strain = simcoon::rotate_strain(v,R_cpp,active);
vec rotated_strain = simcoon::rotate_strain(strain, R_cpp, active);
return carma::col_to_arr(rotated_strain, copy);
}
else if (input.ndim() == 2){
mat m = carma::arr_to_mat_view(input);
mat strain_batch = carma::arr_to_mat_view(input);
cube R_cpp = carma::arr_to_cube_view(R);
int nb_points = m.n_cols;
mat rotated_strain(6,nb_points);
int nb_points = strain_batch.n_cols;
mat rotated_strain(6, nb_points);
for (int pt = 0; pt < nb_points; pt++) {
vec v = m.unsafe_col(pt);
rotated_strain.col(pt) = simcoon::rotate_strain(v,R_cpp.slice(pt),active);
vec strain = strain_batch.unsafe_col(pt);
rotated_strain.col(pt) = simcoon::rotate_strain(strain, R_cpp.slice(pt), active);
}
return carma::mat_to_arr(rotated_strain, copy);
}
@@ -229,88 +192,4 @@ py::array_t<double> rotate_strain_R(const py::array_t<double> &input, const py::
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up-to-date?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file will disappear

Comment on lines 214 to 229
m.def("rotate_vec_R", &rotate_vec_R, "input"_a, "R"_a, "copy"_a = true, simcoon_docs::rotate_vec_R);
m.def("rotate_vec_angle", &rotate_vec_angle, "input"_a, "angle"_a, "axis"_a, "copy"_a = true, simcoon_docs::rotate_vec_angle);
m.def("rotate_mat_R", &rotate_mat_R, "input"_a, "R"_a, "copy"_a = true, simcoon_docs::rotate_mat_R);
m.def("rotate_mat_angle", &rotate_mat_angle, "input"_a, "angle"_a, "axis"_a, "copy"_a = true, simcoon_docs::rotate_mat_angle);
m.def("rotate_stiffness_angle", &rotate_stiffness_angle, "input"_a, "angle"_a, "axis"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 stiffness matrix according to an angle and an axis");
m.def("rotate_stiffness_R", &rotate_stiffness_R, "input"_a, "R"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 stiffness matrix according to a rotation matrix");
m.def("rotate_compliance_angle", &rotate_compliance_angle, "input"_a, "angle"_a, "axis"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 compliance matrix according to an angle and an axis");
m.def("rotate_compliance_R", &rotate_compliance_R, "input"_a, "R"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 compliance matrix according to a rotation matrix");
m.def("rotate_strain_concentration_angle", &rotate_strain_concentration_angle, "input"_a, "angle"_a, "axis"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 strain concentration tensor according to an angle and an axis");
m.def("rotate_strain_concentration_R", &rotate_strain_concentration_R, "input"_a, "R"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 strain concentration tensor according to a rotation matrix");
m.def("rotate_stress_concentration_angle", &rotate_stress_concentration_angle, "input"_a, "angle"_a, "axis"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 stress concentration tensor according to an angle and an axis");
m.def("rotate_stress_concentration_R", &rotate_stress_concentration_R, "input"_a, "R"_a, "active"_a = true, "copy"_a = true, "Return the rotated 6x6 stress concentration tensor according to a rotation matrix");
m.def("rotate_strain_angle", &rotate_strain_angle, "input"_a, "angle"_a, "axis"_a, "active"_a = true, "copy"_a = false, "Return the rotated strain vector using Voigt notation according to an angle and an axis");
m.def("rotate_strain_R", &rotate_strain_R, "input"_a, "R"_a, "active"_a = true, "copy"_a = false, "Return the rotated strain vector using Voigt notation according to a rotation matrix");
m.def("rotate_stress_angle", &rotate_stress_angle, "input"_a, "angle"_a, "axis"_a, "active"_a = true, "copy"_a = false, "Return the rotated stress vector using Voigt notation according to an angle and an axis");
m.def("rotate_stress_R", &rotate_stress_R, "input"_a, "R"_a, "active"_a = true, "copy"_a = false, "Return the rotated stress vector using Voigt notation according to a rotation matrix");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up-to-date?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, all these functions are to be removed

Comment on lines 98 to 126
@@ -75,16 +116,16 @@ mat fillR(const double &alpha, const int &axis, const bool &active) {
break;
}
default: {
cout << "Please choose the axis 1,2 or 3\n";
throw invalid_argument("Please choose the axis 1, 2 or 3");
}
}
return R;
}

mat fillR(const double &psi, const double &theta, const double &phi, const bool &active, const std::string &conv) {
// Internal: Generate a 3x3 rotation matrix using Euler angles
mat fillR_euler_internal(const double &psi, const double &theta, const double &phi, const bool &active, const std::string &conv) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining R notations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the file will disappear

Copy link
Member

@kmarchais kmarchais left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably there are still a few notations left to modify unless this is intentional

Remove the legacy Python bindings and documentation for the standalone rotation free-functions and migrate examples/docs to use the Rotation class API.

Changes:
- Docs: updated docs/continuum_mechanics/functions/doc_rotation.rst and docs/cpp_api/simulation/rotation.rst to remove free-function sections and emphasize the Rotation class.
- Examples: examples/continuum_mechanics/rotation.py rewritten to use simcoon.Rotation (from_axis_angle/from_euler and apply/apply_tensor/apply_stress/etc.) instead of the rotate_* free functions.
- Python bindings: deleted simcoon-python-builder/include/simcoon/docs/Libraries/Maths/doc_rotation.hpp, include/simcoon/python_wrappers/Libraries/Maths/rotation.hpp and src/python_wrappers/Libraries/Maths/rotation.cpp; removed their registration from python_module.cpp.
- Build: simcoon-python-builder/CMakeLists.txt no longer compiles src/python_wrappers/Libraries/Maths/rotation.cpp.

Rationale: consolidate the public Python API around the object-oriented Rotation class and remove duplicated/free-function Python wrappers while keeping the Rotation class binding and C++ API intact.
Rename the Rotation pybind11 wrapper files and update references: rotation_class.hpp -> rotation.hpp and rotation_class.cpp -> rotation.cpp. Rename the registration function register_rotation_class -> register_rotation and update its declaration, definition, includes, and the call in python_module.cpp. Update CMakeLists.txt to build src/python_wrappers/Libraries/Maths/rotation.cpp. This unifies the wrapper naming and keeps module registration consistent.
@github-project-automation github-project-automation bot moved this to Backlog in simcoon 2.0 Feb 7, 2026
Make simcoon.Rotation a subclass of scipy.spatial.transform.Rotation and add full scipy interoperability. Adds a pure-Python simcoon.rotation.Rotation wrapper that inherits scipy Rotation and delegates mechanics operations (apply_stress/strain/stiffness/etc.) to the C++ backend via a new _CppRotation interface. The C++ pybind wrapper was adjusted to expose simcoon::Rotation as _CppRotation and to accept plain scipy-like Rotation objects (duck-typed via as_quat) for composition, slerp and equality. Updated package metadata to require scipy, refreshed docs and examples to use scipy Euler conventions and show interoperability, and added comprehensive tests for type identity, mechanics methods, scipy upgrades, and C++ handling of scipy objects. Also import Rotation in __init__ to override the star-imported C++ class.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants