/// <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;
            }
        }
        /// <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>
        /// Функция моделирования работы сухой скважины
        /// </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>
        public double CalcStaticBottomholePressureByAnnularTubing(double annularWellheadPressure)
        {
            AnnularTubing = new Tubing(Tubing);
            AnnularTubing.TubingDiameter = Tubing.CalcEquivalentAnnularDiameter();

            DryWell well = new DryWell(this);

            well.Tubing           = AnnularTubing;
            well.WellheadPressure = annularWellheadPressure;

            GasFlow gasFlow = new GasFlow(GasFluid, 0, annularWellheadPressure, WellheadTemperature);
            double  Pb      = well.Tubing.CalcStaticBottomholePressure(gasFlow, BottomholeTemperature);

            return(Pb);
        }
        /// <summary>
        /// Функция высчитывания затрубного давления на устье остановленной скважины по забойному давлению (МПа)
        /// </summary>
        public double CalcStaticAnnularTubingByBottomholePressure(double bottomholePressure)
        {
            AnnularTubing = new Tubing(Tubing);
            AnnularTubing.TubingDiameter = Tubing.CalcEquivalentAnnularDiameter();

            DryWell well = new DryWell(this);

            well.Tubing             = AnnularTubing;
            well.WellheadPressure   = 0;
            well.BottomholePressure = bottomholePressure;

            GasFlow gasFlow = new GasFlow(GasFluid, 0, bottomholePressure, BottomholeTemperature, true);

            double annularWellheadPressure = well.Tubing.CalcStaticWellheadPressure(gasFlow, WellheadTemperature);

            return(annularWellheadPressure);
        }
        /// <summary>
        /// Функция получения точек кривых притока P2 и оттока P1 по затрубному пространству для узлового анализа
        /// обводненной скважины (с откачкой насосом)
        /// </summary>
        /// <param name="dynamicH">Динамический уровень пластовой жидкости, отсчитывается от входа в насос (м)</param>
        /// <param name="num">Число точек</param>
        /// <param name="P1">Массив значений забойного давления для точек кривой оттока с забоя (МПа)</param>
        /// <param name="P2">Массив значений забойного давления для точек кривой притока из пласта к забою (МПа)</param>
        /// <param name="gasDischarge">Массив значений дебита газа (тыс.куб.м/сут)</param>
        /// <param name="waterDischarge">Массив значений дебит воды (м3/сут)</param>
        public void GetPointsAnnularTubingNodeAnalize(double dynamicH, int num, out double[] P1, out double[] P2, out double[] gasDischarge, out double[] waterDischarge)
        {
            double topPartLength       = Tubing.Length - dynamicH;
            double dynamicHTemperature = BottomholeTemperature + (WellheadTemperature - BottomholeTemperature) * (dynamicH / Tubing.Length);


            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 annularTubing = new Tubing(AnnularTubing);

            //Для затрубного пространства свободного от жидкости создаем эквивалент сухой скважины
            DryWell topPartWell = new DryWell(this);

            topPartWell.Tubing             = annularTubing;
            topPartWell.BottomholePressure = dynamicHTemperature;

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

                GasFlow gasFlow = new GasFlow(GasFluid, gasQ, WellheadPressure, WellheadTemperature);

                P2[i] = topPartWell.Layer.CalcBottomholePressure(gasQ);
                P1[i] = topPartWell.Tubing.CalcBottomholePressure(gasFlow, dynamicHTemperature);
                //Давление для притока воды берется как давление на середине динамического уровня
                double waterPres = P2[i] + WaterFluid.CalcColumnPressure(dynamicH / 2);
                waterDischarge[i] = Layer.CalcWaterRate(waterPres);

                gasQ += step;
            }
        }
Exemple #7
0
        /// <summary>
        /// Генерация верхнего потока
        /// </summary>
        public GasFlow GenerateTopFlow()
        {
            GasFlow generatedFlow = new GasFlow(Fluid, RateAtStandardConditions, TopPressure, TopTemperature, true);

            return(generatedFlow);
        }
Exemple #8
0
        /// <summary>
        /// Генерация нижнего потока
        /// </summary>
        public GasFlow GenerateBottomFlow()
        {
            GasFlow generatedFlow = new GasFlow(Fluid, RateAtStandardConditions, BottomPressure, BottomTemperature);

            return(generatedFlow);
        }
        /// <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);
        }