//Method Name: getTransmissibility //Objectives: calculating the transmissibility between two blocks //Inputs: two variables of type "GridBlock", the value of the geometric factor and a variable of type "Phase" public static double getTransmissibility(GridBlock block_1, GridBlock block_2, double geometric_factor, Phase phase) { GridBlock upstream_block; double viscosity, FVF, Kr; //Check for Inactive blocks if (block_1.type == GridBlock.Type.Inactive || block_2.type == GridBlock.Type.Inactive) { return(0); } //Determine the upstream block if (block_1.pressure >= block_2.pressure) { upstream_block = block_1; } else { upstream_block = block_2; } //Assign the values of viscosity, FVF and Kr according to the appropriate phase if (phase == Phase.Oil) { viscosity = 2 / (1 / block_1.oil_viscosity + 1 / block_2.oil_viscosity); FVF = 2 / (1 / block_1.Bo + 1 / block_2.Bo); Kr = upstream_block.Kro; } else if (phase == Phase.Gas) { viscosity = 2 / (1 / block_1.gas_viscosity + 1 / block_2.gas_viscosity); FVF = 2 / (1 / block_1.Bg + 1 / block_2.Bg); Kr = upstream_block.Krg; } else { viscosity = 2 / (1 / block_1.water_viscosity + 1 / block_2.water_viscosity); FVF = 2 / (1 / block_1.Bw + 1 / block_2.Bw); //viscosity = upstream_block.water_viscosity; //FVF = upstream_block.Bw; Kr = upstream_block.Krw; } double T = geometric_factor * Kr / (viscosity * FVF); return(T); }
//Method Name: assignBlockOrdering_ActiveOnly //Objectives: this method is used for each "active block only" in the grid to assign its numbering and the numbering of neighbouring blocks //Inputs: a variable of type "GridBlock" that contains all the data of the block, a general counter of the loop, block counter, array of block coordinates, array of grid dimensions and an array of the natural ordering of the in-active blocks //Ouputs: N/A. This is an internal method that calculates the numbering and assign it to the variable "block" that is passed to this method private static void assignBlockOrdering_ActiveOnly(GridBlock block, int counter, int block_counter, int[] block_coordinates, int[] grid_diemnsions, int[] inactive_blocks) { int i, j, k; i = block_coordinates[0]; j = block_coordinates[1]; k = block_coordinates[2]; int x, y, z; x = grid_diemnsions[0]; y = grid_diemnsions[1]; z = grid_diemnsions[2]; block.counter = block_counter; block.east_counter = getNextBlockCounter(Direction.East, block_counter, counter, inactive_blocks, grid_diemnsions, block_coordinates); block.west_counter = getNextBlockCounter(Direction.West, block_counter, counter, inactive_blocks, grid_diemnsions, block_coordinates); block.north_counter = getNextBlockCounter(Direction.North, block_counter, counter, inactive_blocks, grid_diemnsions, block_coordinates); block.south_counter = getNextBlockCounter(Direction.South, block_counter, counter, inactive_blocks, grid_diemnsions, block_coordinates); block.top_counter = getNextBlockCounter(Direction.Top, block_counter, counter, inactive_blocks, grid_diemnsions, block_coordinates); block.bottom_counter = getNextBlockCounter(Direction.Bottom, block_counter, counter, inactive_blocks, grid_diemnsions, block_coordinates); }
//Method Name: assignBlockOrdering_Natural //Objectives: this method is used for each block "both active and in-active" in the grid to assign its numbering and the numbering of neighbouring blocks //Inputs: a variable of type "GridBlock" that contains all the data of the block, a general counter of the loop, array of block coordinates, array of grid dimensions and an array of the natural ordering of the in-active blocks //Ouputs: N/A. This is an internal method that calculates the numbering and assign it to the variable "block" that is passed to this method private static void assignBlockOrdering_Natural(GridBlock block, int counter, int[] block_dimensions, int[] grid_diemnsions, int[] inactive_blocks) { int i, j, k; i = block_dimensions[0]; j = block_dimensions[1]; k = block_dimensions[2]; int x, y, z; x = grid_diemnsions[0]; y = grid_diemnsions[1]; z = grid_diemnsions[2]; block.counter = counter; block.east_counter = i < (x - 1) ? counter + 1 : -1; block.west_counter = i > 0 ? counter - 1 : -1; block.north_counter = j < (y - 1) ? counter + x : -1; block.south_counter = j > 0 ? counter - x : -1; block.top_counter = k > 0 ? (k - 1) : -1; block.bottom_counter = k < (z - 1) ? (k + 1) : -1; }
//Homogeneous grid public static double getGeometricFactor(GridBlock block, GridType type, Direction direction) { double area, length, permeability, G; //Rectangular grid if (type == GridType.Rectangular) { if (direction == Direction.x) { area = block.delta_y * block.h; length = block.delta_x; permeability = block.Kx; } else if (direction == Direction.y) { area = block.delta_x * block.h; length = block.delta_y; permeability = block.Ky; } else { area = block.delta_x * block.delta_y; length = block.h; permeability = block.Kz; } G = Bc * permeability * area / length; return(G); } //Cylindrical grid else { //To-Do: implement this method return(0); } }
//Method Name: getGeometricFactor //Objectives: calculate the geometric factor of the well if it is perfectly centred within a grid block //Inputs: a variable of type "GridBlock" //Outputs: the value of the geometric factor of the well public static double getGeometricFactor(GridBlock block) { double r_equivalent; double Kh; if (block.delta_x == block.delta_y && block.Kx == block.Ky) { r_equivalent = 0.198 * block.delta_x; } else if (block.delta_x == block.delta_y) { r_equivalent = 0.14 * Math.Sqrt(Math.Pow(block.delta_x, 2) + Math.Pow(block.delta_y, 2)); } else { r_equivalent = 0.28 * Math.Sqrt(Math.Sqrt(block.Ky / block.Kx) * Math.Pow(block.delta_x, 2) + Math.Sqrt(block.Kx / block.Ky) * Math.Pow(block.delta_y, 2)) / (Math.Pow((block.Ky / block.Kx), 0.25) + Math.Pow((block.Kx / block.Ky), 0.25)); } Kh = Math.Sqrt(block.Kx * block.Ky); double G = 2 * Math.PI * Bc * Kh * block.h / (Math.Log(r_equivalent / (block.rw / 12)) + block.skin); return(G); }
//Method Name: assignGridOrdering //Objectives: gives each block in the grid a number according to the numbering scheme used //Inputs: an array of the (x, y, z) grid dimensions and an array of the Inactive blocks numberings //Ouputs: an array of GridBlocks that are given numbers according to the numbering scheme used public static GridBlock[] assignGridOrdering(int[] grid_dimensions, int[] inactive_blocks, NumberingScheme scheme) { //variables to store the grid dimensions int x, y, z; //store the grid dimensions x = grid_dimensions[0]; y = grid_dimensions[1]; z = grid_dimensions[2]; //an array to store a block's i, j and k coordinates within the grid according to the engineering notation int[] block_coordinates = new int[3]; //A variable to store block's data GridBlock block; //A variable representing the grid array of blocks GridBlock[] grid = new GridBlock[0]; if (scheme == NumberingScheme.All) { //Grid array size is equal to all the block "including in-active blocks" grid = new GridBlock[x * y * z]; } else if (scheme == NumberingScheme.Active_Only) { //Grid array size is equal to the number of active-only blocks grid = new GridBlock[x * y * z - inactive_blocks.Length]; } //A general loop counter int counter = 0; //A block counter //This variable is used only with the "assignBlockOrdering_ActiveOnly" method to keep track of the number of active blocks added to the grid int block_counter = 0; //A loop to iterate over all the blocks in the grid according to the engineering notation for (int k = 0; k < z; k++) { for (int j = 0; j < y; j++) { for (int i = 0; i < x; i++) { block = new GridBlock(); //assign the values of the block coordinates block.x = i; block.y = j; block.z = k; //set block type "either Inactive or normal" if (inactive_blocks.Contains(counter)) { block.type = GridBlock.Type.Inactive; } //set the block coordinates array that will be passed to other methods block_coordinates[0] = i; block_coordinates[1] = j; block_coordinates[2] = k; //########################################################################################### if (scheme == NumberingScheme.All) { //Natural ordering for the entire grid "both active and in-active blocks" RectangularBlockNumbering.assignBlockOrdering_Natural(block, counter, block_coordinates, grid_dimensions, inactive_blocks); } else if (scheme == NumberingScheme.Active_Only) { //Natural ordering for the grid "active blocks only" if (block.type == GridBlock.Type.Inactive) { //increment the general loop counter and skip this block counter += 1; continue; } RectangularBlockNumbering.assignBlockOrdering_ActiveOnly(block, counter, block_counter, block_coordinates, grid_dimensions, inactive_blocks); } //########################################################################################### //increment counter at the end of the loop counter += 1; //this statement adds the block to the grid array grid[block_counter] = block; //only increment block_counter when a block is added to the grid to keep track of how many blocks have been added block_counter += 1; } } } return(grid); }
public static double calculate_BHP(GridBlock block) { return(block.pressure - (block.well_flow_rate / block.well_transmissibility)); }