Skip to content

Ammo

Ammo dataclass

Ammo(
    dm: DragModel,
    mv: Union[float, Velocity],
    powder_temp: Optional[Union[float, Temperature]] = None,
    temp_modifier: float = 0,
    use_powder_sensitivity: bool = False,
)

Ammunition configuration for ballistic calculations.

This class represents the physical and ballistic properties of ammunition, including the drag model, muzzle velocity, and powder temperature sensitivity. It provides methods for calculating temperature-dependent velocity adjustments.

Attributes:

Name Type Description
dm DragModel

DragModel instance defining the projectile's ballistic coefficient and drag characteristics.

mv Velocity

Muzzle velocity at the baseline powder temperature.

powder_temp Temperature

Baseline temperature that produces the given muzzle velocity.

temp_modifier float

Change in velocity with temperature as a percentage per 15°C. Can be computed using calc_powder_sens() method.

use_powder_sensitivity bool

Flag to enable automatic muzzle velocity adjustment based on powder temperature.

Note

When use_powder_sensitivity is True, the actual muzzle velocity will be automatically adjusted based on the difference between the current powder temperature and the baseline powder_temp using the temp_modifier.

Example
ammo = Ammo(
    dm=DragModel(0.381, TableG7, Unit.Grain(300), Unit.Inch(0.338)),
    mv=Unit.MPS(815),
    powder_temp=Unit.Celsius(15),
    temp_modifier=0.123,
    use_powder_sensitivity=True
)

Parameters:

Name Type Description Default
dm DragModel

DragModel instance defining projectile ballistic characteristics.

required
mv Union[float, Velocity]

Muzzle velocity at the baseline powder temperature.

required
powder_temp Optional[Union[float, Temperature]]

Baseline temperature that produces the given muzzle velocity. If None, defaults to 15°C.

None
temp_modifier float

Change in velocity with temperature as percentage per 15°C. Can be computed with calc_powder_sens() method. Only applies if use_powder_sensitivity is True.

0
use_powder_sensitivity bool

If True, automatically adjust muzzle velocity based on powder temperature differences.

False
Example
from py_ballisticcalc import Ammo, DragModel, TableG7, Unit

# Basic ammunition without temperature sensitivity
ammo = Ammo(dm=DragModel(0.381, TableG7), mv=Unit.MPS(815))

# Advanced ammunition with powder temperature sensitivity
ammo = Ammo(
    dm=DragModel(0.381, TableG7, Unit.Grain(300), Unit.Inch(0.338)),
    mv=Unit.MPS(815),
    powder_temp=Unit.Celsius(15),
    temp_modifier=0.123,
    use_powder_sensitivity=True
)
# Calculate sensitivity from known data points
ammo.calc_powder_sens(Unit.MPS(830), Unit.Celsius(30))

Methods:

Name Description
calc_powder_sens

Calculate velocity temperature sensitivity and update temp_modifier.

get_velocity_for_temp

Calculate muzzle velocity adjusted for powder temperature.

Source code in py_ballisticcalc/munition.py
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
def __init__(self,
             dm: DragModel,
             mv: Union[float, Velocity],
             powder_temp: Optional[Union[float, Temperature]] = None,
             temp_modifier: float = 0,
             use_powder_sensitivity: bool = False):
    """Initialize an Ammo instance with given parameters.

    Args:
        dm: DragModel instance defining projectile ballistic characteristics.
        mv: Muzzle velocity at the baseline powder temperature.
        powder_temp: Baseline temperature that produces the given muzzle velocity.
                    If None, defaults to 15°C.
        temp_modifier: Change in velocity with temperature as percentage per 15°C.
                      Can be computed with calc_powder_sens() method.
                      Only applies if use_powder_sensitivity is True.
        use_powder_sensitivity: If True, automatically adjust muzzle velocity
                               based on powder temperature differences.

    Example:
        ```python
        from py_ballisticcalc import Ammo, DragModel, TableG7, Unit

        # Basic ammunition without temperature sensitivity
        ammo = Ammo(dm=DragModel(0.381, TableG7), mv=Unit.MPS(815))

        # Advanced ammunition with powder temperature sensitivity
        ammo = Ammo(
            dm=DragModel(0.381, TableG7, Unit.Grain(300), Unit.Inch(0.338)),
            mv=Unit.MPS(815),
            powder_temp=Unit.Celsius(15),
            temp_modifier=0.123,
            use_powder_sensitivity=True
        )
        # Calculate sensitivity from known data points
        ammo.calc_powder_sens(Unit.MPS(830), Unit.Celsius(30))
        ```
    """
    self.dm = dm
    self.mv = PreferredUnits.velocity(mv or 0)
    self.powder_temp = PreferredUnits.temperature(powder_temp or Temperature.Celsius(15))
    self.temp_modifier = temp_modifier or 0
    self.use_powder_sensitivity = use_powder_sensitivity

Functions

calc_powder_sens
calc_powder_sens(
    other_velocity: Union[float, Velocity],
    other_temperature: Union[float, Temperature],
) -> float

Calculate velocity temperature sensitivity and update temp_modifier.

This method calculates the powder temperature sensitivity coefficient based on two known velocity/temperature data points and assigns the result to the temp_modifier attribute.

Parameters:

Name Type Description Default
other_velocity Union[float, Velocity]

Known velocity at other_temperature.

required
other_temperature Union[float, Temperature]

Temperature corresponding to other_velocity.

required

Returns:

Type Description
float

Temperature modifier in terms of percentage velocity change per 15°C.

Raises:

Type Description
ValueError

If other_velocity and temperature are the same as baseline, making calculation impossible.

Note

The calculation uses the formula: temp_modifier = (velocity_delta / temperature_delta) * (15 / lower_velocity)

This provides a normalized sensitivity value representing the percentage change in velocity per 15°C temperature change.

Example
# Calculate sensitivity from known velocity drop in cold weather
sensitivity = ammo.calc_powder_sens(
    other_velocity=Unit.MPS(800),  # Velocity at cold temp
    other_temperature=Unit.Celsius(0)  # Cold temperature
)
print(f"Powder sensitivity: {sensitivity:.4f}% per 15°C")

# The temp_modifier is now automatically set
print(f"Current temp_modifier: {ammo.temp_modifier}")
Source code in py_ballisticcalc/munition.py
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
def calc_powder_sens(self, other_velocity: Union[float, Velocity],
                     other_temperature: Union[float, Temperature]) -> float:
    """Calculate velocity temperature sensitivity and update temp_modifier.

    This method calculates the powder temperature sensitivity coefficient
    based on two known velocity/temperature data points and assigns the
    result to the temp_modifier attribute.

    Args:
        other_velocity: Known velocity at other_temperature.
        other_temperature: Temperature corresponding to other_velocity.

    Returns:
        Temperature modifier in terms of percentage velocity change per 15°C.

    Raises:
        ValueError: If other_velocity and temperature are the same as baseline,
                   making calculation impossible.

    Note:
        The calculation uses the formula:
        temp_modifier = (velocity_delta / temperature_delta) * (15 / lower_velocity)

        This provides a normalized sensitivity value representing the percentage
        change in velocity per 15°C temperature change.

    Example:
        ```python
        # Calculate sensitivity from known velocity drop in cold weather
        sensitivity = ammo.calc_powder_sens(
            other_velocity=Unit.MPS(800),  # Velocity at cold temp
            other_temperature=Unit.Celsius(0)  # Cold temperature
        )
        print(f"Powder sensitivity: {sensitivity:.4f}% per 15°C")

        # The temp_modifier is now automatically set
        print(f"Current temp_modifier: {ammo.temp_modifier}")
        ```
    """
    v0 = self.mv >> Velocity.MPS
    t0 = self.powder_temp >> Temperature.Celsius
    v1 = PreferredUnits.velocity(other_velocity) >> Velocity.MPS
    t1 = PreferredUnits.temperature(other_temperature) >> Temperature.Celsius

    if v0 <= 0 or v1 <= 0:
        raise ValueError("calc_powder_sens requires positive muzzle velocities")
    v_delta = math.fabs(v0 - v1)
    t_delta = math.fabs(t0 - t1)
    v_lower = v1 if v1 < v0 else v0

    if v_delta == 0 or t_delta == 0:
        raise ValueError("other_velocity and temperature can't be same as default")
    self.temp_modifier = v_delta / t_delta * (15 / v_lower)  # * 100
    return self.temp_modifier
get_velocity_for_temp
get_velocity_for_temp(
    current_temp: Union[float, Temperature],
) -> Velocity

Calculate muzzle velocity adjusted for powder temperature.

This method calculates the muzzle velocity at a given temperature based on the baseline velocity, powder temperature, and temperature sensitivity modifier. If powder sensitivity is disabled, returns the baseline velocity.

Parameters:

Name Type Description Default
current_temp Union[float, Temperature]

Temperature of the cartridge powder.

required

Returns:

Type Description
Velocity

Muzzle velocity corrected for the specified temperature.

Note

The calculation uses the formula: adjusted_velocity = baseline_velocity + (temp_modifier / (15 / baseline_velocity)) * temp_delta ... where temp_delta is the difference between current_temp and powder_temp.

If use_powder_sensitivity is False, returns the baseline muzzle velocity regardless of temperature.

Example
# Get velocity for current conditions
cold_velocity = ammo.get_velocity_for_temp(Unit.Celsius(-10))
hot_velocity = ammo.get_velocity_for_temp(Unit.Celsius(35))

print(f"Baseline velocity: {ammo.mv}")
print(f"Cold weather velocity: {cold_velocity}")
print(f"Hot weather velocity: {hot_velocity}")

# With powder sensitivity disabled
ammo.use_powder_sensitivity = False
constant_velocity = ammo.get_velocity_for_temp(Unit.Celsius(-10))
# constant_velocity equals ammo.mv regardless of temperature
Source code in py_ballisticcalc/munition.py
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
def get_velocity_for_temp(self, current_temp: Union[float, Temperature]) -> Velocity:
    """Calculate muzzle velocity adjusted for powder temperature.

    This method calculates the muzzle velocity at a given temperature based
    on the baseline velocity, powder temperature, and temperature sensitivity
    modifier. If powder sensitivity is disabled, returns the baseline velocity.

    Args:
        current_temp: Temperature of the cartridge powder.

    Returns:
        Muzzle velocity corrected for the specified temperature.

    Note:
        The calculation uses the formula:
        adjusted_velocity = baseline_velocity + (temp_modifier / (15 / baseline_velocity)) * temp_delta
        ... where temp_delta is the difference between current_temp and powder_temp.

        If use_powder_sensitivity is False, returns the baseline muzzle velocity regardless of temperature.

    Example:
        ```python
        # Get velocity for current conditions
        cold_velocity = ammo.get_velocity_for_temp(Unit.Celsius(-10))
        hot_velocity = ammo.get_velocity_for_temp(Unit.Celsius(35))

        print(f"Baseline velocity: {ammo.mv}")
        print(f"Cold weather velocity: {cold_velocity}")
        print(f"Hot weather velocity: {hot_velocity}")

        # With powder sensitivity disabled
        ammo.use_powder_sensitivity = False
        constant_velocity = ammo.get_velocity_for_temp(Unit.Celsius(-10))
        # constant_velocity equals ammo.mv regardless of temperature
        ```
    """
    if not self.use_powder_sensitivity:
        return self.mv
    try:
        v0 = self.mv >> Velocity.MPS
        t0 = self.powder_temp >> Temperature.Celsius
        t1 = PreferredUnits.temperature(current_temp) >> Temperature.Celsius
        t_delta = t1 - t0
        muzzle_velocity = self.temp_modifier / (15 / v0) * t_delta + v0
    except ZeroDivisionError:
        muzzle_velocity = 0
    return Velocity.MPS(muzzle_velocity)