Implement pp6calculator Day 2 Homework Part 1

Refactor top level menu loop into a main menu from which user selects
a submenu to open. Implement submenus as functions, each of which
contains its own menu loop. Refactor top level menu operations into
these functions, separating operations by which day of the PP6 course
they were implemented in.

When quitting a submenu, exit back into main menu loop.
Implement pp6calculator Day 2 Homework Part 2

Add the following support functions in PP6Math.hpp

- getRandom  : return a pseudo-random number between 0 and 1
- sumVectors : sum components of a vector supplied as three double
  arrays, returning the summed components
- getMeanAndStdDev : calculate the mean and standard deviation of an
  array of doubles
- swap : swap function for ints rather than doubles
- associative_sort : bubble sort of a an array of doubles, but returning
  an array of the indices of the sorted elements. The supplied array is
  not sorted.

Add operation to PP6Day2Menu to read in an integer N from the user
between 1 and 1000. Randomly generate N 4-vectors, first generating
random momentum components and a mass, from which the energy is derived.
Calculate and report the total momentum, mean and standard deviation of
the energy and use associative_sort to find the highest energy vector
and the index location in the original array.

Take care with error checking so that if any step in the analysis fails,
the dynamic arrays created are deleted cleanly.
Import FileReader Library

Dump FileReader 1.0.0 package as a subproject. Add its directory to the
include path, and use add_subdirectory to recurse into the project and
build it using the supplied CMake script.
Refactor pp6calculator Day 2 Homework Part 2

Refactor vector analysis operation into dedicated function, calling
this function in place of the old functionality. Move operation code
into the dedicated function as is, adapting continue statements used
for menu control to returns for error codes. As with other error
codes, 0 indicates success, anything else failure.
Implement getString function for user input

Part 3/4 of Day2 homework requires a filename to be read in, i.e. a
string. To handle errors in input, though strings are fairly forgiving,
provide a getString function to read and return a string from cin.
Copy implementation of error handling from existing getDouble function.
Implement pp6calculator Day 2 Homework Part 3

Implement solution using a new function pp6day2_muonanalysis called as
an operation from the pp6day2_menu function.

Read in filename to be analysed from user, and use FileReader to check
file is valid and to count the number of mu+ and mu- particles observed
in "run4.dat". Create arrays of these sizes to hold the event number,
momentum components and energy of the muons and antimuons respectively.
Use a second FileReader instance to reiterate over the file and fill the
arrays with the relevant information. Hard code the value for the muon
mass to calculate mu-/mu+ energies from the extracted momenta.

Create arrays to hold invariant masses formed between each mu- with each
mu+, filling this and an indexing array using a bi-directional scheme
so that each entry in the index can go back to the indices of the
individual muon and antimuon indices.

Sort the invariant mass array using an associative sort to sort the
indexing array.

Read and present to stdout the 10 highest invariant masses and the event
number, energy and momenta of the mu+/mu- pair forming them.
Complete pp6calculator Homework Exercise for Day 2