From c77a98533e889381e91824495012f6724e797d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Mon, 14 Dec 2020 21:15:11 +0100 Subject: [PATCH 01/31] utils: Calculate the angle between vectors --- src/utils/include/utils/math/vec_rotate.hpp | 7 +++++++ src/utils/tests/vec_rotate_test.cpp | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/utils/include/utils/math/vec_rotate.hpp b/src/utils/include/utils/math/vec_rotate.hpp index 32c1cc23d8d..3cb9f48e340 100644 --- a/src/utils/include/utils/math/vec_rotate.hpp +++ b/src/utils/include/utils/math/vec_rotate.hpp @@ -64,6 +64,13 @@ rotation_params(Vector3d const &vec, Vector3d const &target_vec) { return std::make_tuple(0.0, Vector3d{}); } +/** + * @brief Determine the angle between two vectors. + */ +inline double angle_between(Vector3d const &v1, Vector3d const &v2) { + return std::acos(v1 * v2 / std::sqrt(v1.norm2() * v2.norm2())); +} + } // namespace Utils #endif diff --git a/src/utils/tests/vec_rotate_test.cpp b/src/utils/tests/vec_rotate_test.cpp index 18b9b14ef45..6539c5c5d46 100644 --- a/src/utils/tests/vec_rotate_test.cpp +++ b/src/utils/tests/vec_rotate_test.cpp @@ -60,3 +60,11 @@ BOOST_AUTO_TEST_CASE(rotation_params) { BOOST_CHECK_SMALL((rotation_axis * v1), 1e-7); BOOST_CHECK_SMALL((rotation_axis * v2), 1e-7); } + +BOOST_AUTO_TEST_CASE(angle_between) { + Utils::Vector3d const v1 = {1.0, 0.0, 0.0}; + Utils::Vector3d const v2 = {1.0, 1.0, 0.0}; + + auto const angle = Utils::angle_between(v1, v2); + BOOST_CHECK_CLOSE(angle, Utils::pi() / 4.0, 1e-7); +} From 27fbcde97f6d4572606fe9c4858bc99e1fd59ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Mon, 14 Dec 2020 21:23:55 +0100 Subject: [PATCH 02/31] tests: Add floating point tolerance --- src/utils/tests/coordinate_transformation.cpp | 14 ++++++++------ src/utils/tests/matrix_test.cpp | 4 +++- src/utils/tests/vec_rotate_test.cpp | 3 +-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/utils/tests/coordinate_transformation.cpp b/src/utils/tests/coordinate_transformation.cpp index 714a11700e1..77b27ca43ea 100644 --- a/src/utils/tests/coordinate_transformation.cpp +++ b/src/utils/tests/coordinate_transformation.cpp @@ -29,6 +29,7 @@ using Utils::Vector3d; BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_test) { + constexpr auto eps = 1e-14; Vector3d const cart_coord{{1.0, 3.3, 2.0}}; auto const transformed_x = transform_coordinate_cartesian_to_cylinder( cart_coord, Vector3d{{1, 0, 0}}); @@ -51,13 +52,14 @@ BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_test) { std::atan2(cart_coord[1], cart_coord[0]), cart_coord[2]}}; for (int i = 0; i < 3; ++i) { - BOOST_CHECK(transformed_x[i] == expected_x[i]); - BOOST_CHECK(transformed_y[i] == expected_y[i]); - BOOST_CHECK(transformed_z[i] == expected_z[i]); + BOOST_CHECK_SMALL(transformed_x[i] - expected_x[i], eps); + BOOST_CHECK_SMALL(transformed_y[i] - expected_y[i], eps); + BOOST_CHECK_SMALL(transformed_z[i] - expected_z[i], eps); } } BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_test) { + constexpr auto eps = 1e-14; Vector3d const cylinder_coord{{1.2, 3.123, 42.0}}; auto const transformed_x = transform_coordinate_cylinder_to_cartesian( cylinder_coord, Vector3d{{1, 0, 0}}); @@ -80,8 +82,8 @@ BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_test) { {cylinder_coord[0] * std::cos(cylinder_coord[1]), cylinder_coord[0] * std::sin(cylinder_coord[1]), cylinder_coord[2]}}; for (int i = 0; i < 3; ++i) { - BOOST_CHECK(transformed_x[i] == expected_x[i]); - BOOST_CHECK(transformed_y[i] == expected_y[i]); - BOOST_CHECK(transformed_z[i] == expected_z[i]); + BOOST_CHECK_SMALL(transformed_x[i] - expected_x[i], eps); + BOOST_CHECK_SMALL(transformed_y[i] - expected_y[i], eps); + BOOST_CHECK_SMALL(transformed_z[i] - expected_z[i], eps); } } diff --git a/src/utils/tests/matrix_test.cpp b/src/utils/tests/matrix_test.cpp index e5f9898c4b4..0c9165fe57d 100644 --- a/src/utils/tests/matrix_test.cpp +++ b/src/utils/tests/matrix_test.cpp @@ -1,6 +1,8 @@ /* * Copyright (C) 2018-2019 The ESPResSo project * + * This file is part of ESPResSo. + * * ESPResSo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -18,7 +20,7 @@ #define BOOST_TEST_MODULE Utils::Mat test #define BOOST_TEST_DYN_LINK -#include +#include #include #include #include diff --git a/src/utils/tests/vec_rotate_test.cpp b/src/utils/tests/vec_rotate_test.cpp index 6539c5c5d46..7dc99eb666b 100644 --- a/src/utils/tests/vec_rotate_test.cpp +++ b/src/utils/tests/vec_rotate_test.cpp @@ -22,7 +22,6 @@ #include #include #include -using Utils::vec_rotate; #include #include @@ -43,7 +42,7 @@ BOOST_AUTO_TEST_CASE(rotation) { auto const expected = cos(t) * v + sin(t) * vector_product(k, v) + (1. - cos(t)) * (k * v) * k; - auto const is = vec_rotate(k, t, v); + auto const is = Utils::vec_rotate(k, t, v); auto const rel_diff = (expected - is).norm() / expected.norm(); BOOST_CHECK(rel_diff < std::numeric_limits::epsilon()); From 5af53cf1dd71dd14e6e06b2a6fc072ad885e1429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Mon, 14 Dec 2020 21:33:40 +0100 Subject: [PATCH 03/31] utils: Refactor coordinate transformation code --- .../CylindricalLBProfileObservable.hpp | 9 +- src/shapes/src/HollowConicalFrustum.cpp | 6 +- .../utils/math/coordinate_transformation.hpp | 145 +++++++++--- src/utils/include/utils/math/vec_rotate.hpp | 18 -- src/utils/tests/coordinate_transformation.cpp | 210 +++++++++++++++++- src/utils/tests/vec_rotate_test.cpp | 13 -- 6 files changed, 324 insertions(+), 77 deletions(-) diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index c1d5eea4d7e..6a846e53016 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -47,16 +47,15 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { limits[0], limits[1], limits[2], n_bins[0], n_bins[1], n_bins[2], sampling_density); for (auto &p : sampling_positions) { - double theta; - Utils::Vector3d rotation_axis; auto p_cart = Utils::transform_coordinate_cylinder_to_cartesian( p, Utils::Vector3d{{0.0, 0.0, 1.0}}); // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. - std::tie(theta, rotation_axis) = - Utils::rotation_params(Utils::Vector3d{{0.0, 0.0, 1.0}}, axis); + constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; + auto const theta = Utils::angle_between(z_axis, axis); + auto const rot_axis = Utils::vector_product(z_axis, axis).normalize(); if (theta > std::numeric_limits::epsilon()) - p_cart = Utils::vec_rotate(rotation_axis, theta, p_cart); + p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); p = p_cart + center; } } diff --git a/src/shapes/src/HollowConicalFrustum.cpp b/src/shapes/src/HollowConicalFrustum.cpp index 3db5fb59fc0..feeba7bc91d 100644 --- a/src/shapes/src/HollowConicalFrustum.cpp +++ b/src/shapes/src/HollowConicalFrustum.cpp @@ -33,8 +33,12 @@ void HollowConicalFrustum::calculate_dist(const Utils::Vector3d &pos, Utils::Vector3d &vec) const { // transform given position to cylindrical coordinates in the reference frame // of the cone + auto const v = pos - m_center; + auto orientation = Utils::Vector3d{{1, 0, 0}}; + if (m_axis[1] == 0. and m_axis[2] == 0.) + orientation = Utils::vector_product(v, m_axis); auto const pos_cyl = - Utils::transform_coordinate_cartesian_to_cylinder(pos - m_center, m_axis); + Utils::transform_coordinate_cartesian_to_cylinder(v, m_axis, orientation); // clang-format off /* * the following implementation is based on: diff --git a/src/utils/include/utils/math/coordinate_transformation.hpp b/src/utils/include/utils/math/coordinate_transformation.hpp index 20e432afe35..dd43b2b6241 100644 --- a/src/utils/include/utils/math/coordinate_transformation.hpp +++ b/src/utils/include/utils/math/coordinate_transformation.hpp @@ -19,64 +19,135 @@ #ifndef UTILS_COORDINATE_TRANSFORMATION_HPP #define UTILS_COORDINATE_TRANSFORMATION_HPP +/** + * @file + * Convert coordinates from the Cartesian system to the cylindrical system. + * The transformation functions are provided with three overloads: + * - one function for the trivial Cartesian <-> cylindrical transformation + * - one function to transform from/to a cylindrical system with custom axis + * (extra @p axis argument, keep in mind the angle phi is under-defined) + * - one function to transform from/to an oriented cylindrical system with + * custom axis (extra @p orientation argument, the angle phi is well-defined) + */ + #include "utils/Vector.hpp" #include "utils/constants.hpp" #include "utils/math/vec_rotate.hpp" +#include "utils/matrix.hpp" #include "utils/quaternion.hpp" +#include + namespace Utils { -/** \brief Transform the given 3D position to cylinder coordinates with - * longitudinal axis aligned with axis parameter. +/** + * @brief Basis change. */ -inline Vector3d -transform_coordinate_cartesian_to_cylinder(const Vector3d &pos, - const Vector3d &axis) { - static auto const z_axis = Vector3d{{0, 0, 1}}; - double theta; - Vector3d rotation_axis; - auto r = [](auto const &pos) { - return std::sqrt(pos[0] * pos[0] + pos[1] * pos[1]); - }; - auto phi = [](auto const &pos) { return std::atan2(pos[1], pos[0]); }; - if (axis != z_axis) { - std::tie(theta, rotation_axis) = rotation_params(axis, z_axis); - auto const rotated_pos = vec_rotate(rotation_axis, theta, pos); - return {r(rotated_pos), phi(rotated_pos), rotated_pos[2]}; +inline Vector3d basis_change(Vector3d const &b1, Vector3d const &b2, + Vector3d const &b3, Vector3d const &v, + bool reverse = false) { + auto const e_x = b1.normalized(); + auto const e_y = b2.normalized(); + auto const e_z = b3.normalized(); + Mat const M = Mat{ + {e_x[0], e_x[1], e_x[2]}, + {e_y[0], e_y[1], e_y[2]}, + {e_z[0], e_z[1], e_z[2]}}.transposed(); + if (reverse) { + return M * v; } - return {r(pos), phi(pos), pos[2]}; + return M.inversed() * v; } /** - * @brief Coordinate transformation from cylinder to cartesian coordinates. + * @brief Coordinate transformation from Cartesian to cylindrical coordinates. + * The origins and z-axis of the coordinate systems co-incide. + * The @f$ \phi = 0 @f$ direction corresponds to the x-axis in the + * original coordinate system. + * @param pos %Vector to transform */ inline Vector3d -transform_coordinate_cylinder_to_cartesian(Vector3d const &pos, - Vector3d const &axis) { - Vector3d const transformed{ - {pos[0] * std::cos(pos[1]), pos[0] * std::sin(pos[1]), pos[2]}}; - static auto const z_axis = Vector3d{{0, 0, 1}}; - if (axis == z_axis) - return transformed; - double theta; - Vector3d rotation_axis; - std::tie(theta, rotation_axis) = rotation_params(z_axis, axis); - auto const rotated_pos = vec_rotate(rotation_axis, theta, transformed); - return rotated_pos; +transform_coordinate_cartesian_to_cylinder(Vector3d const &pos) { + auto const r = std::sqrt(pos[0] * pos[0] + pos[1] * pos[1]); + auto const phi = std::atan2(pos[1], pos[0]); + return {r, phi, pos[2]}; +} + +/** + * @brief Coordinate transformation from Cartesian to cylindrical coordinates + * with change of basis. The origins of the coordinate systems co-incide. + * + * If the parameter @p axis is not equal to [0, 0, 1], the value + * of the angle @f$ \phi @f$ in cylindrical coordinates is under-defined. + * To fully define it, it is necessary to provide an orientation vector + * in Cartesian coordinates that will be used as the reference point + * (i.e. such that @f$ \phi = 0 @f$), by default it is the x-axis. + * + * @param pos %Vector to transform + * @param axis Longitudinal axis of the cylindrical coordinates + * @param orientation Reference point (in untransformed coordinates) for + * which @f$ \phi = 0 @f$ + */ +inline Vector3d transform_coordinate_cartesian_to_cylinder( + Vector3d const &pos, Vector3d const &axis, + Vector3d const &orientation = {{1, 0, 0}}) { + auto const rotation_axis = vector_product(axis, orientation); + auto const pos_t = basis_change(orientation, rotation_axis, axis, pos); + return transform_coordinate_cartesian_to_cylinder(pos_t); } -/** \brief Transform the given 3D vector to cylinder coordinates with - * symmetry axis aligned with axis parameter. +/** + * @brief Coordinate transformation from cylindrical to Cartesian coordinates. + * The origins and z-axis of the coordinate systems co-incide. + * The @f$ \phi = 0 @f$ direction corresponds to the x-axis in the + * transformed coordinate system. + * @param pos %Vector to transform + */ +inline Vector3d +transform_coordinate_cylinder_to_cartesian(Vector3d const &pos) { + auto const &rho = pos[0]; + auto const &phi = pos[1]; + auto const &z = pos[2]; + return {rho * std::cos(phi), rho * std::sin(phi), z}; +} + +/** + * @brief Coordinate transformation from cylindrical to Cartesian coordinates + * with change of basis. The origins of the coordinate systems co-incide. + * + * If the parameter @p axis is not equal to [0, 0, 1], the value + * of the angle @f$ \phi @f$ in cylindrical coordinates is under-defined. + * To fully define it, it is necessary to provide an orientation vector + * in Cartesian coordinates that will be used as the reference point + * (i.e. such that @f$ \phi = 0 @f$). + * + * @param pos %Vector to transform + * @param axis Longitudinal axis of the cylindrical coordinates + * @param orientation Reference point (in Cartesian coordinates) for + * which @f$ \phi = 0 @f$ + */ +inline Vector3d transform_coordinate_cylinder_to_cartesian( + Vector3d const &pos, Vector3d const &axis, + Vector3d const &orientation = {{1, 0, 0}}) { + auto const rotation_axis = vector_product(axis, orientation); + auto const pos_t = transform_coordinate_cylinder_to_cartesian(pos); + return basis_change(orientation, rotation_axis, axis, pos_t, true); +} + +/** + * @brief Vector transformation from Cartesian to cylindrical coordinates. + * @param vec %Vector to transform + * @param axis Longitudinal axis of the cylindrical coordinates + * @param pos Origin of the vector */ inline Vector3d transform_vector_cartesian_to_cylinder(Vector3d const &vec, Vector3d const &axis, Vector3d const &pos) { static auto const z_axis = Vector3d{{0, 0, 1}}; - double theta; - Vector3d rotation_axis; - std::tie(theta, rotation_axis) = rotation_params(axis, z_axis); - auto const rotated_pos = vec_rotate(rotation_axis, theta, pos); - auto const rotated_vec = vec_rotate(rotation_axis, theta, vec); + auto const angle = angle_between(axis, z_axis); + auto const rotation_axis = Utils::vector_product(axis, z_axis).normalize(); + auto const rotated_pos = vec_rotate(rotation_axis, angle, pos); + auto const rotated_vec = vec_rotate(rotation_axis, angle, vec); // v_r = (x * v_x + y * v_y) / sqrt(x^2 + y^2) auto const v_r = (rotated_pos[0] * rotated_vec[0] + rotated_pos[1] * rotated_vec[1]) / diff --git a/src/utils/include/utils/math/vec_rotate.hpp b/src/utils/include/utils/math/vec_rotate.hpp index 3cb9f48e340..029852ddd56 100644 --- a/src/utils/include/utils/math/vec_rotate.hpp +++ b/src/utils/include/utils/math/vec_rotate.hpp @@ -46,24 +46,6 @@ inline Vector3d vec_rotate(const Vector3d &axis, double angle, return vector; } -/** - * @brief Determine rotation angle and axis for rotating vec onto target_vec. - * @param vec Vector to be rotated - * @param target_vec Target vector - * @return rotation angle and rotation axis - */ -inline std::tuple -rotation_params(Vector3d const &vec, Vector3d const &target_vec) { - if (vec.normalized() != target_vec.normalized()) { - auto const theta = - std::acos(vec * target_vec / (vec.norm() * target_vec.norm())); - auto const rotation_axis = - Utils::vector_product(vec, target_vec).normalize(); - return std::make_tuple(theta, rotation_axis); - } - return std::make_tuple(0.0, Vector3d{}); -} - /** * @brief Determine the angle between two vectors. */ diff --git a/src/utils/tests/coordinate_transformation.cpp b/src/utils/tests/coordinate_transformation.cpp index 77b27ca43ea..1a158b9a1d4 100644 --- a/src/utils/tests/coordinate_transformation.cpp +++ b/src/utils/tests/coordinate_transformation.cpp @@ -25,14 +25,22 @@ #include #include +#include using Utils::Vector3d; BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_test) { constexpr auto eps = 1e-14; - Vector3d const cart_coord{{1.0, 3.3, 2.0}}; - auto const transformed_x = transform_coordinate_cartesian_to_cylinder( - cart_coord, Vector3d{{1, 0, 0}}); + auto const pos = Vector3d{{1.0, 3.3, 2.0}}; + auto const cyl = transform_coordinate_cartesian_to_cylinder(pos); + BOOST_CHECK_SMALL(cyl[0] - std::sqrt(pos[0] * pos[0] + pos[1] * pos[1]), eps); + BOOST_CHECK_SMALL(cyl[1] - std::atan2(pos[1], pos[0]), eps); + BOOST_CHECK_SMALL(cyl[2] - pos[2], eps); +} + +BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_test) { + constexpr auto eps = 1e-14; + Vector3d const cart_coord{{-1.0, 3.3, 2.0}}; auto const transformed_y = transform_coordinate_cartesian_to_cylinder( cart_coord, Vector3d{{0, 1, 0}}); auto const transformed_z = transform_coordinate_cartesian_to_cylinder( @@ -58,7 +66,136 @@ BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_test) { } } +BOOST_AUTO_TEST_CASE(basis_transform_test) { + constexpr auto eps = 1e-14; + Vector3d const b_x{{1, 0, 0}}; + Vector3d const b_y{{0, 1, 0}}; + Vector3d const b_z{{0, 0, 1}}; + // identity transform + Vector3d const v{{1, 2, 3}}; + Vector3d const v_identity_transform = Utils::basis_change(b_x, b_y, b_z, v); + // identity transform (swap both the vector and coordinate system) + Vector3d const v_swap_coord_transform = + Utils::basis_change(b_z, b_y, b_x, {{v[2], v[1], v[0]}}); + // non-trivial transform + Vector3d const v1 = Vector3d{{2, 2, 2}}.normalized(); + Vector3d const v2 = Vector3d{{3, 3, -6}}.normalized(); + Vector3d const v3 = Utils::vector_product(v1, v2).normalized(); + Vector3d const v4 = basis_change(v1, v2, v3, 0.1 * v1 + 0.2 * v2 - 0.3 * v3); + Vector3d const v4_expected = Vector3d{{0.1, 0.2, -0.3}}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(v_identity_transform[i] - v[i], eps); + BOOST_CHECK_SMALL(v_swap_coord_transform[i] - v[i], eps); + BOOST_CHECK_SMALL(v4[i] - v4_expected[i], eps); + } +} + +BOOST_AUTO_TEST_CASE( + transform_coordinate_cartesian_to_cylinder_base_change_test) { + constexpr auto eps = 1e-14; + Vector3d const v1{{1, 3, 4}}; + Vector3d const v2{{-3.0, 7, 2}}; + Vector3d const axis = Utils::vector_product(v1, v2).normalized(); + Vector3d const v3 = + Utils::transform_coordinate_cartesian_to_cylinder(v1, axis, v1); + Vector3d const v3_ref{{v1.norm(), 0, 0}}; + auto const angle_v1_v2 = Utils::angle_between(v1, v2); + auto const v4 = Utils::transform_coordinate_cartesian_to_cylinder( + v2 + 2 * axis, axis, v1); + Vector3d v4_ref{{v2.norm(), angle_v1_v2, 2}}; + auto const v5 = Utils::transform_coordinate_cartesian_to_cylinder( + v1 + 2 * axis, axis, v2); + Vector3d v5_ref{{v1.norm(), -angle_v1_v2, 2}}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(v3[i] - v3_ref[i], eps); + BOOST_CHECK_SMALL(v4[i] - v4_ref[i], eps); + BOOST_CHECK_SMALL(v5[i] - v5_ref[i], eps); + } +} + +BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_with_phi_test) { + constexpr auto eps = 1e-14; + // tilted orthogonal basis + auto const x = + (Vector3d{{1, 0, 0}} - (1. / 3.) * Vector3d{{1, 1, 1}}).normalize(); + auto const y = (Vector3d{{0, 1, -1}}).normalize(); + auto const z = (Vector3d{{1, 1, 1}}).normalize(); + // check simple transformation without orientation (phi is random) + { + auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z); + auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z); + auto const z_cyl = transform_coordinate_cartesian_to_cylinder(z, z); + auto const x_ref = Vector3d{{1.0, x_cyl[1], 0.0}}; + auto const y_ref = Vector3d{{1.0, y_cyl[1], 0.0}}; + auto const z_ref = Vector3d{{0.0, z_cyl[1], 1.0}}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(x_cyl[i] - x_ref[i], eps); + BOOST_CHECK_SMALL(y_cyl[i] - y_ref[i], eps); + BOOST_CHECK_SMALL(z_cyl[i] - z_ref[i], eps); + } + } + // check transformation with orientation (phi is only random for r=0) + { + auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z, y); + auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z, y); + auto const z_cyl = transform_coordinate_cartesian_to_cylinder(z, z, y); + auto const x_ref = Vector3d{{1.0, -Utils::pi() / 2.0, 0.0}}; + auto const y_ref = Vector3d{{1.0, 0.0, 0.0}}; + auto const z_ref = Vector3d{{0.0, z_cyl[1], 1.0}}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(x_cyl[i] - x_ref[i], eps); + BOOST_CHECK_SMALL(y_cyl[i] - y_ref[i], eps); + BOOST_CHECK_SMALL(z_cyl[i] - z_ref[i], eps); + } + } + // check transformation with orientation for another angle + { + auto const u = vec_rotate(z, Utils::pi() / 3.0, x); + auto const v = vec_rotate(z, Utils::pi() / 3.0, y); + auto const u_cyl = transform_coordinate_cartesian_to_cylinder(u, z, y); + auto const v_cyl = transform_coordinate_cartesian_to_cylinder(v, z, y); + auto const u_ref = Vector3d{{1.0, Utils::pi() * (1. / 3. - 1. / 2.), 0.0}}; + auto const v_ref = Vector3d{{1.0, Utils::pi() / 3.0, 0.0}}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(u_cyl[i] - u_ref[i], eps); + BOOST_CHECK_SMALL(v_cyl[i] - v_ref[i], eps); + } + } + // check transformation of random vectors + { + std::subtract_with_carry_engine rng(2); + auto const r_uniform = [&rng]() { + return static_cast(rng() - rng.min()) / (rng.max() - rng.min()); + }; + for (int trial = 0; trial < 100; ++trial) { + Vector3d const v1{r_uniform(), r_uniform(), r_uniform()}; + Vector3d const v2{r_uniform(), r_uniform(), r_uniform()}; + auto const a = Utils::vector_product(v1, v2) / v1.norm() / v2.norm(); + auto const v1_v1 = transform_coordinate_cartesian_to_cylinder(v1, a, v1); + auto const v2_v1 = transform_coordinate_cartesian_to_cylinder(v2, a, v1); + auto const v1_v2 = transform_coordinate_cartesian_to_cylinder(v1, a, v2); + Vector3d const v1_v1_ref{v1.norm(), 0.0, 0.0}; + Vector3d const v2_v1_ref{v2.norm(), Utils::angle_between(v1, v2), 0.0}; + Vector3d const v1_v2_ref{v1.norm(), -Utils::angle_between(v1, v2), 0.0}; + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(v1_v1[i] - v1_v1_ref[i], eps); + BOOST_CHECK_SMALL(v2_v1[i] - v2_v1_ref[i], eps); + BOOST_CHECK_SMALL(v1_v2[i] - v1_v2_ref[i], eps); + } + } + } +} + BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_test) { + constexpr auto eps = 1e-14; + auto const cyl = Vector3d{{1.0, Utils::pi() / 4, 2.0}}; + auto const pos = transform_coordinate_cylinder_to_cartesian(cyl); + BOOST_CHECK_SMALL(pos[0] - std::sqrt(2) / 2, eps); + BOOST_CHECK_SMALL(pos[1] - std::sqrt(2) / 2, eps); + BOOST_CHECK_SMALL(pos[2] - cyl[2], eps); +} + +BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_test) { constexpr auto eps = 1e-14; Vector3d const cylinder_coord{{1.2, 3.123, 42.0}}; auto const transformed_x = transform_coordinate_cylinder_to_cartesian( @@ -87,3 +224,70 @@ BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_test) { BOOST_CHECK_SMALL(transformed_z[i] - expected_z[i], eps); } } + +BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_with_phi_2_test) { + constexpr auto eps = 1e-14; + // tilted orthogonal basis + auto const x = + (Vector3d{{1, 0, 0}} - (1. / 3.) * Vector3d{{1, 1, 1}}).normalize(); + auto const y = (Vector3d{{0, 1, -1}}).normalize(); + auto const z = (Vector3d{{1, 1, 1}}).normalize(); + // check simple transformation without orientation + { + auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z); + auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z); + auto const z_cyl = transform_coordinate_cartesian_to_cylinder(z, z); + auto const x_cart = transform_coordinate_cylinder_to_cartesian(x_cyl, z); + auto const y_cart = transform_coordinate_cylinder_to_cartesian(y_cyl, z); + auto const z_cart = transform_coordinate_cylinder_to_cartesian(z_cyl, z); + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(x_cart[i] - x[i], eps); + BOOST_CHECK_SMALL(y_cart[i] - y[i], eps); + BOOST_CHECK_SMALL(z_cart[i] - z[i], eps); + } + } + // check transformation with orientation + { + auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z, y); + auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z, y); + auto const z_cyl = transform_coordinate_cartesian_to_cylinder(z, z, y); + auto const x_cart = transform_coordinate_cylinder_to_cartesian(x_cyl, z, y); + auto const y_cart = transform_coordinate_cylinder_to_cartesian(y_cyl, z, y); + auto const z_cart = transform_coordinate_cylinder_to_cartesian(z_cyl, z, y); + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(x_cart[i] - x[i], eps); + BOOST_CHECK_SMALL(y_cart[i] - y[i], eps); + BOOST_CHECK_SMALL(z_cart[i] - z[i], eps); + } + } + // check transformation with orientation for another angle + { + auto const u = vec_rotate(z, Utils::pi() / 3.0, x); + auto const v = vec_rotate(z, Utils::pi() / 3.0, y); + auto const u_cyl = transform_coordinate_cartesian_to_cylinder(u, z, y); + auto const v_cyl = transform_coordinate_cartesian_to_cylinder(v, z, y); + auto const u_cart = transform_coordinate_cylinder_to_cartesian(u_cyl, z, y); + auto const v_cart = transform_coordinate_cylinder_to_cartesian(v_cyl, z, y); + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(u_cart[i] - u[i], eps); + BOOST_CHECK_SMALL(v_cart[i] - v[i], eps); + } + } + // check transformation of random vectors + { + std::subtract_with_carry_engine rng(2); + auto const r_uniform = [&rng]() { + return static_cast(rng() - rng.min()) / (rng.max() - rng.min()); + }; + for (int trial = 0; trial < 100; ++trial) { + Vector3d const v1{r_uniform(), r_uniform(), r_uniform()}; + Vector3d const v2{r_uniform(), r_uniform(), r_uniform()}; + auto const a = Utils::vector_product(v1, v2) / v1.norm() / v2.norm(); + auto const v3 = transform_coordinate_cartesian_to_cylinder(v2, a, v1); + auto const v4 = transform_coordinate_cylinder_to_cartesian(v3, a, v1); + for (int i = 0; i < 3; ++i) { + BOOST_CHECK_SMALL(v4[i] - v2[i], eps); + } + } + } +} diff --git a/src/utils/tests/vec_rotate_test.cpp b/src/utils/tests/vec_rotate_test.cpp index 7dc99eb666b..f1d5727a2cd 100644 --- a/src/utils/tests/vec_rotate_test.cpp +++ b/src/utils/tests/vec_rotate_test.cpp @@ -25,7 +25,6 @@ #include #include -#include BOOST_AUTO_TEST_CASE(rotation) { using std::cos; @@ -48,18 +47,6 @@ BOOST_AUTO_TEST_CASE(rotation) { BOOST_CHECK(rel_diff < std::numeric_limits::epsilon()); } -BOOST_AUTO_TEST_CASE(rotation_params) { - Utils::Vector3d v1 = {1.0, 0.0, 0.0}; - Utils::Vector3d v2 = {1.0, 1.0, 0.0}; - - double angle; - Utils::Vector3d rotation_axis; - std::tie(angle, rotation_axis) = Utils::rotation_params(v1, v2); - BOOST_CHECK_CLOSE(angle, Utils::pi() / 4.0, 1e-7); - BOOST_CHECK_SMALL((rotation_axis * v1), 1e-7); - BOOST_CHECK_SMALL((rotation_axis * v2), 1e-7); -} - BOOST_AUTO_TEST_CASE(angle_between) { Utils::Vector3d const v1 = {1.0, 0.0, 0.0}; Utils::Vector3d const v2 = {1.0, 1.0, 0.0}; From 2ce79ff80e4767abde59b13f006181af03de37f5 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 10 Feb 2021 16:45:44 +0100 Subject: [PATCH 04/31] fix merge aftermath --- .../utils/math/coordinate_transformation.hpp | 3 ++- src/utils/tests/coordinate_transformation.cpp | 19 +++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/utils/include/utils/math/coordinate_transformation.hpp b/src/utils/include/utils/math/coordinate_transformation.hpp index 7a67a289e57..9e98ef3c1ad 100644 --- a/src/utils/include/utils/math/coordinate_transformation.hpp +++ b/src/utils/include/utils/math/coordinate_transformation.hpp @@ -49,7 +49,7 @@ inline Vector3d basis_change(Vector3d const &b1, Vector3d const &b2, auto const e_x = b1.normalized(); auto const e_y = b2.normalized(); auto const e_z = b3.normalized(); - Mat const M = Mat{ + auto const M = Matrix{ {e_x[0], e_x[1], e_x[2]}, {e_y[0], e_y[1], e_y[2]}, {e_z[0], e_z[1], e_z[2]}}.transposed(); @@ -148,6 +148,7 @@ inline Vector3d transform_vector_cartesian_to_cylinder(Vector3d const &vec, auto const rotation_axis = Utils::vector_product(axis, z_axis).normalize(); auto const rotated_pos = vec_rotate(rotation_axis, angle, pos); auto const rotated_vec = vec_rotate(rotation_axis, angle, vec); + auto const r = std::sqrt(rotated_pos[0]*rotated_pos[0]+rotated_pos[1]*rotated_pos[1]); // v_r = (x * v_x + y * v_y) / sqrt(x^2 + y^2) auto const v_r = (rotated_pos[0] * rotated_vec[0] + rotated_pos[1] * rotated_vec[1]) / r; diff --git a/src/utils/tests/coordinate_transformation.cpp b/src/utils/tests/coordinate_transformation.cpp index 1afc0b12189..7130ff77b5a 100644 --- a/src/utils/tests/coordinate_transformation.cpp +++ b/src/utils/tests/coordinate_transformation.cpp @@ -41,26 +41,21 @@ BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_test) { BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_test) { constexpr auto eps = 1e-14; Vector3d const cart_coord{{-1.0, 3.3, 2.0}}; - auto const transformed_y = transform_coordinate_cartesian_to_cylinder( - cart_coord, Vector3d{{0, 1, 0}}); + // check case where the cylinder axis is the original z axis auto const transformed_z = transform_coordinate_cartesian_to_cylinder( cart_coord, Vector3d{{0, 0, 1}}); - // For x as the symmetry axis we rotate the cartesian coordinates around the - // y-axis by -pi/2. - auto const expected_x = transform_coordinate_cartesian_to_cylinder( - vec_rotate(Vector3d{{0.0, 1.0, 0.0}}, -Utils::pi() / 2.0, cart_coord), - Vector3d{{0, 0, 1}}); + auto const expected_z = Vector3d{ + {std::sqrt(cart_coord[0] * cart_coord[0] + cart_coord[1] * cart_coord[1]), + std::atan2(cart_coord[1], cart_coord[0]), cart_coord[2]}}; // For y as the symmetry axis we rotate the cartesian coordinates around the // x-axis by pi/2. + auto const transformed_y = transform_coordinate_cartesian_to_cylinder( + cart_coord, Vector3d{{0, 1, 0}}); auto const expected_y = transform_coordinate_cartesian_to_cylinder( vec_rotate(Vector3d{{1.0, 0.0, 0.0}}, Utils::pi() / 2.0, cart_coord), Vector3d{{0, 0, 1}}); - auto const expected_z = Vector3d{ - {std::sqrt(cart_coord[0] * cart_coord[0] + cart_coord[1] * cart_coord[1]), - std::atan2(cart_coord[1], cart_coord[0]), cart_coord[2]}}; - + for (int i = 0; i < 3; ++i) { - BOOST_CHECK_SMALL(transformed_x[i] - expected_x[i], eps); BOOST_CHECK_SMALL(transformed_y[i] - expected_y[i], eps); BOOST_CHECK_SMALL(transformed_z[i] - expected_z[i], eps); } From 5be670e3f0605d695c1806ba200c50fc86dbe532 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 14:34:14 +0100 Subject: [PATCH 05/31] add orientation to hollowconicalfrustum --- .../include/shapes/HollowConicalFrustum.hpp | 26 ++++++++++++------- src/shapes/src/HollowConicalFrustum.cpp | 7 ++--- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/shapes/include/shapes/HollowConicalFrustum.hpp b/src/shapes/include/shapes/HollowConicalFrustum.hpp index ac846e0e545..efe0bb17c2a 100644 --- a/src/shapes/include/shapes/HollowConicalFrustum.hpp +++ b/src/shapes/include/shapes/HollowConicalFrustum.hpp @@ -47,16 +47,23 @@ class HollowConicalFrustum : public Shape { public: HollowConicalFrustum() : m_r1(0.0), m_r2(0.0), m_length(0.0), m_thickness(0.0), - m_direction(1), m_center{Utils::Vector3d{}}, m_axis{Utils::Vector3d{ - 0, 0, 1}} {} - - void set_r1(double radius) { m_r1 = radius; } - void set_r2(double radius) { m_r2 = radius; } - void set_length(double length) { m_length = length; } - void set_thickness(double thickness) { m_thickness = thickness; } - void set_direction(int dir) { m_direction = dir; } - void set_axis(Utils::Vector3d const &axis) { m_axis = axis; } + m_direction(1), m_center{Utils::Vector3d{}}, + m_axis{Utils::Vector3d{0, 0, 1}}, m_orientation{Utils::Vector3d {1.,0.,0.}} {} + void set_r1(double const radius) { m_r1 = radius; } + void set_r2(double const radius) { m_r2 = radius; } + void set_length(double const length) { m_length = length; } + void set_thickness(double const thickness) { m_thickness = thickness; } + void set_direction(int const dir) { m_direction = dir; } + void set_axis(Utils::Vector3d const &axis) { + m_axis = axis; + // Even though the HCF is cylinder-symmetric, it needs a well defined phi=0 orientation for the coordinate transformation. + // If the default orientation is too parallel to axis, choose again + if ((m_orientation - (m_orientation*m_axis)*m_axis).norm() < 0.01) { + m_orientation = Utils::Vector3d{{0.,1.,0.}}; + std::printf("changing orientation"); + } + } void set_center(Utils::Vector3d const ¢er) { m_center = center; } /// Get radius 1 perpendicular to axis. @@ -92,6 +99,7 @@ class HollowConicalFrustum : public Shape { int m_direction; Utils::Vector3d m_center; Utils::Vector3d m_axis; + Utils::Vector3d m_orientation; }; } // namespace Shapes diff --git a/src/shapes/src/HollowConicalFrustum.cpp b/src/shapes/src/HollowConicalFrustum.cpp index feeba7bc91d..ceb3ae76883 100644 --- a/src/shapes/src/HollowConicalFrustum.cpp +++ b/src/shapes/src/HollowConicalFrustum.cpp @@ -34,11 +34,8 @@ void HollowConicalFrustum::calculate_dist(const Utils::Vector3d &pos, // transform given position to cylindrical coordinates in the reference frame // of the cone auto const v = pos - m_center; - auto orientation = Utils::Vector3d{{1, 0, 0}}; - if (m_axis[1] == 0. and m_axis[2] == 0.) - orientation = Utils::vector_product(v, m_axis); auto const pos_cyl = - Utils::transform_coordinate_cartesian_to_cylinder(v, m_axis, orientation); + Utils::transform_coordinate_cartesian_to_cylinder(v, m_axis, m_orientation); // clang-format off /* * the following implementation is based on: @@ -65,7 +62,7 @@ void HollowConicalFrustum::calculate_dist(const Utils::Vector3d &pos, // Transform back to cartesian coordinates. auto const pos_intersection = Utils::transform_coordinate_cylinder_to_cartesian( - {r_intersection, pos_cyl[1], z_intersection}, m_axis) + + {r_intersection, pos_cyl[1], z_intersection}, m_axis, m_orientation) + m_center; auto const u = (pos - pos_intersection).normalize(); From e67e09fd65311a7bc22204e1aa07c7020490057a Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 14:34:57 +0100 Subject: [PATCH 06/31] remove default orientation if axis is provided --- .../utils/math/coordinate_transformation.hpp | 9 +- .../math/coordinate_transformation.hpp.orig | 171 ++++++++++++++++++ src/utils/tests/coordinate_transformation.cpp | 85 ++------- 3 files changed, 197 insertions(+), 68 deletions(-) create mode 100644 src/utils/include/utils/math/coordinate_transformation.hpp.orig diff --git a/src/utils/include/utils/math/coordinate_transformation.hpp b/src/utils/include/utils/math/coordinate_transformation.hpp index 9e98ef3c1ad..7203f0da033 100644 --- a/src/utils/include/utils/math/coordinate_transformation.hpp +++ b/src/utils/include/utils/math/coordinate_transformation.hpp @@ -36,6 +36,7 @@ #include "utils/matrix.hpp" #include "utils/quaternion.hpp" +#include #include namespace Utils { @@ -90,7 +91,9 @@ transform_coordinate_cartesian_to_cylinder(Vector3d const &pos) { */ inline Vector3d transform_coordinate_cartesian_to_cylinder( Vector3d const &pos, Vector3d const &axis, - Vector3d const &orientation = {{1, 0, 0}}) { + Vector3d const &orientation) { + // check that axis and orientation are orthogonal + assert(std::abs(axis*orientation)<5*std::numeric_limits::epsilon()); auto const rotation_axis = vector_product(axis, orientation); auto const pos_t = basis_change(orientation, rotation_axis, axis, pos); return transform_coordinate_cartesian_to_cylinder(pos_t); @@ -128,7 +131,9 @@ transform_coordinate_cylinder_to_cartesian(Vector3d const &pos) { */ inline Vector3d transform_coordinate_cylinder_to_cartesian( Vector3d const &pos, Vector3d const &axis, - Vector3d const &orientation = {{1, 0, 0}}) { + Vector3d const &orientation) { + // check that axis and orientation are orthogonal + assert(std::abs(axis*orientation)<5*std::numeric_limits::epsilon()); auto const rotation_axis = vector_product(axis, orientation); auto const pos_t = transform_coordinate_cylinder_to_cartesian(pos); return basis_change(orientation, rotation_axis, axis, pos_t, true); diff --git a/src/utils/include/utils/math/coordinate_transformation.hpp.orig b/src/utils/include/utils/math/coordinate_transformation.hpp.orig new file mode 100644 index 00000000000..ac8fc4d10cc --- /dev/null +++ b/src/utils/include/utils/math/coordinate_transformation.hpp.orig @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010-2019 The ESPResSo project + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef UTILS_COORDINATE_TRANSFORMATION_HPP +#define UTILS_COORDINATE_TRANSFORMATION_HPP + +/** + * @file + * Convert coordinates from the Cartesian system to the cylindrical system. + * The transformation functions are provided with three overloads: + * - one function for the trivial Cartesian <-> cylindrical transformation + * - one function to transform from/to a cylindrical system with custom axis + * (extra @p axis argument, keep in mind the angle phi is under-defined) + * - one function to transform from/to an oriented cylindrical system with + * custom axis (extra @p orientation argument, the angle phi is well-defined) + */ + +#include "utils/Vector.hpp" +#include "utils/constants.hpp" +#include "utils/math/vec_rotate.hpp" +#include "utils/matrix.hpp" +#include "utils/quaternion.hpp" + +#include + +namespace Utils { + +/** + * @brief Basis change. + */ +inline Vector3d basis_change(Vector3d const &b1, Vector3d const &b2, + Vector3d const &b3, Vector3d const &v, + bool reverse = false) { + auto const e_x = b1.normalized(); + auto const e_y = b2.normalized(); + auto const e_z = b3.normalized(); + Mat const M = Mat{ + {e_x[0], e_x[1], e_x[2]}, + {e_y[0], e_y[1], e_y[2]}, + {e_z[0], e_z[1], e_z[2]}}.transposed(); + if (reverse) { + return M * v; + } + return M.inversed() * v; +} + +/** + * @brief Coordinate transformation from Cartesian to cylindrical coordinates. + * The origins and z-axis of the coordinate systems co-incide. + * The @f$ \phi = 0 @f$ direction corresponds to the x-axis in the + * original coordinate system. + * @param pos %Vector to transform + */ +inline Vector3d +transform_coordinate_cartesian_to_cylinder(Vector3d const &pos) { + auto const r = std::sqrt(pos[0] * pos[0] + pos[1] * pos[1]); + auto const phi = std::atan2(pos[1], pos[0]); + return {r, phi, pos[2]}; +} + +/** + * @brief Coordinate transformation from Cartesian to cylindrical coordinates + * with change of basis. The origins of the coordinate systems co-incide. + * + * If the parameter @p axis is not equal to [0, 0, 1], the value + * of the angle @f$ \phi @f$ in cylindrical coordinates is under-defined. + * To fully define it, it is necessary to provide an orientation vector + * in Cartesian coordinates that will be used as the reference point + * (i.e. such that @f$ \phi = 0 @f$), by default it is the x-axis. + * + * @param pos %Vector to transform + * @param axis Longitudinal axis of the cylindrical coordinates + * @param orientation Reference point (in untransformed coordinates) for + * which @f$ \phi = 0 @f$ + */ +inline Vector3d transform_coordinate_cartesian_to_cylinder( + Vector3d const &pos, Vector3d const &axis, + Vector3d const &orientation = {{1, 0, 0}}) { + auto const rotation_axis = vector_product(axis, orientation); + auto const pos_t = basis_change(orientation, rotation_axis, axis, pos); + return transform_coordinate_cartesian_to_cylinder(pos_t); +} + +/** + * @brief Coordinate transformation from cylindrical to Cartesian coordinates. + * The origins and z-axis of the coordinate systems co-incide. + * The @f$ \phi = 0 @f$ direction corresponds to the x-axis in the + * transformed coordinate system. + * @param pos %Vector to transform + */ +inline Vector3d +transform_coordinate_cylinder_to_cartesian(Vector3d const &pos) { + auto const &rho = pos[0]; + auto const &phi = pos[1]; + auto const &z = pos[2]; + return {rho * std::cos(phi), rho * std::sin(phi), z}; +} + +/** + * @brief Coordinate transformation from cylindrical to Cartesian coordinates + * with change of basis. The origins of the coordinate systems co-incide. + * + * If the parameter @p axis is not equal to [0, 0, 1], the value + * of the angle @f$ \phi @f$ in cylindrical coordinates is under-defined. + * To fully define it, it is necessary to provide an orientation vector + * in Cartesian coordinates that will be used as the reference point + * (i.e. such that @f$ \phi = 0 @f$). + * + * @param pos %Vector to transform + * @param axis Longitudinal axis of the cylindrical coordinates + * @param orientation Reference point (in Cartesian coordinates) for + * which @f$ \phi = 0 @f$ + */ +inline Vector3d transform_coordinate_cylinder_to_cartesian( + Vector3d const &pos, Vector3d const &axis, + Vector3d const &orientation = {{1, 0, 0}}) { + auto const rotation_axis = vector_product(axis, orientation); + auto const pos_t = transform_coordinate_cylinder_to_cartesian(pos); + return basis_change(orientation, rotation_axis, axis, pos_t, true); +} + +/** + * @brief Vector transformation from Cartesian to cylindrical coordinates. + * @param vec %Vector to transform + * @param axis Longitudinal axis of the cylindrical coordinates + * @param pos Origin of the vector + */ +inline Vector3d transform_vector_cartesian_to_cylinder(Vector3d const &vec, + Vector3d const &axis, + Vector3d const &pos) { + static auto const z_axis = Vector3d{{0, 0, 1}}; +<<<<<<< HEAD + auto const angle = angle_between(axis, z_axis); + auto const rotation_axis = Utils::vector_product(axis, z_axis).normalize(); + auto const rotated_pos = vec_rotate(rotation_axis, angle, pos); + auto const rotated_vec = vec_rotate(rotation_axis, angle, vec); +======= + double theta; + Vector3d rotation_axis; + std::tie(theta, rotation_axis) = rotation_params(axis, z_axis); + auto const rotated_pos = vec_rotate(rotation_axis, theta, pos); + auto const rotated_vec = vec_rotate(rotation_axis, theta, vec); + auto const r = std::sqrt(rotated_pos[0] * rotated_pos[0] + + rotated_pos[1] * rotated_pos[1]); +>>>>>>> python + // v_r = (x * v_x + y * v_y) / sqrt(x^2 + y^2) + auto const v_r = + (rotated_pos[0] * rotated_vec[0] + rotated_pos[1] * rotated_vec[1]) / r; + // v_phi = (x * v_y - y * v_x ) / sqrt(x^2 + y^2) + auto const v_phi = + (rotated_pos[0] * rotated_vec[1] - rotated_pos[1] * rotated_vec[0]) / r; + return Vector3d{v_r, v_phi, rotated_vec[2]}; +} + +} // namespace Utils +#endif diff --git a/src/utils/tests/coordinate_transformation.cpp b/src/utils/tests/coordinate_transformation.cpp index 7130ff77b5a..1b9cbb71b44 100644 --- a/src/utils/tests/coordinate_transformation.cpp +++ b/src/utils/tests/coordinate_transformation.cpp @@ -38,29 +38,6 @@ BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_test) { BOOST_CHECK_SMALL(cyl[2] - pos[2], eps); } -BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_test) { - constexpr auto eps = 1e-14; - Vector3d const cart_coord{{-1.0, 3.3, 2.0}}; - // check case where the cylinder axis is the original z axis - auto const transformed_z = transform_coordinate_cartesian_to_cylinder( - cart_coord, Vector3d{{0, 0, 1}}); - auto const expected_z = Vector3d{ - {std::sqrt(cart_coord[0] * cart_coord[0] + cart_coord[1] * cart_coord[1]), - std::atan2(cart_coord[1], cart_coord[0]), cart_coord[2]}}; - // For y as the symmetry axis we rotate the cartesian coordinates around the - // x-axis by pi/2. - auto const transformed_y = transform_coordinate_cartesian_to_cylinder( - cart_coord, Vector3d{{0, 1, 0}}); - auto const expected_y = transform_coordinate_cartesian_to_cylinder( - vec_rotate(Vector3d{{1.0, 0.0, 0.0}}, Utils::pi() / 2.0, cart_coord), - Vector3d{{0, 0, 1}}); - - for (int i = 0; i < 3; ++i) { - BOOST_CHECK_SMALL(transformed_y[i] - expected_y[i], eps); - BOOST_CHECK_SMALL(transformed_z[i] - expected_z[i], eps); - } -} - BOOST_AUTO_TEST_CASE(basis_transform_test) { constexpr auto eps = 1e-14; Vector3d const b_x{{1, 0, 0}}; @@ -108,28 +85,14 @@ BOOST_AUTO_TEST_CASE( } } -BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_with_phi_test) { +BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_and_orientation_test) { constexpr auto eps = 1e-14; // tilted orthogonal basis - auto const x = - (Vector3d{{1, 0, 0}} - (1. / 3.) * Vector3d{{1, 1, 1}}).normalize(); auto const y = (Vector3d{{0, 1, -1}}).normalize(); auto const z = (Vector3d{{1, 1, 1}}).normalize(); - // check simple transformation without orientation (phi is random) - { - auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z); - auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z); - auto const z_cyl = transform_coordinate_cartesian_to_cylinder(z, z); - auto const x_ref = Vector3d{{1.0, x_cyl[1], 0.0}}; - auto const y_ref = Vector3d{{1.0, y_cyl[1], 0.0}}; - auto const z_ref = Vector3d{{0.0, z_cyl[1], 1.0}}; - for (int i = 0; i < 3; ++i) { - BOOST_CHECK_SMALL(x_cyl[i] - x_ref[i], eps); - BOOST_CHECK_SMALL(y_cyl[i] - y_ref[i], eps); - BOOST_CHECK_SMALL(z_cyl[i] - z_ref[i], eps); - } - } - // check transformation with orientation (phi is only random for r=0) + auto const x = Utils::vector_product(y,z); + + // check transformation with orientation (phi is random for r=0) { auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z, y); auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z, y); @@ -190,25 +153,29 @@ BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_test) { BOOST_CHECK_SMALL(pos[2] - cyl[2], eps); } -BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_test) { - constexpr auto eps = 1e-14; +BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_and_orientation_test) { + constexpr auto eps = 2e-14; Vector3d const cylinder_coord{{1.2, 3.123, 42.0}}; + auto const e_x = Vector3d{{1.,0.,0.}}; + auto const e_y = Vector3d{{0.,1.,0.}}; + auto const e_z = Vector3d{{0.,0.,1.}}; + auto const transformed_x = transform_coordinate_cylinder_to_cartesian( - cylinder_coord, Vector3d{{1, 0, 0}}); + cylinder_coord, e_x, -e_z ); auto const transformed_y = transform_coordinate_cylinder_to_cartesian( - cylinder_coord, Vector3d{{0, 1, 0}}); + cylinder_coord, e_y, e_x ); auto const transformed_z = transform_coordinate_cylinder_to_cartesian( - cylinder_coord, Vector3d{{0, 0, 1}}); + cylinder_coord, e_z, e_x); // We transform from cylinder zu cartesian and have to rotate back. See test // cartesian_to_cylinder_test. auto const expected_x = - vec_rotate(Vector3d{{0.0, 1.0, 0.0}}, Utils::pi() / 2.0, + vec_rotate(e_y, Utils::pi() / 2.0, transform_coordinate_cylinder_to_cartesian( - cylinder_coord, Vector3d{{0, 0, 1}})); + cylinder_coord, e_z, e_x)); auto const expected_y = - vec_rotate(Vector3d{{1.0, 0.0, 0.0}}, -Utils::pi() / 2.0, + vec_rotate(e_x, -Utils::pi() / 2.0, transform_coordinate_cylinder_to_cartesian( - cylinder_coord, Vector3d{{0, 0, 1}})); + cylinder_coord, e_z, e_x)); // x = r * cos(phi); y = r * sin(phi); z = z auto const expected_z = Vector3d{ {cylinder_coord[0] * std::cos(cylinder_coord[1]), @@ -223,24 +190,10 @@ BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_test) { BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_with_phi_2_test) { constexpr auto eps = 1e-14; // tilted orthogonal basis - auto const x = - (Vector3d{{1, 0, 0}} - (1. / 3.) * Vector3d{{1, 1, 1}}).normalize(); auto const y = (Vector3d{{0, 1, -1}}).normalize(); auto const z = (Vector3d{{1, 1, 1}}).normalize(); - // check simple transformation without orientation - { - auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z); - auto const y_cyl = transform_coordinate_cartesian_to_cylinder(y, z); - auto const z_cyl = transform_coordinate_cartesian_to_cylinder(z, z); - auto const x_cart = transform_coordinate_cylinder_to_cartesian(x_cyl, z); - auto const y_cart = transform_coordinate_cylinder_to_cartesian(y_cyl, z); - auto const z_cart = transform_coordinate_cylinder_to_cartesian(z_cyl, z); - for (int i = 0; i < 3; ++i) { - BOOST_CHECK_SMALL(x_cart[i] - x[i], eps); - BOOST_CHECK_SMALL(y_cart[i] - y[i], eps); - BOOST_CHECK_SMALL(z_cart[i] - z[i], eps); - } - } + auto const x = Utils::vector_product(y,z); + // check transformation with orientation { auto const x_cyl = transform_coordinate_cartesian_to_cylinder(x, z, y); From 432a29e2ce4079924d14385877de5ac66d9b291a Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Thu, 17 Dec 2020 16:05:49 +0100 Subject: [PATCH 07/31] observables: introduce orientation argument to all cylindrical observables --- .../observables/CylindricalDensityProfile.hpp | 3 +- .../CylindricalFluxDensityProfile.hpp | 8 +-- ...BFluxDensityProfileAtParticlePositions.cpp | 3 +- .../CylindricalLBProfileObservable.hpp | 15 ++-- .../CylindricalLBVelocityProfile.cpp | 4 +- ...alLBVelocityProfileAtParticlePositions.cpp | 3 +- .../CylindricalPidProfileObservable.hpp | 15 ++-- .../CylindricalProfileObservable.hpp | 6 +- .../CylindricalVelocityProfile.hpp | 8 +-- src/python/espressomd/observables.py | 72 ++++++++++++++----- .../CylindricalLBProfileObservable.hpp | 16 +++-- .../CylindricalPidProfileObservable.hpp | 18 +++-- 12 files changed, 114 insertions(+), 57 deletions(-) diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index d18ea8baeac..923662bf0fb 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -41,7 +41,8 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - folded_position(traits.position(p), box_geo) - center, axis)); + folded_position(traits.position(p), box_geo) - center, axis, + orientation)); } histogram.normalize(); diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index 13ef33b9178..ee06c759114 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -44,10 +44,10 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { auto const pos = folded_position(traits.position(p), box_geo) - center; - histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos, axis), - Utils::transform_vector_cartesian_to_cylinder(traits.velocity(p), - axis, pos)); + histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( + pos, axis, orientation), + Utils::transform_vector_cartesian_to_cylinder( + traits.velocity(p), axis, pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index de51d4a9e10..f6179e01ef7 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -44,7 +44,8 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( lb_lbfluid_get_lattice_speed(); histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis), + Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis, + orientation), Utils::transform_vector_cartesian_to_cylinder(v, axis, pos - center)); } diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index 6a846e53016..a94a7c64871 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -31,14 +31,15 @@ namespace Observables { class CylindricalLBProfileObservable : public CylindricalProfileObservable { public: CylindricalLBProfileObservable(Utils::Vector3d const ¢er, - Utils::Vector3d const &axis, int n_r_bins, - int n_phi_bins, int n_z_bins, double min_r, - double max_r, double min_phi, double max_phi, - double min_z, double max_z, + Utils::Vector3d const &axis, + Utils::Vector3d const &orientation, + int n_r_bins, int n_phi_bins, int n_z_bins, + double min_r, double max_r, double min_phi, + double max_phi, double min_z, double max_z, double sampling_density) - : CylindricalProfileObservable(center, axis, n_r_bins, n_phi_bins, - n_z_bins, min_r, max_r, min_phi, max_phi, - min_z, max_z), + : CylindricalProfileObservable(center, axis, orientation, n_r_bins, + n_phi_bins, n_z_bins, min_r, max_r, + min_phi, max_phi, min_z, max_z), sampling_density(sampling_density) { calculate_sampling_positions(); } diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index 28148f5d493..65023595e65 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -36,8 +36,8 @@ std::vector CylindricalLBVelocityProfile::operator()() const { auto const velocity = lb_lbfluid_get_interpolated_velocity(p) * lb_lbfluid_get_lattice_speed(); auto const pos_shifted = p - center; - auto const pos_cyl = - Utils::transform_coordinate_cartesian_to_cylinder(pos_shifted, axis); + auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( + pos_shifted, axis, orientation); histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( velocity, axis, pos_shifted)); } diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index e1106574cfa..ac0386f0361 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -41,7 +41,8 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( lb_lbfluid_get_lattice_speed(); histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis), + Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis, + orientation), Utils::transform_vector_cartesian_to_cylinder(v, axis, pos - center)); } diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index bbece2be6e5..3e7e47405c6 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -29,14 +29,15 @@ class CylindricalPidProfileObservable : public PidObservable, public: CylindricalPidProfileObservable(std::vector const &ids, Utils::Vector3d const ¢er, - Utils::Vector3d const &axis, int n_r_bins, - int n_phi_bins, int n_z_bins, double min_r, - double max_r, double min_phi, double max_phi, - double min_z, double max_z) + Utils::Vector3d const &axis, + Utils::Vector3d const &orientation, + int n_r_bins, int n_phi_bins, int n_z_bins, + double min_r, double max_r, double min_phi, + double max_phi, double min_z, double max_z) : PidObservable(ids), - CylindricalProfileObservable(center, axis, n_r_bins, n_phi_bins, - n_z_bins, min_r, max_r, min_phi, max_phi, - min_z, max_z) {} + CylindricalProfileObservable(center, axis, orientation, n_r_bins, + n_phi_bins, n_z_bins, min_r, max_r, + min_phi, max_phi, min_z, max_z) {} }; } // Namespace Observables diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index c28669a4e62..661a5184806 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -36,15 +36,17 @@ namespace Observables { class CylindricalProfileObservable : public ProfileObservable { public: CylindricalProfileObservable(Utils::Vector3d const ¢er, - Utils::Vector3d const &axis, int n_r_bins, + Utils::Vector3d const &axis, + Utils::Vector3d const &orientation, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), - center(center), axis(axis) {} + center(center), axis(axis), orientation(orientation) {} Utils::Vector3d center; Utils::Vector3d axis; + Utils::Vector3d orientation; }; } // Namespace Observables diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 58dfa0bc5fc..64d44e5d23a 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -44,10 +44,10 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { auto const pos = folded_position(traits.position(p), box_geo) - center; - histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos, axis), - Utils::transform_vector_cartesian_to_cylinder(traits.velocity(p), - axis, pos)); + histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( + pos, axis, orientation), + Utils::transform_vector_cartesian_to_cylinder( + traits.velocity(p), axis, pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 2169bee15e9..8d025b90abe 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import itertools import numpy as np +import sys from .script_interface import ScriptInterfaceHelper, script_interface_register @@ -69,6 +70,27 @@ def bin_centers(self): return np.array(list(itertools.product(*edges))).reshape(shape) +class CylindricalProfileObservables(ProfileObservable): + """ + Base Class for ProfileObservables that work with cylindrical coordinates + to inject default behaviour for the ``orientation`` parameter + """ + + def __init__(self, **kwargs): + if "oid" not in kwargs and "orientation" not in kwargs and kwargs["n_phi_bins"] == 1: + # if the phi angle is not important, choose an orientation that is + # not parallel to ``axis`` + try_vectors = [[1., 0., 0.], [0., 0., 1.]] + axis = kwargs["axis"] + for vec in try_vectors: + proj = np.dot(vec, axis / np.linalg.norm(axis)) + if np.arccos(proj) > sys.float_info.epsilon: + vec -= proj * axis + kwargs["orientation"] = vec / np.linalg.norm(vec) + break + super().__init__(**kwargs) + + @script_interface_register class ComPosition(Observable): @@ -636,7 +658,7 @@ class DPDStress(Observable): @script_interface_register -class CylindricalDensityProfile(ProfileObservable): +class CylindricalDensityProfile(CylindricalProfileObservables): """Calculates the particle density in cylindrical coordinates. @@ -648,6 +670,8 @@ class CylindricalDensityProfile(ProfileObservable): Position of the center of the cylindrical coordinate system for the histogram. axis : (3,) array_like of :obj:`float` Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. + orientation: (3,) array_like of :obj:`float` + The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. n_r_bins : :obj:`int` Number of bins in radial direction. n_phi_bins : :obj:`int` @@ -657,13 +681,13 @@ class CylindricalDensityProfile(ProfileObservable): min_r : :obj:`float` Minimum ``r`` to consider. min_phi : :obj:`float` - Minimum ``phi`` to consider. + Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. max_phi : :obj:`float` - Maximum ``phi`` to consider. + Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -676,7 +700,7 @@ class CylindricalDensityProfile(ProfileObservable): @script_interface_register -class CylindricalFluxDensityProfile(ProfileObservable): +class CylindricalFluxDensityProfile(CylindricalProfileObservables): """Calculates the particle flux density in cylindrical coordinates. @@ -688,6 +712,8 @@ class CylindricalFluxDensityProfile(ProfileObservable): Position of the center of the cylindrical coordinate system for the histogram. axis : (3,) array_like of :obj:`float` Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. + orientation: (3,) array_like of :obj:`float` + The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. n_r_bins : :obj:`int` Number of bins in radial direction. n_phi_bins : :obj:`int` @@ -697,13 +723,13 @@ class CylindricalFluxDensityProfile(ProfileObservable): min_r : :obj:`float` Minimum ``r`` to consider. min_phi : :obj:`float` - Minimum ``phi`` to consider. + Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. max_phi : :obj:`float` - Maximum ``phi`` to consider. + Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -718,7 +744,8 @@ class CylindricalFluxDensityProfile(ProfileObservable): @script_interface_register -class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): +class CylindricalLBFluxDensityProfileAtParticlePositions( + CylindricalProfileObservables): """Calculates the LB fluid flux density at the particle positions in cylindrical coordinates. @@ -731,6 +758,8 @@ class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): Position of the center of the cylindrical coordinate system for the histogram. axis : (3,) array_like of :obj:`float` Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. + orientation: (3,) array_like of :obj:`float` + The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. n_r_bins : :obj:`int` Number of bins in radial direction. n_phi_bins : :obj:`int` @@ -740,13 +769,13 @@ class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): min_r : :obj:`float` Minimum ``r`` to consider. min_phi : :obj:`float` - Minimum ``phi`` to consider. + Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. max_phi : :obj:`float` - Maximum ``phi`` to consider. + Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -761,7 +790,8 @@ class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): @script_interface_register -class CylindricalLBVelocityProfileAtParticlePositions(ProfileObservable): +class CylindricalLBVelocityProfileAtParticlePositions( + CylindricalProfileObservables): """Calculates the LB fluid velocity at the particle positions in cylindrical coordinates. @@ -774,6 +804,8 @@ class CylindricalLBVelocityProfileAtParticlePositions(ProfileObservable): Position of the center of the cylindrical coordinate system for the histogram. axis : (3,) array_like of :obj:`float` Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. + orientation: (3,) array_like of :obj:`float` + The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. n_r_bins : :obj:`int` Number of bins in radial direction. n_phi_bins : :obj:`int` @@ -783,13 +815,13 @@ class CylindricalLBVelocityProfileAtParticlePositions(ProfileObservable): min_r : :obj:`float` Minimum ``r`` to consider. min_phi : :obj:`float` - Minimum ``phi`` to consider. + Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. max_phi : :obj:`float` - Maximum ``phi`` to consider. + Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -804,7 +836,7 @@ class CylindricalLBVelocityProfileAtParticlePositions(ProfileObservable): @script_interface_register -class CylindricalVelocityProfile(ProfileObservable): +class CylindricalVelocityProfile(CylindricalProfileObservables): """Calculates the particle velocity profile in cylindrical coordinates. @@ -816,6 +848,8 @@ class CylindricalVelocityProfile(ProfileObservable): Position of the center of the cylindrical coordinate system for the histogram. axis : (3,) array_like of :obj:`float` Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. + orientation: (3,) array_like of :obj:`float` + The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. n_r_bins : :obj:`int` Number of bins in radial direction. n_phi_bins : :obj:`int` @@ -825,13 +859,13 @@ class CylindricalVelocityProfile(ProfileObservable): min_r : :obj:`float` Minimum ``r`` to consider. min_phi : :obj:`float` - Minimum ``phi`` to consider. + Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. max_phi : :obj:`float` - Maximum ``phi`` to consider. + Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -846,7 +880,7 @@ class CylindricalVelocityProfile(ProfileObservable): @script_interface_register -class CylindricalLBVelocityProfile(ProfileObservable): +class CylindricalLBVelocityProfile(CylindricalProfileObservables): """Calculates the LB fluid velocity profile in cylindrical coordinates. @@ -860,6 +894,8 @@ class CylindricalLBVelocityProfile(ProfileObservable): Position of the center of the cylindrical coordinate system for the histogram. axis : (3,) array_like of :obj:`float` Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. + orientation: (3,) array_like of :obj:`float` + The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. n_r_bins : :obj:`int` Number of bins in radial direction. n_phi_bins : :obj:`int` @@ -869,13 +905,13 @@ class CylindricalLBVelocityProfile(ProfileObservable): min_r : :obj:`float` Minimum ``r`` to consider. min_phi : :obj:`float` - Minimum ``phi`` to consider. + Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. max_phi : :obj:`float` - Maximum ``phi`` to consider. + Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. sampling_density : :obj:`float` diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index f0f12e3e639..740bd60ea6e 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -65,6 +65,12 @@ class CylindricalLBProfileObservable get_value(v); }, [this]() { return cylindrical_profile_observable()->axis; }}, + {"orientation", + [this](const Variant &v) { + cylindrical_profile_observable()->orientation = + get_value(v); + }, + [this]() { return cylindrical_profile_observable()->orientation; }}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = @@ -151,11 +157,11 @@ class CylindricalLBProfileObservable void do_construct(VariantMap const ¶ms) override { m_observable = make_shared_from_args( - params, "center", "axis", "n_r_bins", "n_phi_bins", "n_z_bins", - "min_r", "max_r", "min_phi", "max_phi", "min_z", "max_z", - "sampling_density"); + Utils::Vector3d, int, int, int, double, double, + double, double, double, double, double>( + params, "center", "axis", "orientation", "n_r_bins", "n_phi_bins", + "n_z_bins", "min_r", "max_r", "min_phi", "max_phi", "min_z", + "max_z", "sampling_density"); } Variant do_call_method(std::string const &method, diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index 9d22325af17..7755a74171a 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -70,6 +70,14 @@ class CylindricalPidProfileObservable get_value(v); }, [this]() { return cylindrical_pid_profile_observable()->axis; }}, + {"orientation", + [this](const Variant &v) { + cylindrical_pid_profile_observable()->orientation = + get_value(v); + }, + [this]() { + return cylindrical_pid_profile_observable()->orientation; + }}, {"n_r_bins", [this](const Variant &v) { cylindrical_pid_profile_observable()->n_bins[0] = @@ -151,11 +159,11 @@ class CylindricalPidProfileObservable void do_construct(VariantMap const ¶ms) override { m_observable = make_shared_from_args, Utils::Vector3d, - Utils::Vector3d, int, int, int, double, double, - double, double, double, double>( - params, "ids", "center", "axis", "n_r_bins", "n_phi_bins", - "n_z_bins", "min_r", "max_r", "min_phi", "max_phi", "min_z", - "max_z"); + Utils::Vector3d, Utils::Vector3d, int, int, int, + double, double, double, double, double, double>( + params, "ids", "center", "axis", "orientation", "n_r_bins", + "n_phi_bins", "n_z_bins", "min_r", "max_r", "min_phi", "max_phi", + "min_z", "max_z"); } Variant do_call_method(std::string const &method, From 268621500297d51c7abc8e8f14f4df0e6de6517d Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 15:03:08 +0100 Subject: [PATCH 08/31] fix leftover transformation with axis --- src/core/observables/CylindricalLBProfileObservable.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index a94a7c64871..fab347ea3a0 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -48,8 +48,7 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { limits[0], limits[1], limits[2], n_bins[0], n_bins[1], n_bins[2], sampling_density); for (auto &p : sampling_positions) { - auto p_cart = Utils::transform_coordinate_cylinder_to_cartesian( - p, Utils::Vector3d{{0.0, 0.0, 1.0}}); + auto p_cart = Utils::transform_coordinate_cylinder_to_cartesian(p); // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; From d33df386a4b72db54a93b7f6ca0febe4e5d4bf49 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 15:15:41 +0100 Subject: [PATCH 09/31] rework cylindrical tests --- src/python/espressomd/observables.py | 6 +- testsuite/python/lb_poiseuille_cylinder.py | 7 +- testsuite/python/observable_cylindrical.py | 281 ++++++++--------- testsuite/python/observable_cylindricalLB.py | 313 ++++++++----------- testsuite/python/tests_common.py | 84 ++--- 5 files changed, 305 insertions(+), 386 deletions(-) diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 8d025b90abe..99f720d5fa6 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -80,11 +80,11 @@ def __init__(self, **kwargs): if "oid" not in kwargs and "orientation" not in kwargs and kwargs["n_phi_bins"] == 1: # if the phi angle is not important, choose an orientation that is # not parallel to ``axis`` - try_vectors = [[1., 0., 0.], [0., 0., 1.]] - axis = kwargs["axis"] + try_vectors = [np.array([1., 0., 0.]), np.array([0., 0., 1.])] + axis = np.asarray(kwargs["axis"]) for vec in try_vectors: proj = np.dot(vec, axis / np.linalg.norm(axis)) - if np.arccos(proj) > sys.float_info.epsilon: + if np.arccos(proj) > 10*sys.float_info.epsilon: vec -= proj * axis kwargs["orientation"] = vec / np.linalg.norm(vec) break diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index 981c0c23e28..96387fde624 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -81,7 +81,8 @@ class LBPoiseuilleCommon: system = espressomd.System(box_l=[BOX_L] * 3) system.time_step = TIME_STEP system.cell_system.skin = 0.4 * AGRID - params = {'axis': [0, 0, 1]} + params = {'axis': [0, 0, 1], + 'orientation' : [1,0,0]} def prepare(self): """ @@ -152,6 +153,7 @@ def prepare_obs(self): local_obs_params = OBS_PARAMS.copy() local_obs_params['center'] = obs_center local_obs_params['axis'] = self.params['axis'] + local_obs_params['orientation'] = self.params['orientation'] obs = espressomd.observables.CylindricalLBVelocityProfile( **local_obs_params) self.accumulator = espressomd.accumulators.MeanVarianceCalculator( @@ -178,16 +180,19 @@ def check_observable(self): def test_x(self): self.params['axis'] = [1, 0, 0] + self.params['orientation'] = [0, 0, -1] self.compare_to_analytical() self.check_observable() def test_y(self): self.params['axis'] = [0, 1, 0] + self.params['orientation'] = [1, 0, 0] self.compare_to_analytical() self.check_observable() def test_z(self): self.params['axis'] = [0, 0, 1] + self.params['orientation'] = [1, 0, 0] self.compare_to_analytical() self.check_observable() diff --git a/testsuite/python/observable_cylindrical.py b/testsuite/python/observable_cylindrical.py index 2e6e7a79ec2..99d528462ed 100644 --- a/testsuite/python/observable_cylindrical.py +++ b/testsuite/python/observable_cylindrical.py @@ -33,11 +33,12 @@ class TestCylindricalObservable(ut.TestCase): params = { 'ids': list(range(100)), - 'center': [7.5, 7.5, 7.5], # center of the histogram - 'axis': 'y', - 'n_r_bins': 4, # number of bins in r - 'n_phi_bins': 4, # -*- in phi - 'n_z_bins': 4, # -*- in z + 'center': 3 * [7.5], + 'axis': [np.sqrt(2), np.sqrt(2), 0], + 'orientation': [0, 0, 1], + 'n_r_bins': 4, + 'n_phi_bins': 3, + 'n_z_bins': 4, 'min_r': 0.0, 'min_phi': -np.pi, 'min_z': -5.0, @@ -46,180 +47,146 @@ class TestCylindricalObservable(ut.TestCase): 'max_z': 5.0, } + v_r = 0.6 + v_phi = 0.7 + v_z = 0.8 + def tearDown(self): self.system.part.clear() - def swap_axis(self, arr, axis): - if axis == 'x': - arr = np.dot( - tests_common.rotation_matrix([0, 1, 0], np.pi / 2.0), arr) - elif axis == 'y': - arr = np.dot( - tests_common.rotation_matrix([1, 0, 0], -np.pi / 2.0), arr) - return arr - - def swap_axis_inverse(self, arr, axis): - if axis == 'x': - arr = np.dot( - tests_common.rotation_matrix([0, 1, 0], -np.pi / 2.0), arr) - elif axis == 'y': - arr = np.dot( - tests_common.rotation_matrix([1, 0, 0], np.pi / 2.0), arr) - return arr + def calc_ellipsis_pos_vel(self, n_part, z_min, z_max, semi_x=1., semi_y=1.): + """ + Calculate positions on an elliptical corkscrew line. Calculate cartesian velocities that lead to a constant velocity in cylindrical coordinates + """ + + zs = np.linspace(z_min, z_max, num=n_part) + angles = np.linspace(-0.99*np.pi, 0.999 * np.pi, num=n_part) - def pol_coords(self): - positions = np.zeros((len(self.params['ids']), 3)) - for i, p in enumerate(self.system.part): - tmp = p.pos - np.array(self.params['center']) - tmp = self.swap_axis_inverse(tmp, self.params['axis']) - positions[ - i, :] = tests_common.transform_pos_from_cartesian_to_polar_coordinates(tmp) - return positions + positions = [] + velocities = [] - def set_particles(self): - self.system.part.clear() - # Parameters for an ellipse. - a = 1.0 # semi minor-axis length - b = 2.0 # semi major-axis length - # Choose the cartesian velocities such that each particle gets the same - # v_r, v_phi and v_z, respectively. - self.v_r = .75 - self.v_phi = 2.5 - self.v_z = 1.5 - for i in self.params['ids']: + for angle, z in zip(angles, zs): position = np.array( - [a * np.cos(i * 2.0 * np.pi / (len(self.params['ids']) + 1)), - b * np.sin(i * 2.0 * np.pi / (len(self.params['ids']) + 1)), - i * (self.params['max_z'] - self.params['min_z']) / - (len(self.params['ids']) + 1) - self.params['center'][2]]) - - e_z = np.array([0, 0, 1]) - e_r = position - (position * e_z) * e_z - e_r /= np.linalg.norm(e_r) - e_phi = np.cross(e_z, e_r) - velocity = e_r * self.v_r + e_phi * self.v_phi + e_z * self.v_z - - velocity = self.swap_axis(velocity, self.params['axis']) - position = self.swap_axis(position, self.params['axis']) - position += np.array(self.params['center']) - self.system.part.add(id=i, pos=position, v=velocity) - - def calculate_numpy_histogram(self): - pol_positions = self.pol_coords() + [semi_x * np.cos(angle), + semi_y * np.sin(angle), + z]) + + e_r,e_phi,e_z = tests_common.get_cylindrical_basis_vectors(position) + velocity = self.v_r * e_r + self.v_phi * e_phi + self.v_z * e_z + + positions.append(position) + velocities.append(velocity) + + return np.array(positions), np.array(velocities) + + def align_with_observable_frame(self, vec): + """ + Rotate vectors from the original box frame to the frame of the observables. + """ + + # align original z to observable z + vec = tests_common.rodrigues_rot(vec,[1,-1,0],-np.pi/2.) + # original x now points along [sqrt(3),-sqrt(3),-sqrt(3)] + + # align original x to observable orientation + vec =tests_common.rodrigues_rot(vec,[1,1,0],-3./4.*np.pi) + return vec + + def setup_system_get_np_hist(self): + """ + Pick positions and velocities in the original box frame and calculate the np histogram. Then rotate and move the positions and velocities to the frame of the observables. + After calculating the core observables, the result should be the same as the np histogram obtained from the original box frame. + """ + + positions, velocities = self.calc_ellipsis_pos_vel(len( + self.params['ids']), 0.99 * self.params['min_z'], 0.9 * self.params['max_z'], semi_x= 0.9 * self.params['max_r'], semi_y= 0.2 * self.params['max_r']) + + # first, get the numpy histogram of the cylinder coordinates + pos_cyl = [] + for pos in positions: + pos_cyl.append( + tests_common.transform_pos_from_cartesian_to_polar_coordinates(pos)) np_hist, np_edges = tests_common.get_histogram( - pol_positions, self.params, 'cylindrical') - return np_hist, np_edges - - def normalize_with_bin_volume(self, histogram): - bin_volume = tests_common.get_cylindrical_bin_volume( - self.params['n_r_bins'], - self.params['n_phi_bins'], - self.params['n_z_bins'], - self.params['min_r'], - self.params['max_r'], - self.params['min_phi'], - self.params['max_phi'], - self.params['min_z'], - self.params['max_z']) - for i in range(self.params['n_r_bins']): - histogram[i, :, :] /= bin_volume[i] - return histogram - - def density_profile_test(self): - self.set_particles() - # Set up the Observable. - local_params = self.params.copy() - if self.params['axis'] == 'x': - local_params['axis'] = [1.0, 0.0, 0.0] - elif self.params['axis'] == 'y': - local_params['axis'] = [0.0, 1.0, 0.0] - else: - local_params['axis'] = [0.0, 0.0, 1.0] - obs = espressomd.observables.CylindricalDensityProfile(**local_params) - core_hist = obs.calculate() - core_edges = obs.call_method("edges") - np_hist, np_edges = self.calculate_numpy_histogram() - np_hist = self.normalize_with_bin_volume(np_hist) - np.testing.assert_array_almost_equal(np_hist, core_hist) - for i in range(3): - np.testing.assert_array_almost_equal(np_edges[i], core_edges[i]) - self.assertEqual(np.prod(obs.shape()), len(np_hist.flatten())) - - def velocity_profile_test(self): - self.set_particles() - # Set up the Observable. - local_params = self.params.copy() - if self.params['axis'] == 'x': - local_params['axis'] = [1.0, 0.0, 0.0] - elif self.params['axis'] == 'y': - local_params['axis'] = [0.0, 1.0, 0.0] - else: - local_params['axis'] = [0.0, 0.0, 1.0] - obs = espressomd.observables.CylindricalVelocityProfile(**local_params) - core_hist = obs.calculate() + np.array(pos_cyl), self.params, 'cylindrical') + np_dens = tests_common.normalize_cylindrical_hist(np_hist.copy(), self.params) + + # now align the positions and velocities with the frame of reference + # used in the observables + pos_aligned = [] + vel_aligned = [] + for pos, vel in zip(positions, velocities): + pos_aligned.append( + self.align_with_observable_frame(pos) + + self.params['center']) + vel_aligned.append(self.align_with_observable_frame(vel)) + self.system.part.add(pos=pos_aligned, v=vel_aligned) + + return np_dens, np_edges + + def check_edges(self,observable, np_edges): + core_edges = observable.call_method("edges") + for core_edge, np_edge in zip(core_edges, np_edges): + np.testing.assert_array_almost_equal(core_edge, np_edge) + + def test_density_profile(self): + """ + Check that the result from the observable (in its own frame) matches the np result from the box frame + """ + np_dens, np_edges = self.setup_system_get_np_hist() + + cyl_dens_prof = espressomd.observables.CylindricalDensityProfile( + **self.params) + core_hist = cyl_dens_prof.calculate() + np.testing.assert_array_almost_equal(np_dens, core_hist) + self.check_edges(cyl_dens_prof,np_edges) + + def test_vel_profile(self): + """ + Check that the result from the observable (in its own frame) matches the np result from the box frame + """ + np_dens, np_edges = self.setup_system_get_np_hist() + cyl_vel_prof = espressomd.observables.CylindricalVelocityProfile( + **self.params) + core_hist = cyl_vel_prof.calculate() core_hist_v_r = core_hist[:, :, :, 0] core_hist_v_phi = core_hist[:, :, :, 1] core_hist_v_z = core_hist[:, :, :, 2] - np_hist, _ = self.calculate_numpy_histogram() - for x in np.nditer(np_hist, op_flags=['readwrite']): - if x[...] > 0.0: - x[...] /= x[...] - np.testing.assert_array_almost_equal(np_hist * self.v_r, core_hist_v_r) + np_hist_binary = np_dens + np_hist_binary[np.nonzero(np_hist_binary)] = 1 np.testing.assert_array_almost_equal( - np_hist * self.v_phi, core_hist_v_phi) - np.testing.assert_array_almost_equal(np_hist * self.v_z, core_hist_v_z) - self.assertEqual(np.prod(obs.shape()), len(np_hist.flatten()) * 3) - - def flux_density_profile_test(self): - self.set_particles() - # Set up the Observable. - local_params = self.params.copy() - if self.params['axis'] == 'x': - local_params['axis'] = [1.0, 0.0, 0.0] - elif self.params['axis'] == 'y': - local_params['axis'] = [0.0, 1.0, 0.0] - else: - local_params['axis'] = [0.0, 0.0, 1.0] - obs = espressomd.observables.CylindricalFluxDensityProfile( - **local_params) - core_hist = obs.calculate() + np_hist_binary * self.v_r, core_hist_v_r) + np.testing.assert_array_almost_equal( + np_hist_binary * self.v_phi, core_hist_v_phi) + np.testing.assert_array_almost_equal( + np_hist_binary * self.v_z, core_hist_v_z) + self.check_edges(cyl_vel_prof,np_edges) + + def test_flux_density_profile(self): + """ + Check that the result from the observable (in its own frame) matches the np result from the box frame + """ + np_dens, np_edges = self.setup_system_get_np_hist() + cyl_flux_dens = espressomd.observables.CylindricalFluxDensityProfile( + **self.params) + core_hist = cyl_flux_dens.calculate() core_hist_v_r = core_hist[:, :, :, 0] core_hist_v_phi = core_hist[:, :, :, 1] core_hist_v_z = core_hist[:, :, :, 2] - np_hist, _ = self.calculate_numpy_histogram() - np_hist = self.normalize_with_bin_volume(np_hist) - np.testing.assert_array_almost_equal(np_hist * self.v_r, core_hist_v_r) + np.testing.assert_array_almost_equal(np_dens * self.v_r, core_hist_v_r) np.testing.assert_array_almost_equal( - np_hist * self.v_phi, core_hist_v_phi) - np.testing.assert_array_almost_equal(np_hist * self.v_z, core_hist_v_z) - self.assertEqual(np.prod(obs.shape()), len(np_hist.flatten()) * 3) - - def test_hist_x(self): - self.params['axis'] = 'x' - self.velocity_profile_test() - self.flux_density_profile_test() - self.density_profile_test() - - def test_hist_y(self): - self.params['axis'] = 'y' - self.velocity_profile_test() - self.flux_density_profile_test() - self.density_profile_test() - - def test_hist_z(self): - self.params['axis'] = 'z' - self.velocity_profile_test() - self.flux_density_profile_test() - self.density_profile_test() + np_dens * self.v_phi, core_hist_v_phi) + np.testing.assert_array_almost_equal(np_dens * self.v_z, core_hist_v_z) + self.check_edges(cyl_flux_dens,np_edges) def test_cylindrical_pid_profile_interface(self): - # test setters and getters + """ + Test setters and getters of the script interface + """ params = self.params.copy() params['n_r_bins'] = 4 params['n_phi_bins'] = 6 params['n_z_bins'] = 8 params['ids'] = [0, 1] - params['axis'] = [0.0, 1.0, 0.0] self.system.part.add(id=0, pos=[0, 0, 0], type=0) self.system.part.add(id=1, pos=[0, 0, 0], type=1) observable = espressomd.observables.CylindricalDensityProfile(**params) diff --git a/testsuite/python/observable_cylindricalLB.py b/testsuite/python/observable_cylindricalLB.py index e2ba5a665c6..d6c2ddae8a5 100644 --- a/testsuite/python/observable_cylindricalLB.py +++ b/testsuite/python/observable_cylindricalLB.py @@ -22,206 +22,133 @@ import espressomd.lb import tests_common - -AGRID = 1.0 -VISC = 2.7 -DENS = 1.7 -TIME_STEP = 0.1 -LB_PARAMS = {'agrid': AGRID, - 'dens': DENS, - 'visc': VISC, - 'tau': TIME_STEP, - } - - class CylindricalLBObservableCommon: """ - Testcase for the CylindricalLBObservable. + Testcase for the CylindricalLBObservables. """ lbf = None - system = espressomd.System(box_l=(10, 10, 10)) + system = espressomd.System(box_l=3*[15]) system.time_step = 0.01 system.cell_system.skin = 0.4 positions = [] + lb_params = {'agrid': 1., + 'dens': 1.2, + 'visc': 2.7, + 'tau': 0.1, + } params = { - 'ids': list(range(10)), - 'center': [5.0, 5.0, 5.0], # center of the histogram - 'axis': 'y', - 'n_r_bins': 10, # number of bins in r - 'n_phi_bins': 2, # -*- in phi - 'n_z_bins': 2, # -*- in z + 'ids': list(range(9)), + 'center': 3*[7], + 'axis': [1,0,0], + 'orientation' : [0,0,1], + 'n_r_bins': 4, + 'n_phi_bins': 3, + 'n_z_bins': 5, 'min_r': 0.0, 'min_phi': -np.pi, - 'min_z': -5.0, - 'max_r': 5.0, + 'min_z': -6.0, + 'max_r': 6.0, 'max_phi': np.pi, - 'max_z': 5.0, + 'max_z': 6.0, } - - def tearDown(self): - self.system.part.clear() - - def swap_axis(self, arr, axis): - if axis == 'x': - arr = np.dot(tests_common.rotation_matrix( - [0, 1, 0], np.pi / 2.0), arr) - elif axis == 'y': - arr = np.dot(tests_common.rotation_matrix( - [1, 0, 0], -np.pi / 2.0), arr) - return arr - - def swap_axis_inverse(self, arr, axis): - if axis == 'x': - arr = np.dot(tests_common.rotation_matrix( - [0, 1, 0], -np.pi / 2.0), arr) - elif axis == 'y': - arr = np.dot(tests_common.rotation_matrix( - [1, 0, 0], np.pi / 2.0), arr) - return arr - - def pol_coords(self): - positions = np.zeros((len(self.positions), 3)) - for i, p in enumerate(self.positions): - tmp = p - np.array(self.params['center']) - tmp = self.swap_axis_inverse(tmp, self.params['axis']) - positions[i, :] = tests_common.transform_pos_from_cartesian_to_polar_coordinates( - tmp) - return positions - - def set_particles(self): - self.system.part.clear() - self.system.part.add(pos=self.positions) - - def set_fluid_velocity(self): - del self.positions[:] - # Choose the cartesian velocities such that each particle gets the same - # v_r, v_phi and v_z, respectively. - self.v_r = .75 - self.v_phi = 2.5 - self.v_z = 1.5 - node_positions = np.arange(-4.5, 5.0, 1.0) - for i, _ in enumerate(node_positions): - position = np.array( - [node_positions[i], node_positions[i], node_positions[i]]) - - e_z = np.array([0, 0, 1]) - e_r = position - (position * e_z) * e_z - e_r /= np.linalg.norm(e_r) - e_phi = np.cross(e_z, e_r) - - velocity = e_r * self.v_r + e_phi * self.v_phi + e_z * self.v_z - - velocity = self.swap_axis(velocity, self.params['axis']) - position = self.swap_axis(position, self.params['axis']) - position += np.array(self.params['center']) - self.positions.append(position) - self.lbf[np.array(position, dtype=int)].velocity = velocity - - def normalize_with_bin_volume(self, histogram): - bin_volume = tests_common.get_cylindrical_bin_volume( - self.params['n_r_bins'], - self.params['n_phi_bins'], - self.params['n_z_bins'], - self.params['min_r'], - self.params['max_r'], - self.params['min_phi'], - self.params['max_phi'], - self.params['min_z'], - self.params['max_z']) - # Normalization - for i in range(self.params['n_r_bins']): - histogram[i, :, :] /= bin_volume[i] - return histogram - - def LB_fluxdensity_profile_test(self): - self.set_fluid_velocity() - self.set_particles() - # Set up the Observable. - local_params = self.params.copy() - if self.params['axis'] == 'x': - local_params['axis'] = [1.0, 0.0, 0.0] - elif self.params['axis'] == 'y': - local_params['axis'] = [0.0, 1.0, 0.0] - else: - local_params['axis'] = [0.0, 0.0, 1.0] - p = espressomd.observables.CylindricalLBFluxDensityProfileAtParticlePositions( - **local_params) - core_hist = p.calculate() - core_hist_v_r = core_hist[:, :, :, 0] - core_hist_v_phi = core_hist[:, :, :, 1] - core_hist_v_z = core_hist[:, :, :, 2] - core_edges = p.call_method("edges") - self.pol_positions = self.pol_coords() + + v_r = 0.02 + v_phi = 0.04 + v_z = 0.03 + + def calc_vel_at_pos(self, positions): + """ + In cylinde coordinates, all velocities are the same. In cartesian they depend on the position. The cartesian velocities are calculated here. + """ + + vels = [] + for pos in positions: + e_r,e_phi,e_z = tests_common.get_cylindrical_basis_vectors(pos) + velocity = self.v_r * e_r + self.v_phi * e_phi + self.v_z * e_z + vels.append(velocity) + return vels + + def align_with_observable_frame(self, vec): + """ + Rotate vectors from the original box frame to the frame of the observables. + """ + + # align original z to observable z + vec = tests_common.rodrigues_rot(vec, [0,1,0], np.pi/2.) + # original x now points along [0,0,-1] + + # align original x to observable orientation + vec = tests_common.rodrigues_rot(vec,[1,0,0],np.pi) + return vec + + def setup_system_get_np_hist(self): + """ + Pick positions and velocities in the original box frame and calculate the np histogram. Then rotate and move the positions and velocities to the frame of the observables. + After calculating the core observables, the result should be the same as the np histogram obtained from the original box frame. + """ + + nodes = np.array(np.meshgrid([1,2], [1,2], [1,1,1,1,2])).T.reshape(-1,3) + positions = nodes+3*[0.5] + velocities = self.calc_vel_at_pos(positions) + + # get the histogram from numpy + pos_cyl = [] + for pos in positions: + pos_cyl.append( + tests_common.transform_pos_from_cartesian_to_polar_coordinates(pos)) np_hist, np_edges = tests_common.get_histogram( - self.pol_positions, self.params, 'cylindrical') - np_hist = self.normalize_with_bin_volume(np_hist) - np.testing.assert_array_almost_equal(np_hist * self.v_r, core_hist_v_r) - np.testing.assert_array_almost_equal( - np_hist * self.v_phi, core_hist_v_phi) - np.testing.assert_array_almost_equal(np_hist * self.v_z, core_hist_v_z) - for i in range(3): - np.testing.assert_array_almost_equal(np_edges[i], core_edges[i]) - self.assertEqual(np.prod(p.shape()), len(np_hist.flatten()) * 3) + np.array(pos_cyl), self.params, 'cylindrical') + + # the particles only determine the evaluation points, not the values of the observables + np_hist[np.nonzero(np_hist)] = 1 + + # now align the positions and velocities with the frame of reference + # used in the observables + pos_aligned = [] + vel_aligned = [] + for pos, vel in zip(positions, velocities): + pos_aligned.append( + self.align_with_observable_frame(pos) + + self.params['center']) + vel_aligned.append(self.align_with_observable_frame(vel)) + node_aligned= np.array(np.rint( np.array(pos_aligned)-3*[0.5]) , dtype = int) + self.system.part.add(pos=pos_aligned, v = vel_aligned) + + for node,vel in zip(node_aligned, vel_aligned): + self.lbf[node].velocity=vel + + return np_hist, np_edges + + def check_edges(self,observable, np_edges): + core_edges = observable.call_method("edges") + for core_edge, np_edge in zip(core_edges, np_edges): + np.testing.assert_array_almost_equal(core_edge, np_edge) + + def test_cylindrical_lb_vel_profile_obs(self): + """ + Check that the result from the observable (in its own frame) matches the np result from the box frame + """ + + np_hist_binary, np_edges = self.setup_system_get_np_hist() + vel_obs = espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions(**self.params) + core_hist_v = vel_obs.calculate() + core_hist_v_r = core_hist_v[:, :, :, 0] + core_hist_v_phi = core_hist_v[:, :, :, 1] + core_hist_v_z = core_hist_v[:, :, :, 2] + np.testing.assert_array_almost_equal(np_hist_binary * self.v_r, core_hist_v_r) + np.testing.assert_array_almost_equal(np_hist_binary * self.v_phi, core_hist_v_phi) + np.testing.assert_array_almost_equal(np_hist_binary * self.v_z, core_hist_v_z) + self.check_edges(vel_obs, np_edges) - def LB_velocity_profile_at_particle_positions_test(self): - self.set_fluid_velocity() - self.set_particles() - # Set up the Observable. - local_params = self.params.copy() - if self.params['axis'] == 'x': - local_params['axis'] = [1.0, 0.0, 0.0] - elif self.params['axis'] == 'y': - local_params['axis'] = [0.0, 1.0, 0.0] - else: - local_params['axis'] = [0.0, 0.0, 1.0] - p = espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions( - **local_params) - core_hist = p.calculate() - core_hist_v_r = core_hist[:, :, :, 0] - core_hist_v_phi = core_hist[:, :, :, 1] - core_hist_v_z = core_hist[:, :, :, 2] - self.pol_positions = self.pol_coords() - np_hist, _ = np.histogramdd( - self.pol_positions, - bins=(self.params['n_r_bins'], - self.params['n_phi_bins'], - self.params['n_z_bins']), - range=[(self.params['min_r'], - self.params['max_r']), - (self.params['min_phi'], - self.params['max_phi']), - (self.params['min_z'], - self.params['max_z'])]) - for x in np.nditer(np_hist, op_flags=['readwrite']): - if x[...] > 0.0: - x[...] /= x[...] - np.testing.assert_array_almost_equal(np_hist * self.v_r, core_hist_v_r) - np.testing.assert_array_almost_equal( - np_hist * self.v_phi, core_hist_v_phi) - np.testing.assert_array_almost_equal(np_hist * self.v_z, core_hist_v_z) - self.assertEqual(np.prod(p.shape()), len(np_hist.flatten()) * 3) - - def perform_tests(self): - self.LB_fluxdensity_profile_test() - self.LB_velocity_profile_at_particle_positions_test() - - def test_x_axis(self): - self.params['axis'] = 'x' - self.perform_tests() - - def test_y_axis(self): - self.params['axis'] = 'y' - self.perform_tests() - - def test_z_axis(self): - self.params['axis'] = 'z' - self.perform_tests() def test_cylindrical_lb_profile_interface(self): - # test setters and getters + """ + Test setters and getters of the script interface + """ + params = self.params.copy() params['n_r_bins'] = 4 params['n_phi_bins'] = 6 @@ -287,7 +214,7 @@ def test_cylindrical_lb_profile_interface(self): class CylindricalLBObservableCPU(ut.TestCase, CylindricalLBObservableCommon): def setUp(self): - self.lbf = espressomd.lb.LBFluid(**LB_PARAMS) + self.lbf = espressomd.lb.LBFluid(**self.lb_params) self.system.actors.add(self.lbf) def tearDown(self): @@ -295,16 +222,34 @@ def tearDown(self): self.system.actors.remove(self.lbf) self.system.part.clear() + def test_cylindrical_lb_flux_density_obs(self): + """ + Check that the result from the observable (in its own frame) matches the np result from the box frame. + Only for CPU because density interpolation is not implemented for GPU LB. + """ + np_hist_binary, np_edges = self.setup_system_get_np_hist() + + flux_obs = espressomd.observables.CylindricalLBFluxDensityProfileAtParticlePositions( + **self.params) + core_hist_fl = flux_obs.calculate() + core_hist_fl_r = core_hist_fl[:, :, :, 0] + core_hist_fl_phi = core_hist_fl[:, :, :, 1] + core_hist_fl_z = core_hist_fl[:, :, :, 2] + core_edges_fl = flux_obs.call_method("edges") + + np.testing.assert_array_almost_equal(np_hist_binary*self.lb_params['dens'] * self.v_r, core_hist_fl_r) + np.testing.assert_array_almost_equal(np_hist_binary * self.lb_params['dens'] * self.v_phi, core_hist_fl_phi) + np.testing.assert_array_almost_equal(np_hist_binary * self.lb_params['dens'] * self.v_z, core_hist_fl_z) + self.check_edges(flux_obs, np_edges) @utx.skipIfMissingGPU() class CylindricalLBObservableGPU(ut.TestCase, CylindricalLBObservableCommon): def setUp(self): - self.lbf = espressomd.lb.LBFluidGPU(**LB_PARAMS) + self.lbf = espressomd.lb.LBFluidGPU(**self.lb_params) self.system.actors.add(self.lbf) def tearDown(self): - del self.positions[:] self.system.actors.remove(self.lbf) self.system.part.clear() diff --git a/testsuite/python/tests_common.py b/testsuite/python/tests_common.py index 92d169a1620..e7ed9ab3f9d 100644 --- a/testsuite/python/tests_common.py +++ b/testsuite/python/tests_common.py @@ -132,9 +132,8 @@ def verify_lj_forces(system, tolerance, ids_to_skip=()): def abspath(path): return os.path.join(os.path.dirname(os.path.abspath(__file__)), path) - def transform_pos_from_cartesian_to_polar_coordinates(pos): - """Transform the given cartesian coordinates to polar coordinates. + """Transform the given cartesian coordinates to cylindrical coordinates. Parameters ---------- @@ -166,11 +165,23 @@ def transform_vel_from_cartesian_to_polar_coordinates(pos, vel): (pos[0] * vel[0] + pos[1] * vel[1]) / np.sqrt(pos[0]**2 + pos[1]**2), (pos[0] * vel[1] - pos[1] * vel[0]) / np.sqrt(pos[0]**2 + pos[1]**2), vel[2]]) +def get_cylindrical_basis_vectors(pos): + phi = transform_pos_from_cartesian_to_polar_coordinates(pos)[1] + e_r = np.array([np.cos(phi), np.sin(phi),0.]) + e_phi = np.array([-np.sin(phi), np.cos(phi),0.]) + e_z = np.array([0.,0.,1.]) + return e_r, e_phi, e_z def convert_vec_body_to_space(system, part, vec): A = rotation_matrix_quat(system, part) return np.dot(A.transpose(), vec) +def rodrigues_rot(vec, axis, angle): + """ + https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula#Statement + """ + axis/=np.linalg.norm(axis) + return np.cos(angle)*vec + np.sin(angle)*np.cross(axis,vec)+(1-np.cos(angle))*np.dot(axis,vec)*axis def rotation_matrix(axis, theta): """ @@ -224,57 +235,41 @@ def rotation_matrix_quat(system, part): return A - -def get_cylindrical_bin_volume( - n_r_bins, - n_phi_bins, - n_z_bins, - min_r, - max_r, - min_phi, - max_phi, - min_z, - max_z): +def normalize_cylindrical_hist(histogram, cyl_obs_params): """ - Return the bin volumes for a cylindrical histogram. - + normalize a histogram in cylindrical coordinates. Helper to test the output + of cylindrical histogram observables + Parameters ---------- - n_r_bins : :obj:`float` - Number of bins in ``r`` direction. - n_phi_bins : :obj:`float` - Number of bins in ``phi`` direction. - n_z_bins : :obj:`float` - Number of bins in ``z`` direction. - min_r : :obj:`float` - Minimum considered value in ``r`` direction. - max_r : :obj:`float` - Maximum considered value in ``r`` direction. - min_phi : :obj:`float` - Minimum considered value in ``phi`` direction. - max_phi : :obj:`float` - Maximum considered value in ``phi`` direction. - min_z : :obj:`float` - Minimum considered value in ``z`` direction. - max_z : :obj:`float` - Maximum considered value in ``z`` direction. - - Returns - ------- - array_like - Bin volumes. - + histogram : (N,3) array_like of :obj:`float` + The histogram that needs to be normalized + cyl_obs_params : :obj:`dict` + A dictionary containing the common parameters of the cylindrical histogram observables. + Needs to contain the information about number and range of bins. """ + + n_r_bins = cyl_obs_params['n_r_bins'] + n_phi_bins =cyl_obs_params['n_phi_bins'] + n_z_bins =cyl_obs_params['n_z_bins'] + min_r =cyl_obs_params['min_r'] + max_r =cyl_obs_params['max_r'] + min_phi =cyl_obs_params['min_phi'] + max_phi =cyl_obs_params['max_phi'] + min_z =cyl_obs_params['min_z'] + max_z =cyl_obs_params['max_z'] + bin_volume = np.zeros(n_r_bins) r_bin_size = (max_r - min_r) / n_r_bins phi_bin_size = (max_phi - min_phi) / n_phi_bins z_bin_size = (max_z - min_z) / n_z_bins for i in range(n_r_bins): - bin_volume[i] = np.pi * ((min_r + r_bin_size * (i + 1))**2.0 - + bin_volume = np.pi * ((min_r + r_bin_size * (i + 1))**2.0 - (min_r + r_bin_size * i)**2.0) * \ phi_bin_size / (2.0 * np.pi) * z_bin_size - return bin_volume + histogram[i, :, :] /= bin_volume + return histogram def get_histogram(pos, obs_params, coord_system, **kwargs): """ @@ -638,6 +633,13 @@ def gay_berne_potential(r_ij, u_i, u_j, epsilon_0, sigma_0, mu, nu, k_1, k_2): return 4. * epsilon * (rr**-12 - rr**-6) +class DynamicDict(dict): + + def __getitem__(self, key): + value = super().__getitem__(key) + return eval(value, self) if isinstance(value, str) else value + + def count_fluid_nodes(lbf): """Counts the non-boundary nodes in the passed lb fluid instance.""" From cca7158594113a987b374a37ce0e196acc7f0bf0 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 15:23:57 +0100 Subject: [PATCH 10/31] fix fluxdensity observable --- .../lb_collective_interface.cpp | 9 +++++ .../lb_collective_interface.hpp | 2 ++ .../grid_based_algorithms/lb_interface.cpp | 33 +++++++++++++++++++ .../grid_based_algorithms/lb_interface.hpp | 8 +++++ .../lb_interpolation.cpp | 24 ++++++++++++++ .../lb_interpolation.hpp | 8 +++++ ...BFluxDensityProfileAtParticlePositions.cpp | 10 ++++-- 7 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/core/grid_based_algorithms/lb_collective_interface.cpp b/src/core/grid_based_algorithms/lb_collective_interface.cpp index f6a5b9aa69a..a2e1cb8e13c 100644 --- a/src/core/grid_based_algorithms/lb_collective_interface.cpp +++ b/src/core/grid_based_algorithms/lb_collective_interface.cpp @@ -81,6 +81,15 @@ mpi_lb_get_interpolated_velocity(Utils::Vector3d const &pos) { REGISTER_CALLBACK_ONE_RANK(mpi_lb_get_interpolated_velocity) +boost::optional +mpi_lb_get_interpolated_density(Utils::Vector3d const &pos) { + return detail::lb_calc_for_pos(pos, [&](auto pos) { + return lb_lbinterpolation_get_interpolated_density(pos); + }); +} + +REGISTER_CALLBACK_ONE_RANK(mpi_lb_get_interpolated_density) + auto mpi_lb_get_density(Utils::Vector3i const &index) { return detail::lb_calc_fluid_kernel( index, [&](auto const &modes, auto const &force_density) { diff --git a/src/core/grid_based_algorithms/lb_collective_interface.hpp b/src/core/grid_based_algorithms/lb_collective_interface.hpp index 1c9afa8fb31..4b6b0272ab4 100644 --- a/src/core/grid_based_algorithms/lb_collective_interface.hpp +++ b/src/core/grid_based_algorithms/lb_collective_interface.hpp @@ -27,6 +27,8 @@ /* collective getter functions */ boost::optional mpi_lb_get_interpolated_velocity(Utils::Vector3d const &pos); +boost::optional +mpi_lb_get_interpolated_density(Utils::Vector3d const &pos); boost::optional mpi_lb_get_density(Utils::Vector3i const &index); boost::optional mpi_lb_get_populations(Utils::Vector3i const &index); diff --git a/src/core/grid_based_algorithms/lb_interface.cpp b/src/core/grid_based_algorithms/lb_interface.cpp index d6c0e58ae89..2c020955524 100644 --- a/src/core/grid_based_algorithms/lb_interface.cpp +++ b/src/core/grid_based_algorithms/lb_interface.cpp @@ -1273,3 +1273,36 @@ lb_lbfluid_get_interpolated_velocity(const Utils::Vector3d &pos) { } throw NoLBActive(); } + +double +lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos) { + auto const folded_pos = folded_position(pos, box_geo); + auto const interpolation_order = lb_lbinterpolation_get_interpolation_order(); + if (lattice_switch == ActiveLB::GPU) { +#ifdef CUDA + double interpolated_dens; + switch (interpolation_order) { + case (InterpolationOrder::linear): + lb_get_interpolated_density_gpu<8>(folded_pos.data(), + interpolated_dens, 1); + break; + case (InterpolationOrder::quadratic): + lb_get_interpolated_density_gpu<27>(folded_pos.data(), + interpolated_dens, 1); + break; + } + return interpolated_dens; +#endif + } + if (lattice_switch == ActiveLB::CPU) { + switch (interpolation_order) { + case (InterpolationOrder::quadratic): + throw std::runtime_error("The non-linear interpolation scheme is not " + "implemented for the CPU LB."); + case (InterpolationOrder::linear): + return mpi_call(::Communication::Result::one_rank, + mpi_lb_get_interpolated_density, folded_pos); + } + } + throw NoLBActive(); +} diff --git a/src/core/grid_based_algorithms/lb_interface.hpp b/src/core/grid_based_algorithms/lb_interface.hpp index c72ef9b7f8b..1661f1026be 100644 --- a/src/core/grid_based_algorithms/lb_interface.hpp +++ b/src/core/grid_based_algorithms/lb_interface.hpp @@ -265,4 +265,12 @@ Utils::Vector3d lb_lbfluid_calc_fluid_momentum(); const Utils::Vector3d lb_lbfluid_get_interpolated_velocity(const Utils::Vector3d &pos); +/** + * @brief Calculates the interpolated fluid density on the master process. + * @param pos Position at which the density is to be calculated. + * @retval interpolated fluid density. + */ +double +lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos); + #endif diff --git a/src/core/grid_based_algorithms/lb_interpolation.cpp b/src/core/grid_based_algorithms/lb_interpolation.cpp index ea0cd46e1dd..5ed48e5be8b 100644 --- a/src/core/grid_based_algorithms/lb_interpolation.cpp +++ b/src/core/grid_based_algorithms/lb_interpolation.cpp @@ -82,6 +82,16 @@ Utils::Vector3d node_u(Lattice::index_t index) { return Utils::Vector3d{modes[1], modes[2], modes[3]} / local_density; } +double node_dens(Lattice::index_t index) { +#ifdef LB_BOUNDARIES + if (lbfields[index].boundary) { + return lbpar.density; + } +#endif // LB_BOUNDARIES + auto const modes = lb_calc_modes(index, lbfluid); + return lbpar.density + modes[0]; +} + } // namespace const Utils::Vector3d @@ -98,6 +108,20 @@ lb_lbinterpolation_get_interpolated_velocity(const Utils::Vector3d &pos) { return interpolated_u; } +double +lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &pos) { + double interpolated_dens; + + /* Calculate fluid density at the position. + This is done by linear interpolation (eq. (11) @cite ahlrichs99a) */ + lattice_interpolation(lblattice, pos, + [&interpolated_dens](Lattice::index_t index, double w) { + interpolated_dens += w * node_dens(index); + }); + + return interpolated_dens; +} + void lb_lbinterpolation_add_force_density( const Utils::Vector3d &pos, const Utils::Vector3d &force_density) { switch (interpolation_order) { diff --git a/src/core/grid_based_algorithms/lb_interpolation.hpp b/src/core/grid_based_algorithms/lb_interpolation.hpp index 68d9c6e1be6..dd33ebe8f16 100644 --- a/src/core/grid_based_algorithms/lb_interpolation.hpp +++ b/src/core/grid_based_algorithms/lb_interpolation.hpp @@ -41,6 +41,14 @@ InterpolationOrder lb_lbinterpolation_get_interpolation_order(); const Utils::Vector3d lb_lbinterpolation_get_interpolated_velocity(const Utils::Vector3d &p); +/** + * @brief Calculates the fluid density at a given position of the + * lattice. + * @note It can lead to undefined behaviour if the + * position is not within the local lattice. */ +double +lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &p); + /** * @brief Add a force density to the fluid at the given position. */ diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index f6179e01ef7..b20ba34b666 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -42,14 +42,18 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( auto const pos = folded_position(traits.position(p), box_geo); auto const v = lb_lbfluid_get_interpolated_velocity(pos) * lb_lbfluid_get_lattice_speed(); + auto const flux_dens = lb_lbfluid_get_interpolated_density(pos)*v; histogram.update( Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis, orientation), - Utils::transform_vector_cartesian_to_cylinder(v, axis, pos - center)); + Utils::transform_vector_cartesian_to_cylinder(flux_dens, axis, pos - center)); } - histogram.normalize(); - return histogram.get_histogram(); + // normalize by number of hits per bin + auto hist_tmp = histogram.get_histogram(); + auto tot_count = histogram.get_tot_count(); + std::transform(hist_tmp.begin(),hist_tmp.end(),tot_count.begin(),hist_tmp.begin(),[](auto hi, auto ci){return ci>0 ? hi/ci : 0.;}); + return hist_tmp; } } // namespace Observables From f32182da611b100646fbf4319d39a4e5f1baade1 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 15:38:49 +0100 Subject: [PATCH 11/31] no density inerpolation for GPU LB --- .../grid_based_algorithms/lb_interface.cpp | 18 ++---------------- ...calLBVelocityProfileAtParticlePositions.cpp | 7 ++----- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/core/grid_based_algorithms/lb_interface.cpp b/src/core/grid_based_algorithms/lb_interface.cpp index 2c020955524..67b7461dff1 100644 --- a/src/core/grid_based_algorithms/lb_interface.cpp +++ b/src/core/grid_based_algorithms/lb_interface.cpp @@ -1274,25 +1274,11 @@ lb_lbfluid_get_interpolated_velocity(const Utils::Vector3d &pos) { throw NoLBActive(); } -double -lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos) { +double lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos) { auto const folded_pos = folded_position(pos, box_geo); auto const interpolation_order = lb_lbinterpolation_get_interpolation_order(); if (lattice_switch == ActiveLB::GPU) { -#ifdef CUDA - double interpolated_dens; - switch (interpolation_order) { - case (InterpolationOrder::linear): - lb_get_interpolated_density_gpu<8>(folded_pos.data(), - interpolated_dens, 1); - break; - case (InterpolationOrder::quadratic): - lb_get_interpolated_density_gpu<27>(folded_pos.data(), - interpolated_dens, 1); - break; - } - return interpolated_dens; -#endif + throw std::runtime_error("Density interpolation is not implemented for the GPU LB."); } if (lattice_switch == ActiveLB::CPU) { switch (interpolation_order) { diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index ac0386f0361..15477bf6a3f 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -46,13 +46,10 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( Utils::transform_vector_cartesian_to_cylinder(v, axis, pos - center)); } + // normalize by number of hits per bin auto hist_tmp = histogram.get_histogram(); auto tot_count = histogram.get_tot_count(); - for (size_t ind = 0; ind < hist_tmp.size(); ++ind) { - if (tot_count[ind] > 0) { - hist_tmp[ind] /= static_cast(tot_count[ind]); - } - } + std::transform(hist_tmp.begin(),hist_tmp.end(),tot_count.begin(),hist_tmp.begin(),[](auto hi, auto ci){return ci>0 ? hi/ci : 0.;}); return hist_tmp; } From 70ee1fd19458bda9a86d691c3f7c8449e71e464f Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 12 Feb 2021 15:39:59 +0100 Subject: [PATCH 12/31] fix tests, tests common --- .../grid_based_algorithms/lb_interface.cpp | 3 +- .../grid_based_algorithms/lb_interface.hpp | 3 +- .../lb_interpolation.cpp | 3 +- .../lb_interpolation.hpp | 3 +- ...BFluxDensityProfileAtParticlePositions.cpp | 14 +- ...alLBVelocityProfileAtParticlePositions.cpp | 4 +- src/python/espressomd/observables.py | 2 +- .../include/shapes/HollowConicalFrustum.hpp | 16 +- src/shapes/src/HollowConicalFrustum.cpp | 4 +- .../utils/math/coordinate_transformation.hpp | 18 +- .../math/coordinate_transformation.hpp.orig | 171 ------------------ src/utils/tests/coordinate_transformation.cpp | 36 ++-- testsuite/python/lb_poiseuille_cylinder.py | 2 +- testsuite/python/observable_cylindrical.py | 49 ++--- testsuite/python/observable_cylindricalLB.py | 116 +++++++----- testsuite/python/tests_common.py | 49 ++--- 16 files changed, 179 insertions(+), 314 deletions(-) delete mode 100644 src/utils/include/utils/math/coordinate_transformation.hpp.orig diff --git a/src/core/grid_based_algorithms/lb_interface.cpp b/src/core/grid_based_algorithms/lb_interface.cpp index 67b7461dff1..3fabd382a99 100644 --- a/src/core/grid_based_algorithms/lb_interface.cpp +++ b/src/core/grid_based_algorithms/lb_interface.cpp @@ -1278,7 +1278,8 @@ double lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos) { auto const folded_pos = folded_position(pos, box_geo); auto const interpolation_order = lb_lbinterpolation_get_interpolation_order(); if (lattice_switch == ActiveLB::GPU) { - throw std::runtime_error("Density interpolation is not implemented for the GPU LB."); + throw std::runtime_error( + "Density interpolation is not implemented for the GPU LB."); } if (lattice_switch == ActiveLB::CPU) { switch (interpolation_order) { diff --git a/src/core/grid_based_algorithms/lb_interface.hpp b/src/core/grid_based_algorithms/lb_interface.hpp index 1661f1026be..9b831197a68 100644 --- a/src/core/grid_based_algorithms/lb_interface.hpp +++ b/src/core/grid_based_algorithms/lb_interface.hpp @@ -270,7 +270,6 @@ lb_lbfluid_get_interpolated_velocity(const Utils::Vector3d &pos); * @param pos Position at which the density is to be calculated. * @retval interpolated fluid density. */ -double -lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos); +double lb_lbfluid_get_interpolated_density(const Utils::Vector3d &pos); #endif diff --git a/src/core/grid_based_algorithms/lb_interpolation.cpp b/src/core/grid_based_algorithms/lb_interpolation.cpp index 5ed48e5be8b..dee4693944e 100644 --- a/src/core/grid_based_algorithms/lb_interpolation.cpp +++ b/src/core/grid_based_algorithms/lb_interpolation.cpp @@ -108,8 +108,7 @@ lb_lbinterpolation_get_interpolated_velocity(const Utils::Vector3d &pos) { return interpolated_u; } -double -lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &pos) { +double lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &pos) { double interpolated_dens; /* Calculate fluid density at the position. diff --git a/src/core/grid_based_algorithms/lb_interpolation.hpp b/src/core/grid_based_algorithms/lb_interpolation.hpp index dd33ebe8f16..28544afa9ef 100644 --- a/src/core/grid_based_algorithms/lb_interpolation.hpp +++ b/src/core/grid_based_algorithms/lb_interpolation.hpp @@ -46,8 +46,7 @@ lb_lbinterpolation_get_interpolated_velocity(const Utils::Vector3d &p); * lattice. * @note It can lead to undefined behaviour if the * position is not within the local lattice. */ -double -lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &p); +double lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &p); /** * @brief Add a force density to the fluid at the given position. diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index b20ba34b666..694cc94748c 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -42,18 +42,20 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( auto const pos = folded_position(traits.position(p), box_geo); auto const v = lb_lbfluid_get_interpolated_velocity(pos) * lb_lbfluid_get_lattice_speed(); - auto const flux_dens = lb_lbfluid_get_interpolated_density(pos)*v; + auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; - histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis, - orientation), - Utils::transform_vector_cartesian_to_cylinder(flux_dens, axis, pos - center)); + histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( + pos - center, axis, orientation), + Utils::transform_vector_cartesian_to_cylinder( + flux_dens, axis, pos - center)); } // normalize by number of hits per bin auto hist_tmp = histogram.get_histogram(); auto tot_count = histogram.get_tot_count(); - std::transform(hist_tmp.begin(),hist_tmp.end(),tot_count.begin(),hist_tmp.begin(),[](auto hi, auto ci){return ci>0 ? hi/ci : 0.;}); + std::transform(hist_tmp.begin(), hist_tmp.end(), tot_count.begin(), + hist_tmp.begin(), + [](auto hi, auto ci) { return ci > 0 ? hi / ci : 0.; }); return hist_tmp; } } // namespace Observables diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index 15477bf6a3f..c1c46fb90fc 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -49,7 +49,9 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( // normalize by number of hits per bin auto hist_tmp = histogram.get_histogram(); auto tot_count = histogram.get_tot_count(); - std::transform(hist_tmp.begin(),hist_tmp.end(),tot_count.begin(),hist_tmp.begin(),[](auto hi, auto ci){return ci>0 ? hi/ci : 0.;}); + std::transform(hist_tmp.begin(), hist_tmp.end(), tot_count.begin(), + hist_tmp.begin(), + [](auto hi, auto ci) { return ci > 0 ? hi / ci : 0.; }); return hist_tmp; } diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 99f720d5fa6..21eea82f677 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -84,7 +84,7 @@ def __init__(self, **kwargs): axis = np.asarray(kwargs["axis"]) for vec in try_vectors: proj = np.dot(vec, axis / np.linalg.norm(axis)) - if np.arccos(proj) > 10*sys.float_info.epsilon: + if np.arccos(proj) > 10 * sys.float_info.epsilon: vec -= proj * axis kwargs["orientation"] = vec / np.linalg.norm(vec) break diff --git a/src/shapes/include/shapes/HollowConicalFrustum.hpp b/src/shapes/include/shapes/HollowConicalFrustum.hpp index efe0bb17c2a..202e5e446cb 100644 --- a/src/shapes/include/shapes/HollowConicalFrustum.hpp +++ b/src/shapes/include/shapes/HollowConicalFrustum.hpp @@ -47,8 +47,9 @@ class HollowConicalFrustum : public Shape { public: HollowConicalFrustum() : m_r1(0.0), m_r2(0.0), m_length(0.0), m_thickness(0.0), - m_direction(1), m_center{Utils::Vector3d{}}, - m_axis{Utils::Vector3d{0, 0, 1}}, m_orientation{Utils::Vector3d {1.,0.,0.}} {} + m_direction(1), m_center{Utils::Vector3d{}}, m_axis{Utils::Vector3d{ + 0, 0, 1}}, + m_orientation{Utils::Vector3d{1., 0., 0.}} {} void set_r1(double const radius) { m_r1 = radius; } void set_r2(double const radius) { m_r2 = radius; } @@ -57,11 +58,12 @@ class HollowConicalFrustum : public Shape { void set_direction(int const dir) { m_direction = dir; } void set_axis(Utils::Vector3d const &axis) { m_axis = axis; - // Even though the HCF is cylinder-symmetric, it needs a well defined phi=0 orientation for the coordinate transformation. - // If the default orientation is too parallel to axis, choose again - if ((m_orientation - (m_orientation*m_axis)*m_axis).norm() < 0.01) { - m_orientation = Utils::Vector3d{{0.,1.,0.}}; - std::printf("changing orientation"); + // Even though the HCF is cylinder-symmetric, it needs a well defined phi=0 + // orientation for the coordinate transformation. If the default orientation + // is too parallel to axis, choose again + if ((m_orientation - (m_orientation * m_axis) * m_axis).norm() < 0.01) { + m_orientation = Utils::Vector3d{{0., 1., 0.}}; + std::printf("changing orientation"); } } void set_center(Utils::Vector3d const ¢er) { m_center = center; } diff --git a/src/shapes/src/HollowConicalFrustum.cpp b/src/shapes/src/HollowConicalFrustum.cpp index ceb3ae76883..ea384252cc4 100644 --- a/src/shapes/src/HollowConicalFrustum.cpp +++ b/src/shapes/src/HollowConicalFrustum.cpp @@ -34,8 +34,8 @@ void HollowConicalFrustum::calculate_dist(const Utils::Vector3d &pos, // transform given position to cylindrical coordinates in the reference frame // of the cone auto const v = pos - m_center; - auto const pos_cyl = - Utils::transform_coordinate_cartesian_to_cylinder(v, m_axis, m_orientation); + auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( + v, m_axis, m_orientation); // clang-format off /* * the following implementation is based on: diff --git a/src/utils/include/utils/math/coordinate_transformation.hpp b/src/utils/include/utils/math/coordinate_transformation.hpp index 7203f0da033..07f84265f8b 100644 --- a/src/utils/include/utils/math/coordinate_transformation.hpp +++ b/src/utils/include/utils/math/coordinate_transformation.hpp @@ -53,7 +53,8 @@ inline Vector3d basis_change(Vector3d const &b1, Vector3d const &b2, auto const M = Matrix{ {e_x[0], e_x[1], e_x[2]}, {e_y[0], e_y[1], e_y[2]}, - {e_z[0], e_z[1], e_z[2]}}.transposed(); + {e_z[0], e_z[1], + e_z[2]}}.transposed(); if (reverse) { return M * v; } @@ -90,10 +91,10 @@ transform_coordinate_cartesian_to_cylinder(Vector3d const &pos) { * which @f$ \phi = 0 @f$ */ inline Vector3d transform_coordinate_cartesian_to_cylinder( - Vector3d const &pos, Vector3d const &axis, - Vector3d const &orientation) { + Vector3d const &pos, Vector3d const &axis, Vector3d const &orientation) { // check that axis and orientation are orthogonal - assert(std::abs(axis*orientation)<5*std::numeric_limits::epsilon()); + assert(std::abs(axis * orientation) < + 5 * std::numeric_limits::epsilon()); auto const rotation_axis = vector_product(axis, orientation); auto const pos_t = basis_change(orientation, rotation_axis, axis, pos); return transform_coordinate_cartesian_to_cylinder(pos_t); @@ -130,10 +131,10 @@ transform_coordinate_cylinder_to_cartesian(Vector3d const &pos) { * which @f$ \phi = 0 @f$ */ inline Vector3d transform_coordinate_cylinder_to_cartesian( - Vector3d const &pos, Vector3d const &axis, - Vector3d const &orientation) { + Vector3d const &pos, Vector3d const &axis, Vector3d const &orientation) { // check that axis and orientation are orthogonal - assert(std::abs(axis*orientation)<5*std::numeric_limits::epsilon()); + assert(std::abs(axis * orientation) < + 5 * std::numeric_limits::epsilon()); auto const rotation_axis = vector_product(axis, orientation); auto const pos_t = transform_coordinate_cylinder_to_cartesian(pos); return basis_change(orientation, rotation_axis, axis, pos_t, true); @@ -153,7 +154,8 @@ inline Vector3d transform_vector_cartesian_to_cylinder(Vector3d const &vec, auto const rotation_axis = Utils::vector_product(axis, z_axis).normalize(); auto const rotated_pos = vec_rotate(rotation_axis, angle, pos); auto const rotated_vec = vec_rotate(rotation_axis, angle, vec); - auto const r = std::sqrt(rotated_pos[0]*rotated_pos[0]+rotated_pos[1]*rotated_pos[1]); + auto const r = std::sqrt(rotated_pos[0] * rotated_pos[0] + + rotated_pos[1] * rotated_pos[1]); // v_r = (x * v_x + y * v_y) / sqrt(x^2 + y^2) auto const v_r = (rotated_pos[0] * rotated_vec[0] + rotated_pos[1] * rotated_vec[1]) / r; diff --git a/src/utils/include/utils/math/coordinate_transformation.hpp.orig b/src/utils/include/utils/math/coordinate_transformation.hpp.orig deleted file mode 100644 index ac8fc4d10cc..00000000000 --- a/src/utils/include/utils/math/coordinate_transformation.hpp.orig +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2010-2019 The ESPResSo project - * - * This file is part of ESPResSo. - * - * ESPResSo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ESPResSo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef UTILS_COORDINATE_TRANSFORMATION_HPP -#define UTILS_COORDINATE_TRANSFORMATION_HPP - -/** - * @file - * Convert coordinates from the Cartesian system to the cylindrical system. - * The transformation functions are provided with three overloads: - * - one function for the trivial Cartesian <-> cylindrical transformation - * - one function to transform from/to a cylindrical system with custom axis - * (extra @p axis argument, keep in mind the angle phi is under-defined) - * - one function to transform from/to an oriented cylindrical system with - * custom axis (extra @p orientation argument, the angle phi is well-defined) - */ - -#include "utils/Vector.hpp" -#include "utils/constants.hpp" -#include "utils/math/vec_rotate.hpp" -#include "utils/matrix.hpp" -#include "utils/quaternion.hpp" - -#include - -namespace Utils { - -/** - * @brief Basis change. - */ -inline Vector3d basis_change(Vector3d const &b1, Vector3d const &b2, - Vector3d const &b3, Vector3d const &v, - bool reverse = false) { - auto const e_x = b1.normalized(); - auto const e_y = b2.normalized(); - auto const e_z = b3.normalized(); - Mat const M = Mat{ - {e_x[0], e_x[1], e_x[2]}, - {e_y[0], e_y[1], e_y[2]}, - {e_z[0], e_z[1], e_z[2]}}.transposed(); - if (reverse) { - return M * v; - } - return M.inversed() * v; -} - -/** - * @brief Coordinate transformation from Cartesian to cylindrical coordinates. - * The origins and z-axis of the coordinate systems co-incide. - * The @f$ \phi = 0 @f$ direction corresponds to the x-axis in the - * original coordinate system. - * @param pos %Vector to transform - */ -inline Vector3d -transform_coordinate_cartesian_to_cylinder(Vector3d const &pos) { - auto const r = std::sqrt(pos[0] * pos[0] + pos[1] * pos[1]); - auto const phi = std::atan2(pos[1], pos[0]); - return {r, phi, pos[2]}; -} - -/** - * @brief Coordinate transformation from Cartesian to cylindrical coordinates - * with change of basis. The origins of the coordinate systems co-incide. - * - * If the parameter @p axis is not equal to [0, 0, 1], the value - * of the angle @f$ \phi @f$ in cylindrical coordinates is under-defined. - * To fully define it, it is necessary to provide an orientation vector - * in Cartesian coordinates that will be used as the reference point - * (i.e. such that @f$ \phi = 0 @f$), by default it is the x-axis. - * - * @param pos %Vector to transform - * @param axis Longitudinal axis of the cylindrical coordinates - * @param orientation Reference point (in untransformed coordinates) for - * which @f$ \phi = 0 @f$ - */ -inline Vector3d transform_coordinate_cartesian_to_cylinder( - Vector3d const &pos, Vector3d const &axis, - Vector3d const &orientation = {{1, 0, 0}}) { - auto const rotation_axis = vector_product(axis, orientation); - auto const pos_t = basis_change(orientation, rotation_axis, axis, pos); - return transform_coordinate_cartesian_to_cylinder(pos_t); -} - -/** - * @brief Coordinate transformation from cylindrical to Cartesian coordinates. - * The origins and z-axis of the coordinate systems co-incide. - * The @f$ \phi = 0 @f$ direction corresponds to the x-axis in the - * transformed coordinate system. - * @param pos %Vector to transform - */ -inline Vector3d -transform_coordinate_cylinder_to_cartesian(Vector3d const &pos) { - auto const &rho = pos[0]; - auto const &phi = pos[1]; - auto const &z = pos[2]; - return {rho * std::cos(phi), rho * std::sin(phi), z}; -} - -/** - * @brief Coordinate transformation from cylindrical to Cartesian coordinates - * with change of basis. The origins of the coordinate systems co-incide. - * - * If the parameter @p axis is not equal to [0, 0, 1], the value - * of the angle @f$ \phi @f$ in cylindrical coordinates is under-defined. - * To fully define it, it is necessary to provide an orientation vector - * in Cartesian coordinates that will be used as the reference point - * (i.e. such that @f$ \phi = 0 @f$). - * - * @param pos %Vector to transform - * @param axis Longitudinal axis of the cylindrical coordinates - * @param orientation Reference point (in Cartesian coordinates) for - * which @f$ \phi = 0 @f$ - */ -inline Vector3d transform_coordinate_cylinder_to_cartesian( - Vector3d const &pos, Vector3d const &axis, - Vector3d const &orientation = {{1, 0, 0}}) { - auto const rotation_axis = vector_product(axis, orientation); - auto const pos_t = transform_coordinate_cylinder_to_cartesian(pos); - return basis_change(orientation, rotation_axis, axis, pos_t, true); -} - -/** - * @brief Vector transformation from Cartesian to cylindrical coordinates. - * @param vec %Vector to transform - * @param axis Longitudinal axis of the cylindrical coordinates - * @param pos Origin of the vector - */ -inline Vector3d transform_vector_cartesian_to_cylinder(Vector3d const &vec, - Vector3d const &axis, - Vector3d const &pos) { - static auto const z_axis = Vector3d{{0, 0, 1}}; -<<<<<<< HEAD - auto const angle = angle_between(axis, z_axis); - auto const rotation_axis = Utils::vector_product(axis, z_axis).normalize(); - auto const rotated_pos = vec_rotate(rotation_axis, angle, pos); - auto const rotated_vec = vec_rotate(rotation_axis, angle, vec); -======= - double theta; - Vector3d rotation_axis; - std::tie(theta, rotation_axis) = rotation_params(axis, z_axis); - auto const rotated_pos = vec_rotate(rotation_axis, theta, pos); - auto const rotated_vec = vec_rotate(rotation_axis, theta, vec); - auto const r = std::sqrt(rotated_pos[0] * rotated_pos[0] + - rotated_pos[1] * rotated_pos[1]); ->>>>>>> python - // v_r = (x * v_x + y * v_y) / sqrt(x^2 + y^2) - auto const v_r = - (rotated_pos[0] * rotated_vec[0] + rotated_pos[1] * rotated_vec[1]) / r; - // v_phi = (x * v_y - y * v_x ) / sqrt(x^2 + y^2) - auto const v_phi = - (rotated_pos[0] * rotated_vec[1] - rotated_pos[1] * rotated_vec[0]) / r; - return Vector3d{v_r, v_phi, rotated_vec[2]}; -} - -} // namespace Utils -#endif diff --git a/src/utils/tests/coordinate_transformation.cpp b/src/utils/tests/coordinate_transformation.cpp index 1b9cbb71b44..e70709718b6 100644 --- a/src/utils/tests/coordinate_transformation.cpp +++ b/src/utils/tests/coordinate_transformation.cpp @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(cartesian_to_cylinder_with_axis_and_orientation_test) { // tilted orthogonal basis auto const y = (Vector3d{{0, 1, -1}}).normalize(); auto const z = (Vector3d{{1, 1, 1}}).normalize(); - auto const x = Utils::vector_product(y,z); + auto const x = Utils::vector_product(y, z); // check transformation with orientation (phi is random for r=0) { @@ -156,26 +156,24 @@ BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_test) { BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_and_orientation_test) { constexpr auto eps = 2e-14; Vector3d const cylinder_coord{{1.2, 3.123, 42.0}}; - auto const e_x = Vector3d{{1.,0.,0.}}; - auto const e_y = Vector3d{{0.,1.,0.}}; - auto const e_z = Vector3d{{0.,0.,1.}}; + auto const e_x = Vector3d{{1., 0., 0.}}; + auto const e_y = Vector3d{{0., 1., 0.}}; + auto const e_z = Vector3d{{0., 0., 1.}}; - auto const transformed_x = transform_coordinate_cylinder_to_cartesian( - cylinder_coord, e_x, -e_z ); - auto const transformed_y = transform_coordinate_cylinder_to_cartesian( - cylinder_coord, e_y, e_x ); - auto const transformed_z = transform_coordinate_cylinder_to_cartesian( - cylinder_coord, e_z, e_x); + auto const transformed_x = + transform_coordinate_cylinder_to_cartesian(cylinder_coord, e_x, -e_z); + auto const transformed_y = + transform_coordinate_cylinder_to_cartesian(cylinder_coord, e_y, e_x); + auto const transformed_z = + transform_coordinate_cylinder_to_cartesian(cylinder_coord, e_z, e_x); // We transform from cylinder zu cartesian and have to rotate back. See test // cartesian_to_cylinder_test. - auto const expected_x = - vec_rotate(e_y, Utils::pi() / 2.0, - transform_coordinate_cylinder_to_cartesian( - cylinder_coord, e_z, e_x)); - auto const expected_y = - vec_rotate(e_x, -Utils::pi() / 2.0, - transform_coordinate_cylinder_to_cartesian( - cylinder_coord, e_z, e_x)); + auto const expected_x = vec_rotate( + e_y, Utils::pi() / 2.0, + transform_coordinate_cylinder_to_cartesian(cylinder_coord, e_z, e_x)); + auto const expected_y = vec_rotate( + e_x, -Utils::pi() / 2.0, + transform_coordinate_cylinder_to_cartesian(cylinder_coord, e_z, e_x)); // x = r * cos(phi); y = r * sin(phi); z = z auto const expected_z = Vector3d{ {cylinder_coord[0] * std::cos(cylinder_coord[1]), @@ -192,7 +190,7 @@ BOOST_AUTO_TEST_CASE(cylinder_to_cartesian_with_axis_with_phi_2_test) { // tilted orthogonal basis auto const y = (Vector3d{{0, 1, -1}}).normalize(); auto const z = (Vector3d{{1, 1, 1}}).normalize(); - auto const x = Utils::vector_product(y,z); + auto const x = Utils::vector_product(y, z); // check transformation with orientation { diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index 96387fde624..e58f1a7c6c3 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -82,7 +82,7 @@ class LBPoiseuilleCommon: system.time_step = TIME_STEP system.cell_system.skin = 0.4 * AGRID params = {'axis': [0, 0, 1], - 'orientation' : [1,0,0]} + 'orientation': [1, 0, 0]} def prepare(self): """ diff --git a/testsuite/python/observable_cylindrical.py b/testsuite/python/observable_cylindrical.py index 99d528462ed..4d123aff767 100644 --- a/testsuite/python/observable_cylindrical.py +++ b/testsuite/python/observable_cylindrical.py @@ -32,7 +32,7 @@ class TestCylindricalObservable(ut.TestCase): system.cell_system.skin = 0.4 params = { - 'ids': list(range(100)), + 'ids': None, 'center': 3 * [7.5], 'axis': [np.sqrt(2), np.sqrt(2), 0], 'orientation': [0, 0, 1], @@ -54,13 +54,14 @@ class TestCylindricalObservable(ut.TestCase): def tearDown(self): self.system.part.clear() - def calc_ellipsis_pos_vel(self, n_part, z_min, z_max, semi_x=1., semi_y=1.): + def calc_ellipsis_pos_vel( + self, n_part, z_min, z_max, semi_x=1., semi_y=1.): """ Calculate positions on an elliptical corkscrew line. Calculate cartesian velocities that lead to a constant velocity in cylindrical coordinates """ - + zs = np.linspace(z_min, z_max, num=n_part) - angles = np.linspace(-0.99*np.pi, 0.999 * np.pi, num=n_part) + angles = np.linspace(-0.99 * np.pi, 0.999 * np.pi, num=n_part) positions = [] velocities = [] @@ -70,26 +71,27 @@ def calc_ellipsis_pos_vel(self, n_part, z_min, z_max, semi_x=1., semi_y=1.): [semi_x * np.cos(angle), semi_y * np.sin(angle), z]) - - e_r,e_phi,e_z = tests_common.get_cylindrical_basis_vectors(position) + + e_r, e_phi, e_z = tests_common.get_cylindrical_basis_vectors( + position) velocity = self.v_r * e_r + self.v_phi * e_phi + self.v_z * e_z positions.append(position) velocities.append(velocity) return np.array(positions), np.array(velocities) - + def align_with_observable_frame(self, vec): """ Rotate vectors from the original box frame to the frame of the observables. """ - + # align original z to observable z - vec = tests_common.rodrigues_rot(vec,[1,-1,0],-np.pi/2.) + vec = tests_common.rodrigues_rot(vec, [1, -1, 0], -np.pi / 2.) # original x now points along [sqrt(3),-sqrt(3),-sqrt(3)] # align original x to observable orientation - vec =tests_common.rodrigues_rot(vec,[1,1,0],-3./4.*np.pi) + vec = tests_common.rodrigues_rot(vec, [1, 1, 0], -3. / 4. * np.pi) return vec def setup_system_get_np_hist(self): @@ -97,9 +99,12 @@ def setup_system_get_np_hist(self): Pick positions and velocities in the original box frame and calculate the np histogram. Then rotate and move the positions and velocities to the frame of the observables. After calculating the core observables, the result should be the same as the np histogram obtained from the original box frame. """ - - positions, velocities = self.calc_ellipsis_pos_vel(len( - self.params['ids']), 0.99 * self.params['min_z'], 0.9 * self.params['max_z'], semi_x= 0.9 * self.params['max_r'], semi_y= 0.2 * self.params['max_r']) + + positions, velocities = self.calc_ellipsis_pos_vel(100, 0.99 * + self.params['min_z'], 0.9 * + self.params['max_z'], semi_x=0.9 * + self.params['max_r'], semi_y=0.2 * + self.params['max_r']) # first, get the numpy histogram of the cylinder coordinates pos_cyl = [] @@ -108,7 +113,8 @@ def setup_system_get_np_hist(self): tests_common.transform_pos_from_cartesian_to_polar_coordinates(pos)) np_hist, np_edges = tests_common.get_histogram( np.array(pos_cyl), self.params, 'cylindrical') - np_dens = tests_common.normalize_cylindrical_hist(np_hist.copy(), self.params) + np_dens = tests_common.normalize_cylindrical_hist( + np_hist.copy(), self.params) # now align the positions and velocities with the frame of reference # used in the observables @@ -120,14 +126,15 @@ def setup_system_get_np_hist(self): self.params['center']) vel_aligned.append(self.align_with_observable_frame(vel)) self.system.part.add(pos=pos_aligned, v=vel_aligned) - + self.params['ids'] = self.system.part[:].id + return np_dens, np_edges - - def check_edges(self,observable, np_edges): + + def check_edges(self, observable, np_edges): core_edges = observable.call_method("edges") for core_edge, np_edge in zip(core_edges, np_edges): np.testing.assert_array_almost_equal(core_edge, np_edge) - + def test_density_profile(self): """ Check that the result from the observable (in its own frame) matches the np result from the box frame @@ -138,7 +145,7 @@ def test_density_profile(self): **self.params) core_hist = cyl_dens_prof.calculate() np.testing.assert_array_almost_equal(np_dens, core_hist) - self.check_edges(cyl_dens_prof,np_edges) + self.check_edges(cyl_dens_prof, np_edges) def test_vel_profile(self): """ @@ -159,7 +166,7 @@ def test_vel_profile(self): np_hist_binary * self.v_phi, core_hist_v_phi) np.testing.assert_array_almost_equal( np_hist_binary * self.v_z, core_hist_v_z) - self.check_edges(cyl_vel_prof,np_edges) + self.check_edges(cyl_vel_prof, np_edges) def test_flux_density_profile(self): """ @@ -176,7 +183,7 @@ def test_flux_density_profile(self): np.testing.assert_array_almost_equal( np_dens * self.v_phi, core_hist_v_phi) np.testing.assert_array_almost_equal(np_dens * self.v_z, core_hist_v_z) - self.check_edges(cyl_flux_dens,np_edges) + self.check_edges(cyl_flux_dens, np_edges) def test_cylindrical_pid_profile_interface(self): """ diff --git a/testsuite/python/observable_cylindricalLB.py b/testsuite/python/observable_cylindricalLB.py index d6c2ddae8a5..c8b67afd2e5 100644 --- a/testsuite/python/observable_cylindricalLB.py +++ b/testsuite/python/observable_cylindricalLB.py @@ -22,6 +22,7 @@ import espressomd.lb import tests_common + class CylindricalLBObservableCommon: """ @@ -29,21 +30,21 @@ class CylindricalLBObservableCommon: """ lbf = None - system = espressomd.System(box_l=3*[15]) + system = espressomd.System(box_l=3 * [15]) system.time_step = 0.01 system.cell_system.skin = 0.4 positions = [] lb_params = {'agrid': 1., - 'dens': 1.2, - 'visc': 2.7, - 'tau': 0.1, - } + 'dens': 1.2, + 'visc': 2.7, + 'tau': 0.1, + } params = { - 'ids': list(range(9)), - 'center': 3*[7], - 'axis': [1,0,0], - 'orientation' : [0,0,1], + 'ids': None, + 'center': 3 * [7], + 'axis': [1, 0, 0], + 'orientation': [0, 0, 1], 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 5, @@ -54,46 +55,47 @@ class CylindricalLBObservableCommon: 'max_phi': np.pi, 'max_z': 6.0, } - + v_r = 0.02 v_phi = 0.04 v_z = 0.03 - + def calc_vel_at_pos(self, positions): """ In cylinde coordinates, all velocities are the same. In cartesian they depend on the position. The cartesian velocities are calculated here. """ - + vels = [] for pos in positions: - e_r,e_phi,e_z = tests_common.get_cylindrical_basis_vectors(pos) + e_r, e_phi, e_z = tests_common.get_cylindrical_basis_vectors(pos) velocity = self.v_r * e_r + self.v_phi * e_phi + self.v_z * e_z vels.append(velocity) return vels - + def align_with_observable_frame(self, vec): """ Rotate vectors from the original box frame to the frame of the observables. """ - + # align original z to observable z - vec = tests_common.rodrigues_rot(vec, [0,1,0], np.pi/2.) + vec = tests_common.rodrigues_rot(vec, [0, 1, 0], np.pi / 2.) # original x now points along [0,0,-1] # align original x to observable orientation - vec = tests_common.rodrigues_rot(vec,[1,0,0],np.pi) + vec = tests_common.rodrigues_rot(vec, [1, 0, 0], np.pi) return vec - + def setup_system_get_np_hist(self): """ Pick positions and velocities in the original box frame and calculate the np histogram. Then rotate and move the positions and velocities to the frame of the observables. After calculating the core observables, the result should be the same as the np histogram obtained from the original box frame. """ - - nodes = np.array(np.meshgrid([1,2], [1,2], [1,1,1,1,2])).T.reshape(-1,3) - positions = nodes+3*[0.5] + + nodes = np.array(np.meshgrid([1, 2], [1, 2], [ + 1, 1, 1, 1, 2])).T.reshape(-1, 3) + positions = nodes + 3 * [0.5] velocities = self.calc_vel_at_pos(positions) - + # get the histogram from numpy pos_cyl = [] for pos in positions: @@ -101,10 +103,11 @@ def setup_system_get_np_hist(self): tests_common.transform_pos_from_cartesian_to_polar_coordinates(pos)) np_hist, np_edges = tests_common.get_histogram( np.array(pos_cyl), self.params, 'cylindrical') - - # the particles only determine the evaluation points, not the values of the observables + + # the particles only determine the evaluation points, not the values of + # the observables np_hist[np.nonzero(np_hist)] = 1 - + # now align the positions and velocities with the frame of reference # used in the observables pos_aligned = [] @@ -114,41 +117,50 @@ def setup_system_get_np_hist(self): self.align_with_observable_frame(pos) + self.params['center']) vel_aligned.append(self.align_with_observable_frame(vel)) - node_aligned= np.array(np.rint( np.array(pos_aligned)-3*[0.5]) , dtype = int) - self.system.part.add(pos=pos_aligned, v = vel_aligned) - - for node,vel in zip(node_aligned, vel_aligned): - self.lbf[node].velocity=vel - + node_aligned = np.array( + np.rint( + np.array(pos_aligned) - + 3 * + [0.5]), + dtype=int) + self.system.part.add(pos=pos_aligned, v=vel_aligned) + self.params['ids'] = self.system.part[:].id + + for node, vel in zip(node_aligned, vel_aligned): + self.lbf[node].velocity = vel + return np_hist, np_edges - - def check_edges(self,observable, np_edges): + + def check_edges(self, observable, np_edges): core_edges = observable.call_method("edges") for core_edge, np_edge in zip(core_edges, np_edges): np.testing.assert_array_almost_equal(core_edge, np_edge) - + def test_cylindrical_lb_vel_profile_obs(self): """ Check that the result from the observable (in its own frame) matches the np result from the box frame """ - + np_hist_binary, np_edges = self.setup_system_get_np_hist() - vel_obs = espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions(**self.params) + vel_obs = espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions( + **self.params) core_hist_v = vel_obs.calculate() core_hist_v_r = core_hist_v[:, :, :, 0] core_hist_v_phi = core_hist_v[:, :, :, 1] core_hist_v_z = core_hist_v[:, :, :, 2] - np.testing.assert_array_almost_equal(np_hist_binary * self.v_r, core_hist_v_r) - np.testing.assert_array_almost_equal(np_hist_binary * self.v_phi, core_hist_v_phi) - np.testing.assert_array_almost_equal(np_hist_binary * self.v_z, core_hist_v_z) + np.testing.assert_array_almost_equal( + np_hist_binary * self.v_r, core_hist_v_r) + np.testing.assert_array_almost_equal( + np_hist_binary * self.v_phi, core_hist_v_phi) + np.testing.assert_array_almost_equal( + np_hist_binary * self.v_z, core_hist_v_z) self.check_edges(vel_obs, np_edges) - def test_cylindrical_lb_profile_interface(self): """ Test setters and getters of the script interface """ - + params = self.params.copy() params['n_r_bins'] = 4 params['n_phi_bins'] = 6 @@ -228,20 +240,32 @@ def test_cylindrical_lb_flux_density_obs(self): Only for CPU because density interpolation is not implemented for GPU LB. """ np_hist_binary, np_edges = self.setup_system_get_np_hist() - + flux_obs = espressomd.observables.CylindricalLBFluxDensityProfileAtParticlePositions( **self.params) core_hist_fl = flux_obs.calculate() core_hist_fl_r = core_hist_fl[:, :, :, 0] core_hist_fl_phi = core_hist_fl[:, :, :, 1] core_hist_fl_z = core_hist_fl[:, :, :, 2] - core_edges_fl = flux_obs.call_method("edges") - np.testing.assert_array_almost_equal(np_hist_binary*self.lb_params['dens'] * self.v_r, core_hist_fl_r) - np.testing.assert_array_almost_equal(np_hist_binary * self.lb_params['dens'] * self.v_phi, core_hist_fl_phi) - np.testing.assert_array_almost_equal(np_hist_binary * self.lb_params['dens'] * self.v_z, core_hist_fl_z) + np.testing.assert_array_almost_equal( + np_hist_binary * + self.lb_params['dens'] * + self.v_r, + core_hist_fl_r) + np.testing.assert_array_almost_equal( + np_hist_binary * + self.lb_params['dens'] * + self.v_phi, + core_hist_fl_phi) + np.testing.assert_array_almost_equal( + np_hist_binary * + self.lb_params['dens'] * + self.v_z, + core_hist_fl_z) self.check_edges(flux_obs, np_edges) + @utx.skipIfMissingGPU() class CylindricalLBObservableGPU(ut.TestCase, CylindricalLBObservableCommon): diff --git a/testsuite/python/tests_common.py b/testsuite/python/tests_common.py index e7ed9ab3f9d..450718ad76f 100644 --- a/testsuite/python/tests_common.py +++ b/testsuite/python/tests_common.py @@ -132,6 +132,7 @@ def verify_lj_forces(system, tolerance, ids_to_skip=()): def abspath(path): return os.path.join(os.path.dirname(os.path.abspath(__file__)), path) + def transform_pos_from_cartesian_to_polar_coordinates(pos): """Transform the given cartesian coordinates to cylindrical coordinates. @@ -165,23 +166,28 @@ def transform_vel_from_cartesian_to_polar_coordinates(pos, vel): (pos[0] * vel[0] + pos[1] * vel[1]) / np.sqrt(pos[0]**2 + pos[1]**2), (pos[0] * vel[1] - pos[1] * vel[0]) / np.sqrt(pos[0]**2 + pos[1]**2), vel[2]]) + def get_cylindrical_basis_vectors(pos): phi = transform_pos_from_cartesian_to_polar_coordinates(pos)[1] - e_r = np.array([np.cos(phi), np.sin(phi),0.]) - e_phi = np.array([-np.sin(phi), np.cos(phi),0.]) - e_z = np.array([0.,0.,1.]) + e_r = np.array([np.cos(phi), np.sin(phi), 0.]) + e_phi = np.array([-np.sin(phi), np.cos(phi), 0.]) + e_z = np.array([0., 0., 1.]) return e_r, e_phi, e_z + def convert_vec_body_to_space(system, part, vec): A = rotation_matrix_quat(system, part) return np.dot(A.transpose(), vec) + def rodrigues_rot(vec, axis, angle): """ https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula#Statement """ - axis/=np.linalg.norm(axis) - return np.cos(angle)*vec + np.sin(angle)*np.cross(axis,vec)+(1-np.cos(angle))*np.dot(axis,vec)*axis + axis /= np.linalg.norm(axis) + return np.cos(angle) * vec + np.sin(angle) * np.cross(axis, + vec) + (1 - np.cos(angle)) * np.dot(axis, vec) * axis + def rotation_matrix(axis, theta): """ @@ -235,11 +241,12 @@ def rotation_matrix_quat(system, part): return A + def normalize_cylindrical_hist(histogram, cyl_obs_params): """ normalize a histogram in cylindrical coordinates. Helper to test the output of cylindrical histogram observables - + Parameters ---------- histogram : (N,3) array_like of :obj:`float` @@ -248,29 +255,30 @@ def normalize_cylindrical_hist(histogram, cyl_obs_params): A dictionary containing the common parameters of the cylindrical histogram observables. Needs to contain the information about number and range of bins. """ - + n_r_bins = cyl_obs_params['n_r_bins'] - n_phi_bins =cyl_obs_params['n_phi_bins'] - n_z_bins =cyl_obs_params['n_z_bins'] - min_r =cyl_obs_params['min_r'] - max_r =cyl_obs_params['max_r'] - min_phi =cyl_obs_params['min_phi'] - max_phi =cyl_obs_params['max_phi'] - min_z =cyl_obs_params['min_z'] - max_z =cyl_obs_params['max_z'] - + n_phi_bins = cyl_obs_params['n_phi_bins'] + n_z_bins = cyl_obs_params['n_z_bins'] + min_r = cyl_obs_params['min_r'] + max_r = cyl_obs_params['max_r'] + min_phi = cyl_obs_params['min_phi'] + max_phi = cyl_obs_params['max_phi'] + min_z = cyl_obs_params['min_z'] + max_z = cyl_obs_params['max_z'] + bin_volume = np.zeros(n_r_bins) r_bin_size = (max_r - min_r) / n_r_bins phi_bin_size = (max_phi - min_phi) / n_phi_bins z_bin_size = (max_z - min_z) / n_z_bins for i in range(n_r_bins): bin_volume = np.pi * ((min_r + r_bin_size * (i + 1))**2.0 - - (min_r + r_bin_size * i)**2.0) * \ + (min_r + r_bin_size * i)**2.0) * \ phi_bin_size / (2.0 * np.pi) * z_bin_size histogram[i, :, :] /= bin_volume return histogram + def get_histogram(pos, obs_params, coord_system, **kwargs): """ Helper function for ``np.histogramdd()`` and observables. @@ -633,13 +641,6 @@ def gay_berne_potential(r_ij, u_i, u_j, epsilon_0, sigma_0, mu, nu, k_1, k_2): return 4. * epsilon * (rr**-12 - rr**-6) -class DynamicDict(dict): - - def __getitem__(self, key): - value = super().__getitem__(key) - return eval(value, self) if isinstance(value, str) else value - - def count_fluid_nodes(lbf): """Counts the non-boundary nodes in the passed lb fluid instance.""" From a0bb5c481ee251e06452c087e5ff440f8838d293 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Thu, 18 Feb 2021 12:43:30 +0100 Subject: [PATCH 13/31] fix undefined behaviour in density interpolation, remove debug clutter --- src/core/grid_based_algorithms/lb_interpolation.cpp | 2 +- src/shapes/include/shapes/HollowConicalFrustum.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/grid_based_algorithms/lb_interpolation.cpp b/src/core/grid_based_algorithms/lb_interpolation.cpp index dee4693944e..d0db33f33ae 100644 --- a/src/core/grid_based_algorithms/lb_interpolation.cpp +++ b/src/core/grid_based_algorithms/lb_interpolation.cpp @@ -109,7 +109,7 @@ lb_lbinterpolation_get_interpolated_velocity(const Utils::Vector3d &pos) { } double lb_lbinterpolation_get_interpolated_density(const Utils::Vector3d &pos) { - double interpolated_dens; + double interpolated_dens = 0.; /* Calculate fluid density at the position. This is done by linear interpolation (eq. (11) @cite ahlrichs99a) */ diff --git a/src/shapes/include/shapes/HollowConicalFrustum.hpp b/src/shapes/include/shapes/HollowConicalFrustum.hpp index 202e5e446cb..43a4ce6a49b 100644 --- a/src/shapes/include/shapes/HollowConicalFrustum.hpp +++ b/src/shapes/include/shapes/HollowConicalFrustum.hpp @@ -63,7 +63,6 @@ class HollowConicalFrustum : public Shape { // is too parallel to axis, choose again if ((m_orientation - (m_orientation * m_axis) * m_axis).norm() < 0.01) { m_orientation = Utils::Vector3d{{0., 1., 0.}}; - std::printf("changing orientation"); } } void set_center(Utils::Vector3d const ¢er) { m_center = center; } From 74505cd2ce400c587b35acf0480e5c50c6d6f384 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Thu, 18 Feb 2021 17:54:16 +0100 Subject: [PATCH 14/31] better handling for default orientations --- src/python/espressomd/observables.py | 9 ++++----- .../include/shapes/HollowConicalFrustum.hpp | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 21eea82f677..b503aa70104 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -16,7 +16,6 @@ # along with this program. If not, see . import itertools import numpy as np -import sys from .script_interface import ScriptInterfaceHelper, script_interface_register @@ -83,10 +82,10 @@ def __init__(self, **kwargs): try_vectors = [np.array([1., 0., 0.]), np.array([0., 0., 1.])] axis = np.asarray(kwargs["axis"]) for vec in try_vectors: - proj = np.dot(vec, axis / np.linalg.norm(axis)) - if np.arccos(proj) > 10 * sys.float_info.epsilon: - vec -= proj * axis - kwargs["orientation"] = vec / np.linalg.norm(vec) + orthogonal_component = vec - np.dot(vec, axis) * axis + norm = np.linalg.norm(orthogonal_component) + if norm > 0.01: + kwargs["orientation"] = orthogonal_component / norm break super().__init__(**kwargs) diff --git a/src/shapes/include/shapes/HollowConicalFrustum.hpp b/src/shapes/include/shapes/HollowConicalFrustum.hpp index 43a4ce6a49b..2e9714aa49d 100644 --- a/src/shapes/include/shapes/HollowConicalFrustum.hpp +++ b/src/shapes/include/shapes/HollowConicalFrustum.hpp @@ -23,6 +23,8 @@ #include "Shape.hpp" #include +#include + namespace Shapes { /** @@ -59,10 +61,17 @@ class HollowConicalFrustum : public Shape { void set_axis(Utils::Vector3d const &axis) { m_axis = axis; // Even though the HCF is cylinder-symmetric, it needs a well defined phi=0 - // orientation for the coordinate transformation. If the default orientation - // is too parallel to axis, choose again - if ((m_orientation - (m_orientation * m_axis) * m_axis).norm() < 0.01) { - m_orientation = Utils::Vector3d{{0., 1., 0.}}; + // orientation for the coordinate transformation. + // We need to try two different vectors in case one is parallel to axis. + std::list try_vectors = {Utils::Vector3d{{1., 0., 0.}}, + Utils::Vector3d{{0., 1., 0.}}}; + for (auto vec : try_vectors) { + auto orth_component = vec - (vec * axis) * axis; + auto norm = orth_component.norm(); + if (norm > 0.01) { + m_orientation = orth_component / norm; + break; + } } } void set_center(Utils::Vector3d const ¢er) { m_center = center; } From 9a00b4d770c473f19bf409df5558032ed4e8fa1a Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 19 Feb 2021 16:55:54 +0100 Subject: [PATCH 15/31] separate and test orthonormal vector generation --- .../include/shapes/HollowConicalFrustum.hpp | 15 ++---- .../include/utils/math/orthonormal_vec.hpp | 54 +++++++++++++++++++ src/utils/tests/CMakeLists.txt | 2 + src/utils/tests/orthonormal_vec_test.cpp | 39 ++++++++++++++ 4 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 src/utils/include/utils/math/orthonormal_vec.hpp create mode 100644 src/utils/tests/orthonormal_vec_test.cpp diff --git a/src/shapes/include/shapes/HollowConicalFrustum.hpp b/src/shapes/include/shapes/HollowConicalFrustum.hpp index 2e9714aa49d..1deb0d98f2e 100644 --- a/src/shapes/include/shapes/HollowConicalFrustum.hpp +++ b/src/shapes/include/shapes/HollowConicalFrustum.hpp @@ -22,6 +22,7 @@ #include "Shape.hpp" #include +#include #include @@ -50,7 +51,7 @@ class HollowConicalFrustum : public Shape { HollowConicalFrustum() : m_r1(0.0), m_r2(0.0), m_length(0.0), m_thickness(0.0), m_direction(1), m_center{Utils::Vector3d{}}, m_axis{Utils::Vector3d{ - 0, 0, 1}}, + 0., 0., 1.}}, m_orientation{Utils::Vector3d{1., 0., 0.}} {} void set_r1(double const radius) { m_r1 = radius; } @@ -62,17 +63,7 @@ class HollowConicalFrustum : public Shape { m_axis = axis; // Even though the HCF is cylinder-symmetric, it needs a well defined phi=0 // orientation for the coordinate transformation. - // We need to try two different vectors in case one is parallel to axis. - std::list try_vectors = {Utils::Vector3d{{1., 0., 0.}}, - Utils::Vector3d{{0., 1., 0.}}}; - for (auto vec : try_vectors) { - auto orth_component = vec - (vec * axis) * axis; - auto norm = orth_component.norm(); - if (norm > 0.01) { - m_orientation = orth_component / norm; - break; - } - } + m_orientation = Utils::calc_orthonormal_vector(axis); } void set_center(Utils::Vector3d const ¢er) { m_center = center; } diff --git a/src/utils/include/utils/math/orthonormal_vec.hpp b/src/utils/include/utils/math/orthonormal_vec.hpp new file mode 100644 index 00000000000..57f2637fab4 --- /dev/null +++ b/src/utils/include/utils/math/orthonormal_vec.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010-2019 The ESPResSo project + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef ESPRESSO_ORTHONORMAL_VEC_HPP +#define ESPRESSO_ORTHONORMAL_VEC_HPP + +#include "utils/Vector.hpp" +#include "utils/constants.hpp" + +namespace Utils { +/** + * @brief Return a vector that is orthonormal to vec + */ +template +Vector calc_orthonormal_vector(Vector const &vec) { + /* Calculate orthonormal vector using Gram-Schmidt orthogonalization of a + trial vector. Only works if the trial vector is not parallel, so we have to + try a second one in that case + */ + Vector, 2> try_vectors = {Vector::broadcast(0), + Vector::broadcast(0)}; + try_vectors[0][0] = 1; + try_vectors[1][1] = 1; + + Vector ret; + for (auto v : try_vectors) { + auto orth_component = v - (v * vec) / vec.norm2() * vec; + auto norm = orth_component.norm(); + if (norm >= 1. / Utils::sqrt_2()) { + ret = orth_component / norm; + break; + } + } + return ret; +} + +} // namespace Utils + +#endif // ESPRESSO_ORTHONORMAL_VEC_HPP \ No newline at end of file diff --git a/src/utils/tests/CMakeLists.txt b/src/utils/tests/CMakeLists.txt index 90508ce2539..a230d4b84ba 100644 --- a/src/utils/tests/CMakeLists.txt +++ b/src/utils/tests/CMakeLists.txt @@ -78,3 +78,5 @@ unit_test(NAME sendrecv_test SRC sendrecv_test.cpp DEPENDS EspressoUtils Boost::mpi MPI::MPI_CXX EspressoUtils NUM_PROC 3) unit_test(NAME matrix_test SRC matrix_test.cpp DEPENDS EspressoUtils Boost::serialization NUM_PROC 1) +unit_test(NAME orthonormal_vec_test SRC orthonormal_vec_test.cpp DEPENDS + EspressoUtils Boost::serialization NUM_PROC 1) diff --git a/src/utils/tests/orthonormal_vec_test.cpp b/src/utils/tests/orthonormal_vec_test.cpp new file mode 100644 index 00000000000..51f9679dfe2 --- /dev/null +++ b/src/utils/tests/orthonormal_vec_test.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 The ESPResSo project + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define BOOST_TEST_MODULE Utils::orthonormal_vec test +#define BOOST_TEST_DYN_LINK +#include + +#include +#include + +BOOST_AUTO_TEST_CASE(orthonormal_vec_test) { + constexpr auto eps = 1e-14; + + auto const v0 = Utils::Vector3d{{1.1, -2.2, 3.3}}; + auto v0_orth = Utils::calc_orthonormal_vector(v0); + BOOST_CHECK_SMALL(v0 * v0_orth, eps); + BOOST_CHECK_SMALL(1 - v0_orth.norm(), eps); + + auto const v1 = Utils::VectorXd<2>{{1., 0.}}; + auto v1_orth = Utils::calc_orthonormal_vector(v1); + BOOST_CHECK_SMALL(v1 * v1_orth, eps); + BOOST_CHECK_SMALL(1 - v1_orth.norm(), eps); +} \ No newline at end of file From d4c5b9b5030c1cbb960786680eb3e67979114243 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 15:00:20 +0100 Subject: [PATCH 16/31] add cyltrafoparams class --- .../include/utils/math/cyl_trafo_params.hpp | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/utils/include/utils/math/cyl_trafo_params.hpp diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cyl_trafo_params.hpp new file mode 100644 index 00000000000..bc2ea41d23c --- /dev/null +++ b/src/utils/include/utils/math/cyl_trafo_params.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010-2019 The ESPResSo project + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP +#define ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP + +namespace Utils { + +class CylTrafoParams { +public: + CylTrafoParams(Utils::Vector3d const ¢er = Utils::Vector3d{{0,0,0}}, + Utils::Vector3d const &axis = Utils::Vector3d{{0,0,1}}, + Utils::Vector3d const &orientation = Utils::Vector3d{{1,0,0}}) + : m_center(center), m_axis(axis), m_orientation(orientation){ + check_valid(); + } + + Utils::Vector3d get_center() const {return m_center;} + Utils::Vector3d get_axis() const {return m_axis;} + Utils::Vector3d get_orientation() const {return m_orientation;} + +private: + void check_valid(){ + auto const eps = std::numeric_limits::epsilon(); + if (Utils::abs(m_center * m_axis) > eps){ + throw std::runtime_error("cylinder transformation: axis and orientation must be orthogonal"); + } + if (Utils::abs(m_axis.norm() -1) > eps){ + throw std::runtime_error("cylinder transformation: axis must be normalized"); + } + if (Utils::abs(m_orientation.norm() -1) > eps){ + throw std::runtime_error("cylinder transformation: orientation must be normalized"); + } + } + + Utils::Vector3d m_center; + Utils::Vector3d m_axis; + Utils::Vector3d m_orientation; +}; + +} // namespace Utils + +#endif // ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP \ No newline at end of file From 0fd837f94a11c1bbf56de17817a9453be94b9217 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 17:23:25 +0100 Subject: [PATCH 17/31] cyltrafoparams as a standalone class --- src/python/espressomd/math.py | 5 ++ src/script_interface/CylTrafoParams.hpp | 52 +++++++++++++++++++ src/script_interface/initialize.cpp | 2 + .../include/utils/math/cyl_trafo_params.hpp | 14 +++-- 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 src/python/espressomd/math.py create mode 100644 src/script_interface/CylTrafoParams.hpp diff --git a/src/python/espressomd/math.py b/src/python/espressomd/math.py new file mode 100644 index 00000000000..38180ce6e5b --- /dev/null +++ b/src/python/espressomd/math.py @@ -0,0 +1,5 @@ +from .script_interface import ScriptInterfaceHelper, script_interface_register + +@script_interface_register +class CylTrafoParams(ScriptInterfaceHelper): + _so_name = "CylTrafoParams" diff --git a/src/script_interface/CylTrafoParams.hpp b/src/script_interface/CylTrafoParams.hpp new file mode 100644 index 00000000000..456a7d61c9b --- /dev/null +++ b/src/script_interface/CylTrafoParams.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010-2019 The ESPResSo project + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + * Max-Planck-Institute for Polymer Research, Theory Group + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SCRIPT_INTERFACE_CYL_TRAFO_PARAMS_HPP +#define SCRIPT_INTERFACE_CYL_TRAFO_PARAMS_HPP + +#include "script_interface/ScriptInterface.hpp" + +#include "utils/math/cyl_trafo_params.hpp" + +namespace ScriptInterface { + +class CylTrafoParams : public AutoParameters { +public: + CylTrafoParams() : m_cyl_trafo_params(new ::Utils::CylTrafoParams()) { + add_parameters({{"center", + [this](Variant const &v) { m_cyl_trafo_params->set_center(get_value(v));}, + [this]() { return m_cyl_trafo_params->get_center(); } + }, + {"axis", + [this](Variant const &v) { m_cyl_trafo_params->set_axis(get_value(v));}, + [this]() { return m_cyl_trafo_params->get_axis(); } + }, + {"orientation", + [this](Variant const &v) {m_cyl_trafo_params->set_orientation(get_value(v));}, + [this]() { return m_cyl_trafo_params->get_orientation(); } + } }); + } + +private: + std::shared_ptr<::Utils::CylTrafoParams> m_cyl_trafo_params; +}; +} // namespace ScriptInterface +#endif diff --git a/src/script_interface/initialize.cpp b/src/script_interface/initialize.cpp index 88a7048bc4b..c5c6a538d81 100644 --- a/src/script_interface/initialize.cpp +++ b/src/script_interface/initialize.cpp @@ -29,6 +29,7 @@ #include "h5md/initialize.hpp" #endif #include "ComFixed.hpp" +#include "CylTrafoParams.hpp" #include "accumulators/initialize.hpp" #include "collision_detection/initialize.hpp" #include "lbboundaries/initialize.hpp" @@ -53,6 +54,7 @@ void initialize(Utils::Factory *f) { CollisionDetection::initialize(f); f->register_new("ComFixed"); + f->register_new("CylTrafoParams"); } } /* namespace ScriptInterface */ diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cyl_trafo_params.hpp index bc2ea41d23c..ce2ff7066a5 100644 --- a/src/utils/include/utils/math/cyl_trafo_params.hpp +++ b/src/utils/include/utils/math/cyl_trafo_params.hpp @@ -19,6 +19,10 @@ #ifndef ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP #define ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP +#include + +#include + namespace Utils { class CylTrafoParams { @@ -34,17 +38,21 @@ class CylTrafoParams { Utils::Vector3d get_axis() const {return m_axis;} Utils::Vector3d get_orientation() const {return m_orientation;} + void set_center(Vector3d const ¢er) {m_center = center;} + void set_axis(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Axis can only be set at construction.");} + void set_orientation(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Orientation can only be set at construction.");} + private: void check_valid(){ auto const eps = std::numeric_limits::epsilon(); if (Utils::abs(m_center * m_axis) > eps){ - throw std::runtime_error("cylinder transformation: axis and orientation must be orthogonal"); + throw std::runtime_error("CylTrafoParams: Axis and orientation must be orthogonal."); } if (Utils::abs(m_axis.norm() -1) > eps){ - throw std::runtime_error("cylinder transformation: axis must be normalized"); + throw std::runtime_error("CylTrafoParams: Axis must be normalized."); } if (Utils::abs(m_orientation.norm() -1) > eps){ - throw std::runtime_error("cylinder transformation: orientation must be normalized"); + throw std::runtime_error("CylTrafoParams: orientation must be normalized."); } } From 63371eca72afbc9aab7bc458a4fe5feb53722609 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 17:42:16 +0100 Subject: [PATCH 18/31] use cyltrafoparams in observables --- .../observables/CylindricalFluxDensityProfile.hpp | 6 +++--- ...ricalLBFluxDensityProfileAtParticlePositions.cpp | 4 ++-- .../observables/CylindricalLBProfileObservable.hpp | 12 +++++------- .../observables/CylindricalLBVelocityProfile.cpp | 6 +++--- ...indricalLBVelocityProfileAtParticlePositions.cpp | 6 +++--- .../observables/CylindricalPidProfileObservable.hpp | 6 ++---- .../observables/CylindricalProfileObservable.hpp | 13 ++++++------- src/core/observables/CylindricalVelocityProfile.hpp | 6 +++--- src/utils/include/utils/math/cyl_trafo_params.hpp | 6 +++--- 9 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index ee06c759114..b695d70fce3 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -43,11 +43,11 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - center; + auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params.get_center(); histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos, axis, orientation), + pos, cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), axis, pos)); + traits.velocity(p), cyl_trafo_params.get_axis(), pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index 694cc94748c..816e752802c 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -45,9 +45,9 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos - center, axis, orientation), + pos - cyl_trafo_params.get_center(), cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - flux_dens, axis, pos - center)); + flux_dens, cyl_trafo_params.get_axis(), pos - cyl_trafo_params.get_center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index fab347ea3a0..a464d95ec99 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -30,14 +30,12 @@ namespace Observables { class CylindricalLBProfileObservable : public CylindricalProfileObservable { public: - CylindricalLBProfileObservable(Utils::Vector3d const ¢er, - Utils::Vector3d const &axis, - Utils::Vector3d const &orientation, + CylindricalLBProfileObservable(Utils::CylTrafoParams const &cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z, double sampling_density) - : CylindricalProfileObservable(center, axis, orientation, n_r_bins, + : CylindricalProfileObservable(cyl_trafo_params, n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), sampling_density(sampling_density) { @@ -52,11 +50,11 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; - auto const theta = Utils::angle_between(z_axis, axis); - auto const rot_axis = Utils::vector_product(z_axis, axis).normalize(); + auto const theta = Utils::angle_between(z_axis, cyl_trafo_params.get_axis()); + auto const rot_axis = Utils::vector_product(z_axis, cyl_trafo_params.get_axis()).normalize(); if (theta > std::numeric_limits::epsilon()) p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); - p = p_cart + center; + p = p_cart + cyl_trafo_params.get_center(); } } std::vector sampling_positions; diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index 65023595e65..ecac7cb3d9d 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -35,11 +35,11 @@ std::vector CylindricalLBVelocityProfile::operator()() const { for (auto const &p : sampling_positions) { auto const velocity = lb_lbfluid_get_interpolated_velocity(p) * lb_lbfluid_get_lattice_speed(); - auto const pos_shifted = p - center; + auto const pos_shifted = p - cyl_trafo_params.get_center(); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( - pos_shifted, axis, orientation); + pos_shifted, cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()); histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( - velocity, axis, pos_shifted)); + velocity, cyl_trafo_params.get_axis(), pos_shifted)); } auto hist_data = histogram.get_histogram(); auto const tot_count = histogram.get_tot_count(); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index c1c46fb90fc..29fe33f0219 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -41,9 +41,9 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( lb_lbfluid_get_lattice_speed(); histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos - center, axis, - orientation), - Utils::transform_vector_cartesian_to_cylinder(v, axis, pos - center)); + Utils::transform_coordinate_cartesian_to_cylinder(pos - cyl_trafo_params.get_center(), cyl_trafo_params.get_axis(), + cyl_trafo_params.get_orientation()), + Utils::transform_vector_cartesian_to_cylinder(v, cyl_trafo_params.get_axis(), pos - cyl_trafo_params.get_center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index 3e7e47405c6..2b744755e7f 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -28,14 +28,12 @@ class CylindricalPidProfileObservable : public PidObservable, public CylindricalProfileObservable { public: CylindricalPidProfileObservable(std::vector const &ids, - Utils::Vector3d const ¢er, - Utils::Vector3d const &axis, - Utils::Vector3d const &orientation, + Utils::CylTrafoParams const &cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : PidObservable(ids), - CylindricalProfileObservable(center, axis, orientation, n_r_bins, + CylindricalProfileObservable(cyl_trafo_params, n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z) {} }; diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index 661a5184806..f45cbed7fd5 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -22,12 +22,15 @@ #include "ProfileObservable.hpp" #include +#include +#include #include #include #include #include +#include #include namespace Observables { @@ -35,18 +38,14 @@ namespace Observables { /** Cylindrical profile observable */ class CylindricalProfileObservable : public ProfileObservable { public: - CylindricalProfileObservable(Utils::Vector3d const ¢er, - Utils::Vector3d const &axis, - Utils::Vector3d const &orientation, int n_r_bins, + CylindricalProfileObservable(Utils::CylTrafoParams const &cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), - center(center), axis(axis), orientation(orientation) {} - Utils::Vector3d center; - Utils::Vector3d axis; - Utils::Vector3d orientation; + cyl_trafo_params(cyl_trafo_params) {} + Utils::CylTrafoParams cyl_trafo_params; }; } // Namespace Observables diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 64d44e5d23a..d79feac4abf 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -43,11 +43,11 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { Utils::CylindricalHistogram histogram(n_bins, 3, limits); for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - center; + auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params.get_center(); histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos, axis, orientation), + pos, cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), axis, pos)); + traits.velocity(p), cyl_trafo_params.get_axis(), pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cyl_trafo_params.hpp index ce2ff7066a5..f64b28110f1 100644 --- a/src/utils/include/utils/math/cyl_trafo_params.hpp +++ b/src/utils/include/utils/math/cyl_trafo_params.hpp @@ -27,7 +27,7 @@ namespace Utils { class CylTrafoParams { public: - CylTrafoParams(Utils::Vector3d const ¢er = Utils::Vector3d{{0,0,0}}, + explicit CylTrafoParams(Utils::Vector3d const ¢er = Utils::Vector3d{{0,0,0}}, Utils::Vector3d const &axis = Utils::Vector3d{{0,0,1}}, Utils::Vector3d const &orientation = Utils::Vector3d{{1,0,0}}) : m_center(center), m_axis(axis), m_orientation(orientation){ @@ -39,8 +39,8 @@ class CylTrafoParams { Utils::Vector3d get_orientation() const {return m_orientation;} void set_center(Vector3d const ¢er) {m_center = center;} - void set_axis(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Axis can only be set at construction.");} - void set_orientation(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Orientation can only be set at construction.");} + static void set_axis(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Axis can only be set at construction.");} + static void set_orientation(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Orientation can only be set at construction.");} private: void check_valid(){ From af1c9d934a88c88b452a64495cf0f13168c5925e Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 18:43:53 +0100 Subject: [PATCH 19/31] observables own only pointers to cyk_tafo_params --- .../observables/CylindricalDensityProfile.hpp | 4 +- .../CylindricalFluxDensityProfile.hpp | 6 +-- ...BFluxDensityProfileAtParticlePositions.cpp | 4 +- .../CylindricalLBProfileObservable.hpp | 8 ++-- .../CylindricalLBVelocityProfile.cpp | 6 +-- ...alLBVelocityProfileAtParticlePositions.cpp | 6 +-- .../CylindricalPidProfileObservable.hpp | 2 +- .../CylindricalProfileObservable.hpp | 6 ++- .../CylindricalVelocityProfile.hpp | 6 +-- src/script_interface/CylTrafoParams.hpp | 12 ++++- .../CylindricalLBProfileObservable.hpp | 44 +++++++---------- .../CylindricalPidProfileObservable.hpp | 47 ++++++++----------- .../include/utils/math/cyl_trafo_params.hpp | 11 +++-- 13 files changed, 78 insertions(+), 84 deletions(-) diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index 923662bf0fb..40f25980a05 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -41,8 +41,8 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - folded_position(traits.position(p), box_geo) - center, axis, - orientation)); + folded_position(traits.position(p), box_geo) - cyl_trafo_params->get_center(), cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation())); } histogram.normalize(); diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index b695d70fce3..41c52236ce5 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -43,11 +43,11 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params.get_center(); + auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params->get_center(); histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()), + pos, cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params.get_axis(), pos)); + traits.velocity(p), cyl_trafo_params->get_axis(), pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index 816e752802c..007fe01f1ba 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -45,9 +45,9 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos - cyl_trafo_params.get_center(), cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()), + pos - cyl_trafo_params->get_center(), cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - flux_dens, cyl_trafo_params.get_axis(), pos - cyl_trafo_params.get_center())); + flux_dens, cyl_trafo_params->get_axis(), pos - cyl_trafo_params->get_center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index a464d95ec99..fe3c9d2710e 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -30,7 +30,7 @@ namespace Observables { class CylindricalLBProfileObservable : public CylindricalProfileObservable { public: - CylindricalLBProfileObservable(Utils::CylTrafoParams const &cyl_trafo_params, + CylindricalLBProfileObservable(std::shared_ptr cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z, @@ -50,11 +50,11 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; - auto const theta = Utils::angle_between(z_axis, cyl_trafo_params.get_axis()); - auto const rot_axis = Utils::vector_product(z_axis, cyl_trafo_params.get_axis()).normalize(); + auto const theta = Utils::angle_between(z_axis, cyl_trafo_params->get_axis()); + auto const rot_axis = Utils::vector_product(z_axis, cyl_trafo_params->get_axis()).normalize(); if (theta > std::numeric_limits::epsilon()) p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); - p = p_cart + cyl_trafo_params.get_center(); + p = p_cart + cyl_trafo_params->get_center(); } } std::vector sampling_positions; diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index ecac7cb3d9d..c811025dd6d 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -35,11 +35,11 @@ std::vector CylindricalLBVelocityProfile::operator()() const { for (auto const &p : sampling_positions) { auto const velocity = lb_lbfluid_get_interpolated_velocity(p) * lb_lbfluid_get_lattice_speed(); - auto const pos_shifted = p - cyl_trafo_params.get_center(); + auto const pos_shifted = p - cyl_trafo_params->get_center(); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( - pos_shifted, cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()); + pos_shifted, cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()); histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( - velocity, cyl_trafo_params.get_axis(), pos_shifted)); + velocity, cyl_trafo_params->get_axis(), pos_shifted)); } auto hist_data = histogram.get_histogram(); auto const tot_count = histogram.get_tot_count(); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index 29fe33f0219..08bdb39e783 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -41,9 +41,9 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( lb_lbfluid_get_lattice_speed(); histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos - cyl_trafo_params.get_center(), cyl_trafo_params.get_axis(), - cyl_trafo_params.get_orientation()), - Utils::transform_vector_cartesian_to_cylinder(v, cyl_trafo_params.get_axis(), pos - cyl_trafo_params.get_center())); + Utils::transform_coordinate_cartesian_to_cylinder(pos - cyl_trafo_params->get_center(), cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation()), + Utils::transform_vector_cartesian_to_cylinder(v, cyl_trafo_params->get_axis(), pos - cyl_trafo_params->get_center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index 2b744755e7f..f6cfb475a51 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -28,7 +28,7 @@ class CylindricalPidProfileObservable : public PidObservable, public CylindricalProfileObservable { public: CylindricalPidProfileObservable(std::vector const &ids, - Utils::CylTrafoParams const &cyl_trafo_params, + std::shared_ptr cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index f45cbed7fd5..caeaecb1795 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace Observables { @@ -38,14 +39,15 @@ namespace Observables { /** Cylindrical profile observable */ class CylindricalProfileObservable : public ProfileObservable { public: - CylindricalProfileObservable(Utils::CylTrafoParams const &cyl_trafo_params, int n_r_bins, + CylindricalProfileObservable(std::shared_ptr cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), cyl_trafo_params(cyl_trafo_params) {} - Utils::CylTrafoParams cyl_trafo_params; + + std::shared_ptr cyl_trafo_params; }; } // Namespace Observables diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index d79feac4abf..50567ddacb0 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -43,11 +43,11 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { Utils::CylindricalHistogram histogram(n_bins, 3, limits); for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params.get_center(); + auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params->get_center(); histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params.get_axis(), cyl_trafo_params.get_orientation()), + pos, cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params.get_axis(), pos)); + traits.velocity(p), cyl_trafo_params->get_axis(), pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/script_interface/CylTrafoParams.hpp b/src/script_interface/CylTrafoParams.hpp index 456a7d61c9b..c65cded57b8 100644 --- a/src/script_interface/CylTrafoParams.hpp +++ b/src/script_interface/CylTrafoParams.hpp @@ -44,9 +44,17 @@ class CylTrafoParams : public AutoParameters { [this]() { return m_cyl_trafo_params->get_orientation(); } } }); } - + std::shared_ptr<::Utils::CylTrafoParams> cyl_trafo_params(){ + return m_cyl_trafo_params; + } + void do_construct(VariantMap const ¶ms) override { + m_cyl_trafo_params = std::make_shared( + get_value_or(params, "center", Utils::Vector3d{{0,0,0}}), + get_value_or(params, "axis", Utils::Vector3d{{0,0,1}}), + get_value_or(params, "orientation", Utils::Vector3d{{1,0,0}})); + } private: - std::shared_ptr<::Utils::CylTrafoParams> m_cyl_trafo_params; + std::shared_ptr m_cyl_trafo_params; }; } // namespace ScriptInterface #endif diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index 740bd60ea6e..dfa3d0b115f 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -28,6 +28,8 @@ #include "core/observables/CylindricalLBProfileObservable.hpp" #include "script_interface/get_value.hpp" +#include "script_interface/CylTrafoParams.hpp" + #include #include @@ -53,24 +55,7 @@ class CylindricalLBProfileObservable using Base::Base; CylindricalLBProfileObservable() { this->add_parameters({ - {"center", - [this](const Variant &v) { - cylindrical_profile_observable()->center = - get_value<::Utils::Vector3d>(v); - }, - [this]() { return cylindrical_profile_observable()->center; }}, - {"axis", - [this](const Variant &v) { - cylindrical_profile_observable()->axis = - get_value(v); - }, - [this]() { return cylindrical_profile_observable()->axis; }}, - {"orientation", - [this](const Variant &v) { - cylindrical_profile_observable()->orientation = - get_value(v); - }, - [this]() { return cylindrical_profile_observable()->orientation; }}, + {"cyl_trafo_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = @@ -155,14 +140,20 @@ class CylindricalLBProfileObservable } void do_construct(VariantMap const ¶ms) override { - m_observable = - make_shared_from_args( - params, "center", "axis", "orientation", "n_r_bins", "n_phi_bins", - "n_z_bins", "min_r", "max_r", "min_phi", "max_phi", "min_z", - "max_z", "sampling_density"); - } + set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + m_observable = std::make_shared( + m_cyl_trafo_params->cyl_trafo_params(), + get_value_or(params, "n_r_bins", 1), + get_value_or(params, "n_phi_bins", 1), + get_value_or(params, "n_z_bins", 1), + get_value_or(params, "min_r", 0.), + get_value(params, "max_r"), + get_value_or(params, "min_phi", -Utils::pi()), + get_value_or(params, "max_phi", Utils::pi()), + get_value(params, "min_z"), + get_value(params, "max_z"), + get_value(params, "sampling_density")); + } Variant do_call_method(std::string const &method, VariantMap const ¶meters) override { @@ -186,6 +177,7 @@ class CylindricalLBProfileObservable private: std::shared_ptr m_observable; + std::shared_ptr m_cyl_trafo_params; }; } /* namespace Observables */ diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index 7755a74171a..941501b8c54 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -27,11 +27,14 @@ #include "Observable.hpp" #include "core/observables/CylindricalPidProfileObservable.hpp" -#include +#include +#include +#include #include #include #include + #include #include @@ -58,26 +61,7 @@ class CylindricalPidProfileObservable get_value>(v); }, [this]() { return cylindrical_pid_profile_observable()->ids(); }}, - {"center", - [this](const Variant &v) { - cylindrical_pid_profile_observable()->center = - get_value<::Utils::Vector3d>(v); - }, - [this]() { return cylindrical_pid_profile_observable()->center; }}, - {"axis", - [this](const Variant &v) { - cylindrical_pid_profile_observable()->axis = - get_value(v); - }, - [this]() { return cylindrical_pid_profile_observable()->axis; }}, - {"orientation", - [this](const Variant &v) { - cylindrical_pid_profile_observable()->orientation = - get_value(v); - }, - [this]() { - return cylindrical_pid_profile_observable()->orientation; - }}, + {"cyl_trafo_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_pid_profile_observable()->n_bins[0] = @@ -157,13 +141,19 @@ class CylindricalPidProfileObservable }; void do_construct(VariantMap const ¶ms) override { - m_observable = - make_shared_from_args, Utils::Vector3d, - Utils::Vector3d, Utils::Vector3d, int, int, int, - double, double, double, double, double, double>( - params, "ids", "center", "axis", "orientation", "n_r_bins", - "n_phi_bins", "n_z_bins", "min_r", "max_r", "min_phi", "max_phi", - "min_z", "max_z"); + set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + m_observable = std::make_shared( + get_value>(params, "ids"), + m_cyl_trafo_params->cyl_trafo_params(), + get_value_or(params,"n_r_bins", 1), + get_value_or(params, "n_phi_bins", 1), + get_value_or(params, "n_z_bins", 1), + get_value_or(params, "min_r", 0.), + get_value(params,"max_r"), + get_value_or(params, "min_phi", -Utils::pi()), + get_value_or(params, "max_phi", Utils::pi()), + get_value(params, "min_z"), + get_value(params, "max_z")); } Variant do_call_method(std::string const &method, @@ -188,6 +178,7 @@ class CylindricalPidProfileObservable private: std::shared_ptr m_observable; + std::shared_ptr m_cyl_trafo_params; }; } /* namespace Observables */ diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cyl_trafo_params.hpp index f64b28110f1..16d59077ac9 100644 --- a/src/utils/include/utils/math/cyl_trafo_params.hpp +++ b/src/utils/include/utils/math/cyl_trafo_params.hpp @@ -20,6 +20,7 @@ #define ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP #include +#include #include @@ -44,15 +45,15 @@ class CylTrafoParams { private: void check_valid(){ - auto const eps = std::numeric_limits::epsilon(); - if (Utils::abs(m_center * m_axis) > eps){ - throw std::runtime_error("CylTrafoParams: Axis and orientation must be orthogonal."); + auto const eps = 10*std::numeric_limits::epsilon(); + if (Utils::abs(m_orientation * m_axis) > eps){ + throw std::runtime_error("CylTrafoParams: Axis and orientation must be orthogonal. Scalar product is " + std::to_string(m_orientation*m_axis)); } if (Utils::abs(m_axis.norm() -1) > eps){ - throw std::runtime_error("CylTrafoParams: Axis must be normalized."); + throw std::runtime_error("CylTrafoParams: Axis must be normalized. Norm is " + std::to_string(m_axis.norm())); } if (Utils::abs(m_orientation.norm() -1) > eps){ - throw std::runtime_error("CylTrafoParams: orientation must be normalized."); + throw std::runtime_error("CylTrafoParams: orientation must be normalized. Norm is " + std::to_string(m_orientation.norm())); } } From 2667d9c1c24026b2dd690d2360e1b690e6769b17 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 20:19:30 +0100 Subject: [PATCH 20/31] remove python-level default orientation --- src/python/espressomd/observables.py | 35 +++++----------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index b503aa70104..568c11a6989 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -68,28 +68,6 @@ def bin_centers(self): shape = list(map(len, edges)) + [len(edges)] return np.array(list(itertools.product(*edges))).reshape(shape) - -class CylindricalProfileObservables(ProfileObservable): - """ - Base Class for ProfileObservables that work with cylindrical coordinates - to inject default behaviour for the ``orientation`` parameter - """ - - def __init__(self, **kwargs): - if "oid" not in kwargs and "orientation" not in kwargs and kwargs["n_phi_bins"] == 1: - # if the phi angle is not important, choose an orientation that is - # not parallel to ``axis`` - try_vectors = [np.array([1., 0., 0.]), np.array([0., 0., 1.])] - axis = np.asarray(kwargs["axis"]) - for vec in try_vectors: - orthogonal_component = vec - np.dot(vec, axis) * axis - norm = np.linalg.norm(orthogonal_component) - if norm > 0.01: - kwargs["orientation"] = orthogonal_component / norm - break - super().__init__(**kwargs) - - @script_interface_register class ComPosition(Observable): @@ -657,7 +635,7 @@ class DPDStress(Observable): @script_interface_register -class CylindricalDensityProfile(CylindricalProfileObservables): +class CylindricalDensityProfile(ProfileObservable): """Calculates the particle density in cylindrical coordinates. @@ -699,7 +677,7 @@ class CylindricalDensityProfile(CylindricalProfileObservables): @script_interface_register -class CylindricalFluxDensityProfile(CylindricalProfileObservables): +class CylindricalFluxDensityProfile(ProfileObservable): """Calculates the particle flux density in cylindrical coordinates. @@ -743,8 +721,7 @@ class CylindricalFluxDensityProfile(CylindricalProfileObservables): @script_interface_register -class CylindricalLBFluxDensityProfileAtParticlePositions( - CylindricalProfileObservables): +class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): """Calculates the LB fluid flux density at the particle positions in cylindrical coordinates. @@ -790,7 +767,7 @@ class CylindricalLBFluxDensityProfileAtParticlePositions( @script_interface_register class CylindricalLBVelocityProfileAtParticlePositions( - CylindricalProfileObservables): + ProfileObservable): """Calculates the LB fluid velocity at the particle positions in cylindrical coordinates. @@ -835,7 +812,7 @@ class CylindricalLBVelocityProfileAtParticlePositions( @script_interface_register -class CylindricalVelocityProfile(CylindricalProfileObservables): +class CylindricalVelocityProfile(ProfileObservable): """Calculates the particle velocity profile in cylindrical coordinates. @@ -879,7 +856,7 @@ class CylindricalVelocityProfile(CylindricalProfileObservables): @script_interface_register -class CylindricalLBVelocityProfile(CylindricalProfileObservables): +class CylindricalLBVelocityProfile(ProfileObservable): """Calculates the LB fluid velocity profile in cylindrical coordinates. From bd0d752cd8ecde6bbbdad1e6190732620a2fd0cb Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 20:20:23 +0100 Subject: [PATCH 21/31] adapt tests tp ctp --- testsuite/python/lb_poiseuille_cylinder.py | 8 +++-- testsuite/python/observable_cylindrical.py | 29 +++++++++-------- testsuite/python/observable_cylindricalLB.py | 33 ++++++++++---------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index e58f1a7c6c3..db08f19ad3f 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -18,6 +18,7 @@ import unittest_decorators as utx import numpy as np +import espressomd.math import espressomd.lb import espressomd.lbboundaries import espressomd.observables @@ -151,9 +152,10 @@ def prepare_obs(self): else: obs_center = [BOX_L / 2.0, BOX_L / 2.0, 0.0] local_obs_params = OBS_PARAMS.copy() - local_obs_params['center'] = obs_center - local_obs_params['axis'] = self.params['axis'] - local_obs_params['orientation'] = self.params['orientation'] + ctp = espressomd.math.CylTrafoParams(center = obs_center, + axis = self.params['axis'], + orientation = self.params['orientation']) + local_obs_params['cyl_obs_params'] = ctp obs = espressomd.observables.CylindricalLBVelocityProfile( **local_obs_params) self.accumulator = espressomd.accumulators.MeanVarianceCalculator( diff --git a/testsuite/python/observable_cylindrical.py b/testsuite/python/observable_cylindrical.py index 4d123aff767..a067ab351c4 100644 --- a/testsuite/python/observable_cylindrical.py +++ b/testsuite/python/observable_cylindrical.py @@ -18,6 +18,7 @@ import unittest as ut import espressomd import espressomd.observables +import espressomd.math import tests_common @@ -30,12 +31,14 @@ class TestCylindricalObservable(ut.TestCase): system = espressomd.System(box_l=[15.0, 15.0, 15.0]) system.time_step = 0.01 system.cell_system.skin = 0.4 + + cyl_trafo_params = espressomd.math.CylTrafoParams(center = 3*[7.5], + axis = [1/np.sqrt(2), 1/np.sqrt(2), 0], + orientation = [0, 0, 1]) params = { 'ids': None, - 'center': 3 * [7.5], - 'axis': [np.sqrt(2), np.sqrt(2), 0], - 'orientation': [0, 0, 1], + 'cyl_trafo_params':cyl_trafo_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 4, @@ -123,7 +126,7 @@ def setup_system_get_np_hist(self): for pos, vel in zip(positions, velocities): pos_aligned.append( self.align_with_observable_frame(pos) + - self.params['center']) + self.cyl_trafo_params.center) vel_aligned.append(self.align_with_observable_frame(vel)) self.system.part.add(pos=pos_aligned, v=vel_aligned) self.params['ids'] = self.system.part[:].id @@ -240,15 +243,15 @@ def test_cylindrical_pid_profile_interface(self): self.assertEqual(observable.max_z, 9) obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) - # check center - np.testing.assert_array_equal( - np.copy(observable.center), params['center']) - observable.center = [3, 2, 1] - np.testing.assert_array_equal(np.copy(observable.center), [3, 2, 1]) - # check axis - np.testing.assert_array_equal(np.copy(observable.axis), params['axis']) - observable.axis = [6, 5, 4] - np.testing.assert_array_equal(np.copy(observable.axis), [6, 5, 4]) + # check center, axis, orientation + ctp = espressomd.math.CylTrafoParams(center = [1,2,3], + axis = [0,1,0], + orientation = [0,0,1]) + observable.cyl_trafo_params = ctp + + for attr_name in ['center','axis', 'orientation']: + np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), + np.copy(observable.cyl_trafo_params.__getattr__(attr_name))) if __name__ == "__main__": diff --git a/testsuite/python/observable_cylindricalLB.py b/testsuite/python/observable_cylindricalLB.py index c8b67afd2e5..90404b9fe5b 100644 --- a/testsuite/python/observable_cylindricalLB.py +++ b/testsuite/python/observable_cylindricalLB.py @@ -18,6 +18,7 @@ import unittest as ut import unittest_decorators as utx import espressomd +import espressomd.math import espressomd.observables import espressomd.lb import tests_common @@ -40,11 +41,13 @@ class CylindricalLBObservableCommon: 'visc': 2.7, 'tau': 0.1, } + cyl_trafo_params = espressomd.math.CylTrafoParams(center = 3*[7], + axis = [1,0,0], + orientation = [0,0,1]) + params = { 'ids': None, - 'center': 3 * [7], - 'axis': [1, 0, 0], - 'orientation': [0, 0, 1], + 'cyl_trafo_params' : cyl_trafo_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 5, @@ -115,7 +118,7 @@ def setup_system_get_np_hist(self): for pos, vel in zip(positions, velocities): pos_aligned.append( self.align_with_observable_frame(pos) + - self.params['center']) + self.cyl_trafo_params.center) vel_aligned.append(self.align_with_observable_frame(vel)) node_aligned = np.array( np.rint( @@ -208,19 +211,15 @@ def test_cylindrical_lb_profile_interface(self): self.assertEqual(observable.max_z, 9) obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) - # check center - np.testing.assert_array_equal( - np.copy(observable.center), params['center']) - observable.center = [3, 2, 1] - np.testing.assert_array_equal(np.copy(observable.center), [3, 2, 1]) - # check axis - np.testing.assert_array_equal(np.copy(observable.axis), params['axis']) - observable.axis = [6, 5, 4] - np.testing.assert_array_equal(np.copy(observable.axis), [6, 5, 4]) - # check sampling_density - self.assertEqual(observable.sampling_density, 2) - observable.sampling_density = 3 - self.assertEqual(observable.sampling_density, 3) + # check center, axis, orientation + ctp = espressomd.math.CylTrafoParams(center = [1,2,3], + axis = [0,1,0], + orientation = [0,0,1]) + observable.cyl_trafo_params = ctp + + for attr_name in ['center','axis', 'orientation']: + np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), + np.copy(observable.cyl_trafo_params.__getattr__(attr_name))) class CylindricalLBObservableCPU(ut.TestCase, CylindricalLBObservableCommon): From 249fd24a2be2859bbad4447b13f8350dd5580f70 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Wed, 3 Mar 2021 20:21:24 +0100 Subject: [PATCH 22/31] inject default behaviour if no ctp is given --- .../observables/CylindricalDensityProfile.hpp | 5 +- .../CylindricalFluxDensityProfile.hpp | 13 +++-- ...BFluxDensityProfileAtParticlePositions.cpp | 7 ++- .../CylindricalLBProfileObservable.hpp | 22 +++++---- .../CylindricalLBVelocityProfile.cpp | 8 +-- ...alLBVelocityProfileAtParticlePositions.cpp | 11 +++-- .../CylindricalPidProfileObservable.hpp | 16 +++--- .../CylindricalProfileObservable.hpp | 8 +-- .../CylindricalVelocityProfile.hpp | 13 +++-- src/python/espressomd/math.py | 1 + src/python/espressomd/observables.py | 1 + src/script_interface/CylTrafoParams.hpp | 33 ++++++------- .../CylindricalLBProfileObservable.hpp | 27 +++++----- .../CylindricalPidProfileObservable.hpp | 15 +++--- .../include/utils/math/cyl_trafo_params.hpp | 49 ++++++++++++------- testsuite/python/lb_poiseuille_cylinder.py | 6 +-- testsuite/python/observable_cylindrical.py | 21 ++++---- testsuite/python/observable_cylindricalLB.py | 20 ++++---- 18 files changed, 157 insertions(+), 119 deletions(-) diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index 40f25980a05..b3d3fcde22c 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -41,8 +41,9 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - folded_position(traits.position(p), box_geo) - cyl_trafo_params->get_center(), cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation())); + folded_position(traits.position(p), box_geo) - + cyl_trafo_params->get_center(), + cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation())); } histogram.normalize(); diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index 41c52236ce5..325053b8bb4 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -43,11 +43,14 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params->get_center(); - histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()), - Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params->get_axis(), pos)); + auto const pos = folded_position(traits.position(p), box_geo) - + cyl_trafo_params->get_center(); + histogram.update( + Utils::transform_coordinate_cartesian_to_cylinder( + pos, cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation()), + Utils::transform_vector_cartesian_to_cylinder( + traits.velocity(p), cyl_trafo_params->get_axis(), pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index 007fe01f1ba..29fce46a75a 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -45,9 +45,12 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos - cyl_trafo_params->get_center(), cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()), + pos - cyl_trafo_params->get_center(), + cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation()), Utils::transform_vector_cartesian_to_cylinder( - flux_dens, cyl_trafo_params->get_axis(), pos - cyl_trafo_params->get_center())); + flux_dens, cyl_trafo_params->get_axis(), + pos - cyl_trafo_params->get_center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index fe3c9d2710e..edcc5d8c518 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -30,14 +30,13 @@ namespace Observables { class CylindricalLBProfileObservable : public CylindricalProfileObservable { public: - CylindricalLBProfileObservable(std::shared_ptr cyl_trafo_params, - int n_r_bins, int n_phi_bins, int n_z_bins, - double min_r, double max_r, double min_phi, - double max_phi, double min_z, double max_z, - double sampling_density) - : CylindricalProfileObservable(cyl_trafo_params, n_r_bins, - n_phi_bins, n_z_bins, min_r, max_r, - min_phi, max_phi, min_z, max_z), + CylindricalLBProfileObservable( + std::shared_ptr cyl_trafo_params, int n_r_bins, + int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, + double max_phi, double min_z, double max_z, double sampling_density) + : CylindricalProfileObservable(cyl_trafo_params, n_r_bins, n_phi_bins, + n_z_bins, min_r, max_r, min_phi, max_phi, + min_z, max_z), sampling_density(sampling_density) { calculate_sampling_positions(); } @@ -50,8 +49,11 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; - auto const theta = Utils::angle_between(z_axis, cyl_trafo_params->get_axis()); - auto const rot_axis = Utils::vector_product(z_axis, cyl_trafo_params->get_axis()).normalize(); + auto const theta = + Utils::angle_between(z_axis, cyl_trafo_params->get_axis()); + auto const rot_axis = + Utils::vector_product(z_axis, cyl_trafo_params->get_axis()) + .normalize(); if (theta > std::numeric_limits::epsilon()) p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); p = p_cart + cyl_trafo_params->get_center(); diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index c811025dd6d..56de507c2d9 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -37,9 +37,11 @@ std::vector CylindricalLBVelocityProfile::operator()() const { lb_lbfluid_get_lattice_speed(); auto const pos_shifted = p - cyl_trafo_params->get_center(); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( - pos_shifted, cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()); - histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( - velocity, cyl_trafo_params->get_axis(), pos_shifted)); + pos_shifted, cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation()); + histogram.update(pos_cyl, + Utils::transform_vector_cartesian_to_cylinder( + velocity, cyl_trafo_params->get_axis(), pos_shifted)); } auto hist_data = histogram.get_histogram(); auto const tot_count = histogram.get_tot_count(); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index 08bdb39e783..967aea0d736 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -40,10 +40,13 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( auto const v = lb_lbfluid_get_interpolated_velocity(pos) * lb_lbfluid_get_lattice_speed(); - histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder(pos - cyl_trafo_params->get_center(), cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation()), - Utils::transform_vector_cartesian_to_cylinder(v, cyl_trafo_params->get_axis(), pos - cyl_trafo_params->get_center())); + histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( + pos - cyl_trafo_params->get_center(), + cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation()), + Utils::transform_vector_cartesian_to_cylinder( + v, cyl_trafo_params->get_axis(), + pos - cyl_trafo_params->get_center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index f6cfb475a51..ea65e6fc3b7 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -27,15 +27,15 @@ namespace Observables { class CylindricalPidProfileObservable : public PidObservable, public CylindricalProfileObservable { public: - CylindricalPidProfileObservable(std::vector const &ids, - std::shared_ptr cyl_trafo_params, - int n_r_bins, int n_phi_bins, int n_z_bins, - double min_r, double max_r, double min_phi, - double max_phi, double min_z, double max_z) + CylindricalPidProfileObservable( + std::vector const &ids, + std::shared_ptr cyl_trafo_params, int n_r_bins, + int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, + double max_phi, double min_z, double max_z) : PidObservable(ids), - CylindricalProfileObservable(cyl_trafo_params, n_r_bins, - n_phi_bins, n_z_bins, min_r, max_r, - min_phi, max_phi, min_z, max_z) {} + CylindricalProfileObservable(cyl_trafo_params, n_r_bins, n_phi_bins, + n_z_bins, min_r, max_r, min_phi, max_phi, + min_z, max_z) {} }; } // Namespace Observables diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index caeaecb1795..55abb638971 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -39,10 +39,10 @@ namespace Observables { /** Cylindrical profile observable */ class CylindricalProfileObservable : public ProfileObservable { public: - CylindricalProfileObservable(std::shared_ptr cyl_trafo_params, int n_r_bins, - int n_phi_bins, int n_z_bins, double min_r, - double max_r, double min_phi, double max_phi, - double min_z, double max_z) + CylindricalProfileObservable( + std::shared_ptr cyl_trafo_params, int n_r_bins, + int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, + double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), cyl_trafo_params(cyl_trafo_params) {} diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 50567ddacb0..5fa0a0b39ed 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -43,11 +43,14 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { Utils::CylindricalHistogram histogram(n_bins, 3, limits); for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - cyl_trafo_params->get_center(); - histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation()), - Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params->get_axis(), pos)); + auto const pos = folded_position(traits.position(p), box_geo) - + cyl_trafo_params->get_center(); + histogram.update( + Utils::transform_coordinate_cartesian_to_cylinder( + pos, cyl_trafo_params->get_axis(), + cyl_trafo_params->get_orientation()), + Utils::transform_vector_cartesian_to_cylinder( + traits.velocity(p), cyl_trafo_params->get_axis(), pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/python/espressomd/math.py b/src/python/espressomd/math.py index 38180ce6e5b..01417419ff7 100644 --- a/src/python/espressomd/math.py +++ b/src/python/espressomd/math.py @@ -1,5 +1,6 @@ from .script_interface import ScriptInterfaceHelper, script_interface_register + @script_interface_register class CylTrafoParams(ScriptInterfaceHelper): _so_name = "CylTrafoParams" diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 568c11a6989..33766e6c12b 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -68,6 +68,7 @@ def bin_centers(self): shape = list(map(len, edges)) + [len(edges)] return np.array(list(itertools.product(*edges))).reshape(shape) + @script_interface_register class ComPosition(Observable): diff --git a/src/script_interface/CylTrafoParams.hpp b/src/script_interface/CylTrafoParams.hpp index c65cded57b8..c6e817502d8 100644 --- a/src/script_interface/CylTrafoParams.hpp +++ b/src/script_interface/CylTrafoParams.hpp @@ -30,29 +30,28 @@ namespace ScriptInterface { class CylTrafoParams : public AutoParameters { public: - CylTrafoParams() : m_cyl_trafo_params(new ::Utils::CylTrafoParams()) { - add_parameters({{"center", - [this](Variant const &v) { m_cyl_trafo_params->set_center(get_value(v));}, - [this]() { return m_cyl_trafo_params->get_center(); } - }, - {"axis", - [this](Variant const &v) { m_cyl_trafo_params->set_axis(get_value(v));}, - [this]() { return m_cyl_trafo_params->get_axis(); } - }, - {"orientation", - [this](Variant const &v) {m_cyl_trafo_params->set_orientation(get_value(v));}, - [this]() { return m_cyl_trafo_params->get_orientation(); } - } }); + CylTrafoParams() { + add_parameters({{"center", AutoParameter::read_only, + [this]() { return m_cyl_trafo_params->get_center(); }}, + {"axis", AutoParameter::read_only, + [this]() { return m_cyl_trafo_params->get_axis(); }}, + {"orientation", AutoParameter::read_only, [this]() { + return m_cyl_trafo_params->get_orientation(); + }}}); } - std::shared_ptr<::Utils::CylTrafoParams> cyl_trafo_params(){ + std::shared_ptr<::Utils::CylTrafoParams> cyl_trafo_params() { return m_cyl_trafo_params; } void do_construct(VariantMap const ¶ms) override { m_cyl_trafo_params = std::make_shared( - get_value_or(params, "center", Utils::Vector3d{{0,0,0}}), - get_value_or(params, "axis", Utils::Vector3d{{0,0,1}}), - get_value_or(params, "orientation", Utils::Vector3d{{1,0,0}})); + get_value_or(params, "center", + Utils::Vector3d{{0, 0, 0}}), + get_value_or(params, "axis", + Utils::Vector3d{{0, 0, 1}}), + get_value_or(params, "orientation", + Utils::Vector3d{{1, 0, 0}})); } + private: std::shared_ptr m_cyl_trafo_params; }; diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index dfa3d0b115f..399b3584c95 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -140,20 +140,23 @@ class CylindricalLBProfileObservable } void do_construct(VariantMap const ¶ms) override { + if (params.count("cyl_trafo_params")) { set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); - m_observable = std::make_shared( - m_cyl_trafo_params->cyl_trafo_params(), - get_value_or(params, "n_r_bins", 1), - get_value_or(params, "n_phi_bins", 1), - get_value_or(params, "n_z_bins", 1), - get_value_or(params, "min_r", 0.), - get_value(params, "max_r"), - get_value_or(params, "min_phi", -Utils::pi()), - get_value_or(params, "max_phi", Utils::pi()), - get_value(params, "min_z"), - get_value(params, "max_z"), - get_value(params, "sampling_density")); + } else { + m_cyl_trafo_params = std::make_shared(); } + m_observable = std::make_shared( + m_cyl_trafo_params->cyl_trafo_params(), + get_value_or(params, "n_r_bins", 1), + get_value_or(params, "n_phi_bins", 1), + get_value_or(params, "n_z_bins", 1), + get_value_or(params, "min_r", 0.), + get_value(params, "max_r"), + get_value_or(params, "min_phi", -Utils::pi()), + get_value_or(params, "max_phi", Utils::pi()), + get_value(params, "min_z"), get_value(params, "max_z"), + get_value(params, "sampling_density")); + } Variant do_call_method(std::string const &method, VariantMap const ¶meters) override { diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index 941501b8c54..14e93d92b4e 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -27,8 +27,8 @@ #include "Observable.hpp" #include "core/observables/CylindricalPidProfileObservable.hpp" -#include #include +#include #include #include @@ -141,19 +141,22 @@ class CylindricalPidProfileObservable }; void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + if (params.count("cyl_trafo_params")) { + set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + } else { + m_cyl_trafo_params = std::make_shared(); + } m_observable = std::make_shared( get_value>(params, "ids"), m_cyl_trafo_params->cyl_trafo_params(), - get_value_or(params,"n_r_bins", 1), + get_value_or(params, "n_r_bins", 1), get_value_or(params, "n_phi_bins", 1), get_value_or(params, "n_z_bins", 1), get_value_or(params, "min_r", 0.), - get_value(params,"max_r"), + get_value(params, "max_r"), get_value_or(params, "min_phi", -Utils::pi()), get_value_or(params, "max_phi", Utils::pi()), - get_value(params, "min_z"), - get_value(params, "max_z")); + get_value(params, "min_z"), get_value(params, "max_z")); } Variant do_call_method(std::string const &method, diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cyl_trafo_params.hpp index 16d59077ac9..0faf0cd5e8b 100644 --- a/src/utils/include/utils/math/cyl_trafo_params.hpp +++ b/src/utils/include/utils/math/cyl_trafo_params.hpp @@ -28,32 +28,45 @@ namespace Utils { class CylTrafoParams { public: - explicit CylTrafoParams(Utils::Vector3d const ¢er = Utils::Vector3d{{0,0,0}}, - Utils::Vector3d const &axis = Utils::Vector3d{{0,0,1}}, - Utils::Vector3d const &orientation = Utils::Vector3d{{1,0,0}}) - : m_center(center), m_axis(axis), m_orientation(orientation){ + explicit CylTrafoParams( + Utils::Vector3d const ¢er = Utils::Vector3d{{0, 0, 0}}, + Utils::Vector3d const &axis = Utils::Vector3d{{0, 0, 1}}, + Utils::Vector3d const &orientation = Utils::Vector3d{{1, 0, 0}}) + : m_center(center), m_axis(axis), m_orientation(orientation) { check_valid(); } - Utils::Vector3d get_center() const {return m_center;} - Utils::Vector3d get_axis() const {return m_axis;} - Utils::Vector3d get_orientation() const {return m_orientation;} + Utils::Vector3d get_center() const { return m_center; } + Utils::Vector3d get_axis() const { return m_axis; } + Utils::Vector3d get_orientation() const { return m_orientation; } - void set_center(Vector3d const ¢er) {m_center = center;} - static void set_axis(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Axis can only be set at construction.");} - static void set_orientation(Vector3d const ¢er) {throw std::runtime_error("CylTrafoParams: Orientation can only be set at construction.");} + void set_center(Vector3d const ¢er) { m_center = center; } + static void set_axis(Vector3d const ¢er) { + throw std::runtime_error( + "CylTrafoParams: Axis can only be set at construction."); + } + static void set_orientation(Vector3d const ¢er) { + throw std::runtime_error( + "CylTrafoParams: Orientation can only be set at construction."); + } private: - void check_valid(){ - auto const eps = 10*std::numeric_limits::epsilon(); - if (Utils::abs(m_orientation * m_axis) > eps){ - throw std::runtime_error("CylTrafoParams: Axis and orientation must be orthogonal. Scalar product is " + std::to_string(m_orientation*m_axis)); + void check_valid() { + auto const eps = 10 * std::numeric_limits::epsilon(); + if (Utils::abs(m_orientation * m_axis) > eps) { + throw std::runtime_error("CylTrafoParams: Axis and orientation must be " + "orthogonal. Scalar product is " + + std::to_string(m_orientation * m_axis)); } - if (Utils::abs(m_axis.norm() -1) > eps){ - throw std::runtime_error("CylTrafoParams: Axis must be normalized. Norm is " + std::to_string(m_axis.norm())); + if (Utils::abs(m_axis.norm() - 1) > eps) { + throw std::runtime_error( + "CylTrafoParams: Axis must be normalized. Norm is " + + std::to_string(m_axis.norm())); } - if (Utils::abs(m_orientation.norm() -1) > eps){ - throw std::runtime_error("CylTrafoParams: orientation must be normalized. Norm is " + std::to_string(m_orientation.norm())); + if (Utils::abs(m_orientation.norm() - 1) > eps) { + throw std::runtime_error( + "CylTrafoParams: orientation must be normalized. Norm is " + + std::to_string(m_orientation.norm())); } } diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index db08f19ad3f..e7e60f067f2 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -152,9 +152,9 @@ def prepare_obs(self): else: obs_center = [BOX_L / 2.0, BOX_L / 2.0, 0.0] local_obs_params = OBS_PARAMS.copy() - ctp = espressomd.math.CylTrafoParams(center = obs_center, - axis = self.params['axis'], - orientation = self.params['orientation']) + ctp = espressomd.math.CylTrafoParams(center=obs_center, + axis=self.params['axis'], + orientation=self.params['orientation']) local_obs_params['cyl_obs_params'] = ctp obs = espressomd.observables.CylindricalLBVelocityProfile( **local_obs_params) diff --git a/testsuite/python/observable_cylindrical.py b/testsuite/python/observable_cylindrical.py index a067ab351c4..73dfd0ab729 100644 --- a/testsuite/python/observable_cylindrical.py +++ b/testsuite/python/observable_cylindrical.py @@ -31,14 +31,15 @@ class TestCylindricalObservable(ut.TestCase): system = espressomd.System(box_l=[15.0, 15.0, 15.0]) system.time_step = 0.01 system.cell_system.skin = 0.4 - - cyl_trafo_params = espressomd.math.CylTrafoParams(center = 3*[7.5], - axis = [1/np.sqrt(2), 1/np.sqrt(2), 0], - orientation = [0, 0, 1]) + + cyl_trafo_params = espressomd.math.CylTrafoParams(center=3 * [7.5], + axis=[ + 1 / np.sqrt(2), 1 / np.sqrt(2), 0], + orientation=[0, 0, 1]) params = { 'ids': None, - 'cyl_trafo_params':cyl_trafo_params, + 'cyl_trafo_params': cyl_trafo_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 4, @@ -244,12 +245,12 @@ def test_cylindrical_pid_profile_interface(self): obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) # check center, axis, orientation - ctp = espressomd.math.CylTrafoParams(center = [1,2,3], - axis = [0,1,0], - orientation = [0,0,1]) + ctp = espressomd.math.CylTrafoParams(center=[1, 2, 3], + axis=[0, 1, 0], + orientation=[0, 0, 1]) observable.cyl_trafo_params = ctp - - for attr_name in ['center','axis', 'orientation']: + + for attr_name in ['center', 'axis', 'orientation']: np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), np.copy(observable.cyl_trafo_params.__getattr__(attr_name))) diff --git a/testsuite/python/observable_cylindricalLB.py b/testsuite/python/observable_cylindricalLB.py index 90404b9fe5b..8c8e0d4c631 100644 --- a/testsuite/python/observable_cylindricalLB.py +++ b/testsuite/python/observable_cylindricalLB.py @@ -41,13 +41,13 @@ class CylindricalLBObservableCommon: 'visc': 2.7, 'tau': 0.1, } - cyl_trafo_params = espressomd.math.CylTrafoParams(center = 3*[7], - axis = [1,0,0], - orientation = [0,0,1]) - + cyl_trafo_params = espressomd.math.CylTrafoParams(center=3 * [7], + axis=[1, 0, 0], + orientation=[0, 0, 1]) + params = { 'ids': None, - 'cyl_trafo_params' : cyl_trafo_params, + 'cyl_trafo_params': cyl_trafo_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 5, @@ -212,12 +212,12 @@ def test_cylindrical_lb_profile_interface(self): obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) # check center, axis, orientation - ctp = espressomd.math.CylTrafoParams(center = [1,2,3], - axis = [0,1,0], - orientation = [0,0,1]) + ctp = espressomd.math.CylTrafoParams(center=[1, 2, 3], + axis=[0, 1, 0], + orientation=[0, 0, 1]) observable.cyl_trafo_params = ctp - - for attr_name in ['center','axis', 'orientation']: + + for attr_name in ['center', 'axis', 'orientation']: np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), np.copy(observable.cyl_trafo_params.__getattr__(attr_name))) From a54af97c0993f73c63c15fda28bc49c6ccc0c997 Mon Sep 17 00:00:00 2001 From: Kai Szuttor Date: Thu, 4 Mar 2021 16:05:46 +0100 Subject: [PATCH 23/31] Beautification. --- .../observables/CylindricalDensityProfile.hpp | 4 +- .../CylindricalFluxDensityProfile.hpp | 7 ++-- ...BFluxDensityProfileAtParticlePositions.cpp | 15 ++++---- .../CylindricalLBProfileObservable.hpp | 8 ++-- .../CylindricalLBVelocityProfile.cpp | 7 ++-- ...alLBVelocityProfileAtParticlePositions.cpp | 18 ++++----- .../CylindricalVelocityProfile.hpp | 7 ++-- src/script_interface/CylTrafoParams.hpp | 9 ++--- .../include/utils/math/cyl_trafo_params.hpp | 37 +++++++------------ 9 files changed, 48 insertions(+), 64 deletions(-) diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index b3d3fcde22c..96261a0593f 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -42,8 +42,8 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( folded_position(traits.position(p), box_geo) - - cyl_trafo_params->get_center(), - cyl_trafo_params->get_axis(), cyl_trafo_params->get_orientation())); + cyl_trafo_params->center(), + cyl_trafo_params->axis(), cyl_trafo_params->orientation())); } histogram.normalize(); diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index 325053b8bb4..b5e8c8ba0f9 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -44,13 +44,12 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { auto const pos = folded_position(traits.position(p), box_geo) - - cyl_trafo_params->get_center(); + cyl_trafo_params->center(); histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation()), + pos, cyl_trafo_params->axis(), cyl_trafo_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params->get_axis(), pos)); + traits.velocity(p), cyl_trafo_params->axis(), pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index 29fce46a75a..6ee859a66ea 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -45,20 +45,21 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos - cyl_trafo_params->get_center(), - cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation()), + pos - cyl_trafo_params->center(), + cyl_trafo_params->axis(), + cyl_trafo_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - flux_dens, cyl_trafo_params->get_axis(), - pos - cyl_trafo_params->get_center())); + flux_dens, cyl_trafo_params->axis(), + pos - cyl_trafo_params->center())); } // normalize by number of hits per bin auto hist_tmp = histogram.get_histogram(); auto tot_count = histogram.get_tot_count(); std::transform(hist_tmp.begin(), hist_tmp.end(), tot_count.begin(), - hist_tmp.begin(), - [](auto hi, auto ci) { return ci > 0 ? hi / ci : 0.; }); + hist_tmp.begin(), [](auto hi, auto ci) { + return ci > 0 ? hi / static_cast(ci) : 0.; + }); return hist_tmp; } } // namespace Observables diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index edcc5d8c518..2aa25f8c057 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -49,14 +49,12 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; - auto const theta = - Utils::angle_between(z_axis, cyl_trafo_params->get_axis()); + auto const theta = Utils::angle_between(z_axis, cyl_trafo_params->axis()); auto const rot_axis = - Utils::vector_product(z_axis, cyl_trafo_params->get_axis()) - .normalize(); + Utils::vector_product(z_axis, cyl_trafo_params->axis()).normalize(); if (theta > std::numeric_limits::epsilon()) p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); - p = p_cart + cyl_trafo_params->get_center(); + p = p_cart + cyl_trafo_params->center(); } } std::vector sampling_positions; diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index 56de507c2d9..ca7e4a6059a 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -35,13 +35,12 @@ std::vector CylindricalLBVelocityProfile::operator()() const { for (auto const &p : sampling_positions) { auto const velocity = lb_lbfluid_get_interpolated_velocity(p) * lb_lbfluid_get_lattice_speed(); - auto const pos_shifted = p - cyl_trafo_params->get_center(); + auto const pos_shifted = p - cyl_trafo_params->center(); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( - pos_shifted, cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation()); + pos_shifted, cyl_trafo_params->axis(), cyl_trafo_params->orientation()); histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( - velocity, cyl_trafo_params->get_axis(), pos_shifted)); + velocity, cyl_trafo_params->axis(), pos_shifted)); } auto hist_data = histogram.get_histogram(); auto const tot_count = histogram.get_tot_count(); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index 967aea0d736..6f9122e70e9 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -40,21 +40,21 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( auto const v = lb_lbfluid_get_interpolated_velocity(pos) * lb_lbfluid_get_lattice_speed(); - histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos - cyl_trafo_params->get_center(), - cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation()), - Utils::transform_vector_cartesian_to_cylinder( - v, cyl_trafo_params->get_axis(), - pos - cyl_trafo_params->get_center())); + histogram.update( + Utils::transform_coordinate_cartesian_to_cylinder( + pos - cyl_trafo_params->center(), cyl_trafo_params->axis(), + cyl_trafo_params->orientation()), + Utils::transform_vector_cartesian_to_cylinder( + v, cyl_trafo_params->axis(), pos - cyl_trafo_params->center())); } // normalize by number of hits per bin auto hist_tmp = histogram.get_histogram(); auto tot_count = histogram.get_tot_count(); std::transform(hist_tmp.begin(), hist_tmp.end(), tot_count.begin(), - hist_tmp.begin(), - [](auto hi, auto ci) { return ci > 0 ? hi / ci : 0.; }); + hist_tmp.begin(), [](auto hi, auto ci) { + return ci > 0 ? hi / static_cast(ci) : 0.; + }); return hist_tmp; } diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 5fa0a0b39ed..2d7bedb5ce0 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -44,13 +44,12 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { auto const pos = folded_position(traits.position(p), box_geo) - - cyl_trafo_params->get_center(); + cyl_trafo_params->center(); histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params->get_axis(), - cyl_trafo_params->get_orientation()), + pos, cyl_trafo_params->axis(), cyl_trafo_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params->get_axis(), pos)); + traits.velocity(p), cyl_trafo_params->axis(), pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/script_interface/CylTrafoParams.hpp b/src/script_interface/CylTrafoParams.hpp index c6e817502d8..63f10d22e13 100644 --- a/src/script_interface/CylTrafoParams.hpp +++ b/src/script_interface/CylTrafoParams.hpp @@ -32,12 +32,11 @@ class CylTrafoParams : public AutoParameters { public: CylTrafoParams() { add_parameters({{"center", AutoParameter::read_only, - [this]() { return m_cyl_trafo_params->get_center(); }}, + [this]() { return m_cyl_trafo_params->center(); }}, {"axis", AutoParameter::read_only, - [this]() { return m_cyl_trafo_params->get_axis(); }}, - {"orientation", AutoParameter::read_only, [this]() { - return m_cyl_trafo_params->get_orientation(); - }}}); + [this]() { return m_cyl_trafo_params->axis(); }}, + {"orientation", AutoParameter::read_only, + [this]() { return m_cyl_trafo_params->orientation(); }}}); } std::shared_ptr<::Utils::CylTrafoParams> cyl_trafo_params() { return m_cyl_trafo_params; diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cyl_trafo_params.hpp index 0faf0cd5e8b..c4c62914b99 100644 --- a/src/utils/include/utils/math/cyl_trafo_params.hpp +++ b/src/utils/include/utils/math/cyl_trafo_params.hpp @@ -28,31 +28,20 @@ namespace Utils { class CylTrafoParams { public: - explicit CylTrafoParams( - Utils::Vector3d const ¢er = Utils::Vector3d{{0, 0, 0}}, - Utils::Vector3d const &axis = Utils::Vector3d{{0, 0, 1}}, - Utils::Vector3d const &orientation = Utils::Vector3d{{1, 0, 0}}) + CylTrafoParams() = default; + CylTrafoParams(Utils::Vector3d const ¢er, Utils::Vector3d const &axis, + Utils::Vector3d const &orientation) : m_center(center), m_axis(axis), m_orientation(orientation) { - check_valid(); + validate(); } - Utils::Vector3d get_center() const { return m_center; } - Utils::Vector3d get_axis() const { return m_axis; } - Utils::Vector3d get_orientation() const { return m_orientation; } - - void set_center(Vector3d const ¢er) { m_center = center; } - static void set_axis(Vector3d const ¢er) { - throw std::runtime_error( - "CylTrafoParams: Axis can only be set at construction."); - } - static void set_orientation(Vector3d const ¢er) { - throw std::runtime_error( - "CylTrafoParams: Orientation can only be set at construction."); - } + Utils::Vector3d center() const { return m_center; } + Utils::Vector3d axis() const { return m_axis; } + Utils::Vector3d orientation() const { return m_orientation; } private: - void check_valid() { - auto const eps = 10 * std::numeric_limits::epsilon(); + void validate() const { + auto constexpr eps = 10 * std::numeric_limits::epsilon(); if (Utils::abs(m_orientation * m_axis) > eps) { throw std::runtime_error("CylTrafoParams: Axis and orientation must be " "orthogonal. Scalar product is " + @@ -70,11 +59,11 @@ class CylTrafoParams { } } - Utils::Vector3d m_center; - Utils::Vector3d m_axis; - Utils::Vector3d m_orientation; + const Utils::Vector3d m_center{}; + const Utils::Vector3d m_axis{0, 0, 1}; + const Utils::Vector3d m_orientation{1, 0, 0}; }; } // namespace Utils -#endif // ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP \ No newline at end of file +#endif // ESPRESSO_CYLINDER_TRANSFORMATION_PARAMETERS_HPP From d1ef4e1c973f29931cbb4354a4c1623147ad7cef Mon Sep 17 00:00:00 2001 From: Kai Szuttor Date: Thu, 4 Mar 2021 16:37:46 +0100 Subject: [PATCH 24/31] Remove default from scriptinterface. --- .../CylindricalLBProfileObservable.hpp | 33 +++++++++---------- .../CylindricalPidProfileObservable.hpp | 31 +++++++++-------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index 399b3584c95..ca1a487e01e 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -55,7 +55,7 @@ class CylindricalLBProfileObservable using Base::Base; CylindricalLBProfileObservable() { this->add_parameters({ - {"cyl_trafo_params", m_cyl_trafo_params}, + {"cyl_trafo_params", Utils::as_const(m_cyl_trafo_params)}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = @@ -140,22 +140,21 @@ class CylindricalLBProfileObservable } void do_construct(VariantMap const ¶ms) override { - if (params.count("cyl_trafo_params")) { - set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); - } else { - m_cyl_trafo_params = std::make_shared(); - } - m_observable = std::make_shared( - m_cyl_trafo_params->cyl_trafo_params(), - get_value_or(params, "n_r_bins", 1), - get_value_or(params, "n_phi_bins", 1), - get_value_or(params, "n_z_bins", 1), - get_value_or(params, "min_r", 0.), - get_value(params, "max_r"), - get_value_or(params, "min_phi", -Utils::pi()), - get_value_or(params, "max_phi", Utils::pi()), - get_value(params, "min_z"), get_value(params, "max_z"), - get_value(params, "sampling_density")); + set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + + if (m_cyl_trafo_params) + m_observable = std::make_shared( + m_cyl_trafo_params->cyl_trafo_params(), + get_value_or(params, "n_r_bins", 1), + get_value_or(params, "n_phi_bins", 1), + get_value_or(params, "n_z_bins", 1), + get_value_or(params, "min_r", 0.), + get_value(params, "max_r"), + get_value_or(params, "min_phi", -Utils::pi()), + get_value_or(params, "max_phi", Utils::pi()), + get_value(params, "min_z"), + get_value(params, "max_z"), + get_value(params, "sampling_density")); } Variant do_call_method(std::string const &method, diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index 14e93d92b4e..06277cc1616 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -141,22 +141,21 @@ class CylindricalPidProfileObservable }; void do_construct(VariantMap const ¶ms) override { - if (params.count("cyl_trafo_params")) { - set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); - } else { - m_cyl_trafo_params = std::make_shared(); - } - m_observable = std::make_shared( - get_value>(params, "ids"), - m_cyl_trafo_params->cyl_trafo_params(), - get_value_or(params, "n_r_bins", 1), - get_value_or(params, "n_phi_bins", 1), - get_value_or(params, "n_z_bins", 1), - get_value_or(params, "min_r", 0.), - get_value(params, "max_r"), - get_value_or(params, "min_phi", -Utils::pi()), - get_value_or(params, "max_phi", Utils::pi()), - get_value(params, "min_z"), get_value(params, "max_z")); + set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + + if (m_cyl_trafo_params) + m_observable = std::make_shared( + get_value>(params, "ids"), + m_cyl_trafo_params->cyl_trafo_params(), + get_value_or(params, "n_r_bins", 1), + get_value_or(params, "n_phi_bins", 1), + get_value_or(params, "n_z_bins", 1), + get_value_or(params, "min_r", 0.), + get_value(params, "max_r"), + get_value_or(params, "min_phi", -Utils::pi()), + get_value_or(params, "max_phi", Utils::pi()), + get_value(params, "min_z"), + get_value(params, "max_z")); } Variant do_call_method(std::string const &method, From 263d77ac652745adf39dfef3da33a5d1a309ef4c Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Thu, 4 Mar 2021 17:36:07 +0100 Subject: [PATCH 25/31] move ctp default to python --- src/python/espressomd/observables.py | 26 ++++++++++++++----- .../CylindricalLBProfileObservable.hpp | 2 +- testsuite/python/lb_poiseuille_cylinder.py | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 33766e6c12b..e4d645f9773 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -17,6 +17,7 @@ import itertools import numpy as np from .script_interface import ScriptInterfaceHelper, script_interface_register +from .math import CylTrafoParams @script_interface_register @@ -69,6 +70,18 @@ def bin_centers(self): return np.array(list(itertools.product(*edges))).reshape(shape) +class CylindricalProfileObservable(ProfileObservable): + """ + Base class for observables that work with cylinder coordinates + """ + + def __init__(self, **kwargs): + if "oid" not in kwargs and "cyl_trafo_params" not in kwargs: + # If the user does not provide cyl_trafo_params, use the default + kwargs["cyl_trafo_params"] = CylTrafoParams() + super().__init__(**kwargs) + + @script_interface_register class ComPosition(Observable): @@ -636,7 +649,7 @@ class DPDStress(Observable): @script_interface_register -class CylindricalDensityProfile(ProfileObservable): +class CylindricalDensityProfile(CylindricalProfileObservable): """Calculates the particle density in cylindrical coordinates. @@ -678,7 +691,7 @@ class CylindricalDensityProfile(ProfileObservable): @script_interface_register -class CylindricalFluxDensityProfile(ProfileObservable): +class CylindricalFluxDensityProfile(CylindricalProfileObservable): """Calculates the particle flux density in cylindrical coordinates. @@ -722,7 +735,8 @@ class CylindricalFluxDensityProfile(ProfileObservable): @script_interface_register -class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): +class CylindricalLBFluxDensityProfileAtParticlePositions( + CylindricalProfileObservable): """Calculates the LB fluid flux density at the particle positions in cylindrical coordinates. @@ -768,7 +782,7 @@ class CylindricalLBFluxDensityProfileAtParticlePositions(ProfileObservable): @script_interface_register class CylindricalLBVelocityProfileAtParticlePositions( - ProfileObservable): + CylindricalProfileObservable): """Calculates the LB fluid velocity at the particle positions in cylindrical coordinates. @@ -813,7 +827,7 @@ class CylindricalLBVelocityProfileAtParticlePositions( @script_interface_register -class CylindricalVelocityProfile(ProfileObservable): +class CylindricalVelocityProfile(CylindricalProfileObservable): """Calculates the particle velocity profile in cylindrical coordinates. @@ -857,7 +871,7 @@ class CylindricalVelocityProfile(ProfileObservable): @script_interface_register -class CylindricalLBVelocityProfile(ProfileObservable): +class CylindricalLBVelocityProfile(CylindricalProfileObservable): """Calculates the LB fluid velocity profile in cylindrical coordinates. diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index ca1a487e01e..e3890fbb373 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -55,7 +55,7 @@ class CylindricalLBProfileObservable using Base::Base; CylindricalLBProfileObservable() { this->add_parameters({ - {"cyl_trafo_params", Utils::as_const(m_cyl_trafo_params)}, + {"cyl_trafo_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index e7e60f067f2..dd5610d0f80 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -155,7 +155,7 @@ def prepare_obs(self): ctp = espressomd.math.CylTrafoParams(center=obs_center, axis=self.params['axis'], orientation=self.params['orientation']) - local_obs_params['cyl_obs_params'] = ctp + local_obs_params['cyl_trafo_params'] = ctp obs = espressomd.observables.CylindricalLBVelocityProfile( **local_obs_params) self.accumulator = espressomd.accumulators.MeanVarianceCalculator( From a9e1fe6dedf7c518f31e2242b9963f4438103586 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Fri, 5 Mar 2021 12:16:25 +0100 Subject: [PATCH 26/31] using std::move to pass shared ptrs --- src/core/observables/CylindricalLBProfileObservable.hpp | 7 ++++--- src/core/observables/CylindricalPidProfileObservable.hpp | 8 +++++--- src/core/observables/CylindricalProfileObservable.hpp | 3 ++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index 2aa25f8c057..72c8cfdcd91 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -21,6 +21,7 @@ #include "CylindricalProfileObservable.hpp" +#include #include #include #include @@ -34,9 +35,9 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { std::shared_ptr cyl_trafo_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z, double sampling_density) - : CylindricalProfileObservable(cyl_trafo_params, n_r_bins, n_phi_bins, - n_z_bins, min_r, max_r, min_phi, max_phi, - min_z, max_z), + : CylindricalProfileObservable(std::move(cyl_trafo_params), n_r_bins, + n_phi_bins, n_z_bins, min_r, max_r, + min_phi, max_phi, min_z, max_z), sampling_density(sampling_density) { calculate_sampling_positions(); } diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index ea65e6fc3b7..7ecfeac00aa 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -19,6 +19,8 @@ #ifndef OBSERVABLES_CYLINDRICALPIDPROFILEOBSERVABLE_HPP #define OBSERVABLES_CYLINDRICALPIDPROFILEOBSERVABLE_HPP +#include + #include "CylindricalProfileObservable.hpp" #include "PidObservable.hpp" @@ -33,9 +35,9 @@ class CylindricalPidProfileObservable : public PidObservable, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : PidObservable(ids), - CylindricalProfileObservable(cyl_trafo_params, n_r_bins, n_phi_bins, - n_z_bins, min_r, max_r, min_phi, max_phi, - min_z, max_z) {} + CylindricalProfileObservable(std::move(cyl_trafo_params), n_r_bins, + n_phi_bins, n_z_bins, min_r, max_r, + min_phi, max_phi, min_z, max_z) {} }; } // Namespace Observables diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index 55abb638971..f16030f968d 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include namespace Observables { @@ -45,7 +46,7 @@ class CylindricalProfileObservable : public ProfileObservable { double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), - cyl_trafo_params(cyl_trafo_params) {} + cyl_trafo_params(std::move(cyl_trafo_params)) {} std::shared_ptr cyl_trafo_params; }; From 17b81c460de6605adbde2bf8aebcb7755ec29de0 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Mon, 8 Mar 2021 17:55:02 +0100 Subject: [PATCH 27/31] rename cyltraforparams --- .../observables/CylindricalDensityProfile.hpp | 5 ++- .../CylindricalFluxDensityProfile.hpp | 8 ++--- ...BFluxDensityProfileAtParticlePositions.cpp | 13 ++++--- .../CylindricalLBProfileObservable.hpp | 15 ++++---- .../CylindricalLBVelocityProfile.cpp | 9 +++-- ...alLBVelocityProfileAtParticlePositions.cpp | 6 ++-- .../CylindricalPidProfileObservable.hpp | 8 ++--- .../CylindricalProfileObservable.hpp | 12 +++---- .../CylindricalVelocityProfile.hpp | 8 ++--- src/python/espressomd/math.py | 4 +-- src/python/espressomd/observables.py | 10 +++--- ...> CylindricalTransformationParameters.hpp} | 35 ++++++++++--------- src/script_interface/initialize.cpp | 5 +-- .../CylindricalLBProfileObservable.hpp | 8 ++--- .../CylindricalPidProfileObservable.hpp | 8 ++--- ...cylindrical_transformation_parameters.hpp} | 28 ++++++++------- testsuite/python/lb_poiseuille_cylinder.py | 8 ++--- testsuite/python/observable_cylindrical.py | 19 +++++----- testsuite/python/observable_cylindricalLB.py | 20 ++++++----- 19 files changed, 117 insertions(+), 112 deletions(-) rename src/script_interface/{CylTrafoParams.hpp => CylindricalTransformationParameters.hpp} (54%) rename src/utils/include/utils/math/{cyl_trafo_params.hpp => cylindrical_transformation_parameters.hpp} (66%) diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index 96261a0593f..a071aa737dc 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -41,9 +41,8 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - folded_position(traits.position(p), box_geo) - - cyl_trafo_params->center(), - cyl_trafo_params->axis(), cyl_trafo_params->orientation())); + folded_position(traits.position(p), box_geo) - trafo_params->center(), + trafo_params->axis(), trafo_params->orientation())); } histogram.normalize(); diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index b5e8c8ba0f9..e4d114e8668 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -43,13 +43,13 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - - cyl_trafo_params->center(); + auto const pos = + folded_position(traits.position(p), box_geo) - trafo_params->center(); histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params->axis(), cyl_trafo_params->orientation()), + pos, trafo_params->axis(), trafo_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params->axis(), pos)); + traits.velocity(p), trafo_params->axis(), pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index 6ee859a66ea..b01cf78f311 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -44,13 +44,12 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( lb_lbfluid_get_lattice_speed(); auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; - histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - pos - cyl_trafo_params->center(), - cyl_trafo_params->axis(), - cyl_trafo_params->orientation()), - Utils::transform_vector_cartesian_to_cylinder( - flux_dens, cyl_trafo_params->axis(), - pos - cyl_trafo_params->center())); + histogram.update( + Utils::transform_coordinate_cartesian_to_cylinder( + pos - trafo_params->center(), trafo_params->axis(), + trafo_params->orientation()), + Utils::transform_vector_cartesian_to_cylinder( + flux_dens, trafo_params->axis(), pos - trafo_params->center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index 72c8cfdcd91..e9ce648cabe 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -32,10 +32,11 @@ namespace Observables { class CylindricalLBProfileObservable : public CylindricalProfileObservable { public: CylindricalLBProfileObservable( - std::shared_ptr cyl_trafo_params, int n_r_bins, - int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, - double max_phi, double min_z, double max_z, double sampling_density) - : CylindricalProfileObservable(std::move(cyl_trafo_params), n_r_bins, + std::shared_ptr trafo_params, + int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, + double min_phi, double max_phi, double min_z, double max_z, + double sampling_density) + : CylindricalProfileObservable(std::move(trafo_params), n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), sampling_density(sampling_density) { @@ -50,12 +51,12 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; - auto const theta = Utils::angle_between(z_axis, cyl_trafo_params->axis()); + auto const theta = Utils::angle_between(z_axis, trafo_params->axis()); auto const rot_axis = - Utils::vector_product(z_axis, cyl_trafo_params->axis()).normalize(); + Utils::vector_product(z_axis, trafo_params->axis()).normalize(); if (theta > std::numeric_limits::epsilon()) p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); - p = p_cart + cyl_trafo_params->center(); + p = p_cart + trafo_params->center(); } } std::vector sampling_positions; diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index ca7e4a6059a..2b32b348c31 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -35,12 +35,11 @@ std::vector CylindricalLBVelocityProfile::operator()() const { for (auto const &p : sampling_positions) { auto const velocity = lb_lbfluid_get_interpolated_velocity(p) * lb_lbfluid_get_lattice_speed(); - auto const pos_shifted = p - cyl_trafo_params->center(); + auto const pos_shifted = p - trafo_params->center(); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( - pos_shifted, cyl_trafo_params->axis(), cyl_trafo_params->orientation()); - histogram.update(pos_cyl, - Utils::transform_vector_cartesian_to_cylinder( - velocity, cyl_trafo_params->axis(), pos_shifted)); + pos_shifted, trafo_params->axis(), trafo_params->orientation()); + histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( + velocity, trafo_params->axis(), pos_shifted)); } auto hist_data = histogram.get_histogram(); auto const tot_count = histogram.get_tot_count(); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index 6f9122e70e9..e55178e956e 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -42,10 +42,10 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos - cyl_trafo_params->center(), cyl_trafo_params->axis(), - cyl_trafo_params->orientation()), + pos - trafo_params->center(), trafo_params->axis(), + trafo_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - v, cyl_trafo_params->axis(), pos - cyl_trafo_params->center())); + v, trafo_params->axis(), pos - trafo_params->center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index 7ecfeac00aa..8478d451c11 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -31,11 +31,11 @@ class CylindricalPidProfileObservable : public PidObservable, public: CylindricalPidProfileObservable( std::vector const &ids, - std::shared_ptr cyl_trafo_params, int n_r_bins, - int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, - double max_phi, double min_z, double max_z) + std::shared_ptr trafo_params, + int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, + double min_phi, double max_phi, double min_z, double max_z) : PidObservable(ids), - CylindricalProfileObservable(std::move(cyl_trafo_params), n_r_bins, + CylindricalProfileObservable(std::move(trafo_params), n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z) {} }; diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index f16030f968d..7fe81aad127 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -41,14 +41,14 @@ namespace Observables { class CylindricalProfileObservable : public ProfileObservable { public: CylindricalProfileObservable( - std::shared_ptr cyl_trafo_params, int n_r_bins, - int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, - double max_phi, double min_z, double max_z) + std::shared_ptr trafo_params, + int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, + double min_phi, double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), - cyl_trafo_params(std::move(cyl_trafo_params)) {} + trafo_params(std::move(trafo_params)) {} - std::shared_ptr cyl_trafo_params; + std::shared_ptr trafo_params; }; } // Namespace Observables diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 2d7bedb5ce0..76a0d49872b 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -43,13 +43,13 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { Utils::CylindricalHistogram histogram(n_bins, 3, limits); for (auto p : particles) { - auto const pos = folded_position(traits.position(p), box_geo) - - cyl_trafo_params->center(); + auto const pos = + folded_position(traits.position(p), box_geo) - trafo_params->center(); histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos, cyl_trafo_params->axis(), cyl_trafo_params->orientation()), + pos, trafo_params->axis(), trafo_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), cyl_trafo_params->axis(), pos)); + traits.velocity(p), trafo_params->axis(), pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/python/espressomd/math.py b/src/python/espressomd/math.py index 01417419ff7..d23fd8bce77 100644 --- a/src/python/espressomd/math.py +++ b/src/python/espressomd/math.py @@ -2,5 +2,5 @@ @script_interface_register -class CylTrafoParams(ScriptInterfaceHelper): - _so_name = "CylTrafoParams" +class CylindricalTransformationParameters(ScriptInterfaceHelper): + _so_name = "CylindricalTransformationParameters" diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index e4d645f9773..4c50f0237cd 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -17,7 +17,7 @@ import itertools import numpy as np from .script_interface import ScriptInterfaceHelper, script_interface_register -from .math import CylTrafoParams +from .math import CylindricalTransformationParameters @script_interface_register @@ -75,10 +75,10 @@ class CylindricalProfileObservable(ProfileObservable): Base class for observables that work with cylinder coordinates """ - def __init__(self, **kwargs): - if "oid" not in kwargs and "cyl_trafo_params" not in kwargs: - # If the user does not provide cyl_trafo_params, use the default - kwargs["cyl_trafo_params"] = CylTrafoParams() + def __init__( + self, trafo_params=CylindricalTransformationParameters(), **kwargs): + # Provide default transformation parameters if not user-provided + kwargs['trafo_params'] = trafo_params super().__init__(**kwargs) diff --git a/src/script_interface/CylTrafoParams.hpp b/src/script_interface/CylindricalTransformationParameters.hpp similarity index 54% rename from src/script_interface/CylTrafoParams.hpp rename to src/script_interface/CylindricalTransformationParameters.hpp index 63f10d22e13..564852f7389 100644 --- a/src/script_interface/CylTrafoParams.hpp +++ b/src/script_interface/CylindricalTransformationParameters.hpp @@ -24,35 +24,38 @@ #include "script_interface/ScriptInterface.hpp" -#include "utils/math/cyl_trafo_params.hpp" +#include "utils/math/cylindrical_transformation_parameters.hpp" namespace ScriptInterface { -class CylTrafoParams : public AutoParameters { +class CylindricalTransformationParameters + : public AutoParameters { public: - CylTrafoParams() { + CylindricalTransformationParameters() { add_parameters({{"center", AutoParameter::read_only, - [this]() { return m_cyl_trafo_params->center(); }}, + [this]() { return m_trafo_params->center(); }}, {"axis", AutoParameter::read_only, - [this]() { return m_cyl_trafo_params->axis(); }}, + [this]() { return m_trafo_params->axis(); }}, {"orientation", AutoParameter::read_only, - [this]() { return m_cyl_trafo_params->orientation(); }}}); + [this]() { return m_trafo_params->orientation(); }}}); } - std::shared_ptr<::Utils::CylTrafoParams> cyl_trafo_params() { - return m_cyl_trafo_params; + std::shared_ptr<::Utils::CylindricalTransformationParameters> + cyl_trafo_params() { + return m_trafo_params; } void do_construct(VariantMap const ¶ms) override { - m_cyl_trafo_params = std::make_shared( - get_value_or(params, "center", - Utils::Vector3d{{0, 0, 0}}), - get_value_or(params, "axis", - Utils::Vector3d{{0, 0, 1}}), - get_value_or(params, "orientation", - Utils::Vector3d{{1, 0, 0}})); + m_trafo_params = + std::make_shared( + get_value_or(params, "center", + Utils::Vector3d{{0, 0, 0}}), + get_value_or(params, "axis", + Utils::Vector3d{{0, 0, 1}}), + get_value_or(params, "orientation", + Utils::Vector3d{{1, 0, 0}})); } private: - std::shared_ptr m_cyl_trafo_params; + std::shared_ptr m_trafo_params; }; } // namespace ScriptInterface #endif diff --git a/src/script_interface/initialize.cpp b/src/script_interface/initialize.cpp index c5c6a538d81..f971b29ae12 100644 --- a/src/script_interface/initialize.cpp +++ b/src/script_interface/initialize.cpp @@ -29,7 +29,7 @@ #include "h5md/initialize.hpp" #endif #include "ComFixed.hpp" -#include "CylTrafoParams.hpp" +#include "CylindricalTransformationParameters.hpp" #include "accumulators/initialize.hpp" #include "collision_detection/initialize.hpp" #include "lbboundaries/initialize.hpp" @@ -54,7 +54,8 @@ void initialize(Utils::Factory *f) { CollisionDetection::initialize(f); f->register_new("ComFixed"); - f->register_new("CylTrafoParams"); + f->register_new( + "CylindricalTransformationParameters"); } } /* namespace ScriptInterface */ diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index e3890fbb373..34bc7a21d08 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -28,7 +28,7 @@ #include "core/observables/CylindricalLBProfileObservable.hpp" #include "script_interface/get_value.hpp" -#include "script_interface/CylTrafoParams.hpp" +#include "script_interface/CylindricalTransformationParameters.hpp" #include @@ -55,7 +55,7 @@ class CylindricalLBProfileObservable using Base::Base; CylindricalLBProfileObservable() { this->add_parameters({ - {"cyl_trafo_params", m_cyl_trafo_params}, + {"trafo_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = @@ -140,7 +140,7 @@ class CylindricalLBProfileObservable } void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + set_from_args(m_cyl_trafo_params, params, "trafo_params"); if (m_cyl_trafo_params) m_observable = std::make_shared( @@ -179,7 +179,7 @@ class CylindricalLBProfileObservable private: std::shared_ptr m_observable; - std::shared_ptr m_cyl_trafo_params; + std::shared_ptr m_cyl_trafo_params; }; } /* namespace Observables */ diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index 06277cc1616..a48694869a1 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -27,7 +27,7 @@ #include "Observable.hpp" #include "core/observables/CylindricalPidProfileObservable.hpp" -#include +#include #include #include @@ -61,7 +61,7 @@ class CylindricalPidProfileObservable get_value>(v); }, [this]() { return cylindrical_pid_profile_observable()->ids(); }}, - {"cyl_trafo_params", m_cyl_trafo_params}, + {"trafo_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_pid_profile_observable()->n_bins[0] = @@ -141,7 +141,7 @@ class CylindricalPidProfileObservable }; void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "cyl_trafo_params"); + set_from_args(m_cyl_trafo_params, params, "trafo_params"); if (m_cyl_trafo_params) m_observable = std::make_shared( @@ -180,7 +180,7 @@ class CylindricalPidProfileObservable private: std::shared_ptr m_observable; - std::shared_ptr m_cyl_trafo_params; + std::shared_ptr m_cyl_trafo_params; }; } /* namespace Observables */ diff --git a/src/utils/include/utils/math/cyl_trafo_params.hpp b/src/utils/include/utils/math/cylindrical_transformation_parameters.hpp similarity index 66% rename from src/utils/include/utils/math/cyl_trafo_params.hpp rename to src/utils/include/utils/math/cylindrical_transformation_parameters.hpp index c4c62914b99..4646805ebdf 100644 --- a/src/utils/include/utils/math/cyl_trafo_params.hpp +++ b/src/utils/include/utils/math/cylindrical_transformation_parameters.hpp @@ -26,11 +26,12 @@ namespace Utils { -class CylTrafoParams { +class CylindricalTransformationParameters { public: - CylTrafoParams() = default; - CylTrafoParams(Utils::Vector3d const ¢er, Utils::Vector3d const &axis, - Utils::Vector3d const &orientation) + CylindricalTransformationParameters() = default; + CylindricalTransformationParameters(Utils::Vector3d const ¢er, + Utils::Vector3d const &axis, + Utils::Vector3d const &orientation) : m_center(center), m_axis(axis), m_orientation(orientation) { validate(); } @@ -43,19 +44,20 @@ class CylTrafoParams { void validate() const { auto constexpr eps = 10 * std::numeric_limits::epsilon(); if (Utils::abs(m_orientation * m_axis) > eps) { - throw std::runtime_error("CylTrafoParams: Axis and orientation must be " - "orthogonal. Scalar product is " + - std::to_string(m_orientation * m_axis)); + throw std::runtime_error( + "CylindricalTransformationParameters: Axis and orientation must be " + "orthogonal. Scalar product is " + + std::to_string(m_orientation * m_axis)); } if (Utils::abs(m_axis.norm() - 1) > eps) { - throw std::runtime_error( - "CylTrafoParams: Axis must be normalized. Norm is " + - std::to_string(m_axis.norm())); + throw std::runtime_error("CylindricalTransformationParameters: Axis must " + "be normalized. Norm is " + + std::to_string(m_axis.norm())); } if (Utils::abs(m_orientation.norm() - 1) > eps) { - throw std::runtime_error( - "CylTrafoParams: orientation must be normalized. Norm is " + - std::to_string(m_orientation.norm())); + throw std::runtime_error("CylindricalTransformationParameters: " + "orientation must be normalized. Norm is " + + std::to_string(m_orientation.norm())); } } diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index dd5610d0f80..933a1bc6bac 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -152,10 +152,10 @@ def prepare_obs(self): else: obs_center = [BOX_L / 2.0, BOX_L / 2.0, 0.0] local_obs_params = OBS_PARAMS.copy() - ctp = espressomd.math.CylTrafoParams(center=obs_center, - axis=self.params['axis'], - orientation=self.params['orientation']) - local_obs_params['cyl_trafo_params'] = ctp + ctp = espressomd.math.CylindricalTransformationParameters(center=obs_center, + axis=self.params['axis'], + orientation=self.params['orientation']) + local_obs_params['trafo_params'] = ctp obs = espressomd.observables.CylindricalLBVelocityProfile( **local_obs_params) self.accumulator = espressomd.accumulators.MeanVarianceCalculator( diff --git a/testsuite/python/observable_cylindrical.py b/testsuite/python/observable_cylindrical.py index 73dfd0ab729..709dca89a4a 100644 --- a/testsuite/python/observable_cylindrical.py +++ b/testsuite/python/observable_cylindrical.py @@ -32,14 +32,12 @@ class TestCylindricalObservable(ut.TestCase): system.time_step = 0.01 system.cell_system.skin = 0.4 - cyl_trafo_params = espressomd.math.CylTrafoParams(center=3 * [7.5], - axis=[ - 1 / np.sqrt(2), 1 / np.sqrt(2), 0], - orientation=[0, 0, 1]) + cyl_trafo_params = espressomd.math.CylindricalTransformationParameters( + center=3 * [7.5], axis=[1 / np.sqrt(2), 1 / np.sqrt(2), 0], orientation=[0, 0, 1]) params = { 'ids': None, - 'cyl_trafo_params': cyl_trafo_params, + 'trafo_params': cyl_trafo_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 4, @@ -245,14 +243,15 @@ def test_cylindrical_pid_profile_interface(self): obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) # check center, axis, orientation - ctp = espressomd.math.CylTrafoParams(center=[1, 2, 3], - axis=[0, 1, 0], - orientation=[0, 0, 1]) - observable.cyl_trafo_params = ctp + ctp = espressomd.math.CylindricalTransformationParameters(center=[1, 2, 3], + axis=[ + 0, 1, 0], + orientation=[0, 0, 1]) + observable.trafo_params = ctp for attr_name in ['center', 'axis', 'orientation']: np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), - np.copy(observable.cyl_trafo_params.__getattr__(attr_name))) + np.copy(observable.trafo_params.__getattr__(attr_name))) if __name__ == "__main__": diff --git a/testsuite/python/observable_cylindricalLB.py b/testsuite/python/observable_cylindricalLB.py index 8c8e0d4c631..5dee2b7e79a 100644 --- a/testsuite/python/observable_cylindricalLB.py +++ b/testsuite/python/observable_cylindricalLB.py @@ -41,13 +41,14 @@ class CylindricalLBObservableCommon: 'visc': 2.7, 'tau': 0.1, } - cyl_trafo_params = espressomd.math.CylTrafoParams(center=3 * [7], - axis=[1, 0, 0], - orientation=[0, 0, 1]) + cyl_trafo_params = espressomd.math.CylindricalTransformationParameters(center=3 * [7], + axis=[ + 1, 0, 0], + orientation=[0, 0, 1]) params = { 'ids': None, - 'cyl_trafo_params': cyl_trafo_params, + 'trafo_params': cyl_trafo_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 5, @@ -212,14 +213,15 @@ def test_cylindrical_lb_profile_interface(self): obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) # check center, axis, orientation - ctp = espressomd.math.CylTrafoParams(center=[1, 2, 3], - axis=[0, 1, 0], - orientation=[0, 0, 1]) - observable.cyl_trafo_params = ctp + ctp = espressomd.math.CylindricalTransformationParameters(center=[1, 2, 3], + axis=[ + 0, 1, 0], + orientation=[0, 0, 1]) + observable.trafo_params = ctp for attr_name in ['center', 'axis', 'orientation']: np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), - np.copy(observable.cyl_trafo_params.__getattr__(attr_name))) + np.copy(observable.trafo_params.__getattr__(attr_name))) class CylindricalLBObservableCPU(ut.TestCase, CylindricalLBObservableCommon): From 9be3f01d1fcbea8898e7546f0e118ff4fc711e42 Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Mon, 8 Mar 2021 18:53:27 +0100 Subject: [PATCH 28/31] docs --- doc/sphinx/analysis.rst | 16 ++- src/python/espressomd/math.py | 30 +++++ src/python/espressomd/observables.py | 120 +++++++----------- .../cylindrical_transformation_parameters.hpp | 9 ++ 4 files changed, 101 insertions(+), 74 deletions(-) diff --git a/doc/sphinx/analysis.rst b/doc/sphinx/analysis.rst index d15f3cf7707..444ed8cc853 100644 --- a/doc/sphinx/analysis.rst +++ b/doc/sphinx/analysis.rst @@ -411,10 +411,22 @@ or bin edges for the axes. Example:: density_profile.min_y, density_profile.max_y]) plt.show() +Observables based on cylindrical coordinates are also available. +They require special parameters if the cylindrical coordinate system is non-standard, e.g. if you want the origin of the cylindrical coordinates to be at a special location of the box or if you want to make use of symmetries along an axis that is not parallel to the z-axis. +For this purpose, use :class:`espressomd.math.CylindricalTransformationParameters` to create a consistent set of the parameters needed. Example:: + + import espressomd.math + + # shifted and rotated cylindrical coordinates + cyl_trafo_params = espressomd.math(center=[5.0, 5.0, 0.0], + axis=[0, 1, 0], + orientation=[0, 0, 1]) + # histogram in cylindrical coordinates density_profile = espressomd.observables.CylindricalDensityProfile( - ids=[0, 1], center=[5.0, 5.0, 0.0], axis=[0, 0, 1], - n_r_bins=8, min_r=0.0, max_r=4.0, + ids=[0, 1], + trafo_params = cyl_trafo_params, + n_r_bins=8, min_r=1.0, max_r=4.0, n_phi_bins=16, min_phi=-np.pi, max_phi=np.pi, n_z_bins=4, min_z=4.0, max_z=8.0) obs_data = density_profile.calculate() diff --git a/src/python/espressomd/math.py b/src/python/espressomd/math.py index d23fd8bce77..5b7ff893eb4 100644 --- a/src/python/espressomd/math.py +++ b/src/python/espressomd/math.py @@ -1,6 +1,36 @@ +# Copyright (C) 2010-2019 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + from .script_interface import ScriptInterfaceHelper, script_interface_register @script_interface_register class CylindricalTransformationParameters(ScriptInterfaceHelper): + """ + Class to hold and validate the parameters needed for a cylindrical transformation. + The three parameters are available as attributes but are read-only. + + Parameters + ---------- + center : (3,) array_like of :obj:`float`, default = [0, 0, 0] + Position of the origin of the cylindrical coordinate system. + axis : (3,) array_like of :obj:`float`, default = [0, 0, 1] + Orientation vector of the ``z``-axis of the cylindrical coordinate system. + orientation: (3,) array_like of :obj:`float`, default = [1, 0, 0] + The axis on which ``phi = 0``. + """ _so_name = "CylindricalTransformationParameters" diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index 4c50f0237cd..f16a0cc59f8 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -657,27 +657,23 @@ class CylindricalDensityProfile(CylindricalProfileObservable): ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - center : (3,) array_like of :obj:`float` - Position of the center of the cylindrical coordinate system for the histogram. - axis : (3,) array_like of :obj:`float` - Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. - orientation: (3,) array_like of :obj:`float` - The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. - n_r_bins : :obj:`int` + trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. - n_phi_bins : :obj:`int` + n_phi_bins : :obj:`int`, default = 1 Number of bins for the azimuthal direction. - n_z_bins : :obj:`int` + n_z_bins : :obj:`int`, default = 1 Number of bins in ``z`` direction. - min_r : :obj:`float` + min_r : :obj:`float`, default = 0 Minimum ``r`` to consider. - min_phi : :obj:`float` + min_phi : :obj:`float`, default = -pi Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. - max_phi : :obj:`float` + max_phi : :obj:`float`, default = pi Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -699,27 +695,23 @@ class CylindricalFluxDensityProfile(CylindricalProfileObservable): ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - center : (3,) array_like of :obj:`float` - Position of the center of the cylindrical coordinate system for the histogram. - axis : (3,) array_like of :obj:`float` - Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. - orientation: (3,) array_like of :obj:`float` - The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. - n_r_bins : :obj:`int` + trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. - n_phi_bins : :obj:`int` + n_phi_bins : :obj:`int`, default = 1 Number of bins for the azimuthal direction. - n_z_bins : :obj:`int` + n_z_bins : :obj:`int`, default = 1 Number of bins in ``z`` direction. - min_r : :obj:`float` + min_r : :obj:`float`, default = 0 Minimum ``r`` to consider. - min_phi : :obj:`float` + min_phi : :obj:`float`, default = -pi Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. - max_phi : :obj:`float` + max_phi : :obj:`float`, default = pi Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -745,27 +737,23 @@ class CylindricalLBFluxDensityProfileAtParticlePositions( ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - center : (3,) array_like of :obj:`float` - Position of the center of the cylindrical coordinate system for the histogram. - axis : (3,) array_like of :obj:`float` - Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. - orientation: (3,) array_like of :obj:`float` - The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. - n_r_bins : :obj:`int` + trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. - n_phi_bins : :obj:`int` + n_phi_bins : :obj:`int`, default = 1 Number of bins for the azimuthal direction. - n_z_bins : :obj:`int` + n_z_bins : :obj:`int`, default = 1 Number of bins in ``z`` direction. - min_r : :obj:`float` + min_r : :obj:`float`, default = 0 Minimum ``r`` to consider. - min_phi : :obj:`float` + min_phi : :obj:`float`, default = -pi Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. - max_phi : :obj:`float` + max_phi : :obj:`float`, default = pi Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -791,27 +779,23 @@ class CylindricalLBVelocityProfileAtParticlePositions( ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - center : (3,) array_like of :obj:`float` - Position of the center of the cylindrical coordinate system for the histogram. - axis : (3,) array_like of :obj:`float` - Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. - orientation: (3,) array_like of :obj:`float` - The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. - n_r_bins : :obj:`int` + trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. - n_phi_bins : :obj:`int` + n_phi_bins : :obj:`int`, default = 1 Number of bins for the azimuthal direction. - n_z_bins : :obj:`int` + n_z_bins : :obj:`int`, default = 1 Number of bins in ``z`` direction. - min_r : :obj:`float` + min_r : :obj:`float`, default = 0 Minimum ``r`` to consider. - min_phi : :obj:`float` + min_phi : :obj:`float`, default = -pi Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. - max_phi : :obj:`float` + max_phi : :obj:`float`, default = pi Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -835,27 +819,23 @@ class CylindricalVelocityProfile(CylindricalProfileObservable): ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - center : (3,) array_like of :obj:`float` - Position of the center of the cylindrical coordinate system for the histogram. - axis : (3,) array_like of :obj:`float` - Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. - orientation: (3,) array_like of :obj:`float` - The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. - n_r_bins : :obj:`int` + trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. - n_phi_bins : :obj:`int` + n_phi_bins : :obj:`int`, default = 1 Number of bins for the azimuthal direction. - n_z_bins : :obj:`int` + n_z_bins : :obj:`int`, default = 1 Number of bins in ``z`` direction. - min_r : :obj:`float` + min_r : :obj:`float`, default = 0 Minimum ``r`` to consider. - min_phi : :obj:`float` + min_phi : :obj:`float`, default = -pi Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. - max_phi : :obj:`float` + max_phi : :obj:`float`, default = pi Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. @@ -881,27 +861,23 @@ class CylindricalLBVelocityProfile(CylindricalProfileObservable): Parameters ---------- - center : (3,) array_like of :obj:`float` - Position of the center of the cylindrical coordinate system for the histogram. - axis : (3,) array_like of :obj:`float` - Orientation vector of the ``z``-axis of the cylindrical coordinate system for the histogram. - orientation: (3,) array_like of :obj:`float` - The axis on which ``phi = 0``. Can be omitted if ``n_phi_bins == 1``. - n_r_bins : :obj:`int` + trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. - n_phi_bins : :obj:`int` + n_phi_bins : :obj:`int`, default = 1 Number of bins for the azimuthal direction. - n_z_bins : :obj:`int` + n_z_bins : :obj:`int`, default = 1 Number of bins in ``z`` direction. - min_r : :obj:`float` + min_r : :obj:`float`, default = 0 Minimum ``r`` to consider. - min_phi : :obj:`float` + min_phi : :obj:`float`, default = -pi Minimum ``phi`` to consider. Must be in [-pi,pi). min_z : :obj:`float` Minimum ``z`` to consider. max_r : :obj:`float` Maximum ``r`` to consider. - max_phi : :obj:`float` + max_phi : :obj:`float`, default = pi Maximum ``phi`` to consider. Must be in (-pi,pi]. max_z : :obj:`float` Maximum ``z`` to consider. diff --git a/src/utils/include/utils/math/cylindrical_transformation_parameters.hpp b/src/utils/include/utils/math/cylindrical_transformation_parameters.hpp index 4646805ebdf..20f18d78a77 100644 --- a/src/utils/include/utils/math/cylindrical_transformation_parameters.hpp +++ b/src/utils/include/utils/math/cylindrical_transformation_parameters.hpp @@ -26,6 +26,15 @@ namespace Utils { +/** + * @brief A class to hold and validate parameters for a cylindrical coordinate + * transformations. + * + * @param center The origin of the cylindrical coordinates. + * @param axis The "z"-axis. Must be normalized. + * @param orientation The axis along which phi = 0. Must be normalized and + * orthogonal to axis. + */ class CylindricalTransformationParameters { public: CylindricalTransformationParameters() = default; From b23aa44ee258713139291d9b012ed91994e5816e Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Mon, 8 Mar 2021 18:55:18 +0100 Subject: [PATCH 29/31] tutorial, samples --- .../charged_system/charged_system-1.ipynb | 14 ++++++-------- samples/lb_profile.py | 11 +++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/doc/tutorials/charged_system/charged_system-1.ipynb b/doc/tutorials/charged_system/charged_system-1.ipynb index d743b8731db..9786b6114a3 100644 --- a/doc/tutorials/charged_system/charged_system-1.ipynb +++ b/doc/tutorials/charged_system/charged_system-1.ipynb @@ -36,7 +36,7 @@ "import espressomd\n", "espressomd.assert_features(['WCA', 'ELECTROSTATICS'])\n", "\n", - "from espressomd import System, interactions, electrostatics, observables, accumulators\n", + "from espressomd import System, interactions, electrostatics, observables, accumulators, math\n", "\n", "import numpy as np\n", "from scipy import optimize\n", @@ -438,20 +438,18 @@ "```python\n", "def setup_profile_calculation(system, delta_N, ion_types, r_min, n_radial_bins):\n", " radial_profile_accumulators = {}\n", + " ctp = math.CylindricalTransformationParameters(center = np.array(system.box_l) / 2.,\n", + " axis = [0, 0, 1],\n", + " orientation = [1, 0, 0])\n", " for ion_type in ion_types:\n", " ion_ids = system.part.select(type=ion_type).id\n", " radial_profile_obs = observables.CylindricalDensityProfile(\n", " ids=ion_ids,\n", - " center=np.array(system.box_l) / 2.,\n", - " axis=[0, 0, 1, ],\n", + " trafo_params = ctp,\n", " n_r_bins=n_radial_bins,\n", - " n_phi_bins=1,\n", - " n_z_bins=1,\n", " min_r=r_min,\n", - " min_phi=-np.pi,\n", " min_z=-system.box_l[2] / 2.,\n", " max_r=system.box_l[0] / 2.,\n", - " max_phi=np.pi,\n", " max_z=system.box_l[2] / 2.)\n", "\n", " bin_edges = radial_profile_obs.bin_edges()\n", @@ -945,7 +943,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.8.5" } }, "nbformat": 4, diff --git a/samples/lb_profile.py b/samples/lb_profile.py index 7f4f6235dd6..cc342e00f84 100644 --- a/samples/lb_profile.py +++ b/samples/lb_profile.py @@ -32,6 +32,7 @@ import espressomd.shapes import espressomd.lbboundaries import espressomd.accumulators +import espressomd.math system = espressomd.System(box_l=[10.0, 10.0, 5.0]) system.time_step = 0.01 @@ -42,16 +43,14 @@ agrid=1.0, dens=1.0, visc=1.0, tau=0.01, ext_force_density=[0, 0, 0.15], kT=1.0, seed=32) system.actors.add(lb_fluid) system.thermostat.set_lb(LB_fluid=lb_fluid, seed=23) -fluid_obs = espressomd.observables.CylindricalLBVelocityProfile( +ctp = espressomd.math.CylindricalTransformationParameters( center=[5.0, 5.0, 0.0], axis=[0, 0, 1], + orientation=[1, 0, 0]) +fluid_obs = espressomd.observables.CylindricalLBVelocityProfile( + trafo_params=ctp, n_r_bins=100, - n_phi_bins=1, - n_z_bins=1, - min_r=0.0, max_r=4.0, - min_phi=-np.pi, - max_phi=np.pi, min_z=0.0, max_z=10.0, sampling_density=0.1) From 0e67661e6f5e821c52296030af6920637f6b063c Mon Sep 17 00:00:00 2001 From: christophlohrmann <47663906+christophlohrmann@users.noreply.github.com> Date: Tue, 9 Mar 2021 12:49:02 +0100 Subject: [PATCH 30/31] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jean-Noël Grad --- doc/sphinx/analysis.rst | 8 ++-- .../charged_system/charged_system-1.ipynb | 2 +- samples/lb_profile.py | 2 +- src/python/espressomd/observables.py | 16 ++++---- .../CylindricalLBProfileObservable.hpp | 4 +- .../CylindricalPidProfileObservable.hpp | 4 +- testsuite/python/lb_poiseuille_cylinder.py | 2 +- testsuite/python/observable_cylindrical.py | 37 ++++++++++------- testsuite/python/observable_cylindricalLB.py | 40 ++++++++++--------- testsuite/python/tests_common.py | 4 +- 10 files changed, 64 insertions(+), 55 deletions(-) diff --git a/doc/sphinx/analysis.rst b/doc/sphinx/analysis.rst index 444ed8cc853..a346007fd20 100644 --- a/doc/sphinx/analysis.rst +++ b/doc/sphinx/analysis.rst @@ -418,14 +418,13 @@ For this purpose, use :class:`espressomd.math.CylindricalTransformationParameter import espressomd.math # shifted and rotated cylindrical coordinates - cyl_trafo_params = espressomd.math(center=[5.0, 5.0, 0.0], - axis=[0, 1, 0], - orientation=[0, 0, 1]) + cyl_transform_params = espressomd.math.CylindricalTransformationParameters( + center=[5.0, 5.0, 0.0], axis=[0, 1, 0], orientation=[0, 0, 1]) # histogram in cylindrical coordinates density_profile = espressomd.observables.CylindricalDensityProfile( ids=[0, 1], - trafo_params = cyl_trafo_params, + transform_params = cyl_transform_params, n_r_bins=8, min_r=1.0, max_r=4.0, n_phi_bins=16, min_phi=-np.pi, max_phi=np.pi, n_z_bins=4, min_z=4.0, max_z=8.0) @@ -791,4 +790,3 @@ Note that the cluster objects do not contain copies of the particles, but refer - diff --git a/doc/tutorials/charged_system/charged_system-1.ipynb b/doc/tutorials/charged_system/charged_system-1.ipynb index 9786b6114a3..7f223216e8e 100644 --- a/doc/tutorials/charged_system/charged_system-1.ipynb +++ b/doc/tutorials/charged_system/charged_system-1.ipynb @@ -445,7 +445,7 @@ " ion_ids = system.part.select(type=ion_type).id\n", " radial_profile_obs = observables.CylindricalDensityProfile(\n", " ids=ion_ids,\n", - " trafo_params = ctp,\n", + " transform_params = ctp,\n", " n_r_bins=n_radial_bins,\n", " min_r=r_min,\n", " min_z=-system.box_l[2] / 2.,\n", diff --git a/samples/lb_profile.py b/samples/lb_profile.py index cc342e00f84..06e6e05f516 100644 --- a/samples/lb_profile.py +++ b/samples/lb_profile.py @@ -48,7 +48,7 @@ axis=[0, 0, 1], orientation=[1, 0, 0]) fluid_obs = espressomd.observables.CylindricalLBVelocityProfile( - trafo_params=ctp, + transform_params=ctp, n_r_bins=100, max_r=4.0, min_z=0.0, diff --git a/src/python/espressomd/observables.py b/src/python/espressomd/observables.py index f16a0cc59f8..775ea09fbce 100644 --- a/src/python/espressomd/observables.py +++ b/src/python/espressomd/observables.py @@ -76,9 +76,9 @@ class CylindricalProfileObservable(ProfileObservable): """ def __init__( - self, trafo_params=CylindricalTransformationParameters(), **kwargs): + self, transform_params=CylindricalTransformationParameters(), **kwargs): # Provide default transformation parameters if not user-provided - kwargs['trafo_params'] = trafo_params + kwargs['transform_params'] = transform_params super().__init__(**kwargs) @@ -657,7 +657,7 @@ class CylindricalDensityProfile(CylindricalProfileObservable): ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. @@ -695,7 +695,7 @@ class CylindricalFluxDensityProfile(CylindricalProfileObservable): ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. @@ -737,7 +737,7 @@ class CylindricalLBFluxDensityProfileAtParticlePositions( ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. @@ -779,7 +779,7 @@ class CylindricalLBVelocityProfileAtParticlePositions( ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. @@ -819,7 +819,7 @@ class CylindricalVelocityProfile(CylindricalProfileObservable): ---------- ids : array_like of :obj:`int` The ids of (existing) particles to take into account. - trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. @@ -861,7 +861,7 @@ class CylindricalLBVelocityProfile(CylindricalProfileObservable): Parameters ---------- - trafo_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` n_r_bins : :obj:`int`, default = 1 Number of bins in radial direction. diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index 34bc7a21d08..5ade0dcd359 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -55,7 +55,7 @@ class CylindricalLBProfileObservable using Base::Base; CylindricalLBProfileObservable() { this->add_parameters({ - {"trafo_params", m_cyl_trafo_params}, + {"transform_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = @@ -140,7 +140,7 @@ class CylindricalLBProfileObservable } void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "trafo_params"); + set_from_args(m_cyl_trafo_params, params, "transform_params"); if (m_cyl_trafo_params) m_observable = std::make_shared( diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index a48694869a1..d1d180ba5d3 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -61,7 +61,7 @@ class CylindricalPidProfileObservable get_value>(v); }, [this]() { return cylindrical_pid_profile_observable()->ids(); }}, - {"trafo_params", m_cyl_trafo_params}, + {"transform_params", m_cyl_trafo_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_pid_profile_observable()->n_bins[0] = @@ -141,7 +141,7 @@ class CylindricalPidProfileObservable }; void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "trafo_params"); + set_from_args(m_cyl_trafo_params, params, "transform_params"); if (m_cyl_trafo_params) m_observable = std::make_shared( diff --git a/testsuite/python/lb_poiseuille_cylinder.py b/testsuite/python/lb_poiseuille_cylinder.py index 933a1bc6bac..0607a60641f 100644 --- a/testsuite/python/lb_poiseuille_cylinder.py +++ b/testsuite/python/lb_poiseuille_cylinder.py @@ -155,7 +155,7 @@ def prepare_obs(self): ctp = espressomd.math.CylindricalTransformationParameters(center=obs_center, axis=self.params['axis'], orientation=self.params['orientation']) - local_obs_params['trafo_params'] = ctp + local_obs_params['transform_params'] = ctp obs = espressomd.observables.CylindricalLBVelocityProfile( **local_obs_params) self.accumulator = espressomd.accumulators.MeanVarianceCalculator( diff --git a/testsuite/python/observable_cylindrical.py b/testsuite/python/observable_cylindrical.py index 709dca89a4a..3d4cefbf0ce 100644 --- a/testsuite/python/observable_cylindrical.py +++ b/testsuite/python/observable_cylindrical.py @@ -32,12 +32,12 @@ class TestCylindricalObservable(ut.TestCase): system.time_step = 0.01 system.cell_system.skin = 0.4 - cyl_trafo_params = espressomd.math.CylindricalTransformationParameters( + cyl_transform_params = espressomd.math.CylindricalTransformationParameters( center=3 * [7.5], axis=[1 / np.sqrt(2), 1 / np.sqrt(2), 0], orientation=[0, 0, 1]) params = { 'ids': None, - 'trafo_params': cyl_trafo_params, + 'transform_params': cyl_transform_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 4, @@ -59,7 +59,9 @@ def tearDown(self): def calc_ellipsis_pos_vel( self, n_part, z_min, z_max, semi_x=1., semi_y=1.): """ - Calculate positions on an elliptical corkscrew line. Calculate cartesian velocities that lead to a constant velocity in cylindrical coordinates + Calculate positions on an elliptical corkscrew line. + Calculate cartesian velocities that lead to a + constant velocity in cylindrical coordinates """ zs = np.linspace(z_min, z_max, num=n_part) @@ -98,8 +100,12 @@ def align_with_observable_frame(self, vec): def setup_system_get_np_hist(self): """ - Pick positions and velocities in the original box frame and calculate the np histogram. Then rotate and move the positions and velocities to the frame of the observables. - After calculating the core observables, the result should be the same as the np histogram obtained from the original box frame. + Pick positions and velocities in the original box frame + and calculate the np histogram. + Then rotate and move the positions and velocities + to the frame of the observables. + After calculating the core observables, the result should be + the same as the np histogram obtained from the original box frame. """ positions, velocities = self.calc_ellipsis_pos_vel(100, 0.99 * @@ -125,7 +131,7 @@ def setup_system_get_np_hist(self): for pos, vel in zip(positions, velocities): pos_aligned.append( self.align_with_observable_frame(pos) + - self.cyl_trafo_params.center) + self.cyl_transform_params.center) vel_aligned.append(self.align_with_observable_frame(vel)) self.system.part.add(pos=pos_aligned, v=vel_aligned) self.params['ids'] = self.system.part[:].id @@ -139,7 +145,8 @@ def check_edges(self, observable, np_edges): def test_density_profile(self): """ - Check that the result from the observable (in its own frame) matches the np result from the box frame + Check that the result from the observable (in its own frame) + matches the np result from the box frame """ np_dens, np_edges = self.setup_system_get_np_hist() @@ -151,7 +158,8 @@ def test_density_profile(self): def test_vel_profile(self): """ - Check that the result from the observable (in its own frame) matches the np result from the box frame + Check that the result from the observable (in its own frame) + matches the np result from the box frame """ np_dens, np_edges = self.setup_system_get_np_hist() cyl_vel_prof = espressomd.observables.CylindricalVelocityProfile( @@ -172,7 +180,8 @@ def test_vel_profile(self): def test_flux_density_profile(self): """ - Check that the result from the observable (in its own frame) matches the np result from the box frame + Check that the result from the observable (in its own frame) + matches the np result from the box frame """ np_dens, np_edges = self.setup_system_get_np_hist() cyl_flux_dens = espressomd.observables.CylindricalFluxDensityProfile( @@ -243,15 +252,13 @@ def test_cylindrical_pid_profile_interface(self): obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) # check center, axis, orientation - ctp = espressomd.math.CylindricalTransformationParameters(center=[1, 2, 3], - axis=[ - 0, 1, 0], - orientation=[0, 0, 1]) - observable.trafo_params = ctp + ctp = espressomd.math.CylindricalTransformationParameters( + center=[1, 2, 3], axis=[0, 1, 0], orientation=[0, 0, 1]) + observable.transform_params = ctp for attr_name in ['center', 'axis', 'orientation']: np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), - np.copy(observable.trafo_params.__getattr__(attr_name))) + np.copy(observable.transform_params.__getattr__(attr_name))) if __name__ == "__main__": diff --git a/testsuite/python/observable_cylindricalLB.py b/testsuite/python/observable_cylindricalLB.py index 5dee2b7e79a..45001c928e6 100644 --- a/testsuite/python/observable_cylindricalLB.py +++ b/testsuite/python/observable_cylindricalLB.py @@ -41,14 +41,12 @@ class CylindricalLBObservableCommon: 'visc': 2.7, 'tau': 0.1, } - cyl_trafo_params = espressomd.math.CylindricalTransformationParameters(center=3 * [7], - axis=[ - 1, 0, 0], - orientation=[0, 0, 1]) + cyl_transform_params = espressomd.math.CylindricalTransformationParameters( + center=3 * [7], axis=[1, 0, 0], orientation=[0, 0, 1]) params = { 'ids': None, - 'trafo_params': cyl_trafo_params, + 'transform_params': cyl_transform_params, 'n_r_bins': 4, 'n_phi_bins': 3, 'n_z_bins': 5, @@ -66,7 +64,9 @@ class CylindricalLBObservableCommon: def calc_vel_at_pos(self, positions): """ - In cylinde coordinates, all velocities are the same. In cartesian they depend on the position. The cartesian velocities are calculated here. + In cylindrical coordinates, all velocities are the same. + In cartesian they depend on the position. + The cartesian velocities are calculated here. """ vels = [] @@ -78,7 +78,8 @@ def calc_vel_at_pos(self, positions): def align_with_observable_frame(self, vec): """ - Rotate vectors from the original box frame to the frame of the observables. + Rotate vectors from the original box frame to + the frame of the observables. """ # align original z to observable z @@ -91,8 +92,11 @@ def align_with_observable_frame(self, vec): def setup_system_get_np_hist(self): """ - Pick positions and velocities in the original box frame and calculate the np histogram. Then rotate and move the positions and velocities to the frame of the observables. - After calculating the core observables, the result should be the same as the np histogram obtained from the original box frame. + Pick positions and velocities in the original box frame and + calculate the np histogram. Then rotate and move the positions + and velocities to the frame of the observables. + After calculating the core observables, the result should be + the same as the np histogram obtained from the original box frame. """ nodes = np.array(np.meshgrid([1, 2], [1, 2], [ @@ -119,7 +123,7 @@ def setup_system_get_np_hist(self): for pos, vel in zip(positions, velocities): pos_aligned.append( self.align_with_observable_frame(pos) + - self.cyl_trafo_params.center) + self.cyl_transform_params.center) vel_aligned.append(self.align_with_observable_frame(vel)) node_aligned = np.array( np.rint( @@ -142,7 +146,8 @@ def check_edges(self, observable, np_edges): def test_cylindrical_lb_vel_profile_obs(self): """ - Check that the result from the observable (in its own frame) matches the np result from the box frame + Check that the result from the observable (in its own frame) + matches the np result from the box frame """ np_hist_binary, np_edges = self.setup_system_get_np_hist() @@ -213,15 +218,13 @@ def test_cylindrical_lb_profile_interface(self): obs_bin_edges = observable.bin_edges() np.testing.assert_array_equal(obs_bin_edges[-1, -1, -1], [7, 8, 9]) # check center, axis, orientation - ctp = espressomd.math.CylindricalTransformationParameters(center=[1, 2, 3], - axis=[ - 0, 1, 0], - orientation=[0, 0, 1]) - observable.trafo_params = ctp + ctp = espressomd.math.CylindricalTransformationParameters( + center=[1, 2, 3], axis=[0, 1, 0], orientation=[0, 0, 1]) + observable.transform_params = ctp for attr_name in ['center', 'axis', 'orientation']: np.testing.assert_array_almost_equal(np.copy(ctp.__getattr__(attr_name)), - np.copy(observable.trafo_params.__getattr__(attr_name))) + np.copy(observable.transform_params.__getattr__(attr_name))) class CylindricalLBObservableCPU(ut.TestCase, CylindricalLBObservableCommon): @@ -237,7 +240,8 @@ def tearDown(self): def test_cylindrical_lb_flux_density_obs(self): """ - Check that the result from the observable (in its own frame) matches the np result from the box frame. + Check that the result from the observable (in its own frame) + matches the np result from the box frame. Only for CPU because density interpolation is not implemented for GPU LB. """ np_hist_binary, np_edges = self.setup_system_get_np_hist() diff --git a/testsuite/python/tests_common.py b/testsuite/python/tests_common.py index 450718ad76f..5c259cd49b2 100644 --- a/testsuite/python/tests_common.py +++ b/testsuite/python/tests_common.py @@ -185,8 +185,8 @@ def rodrigues_rot(vec, axis, angle): https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula#Statement """ axis /= np.linalg.norm(axis) - return np.cos(angle) * vec + np.sin(angle) * np.cross(axis, - vec) + (1 - np.cos(angle)) * np.dot(axis, vec) * axis + return np.cos(angle) * vec + np.sin(angle) * np.cross(axis, vec) + \ + (1 - np.cos(angle)) * np.dot(axis, vec) * axis def rotation_matrix(axis, theta): From ad0010658169752492b7937267d9323917b2679d Mon Sep 17 00:00:00 2001 From: Christoph Lohrmann Date: Tue, 9 Mar 2021 22:13:02 +0100 Subject: [PATCH 31/31] core: trafo_params -> transform_params --- .../observables/CylindricalDensityProfile.hpp | 5 +++-- .../CylindricalFluxDensityProfile.hpp | 8 ++++---- ...BFluxDensityProfileAtParticlePositions.cpp | 13 +++++++------ .../CylindricalLBProfileObservable.hpp | 11 ++++++----- .../CylindricalLBVelocityProfile.cpp | 9 +++++---- ...alLBVelocityProfileAtParticlePositions.cpp | 6 +++--- .../CylindricalPidProfileObservable.hpp | 5 +++-- .../CylindricalProfileObservable.hpp | 7 ++++--- .../CylindricalVelocityProfile.hpp | 8 ++++---- .../CylindricalTransformationParameters.hpp | 19 ++++++++++--------- .../CylindricalLBProfileObservable.hpp | 10 +++++----- .../CylindricalPidProfileObservable.hpp | 10 +++++----- 12 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index a071aa737dc..a7d1de6e312 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -41,8 +41,9 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { for (auto p : particles) { histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( - folded_position(traits.position(p), box_geo) - trafo_params->center(), - trafo_params->axis(), trafo_params->orientation())); + folded_position(traits.position(p), box_geo) - + transform_params->center(), + transform_params->axis(), transform_params->orientation())); } histogram.normalize(); diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index e4d114e8668..73b65f08c81 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -43,13 +43,13 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { // Write data to the histogram for (auto p : particles) { - auto const pos = - folded_position(traits.position(p), box_geo) - trafo_params->center(); + auto const pos = folded_position(traits.position(p), box_geo) - + transform_params->center(); histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos, trafo_params->axis(), trafo_params->orientation()), + pos, transform_params->axis(), transform_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), trafo_params->axis(), pos)); + traits.velocity(p), transform_params->axis(), pos)); } histogram.normalize(); return histogram.get_histogram(); diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index b01cf78f311..5ef211f40db 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -44,12 +44,13 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( lb_lbfluid_get_lattice_speed(); auto const flux_dens = lb_lbfluid_get_interpolated_density(pos) * v; - histogram.update( - Utils::transform_coordinate_cartesian_to_cylinder( - pos - trafo_params->center(), trafo_params->axis(), - trafo_params->orientation()), - Utils::transform_vector_cartesian_to_cylinder( - flux_dens, trafo_params->axis(), pos - trafo_params->center())); + histogram.update(Utils::transform_coordinate_cartesian_to_cylinder( + pos - transform_params->center(), + transform_params->axis(), + transform_params->orientation()), + Utils::transform_vector_cartesian_to_cylinder( + flux_dens, transform_params->axis(), + pos - transform_params->center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalLBProfileObservable.hpp b/src/core/observables/CylindricalLBProfileObservable.hpp index e9ce648cabe..df4e66e5936 100644 --- a/src/core/observables/CylindricalLBProfileObservable.hpp +++ b/src/core/observables/CylindricalLBProfileObservable.hpp @@ -32,11 +32,12 @@ namespace Observables { class CylindricalLBProfileObservable : public CylindricalProfileObservable { public: CylindricalLBProfileObservable( - std::shared_ptr trafo_params, + std::shared_ptr + transform_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z, double sampling_density) - : CylindricalProfileObservable(std::move(trafo_params), n_r_bins, + : CylindricalProfileObservable(std::move(transform_params), n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), sampling_density(sampling_density) { @@ -51,12 +52,12 @@ class CylindricalLBProfileObservable : public CylindricalProfileObservable { // We have to rotate the coordinates since the utils function assumes // z-axis symmetry. constexpr Utils::Vector3d z_axis{{0.0, 0.0, 1.0}}; - auto const theta = Utils::angle_between(z_axis, trafo_params->axis()); + auto const theta = Utils::angle_between(z_axis, transform_params->axis()); auto const rot_axis = - Utils::vector_product(z_axis, trafo_params->axis()).normalize(); + Utils::vector_product(z_axis, transform_params->axis()).normalize(); if (theta > std::numeric_limits::epsilon()) p_cart = Utils::vec_rotate(rot_axis, theta, p_cart); - p = p_cart + trafo_params->center(); + p = p_cart + transform_params->center(); } } std::vector sampling_positions; diff --git a/src/core/observables/CylindricalLBVelocityProfile.cpp b/src/core/observables/CylindricalLBVelocityProfile.cpp index 2b32b348c31..791417859b8 100644 --- a/src/core/observables/CylindricalLBVelocityProfile.cpp +++ b/src/core/observables/CylindricalLBVelocityProfile.cpp @@ -35,11 +35,12 @@ std::vector CylindricalLBVelocityProfile::operator()() const { for (auto const &p : sampling_positions) { auto const velocity = lb_lbfluid_get_interpolated_velocity(p) * lb_lbfluid_get_lattice_speed(); - auto const pos_shifted = p - trafo_params->center(); + auto const pos_shifted = p - transform_params->center(); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( - pos_shifted, trafo_params->axis(), trafo_params->orientation()); - histogram.update(pos_cyl, Utils::transform_vector_cartesian_to_cylinder( - velocity, trafo_params->axis(), pos_shifted)); + pos_shifted, transform_params->axis(), transform_params->orientation()); + histogram.update(pos_cyl, + Utils::transform_vector_cartesian_to_cylinder( + velocity, transform_params->axis(), pos_shifted)); } auto hist_data = histogram.get_histogram(); auto const tot_count = histogram.get_tot_count(); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index e55178e956e..9650c7dda6f 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -42,10 +42,10 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos - trafo_params->center(), trafo_params->axis(), - trafo_params->orientation()), + pos - transform_params->center(), transform_params->axis(), + transform_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - v, trafo_params->axis(), pos - trafo_params->center())); + v, transform_params->axis(), pos - transform_params->center())); } // normalize by number of hits per bin diff --git a/src/core/observables/CylindricalPidProfileObservable.hpp b/src/core/observables/CylindricalPidProfileObservable.hpp index 8478d451c11..8a3ae7886e1 100644 --- a/src/core/observables/CylindricalPidProfileObservable.hpp +++ b/src/core/observables/CylindricalPidProfileObservable.hpp @@ -31,11 +31,12 @@ class CylindricalPidProfileObservable : public PidObservable, public: CylindricalPidProfileObservable( std::vector const &ids, - std::shared_ptr trafo_params, + std::shared_ptr + transform_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : PidObservable(ids), - CylindricalProfileObservable(std::move(trafo_params), n_r_bins, + CylindricalProfileObservable(std::move(transform_params), n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z) {} }; diff --git a/src/core/observables/CylindricalProfileObservable.hpp b/src/core/observables/CylindricalProfileObservable.hpp index 7fe81aad127..224856f0cfd 100644 --- a/src/core/observables/CylindricalProfileObservable.hpp +++ b/src/core/observables/CylindricalProfileObservable.hpp @@ -41,14 +41,15 @@ namespace Observables { class CylindricalProfileObservable : public ProfileObservable { public: CylindricalProfileObservable( - std::shared_ptr trafo_params, + std::shared_ptr + transform_params, int n_r_bins, int n_phi_bins, int n_z_bins, double min_r, double max_r, double min_phi, double max_phi, double min_z, double max_z) : ProfileObservable(n_r_bins, n_phi_bins, n_z_bins, min_r, max_r, min_phi, max_phi, min_z, max_z), - trafo_params(std::move(trafo_params)) {} + transform_params(std::move(transform_params)) {} - std::shared_ptr trafo_params; + std::shared_ptr transform_params; }; } // Namespace Observables diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 76a0d49872b..6b70dd2feaf 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -43,13 +43,13 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { Utils::CylindricalHistogram histogram(n_bins, 3, limits); for (auto p : particles) { - auto const pos = - folded_position(traits.position(p), box_geo) - trafo_params->center(); + auto const pos = folded_position(traits.position(p), box_geo) - + transform_params->center(); histogram.update( Utils::transform_coordinate_cartesian_to_cylinder( - pos, trafo_params->axis(), trafo_params->orientation()), + pos, transform_params->axis(), transform_params->orientation()), Utils::transform_vector_cartesian_to_cylinder( - traits.velocity(p), trafo_params->axis(), pos)); + traits.velocity(p), transform_params->axis(), pos)); } auto hist_tmp = histogram.get_histogram(); diff --git a/src/script_interface/CylindricalTransformationParameters.hpp b/src/script_interface/CylindricalTransformationParameters.hpp index 564852f7389..89ed4b840d0 100644 --- a/src/script_interface/CylindricalTransformationParameters.hpp +++ b/src/script_interface/CylindricalTransformationParameters.hpp @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#ifndef SCRIPT_INTERFACE_CYL_TRAFO_PARAMS_HPP -#define SCRIPT_INTERFACE_CYL_TRAFO_PARAMS_HPP +#ifndef SCRIPT_INTERFACE_CYL_TRANSFORM_PARAMS_HPP +#define SCRIPT_INTERFACE_CYL_TRANSFORM_PARAMS_HPP #include "script_interface/ScriptInterface.hpp" @@ -33,18 +33,18 @@ class CylindricalTransformationParameters public: CylindricalTransformationParameters() { add_parameters({{"center", AutoParameter::read_only, - [this]() { return m_trafo_params->center(); }}, + [this]() { return m_transform_params->center(); }}, {"axis", AutoParameter::read_only, - [this]() { return m_trafo_params->axis(); }}, + [this]() { return m_transform_params->axis(); }}, {"orientation", AutoParameter::read_only, - [this]() { return m_trafo_params->orientation(); }}}); + [this]() { return m_transform_params->orientation(); }}}); } std::shared_ptr<::Utils::CylindricalTransformationParameters> - cyl_trafo_params() { - return m_trafo_params; + cyl_transform_params() { + return m_transform_params; } void do_construct(VariantMap const ¶ms) override { - m_trafo_params = + m_transform_params = std::make_shared( get_value_or(params, "center", Utils::Vector3d{{0, 0, 0}}), @@ -55,7 +55,8 @@ class CylindricalTransformationParameters } private: - std::shared_ptr m_trafo_params; + std::shared_ptr + m_transform_params; }; } // namespace ScriptInterface #endif diff --git a/src/script_interface/observables/CylindricalLBProfileObservable.hpp b/src/script_interface/observables/CylindricalLBProfileObservable.hpp index 5ade0dcd359..b0eafa3942a 100644 --- a/src/script_interface/observables/CylindricalLBProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalLBProfileObservable.hpp @@ -55,7 +55,7 @@ class CylindricalLBProfileObservable using Base::Base; CylindricalLBProfileObservable() { this->add_parameters({ - {"transform_params", m_cyl_trafo_params}, + {"transform_params", m_transform_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_profile_observable()->n_bins[0] = @@ -140,11 +140,11 @@ class CylindricalLBProfileObservable } void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "transform_params"); + set_from_args(m_transform_params, params, "transform_params"); - if (m_cyl_trafo_params) + if (m_transform_params) m_observable = std::make_shared( - m_cyl_trafo_params->cyl_trafo_params(), + m_transform_params->cyl_transform_params(), get_value_or(params, "n_r_bins", 1), get_value_or(params, "n_phi_bins", 1), get_value_or(params, "n_z_bins", 1), @@ -179,7 +179,7 @@ class CylindricalLBProfileObservable private: std::shared_ptr m_observable; - std::shared_ptr m_cyl_trafo_params; + std::shared_ptr m_transform_params; }; } /* namespace Observables */ diff --git a/src/script_interface/observables/CylindricalPidProfileObservable.hpp b/src/script_interface/observables/CylindricalPidProfileObservable.hpp index d1d180ba5d3..d541880b367 100644 --- a/src/script_interface/observables/CylindricalPidProfileObservable.hpp +++ b/src/script_interface/observables/CylindricalPidProfileObservable.hpp @@ -61,7 +61,7 @@ class CylindricalPidProfileObservable get_value>(v); }, [this]() { return cylindrical_pid_profile_observable()->ids(); }}, - {"transform_params", m_cyl_trafo_params}, + {"transform_params", m_transform_params}, {"n_r_bins", [this](const Variant &v) { cylindrical_pid_profile_observable()->n_bins[0] = @@ -141,12 +141,12 @@ class CylindricalPidProfileObservable }; void do_construct(VariantMap const ¶ms) override { - set_from_args(m_cyl_trafo_params, params, "transform_params"); + set_from_args(m_transform_params, params, "transform_params"); - if (m_cyl_trafo_params) + if (m_transform_params) m_observable = std::make_shared( get_value>(params, "ids"), - m_cyl_trafo_params->cyl_trafo_params(), + m_transform_params->cyl_transform_params(), get_value_or(params, "n_r_bins", 1), get_value_or(params, "n_phi_bins", 1), get_value_or(params, "n_z_bins", 1), @@ -180,7 +180,7 @@ class CylindricalPidProfileObservable private: std::shared_ptr m_observable; - std::shared_ptr m_cyl_trafo_params; + std::shared_ptr m_transform_params; }; } /* namespace Observables */