Ejemplo n.º 1
0
        //Method Name: initializeSimulationSinglePhase
        //Objectives: reads the data from the data object passed to it and assign the values to the blocks after constructing the grid and starting the solver
        //Inputs: a variable of type "SimulatorData" that contains all the simulation data read from the data input file
        //Outpits: N/A
        public static void initializeSimulationSinglePhase(SimulatorData data)
        {
            #region Initialize Rectangular grid dimensions
            bool homogeneous = data.homogeneous;
            int  x = data.x, y = data.y, z = data.z;

            int[] inactive_blocks = data.inactive_blocks;

            //creates an array for the grid x, y and z dimensions
            int[] grid_dimensions = new int[] { x, y, z };

            //calculates the size of the entire grid "including both active and non-active blocks"
            int size = x * y * z;
            //calculates the size of the active-blocks only
            int size_active = x * y * z - inactive_blocks.Length;

            //use this if the natural ordering excludes inactive blocks
            if (data.natural_ordering == SimulatorData.NaturalOrdering.Active_Only)
            {
                size = size_active;
            }

            GridBlock[] grid;
            #endregion

            #region Initialize grid data
            //The gridding technique used here is for only a single row or a single column
            int[] delta_X = new int[x];
            int[] delta_Y = new int[y];
            int[] delta_Z = new int[size];

            double[] depth_top_array = new double[size];
            double   depth_top;

            //Homogeneous grid sizing
            if (homogeneous)
            {
                for (int i = 0; i < x; i++)
                {
                    delta_X[i] = data.delta_X;
                }
                for (int i = 0; i < y; i++)
                {
                    delta_Y[i] = data.delta_Y;
                }
                for (int i = 0; i < size; i++)
                {
                    delta_Z[i] = data.delta_Z;
                }
            }
            //Heterogeneous grid sizing
            else
            {
                delta_X = data.delta_X_array;
                delta_Y = data.delta_Y_array;
                delta_Z = data.delta_Z_array;

                depth_top_array = data.depth_top_array;
            }
            #endregion

            #region Initialize Rock properties
            //The gridding technique used here is for the whole grid

            double[] Kx_data              = new double[size];
            double[] Ky_data              = new double[size];
            double[] Kz_data              = new double[size];
            double[] porosity             = new double[size];
            double   compressibility_rock = 0;

            //Homogeneous grid
            if (homogeneous)
            {
                for (int i = 0; i < size; i++)
                {
                    Kx_data[i]           = data.Kx_data;
                    Ky_data[i]           = data.Ky_data;
                    Kz_data[i]           = data.Kz_data;
                    porosity[i]          = data.porosity;
                    compressibility_rock = data.compressibility_rock;
                }
            }
            //Heterogeneous grid
            else
            {
                Kx_data              = data.Kx_data_array;
                Ky_data              = data.Ky_data_array;
                Kz_data              = data.Kz_data_array;
                porosity             = data.porosity_array;
                compressibility_rock = data.compressibility_rock;
            }
            #endregion

            #region Initialize PVT

            double FVF              = data.FVF;
            double viscosity        = data.viscosity;
            double density          = data.density;
            double molecular_weight = data.molecular_weight;
            double temperature      = data.temperature;

            PVT pvt = new PVT(us_w_d: data.water_data);

            //For slightly-compressibly fluid
            double compressibility_fluid = data.compressibility_fluid;

            //For compressible fluid, this data is used for constructing the PVT table
            double[][] g_data = data.g_data;

            //PVT pvt = new PVT(g_data: g_data);
            #endregion

            #region  Initialize boundary conditions

            double initial_pressure = data.initial_pressure;

            double[] boundary_flow_rate           = data.boundary_flow_rate;
            double[] boundary_pressure_x          = data.boundary_pressure_x;
            double[] boundary_pressure_y          = data.boundary_pressure_y;
            double[] boundary_pressure_gradient_x = data.boundary_pressure_gradient_x;
            double[] boundary_pressure_gradient_y = data.boundary_pressure_gradient_y;

            #endregion

            #region  Initialize wells data
            Well[] wells = data.well_array;
            Well   well;

            #endregion

            #region run specifications
            TypeDefinitions.Compressibility compressibility = data.compressibility;
            var phase     = Transmissibility.Phase.Water;
            var grid_type = data.grid_type;

            //For compressible and slightly-compressible fluids, define the values for time steps and total simulation time
            double delta_t  = data.delta_t;
            double time_max = data.time_max;

            //For compressible fluid problems
            double convergence_pressure = data.convergence_pressure;
            #endregion

            #region Initialize grid
            //#########################################################################################
            //Assign neighbouring blocks "according to the natural ordering procedure"
            //set numbering scheme
            var numbering_scheme = RectangularBlockNumbering.NumberingScheme.Active_Only;
            //contruct the grid
            grid = RectangularBlockNumbering.assignGridOrdering(grid_dimensions, inactive_blocks, numbering_scheme);

            GridBlock block;
            //assign properties to each block in the grid
            for (int counter = 0; counter < grid.Length; counter++)
            {
                block = grid[counter];

                //#########################################################################################
                //Assign PVT and rock properties

                block.delta_x     = delta_X[block.x]; block.delta_y = delta_Y[block.y]; block.h = delta_Z[counter];
                block.depth       = depth_top_array[counter] + block.h * 0.5;
                block.bulk_volume = block.delta_x * block.delta_y * block.h;

                block.Kx = Kx_data[counter]; block.Ky = Ky_data[counter]; block.Kz = Kz_data[counter];

                //To-Do: initialize pressure through hydraulic equilibrium
                block.pressure = initial_pressure;

                if (compressibility == TypeDefinitions.Compressibility.Compressible)
                {
                    block.water_viscosity = pvt.getWaterViscosity(initial_pressure);

                    //For a single phase fluid, saturation and relative permeabilities of the fluid is equal to unity
                    block.So  = 0; block.Sg = 0; block.Sw = 1;
                    block.Kro = 0; block.Krg = 0; block.Krw = 1;
                    //For slightly compressible fluids, the values of rock compressibility "Cf" and fluid compressibility C_fluid are used to estimate the new values
                    block.Cf = compressibility_rock; block.C = compressibility_fluid;

                    const double a             = 5.614583;
                    double       FVF_constants = 14.7 / (60 + 460) * (190 + 460) / 1;
                    double       z_factor      = PVT.calculateZ(738.44, 418.38, initial_pressure, 190, 1);
                    block.Bw            = FVF_constants * z_factor / initial_pressure;
                    density             = PVT.calculateGasDensity(initial_pressure, molecular_weight, z_factor, temperature);
                    block.water_density = density * gamma_c * gravity_c;
                    block.porosity      = Vp_Calculator.chord_slope_Vp(compressibility_rock, porosity[counter], block.pressure, initial_pressure);
                }
                else if (compressibility == TypeDefinitions.Compressibility.Slightly_Compressible)
                {
                    //For slightly compressibly fluids, viscosity is independent of pressure
                    if (viscosity > 0)
                    {
                        block.water_viscosity = viscosity;
                    }
                    else
                    {
                        block.water_viscosity = pvt.getWaterViscosity(initial_pressure);
                    }

                    //For a single phase fluid, saturation and relative permeabilities of the fluid is equal to unity
                    block.So  = 0; block.Sg = 0; block.Sw = 1;
                    block.Kro = 0; block.Krg = 0; block.Krw = 1;
                    //For slightly compressible fluids, the values of rock compressibility "Cf" and fluid compressibility C_fluid are used to estimate the new values
                    block.Cf = compressibility_rock; block.C = compressibility_fluid;

                    block.Bw            = PVT.chord_slope_FVF(compressibility_fluid, 14.7);
                    block.water_density = density * gamma_c * gravity_c;
                    block.porosity      = Vp_Calculator.chord_slope_Vp(compressibility_rock, porosity[counter], block.pressure, initial_pressure);
                }
                else
                {
                    block.water_viscosity = viscosity; block.Bw = FVF; block.water_density = density * gamma_c * gravity_c;
                    block.porosity        = porosity[counter];
                    block.So  = 0; block.Sg = 0; block.Sw = 1;
                    block.Kro = 0; block.Krg = 0; block.Krw = 1;
                }

                //#########################################################################################
                //Calculate geometric factors "the part of the transmissibility that is always constant" only once in the initialization process
                var direction_x = Transmissibility.Direction.x;
                var direction_y = Transmissibility.Direction.y;

                if (homogeneous)
                {
                    block.GF_x = Transmissibility.getGeometricFactor(block, grid_type, direction_x);
                    block.GF_y = Transmissibility.getGeometricFactor(block, grid_type, direction_y);
                }

                //#########################################################################################
                //Set boundary conditions

                double boundary_transmissibility = 0;

                block.boundary_flow_rate = boundary_flow_rate[counter];
                if (boundary_pressure_x[counter] != 0)
                {
                    boundary_transmissibility = Transmissibility.getBoundaryTransmissibility(block, grid_type, direction_x, phase);
                    block.boundary_pressure   = boundary_pressure_x[counter];
                    block.boundary_pressure_times_transmissibility = boundary_transmissibility * boundary_pressure_x[counter];
                    block.boundary_transmissibility = boundary_transmissibility;
                }
                else if (boundary_pressure_y[counter] != 0)
                {
                    boundary_transmissibility = Transmissibility.getBoundaryTransmissibility(block, grid_type, direction_y, phase);
                    block.boundary_pressure   = boundary_pressure_y[counter];
                    block.boundary_pressure_times_transmissibility = boundary_transmissibility * boundary_pressure_y[counter];
                    block.boundary_transmissibility = boundary_transmissibility;
                }

                //boundary pressure gradient is positive for depletion and negative for encroachment
                boundary_transmissibility         = Transmissibility.getBoundaryTransmissibility(block, grid_type, direction_x, phase);
                block.boundary_pressure_gradient += boundary_pressure_gradient_x[counter] * block.delta_x / 2 * boundary_transmissibility;

                boundary_transmissibility         = Transmissibility.getBoundaryTransmissibility(block, grid_type, direction_y, phase);
                block.boundary_pressure_gradient += boundary_pressure_gradient_y[counter] * block.delta_y / 2 * boundary_transmissibility;


                //#########################################################################################
                //Set well rates
                if (wells[counter] != null)
                {
                    well       = wells[counter];
                    block.type = GridBlock.Type.Well;

                    //specified flow rate wells
                    if (well.type_calculation == Well.TypeCalculation.Specified_Flow_Rate)
                    {
                        block.well_type      = GridBlock.WellType.Specified_Flow_Rate;
                        block.well_flow_rate = well.specified_flow_rate;
                        block.specified_BHP  = well.specified_BHP;
                        block.skin           = well.skin;
                        block.rw             = well.rw;
                        double well_geometric_factor = Well.getGeometricFactor(block);
                        block.well_geometric_factor = well_geometric_factor;
                        block.well_transmissibility = Well.getTransmissibility(block, well_geometric_factor, Well.Phase.Water);
                    }
                    //specified BHP wells
                    else
                    {
                        block.well_type = GridBlock.WellType.Specified_BHP;
                        block.BHP       = well.specified_BHP;
                        block.rw        = well.rw;
                        block.skin      = well.skin;
                        double well_geometric_factor = Well.getGeometricFactor(block);
                        block.well_geometric_factor = well_geometric_factor;
                        block.well_transmissibility = Well.getTransmissibility(block, well_geometric_factor, Well.Phase.Water);
                    }
                }
            }

            #region calculate the geometric factors of a heterogeneous grid
            if (!homogeneous)
            {
                var direction_x = Transmissibility.Direction.x;
                var direction_y = Transmissibility.Direction.y;
                int x_counter   = 0;
                int y_counter   = 0;
                //int z_counter = 0;

                for (int i = 0; i < grid.Length; i++)
                {
                    block = grid[i];

                    if (x > 1)
                    {
                        x_counter = block.east_counter != -1 ? block.east_counter : block.west_counter;

                        block.GF_x = x_counter != -1 ? Transmissibility.getGeometricFactor(block, grid[x_counter], grid_type, direction_x) : 0;
                    }
                    if (y > 1)
                    {
                        y_counter = block.north_counter != -1 ? block.north_counter : block.south_counter;

                        block.GF_y = y_counter != -1 ? Transmissibility.getGeometricFactor(block, grid[y_counter], grid_type, direction_y) : 0;
                    }
                }
            }
            #endregion

            #endregion

            #region Output
            SinglePhase.OutPut2D output = new SinglePhase.OutPut2D(grid, grid_dimensions, data.what, data.where, compressibility, data.file_name, data.formatted, data.single_file, inactive_blocks);
            #endregion

            #region Choose Solver
            if (compressibility == TypeDefinitions.Compressibility.Incompressible)
            {
                SolverSinglePhase.incompressible(grid, output);
            }
            else if (compressibility == TypeDefinitions.Compressibility.Slightly_Compressible)
            {
                SolverSinglePhase.slightly_compressible(grid, delta_t, time_max, output, pvt);
            }
            else
            {
                SolverSinglePhase.compressible(grid, delta_t, time_max, convergence_pressure, output, pvt);
            }
            #endregion
        }