From 4dad0bdf3c5058c6cc9f712f458310de74d91417 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Thu, 2 Aug 2012 20:44:08 +0800 Subject: [PATCH] Started Parallel Programming Self Assessment It is an N-Body simulator. Fun! Hopefully I don't fail my research project because of this module... --- course/semester2/pprog/assignment0/Makefile | 22 ++ course/semester2/pprog/assignment0/graphics.c | 170 +++++++++ course/semester2/pprog/assignment0/graphics.h | 35 ++ course/semester2/pprog/assignment0/main.c | 42 +++ course/semester2/pprog/assignment0/nbody.c | 343 ++++++++++++++++++ course/semester2/pprog/assignment0/nbody.h | 85 +++++ 6 files changed, 697 insertions(+) create mode 100644 course/semester2/pprog/assignment0/Makefile create mode 100644 course/semester2/pprog/assignment0/graphics.c create mode 100644 course/semester2/pprog/assignment0/graphics.h create mode 100644 course/semester2/pprog/assignment0/main.c create mode 100644 course/semester2/pprog/assignment0/nbody.c create mode 100644 course/semester2/pprog/assignment0/nbody.h diff --git a/course/semester2/pprog/assignment0/Makefile b/course/semester2/pprog/assignment0/Makefile new file mode 100644 index 00000000..538a0fa0 --- /dev/null +++ b/course/semester2/pprog/assignment0/Makefile @@ -0,0 +1,22 @@ +#Makefile for nbody program + +CXX = gcc --std=c99 -Wall -pedantic -g -lm -lSDL -lGL +OBJ = main.o nbody.o graphics.o + +BIN = nbody + + + +$(BIN) : $(OBJ) + $(CXX) -o $(BIN) $(OBJ) + +%.o : %.c %.h + $(CXX) -c $< + +clean : + $(RM) $(BIN) $(OBJ) $(LINKOBJ) + +clean_full: #cleans up all backup files + $(RM) $(BIN) $(OBJ) $(LINKOBJ) + $(RM) *.*~ + $(RM) *~ diff --git a/course/semester2/pprog/assignment0/graphics.c b/course/semester2/pprog/assignment0/graphics.c new file mode 100644 index 00000000..747e3991 --- /dev/null +++ b/course/semester2/pprog/assignment0/graphics.c @@ -0,0 +1,170 @@ +/** + * @file graphics.c + * @purpose Wrapper for SDL and OpenGL graphics libraries. Used for N-Body simulator. Implementations. Mostly copied from internet tutorials. + * @author Sam Moore + * @date August 2012 + */ + + + +#include "graphics.h" + +#include //For trig functions + +/** + * @function Graphics_Init + * @purpose Initialise the SDL/OpenGL graphics system + * @param caption - The caption to give the view window + * @param w - The width of the view window + * @param h - The height of the view window + */ +void Graphics_Init(const char * caption, int w, int h) +{ + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + fprintf(stderr, "Graphics_Init - Couldn't initialise SDL! SDL_GetError() = %s\n",SDL_GetError()); + exit(EXIT_FAILURE); + } + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_Surface * screen = SDL_SetVideoMode(w,h, 32, SDL_OPENGL); + if ( screen == NULL ) + { + fprintf(stderr, "Graphics_Init - Couldn't set SDL VideoMode (%d x %d x 32). SDL_GetError() = %s\n", w, h, SDL_GetError()); + exit(EXIT_FAILURE); + } + + glEnable(GL_TEXTURE_2D); + glClearColor(0,0,0,0); + glViewport(0,0,w,h); //DOES matter + glClear(GL_COLOR_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0,w,h,0,-1,1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_DEPTH_TEST); + SDL_WM_SetCaption(caption, NULL); + + atexit(Graphics_Destroy); +} + +/** + * @function Graphics_Destroy + * @purpose Destroy the Graphics system + * Note: Just wrap to SDL_Quit for now + */ +void Graphics_Destroy() +{ + SDL_Quit(); +} + +/** + * @function Graphics_DrawPixel + * @purpose Draw a pixel + * @param x[...] Position of pixel + * @param r - Red component (0-1) + * @param g - Green component (0-1) + * @param b - Blue component (0-1) + */ +void Graphics_Pixel(int x[DIMENSIONS], float r, float g, float b) +{ + glBegin(GL_POINTS); + glColor3f(r, g, b); + if (DIMENSIONS == 2) + glVertex2f(x[0], x[1]); + else if (DIMENSIONS == 3) + glVertex3f(x[0], x[1], x[2]); + else + { + fprintf(stderr, "Graphics_DrawPixel - DIMENSIONS = %d, expected 2 or 3\n", DIMENSIONS); + exit(EXIT_FAILURE); + } + + glColor3f(1,1,1); + glEnd(); +} + +/** + * @function Graphics_DrawLine + * @purpose Draw a straight line between two points + * @param x1[...] - First coordinate + * @param x2[...] - Second coordinate + * @param r - Red component (0-1) + * @param g - Green component (0-1) + * @param b - Blue component (0-1) + */ +void Graphics_Line(int x1[DIMENSIONS], int x2[DIMENSIONS], float r, float g, float b) +{ + + glColor3f(r, g, b); + glBegin(GL_LINES); + if (DIMENSIONS == 2) + { + glVertex2f(x1[0], x1[1]); // origin of the line + glVertex2f(x2[0], x2[1]); // ending point of the line + } + else if (DIMENSIONS == 3) + { + glVertex3f(x1[0], x1[1], x1[2]); // origin of the line + glVertex3f(x2[0], x2[1], x2[2]); // ending point of the line + } + else + { + fprintf(stderr, "Graphics_DrawLine - DIMENSIONS = %d, expected 2 or 3\n", DIMENSIONS); + exit(EXIT_FAILURE); + } + glColor3f(1,1,1); + glEnd(); + + +} + +/** + * @function Graphics_Circle + * @purpose Draw a 2D Circle (filled) + * @param x[...] Position to draw at + * @param radius - Radius of circle + * @param r - Red component (0-1) + * @param g - Green component (0-1) + * @param b - Blue component (0-1) + */ + +void Graphics_Circle(int x[2], float radius, float r, float g, float b) +{ + glColor3f(r, g, b); + + glBegin(GL_TRIANGLE_FAN); + glVertex2f(x[0], x[1]); + for (float angle = 0; angle < 360; angle+=1) + { + glVertex2f(x[0] + sin(angle) * radius, x[1] + cos(angle) * radius); + } + glColor3f(1, 1, 1); + glEnd(); +} + +/** + * @function Graphics_Clear + * @purpose Clear the screen + * @param r - Red component of clear colour + * @param g - Green component + * @param b - Blue component + */ +void Graphics_Clear(float r, float g, float b) +{ + glClearColor(r,g,b,1); + glClear(GL_COLOR_BUFFER_BIT); +} + +/** + * @function Graphics_Update + * @purpose Update the screen + */ +void Graphics_Update() +{ + SDL_GL_SwapBuffers(); + //SDL_Flip(screen); +} + diff --git a/course/semester2/pprog/assignment0/graphics.h b/course/semester2/pprog/assignment0/graphics.h new file mode 100644 index 00000000..f977bd9a --- /dev/null +++ b/course/semester2/pprog/assignment0/graphics.h @@ -0,0 +1,35 @@ +/** + * @file graphics.h + * @purpose Wrapper to the SDL and OpenGL libraries, used for N-Body simulator. Declarations. + * @author Sam Moore + * @date August 2012 + */ + +#ifndef _GRAPHICS_H +#define _GRAPHICS_H + +#include +#include +#include + +#ifndef DIMENSIONS //Check so that DIMENSIONS can be defined elsewhere (ie in "nbody.h") + #define DIMENSIONS 2 +#endif //DIMENSIONS + + +void Graphics_Init(const char * caption, int w, int h); //Initialise graphics +void Graphics_Destroy(); //Destroy graphics +void Graphics_Update(); //Update view +void Graphics_Clear(float r, float g, float b); //Clear screen +void Graphics_Pixel(int x[DIMENSIONS], float r, float g, float b); //Draw single pixel +void Graphics_Line(int x1[DIMENSIONS], int x2[DIMENSIONS], float r, float g, float b); //Draw straight line +void Graphics_Circle(int x[2], float radius, float r, float g, float b); //Draw circle + + + +void Graphics_DrawPixel(int x[DIMENSIONS], float r, float g, float b); + + +#endif //_GRAPHICS_H + +//EOF diff --git a/course/semester2/pprog/assignment0/main.c b/course/semester2/pprog/assignment0/main.c new file mode 100644 index 00000000..c3357906 --- /dev/null +++ b/course/semester2/pprog/assignment0/main.c @@ -0,0 +1,42 @@ +/** + * @file main.c + * @purpose Main program for N-Body simulator (single threaded) + * @author Sam Moore + * @date August 2012 + */ + +#include +#include +#include +#include + +#include "nbody.h" + +int main(int argc, char ** argv) +{ + + System system; + System_Init(&system, (float[3]){320,240,0}, 0.1, 10, 1); + #ifdef _GRAPHICS_H + Graphics_Init("N-Body", 640, 480); + #endif //_GRAPHICS_H + + assert(System_AddBody(&system, 1, (float[2]){0.0f,0.0f}, (float[2]){0.0f,0.0f})->exists); + assert(System_AddBody(&system, 0.01, (float[2]){120.0f, -120.0f}, (float[2]){-1.1f, 1.0f})->exists); + while (true) + { + + System_Step(&system); + //System_WriteData(&system, stdout); + #ifdef _GRAPHICS_H + Graphics_Clear(1, 1, 1); //Clear screen + System_Draw(&system); //Draw system + Graphics_Update(); //Update screen + Process_Events(); //Process SDL events + #endif //_GRAPHICS_H + + } + System_Destroy(&system); + return 0; +} + diff --git a/course/semester2/pprog/assignment0/nbody.c b/course/semester2/pprog/assignment0/nbody.c new file mode 100644 index 00000000..6f3ce508 --- /dev/null +++ b/course/semester2/pprog/assignment0/nbody.c @@ -0,0 +1,343 @@ +/** + * @file nbody.c + * @purpose Implementations for N-Body simulator + * @author Sam Moore + * @date August 2012 + */ + +#include // To make sure I don't do anything stupid. +#include //For maths and stuff +#include //For writing data to files +#include "nbody.h" //Declarations of functions and structures in this file + +// --- Body functions --- // + +/** + * @function Body_Init + * @purpose Initialise a Body object with mass, position and velocity + * @param body - Target Body + * @param m - The mass of the Body + * @param x[...] - The position vector of the body + * @param v[...] - The velocity vector of the body + */ +void Body_Init(Body * body, float m, float x[DIMENSIONS], float v[DIMENSIONS]) +{ + assert(body != NULL); + body->m = m; + for (unsigned i = 0; i < DIMENSIONS; ++i) + { + body->x[i] = x[i]; + body->v[i] = v[i]; + body->F[i] = 0.00; + } + body->exists = true; +} + +/** + * @function Body_Destroy + * @purpose Destroy a Body + * @param body - Target Body + */ +void Body_Destroy(Body * body) +{ + assert(body != NULL); + body->exists = false; +} + +/** + * @function Body_Step + * @purpose Perform a single step, updating target Body + * @param body - Target Body + * @param system - System that the Body is part of (used for universal constants, etc) + */ +void Body_Step(Body * body, System * system) +{ + assert(body != NULL && system != NULL && body->exists); + + //fprintf(stderr, "DEBUG - Body %p\t%d\n", (void*)(body), body->exists); + for (unsigned i = 0; i < DIMENSIONS; ++i) + { + body->x[i] += body->v[i] * system->dt; //Update the position vector + body->v[i] += (body->F[i] / body->m) * system->dt; //Update the velocity vector + body->F[i] = 0.00; //Reset the net force vector + } + + //Do collision checking + +} + +/** + * @function Body_Force + * @purpose Update the net force on Body A due to Body B + * @param A - Body to update; subject of force from B + * @param B - Body causing force on A; NOT CHANGED BY THIS FUNCTION + * @param system - System which Body A is a part of (used for universal constants, etc) + */ +void Body_Force(Body * A, Body * B, System * system) +{ + + assert(A != NULL && B != NULL && system != NULL && A->exists && B->exists); + if (A == B) + return; + + float r2 = 0.00; + for (unsigned i = 0; i < DIMENSIONS; ++i) + r2 += powf((B->x[i] - A->x[i]), 2); + + float k = system->G * (A->m * B->m) / powf(r2, 1.50); + for (unsigned i = 0; i < DIMENSIONS; ++i) + A->F[i] += k * (B->x[i] - A->x[i]); + +} + +/** + * @function Body_Radius + * @purpose Calculate the radius of a body + * @param body - Target Body + * @returns The radius of body + */ +float Body_Radius(Body * body) +{ + assert(body != NULL && body->exists); + float radius = 5.0; + return radius; +} + +/** + * @function Body_WriteData + * @purpose Write data about the Body to a file + * @param body - The target Body + * @param system - System to which the Body belongs + * @param file - File to write data to + */ +void Body_WriteData(Body * body, System * system, FILE * file) +{ + assert(body != NULL && system != NULL && file != NULL && body->exists); + fprintf(file,"%d\t%p\t%f", system->step, (void*)(body), body->m); + for (unsigned i = 0; i < DIMENSIONS; ++i) + fprintf(file,"\t%f", body->x[i]); + for (unsigned i = 0; i < DIMENSIONS; ++i) + fprintf(file,"\t%f", body->v[i]); + for (unsigned i = 0; i < DIMENSIONS; ++i) + fprintf(file,"\t%f", body->F[i]); + + fprintf(file,"\n"); + +} + +// --- System functions --- // + +/** + * @function System_Init + * @purpose Initialise a System object + * @param system - Target System + * @param x - The origin of the System (currently used for offset of graphics) + * @param dt - Time step + * @param G - Universal Gravitational Constant + * @param nMax - Number of Body objects this System will contain (DEFAULT = 10) + */ +void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax) +{ + assert(system != NULL); + for (unsigned i = 0; i < DIMENSIONS; ++i) + system->x[i] = x[i]; + + + system->dt = dt; + system->G = G; + system->nMax = nMax; + system->n = 0; + + system->bodies = (Body*)(calloc(sizeof(Body), nMax)); //Allocate space for nMax bodies + for (unsigned a = 0; a < nMax; ++a) + (system->bodies+a)->exists = false; +} + +/** + * @function System_Destroy + * @purpose Destroy all Bodies in a system + * @param system - Target system + */ + +void System_Destroy(System * system) +{ + assert(system != NULL); + if (system->bodies != NULL) + free(system->bodies); + system->nMax = 0; +} + +/** + * @function System_Step + * @purpose Compute single step for all Bodies in System + * @param system - Target system + */ +void System_Step(System * system) +{ + assert(system != NULL); + + // Update forces + for (unsigned a = 0; a < system->nMax; ++a) + { + if (system->bodies[a].exists) + { + for (unsigned b = 0; b < system->nMax; ++b) + { + //fprintf(stderr, "DEBUG1 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists); + if (system->bodies[b].exists) + { + //fprintf(stderr, "DEBUG2 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists); + Body_Force(&(system->bodies[a]), &(system->bodies[b]), system); //Update force on bodies[a] due to bodies[b] + //fprintf(stderr, "DEBUG3 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists); + } + } + } + } + + // Perform steps + for (unsigned a = 0; a < system->nMax; ++a) + { + if ((system->bodies+a)->exists) + Body_Step(system->bodies+a, system); + } +} + +/** + * @function System_AddBody + * @purpose Add a Body to a System. Resizes the System's bodies array if necessary. + * @param system - Target System + * @param m - Mass of the new Body + * @param x[...] - position vector for the new Body + * @param v[...] - velocity vector for the new Body + * @returns Pointer to new Body + */ + +Body * System_AddBody(System * system, float m, float x[DIMENSIONS], float v[DIMENSIONS]) +{ + assert(system != NULL); + + unsigned a = 0; + for (a = 0; a < system->nMax; ++a) + { + if (!(system->bodies+a)->exists) + break; + } + + if (a >= system->nMax) + { + system->nMax = (system->nMax+1) * 2; + system->bodies = (Body*)(realloc(system->bodies, sizeof(Body) * system->nMax)); + for (unsigned b = a; b < system->nMax; ++b) + (system->bodies+b)->exists = false; + } + + Body_Init(system->bodies+a, m, x, v); + system->n += 1; + + return (system->bodies+a); + +} + +/** + * @function System_WriteData + * @purpose Write all information about System to a file + * @param system - Target System + * @param file - Target FILE (must be opened for writing) + */ +void System_WriteData(System * system, FILE * file) +{ + assert(system != NULL && file != NULL); + for (unsigned a = 0; a < system->nMax; ++a) + { + if ((system->bodies+a)->exists) + Body_WriteData(system->bodies+a, system, file); + } + fprintf(file, "\n"); + +} + +// --- Graphical functions --- // + +#ifdef _GRAPHICS_H + +/** + * @function Body_Draw + * @purpose Draw an individual Body + * @param body - Target Body + * @param system - System to which the Body belongs + */ + +void Body_Draw(Body * body, System * system) +{ + assert(body != NULL && system != NULL && body->exists); + int pixel_pos[DIMENSIONS]; + for (unsigned i = 0; i < DIMENSIONS; ++i) + pixel_pos[i] = (int)(system->x[i] - body->x[i]); + + float rgb[3] = {0.0f, 0.0f, 0.0f}; + if (body->m >= 100.0) + { + rgb[0] = 0.0f; rgb[1] = 0.0f; rgb[2] = 1.0f; + } + if (body->m >= 10.0) + { + rgb[0] = 0.5f; rgb[1] = 0.5f; rgb[2] = 1.0f; + } + else if (body->m >= 1.0) + { + rgb[0] = 0.8f; rgb[1] = 0.2f; rgb[2] = 0.1f; + } + else if (body->m >= 0.1) + { + rgb[0] = 0.0f; rgb[1] = 0.5f; rgb[2] = 0.0f; + } + else if (body->m >= 0.01) + { + rgb[0] = 0.5f; rgb[1] = 0.5f; rgb[2] = 0.5f; + } + + + Graphics_Circle(pixel_pos,Body_Radius(body), rgb[0], rgb[1], rgb[2]); + + //fprintf(stdout, "DEBUG - Body_Draw - Called\n"); +} + +/** + * @function System_Draw + * @purpose Draw a System of Bodies + * @param system - Target System to draw + */ +void System_Draw(System * system) +{ + assert(system != NULL); + for (unsigned a = 0; a < system->nMax; ++a) + { + if ((system->bodies+a)->exists) + Body_Draw(system->bodies+a, system); + } +} + +/** + * @function Process_Events + * @purpose Handle any SDL events recieved. + */ +void Process_Events() +{ + SDL_Event event; + while (SDL_PollEvent(&event)) + { + switch(event.type) + { + case SDL_QUIT: + exit(EXIT_SUCCESS); + break; + } + } + //SDL_Delay(1); +} + +#endif //_GRAPHICS_H + +//EOF + + diff --git a/course/semester2/pprog/assignment0/nbody.h b/course/semester2/pprog/assignment0/nbody.h new file mode 100644 index 00000000..775699f0 --- /dev/null +++ b/course/semester2/pprog/assignment0/nbody.h @@ -0,0 +1,85 @@ +/** + * @file nbody.h + * @purpose Declarations for N-Body simulator + * @author Sam Moore + * @date August 2012 + */ + +#ifndef _NBODY_H +#define _NBODY_H + +#include +#include + +#include "graphics.h" //TODO: Comment out this line to build the program without any graphics at all + +#define DIMENSIONS 2 //Number of dimensions to use in the simulation (2 or 3) + +/** + * Structure to represent a single Body + */ + +typedef struct +{ + float m; //Mass + float x[DIMENSIONS]; //Position vector + float v[DIMENSIONS]; //Velocity vector + float F[DIMENSIONS]; //Net force due to all other bodies in the System + + bool exists; //Used by memory management +} Body; + +/** + * Structure to represent a system of N Bodies + */ +typedef struct +{ + Body * bodies; //Array of Bodies + unsigned nMax; //Size of array; maximum number of Bodies before Array needs to be resized + unsigned n; //Number of bodies currently in the system + float G; //Universal Gravitational Constant; used to calculate forces between Bodies + + float dt; //Time interval + unsigned step; //Number of steps executed by the System + + float x[DIMENSIONS]; //The origin of the system + +} System; + +/** + * Functions for operating with Body objects + */ +extern void Body_Init(Body * body, float m, float x[DIMENSIONS], float v[DIMENSIONS]); //Initialise Body +extern void Body_Destroy(Body * body); //Destroy Body +extern void Body_Step(Body * body, System * system); //Step Body +extern void Body_Force(Body * A, Body * B, System * system); //Calculate Force between Bodies + + +/** + * Functions for operating with System object + */ +extern void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax); //Initialise System +extern void System_Destroy(System * system); //Destroy System +extern void System_Step(System * system); //Step all Bodies in System +extern Body * System_AddBody(System * system, float m, float x[DIMENSIONS], float v[DIMENSIONS]); //Add Body to System +extern void System_RemoveBody(System * system, Body * body); // +extern void System_MergeBodies(System * system, Body * A, Body * B); +extern void System_WriteData(System * system, FILE * file); //Write System info to a file + + +/** + * Functions to be used when "graphics.h" is included + */ + +#ifdef _GRAPHICS_H + extern void System_Draw(System * system); //Draw a System of Bodies + extern void Body_Draw(Body * body, System * system); //Draw an individual Body + + extern void Process_Events(); //Handle any events from the SDL system +#endif //_GRAPHICS_H + + + +#endif //_NBODY_H + +//EOF -- 2.20.1