Skip to content

Commit

Permalink
Deal with rotation.
Browse files Browse the repository at this point in the history
  • Loading branch information
pkreissl committed Dec 14, 2022
1 parent 936e05c commit 1baa2db
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 68 deletions.
10 changes: 10 additions & 0 deletions src/core/particle_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>(0u);
if (flag[0])
bitfield |= static_cast<uint8_t>(1u);
if (flag[1])
bitfield |= static_cast<uint8_t>(2u);
if (flag[2])
bitfield |= static_cast<uint8_t>(4u);
return bitfield;
}
#ifdef DIPOLES
void set_particle_dipm(int part, double dipm) {
mpi_update_particle_property<double, &ParticleProperties::dipm>(part, dipm);
Expand Down
2 changes: 2 additions & 0 deletions src/core/particle_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
151 changes: 92 additions & 59 deletions src/script_interface/particle_data/ParticleHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
#include <type_traits>
#include <vector>


namespace ScriptInterface {
namespace Particles {

Expand Down Expand Up @@ -91,26 +90,26 @@ static auto get_bond_vector(VariantMap const &params) {
return bond_view;
}


template <typename T>
T ParticleHandle::get_particle_property(T &(Particle::*getter)()) const {
boost::optional<T> ret;
auto const part = cell_structure.get_local_particle(m_pid);
if (part == nullptr or part->is_ghost()) {
ret = {};
} else {
ret = {(part->*getter)()};
}
return mpi_reduce_optional(context()->get_comm(), ret);
boost::optional<T> ret;
auto const part = cell_structure.get_local_particle(m_pid);
if (part == nullptr or part->is_ghost()) {
ret = {};
} else {
ret = {(part->*getter)()};
}
return mpi_reduce_optional(context()->get_comm(), ret);
}

template <typename T>
void ParticleHandle::set_particle_property(T& (Particle::*setter)(), Variant const & value) const {
auto const part = cell_structure.get_local_particle(m_pid);
if (not (part == nullptr or part->is_ghost())) {
(part->*setter)() = get_value<T>(value);
}
on_particle_change();
void ParticleHandle::set_particle_property(T &(Particle::*setter)(),
Variant const &value) const {
auto const part = cell_structure.get_local_particle(m_pid);
if (not(part == nullptr or part->is_ghost())) {
(part->*setter)() = get_value<T>(value);
}
on_particle_change();
}

ParticleHandle::ParticleHandle() {
Expand Down Expand Up @@ -187,83 +186,108 @@ ParticleHandle::ParticleHandle() {
#ifdef ROTATION
{"director",
[this](Variant const &value) {
if (context()->get_comm().rank() == 0) {
set_particle_director(m_pid, get_value<Utils::Vector3d>(value));
auto const part = cell_structure.get_local_particle(m_pid);
if (not(part == nullptr or part->is_ghost())) {
auto const director = get_value<Utils::Vector3d>(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<Utils::Vector3d>(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<Utils::Vector3b>(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<Utils::Vector3b>(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<Utils::Vector3d>(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<Utils::Vector3d>(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<Utils::Vector3d>(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<Utils::Vector3d>(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<Utils::Vector3d>(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<Utils::Vector3d>(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<double>(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<Utils::Vector3d>(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",
Expand All @@ -275,15 +299,20 @@ 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<Utils::Vector3b>(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<Utils::Vector3b>(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) {
Expand Down Expand Up @@ -322,9 +351,13 @@ ParticleHandle::ParticleHandle() {
[this](Variant const &value) {
set_particle_property(&Particle::lees_edwards_offset, value);
},
[this]() { return get_particle_property(&Particle::lees_edwards_offset); }},
[this]() {
return get_particle_property(&Particle::lees_edwards_offset);
}},
{"lees_edwards_flag", AutoParameter::read_only,
[this]() { return get_particle_property(&Particle::lees_edwards_flag); }},
[this]() {
return get_particle_property(&Particle::lees_edwards_flag);
}},
{"image_box", AutoParameter::read_only,
[this]() { return get_particle_property(&Particle::image_box); }},
{"node", AutoParameter::read_only,
Expand Down
7 changes: 3 additions & 4 deletions src/script_interface/particle_data/ParticleHandle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

#include <string>


Particle const &get_particle_data(int p_id);

namespace ScriptInterface {
Expand All @@ -38,11 +37,11 @@ class ParticleHandle : public AutoParameters<ParticleHandle> {

Particle const &particle() const { return get_particle_data(m_pid); }

template <typename T>
T get_particle_property(T& (Particle::*getter)()) const;
template <typename T> T get_particle_property(T &(Particle::*getter)()) const;

template <typename T>
void set_particle_property(T& (Particle::*setter)(), Variant const & value) const;
void set_particle_property(T &(Particle::*setter)(),
Variant const &value) const;

public:
ParticleHandle();
Expand Down
10 changes: 5 additions & 5 deletions testsuite/python/particle.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down

0 comments on commit 1baa2db

Please sign in to comment.