示例#1
0
        //Method Name: initializeSimulationSinglePhase
        //Objectives: The same as the previous method, but it does not take data as input. It uses internal hard coded sata.
        //Inputs: N/A
        //Outputs: N/A
        public static void initializeSimulationSinglePhase()
        {
            #region Initialize Rectangular grid dimensions
            bool homogeneous = false;
            int  x = 5, y = 1, z = 1;

            int[] inactive_blocks = new int[] { };

            //creates an arrayfor 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 (inactive_blocks.Length > 0)
            {
                size = size_active;
            }

            GridBlock[] grid;
            #endregion

            #region Initialize grid
            //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[z];

            //Homogeneous grid sizing
            if (homogeneous)
            {
                for (int i = 0; i < x; i++)
                {
                    delta_X[i] = 300;
                }
                for (int i = 0; i < y; i++)
                {
                    delta_Y[i] = 350;
                }
                for (int i = 0; i < z; i++)
                {
                    delta_Z[i] = 40;
                }
            }
            //Heterogeneous grid sizing
            else
            {
                //General grid values
                for (int i = 0; i < x; i++)
                {
                    delta_X[i] = 300;
                }
                for (int i = 0; i < y; i++)
                {
                    delta_Y[i] = 500;
                }
                for (int i = 0; i < z; i++)
                {
                    delta_Z[i] = 50;
                }
                //Specific heterogenities
                delta_X = new int[] { 400, 300, 150, 200, 250 };
            }
            #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]           = 270;
                    Ky_data[i]           = 270;
                    porosity[i]          = 0.27;
                    compressibility_rock = 0.000001;
                }
            }
            //Heterogeneous grid
            else
            {
                //General
                for (int i = 0; i < size; i++)
                {
                    Kx_data[i]  = 270;
                    Ky_data[i]  = 270;
                    porosity[i] = 0.27;
                    //compressibility_rock = 0.000001;
                }
                //Specific heterogenities
                Kx_data              = new double[] { 273, 248, 127, 333, 198 };
                Ky_data              = Kx_data;
                porosity             = new double[] { 0.21, 0.17, 0.1, 0.25, 0.13 };
                compressibility_rock = 0;
            }
            #endregion

            #region Initialize PVT

            double FVF       = 1;
            double viscosity = 1.5;

            //For slightly-compressibly fluid
            double compressibility_fluid = 2.5 * Math.Pow(10, -5);

            //For compressible fluid, this data is used for constructing the PVT table
            double[][] g_data = new double[4][];
            g_data[0] = new double[] { 14.7, 264.7, 514.7, 1014.7, 2014.7, 2514.7, 3014.7, 4014.7, 5014.7, 9014.7 };
            g_data[1] = new double[] { 0.166666, 0.012093, 0.006274, 0.003197, 0.001614, 0.001294, 0.00108, 0.000811, 0.0006490, 0.000386 };
            g_data[2] = new double[] { 0.008, 0.0096, 0.0112, 0.014, 0.0189, 0.0208, 0.0228, 0.0268, 0.0309, 0.047 };
            g_data[3] = new double[] { 0.0647, 0.8916, 1.7185, 3.3727, 6.8806, 8.3326, 9.9837, 13.2952, 16.6139, 27.948 };

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

            #region  Initialize boundary conditions

            int initial_pressure = 3000;

            double[] boundary_flow_rate           = new double[size];
            double[] boundary_pressure_x          = new double[size];
            double[] boundary_pressure_y          = new double[size];
            double[] boundary_pressure_gradient_x = new double[size];
            double[] boundary_pressure_gradient_y = new double[size];


            //boundary_pressure_x[0] = 4000;
            //boundary_flow_rate[0] = -500;
            //boundary_flow_rate[3] = 200;
            //boundary_pressure_gradient_x[1] = 0.3; boundary_pressure_gradient_x[3] = 0.3;
            //boundary_pressure_y[0] = 4000; boundary_pressure_y[1] = 4000;
            //boundary_pressure_gradient_x[3] = 0.2;
            #endregion

            #region  Initialize wells data
            Well[] wells = new Well[size];
            Well   well;
            for (int i = 0; i < wells.Length; i++)
            {
                if (i == 3)
                {
                    well = new Well();

                    well.type_calculation    = Well.TypeCalculation.Specified_Flow_Rate;
                    well.specified_flow_rate = 400;
                    well.specified_BHP       = 1500;
                    well.skin = 0;
                    well.rw   = 3;
                    well.type = Well.Type.Production;
                    //Add the well to the array
                    wells[i] = well;
                }

                //if (i == 3)
                //{
                //    well = new Well();

                //    well.type_calculation = Well.TypeCalculation.Specified_BHP;
                //    well.specified_BHP = 3500;
                //    well.rw = 3;
                //    well.skin = 0;
                //    well.type = Well.Type.Injection;
                //    //Add the well to the array
                //    wells[i] = well;
                //}
                //if (i == 4)
                //{
                //    well = new Well();

                //    well.type_calculation = Well.TypeCalculation.Specified_Flow_Rate;
                //    well.well_flow_rate = 1000;
                //    well.type = Well.Type.Production;

                //    //Add the well to the array
                //    wells[i] = well;
                //}
            }
            #endregion

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

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

            //For compressible fluid problems
            double convergence_pressure = 0.001;
            #endregion

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

            GridBlock block;

            //Parallel.For(0, grid.Length, (counter) =>
            //{

            //});
            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.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);
                    block.So  = 0; block.Sg = 0; block.Sw = 1;
                    block.Kro = 0; block.Krg = 0; block.Krw = 1;
                    block.Cf  = compressibility_rock; block.C = compressibility_fluid;

                    block.Bw       = pvt.getWaterFVF(initial_pressure);
                    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
                    block.water_viscosity = viscosity;
                    //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, initial_pressure);
                    block.porosity = Vp_Calculator.chord_slope_Vp(compressibility_rock, porosity[counter], block.pressure, initial_pressure);
                }
                else
                {
                    block.water_viscosity = viscosity; block.Bw = FVF;
                    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_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_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;

                    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.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);
                    }
                    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 = Transmissibility.getGeometricFactor(block, grid[x_counter], grid_type, direction_x);
                    }
                    if (y > 1)
                    {
                        y_counter = block.north_counter != -1 ? block.north_counter : block.south_counter;

                        block.GF_y = Transmissibility.getGeometricFactor(block, grid[y_counter], grid_type, direction_y);
                    }
                }
            }
            #endregion

            #endregion

            #region Choose Solver
            if (compressibility == TypeDefinitions.Compressibility.Incompressible)
            {
                //SolverSinglePhase.incompressible(grid);
            }
            else if (compressibility == TypeDefinitions.Compressibility.Slightly_Compressible)
            {
                //SolverSinglePhase.slightly_compressible(grid, delta_t, time_max);
            }
            else
            {
                //SolverSinglePhase.compressible(grid, delta_t, time_max, convergence_pressure, output, pvt);
            }
            #endregion
        }
示例#2
0
        //Method Name: AssignValues
        //Objectives: It gets the data from the ReadFile method and decides on which variables get values and which solvers are used or methods are called depending on these values
        //Inputs: a string to indicate file_name
        //Outputs: a variabe of type "SimulatorData" that contains the data read from the file in a form suitable for the use of the simulator
        public static SimulatorData ReadData(string file_name)
        {
            //a dictionary to store the data read from the file in a key-value pairs format
            Dictionary <string, string> dictionary = ReadFile(file_name + ".txt");
            SimulatorData simulator_data           = new SimulatorData();

            if (dictionary.Count > 0)
            {
                // Chek if the input data file exists and it succefully was loaded.
                simulator_data.successfully_loaded_data = true;
                // Sets the file name.
                simulator_data.file_name = file_name;
                // This variable stores the size of the grid according to the numbering system used "active-blocks only, or all blocks".
                int    size = 0;
                String key;

                #region Run Specs
                key = "natural_ordering";
                if (dictionary.ContainsKey(key))
                {
                    if (dictionary[key] == "all_blocks")
                    {
                        simulator_data.natural_ordering = SimulatorData.NaturalOrdering.All_Blocks;
                    }
                    else if (dictionary[key] == "active_only")
                    {
                        simulator_data.natural_ordering = SimulatorData.NaturalOrdering.Active_Only;
                    }
                }

                key = "single_phase_compressibility";
                if (dictionary.ContainsKey(key))
                {
                    if (dictionary[key] == "incompressible")
                    {
                        simulator_data.compressibility = TypeDefinitions.Compressibility.Incompressible;
                    }
                    else if (dictionary[key] == "slightly_compressible")
                    {
                        simulator_data.compressibility = TypeDefinitions.Compressibility.Slightly_Compressible;
                    }
                    else if (dictionary[key] == "compressible")
                    {
                        simulator_data.compressibility = TypeDefinitions.Compressibility.Compressible;
                    }
                }

                key = "grid_type";
                if (dictionary.ContainsKey(key))
                {
                    if (dictionary[key] == "rectangular")
                    {
                        simulator_data.grid_type = Transmissibility.GridType.Rectangular;
                    }
                    else if (dictionary[key] == "cylindrical")
                    {
                        simulator_data.grid_type = Transmissibility.GridType.Cylindrical;
                    }
                }

                key = "delta_t";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.delta_t = double.Parse(dictionary[key]);
                }

                key = "time_max";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.time_max = double.Parse(dictionary[key]);
                }

                key = "convergence_pressure";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.convergence_pressure = double.Parse(dictionary[key]);
                }
                #endregion

                #region Output
                key = "what";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.what = dictionary[key].Split(',');
                }

                key = "where";
                if (dictionary.ContainsKey(key))
                {
                    string temp = dictionary[key];
                    simulator_data.where = temp == "console" ? SinglePhase.OutPut2D.Where.Console : SinglePhase.OutPut2D.Where.File;
                }

                key = "formatted";
                if (dictionary.ContainsKey(key))
                {
                    string temp = dictionary[key];
                    simulator_data.formatted = temp == "yes" ? true : false;
                }

                key = "single_file";
                if (dictionary.ContainsKey(key))
                {
                    string temp = dictionary[key];
                    simulator_data.single_file = temp == "yes" ? true : false;
                }
                #endregion

                #region Grid

                // For a rectangular grid
                if (simulator_data.grid_type == Transmissibility.GridType.Rectangular)
                {
                    key = "homogeneous";
                    if (dictionary.ContainsKey(key))
                    {
                        if (dictionary[key] == "yes")
                        {
                            simulator_data.homogeneous = true;
                        }
                        else
                        {
                            simulator_data.homogeneous = false;
                        }
                    }

                    key = "inactive_blocks";
                    if (dictionary.ContainsKey(key))
                    {
                        simulator_data.inactive_blocks = getArrayFromDictionary_int(dictionary[key]);
                    }
                    else
                    {
                        simulator_data.inactive_blocks = new int[0];
                    }

                    key = "grid_dimensions";
                    if (dictionary.ContainsKey(key))
                    {
                        string[] grid_dimensions = dictionary[key].Split(',');
                        simulator_data.x = int.Parse(grid_dimensions[0]); simulator_data.y = int.Parse(grid_dimensions[1]); simulator_data.z = int.Parse(grid_dimensions[2]);
                    }

                    // Set the size of the grid according to the numbering system used "active-blocks only, or all blocks"
                    if (simulator_data.natural_ordering == SimulatorData.NaturalOrdering.All_Blocks)
                    {
                        size = simulator_data.x * simulator_data.y * simulator_data.z;
                    }
                    else
                    {
                        size = simulator_data.x * simulator_data.y * simulator_data.z - simulator_data.inactive_blocks.Length;
                    }
                    //////////////////////////////////////////////////////////////////

                    //Block dimensions
                    if (simulator_data.homogeneous == true)
                    {
                        simulator_data.delta_X = int.Parse(dictionary["delta_x"]);
                        simulator_data.delta_Y = int.Parse(dictionary["delta_y"]);
                        simulator_data.delta_Z = int.Parse(dictionary["delta_z"]);

                        key = "depth_top";
                        if (dictionary.ContainsKey(key))
                        {
                            simulator_data.depth_top = double.Parse(dictionary["depth_top"]);
                        }
                    }
                    else
                    {
                        //Delta x values
                        simulator_data.delta_X_array = getArrayFromDictionary_int(dictionary["delta_x"]);

                        //Delta y values
                        simulator_data.delta_Y_array = getArrayFromDictionary_int(dictionary["delta_y"]);

                        //Heights values
                        simulator_data.delta_Z_array = getArrayFromDictionary_int(dictionary["delta_z"]);

                        key = "depth_top";
                        if (dictionary.ContainsKey(key))
                        {
                            simulator_data.depth_top_array = getArrayFromDictionary_double(dictionary[key]);
                        }
                        else
                        {
                            simulator_data.depth_top_array = new double[size];
                        }
                    }
                }
                // For a cylindrical grid
                // Single-well simulations. Always homogeneous rock properties. No in-active blocks
                else
                {
                }


                #endregion

                #region Rock Properties

                if (simulator_data.homogeneous)
                {
                    if (dictionary.ContainsKey("Kz"))
                    {
                        //
                        simulator_data.Kz_data = double.Parse(dictionary["Kz"]);
                    }
                    simulator_data.Kx_data = double.Parse(dictionary["Kx"]);
                    simulator_data.Ky_data = double.Parse(dictionary["Ky"]);

                    simulator_data.porosity = double.Parse(dictionary["porosity"]);
                    //Rock Compressiblity
                    key = "compressibility_rock";
                    if (dictionary.ContainsKey(key))
                    {
                        simulator_data.compressibility_rock = double.Parse(dictionary["compressibility_rock"]);
                    }
                }
                else
                {
                    //Kx values
                    simulator_data.Kx_data_array = getArrayFromDictionary_double(dictionary["Kx"]);

                    //Ky values
                    simulator_data.Ky_data_array = getArrayFromDictionary_double(dictionary["Ky"]);

                    //Kz values
                    if (dictionary.ContainsKey("Kz"))
                    {
                        simulator_data.Kz_data_array = getArrayFromDictionary_double(dictionary["Kz"]);
                    }
                    else
                    {
                        simulator_data.Kz_data_array = new double[size];
                    }

                    //Porosity values
                    simulator_data.porosity_array = getArrayFromDictionary_double(dictionary["porosity"]);

                    //Rock Compressiblity
                    key = "compressibility_rock";
                    if (dictionary.ContainsKey(key))
                    {
                        simulator_data.compressibility_rock = double.Parse(dictionary["compressibility_rock"]);
                    }
                }

                #endregion

                #region PVT
                key = "FVF";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.FVF = double.Parse(dictionary[key]);
                }

                key = "density";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.density = double.Parse(dictionary[key]);
                }

                key = "molecular_weight";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.molecular_weight = double.Parse(dictionary[key]);
                }

                key = "temperature";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.temperature = double.Parse(dictionary[key]);
                }

                key = "viscosity";
                if (simulator_data.compressibility == TypeDefinitions.Compressibility.Incompressible)
                {
                    if (dictionary.ContainsKey(key))
                    {
                        simulator_data.viscosity = double.Parse(dictionary[key]);
                    }
                }
                else
                {
                    if (dictionary[key].Contains(','))
                    {
                        double[][] temp = getTwoColumns(dictionary[key]);
                        simulator_data.water_data[0] = temp[0];
                        simulator_data.water_data[2] = temp[1];
                    }
                    else
                    {
                        simulator_data.viscosity = double.Parse(dictionary[key]);
                    }
                }

                key = "compressibility_fluid";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.compressibility_fluid = double.Parse(dictionary[key]);
                }

                key = "g_data_pressure";
                if (dictionary.ContainsKey(key))
                {
                    ////pressure
                    //simulator_data.g_data[0] = getArrayFromDictionary_double(dictionary, "g_data_pressure");
                    ////FVF
                    //simulator_data.g_data[1] = getArrayFromDictionary_double(dictionary, "g_data_FVF");
                    ////Viscosity
                    //simulator_data.g_data[2] = getArrayFromDictionary_double(dictionary, "g_data_viscosity");
                    ////Density
                    //simulator_data.g_data[3] = getArrayFromDictionary_double(dictionary, "g_data_density");
                }
                #endregion

                #region Boundary Conditions
                key = "initial_pressure";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.initial_pressure = double.Parse(dictionary[key]);
                }

                key = "boundary_flow_rate";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.boundary_flow_rate = getArrayFromDictionary_double(dictionary[key]);
                }
                else
                {
                    simulator_data.boundary_flow_rate = new double[size];
                }

                key = "boundary_pressure_x";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.boundary_pressure_x = getArrayFromDictionary_double(dictionary[key]);
                }
                else
                {
                    simulator_data.boundary_pressure_x = new double[size];
                }

                key = "boundary_pressure_y";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.boundary_pressure_y = getArrayFromDictionary_double(dictionary[key]);
                }
                else
                {
                    simulator_data.boundary_pressure_y = new double[size];
                }

                key = "boundary_pressure_gradient_x";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.boundary_pressure_gradient_x = getArrayFromDictionary_double(dictionary[key]);
                }
                else
                {
                    simulator_data.boundary_pressure_gradient_x = new double[size];
                }

                key = "boundary_pressure_gradient_y";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.boundary_pressure_gradient_y = getArrayFromDictionary_double(dictionary[key]);
                }
                else
                {
                    simulator_data.boundary_pressure_gradient_y = new double[size];
                }
                #endregion

                #region Well Data
                key = "well_locations";
                if (dictionary.ContainsKey(key))
                {
                    simulator_data.well_locations = getArrayFromDictionary_int(dictionary[key]);
                }


                int number_of_wells = simulator_data.well_locations.Length;

                simulator_data.well_array = new Well[size];

                for (int i = 1; i <= number_of_wells; i++)
                {
                    Well well = new Well();

                    double[] well_data = getArrayFromDictionary_double(dictionary["well_" + i]);
                    well.rw = well_data[0]; well.skin = well_data[1]; well.specified_BHP = well_data[2]; well.specified_flow_rate = well_data[3];
                    well.type_calculation = well_data[4] == 0 ? Well.TypeCalculation.Specified_BHP : Well.TypeCalculation.Specified_Flow_Rate;

                    int location = simulator_data.well_locations[i - 1];
                    simulator_data.well_array[location] = well;
                }
                #endregion
            }

            return(simulator_data);
        }
示例#3
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
        }