气体粒子模拟碰撞计算C ++

时间:2016-03-30 13:31:38

标签: c++

我认为这是一个相当复杂的问题,我希望我可以将它放入足够小的空间以使其易于理解。我现在正在编写代码

  

模拟盒子内的理想气体颗粒。我计算两个粒子是否会碰撞,计算出它们到达最近点的时间。 (使用他们碰撞的例子。)

在这部分代码中,我需要找出它们是否会碰撞两个粒子,然后计算它们在什么时间碰撞以及它们如何碰撞等。 因此,对于我的两个颗粒:

Main.cpp

Vector vp1(0,0,0);
Vector vv1(1,0,0);
Vector vp2(12,0,0);
Vector vv2(-1,0,0);
Particle Particle1(1, vp1, vv1);
Particle Particle2(1, vp2, vv2);
Particle1.timeToCollision(Particle2);

在我的程序中,我将粒子定义为:

标头文件

class Particle {
private:

    Vector p;   //position
    Vector v;   //velocity
    double radius;   //radius

public:

    Particle();

    Particle(double r, const Vector Vecp, const Vector Vecv);

    void setPosition(Vector);
    void setVelocity(Vector);

    Vector getPosition() const;
    Vector getVelocity() const;

    double getRadius() const;

    void move(double t);

    double timeToCollision(const Particle particle);

    void collideParticles(Particle);

    ~Particle();
};

Vector是另一个类,简而言之就是提供xyz值。它还包含多个用于操作它们的函数。

我需要帮助的部分,在.cpp内(忽略cout开头和字母等,它们是我的代码退出测试的简单检查。)

给出方程:

enter image description here

我已经编写了代码来为我做点积和模数:

b^2=r(0)^2-s^2

其中

s^2=((-r(0) dot product v)^2 / modulus squared v)

s是时间旅行的距离tac

double Particle::timeToCollision(const Particle particle){
    Vector r2 = particle.getPosition();
    Vector r1 = p;
    Vector v2 = particle.getVelocity();
    Vector v1 = v;
    Vector r0 = r2 - r1;
    Vector v = v2 - v1;

    double modv;
    double tca;
    double result = 0;
    double bsqr;

    modv = getVelocity().modulus();

    cout << "start" << endl;

    if(modv < 0.0000001){
        cout << "a" << endl;
        result = FLT_MAX;
    }else{
        cout << "b" << endl;
        tca = ((--r0).dot(v)) / v.modulusSqr();

// -- is an overridden operator that gives the negation ( eg (2, 3, 4) to (-2, -3, -4) )
        if (tca < 0) {
            cout << "c" << endl;
            result = FLT_MAX;
        }else{
            cout << "d" << endl;
            Vector s(v.GetX(), v.GetY(), v.GetZ());
            s.Scale(tca);
            cout << getVelocity().GetX() << endl;
            cout << getVelocity().GetY() << endl;
            cout << getVelocity().GetZ() << endl;

            double radsqr = radius * radius;
            double bx = (r0.GetX() * r0.GetX() - (((r0).dot(v)) *((r0).dot(v)) / v.modulusSqr()));
            double by = (r0.GetY() * r0.GetY() - (((r0).dot(v)) *((r0).dot(v)) / v.modulusSqr()));
            double bz=(r0.GetZ() * r0.GetZ() - (((r0).dot(v)) * ((r0).dot(v)) / v.modulusSqr()));

            if (bsqr < 4 * radsqr) {
                cout << "e" << endl;
                result = FLT_MAX;
            } else {
            }
            cout << "tca: " << tca << endl;
        }
    }
    cout << "fin" << endl;
    return result;
}

我有计算几个方面的等式,tca指的是最接近的时间。

正如我在代码中所写,我需要检查b > 4 r^2是否已成功,我已经做了一些尝试,并编写了X的{​​{1}},YZ组件出去但是我得到了垃圾回答。 我只是需要帮助来确定我是否已经犯了错误或者我应该走的方向。

我之前的所有代码都按预期工作,并且我已经为每个代码编写了多个测试。

如果您认为我遗漏了任何信息,请通知我。

任何帮助非常感谢。

2 个答案:

答案 0 :(得分:1)

您的代码中有几处错误。您从未将result设置为与0FLT_MAX不同的值。你也永远不会计算bsqr。我想如果bsqr < 4r^2发生碰撞而不是相反。 (我不明白为什么4r^2而不是r^2,但没关系。由于你隐藏了矢量实现,我使用了一个通用的矢量库。我还建议不要使用手工制作的东西。看看犰狳或igen。

在这里,您将尝试使用Eigen。

#include <iostream>
#include <limits>
#include <type_traits>
#include "Eigen/Dense"

struct Particle {
    double radius;
    Eigen::Vector3d p;
    Eigen::Vector3d v;
};

template <class FloatingPoint>
    std::enable_if_t<std::is_floating_point<FloatingPoint>::value, bool>
        almost_equal(FloatingPoint x, FloatingPoint y, unsigned ulp=1)
        {
            FloatingPoint max = std::max(std::abs(x), std::abs(y));
            return std::abs(x-y) <= std::numeric_limits<FloatingPoint>::epsilon()*max*ulp;
        }

double timeToCollision(const Particle& left, const Particle& right){
    Eigen::Vector3d r0 = right.p - left.p;
    Eigen::Vector3d v  = right.v - left.v;

    double result = std::numeric_limits<double>::infinity();

    double vv = v.dot(v);
    if (!almost_equal(vv, 0.)) {
        double tca = (-r0).dot(v) / vv;
        if (tca >= 0) {
            Eigen::Vector3d s = tca*v;
            double bb = r0.dot(r0) - s.dot(s);
            double radius = std::max(left.radius, right.radius);
            if (bb < 4*radius*radius)
                result = tca;
        }
    }
    return result;
}

int main()
{
    Eigen::Vector3d vp1 {0,0,0};
    Eigen::Vector3d vv1 {1,0,0};
    Eigen::Vector3d vp2 {12,0,0};
    Eigen::Vector3d vv2 {-1,0,0};
    Particle p1 {1, vp1, vv1};
    Particle p2 {1, vp2, vv2};
    std::cout << timeToCollision(p1, p2) << '\n';
}

答案 1 :(得分:0)

我对一个措辞非常糟糕的问题表示道歉,这个问题很长而且很笨重。幸运的是,我发现自己的答案比最初预期的要容易得多。

double Particle::timeToCollision(const Particle particle){

    Vector r2=particle.getPosition();
    Vector r1=p;
    Vector v2=particle.getVelocity();
    Vector v1=v;
    Vector r0=r2-r1;
    Vector v=v2-v1;

    double modv;
    double tca = ((--r0).dot(v)) / v.modulusSqr();
    double bsqr;

    double result=0;

    double rColTestx=r0.GetX()+v.GetX()*tca;
    double rColTesty=r0.GetY()+v.GetY()*tca;
    double rColTestz=r0.GetZ()+v.GetZ()*tca;

    Vector rtColTest(rColTestx, rColTesty, rColTestz);


    modv=getVelocity().modulus();

    cout << "start " << endl;

    if(modv<0.0000001){
        cout << "a" << endl;
        result=FLT_MAX;
    }else{
        cout << "b" << endl;

        if (tca < 0) {
            cout << "c" << endl;
            result=FLT_MAX;
        }else{
            cout << "d" << endl;
            Vector s(v.GetX(), v.GetY(), v.GetZ());
            s.Scale(tca);

            cout << getVelocity().GetX() << endl;
            cout << getVelocity().GetY() << endl;
            cout << getVelocity().GetZ() << endl;


           double radsqr= radius*radius;

            bsqr=rtColTest.modulusSqr();

            if (bsqr < 4*radsqr) {
                cout << "e" << endl;
                cout << "collision occurs" << endl;
                result = FLT_MAX;
            } else {
                cout << "collision does not occurs" << endl;
            }

        }

    }
    cout << "fin" << endl;
    return result;

}

对不起它的大部分代码。 FLT_MAX也来自cfloat lib。在我的问题中,我没有对此进行统计。我发现这适用于我在纸上计算的几个例子。

要明确,return resultresult=0是任意的。我后来编辑返回时间,但这部分并不需要或想要。