+/**
+ * @file nbody.c
+ * @purpose OpenMP version of N-Body simulator, implementation
+ * @author Sam Moore (20503628) - 2012
+ */
+
+#include "nbody.h"
+#include "../single-thread/nbody.c" // Include original code
+#include "graphics.h" // For Graphics_Run function only
+
+/**
+ * @function Simulation_Run
+ * @purpose Start the simulation
+ * @param argc, argv - Passed to Graphics_Run if needed, otherwise unused
+ */
+void Simulation_Run(int argc, char ** argv)
+{
+ omp_set_nested(1);
+ if (omp_get_nested() != 1)
+ {
+ fprintf(stderr, "Couldn't set nested parallelism, I kind of need that\n");
+ exit(EXIT_FAILURE);
+ }
+
+
+ if (options.num_threads == 0)
+ options.num_threads = omp_get_max_threads();
+
+ if (options.draw_graphics)
+ omp_set_num_threads(2);
+ else
+ omp_set_num_threads(1);
+
+
+
+
+ #pragma omp parallel sections
+ {
+
+ #pragma omp section
+ {
+ omp_set_num_threads(options.num_threads);
+ while (true)
+ {
+
+ if (runstate != RUN) break; //Check whether the main thread wants to exit
+
+ if (ExitCondition())
+ {
+ break;
+ }
+
+
+ if (options.draw_graphics == false && options.verbosity != 0
+ && universe.steps % options.verbosity == 1)
+ {
+ DisplayStatistics();
+ }
+
+
+ Compute();
+ }
+ }
+
+ #pragma omp section
+ {
+ if (options.draw_graphics)
+ Graphics_Run(argc, argv);
+ printf("Got to bit after Graphics_Run()\n");
+ }
+
+ }
+}
+
+/**
+ * @function Compute
+ * @purpose Compute a single step, multithreaded using OpenMP
+ */
+void Compute(void)
+{
+ //printf("There are %d threads working and %d available\n", omp_get_num_threads(), omp_get_max_threads());
+ //return;
+ unsigned n_per_thread = (universe.N) / options.num_threads;
+ unsigned remainder = (universe.N) % options.num_threads;
+ #pragma omp parallel for
+ for (unsigned i = 0; i < options.num_threads; ++i)
+ {
+ //printf("Thread %d executes iteration %u\n", omp_get_thread_num(), i);
+ System s;
+ s.body = universe.body + (i * n_per_thread);
+ s.N = (i == options.num_threads - 1) ? n_per_thread : n_per_thread + remainder;
+ System_Forces(&s, &universe);
+ }
+
+ #pragma omp parallel for
+ for (unsigned i = 0; i < options.num_threads; ++i)
+ {
+ //printf("Thread %d executes iteration %u\n", omp_get_thread_num(), i);
+ System s;
+ s.body = universe.body + (i * n_per_thread);
+ s.N = (i == options.num_threads - 1) ? n_per_thread : n_per_thread + remainder;
+ System_Positions(&s);
+ }
+
+ universe.steps += 1;
+
+}