/// <summary>
        /// Overloaded constructor for model grid to construct the grid for specific locations
        /// </summary>
        /// <param name="minLat">Minimum grid latitude (degrees)</param>
        /// <param name="minLon">Minimum grid longitude (degrees, currently -180 to 180)</param>
        /// <param name="maxLat">Maximum grid latitude (degrees)</param>
        /// <param name="maxLon">Maximum grid longitude (degrees, currently -180 to 180)</param>
        /// <param name="latCellSize">Latitudinal size of grid cells</param>
        /// <param name="lonCellSize">Longitudinal size of grid cells</param>
        /// <param name="cellList">List of indices of active cells in the model grid</param>
        /// <param name="enviroStack">List of environmental data layers</param>
        /// <param name="cohortFunctionalGroups">The functional group definitions for cohorts in the model</param>
        /// <param name="stockFunctionalGroups">The functional group definitions for stocks in the model</param>
        /// <param name="globalDiagnostics">Global diagnostic variables</param>
        /// <param name="tracking">Whether process tracking is enabled</param>
        /// <param name="specificLocations">Whether the model is to be run for specific locations</param>
        /// <param name="runInParallel">Whether model grid cells will be run in parallel</param>
        public ModelGrid(float minLat, float minLon, float maxLat, float maxLon, float latCellSize, float lonCellSize, List<uint[]> cellList, 
            SortedList<string, EnviroData> enviroStack, FunctionalGroupDefinitions cohortFunctionalGroups,
            FunctionalGroupDefinitions stockFunctionalGroups, SortedList<string, double> globalDiagnostics, Boolean tracking, 
            Boolean specificLocations, Boolean runInParallel)
        {
            // Add one to the counter of the number of grids. If there is more than one model grid, exit the program with a debug crash.
            NumGrids = NumGrids + 1;
            //Debug.Assert(NumGrids < 2, "You have initialised more than one grid on which to apply models. At present, this is not supported");

            // Initialise the utility functions
            Utilities = new UtilityFunctions();

            // CURRENTLY DEFINING MODEL CELLS BY BOTTOM LEFT CORNER
            _MinLatitude = minLat;
            _MinLongitude = minLon;
            _MaxLatitude = maxLat;
            _MaxLongitude = maxLon;
            _LatCellSize = latCellSize;
            _LonCellSize = lonCellSize;
            _GridCellRarefaction = 1;

            // Check to see if the number of grid cells is an integer
            Debug.Assert((((_MaxLatitude - _MinLatitude) % _LatCellSize) == 0), "Error: number of grid cells is non-integer: check cell size");

            _NumLatCells = (UInt32)((_MaxLatitude - _MinLatitude) / _LatCellSize);
            _NumLonCells = (UInt32)((_MaxLongitude - _MinLongitude) / _LonCellSize);
            _Lats = new float[_NumLatCells];
            _Lons = new float[_NumLonCells];

            // Set up latitude and longitude vectors - lower left
            for (int ii = 0; ii < _NumLatCells; ii++)
            {
                _Lats[ii] = _MinLatitude + ii * _LatCellSize;
            }
            for (int jj = 0; jj < _NumLonCells; jj++)
            {
                _Lons[jj] = _MinLongitude + jj * _LonCellSize;
            }

            // Set up a grid of grid cells
            InternalGrid = new GridCell[_NumLatCells, _NumLonCells];

            // Instantiate the arrays of lists of cohorts to disperse
            DeltaFunctionalGroupDispersalArray = new List<uint>[_NumLatCells, _NumLonCells];
            DeltaCohortNumberDispersalArray = new List<uint>[_NumLatCells, _NumLonCells];

            // Instantiate the array of lists of grid cells to disperse those cohorts to
            DeltaCellToDisperseToArray = new List<uint[]>[_NumLatCells, _NumLonCells];

            // Instantiate the arrays of cell entry and exit directions
            DeltaCellExitDirection = new List<uint>[_NumLatCells, _NumLonCells];
            DeltaCellEntryDirection = new List<uint>[_NumLatCells, _NumLonCells];

            // An array of lists of cells to which organisms in each cell can disperse to; includes all cells which contribute to the
            // perimeter list, plus diagonal cells if they are in the same realm
            CellsForDispersal = new List<uint[]>[_NumLatCells, _NumLonCells];

            // An array of lists of directions corresponding to cells which organisms can disperse to
            CellsForDispersalDirection = new List<uint>[_NumLatCells, _NumLonCells];

            Console.WriteLine("Initialising grid cell environment:");

            int Count = 0;

            int NCells = cellList.Count;

            if (!runInParallel)
            {
                // Loop over cells to set up the model grid
                for (int ii = 0; ii < cellList.Count; ii++)
                {
                    // Create the grid cell at the specified position
                    InternalGrid[cellList[ii][0], cellList[ii][1]] = new GridCell(_Lats[cellList[ii][0]], cellList[ii][0],
                        _Lons[cellList[ii][1]], cellList[ii][1], latCellSize, lonCellSize, enviroStack, _GlobalMissingValue,
                        cohortFunctionalGroups, stockFunctionalGroups, globalDiagnostics, tracking, specificLocations);
                    if (!specificLocations)
                    {
                        CellsForDispersal[cellList[ii][0], cellList[ii][1]] = new List<uint[]>();
                        CellsForDispersalDirection[cellList[ii][0], cellList[ii][1]] = new List<uint>();
                        Count++;
                        Console.Write("\rInitialised {0} of {1}", Count, NCells);
                    }
                    else
                    {
                        Console.Write("\rRow {0} of {1}", ii + 1, NumLatCells / GridCellRarefaction);
                        Console.WriteLine("");
                        Console.WriteLine("");
                    }
                }
            }
            else
            {

                // Run a parallel loop over rows

                Parallel.For(0, NCells, ii =>
                {
                    // Create the grid cell at the specified position
                    InternalGrid[cellList[ii][0], cellList[ii][1]] = new GridCell(_Lats[cellList[ii][0]], cellList[ii][0],
                        _Lons[cellList[ii][1]], cellList[ii][1], latCellSize, lonCellSize, enviroStack, _GlobalMissingValue,
                        cohortFunctionalGroups, stockFunctionalGroups, globalDiagnostics, tracking, specificLocations);
                    if (!specificLocations)
                    {
                        CellsForDispersal[cellList[ii][0], cellList[ii][1]] = new List<uint[]>();
                        CellsForDispersalDirection[cellList[ii][0], cellList[ii][1]] = new List<uint>();
                    }

                    Count++;
                    Console.Write("\rInitialised {0} of {1}", Count, NCells);
                }
                 );

            }

            if (!specificLocations)
            {
                InterpolateMissingValues();

                // Fill in the array of dispersable perimeter lengths for each grid cell
                CalculatePerimeterLengthsAndCellsDispersableTo();

                CellHeightsKm = new double[_Lats.Length];
                CellWidthsKm = new double[_Lats.Length];

                // Calculate the lengths of widths of grid cells in each latitudinal strip
                // Assume that we are at the midpoint of each cell when calculating lengths
                for (int ii = 0; ii < _Lats.Length; ii++)
                {
                    CellHeightsKm[ii] = Utilities.CalculateLengthOfDegreeLatitude(_Lats[ii] + _LatCellSize / 2) * _LatCellSize;
                    CellWidthsKm[ii] = Utilities.CalculateLengthOfDegreeLongitude(_Lats[ii] + _LatCellSize / 2) * _LonCellSize;
                }
            }

            Console.WriteLine("\n");
        }
        /// <summary>
        /// Constructor for model grid: assigns grid properties and initialises the grid cells
        /// </summary>
        /// <param name="minLat">Minimum grid latitude (degrees)</param>
        /// <param name="minLon">Minimum grid longitude (degrees, currently -180 to 180)</param>
        /// <param name="maxLat">Maximum grid latitude (degrees)</param>
        /// <param name="maxLon">Maximum grid longitude (degrees, currently -180 to 180)</param>
        /// <param name="latCellSize">Latitudinal resolution of grid cell</param>
        /// <param name="lonCellSize">Longitudinal resolution of grid cell</param>
        /// <param name="cellRarefaction">The rarefaction to be applied to active grid cells in the model</param>
        /// <param name="enviroStack">Environmental data layers</param>
        /// <param name="cohortFunctionalGroups">The functional group definitions for cohorts in the model</param>
        /// <param name="stockFunctionalGroups">The functional group definitions for stocks in the model</param>
        /// <param name="globalDiagnostics">Global daignostic variables</param>
        /// <param name="tracking">Whether process-tracking is enabled</param>
        /// <param name="DrawRandomly">Whether the model is set to use a random draw</param>
        /// <param name="specificLocations">Whether the model is to be run for specific locations</param>
        public ModelGrid(float minLat, float minLon,float maxLat,float maxLon,float latCellSize,float lonCellSize, 
            SortedList<string,EnviroData> enviroStack, FunctionalGroupDefinitions cohortFunctionalGroups, FunctionalGroupDefinitions
            stockFunctionalGroups, SortedList<string, double> globalDiagnostics, Boolean tracking, Boolean DrawRandomly, 
            Boolean specificLocations, string globalModelTimeStepUnit)
        {
            // Add one to the counter of the number of grids. If there is more than one model grid, exit the program with a debug crash.
            NumGrids = NumGrids + 1;
            //Debug.Assert(NumGrids < 2, "You have initialised more than one grid on which to apply models. At present, this is not supported");

            // Initialise the utility functions
            Utilities = new UtilityFunctions();

            // Seed the random number generator
            // Set the seed for the random number generator
            RandomNumberGenerator = new NonStaticSimpleRNG();
            if (DrawRandomly)
            {
                RandomNumberGenerator.SetSeedFromSystemTime();
            }
            else
            {
                RandomNumberGenerator.SetSeed(4315);
            }

            // CURRENTLY DEFINING MODEL CELLS BY BOTTOM LEFT CORNER
            _MinLatitude = minLat;
            _MinLongitude = minLon;
            _MaxLatitude = maxLat;
            _MaxLongitude = maxLon;
            _LatCellSize = latCellSize;
            _LonCellSize = lonCellSize;

            // Check to see if the number of grid cells is an integer
            Debug.Assert((((_MaxLatitude - _MinLatitude) % _LatCellSize) == 0), "Error: number of grid cells is non-integer: check cell size");

            _NumLatCells = (UInt32)((_MaxLatitude - _MinLatitude) / _LatCellSize);
            _NumLonCells = (UInt32)((_MaxLongitude - _MinLongitude) / _LonCellSize);
            _Lats = new float[_NumLatCells];
            _Lons = new float[_NumLonCells];

            // Set up latitude and longitude vectors - lower left
            for (int ii = 0; ii < _NumLatCells; ii++)
            {
                _Lats[ii] = _MinLatitude + ii * _LatCellSize;
            }
            for (int jj = 0; jj < _NumLonCells; jj++)
            {
                _Lons[jj] = _MinLongitude + jj * _LonCellSize;
            }

            // Instantiate a grid of grid cells
            InternalGrid = new GridCell[_NumLatCells, _NumLonCells];

            // Instantiate the arrays of lists of cohorts to disperse
            DeltaFunctionalGroupDispersalArray = new List<uint>[_NumLatCells, _NumLonCells];
            DeltaCohortNumberDispersalArray = new List<uint>[_NumLatCells, _NumLonCells];

            // Instantiate the array of lists of grid cells to disperse those cohorts to
            DeltaCellToDisperseToArray = new List<uint[]>[_NumLatCells, _NumLonCells];

            // Instantiate the arrays of cell entry and exit directions
            DeltaCellExitDirection = new List<uint>[_NumLatCells, _NumLonCells];
            DeltaCellEntryDirection = new List<uint>[_NumLatCells, _NumLonCells];

            // An array of lists of cells to which organisms in each cell can disperse to; includes all cells which contribute to the
            // perimeter list, plus diagonal cells if they are in the same realm
            CellsForDispersal = new List<uint[]>[_NumLatCells, _NumLonCells];

            // An array of lists of directions corresponding to cells which organisms can disperse to
            CellsForDispersalDirection = new List<uint>[_NumLatCells, _NumLonCells];

            Console.WriteLine("Initialising grid cell environment:");

            // Loop through to set up model grid
            for (int ii = 0; ii < _NumLatCells; ii+=GridCellRarefaction)
            {
                for (int jj = 0; jj < _NumLonCells; jj+=GridCellRarefaction)
                {
                    InternalGrid[ii, jj] = new GridCell(_Lats[ii],(uint)ii, _Lons[jj],(uint)jj, LatCellSize, LonCellSize, enviroStack,
                        GlobalMissingValue, cohortFunctionalGroups, stockFunctionalGroups, globalDiagnostics, tracking, specificLocations,globalModelTimeStepUnit);
                    CellsForDispersal[ii,jj] = new List<uint[]>();
                    CellsForDispersalDirection[ii, jj] = new List<uint>();
                    Console.Write("\rRow {0} of {1}", ii+1, NumLatCells/GridCellRarefaction);
                }
            }
            Console.WriteLine("");
            Console.WriteLine("");

            InterpolateMissingValues(globalModelTimeStepUnit);

            // Fill in the array of dispersable perimeter lengths for each grid cell
            CalculatePerimeterLengthsAndCellsDispersableTo();

            CellHeightsKm = new double[_Lats.Length];
            CellWidthsKm = new double[_Lats.Length];

            // Calculate the lengths of widths of grid cells in each latitudinal strip
            // Assume that we are at the midpoint of each cell when calculating lengths
            for (int ii = 0; ii < _Lats.Length; ii++)
            {
                 CellHeightsKm[ii] = Utilities.CalculateLengthOfDegreeLatitude(_Lats[ii] + _LatCellSize / 2) * _LatCellSize;
                 CellWidthsKm[ii] = Utilities.CalculateLengthOfDegreeLongitude(_Lats[ii] + _LatCellSize / 2) * _LonCellSize;
            }
        }