3 * @author Sam Moore (20503628) 2012
4 * @purpose N-Body simulator - Definition of simulation functions; single threaded version
18 //Stuff to do with worker threads
19 // The worker threads (if used) are spawned by the computation thread, not the main thread
20 // The main thread (which handles initialisation, graphics, user input, cleanup and exit) does not need to know about these.
23 pthread_t worker_thread[NUM_THREADS]; //Worker threads responsible for Force and Position updates
24 System sub_system[NUM_THREADS]; //Array of System's used to divide up the main "universe" System for worker threads
25 pthread_mutex_t mutex_workers;
26 pthread_cond_t workers_done_cv;
27 unsigned worker_count;
31 * Prints the body on screen
33 void Body_Print(Body * a)
35 printf("Body %p M=%f X=%f Y=%f Z=%f Fx=%f Fy=%f Fz=%f Vx=%f Vy=%f Vz=%f\n",
36 (void*)a, a->mass, a->x[0], a->x[1], a->x[2], a->F[0], a->F[1], a->F[2], a->v[0], a->v[1], a->v[2]);
42 void Body_Force(Body * a, System * s)
48 for (unsigned i = 0; i < DIMENSIONS; ++i)
51 for (unsigned index = 0; index < s->N; ++index)
53 Body * b = s->body+index;
58 for (unsigned i = 0; i < DIMENSIONS; ++i)
59 distance += square(b->x[i] - a->x[i]);
60 distance = sqrt(distance);
61 con = G * a->mass * b->mass / square(distance);
63 for (unsigned i = 0; i < DIMENSIONS; ++i)
64 a->F[i] += gd * (b->x[i] - a->x[i]);
71 void Body_Velocity(Body * a)
73 for (unsigned i = 0; i < DIMENSIONS; ++i)
74 a->v[i] += a->F[i] / a->mass * DELTA_T;
80 void Body_Position(Body * a)
82 for (unsigned i = 0; i < DIMENSIONS; ++i)
83 a->x[i] += a->v[i] * DELTA_T;
87 * Compute forces on each object in System s1 due to all bodies in System s2
89 void System_Forces(System * s1, System * s2)
91 //printf("Compute forces for %p - %d bodies...\n", (void*)s1, s1->N);
92 for (unsigned i = 0; i < s1->N; ++i)
94 Body_Force(s1->body+i, s2);
95 Body_Velocity(s1->body+i);
97 //printf("Compute positions for %p - Done!\n", (void*)s1);
101 * Compute positions of all objects in System
103 void System_Positions(System * s)
105 //printf("Compute positions for %p - %d bodies...\n", (void*)s, s->N);
106 for (unsigned i = 0; i < s->N; ++i)
107 Body_Position(s->body+i);
108 //printf("Compute positions for %p - Done!\n", (void*)s);
115 * This function reads an input file. You can change it if you choose a
116 * different file format
118 #define LINE_SIZE BUFSIZ
119 void System_Init(System * s, char *fileName)
121 char line[LINE_SIZE];
125 file = fopen(fileName, "rt");
126 s->N = atoi(fgets(line, LINE_SIZE, file));
127 s->body = (Body*) calloc((size_t)s->N, sizeof(Body));
129 //printf("----------------------Initial field-------------------------------\n");
131 for (unsigned i = 0; i < s->N; ++i)
133 if (fgets(line, LINE_SIZE, file) != NULL)
135 Body * a = s->body+i;
136 token = strtok(line, ",; ");
137 a->mass = atof(token);
139 for (unsigned j = 0; j < DIMENSIONS; ++j)
141 token = strtok(NULL, ",; ");
142 a->x[j] = atof(token);
144 for (unsigned j = 0; j < DIMENSIONS; ++j)
146 token = strtok(NULL, ",; ");
147 a->v[j] = atof(token);
153 //printf("--------------------------------------------------------------\n");
159 * Cleans up the universe by freeing all memory
161 void Universe_Cleanup()
168 * Thread - Continuously computes steps for a system of bodies
170 void * Compute_Thread(void * arg)
173 System * s = (System*)(arg); //cast argument to a System*
174 // First set up the "sub_system" array
176 unsigned bodies_per_system = (s->N) / NUM_THREADS;
177 unsigned remainder = (s->N) % NUM_THREADS;
178 for (unsigned i = 0; i < NUM_THREADS; ++i)
180 sub_system[i].body = (s->body)+(i*bodies_per_system);
181 sub_system[i].N = bodies_per_system;
182 if (i == NUM_THREADS - 1)
183 sub_system[i].N += remainder;
186 pthread_attr_t attr; //thread attribute for the workers
187 pthread_attr_init(&attr);
188 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
194 if (runstate != RUN) pthread_exit(NULL); //Check whether the main thread wants to exit
199 //No worker threads; do everything in this thread
207 worker_count = NUM_THREADS; //All threads working
210 for (unsigned i = 0; i < NUM_THREADS; ++i)
212 if (pthread_create(worker_thread+i, &attr, Force_Thread, (void*)(sub_system+i)) != 0)
214 perror("In compute thread, couldn't create worker thread (force)");
222 //Wait for forces to be computed
223 pthread_mutex_lock(&mutex_workers);
224 while (worker_count > 0)
225 pthread_cond_wait(&workers_done_cv, &mutex_workers);
226 pthread_mutex_unlock(&mutex_workers);
228 worker_count = NUM_THREADS; //All threads working
231 for (unsigned i = 0; i < NUM_THREADS; ++i)
233 if (pthread_create(worker_thread+i, &attr, Position_Thread, (void*)(sub_system+i)) != 0)
235 perror("In compute thread, couldn't create worker thread (position)");
241 //Wait for positions to be computed
242 pthread_mutex_lock(&mutex_workers);
243 while (worker_count > 0)
244 pthread_cond_wait(&workers_done_cv, &mutex_workers);
245 pthread_mutex_unlock(&mutex_workers);
253 void * Force_Thread(void * s)
256 System_Forces((System*)s, &universe);
257 pthread_mutex_lock(&mutex_workers);
259 if (worker_count == 0)
261 pthread_cond_signal(&workers_done_cv);
263 pthread_mutex_unlock(&mutex_workers);
267 void * Position_Thread(void * s)
270 System_Positions((System*)s);
271 pthread_mutex_lock(&mutex_workers);
273 if (worker_count == 0)
275 pthread_cond_signal(&workers_done_cv);
277 pthread_mutex_unlock(&mutex_workers);
282 * Child threads can call this to signal the main thread to quit the program
283 * The main thread also uses this to tell child threads that the program is quitting
284 * Note that the function doesn't call exit(), that is done by the main thread
286 void QuitProgram(bool error)
289 pthread_mutex_lock(&mutex_runstate);
291 runstate = QUIT_ERROR;
294 pthread_mutex_unlock(&mutex_runstate);