/// <summary> /// Gets the well mobility of a certain phase at a specified time level. /// </summary> /// <param name="data">The data.</param> /// <param name="phase">The phase.</param> /// <param name="timeLevel">The time level.</param> /// <returns></returns> /// <seealso cref="Global.STEPS_MEMORY"/> public double GetWellMobility(SimulationData data, Global.Phase phase, int timeLevel) { BaseBlock block = data.grid[this.index]; if (phase == Global.Phase.Oil) { return(block.Kro[timeLevel] / (block.viscosityOil[timeLevel] * block.Bo[timeLevel])); } else if (phase == Global.Phase.Gas) { return(block.Krg[timeLevel] / (block.viscosityGas[timeLevel] * block.Bg[timeLevel])); } else { return(block.Krw[timeLevel] / (block.viscosityWater[timeLevel] * block.Bw[timeLevel])); } }
/// <summary> /// Gets the relative permeability for a certain phase. /// </summary> /// <param name="phase">The phase.</param> /// <param name="saturation">The saturation.</param> /// <returns>The value of the relative permeability</returns> /// <seealso cref="Global.Phase"/> public double GetKr(Global.Phase phase, double saturation) { switch (phase) { case Global.Phase.Water: return(GetKrw(saturation)); case Global.Phase.Oil: return(GetKro(saturation)); case Global.Phase.Gas: return(GetKrg(saturation)); default: return(1); } }
// The publicly accessible methods. /// <summary> /// Gets the FVF of a certain phase. /// </summary> /// <param name="phase">The phase.</param> /// <param name="pressure">The pressure.</param> /// <returns>The value of FVF</returns> /// <seealso cref="Global.Phase"/> public double GetFVF(Global.Phase phase, double pressure) { switch (phase) { case Global.Phase.Water: return(GetWaterFVF(pressure)); case Global.Phase.Oil: return(GetOilFVF(pressure)); case Global.Phase.Gas: return(GetGasFVF(pressure) * Global.a); default: return(1); } }
/// <summary> /// Gets the solution Gas/Oil ratio. /// </summary> /// <param name="phase">The phase.</param> /// <param name="pressure">The pressure.</param> /// <returns>The value of RsO.</returns> public double GetRs(Global.Phase phase, double pressure) { switch (phase) { case Global.Phase.Water: return(GetRsw(pressure)); case Global.Phase.Oil: return(GetRso(pressure) / Global.a); case Global.Phase.Gas: return(1); default: return(1); } }
/// <summary> /// Gets the density of a certain phase. /// </summary> /// <param name="phase">The phase.</param> /// <param name="pressure">The pressure.</param> /// <returns>The value of density</returns> /// <seealso cref="Global.Phase"/> public double GetDensity(Global.Phase phase, double pressure) { switch (phase) { case Global.Phase.Water: return(GetWaterDensity(pressure)); case Global.Phase.Oil: return(GetOilDensity(pressure)); case Global.Phase.Gas: return(GetGasDensity(pressure)); default: return(1); } }
//public static double getQ_P(this BaseBlock block, SimulationData data) //{ //} /// <summary> /// Gets the residual equation result multiplied by -1. /// </summary> /// <param name="block">The block.</param> /// <param name="data">The <seealso cref="SimulationData"/> data.</param> /// <param name="phase">The phase.</param> /// <returns></returns> public static double getminus_R(this BaseBlock block, SimulationData data, Global.Phase phase) { double R = 0; if (phase == Global.Phase.Oil) { R = -1 / (Global.a * data.timeStep) * (block.Vp[1] * (1 - block.Sg[1]) / block.Bo[1] - block.Vp[0] * (1 - block.Sg[0]) / block.Bo[0]) /*- block.q_oil[1]*/; } else if (phase == Global.Phase.Gas) { R = -1 / (Global.a * data.timeStep) * (block.Vp[1] * block.Sg[1] / block.Bg[1] - block.Vp[0] * block.Sg[0] / block.Bg[0]) /*- block.q_gas[1]*/; if (data.solubleGasPresent) { R += -1 / (Global.a * data.timeStep) * (block.Rso[1] * block.Vp[1] * (1 - block.Sg[1]) / block.Bo[1] - block.Rso[0] * block.Vp[0] * (1 - block.Sg[0]) / block.Bo[0]) /*- block.Rso[1] * block.q_oil[1]*/; } } return(-1 * R); }
// calculates d(1/B)/dP. private static double FVF_dash(this BaseBlock block, Global.Phase phase) { double P_difference = block.P[1] - block.P[0]; double FVF_1 = 1, FVF_0 = 1; if (phase == Global.Phase.Oil) { FVF_1 = block.Bo[1]; FVF_0 = block.Bo[0]; } else if (phase == Global.Phase.Water) { FVF_1 = block.Bw[1]; FVF_0 = block.Bw[0]; } else { FVF_1 = block.Bg[1]; FVF_0 = block.Bg[0]; } return((1 / FVF_1 - 1 / FVF_0) / (P_difference)); }
// perturb the residual equation "calculate at independent variable + epsilon". // the perturbed value will then be subtracted from the original R value and divided by epsilon to get the derivative numerically. private static double Perturb(this BaseBlock block, SimulationData data, Global.Phase equation_phase, int neighbour_block_index, Global.Variable variable) { double R_plus = 0; double transmissibility_temp = 0; double transmissibility_term = 0; double accumulation_term = 0; double kr, viscosity, B, Rso; BaseBlock upstream_block, downstream_block, neighbor_block; double transmissiblity; #region Variable Dependencies int pd = 1, npd = 1, swd = 1, nswd = 1, sgd = 1, nsgd = 1; bool this_block = true; if (neighbour_block_index == -1) { this_block = true; } else { this_block = false; } if (variable == Global.Variable.Pressure) { if (this_block) { pd = 2; } else { npd = 2; } } else if (variable == Global.Variable.SaturationGas) { if (this_block) { sgd = 2; } else { nsgd = 2; } } else if (variable == Global.Variable.SaturationWater) { if (this_block) { swd = 2; } else { nswd = 2; } } #endregion if (equation_phase == Global.Phase.Oil) { if (this_block) { // transmissibility term for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (block.neighborBlocksIndices[i] == -1) { continue; } neighbor_block = data.grid[block.neighborBlocksIndices[i]]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; kr = upstream_block.Kro[sgd]; } else { upstream_block = neighbor_block; downstream_block = block; kr = upstream_block.Kro[nsgd]; } B = 0.5 * (block.Bo[pd] + neighbor_block.Bo[npd]); viscosity = 0.5 * (block.viscosityOil[pd] + neighbor_block.viscosityOil[npd]); transmissiblity = block.transmissibility_list[i]; transmissibility_temp = transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); transmissibility_term += transmissibility_temp; } // accumulation term accumulation_term = 1 / (data.timeStep * Global.a) * ((block.Vp[pd] * (1 - block.Sg[sgd] - block.Sw[swd]) / block.Bo[pd]) - (block.Vp[0] * block.So[0] / block.Bo[0])); } else { // transmissibility term neighbor_block = data.grid[block.neighborBlocksIndices[neighbour_block_index]]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; kr = upstream_block.Kro[sgd]; } else { upstream_block = neighbor_block; downstream_block = block; kr = upstream_block.Kro[nsgd]; } B = 0.5 * (block.Bo[pd] + neighbor_block.Bo[npd]); viscosity = 0.5 * (block.viscosityOil[pd] + neighbor_block.viscosityOil[npd]); transmissiblity = block.transmissibility_list[neighbour_block_index]; transmissibility_temp = transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); transmissibility_term = transmissibility_temp; for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (i == neighbour_block_index) { continue; } transmissibility_term += block.transmissibility_terms_oil[i]; } // accumulation term accumulation_term = block.accumulation_term_oil; } } else if (equation_phase == Global.Phase.Gas) { if (this_block) { // transmissibility term for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (block.neighborBlocksIndices[i] == -1) { continue; } neighbor_block = data.grid[block.neighborBlocksIndices[i]]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; kr = upstream_block.Krg[sgd]; } else { upstream_block = neighbor_block; downstream_block = block; kr = upstream_block.Krg[nsgd]; } B = 0.5 * (block.Bg[pd] + neighbor_block.Bg[npd]); viscosity = 0.5 * (block.viscosityGas[pd] + neighbor_block.viscosityGas[npd]); transmissiblity = block.transmissibility_list[i]; transmissibility_temp = transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); if (data.solubleGasPresent) { if (upstream_block.index == block.index) { kr = upstream_block.Kro[sgd]; } else { kr = upstream_block.Kro[nsgd]; } Rso = 0.5 * (block.Rso[pd] + neighbor_block.Rso[npd]); B = 0.5 * (block.Bo[pd] + neighbor_block.Bo[npd]); viscosity = 0.5 * (block.viscosityOil[pd] + neighbor_block.viscosityOil[npd]); transmissibility_temp += Rso * transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); } transmissibility_term += transmissibility_temp; } // accumulation term accumulation_term = 1 / (data.timeStep * Global.a) * ((block.Vp[pd] * block.Sg[sgd] / block.Bg[pd]) - (block.Vp[0] * block.Sg[0] / block.Bg[0])); if (data.solubleGasPresent) { accumulation_term += 1 / (data.timeStep * Global.a) * (block.Rso[pd] * (block.Vp[pd] * (1 - block.Sg[sgd] - block.Sw[swd]) / block.Bo[pd]) - block.Rso[0] * (block.Vp[0] * block.So[0] / block.Bo[0])); } } else { // transmissibility term neighbor_block = data.grid[block.neighborBlocksIndices[neighbour_block_index]]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; kr = upstream_block.Krg[sgd]; } else { upstream_block = neighbor_block; downstream_block = block; kr = upstream_block.Krg[nsgd]; } B = 0.5 * (block.Bg[pd] + neighbor_block.Bg[npd]); viscosity = 0.5 * (block.viscosityGas[pd] + neighbor_block.viscosityGas[npd]); transmissiblity = block.transmissibility_list[neighbour_block_index]; transmissibility_temp = transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); if (data.solubleGasPresent) { if (upstream_block.index == block.index) { kr = upstream_block.Kro[sgd]; } else { kr = upstream_block.Kro[nsgd]; } Rso = 0.5 * (block.Rso[pd] + neighbor_block.Rso[npd]); B = 0.5 * (block.Bo[pd] + neighbor_block.Bo[npd]); viscosity = 0.5 * (block.viscosityOil[pd] + neighbor_block.viscosityOil[npd]); transmissibility_temp += Rso * transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); } transmissibility_term = transmissibility_temp; for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (i == neighbour_block_index) { continue; } transmissibility_term += block.transmissibility_terms_gas[i]; } // accumulation term accumulation_term = block.accumulation_term_gas; } } else if (equation_phase == Global.Phase.Water) { if (this_block) { // transmissibility term for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (block.neighborBlocksIndices[i] == -1) { continue; } neighbor_block = data.grid[block.neighborBlocksIndices[i]]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; kr = upstream_block.Krw[swd]; } else { upstream_block = neighbor_block; downstream_block = block; kr = upstream_block.Krw[nswd]; } B = 0.5 * (block.Bw[pd] + neighbor_block.Bw[npd]); viscosity = 0.5 * (block.viscosityWater[pd] + neighbor_block.viscosityWater[npd]); transmissiblity = block.transmissibility_list[i]; transmissibility_temp = transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); transmissibility_term += transmissibility_temp; } // accumulation term accumulation_term = 1 / (data.timeStep * Global.a) * ((block.Vp[pd] * block.Sw[swd] / block.Bw[pd]) - (block.Vp[0] * block.Sw[0] / block.Bw[0])); } else { // transmissibility term neighbor_block = data.grid[block.neighborBlocksIndices[neighbour_block_index]]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; kr = upstream_block.Krw[swd]; } else { upstream_block = neighbor_block; downstream_block = block; kr = upstream_block.Krw[nswd]; } B = 0.5 * (block.Bw[pd] + neighbor_block.Bw[npd]); viscosity = 0.5 * (block.viscosityWater[pd] + neighbor_block.viscosityWater[npd]); transmissiblity = block.transmissibility_list[neighbour_block_index]; transmissibility_temp = transmissiblity * kr / (viscosity * B) * (neighbor_block.P[npd] - block.P[pd]); transmissibility_term = transmissibility_temp; for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (i == neighbour_block_index) { continue; } transmissibility_term += block.transmissibility_terms_water[i]; } // accumulation term accumulation_term = block.accumulation_term_water; } } R_plus = transmissibility_term - accumulation_term; return(R_plus); }
// calculate the value of the residual equation for any phase. private static double CalculateR(this BaseBlock block, SimulationData data, Global.Phase phase) { // Note : Kro, Krw, Krg are all calculated based on Sg. BaseBlock upstream_block, downstream_block, neighbor_block; double transmissibility; double Kr, B, viscosity, Rso; double R = 0; double temp, accumulation_term; if (phase == Global.Phase.Oil) { for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (block.neighborBlocksIndices[i] < 0) { continue; } neighbor_block = data.grid[block.neighborBlocksIndices[i]]; transmissibility = block.transmissibility_list[i]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; } else { upstream_block = neighbor_block; downstream_block = block; } Kr = upstream_block.Kro[1]; B = 0.5 * (block.Bo[1] + neighbor_block.Bo[1]); viscosity = 0.5 * (block.viscosityOil[1] + neighbor_block.viscosityOil[1]); temp = transmissibility * Kr / (viscosity * B) * (neighbor_block.P[1] - block.P[1]); block.transmissibility_terms_oil[i] = temp; R += temp; } accumulation_term = 1 / (Global.a * data.timeStep) * ((block.Vp[1] * (1 - block.Sw[1] - block.Sg[1]) / block.Bo[1]) - (block.Vp[0] * block.So[0] / block.Bo[0])); block.accumulation_term_oil = accumulation_term; R -= accumulation_term; } else if (phase == Global.Phase.Water) { for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (block.neighborBlocksIndices[i] < 0) { continue; } neighbor_block = data.grid[block.neighborBlocksIndices[i]]; transmissibility = block.transmissibility_list[i]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; } else { upstream_block = neighbor_block; downstream_block = block; } Kr = upstream_block.Krw[1]; B = 0.5 * (block.Bw[1] + neighbor_block.Bw[1]); viscosity = 0.5 * (block.viscosityWater[1] + neighbor_block.viscosityWater[1]); temp = transmissibility * Kr / (viscosity * B) * (neighbor_block.P[1] - block.P[1]); block.transmissibility_terms_water[i] = temp; R += temp; } accumulation_term = 1 / (Global.a * data.timeStep) * ((block.Vp[1] * block.Sw[1] / block.Bw[1]) - (block.Vp[0] * block.Sw[0] / block.Bw[0])); block.accumulation_term_water = accumulation_term; R -= accumulation_term; } else { for (int i = 0; i < block.neighborBlocksIndices.Length; i++) { if (block.neighborBlocksIndices[i] < 0) { continue; } neighbor_block = data.grid[block.neighborBlocksIndices[i]]; transmissibility = block.transmissibility_list[i]; if (block.P[1] >= neighbor_block.P[1]) { upstream_block = block; downstream_block = neighbor_block; } else { upstream_block = neighbor_block; downstream_block = block; } Kr = upstream_block.Krg[1]; B = 0.5 * (block.Bg[1] + neighbor_block.Bg[1]); viscosity = 0.5 * (block.viscosityGas[1] + neighbor_block.viscosityGas[1]); temp = transmissibility * Kr / (viscosity * B) * (neighbor_block.P[1] - block.P[1]); if (data.solubleGasPresent) { Kr = upstream_block.Kro[1]; B = 0.5 * (block.Bo[1] + neighbor_block.Bo[1]); viscosity = 0.5 * (block.viscosityOil[1] + neighbor_block.viscosityOil[1]); Rso = 0.5 * (block.Rso[1] + neighbor_block.Rso[1]); temp += Rso * transmissibility * Kr / (viscosity * B) * (neighbor_block.P[1] - block.P[1]); //temp += Rso * block.transmissibility_terms_oil[i]; } block.transmissibility_terms_gas[i] = temp; R += temp; } accumulation_term = 1 / (Global.a * data.timeStep) * ((block.Vp[1] * block.Sg[1] / block.Bg[1]) - (block.Vp[0] * block.Sg[0] / block.Bg[0])); // check for presence of soluble_gas in simulation_data if (data.solubleGasPresent) { accumulation_term += 1 / (Global.a * data.timeStep) * ((block.Rso[1] * block.Vp[1] * (1 - block.Sw[1] - block.Sg[1]) / block.Bo[1]) - (block.Rso[0] * block.Vp[0] * block.So[0] / block.Bo[0])); } block.accumulation_term_gas = accumulation_term; R -= accumulation_term; } return(R); }