Replies: 38 comments 1 reply
-
This is implemented in pull request #50 |
Beta Was this translation helpful? Give feedback.
-
I implemented constant time-step calculation here: https://github.com/dbookstaber/py_ballistics/blob/time-step/py_ballisticcalc/trajectory_calc.py However it looks like it will always take more iterations than the current method to achieve any particular level of precision, so I do not recommend pursuing this. |
Beta Was this translation helpful? Give feedback.
-
but in addition to the number of iterations, it is necessary to take into account the time for performing the calculation, it may turn out that due to a decrease in the number of calculations, the number of iterations can be increased without losing performance we have to make a profiling and performance comparing |
Beta Was this translation helpful? Give feedback.
-
By "iterations" I meant the number of passes through the I think the current method of setting the time step based on the velocity is optimal. Any other approach will create excess precision at some points and lower precision at others. |
Beta Was this translation helpful? Give feedback.
-
To improve efficiency, JBM recommends switching from this simple integration approach to something like RK4, which is what he uses. |
Beta Was this translation helpful? Give feedback.
-
I implemented RK4 integration in this branch. It is more robust than the Euler implementation we are running, meaning that as step_size increases errors grow more slowly. However on the example I studied it's not like orders of magnitude better. This provides a foundation for some desirable improvements, including:
|
Beta Was this translation helpful? Give feedback.
-
Right now I don't have much time to study alternative calculation methods, so I'm completely relying on you. In any case, if we're worried about breaking something, we can always implement it as an experimental feature and enable it via the library's global settings. Like we do with gunpowder sensitivity, we can enable an alternative calculation algorithm. Use inheritance, it allows to implement new feature without massive base code changes and lost of backwards compatibility and also allows extend functionality without changing major release version Create new module, inherit from existing backend.TrajectoryCalculator # my_new_solver.py
from py_ballisticcalc.backend import TrajectoryCalculator
class MyNewSolver(TrajectoryCalculator):
def trajectory(*args, **kwargs):
# reimplement methods you need
... Add global flags to trajectory_calc.py # existing flags
_globalUsePowderSensitivity = False
def set_global_use_powder_sensitivity(value: bool) -> None:
# pylint: disable=global-statement
global _globalUsePowderSensitivity
if not isinstance(value, bool):
raise TypeError(f"set_global_use_powder_sensitivity {value=} is not a boolean")
_globalUsePowderSensitivity = value
# new flag
_globalUseNewSolver = False
def set_global_use_new_solver(value: bool) -> None:
global _globalUseNewSolver
_globalUseNewSolver = value Add conditional import of your new solver to interface.Calculator from py_ballisticcalc.backend import TrajectoryCalc, get_global_use_new_solver
# Calculator class
def barrel_elevation_for_target(self, shot: Shot, target_distance: Union[float, Distance]) -> Angular:
if get_global_use_new_solver():
from my_new_solver import MyNewSolver
calc = MyNewSolver()
else:
calc = TrajectoryCalc() |
Beta Was this translation helpful? Give feedback.
-
Hi, David (@dbookstaber). I have a question for you as expert in ballistics - could you comment on possibility of using methods like described in these and similar articles - https://iopscience.iop.org/article/10.1088/0143-0807/37/3/035001, or http://www.jaac-online.com/article/doi/10.11948/20210277 for speeding up the computations? (Search in the internet gives as well a number of other articles). Are they applicable for precise simulations used in ballistics calculator case or only for gaining insights in general behaviour of the system? |
Beta Was this translation helpful? Give feedback.
-
In theory, we are considering the possibility of adding alternative calculation methods, currently the plan is to implement RK. This is something that can be implemented without a significant change in the library architecture without violating backward API compatibility. As project owner and maintainer I think that after reworking the library architecture, there probably will be a clear opportunity to expand the functionality with methods such as the Adomian decomposition method. In addition, the library is developed with minimalism and lightness in mind, while maintaining cross-platform support and the smallest number of mandatory dependencies. Therefore, such innovations will be better implemented as optionally installed plugins. The next stable version is planned to be v2.1.0. If you change the architecture, please increase the API version to v3 |
Beta Was this translation helpful? Give feedback.
-
Hi, Dmytro. Thank you for the clarification. I believe efficiency could be considered from several viewpoints:
In my opinion, the benefit of analytical methods lays in speed of computation (compare calculations for drag-free case using formulas from Wikipedia with numerical integration like Euler or Runge-Kutta method). Runge-Kutta method is optimizing the precision of the computations. As I am not very experienced in ballistics, it is really interesting for me to hear David's opinion about the usage of analytical methods and their limitations. I'm able to see a lot of articles published in this area, but do not know in general their limitations and areas of applicability. Just for understanding - in some articles on analytical methods it is mentioned that computations could be easily done using a simple calculator (not a ballistic one). So, they are offering at least from a speed perspective a good potential for improvement. At the same time, I have not seen yet articles, that discuss using analytical methods for the prediction trajectories of specific projectiles with specified ballistic coefficient and G-function. Hopefully, this clarifies my question. |
Beta Was this translation helpful? Give feedback.
-
@serhiy-yevtushenko, The sorts of analytic approximations discussed in those papers are at best of academic interest, and not considered useful for applied high-velocity ballistics where the drag coefficient as a function of velocity is not only variable but also must be empirically measured. Never mind accounting for variable atmospheric conditions over the trajectory, as we do here! Applied ballistics passed the point of any speed/precision trade-off half a century ago. Runge-Kutta calculation of trajectories was "fast enough" on early 1980s-era electronics to produce solutions that exceed the precision of the inputs in fractions of a second. (By comparison, the Euler implementation here is computationally wasteful, but on modern electronics we set step sizes that are orders of magnitude smaller than necessary for precise solutions and we don't bother fine-tuning for speed – and often don't even bother compiling the code!) TL;DR: Basic numeric integration on these problems is so fast and precise that it's not worth making other approximations or looking for analytic shortcuts. |
Beta Was this translation helpful? Give feedback.
-
Hi, David. Thank you for the clarification. My experience of running simulation of shots with Euler using py-ballisticcalc was about 40 minutes for 900 shots - so, I would not call it blasing fast (using pure python version). I wonder what kind of performance are you getting with Runge-Kutta method |
Beta Was this translation helpful? Give feedback.
-
Yeah, pure python is more of a luxury for development. When you care about speed you should:
We haven't completed Runge-Kutta implementation here, but it should offer a further 1-2 orders of magnitude improvement in speed over Euler. |
Beta Was this translation helpful? Give feedback.
-
Hi, David. Thank you for the tips. Could you clarify, what is the performance impact of extra-data=True? I tried now running the simulation with extensions in version 2.0.8b1, and the performance was even worse than observed before without extensions (and at the end, I got exceptions, and computation did not complete due to new exceptions) |
Beta Was this translation helpful? Give feedback.
-
@serhiy-yevtushenko: We haven't ported the vertical fixes into Cython yet; I think @o-murphy will finish that shortly. If you're not seeing orders of magnitude improvement with Performance impact with |
Beta Was this translation helpful? Give feedback.
-
@serhiy-yevtushenko |
Beta Was this translation helpful? Give feedback.
-
@serhiy-yevtushenko Now I'm on the way to partially refactor library. I wanna write a generics for calculation "Method"s, that can be used with the same interface and input data and inherit from it. the first methods will be available after refactoring is current existed (Euler) and RK4, also the cythonic code will implemented as optional installable "Method". I mean I wanna create a core where you can chose which method u want to use, or even implement your own without changing the entire lib sources |
Beta Was this translation helpful? Give feedback.
-
After such a refactoring, it will not matter how low-level the method is implemented, it can be completely written in another language, or even executable on a remote server, all that is needed is a wrapper that will implement the interface. |
Beta Was this translation helpful? Give feedback.
-
All this would allow me to focus on implementing the functionality, and let’em cook, who’s better versed math and ballistics |
Beta Was this translation helpful? Give feedback.
-
I believe that usage of numpy requires reorganization from viewpoint of thinking about the code. In order to use numpy optimally, one would not try to allocate a lot of small vectors, but would rather do numpy array with dimension (N, 3), where N is the preallocated number of steps to be used. One could look at scikit-learn (from viewpoint on how they organize interfaces of machine learning methods) on good patterns to use, as scikit-learn relies both heavily on numpy and cython. |
Beta Was this translation helpful? Give feedback.
-
Sounds like a great plan |
Beta Was this translation helpful? Give feedback.
-
Here is the promised example for the reproduction of the cython/python differences. This is a simplified version of script which I was running. I used it here for the computation of the maximal reachability zone of .50 BMG bullet, and reduced amount of computed angles almost 10 times (from 901 to 91)
I have added option to switch usage of tqdm for showing progress on and off. I have not observed a difference in performance on my laptop. My personal preference is to use tqdm for long-running task, as in such a way I can see, whether task is doing progress at all Here are the run times on my laptop:
No Cython, no tqdm:
Cython, tqdm:
Cython, no tqdm:
|
Beta Was this translation helpful? Give feedback.
-
Short question - I would like to do an experiment with implementing a TrajectoryCalculator with ivp_solve from scipy. Which unit tests are sensible to use as a starting point and is there a recommended sequence of unit test from functionality progression viewpoint (simplest case -> more complex parameters like handling of air pressure, winds, ...)? |
Beta Was this translation helpful? Give feedback.
-
@serhiy-yevtushenko I expected those advantages from using SciPy, and I did try to get their RK45 method working but couldn't follow far enough to get it working with reasonable performance – almost certainly due to my lack of understanding. Can you try an implementation of it? You could see a kludgy effort to hack a different calculator engine into the existing |
Beta Was this translation helpful? Give feedback.
-
Hi, @dbookstaber . I'm willing to try to get the scheme with scipy working, as I'm interested in getting better performance. What I need the help with is having the sensible set of unit tests against which I could check the implementation. I'm willing to procede as far as too see, whether it really able to bring the performance improvements |
Beta Was this translation helpful? Give feedback.
-
My opinion: Start with Note also that JBM's calculator is presumed to be correct, so you can generate arbitrary scenarios and check against his results. |
Beta Was this translation helpful? Give feedback.
-
@serhiy-yevtushenko Regarding any contributions to TrajectoryCalc, please don't edit TrajectoryCalc directly, don't break backward compatibility as much as possible. This creates a lot of issues that need to be resolved later, from compatibility with cython, to specific dependencies for the contribution, like numpy, scipy etc. Which definitely won't be added as a base library dependency. They can only be installed together with an extension module (like py_ballisticcalc.exts) Use this sample for a new implementation # my_trajectory_calc.py
# type: ignore
from typing import List
from py_ballisticcalc import TrajectoryCalc, Distance, Shot, TrajectoryData, Calculator
class MyTrajectoryCalc(TrajectoryCalc):
... # overrides
def trajectory(self, shot_info: Shot, max_range: Distance, dist_step: Distance,
extra_data: bool = False, time_step: float = 0.0) -> List[TrajectoryData]:
# your implementation there
...
class MyCalculator(Calculator):
... # overrides |
Beta Was this translation helpful? Give feedback.
-
My Idea is to try with derived class from my calc. The only point to the new sample - is it ok to use python 3.11 style type annotations? (I mean using list instead of List and then not importing from typing types, which already exist in python, like list, set, and other ones? |
Beta Was this translation helpful? Give feedback.
-
Going forward, Dmytro wants to separate calculation engines from the core |
Beta Was this translation helpful? Give feedback.
-
Later I will add the link accordingly in README.md |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
All reactions