Inaccuracy of the physics engine?

@dave1707 thanks I had a little play and it seems to have improved the accuracy of it but not by setting it to 1,1. I’m at 10,50 atm which is giving good results, except there are still 2 defined paths, they just follow each other a bit more closely. Thanks for that though I’ve always missed tht function in the reference

.@Saurabh I knew that the default was 10,8. I tried various values going as high as 100,100 but none of them seemed to matter. I would still get the same 2 paths. I then tried going lower and when I reached 1,1 I got one path each time I did the soft restart. The path wasn’t the same as either of the 2 paths when it was set to the 10,8 default. So I’m not sure what’s happening.

Well the iterations change the path each time you change each one, I tried doing 1,1 but no luck so I’m not sure if its to do with that

.@Luatee I modified my collision program to let me compare 1,500 x,y collision points and I was still getting 2 different paths that alternated on soft restarts. That’s also what I saw in my previous experiments. What I then did in the latest program was when I would destroy all the physics objects and recreate them during a soft restart, I would do another soft restart destroying the objects and recreating them again. So basically I was skipping the conditions of the second path and recreating the conditions for the first path again. I compared the 1,500 points and they were the same. So maybe you could determine how many different paths you take and skip the paths that you have to so you get just one path. A hard restart seems to recreate the same conditions each time, but a soft restart seems to vary, in my case creating 2 paths.

Solved, thanks a lot dave and everyone else, @dave1707 you confirmed my theory of the two alternating paths, I got it to create destroy and then create again. This made the ball only follow the one

.@Luatee Glad that helped. I was playing with my program again and I had 7 balls bouncing around the screen. Every 20 collision, I added the 7 current x,y positions up and saved that value in a table for 50 entries. So that was 1000 collisions. Even with 7 objects, the 1st, 3rd, 5th, and 7th loops were the same. The 2nd, 4th, 6th, and 8th loops were the same. So I would say that kind of confirms that there are 2 different physics starting conditions on soft restarts.

EDIT: I don’t think there’s anything wrong with the accuracy, just the starting condition.

I think you’re spot on with that as I always ended up with it having 2 paths, the difference in the physics body at each start? Who knows? I know that something must be defining its path but none of the physics.body attributes cover that so I’m not sure, I don’t think it’s the accuracy of the engine although I’ve noticed a few hiccups and trip ups that can occur with the engine but then again I think they’ll probably occur every time if it isn’t changed so that makes it more accurate i guess…

So what I understood is that we should destroy the physics bodies twice every time and recreate them if we want the same result every time. That should solve the problem. Correct me if I’m wrong.

From what I’ve seen with my collision program, everything I tried so far points to 2 different paths on soft restarts. As @Luatee said, there doesn’t seem to be any attributes that prevents this. So the only solution is to do a destroy and define twice to skip over one of the paths.

It would be interesting to program a double pendulum (http://en.wikipedia.org/wiki/Double_pendulum) in Codea. It’s the classic example of chaotic motion (or the butterfly effect).

Perhaps someone could post some code here (perhaps starting from Test 2 in the physics lab).

.@inoddy Here’s something I wrote a long time ago.


supportedOrientations(PORTRAIT)
displayMode(FULLSCREEN)

function setup()
    c1 = physics.body(CIRCLE,0)
    c1.x = 400
    c1.y = 900
    c1.restitution = 1
    c1.type = STATIC
    
    c2 = physics.body(CIRCLE,25)
    c2.x = 300
    c2.y = 600
    c2.restitution = 1  
    
    c3 = physics.body(CIRCLE, 25)
    c3.x = 300
    c3.y = 800
    c3.restitution = 1  
    
    c4 = physics.body(CIRCLE, 25)
    c4.x = 100
    c4.y = 700
    c4.restitution = 1 
    
    p1=physics.body(POLYGON,vec2(-10,25),vec2(-10,-25),vec2(10,-25),vec2(10,25)) 
    p1.x=200
    p1.y=700        
    
    joint1 = physics.joint(REVOLUTE,c1,c2,c1.position)
    joint2 = physics.joint(REVOLUTE, c2, c3,vec2(c2.x,c2.y))   
    joint3 = physics.joint(REVOLUTE, c3, c4,vec2(c3.x,c3.y)) 
    joint4 = physics.joint(REVOLUTE, c4, p1,vec2(c4.x,c4.y))           
end

function draw()
    background(40, 40, 50)
    
    noFill()     
    stroke(255)
    strokeWidth(2)
    line(c1.x,c1.y,c2.x,c2.y)
    line(c2.x,c2.y,c3.x,c3.y) 
    line(c3.x,c3.y,c4.x,c4.y) 
    line(c4.x,c4.y,p1.x,p1.y)       
    
    strokeWidth(1)
    ellipse(c1.x,c1.y,4)        
    ellipse(c2.x,c2.y,c2.radius*2)     
    ellipse(c3.x,c3.y,c3.radius*2)    
    ellipse(c4.x,c4.y,c4.radius*2)    

    strokeWidth(3)    
    translate(p1.x,p1.y)
    rotate(p1.angle)
    local points = p1.points
    for j = 1,#points do
        a = points[j]
        b = points[(j % #points)+1]
        line(a.x, a.y, b.x, b.y)    
    end
end

.@inoddy Heres your butterfly effect. I draw the initial path and keep it for the first loop, then I overlay the loops after that without saving them to show the effect of increasing the initial speed (x axis) of the pendulum. The paths are similar starting at 1 until it gets to the 470’s which is where I start this example. This shows how small changes have small effects until it reaches a critical point, then it has a major change. I draw each loop for 10 seconds then add 2 to the speed and draw the next loop.


supportedOrientations(PORTRAIT)
displayMode(FULLSCREEN)

function setup()
    speed=470  -- starting speed
    tab1={}
    tab2={}
    loop=1
    c1 = physics.body(CIRCLE,0)
    c1.x = 400
    c1.y = 900
    c1.restitution = 1
    c1.type = STATIC
    setup2()
end

function setup2()
    et=ElapsedTime
    if c2 ~= nil then
        loop=2
        tab2={}
        c2:destroy()
        c3:destroy()
        speed=speed+2  -- speed increase each loop
    end
    c2 = physics.body(CIRCLE,25)
    c2.x = 400
    c2.y = 600
    c2.restitution = 1  
    
    c3 = physics.body(CIRCLE, 25)
    c3.x = 400
    c3.y = 800
    c3.linearVelocity=vec2(speed,0)
    c3.restitution = 1  
    
    joint1 = physics.joint(REVOLUTE,c1,c2,c1.position)
    joint2 = physics.joint(REVOLUTE, c2, c3,vec2(c2.x,c2.y))   
end

function draw()
    background(40, 40, 50)
    fill(255)
    text("Speed".."  "..speed,400,920)
    if ElapsedTime-et>10 then  -- draw loop for 10 seconds
        setup2()
    end
    
    noFill()     
    stroke(255)
    strokeWidth(2)
    line(c1.x,c1.y,c2.x,c2.y)
    line(c2.x,c2.y,c3.x,c3.y) 
    ellipse(c1.x,c1.y,2)        
    ellipse(c2.x,c2.y,c2.radius*2)     
    ellipse(c3.x,c3.y,c3.radius*2) 
    
    if loop==1 then
        table.insert(tab1,vec2(c3.x,c3.y))  -- save initial loop
    else
        table.insert(tab2,vec2(c3.x,c3.y))   -- save current loop
    end
    for a,b in pairs(tab1) do  -- draw initial loop
        stroke(255, 255, 0, 255)
        ellipse(b.x,b.y,2)
    end
    for a,b in pairs(tab2) do  -- draw current loop
        stroke(255)
        ellipse(b.x,b.y,2)
    end
end

Thanks @dave1707. That’s actually quite pretty. I’m going to use that code as my starting point for exploration of the physics engine.

@Dave1707 can you share the code of the 2 bouncing balls where you used to get two results and fixed it and got one result by creating the body twice. I am not able to recreate the same results every time. Thanks!!

.@Saurabh Here’s the code. I keep the x,y values from loop 1 to compare to loops 2,3,4,5, etc. The values (20 of them) are every 5 collisions for 100 collisions. Run this code for several loops to see how the odd loops match loop 1 and the even loops don’t. Then uncomment the line in the draw routine that will do a double setup2 to skip the even loops.


supportedOrientations(PORTRAIT_ANY)
displayMode(FULLSCREEN)

function setup()
    font("Courier")
    loop=0
    tab1={}
    tab2={}
    restart=true
end

function setup2()
    tab2={}
    count=0
    loop=loop+1
    if b1 then
        b1:destroy()
        b2:destroy()
        e1:destroy()
        e2:destroy()
        e3:destroy()
        e4:destroy()
    end
    
    e1=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    e2=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT))
    e3=physics.body(EDGE,vec2(WIDTH,HEIGHT),vec2(WIDTH,0))
    e4=physics.body(EDGE,vec2(WIDTH,0),vec2(0,0))
    
    b1=physics.body(CIRCLE,60)
    b1.gravityScale=0
    b1.restitution=1
    b1.linearDamping=0
    b1.linearVelocity=vec2(380,700)
    b1.x=200
    b1.y=600
    b1.friction=0

    b2=physics.body(CIRCLE,60)
    b2.gravityScale=0
    b2.restitution=1
    b2.linearDamping=0
    b2.linearVelocity=vec2(620,450)
    b2.x=400
    b2.y=200
    b2.friction=0

end

function draw()
    background(40,40,50)
    textMode(CORNER)
    if restart then
        setup2()  -- setup for the physics objects
        if loop>1 then
           --setup2() -- uncomment this line to skip loops
        end
        restart=false
    end
    noFill()
    strokeWidth(4)
    stroke(255)
    ellipse(b1.x,b1.y,120)
    ellipse(b2.x,b2.y,120)
    fill(255)
    text("x,y loop 1          x,y loop 2,3,4 etc.",100,1000)
    text("loop "..loop,600,1000)
    text("Shows the x,y position every 5 collisions for 100 collisions.",100,300)
    text("Retains the values for loop 1 to compare to loops 2,3,4, etc.",100,260)
    text("The odd loops are the same and the even loops are the same.",100,220)
    text("But the odd loops and the even loops don't match each other.",100,180)
    text("The odd, even loops start out equal, but then differ.",100,140)
    for a,b in pairs(tab1) do
        text(b.x.." "..b.y,100,HEIGHT-50-a*20)
    end
    for a,b in pairs(tab2) do
        text(b.x.." "..b.y,300,HEIGHT-50-a*20)
    end
end

function collide(c)
    if c.state==BEGAN then
        count = count + 1
        if count%5 == 0 then
            if loop==1 then
                table.insert(tab1,vec2(b1.x,b1.y))
            end
            if loop>1 then
                table.insert(tab2,vec2(b1.x,b1.y))
            end
        end
        if count==100 then
            restart=true
        end
    end  
end

Thanks for the example @dave1707. I’m going to do some testing to try to get to the bottom of the Physics determinism issues. It’s interesting how it manifests only on even play throughs.

.@John It’s not the even plays, it’s the alternating plays. All of the odd runs have the same values, and all of the even runs have the same values. It’s just that the odd/even runs differ from each other. It’s like every time the physics engine does a soft restart, some starting value alternates. Like one run starts with 0 and the next starts with 1, then 0, then 1, etc. It would be interesting to see what’s really happening.

Thats what I have been seeing a lot @dave1707 it has different attributes applied to the body when the physics engine is run/restarted and they consist of 2 different sets of attributes which alternate but I dont think its the actual attributes of the physics bodies, maybe the way they’re applied with set values in the engine which change every restart, from what I’ve seen anyway

Thanks @Dave1707 useful code.

Okay so I was just wondering if the new restart function will give the same result every time or different result. Anyone has any idea??