Verlet integration is essentially a solution to the kinematic equation for the motion of any object,
where
So, let's say we want to solve for the next timestep in
This means that if we need to find the next
Now, we have two equations to solve for two different timesteps in x, one of which we already have. If we add the two equations together and solve for
So, this means we can find our next
{% method %} {% sample lang="jl" %} import:1-13, lang:"julia" {% sample lang="cpp" %} import:9-22, lang:"cpp" {% sample lang="c" %} import:3-14, lang:"c" {% sample lang="java" %} import:14-29, lang:"java" {% sample lang="py" %} import:1-10, lang:"python" {% sample lang="hs" %} import:14-21, lang:"haskell" {% sample lang="js" %} import:1-14, lang:"javascript" {% sample lang="rs" %} import:1-13, lang:"rust" {% sample lang="swift" %} import:1-15, lang:"swift" {% sample lang="f90" %} import:1-20, lang:"fortran" {% sample lang="ruby" %} import:1-14, lang="ruby" {% sample lang="go" %} import:5-16, lang:"go" {% sample lang="asm-x64" %} import:18-42, lang:"asm-x64" {% sample lang="kotlin" %} import:3-15, lang:"kotlin" {% sample lang="nim" %} import:1-14, lang:"nim" {% sample lang="lisp" %} import:3-13, lang:"lisp" {% endmethod %}
Now, obviously this poses a problem; what if we want to calculate a term that requires velocity, like the kinetic energy,
When we solve for
Note that the 2 in the denominator makes sense because we are going over 2 timesteps. It's essentially solving
However, the error for this is
{% method %} {% sample lang="jl" %} import:15-31, lang:"julia" {% sample lang="cpp" %} import:24-41, lang:"cpp" {% sample lang="c" %} import:16-31, lang:"c" {% sample lang="java" %} import:31-49, lang:"java" {% sample lang="py" %} import:12-23, lang:"python" {% sample lang="hs" %} import:23-28, lang:"haskell" {% sample lang="js" %} import:16-32, lang:"javascript" {% sample lang="rs" %} import:15-32, lang:"rust" {% sample lang="swift" %} import:17-34, lang:"swift" {% sample lang="f90" %} import:22-42, lang:"fortran" {% sample lang="ruby" %} import:16-32, lang="ruby" {% sample lang="go" %} import:18-30, lang:"go" {% sample lang="asm-x64" %} import:44-71, lang:"asm-x64" {% sample lang="kotlin" %} import:17-30, lang:"kotlin" {% sample lang="nim" %} import:16-32, lang:"nim" {% sample lang="lisp" %} import:15-26, lang:"lisp" {% endmethod %}
Now, let's say we actually need the velocity to calculate out next timestep. Well, in this case, we simply cannot use the above approximation and instead need to use the Velocity Verlet algorithm.
In some ways, this algorithm is even simpler than above. We can calculate everything like
which is literally the kinematic equation above, solving for
Here is the velocity Verlet method in code:
{% method %} {% sample lang="jl" %} import:33-45, lang:"julia" {% sample lang="cpp" %} import:43-54, lang:"cpp" {% sample lang="c" %} import:33-43, lang:"c" {% sample lang="java" %} import:51-63, lang:"java" {% sample lang="py" %} import:25-34, lang:"python" {% sample lang="hs" %} import:30-35, lang:"haskell" {% sample lang="js" %} import:34-45, lang:"javascript" {% sample lang="rs" %} import:34-45, lang:"rust" {% sample lang="swift" %} import:36-49, lang:"swift" {% sample lang="f90" %} import:44-60, lang:"fortran" {% sample lang="ruby" %} import:34-46, lang="ruby" {% sample lang="go" %} import:32-42, lang:"go" {% sample lang="asm-x64" %} import:73-101, lang:"asm-x64" {% sample lang="kotlin" %} import:32-42, lang:"kotlin" {% sample lang="nim" %} import:34-45, lang:"nim" {% sample lang="lisp" %} import:28-35, lang:"lisp" {% endmethod %}
Even though this method is more widely used than the simple Verlet method mentioned above, it unfortunately has an error term of
Here is a video describing Verlet integration:
Both of these methods work simply by iterating timestep-by-timestep and can be written straightforwardly in any language. For reference, here are snippets of code that use both the classic and velocity Verlet methods to find the time it takes for a ball to hit the ground after being dropped from a given height.
{% method %} {% sample lang="jl" %} import, lang:"julia" {% sample lang="cpp" %} import, lang:"cpp" {% sample lang="c" %} import, lang:"c" {% sample lang="java" %} import, lang:"java" {% sample lang="py" %} import, lang:"python" {% sample lang="hs" %} import, lang:"haskell" {% sample lang="js" %} import, lang:"javascript" {% sample lang="rs" %} import, lang:"rust" {% sample lang="swift" %} import, lang:"swift" {% sample lang="f90" %} import, lang:"fortran" {% sample lang="ruby" %} import, lang="ruby" {% sample lang="go" %} import, lang:"go" {% sample lang="asm-x64" %} import, lang:"asm-x64" {% sample lang="kotlin" %} import, lang:"kotlin" {% sample lang="nim" %} import, lang="nim" {% sample lang="lisp" %} import, lang:"lisp" {% endmethod %}
<script> MathJax.Hub.Queue(["Typeset",MathJax.Hub]); </script>The code examples are licensed under the MIT license (found in LICENSE.md).
The text of this chapter was written by James Schloss and is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
After initial licensing (#560), the following pull requests have modified the text or graphics of this chapter:
- none