Skip to main content
Glama

pyResToolbox MCP Server

oil_rate_radial

Calculate oil production rates for vertical wells using radial flow analysis with Darcy's law. Automatically computes PVT properties and applies Vogel IPR model for two-phase flow below bubble point pressure.

Instructions

Calculate oil production rate for radial flow (vertical well).

INFLOW PERFORMANCE TOOL - Computes oil production rate for vertical wells with radial flow geometry using Darcy's law. Automatically calculates PVT properties (Rs, Bo, μo) at average pressure. Optionally applies Vogel IPR model for two-phase flow below bubble point.

Parameters:

  • pi (float, required): Initial/reservoir pressure in psia. Must be > 0. Example: 4000.0.

  • pb (float, required): Bubble point pressure in psia. Must be ≥ 0. Example: 3500.0. If pi < pb, reservoir is saturated (gas cap present).

  • api (float, required): Oil API gravity in degrees. Valid: 0-100. Example: 35.0.

  • degf (float, required): Reservoir temperature in °F. Valid: -460 to 1000. Example: 180.0.

  • sg_g (float, required): Gas specific gravity (air=1). Valid: 0-3. Typical: 0.6-1.2. Example: 0.75.

  • psd (float or list, required): Sandface/draining pressure(s) in psia. Must be > 0 and < pi. Can be scalar or array. Example: 1500.0 or [1000, 1500, 2000].

  • h (float, required): Net pay thickness in feet. Must be > 0. Typical: 10-200 ft. Example: 50.0.

  • k (float, required): Permeability in millidarcies (mD). Must be > 0. Typical: 1-1000 mD. Example: 100.0.

  • s (float, optional, default=0.0): Skin factor (dimensionless). Negative = stimulation, positive = damage. Typical: -5 to +20. Example: 0.0 for undamaged well.

  • re (float, required): Drainage radius in feet. Must be > rw. Typical: 500-5000 ft. Example: 1000.0.

  • rw (float, required): Wellbore radius in feet. Must be > 0. Typical: 0.25-0.5 ft. Example: 0.5.

  • rsb (float, required): Solution GOR at bubble point in scf/stb. Must be ≥ 0. Example: 800.0.

  • vogel (bool, optional, default=False): Apply Vogel IPR model. Set True when pi < pb (saturated reservoir). Example: False.

Flow Regime:

  • Undersaturated (pi > pb): Single-phase oil flow, Darcy's law applies

  • Saturated (pi < pb): Two-phase flow, use Vogel=True for accurate IPR

Darcy's Law Formula: qo = (0.00708 × k × h × (pi - pwf)) / (μo × Bo × (ln(re/rw) + S))

Where PVT properties (μo, Bo) are calculated at average pressure (pi + pwf)/2.

Returns: Dictionary with:

  • value (float or list): Oil rate in STB/day (matches input psd shape)

  • method (str): "Darcy radial flow" or "Vogel IPR"

  • units (str): "STB/day"

  • inputs (dict): Echo of input parameters

Common Mistakes:

  • Using separator temperature instead of reservoir temperature

  • Pressure in barg/psig instead of psia (must be absolute)

  • Not setting vogel=True when pi < pb (underestimates rate)

  • Using wrong drainage radius (re) - should be well spacing/2

  • Confusing net pay (h) with gross thickness

  • Not accounting for skin factor (s)

Example Usage:

{ "pi": 4000.0, "pb": 3500.0, "api": 35.0, "degf": 180.0, "sg_g": 0.75, "psd": [1500, 2000, 2500], "h": 50.0, "k": 100.0, "s": 0.0, "re": 1000.0, "rw": 0.5, "rsb": 800.0, "vogel": False }

Result: Oil rate decreases as sandface pressure increases (typical IPR curve).

Note: This tool automatically calculates PVT properties. You don't need to provide Rs, Bo, or μo - they are computed internally at average pressure. For saturated reservoirs (pi < pb), set vogel=True for accurate two-phase flow.

Input Schema

NameRequiredDescriptionDefault
requestYes

Input Schema (JSON Schema)

{ "properties": { "request": { "$ref": "#/$defs/OilRateRadialRequest" } }, "required": [ "request" ], "type": "object" }

Implementation Reference

  • The main handler function for the 'oil_rate_radial' tool. It validates input using OilRateRadialRequest, computes necessary PVT properties using pyrestoolbox, and calls oil.oil_rate_radial to calculate the oil production rate for radial flow in vertical wells, supporting both single-phase Darcy flow and Vogel IPR for two-phase flow.
    @mcp.tool() def oil_rate_radial(request: OilRateRadialRequest) -> dict: """Calculate oil production rate for radial flow (vertical well). **INFLOW PERFORMANCE TOOL** - Computes oil production rate for vertical wells with radial flow geometry using Darcy's law. Automatically calculates PVT properties (Rs, Bo, μo) at average pressure. Optionally applies Vogel IPR model for two-phase flow below bubble point. **Parameters:** - **pi** (float, required): Initial/reservoir pressure in psia. Must be > 0. Example: 4000.0. - **pb** (float, required): Bubble point pressure in psia. Must be ≥ 0. Example: 3500.0. If pi < pb, reservoir is saturated (gas cap present). - **api** (float, required): Oil API gravity in degrees. Valid: 0-100. Example: 35.0. - **degf** (float, required): Reservoir temperature in °F. Valid: -460 to 1000. Example: 180.0. - **sg_g** (float, required): Gas specific gravity (air=1). Valid: 0-3. Typical: 0.6-1.2. Example: 0.75. - **psd** (float or list, required): Sandface/draining pressure(s) in psia. Must be > 0 and < pi. Can be scalar or array. Example: 1500.0 or [1000, 1500, 2000]. - **h** (float, required): Net pay thickness in feet. Must be > 0. Typical: 10-200 ft. Example: 50.0. - **k** (float, required): Permeability in millidarcies (mD). Must be > 0. Typical: 1-1000 mD. Example: 100.0. - **s** (float, optional, default=0.0): Skin factor (dimensionless). Negative = stimulation, positive = damage. Typical: -5 to +20. Example: 0.0 for undamaged well. - **re** (float, required): Drainage radius in feet. Must be > rw. Typical: 500-5000 ft. Example: 1000.0. - **rw** (float, required): Wellbore radius in feet. Must be > 0. Typical: 0.25-0.5 ft. Example: 0.5. - **rsb** (float, required): Solution GOR at bubble point in scf/stb. Must be ≥ 0. Example: 800.0. - **vogel** (bool, optional, default=False): Apply Vogel IPR model. Set True when pi < pb (saturated reservoir). Example: False. **Flow Regime:** - **Undersaturated (pi > pb)**: Single-phase oil flow, Darcy's law applies - **Saturated (pi < pb)**: Two-phase flow, use Vogel=True for accurate IPR **Darcy's Law Formula:** qo = (0.00708 × k × h × (pi - pwf)) / (μo × Bo × (ln(re/rw) + S)) Where PVT properties (μo, Bo) are calculated at average pressure (pi + pwf)/2. **Returns:** Dictionary with: - **value** (float or list): Oil rate in STB/day (matches input psd shape) - **method** (str): "Darcy radial flow" or "Vogel IPR" - **units** (str): "STB/day" - **inputs** (dict): Echo of input parameters **Common Mistakes:** - Using separator temperature instead of reservoir temperature - Pressure in barg/psig instead of psia (must be absolute) - Not setting vogel=True when pi < pb (underestimates rate) - Using wrong drainage radius (re) - should be well spacing/2 - Confusing net pay (h) with gross thickness - Not accounting for skin factor (s) **Example Usage:** ```python { "pi": 4000.0, "pb": 3500.0, "api": 35.0, "degf": 180.0, "sg_g": 0.75, "psd": [1500, 2000, 2500], "h": 50.0, "k": 100.0, "s": 0.0, "re": 1000.0, "rw": 0.5, "rsb": 800.0, "vogel": False } ``` Result: Oil rate decreases as sandface pressure increases (typical IPR curve). **Note:** This tool automatically calculates PVT properties. You don't need to provide Rs, Bo, or μo - they are computed internally at average pressure. For saturated reservoirs (pi < pb), set vogel=True for accurate two-phase flow. """ # Convert psd to numpy array for processing psd_array = np.asarray(request.psd) is_scalar = psd_array.ndim == 0 if is_scalar: psd_array = np.array([psd_array]) # Calculate oil specific gravity from API sg_o = oil.oil_sg(api_value=request.api) # Calculate solution GOR at sandface pressure(s) # oil_rs uses sg_sp (separator gas SG), use sg_g as separator gas SG rs_values = oil.oil_rs( api=request.api, degf=request.degf, p=psd_array, sg_sp=request.sg_g, # Use sg_g as separator gas SG pb=request.pb, rsb=request.rsb, rsmethod=rs_method.VELAR, ) # Calculate PVT properties at sandface pressure(s) # Use average pressure for PVT calculation (between reservoir and sandface) avg_pressures = (request.pi + psd_array) / 2.0 # Calculate Rs at average pressures for PVT rs_avg = oil.oil_rs( api=request.api, degf=request.degf, p=avg_pressures, sg_sp=request.sg_g, # Use sg_g as separator gas SG pb=request.pb, rsb=request.rsb, rsmethod=rs_method.VELAR, ) # Calculate Bo and uo at average pressures bo_values = oil.oil_bo( p=avg_pressures, pb=request.pb, degf=request.degf, rs=rs_avg, rsb=request.rsb, sg_o=sg_o, sg_g=request.sg_g, bomethod=bo_method.MCAIN, ) uo_values = oil.oil_viso( p=avg_pressures, api=request.api, degf=request.degf, pb=request.pb, rs=rs_avg, ) # Convert to scalars if needed if is_scalar: bo_values = float(bo_values[0]) if isinstance(bo_values, np.ndarray) else float(bo_values) uo_values = float(uo_values[0]) if isinstance(uo_values, np.ndarray) else float(uo_values) psd_array = psd_array[0] # Call oil_rate_radial with correct parameters qo = oil.oil_rate_radial( k=request.k, h=request.h, pr=request.pi, pwf=psd_array, r_w=request.rw, r_ext=request.re, uo=uo_values, bo=bo_values, S=request.s, vogel=request.vogel, pb=request.pb, ) # Convert numpy array to list for JSON serialization if isinstance(qo, np.ndarray): value = qo.tolist() else: value = float(qo) method = "Darcy radial flow" # Ensure scalar comparison (not array) to avoid "ambiguous truth value" error pi_scalar = float(request.pi) if isinstance(request.pi, (np.ndarray, list)) else request.pi pb_scalar = float(request.pb) if isinstance(request.pb, (np.ndarray, list)) else request.pb if request.vogel and pi_scalar < pb_scalar: method = "Vogel IPR" return { "value": value, "method": method, "units": "STB/day", "inputs": request.model_dump(), }
  • Pydantic BaseModel defining the input schema and validation rules for the oil_rate_radial tool parameters.
    class OilRateRadialRequest(BaseModel): """Request model for radial oil inflow performance calculation.""" pi: float = Field(..., gt=0, description="Initial reservoir pressure (psia)") pb: float = Field(..., ge=0, description="Bubble point pressure (psia)") api: float = Field(..., gt=0, le=100, description="Oil API gravity (degrees)") degf: float = Field( ..., gt=-460, lt=1000, description="Temperature (degrees Fahrenheit)" ) sg_g: float = Field( ..., ge=0, le=3, description="Gas specific gravity (air=1, dimensionless)" ) psd: Union[float, List[float]] = Field( ..., description="Sandface pressure (psia) - scalar or array" ) h: float = Field(..., gt=0, description="Net pay thickness (ft)") k: float = Field(..., gt=0, description="Permeability (mD)") s: float = Field(0.0, description="Skin factor (dimensionless)") re: float = Field(..., gt=0, description="Drainage radius (ft)") rw: float = Field(..., gt=0, description="Wellbore radius (ft)") rsb: float = Field( 0.0, ge=0, description="Solution GOR at bubble point (scf/stb)" ) vogel: bool = Field( False, description="Use Vogel IPR for reservoir pressure below bubble point" ) @field_validator("psd") @classmethod def validate_pressure(cls, v): """Validate pressure values.""" if isinstance(v, list): if not all(p > 0 for p in v): raise ValueError("All sandface pressure values must be positive") else: if v <= 0: raise ValueError("Sandface pressure must be positive") return v @field_validator("rw") @classmethod def validate_rw(cls, v, info): """Validate wellbore radius is less than drainage radius.""" if "re" in info.data and v >= info.data["re"]: raise ValueError("Wellbore radius must be less than drainage radius") return v
  • Main server file where register_inflow_tools(mcp) is called, which in turn defines and registers the oil_rate_radial tool using @mcp.tool() decorator.
    from .tools.oil_tools import register_oil_tools from .tools.gas_tools import register_gas_tools from .tools.inflow_tools import register_inflow_tools from .tools.simtools_tools import register_simtools_tools from .tools.brine_tools import register_brine_tools from .tools.layer_tools import register_layer_tools from .tools.library_tools import register_library_tools register_oil_tools(mcp) register_gas_tools(mcp) register_inflow_tools(mcp) register_simtools_tools(mcp) register_brine_tools(mcp) register_layer_tools(mcp) register_library_tools(mcp)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gabrielserrao/pyrestoolbox-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server