public float[][] ReadRegionAcrossFiles(int xOffset, int yOffset, int xSize, int ySize)
        {
            int nPixPerTile = xSize * ySize;

            float[][] tileData = new float[m_FileDates.Count][];
            int       fileNum  = 0;

            foreach (var t in m_FileDates)
            {
                var newshape = GDAL_Operations.GetRasterShape(t.Value);
                if (newshape.Item1 != Shape.Item1 || newshape.Item2 != Shape.Item2)
                {
                    throw new ArgumentException("Raster shapes don't match");
                }
                var newGT = GDAL_Operations.GetGeoTransform(t.Value);
                if (!GeoTransform.SequenceEqual(newGT))
                {
                    throw new ArgumentException("Raster geotransforms don't match");
                }
                var newNDV = GDAL_Operations.GetNoDataValue(t.Value);
                if (newNDV != NoDataValue)
                {
                    throw new ArgumentException("Raster nodata values don't match");
                }
                var newProj = GDAL_Operations.GetProjection(t.Value);
                if (newProj != Projection)
                {
                    throw new ArgumentException("Raster projections don't match");
                }
                tileData[fileNum] = GDAL_Operations.ReadGDALRasterBandsToFlatArray(
                    t.Value, xSize, ySize, xOffset, yOffset, 1);
                fileNum += 1;
            }
            return(tileData);
        }
        /// <summary>
        /// Parse key information about the first raster: the geotransform, shape (n pixels X and Y), and
        /// nodata value (of the first band). Also calculate the latitude of each row and the longitude of
        /// each column.
        /// </summary>
        private void PopulateRasterProperties()
        {
            string firstFilename = m_FileDates.First().Value;

            GeoTransform = GDAL_Operations.GetGeoTransform(firstFilename);
            Shape        = GDAL_Operations.GetRasterShape(firstFilename);
            NoDataValue  = GDAL_Operations.GetNoDataValue(firstFilename);
            Projection   = GDAL_Operations.GetProjection(firstFilename);
            double[] latcoords = new double[Shape.Item1];
            double[] loncoords = new double[Shape.Item2];
            double   originX   = GeoTransform[0];
            double   cellsizeX = GeoTransform[1];
            double   originY   = GeoTransform[3];
            double   cellsizeY = GeoTransform[5];

            for (int i = 0; i < Shape.Item1; i++)
            {
                latcoords[i] = originY + i * cellsizeY;
            }
            for (int i = 0; i < Shape.Item2; i++)
            {
                loncoords[i] = originX + i * cellsizeX;
            }
            GlobalLatCoords = latcoords;
            GlobalLonCoords = loncoords;
        }
        public float[][] ReadRegionAcrossFiles_MP(int xOffset, int yOffset, int xSize, int ySize)
        {
            int nPixPerTile = xSize * ySize;

            float[][]       tileData = new float[m_FileDates.Count][];
            ParallelOptions b        = new ParallelOptions();

            b.MaxDegreeOfParallelism = 6;
            var keys = m_FileDates.Keys;

            Parallel.For(0, keys.Count, b, c =>
            {
                var fDate    = keys[c];
                var fName    = m_FileDates[fDate];
                var newshape = GDAL_Operations.GetRasterShape(fName);
                if (newshape.Item1 != Shape.Item1 || newshape.Item2 != Shape.Item2)
                {
                    throw new ArgumentException("Raster shapes don't match");
                }
                var newGT = GDAL_Operations.GetGeoTransform(fName);
                if (!GeoTransform.SequenceEqual(newGT))
                {
                    throw new ArgumentException("Raster geotransforms don't match");
                }
                var newNDV = GDAL_Operations.GetNoDataValue(fName);
                if (newNDV != NoDataValue)
                {
                    throw new ArgumentException("Raster nodata values don't match");
                }
                var newProj = GDAL_Operations.GetProjection(fName);
                if (newProj != Projection)
                {
                    throw new ArgumentException("Raster projections don't match");
                }
                tileData[c] = GDAL_Operations.ReadGDALRasterBandsToFlatArray(
                    fName, xSize, ySize, xOffset, yOffset, 1);
            });
            return(tileData);
        }