Skip to content

ShotProps

ShotProps dataclass

ShotProps(
    shot: Shot,
    bc: float,
    drag_curve: PchipPrepared,
    look_angle_rad: float,
    twist_inch: float,
    length_inch: float,
    diameter_inch: float,
    weight_grains: float,
    barrel_elevation_rad: float,
    barrel_azimuth_rad: float,
    sight_height_ft: float,
    cant_cosine: float,
    cant_sine: float,
    alt0_ft: float,
    muzzle_velocity_fps: float,
    coriolis: Optional[Coriolis] = None,
)

Shot configuration and parameters for ballistic trajectory calculations.

Contains all shot-specific parameters converted to standard internal units (feet, seconds, grains, radians) used by the calculation engines. The class pre-computes expensive calculations (drag curve interpolation, atmospheric data, projectile properties) for repeated use during trajectory integration.

Examples:

from py_ballisticcalc import Shot, ShotProps

# Create shot configuration
shot = Shot(weapon=weapon, ammo=ammo, atmo=atmo)

# Convert to ShotProps
shot_props = ShotProps.from_shot(shot)

# Access pre-computed values
print(f"Stability coefficient: {shot_props.stability_coefficient}")

# Get drag coefficient at specific Mach number
drag = shot_props.drag_by_mach(1.5)

# Calculate spin drift at flight time
time = 1.2  # seconds
drift = shot_props.spin_drift(time)  # inches

# Get atmospheric conditions at altitude
altitude = shot_props.alt0_ft + 100  # 100 feet above initial altitude
density_ratio, mach_fps = shot_props.get_density_and_mach_for_altitude(altitude)
Computational Optimizations
  • Drag coefficient curves pre-computed for fast interpolation
  • Trigonometric values (cant_cosine, cant_sine) pre-calculated
  • Atmospheric parameters cached for repeated altitude lookups
  • Miller stability coefficient computed once during initialization
Notes

This class is designed for internal use by ballistic calculation engines. User code should typically work with Shot objects and let the Calculator handle the conversion to ShotProps automatically.

The original Shot object is retained for reference, but modifications to it after ShotProps creation will not affect the stored calculations. Create a new ShotProps instance if Shot parameters change.

Methods:

Name Description
from_shot

Initialize a ShotProps instance from a Shot instance.

get_density_and_mach_for_altitude

Get the air density and Mach number for a given altitude.

drag_by_mach

Calculate a standard drag factor (SDF) for the given Mach number.

spin_drift

Litz spin-drift approximation.

Functions

from_shot classmethod
from_shot(shot: Shot) -> ShotProps

Initialize a ShotProps instance from a Shot instance.

Source code in py_ballisticcalc/shot.py
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
@classmethod
def from_shot(cls, shot: Shot) -> ShotProps:
    """Initialize a ShotProps instance from a Shot instance."""
    muzzle_velocity_fps = shot.ammo.get_velocity_for_temp(shot.atmo.powder_temp) >> Velocity.FPS
    return cls(
        shot=shot,
        bc=shot.ammo.dm.BC,
        drag_curve=cls._precalc_drag_curve(shot.ammo.dm.drag_table),
        look_angle_rad=shot.look_angle >> Angular.Radian,
        twist_inch=shot.weapon.twist >> Distance.Inch,
        length_inch=shot.ammo.dm.length >> Distance.Inch,
        diameter_inch=shot.ammo.dm.diameter >> Distance.Inch,
        weight_grains=shot.ammo.dm.weight >> Weight.Grain,
        barrel_elevation_rad=shot.barrel_elevation >> Angular.Radian,
        barrel_azimuth_rad=shot.barrel_azimuth >> Angular.Radian,
        sight_height_ft=shot.weapon.sight_height >> Distance.Foot,
        cant_cosine=math.cos(shot.cant_angle >> Angular.Radian),
        cant_sine=math.sin(shot.cant_angle >> Angular.Radian),
        alt0_ft=shot.atmo.altitude >> Distance.Foot,
        muzzle_velocity_fps=muzzle_velocity_fps,
        coriolis=Coriolis.create(shot.latitude, shot.azimuth, muzzle_velocity_fps),
    )
get_density_and_mach_for_altitude
get_density_and_mach_for_altitude(
    drop: float,
) -> Tuple[float, float]

Get the air density and Mach number for a given altitude.

Parameters:

Name Type Description Default
drop float

The change in feet from the initial altitude.

required

Returns:

Type Description
Tuple[float, float]

A tuple containing the air density (in lb/ft³) and Mach number at the specified altitude.

Source code in py_ballisticcalc/shot.py
339
340
341
342
343
344
345
346
347
348
def get_density_and_mach_for_altitude(self, drop: float) -> Tuple[float, float]:
    """Get the air density and Mach number for a given altitude.

    Args:
        drop: The change in feet from the initial altitude.

    Returns:
        A tuple containing the air density (in lb/ft³) and Mach number at the specified altitude.
    """
    return self.shot.atmo.get_density_and_mach_for_altitude(self.alt0_ft + drop)
drag_by_mach
drag_by_mach(mach: float) -> float

Calculate a standard drag factor (SDF) for the given Mach number.

Formula:
    Drag force = V^2 * AirDensity * C_d * S / 2m
               = V^2 * density_ratio * SDF
Where:
    - density_ratio = LocalAirDensity / StandardDensity = rho / rho_0
    - StandardDensity of Air = rho_0 = 0.076474 lb/ft^3
    - S is cross-section = d^2 pi/4, where d is bullet diameter in inches
    - m is bullet mass in pounds
    - bc contains m/d^2 in units lb/in^2, which is multiplied by 144 to convert to lb/ft^2
Thus:
    - The magic constant found here = StandardDensity * pi / (4 * 2 * 144)

Parameters:

Name Type Description Default
mach float

The Mach number.

required

Returns:

Type Description
float

The standard drag factor at the given Mach number.

Source code in py_ballisticcalc/shot.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
def drag_by_mach(self, mach: float) -> float:
    """Calculate a standard drag factor (SDF) for the given Mach number.
    ```
    Formula:
        Drag force = V^2 * AirDensity * C_d * S / 2m
                   = V^2 * density_ratio * SDF
    Where:
        - density_ratio = LocalAirDensity / StandardDensity = rho / rho_0
        - StandardDensity of Air = rho_0 = 0.076474 lb/ft^3
        - S is cross-section = d^2 pi/4, where d is bullet diameter in inches
        - m is bullet mass in pounds
        - bc contains m/d^2 in units lb/in^2, which is multiplied by 144 to convert to lb/ft^2
    Thus:
        - The magic constant found here = StandardDensity * pi / (4 * 2 * 144)
    ```

    Args:
        mach: The Mach number.

    Returns:
        The standard drag factor at the given Mach number.
    """
    cd = pchip_eval(self.drag_curve, mach)
    return cd * 2.08551e-04 / self.bc
spin_drift
spin_drift(time: float) -> float

Litz spin-drift approximation.

Parameters:

Name Type Description Default
time float

Time of flight

required

Returns:

Name Type Description
float float

Windage due to spin drift, in inches

Source code in py_ballisticcalc/shot.py
375
376
377
378
379
380
381
382
383
384
385
386
387
def spin_drift(self, time: float) -> float:
    """Litz spin-drift approximation.

    Args:
        time: Time of flight

    Returns:
        float: Windage due to spin drift, in inches
    """
    if (self.stability_coefficient != 0) and (self.twist_inch != 0):
        sign = 1 if self.twist_inch > 0 else -1
        return sign * (1.25 * (self.stability_coefficient + 1.2) * math.pow(time, 1.83)) / 12
    return 0