/// <summary> /// Reads in three-dimensional environmental data from a NetCDF and stores them in the array of values within this instance of EnviroData /// </summary> /// <param name="internalData">The SDS object to get data from</param> /// <param name="dataName">The name of the variable within the NetCDF file</param> /// <param name="latInverted">Whether the latitude values are inverted in the NetCDF file (i.e. large to small values)</param> /// <param name="longInverted">Whether the longitude values are inverted in the NetCDF file (i.e. large to small values)</param> private void EnvironmentListFromNetCDF3D(DataSet internalData, string dataName, bool latInverted, bool longInverted) { // Vector to hold the position in the dimensions of the NetCDF file of the latitude, longitude and third dimensions int[] positions = new int[3]; // Array to store environmental data with latitude as the first dimension and longitude as the second dimension double[,] LatLongArrayUnsorted = new double[_NumLats, _NumLons]; // Check that the requested variable exists in the NetCDF file Debug.Assert(internalData.Variables.Contains(dataName), "Requested variable does not exist in the specified file"); // Check that the environmental variable in the NetCDF file has three dimensions Debug.Assert(internalData.Variables[dataName].Dimensions.Count == 3, "The specified variable in the NetCDF file does not have three dimensions, which is the required number for this method"); // Possible names for the missing value metadata in the NetCDF file string[] SearchStrings = { "missing_value", "MissingValue" }; // Loop over possible names for the missing value metadata until a match is found in the NetCDF file int kk = 0; while ((kk < SearchStrings.Length) & (!internalData.Variables[dataName].Metadata.ContainsKey(SearchStrings[kk]))) kk++; // If a match is found, then set the missing data field equal to the value in the file, otherwise throw an error if (kk < SearchStrings.Length) { _MissingValue = Convert.ToDouble(internalData.Variables[dataName].Metadata[SearchStrings[kk]]); } else { Debug.Fail("No missing data value found for environmental data file: " + internalData.Name.ToString()); } // Possible names for the latitude dimension in the NetCDF file SearchStrings = new string[] { "lat", "Lat", "latitude", "Latitude", "lats", "Lats", "latitudes", "Latitudes", "y" }; // Check which position the latitude dimension is in in the NetCDF file and add this to the vector of positions. If the latitude dimension cannot be // found then throw an error if (SearchStrings.Contains(internalData.Dimensions[0].Name.ToString())) { positions[0] = 1; } else if (SearchStrings.Contains(internalData.Dimensions[1].Name.ToString())) { positions[1] = 1; } else if (SearchStrings.Contains(internalData.Dimensions[2].Name.ToString())) { positions[2] = 1; } else { Debug.Fail("Cannot find a latitude dimension"); } // Possible names for the longitude dimension in the netCDF file SearchStrings = new string[] { "lon", "Lon", "longitude", "Longitude", "lons", "Lons", "long", "Long", "longs", "Longs", "longitudes", "Longitudes", "x" }; // Check which position the latitude dimension is in in the NetCDF file and add this to the vector of positions. If the latitude dimension cannot be // found then throw an error if (SearchStrings.Contains(internalData.Dimensions[0].Name.ToString())) { positions[0] = 2; } else if (SearchStrings.Contains(internalData.Dimensions[1].Name.ToString())) { positions[1] = 2; } else if (SearchStrings.Contains(internalData.Dimensions[2].Name.ToString())) { positions[2] = 2; } else { Debug.Fail("Cannot find a longitude dimension"); } // Possible names for the monthly temporal dimension in the netCDF file SearchStrings = new string[] { "month", "Month", "months", "Months" }; // Check which position the temporal dimension is in in the NetCDF file and add this to the vector of positions. If the temporal dimension cannot be // found then throw an error if (SearchStrings.Contains(internalData.Dimensions[0].Name.ToString())) { positions[0] = 3; } else if (SearchStrings.Contains(internalData.Dimensions[1].Name.ToString())) { positions[1] = 3; } else if (SearchStrings.Contains(internalData.Dimensions[2].Name.ToString())) { positions[2] = 3; } // Check the format of the specified environmental variable if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "single") { // Read the environmental data into a temporary array Single[, ,] TempArray; TempArray = internalData.GetData<Single[, ,]>(dataName); // Revised for speed switch (positions[0]) { case 1: switch (positions[1]) { case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[ii, jj, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[ii, hh, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 2: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[jj, ii, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[jj, hh, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 3: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[hh, ii, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[hh, jj, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } } else if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "double") { // Read the environmental data into a temporary array double[, ,] TempArray; TempArray = internalData.GetData<double[, ,]>(dataName); // Revised for speed switch (positions[0]) { case 1: switch (positions[1]) { case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[ii, jj, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[ii, hh, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 2: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[jj, ii, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[jj, hh, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 3: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[hh, ii, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[hh, jj, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } } else if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "int32") { // Read the environmental data into a temporary array Int32[, ,] TempArray; TempArray = internalData.GetData<Int32[, ,]>(dataName); // Revised for speed switch (positions[0]) { case 1: switch (positions[1]) { case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[ii, jj, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[ii, hh, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 2: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[jj, ii, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[jj, hh, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 3: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[hh, ii, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[hh, jj, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } } else if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "int16") { // Read the environmental data into a temporary array Int16[, ,] TempArray; TempArray = internalData.GetData<Int16[, ,]>(dataName); // Revised for speed switch (positions[0]) { case 1: switch (positions[1]) { case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[ii, jj, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[ii, hh, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 2: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[jj, ii, hh]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 3: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[jj, hh, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; case 3: switch (positions[1]) { case 1: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[hh, ii, jj]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; case 2: // Loop over time steps for (int hh = 0; hh < _NumTimes; hh++) { // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; // Add to the unsorted array of values, transposing the data to be dimensioned by latitude first and // longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = (double)TempArray[hh, jj, ii]; } } // Transpose the environmental data so that they are in ascending order of both latitude and longitude if (latInverted) { if (longInverted) { // Both dimensions inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, LongLengthMinusOne - jj]; } } } else { // Latitude only inverted int LatLengthMinusOne = LatLongArrayUnsorted.GetLength(0) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[LatLengthMinusOne - ii, jj]; } } } } else { if (longInverted) { // Longitude only inverted int LongLengthMinusOne = LatLongArrayUnsorted.GetLength(1) - 1; for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[ii, LongLengthMinusOne - jj]; } } } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } break; default: Debug.Fail("Failure detecting latitude dimension"); break; } } else { // Format of environmental data not recognized so throw an error Debug.Fail("Environmental data are in an unrecognized format"); } // If either latitude or longitude were inverted, then reverse their values in the class fields if (latInverted) { // Temporary vector to store inverted latitude values double[] tempLats = new double[_NumLats]; // Loop over latitude values for (int ii = 0; ii < _NumLats; ii++) { // Invert the values in the temporary vector tempLats[ii] = _Lats[_Lats.Length - 1 - ii]; } // Overwrite the old vector of latitude values with the inverted values _Lats = tempLats; // Reverse the sign on the difference in latitude values between adjacent cells _LatStep = -_LatStep; } if (longInverted) { // Temporary vector to store inverted longitude values double[] tempLongs = new double[_NumLons]; // Loop over longitude values for (int jj = 0; jj < _NumLons; jj++) { // Invert the values in the temporary vector tempLongs[jj] = _Lons[_Lons.Length - 1 - jj]; } // Overwrite the old vector of longitude values with the inverted values _Lons = tempLongs; // Reverse the sign on the difference in longitude values between adjacent cells _LonStep = -_LonStep; } // Check that the increment in both latitudes and longitudes between consecutive grid cells is now positive Debug.Assert(_LatStep > 0.0, "Latitudes are still inverted in an environmental variable stored in EnviroData"); Debug.Assert(_LonStep > 0.0, "Longitudes are still inverted in an environmental variable stored in EnviroData"); }
/// <summary> /// Asynchronously views an SDS /// </summary> /// <param name="DataSetToView">The name of the SDS to view</param> /// <param name="viewingParameters">A string of viewing parameters ('hints') to pass to SDS viewer</param> /// <todoD>Need to update to be able to select which variable to view</todoD> /// <todoD>Pass sleep length</todoD> /// <todoD>UPdate title on each timestep</todoD> public void AsynchronousView(ref DataSet DataSetToView, string viewingParameters) { DataSetToView.SpawnViewer(viewingParameters); // Slow down computation //System.Threading.Thread.Sleep(10); }
/// <summary> /// Provides a snapshot view of an SDS /// </summary> /// <param name="DataSetToView">The name of the SDS to view</param> /// <param name="handle">An object handle for the viewer instance; send the same handle to prevent multiple instances of SDS viewer opening</param> /// <todoD>Need to update to be able to select which variable to view</todoD> /// <todoD>Pass sleep length</todoD> public void SnapshotView(ref DataSet DataSetToView, ref object handle) { // Open the snapshot viewer handle = DataSetToView.ViewSnapshot("", handle); // Slow down computation System.Threading.Thread.Sleep(250); }
/// <summary> /// Adds a one-dimensional variable to the specified SDS object with floating point dimension data /// </summary> /// <param name="SDSObject">A reference to an SDS object</param> /// <param name="variableName">The name of the variable to create</param> /// <param name="units">Units of the data</param> /// <param name="numDimensions">The number of dimensions for the new variable</param> /// <param name="namesDimensions">A vector of names of the dimensions for the variable</param> /// <param name="missingValue">The missing value to apply to the new variable</param> /// <param name="dimension1Data">A vector of values of the first dimension</param> public void AddVariable(DataSet SDSObject, string variableName, string units, int numDimensions, string[] namesDimensions, double missingValue, float[] dimension1Data) { //If the wrong number of dimension names have been provided, then return error if (namesDimensions.Length != numDimensions) Debug.Fail("Error: you have provided the wrong number of dimension names"); //Since this overload method deals with one-dimensional variables, return an error if this is not the case if (numDimensions != 1) Debug.Fail("Error: you have provided data for the wrong number of dimensions"); //If the variable already exists in the SDS, then take no action, otherwise create new variable if (SDSObject.Variables.Contains(variableName)) { Console.WriteLine("SDS object already contains a variable with that name. Skipping..."); } else { //For each dimension, if it already exists in the SDS then take no action, otherwise create a new variable and populate it with the provided data if (SDSObject.Variables.Contains(namesDimensions[0])) { } else { SDSObject.AddVariable<float>(namesDimensions[0], dimension1Data, namesDimensions[0]); } //If the variable is the same as one of the entered dimensions, then take no action, otherwise create the new variable and populate it with missing values if (SDSObject.Variables.Contains(variableName)) { } else { //Create array of missing values of the correct dimensions double[] tempOutData = new double[dimension1Data.Length]; for (int ii = 0; ii < dimension1Data.Length; ii++) { tempOutData[ii] = missingValue; } //Add variable to SDS var testOut = SDSObject.Add<double[]>(variableName, units, missingValue, tempOutData, namesDimensions); //Metadata required by SDS testOut.Metadata["DisplayName"] = variableName; testOut.Metadata["MissingValue"] = missingValue; //Commit changes SDSObject.Commit(); } } }
/// <summary> /// Copies given dataset into dataset determined by <paramref name="dstUri"/>. /// </summary> /// <param name="src">Original dataset to clone.</param> /// <param name="dstUri">URI of the destination dataset.</param> /// <param name="updater">Delegate accepting update progressm notifications.</param> /// <returns>New instance of <see cref="DataSet"/> class.</returns> /// <remarks> /// This method splits the original dataser into parts and therefore is able /// to clone very large datasets not fitting to memory. /// </remarks> public static DataSet Clone(DataSet src, DataSetUri dstUri, ProgressUpdater updater) { DataSet dst = null; try { dst = DataSet.Open(dstUri); return Clone(src, dst, updater); } catch { if (dst != null) dst.Dispose(); throw; } }
internal DataSetChangeset(DataSet sds, DataSet.Changes changes, bool initializeAtOnce) { if (changes == null) throw new ArgumentNullException("changes"); lock (sds) { this.changes = changes; this.dataSet = sds; this.changeSetId = sds.Version;// +1; this.source = changes.ChangesetSource; if (initializeAtOnce) Initialize(); } }
public void Init(string constructionString) { dataSet = DataSet.Create(constructionString); //Инициализируем DataSet Variable X = dataSet.AddVariable<double>("X", "x"); Variable Y = dataSet.AddVariable<double>("Y", "y"); Variable Z = dataSet.AddVariable<double>("Z", "z"); time = dataSet.AddVariable<double>("Time", "t"); u = dataSet.AddVariable<double>("U velocity", "x", "y", "z", "t"); v = dataSet.AddVariable<double>("V velocity", "x", "y", "z", "t"); w = dataSet.AddVariable<double>("W velocity", "x", "y", "z", "t"); T = dataSet.AddVariable<double>("Temperature", "x", "y", "z", "t"); div = dataSet.AddVariable<double>("Divergence", "x", "y", "z", "t"); double[] wArr = new double[modellingParams.Nx]; for (int i = 0; i < modellingParams.Nx; i++) { wArr[i] = i * modellingParams.Dx; } X.PutData(wArr); wArr = new double[modellingParams.Ny]; for (int i = 0; i < modellingParams.Ny; i++) { wArr[i] = i * modellingParams.Dy; } Y.PutData(wArr); wArr = new double[modellingParams.Nz]; for (int i = 0; i < modellingParams.Nz; i++) { wArr[i] = i * modellingParams.Dz; } Z.PutData(wArr); //Инициализируем рассчетный модуль для слоя начальными условиями solver = new LayerSolver(prevData, modellingParams); u.Append(prevData.U.ToArray(), "t"); v.Append(prevData.V.ToArray(), "t"); w.Append(prevData.W.ToArray(), "t"); T.Append(prevData.T.ToArray(), "t"); div.Append(prevData.Div.ToArray(), "t"); time.PutData(new double[1] { 0 }); dataSet.Commit(); }
protected override DataSet ServerProcessInternal(DataSet ds) { if (serviceUri == "(local)") return LocalProcess(ds); string hash = DataSetDiskCache.ComputeHash(ds); DataSet proxyDataSet = null; // Creating new DataSet at the service. // TODO: fix following: try { try { proxyDataSet = ProxyDataSet.CreateProxySync(taskQueue, ServicePort, "msds:memory", false, 10 * 60 * 1000); } catch (CommunicationObjectFaultedException) { //Connection to server closed. //Recreate service port and try again. if (proxyDataSet != null && !proxyDataSet.IsDisposed) proxyDataSet.Dispose(); this._servicePort = null; proxyDataSet = ProxyDataSet.CreateProxySync(taskQueue, ServicePort, "msds:memory", false, 10 * 60 * 1000); } AutoResetEvent completed = new AutoResetEvent(false); OnCommittedHandler onCommitted = new OnCommittedHandler(completed, OnDataSetCommitted); proxyDataSet.Committed += onCommitted.Handler; proxyDataSet.IsAutocommitEnabled = false; FetchClimateRequestBuilder.CopyRequestedDataSet(ds, proxyDataSet, false); proxyDataSet.Metadata[Namings.metadataNameHash] = hash; proxyDataSet.Commit(); if (proxyDataSet.HasChanges) proxyDataSet.Commit(); completed.WaitOne(); proxyDataSet.IsAutocommitEnabled = true; return proxyDataSet; } catch { if (proxyDataSet != null && !proxyDataSet.IsDisposed) proxyDataSet.Dispose(); throw; } }
/// <summary> /// Returns bytes of specified <see cref="DataSet"/> instance after converting it into <see cref="CsvDataSet"/>. /// </summary> /// <param name="ds">Input <see cref="DataSet"/> instance.</param> /// <returns>Resulting bytes array.</returns> public static byte[] GetCsvBytes(DataSet ds) { if (ds == null) { throw new ArgumentNullException("ds"); } string resultTempFileName = GetTempCsvFileName(); byte[] bytes = null; try { ds.Clone(String.Format(CultureInfo.InvariantCulture, "msds:csv?file={0}&openMode=create&appendMetadata=true", resultTempFileName)); bytes = File.ReadAllBytes(resultTempFileName); } finally { if (resultTempFileName != null) File.Delete(resultTempFileName); } return bytes; }
protected override DataSet ServerProcessInternal(DataSet ds) { DateTime start = DateTime.Now; bool resultGot = false; DataSet inputDs = ds; DataSet resultDs = null; while (!resultGot) { resultDs = RestApiWrapper.Instance.Process(ds); if (FetchClimateRequestBuilder.IsResultDataSet(resultDs)) { resultGot = true; } else { if (FetchClimateRequestBuilder.ResendRequest(resultDs)) ds = inputDs; else ds = resultDs; int expectedCalculationTime = 0; string hash = string.Empty; FetchClimateRequestBuilder.GetStatusCheckParams(resultDs, out expectedCalculationTime, out hash); Thread.Sleep(expectedCalculationTime); } if ((!resultGot) && (DateTime.Now - start) > timeout) { throw new TimeoutException("Request to fetch climate has timed out. Increase timeout value or try again later."); } } return resultDs; }
public DataSetChangingEventArgs(DataSet sds, DataSetChangeAction action, object target) { this.sds = sds; this.target = target; this.cancel = false; this.action = action; }
public DataSetChangedEventArgs(DataSet sds, DataSetChangeAction action, object target, DataSetChangeset changes) { this.sds = sds; this.action = action; this.target = target; this.changes = changes; }
/// <summary> /// Initializes the instance of the class. /// </summary> /// <param name="sds">The committed data set.</param> /// <param name="changes">Committed changes.</param> /// <param name="committedSchema">DataSet schema after commit</param> internal DataSetCommittedEventArgs(DataSet sds, DataSetChangeset changes, DataSetSchema committedSchema) { this.sds = sds; this.changes = changes; this.committedSchema = committedSchema; }
/// <summary> /// Set up the file, screen and live outputs prior to the model run /// </summary> /// <param name="EcosystemModelGrid">The model grid that output data will be derived from</param> /// <param name="CohortFunctionalGroupDefinitions">The definitions for cohort functional groups</param> /// <param name="StockFunctionalGroupDefinitions">The definitions for stock functional groups</param> /// <param name="NumTimeSteps">The number of time steps in the model run</param> public void SetUpOutputs(ModelGrid EcosystemModelGrid, FunctionalGroupDefinitions CohortFunctionalGroupDefinitions, FunctionalGroupDefinitions StockFunctionalGroupDefinitions, uint NumTimeSteps, string FileOutputs) { // Get the functional group indices of herbivore, carnivore and omnivore cohorts, and autotroph stocks string[] Trait = { "Nutrition source" }; string[] Trait2 = { "Heterotroph/Autotroph" }; string[] TraitValue1 = { "Herbivory" }; string[] TraitValue2 = { "Carnivory" }; string[] TraitValue3 = { "Omnivory" }; string[] TraitValue4 = { "Autotroph" }; HerbivoreIndices = CohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue1, false); CarnivoreIndices = CohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue2, false); OmnivoreIndices = CohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue3, false); AutotrophIndices = StockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait2, TraitValue4, false); // Set up vectors to hold dimension data for the output variables float[] outLats = new float[EcosystemModelGrid.NumLatCells]; float[] outLons = new float[EcosystemModelGrid.NumLonCells]; float[] IdentityMassBins; // Populate the dimension variable vectors with cell centre latitude and longitudes for (int ii = 0; ii < EcosystemModelGrid.NumLatCells; ii++) { outLats[ii] = EcosystemModelGrid.Lats[ii] + (EcosystemModelGrid.LatCellSize / 2); } for (int jj = 0; jj < EcosystemModelGrid.NumLonCells; jj++) { outLons[jj] = EcosystemModelGrid.Lons[jj] + (EcosystemModelGrid.LonCellSize / 2); } // Create vector to hold the values of the time dimension OutTimes = new float[NumTimeSteps + 1]; // Set the first value to be -1 (this will hold initial outputs) OutTimes[0] = -1; // Fill other values from 0 (this will hold outputs during the model run) for (int ii = 1; ii < NumTimeSteps + 1; ii++) { OutTimes[ii] = ii + 1; } // Set up a vector to hold (log) individual body mass bins OutMassBins = new float[MassBinNumber]; IdentityMassBins = new float[MassBinNumber]; // Get the (log) minimum and maximum possible (log) masses across all functional groups combined, start with default values of // Infinity and -Infinity float MaximumMass = -1 / 0F; float MinimumMass = 1 / 0F; foreach (int FunctionalGroupIndex in CohortFunctionalGroupDefinitions.AllFunctionalGroupsIndex) { MinimumMass = (float)Math.Min(MinimumMass, Math.Log(CohortFunctionalGroupDefinitions.GetBiologicalPropertyOneFunctionalGroup("minimum mass", FunctionalGroupIndex))); MaximumMass = (float)Math.Max(MaximumMass, Math.Log(CohortFunctionalGroupDefinitions.GetBiologicalPropertyOneFunctionalGroup("maximum mass", FunctionalGroupIndex))); } // Get the interval required to span the range between the minimum and maximum values in 100 steps float MassInterval = (MaximumMass - MinimumMass) / MassBinNumber; // Fill the vector of output mass bins with (log) body masses spread evenly between the minimum and maximum values for (int ii = 0; ii < MassBinNumber; ii++) { OutMassBins[ii] = MinimumMass + ii * MassInterval; IdentityMassBins[ii] = Convert.ToSingle(Math.Exp(Convert.ToDouble(OutMassBins[ii]))); } // Create file for model outputs DataSetForFileOutput = CreateSDSObject.CreateSDS("netCDF", FileOutputs); // Add three-dimensional variables to output file, dimensioned by latitude, longtiude and time string[] dimensions3D = { "Latitude", "Longitude", "Time step" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Biomass density", 3, dimensions3D, 0, outLats, outLons, OutTimes); dimensions3D = new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore abundance in juvenile vs adult bins", 3, dimensions3D,Math.Log(0), OutMassBins, OutMassBins, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore abundance in juvenile vs adult bins", 3, dimensions3D, Math.Log(0), OutMassBins, OutMassBins, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore biomass in juvenile vs adult bins", 3, dimensions3D, Math.Log(0), OutMassBins, OutMassBins, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore biomass in juvenile vs adult bins", 3, dimensions3D, Math.Log(0), OutMassBins, OutMassBins, OutTimes); // Add two-dimensional variables to output file, dimensioned by mass bins and time string[] dimensions2D = { "Time step", "Mass bin" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore abundance in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore abundance in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore biomass in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore biomass in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); // Add one-dimensional variables to the output file, dimensioned by time string[] dimensions1D = { "Time step" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Herbivore density", "Individuals / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Herbivore abundance", "Individuals", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Herbivore biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Carnivore density", "Individuals / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Carnivore abundance", "Individuals", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Carnivore biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Omnivore density", "Individuals / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Omnivore abundance", "Individuals", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Omnivore biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Autotroph biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Organic matter pool", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Respiratory CO2 pool", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts extinct", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts produced", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts combined", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts in model", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of stocks in model", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); // Add one-dimensional variables to the output file, dimensioned by mass bin index // To enable outputs to be visualised against mass instead of index // Initialise the arrays that will be used for the grid-based outputs LogBiomassDensityGridCohorts = new double[EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells]; LogBiomassDensityGridStocks = new double[EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells]; LogBiomassDensityGrid = new double[EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells]; }
/// <summary> /// Spawn dataset viewer for the live outputs /// </summary> /// <param name="NumTimeSteps">The number of time steps in the model run</param> /// <param name="gridView">Whether to launch dataset viewer in full model grid view (otherwise in graph view)</param> public void SpawnDatasetViewer(uint NumTimeSteps) { Console.WriteLine("Spawning Dataset Viewer"); // Intialise the SDS object for the live view DataSetToViewLive = CreateSDSObject.CreateSDSInMemory(true); // Set up the grid viewer asynchronously // If the grid view option is selected, then live output will be the full model grid, otherwise the output will be a graph with total // carnivore and herbivore abundance if (GridView) { DataSetToViewLive.Metadata["VisualHints"] = "\"Biomass density\"(Longitude,Latitude) Style:Colormap; Palette:#000040=0,Blue=0.1,Green=0.2661,#FA8000=0.76395,Red; Transparency:0.38"; } else { DataSetToViewLive.Metadata["VisualHints"] = "\"Carnivore density\"[Time step]; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#D95F02; Thickness:3;; \"Herbivore density\"[Time step]; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#1B9E77; Thickness:3;; \"Omnivore density\"[Time step]; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#7570B3;Thickness:3; Title:\"Heterotroph Densities" + "\""; } // Start viewing ViewGrid.AsynchronousView(ref DataSetToViewLive, ""); }
/// <summary> /// Set up all outputs (live, console and file) prior to the model run /// </summary> /// <param name="numTimeSteps">The number of time steps in the model run</param> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="outputFilesSuffix">The suffix to be applied to all output files</param> public void SetupOutputs(uint numTimeSteps, ModelGrid ecosystemModelGrid, string outputFilesSuffix) { Console.WriteLine("Setting up global outputs...\n"); // Set the suffix for all output files _OutputSuffix = outputFilesSuffix + "_Global"; // Create an SDS object to hold total abundance and biomass data BasicOutput = SDSCreator.CreateSDS("netCDF", "BasicOutputs" + _OutputSuffix, _OutputPath); // Create vector to hold the values of the time dimension TimeSteps = new float[numTimeSteps + 1]; // Set the first value to be -1 (this will hold initial outputs) TimeSteps[0] = 0; // Fill other values from 0 (this will hold outputs during the model run) for (int i = 1; i < numTimeSteps + 1; i++) { TimeSteps[i] = i; } // Add basic variables to the output file, dimensioned by time string[] TimeDimension = { "Time step" }; DataConverter.AddVariable(BasicOutput, "Total living biomass", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Organic matter pool", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Respiratory CO2 pool", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Number of cohorts extinct", "", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Number of cohorts produced", "", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Number of cohorts combined", "", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Number of cohorts in model", "", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutput, "Number of stocks in model", "", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); this.FileName = _OutputPath + "BasicOutputs" + _OutputSuffix + ".nc"; }
public void OutputCurrentModelState(ModelGrid currentModelGrid, FunctionalGroupDefinitions functionalGroupHandler, List<uint[]> cellIndices, uint currentTimestep, int maximumNumberOfCohorts, string filename) { float[] Latitude = currentModelGrid.Lats; float[] Longitude = currentModelGrid.Lons; float[] CohortFunctionalGroup = new float[functionalGroupHandler.GetNumberOfFunctionalGroups()]; for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { CohortFunctionalGroup[fg] = fg; } int CellCohortNumber = 0; GridCellCohortHandler CellCohorts; for (int cellIndex = 0; cellIndex < cellIndices.Count; cellIndex++) { CellCohorts = currentModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); for (int i = 0; i < CellCohorts.Count; i++) { if (CellCohorts[i].Count > CellCohortNumber) CellCohortNumber = CellCohorts[i].Count; } } int MaxNumberCohorts = Math.Max(CellCohortNumber, maximumNumberOfCohorts); float[] Cohort = new float[MaxNumberCohorts]; for (int c = 0; c < Cohort.Length; c++) { Cohort[c] = c; } //Define an array for stock functional group - there are only three currently float[] StockFunctionalGroup = new float[] { 1, 2, 3 }; //Define an array for index of stocks - there is only one currently float[] Stock = new float[] { 1 }; string Filename = filename + "_" + currentTimestep.ToString() + Simulation.ToString(); StateOutput = SDSCreator.CreateSDS("netCDF", Filename, _OutputPath); //Define the cohort properties for output string[] CohortProperties = new string[] {"JuvenileMass", "AdultMass", "IndividualBodyMass", "CohortAbundance", "BirthTimeStep", "MaturityTimeStep", "LogOptimalPreyBodySizeRatio", "MaximumAchievedBodyMass","Merged","TrophicIndex","ProportionTimeActive"}; //define the dimensions for cohort outputs string[] dims = new string[] { "Latitude", "Longitude", "Cohort Functional Group", "Cohort" }; // Add the variables for each cohort property // Then calculate the state for this property and put the data to this variable foreach (string v in CohortProperties) { DataConverter.AddVariable(StateOutput, "Cohort" + v, 4, dims, currentModelGrid.GlobalMissingValue, Latitude, Longitude, CohortFunctionalGroup, Cohort); StateOutput.PutData<double[, , ,]>("Cohort" + v, CalculateCurrentCohortState(currentModelGrid, v, Latitude.Length, Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length, cellIndices)); StateOutput.Commit(); } //Define the stock properties for output string[] StockProperties = new string[] { "IndividualBodyMass", "TotalBiomass" }; //define the dimensions for cohort outputs dims = new string[] { "Latitude", "Longitude", "Stock Functional Group", "Stock" }; // Add the variables for each stock property // Then calculate the state for this property and put the data to this variable foreach (string v in StockProperties) { DataConverter.AddVariable(StateOutput, "Stock" + v, 4, dims, currentModelGrid.GlobalMissingValue, Latitude, Longitude, StockFunctionalGroup, Stock); StateOutput.PutData<double[, , ,]>("Stock" + v, CalculateCurrentStockState(currentModelGrid, v, Latitude.Length, Longitude.Length, StockFunctionalGroup.Length, Stock.Length, cellIndices)); StateOutput.Commit(); } //Close this data set StateOutput.Dispose(); }
/// <summary> /// Set up the predation tracker /// </summary>_ /// <param name="numTimeSteps">The total number of timesteps for this simulation</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="massFlowsFilename">Filename for outputs of the flows of mass between predators and prey</param> /// <param name="cohortDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="missingValue">The missing value to be used in the output file</param> /// <param name="outputFileSuffix">The suffix to be applied to the output file</param> /// <param name="outputPath">The path to write the output file to</param> /// <param name="trackerMassBins">The mass bin handler containing the mass bins to be used for predation tracking</param> /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param> public PredationTracker(uint numTimeSteps, List<uint[]> cellIndices, string massFlowsFilename, FunctionalGroupDefinitions cohortDefinitions, double missingValue, string outputFileSuffix, string outputPath, MassBinsHandler trackerMassBins, int cellIndex) { // Assign the missing value _MissingValue = missingValue; // Get the mass bins to use for the predation tracker and the number of mass bins that this correpsonds to _MassBins = trackerMassBins.GetSpecifiedMassBins(); _NumMassBins = trackerMassBins.NumMassBins; // Initialise the array to hold data on mass flows between mass bins _MassFlows = new double[_NumMassBins, _NumMassBins]; // Define the model time steps to be used in the output file float[] TimeSteps = new float[numTimeSteps]; for (int i = 1; i <= numTimeSteps; i++) { TimeSteps[i - 1] = i; } // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); // Create an SDS object to hold the predation tracker data MassFlowsDataSet = SDSCreator.CreateSDS("netCDF", massFlowsFilename + outputFileSuffix + "_Cell" + cellIndex, outputPath); // Define the dimensions to be used in the predation tracker output file string[] dimensions = { "Predator mass bin", "Prey mass bin", "Time steps" }; // Add the mass flow variable to the predation tracker DataConverter.AddVariable(MassFlowsDataSet, "Log mass (g)", 3, dimensions, _MissingValue, _MassBins, _MassBins, TimeSteps); }
/// <summary> /// Spawn dataset viewer for the live outputs /// </summary> /// <param name="NumTimeSteps">The number of time steps in the model run</param> public void SpawnDatasetViewer(uint NumTimeSteps) { Console.WriteLine("Spawning Dataset Viewer\n"); // Intialise the SDS object for the live view DataSetToViewLive = SDSCreator.CreateSDSInMemory(true); // Check the output detail level if (ModelOutputDetail == OutputDetailLevel.Low) { // For low detail level, just show total living biomass DataSetToViewLive.Metadata["VisualHints"] = "\"Total living biomass\"[Time step]; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#D95F02; Thickness:3; Title:\"Total Biomass" + "\""; } else { // For medium and high detail levels, show biomass by trophic level DataSetToViewLive.Metadata["VisualHints"] = "\"autotroph biomass\"[Time step]; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FF008040;Thickness:3;;\"carnivore biomass\"[Time step] ; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FFFF0000;Thickness:3;;\"herbivore biomass\"[Time step] ; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FF00FF00;Thickness:3;;\"omnivore biomass\"[Time step] ; Style:Polyline; Visible: 0,1," + NumTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FF0000FF;Thickness:3; Title:\"Biomass Densities"; } // Start viewing GridViewer.AsynchronousView(ref DataSetToViewLive, ""); }
/// <summary> /// Sets up the outputs associated with the high level of output detail /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The indices of active cells in the model grid</param> /// <param name="cellNumber">The index of the current cell in the list of active cells</param> /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void SetUpHighLevelOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellNumber, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, Boolean marineCell) { // Create an SDS object for outputs by mass bin // MassBinsOutput = SDSCreator.CreateSDS("netCDF", "MassBins" + _OutputSuffix, _OutputPath); MassBinsOutputMemory = SDSCreator.CreateSDSInMemory(true); // Add relevant output variables to the mass bin output file string[] MassBinDimensions = { "Time step", "Mass bin" }; string[] DoubleMassBinDimensions = new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }; if (OutputMetrics) { DataConverter.AddVariable(MassBinsOutputMemory, "Trophic Index Distribution", 2, new string[] {"Time step","Trophic Index Bins"}, ecosystemModelGrid.GlobalMissingValue, TimeSteps, Metrics.TrophicIndexBinValues); } if (marineCell) { foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); } } else { foreach (string TraitValue in CohortTraitIndices.Keys) { DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); } } // Create an SDS object in memory for tracked cohorts outputs // TrackedCohortsOutput = SDSCreator.CreateSDS("netCDF", "TrackedCohorts" + _OutputSuffix, _OutputPath); TrackedCohortsOutputMemory = SDSCreator.CreateSDSInMemory(true); // Initialise list to hold tracked cohorts TrackedCohorts = new List<uint>(); // Identify cohorts to track GridCellCohortHandler TempCohorts = null; bool FoundCohorts = false; // Get a local copy of the cohorts in the grid cell TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellNumber][0], cellIndices[cellNumber][1]); // Loop over functional groups and check whether any cohorts exist in this grid cell foreach (var CohortList in TempCohorts) { if (CohortList.Count > 0) { FoundCohorts = true; break; } } // If there are some cohorts in the grid cell, then setup the tracked cohorts if (FoundCohorts) { // Initialise stream writer to hold details of tracked cohorts StreamWriter sw = new StreamWriter(_OutputPath + "TrackedCohortProperties" + _OutputSuffix + ".txt"); sw.WriteLine("Output ID\tCohort ID\tFunctional group index\tNutrition source\tDiet\tRealm\tMobility\tJuvenile mass\tAdult mass"); // Counter for tracked cohorts int TrackedCohortCounter = 0; for (int i = 0; i < TempCohorts.Count; i++) { if (TempCohorts[i].Count > 0) { for (int j = 0; j < TempCohorts[i].Count; j++) { // Write out properties of the selected cohort sw.WriteLine(Convert.ToString(TrackedCohortCounter) + '\t' + Convert.ToString(TempCohorts[i][j].CohortID[0]) + '\t' + i + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Nutrition source", i) + '\t' + cohortFunctionalGroupDefinitions. GetTraitNames("Diet", i) + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Realm", i) + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Mobility", i) + '\t' + TempCohorts[i][j].JuvenileMass + '\t' + TempCohorts[i][j].AdultMass); // Add the ID of the cohort to the list of tracked cohorts TrackedCohorts.Add(TempCohorts[i][j].CohortID[0]); // Increment the counter of tracked cohorts TrackedCohortCounter++; } } } // Generate an array of floating points to index the tracked cohorts in the output file float[] OutTrackedCohortIDs = new float[TrackedCohortCounter]; for (int i = 0; i < TrackedCohortCounter; i++) { OutTrackedCohortIDs[i] = i; } // Set up outputs for tracked cohorts string[] TrackedCohortsDimensions = { "Time step", "Cohort ID" }; // Add output variables for the tracked cohorts output DataConverter.AddVariable(TrackedCohortsOutputMemory, "Individual body mass", 2, TrackedCohortsDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, OutTrackedCohortIDs); DataConverter.AddVariable(TrackedCohortsOutputMemory, "Number of individuals", 2, TrackedCohortsDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, OutTrackedCohortIDs); // Dispose of the streamwriter sw.Dispose(); } // Get a list of all possible combinations of trait values as a jagged array string[][] TraitValueSearch; if (marineCell) TraitValueSearch = CalculateAllCombinations(CohortTraitValuesMarine[CohortTraits[0]], CohortTraitValuesMarine[CohortTraits[1]]); else TraitValueSearch = CalculateAllCombinations(CohortTraitValues[CohortTraits[0]], CohortTraitValues[CohortTraits[1]]); // Add the functional group indices of these trait combinations to the list of indices of the trait values to consider, // keyed with a concatenated version of the trait values string TraitValueJoin = ""; string[] TimeDimension = { "Time step" }; for (int i = 0; i < TraitValueSearch.Count(); i++) { TraitValueJoin = ""; foreach (string TraitValue in TraitValueSearch[i]) { TraitValueJoin += TraitValue + " "; } if (marineCell) { // Only add indices of marine functional groups int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(CohortTraits, TraitValueSearch[i], true); Boolean[] TempIndices2 = new Boolean[TempIndices.GetLength(0)]; for (int ii = 0; ii < TempIndices.GetLength(0); ii++) { if (cohortFunctionalGroupDefinitions.GetTraitNames("Realm", TempIndices[ii]).Equals("Marine", StringComparison.OrdinalIgnoreCase)) { TempIndices2[ii] = true; } } // Extract only the indices which are marine int[] TempIndices3 = Enumerable.Range(0, TempIndices2.Length).Where(zz => TempIndices2[zz]).ToArray(); if (TempIndices3.Length > 0) { // Extract the values at these indices for (int ii = 0; ii < TempIndices3.Length; ii++) { TempIndices3[ii] = TempIndices[TempIndices3[ii]]; } // Add in the indices for this functional group and this realm CohortTraitIndices.Add(TraitValueJoin, TempIndices3); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); TotalBiomassDensitiesOut.Add(TraitValueJoin, 0.0); TotalDensitiesOut.Add(TraitValueJoin, 0.0); } } else { // Only add indices of terrestrial functional groups int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(CohortTraits, TraitValueSearch[i], true); Boolean[] TempIndices2 = new Boolean[TempIndices.GetLength(0)]; for (int ii = 0; ii < TempIndices.GetLength(0); ii++) { if (cohortFunctionalGroupDefinitions.GetTraitNames("Realm", TempIndices[ii]).Equals("Terrestrial", StringComparison.OrdinalIgnoreCase)) { TempIndices2[ii] = true; } } // Extract only the indices which are terrestrial int[] TempIndices3 = Enumerable.Range(0, TempIndices2.Length).Where(zz => TempIndices2[zz]).ToArray(); if (TempIndices3.Length > 0) { // Extract the values at these indices for (int ii = 0; ii < TempIndices3.Length; ii++) { TempIndices3[ii] = TempIndices[TempIndices3[ii]]; } // Add in the indices for this functional group and this realm CohortTraitIndices.Add(TraitValueJoin, TempIndices3); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); TotalBiomassDensitiesOut.Add(TraitValueJoin, 0.0); TotalDensitiesOut.Add(TraitValueJoin, 0.0); } } } }
/// <summary> /// Reads in two-dimensional environmental data from a NetCDF and stores them in the array of values within this instance of EnviroData /// </summary> /// <param name="internalData">The SDS object to get data from</param> /// <param name="dataName">The name of the variable within the NetCDF file</param> /// <param name="latInverted">Whether the latitude values are inverted in the NetCDF file (i.e. large to small values)</param> /// <param name="longInverted">Whether the longitude values are inverted in the NetCDF file (i.e. large to small values)</param> private void EnvironmentListFromNetCDF(DataSet internalData, string dataName, bool latInverted, bool longInverted) { // Vector two hold the position in the dimensions of the NetCDF file of the latitude and longitude dimensions int[] positions = new int[2]; // Array to store environmental data with latitude as the first dimension and longitude as the second dimension double[,] LatLongArrayUnsorted = new double[_NumLats, _NumLons]; // Array to store environmental data as above, but with data in ascending order of both latitude and longitude double[,] LatLongArraySorted = new double[_NumLats, _NumLons]; Console.WriteLine(dataName); // Check that the requested variable exists in the NetCDF file Debug.Assert(internalData.Variables.Contains(dataName), "Requested variable does not exist in the specified file"); // Check that the environmental variable in the NetCDF file has two dimensions Debug.Assert(internalData.Variables[dataName].Dimensions.Count == 2, "The specified variable in the NetCDF file does not have two dimensions, which is the required number for this method"); // Possible names for the missing value metadata in the NetCDF file string[] SearchStrings = { "missing_value", "MissingValue" }; // Loop over possible names for the missing value metadata until a match is found in the NetCDF file int kk = 0; while ((kk < SearchStrings.Length) && (!internalData.Variables[dataName].Metadata.ContainsKey(SearchStrings[kk]))) kk++; // If a match is found, then set the missing data field equal to the value in the file, otherwise throw an error if (kk < SearchStrings.Length) { _MissingValue = Convert.ToDouble(internalData.Variables[dataName].Metadata[SearchStrings[kk]]); } else { Console.WriteLine("No missing data value found for this variable: assigning a value of -9999"); _MissingValue = -9999; } // Possible names for the latitude dimension in the NetCDF file SearchStrings = new string[] { "lat", "Lat", "latitude", "Latitude", "lats", "Lats", "latitudes", "Latitudes", "y", "Y" }; // Check which position the latitude dimension is in in the NetCDF file and add this to the vector of positions. If the latitude dimension cannot be // found then throw an error if (SearchStrings.Contains(internalData.Dimensions[0].Name.ToString())) { positions[0] = 1; } else if (SearchStrings.Contains(internalData.Dimensions[1].Name.ToString())) { positions[1] = 1; } else { Debug.Fail("Cannot find a latitude dimension"); } // Possible names for the longitude dimension in the netCDF file SearchStrings = new string[] { "lon", "Lon", "longitude", "Longitude", "lons", "Lons", "long", "Long", "longs", "Longs", "longitudes", "Longitudes", "x", "X" }; // Check which position the latitude dimension is in in the NetCDF file and add this to the vector of positions. If the latitude dimension cannot be // found then throw an error if (SearchStrings.Contains(internalData.Dimensions[0].Name.ToString())) { positions[0] = 2; } else if (SearchStrings.Contains(internalData.Dimensions[1].Name.ToString())) { positions[1] = 2; } else { Debug.Fail("Cannot find a longitude dimension"); } // Check the format of the specified environmental variable if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "single") { // Read the environmental data into a temporary array Single[,] TempArray; TempArray = internalData.GetData<Single[,]>(dataName); // Convert the data to double format and add to the unsorted array of values, transposing the data to be dimensioned by latitude first and longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[(int)(ii * Convert.ToDouble(positions[0] == 1) + jj * Convert.ToDouble(positions[0] == 2)), (int)(ii * Convert.ToDouble(positions[1] == 1) + jj * Convert.ToDouble(positions[1] == 2))]; } } } else if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "double") { // Read the environmental data into a temporary array double[,] TempArray; TempArray = internalData.GetData<double[,]>(dataName); // Add the data to the unsorted array of values, transposing the data to be dimensioned by latitude first and longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[(int)(ii * Convert.ToDouble(positions[0] == 1) + jj * Convert.ToDouble(positions[0] == 2)), (int)(ii * Convert.ToDouble(positions[1] == 1) + jj * Convert.ToDouble(positions[1] == 2))]; } } } else if (internalData.Variables[dataName].TypeOfData.Name.ToString().ToLower() == "int32") { // Read the environmental data into a temporary array Int32[,] TempArray; TempArray = internalData.GetData<Int32[,]>(dataName); // Convert the data to double format and add to the unsorted array of values, transposing the data to be dimensioned by latitude first and longitude second for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArrayUnsorted[ii, jj] = TempArray[(int)(ii * Convert.ToDouble(positions[0] == 1) + jj * Convert.ToDouble(positions[0] == 2)), (int)(ii * Convert.ToDouble(positions[1] == 1) + jj * Convert.ToDouble(positions[1] == 2))]; } } } else { // Format of environmental data not recognized so throw an error Debug.Fail("Environmental data are in an unrecognized format"); } // Transpose the environmental data so that they are in ascending order of both latitude and longitude for (int ii = 0; ii < _NumLats; ii++) { for (int jj = 0; jj < _NumLons; jj++) { LatLongArraySorted[ii, jj] = LatLongArrayUnsorted[(int)((1 - Convert.ToDouble(latInverted)) * ii + (Convert.ToDouble(latInverted) * (LatLongArrayUnsorted.GetLength(0) - 1 - ii))), (int)((1 - Convert.ToDouble(longInverted)) * jj + (Convert.ToDouble(longInverted) * (LatLongArrayUnsorted.GetLength(1) - 1 - jj)))]; } } // Add the final array to the class field for environmental data values _DataArray.Add(LatLongArraySorted); // If either latitude or longitude were inverted, then reverse their values in the class fields if (latInverted) { // Temporary vector to store inverted latitude values double[] tempLats = new double[_NumLats]; // Loop over latitude values for (int ii = 0; ii < _NumLats; ii++) { // Invert the values in the temporary vector tempLats[ii] = _Lats[_Lats.Length - 1 - ii]; } // Overwrite the old vector of latitude values with the inverted values _Lats = tempLats; // Reverse the sign on the difference in latitude values between adjacent cells _LatStep = -_LatStep; } if (longInverted) { // Temporary vector to store inverted longitude values double[] tempLongs = new double[_NumLons]; // Loop over longitude values for (int jj = 0; jj < _NumLons; jj++) { // Invert the values in the temporary vector tempLongs[jj] = _Lons[_Lons.Length - 1 - jj]; } // Overwrite the old vector of longitude values with the inverted values _Lons = tempLongs; // Reverse the sign on the difference in longitude values between adjacent cells _LonStep = -_LonStep; } // Check that the increment in both latitudes and longitudes between consecutive grid cells is now positive Debug.Assert(_LatStep > 0.0, "Latitudes are still inverted in an environmental variable stored in EnviroData"); Debug.Assert(_LonStep > 0.0, "Longitudes are still inverted in an environmental variable stored in EnviroData"); }
/// <summary> /// /// </summary> /// <param name="failedDataSet"></param> /// <param name="inner"></param> public DistributedCommitFailedException(DataSet failedDataSet, Exception inner) : base("DataSet " + failedDataSet.URI + " commit failed", inner) { failed = failedDataSet; }
public void Copy(OutputGlobal existing) { this.BasicOutput.Dispose(); this.BasicOutput = null; System.IO.File.Copy(existing.FileName, this.FileName, true); var fileString = "msds:nc?file=" + this.FileName; this.BasicOutput = DataSet.Open(fileString); }
public DataSetCommittingEventArgs(DataSet sds, DataSet.Changes changes) { this.sds = sds; this.cancel = false; this.changes = changes; }
public DataSetRolledBackEventArgs(DataSet sds) { this.sds = sds; }
/// <summary> /// Processes request <see cref="DataSet"/> via Fetch Climate. /// </summary> /// <param name="ds">Request <see cref="DataSet"/> with fetching parameters.</param> /// <returns>DataSet with response.</returns> /// <remarks> /// <para> /// There are two types of responses from server: /// If request time is lower than <see cref="maxExecutionTimeWithoutReturns"/> time, /// <see cref="DataSet"/> with request result will be returned. /// If request time exceeds <see cref="maxExecutionTimeWithoutReturns"/> time, <see cref="DataSet"/> /// instance with requets hash and next time to request ("status response") will be returned instead of <see cref="DataSet"/> with result. /// Pass it to the <see cref="Process"/> method after specified time interval again to get the result. /// If client got status response, it must send it back to server to get next status response, or result. But there is exception in this rule (see next). /// For status response, there are three matdata attributes in it: /// -"ExpectedCalculationTime" is expected time, calculation will take. /// Client should request next time after this time will pass. /// -"Hash" is hash of original request dataset. /// -"ReplyWithRequestDs" indicates, whether client needs to resend request /// next time or not. If so, client needs to send entire request next time /// instead of status response, it got from server. /// </para> /// </remarks> public DataSet Process(DataSet ds) { int retryAttempt = 0; int retryTimeDelta = RestApiWrapper.retryStartTimeDelta; while (true) { if (retryAttempt > 1) { //Increase retry time delta, if not first attempt and not first retry. retryTimeDelta = (int)(Math.Round(retryTimeDelta * RestApiWrapper.retryTimeIncreaseCoeff)); } if (retryAttempt > retriesCount) break; else if (retryAttempt > 0) Thread.Sleep(retryTimeDelta); try { string login = null; string password = null; CredentialsManager.GetCredentials(out login, out password); HttpWebRequest request = WebRequest.Create(serviceUrl) as HttpWebRequest; var credentialCache = new CredentialCache(); credentialCache.Add( new Uri(serviceUrl), "Digest", new NetworkCredential(login, password) ); request.Credentials = credentialCache; request.PreAuthenticate = true; request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested; request.Method = RestApiNamings.postRequestMethodName; //request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; request.ContentType = RestApiNamings.textRequestTypeName; request.Timeout = RestApiWrapper.requestTimeout; byte[] csvBytes = RestApiUtilities.GetCsvBytes(ds); request.ContentLength = csvBytes.Length; using (Stream dataStream = request.GetRequestStream()) { dataStream.Write(csvBytes, 0, csvBytes.Length); } using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) { if (response.ContentType == RestApiNamings.textRequestTypeName) { //DataSet is in response using (Stream dataStream = response.GetResponseStream()) { byte[] responseBytes = RestApiUtilities.ReadBytes(dataStream, (int)response.ContentLength); DataSet resultDs = RestApiUtilities.GetDataSet(responseBytes); return resultDs; } } else { throw new InvalidOperationException("Unexpected exception. You should never see this"); } } } catch (WebException) { Trace.WriteIf(RestApiWrapper.Tracer.TraceWarning, string.Format("Web exception occured while processing input dataSet. {0} retry attempts left", RestApiWrapper.retriesCount - retryAttempt)); retryAttempt++; } } throw new WebException("Failed to connect to service. Make sure, it's available."); }
/// <summary> /// Sets up the outputs associated with all levels of output detail /// </summary> /// <param name="numTimeSteps">The number of time steps in the model run</param> /// <param name="ecosystemModelGrid">The model grid</param> private void SetUpLowLevelOutputs(uint numTimeSteps, ModelGrid ecosystemModelGrid) { // Create an SDS object to hold total abundance and biomass data // BasicOutput = SDSCreator.CreateSDS("netCDF", "BasicOutputs" + _OutputSuffix, _OutputPath); BasicOutputMemory = SDSCreator.CreateSDSInMemory(true); string[] TimeDimension = { "Time step" }; DataConverter.AddVariable(BasicOutputMemory, "Total Biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Heterotroph Abundance density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Heterotroph Biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); }
public void Copy(OutputCell existing) { this.BasicOutputMemory.Dispose(); this.BasicOutputMemory = null; // Somehow this reverses the variables, so do it again to reverse them back again var filename = "msds:nc?file=" + existing.FileName + "&openMode=readOnly"; if (System.IO.File.Exists(existing.FileName)) { var dataSet = DataSet.Open(filename); this.BasicOutputMemory = dataSet.Clone("msds:memory"); dataSet.Dispose(); dataSet = null; } else if (existing.BasicOutputMemory.IsDisposed == false) { var dataSet = existing.BasicOutputMemory.Clone("msds:memory"); this.BasicOutputMemory = dataSet.Clone("msds:memory"); dataSet.Dispose(); dataSet = null; } }
public void SolveAll(string ctorString) { //dataSet = ProxyDataSet.Open("msds:nc?file=../../../temp.nc"); dataSet = ProxyDataSet.Open("msds:memory"); //Инициализируем DataSet Variable X = dataSet.AddVariable<double>("X", "x"); Variable Y = dataSet.AddVariable<double>("Y", "y"); Variable Z = dataSet.AddVariable<double>("Z", "z"); Variable time = dataSet.AddVariable<double>("Time", "t"); Variable u = dataSet.AddVariable<double>("U velocity", "x", "y", "z", "t"); Variable v = dataSet.AddVariable<double>("V velocity", "x", "y", "z", "t"); Variable w = dataSet.AddVariable<double>("W velocity", "x", "y", "z", "t"); Variable T = dataSet.AddVariable<double>("Temperature", "x", "y", "z", "t"); Variable div = dataSet.AddVariable<double>("Divergence", "x", "y", "z", "t"); dataSet.Commit(); double[] wArr = new double[modellingParams.Nx]; for (int i = 0; i < modellingParams.Nx; i++) { wArr[i] = i * modellingParams.Dx; } X.PutData(wArr); wArr = new double[modellingParams.Ny]; for (int i = 0; i < modellingParams.Ny; i++) { wArr[i] = i * modellingParams.Dy; } Y.PutData(wArr); wArr = new double[modellingParams.Nz]; for (int i = 0; i < modellingParams.Nz; i++) { wArr[i] = i * modellingParams.Dz; } Z.PutData(wArr); //Инициализируем рассчетный модуль для слоя начальными условиями LayerSolver solver = new LayerSolver(prevData, modellingParams); u.Append(prevData.U.ToArray(), "t"); v.Append(prevData.V.ToArray(), "t"); w.Append(prevData.W.ToArray(), "t"); T.Append(prevData.T.ToArray(), "t"); div.Append(prevData.Div.ToArray(), "t"); time.PutData(new double[1] { 0 }); dataSet.Commit(); //Основной рассчет for (int i = 1; i < modellingParams.Nt; i++) { LayerData result = solver.Solve(true); //Кладем данные в DataSet u.Append(result.U.ToArray(), "t"); v.Append(result.V.ToArray(), "t"); w.Append(result.W.ToArray(), "t"); T.Append(result.T.ToArray(), "t"); div.Append(result.Div.ToArray(), "t"); time.Append(new double[1] { (double)i / modellingParams.Nt }); dataSet.Commit(); //Переходим на следующий слой solver = new LayerSolver(prevData, result, modellingParams); prevData = result; double temp = 0; int count = 0; for (int ii = 1; ii < result.Width; ii++) { for (int jj = 1; jj < result.Height; jj++) { for (int kk = 1; kk < result.Thickness; kk++) { temp += result.Div[ii, jj, kk]; count++; } } } temp = temp / count * modellingParams.Dx * modellingParams.Dy * modellingParams.Dz; Console.WriteLine((double)i / modellingParams.Nt * 100 + "% Error = " + temp); } dataSet.Commit(); }
/// <summary> /// Constructor for the functional group definitions: reads in the specified functional group definition file, /// constructs lookup tables, mass ranges and initial cohort numbers in each functional group /// </summary> /// <param name="fileName">The name of the functional group definition file to be read in</param> /// <param name="outputPath">The path to the output folder, in which to copy the functional group definitions file</param> public FunctionalGroupDefinitions(string fileName, string outputPath) { // Construct the URI for the functional group definition file string FileString = "msds:csv?file=input/Model setup/ecological definition files/" + fileName + "&openMode=readOnly"; // Copy the Function group definitions file to the output directory System.IO.File.Copy("input/Model setup/ecological definition files/" + fileName, outputPath + fileName, true); // Read in the data InternalData = DataSet.Open(FileString); // Initialise the lists _AllFunctionalGroupsIndex = new int[InternalData.Dimensions[0].Length]; _FunctionalGroupProperties = new SortedList<string, double[]>(); // Loop over columns in the functional group definitions file foreach (Variable v in InternalData.Variables) { // Get the column header string TraitName = v.Name.Split('_')[1].ToLower(); // Get the values in this column var TempValues = v.GetData(); // For functional group definitions if (System.Text.RegularExpressions.Regex.IsMatch(v.Name, "DEFINITION_")) { // Declare a sorted dictionary to hold the index values for each unique trait value SortedDictionary<string, int[]> TraitIndexValuesList = new SortedDictionary<string, int[]>(); // Create a string array with the values of this trait string[] TempString = new string[TempValues.Length]; for (int nn = 0; nn < TempValues.Length; nn++) { TempString[nn] = TempValues.GetValue(nn).ToString().ToLower(); // Add the functional group index to the list of all indices _AllFunctionalGroupsIndex[nn] = nn; } // Add the trait values to the trait-value lookup list TraitLookupFromIndex.Add(TraitName, TempString); // Get the unique values for this trait var DistinctValues = TempString.Distinct().ToArray(); //Loop over the unique values for this trait and list all the functional group indices with the value foreach (string DistinctTraitValue in DistinctValues.ToArray()) { List<int> FunctionalGroupIndex = new List<int>(); //Loop over the string array associated with this trait and add the index values of matching string to a list for (int kk = 0; kk < TempString.Length; kk++) { if (TempString[kk].Equals(DistinctTraitValue)) { FunctionalGroupIndex.Add(kk); } } //Add the unique trait value and the functional group indices to the temporary list TraitIndexValuesList.Add(DistinctTraitValue, FunctionalGroupIndex.ToArray()); } // Add the unique trait values and corresponding functional group indices to the functional group index lookup IndexLookupFromTrait.Add(TraitName, TraitIndexValuesList); } // For functional group properties else if (System.Text.RegularExpressions.Regex.IsMatch(v.Name, "PROPERTY_")) { // Get the values for this property double[] TempDouble = new double[TempValues.Length]; for (int nn = 0; nn < TempValues.Length; nn++) { TempDouble[nn] = Convert.ToDouble(TempValues.GetValue(nn)); } // Add the values to the list of functional group properties _FunctionalGroupProperties.Add(TraitName, TempDouble); } else if (System.Text.RegularExpressions.Regex.IsMatch(v.Name, "NOTES_")) { // Ignore } // Otherwise, throw an error else { Debug.Fail("All functional group data must be prefixed by DEFINITTION OR PROPERTY"); } } }