Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

How a Virus spreads

dave1707dave1707 Mod
in General Posts: 8,505

I took one of my older programs and modified it to show how a virus could spread. When the program starts, there are 350 white balls roaming around the screen. Once you tap the screen, you infect one of the balls (color yellow). That ball will interact with the other balls but nothing will happen. After it’s been infected for 6 days (1 day = 3 seconds), that ball becomes contagious (color red). Any white ball that comes in contact with the red ball becomes infected (yellow). That ball then goes thru the 6 day stretch before it becomes contagious (red). Each red ball will infect other balls for 15 days after which time it will be cured (color green). It takes about 50 some days for all balls to go from white to green. Of course, if we had millions of balls and a larger area, it would take a lot longer for this to run. I have counts in the middle of the screen to show the status of the balls.

Remember, tap the screen to start the infection.

displayMode(FULLSCREEN) 

function setup()
    colTab={color(255),color(255,255,0),color(255,0,0),color(0,255,0)}
    dti=5
    dtc=20
    physics.continuous=true
    speed=50
    line1 = physics.body(EDGE,vec2(5,5),vec2(10,HEIGHT-5))
    line2 = physics.body(EDGE,vec2(WIDTH-5,5),vec2(WIDTH-5,HEIGHT-5))
    line3 = physics.body(EDGE,vec2(5,5),vec2(WIDTH-5,5))
    line4 = physics.body(EDGE,vec2(5,HEIGHT-5),vec2(WIDTH-5,HEIGHT-5)) 
    val=0
    days=0
    cnt=0
    limit=180  
    nbr=350    
    tab={}                    -- table for balls    
    for x=1,nbr do             -- start with 20 balls     
        create()
    end    
end

function draw()
    background(50, 50, 50)    
    normal,infected,contagious,cured=0,0,0,0
    strokeWidth(0)
    for a,b in pairs(tab) do
        if b.inf>0 then
            if days-b.inf>=dti and b.col==2 then
                b.col=3
            elseif days-b.inf>=dtc and b.col==3 then
                b.col=4
            end
        end
        fill(colTab[b.col])
        ellipse(b.x,b.y,12)
        if b.col==1 then
            normal=normal+1
        elseif b.col==2 then
            infected=infected+1
        elseif b.col==3 then
            contagious=contagious+1
        elseif b.col==4 then
            cured=cured+1
        end
    end    
    stroke(255) 
    strokeWidth(5)
    line(5,5,5,HEIGHT-5)  
    line(WIDTH-5,5,WIDTH-5,HEIGHT-5) 
    line(5,5,WIDTH-5,5)
    line(5,HEIGHT-5,WIDTH-5,HEIGHT-5)
    cnt=cnt+val
    if cnt>limit then
        cnt=0
        days=days+1
    end
    fill(255, 0, 217)
    text("day "..days,WIDTH/2,HEIGHT/2+200)
    fill(255)
    text("normal "..normal,WIDTH/2,HEIGHT/2+150)
    fill(255,255,0)
    text("infected "..infected,WIDTH/2,HEIGHT/2+100)
    fill(255,0,0)
    text("contagious "..contagious,WIDTH/2,HEIGHT/2+50)
    fill(0,255,0)
    text("cured "..cured,WIDTH/2,HEIGHT/2)
end

function touched(t)
    if t.state==BEGAN and infected==0 then
        tab[1].col=2
        tab[1].inf=1
        val=1
    end
end

function collide(contact)
    if contact.state==BEGAN then
        if contact.bodyA.col==3 then
            if contact.bodyB.col==1 then
                contact.bodyB.inf=days
                contact.bodyB.col=2
                infected=infected+1
                normal=normal-1
            end
        elseif contact.bodyB.col==3 then
            if contact.bodyA.col==1 then
                contact.bodyA.inf=days
                contact.bodyA.col=2
                infected=infected+1
                normal=normal-1
            end
        end
    end
end

function create()
    local a=#tab+1
    tab[a]=physics.body(CIRCLE,6)
    tab[a].mass=2
    tab[a].friction=0
    tab[a].x=math.random(30,WIDTH-30)
    tab[a].y=math.random(30,HEIGHT-30)
    tab[a].gravityScale=0
    tab[a].restitution=1
    tab[a].sleepingAllowed=false
    a1=math.random(-1,1)*speed
    a2=math.random(-1,1)*speed
    tab[a].linearVelocity=vec2(a1,a2)
    tab[a].inf=0
    tab[a].col=1
end

Comments

  • edited March 17 Posts: 1,768

    @dave1707 - interesting, funnily enough I’ve been looking for game of Life to do something similar. Overlaying a graph of the numbers of the 4 inhabitants of the game would show progress. Saved the project as Corona.

  • Posts: 545

    @dave1707 cool! Would be nice to add a plot of the time dependence for the various categories. Then send it to Boris Johnson, so he finally takes it seriously!

  • Posts: 684

    Neat ... why does it slow to a stop? Looks like there's no friction and perfect collisions ...

  • dave1707dave1707 Mod
    Posts: 8,505

    @RonJeffries I don’t know the exact answer why it’s slows, but it might be based on the angle it hits the side walls. If it’s straight on, it bounces back ok. If it’s a glazing hit, it doesn’t bounce back enough. I’ll have to make a copy and strip out a lot of stuff and display velocities of the ball when it hits at different angles.

  • Posts: 684

    physics, can't live with it, can't live without it.

  • dave1707dave1707 Mod
    Posts: 8,505

    @RonJeffries I tried different angles and speeds with one ball bouncing off the wall. The smaller the angle, the higher the velocity had to be to get a good bounce. There might be a speed that can be calculated based on the angles where you get the bounce limit. I haven’t found a setting that fixes everything. I tried linearDamping to get the bounce to work, but that just caused the balls to speed up out of control.

  • Posts: 72

    I think the balls slow down because they are "sheltering in place". What an interesting program.

  • dave1707dave1707 Mod
    Posts: 8,505

    @Scotty I like your answer, “sheltering in place”. But one thing it shows is that even though they shelter in place, if one of them is infected, eventually they all get infected. I ran this one time where one of the balls didn’t get infected for a very long time. Eventually it ran into an infected ball because just about every ball around it was infected. But it shows that as long as you can avoid the ones infected, then your OK.

  • dave1707dave1707 Mod
    edited March 19 Posts: 8,505

    Added code to graph the different categories as the program runs.

    displayMode(FULLSCREEN) 
    
    function setup()
        nbr=350    
        nTab,iTab,coTab,cuTab={nbr},{0},{0},{0}
        colTab={color(255),color(255,255,0),color(255,0,0),color(0,255,0)}
        dti=5
        dtc=20
        physics.continuous=true
        speed=50
        line1 = physics.body(EDGE,vec2(5,5),vec2(10,HEIGHT-5))
        line2 = physics.body(EDGE,vec2(WIDTH-5,5),vec2(WIDTH-5,HEIGHT-5))
        line3 = physics.body(EDGE,vec2(5,5),vec2(WIDTH-5,5))
        line4 = physics.body(EDGE,vec2(5,HEIGHT-5),vec2(WIDTH-5,HEIGHT-5)) 
        val=0
        days=0
        cnt=0
        limit=180
        tab={}                    -- table for balls    
        for x=1,nbr do             
            create()
        end    
    end
    
    function draw()
        background(50, 50, 50)    
        stroke(255) 
        strokeWidth(5)
        line(5,5,5,HEIGHT-5)  
        line(WIDTH-5,5,WIDTH-5,HEIGHT-5) 
        line(5,5,WIDTH-5,5)
        line(5,HEIGHT-5,WIDTH-5,HEIGHT-5)
    
        normal,infected,contagious,cured=0,0,0,0
        strokeWidth(0)
        for a,b in pairs(tab) do
            if b.inf>0 then
                if days-b.inf>=dti and b.col==2 then
                    b.col=3
                elseif days-b.inf>=dtc and b.col==3 then
                    b.col=4
                end
            end
            fill(colTab[b.col])
            ellipse(b.x,b.y,12)
            if b.col==1 then
                normal=normal+1
            elseif b.col==2 then
                infected=infected+1
            elseif b.col==3 then
                contagious=contagious+1
            elseif b.col==4 then
                cured=cured+1
            end
        end 
    
        fill(255, 0, 217)
        text("day "..days,WIDTH/2,HEIGHT/2+200)
        fill(255)
        text("normal "..normal,WIDTH/2,HEIGHT/2+150)
        fill(255,255,0)
        text("infected "..infected,WIDTH/2,HEIGHT/2+100)
        fill(255,0,0)
        text("contagious "..contagious,WIDTH/2,HEIGHT/2+50)
        fill(0,255,0)
        text("cured "..cured,WIDTH/2,HEIGHT/2)
    
        if days<75 then
            cnt=cnt+val
            if cnt>limit then
                cnt=0
                days=days+1
            end
        end
    
        w=WIDTH/60
        nTab[days]=normal
        iTab[days]=infected
        coTab[days]=contagious
        cuTab[days]=cured 
    
        strokeWidth(3)
        stroke(colTab[1])
        for z=1,#nTab-1 do
            line((z-1)*w,nTab[z-1]*2+100,z*w,nTab[z]*2+100)            
        end
        stroke(colTab[2])
        for z=1,#iTab-1 do
            line((z-1)*w,iTab[z-1]*2+100,z*w,iTab[z]*2+100)            
        end
        stroke(colTab[3])
        for z=1,#coTab-1 do
            line((z-1)*w,coTab[z-1]*2+100,z*w,coTab[z]*2+100)            
        end
        stroke(colTab[4])
        for z=1,#cuTab-1 do
            line((z-1)*w,cuTab[z-1]*2+100,z*w,cuTab[z]*2+100)            
        end
    end
    
    function touched(t)
        if t.state==BEGAN then
            if infected==0 then
                tab[1].col=2
                tab[1].inf=1
                val=1
            end        
        end
    end
    
    function collide(contact)
        if contact.state==BEGAN then
            if contact.bodyA.col==3 then
                if contact.bodyB.col==1 then
                    contact.bodyB.inf=days
                    contact.bodyB.col=2
                    infected=infected+1
                    normal=normal-1
                end
            elseif contact.bodyB.col==3 then
                if contact.bodyA.col==1 then
                    contact.bodyA.inf=days
                    contact.bodyA.col=2
                    infected=infected+1
                    normal=normal-1
                end
            end
        end
    end
    
    function create()
        local a=#tab+1
        tab[a]=physics.body(CIRCLE,6)
        tab[a].mass=20
        tab[a].friction=0
        tab[a].x=math.random(30,WIDTH-30)
        tab[a].y=math.random(30,HEIGHT-30)
        tab[a].gravityScale=0
        tab[a].restitution=1
        tab[a].sleepingAllowed=false
        a1=math.random(-1,1)*speed
        a2=math.random(-1,1)*speed
        tab[a].linearVelocity=vec2(a1,a2)
        tab[a].inf=0
        tab[a].col=1
    end
    
  • Posts: 1,768

    @dave1707 - just started trying to do this today but didn’t get far. Ran the project and it’s great - just misses one component at a level of about 3%. One thing to note - ran this on three occasions and initially followed the progress and exited. On the other two occasions I was interrupted and had to leave it running - on both occasions it crashed Codea. Possibly need an end point on this to stop progress.

  • edited March 19 Posts: 1,768

    @dave1707 - just started trying to do this today but didn’t get far. Ran the project and it’s great - just misses one component at a level of about 3%. Just one thing - I have run the project 4 times now. The first ran to completion one closed the project. The second and third I ran and was interrupted - left the project running and in each case Codea crashed. Ran it on the fourth time and completed, plotted beyond the screen up to 108 days.

    Ran it a fifth time - my iPad has a case with a magnet in the cover which when sensed freezes the iPad. Closed my cover this time - project incomplete and Codea crashed.

    @Simeon - the shutdown is a design feature of the iPad as there are sensors present in the iPad. I have only noticed this with Codea - are there routines/protocols available from Apple to cope with this?

  • Posts: 545

    @dave1707 good, now i can send it to Boris! Interesting, the curves come out quite Gaussian.

  • dave1707dave1707 Mod
    Posts: 8,505

    @Bri_G I modified the above code to stop updating the counts and tables at 75 days. That should stop the crash. How long did you let it run. The program still updates the physics information. I never thought anyone would let this run for any length of time.

  • edited March 19 Posts: 1,768

    @dave1707 - first time when I took the dog for a walk, second time when I had my tea (each about 20 mins) but the third time as soon as the graph plotting had reached the right hand edge of the screen. But - I don’t think it is necessarily the code but due to the iPad freezing running apps. I think there must be routines or protocols to be run/complied with to re-open apps in a frozen state.

  • dave1707dave1707 Mod
    Posts: 8,505

    @piinthesky I’ve run this several times and noticed that when the infected graph peaks, it’s close to when the normal and contagious graphs cross. Also, when the contagious graph peaks, it’s close to when the infected and cured graphs cross.

  • SimeonSimeon Admin Mod
    Posts: 5,387

    @dave1707 that's a very interesting simulation. I like the differentiation between "contagious" and "infected"

  • Posts: 684

    i sure wonder why they grind to a halt on the sides

  • dave1707dave1707 Mod
    Posts: 8,505

    @RonJeffries As far as I can determine, once the speed gets below a certain value, the physics engine doesn’t work like it does at faster speeds. I’m not sure if I’m not setting everything right, or that’s just the way it is.

  • Posts: 684

    Yes ... with restitution = 1, I'd expect perfect collisions. Maybe there's some friction thing somewhere that we're missing. I fiddled with settings on the EDGEs but no joy.

  • dave1707dave1707 Mod
    Posts: 8,505

    @RonJeffries I was trying things with just two balls and with the speed below a certain limit. Even setting the restitution to 2 or higher, when the 2 balls collided, they just stopped. When I would go just 1 above that speed limit, the balls went crazy on each collision with a high restitution. So I would say there’s a speed limit for physics to work right.

  • dave1707dave1707 Mod
    Posts: 8,505

    @RonJeffries Heres some code to show the speed limit for 2 balls to bounce off each other. A speed of 16 or less doesn’t cause a bounce while a speed greater than 16 does. I can set linearDamping to a negative number, but that just causes the balls to speed up with multiple collisions in the other program. Change the speed value to see the bounce, no bounce.

    displayMode(STANDARD) 
    
    function setup()
        physics.continuous=true
        physics.gravity(0,0)  
    
        speed=16
    
        create1()
        create2()
    end
    
    function draw()
        background(0)    
        fill(255)
        ellipse(a1.x,a1.y,20)
        ellipse(a2.x,a2.y,20)
        v=a1.linearVelocity
        text(v.y,a1.x+80,a1.y)
        v1=a2.linearVelocity
        text(v.y,a2.x+80,a2.y)
    end
    
    function create1()
        a1=physics.body(CIRCLE,10)
        a1.sleepingAllowed=false
        a1.linearDamping=0
        a1.restitution=1
        a1.mass=1
        a1.friction=0
        a1.x=WIDTH/2
        a1.y=HEIGHT/2-50
        a1.linearVelocity=vec2(0,speed)
    end
    
    function create2()
        a2=physics.body(CIRCLE,10)
        a2.sleepingAllowed=false
        a2.linearDamping=0
        a2.restitution=1
        a2.mass=1
        a2.friction=0
        a2.x=WIDTH/2
        a2.y=HEIGHT/2+50
        a2.linearVelocity=vec2(0,-speed)
    end
    
  • Posts: 684

    weird

  • Posts: 545

    @dave1707 i was intrigued by the bouncing problem and went to the Box2D documentation. It seems there is a default velocity threshold (1) below which the collisions become inelastic. This might be the origin. This threshold is not exposed in Codea so @John would have do some work to make it user settable or just set it to a lower value.
    http://personal.boristhebrave.com/permanent/09/Box2DFlashAS3Docs/Box2D/Common/b2Settings.html#b2_velocityThreshold

  • dave1707dave1707 Mod
    Posts: 8,505

    @piinthesky Thanks for the link. Lots of interesting info there.

  • SimeonSimeon Admin Mod
    Posts: 5,387

    @dave1707 just saw this video with a bunch of virus transmission simulations and it reminded me of your work

  • Posts: 1,768

    @Simeon - WOW (for the code) OMG - what have they let loose on us???

    Thanks for posting, guess I won’t sleep for a while - lay back and ‘enjoy’ lockdown !!!

  • dave1707dave1707 Mod
    Posts: 8,505

    @Simeon That does look similar, but they put a lot more work into theirs.

Sign In or Register to comment.