calculate_inelastic_collision_3d
Calculate realistic 3D collisions with adjustable coefficient of restitution to model energy loss. Determines final velocities, momentum, kinetic energy changes, and energy lost.
Instructions
Calculate 3D collision with coefficient of restitution.
Models realistic collisions where some kinetic energy is lost.
Coefficient of restitution (e) determines how much energy is retained.
Args:
mass1: Mass of object 1 in kg
velocity1: Velocity of object 1 [x, y, z] in m/s (or JSON string)
mass2: Mass of object 2 in kg
velocity2: Velocity of object 2 [x, y, z] in m/s (or JSON string)
coefficient_of_restitution: e (0.0 = perfectly inelastic, 1.0 = perfectly elastic)
Returns:
Dict containing:
- final_velocity1: Final velocity [x, y, z] in m/s
- final_velocity2: Final velocity [x, y, z] in m/s
- initial_momentum: Total initial momentum [x, y, z]
- final_momentum: Total final momentum [x, y, z]
- initial_kinetic_energy: Total initial KE in Joules
- final_kinetic_energy: Total final KE in Joules
- energy_loss: Energy lost in Joules
- energy_loss_percent: % of energy lost
Coefficient of restitution values:
- e = 0.0: Perfectly inelastic (clay, putty) - objects stick
- e = 0.5: Very inelastic (wet clay)
- e = 0.7: Moderately elastic (basketball)
- e = 0.9: Highly elastic (Super Ball)
- e = 1.0: Perfectly elastic (ideal, no energy loss)
Tips for LLMs:
- Momentum is always conserved (regardless of e)
- Energy lost = (1 - e²) × initial KE in center-of-mass frame
- Use e=1.0 for billiard balls, e=0.0 for car crashes
Example - Car crash:
result = await calculate_inelastic_collision_3d(
mass1=1500, # kg
velocity1=[20, 0, 0], # 20 m/s east
mass2=1200, # kg
velocity2=[-15, 0, 0], # 15 m/s west
coefficient_of_restitution=0.1 # very inelastic
)
# Massive energy loss, objects nearly stick togetherInput Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mass1 | Yes | ||
| velocity1 | Yes | ||
| mass2 | Yes | ||
| velocity2 | Yes | ||
| coefficient_of_restitution | No |
Implementation Reference
- Core implementation: calculates 3D inelastic collision with coefficient of restitution using conservation of momentum and the coefficient of restitution formula to compute final velocities, momentum, and energy analysis.
def calculate_inelastic_collision_3d( request: InelasticCollision3DRequest, ) -> InelasticCollision3DResponse: """Calculate 3D collision with coefficient of restitution. Uses conservation of momentum and coefficient of restitution to solve for final velocities in 3D. For coefficient of restitution e: - e = 0: Perfectly inelastic (objects stick together) - 0 < e < 1: Inelastic (some energy lost) - e = 1: Perfectly elastic (no energy lost) Args: request: Inelastic collision request Returns: Final velocities, momentum, and energy analysis """ m1 = request.mass1 v1 = request.velocity1 m2 = request.mass2 v2 = request.velocity2 e = request.coefficient_of_restitution # Calculate initial momentum p1_initial = _vector_scale(v1, m1) p2_initial = _vector_scale(v2, m2) p_total = _vector_add(p1_initial, p2_initial) # Calculate initial kinetic energy ke1_initial = 0.5 * m1 * _dot_product(v1, v1) ke2_initial = 0.5 * m2 * _dot_product(v2, v2) ke_total_initial = ke1_initial + ke2_initial # For 3D collision, we need to work in the collision frame # Relative velocity v_rel = _vector_subtract(v1, v2) v_rel_mag = _vector_magnitude(v_rel) if v_rel_mag < 1e-10: # Objects already at same velocity return InelasticCollision3DResponse( final_velocity1=v1, final_velocity2=v2, initial_momentum=p_total, final_momentum=p_total, initial_kinetic_energy=ke_total_initial, final_kinetic_energy=ke_total_initial, energy_loss=0.0, energy_loss_percent=0.0, ) # Unit vector in direction of collision (along relative velocity) n = _vector_scale(v_rel, 1.0 / v_rel_mag) # Velocity components along collision normal v1n = _dot_product(v1, n) v2n = _dot_product(v2, n) # Calculate final velocities along normal using 1D collision formulas with restitution # Conservation of momentum: m1*v1n + m2*v2n = m1*v1n' + m2*v2n' # Coefficient of restitution: e = (v2n' - v1n') / (v1n - v2n) # Solving these two equations: v1n_final = ((m1 - e * m2) * v1n + m2 * (1 + e) * v2n) / (m1 + m2) v2n_final = ((m2 - e * m1) * v2n + m1 * (1 + e) * v1n) / (m1 + m2) # Calculate change in normal velocity delta_v1n = v1n_final - v1n delta_v2n = v2n_final - v2n # Apply changes to original velocities v1_final = _vector_add(v1, _vector_scale(n, delta_v1n)) v2_final = _vector_add(v2, _vector_scale(n, delta_v2n)) # Calculate final momentum and energy p1_final = _vector_scale(v1_final, m1) p2_final = _vector_scale(v2_final, m2) p_final = _vector_add(p1_final, p2_final) ke1_final = 0.5 * m1 * _dot_product(v1_final, v1_final) ke2_final = 0.5 * m2 * _dot_product(v2_final, v2_final) ke_total_final = ke1_final + ke2_final energy_loss = ke_total_initial - ke_total_final energy_loss_percent = (energy_loss / ke_total_initial * 100.0) if ke_total_initial > 0 else 0.0 return InelasticCollision3DResponse( final_velocity1=v1_final, final_velocity2=v2_final, initial_momentum=p_total, final_momentum=p_final, initial_kinetic_energy=ke_total_initial, final_kinetic_energy=ke_total_final, energy_loss=energy_loss, energy_loss_percent=energy_loss_percent, ) - MCP tool handler: async function decorated with @tool that parses inputs (velocity as list or JSON string), creates an InelasticCollision3DRequest, delegates to the core calculate_inelastic_collision_3d, and returns the response as a dict.
@tool # type: ignore[arg-type] async def calculate_inelastic_collision_3d( mass1: float, velocity1: Union[list[float], str], mass2: float, velocity2: Union[list[float], str], coefficient_of_restitution: float = 0.0, ) -> dict: """Calculate 3D collision with coefficient of restitution. Models realistic collisions where some kinetic energy is lost. Coefficient of restitution (e) determines how much energy is retained. Args: mass1: Mass of object 1 in kg velocity1: Velocity of object 1 [x, y, z] in m/s (or JSON string) mass2: Mass of object 2 in kg velocity2: Velocity of object 2 [x, y, z] in m/s (or JSON string) coefficient_of_restitution: e (0.0 = perfectly inelastic, 1.0 = perfectly elastic) Returns: Dict containing: - final_velocity1: Final velocity [x, y, z] in m/s - final_velocity2: Final velocity [x, y, z] in m/s - initial_momentum: Total initial momentum [x, y, z] - final_momentum: Total final momentum [x, y, z] - initial_kinetic_energy: Total initial KE in Joules - final_kinetic_energy: Total final KE in Joules - energy_loss: Energy lost in Joules - energy_loss_percent: % of energy lost Coefficient of restitution values: - e = 0.0: Perfectly inelastic (clay, putty) - objects stick - e = 0.5: Very inelastic (wet clay) - e = 0.7: Moderately elastic (basketball) - e = 0.9: Highly elastic (Super Ball) - e = 1.0: Perfectly elastic (ideal, no energy loss) Tips for LLMs: - Momentum is always conserved (regardless of e) - Energy lost = (1 - e²) × initial KE in center-of-mass frame - Use e=1.0 for billiard balls, e=0.0 for car crashes Example - Car crash: result = await calculate_inelastic_collision_3d( mass1=1500, # kg velocity1=[20, 0, 0], # 20 m/s east mass2=1200, # kg velocity2=[-15, 0, 0], # 15 m/s west coefficient_of_restitution=0.1 # very inelastic ) # Massive energy loss, objects nearly stick together """ # Parse inputs parsed_v1 = json.loads(velocity1) if isinstance(velocity1, str) else velocity1 parsed_v2 = json.loads(velocity2) if isinstance(velocity2, str) else velocity2 from ..collisions import ( InelasticCollision3DRequest, calculate_inelastic_collision_3d as calc_coll, ) request = InelasticCollision3DRequest( mass1=mass1, velocity1=parsed_v1, mass2=mass2, velocity2=parsed_v2, coefficient_of_restitution=coefficient_of_restitution, ) response = calc_coll(request) return response.model_dump() - InelasticCollision3DRequest schema: Pydantic model with mass1, velocity1, mass2, velocity2, and coefficient_of_restitution (0.0-1.0) fields.
class InelasticCollision3DRequest(BaseModel): """Request for 3D inelastic collision calculation.""" mass1: float = Field(..., description="Mass of object 1 in kg", gt=0.0) velocity1: list[float] = Field(..., description="Velocity of object 1 [x, y, z] in m/s") mass2: float = Field(..., description="Mass of object 2 in kg", gt=0.0) velocity2: list[float] = Field(..., description="Velocity of object 2 [x, y, z] in m/s") coefficient_of_restitution: float = Field( default=0.0, description="Coefficient of restitution (0.0=perfectly inelastic, 1.0=perfectly elastic)", ge=0.0, le=1.0, ) - InelasticCollision3DResponse schema: Pydantic model with final velocities, momentum, kinetic energy, energy loss, and energy loss percent fields.
class InelasticCollision3DResponse(BaseModel): """Response for 3D inelastic collision calculation.""" final_velocity1: list[float] = Field( ..., description="Final velocity of object 1 [x, y, z] in m/s" ) final_velocity2: list[float] = Field( ..., description="Final velocity of object 2 [x, y, z] in m/s" ) initial_momentum: list[float] = Field( ..., description="Total initial momentum [x, y, z] in kg⋅m/s" ) final_momentum: list[float] = Field(..., description="Total final momentum [x, y, z] in kg⋅m/s") initial_kinetic_energy: float = Field(..., description="Total initial kinetic energy in Joules") final_kinetic_energy: float = Field(..., description="Total final kinetic energy in Joules") energy_loss: float = Field(..., description="Kinetic energy lost in collision in Joules") energy_loss_percent: float = Field(..., description="Percentage of kinetic energy lost") - src/chuk_mcp_physics/tools/collisions.py:9-9 (registration)The @tool decorator registers calculate_inelastic_collision_3d as an MCP tool in the server.
@tool # type: ignore[arg-type]