Example #1
0
        /// <summary>
        /// Функция получения точек кривых притока P2 и оттока P1 для узлового анализа сухой скважины
        /// </summary>
        /// <param name="num">Число точек</param>
        /// <param name="P1">Массив значений забойного давления для точек кривой оттока с забоя (МПа)</param>
        /// <param name="P2">Массив значений забойного давления для точек кривой притока из пласта к забою (МПа)</param>
        /// <param name="Q">Массив значений дебита газа (тыс.куб.м/сут)</param>
        public virtual void GetPointsForNodeAnalize(int num, out double[] P1, out double[] P2, out double[] Q)
        {
            P1 = new double[num];
            P2 = new double[num];
            Q  = new double[num];
            double maxQ = Layer.CalcMaxGasRate();
            double step = maxQ / num;
            double gasQ = 0;
            //создается новый Tubing чтобы не перезаписывать SegmentFlows
            Tubing tubing = new Tubing(Tubing);

            for (int i = 0; i < num; i++)
            {
                Q[i] = gasQ;
                GasFlow gasFlow = new GasFlow(GasFluid, gasQ, WellheadPressure, WellheadTemperature);
                if (Layer.NGLFactor > 0)
                {
                    double     nglQ       = NglFluid.CalcVolumeRate(Layer.NGLFactor, gasQ);
                    LiquidFlow liquidFlow = new LiquidFlow(nglQ, NglFluid);
                    P1[i] = Tubing.CalcBottomholePressure(gasFlow, liquidFlow, BottomholeTemperature);
                }
                else
                {
                    P1[i] = tubing.CalcBottomholePressure(gasFlow, BottomholeTemperature);
                }
                P2[i] = Layer.CalcBottomholePressure(gasQ);
                gasQ += step;
            }
        }
        /// <summary>
        /// Функция получения точек кривых притока P2 и оттока P1 для узлового анализа обводненной скважины (без откачки)
        /// </summary>
        /// <param name="num">Число точек</param>
        /// <param name="P1">Массив значений забойного давления для точек кривой оттока с забоя (МПа)</param>
        /// <param name="P2">Массив значений забойного давления для точек кривой притока из пласта к забою (МПа)</param>
        /// <param name="gasDischarge">Массив значений дебита газа (тыс.куб.м/сут)</param>
        /// <param name="waterDischarge">Массив значений дебит воды (м3/сут)</param>
        public void GetPointsForNodeAnalize(int num, out double[] P1, out double[] P2, out double[] gasDischarge, out double[] waterDischarge)
        {
            P1             = new double[num];
            P2             = new double[num];
            gasDischarge   = new double[num];
            waterDischarge = new double[num];
            double maxQ = Layer.CalcMaxGasRate();
            double step = maxQ / num;
            double gasQ = 0;
            //создается новый Tubing чтобы не перезаписывать SegmentFlows
            Tubing tubing = new Tubing(Tubing);

            for (int i = 0; i < num; i++)
            {
                gasDischarge[i] = gasQ;
                P2[i]           = Layer.CalcBottomholePressure(gasQ);

                double     waterQ     = Layer.CalcWaterRate(P2[i]);
                double     nglQ       = NglFluid.CalcVolumeRate(Layer.NGLFactor, gasQ);
                LiquidFlow liquidFlow = new LiquidFlow(nglQ, NglFluid, waterQ, WaterFluid);
                GasFlow    gasFlow    = new GasFlow(GasFluid, gasQ, WellheadPressure, WellheadTemperature);

                P1[i]             = tubing.CalcBottomholePressure(gasFlow, liquidFlow, BottomholeTemperature);
                waterDischarge[i] = waterQ;
                gasQ += step;
            }
        }
Example #3
0
        /// <summary>
        /// Функция моделирования работы сухой скважины
        /// </summary>
        /// <param name="eps">Точность с которой будет расчитываться забойное давление (безразмерная)</param>
        /// <param name="bottomHolePressure">Забойное давление (МПа)</param>
        /// <param name="nglRate">Дебит конденсата (т/сут)</param>
        /// <returns>Дебит газа в стандартных условиях (тыс.куб.м/сут)</returns>
        public virtual double Modeling(double eps, out double bottomHolePressure, out double nglRate)
        {
            double maxQ = Layer.CalcMaxGasRate();
            double gasQ = maxQ / 2;
            double step = gasQ / 2;
            double P1, P2;

            do
            {
                GasFlow gasFlow = new GasFlow(GasFluid, gasQ, WellheadPressure, WellheadTemperature);
                if (Layer.NGLFactor > 0)
                {
                    double     nglQ       = NglFluid.CalcVolumeRate(Layer.NGLFactor, gasQ);
                    LiquidFlow liquidFlow = new LiquidFlow(nglQ, NglFluid);
                    P1 = Tubing.CalcBottomholePressure(gasFlow, liquidFlow, BottomholeTemperature);
                }
                else
                {
                    P1 = Tubing.CalcBottomholePressure(gasFlow, BottomholeTemperature);
                }
                P2 = Layer.CalcBottomholePressure(gasQ);

                // Если увеличиваем Q, то:
                //	-	P1 увеличивается, т.к. устьевое давление константно, а дебит увеличен, следовательно,
                // увеличивается забойное давление.
                //	-	P2 уменьшается, т.к. пластовое давление константно, а приток к забою увеличивается, следовательно,
                // должно уменьшится забойное давление.
                //
                // Аналогично, когда Q уменьшается, то P1 уменьшается а P2 увеличивается.
                //
                // Отсюда, если давление P1 больше давления P2, значит нужно брать левое половинное деление, иначе
                // берем правое половинное значение.
                if (Math.Abs(P1 - P2) <= eps)
                {
                    break;
                }
                else if (P1 > P2)
                {
                    gasQ = gasQ - step;
                }
                else
                {
                    gasQ = gasQ + step;
                }

                if (gasQ < 0 || gasQ > maxQ)
                {
                    gasQ = 0;
                    break;
                }
                step = step / 2;
            } while (true);

            bottomHolePressure = P1;
            nglRate            = CalcNglRate(gasQ);
            return(gasQ);
        }
        /// <summary>
        /// Функция моделирования работы плунжерного лифта
        /// </summary>
        /// <param name="eps">Точность с которой будет расчитываться забойное давление (безразмерная)</param>
        /// <param name="plunger">Плунжер</param>
        public PlungerModelingResult ModelingPlunger(double eps, Plunger plunger)
        {
            PlungerModelingResult mr = new PlungerModelingResult();

            mr.StartGasRate = Modeling(eps, out mr.StartBtmhPressure, out mr.StartWaterRate, out mr.StartNglRate);

            double P_avg = (WellheadPressure + mr.StartBtmhPressure) / 2;

            mr.CritQ = CalcCriticalGasRate(P_avg);

            //создается новый Tubing чтобы не перезаписывать SegmentFlows
            Tubing tubing = new Tubing(Tubing);

            mr.CloseGasRate = (mr.StartGasRate - mr.CritQ) / 2;
            double step = (mr.StartGasRate - mr.CritQ) / 4;
            int    i    = 0;

            do
            {
                i++;
                mr.CloseBtmhPressure = Layer.CalcBottomholePressure(mr.CloseGasRate);

                mr.CloseWaterRate = Layer.CalcWaterRate(mr.CloseBtmhPressure);
                double closeNglVolumeRate = NglFluid.CalcVolumeRate(Layer.NGLFactor, mr.CloseGasRate);
                mr.CloseNglRate = CalcNglRate(mr.CloseGasRate);
                LiquidFlow liquidFlow = new LiquidFlow(closeNglVolumeRate, NglFluid, mr.CloseWaterRate, WaterFluid);

                GasFlow gasFlow = new GasFlow(GasFluid, mr.CloseGasRate, WellheadPressure, WellheadTemperature);

                //Давление выше столба жидкость высотой h
                double Ph = tubing.CalcBottomholePressure(gasFlow, liquidFlow, BottomholeTemperature);
                //разница  (P2 - P1) = rho*g*h создается столбом жидкости на забое
                mr.ColumnHeight = WaterFluid.CalcColumnHeight(mr.CloseBtmhPressure - Ph);

                // Объем столба воды над плунжером
                mr.ColumnWaterVolume = WaterFluid.CalcVolumeOfColumnHeight(mr.ColumnHeight, Tubing.CrossSectionArea);

                //Находим затрубное давление необходимое для поднятия плунжера с водой
                double Pc_max = plunger.CalcMaxCasingPressure(WellheadPressure, Tubing.Length, mr.ColumnWaterVolume,
                                                              Tubing.AnnularCrossSectionArea, Tubing.CrossSectionArea);
                //Забойное давление необходимое для поднятия плунжера с водой
                mr.OpenBtmhPressure = CalcStaticBottomholePressureByAnnularTubing(Pc_max);
                if (mr.OpenBtmhPressure < Layer.ReservoirPressure)
                {
                    return(mr);
                }

                if (Ph > mr.CloseBtmhPressure)
                {
                    mr.CloseGasRate = mr.CloseGasRate - step;
                }
                else
                {
                    mr.CloseGasRate = mr.CloseGasRate + step;
                }

                step = step / 2;
                if (i > 100)
                {
                    break;
                }
            } while (true);

            mr = new PlungerModelingResult();
            return(mr);
        }