Skip to content

Commit

Permalink
added coordinate mapping functions for torus cylindrical to/from Cart…
Browse files Browse the repository at this point in the history
…esian
  • Loading branch information
will-saunders-ukaea committed Dec 19, 2024
1 parent dc5cb6d commit 873a798
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
11 changes: 11 additions & 0 deletions include/neso_particles/device_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ inline auto fma(const REAL &x, const REAL &y, const REAL &z) {
template <typename T> inline auto pow(const T x, const T y) {
return sycl::pow(x, y);
}
template <typename T> inline auto atan2(const T y, const T x) {
return sycl::atan2(y, x);
}
template <typename T> inline auto rsqrt(const T x) { return sycl::rsqrt(x); }
template <typename T> inline auto sin(const T x) { return sycl::sin(x); }
template <typename T> inline auto cos(const T x) { return sycl::cos(x); }
template <typename T> inline auto tan(const T x) { return sycl::tan(x); }
template <typename T> inline auto sincos(const T x, T *cosval) {
*cosval = sycl::cos(x);
return sycl::sin(x);
}

} // namespace Kernel

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,108 @@ inline void triangle_barycentric_to_cartesian(const REAL x1, const REAL y1,
*y = Kernel::fma(l1, y1, l2 * y2) + l3 * y3;
};

/**
* Given a torus with major radius R convert the coordinate for a point
* specified in (x,y,z) Cartesian coordinates to a torus cylindrical coordinate
* system (r, theta, phi). In this notation:
*
* z /----\
* ^ / / \ In the (z, R) plane, radius "r", angle "theta"
* | | *----| relative to a.
* | \ a /
* | R \----/
* * ---------->
* ^
* |
* (0,0,0) In Cartesian.
*
* @param[in] R Major radius of torus.
* @param[in] x Cartesian coordinate, x component.
* @param[in] y Cartesian coordinate, y component.
* @param[in] z Cartesian coordinate, z component.
* @param[in, out] r Torus cylindrical coordinate, radius in poloidal plane
* from centre (a).
* @param[in, out] theta Torus cylindrical coordinate, angle in poloidal plane
* from centre (a).
* @param[in, out] phi Torus cylindrical coordinate, toroidal angle relative to
* origin (Cartesian (0,0,0)).
*/
inline void cartesian_to_torus_cylindrical(const REAL R, const REAL x,
const REAL y, const REAL z, REAL *r,
REAL *theta, REAL *phi) {
*phi = Kernel::atan2(y, x);

const REAL plane_radius2 = x * x + y * y;
const REAL inverse_plane_radius = Kernel::rsqrt(plane_radius2);
const REAL x_normalised = x * inverse_plane_radius;
const REAL y_normalised = y * inverse_plane_radius;

// Origin in poloidal plane is at (R, phi) = Cartesian (R * cos(theta), R *
// sin(theta)))
// = Cartesian (R * x_normalised, R *
// y_normalised)
const REAL po_x = R * x_normalised;
const REAL po_y = R * y_normalised;
const REAL px = x - po_x;
const REAL py = y - po_y;

// (px, py, z) . (x_normalised, y_normalised, 0) =
// px * x_normalised + py * y_normalised
const REAL xplane = px * x_normalised + py * y_normalised;
const REAL yplane = z;

*r = Kernel::sqrt(px * px + py * py + z * z);
*theta = Kernel::atan2(yplane, xplane);
}

/**
* Given a torus with major radius R convert the coordinate for a point
* specified in torus cylindrical coordinate system (r, theta, phi) to Cartesian
* coordinates (x,y,z). In this notation:
*
* z /----\
* ^ / / \ In the (z, R) plane, radius "r", angle "theta"
* | | *----| relative to a.
* | \ a /
* | R \----/
* * ---------->
* ^
* |
* (0,0,0) In Cartesian.
*
* @param[in] R Major radius of torus.
* @param[in] r Torus cylindrical coordinate, radius in poloidal plane
* from centre (a).
* @param[in] theta Torus cylindrical coordinate, angle in poloidal plane
* from centre (a).
* @param[in] phi Torus cylindrical coordinate, toroidal angle relative to
* origin (Cartesian (0,0,0)).
* @param[in, out] x Cartesian coordinate, x component.
* @param[in, out] y Cartesian coordinate, y component.
* @param[in, out] z Cartesian coordinate, z component.
*
*/
inline void torus_cylindrical_to_cartesian(const REAL R, const REAL r,
const REAL theta, const REAL phi,
REAL *x, REAL *y, REAL *z) {

REAL costheta;
const REAL sintheta = Kernel::sincos(theta, &costheta);

*z = r * sintheta;

REAL cosphi;
const REAL sinphi = Kernel::sincos(phi, &cosphi);

// The vector (planex/length, planey/length, 0) = (cos(phi), sin(phi), 0)
// forms the "x" vector in the poloidol plane.
const REAL planex = R * cosphi;
const REAL planey = R * sinphi;

*x = planex + r * costheta * cosphi;
*y = planey + r * costheta * sinphi;
}

} // namespace NESO::Particles::ExternalCommon

#endif
60 changes: 60 additions & 0 deletions test/test_external_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,3 +740,63 @@ TEST(VTK, VTKHDF) {
vtkhdf.write(data);
vtkhdf.close();
}

TEST(ExternalCommon, cartesian_to_torus_cylindrical) {

const REAL test_pi = 3.14159265358979323846;

auto lambda_test = [&](const REAL R, const REAL x, const REAL y, const REAL z,
const REAL cr, const REAL ctheta, const REAL cphi) {
REAL r, theta, phi;
ExternalCommon::cartesian_to_torus_cylindrical(R, x, y, z, &r, &theta,
&phi);

const REAL two_pi = 2 * test_pi;
const REAL theta_err = std::fmod((theta - ctheta) + 2.0 * two_pi, two_pi);
const REAL phi_err = std::fmod((phi - cphi) + 2.0 * two_pi, two_pi);
ASSERT_NEAR(r, cr, 1.0e-12);
ASSERT_NEAR(theta_err, 0.0, 1.0e-12);
ASSERT_NEAR(phi_err, 0.0, 1.0e-12);

REAL tx, ty, tz;
ExternalCommon::torus_cylindrical_to_cartesian(R, r, theta, phi, &tx, &ty,
&tz);

ASSERT_NEAR(x, tx, 1.0e-12);
ASSERT_NEAR(y, ty, 1.0e-12);
ASSERT_NEAR(z, tz, 1.0e-12);
};

lambda_test(1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
lambda_test(2.0, 3.0, 0.0, 0.0, 1.0, 0.0, 0.0);
lambda_test(2.0, 2.0, 0.0, 1.2, 1.2, 0.5 * test_pi, 0.0);
lambda_test(2.0, 0.8, 0.0, 0.0, 1.2, -test_pi, 0.0);
lambda_test(2.0, 2.0, 0.0, -8.0, 8.0, -0.5 * test_pi, 0.0);
lambda_test(2.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.5 * test_pi);
lambda_test(2.0, 0.0, 3.0, 0.0, 1.0, 0.0, 0.5 * test_pi);
lambda_test(2.0, 0.0, 2.0, 1.2, 1.2, 0.5 * test_pi, 0.5 * test_pi);
lambda_test(2.0, 0.0, -2.0, -1.2, 1.2, -0.5 * test_pi, -0.5 * test_pi);
lambda_test(2.0, -4.0, 0.0, -1.2, Kernel::sqrt(2.0 * 2.0 + 1.2 * 1.2),
Kernel::atan2(-1.2, 2.0), test_pi);

std::mt19937 rng(52234421);
std::normal_distribution<REAL> rng_R(0.2, 4.1);
std::normal_distribution<REAL> rng_x(-3.0, 4.0);
std::normal_distribution<REAL> rng_y(-3.0, 4.0);
std::normal_distribution<REAL> rng_z(-3.0, 4.0);
// fuzzing cartesian to torus cyl
for (int testx = 0; testx < 100; testx++) {
const REAL R = rng_R(rng);
const REAL x = rng_x(rng);
const REAL y = rng_y(rng);
const REAL z = rng_z(rng);
REAL r, theta, phi, tx, ty, tz;
ExternalCommon::cartesian_to_torus_cylindrical(R, x, y, z, &r, &theta,
&phi);
ExternalCommon::torus_cylindrical_to_cartesian(R, r, theta, phi, &tx, &ty,
&tz);
ASSERT_NEAR(x, tx, 1.0e-12);
ASSERT_NEAR(y, ty, 1.0e-12);
ASSERT_NEAR(z, tz, 1.0e-12);
}
}

0 comments on commit 873a798

Please sign in to comment.