File indexing completed on 2024-04-21 03:51:23

0001 /*
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "particle.h"
0008 #include "types.h"
0009 #include <cstring>
0010 #include <cmath>
0011 
0012 namespace StepCore
0013 {
0014 
0015 STEPCORE_META_OBJECT(Particle, QT_TRANSLATE_NOOP("ObjectClass", "Particle"), QT_TRANSLATE_NOOP("ObjectDescription", "Simple zero-size particle"), 0,
0016         STEPCORE_SUPER_CLASS(Item) STEPCORE_SUPER_CLASS(Body),
0017         STEPCORE_PROPERTY_RW_D(StepCore::Vector2d, position, QT_TRANSLATE_NOOP("PropertyName", "position"), QT_TRANSLATE_NOOP("Units", "m"), QT_TRANSLATE_NOOP("PropertyDescription", "position"), position, setPosition)
0018         STEPCORE_PROPERTY_RW_D(StepCore::Vector2d, velocity, QT_TRANSLATE_NOOP("PropertyName", "velocity"), QT_TRANSLATE_NOOP("Units", "m/s"), QT_TRANSLATE_NOOP("PropertyDescription", "velocity"), velocity, setVelocity)
0019         STEPCORE_PROPERTY_R_D(StepCore::Vector2d, acceleration, QT_TRANSLATE_NOOP("PropertyName", "acceleration"), STEPCORE_FROM_UTF8(QT_TRANSLATE_NOOP("Units", "m/s²")),
0020                                                             QT_TRANSLATE_NOOP("PropertyDescription", "acceleration"), acceleration)
0021         STEPCORE_PROPERTY_R_D(StepCore::Vector2d, force, QT_TRANSLATE_NOOP("PropertyName", "force"), QT_TRANSLATE_NOOP("Units", "N"), QT_TRANSLATE_NOOP("PropertyDescription", "force"), force)
0022         STEPCORE_PROPERTY_RW(double, mass, QT_TRANSLATE_NOOP("PropertyName", "mass"), QT_TRANSLATE_NOOP("Units", "kg"), QT_TRANSLATE_NOOP("PropertyDescription", "mass"), mass, setMass)
0023         STEPCORE_PROPERTY_RWF(StepCore::Vector2d, momentum, QT_TRANSLATE_NOOP("PropertyName", "momentum"), QT_TRANSLATE_NOOP("Units", "kg m/s"), QT_TRANSLATE_NOOP("PropertyDescription", "momentum"),
0024                         StepCore::MetaProperty::DYNAMIC, momentum, setMomentum)
0025         STEPCORE_PROPERTY_RWF(double, kineticEnergy, QT_TRANSLATE_NOOP("PropertyName", "kineticEnergy"), QT_TRANSLATE_NOOP("Units", "J"), QT_TRANSLATE_NOOP("PropertyDescription", "kinetic energy"),
0026                         StepCore::MetaProperty::DYNAMIC, kineticEnergy, setKineticEnergy))
0027 
0028 STEPCORE_META_OBJECT(ParticleErrors, QT_TRANSLATE_NOOP("ObjectClass", "ParticleErrors"), QT_TRANSLATE_NOOP("ObjectDescription", "Errors class for Particle"), 0, STEPCORE_SUPER_CLASS(ObjectErrors),
0029         STEPCORE_PROPERTY_RW_D(StepCore::Vector2d, positionVariance, QT_TRANSLATE_NOOP("PropertyName", "positionVariance"), QT_TRANSLATE_NOOP("Units", "m"),
0030                     QT_TRANSLATE_NOOP("PropertyDescription", "position variance"), positionVariance, setPositionVariance)
0031         STEPCORE_PROPERTY_RW_D(StepCore::Vector2d, velocityVariance, QT_TRANSLATE_NOOP("PropertyName", "velocityVariance"), QT_TRANSLATE_NOOP("Units", "m/s"),
0032                     QT_TRANSLATE_NOOP("PropertyDescription", "velocity variance"), velocityVariance, setVelocityVariance)
0033         STEPCORE_PROPERTY_R_D(StepCore::Vector2d, accelerationVariance, QT_TRANSLATE_NOOP("PropertyName", "accelerationVariance"), STEPCORE_FROM_UTF8(QT_TRANSLATE_NOOP("Units", "m/s²")),
0034                     QT_TRANSLATE_NOOP("PropertyDescription", "acceleration variance"), accelerationVariance)
0035         STEPCORE_PROPERTY_R_D(StepCore::Vector2d, forceVariance, QT_TRANSLATE_NOOP("PropertyName", "forceVariance"), QT_TRANSLATE_NOOP("Units", "N"),
0036                     QT_TRANSLATE_NOOP("PropertyDescription", "force variance"), forceVariance)
0037         STEPCORE_PROPERTY_RW(double, massVariance, QT_TRANSLATE_NOOP("PropertyName", "massVariance"), QT_TRANSLATE_NOOP("Units", "kg"),
0038                     QT_TRANSLATE_NOOP("PropertyDescription", "mass variance"), massVariance, setMassVariance )
0039         STEPCORE_PROPERTY_RWF(StepCore::Vector2d, momentumVariance, QT_TRANSLATE_NOOP("PropertyName", "momentumVariance"), QT_TRANSLATE_NOOP("Units", "kg m/s"),
0040                     QT_TRANSLATE_NOOP("PropertyDescription", "momentum variance"), StepCore::MetaProperty::DYNAMIC, momentumVariance, setMomentumVariance)
0041         STEPCORE_PROPERTY_RWF(double, kineticEnergyVariance, QT_TRANSLATE_NOOP("PropertyName", "kineticEnergyVariance"), QT_TRANSLATE_NOOP("Units", "J"),
0042                     QT_TRANSLATE_NOOP("PropertyDescription", "kinetic energy variance"), StepCore::MetaProperty::DYNAMIC, kineticEnergyVariance, setKineticEnergyVariance))
0043 
0044 STEPCORE_META_OBJECT(ChargedParticle, QT_TRANSLATE_NOOP("ObjectClass", "ChargedParticle"), QT_TRANSLATE_NOOP("ObjectDescription", "Charged zero-size particle"), 0, STEPCORE_SUPER_CLASS(Particle),
0045         STEPCORE_PROPERTY_RW(double, charge, QT_TRANSLATE_NOOP("PropertyName", "charge"), QT_TRANSLATE_NOOP("Units", "C"), QT_TRANSLATE_NOOP("PropertyDescription", "charge"), charge, setCharge))
0046 
0047 STEPCORE_META_OBJECT(ChargedParticleErrors, QT_TRANSLATE_NOOP("ObjectClass", "ChargedParticleErrors"), QT_TRANSLATE_NOOP("ObjectDescription", "Errors class for ChargedParticle"), 0,
0048         STEPCORE_SUPER_CLASS(ParticleErrors),
0049         STEPCORE_PROPERTY_RW(double, chargeVariance, QT_TRANSLATE_NOOP("PropertyName", "chargeVariance"), QT_TRANSLATE_NOOP("Units", "kg"),
0050                     QT_TRANSLATE_NOOP("PropertyDescription", "charge variance"), chargeVariance, setChargeVariance ))
0051 
0052 Particle* ParticleErrors::particle() const
0053 {
0054     return static_cast<Particle*>(owner());
0055 }
0056 
0057 Vector2d ParticleErrors::accelerationVariance() const
0058 {
0059     return _forceVariance/square(particle()->mass()) +
0060         _massVariance*(particle()->force()/square(particle()->mass())).array().square().matrix();
0061 }
0062 
0063 Vector2d ParticleErrors::momentumVariance() const
0064 {
0065     return _velocityVariance * square(particle()->mass()) +
0066            (particle()->velocity().array().square()).matrix() * _massVariance;
0067 }
0068 
0069 void ParticleErrors::setMomentumVariance(const Vector2d& momentumVariance)
0070 {
0071     _velocityVariance = (momentumVariance - (particle()->velocity().array().square()).matrix() * _massVariance) /
0072                         square(particle()->mass());
0073 }
0074 
0075 double ParticleErrors::kineticEnergyVariance() const
0076 {
0077     return ((particle()->velocity().array().square()).matrix()).dot(_velocityVariance) * square(particle()->mass()) +
0078            square(particle()->velocity().squaredNorm()/2) * _massVariance;
0079 }
0080 
0081 void ParticleErrors::setKineticEnergyVariance(double kineticEnergyVariance)
0082 {
0083     _velocityVariance = (kineticEnergyVariance - square(particle()->velocity().squaredNorm()/2) * _massVariance) /
0084                         square(particle()->mass()) / 2 *
0085                         (particle()->velocity().array().square().array().inverse());
0086     if(!std::isfinite(_velocityVariance[0]) || _velocityVariance[0] < 0 ||
0087        !std::isfinite(_velocityVariance[1]) || _velocityVariance[1]) {
0088         _velocityVariance.setZero();
0089     }
0090 }
0091 
0092 ChargedParticle* ChargedParticleErrors::chargedParticle() const
0093 {
0094     return static_cast<ChargedParticle*>(owner());
0095 }
0096 
0097 Particle::Particle(const Vector2d &position, const Vector2d &velocity, double mass)
0098     : _position(position), _velocity(velocity), _force(Vector2d::Zero()), _mass(mass)
0099 {
0100 }
0101 
0102 void Particle::getVariables(double* position, double* velocity,
0103                      double* positionVariance, double* velocityVariance)
0104 {
0105     Vector2d::Map(position) = _position;
0106     Vector2d::Map(velocity) = _velocity;
0107     if(positionVariance) {
0108         ParticleErrors* pe = particleErrors();
0109         Vector2d::Map(positionVariance) = pe->_positionVariance;
0110         Vector2d::Map(velocityVariance) = pe->_velocityVariance;
0111     }
0112 }
0113 
0114 void Particle::setVariables(const double* position, const double* velocity,
0115                const double* positionVariance, const double* velocityVariance)
0116 {
0117     _position = Vector2d::Map(position);
0118     _velocity = Vector2d::Map(velocity);
0119     _force.setZero();
0120     if(positionVariance) {
0121         ParticleErrors* pe = particleErrors();
0122         pe->_positionVariance = Vector2d::Map(positionVariance);
0123         pe->_velocityVariance = Vector2d::Map(velocityVariance);
0124         pe->_forceVariance.setZero();
0125     }
0126 }
0127 
0128 void Particle::getAccelerations(double* acceleration, double* accelerationVariance)
0129 {
0130     acceleration[0] = _force[0] / _mass;
0131     acceleration[1] = _force[1] / _mass;
0132     if(accelerationVariance) {
0133         ParticleErrors* pe = particleErrors();
0134         accelerationVariance[0] = pe->_forceVariance[0]/square(_mass) +
0135                                         square(_force[0]/square(_mass))*pe->_massVariance;
0136         accelerationVariance[1] = pe->_forceVariance[1]/square(_mass) +
0137                                         square(_force[1]/square(_mass))*pe->_massVariance;
0138     }
0139 }
0140 
0141 void Particle::addForce(const double* force, const double* forceVariance)
0142 {
0143     _force[0] += force[0];
0144     _force[1] += force[1];
0145     if(forceVariance) {
0146         ParticleErrors* pe = particleErrors();
0147         pe->_forceVariance[0] += forceVariance[0];
0148         pe->_forceVariance[1] += forceVariance[1];
0149     }
0150 }
0151 
0152 void Particle::resetForce(bool resetVariance)
0153 {
0154     _force.setZero();
0155     if(resetVariance) particleErrors()->_forceVariance.setZero();
0156 }
0157 
0158 void Particle::getInverseMass(VectorXd* inverseMass,
0159                               DynSparseRowMatrix* variance, int offset)
0160 {
0161     inverseMass->coeffRef(offset) = ( 1/_mass);
0162     inverseMass->coeffRef(offset+1) = ( 1/_mass);
0163     if(variance) {
0164         double v = particleErrors()->_massVariance / square(square(_mass));
0165         variance->coeffRef(offset, offset) = (v);
0166         variance->coeffRef(offset+1, offset+1) = (v);
0167     }
0168 }
0169 
0170 void Particle::setKineticEnergy(double kineticEnergy)
0171 {
0172     double v = _velocity.norm();
0173     _velocity = sqrt(kineticEnergy*2/_mass) * (v>0 ? (_velocity/v).eval() : Vector2d(1,0));
0174 }
0175 
0176 } // namespace StepCore
0177