/// <summary>
        /// Main method which performs a calculation
        /// </summary>
        /// <param name="calculationType">Name of the calculation method</param>
        /// <param name="results">Containier where result variables are supposed to be saved</param>
        /// <param name="variablesAtAllStep">Container of variables at each calculation step</param>
        /// <param name="async">Flag which specifies if it is calculated in parallel mode</param>
        /// <returns>Calculation time</returns>
        public double Calculate(CalculationTypeName calculationType, out List <DEVariable> results, List <List <DEVariable> > variablesAtAllStep = null)
        {
            // Checking the correctness of input variables
            DifferentialEquationSystemHelpers.CheckVariables(this.ExpressionSystem, this.LeftVariables, this.TimeVariable, this.Tau, this.TEnd);

            Func <List <List <DEVariable> >, List <DEVariable> > F = this.DefineSuitableMethod(calculationType);

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            results = F(variablesAtAllStep);
            stopwatch.Stop();

            return(stopwatch.ElapsedMilliseconds / 1000.0);
        }
        /// <summary>
        /// Method fills the sheet with calculation results
        /// </summary>
        /// <param name="worksheet">Worksheet to save the results there</param>
        /// <param name="calculationTypeName">CalculationType</param>
        /// <param name="result">Container with result variables</param>
        /// <param name="allVariables">Cantainer with variables values for each time step</param>
        /// <param name="calcTime">Time reqiured for calculation</param>
        private static void SetCalculationResults(Excel.Worksheet worksheet, CalculationTypeName calculationTypeName,
                                                  List <Variable> leftVariables, List <DEVariable> result, List <List <DEVariable> > allVariables, double calcTime)
        {
            worksheet.Name = calculationTypeName.ToString();
            int rowIndex    = 1;
            int columnIndex = 1;

            for (int i = 0; i < result.Count; i++)
            {
                worksheet.Cells[rowIndex, columnIndex]     = $"{result[i].Name} = ";
                worksheet.Cells[rowIndex, columnIndex + 1] = result[i].Value;
                rowIndex++;
            }

            rowIndex++;
            worksheet.Cells[rowIndex, columnIndex]     = "Calculation time = ";
            worksheet.Cells[rowIndex, columnIndex + 1] = calcTime;
            rowIndex++;

            if (allVariables != null)
            {
                rowIndex++;
                worksheet.Cells[rowIndex, columnIndex] = "Detailed results";
                rowIndex++;

                for (int i = 0; i < allVariables[0].Count; i++)
                {
                    worksheet.Cells[rowIndex, columnIndex + i] = allVariables[0][i].Name;
                }

                rowIndex++;

                string leftTopCellforChart = GetExcelColumnName(columnIndex) + rowIndex.ToString();
                string horinzontalAxisTop  = GetExcelColumnName(columnIndex + allVariables[0].Count - 1) + rowIndex.ToString();
                int    idxStart            = rowIndex;

                for (int i = 0; i < allVariables.Count; i++)
                {
                    for (int j = 0; j < allVariables[0].Count; j++)
                    {
                        worksheet.Cells[rowIndex, columnIndex + j] = allVariables[i][j].Value;
                    }

                    rowIndex++;
                }

                string             rightDownCellForChart   = GetExcelColumnName(columnIndex + allVariables[0].Count - 2) + (allVariables.Count - 1 + idxStart).ToString();
                string             horizontalAlignmentDown = GetExcelColumnName(columnIndex + allVariables[0].Count - 1) + (allVariables.Count - 1 + idxStart).ToString();
                Excel.Range        chartRange;
                Excel.Range        horizontalAlignmentRange;
                Excel.ChartObjects xlCharts  = (Excel.ChartObjects)worksheet.ChartObjects(Type.Missing);
                Excel.ChartObject  mychart   = xlCharts.Add(10, 80, 500, 450);
                Excel.Chart        chartPage = mychart.Chart;

                chartRange = worksheet.get_Range(leftTopCellforChart, rightDownCellForChart);
                chartPage.SetSourceData(chartRange);
                chartPage.ChartType      = Excel.XlChartType.xlLine;
                horizontalAlignmentRange = worksheet.get_Range(horinzontalAxisTop, horizontalAlignmentDown);

                chartPage.SeriesCollection(1).XValues = horizontalAlignmentRange;

                for (int i = 0; i < leftVariables.Count; i++)
                {
                    chartPage.SeriesCollection(i + 1).Name = leftVariables[i].Name;
                }
            }
        }
        /// <summary>
        /// Method Identifies a correct method for Differential equation system calculation
        /// </summary>
        /// <param name="calculationType">Method name</param>
        /// <param name="async">Flag which signals whether the calculation is executed in parallel mode</param>
        /// <returns>A correct method for Differential equation system calculation</returns>
        private Func <List <List <DEVariable> >, List <DEVariable> > DefineSuitableMethod(CalculationTypeName calculationType)
        {
            switch (calculationType)
            {
            case CalculationTypeName.Euler: return(this.EulerSync);

            case CalculationTypeName.EulerAsyc: return(this.EulerAsync);

            case CalculationTypeName.ForecastCorrection: return(this.ForecastCorrectionSync);

            case CalculationTypeName.ForecastCorrectionAsync: return(this.ForecastCorrectionAsync);

            case CalculationTypeName.RK2: return(this.RK2Sync);

            case CalculationTypeName.RK2Async: return(this.RK2Async);

            case CalculationTypeName.RK4: return(this.RK4Sync);

            case CalculationTypeName.RK4Async: return(this.RK4Async);

            case CalculationTypeName.AdamsExtrapolationOne: return(this.AdamsExtrapolationOneSync);

            case CalculationTypeName.AdamsExtrapolationOneAsync: return(this.AdamsExtrapolationOneAsync);

            case CalculationTypeName.AdamsExtrapolationTwo: return(this.AdamsExtrapolationTwoSync);

            case CalculationTypeName.AdamsExtrapolationTwoAsync: return(this.AdamsExtrapolationTwoAsync);

            case CalculationTypeName.AdamsExtrapolationThree: return(this.AdamsExtrapolationThreeSync);

            case CalculationTypeName.AdamsExtrapolationThreeAsync: return(this.AdamsExtrapolationThreeAsync);

            case CalculationTypeName.AdamsExtrapolationFour: return(this.AdamsExtrapolationFourSync);

            case CalculationTypeName.AdamsExtrapolationFourAsync: return(this.AdamsExtrapolationFourAsync);

            case CalculationTypeName.Miln: return(this.MilnSync);

            case CalculationTypeName.MilnAsync: return(this.MilnAsync);

            default: throw new ArgumentException($"No methods for this type '{calculationType.ToString()}' were found");
            }
        }