From a54792053bbe26dad3b26172868a51ca646ec450 Mon Sep 17 00:00:00 2001 From: Christoph Rettinger <christoph.rettinger@fau.de> Date: Fri, 6 May 2022 10:35:45 +0200 Subject: [PATCH] Changed mesa_pd integrators back to original variant, allowing generaiton of extended angular momentum part --- python/mesa_pd/kernel/ExplicitEuler.py | 3 +- python/mesa_pd/kernel/SemiImplicitEuler.py | 3 +- python/mesa_pd/kernel/VelocityVerlet.py | 6 +- .../templates/kernel/ExplicitEuler.templ.h | 6 ++ .../kernel/SemiImplicitEuler.templ.h | 7 ++ .../templates/kernel/VelocityVerlet.templ.h | 69 ++++++++------ src/mesa_pd/kernel/ExplicitEuler.h | 9 +- src/mesa_pd/kernel/ExplicitEulerWithShape.h | 6 ++ src/mesa_pd/kernel/SemiImplicitEuler.h | 10 +- src/mesa_pd/kernel/VelocityVerlet.h | 95 +++++++++---------- 10 files changed, 120 insertions(+), 94 deletions(-) diff --git a/python/mesa_pd/kernel/ExplicitEuler.py b/python/mesa_pd/kernel/ExplicitEuler.py index 6d7b39fe1..a41fbd733 100644 --- a/python/mesa_pd/kernel/ExplicitEuler.py +++ b/python/mesa_pd/kernel/ExplicitEuler.py @@ -5,8 +5,9 @@ from mesa_pd.utility import generate_file class ExplicitEuler: - def __init__(self, integrate_rotation=True): + def __init__(self, integrate_rotation=True, use_full_angular_momentum_equation=False): self.context = {'bIntegrateRotation': integrate_rotation, + 'bUseFullAngularMomentumEquation': use_full_angular_momentum_equation, 'interface': [ create_access("position", "walberla::mesa_pd::Vec3", access="gs"), create_access("linearVelocity", "walberla::mesa_pd::Vec3", access="gs"), diff --git a/python/mesa_pd/kernel/SemiImplicitEuler.py b/python/mesa_pd/kernel/SemiImplicitEuler.py index 6732a78cf..ce14ca022 100644 --- a/python/mesa_pd/kernel/SemiImplicitEuler.py +++ b/python/mesa_pd/kernel/SemiImplicitEuler.py @@ -5,8 +5,9 @@ from mesa_pd.utility import generate_file class SemiImplicitEuler: - def __init__(self, integrate_rotation=True): + def __init__(self, integrate_rotation=True, use_full_angular_momentum_equation=False): self.context = {'bIntegrateRotation': integrate_rotation, + 'bUseFullAngularMomentumEquation': use_full_angular_momentum_equation, 'interface': [ create_access("position", "walberla::mesa_pd::Vec3", access="gs"), create_access("linearVelocity", "walberla::mesa_pd::Vec3", access="gs"), diff --git a/python/mesa_pd/kernel/VelocityVerlet.py b/python/mesa_pd/kernel/VelocityVerlet.py index 1bb4ff445..ebcaccd69 100644 --- a/python/mesa_pd/kernel/VelocityVerlet.py +++ b/python/mesa_pd/kernel/VelocityVerlet.py @@ -5,8 +5,10 @@ from mesa_pd.utility import generate_file class VelocityVerlet: - def __init__(self, integrate_rotation=True): - self.context = {'bIntegrateRotation': integrate_rotation, 'interface': []} + def __init__(self, integrate_rotation=True, use_full_angular_momentum_equation=False): + self.context = {'bIntegrateRotation': integrate_rotation, + 'bUseFullAngularMomentumEquation': use_full_angular_momentum_equation, + 'interface': []} self.context['interface'].append(create_access("position", "walberla::mesa_pd::Vec3", access="gs")) self.context['interface'].append(create_access("linearVelocity", "walberla::mesa_pd::Vec3", access="gs")) self.context['interface'].append(create_access("invMass", "walberla::real_t", access="g")) diff --git a/python/mesa_pd/templates/kernel/ExplicitEuler.templ.h b/python/mesa_pd/templates/kernel/ExplicitEuler.templ.h index 4cb293517..0519fe186 100644 --- a/python/mesa_pd/templates/kernel/ExplicitEuler.templ.h +++ b/python/mesa_pd/templates/kernel/ExplicitEuler.templ.h @@ -90,12 +90,18 @@ inline void ExplicitEuler::operator()(const size_t idx, ac.getLinearVelocity(idx)); {%- if bIntegrateRotation %} + {%- if bUseFullAngularMomentumEquation %} // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); const auto torqueBF = transformVectorFromWFtoBF(idx, ac, ac.getTorque(idx)); const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + {%- else %} + // note: contribution (J*omega) x omega is ignored here -> see template for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getTorque(idx); + {%- endif %} // Calculating the rotation angle const Vec3 phi( 0.5_r * wdot * dt_ * dt_ + diff --git a/python/mesa_pd/templates/kernel/SemiImplicitEuler.templ.h b/python/mesa_pd/templates/kernel/SemiImplicitEuler.templ.h index 528139501..c7f586ea4 100644 --- a/python/mesa_pd/templates/kernel/SemiImplicitEuler.templ.h +++ b/python/mesa_pd/templates/kernel/SemiImplicitEuler.templ.h @@ -84,12 +84,19 @@ inline void SemiImplicitEuler::operator()(const size_t idx, ac.getPosition(idx)); {%- if bIntegrateRotation %} + {%- if bUseFullAngularMomentumEquation %} // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); const auto torqueBF = transformVectorFromWFtoBF(idx, ac, ac.getTorque(idx)); const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + {%- else %} + // note: contribution (J*omega) x omega is ignored here -> see template for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getTorque(idx); + {%- endif %} + ac.setAngularVelocity(idx, wdot * dt_ + ac.getAngularVelocity(idx)); diff --git a/python/mesa_pd/templates/kernel/VelocityVerlet.templ.h b/python/mesa_pd/templates/kernel/VelocityVerlet.templ.h index 9d37ed22e..05fffd945 100644 --- a/python/mesa_pd/templates/kernel/VelocityVerlet.templ.h +++ b/python/mesa_pd/templates/kernel/VelocityVerlet.templ.h @@ -50,13 +50,13 @@ namespace kernel { * \code {%- for prop in interface %} {%- if 'g' in prop.access %} - * const {{prop.type}}& get{{prop.name | capFirst}}(const size_t p_idx) const; + * const {{prop.type}}& get{{prop.name | capFirst}}(const size_t idx) const; {%- endif %} {%- if 's' in prop.access %} - * void set{{prop.name | capFirst}}(const size_t p_idx, const {{prop.type}}& v); + * void set{{prop.name | capFirst}}(const size_t idx, const {{prop.type}}& v); {%- endif %} {%- if 'r' in prop.access %} - * {{prop.type}}& get{{prop.name | capFirst}}Ref(const size_t p_idx); + * {{prop.type}}& get{{prop.name | capFirst}}Ref(const size_t idx); {%- endif %} * {%- endfor %} @@ -87,64 +87,77 @@ public: }; template <typename Accessor> -inline void VelocityVerletPreForceUpdate::operator()(const size_t p_idx, Accessor& ac) const +inline void VelocityVerletPreForceUpdate::operator()(const size_t idx, Accessor& ac) const { static_assert(std::is_base_of<data::IAccessor, Accessor>::value, "please provide a valid accessor"); - if (!data::particle_flags::isSet( ac.getFlags(p_idx), data::particle_flags::FIXED)) + if (!data::particle_flags::isSet( ac.getFlags(idx), data::particle_flags::FIXED)) { - ac.setPosition(p_idx, ac.getPosition(p_idx) + - ac.getLinearVelocity(p_idx) * dt_ + - real_t(0.5) * ac.getInvMass(p_idx) * ac.getOldForce(p_idx) * dt_ * dt_); + ac.setPosition(idx, ac.getPosition(idx) + + ac.getLinearVelocity(idx) * dt_ + + real_t(0.5) * ac.getInvMass(idx) * ac.getOldForce(idx) * dt_ * dt_); {%- if bIntegrateRotation %} + {%- if bUseFullAngularMomentumEquation %} // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 // note: this implementation (pre and post) is experimental as it is in principle unclear in which order // angular velocities and rotations (affect again the transformations WF - BF) have to be carried out - const auto omegaBF = transformVectorFromWFtoBF(p_idx, ac, ac.getAngularVelocity(p_idx)); - const auto torqueBF = transformVectorFromWFtoBF(p_idx, ac, ac.getOldTorque(p_idx)); - const Vec3 wdotBF = ac.getInvInertiaBF(p_idx) * ( ( ac.getInertiaBF(p_idx) * omegaBF ) % omegaBF + torqueBF ); - const Vec3 wdot = transformVectorFromBFtoWF(p_idx, ac, wdotBF); + const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); + const auto torqueBF = transformVectorFromWFtoBF(idx, ac, ac.getOldTorque(idx)); + const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); + const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + {%- else %} + // note: contribution (J*omega) x omega is ignored here -> see template for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getOldTorque(idx); + {%- endif %} + // Calculating the rotation angle - const Vec3 phi( ac.getAngularVelocity(p_idx) * dt_ + real_t(0.5) * wdot * dt_ * dt_); + const Vec3 phi( ac.getAngularVelocity(idx) * dt_ + real_t(0.5) * wdot * dt_ * dt_); // Calculating the new orientation - auto rotation = ac.getRotation(p_idx); + auto rotation = ac.getRotation(idx); rotation.rotate( phi ); - ac.setRotation(p_idx, rotation); + ac.setRotation(idx, rotation); {%- endif %} } } template <typename Accessor> -inline void VelocityVerletPostForceUpdate::operator()(const size_t p_idx, Accessor& ac) const +inline void VelocityVerletPostForceUpdate::operator()(const size_t idx, Accessor& ac) const { static_assert(std::is_base_of<data::IAccessor, Accessor>::value, "please provide a valid accessor"); - if (!data::particle_flags::isSet( ac.getFlags(p_idx), data::particle_flags::FIXED)) + if (!data::particle_flags::isSet( ac.getFlags(idx), data::particle_flags::FIXED)) { - ac.setLinearVelocity(p_idx, ac.getLinearVelocity(p_idx) + - real_t(0.5) * ac.getInvMass(p_idx) * (ac.getOldForce(p_idx) + ac.getForce(p_idx)) * dt_); + ac.setLinearVelocity(idx, ac.getLinearVelocity(idx) + + real_t(0.5) * ac.getInvMass(idx) * (ac.getOldForce(idx) + ac.getForce(idx)) * dt_); {%- if bIntegrateRotation %} - const auto omegaBF = transformVectorFromWFtoBF(p_idx, ac, ac.getAngularVelocity(p_idx)); - const auto torqueBF = transformVectorFromWFtoBF(p_idx, ac, 0.5_r * (ac.getOldTorque(p_idx) + ac.getTorque(p_idx))); - const Vec3 wdotBF = ac.getInvInertiaBF(p_idx) * ( ( ac.getInertiaBF(p_idx) * omegaBF ) % omegaBF + torqueBF ); - const Vec3 wdot = transformVectorFromBFtoWF(p_idx, ac, wdotBF); + {%- if bUseFullAngularMomentumEquation %} + const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); + const auto torqueBF = transformVectorFromWFtoBF(idx, ac, 0.5_r * (ac.getOldTorque(idx) + ac.getTorque(idx))); + const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); + const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + {%- else %} + const auto torque = 0.5_r * (ac.getOldTorque(idx) + ac.getTorque(idx)); + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * torque; + {%- endif %} - ac.setAngularVelocity(p_idx, ac.getAngularVelocity(p_idx) + + ac.setAngularVelocity(idx, ac.getAngularVelocity(idx) + wdot * dt_ ); {%- endif %} } - ac.setOldForce(p_idx, ac.getForce(p_idx)); - ac.setForce(p_idx, Vec3(real_t(0), real_t(0), real_t(0))); + ac.setOldForce(idx, ac.getForce(idx)); + ac.setForce(idx, Vec3(real_t(0), real_t(0), real_t(0))); {%- if bIntegrateRotation %} - ac.setOldTorque(p_idx, ac.getTorque(p_idx)); - ac.setTorque(p_idx, Vec3(real_t(0), real_t(0), real_t(0))); + ac.setOldTorque(idx, ac.getTorque(idx)); + ac.setTorque(idx, Vec3(real_t(0), real_t(0), real_t(0))); {%- endif %} } diff --git a/src/mesa_pd/kernel/ExplicitEuler.h b/src/mesa_pd/kernel/ExplicitEuler.h index 44afb7b9c..923cf28bc 100644 --- a/src/mesa_pd/kernel/ExplicitEuler.h +++ b/src/mesa_pd/kernel/ExplicitEuler.h @@ -100,12 +100,9 @@ inline void ExplicitEuler::operator()(const size_t idx, ac.getPosition(idx)); ac.setLinearVelocity(idx, ac.getInvMass(idx) * ac.getForce(idx) * dt_ + ac.getLinearVelocity(idx)); - // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame - // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 - const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); - const auto torqueBF = transformVectorFromWFtoBF(idx, ac, ac.getTorque(idx)); - const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); - const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + // note: contribution (J*omega) x omega is ignored here -> see template for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getTorque(idx); // Calculating the rotation angle const Vec3 phi( 0.5_r * wdot * dt_ * dt_ + diff --git a/src/mesa_pd/kernel/ExplicitEulerWithShape.h b/src/mesa_pd/kernel/ExplicitEulerWithShape.h index 982511b8c..a61646ff0 100644 --- a/src/mesa_pd/kernel/ExplicitEulerWithShape.h +++ b/src/mesa_pd/kernel/ExplicitEulerWithShape.h @@ -91,12 +91,18 @@ inline void ExplicitEuler::operator()(const size_t idx, ac.setPosition (idx, ac.getInvMass(idx) * ac.getForce(idx) * dt_ * dt_ + ac.getLinearVelocity(idx) * dt_ + ac.getPosition(idx)); ac.setLinearVelocity(idx, ac.getInvMass(idx) * ac.getForce(idx) * dt_ + ac.getLinearVelocity(idx)); + /* // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); const auto torqueBF = transformVectorFromWFtoBF(idx, ac, ac.getTorque(idx)); const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + */ + + // note: contribution (J*omega) x omega is ignored here -> see comment for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getTorque(idx); // Calculating the rotation angle const Vec3 phi( ac.getAngularVelocity(idx) * dt_ + wdot * dt_ * dt_); diff --git a/src/mesa_pd/kernel/SemiImplicitEuler.h b/src/mesa_pd/kernel/SemiImplicitEuler.h index bf8cec461..57ac8abd6 100644 --- a/src/mesa_pd/kernel/SemiImplicitEuler.h +++ b/src/mesa_pd/kernel/SemiImplicitEuler.h @@ -94,12 +94,10 @@ inline void SemiImplicitEuler::operator()(const size_t idx, ac.getLinearVelocity(idx)); ac.setPosition ( idx, ac.getLinearVelocity(idx) * dt_ + ac.getPosition(idx)); - // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame - // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 - const auto omegaBF = transformVectorFromWFtoBF(idx, ac, ac.getAngularVelocity(idx)); - const auto torqueBF = transformVectorFromWFtoBF(idx, ac, ac.getTorque(idx)); - const Vec3 wdotBF = ac.getInvInertiaBF(idx) * ( ( ac.getInertiaBF(idx) * omegaBF ) % omegaBF + torqueBF ); - const Vec3 wdot = transformVectorFromBFtoWF(idx, ac, wdotBF); + // note: contribution (J*omega) x omega is ignored here -> see template for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getTorque(idx); + ac.setAngularVelocity(idx, wdot * dt_ + ac.getAngularVelocity(idx)); diff --git a/src/mesa_pd/kernel/VelocityVerlet.h b/src/mesa_pd/kernel/VelocityVerlet.h index 93d64239d..0edcc2b54 100644 --- a/src/mesa_pd/kernel/VelocityVerlet.h +++ b/src/mesa_pd/kernel/VelocityVerlet.h @@ -46,37 +46,37 @@ namespace kernel { * * This kernel requires the following particle accessor interface * \code - * const walberla::mesa_pd::Vec3& getPosition(const size_t p_idx) const; - * void setPosition(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getPosition(const size_t idx) const; + * void setPosition(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::mesa_pd::Vec3& getLinearVelocity(const size_t p_idx) const; - * void setLinearVelocity(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getLinearVelocity(const size_t idx) const; + * void setLinearVelocity(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::real_t& getInvMass(const size_t p_idx) const; + * const walberla::real_t& getInvMass(const size_t idx) const; * - * const walberla::mesa_pd::Vec3& getForce(const size_t p_idx) const; - * void setForce(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getForce(const size_t idx) const; + * void setForce(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::mesa_pd::Vec3& getOldForce(const size_t p_idx) const; - * void setOldForce(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getOldForce(const size_t idx) const; + * void setOldForce(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::mesa_pd::Rot3& getRotation(const size_t p_idx) const; - * void setRotation(const size_t p_idx, const walberla::mesa_pd::Rot3& v); + * const walberla::mesa_pd::Rot3& getRotation(const size_t idx) const; + * void setRotation(const size_t idx, const walberla::mesa_pd::Rot3& v); * - * const walberla::mesa_pd::Vec3& getAngularVelocity(const size_t p_idx) const; - * void setAngularVelocity(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getAngularVelocity(const size_t idx) const; + * void setAngularVelocity(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::mesa_pd::Mat3& getInvInertiaBF(const size_t p_idx) const; + * const walberla::mesa_pd::Mat3& getInvInertiaBF(const size_t idx) const; * - * const walberla::mesa_pd::Mat3& getInertiaBF(const size_t p_idx) const; + * const walberla::mesa_pd::Mat3& getInertiaBF(const size_t idx) const; * - * const walberla::mesa_pd::Vec3& getTorque(const size_t p_idx) const; - * void setTorque(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getTorque(const size_t idx) const; + * void setTorque(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::mesa_pd::Vec3& getOldTorque(const size_t p_idx) const; - * void setOldTorque(const size_t p_idx, const walberla::mesa_pd::Vec3& v); + * const walberla::mesa_pd::Vec3& getOldTorque(const size_t idx) const; + * void setOldTorque(const size_t idx, const walberla::mesa_pd::Vec3& v); * - * const walberla::mesa_pd::data::particle_flags::FlagT& getFlags(const size_t p_idx) const; + * const walberla::mesa_pd::data::particle_flags::FlagT& getFlags(const size_t idx) const; * * \endcode * \ingroup mesa_pd_kernel @@ -105,56 +105,51 @@ public: }; template <typename Accessor> -inline void VelocityVerletPreForceUpdate::operator()(const size_t p_idx, Accessor& ac) const +inline void VelocityVerletPreForceUpdate::operator()(const size_t idx, Accessor& ac) const { static_assert(std::is_base_of<data::IAccessor, Accessor>::value, "please provide a valid accessor"); - if (!data::particle_flags::isSet( ac.getFlags(p_idx), data::particle_flags::FIXED)) + if (!data::particle_flags::isSet( ac.getFlags(idx), data::particle_flags::FIXED)) { - ac.setPosition(p_idx, ac.getPosition(p_idx) + - ac.getLinearVelocity(p_idx) * dt_ + - real_t(0.5) * ac.getInvMass(p_idx) * ac.getOldForce(p_idx) * dt_ * dt_); - // computation done in body frame: d(omega)/ dt = J^-1 ((J*omega) x omega + T), update in world frame - // see Wachs, 2019, doi:10.1007/s00707-019-02389-9, Eq. 27 - // note: this implementation (pre and post) is experimental as it is in principle unclear in which order - // angular velocities and rotations (affect again the transformations WF - BF) have to be carried out - const auto omegaBF = transformVectorFromWFtoBF(p_idx, ac, ac.getAngularVelocity(p_idx)); - const auto torqueBF = transformVectorFromWFtoBF(p_idx, ac, ac.getOldTorque(p_idx)); - const Vec3 wdotBF = ac.getInvInertiaBF(p_idx) * ( ( ac.getInertiaBF(p_idx) * omegaBF ) % omegaBF + torqueBF ); - const Vec3 wdot = transformVectorFromBFtoWF(p_idx, ac, wdotBF); + ac.setPosition(idx, ac.getPosition(idx) + + ac.getLinearVelocity(idx) * dt_ + + real_t(0.5) * ac.getInvMass(idx) * ac.getOldForce(idx) * dt_ * dt_); + // note: contribution (J*omega) x omega is ignored here -> see template for other variant + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * ac.getOldTorque(idx); + // Calculating the rotation angle - const Vec3 phi( ac.getAngularVelocity(p_idx) * dt_ + real_t(0.5) * wdot * dt_ * dt_); + const Vec3 phi( ac.getAngularVelocity(idx) * dt_ + real_t(0.5) * wdot * dt_ * dt_); // Calculating the new orientation - auto rotation = ac.getRotation(p_idx); + auto rotation = ac.getRotation(idx); rotation.rotate( phi ); - ac.setRotation(p_idx, rotation); + ac.setRotation(idx, rotation); } } template <typename Accessor> -inline void VelocityVerletPostForceUpdate::operator()(const size_t p_idx, Accessor& ac) const +inline void VelocityVerletPostForceUpdate::operator()(const size_t idx, Accessor& ac) const { static_assert(std::is_base_of<data::IAccessor, Accessor>::value, "please provide a valid accessor"); - if (!data::particle_flags::isSet( ac.getFlags(p_idx), data::particle_flags::FIXED)) + if (!data::particle_flags::isSet( ac.getFlags(idx), data::particle_flags::FIXED)) { - ac.setLinearVelocity(p_idx, ac.getLinearVelocity(p_idx) + - real_t(0.5) * ac.getInvMass(p_idx) * (ac.getOldForce(p_idx) + ac.getForce(p_idx)) * dt_); - const auto omegaBF = transformVectorFromWFtoBF(p_idx, ac, ac.getAngularVelocity(p_idx)); - const auto torqueBF = transformVectorFromWFtoBF(p_idx, ac, 0.5_r * (ac.getOldTorque(p_idx) + ac.getTorque(p_idx))); - const Vec3 wdotBF = ac.getInvInertiaBF(p_idx) * ( ( ac.getInertiaBF(p_idx) * omegaBF ) % omegaBF + torqueBF ); - const Vec3 wdot = transformVectorFromBFtoWF(p_idx, ac, wdotBF); - - ac.setAngularVelocity(p_idx, ac.getAngularVelocity(p_idx) + + ac.setLinearVelocity(idx, ac.getLinearVelocity(idx) + + real_t(0.5) * ac.getInvMass(idx) * (ac.getOldForce(idx) + ac.getForce(idx)) * dt_); + const auto torque = 0.5_r * (ac.getOldTorque(idx) + ac.getTorque(idx)); + const Vec3 wdot = math::transformMatrixRART(ac.getRotation(idx).getMatrix(), + ac.getInvInertiaBF(idx)) * torque; + + ac.setAngularVelocity(idx, ac.getAngularVelocity(idx) + wdot * dt_ ); } - ac.setOldForce(p_idx, ac.getForce(p_idx)); - ac.setForce(p_idx, Vec3(real_t(0), real_t(0), real_t(0))); - ac.setOldTorque(p_idx, ac.getTorque(p_idx)); - ac.setTorque(p_idx, Vec3(real_t(0), real_t(0), real_t(0))); + ac.setOldForce(idx, ac.getForce(idx)); + ac.setForce(idx, Vec3(real_t(0), real_t(0), real_t(0))); + ac.setOldTorque(idx, ac.getTorque(idx)); + ac.setTorque(idx, Vec3(real_t(0), real_t(0), real_t(0))); } } //namespace kernel -- GitLab