--- /dev/null
+/**
+ * @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
+
+
+#ifdef OVER_ENGINEERED
+System * sub_system = NULL;
+#endif //OVER_ENGINEERED
+
+/**
+ * @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)
+{
+
+ if (options.num_threads == 0)
+ options.num_threads = omp_get_max_threads();
+
+ if (options.draw_graphics)
+ {
+ Graphics_Run(argc, argv);
+ if (options.pedantic_graphics == false)
+ {
+ options.num_threads += 1;
+ omp_set_nested(1);
+ if (omp_get_nested() == 0)
+ {
+ fprintf(stderr, "Couldn't enable nested parallelism\n.");
+ exit(EXIT_FAILURE);
+ }
+
+
+ #pragma omp parallel sections num_threads(2)
+ {
+ #pragma omp section
+ {
+ Compute();
+ }
+ #pragma omp section
+ {
+ glutMainLoop();
+ }
+ }
+ return;
+ }
+ }
+ #ifdef OVER_ENGINEERED
+ Compute();
+ #else
+ Compute2();
+ #endif //OVER_ENGINEERED
+
+
+
+}
+
+
+void Compute(void)
+{
+ omp_set_num_threads(options.num_threads);
+ if (omp_get_max_threads() != options.num_threads)
+ {
+ fprintf(stderr, "Couldn't use %d threads!\n", options.num_threads);
+ exit(EXIT_FAILURE);
+ }
+
+ #ifdef OVER_ENGINEERED
+ sub_system = Split_System(&universe, options.num_threads); // I could use omp for loops instead, but I like this way
+ #endif //OVER_ENGINEERED
+
+ #pragma omp parallel
+ {
+ #ifdef OVER_ENGINEERED
+ int index = omp_get_thread_num();
+ #endif //OVER_ENGINEERED
+ while (!ExitCondition())
+ {
+
+ #ifdef OVER_ENGINEERED
+ System_Forces(sub_system+index, &universe);
+ #pragma omp barrier // Look! An explicit barrier!
+ System_Positions(sub_system+index);
+ #pragma omp barrier
+ #else
+ #pragma omp for
+ for (unsigned a = 0; a < universe.N; ++a)
+ {
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ (universe.body+a)->F[i] = 0;
+ //printf("Thread %d computes force for body %d\n", omp_get_thread_num(), a);
+ omp_set_num_threads(options.nested_threads);
+ #pragma omp parallel for
+ for (unsigned b = 0; b < universe.N; ++b)
+ {
+ if (b != a)
+ Body_Force(universe.body+a, universe.body+b);
+ }
+ }
+
+ #pragma omp for
+ for (unsigned a = 0; a < universe.N; ++a)
+ {
+ //printf("Thread %d computes position for body %d\n", omp_get_thread_num(), a);
+ Body_Velocity(universe.body+a);
+ Body_Position(universe.body+a);
+ }
+
+ #endif //OVER_ENGINEERED
+
+ #pragma omp master
+ {
+ // The if statement has a cost, but if can be removed easily in an optimised version.
+ // Only the main thread is allowed to mess with glut, because glut is evil (not thread safe).
+ // Although this function may be nested, that will only happen if the if would be false.
+ // ("if the if would be false"; I am awesome at explaining code)
+ if (options.draw_graphics && options.pedantic_graphics)
+ {
+ glutMainLoopEvent();
+ Graphics_Display();
+ }
+ }
+ #pragma omp single
+ {
+ // Only one thread should execute this, and we don't care which one.
+ // So much easier than the pthread version!
+ universe.steps += 1;
+ if (options.verbosity != 0 && universe.steps % options.verbosity == 0)
+ DisplayStatistics();
+ }
+
+ }
+ }
+}
+