/// <summary> /// Constructs a new TSCellModel to calculate dynamic temperature suitability for Pf transmission, across time at a single /// cell location. The underlying population can be modelled via any object implementing IIterablePopulation. Currently there /// are three such classes which take different approaches to the iteration for performance testing; which of these to use /// is currently specified by the PopulationTypes enum. After construction, call SetData before calling RunModel. /// </summary> /// <param name="modelConfigParams"></param> /// <param name="locationParams"></param> /// <param name="modelType"></param> public TSCellModel(PopulationParams modelConfigParams, GeographicCellLocation locationParams, PopulationTypes modelType) { this.modelParams = modelConfigParams; this.modelLocation = new GeographicCell(locationParams); double sliceLengthDays = modelParams.SliceLength.TotalDays; int lifespanSlices = modelConfigParams.LifespanSlices; switch (modelType) { case PopulationTypes.OOCohorts: m_Pop = new PopulationOO(lifespanSlices, sliceLengthDays, modelConfigParams.MinTempThreshold, modelConfigParams.DegreeDayThreshold, modelConfigParams.MosquitoDeathTemperature); break; case PopulationTypes.Arrays: m_Pop = new PopulationArray(lifespanSlices, sliceLengthDays, modelConfigParams.MinTempThreshold, modelConfigParams.DegreeDayThreshold, modelConfigParams.MosquitoDeathTemperature); break; case PopulationTypes.Pointers: m_Pop = new PopulationPtr(lifespanSlices, sliceLengthDays, modelConfigParams.MinTempThreshold, modelConfigParams.DegreeDayThreshold, modelConfigParams.MosquitoDeathTemperature); break; } }
static double[][] RunForCoarseStripe(string FilePattern, PopulationTypes ModelType) { string fnPattern = "C:\\Users\\zool1301.NDPH\\Documents\\Code_General\\temp-suitability\\Original\\c_code\\test5\\data\\{0}.{1}.dat"; string latFile = String.Format(fnPattern, "lat", FilePattern); string lonFile = String.Format(fnPattern, "long", FilePattern); string minFile = String.Format(fnPattern, "tmin", FilePattern); string maxFile = String.Format(fnPattern, "tmax", FilePattern); double[] tLats = File.ReadAllLines(latFile). Select(l => double.Parse(l)).ToArray(); double[] tLongs = File.ReadAllLines(lonFile). Select(l => double.Parse(l)).ToArray(); double[] tMins = File.ReadAllLines(minFile). Select(l => double.Parse(l)).ToArray(); double[] tMaxs = File.ReadAllLines(maxFile). Select(l => double.Parse(l)).ToArray(); int numCells = tLats.Length; int nDays = tMins.Length / tLats.Length; PopulationParams popParams = new PopulationParams(); popParams.DegreeDayThreshold = 111; popParams.MinTempThreshold = 11; popParams.MosquitoLifespanDays = new TimeSpan(31, 0, 0, 0); popParams.SliceLength = new TimeSpan(2, 0, 0); double[][] tsOut = new double[numCells][]; //int c = 0; int numBlocks = 200; IEnumerable <int> blocks = Enumerable.Range(0, numBlocks); int cellsPerBlock = numCells / numBlocks; Parallel.ForEach(blocks, blockID => { int blockCellStartIdx = blockID * cellsPerBlock; for (int c = blockCellStartIdx; (c < (blockCellStartIdx + cellsPerBlock) && c < numCells); c++) { tsOut[c] = new double[nDays]; double lat = tLats[c]; double lon = tLongs[c]; int startIdx = c * nDays; int endIdx = startIdx + nDays; double[] tMinsForCell = new double[nDays]; double[] tMaxsForCell = new double[nDays]; Array.Copy(tMins, startIdx, tMinsForCell, 0, nDays); Array.Copy(tMaxs, startIdx, tMaxsForCell, 0, nDays); GeographicCellLocation geogParams = new GeographicCellLocation(); geogParams.Latitude = tLats[c]; geogParams.Longitude = tLongs[c]; TSCellModel tsModel = new TSCellModel(popParams, geogParams, ModelType); //double[] tsCell = tsModel.RunModel(tMinsForCell, tMaxsForCell); //for (int i = 0; i < nDays; i++) //{ // tsOut[c][i] = tsCell[i]; //} } }); return(tsOut); }
static double[][] RunForArray( float[] minTemps, float[] maxTemps, float[] latitudes, float[] longitudes, float[] timestamps, PopulationTypes ModelType) { int numCells = latitudes.Length * longitudes.Length; int numRows = latitudes.Length; int numCols = longitudes.Length; Debug.Assert(minTemps.Length == maxTemps.Length); Debug.Assert(minTemps.Length % numCells == 0); Debug.Assert(minTemps.Length / numCells == timestamps.Length); PopulationParams popParams = new PopulationParams(); popParams.DegreeDayThreshold = 111; popParams.MinTempThreshold = 11; popParams.MosquitoLifespanDays = new TimeSpan(31, 0, 0, 0);; popParams.SliceLength = new TimeSpan(2, 0, 0); double[][] tsOut = new double[numCells][]; Parallel.For(0, numCells, c => { int rownum = c / numCols; int colnum = c % numCols; GeographicCellLocation geogParams = new GeographicCellLocation(); geogParams.Latitude = latitudes[rownum]; geogParams.Longitude = longitudes[colnum]; //geogParams.ModelRuntimeDays = nDays; //geogParams.StartJulianDay = 0; }); return(null); }
public GeographicCell(GeographicCellLocation CellLocation) { this.locationParams = CellLocation; }
/// <summary> /// Runs a temperature suitability model for all pixels in a region specified by pixel limits. /// Output is a jagged array with one value for each cell starting at top left and then row by /// row to bottom right, EXCEPT if no pixel in the tile is in a data area in which case the output /// is an array with length zero. /// Otherwise, each value is an array with one TS value for each month of the run period, /// EXCEPT if the cell is in the sea / masked area, in which case it is an array of length 0. /// Each cell location is done independently and this is therefore multithreaded. /// </summary> /// <param name="xOff"></param> /// <param name="yOff"></param> /// <param name="xSize"></param> /// <param name="ySize"></param> /// <returns></returns> public float[][] RunTile(int xOff, int yOff, int xSize, int ySize) { // test area: int xOff=20480, int yOff=9216, int xSize=512, int ySize=512 var lsMask = GDAL_Operations.ReadGDALRasterBandsToFlatArray( _cfg.dataPathConfig.MaskFile, xSize, ySize, xOff, yOff, 1); if (!lsMask.Any(v => v == _cfg.modelRunConfig.MaskValidValue)) { // this whole tile is in the sea, no need to run, return as a special case a zero length cell array return(new float[0][]); } var maxTempData = _maxReader.ReadCellData(xOff, yOff, xSize, ySize); var lats = _maxReader.GetSubsetLatitudeCoords(yOff, ySize); var lons = _maxReader.GetSubsetLongitudeCoords(xOff, xSize); var minTempData = _minReader.ReadCellData(xOff, yOff, xSize, ySize); int numCells = xSize * ySize; // there's no reason in principle why we couldn't allow different numbers of min and max temp files although of // course we'd have to pass separate dates arrays into the model then, but hey. It would be a bit more effort // to handle different geotransforms in the max and min temps data and this way we make it less likely that // they've come from separate sources. Debug.Assert(minTempData.Length == maxTempData.Length); Debug.Assert(maxTempData.Length == numCells); var dates = _maxReader.Filedates.ToArray(); var nFiles = dates.Length; // get the model parameters from the default settings file, bearing in mind that this could have been re-set // at initialisation to a file specified on the commandline, rather than just being the default app config //var set = Properties.Settings.Default; var set = _cfg.modelConfig; PopulationParams popParams = new PopulationParams(); popParams.DegreeDayThreshold = set.SporogenesisDegreeDays; popParams.MinTempThreshold = set.MinTempThresholdCelsius; popParams.MosquitoDeathTemperature = set.DeathTempCelsius;; popParams.MosquitoLifespanDays = new TimeSpan((int)set.LifespanDays, 0, 0, 0);; popParams.SliceLength = new TimeSpan((int)set.SliceLengthHours, 0, 0); popParams.MaxTempSuitability = set.MaxTSNormaliser; // max ts for default settings is 34.2467; the Weiss code had 33.89401 , not sure how generated. // I got this using iterative solver in excel. Console.WriteLine("Tile data loaded, computation beginning"); var mConfig = _cfg.modelRunConfig; float[][] tsOut = new float[numCells][]; DateTime[] outputDates = null; ParallelOptions b = new ParallelOptions(); if (mConfig.MaxThreads != 0) { // set threads to 1 for easier step-through debugging or some other number to not hog the whole machine b.MaxDegreeOfParallelism = (int)mConfig.MaxThreads; //System.Threading.ThreadPool.SetMaxThreads(set.MaxThreads, set.MaxThreads); //System.Threading.ThreadPool.SetMinThreads(set.MinThreads, set.MinThreads); } int testnum = 0; while (outputDates == null && testnum < numCells) { // if we haven't got at least 50% of the data and 100+ points it's probably crap // (unless we're playing with synoptic data or something, so make this threshold configurable). // This doesn't affect the date calculation but the spline will throw an error // on initialisation var nValid = Math.Min( maxTempData[testnum].Count(v => v != _maxReader.NoDataValue), minTempData[testnum].Count(v => v != _minReader.NoDataValue)); if (nValid < nFiles / 2 || nValid < mConfig.MinRequiredDataPoints) { testnum += 1; continue; } // set up a dummy model purely to parse the output dates (that they will all share) // avoids the need to test for the first one to do this in the parallel loop, which needs a lock, // which slows things right down with >>20 cores TSCellModel tsModel = new TSCellModel( popParams, new GeographicCellLocation() { Latitude = lats[0], Longitude = lons[0] }, PopulationTypes.Pointers); if (!tsModel.SetData(maxTempData[testnum], minTempData[testnum], dates, _maxReader.NoDataValue.Value, mConfig.MaxTempFilesAreLST, mConfig.MinTempFilesAreLST)) { throw new ApplicationException("Pop goes the weasel"); } ; outputDates = tsModel.OutputDates; break; } Parallel.For(0, numCells, b, c => { if (lsMask[c] != mConfig.MaskValidValue) { // this cell is in the sea, no need to run, return as a special case a zero length result array tsOut[c] = new float[0]; } else { int rownum = c / xSize; int colnum = c % xSize; GeographicCellLocation geogParams = new GeographicCellLocation(); geogParams.Latitude = lats[rownum]; geogParams.Longitude = lons[colnum]; //geogParams.ModelRuntimeDays = nDays; //geogParams.StartJulianDay = 0; // run only if we've got at least 50% of the data and 100+ points (or whatever is configured) var nValid = Math.Min( maxTempData[c].Count(v => v != _maxReader.NoDataValue), minTempData[c].Count(v => v != _minReader.NoDataValue)); if (nValid < nFiles / 2 || nValid < mConfig.MinRequiredDataPoints) { tsOut[c] = new float[0]; } else { TSCellModel tsModel = new TSCellModel(popParams, geogParams, PopulationTypes.Pointers); // var dd = dayData[c]; // var nd = nightData[c]; // float optimal = 28.6857194664029F; // for (int i = 0; i < 727; i++) { // dd[i] = optimal; // if (i%3==0) { dd[i] = 43; } // nd[i] = optimal; } //tsModel.SetData(dd, nd, dates, _maxReader.NoDataValue.Value, false); if (!tsModel.SetData(maxTempData[c], minTempData[c], dates, _maxReader.NoDataValue.Value, mConfig.MaxTempFilesAreLST, mConfig.MinTempFilesAreLST)) { throw new ApplicationException("Pop goes the weasel"); } ; // run the entire ts model for this location float[] tsCell = tsModel.RunModel(); int nOutputPoints = tsCell.Length; tsOut[c] = tsCell; /*lock (_lockobj) // ensure only 1 thread makes this check * { * // calculate and record the dates of the outputs for an arbitrary one of the cell models * if (outputDates == null) * { * outputDates = tsModel.OutputDates; * } * }*/ } } } ); if (_outputDates == null) { _outputDates = outputDates; } else if (outputDates != null && !_outputDates.SequenceEqual(outputDates)) { throw new ApplicationException("Dates have changed between tiles somehow, this shouldn't happen..."); } return(tsOut); }