Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Accretion Disk
#1
My goal with this one was to simulate a black hole's accretion disk using my standard vector library tools. It will eventually settle down to the entropic disk that I was after, but I wasn't expecting the initial splash patterns. I like how the particles will arrange themselves into discrete orbit shells. That said, this is NOT a gravity simulation, as attraction does not vary with distance.

Use the space bar to display a green "event horizon", which shows how close the orbits skim it.

It's an amusement to change some of the parameters and see how it affects the pattern and/or number of survivors.

The number in the upper right corner is the number of surviving particles, the rest are lost, forever lost! Wink

If you stare at it long enough the world will start spinning too. Maybe you might also begin to feel sleepy and have an irresistible urge to send me a sizeable check. Tongue

Code: (Select All)
OPTION _EXPLICIT

TYPE V2 '                                                       R2 vector format: used with R2_ subs & functions
    x AS SINGLE
    y AS SINGLE
END TYPE

TYPE particle
    ex AS INTEGER '                                             particle exists -1=yes 0=no
    p AS V2 '                                                   position
    d AS V2 '                                                   displacement aka movement
END TYPE

DIM c&, bs&, rs&
DIM vl%, vecs%, attrad%, wd%, ht%, eh%
DIM AS V2 tmp, op, cn
DIM speed!, attstr!

wd% = _DESKTOPWIDTH
ht% = _DESKTOPHEIGHT

SCREEN _NEWIMAGE(wd%, ht%, 32)
DO UNTIL _SCREENEXISTS: LOOP
_SCREENMOVE 0, 0
_TITLE "Accretion disk  {esc to quit}"

vecs% = 10000 '                                                 total starting particles
attrad% = 50 '                                                  radius of the attractor
attstr! = .1 '                                                  pull of the attractor
speed! = 1 '                                                    particle orbit velocity
bs& = &HFFAFAFFF '                                              particle color blue shift
rs& = &HFFFFAFAF '                                              particle color red shift

cn.x = _SHR(wd%, 1): cn.y = _SHR(ht%, 1) '                      screen center

'set initial particle data
RANDOMIZE TIMER
DIM SHARED V(vecs%) AS particle
FOR vl% = 0 TO UBOUND(V)
    V(vl%).ex = -1 '                                            particle exists at start
    DO
        V(vl%).p.x = INT(RND * wd%) '                           random position start
        V(vl%).p.y = INT(RND * wd%) - _SHR(wd% - ht%, 1)
        R2_P2P tmp, V(vl%).p, cn '                              get particle position vector <tmp> relative to screen center
    LOOP UNTIL R2_Mag(tmp) < _SHR(wd%, 1) '                     redo until particle within a circular area
    R2_Orth tmp, tmp, -1 '                                      convert position vector to an orthogonal rotation vector  - CCW  + CW
    R2_Norm V(vl%).d, tmp, speed! '                             set magnitude of rotation vector to speed! and assign it to particle displacement
NEXT vl%

'Main program loop
DO
    IF _KEYDOWN(32) THEN eh% = NOT eh%
    CLS
    _PRINTSTRING (0, 0), STR$(vecs%) '                          number of surviving particles
    IF eh% THEN CIRCLE (cn.x, cn.y), attrad%, &HFF00FF00 '      space bar to toggle the boundary of the attractor in green if desired
    FOR vl% = 0 TO UBOUND(V)
        IF NOT V(vl%).ex THEN _CONTINUE '                       skip particles that have been swallowed by attractor
        op = V(vl%).p
        R2_P2P tmp, op, cn '                                    obtain the inward pointing vector between particle and attractor
        c& = _IIF(R2_Dot(tmp, V(vl%).d) > 0, rs&, bs&) '        blue shift = approaching apogee, red shift = approaching perigee
        IF R2_Mag(tmp) < attrad% THEN '                         if particle is within "event horizon"
            V(vl%).ex = 0: vecs% = vecs% - 1 '                  particle has been absorbed by attractor
        ELSE
            R2_Norm tmp, tmp, attstr! '                         attractor force vector
            R2_Add V(vl%).d, tmp, 1 '                           add that to V(vl%).d
            R2_Add V(vl%).p, V(vl%).d, 1 '                      add displacement to position aka move it
            LINE (op.x, op.y)-(V(vl%).p.x, V(vl%).p.y), c& '    show the vector
        END IF
    NEXT vl%
    _LIMIT 30
    _DISPLAY
LOOP UNTIL _KEYDOWN(27)
END

'------------------------------------------------------------------------------
'SUBROUTINES
'------------------------------------------------------------------------------
SUB R2_P2P (re AS V2, st AS V2, nd AS V2)
    'ÞßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÝ
    'Þ Return a 2D position vector <re> from point (st) to point (nd)          Ý
    'ÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝ
    re.x = nd.x - st.x
    re.y = nd.y - st.y
END SUB 'R2_P2P

'------------------------------------------------------------------------------
SUB R2_Add (re AS V2, se AS V2, m AS SINGLE)
    'ÞßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÝ
    'Þ Adds (or subtracts) a scalar multiple (m) of vector <se> to vector <re> Ý
    'Þ if <re> is to be preserved in its prior state then a copy should be     Ý
    'Þ made for the subroutine call. Send a negative scalar (m) to subtract    Ý
    'Þ Returns: vector <re>                                                    Ý
    'ÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝ
    re.x = re.x + se.x * m
    re.y = re.y + se.y * m
END SUB 'R2_Add

'------------------------------------------------------------------------------
FUNCTION R2_Dot (v AS V2, v2 AS V2)
    'ÞßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÝ
    'Þ Return scalar dot product between two V2 vectors <v> & <v2>            Ý
    'ÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝ
    R2_Dot = v.x * v2.x + v.y * v2.y
END FUNCTION 'R3_Dot

'------------------------------------------------------------------------------
FUNCTION R2_Mag! (v AS V2)
    'ÞßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÝ
    'Þ Return the scalar magnitude of 2D vector (v)                           Ý
    'ÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝ
    R2_Mag! = _HYPOT(v.x, v.y)
END FUNCTION 'R2_Mag!

'------------------------------------------------------------------------------
SUB R2_Orth (re AS V2, v AS V2, d AS INTEGER)
    'ÞßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÝ
    'Þ Returns vector <re> as a 90ø orthogonal of vector <v>. Sending a       Ý
    'Þ positive value for d rotates clockwise, while a negative value for     Ý
    'Þ d rotates counterclockwise. <re> & <v> can be the same.                Ý
    'ÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝ
    DIM x!, y!
    x! = v.x: y! = v.y
    re.x = y! * SGN(d)
    re.y = -x! * SGN(d)
END SUB 'R2_Orth

'------------------------------------------------------------------------------
SUB R2_Norm (re AS V2, v AS V2, scalar AS SINGLE)
    'ÞßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÝ
    'Þ Grow/Shrink V2 vector <v> to (scalar) length. <re> & <v> can be the    Ý
    'Þ same vectors, overwriting the original. Vector direction is preserved. Ý
    'Þ Returns: vector <re> as new length of <v>                              Ý
    'ÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝ
    DIM m!
    DIM t AS V2 '                                               temporary vector
    t = v '                                                     V vector to temporary container
    m! = R2_Mag!(t) '                                           magnitude of temporary
    IF m! = 0 THEN
        re.x = 0: re.y = 0 '                                    zero vector- no direction information available
    ELSE
        re.x = (t.x / m!) * scalar '                            reduce to unit and expand to scalar
        re.y = (t.y / m!) * scalar '                            and assign to return vector
    END IF
END SUB 'R2_Norm
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply


Messages In This Thread
Accretion Disk - by OldMoses - Yesterday, 12:08 PM
RE: Accretion Disk - by Dimster - Yesterday, 12:28 PM
RE: Accretion Disk - by OldMoses - Yesterday, 04:41 PM
RE: Accretion Disk - by bplus - Yesterday, 12:34 PM
RE: Accretion Disk - by NakedApe - Yesterday, 05:12 PM
RE: Accretion Disk - by OldMoses - Yesterday, 07:10 PM
RE: Accretion Disk - by Dav - Yesterday, 08:46 PM
RE: Accretion Disk - by a740g - Yesterday, 10:49 PM
RE: Accretion Disk - by hsiangch_ong - 10 hours ago
RE: Accretion Disk - by bplus - 2 hours ago

Forum Jump:


Users browsing this thread: 1 Guest(s)