Skip to content
Snippets Groups Projects
Select Git revision
  • 2023ws
  • 2024ws default
  • 2022ws
  • 2021ws
  • 2020ws
  • 2018ws
  • 2019ws
  • 2017ws
  • 2016ws
9 results

wurf-11.c

Blame
  • Particle.cpp 8.21 KiB
    ///
    /// @file       Particle.cpp
    /// @author     Armin Co
    ///
    /// @brief      Particle class implemantation and main().
    /// 
    
    #include <iostream>
    #include <thread>
    #include <vector>
    
    #include "Common.hpp"
    #include "Particle.hpp"
    
    /// @brief Planck constant.
    ///
    constexpr double hbar = 0.0002;
    
    const std::complex<double> Ci(0.0, 1.0);
    
    
    /// @brief Takes the row index of an array and turns it 
    ///         into a position.
    ///
    const double xAt(int x)
    {
        return 2.0 * x / QPong::arrayWidth - 1.0; 
    }
    
    
    /// @brief Takes the line index of an array and turns it
    ///         into a position.
    ///
    const double yAt(int y)
    {
        return 2.0 * y / QPong::arrayHeight - 1.0;
    }
    
    
    void Particle::initMomentum()
    {
        double sumAtInit = 0.0;
        for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
        {
            double y = yAt(iy);
            for (unsigned ix = 0; ix < QPong::arrayWidth; ix++)
            {
                double x = xAt(ix);
                unsigned index = QPong::arrayWidth * iy + ix;
                constexpr double k_px0 = 0.063;
                constexpr double k_py0 = 0.042;
                constexpr double k_x0 = 0.0;
                constexpr double k_y0 = -0.0;
                constexpr double lambda = 60.0;
                constexpr double A0 = 0.5;
                m_psi[index] = A0 * exp(Ci / hbar * (x * k_px0 + y * k_py0) - lambda * (sqr(x - k_x0) + sqr(y - k_y0)));
                sumAtInit += sqr(real(m_psi[index])) + sqr(imag(m_psi[index]));
            }
        }
        for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
        {
            double y = yAt(iy);
            for (unsigned ix = 0; ix < QPong::arrayWidth; ix++)
            {
                double x = xAt(ix);
                unsigned index = QPong::arrayWidth * iy + ix;
                m_psi[index] *= 1.0 / sqrt(sumAtInit);
            }
        }
    }
    
    
    Particle::Particle(ImageBuffer *momentum, ImageBuffer *position, std::map<Player::Id, std::shared_ptr<Player>> players)
        : m_bufMomentumRepresentation{momentum}
        , m_bufPositionRepresentation{position}
        , m_ready{false}
        , m_players {players}
    {
        fftw_init_threads();
        fftw_plan_with_nthreads(QPong::numberOfThreads);
        m_psi = static_cast<std::complex<double> *>(fftw_malloc(sizeof(fftw_complex) * QPong::arraySize));
        m_planForward = fftw_plan_dft_2d(QPong::arrayHeight, QPong::arrayWidth, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_FORWARD, FFTW_MEASURE);
        m_planBackward = fftw_plan_dft_2d(QPong::arrayHeight, QPong::arrayWidth, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_BACKWARD, FFTW_MEASURE);
        initMomentum();
        m_ready = true;
    }
    
    
    Particle::~Particle()
    {
        fftw_free((fftw_complex *)m_psi);
        fftw_destroy_plan(m_planForward);
        fftw_destroy_plan(m_planBackward);
    }
    
    
    bool Particle::notReady()
    {
        return !m_ready;
    }
    
    
    double Particle::removeParticle(int index, double cx)
    {
        double normPre  = sqr(std::real(m_psi[index])) + sqr(std::imag(m_psi[index]));
        double e =  sqr(cos(cx));
        m_psi[index] *= e;
        double dif = normPre - (sqr(std::real(m_psi[index])) + sqr(std::imag(m_psi[index])));
        return dif;
    }
    
    
    const double batPotential(double x, double y, Player::Position pos)
    {
        y -= pos.y;
        double E = 0.0;
        constexpr double scale = 0.000015;
        constexpr double height = 0.31;
        constexpr double cutoff = 0.0015;
        if (y >= height)
        {
            double d = sqr(x-pos.x) + sqr(y-height) + cutoff;
            E = 1.0 / d * scale;
        }
        else if (y <= (-height))
        {
            double d = sqr(x-pos.x) + sqr((-y)-height) + cutoff;
            E = 1.0 / d * scale;
        }
        else
        {
            double d = sqr(pos.x-x) + cutoff;
            E = 1.0 / d * scale;
        }
        return E;
    }
    
    
    constexpr double dt = 0.15;
    void Particle::manipulateParticleInPosition(int indexFrom, int indexTo)
    {
        auto pOneX = m_players[Player::Id::One]->getPosition().x;
        auto pTwoX = m_players[Player::Id::Two]->getPosition().x;
        float sumScorePlayerOne = 0.0;
        float sumScorePlayerTwo = 0.0;
    
        for (int index = indexFrom; index < indexTo; index++)
        {
            double x = xAt(index % QPong::arrayWidth);
            double y = yAt(index / QPong::arrayWidth);
            if (x < pOneX) //< expects p1.x < 0
            {
                double cx = -pOneX + x;
                cx = cx * (M_PI / 2.0) / (1.0 + pOneX);
                double dif = removeParticle(index, cx);
                sumScorePlayerTwo += dif;
            }
            if (x > pTwoX) //< expects p2.x > 0
            {
                double cx = x - pTwoX;
                cx = cx * (M_PI / 2.0) / (1.0 - pTwoX);
                double dif = removeParticle(index, cx);
                sumScorePlayerOne += dif;
            }
            double playerOneBat = batPotential(x, y, m_players[Player::Id::One]->getPosition());
            double playerTwoBat = batPotential(x, y, m_players[Player::Id::Two]->getPosition());
            double horizontalBorders = sqr(y) * sqr(y) * sqr(y) * sqr(y) * 0.01;
            auto potentialSum = playerOneBat + playerTwoBat + horizontalBorders;
            auto tmpPsi = m_psi[index] * exp(-Ci * dt / hbar * potentialSum);
            m_psi[index] = tmpPsi;
            m_bufPositionRepresentation->updateAt(index, tmpPsi * 125.0, potentialSum * 150);
        }
        m_players[Player::Id::One]->addScore(sumScorePlayerOne);
        m_players[Player::Id::Two]->addScore(sumScorePlayerTwo);
    }
    
    
    double flattenMomentum(double x, double y)
    {
        double distanceToCenter = sqr(x) + sqr(y);
        constexpr double offset = 0.012;
        if (distanceToCenter > offset)
        {
            return 1.0 / (1.0 + (distanceToCenter * 2.5));
        }
        else
        {
            return 1.0;
        }
    }
    
    
    const double pxAt(int ix)
    {
        if (ix > QPong::arrayWidth / 2)
        {
            ix -= QPong::arrayWidth;
        }
        return ix * M_PI * hbar;
    }
    
    
    const double pyAt(int iy)
    {
        if (iy > QPong::arrayHeight / 2)
        {
            iy -= QPong::arrayHeight;
        }
        return iy * M_PI * hbar;
    }
    
    
    void Particle::moveStep(int indexFrom, int indexTo)
    {
        for (int i = indexFrom; i < indexTo; i++)
        {
            double py = pyAt(i / QPong::arrayWidth);
            double px = pxAt(i % QPong::arrayWidth);
            constexpr double m = 1.0;   
            constexpr double N = 1.0 / QPong::arraySize;
            double E = (sqr(px) + sqr(py)) / (2.0 * m);
            auto f = flattenMomentum(px, py);
            m_psi[i] *= exp(-Ci * dt / hbar * E) * N * f;
            // m_psi[i] = flattenMomentum(px, py) * 0.00001;
        }
    }
    
    
    void Particle::propagate()
    { 
        for (auto &player : m_players)
        {
            player.second->update(dt);
        }
    
        std::vector<std::thread> positionThreads;
        for (int i = 0; i < QPong::numberOfThreads; i++)
        {
            int from =  i * (QPong::arraySize/QPong::numberOfThreads);
            int to = (i+1) * (QPong::arraySize/QPong::numberOfThreads);
            positionThreads.emplace_back(&Particle::manipulateParticleInPosition, this, i * (QPong::arraySize/QPong::numberOfThreads), (i+1) * (QPong::arraySize/QPong::numberOfThreads));
        }
        for (auto &thread : positionThreads)
        {
            thread.join();
        }
        fftw_execute (m_planForward); // transform into momentum repr.
        
        std::vector<std::thread> momentumThreads;
        for (int i = 0; i < QPong::numberOfThreads; i++)
        {
            momentumThreads.emplace_back(&Particle::moveStep, this, i * (QPong::arraySize / QPong::numberOfThreads), (i + 1) * (QPong::arraySize / QPong::numberOfThreads));
        }
        for (auto &thread : momentumThreads)
        {
            thread.join();
        }
        /// @todo Pull update Momentum image into moveStep()
        updateMomentumImage(); //momentum
        fftw_execute(m_planBackward); // transform into position repr.
    }
    
    
    void Particle::updateMomentumImage()
    {
        for (int index = 0; index < QPong::arraySize; index++)
        {
            auto y = index / QPong::arrayWidth;
            unsigned py = 0;
            if (y >= QPong::arrayHeight / 2)
            {
                py = y - QPong::arrayHeight / 2;
            }
            else 
            {
                py = y + QPong::arrayHeight / 2;
            }
    
            auto x = index % QPong::arrayWidth;
            unsigned px = 0;
            if (x >= QPong::arrayWidth / 2)
            {
                px = x - QPong::arrayWidth / 2;
            }
            else
            {
                px = x + QPong::arrayWidth / 2;
            }
            
            constexpr double scale = 55580.0;;
            auto array_index = y * QPong::arrayWidth + x;
            auto momentum_index = py * QPong::arrayWidth + px;
            m_bufMomentumRepresentation->updateAt(array_index, (m_psi[momentum_index] * scale), 0.0);
        }
    }