Interface
Calculator
¶
Calculator(
*,
config: ConfigT,
engine: EngineFactoryProtocol[ConfigT],
)
Calculator(
*,
config: Any = None,
engine: EngineFactoryProtocolEntry = None,
)
The main interface for the ballistics calculator.
This class provides thread-safe access to the underlying integration engines by creating a new, isolated engine instance for every method call.
Crucially: The engine instance is not created here. To ensure thread safety (especially in free-threaded Python), each method call must operate on a new, isolated engine instance.
Methods:
| Name | Description |
|---|---|
__enter__ |
Enter the runtime context for this Calculator. |
__exit__ |
Exit the runtime context. |
__getattr__ |
Delegate attribute access to the underlying engine instance. |
__getstate__ |
Called by pickle for serialization. |
__setstate__ |
Called by pickle for deserialization. |
barrel_elevation_for_target |
Calculate barrel elevation to hit target at zero_distance. |
set_weapon_zero |
Set shot.weapon.zero_elevation so that it hits a target at zero_distance. |
fire |
Calculate the trajectory for the given shot parameters. |
iter_engines |
Iterate all available engines in the entry points. |
Source code in py_ballisticcalc/interface.py
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | |
Attributes¶
_engine_instance
property
¶
_engine_instance: EngineProtocol
Creates and returns a fresh, isolated engine instance upon every access.
This implementation is the core mechanism for ensuring thread safety in the Calculator class,
particularly essential in free-threaded Python (e.g., CPython with GIL disabled, Python 3.13+).
Thread Safety Rationale¶
Instead of using traditional synchronization primitives (like threading.Lock)
to protect a single, shared engine instance, this method employs isolation.
Since the underlying engine instances are not guaranteed to be thread-safe
internally, generating a new instance for each operation ensures that
no two concurrent threads will ever modify the same engine object. This
approach eliminates race conditions without introducing the overhead or
potential deadlocks associated with locking mechanisms.
Performance Consideration¶
Note: The overall performance of concurrent operations critically depends
on the initialization cost of the underlying engine class (self._engine_class).
If the engine's constructor performs extensive I/O, loads large data tables,
or executes complex setup, repeated instantiation may introduce significant
overhead. For optimal performance, the engine's initialization (__init__)
should be designed to be as lightweight as possible.
Returns:
| Type | Description |
|---|---|
EngineProtocol
|
EngineProtocol[Any]: A new, single-use engine instance configured
with the |
Functions¶
__enter__
¶
__enter__() -> Self
Enter the runtime context for this Calculator.
Returns:
| Name | Type | Description |
|---|---|---|
Self |
Self
|
The Calculator instance. |
Example
with Calculator(config, RK4IntegrationEngine) as calc: ... result = calc.fire(shot, Distance.Meter(1000))
Source code in py_ballisticcalc/interface.py
146 147 148 149 150 151 152 153 154 155 156 | |
__exit__
¶
__exit__(
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None
Exit the runtime context.
This is a no-op as Calculator is stateless and thread-safe by design — each method call creates an isolated engine instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exc_type
|
type[BaseException] | None
|
Exception type if an exception was raised, None otherwise. |
required |
exc_val
|
BaseException | None
|
Exception instance if an exception was raised, None otherwise. |
required |
exc_tb
|
TracebackType | None
|
Traceback if an exception was raised, None otherwise. |
required |
Source code in py_ballisticcalc/interface.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | |
__getattr__
¶
Delegate attribute access to the underlying engine instance.
This method is called when an attribute is requested on the Calculator
instance that is not found through normal attribute lookup (i.e., it's
not a direct attribute of Calculator or its class). It then attempts
to retrieve the attribute from the _engine_instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item
|
str
|
The name of the attribute to retrieve. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Any |
Any
|
The value of the attribute from |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If the attribute is not found on either the
|
Examples:
>>> calc = Calculator(engine=DEFAULT_ENTRY)
>>> calc_step = calc.get_calc_step()
>>> print(calc_step)
0.0025
>>> try:
... calc.unknown_method()
... except AttributeError as e:
... print(e)
'Calculator' object or its underlying engine 'RK4IntegrationEngine' has no attribute 'unknown_method'
Source code in py_ballisticcalc/interface.py
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | |
__getstate__
¶
__getstate__()
Called by pickle for serialization. We only serialize the public fields required for reconstruction. We explicitly exclude the calculated fields like _engine_class to ensure proper re-initialization in the new process.
Source code in py_ballisticcalc/interface.py
246 247 248 249 250 251 252 253 | |
__setstate__
¶
__setstate__(state)
Called by pickle for deserialization. We manually set the fields and call post_init to reload the engine class.
Source code in py_ballisticcalc/interface.py
255 256 257 258 259 260 261 262 263 264 | |
barrel_elevation_for_target
¶
Calculate barrel elevation to hit target at zero_distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot
|
Shot
|
Shot instance we want to zero. |
required |
target_distance
|
float | Distance
|
Look-distance to "zero," which is point we want to hit. This is the distance that a rangefinder would return with no ballistic adjustment. |
required |
Note
Some rangefinders offer an adjusted distance based on inclinometer measurement. However, without a complete ballistic model these can only approximate the effects on ballistic trajectory of shooting uphill or downhill. Therefore: For maximum accuracy, use the raw sight distance and look_angle as inputs here.
Source code in py_ballisticcalc/interface.py
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
set_weapon_zero
¶
Set shot.weapon.zero_elevation so that it hits a target at zero_distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot
|
Shot
|
Shot instance to zero. |
required |
zero_distance
|
float | Distance
|
Look-distance to "zero," which is point we want to hit. |
required |
Source code in py_ballisticcalc/interface.py
284 285 286 287 288 289 290 291 292 | |
fire
¶
fire(
shot: Shot,
trajectory_range: float | Distance,
trajectory_step: float | Distance | None = None,
*,
extra_data: bool = False,
dense_output: bool = False,
time_step: float = 0.0,
flags: TrajFlag | int = NONE,
raise_range_error: bool = True,
) -> HitResult
Calculate the trajectory for the given shot parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot
|
Shot
|
Shot parameters, including position and barrel angle. |
required |
trajectory_range
|
float | Distance
|
Distance at which to stop computing the trajectory. |
required |
trajectory_step
|
float | Distance | None
|
Distance between recorded trajectory points. Defaults to |
None
|
extra_data
|
bool
|
[DEPRECATED] Requests flags=TrajFlags.ALL and trajectory_step=PreferredUnits.distance(1). |
False
|
dense_output
|
bool
|
HitResult stores all calculation steps so it can interpolate any point. |
False
|
time_step
|
float
|
Maximum time between recorded points. If > 0, points are recorded at least this frequently. Defaults to 0.0. |
0.0
|
flags
|
TrajFlag | int
|
Flags for specific points of interest. Defaults to TrajFlag.NONE. |
NONE
|
raise_range_error
|
bool
|
If True, raises RangeError if returned by integration. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
HitResult |
HitResult
|
Object containing computed trajectory. |
Source code in py_ballisticcalc/interface.py
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | |
iter_engines
staticmethod
¶
iter_engines() -> Generator[EntryPoint, None, None]
Iterate all available engines in the entry points.
Source code in py_ballisticcalc/interface.py
347 348 349 350 | |
_EngineLoader
dataclass
¶
_EngineLoader()
Methods:
| Name | Description |
|---|---|
iter_engines |
Iterate over all available engines in the entry points. |
iter_engines
classmethod
¶
iter_engines() -> Generator[EntryPoint, None, None]
Iterate over all available engines in the entry points.
Source code in py_ballisticcalc/interface.py
55 56 57 58 59 60 61 | |