Identifying steady-state slope via linear regression made me think about processes that would have a naturally changing behavior over time and how to make some JSL to simulate some data. This JSL runs a simulation of 30 points bouncing between the ends of a one-dimensional tube; the points can't pass each other and bounce off each other and the ends of the tube. There is a bit of friction at the ends of the tube to make the velocity decay over time and velocity averaging else where. The simulation loop is fairly efficient; it runs 100 million cycles in half an hour. Because of the 1-D constraint it can check for collisions on all 30 objects in a fast matrix operation.
The graph presents time on the X axis, as the cycle number. The colorful graph on the bottom is tracking the 30 point positions on the Y axis. Watch the point color and you can see points moving up and down and bouncing when they hit. The upper graph shows the decay in the total of the absolute velocities. Because points become identical opposites when they bounce, the right end of the graph shows a lot of similar banding as behaviors synchronize.
Rainbow graph of point positions.
dt = New Table( "particles" );
n = 30;
dt << addmultiplecolumns( "pos", n, "Numeric" );
dt << addmultiplecolumns( "vel", n, "Numeric" );
dt << newcolumn("time");
dt << newcolumn("energy");
dt << addrow( 1 );
allpos = 1 :: n;
allposDown = 1 :: n - 1;
dt[N Rows( dt ), allpos] = Sort List( J( 1, n, Random Uniform( 0, .01 ) ) );
allvel = allpos + n;
dt[N Rows( dt ), allvel] = J( 1, n, Random Normal( 0, .0001 ) );
newvel = dt[N Rows( dt ), allvel];
newpos = dt[N Rows( dt ), allpos] + newvel;
limit=1e8;
start = tickseconds();
For( i = 1, i < limit, i += 1,
change = 0;
newpos += newvel;
seq1 = Loc( newpos - (0 || newpos[0, allposDown]) < 0 );
For Each( {iPos}, seq1,
If( ipos > 1,
where = Mean( newpos[iPos - 1], newpos[iPos] );
speed = Mean( Abs( newvel[iPos - 1] ), Abs( newvel[iPos] ) );
newpos[iPos - 1] = Max( 0, where );
newvel[iPos - 1] = -speed;
,
where = -newpos[iPos] / 1000;
speed = Abs( newvel[iPos] ) / 2;
);
newpos[iPos] = Min( 1, where );
newvel[iPos] = speed;
change = 1;
);
if( newpos[n]>1,
newpos[n] = 1 - (newpos[n] - 1) / 1000;
newvel[n] = -newvel[n]/2;
change = 1;
);
If( change,
dt << addrows( 1 );
dt[N Rows( dt ), allvel] = newvel;
dt[N Rows( dt ), allpos] = newpos;
dt:time[N Rows( dt )] = i;
dt:energy[N Rows( dt )] = sum(abs(newvel));
);
);
stop = tickseconds();
speed = "Wall clock time: "||char(stop-start,9,1)||" seconds.";
dt << Graph Builder( Size( 1754, 804 ), Show Control Panel( 0 ), Show Legend( 0 ),
Variables( X( :time ), Y( :energy ), Y( :pos 01 ), Y( :pos 02, Position( 2 ) ), Y( :pos 03, Position( 2 ) ), Y( :pos 04, Position( 2 ) ), Y( :pos 05, Position( 2 ) ), Y( :pos 06, Position( 2 ) ), Y( :pos 07, Position( 2 ) ), Y( :pos 08, Position( 2 ) ), Y( :pos 09, Position( 2 ) ), Y( :pos 10, Position( 2 ) ), Y( :pos 11, Position( 2 ) ), Y( :pos 12, Position( 2 ) ), Y( :pos 13, Position( 2 ) ), Y( :pos 14, Position( 2 ) ), Y( :pos 15, Position( 2 ) ), Y( :pos 16, Position( 2 ) ), Y( :pos 17, Position( 2 ) ), Y( :pos 18, Position( 2 ) ), Y( :pos 19, Position( 2 ) ), Y( :pos 20, Position( 2 ) ), Y( :pos 21, Position( 2 ) ), Y( :pos 22, Position( 2 ) ), Y( :pos 23, Position( 2 ) ), Y( :pos 24, Position( 2 ) ), Y( :pos 25, Position( 2 ) ), Y( :pos 26, Position( 2 ) ), Y( :pos 27, Position( 2 ) ), Y( :pos 28, Position( 2 ) ), Y( :pos 29, Position( 2 ) ), Y( :pos 30, Position( 2 ) )),
Relative Sizes( "Y", [79 337] ),
Elements( Position( 1, 1 ), Points( X, Y, Legend( 5 ) ) ),
Elements( Position( 1, 2 ), Points( X, Y( 1 ), Y( 2 ), Y( 3 ), Y( 4 ), Y( 5 ), Y( 6 ), Y( 7 ), Y( 8 ), Y( 9 ), Y( 10 ), Y( 11 ), Y( 12 ), Y( 13 ), Y( 14 ), Y( 15 ), Y( 16 ), Y( 17 ), Y( 18 ), Y( 19 ), Y( 20 ), Y( 21 ), Y( 22 ), Y( 23 ), Y( 24 ), Y( 25 ), Y( 26 ), Y( 27 ), Y( 28 ), Y( 29 ), Y( 30 ), Legend( 3 ))),
SendToReport( Dispatch( {}, "time", ScaleBox, {Scale( "Log" ), Min( 99 ), Max( 101000000 ), Inc( 1 ), Minor Ticks( 1 ), Label Row( {Show Minor Labels( 0 )})} ),
Dispatch( {}, "energy", ScaleBox, {Scale( "Log" ), Format( "Best", 10 ), Min( 0.0000009 ), Max( 0.003 ), Inc( 1 ), Minor Ticks( 1 ), Label Row( {Show Major Grid( 1 ), Show Minor Labels( 0 )})}),
Dispatch( {}, "pos 01", ScaleBox, {Min( -0.008 ), Max( 1.03 ), Inc( 0.2 ), Minor Ticks( 3 )} ),
Dispatch( {}, "400", ScaleBox, {Legend Model( 5, Properties( 0, {Line Color( 0 )}, Item ID( "energy", 1 ) ) )} ),
Dispatch( {}, "graph title", TextEditBox, {Set Text( "energy remaining in system (top), 30 points spreading out (bottom)" )} ),
Dispatch( {}, "Graph Builder", FrameBox, {Background Color( 32 ), Marker Size( 0 ), Marker Drawing Mode( "Fast" )} ),
Dispatch( {}, "Y 1 title", TextEditBox, {Set Text( "points" )} ),
Dispatch( {}, "Graph Builder", FrameBox( 2 ), {Marker Size( 0 ), Marker Drawing Mode( "Fast" ), {Add Text Annotation(Text("the points are initially near y==0 and are confined to a 1-dimensional Y axis from 0 to 1. As they bump each other they exchange some velocity/energy and bounce so they never exchange positions in the 1-D column. When the first or last point bumps the end, half of its energy is lost, so the energy curve drops toward zero and the points slow down. The initial velocities are random normal. The fish-net appearance around 10,000 shows the zig-zag bouncing if the colors are examined rather than the long straight lines. Each iteration adds 1 to the time axis for 100 million iterations."),Fixed Size( 0 ),Text Box( {44, 47, 392, 614} ),Filled( 0 )), Add Text Annotation( Text( speed ), Fixed Size( 0 ), Text Box( {56, 459, 278, 496} ), Filled( 0 ) )}})
)
);
It's just for fun and does not represent any real-world system. Not a physics major. Enjoy.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.