From 9d144d64d262fce51d9dbe5c21f96f4a0f8daf81 Mon Sep 17 00:00:00 2001 From: Patrick Kreissl Date: Wed, 14 Dec 2022 12:55:43 +0100 Subject: [PATCH] Deal with rotation. --- src/core/particle_data.cpp | 10 ++ src/core/particle_data.hpp | 2 + .../particle_data/ParticleHandle.cpp | 105 +++++++++++------- testsuite/python/particle.py | 10 +- 4 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/core/particle_data.cpp b/src/core/particle_data.cpp index 7022f1e807b..0b556913e15 100644 --- a/src/core/particle_data.cpp +++ b/src/core/particle_data.cpp @@ -460,6 +460,16 @@ void rotate_particle(int part, const Utils::Vector3d &axis, double angle) { } #endif +uint8_t bitfield_from_flag(Utils::Vector3i const &flag) { + auto bitfield = static_cast(0u); + if (flag[0]) + bitfield |= static_cast(1u); + if (flag[1]) + bitfield |= static_cast(2u); + if (flag[2]) + bitfield |= static_cast(4u); + return bitfield; +} #ifdef DIPOLES void set_particle_dipm(int part, double dipm) { mpi_update_particle_property(part, dipm); diff --git a/src/core/particle_data.hpp b/src/core/particle_data.hpp index 0418ce63340..476690fe240 100644 --- a/src/core/particle_data.hpp +++ b/src/core/particle_data.hpp @@ -96,6 +96,8 @@ void set_particle_rotation(int part, Utils::Vector3i const &flag); void rotate_particle(int part, const Utils::Vector3d &axis, double angle); #endif +uint8_t bitfield_from_flag(Utils::Vector3i const &flag); + #ifdef ELECTROSTATICS /** Call only on the head node: set particle charge. * @param part the particle. diff --git a/src/script_interface/particle_data/ParticleHandle.cpp b/src/script_interface/particle_data/ParticleHandle.cpp index b8bdfea5e56..4cb24ef6929 100644 --- a/src/script_interface/particle_data/ParticleHandle.cpp +++ b/src/script_interface/particle_data/ParticleHandle.cpp @@ -187,83 +187,102 @@ ParticleHandle::ParticleHandle() { #ifdef ROTATION {"director", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_director(m_pid, get_value(value)); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + auto const director = get_value(value).normalized(); + auto const quat = Utils::convert_director_to_quaternion(director); + (part->quat)() = quat; } + on_particle_change(); }, - [this]() { return particle().calc_director(); }}, + [this]() { + auto const quat = get_particle_property(&Particle::quat); + return Utils::convert_quaternion_to_director(quat); + }}, {"quat", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_quat(m_pid, get_quaternion_safe("quat", value)); + auto const quat = get_quaternion_safe("quat", value); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + (part->quat)() = quat; } + on_particle_change(); }, - [this]() { return quat2vector(particle().quat()); }}, + [this]() { return quat2vector(get_particle_property(&Particle::quat)); }}, {"omega_body", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_omega_body(m_pid, get_value(value)); - } + set_particle_property(&Particle::omega, value); }, - [this]() { return particle().omega(); }}, + [this]() { return get_particle_property(&Particle::omega); }}, {"rotation", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_rotation( - m_pid, Utils::Vector3i{get_value(value)}); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + auto const rotation_flag = Utils::Vector3i{(get_value(value))}; + auto const bitfield = bitfield_from_flag(rotation_flag); + (part->rotation)() = bitfield; } + on_particle_change(); }, [this]() { - auto const &p = particle(); - return Utils::Vector3b{{p.can_rotate_around(0), p.can_rotate_around(1), - p.can_rotate_around(2)}}; + auto const rotation_bits = get_particle_property(&Particle::rotation); + return Utils::Vector3b{{::detail::get_nth_bit(rotation_bits, 0), + ::detail::get_nth_bit(rotation_bits, 1), + ::detail::get_nth_bit(rotation_bits, 2)}}; }}, {"omega_lab", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_omega_lab(m_pid, get_value(value)); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + auto const omega = convert_vector_space_to_body(*part, get_value(value)); + (part->omega)() = omega; } + on_particle_change(); }, [this]() { - auto const &p = particle(); - return convert_vector_body_to_space(p, p.omega()); + auto const &part = cell_structure.get_local_particle(m_pid); + auto const omega = get_particle_property(&Particle::omega); + return convert_vector_body_to_space(*part, omega); }}, {"torque_lab", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_torque_lab(m_pid, get_value(value)); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + auto const torque = convert_vector_space_to_body(*part, get_value(value)); + (part->torque)() = torque; } + on_particle_change(); }, [this]() { - auto const &p = particle(); - return convert_vector_body_to_space(p, p.torque()); + auto const &part = cell_structure.get_local_particle(m_pid); + auto const torque = get_particle_property(&Particle::torque); + return convert_vector_body_to_space(*part, torque); }}, #endif // ROTATION #ifdef DIPOLES {"dip", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_dip(m_pid, get_value(value)); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + auto const [quat, dipm] = convert_dip_to_quat(get_value(value)); + (part->quat)() = quat; + (part->dipm)() = dipm; } + on_particle_change(); }, [this]() { return particle().calc_dip(); }}, {"dipm", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_dipm(m_pid, get_value(value)); - } + set_particle_property(&Particle::dipm, value); }, - [this]() { return particle().dipm(); }}, + [this]() { return get_particle_property(&Particle::dipm); }}, #endif // DIPOLES #ifdef ROTATIONAL_INERTIA {"rinertia", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_rotational_inertia(m_pid, - get_value(value)); - } + set_particle_property(&Particle::rinertia, value); }, - [this]() { return particle().rinertia(); }}, + [this]() { return get_particle_property(&Particle::rinertia); }}, #endif // ROTATIONAL_INERTIA #ifdef LB_ELECTROHYDRODYNAMICS {"mu_E", @@ -275,15 +294,19 @@ ParticleHandle::ParticleHandle() { #ifdef EXTERNAL_FORCES {"fix", [this](Variant const &value) { - if (context()->get_comm().rank() == 0) { - set_particle_fix(m_pid, - Utils::Vector3i{get_value(value)}); + auto const part = cell_structure.get_local_particle(m_pid); + if (not (part == nullptr or part->is_ghost())) { + auto const fix_flag = Utils::Vector3i{(get_value(value))}; + auto const bitfield = bitfield_from_flag(fix_flag); + (part->fixed)() = bitfield; } + on_particle_change(); }, [this]() { - auto const &p = particle(); - return Utils::Vector3b{ - {p.is_fixed_along(0), p.is_fixed_along(1), p.is_fixed_along(2)}}; + auto const fixed = get_particle_property(&Particle::fixed); + return Utils::Vector3b{{::detail::get_nth_bit(fixed, 0), + ::detail::get_nth_bit(fixed, 1), + ::detail::get_nth_bit(fixed, 2)}}; }}, {"ext_force", [this](Variant const &value) { diff --git a/testsuite/python/particle.py b/testsuite/python/particle.py index e77d606912f..ee8b663e916 100644 --- a/testsuite/python/particle.py +++ b/testsuite/python/particle.py @@ -239,11 +239,11 @@ def test_contradicting_properties_dip_quat(self): self.system.part.add(pos=[0, 0, 0], dip=[1, 1, 1], quat=[1.0, 1.0, 1.0, 1.0]) -# @utx.skipIfMissingFeatures(["ROTATION"]) -# def test_invalid_quat(self): -# system = self.system -# with self.assertRaisesRegex(ValueError, "attribute 'quat' of 'ParticleHandle' must be non-zero"): -# system.part.add(pos=[0., 0., 0.], quat=[0., 0., 0., 0.]) + @utx.skipIfMissingFeatures(["ROTATION"]) + def test_invalid_quat(self): + system = self.system + with self.assertRaisesRegex(ValueError, "attribute 'quat' of 'ParticleHandle' must be non-zero"): + system.part.add(pos=[0., 0., 0.], quat=[0., 0., 0., 0.]) @utx.skipIfMissingFeatures("ELECTROSTATICS") def test_particle_selection(self):