calculate_drag_force
Calculate the drag force opposing motion of an object through a fluid using velocity, cross-sectional area, fluid density, and drag coefficient. Also returns Reynolds number.
Instructions
Calculate drag force for an object moving through a fluid.
The drag force opposes motion and is given by:
F_drag = 0.5 * ρ * v² * C_d * A
Common drag coefficients:
- Sphere: 0.47
- Streamlined shape: 0.04
- Flat plate (perpendicular): 1.28
- Human (standing): 1.0-1.3
- Car: 0.25-0.35
Args:
velocity: Velocity vector [x, y, z] in m/s (or JSON string)
cross_sectional_area: Area perpendicular to flow in m²
fluid_density: Fluid density in kg/m³ (water=1000, air=1.225)
drag_coefficient: Drag coefficient (default 0.47 for sphere)
viscosity: Dynamic viscosity in Pa·s (water=1.002e-3, air=1.825e-5, oil=0.1).
If not provided, estimated from fluid_density for Reynolds number calculation.
Returns:
Drag force vector, magnitude, and Reynolds number
Example - Ball falling through water:
result = await calculate_drag_force(
velocity=[0, -5.0, 0],
cross_sectional_area=0.00785, # π * (0.05m)² for 10cm diameter
fluid_density=1000, # water
drag_coefficient=0.47,
viscosity=1.002e-3 # water viscosity for accurate Reynolds number
)
# Returns upward drag force opposing downward motion
Example - Ball falling through motor oil:
result = await calculate_drag_force(
velocity=[0, -2.0, 0],
cross_sectional_area=0.00785,
fluid_density=900, # oil
drag_coefficient=0.47,
viscosity=0.1 # motor oil is much more viscous
)Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| velocity | Yes | ||
| cross_sectional_area | Yes | ||
| fluid_density | Yes | ||
| drag_coefficient | No | ||
| viscosity | No |
Implementation Reference
- src/chuk_mcp_physics/fluid.py:29-94 (handler)Core implementation of the drag force calculation. Takes a DragForceRequest, computes the drag force vector (opposing velocity) using F = 0.5 * ρ * v² * C_d * A, and also calculates the Reynolds number. Returns a DragForceResponse with drag_force, magnitude, and reynolds_number.
def calculate_drag_force(request: DragForceRequest) -> DragForceResponse: """Calculate drag force using quadratic drag equation. The drag force is given by: F_drag = 0.5 * ρ * v² * C_d * A Where: ρ = fluid density (kg/m³) v = velocity magnitude (m/s) C_d = drag coefficient (dimensionless) A = cross-sectional area (m²) The force opposes the direction of motion. Args: request: Drag force calculation parameters Returns: Drag force vector and Reynolds number """ vx, vy, vz = request.velocity speed = math.sqrt(vx * vx + vy * vy + vz * vz) if speed < 1e-10: # No motion, no drag return DragForceResponse( drag_force=[0.0, 0.0, 0.0], magnitude=0.0, reynolds_number=0.0, ) # Drag force magnitude: F = 0.5 * ρ * v² * C_d * A drag_magnitude = ( 0.5 * request.fluid_density * speed * speed * request.drag_coefficient * request.cross_sectional_area ) # Direction opposite to velocity drag_force = [ -drag_magnitude * vx / speed, -drag_magnitude * vy / speed, -drag_magnitude * vz / speed, ] # Calculate Reynolds number for flow regime estimation # Re = ρ * v * L / μ where L is characteristic length (use √A as approximation) characteristic_length = math.sqrt(request.cross_sectional_area) # Use provided viscosity, or estimate from density for backwards compatibility if request.viscosity is not None: viscosity = request.viscosity else: # Heuristic: if density > 100 kg/m³, assume water-like, else assume air-like viscosity = 1.0e-3 if request.fluid_density > 100 else 1.8e-5 reynolds_number = request.fluid_density * speed * characteristic_length / viscosity return DragForceResponse( drag_force=drag_force, magnitude=drag_magnitude, reynolds_number=reynolds_number, ) - DragForceRequest Pydantic model defining the input schema: velocity (list[float]), drag_coefficient, cross_sectional_area, fluid_density, and optional viscosity.
class DragForceRequest(BaseModel): """Request for drag force calculation.""" velocity: list[float] = Field(..., description="Velocity vector [x, y, z] in m/s") drag_coefficient: float = Field( default=0.47, description="Drag coefficient (sphere=0.47, streamlined=0.04, flat plate=1.28)", gt=0.0, ) cross_sectional_area: float = Field( ..., description="Cross-sectional area in m² (perpendicular to flow)", gt=0.0 ) fluid_density: float = Field( ..., description="Fluid density in kg/m³ (water=1000, air=1.225)", gt=0.0 ) viscosity: Optional[float] = Field( None, description="Dynamic viscosity in Pa·s (water=1.002e-3, air=1.825e-5, oil=0.1). If not provided, estimated from density", gt=0.0, ) - DragForceResponse Pydantic model defining the output schema: drag_force vector, magnitude, and reynolds_number.
class DragForceResponse(BaseModel): """Response for drag force calculation.""" drag_force: list[float] = Field(..., description="Drag force vector [x, y, z] in Newtons") magnitude: float = Field(..., description="Drag force magnitude in Newtons") reynolds_number: float = Field( ..., description="Reynolds number (indicates flow regime: <2300=laminar, >4000=turbulent)" ) - src/chuk_mcp_physics/tools/fluid.py:23-85 (registration)MCP @tool-decorated async function that exposes calculate_drag_force as a tool. Parses velocity if needed, creates a DragForceRequest, delegates to fluid_module.calculate_drag_force(), and returns the response dict.
@tool # type: ignore[arg-type] async def calculate_drag_force( velocity: Union[list[float], str], cross_sectional_area: float, fluid_density: float, drag_coefficient: float = 0.47, viscosity: Optional[float] = None, ) -> dict: """Calculate drag force for an object moving through a fluid. The drag force opposes motion and is given by: F_drag = 0.5 * ρ * v² * C_d * A Common drag coefficients: - Sphere: 0.47 - Streamlined shape: 0.04 - Flat plate (perpendicular): 1.28 - Human (standing): 1.0-1.3 - Car: 0.25-0.35 Args: velocity: Velocity vector [x, y, z] in m/s (or JSON string) cross_sectional_area: Area perpendicular to flow in m² fluid_density: Fluid density in kg/m³ (water=1000, air=1.225) drag_coefficient: Drag coefficient (default 0.47 for sphere) viscosity: Dynamic viscosity in Pa·s (water=1.002e-3, air=1.825e-5, oil=0.1). If not provided, estimated from fluid_density for Reynolds number calculation. Returns: Drag force vector, magnitude, and Reynolds number Example - Ball falling through water: result = await calculate_drag_force( velocity=[0, -5.0, 0], cross_sectional_area=0.00785, # π * (0.05m)² for 10cm diameter fluid_density=1000, # water drag_coefficient=0.47, viscosity=1.002e-3 # water viscosity for accurate Reynolds number ) # Returns upward drag force opposing downward motion Example - Ball falling through motor oil: result = await calculate_drag_force( velocity=[0, -2.0, 0], cross_sectional_area=0.00785, fluid_density=900, # oil drag_coefficient=0.47, viscosity=0.1 # motor oil is much more viscous ) """ # Parse velocity if string parsed_velocity = json.loads(velocity) if isinstance(velocity, str) else velocity request = DragForceRequest( velocity=parsed_velocity, cross_sectional_area=cross_sectional_area, fluid_density=fluid_density, drag_coefficient=drag_coefficient, viscosity=viscosity, ) response = fluid_module.calculate_drag_force(request) return response.model_dump() - src/chuk_mcp_physics/fluid.py:77-94 (helper)Reynolds number calculation within the drag force handler. Computes Re = ρ * v * L / μ using characteristic length sqrt(area) and provided or estimated viscosity.
# Calculate Reynolds number for flow regime estimation # Re = ρ * v * L / μ where L is characteristic length (use √A as approximation) characteristic_length = math.sqrt(request.cross_sectional_area) # Use provided viscosity, or estimate from density for backwards compatibility if request.viscosity is not None: viscosity = request.viscosity else: # Heuristic: if density > 100 kg/m³, assume water-like, else assume air-like viscosity = 1.0e-3 if request.fluid_density > 100 else 1.8e-5 reynolds_number = request.fluid_density * speed * characteristic_length / viscosity return DragForceResponse( drag_force=drag_force, magnitude=drag_magnitude, reynolds_number=reynolds_number, )