Example #1
0
        /// <summary>
        /// Automatically selects approppriate linear integrator by axis data
        /// </summary>
        /// <param name="context"></param>
        /// <param name="axisArrayName"></param>
        /// <returns></returns>
        public static async Task <IGridAxisAvgProcessing> SmartConstructAsync(IStorageContext context, string axisArrayName)
        {
            DoubleEpsComparer epsComparer = new DoubleEpsComparer(1e-5);
            var axis = await context.GetDataAsync(axisArrayName);

            double firstElem  = Convert.ToDouble(axis.GetValue(0));
            double secondElem = Convert.ToDouble(axis.GetValue(1));
            double lastElem   = Convert.ToDouble(axis.GetValue(axis.Length - 1));

            if (epsComparer.Compare(firstElem + 360.0, lastElem) == 0)
            {
                //longitudes cycled, last and ferst elemets repeated
                return(new LinearCycledLonsAvgProcessing(axis, true));
            }
            else if (epsComparer.Compare(firstElem + 360.0 - (secondElem - firstElem), lastElem) == 0)
            {
                //longitudes cycled
                return(new LinearCycledLonsAvgProcessing(axis, false));
            }
            else
            {
                return(new LinearGridIntegrator(axis));
            }
        }
        //the method is not static as the class is used in typed parmeters
        public double[] GetWeights(double[] grid, double min, double max, out int start, out int stop, DoubleEpsComparer dec = null)
        {
            if (DoubleEpsComparer.Instance.Compare(min, max) > 0)
            {
                throw new ArgumentException("Min should be less or equal to max");
            }

            if (grid[0] > grid[grid.Length - 1])
            {
                throw new ArgumentException("Grid is not ascending. LinearWeightsProvider can't be used");
            }

            if (grid.Length < 2)
            {
                if (grid.Length == 1 && (Math.Abs(max - min) < 0.0000000000001) && (Math.Abs(grid[0] - min) < 0.00001))
                {
                    start = 0;
                    stop  = 0;
                    return(new double[] { 1.0 });
                }
                else
                {
                    throw new ArgumentException("Grid length must be at least 2");
                }
            }

            DoubleEpsComparer effDec = (dec == null) ? DoubleEpsComparer.Instance : dec;

            if (effDec.Compare(min, grid[0]) < 0)
            {
                start = stop = 0;
                return(new double[0]);
            }
            if (effDec.Compare(max, grid[grid.Length - 1]) > 0)
            //    max = grid[grid.Length - 1];
            {
                start = stop = 0;
                return(new double[0]);
            }

            bool leftBoundUnexact = false, rightBoundUnexact = false;

            int imin = Array.BinarySearch <double>(grid, (double)min, effDec);

            if (imin < 0)
            {
                imin             = ~imin - 1;
                leftBoundUnexact = true;
            }

            int imax = Array.BinarySearch <double>(grid, imin, grid.Length - imin, (double)max, effDec);

            if (imax < 0)
            {
                imax = ~imax;
                rightBoundUnexact = true;
            }
            System.Diagnostics.Debug.Assert(imax < grid.Length);


            double[] w = new double[imax - imin + 1];
            w.Initialize();

            if (imax == imin)
            {
                w[0]  = 1.0;
                start = stop = imin;
            }
            else if (imax == imin + 1) //inside single grid interval
            {
                double x_k = grid[imin];
                double x_m = grid[imax];

                double k;

                double x_m_k = x_m - x_k;

                k    = 0.5 * (min + max - 2.0 * x_k) / x_m_k; //both for min=max and non-zero length intervals
                w[1] = k;
                w[0] = 1 - k;
            }
            else
            {
                double divider    = (max - min) * 2.0;
                double multiplier = 1.0 / divider;

                int solidIntervals_imin   = leftBoundUnexact ? imin + 1 : imin;
                int solidIntervals_imax   = rightBoundUnexact ? imax - 1 : imax;
                int solid_imin_output_idx = leftBoundUnexact ? 1 : 0;
                int solid_imax_output_idx = rightBoundUnexact ? w.Length - 2 : w.Length - 1;
                if (solidIntervals_imax > solidIntervals_imin) //full covered intervals
                {
                    w[solid_imin_output_idx] = (grid[solidIntervals_imin + 1] - grid[solidIntervals_imin]) * multiplier;

                    for (int i = 1; i < solidIntervals_imax - solidIntervals_imin; i++)
                    {
                        w[solid_imin_output_idx + i] = (grid[solidIntervals_imin + i + 1] - grid[solidIntervals_imin + i - 1]) * multiplier;
                    }

                    w[solid_imax_output_idx] = (grid[solidIntervals_imax] - grid[solidIntervals_imax - 1]) * multiplier;
                }
                if (leftBoundUnexact) //partially covered intervals, if present
                {
                    double x_0 = grid[imin + 1];
                    double x_a = grid[imin];
                    double x_l = min;

                    double k = (x_l + x_0 - 2.0 * x_a) / (x_0 - x_a);

                    double width = x_0 - x_l;

                    w[0]  = (2.0 - k) * width * multiplier;
                    w[1] += k * width * multiplier;
                }
                if (rightBoundUnexact)
                {
                    double x_r = max;
                    double x_z = grid[imax];
                    double x_n = grid[imax - 1];

                    double k = (x_n + x_r - 2.0 * x_n) / (x_z - x_n);

                    double width = x_r - x_n;

                    w[solid_imax_output_idx]    += (2.0 - k) * width * multiplier;
                    w[solid_imax_output_idx + 1] = k * width * multiplier;
                }
            }

            System.Diagnostics.Debug.Assert(Math.Abs(w.Sum() - 1.0) < 1e-3); // test for unbiasness

            start = imin;
            stop  = imax;
            return(w);
        }