Giter Club home page Giter Club logo

dynamicalbilliards.jl's Introduction

DynamicalBilliards v3.0 Logo: The Julia billiard

A Julia package for dynamical billiard systems in two dimensions. The goals of the package is to provide a flexible and intuitive framework for fast implementation of billiard systems of arbitrary construction.

Documentation Citation Travis Gitter
, status Build Status Gitter

If you have used this package for research that resulted in a publication, please be kind enough to cite the papers listed in the CITATION.bib file.

Features

Please see the documentation for list of features, tutorials and installation instructions.

Acknowledgements

This package is mainly developed by George Datseris. However, this development would not have been possible without significant help from other people:

  1. Lukas Hupe(@lhupe) Contributed the lyapunov spectrum calculation for magnetic propagation, implemented the boundary map function and did other contributions in bringing this package to version 2.0 (see here).
  2. Diego Tapias (@dapias) Contributed the lyapunov spectrum calculation method for straight propagation.
  3. David. P. Sanders (@dpsanders) and Ragnar Fleischmann contributed in fruitful discussions about the programming and physics of Billiard systems all-around.
  4. Christopher Rackauckas (@ChrisRackauckas) helped set-up the continuous integration, testing, documentation publishing and all around package development-related concepts.
  5. Tony Kelman (@tkelman) helped significantly in the package publication process, especially in making it work correctly without destroying METADATA.jl.

dynamicalbilliards.jl's People

Contributors

anaveragehuman avatar chrisrackauckas avatar dapias avatar datseris avatar github-actions[bot] avatar imgbot[bot] avatar juliatagbot avatar kristofferc avatar lhupe avatar mortenpi avatar omdowley avatar scottpjones avatar sleort avatar staticfloat avatar tkelman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

dynamicalbilliards.jl's Issues

Introduce `affect!(bt::BilliardTable)`

This is a suggestion for making #47 possible.

At the moment, raysplitting automatically changes the pflag field of the collided object to its opposite value.

Maybe we can introduce one more function argument to the "ray-splitter", something like an affect! function, that does some in-place operation to the entire billiard table, e.g. inverting the pflag of all obstacles.

(it must be ensured that the collided obstacle changes its pflag though!)

`distance` and `propagate` result in big innacuraccies

the distance function measures the signed distance between particle and obstacle. The collisiontime function calculates the time until collision with a given obstacle. The function propagate! moves a particle forwards in time.

The basic way the package works is that it first calculates the collision time and then propagates a particle for that amount of time. After that other processes happen (e.g. specular reflection).

The problem is that after the particle is propagated, it should be really close (if not exactly on top) of an obstacle. However, measuring the distance between the particle and the obstacle, it can be as large as of order 1e-9. I think that this is really inaccurate and I cannot understand the reason why. Both the functions collisiontime and distance are supposed to result in exact answers in the "theoretical sense". How come that the numeric implementation is so far from it?

@dpsanders what do you think? Is it reasonable that after propagation the particle can still be so far away from an obstacle's borders?

Use Plots.jl for plotting

I suggest to consider using Plots.jl, rather than straight PyPlot for plotting.

This has a few benefits:

  • Allows to use various backends
  • Has @gif for automatically generating GIFs.

(The current plotting looks very nice, though!)

Allow magnetic particles with B = 0

Issue Description

In Ray-splitting, magnetic particles cannot be turned into normal particles, e.g. without magnetic field. Using an extremely large magnetic field does not help, because it leads to extreme inaccuracies in the internals

Solution

We must somehow either overhaul or re-think how we define magnetic particles so that this is possible.

Inline `timeprec` using their actual constants using `@generated`

Julia does not replace this:

@inline timeprec(::Type{T}) where {T} = eps(T)^(4/5)

with a constant value, but actually evaluates stuff
We can use @eval and a loop over the possible {T} and simply "manually" inline the function.

Or we can even use @generated as well

Create DoorWall and escapetime function

A DoorWall will simply be a FiniteWall, where when the particle collides with it, it "escapes" the billiard.

This allows for computation of escape times.

I am guessing that the DoorWall will be super easy to implement, but one would need to also create an
escapetime function, such that when the index of collision becomes the index of the DoorWall, the escape function stops and returns the time of escape!

Raysplitting mangetic is very slow

raysplit magnetic is IMPOSSIBLY AND EXTREMELY slow sometimes. There are some
problematic orbits for sure (because sometimes its fast).
Or maybe there is some really slow regression happening during relocate.
One really needs to debug this. (That "one" is me).

Implement arclength function

A function arclength that reduces the billiard table to a single variable (the arclength) will be helpful.

The function can either get a position (assumed on the obstacle) and spit out s.

However, one can associate the function with a billiard table. Given the table and an angle φ, it can again spit out s.

issue already in progress by Lukas


I also have an idea, but not sure yet if possible:

When calling functions like psos one can use a precomputed arc length array with some kind of resolution ds ... as to not compute arclengths at every collision but instead extrapolate...? will be tricky, because I dont see how to extrapolate from given position.

Raysplitting Magnetic tests freeze sometimes

I cannot replicate that issue in my computer. No matter how many times I run the tests they always pass.

If somebody can replicate this please investigate.
The function to run is raysplit_magnetic() at the /test/raysplit.jl file. If this function freezes for you I can tell you what to look for.

Make plotting use `@require`

Plotting in DynamicalSystems uses the Requires module. E.G.:

using Requires
@require PyPlot include("visualizations.jl")

and then noone has to ever do the nonsense enableplotting. The plotting functions become available the moment you do using PyPlot.

Pretty print billiard table

pretty printing works by overloading show. e;g;

#pretty print:
show(io::IO, w::Wall{T}) where {T} = print(io, "$(w.name) {$T}\n",
"start point: $(w.sp)\nend point: $(w.ep)\nnormal vector: $(w.normal)")

the printing of billiard table should list all obstacle names line by line

re-organize (and reduce) source code

With the new billiard table, we should split particles and obstacles.

I also believe that may method declarations could be reduced. In general many functions are copied and pasted all over the place. This is clearly not a good approach and I am sure we can do better.

  • split code into more files
  • randominside 1 function
  • relocate (without raysplitting) one function
  • escape time 1 function
  • reduce source code of evolve! functions

Re-work raysplitter?

(Related with #53 )

Should we create a dedicated struct for a "raysplitter", and make the ray-splitting dictionary a tuple of ray splitters???

something like:

struct RaySplitter{A,B,C,D}
  transmission::A
  refraction::B
  angular::C
  affect!::D
end

with the default implementation of affect! discussed in #53, and also angular defaulting to nothing?

Allocations in magnetic case must be removed

Changing the billiard table to a tuple completely removes any allocations in the case of straight propagation:

bt = billiard_buminovich()
p = randominside()
bt2 = (bt...)
@btime next_collision($p, $bt);

  1.237 μs (8 allocations: 128 bytes)
@btime next_collision($p, $bt2);

  36.266 ns (0 allocations: 0 bytes)

however, it does not in the case of magnetic fields. We all know why, because of creating the vector of intersection points before finding which one is the point of first collision.

Implement Inverse magnetic billiards

Inverse magnetic billiards are systems where there is magnetic field outside a region, but not inside, making the particle exit the boundary and return again inside the billiard. An excellent example is this one:

image

where you have inverse Buminovich, taken from 10.1103/PhysRevE.67.065202

Making this possible would allow all kind of craziness in inverse periodic billiards, SUPER COOL STUFF.

Heavily relies on somehow solving #46 first.

Decrease allocations done

A standard evolve call has at least 100,000 allocations even though everything is done through SVectors.

I do not know how or why this happens and also how to solve it.

Just do

using DynamicalBilliards, BenchmarkTools
bt = billiard_sinai()
p = randominside(bt)
evolve!(p, bt, 1.0) # compile
@btime evolve!(p, bt, 1000.0)

to see what I mean.

Define a `BilliardTable{T, O}` struct

, which will represent the billiard table from now on.

The plan is to incorporate this with #30, and have a tuple instead of a Vector of Obstacles.

A second field will be a vector of indices, that sorts the obstacles to an increasing arclength order.

It is probably necessary to parameterize the table to the entire tuple O, but maybe it is possible to parameterize only on T, the number type (only if there are no performance hits).

Documentation and newest release not synchronized...

I noticed that the most current release of DynamicalBilliards is version 1.5.1, while the documentation seems to be geared towards v1.6. In case this is intended: Maybe it would be nice to keep two versions of the documentation, like latest/stable? (In that way the reputation of a nice package doesn't get tarnished by failing examples in the documentation 😉 )

use SMatrix and access with SVector{Int} in lyapunovs

I am quite sure it will be much faster to use static vectors and not mutable static vectors all over lyapunovs.

Also, there is no need for mutable matrix, because you can simply vcat or hcat static vectors and it is super efficient, and you simply use static matrices.

Also, accessing static matrices with ranges like 1:2 is bad for performance. They should be accessed with static vectors of indices, like SVector(1, 2) instead.

make cyclotron center and radius field of particle

The function cyclotron is computed at all collisiontime functions. This means that the same computation is done like 5 times. We should make both center and radius fields of MagneticParticle and instead have the functions resolvecollision to change the fields when they e.g. reflect the particle.

make relocate! non-allocating

tmin, i = next_collision(p, bt)

(0.388, 2)
@btime relocate!($p, $bt[i], $tmin)

  59.723 ns (2 allocations: 32 bytes)

I think there is no reason for relocate! to allocate, besides bad programming.

Add function to compute Poincare surface of section

The function will propagate a particle in a billiard table with a set of initial conditions (either number->random i.c. or vector of vectors).

The will compute the poincare sos for when the j variable crosses some value either from positive to negative or vise versa.

The crossing is calculated via interpolation, and same technique applies to magnetic and standard:

  1. propagate (either for full time or step by step).
  2. Start iterating through j variable timeseries. When sign*(a[j] - a[j-1]) > crossing point then you have crossing of psos.
  3. interpolate between a[j] and a[j-1] linearly.
  4. profit

Re-work `evolve!` to use stepping. Add `evolve`

We need a function that evolves the particle with a single step, for only a single collision, without doing any unnecessary stuff like collecting vectors or whatever. This function should be non-allocating! A good name inspired by DiffEq is step!. But I really feel like we could come up with something even better.

Then, the high level function evolve! or evolve (that first deepcopies the particle) will call this new step! function as necessary.

This will make many other aspects of code clearer and fasterer and betterer. Especially the process used for plotting!

Update lyapunovs for new version

I have made major changes in the way this package work. I don't remember how fast it was before, but it certainly is fast now. And very precise as well, with the user being able to control the precision!

In the section https://juliadynamics.github.io/DynamicalBilliards.jl/latest/physics/#numerical-precision I am describing how this process works.

As far as the lyapunov exponents are concerned, the functions that are introduced/changed are:

  1. timeprec(T) at https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/src/Propagation.jl#L11
  2. specular at https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/src/Propagation.jl#L37 (which is made to depend on parametric types)
  3. resolvecollision at https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/src/Propagation.jl#L77 now simply decides whether to do specular reflection or not
  4. Most importantly, the function relocate! at https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/src/Propagation.jl#L87 has been fundamentally changed.
  5. Due to the above change, the way propagate! works and is used in evolve!() is different now. See https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/src/Propagation.jl#L162 and https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/src/Propagation.jl#L321

@dapias Since you have contributed the Lyapunov exponents, would you also like to update your functions so that they work with this new and major change to the package? If you do that, the lyapunovspectrum will be included in the 1.5.0 release version!

Also, notice that the tests have been updated. I have created an entirely new function that takes care of the lyapunov exponents: https://github.com/JuliaDynamics/DynamicalBilliards.jl/blob/master/test/various.jl#L61 and you don't have to do anything about that (when the functions in the LyapunovSpectrum.jl file work properly).

`billiard_polygon` with periodic conditions does not work adequately

Hello. I have found that this piece of code does not work adequately

using Dynamical Billiards
a = 1.0
b = 3.0
bt = billiard_polygon(6, b; setting = "periodic")
disc = Disk([0., 0.], a)
push!(bt, disc)
p = randominside(bt)
t = 5
ts, pos, vel = evolve!(p, bt, t)

And the reason is that when we create the normal vector as

normal = inr*normalize([-w[2], w[1]])

defined in the function billiard_polygon (line 151 of StandardBilliards.jl), the periodicity! function updates the position of the particle wrongly as w.normal is normalized. What I have tried to fix the problem is to change that line by

normal = normalize([-w[2], w[1]])*sqrt(3)*r

As $sqrt(3) \times r$ is the distance between any two parallel sides of a hexagon. The new problem is that this just works for a triangular billiard (hexagonal unit cell). As the function billiard_polygon works only for $4$ or $6$ sides (by mathematical reasons) and the square case works correctly, I propose to implement a specific function for the triangular lattice.

Additionally, a specific function for plotting this kind of unit cell needs to be implemented as the existing function does not translate correctly the scatterers when the periodicity is along non-coordinate vectors. I have made some code for the case discussed here but we could consider to open another issue after solving this one.

add lyapunov exponent for magnetic particle

By reading the paper, we know that in actuality only a method that propagates the offset vectors in magnetic field needs to be added, all the reflection methods are the same!

Only return largest lyapunov exponent

Since the exponents are known to be λ1 = -λ4 and λ2=λ3=0 , Only return λ1?

Although having all 4 serves as a good test case. Still, we can do the computation for all 4 (which will happen anyway) and only return the largest one.

Make randominside more performant

The function randominside takes about 2.3µs per particle in some billiards (see benchmark report attached below). Maybe there is a way to make it faster, which would be great for applications that require lots of particles.

Benchmark report for randominside

This code

using DynamicalBilliards, BenchmarkTools
bt = billiard_mushroom()
@benchmark randominside($bt)

produced this output

BenchmarkTools.Trial: 
  memory estimate:  1.05 KiB
  allocs estimate:  30
  --------------
  minimum time:     716.871 ns (0.00% GC)
  median time:      1.574 μs (0.00% GC)
  mean time:        2.284 μs (28.37% GC)
  maximum time:     136.644 μs (97.92% GC)
  --------------
  samples:          10000
  evals/sample:     124

Create *true* FiniteWall

  1. Rename FiniteWall to InfiniteWall
  2. Create a FiniteWall.
  3. The collision time will return Inf if the collision happens at a point which does not belong to the actual length of the wall.
  4. This will be only a small amount of additional operations, and will allow the creation of non-convex billiards, like the mushroom one.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.