public LayerSolver(LayerData prevLayer, NumericalParameters numericalParameters)
        {
            width = prevLayer.Width;
            height = prevLayer.Height;
            thickness = prevLayer.Thickness;

            this.prevLayer = prevLayer;
            this.oldLayer = prevLayer;
            this.nextLayer = new LayerData(width, height, thickness);
            this.intermediateLayer1 = new LayerData(width, height, thickness);
            this.intermediateLayer2 = new LayerData(width, height, thickness);

            this.numPar = numericalParameters;
            this.cp = (numericalParameters.Gamma - 1) / (numericalParameters.Gamma * numericalParameters.Re);

            //Параметры колонны
            Ax = Az = 0;
            Dx = width;
            Dz = thickness;
            //if (Nz = 50, Ny = Nx = 40) =>
            Bx = (int)(numericalParameters.Nx / 2.0 - numericalParameters.Nx / 4.0);    //10
            Cx = (int)(numericalParameters.Nx / 2.0 + numericalParameters.Nx / 4.0);    //30
            Bz = (int)(numericalParameters.Nz / 2.0 - numericalParameters.Nz / 5.0);    //15
            Cz = (int)(numericalParameters.Nz / 2.0 + numericalParameters.Nz / 5.0);    //35
        }
		public FluidCurrentSolver(NumericalParameters modellingParams)
		{
			this.modellingParams = modellingParams;

			prevData = new LayerData(modellingParams.Nx, modellingParams.Ny, modellingParams.Nz);

			//Задаем начальные условия. Жидкость покоится, температура постоянна по всему объему
			prevData.U.InitializeData(0);
			prevData.V.InitializeData(0);
			prevData.W.InitializeData(0);
			prevData.T.InitializeData(1.0);
			prevData.Div.InitializeData(0);
		}
 private void SetZero(int i, int j, int startIndex, int endIndex, Dimensions dimension, LayerData layer)
 {
     int length = endIndex - startIndex;
     double[] zeroArray = new double[length];
     for (int k = 0; k < length; k++)
     {
         zeroArray[k] = 0;
     }
     layer.U.SetColumn(i, j, startIndex, dimension, zeroArray);
     layer.V.SetColumn(i, j, startIndex, dimension, zeroArray);
     layer.W.SetColumn(i, j, startIndex, dimension, zeroArray);
     layer.T.SetColumn(i, j, startIndex, dimension, zeroArray);
 }
		public void SolveAll(string ctorString)
		{
			//dataSet = ProxyDataSet.Open("msds:nc?file=../../../temp.nc");
			dataSet = ProxyDataSet.Open("msds:memory");

			//Инициализируем DataSet
			Variable X = dataSet.AddVariable<double>("X", "x");
			Variable Y = dataSet.AddVariable<double>("Y", "y");
			Variable Z = dataSet.AddVariable<double>("Z", "z");
			Variable time = dataSet.AddVariable<double>("Time", "t");

			Variable u = dataSet.AddVariable<double>("U velocity", "x", "y", "z", "t");
			Variable v = dataSet.AddVariable<double>("V velocity", "x", "y", "z", "t");
			Variable w = dataSet.AddVariable<double>("W velocity", "x", "y", "z", "t");
			Variable T = dataSet.AddVariable<double>("Temperature", "x", "y", "z", "t");
			Variable div = dataSet.AddVariable<double>("Divergence", "x", "y", "z", "t");
			dataSet.Commit();

			double[] wArr = new double[modellingParams.Nx];
			for (int i = 0; i < modellingParams.Nx; i++)
			{
				wArr[i] = i * modellingParams.Dx;
			}
			X.PutData(wArr);
			wArr = new double[modellingParams.Ny];
			for (int i = 0; i < modellingParams.Ny; i++)
			{
				wArr[i] = i * modellingParams.Dy;
			}
			Y.PutData(wArr);
			wArr = new double[modellingParams.Nz];
			for (int i = 0; i < modellingParams.Nz; i++)
			{
				wArr[i] = i * modellingParams.Dz;
			}
			Z.PutData(wArr);

			//Инициализируем рассчетный модуль для слоя начальными условиями
			LayerSolver solver = new LayerSolver(prevData, modellingParams);
			u.Append(prevData.U.ToArray(), "t");
			v.Append(prevData.V.ToArray(), "t");
			w.Append(prevData.W.ToArray(), "t");
			T.Append(prevData.T.ToArray(), "t");
			div.Append(prevData.Div.ToArray(), "t");

			time.PutData(new double[1] { 0 });
			dataSet.Commit();

			//Основной рассчет
			for (int i = 1; i < modellingParams.Nt; i++)
			{
				LayerData result = solver.Solve(true);
				//Кладем данные в DataSet
				u.Append(result.U.ToArray(), "t");
				v.Append(result.V.ToArray(), "t");
				w.Append(result.W.ToArray(), "t");
				T.Append(result.T.ToArray(), "t");
				div.Append(result.Div.ToArray(), "t");
				time.Append(new double[1] { (double)i / modellingParams.Nt });
				dataSet.Commit();
				//Переходим на следующий слой
				solver = new LayerSolver(prevData, result, modellingParams);
				prevData = result;

				double temp = 0;
				int count = 0;
				for (int ii = 1; ii < result.Width; ii++)
				{
					for (int jj = 1; jj < result.Height; jj++)
					{
						for (int kk = 1; kk < result.Thickness; kk++)
						{
							temp += result.Div[ii, jj, kk];
							count++;
						}
					}
				}
				temp = temp / count * modellingParams.Dx * modellingParams.Dy * modellingParams.Dz;

				Console.WriteLine((double)i / modellingParams.Nt * 100 + "% Error = " + temp);
			}
			dataSet.Commit();
		}
		public void PerformIteration(int i)
		{
			//Основной рассчет
			//for (int i = 1; i < modellingParams.Nt; i++)
			//{
			LayerData result = solver.Solve(true);
			//Кладем данные в DataSet
			u.Append(result.U.ToArray(), "t");
			v.Append(result.V.ToArray(), "t");
			w.Append(result.W.ToArray(), "t");
			T.Append(result.T.ToArray(), "t");
			div.Append(result.Div.ToArray(), "t");
			time.Append(new double[1] { (double)i / modellingParams.Nt });
			dataSet.Commit();
			//Переходим на следующий слой
			solver = new LayerSolver(prevData, result, modellingParams);
			prevData = result;

			double temp = 0;
			int count = result.Width * result.Height * result.Thickness;
			for (int ii = 1; ii < result.Width; ii++)
			{
				for (int jj = 1; jj < result.Height; jj++)
				{
					for (int kk = 1; kk < result.Thickness; kk++)
					{
						temp += result.Div[ii, jj, kk];
					}
				}
			}
			temp = temp / count * modellingParams.Dx * modellingParams.Dy * modellingParams.Dz;

			Console.WriteLine((double)i / modellingParams.Nt * 100 + "% Error = " + temp);
			//}
			//dataSet.Commit();
		}
        private void SolveColumnX(int i, int j, int startIndex, int endIndex, LayerData oldLayer, LayerData prevLayer, LayerData nextLayer, bool state)
        {
            DoubleMatrix3D u = new DoubleMatrix3D { FirstMatrix = oldLayer.U, SecondMatrix = prevLayer.U };
            DoubleMatrix3D v = new DoubleMatrix3D { FirstMatrix = oldLayer.V, SecondMatrix = prevLayer.V };
            DoubleMatrix3D w = new DoubleMatrix3D { FirstMatrix = oldLayer.W, SecondMatrix = prevLayer.W };
            DoubleMatrix3D T = new DoubleMatrix3D { FirstMatrix = oldLayer.T, SecondMatrix = prevLayer.T };

            int length = endIndex - startIndex;
            double[] downRow = new double[length];
            double[] middleRow = new double[length];
            double[] upperRow = new double[length];
            double[] f = new double[length];

            //Solving for U
            double h = 1.0 / (numPar.Re * numPar.Dx * numPar.Dx);
            for (int k = 1; k < length - 1; k++)
            {
                if (i == 0 || i == height - 1 || j == Az || j == Dz - 1)
                {
                    downRow[k] = 0.0;
                    middleRow[k] = 1.0;
                    upperRow[k] = 0.0;
                    f[k] = 0.0;
                }
                else
                {
                    downRow[k] = Auxiliaries.GetValue(u, startIndex + k, i, j) / (2 * numPar.Dx) - h;
                    middleRow[k] = 3.0 / numPar.Dt + 2.0 * h;
                    upperRow[k] = -Auxiliaries.GetValue(u, startIndex + k, i, j) / (2.0 * numPar.Dx) - h;
                    f[k] = 3.0 * prevLayer.U[startIndex + k, i, j] / numPar.Dt -
                            (Auxiliaries.GetValue(T, startIndex + k + 1, i, j) - Auxiliaries.GetValue(T, startIndex + k - 1, i, j)) / (2.0 * numPar.Dx);
                }
                if (column)
                    if ((j == Bz || j == Cz - 1) && (k >= Bx && k <= Cx - 1))
                    {
                        downRow[k] = 0.0;
                        middleRow[k] = 1.0;
                        upperRow[k] = 0.0;
                        f[k] = 0.0;
                    }
            }
            if (startIndex == Ax && i != 0 && i != height - 1 && j != Az && j != Dz - 1)
                f[0] = 1.0;
            else
                f[0] = 0.0;
            upperRow[0] = 0.0;
            middleRow[0] = 1.0;
            downRow[0] = 0.0;

            if (!state)
            {
                f[length - 1] = 0.0;
                upperRow[length - 1] = 0.0;
                middleRow[length - 1] = 1.0;
                downRow[length - 1] = 0.0;
            }
            else
            {
                f[length - 1] = 2.0 * prevLayer.U[length - 2, i, j] - prevLayer.U[length - 3, i, j];
                upperRow[length - 1] = 0.0;
                middleRow[length - 1] = 1.0;
                downRow[length - 1] = 0.0;
            }
            
            PurlinMatrix pmatrix = new PurlinMatrix(downRow, middleRow, upperRow);
            PurlinSolver pSolver = new PurlinSolver(pmatrix, f);

            double[] result = pSolver.Solve();
            nextLayer.U.SetColumn(i, j, startIndex, Dimensions.Width, result);

            //if (state)
            //    nextLayer.U[length - 1, i, j] = 2.0 * nextLayer.U[length - 2, i, j] - nextLayer.U[length - 3, i, j];

            //Solving for V
            for (int k = 1; k < length - 1; k++)
            {
                if (i == 0 || i == height - 1 || j == Az || j == Dz - 1)
                    f[k] = 0.0;
                else
                    f[k] = 3 * prevLayer.V[startIndex + k, i, j] / numPar.Dt;
                if (column)
                    if ((j == Bz || j == Cz - 1) && (k >= Bx && k <= Cx - 1))
                        f[k] = 0.0;
            }

            f[0] = 0.0;
            if (!state)
                f[length - 1] = 0.0;
            else
                f[length - 1] = 2.0 * prevLayer.V[length - 2, i, j] - prevLayer.V[length - 3, i, j];

            pSolver = new PurlinSolver(pmatrix, f);

            result = pSolver.Solve();
            nextLayer.V.SetColumn(i, j, startIndex, Dimensions.Width, result);

            //if (state)
            //    nextLayer.V[length - 1, i, j] = 2.0 * nextLayer.V[length - 2, i, j] - nextLayer.V[length - 3, i, j];

            //Solving for W
            for (int k = 1; k < length - 1; k++)
            {
                if (i == 0 || i == height - 1 || j == Az || j == Dz - 1)
                    f[k] = 0.0;
                else
                    f[k] = 3 * prevLayer.W[startIndex + k, i, j] / numPar.Dt;
                if (column)
                    if ((j == Bz || j == Cz - 1) && (k >= Bx && k <= Cx - 1))
                        f[k] = 0.0;
            }
            f[0] = 0.0;
            if (state)
                f[length - 1] = 0.0;
            else
                f[length - 1] = 2.0 * prevLayer.W[length - 2, i, j] - prevLayer.W[length - 3, i, j];

            pSolver = new PurlinSolver(pmatrix, f);

            result = pSolver.Solve();
            nextLayer.W.SetColumn(i, j, startIndex, Dimensions.Width, result);

            //if (state)
            //    nextLayer.W[length - 1, i, j] = 2.0 * nextLayer.W[length - 2, i, j] - nextLayer.W[length - 3, i, j];

            //Solving for T
            h = 1.0 / (numPar.Re * numPar.Pr * numPar.Dx * numPar.Dx);
            for (int k = 1; k < length - 1; k++)
            {
                upperRow[k] = 0.0;
                middleRow[k] = 1.0;
                downRow[k] = 0.0;
                if (i == 0)
                    f[k] = prevLayer.T[k, i + 1, j];
                else if (i == height - 1)
                    f[k] = prevLayer.T[k, i - 1, j];
                else if (j == Az)
                    f[k] = oldLayer.T[k, i, j + 1];
                else if (j == Dz - 1)
                    f[k] = oldLayer.T[k, i, j - 1];
                else
                {
                    downRow[k] = Auxiliaries.GetValue(u, startIndex + k, i, j) / (2 * numPar.Dx) - h;
                    middleRow[k] = 3.0 / numPar.Dt + 2.0 * h;
                    upperRow[k] = -Auxiliaries.GetValue(u, startIndex + k, i, j) / (2.0 * numPar.Dx) - h;
                    f[k] = 3 * prevLayer.T[startIndex + k, i, j] / numPar.Dt + cp * Auxiliaries.GetPhiX(u, v, w, startIndex + k, i, j, numPar);
                }
                if (column)
                {
                    if ((j == Bz) && (k >= Bx && k <= Cx - 1))
                        f[k] = oldLayer.T[k, i, j - 1];
                    else if ((j == Cz - 1) && (k >= Bx && k <= Cx - 1))
                        f[k] = oldLayer.T[k, i, j + 1];
                }
            }
            if (startIndex == Ax && i != 0 && i != height - 1 && j != Az && j != Dz - 1)
            {
                f[0] = 1.0;
                upperRow[0] = 0.0;
                middleRow[0] = 1.0;
                downRow[0] = 0.0;
            }
            else
            {
                f[0] = 0.0;
                upperRow[0] = 1.0;
                middleRow[0] = -1.0;
                downRow[0] = 0.0;
            }
            if (!state)
            {
                upperRow[length - 1] = 0.0;
                middleRow[length - 1] = -1.0;
                downRow[length - 1] = 1.0;
                f[length - 1] = 0.0;
            }
            else
            {
                upperRow[length - 1] = 0.0;
                middleRow[length - 1] = 1.0;
                downRow[length - 1] = 0.0;
                f[length - 1] = 2.0 * prevLayer.T[length - 2, i, j] - prevLayer.T[length - 3, i, j];
            }

            pmatrix = new PurlinMatrix(downRow, middleRow, upperRow);
            pSolver = new PurlinSolver(pmatrix, f);

            result = pSolver.Solve();
            nextLayer.T.SetColumn(i, j, startIndex, Dimensions.Width, result);

            //if (state)
            //    nextLayer.T[length - 1, i, j] = 2.0 * nextLayer.T[length - 2, i, j] - nextLayer.T[length - 3, i, j];
        }
        private void SolveColumnZ(int i, int j, int startIndex, int endIndex, LayerData oldLayer, LayerData prevLayer, LayerData nextLayer)
        {
            DoubleMatrix3D u = new DoubleMatrix3D { FirstMatrix = oldLayer.U, SecondMatrix = prevLayer.U };
            DoubleMatrix3D v = new DoubleMatrix3D { FirstMatrix = oldLayer.V, SecondMatrix = prevLayer.V };
            DoubleMatrix3D w = new DoubleMatrix3D { FirstMatrix = oldLayer.W, SecondMatrix = prevLayer.W };
            DoubleMatrix3D T = new DoubleMatrix3D { FirstMatrix = oldLayer.T, SecondMatrix = prevLayer.T };

            int length = endIndex - startIndex;
            double[] downRow = new double[length];
            double[] middleRow = new double[length];
            double[] upperRow = new double[length];
            double[] f = new double[length];

            //Solving for U
            double h = 1.0 / (numPar.Dz * numPar.Dz * numPar.Re);
            for (int k = 1; k < length - 1; k++)
            {
                downRow[k] = Auxiliaries.GetValue(w, i, j, startIndex + k) / (2.0 * numPar.Dz) - h;
                middleRow[k] = 3.0 / numPar.Dt + 2.0 * h;
                upperRow[k] = -Auxiliaries.GetValue(w, i, j, startIndex + k) / (2.0 * numPar.Dz) - h;
                f[k] = 3.0 * prevLayer.U[i, j, startIndex + k] / numPar.Dt;
            }
            upperRow[0] = 0.0;
            middleRow[0] = 1.0;
            downRow[0] = 0.0;
            f[0] = 0.0;
            upperRow[length - 1] = 0.0;
            middleRow[length - 1] = 1.0;
            downRow[length - 1] = 0.0;
            f[length - 1] = 0.0;
            
            PurlinMatrix pmatrix = new PurlinMatrix(downRow, middleRow, upperRow);
            PurlinSolver pSolver = new PurlinSolver(pmatrix, f);

            double[] result = pSolver.Solve();
            nextLayer.U.SetColumn(i, j, startIndex, Dimensions.Thickness, result);

            //Solving for V
            for (int k = 1; k < length - 1; k++)
            {
                f[k] = 3.0 * prevLayer.V[i, j, startIndex + k] / numPar.Dt;
            }
            f[0] = 0.0;
            f[length - 1] = 0.0;
            
            pSolver = new PurlinSolver(pmatrix, f);
            result = pSolver.Solve();
            nextLayer.V.SetColumn(i, j, startIndex, Dimensions.Thickness, result);

            //Solving for W
            for (int k = 1; k < length - 1; k++)
            {
                f[k] = 3.0 * prevLayer.W[i, j, startIndex + k] / numPar.Dt -
                    (Auxiliaries.GetValue(T, i, j, startIndex + k + 1) - Auxiliaries.GetValue(T, i, j, startIndex + k - 1)) / (2.0 * numPar.Dz);
            }
            f[0] = 0.0;
            f[length - 1] = 0.0;
            
            pSolver = new PurlinSolver(pmatrix, f);
            result = pSolver.Solve();
            nextLayer.W.SetColumn(i, j, startIndex, Dimensions.Thickness, result);

            //Solving for T
            h = 1.0 / (numPar.Dz * numPar.Dz * numPar.Re * numPar.Pr);
            for (int k = 1; k < length - 1; k++)
            {
                downRow[k] = Auxiliaries.GetValue(w, i, j, startIndex + k) / (2.0 * numPar.Dz) - h;
                middleRow[k] = 3.0 / numPar.Dt + 2.0 * h;
                upperRow[k] = -Auxiliaries.GetValue(w, i, j, startIndex + k) / (2.0 * numPar.Dz) - h;
                f[k] = 3.0 * prevLayer.T[i, j, startIndex + k] / numPar.Dt +
                   cp * Auxiliaries.GetPhiZ(u, v, w, i, j, startIndex + k, numPar);
            }
            upperRow[0] = 1.0;
            middleRow[0] = -1.0;
            downRow[0] = 0.0; 
            f[0] = 0.0;
            upperRow[length - 1] = 0.0; 
            middleRow[length - 1] = -1.0;
            downRow[length - 1] = 1.0;
            f[length - 1] = 0;
            
            pSolver = new PurlinSolver(pmatrix, f);
            result = pSolver.Solve();
            nextLayer.T.SetColumn(i, j, startIndex, Dimensions.Thickness, result);
        }