public void CalculateTotalPrecipitation() { var GP = Earth.ATM.MidLevel.P.Gradient2().Rescale(new float[] { 0, 100 }); var GT = Earth.ATM.MidLevel.T.Gradient2().Rescale(new float[] { 0, 100 }); var TS = Earth.SFC.TS; var TE = Earth.SFC.TE; DenseMatrix WIND = MatrixFactory.Init(); if (Earth.ATM.SeaLevel.P != null) { WIND = Earth.ATM.SeaLevel.P.Gradient2(); } var HMid = Earth.ATM.MidLevel.H; var HSea = Earth.ATM.SeaLevel.H; if (HSea == null) { HSea = HMid; } var eqFronts = Earth.ATM.Fronts;//.EQ(); // Calculate convective precipitation (thunderstorms) CalculateInstabilityIndex(eqFronts); var FP = Earth.ATM.JetLevel.FP; Precip.Assign((r, c) => { var hgt = Earth.SFC.Height[r, c]; float h = 0; var hTop = Earth.ATM.TopLevel.H[r, c]; var hMid = Earth.ATM.MidLevel.H[r, c]; var hSea = Earth.ATM.SeaLevel.H[r, c]; if (hgt > SimConstants.LevelHeights[LevelType.TopLevel]) { h = 0.5f * hTop; } else if (hgt > SimConstants.LevelHeights[LevelType.MidLevel]) { h = 0.5f * (hTop + hMid); } else { h = 0.5f * (hSea + hMid); } var lidx = LIDX[r, c]; var gp = GP[r, c]; var gt = GT[r, c]; var fp = FP[r, c]; // Baric gradient precipitation var pRate = 0.5f * Math.Abs(gp); // Frontal precipitation var f = eqFronts[r, c]; var dx = (f > 0) ? 0.75f : 1.5f; var fRate = dx * 20 * Math.Abs(f); // Orographic precipitation var oRate = 0.3f * ((hgt >= 900) ? h : 0); // Convective precipitation var cRate = 0f; if (lidx < 0) { var lidxRate = Math.Abs(lidx); var mul = 1; if (lidx > 3) { mul = 2; } if (lidx > 5) { mul = 3; } if (lidx > 7) { mul = 4; } if (lidx > 9) { mul = 5; } cRate = fp * mul * Math.Abs(lidxRate); } var totalRate = (pRate + fRate + oRate + cRate) * h / 100; return(Math.Min(300, totalRate)); }); DenseMatrix SolidPrecip = MatrixFactory.Init(); for (int r = 0; r < SolidPrecip.RowCount; r++) { for (int c = 0; c < SolidPrecip.ColumnCount; c++) { var wl = WL[r, c]; var ts = TS[r, c]; var te = TE[r, c]; var cl = Precip[r, c]; var t01 = Earth.ATM.MidLevel.T[r, c]; var totalRain = RAIN[r, c]; var totalSnow = SNOW[r, c]; var fogMeltFactor = Math.Min(1, 1 - FOG[r, c] / 100); const float precipClThreshold = 10f; if (te >= -10f || cl <= precipClThreshold) { if (te >= 0) { // Accumulated soil moisture evaporation totalRain -= 0.5f * te * Earth.SnapshotLength; if (totalRain < 0) { totalRain = 0; } // Old snow cover is melting and transforming into water // OBS: Snow melts faster when we have fog var meltedSnow = Math.Min(totalSnow, 0.2f * (1 + fogMeltFactor) * te * Earth.SnapshotLength); totalSnow -= meltedSnow; if (totalSnow < 0) { totalSnow = 0; } // Consider melted snow as rain because it contributes to the total soil moisture totalRain += meltedSnow; } else { // Old snow cover is slowly compacting due to daytime melt / night time freeze totalSnow -= 0.025f * (1 + fogMeltFactor) * Earth.SnapshotLength; if (totalSnow < 0) { totalSnow = 0; } } } DaysSinceLastRainFall[r, c] = (DaysSinceLastRainFall[r, c] + Earth.SnapshotDivFactor); DaysSinceLastSnowFall[r, c] = (DaysSinceLastSnowFall[r, c] + Earth.SnapshotDivFactor); float actualPrecipRate = (cl - precipClThreshold); if (actualPrecipRate > 0) { var unitPrecipFall = actualPrecipRate * Earth.SnapshotDivFactor; PrecipTypeComputer <float> .Compute( // Actual temperatures te, ts, t01, // Boundary temperatures as read from simulation parameters SimulationParameters.Instance, // Computed precip type: snow () => { totalSnow += 0.3f * unitPrecipFall; SolidPrecip[r, c] = 1; DaysSinceLastSnowFall[r, c] = 0; return(0); }, // Computed precip type: rain () => { totalRain += unitPrecipFall; DaysSinceLastRainFall[r, c] = 0; return(0); }, // Computed precip type: freezing rain () => { totalSnow += 0.1f * unitPrecipFall; totalRain += 0.9f * unitPrecipFall; SolidPrecip[r, c] = 1; DaysSinceLastSnowFall[r, c] = 0; return(0); }, // Computed precip type: sleet () => { totalSnow += 0.2f * unitPrecipFall; totalRain += 0.8f * unitPrecipFall; SolidPrecip[r, c] = 1; DaysSinceLastSnowFall[r, c] = 0; return(0); } ); } if (totalSnow < 0 || // Snow does not accumulate on a water surface if water is not frozen (wl != 0 && ts > 0)) { totalSnow = 0; } if (totalRain < 0 || // Rain water does not accumulate on a water surface wl != 0) { totalRain = 0; } RAIN[r, c] = totalRain; SNOW[r, c] = totalSnow; } } ; Earth.SFC.BLIZZARD.Assign((r, c) => { var wind = WIND[r, c]; var cl = Precip[r, c] / 20f; bool solidPrecip = (SolidPrecip[r, c] != 0); if (solidPrecip) { return(Math.Abs(cl * wind)); } return(0); }); Earth.SFC.ALBEDO.Assign((r, c) => { var wl = WL[r, c]; var defAlbedo = DEF_ALBEDO[r, c]; //if (wl == 0) { var snowAlbedo = 0f; var rainAlbedo = 0f; if (SNOW[r, c] > 3f) { snowAlbedo = SNOW[r, c] + 20f * Math.Max(0, 5 - DaysSinceLastSnowFall[r, c]); } if (RAIN[r, c] >= 10f) { rainAlbedo = 0.5f * RAIN[r, c] + 10f * Math.Max(0, 3 - DaysSinceLastRainFall[r, c]); } var total = Math.Min(100f, defAlbedo + snowAlbedo + rainAlbedo); return(total); //return Math.Max(total, defAlbedo); } //return defAlbedo; }); }
private void DoReloadModel(string fieldDataFile, bool isWindMap) { // Create the plot model PlotModel model = this.Model; model.PlotMargins = new OxyThickness(30, 0, 60, 30); model.Axes.Clear(); model.Series.Clear(); model.Annotations.Clear(); string fileTitle = Path.GetFileNameWithoutExtension(fieldDataFile); this.FileTitle = fileTitle; WeatherDataPalette wdp = WeatherDataPaletteFactory.GetPaletteForDataFile(fieldDataFile); bool contours = wdp.ShowContours; bool heatmap = wdp.ShowHeatmap; bool precipitationMap = false; model.Title = string.Format("{0}: {1} [{2}]{3}", App.ControlPanelModel.SelectedViewport.Name, App.ControlPanelModel.SelectedDataType.Value, fileTitle, App.ControlPanelModel.SelectedDataType.Comments); DenseMatrix m = null; int minLon = App.ControlPanelModel.SelectedViewport.MinLon.Round(); int maxLon = App.ControlPanelModel.SelectedViewport.MaxLon.Round(); int minLat = App.ControlPanelModel.SelectedViewport.MinLat.Round(); int maxLat = App.ControlPanelModel.SelectedViewport.MaxLat.Round(); var fieldMatrix = FileSupport.LoadSubMatrixFromFile(fieldDataFile, minLon, maxLon, minLat, maxLat); bool interpolate = (fieldMatrix.RowCount < 10); if (interpolate) { fieldMatrix = fieldMatrix.Interpolate(); } float[,] data = null; float[,] data2 = null; float actualOffset = 0; if (wdp.ShowHeatmap) { float fOffset = (float)App.ControlPanelModel.Offset / 100; float delta = wdp.MinMax.Delta; if (wdp.GetType() == typeof(C_00_Palette)) { delta = 100; } actualOffset = delta * fOffset; } if (wdp.GetType() == typeof(C_00_Palette)) { // It's a map of the precipitation precipitationMap = true; string t01File = fieldDataFile.Replace("C_00", "T_01"); string teFile = fieldDataFile.Replace("C_00", "T_TE"); string tsFile = fieldDataFile.Replace("C_00", "T_TS"); DenseMatrix T01 = FileSupport.LoadSubMatrixFromFile(t01File, minLon, maxLon, minLat, maxLat); DenseMatrix TE = FileSupport.LoadSubMatrixFromFile(teFile, minLon, maxLon, minLat, maxLat); DenseMatrix TS = FileSupport.LoadSubMatrixFromFile(tsFile, minLon, maxLon, minLat, maxLat); DenseMatrix C00 = fieldMatrix; if (interpolate) { T01 = T01.Interpolate(); TE = TE.Interpolate(); TS = TS.Interpolate(); } float sRain = 0; float sSnow = 300; float sSleet = 600; float sFreezingRain = 900; data2 = C00.Transpose().ToArray(); m = DenseMatrix.Create(C00.RowCount, C00.ColumnCount, (r, c) => { float cl = Math.Abs(C00[r, c]) + actualOffset; if (cl <= 0) { cl = 0; } if (cl >= 100) { cl = 100; } float t01 = T01[r, c]; float te = TE[r, c]; float ts = TS[r, c]; float precipClThreshold = 10f; float actualPrecipRate = (cl - precipClThreshold); if (actualPrecipRate >= 0) { return(PrecipTypeComputer <float> .Compute( // Actual temperatures te, ts, t01, // Boundary temperatures as read from simulation parameters SimulationParameters.Instance, // Computed precip type: snow () => (cl + sSnow), // Computed precip type: rain () => (cl + sRain), // Computed precip type: freezing rain () => (cl + sFreezingRain), // Computed precip type: sleet () => (cl + sSleet) )); } else if (cl > 5) { // Cloudy but without precipitation. return(5); } // Sunny return(0); }); } else { m = DenseMatrix.Create(fieldMatrix.RowCount, fieldMatrix.ColumnCount, (r, c) => fieldMatrix[r, c]); m.ADD(actualOffset); } Range <float> minMax = wdp.MinMax; float lineSpacing = wdp.LineSpacing; m = m.MIN(minMax.Max).MAX(minMax.Min); data = m.Transpose().ToArray(); float step = interpolate ? 0.5f : 1; List <float> cols = new List <float>(); for (float i = minLon; i <= maxLon; i += step) { cols.Add(i); } List <float> rows = new List <float>(); for (float i = maxLat; i >= minLat; i -= step) { rows.Add(i); } List <float> levels = new List <float>(); for (float i = wdp.MinMax.Min; i <= wdp.MinMax.Max; i += wdp.LineSpacing) { levels.Add(i); } var pal = OxyPalette.Interpolate(levels.Count, wdp.ColorSteps.ToArray()); List <OxyColor> lineColors = new List <OxyColor>(); foreach (OxyColor c in wdp.ColorSteps) { if (heatmap) { switch (wdp.LineColor.ColorMode) { case Views.LineColorMode.FixedColor: lineColors.Add(wdp.LineColor.Color); break; case Views.LineColorMode.Best_Contrast: lineColors.Add(c.Complementary()); break; case Views.LineColorMode.Black_And_White: { System.Drawing.Color cw = System.Drawing.Color.FromArgb(c.R, c.G, c.B); float br = cw.GetBrightness(); if (br < 0.5f) { lineColors.Add(OxyColors.White); } else { lineColors.Add(OxyColors.Black); } } break; } } else { lineColors.Add(c); } } if (isWindMap) { this.FileTitle += "_WINDMAP"; var D = (App.ControlPanelModel.SelectedViewport.MaxLon - App.ControlPanelModel.SelectedViewport.MinLon); float hf = 1; if (D > 200) { hf = 0.45f; } else if (D > 20) { hf = 0.55f; } else { hf = 1; } float sf = 0.9f * hf; DenseMatrix[] gr = fieldMatrix.ToWindComponents(); float[,] dataX = gr[Direction.X].ToArray(); float[,] dataY = gr[Direction.Y].ToArray(); int rowCount = dataX.GetLength(0); int colCount = dataX.GetLength(1); for (int r = 0; r < rowCount; r++) { for (int c = 0; c < colCount; c++) { float x = c + App.ControlPanelModel.SelectedViewport.MinLon; float y = App.ControlPanelModel.SelectedViewport.MaxLat - r; float dx = dataX[r, c]; float dy = -dataY[r, c]; int mod = (int)Math.Sqrt(dx * dx + dy * dy); LineSeries line = new LineSeries(); line.Points.Add(new DataPoint(x, y)); line.Points.Add(new DataPoint(x + dx, y + dy)); line.StrokeThickness = 1; if (mod < 2) { line.Color = OxyColors.Green; line.StrokeThickness = 2 * hf; } else if (mod < 5) { line.Color = OxyColors.Red; line.StrokeThickness = 2.5 * hf; } else { line.Color = OxyColors.Magenta; line.StrokeThickness = 3 * hf; } model.Series.Add(line); ArrowAnnotation arrow = new ArrowAnnotation(); var edy = Math.Min(dy, 2); arrow.StartPoint = new DataPoint(x + sf * dx, y + sf * edy); arrow.EndPoint = new DataPoint(x + dx, y + edy); arrow.Color = line.Color; arrow.StrokeThickness = line.StrokeThickness; arrow.HeadWidth = 1.5 * line.StrokeThickness; arrow.HeadLength = 3 * line.StrokeThickness; model.Annotations.Add(arrow); //goto MapFeatures; } } } else { if (heatmap) { if (precipitationMap) { HeatMapSeriesEx cloudMapSeries = new HeatMapSeriesEx { Data = data.ToDoubleArray(), X0 = cols[0], X1 = cols[cols.Count - 1], Y0 = rows[0], Y1 = rows[rows.Count - 1], }; model.Series.Add(cloudMapSeries); } else { OxyPlot.Series.HeatMapSeries heatmapSeries = new OxyPlot.Series.HeatMapSeries { Data = data.ToDoubleArray(), X0 = cols[0], X1 = cols[cols.Count - 1], Y0 = rows[0], Y1 = rows[rows.Count - 1], }; model.Series.Add(heatmapSeries); } } if (contours) { OxyPlot.Series.ContourSeries contour = new OxyPlot.Series.ContourSeries { ColumnCoordinates = cols.ToArray().ToDoubleArray(), RowCoordinates = rows.ToArray().ToDoubleArray(), ContourLevels = levels.ToArray().ToDoubleArray(), ContourColors = lineColors.ToArray(), // Same # elements as the levels' array Data = (data2 == null) ? data.ToDoubleArray() : data2.ToDoubleArray(), LabelBackground = OxyColors.Transparent, ContourLevelStep = wdp.LineSpacing, StrokeThickness = wdp.LineWidth, FontSize = 15, FontWeight = 500, }; model.Series.Add(contour); } } MapFeatures: // Always do this last. AddMapFeatures(model, wdp, pal, isWindMap); }