Skip to content
Snippets Groups Projects
Commit 99245536 authored by Armin Co's avatar Armin Co
Browse files

Merge branch 'feature_heapBuffer'

parents 70728e00 a869aaa1
No related branches found
No related tags found
No related merge requests found
# CMake file for the Q-Pong game.
## CMake file for the Q-Pong game.
##
project(QuantumPong)
cmake_minimum_required(VERSION 3.2)
project(run VERSION 1.0 LANGUAGES CXX)
## Use modern C++!
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTKMM gtkmm-3.0)
message(" - Build type is set to ${CMAKE_BUILD_TYPE}")
include_directories(${GTKMM_INCLUDE_DIRS})
include_directories(src)
add_definitions(${GTKMM_INCLUDE_DIRS})
add_subdirectory(
src
)
add_executable(run src/main.cpp src/ArrayCanvas.cpp src/Particle.cpp src/QuantumMath.cpp)
find_package (Threads)
target_link_libraries (run ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(run ${GTKMM_LIBRARIES})
target_link_libraries(run m)
target_link_libraries(run fftw3 fftw3_omp)
......@@ -7,32 +7,63 @@
#include "ArrayCanvas.hpp"
bool ArrayCanvas::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
// Clear background.
cr->save();
cr->set_source_rgba(0.0, 0.0, 0.0, 0.0);
cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
cr->paint();
// Print arrays.
for (unsigned y = 0; y < verticalArraySize; y++)
for (unsigned y = 0; y < k_drawingAreaHeight; y++)
{
for (unsigned x = 0; x < horizontalArraySize; x++)
for (unsigned x = 0; x < k_drawingAreaWidth; x++)
{
// Print local
QColor c;
c = m_bufLocalRepresentation.getValue(x, y);
double xi = x * imageScaleFactor;
double yi = y * imageScaleFactor;
// Print obstacles
// c = m_obstacles->getValue(x, y);
// cr->set_source_rgba(c.r, c.g, c.b, c.a);
// cr->rectangle(xi, yi, imageScaleFactor, imageScaleFactor);
// cr->fill();
// Print position
c = m_bufPositionRepresentation->getValue(x, y);
cr->set_source_rgba(c.r, c.g, c.b, c.a);
cr->rectangle(x, y, 1, 1);
cr->rectangle(xi, yi, imageScaleFactor, imageScaleFactor);
cr->fill();
// Print impulse
c = m_bufImpulseRepresentation.getValue(x,y);
// Print momentum
c = m_bufMomentumRepresentation->getValue(x, y);
cr->set_source_rgba(c.r, c.g, c.b, c.a);
cr->rectangle((x + horizontalArraySize), y, 1, 1);
cr->rectangle((xi+ k_drawingAreaWidth*imageScaleFactor), yi, imageScaleFactor, imageScaleFactor);
cr->fill();
}
}
constexpr int crossSize = 10;
QColor c = {1.0, 0.9, 0.9, 0.2};
cr->set_source_rgba(c.r, c.g, c.b, c.a);
// draw horizontal half of cross
cr->move_to((nx* imageScaleFactor + nx* imageScaleFactor/2 - crossSize* imageScaleFactor/2), (nx* imageScaleFactor/2));
cr->line_to(nx* imageScaleFactor + nx* imageScaleFactor/2 + crossSize* imageScaleFactor/2, (ny* imageScaleFactor/2));
cr->stroke();
// draw certical half of cross
cr->move_to((nx* imageScaleFactor + nx* imageScaleFactor/2), (nx* imageScaleFactor/2 - crossSize* imageScaleFactor/2));
cr->line_to((nx* imageScaleFactor + nx* imageScaleFactor/2), (nx* imageScaleFactor/2 + crossSize* imageScaleFactor/2));
cr->stroke();
// draw seperator between position and momentum image
cr->move_to(nx*imageScaleFactor, 0);
cr->line_to(nx*imageScaleFactor, ny * imageScaleFactor);
cr->stroke();
cr->restore();
return true;
}
\ No newline at end of file
......@@ -15,7 +15,7 @@
#include "ParticleImage.hpp"
///
/// @brief Class ArrayCanvas. Draws two ParticleImages when triggered.
///
class ArrayCanvas : public Gtk::DrawingArea
......@@ -23,16 +23,14 @@ class ArrayCanvas : public Gtk::DrawingArea
public:
///
/// @brief Class ArrayCanvas drawing area for two ParticleImages.
///
ArrayCanvas()
ArrayCanvas(ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles) : m_bufMomentumRepresentation{momentum}, m_bufPositionRepresentation{position}, m_obstacles{obstacles}
{
// Connect dispatcher
m_dispatcher.connect(sigc::mem_fun(*this, &ArrayCanvas::queueDraw));
}
///
/// @brief Trigger the redraw of this Canvas for example from another thread.
///
void triggerRedraw()
......@@ -40,42 +38,25 @@ public:
m_dispatcher.emit();
}
///
/// @brief Copy buffer.
///
void updateLocalRepresentation(const ParticleImage localRepresentation)
{
m_bufLocalRepresentation = localRepresentation;
}
///
/// @brief Copy buffer.
///
void updateImpulseRepresentation(const ParticleImage impulseRepresentation)
{
m_bufImpulseRepresentation = impulseRepresentation;
}
protected:
///
/// @brief Define the behaviour when on_draw is called.
///
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
///
/// @brief Bridge between threads to trigger the redraw of the canvas.
///
Glib::Dispatcher m_dispatcher;
///
/// @brief ParitcleImage copys from the simulation, which will be drawn to the screen.
///
ParticleImage m_bufLocalRepresentation;
ParticleImage m_bufImpulseRepresentation;
ParticleImage *m_bufPositionRepresentation;
ParticleImage *m_bufMomentumRepresentation;
ParticleImage *m_obstacles;
///
/// @brief Wraps function to trigger redraw.
/// This function cannot be called from another thread.
/// Therefore the call of this function will be triggered by the dispatcher.
......
## library for the app
add_library(qpong
QuantumMath.cpp
Particle.cpp
ParticleImage.cpp
ArrayCanvas.cpp
)
## create the application
add_executable(qpong.app
main.cpp
)
# we do need some threads
find_package(Threads)
## get all GTKMM dependencies and configuration
pkg_check_modules(GTKMM gtkmm-3.0)
link_directories(${GTKMM_LIBRARY_DIRS})
include_directories(${GTKMM_INCLUDE_DIRS})
## link all necessary libs to the target
target_link_libraries(qpong.app
qpong
${CMAKE_THREAD_LIBS_INIT}
${GTKMM_LIBRARIES}
fftw3
fftw3_omp
m # math
)
......@@ -8,63 +8,52 @@
#ifndef QPONG_CONFIGURATION_HPP
#define QPONG_CONFIGURATION_HPP
///
/// @brief Width of the drawing area in pixels.
///
constexpr unsigned long k_drawingAreaWidth = 256; // crashes at 418
constexpr unsigned imageScaleFactor = 3;
///
/// @brief Height of the drawing area in pixels.
///
constexpr unsigned long k_drawingAreaHeight = k_drawingAreaWidth;
///
/// @brief Size of one time step.
///
constexpr double dt = 0.1;
constexpr double dt = 0.15;
///
/// @brief Start position on the x-Axis.
///
constexpr double k_x0 = 0.1;
constexpr double k_x0 = 0.0;
///
/// @brief Start position on the y-Axis.
///
constexpr double k_y0 = 0.1;
constexpr double k_y0 = -0.5;
///
/// @brief Acceleration of gravity.
///
constexpr double g = 9.81;
///
/// @brief Mass of the particle.
///
constexpr double m = 1.0;
///
/// @brief Planck constant.
///
constexpr double hbar = 0.0001;
/// @brief Initial momentum in x direction.
///
/// @brief Initial impulse in x direction.
///
constexpr double k_px0 = 0.007;
constexpr double k_px0 = 0.02;
///
/// @brief Initial impuls in y direction.
///
constexpr double k_py0 = 0.014;
constexpr double k_py0 = 0.009;
///
/// @brief This constants scales the size of the impulse on initialisation.
/// @brief This constants scales the size of the momentum on initialisation.
///
constexpr double lambda = 80.0;
///
/// @brief Scale the max value at initialisation of the impulse
/// @brief Scale the max value at initialisation of the momentum
///
constexpr double A0 = 1.0;
......
......@@ -15,8 +15,11 @@
const Complex Ci(0.0, 1.0);
void Particle::initImpulse()
void Particle::initMomentum()
{
std::cout << "Initialising particle" << std::endl;
#pragma omp parallel for
for (unsigned iy = 0; iy < ny; iy++)
{
double y = yAt(iy);
......@@ -29,19 +32,20 @@ void Particle::initImpulse()
}
}
Particle::Particle(ArrayCanvas &ac) : m_arrayCanvas{ac}
Particle::Particle(ArrayCanvas &ac, ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles) : m_arrayCanvas{ac},m_bufMomentumRepresentation{momentum}, m_bufPositionRepresentation{position}, m_obstacleImage{obstacles}
{
std::cout << "Creating particle" << std::endl;
fftw_init_threads();
constexpr int k_numThreads = 4;
fftw_plan_with_nthreads(k_numThreads);
m_psi = (Complex *)fftw_malloc(sizeof(fftw_complex) * n);
m_psi = static_cast<Complex *>(fftw_malloc(sizeof(fftw_complex) * n));
m_planForward = fftw_plan_dft_1d(n, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_FORWARD, FFTW_MEASURE);
m_planBackward = fftw_plan_dft_1d(n, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_BACKWARD, FFTW_MEASURE);
m_planForward = fftw_plan_dft_2d(ny, nx, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_FORWARD, FFTW_MEASURE);
m_planBackward = fftw_plan_dft_2d(ny, nx, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_BACKWARD, FFTW_MEASURE);
initImpulse();
initMomentum();
}
Particle::~Particle()
......@@ -57,23 +61,32 @@ void Particle::propagate()
for (unsigned iy = 0; iy < ny; iy++)
{
double y = yAt(iy);
for (unsigned ix = 0; ix < nx; ix++)
#pragma omp parallel for
for (unsigned long ix = 0; ix < nx; ix++)
{
constexpr double l = 0.001; //lambda
constexpr double l = 0.0007; //lambda
double x = xAt(ix);
double E = square(y) * l;
unsigned index = nx * iy + ix;
// double E = obstaclePotential(x, y);
double E = (square(x) * square(x) + square(y/2)) * l;
// double E = (square(x) + square(y)) * l;
int index = nx * iy + ix;
m_psi[index] *= exp(-Ci * dt / hbar * E);
// Complex tmp = m_psi[index] * exp(-Ci * dt / hbar * E);
// m_psi[index] = tmp;
// m_bufPositionRepresentation->updateBuffer(index, tmp + E*600*Ci);
m_bufPositionRepresentation->updateBuffer(index, m_psi[index]);
}
}
fftw_execute (m_planForward); // transform into impulse repr.
fftw_execute (m_planForward); // transform into momentum repr.
#pragma omp parallel for
for (unsigned iy = 0; iy < ny; iy++)
{
double py = pyAt(iy);
for (unsigned ix = 0; ix < nx; ix++)
#pragma omp parallel for
for (unsigned long ix = 0; ix < nx; ix++)
{
double px = pxAt(ix);
double E = (square(px) + square(py)) / (2.0 * m);
......@@ -82,21 +95,20 @@ void Particle::propagate()
m_psi[index] *= exp(-Ci * dt / hbar * E) * N;
}
}
updateImpulseImage(); //momentum
fftw_execute(m_planBackward); // transform into local repr.
updateLocalImage(); //position
updateMomentumImage(); //momentum
fftw_execute(m_planBackward); // transform into position repr.
// updatePositionImage(); //position
}
void Particle::updateImpulseImage()
void Particle::updateMomentumImage()
{
std::array<Complex, valuesInArray> array;
unsigned px = 0;
unsigned py = 0;
unsigned impulse_index = 0;
unsigned array_index = 0;
unsigned long momentum_index = 0;
unsigned long array_index = 0;
#pragma omp parallel for
for (unsigned y = 0; y < ny; y++)
{
for (unsigned x = 0; x < nx; x++)
......@@ -118,24 +130,24 @@ void Particle::updateImpulseImage()
{
px = x + nx / 2;
}
impulse_index = py * nx + px;
momentum_index = py * nx + px;
array_index = y * nx + x;
array[array_index] = (m_psi[impulse_index] * 142.42) + 0.03;
m_bufMomentumRepresentation->updateBuffer(array_index, (m_psi[momentum_index] * 142.42));
}
}
m_arrayCanvas.updateImpulseRepresentation(ParticleImage(array));
}
void Particle::updateLocalImage()
void Particle::updatePositionImage()
{
std::array<Complex, valuesInArray> array;
#pragma omp parallel for
for (unsigned y = 0; y < ny; y++)
{
for (unsigned x = 0; x < nx; x++)
{
int index = y * nx + x;
array[index] = m_psi[index];
unsigned index = y * nx + x;
m_bufPositionRepresentation->updateBuffer(index, m_psi[index]);
}
}
m_arrayCanvas.updateLocalRepresentation(ParticleImage(array));
}
......@@ -13,7 +13,7 @@
#include "ArrayCanvas.hpp"
#include "QuantumMath.hpp"
#include "ParticleImage.hpp"
class ArrayCanvas; // Forward declaration
......@@ -21,27 +21,29 @@ class Particle
{
public:
Particle() = delete;
Particle(ArrayCanvas &ac);
Particle(ArrayCanvas &ac, ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles);
~Particle();
void propagate();
/// @brief Init the array with initial momentum.
/// Representation is in position representation.
///
void initMomentum();
private:
fftw_plan m_planForward;
fftw_plan m_planBackward;
Complex *m_psi;
ArrayCanvas &m_arrayCanvas;
fftw_plan m_planForward;
fftw_plan m_planBackward;
///
/// @brief Init the array with initial impulse.
/// Representation is in local representation.
///
void initImpulse();
///
ParticleImage *m_bufPositionRepresentation;
ParticleImage *m_bufMomentumRepresentation;
ParticleImage *m_obstacleImage;
/// @brief Update the array at the ArrayCanvas
///
void updateImpulseImage();
void updateLocalImage();
void updateMomentumImage();
void updatePositionImage();
};
#endif
\ No newline at end of file
///
/// @file ParticleImage.cpp
/// @author Armin Co
///
#include "ParticleImage.hpp"
constexpr unsigned maxBufferCount = 2;
void ParticleImage::updateBuffer(unsigned index, Complex v)
{
m_buffer[index] = v;
}
const QColor ParticleImage::getValue(const unsigned x, const unsigned y)
{
unsigned long index = y * nx + x;
constexpr double scale_factor = 0.9;
Complex val = m_buffer[index];
QColor c;
val *= scale_factor;
double r = real(val);
double i = imag(val);
c.r = square(r);
c.g = square(r) + square(i);
c.b = square(i);
return c;
}
\ No newline at end of file
......@@ -11,17 +11,9 @@
#include <array>
#include <cairomm/context.h>
#include "Particle.hpp"
#include "QuantumMath.hpp"
///
/// @brief Array config.
///
constexpr unsigned horizontalArraySize = k_drawingAreaWidth;
constexpr unsigned verticalArraySize = k_drawingAreaHeight;
constexpr unsigned long valuesInArray = horizontalArraySize * verticalArraySize;
///
/// @brief Convinient conatiner to store a RGBA value.
///
struct QColor
......@@ -29,48 +21,27 @@ struct QColor
float r = 0;
float g = 0;
float b = 0;
float a = 0.95;
float a = 1.0;
};
///
/// @brief Wraps an one dimensional array.
/// Values can be accessed as in 2D.
///
class ParticleImage
{
public:
ParticleImage()
{
}
ParticleImage(std::array<Complex, valuesInArray> array) : m_buffer{array}
{
}
///
/// @return Get Color value from particle at position (x,y).
///
const QColor getValue(const unsigned x, const unsigned y)
{
unsigned long index = y * nx + x;
constexpr double scale_factor = 1.0;
Complex val = m_buffer[index] * scale_factor;
double r = real(val);
double i = imag(val);
QColor c;
c.r = square(r);
c.g = square(r) + square(i);
c.b = square(i);
return c;
}
const QColor getValue(const unsigned x, const unsigned y);
void updateBuffer(unsigned index, Complex v);
private:
///
/// @brief Buffer for array with complex values from simulation.
///
std::array<Complex, valuesInArray> m_buffer;
std::array<Complex, n> m_buffer;
};
#endif
\ No newline at end of file
......@@ -7,26 +7,40 @@
#include "QuantumMath.hpp"
const double obstaclePotential(double x, double y)
{
double xPos = 0;
double yPos = 0;
constexpr double maxV = 1;
constexpr double l = 0.0007; //lambda
double E = (square(x) * square(x) + square(y/2)) * l;
return E;
}
const double xAt(int i)
{
return ((int)i - (int)nx / 2) * dx;
return (i - (nx / 2)) * dx;
}
const double yAt(int iy)
{
return ((int)iy - (int)ny / 2) * dy;
return (iy - (ny / 2)) * dy;
}
const double pxAt(int ix)
{
if ((int)ix > (int)nx / 2)
ix -= (int)nx;
if (ix > nx / 2)
ix -= nx;
return ix * 2.0 * M_PI * hbar / (nx * dx);
}
const double pyAt(int iy)
{
if ((int)iy > (int)ny / 2)
iy -= (int)ny;
if (iy > ny / 2)
iy -= ny;
return iy * 2.0 * M_PI * hbar / (ny * dy);
}
......@@ -24,24 +24,27 @@ const T square(const T n)
}
// Points in x direction.
const unsigned long nx = k_drawingAreaWidth;
const int nx = k_drawingAreaWidth;
// Points in y direction.
const unsigned long ny = k_drawingAreaHeight;
const int ny = k_drawingAreaHeight;
// Number of all points/pixels.
const unsigned long n = nx * ny;
constexpr int n = nx * ny;
const double dx = 2.0 / nx;
const double dy = 2.0 / ny;
/// @brief Potential of the obstachle that is controlled by the player.
///
/// @brief Get index to access array in local representation.
const double obstaclePotential(double x, double y);
/// @brief Get index to access array in position representation.
///
const double xAt(int i);
const double yAt(int iy);
///
/// @brief Get index to access array in impulse representation.
/// @brief Get index to access array in momentum representation.
///
const double pxAt(int ix);
......
......@@ -8,59 +8,118 @@
#include <chrono>
#include <thread>
#include <gtkmm/application.h>
#include <gtkmm/window.h>
#include <gtkmm.h>
#include "ArrayCanvas.hpp"
#include "Particle.hpp"
#include "Configuration.hpp"
bool propagating = true;
///
/// @brief This functino has to run in its own thread and propagates the particle as fast as possible.
///
void simulation(ArrayCanvas & ac)
void simulation(Particle *p)
{
Particle p(ac);
do
{
p.propagate();
p->propagate();
}
while (true);
while (propagating);
}
///
/// @brief This function has to run in its own thread an will redraw the canvas every ~25ms.
///
void render(ArrayCanvas &ac)
void render(ArrayCanvas *ac)
{
do
{
using namespace std::chrono_literals;
std::this_thread::sleep_for(25ms);
ac.triggerRedraw();
std::this_thread::sleep_for(5ms);
ac->triggerRedraw();
} while (true);
}
class QWindow : public Gtk::Window
{
public:
QWindow() : m_button{"Initialise Particle"}
{
m_momentum = new ParticleImage;
m_position = new ParticleImage;
m_obstacles = new ParticleImage;
m_ac = new ArrayCanvas(m_momentum, m_position, m_obstacles);
m_particle = new Particle(*m_ac, m_momentum, m_position, m_obstacles);
set_border_width(10);
m_button.signal_clicked().connect(sigc::mem_fun(*this, &QWindow::on_button_clicked));
add(m_box);
m_box.pack_start(m_vBox);
m_vBox.pack_start(m_button, Gtk::PACK_SHRINK);
m_vBox.pack_start(m_label, Gtk::PACK_SHRINK);
m_vBox.pack_start(*m_ac);
m_label.set_margin_top(5);
m_label.set_margin_bottom(5);
m_ac->show();
m_button.show();
m_box.show();
m_vBox.show();
m_label.show();
m_label.set_text("Hi, you are playing QPong and this is a label!");
m_propagatingThread = std::thread(simulation, m_particle);
m_propagatingThread.detach();
std::cout << "Starting to draw images" << std::endl;
std::thread rendering(render,m_ac);
rendering.detach();
}
virtual ~QWindow(){}
protected:
// signal handlers:
void on_button_clicked()
{
propagating = false;
std::this_thread::sleep_for((std::chrono::seconds)1);
m_particle->initMomentum();
m_propagatingThread = std::thread(simulation, m_particle);
propagating = true;
m_propagatingThread.detach();
}
// Member widgets:
Gtk::Box m_box;
Gtk::VBox m_vBox;
Gtk::Label m_label;
Gtk::Button m_button;
ArrayCanvas *m_ac;
// qpong
Particle *m_particle;
std::thread m_propagatingThread;
ParticleImage *m_momentum;
ParticleImage *m_position;
ParticleImage *m_obstacles;
};
///
/// @brief MAIN
///
int main(int argc, char* argv[])
{
// App and window
auto app = Gtk::Application::create(argc, argv, "cvh.qpong");
Gtk::Window window;
window.set_default_size(1024, 512);
// canvas
ArrayCanvas ac;
// threads
std::thread prop(simulation, std::ref(ac));
prop.detach();
std::thread rendering(render, std::ref(ac));
rendering.detach();
std::cout << "Starting QPong" << std::endl;
auto app = Gtk::Application::create(argc, argv, "de.armin-co.qpong");
std::cout << "Creating window" << std::endl;
QWindow window;
window.set_default_size(k_drawingAreaWidth*imageScaleFactor*2+130, k_drawingAreaWidth*imageScaleFactor+100);
// show and run
window.add(ac);
ac.show();
return app->run(window);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment