From 1268594573485939e8affd5ba2b4eb650067c8af Mon Sep 17 00:00:00 2001 From: lbross Date: Mon, 23 Jan 2023 14:39:59 -0800 Subject: [PATCH] issue #40: Don't try to clip series of layers if the first one gets NoData values; Clean up error handling in preparation for Alaska AOIs. --- bagis-pro/AnalysisTools.cs | 173 +++++++++++++++++++++++++------------ bagis-pro/MapTools.cs | 22 +++++ 2 files changed, 138 insertions(+), 57 deletions(-) diff --git a/bagis-pro/AnalysisTools.cs b/bagis-pro/AnalysisTools.cs index 8a5fa50..4e30a6d 100644 --- a/bagis-pro/AnalysisTools.cs +++ b/bagis-pro/AnalysisTools.cs @@ -919,6 +919,7 @@ await QueuedTask.Run(async () => } int i = 0; + bool bIsNoData = false; foreach (string strUri in arrClipUris) { Uri imageServiceUri = new Uri(strWsPrefix + strUri + Constants.URI_IMAGE_SERVER); @@ -943,6 +944,16 @@ await QueuedTask.Run(async () => } else { + // Check for NoData + if (i==0) // Check the first raster only + { + bIsNoData = await IsNoDataRasterAsync(strAoiPath, strOutputGdb, arrClippedFileNames[i]); + if (bIsNoData) + { + intError++; + break; + } + } Module1.Current.ModuleLogManager.LogDebug(nameof(ClipLayersAsync), "Clipped " + arrClippedFileNames[i] + " layer"); //We need to add a new tag at "/metadata/dataIdInfo/searchKeys/keyword" @@ -1026,9 +1037,9 @@ await QueuedTask.Run(async () => { Module1.Current.ModuleLogManager.LogDebug(nameof(ClipLayersAsync), "At least one error occurred while clipping " + strDataType + " layers!"); + return BA_ReturnCode.UnknownError; } - success = BA_ReturnCode.Success; - return success; + return BA_ReturnCode.Success; } public static async Task CalculateZonesAsync(string strAoiPath, string strSourceLayer, @@ -1396,8 +1407,8 @@ await QueuedTask.Run(() => { IList lstIntervals = new List(); - double dblMin = -999; - double dblMax = 999; + double dblMin = 9999; + double dblMax = -9999; double dblInterval = 999; bool bTooSmall = false; @@ -1417,7 +1428,6 @@ await QueuedTask.Run(() => } else { - MessageBox.Show("Unable to extract minimum " + strMessageKey + " value. Calculation halted !!", "BAGIS-PRO"); Module1.Current.ModuleLogManager.LogError(nameof(GetPrismClassesAsync), "Unable to calculate " + strMessageKey + " miniumum"); return; @@ -1434,7 +1444,6 @@ await QueuedTask.Run(() => } else { - MessageBox.Show("Unable to extract maximum " + strMessageKey + " value. Calculation halted !!", "BAGIS-PRO"); Module1.Current.ModuleLogManager.LogError(nameof(GetPrismClassesAsync), "Unable to calculate " + strMessageKey + " maximum"); return; @@ -1453,6 +1462,11 @@ await QueuedTask.Run(() => dblInterval = Math.Round(dblInterval); } }); + if (dblMin == 9999 || dblMax == -9999) + { + Module1.Current.PrismZonesInterval = -1; + return null; + } int zones = GeneralTools.CreateRangeArray(dblMin, dblMax, dblInterval, out lstIntervals); // issue #18 // Check to be sure the highest interval isn't too small; if it is merge into the second-to-last @@ -3332,39 +3346,43 @@ public static async Task CalculatePrecipitationZonesAsync(string { string strMaskPath = GeodatabaseTools.GetGeodatabasePath(Module1.Current.Aoi.FilePath, GeodatabaseNames.Aoi, true) + Constants.FILE_AOI_PRISM_VECTOR; int prismZonesCount = (int)Module1.Current.BatchToolSettings.PrecipZonesCount; + BA_ReturnCode success = BA_ReturnCode.UnknownError; IList lstInterval = await AnalysisTools.GetPrismClassesAsync(Module1.Current.Aoi.FilePath, strLayer, prismZonesCount, "PRISM"); - BA_ReturnCode success = await AnalysisTools.CalculateZonesAsync(Module1.Current.Aoi.FilePath, strLayer, - lstInterval, strZonesRaster, strMaskPath, "PRISM"); - string zonesFile = Path.GetFileName(strZonesRaster); - if (success == BA_ReturnCode.Success && !Constants.FILE_WINTER_PRECIPITATION_ZONE.Equals(zonesFile)) + if (lstInterval != null) { - // Record the prism zones information to be used later when presenting maps/charts - // Open the current Analysis.xml from disk, if it exists - BA_Objects.Analysis oAnalysis = new BA_Objects.Analysis(); - string strSettingsFile = Module1.Current.Aoi.FilePath + "\\" + Constants.FOLDER_MAPS + "\\" + - Constants.FILE_SETTINGS; - if (File.Exists(strSettingsFile)) + success = await AnalysisTools.CalculateZonesAsync(Module1.Current.Aoi.FilePath, strLayer, + lstInterval, strZonesRaster, strMaskPath, "PRISM"); + string zonesFile = Path.GetFileName(strZonesRaster); + if (success == BA_ReturnCode.Success && !Constants.FILE_WINTER_PRECIPITATION_ZONE.Equals(zonesFile)) { - using (var file = new StreamReader(strSettingsFile)) + // Record the prism zones information to be used later when presenting maps/charts + // Open the current Analysis.xml from disk, if it exists + BA_Objects.Analysis oAnalysis = new BA_Objects.Analysis(); + string strSettingsFile = Module1.Current.Aoi.FilePath + "\\" + Constants.FOLDER_MAPS + "\\" + + Constants.FILE_SETTINGS; + if (File.Exists(strSettingsFile)) { - var reader = new System.Xml.Serialization.XmlSerializer(typeof(BA_Objects.Analysis)); - oAnalysis = (BA_Objects.Analysis)reader.Deserialize(file); + using (var file = new StreamReader(strSettingsFile)) + { + var reader = new System.Xml.Serialization.XmlSerializer(typeof(BA_Objects.Analysis)); + oAnalysis = (BA_Objects.Analysis)reader.Deserialize(file); + } + } + // Set the prism zones information on the analysis object and save + oAnalysis.PrecipZonesIntervalCount = prismZonesCount; + oAnalysis.PrecipZonesInterval = Module1.Current.PrismZonesInterval; + Module1.Current.PrismZonesInterval = 999; + string strPrecipFile = Path.GetFileName(strLayer); + oAnalysis.PrecipZonesBegin = strPrecipFile; + oAnalysis.PrecipZonesEnd = strPrecipFile; + using (var file_stream = File.Create(strSettingsFile)) + { + var serializer = new System.Xml.Serialization.XmlSerializer(typeof(BA_Objects.Analysis)); + serializer.Serialize(file_stream, oAnalysis); + Module1.Current.ModuleLogManager.LogDebug(nameof(CalculatePrecipitationZonesAsync), + "Set precipitation zone parameters in analysis.xml file"); } - } - // Set the prism zones information on the analysis object and save - oAnalysis.PrecipZonesIntervalCount = prismZonesCount; - oAnalysis.PrecipZonesInterval = Module1.Current.PrismZonesInterval; - Module1.Current.PrismZonesInterval = 999; - string strPrecipFile = Path.GetFileName(strLayer); - oAnalysis.PrecipZonesBegin = strPrecipFile; - oAnalysis.PrecipZonesEnd = strPrecipFile; - using (var file_stream = File.Create(strSettingsFile)) - { - var serializer = new System.Xml.Serialization.XmlSerializer(typeof(BA_Objects.Analysis)); - serializer.Serialize(file_stream, oAnalysis); - Module1.Current.ModuleLogManager.LogDebug(nameof(CalculatePrecipitationZonesAsync), - "Set precipitation zone parameters in analysis.xml file"); } } return success; @@ -3561,32 +3579,32 @@ public static async Task CalculateSWEDeltaAsync(string strAoiPath success = GeneralTools.SaveDataSourcesToFile(dictLocalDataSources); Module1.Current.ModuleLogManager.LogDebug(nameof(CalculateSWEDeltaAsync), "Updated settings overall min and max metadata for SWE Delta"); - } - int intDefaultMonth = 8; - IList lstInterval = await MapTools.CalculateSweDeltaZonesAsync(intDefaultMonth); - //Reclassify into 7 classes for map - if (lstInterval.Count > 0) - { - for (int j = 0; j < Constants.FILES_SWE_DELTA.Length; j++) - { - string strInput = $@"{strAnalysisGdb}\temp{j}"; - string strOutput = strAnalysisGdb + "\\" + Constants.FILES_SWE_DELTA[j]; - string strMaskPath = GeodatabaseTools.GetGeodatabasePath(strAoiPath, GeodatabaseNames.Aoi, true) + Constants.FILE_AOI_PRISM_VECTOR; - success = await AnalysisTools.CalculateZonesAsync(strAoiPath, strInput, lstInterval, - strOutput, strMaskPath, "SWE DELTA"); - if (success == BA_ReturnCode.Success) + + int intDefaultMonth = 8; + IList lstInterval = await MapTools.CalculateSweDeltaZonesAsync(intDefaultMonth); + //Reclassify into 7 classes for map + if (lstInterval.Count > 0) + { + for (int j = 0; j < Constants.FILES_SWE_DELTA.Length; j++) { - success = await GeoprocessingTools.DeleteDatasetAsync(strInput); + string strInput = $@"{strAnalysisGdb}\temp{j}"; + string strOutput = strAnalysisGdb + "\\" + Constants.FILES_SWE_DELTA[j]; + string strMaskPath = GeodatabaseTools.GetGeodatabasePath(strAoiPath, GeodatabaseNames.Aoi, true) + Constants.FILE_AOI_PRISM_VECTOR; + success = await AnalysisTools.CalculateZonesAsync(strAoiPath, strInput, lstInterval, + strOutput, strMaskPath, "SWE DELTA"); + if (success == BA_ReturnCode.Success) + { + success = await GeoprocessingTools.DeleteDatasetAsync(strInput); + } } } + else + { + Module1.Current.ModuleLogManager.LogError(nameof(CalculateQuarterlyPrecipitationAsync), + "Unable to calculate interval list and publish classified quarterly precipitation layers!"); + return BA_ReturnCode.UnknownError; + } } - else - { - Module1.Current.ModuleLogManager.LogError(nameof(CalculateQuarterlyPrecipitationAsync), - "Unable to calculate interval list and publish classified quarterly precipitation layers!"); - return BA_ReturnCode.UnknownError; - } - return success; } @@ -5257,7 +5275,48 @@ await QueuedTask.Run(() => { return success; } - + private static async Task IsNoDataRasterAsync(string strAoiPath, string strGdbFolder, string strRasterFile) + { + var parameters = Geoprocessing.MakeValueArray($@"{strGdbFolder}\{strRasterFile}", "MAXIMUM"); + var environments = Geoprocessing.MakeEnvironmentArray(workspace: strAoiPath); + var gpResult = await Geoprocessing.ExecuteToolAsync("GetRasterProperties_management", parameters, environments, + CancelableProgressor.None, GPExecuteToolFlags.AddToHistory); + if (gpResult.IsFailed) + { + if (gpResult.ErrorCode == 2) + { + Module1.Current.ModuleLogManager.LogError(nameof(IsNoDataRasterAsync), + "Unable to calculate maximum for raster data. Failed because no statistics are available!"); + } + else + { + Module1.Current.ModuleLogManager.LogError(nameof(IsNoDataRasterAsync), + "Error Code: " + gpResult.ErrorCode + ". Unable to calculate maximum for raster data!"); + } + return true; + } + string strMax = Convert.ToString(gpResult.ReturnValue); + string strNoData = "-9998"; + await QueuedTask.Run(() => + { + using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(strGdbFolder)))) + using (RasterDataset rasterDataset = geodatabase.OpenDataset(strRasterFile)) + { + RasterBandDefinition bandDefinition = rasterDataset.GetBand(0).GetDefinition(); + Raster raster = rasterDataset.CreateDefaultRaster(); + strNoData = Convert.ToString(raster.GetNoDataValue()); + } + }); + if (strMax.Equals(strNoData)) + { + return true; + } + else + { + return false; + } } - } \ No newline at end of file + } + +} \ No newline at end of file diff --git a/bagis-pro/MapTools.cs b/bagis-pro/MapTools.cs index 240ae1e..807fb45 100644 --- a/bagis-pro/MapTools.cs +++ b/bagis-pro/MapTools.cs @@ -3029,6 +3029,13 @@ await QueuedTask.Run(() => string dataSourceUnits = await QuerySweLayerUnitsAsync(strPath); if (arrReturnValues.Length == 4) { + // An error occurred getting the min/max + if (arrReturnValues[IDX_STRETCH_MIN] == ERROR_MIN) + { + Module1.Current.ModuleLogManager.LogError(nameof(CalculateSweZonesAsync), + "Unable to retrieve min/max values from SWE layers. Calculation halted!"); + return null; + } bool bSkipInterval2 = false; double floor = 0.5; if (arrReturnValues[2] > floor) @@ -3146,6 +3153,14 @@ await QueuedTask.Run(() => intZones = intZones - 1; //Subtract the zones in the middle that we create int halfZones = intZones / 2; double[] arrReturnValues = await MapTools.SWEUnitsConversionAsync(Constants.DATA_TYPE_SWE_DELTA, idxDefaultMonth); + // An error occurred getting the min/max + if (arrReturnValues[IDX_STRETCH_MIN] == ERROR_MIN) + { + Module1.Current.ModuleLogManager.LogError(nameof(CalculateSweDeltaZonesAsync), + "Unable to retrieve min/max values from SWE Delta layers. Calculation halted!"); + return null; + } + string strPath = GeodatabaseTools.GetGeodatabasePath(Module1.Current.Aoi.FilePath, GeodatabaseNames.Layers, true) + Constants.FILES_SNODAS_SWE[idxDefaultMonth]; string dataSourceUnits = await QuerySweLayerUnitsAsync(strPath); // Data source units come from source SWE layer @@ -3535,6 +3550,13 @@ private static async Task DisplayMultiMapPageLayoutAsync(string s break; } + if (lstInterval == null) + { + Module1.Current.ModuleLogManager.LogError(nameof(DisplayMultiMapPageLayoutAsync), + "Unable to calculate interval list for multi page map. Map cannot be displayed!"); + return BA_ReturnCode.UnknownError; + } + //Get the map frame in the layout string legendMapFrameName = ""; // hook up the legend to the map frame with all the classifications for (int i = 0; i < arrMapFrames.Length; i++)