3 * @author Sam Moore (20503628) - 2012
4 * @purpose Contains main function, argument handling
5 * NOTE: This file is identical for both the single-threaded and multi-threaded versions of the program
12 #include <string.h> // For parsing arguments
17 // --- Variable definitions --- //
18 System universe; // global variable declared in "nbody.h" - The universe of bodies
19 Options options; // global variable declared in "nbody.h" - Options passed to program through arguments
22 // --- Function forward declarations --- //
23 void HandleArguments(int argc, char ** argv); //Interprets program arguments and sets up the "options" variable
24 unsigned IntegerArgument(unsigned * i, int argc, char ** argv, int * store, int * store2); //Helper function to get integer switch
25 void FloatArgument(unsigned * i, int argc, char ** argv, float * store); //Helper function to get switch value for float
26 void DisplayStatistics(); //Called on exit of program, displays information about computation time, steps computed, etc
27 void Interrupt(int dummy); // Interrupt handler function, called when SIGINT (Ctrl-C) is sent to program
30 // --- Function implementations --- //
34 * @purpose The main function. Calls HandleArguments to set up options,
35 * sets up functions to call at exit, starts simulation and graphics loops
36 * @param argc - Number of arguments
37 * @param argv - The argument strings
39 int main(int argc, char** argv)
41 //Set default options values here
42 options.program = argv[0];
44 options.output = NULL;
45 options.num_threads = 0;
46 options.nested_threads = 0;
47 options.num_steps = -1; // Negative values => simulation runs forever unless otherwise specified
49 options.draw_graphics = true;
50 options.pedantic_graphics = true;
51 options.print_positions = false;
52 options.verbosity = 0;
56 //If there are no arguments, print information about usage
59 printf("Usage: %s [OPTIONS] field\n", argv[0]);
60 printf("Controls:\n X - exit\n I, J, K, M - rotate\n W, Z, A, S - move to view"
61 " point\n ./, - zoom in/out\n +/- - scaled zoom in/out\n");
66 HandleArguments(argc, argv);
68 //Check there is an initial field.
69 if (options.input == NULL && options.random <= 0)
71 fprintf(stderr, "Usage: %s [OPTIONS] field\n", argv[0]);
72 fprintf(stderr, " (You did not provide a file for the initial field of bodies)\n");
78 signal(SIGINT, Interrupt); //Handle SIGINT signals
79 atexit(Universe_Cleanup); //On exit, cleanup universe (and write positions of bodies to file if supplied).
80 atexit(DisplayStatistics); //On exit, print information about the computations done
81 if (options.input != NULL)
82 System_Init(&universe,options.input); //Initialise the universe from the initial field
84 System_Random(&universe, options.random); //Randomly create bodies
87 //Setup the time of day at which the simulation starts
88 if (gettimeofday(&(options.start_time), NULL) != 0)
90 perror("Couldn't get time of day");
94 options.start_clock = clock(); //Get CPU cycles executed before simulation starts
95 Simulation_Run(argc, argv); // Start the simulation
97 //printf("Main thread done!\n");
100 exit(EXIT_SUCCESS); //Should never get to this line
105 * @function HandleArguments
106 * @purpose Fill the "options" variable by parsing command line arguments
107 * @param argc - Number of arguments
108 * @param argv - Argument strings
110 void HandleArguments(int argc, char ** argv)
112 for (unsigned i = 1; i < argc; ++i) //For all arguments
114 if (argv[i][0] != '-') //If the argument is not a switch value...
116 //Interpret first non switch as input file, and second as output file.
117 //If there are too many non switch arguments, give an error.
118 if (options.input == NULL)
119 options.input = argv[i];
120 else if (options.output == NULL)
121 options.output = argv[i];
124 fprintf(stderr,"Usage: %s [OPTIONS] field [output]\n", argv[0]);
125 fprintf(stderr," (You provided too many file names)\n");
130 switch (argv[i][1]) //The argument is a switch if we get here
132 case 'n': //Number of threads switch
133 IntegerArgument(&i, argc, argv, &(options.num_threads), &(options.nested_threads));
134 #ifdef SINGLE_THREADED
135 fprintf(stderr, "Warning: -%c switch has no effect in the single-threaded program.\n", 'n');
138 if (options.num_threads <= 0)
140 fprintf(stderr, "Require at least one thread (-%c %s is invalid).\n",'n', argv[i]);
143 #endif //SINGLE_THREADED
145 case 's': //Number of steps switch
146 IntegerArgument(&i, argc, argv, &(options.num_steps), NULL);
147 if (options.num_steps < 0)
149 fprintf(stderr, "Require zero or more steps to run (-%c %s is invalid).\n", 's', argv[i]);
153 case 't': //Timeout switch (in seconds)
154 IntegerArgument(&i, argc, argv, &(options.timeout), NULL);
155 if (options.timeout < 0)
157 fprintf(stderr, "Require a timeout greater or equal to zero (-%c %s is invalid).", 't', argv[i]);
161 case 'r': //Random initial field
162 IntegerArgument(&i, argc, argv, &(options.random), NULL);
163 if (options.random < 0)
165 fprintf(stderr, "Require a positive integer number of bodies (-%c %s is invalid).", 'r', argv[i]);
169 case 'g': //Graphics switch
170 options.draw_graphics = !options.draw_graphics;
172 case 'v': //Verbosity switch
173 IntegerArgument(&i, argc, argv, &(options.verbosity), NULL);
177 if (strcmp(argv[i]+2, "pedantic-graphics") == 0)
179 options.pedantic_graphics = true;
180 #ifdef SINGLE_THREADED
181 fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
182 #endif //SINGLE_THREADED
184 else if (strcmp(argv[i]+2, "fast-graphics") == 0)
186 options.pedantic_graphics = false;
187 #ifdef SINGLE_THREADED
188 fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
189 #endif //SINGLE_THREADED
192 else if (strcmp(argv[i]+2, "theta") == 0)
194 FloatArgument(&i, argc, argv, &(options.theta));
196 fprintf(stderr, "Warning: %s switch only works in Barnes Hut version.\n", argv[i-1]);
198 if (options.theta < 0)
200 fprintf(stderr, "Require a theta value greater or equal to zero (%s %s is invalid).\n", argv[i-1], argv[i]);
209 fprintf(stderr, "Unrecognised switch %s\n", argv[i]);
216 fprintf(stderr, "Unrecognised switch -%c\n", argv[i][1]);
225 * @function IntegerArgument
226 * @purpose Helper function to get up to two integers following a argument switch, seperated by ':'
227 * @param i - position in the argument array, will be updated after this function
228 * @param argc - number of arguments
229 * @param argv - argument strings
230 * @param store - pointer to unsigned to store result in
231 * @param store2 - pointer to second integer (set to NULL if there is only one integer)
232 * @returns 1 if store was filled, 2 if both store1 and store2 were filled
234 unsigned IntegerArgument(unsigned * i, int argc, char ** argv, int * store, int * store2)
238 fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
242 char * seperator = strstr(argv[*i+1], ":");
243 if (seperator != NULL)
247 fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
250 int val = atoi(seperator+1);
253 fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
256 *store2 = (unsigned)val;
261 int val = atoi(argv[*i+1]);
262 if (val <= 0 && strcmp("0", argv[*i+1]) != 0)
264 fprintf(stderr,"Supply a positive integer for the -%c switch. %s is invalid.\n", argv[*i][1], argv[*i+1]);
270 return (seperator == NULL) ? 1 : 2;
273 * @function FloatArgument
274 * @purpose Helper function to get a float following a argument switch
275 * @param i - position in the argument array, will be updated after this function
276 * @param argc - number of arguments
277 * @param argv - argument strings
278 * @param store - pointer to float to store result in
280 void FloatArgument(unsigned * i, int argc, char ** argv, float * store)
284 fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]);
287 *store = atof(argv[*i+1]);
288 if (*store == 0.0 && argv[*i+1][0] != '0')
290 fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]);
299 * @function Interrupt
300 * @purpose Handle SIGINT signal; quit the program gracefully, so that statistics are still displayed
301 * @param dummy - a dummy
304 void Interrupt(int dummy)