gas_sg_from_gradient
Calculate gas specific gravity from measured pressure gradient using Newton-Raphson solver for formation fluid identification and gas property verification when only gradient data is available.
Instructions
Calculate gas specific gravity from pressure gradient.
DIAGNOSTIC TOOL - Determines gas specific gravity from measured pressure gradient in a gas column. Uses standalone Newton-Raphson solver (fixed implementation) to solve the inverse problem. Essential for formation fluid identification and gas property verification when only gradient data is available.
Parameters:
gradient (float, required): Pressure gradient in psi/ft. Must be > 0. Typical: 0.05-0.15 psi/ft. Example: 0.1 psi/ft.
degf (float, required): Temperature in °F at measurement depth. Valid: -460 to 1000. Typical: 100-400°F. Example: 180.0.
p (float, required): Pressure in psia at measurement depth. Must be > 0. Example: 3500.0.
method (str, optional, default="DAK"): Z-factor method for calculation. Options: "DAK", "HY", "WYW", "BUR". DAK recommended.
Gradient Principle: Gas gradient = dP/dh = (ρg × g) / 144 = (P × MW) / (Z × R × T × 144)
Where:
ρg = gas density (lb/cuft)
MW = molecular weight = sg × 28.97 lb/lbmol
Z = gas compressibility factor
R = gas constant = 10.732 psia·ft³/(lbmol·°R)
T = temperature (°R = °F + 460)
Applications:
Formation Fluid ID: Identify gas vs oil vs water from gradient
Gas Density Verification: Check measured gas gravity against gradient
Completion Fluid Design: Design mud weight based on gas gradient
Wellbore Pressure Modeling: Calculate pressure profiles in gas columns
Typical Gradients:
Dry gas (sg=0.6): ~0.08 psi/ft
Associated gas (sg=0.8): ~0.11 psi/ft
Heavy gas (sg=1.0): ~0.14 psi/ft
Solution Method: Uses Newton-Raphson iterative solver to find sg that yields the specified gradient. This is a standalone fixed implementation that avoids upstream library bugs.
Returns: Dictionary with:
value (float): Gas specific gravity (dimensionless, air=1)
method (str): "Gradient correlation (Newton-Raphson)"
units (str): "dimensionless (air=1)"
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 accounting for non-hydrocarbon fractions (affects MW and Z)
Using wrong gradient units (must be psi/ft, not psi/100ft)
Temperature in Celsius instead of Fahrenheit
Example Usage:
Result: Gas SG ≈ 0.7-0.8 for typical natural gas gradient.
Note: This tool uses a standalone fixed implementation to avoid upstream bugs. Always use reservoir conditions (pressure and temperature at measurement depth). Gradient is sensitive to temperature - use correct temperature for accurate results.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
Implementation Reference
- The core handler function for the 'gas_sg_from_gradient' tool. Decorated with @mcp.tool() for automatic registration. Computes gas specific gravity using a fixed Newton-Raphson solver and returns formatted results.@mcp.tool() def gas_sg_from_gradient(request: GasSGFromGradientRequest) -> dict: """Calculate gas specific gravity from pressure gradient. **DIAGNOSTIC TOOL** - Determines gas specific gravity from measured pressure gradient in a gas column. Uses standalone Newton-Raphson solver (fixed implementation) to solve the inverse problem. Essential for formation fluid identification and gas property verification when only gradient data is available. **Parameters:** - **gradient** (float, required): Pressure gradient in psi/ft. Must be > 0. Typical: 0.05-0.15 psi/ft. Example: 0.1 psi/ft. - **degf** (float, required): Temperature in °F at measurement depth. Valid: -460 to 1000. Typical: 100-400°F. Example: 180.0. - **p** (float, required): Pressure in psia at measurement depth. Must be > 0. Example: 3500.0. - **method** (str, optional, default="DAK"): Z-factor method for calculation. Options: "DAK", "HY", "WYW", "BUR". DAK recommended. **Gradient Principle:** Gas gradient = dP/dh = (ρg × g) / 144 = (P × MW) / (Z × R × T × 144) Where: - ρg = gas density (lb/cuft) - MW = molecular weight = sg × 28.97 lb/lbmol - Z = gas compressibility factor - R = gas constant = 10.732 psia·ft³/(lbmol·°R) - T = temperature (°R = °F + 460) **Applications:** - **Formation Fluid ID:** Identify gas vs oil vs water from gradient - **Gas Density Verification:** Check measured gas gravity against gradient - **Completion Fluid Design:** Design mud weight based on gas gradient - **Wellbore Pressure Modeling:** Calculate pressure profiles in gas columns **Typical Gradients:** - Dry gas (sg=0.6): ~0.08 psi/ft - Associated gas (sg=0.8): ~0.11 psi/ft - Heavy gas (sg=1.0): ~0.14 psi/ft **Solution Method:** Uses Newton-Raphson iterative solver to find sg that yields the specified gradient. This is a standalone fixed implementation that avoids upstream library bugs. **Returns:** Dictionary with: - **value** (float): Gas specific gravity (dimensionless, air=1) - **method** (str): "Gradient correlation (Newton-Raphson)" - **units** (str): "dimensionless (air=1)" - **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 accounting for non-hydrocarbon fractions (affects MW and Z) - Using wrong gradient units (must be psi/ft, not psi/100ft) - Temperature in Celsius instead of Fahrenheit **Example Usage:** ```python { "gradient": 0.1, "degf": 180.0, "p": 3500.0, "method": "DAK" } ``` Result: Gas SG ≈ 0.7-0.8 for typical natural gas gradient. **Note:** This tool uses a standalone fixed implementation to avoid upstream bugs. Always use reservoir conditions (pressure and temperature at measurement depth). Gradient is sensitive to temperature - use correct temperature for accurate results. """ # Use fixed version that doesn't have the bisect_solve bug sg = gas_grad2sg_fixed( grad=request.grad, degf=request.degf, p=request.p, zmethod='DAK', cmethod='PMC', ) value = float(sg) return { "value": value, "method": "Gradient correlation (Newton-Raphson)", "units": "dimensionless (air=1)", "inputs": request.model_dump(), }
- Pydantic model defining the input schema (parameters: gradient, degf, p) with validation for the tool.class GasSGFromGradientRequest(BaseModel): """Request model for gas SG from pressure gradient.""" grad: Union[float, List[float]] = Field( ..., description="Pressure gradient (psi/ft) - scalar or array" ) degf: float = Field( ..., gt=-460, lt=1000, description="Temperature (degrees Fahrenheit)" ) p: float = Field(..., gt=0, description="Pressure (psia)")
- src/pyrestoolbox_mcp/server.py:25-25 (registration)Call to register_gas_tools(mcp) which defines and registers the gas tools including gas_sg_from_gradient to the MCP server instance.register_gas_tools(mcp)
- Helper function implementing the Newton-Raphson solver to compute gas SG from gradient, fixing bugs in the upstream pyrestoolbox library. Called by the main handler.def gas_grad2sg_fixed( grad: float, p: float, degf: float, zmethod: z_method = z_method.DAK, cmethod: c_method = c_method.PMC, co2: float = 0, h2s: float = 0, n2: float = 0, tc: float = 0, pc: float = 0, rtol: float = 1e-7, ) -> float: """Returns insitu gas specific gravity consistent with observed gas gradient. Fixed version of gas_grad2sg that doesn't rely on buggy bisect_solve. Uses Newton-Raphson iteration instead of bisection. Args: grad: Observed gas gradient (psi/ft) p: Pressure at observation (psia) degf: Reservoir Temperature (deg F) zmethod: Method for calculating Z-Factor cmethod: Method for calculating critical properties co2: Molar fraction of CO2 h2s: Molar fraction of H2S n2: Molar fraction of Nitrogen tc: Critical gas temperature (deg R) pc: Critical gas pressure (psia) rtol: Relative solution tolerance Returns: Gas specific gravity (air = 1.0) """ degR = degf + degF2R def calc_gradient(sg): """Calculate gradient for a given gas SG.""" m = sg * MW_AIR zee = gas.gas_z( p=p, degf=degf, sg=sg, zmethod=zmethod, cmethod=cmethod, co2=co2, h2s=h2s, n2=n2, tc=tc, pc=pc, ) grad_calc = p * m / (zee * R * degR) / 144 return grad_calc # Newton-Raphson iteration sg_guess = 0.7 # Initial guess max_iter = 50 for i in range(max_iter): grad_calc = calc_gradient(sg_guess) error = abs((grad - grad_calc) / grad) if error < rtol: return sg_guess # Numerical derivative delta = 0.001 grad_plus = calc_gradient(sg_guess + delta) derivative = (grad_plus - grad_calc) / delta # Newton-Raphson update if abs(derivative) > 1e-10: sg_new = sg_guess - (grad_calc - grad) / derivative # Keep within reasonable bounds sg_new = max(0.55, min(1.75, sg_new)) sg_guess = sg_new else: # If derivative is too small, use bisection fallback if grad_calc > grad: sg_guess *= 0.95 else: sg_guess *= 1.05 # Return best estimate even if not fully converged return sg_guess