Ejemplo n.º 1
0
        /// <summary>
        /// Calculates the metalimnion boundaries
        /// </summary>
        /// <param name="dataset">The dataset to use</param>
        /// <param name="thermoclineDepths">The precalculated thermocline depths for the dataset</param>
        /// <param name="minimumMetalimionSlope">The minimum metalimnion slope</param>
        /// <returns></returns>
        public static Dictionary<DateTime, MetalimnionBoundariesDetails> CalculateMetalimnionBoundaries(Dataset dataset, Dictionary<DateTime, ThermoclineDepthDetails> thermoclineDepths, float minimumMetalimionSlope = 0.1f)
        {
            var metalimnionBoundaries = new Dictionary<DateTime, MetalimnionBoundariesDetails>();

            foreach (var timestamp in thermoclineDepths.Keys)
            {
                var depths = dataset.Sensors.Where(x => x.SensorType == "Water_Temperature" && x.CurrentState.Values.ContainsKey(timestamp)).Select(x => x.Elevation).Distinct().OrderBy(x => x).ToArray();

                var meanDepths = new float[depths.Length - 1];

                for (var i = 0; i < depths.Length - 1; i++)
                {
                    meanDepths[i] = (depths[i] + depths[i + 1]) / 2;
                }

                var metalimnionBoundary = new MetalimnionBoundariesDetails();

                var sortedDepths = meanDepths.Union(new[] { thermoclineDepths[timestamp].ThermoclineDepth }).OrderBy(x => x).ToArray();
                var sortedDepthsParent = meanDepths.Union(new[] { thermoclineDepths[timestamp].SeasonallyAdjustedThermoclineDepth }).OrderBy(x => x).ToArray();

                var points = new Point[meanDepths.Length];

                for (var i = 0; i < points.Length; i++)
                {
                    points[i] = new Point(meanDepths[i], thermoclineDepths[timestamp].DrhoDz[i]);
                }

                var slopes = Interpolate(points, sortedDepths).ToArray();
                var slopesParent = Interpolate(points, sortedDepthsParent).ToArray();

                var thermoclineIndex = Array.IndexOf(slopes.Select(x => x.X).ToArray(), thermoclineDepths[timestamp].ThermoclineDepth);
                var thermoclineIndexParent = Array.IndexOf(slopesParent.Select(x => x.X).ToArray(), thermoclineDepths[timestamp].SeasonallyAdjustedThermoclineDepth);

                #region Top

                metalimnionBoundary.Top = meanDepths[0];
                int k;
                for (k = thermoclineIndex; k > -1; k--)
                {
                    if (slopes[k].Y < minimumMetalimionSlope)
                    {
                        metalimnionBoundary.Top = sortedDepths[k];
                        break;
                    }
                }

                if (k == -1)
                    k = 0;

                if (thermoclineIndex - k > 1 && slopes[thermoclineIndex].Y > minimumMetalimionSlope)
                {
                    var outsidePoints = new List<Point>();
                    for (var j = k; j <= thermoclineIndex; j++)
                    {
                        outsidePoints.Add(new Point(slopes[j].Y, sortedDepths[j]));
                    }
                    metalimnionBoundary.Top = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                }

                #endregion

                #region Bottom

                metalimnionBoundary.Bottom = meanDepths.Last();

                for (k = thermoclineIndex; k < slopes.Length; k++)
                {
                    if (slopes[k].Y < minimumMetalimionSlope)
                    {
                        metalimnionBoundary.Bottom = sortedDepths[k];
                        break;
                    }
                }

                if (k == slopes.Length)
                    k--;

                if (k - thermoclineIndex > 1 && slopes[thermoclineIndex].Y > minimumMetalimionSlope)
                {
                    var outsidePoints = new List<Point>();
                    for (var j = thermoclineIndex; j <= k; j++)
                    {
                        outsidePoints.Add(new Point(slopes[j].Y, sortedDepths[j]));
                    }
                    metalimnionBoundary.Bottom = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                }

                #endregion

                #region IfParent

                if (thermoclineDepths[timestamp].HasSeaonallyAdjusted)
                {
                    #region Top

                    metalimnionBoundary.SeasonallyAdjustedTop = meanDepths[0];
                    int m;
                    for (m = thermoclineIndexParent; m > -1; m--)
                    {
                        if (slopesParent[m].Y < minimumMetalimionSlope)
                        {
                            metalimnionBoundary.SeasonallyAdjustedTop = sortedDepthsParent[m];
                            break;
                        }
                    }

                    if (m == -1)
                        m = 0;

                    if (thermoclineIndexParent - m > 0 && slopesParent[thermoclineIndexParent].Y > minimumMetalimionSlope)
                    {
                        var outsidePoints = new List<Point>();
                        for (var j = m; j <= thermoclineIndexParent; j++)
                        {
                            outsidePoints.Add(new Point(slopesParent[j].Y, sortedDepthsParent[j]));
                        }
                        metalimnionBoundary.SeasonallyAdjustedTop = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                    }

                    #endregion

                    #region Bottom

                    metalimnionBoundary.SeasonallyAdjustedBottom = meanDepths.Last();

                    for (m = thermoclineIndexParent; m < slopesParent.Length; m++)
                    {
                        if (slopesParent[m].Y < minimumMetalimionSlope)
                        {
                            metalimnionBoundary.SeasonallyAdjustedBottom = sortedDepthsParent[m];
                            break;
                        }
                    }

                    if (m == slopes.Length)
                        m--;

                    if (m - thermoclineIndexParent > 0 && slopesParent[thermoclineIndexParent].Y > minimumMetalimionSlope)
                    {
                        var outsidePoints = new List<Point>();
                        for (var j = thermoclineIndexParent; j <= m; j++)
                        {
                            outsidePoints.Add(new Point(slopesParent[j].Y, sortedDepthsParent[j]));
                        }
                        metalimnionBoundary.SeasonallyAdjustedBottom = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                    }

                    #endregion
                }
                else
                {
                    metalimnionBoundary.NoSeasonalFound();
                }

                #endregion

                metalimnionBoundaries[timestamp] = metalimnionBoundary;
            }

            return metalimnionBoundaries;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Calculates the metalimnion boundaries
        /// </summary>
        /// <param name="dataset">The dataset to use</param>
        /// <param name="thermoclineDepths">The precalculated thermocline depths for the dataset</param>
        /// <param name="minimumMetalimionSlope">The minimum metalimnion slope</param>
        /// <returns></returns>
        public static Dictionary <DateTime, MetalimnionBoundariesDetails> CalculateMetalimnionBoundaries(Dataset dataset, Dictionary <DateTime, ThermoclineDepthDetails> thermoclineDepths, float minimumMetalimionSlope = 0.1f)
        {
            var metalimnionBoundaries = new Dictionary <DateTime, MetalimnionBoundariesDetails>();

            foreach (var timestamp in thermoclineDepths.Keys)
            {
                var depths = dataset.Sensors.Where(x => x.SensorType == "Water_Temperature" && x.CurrentState.Values.ContainsKey(timestamp)).Select(x => x.Elevation).Distinct().OrderBy(x => x).ToArray();

                var meanDepths = new float[depths.Length - 1];

                for (var i = 0; i < depths.Length - 1; i++)
                {
                    meanDepths[i] = (depths[i] + depths[i + 1]) / 2;
                }

                var metalimnionBoundary = new MetalimnionBoundariesDetails();

                var sortedDepths       = meanDepths.Union(new[] { thermoclineDepths[timestamp].ThermoclineDepth }).OrderBy(x => x).ToArray();
                var sortedDepthsParent = meanDepths.Union(new[] { thermoclineDepths[timestamp].SeasonallyAdjustedThermoclineDepth }).OrderBy(x => x).ToArray();

                var points = new Point[meanDepths.Length];

                for (var i = 0; i < points.Length; i++)
                {
                    points[i] = new Point(meanDepths[i], thermoclineDepths[timestamp].DrhoDz[i]);
                }

                var slopes       = Interpolate(points, sortedDepths).ToArray();
                var slopesParent = Interpolate(points, sortedDepthsParent).ToArray();

                var thermoclineIndex       = Array.IndexOf(slopes.Select(x => x.X).ToArray(), thermoclineDepths[timestamp].ThermoclineDepth);
                var thermoclineIndexParent = Array.IndexOf(slopesParent.Select(x => x.X).ToArray(), thermoclineDepths[timestamp].SeasonallyAdjustedThermoclineDepth);

                #region Top

                metalimnionBoundary.Top = meanDepths[0];
                int k;
                for (k = thermoclineIndex; k > -1; k--)
                {
                    if (slopes[k].Y < minimumMetalimionSlope)
                    {
                        metalimnionBoundary.Top = sortedDepths[k];
                        break;
                    }
                }

                if (k == -1)
                {
                    k = 0;
                }

                if (thermoclineIndex - k > 1 && slopes[thermoclineIndex].Y > minimumMetalimionSlope)
                {
                    var outsidePoints = new List <Point>();
                    for (var j = k; j <= thermoclineIndex; j++)
                    {
                        outsidePoints.Add(new Point(slopes[j].Y, sortedDepths[j]));
                    }
                    metalimnionBoundary.Top = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                }

                #endregion

                #region Bottom

                metalimnionBoundary.Bottom = meanDepths.Last();

                for (k = thermoclineIndex; k < slopes.Length; k++)
                {
                    if (slopes[k].Y < minimumMetalimionSlope)
                    {
                        metalimnionBoundary.Bottom = sortedDepths[k];
                        break;
                    }
                }

                if (k == slopes.Length)
                {
                    k--;
                }

                if (k - thermoclineIndex > 1 && slopes[thermoclineIndex].Y > minimumMetalimionSlope)
                {
                    var outsidePoints = new List <Point>();
                    for (var j = thermoclineIndex; j <= k; j++)
                    {
                        outsidePoints.Add(new Point(slopes[j].Y, sortedDepths[j]));
                    }
                    metalimnionBoundary.Bottom = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                }

                #endregion

                #region IfParent

                if (thermoclineDepths[timestamp].HasSeaonallyAdjusted)
                {
                    #region Top

                    metalimnionBoundary.SeasonallyAdjustedTop = meanDepths[0];
                    int m;
                    for (m = thermoclineIndexParent; m > -1; m--)
                    {
                        if (slopesParent[m].Y < minimumMetalimionSlope)
                        {
                            metalimnionBoundary.SeasonallyAdjustedTop = sortedDepthsParent[m];
                            break;
                        }
                    }

                    if (m == -1)
                    {
                        m = 0;
                    }

                    if (thermoclineIndexParent - m > 0 && slopesParent[thermoclineIndexParent].Y > minimumMetalimionSlope)
                    {
                        var outsidePoints = new List <Point>();
                        for (var j = m; j <= thermoclineIndexParent; j++)
                        {
                            outsidePoints.Add(new Point(slopesParent[j].Y, sortedDepthsParent[j]));
                        }
                        metalimnionBoundary.SeasonallyAdjustedTop = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                    }

                    #endregion

                    #region Bottom

                    metalimnionBoundary.SeasonallyAdjustedBottom = meanDepths.Last();

                    for (m = thermoclineIndexParent; m < slopesParent.Length; m++)
                    {
                        if (slopesParent[m].Y < minimumMetalimionSlope)
                        {
                            metalimnionBoundary.SeasonallyAdjustedBottom = sortedDepthsParent[m];
                            break;
                        }
                    }

                    if (m == slopes.Length)
                    {
                        m--;
                    }

                    if (m - thermoclineIndexParent > 0 && slopesParent[thermoclineIndexParent].Y > minimumMetalimionSlope)
                    {
                        var outsidePoints = new List <Point>();
                        for (var j = thermoclineIndexParent; j <= m; j++)
                        {
                            outsidePoints.Add(new Point(slopesParent[j].Y, sortedDepthsParent[j]));
                        }
                        metalimnionBoundary.SeasonallyAdjustedBottom = (float)Interpolate(outsidePoints.ToArray(), new[] { minimumMetalimionSlope })[0].Y;
                    }

                    #endregion
                }
                else
                {
                    metalimnionBoundary.NoSeasonalFound();
                }

                #endregion

                metalimnionBoundaries[timestamp] = metalimnionBoundary;
            }

            return(metalimnionBoundaries);
        }