% file: "barnes.erl"
-module(barnes2).
-export([?MODULE/0]).
?MODULE() ->
Stars = create_scenario(1000, 1.0),
R = hd(loop(10,1000.0,Stars,0)),
Str = lists:flatten(io:lib_format("~s", [R])),
{R,Str =:= {1.00000,-1.92269e+4,-1.92269e+4,2.86459e-2,2.86459e-2}}.
create_scenario(N, M) ->
create_scenario0(0, 0, trunc(math:sqrt(N)), M).
create_scenario0(_X, _SN, _SN, _M) ->
[];
create_scenario0(SN, Y, SN, M) ->
create_scenario0(0, Y+1, SN, M);
create_scenario0(X, Y, SN, M) ->
XPos0 = (((20000.0 * 2) / SN) * X) - 20000.0,
YPos0 = (((20000.0 * 2) / SN) * Y) - 20000.0,
Calibrate = ((20000.0 * 2) / SN) / 2,
XPos = XPos0 + Calibrate,
YPos = YPos0 + Calibrate,
[{M, XPos, YPos, 0.0, 0.0} | create_scenario0(X+1, Y, SN, M)].
relpos_to_quadrant(DX, DY) when DX >= 0 ->
if
DY >= 0 -> 0;
true -> 3
end;
relpos_to_quadrant(_, DY) ->
if
DY >= 0 -> 1;
true -> 2
end.
quadrant_to_dx(0, D) -> D;
quadrant_to_dx(1, D) -> -D;
quadrant_to_dx(2, D) -> -D;
quadrant_to_dx(3, D) -> D.
quadrant_to_dy(Q,D) ->
if
Q < 2 -> D;
true -> -D
end.
create_tree(Stars) ->
create_tree0(Stars, empty).
create_tree0([],Tree) ->
Tree;
create_tree0([{M,X,Y,_,_} | Stars], Tree) ->
create_tree0(Stars, insert_tree_element(Tree, M, X, Y, 0.0, 0.0, 20000.0)).
insert_tree_element(empty, M, X, Y, _OX, _OY, _D) ->
{body,M,X,Y};
insert_tree_element({branch,M0,SubTree}, M, X, Y, OX, OY, D) ->
Q = relpos_to_quadrant(X-OX,Y-OY),
D2 = D / 2,
DX = quadrant_to_dx(Q,D2),
DY = quadrant_to_dy(Q,D2),
{branch,M0+M,setelement(Q+1,SubTree,
insert_tree_element(element(Q+1,SubTree),
M, X, Y, OX+DX, OY+DY,D2))};
insert_tree_element({body,M0,X0,Y0},M,X,Y,OX,OY,D) ->
resolve_body_conflict(M,X,Y,M0,X0,Y0,OX,OY,D).
resolve_body_conflict(M0, X0, Y0, M1, X1, Y1, OX, OY, D) ->
T = {empty,empty,empty,empty},
Q0 = relpos_to_quadrant(X0-OX,Y0-OY),
Q1 = relpos_to_quadrant(X1-OX,Y1-OY),
D2 = D / 2,
if
Q0 == Q1 -> DX = quadrant_to_dx(Q0,D2),
DY = quadrant_to_dy(Q1,D2),
{branch,M0+M1,setelement(Q0+1,T,
resolve_body_conflict(M0,X0,Y0,
M1,X1,Y1,
OX+DX,OY+DY,
D2))} ;
true -> {branch,M0+M1, setelement(Q1+1,
setelement(Q0+1,T,{body,M0,X0,Y0}),
{body,M1,X1,Y1})}
end.
compute_acceleration(empty, _, _, _, _, _,L) ->
{{0.0, 0.0},L+1};
compute_acceleration({body,BM,BX,BY}, _D, _OX, _OY, X, Y,L) ->
DX = BX - X,
DY = BY - Y,
R2 = (DX * DX) + (DY * DY),
Divisor = R2 * math:sqrt(R2),
if
Divisor < 0.000001 -> % was: Divisor < ?EPSILON ->
{{0.0, 0.0},L+1};
true ->
Expr = BM / Divisor,
{{DX * Expr, DY * Expr},L+1}
end;
compute_acceleration({branch,M,SubTree}, D, OX, OY, X, Y,L) ->
DX = OX - X,
DY = OY - Y,
R2 = (DX * DX) + (DY * DY),
DD = D*D,
R2_THETA2 = 0.09 * R2, % TRY 2.0 *R2, !!! was: R2_THETA2 = ?THETA2*R2,
if
% Ok to approximate?
DD < R2_THETA2 ->
Divisor = R2 * math:sqrt(R2),
if
Divisor < 0.000001 ->
{{0.0,0.0},L};
true ->
Expr = M / Divisor,
{{DX*Expr, DY*Expr},L+1}
end;
% Not ok to approximate...
true ->
D2 = D / 2,
{{AX0, AY0},L1} = compute_acceleration(element(1,SubTree),
D2, OX + quadrant_to_dx(0,D2),
OY + quadrant_to_dy(0,D2),X,Y,L),
{{AX1, AY1},L2} = compute_acceleration(element(2,SubTree),
D2, OX + quadrant_to_dx(1,D2),
OY + quadrant_to_dy(1,D2),X,Y,L1),
{{AX2, AY2},L3} = compute_acceleration(element(3,SubTree),
D2,OX + quadrant_to_dx(2,D2),
OY + quadrant_to_dy(2,D2),X,Y,L2),
{{AX3, AY3},L4} = compute_acceleration(element(4,SubTree),
D2, OX + quadrant_to_dx(3,D2),
OY + quadrant_to_dy(3,D2),X,Y,L3),
{{AX0+AX1+AX2+AX3, AY0+AY1+AY2+AY3},L4+1}
end.
compute_star_accelerations(_Tree,[],L) ->
{[],L};
compute_star_accelerations(Tree,[{_,X, Y,_,_}|Stars],L) ->
{A,AL} = compute_acceleration(Tree, 20000.0, 0.0, 0.0, X, Y,L),
{B,BL} = compute_star_accelerations(Tree, Stars,AL),
{[A | B],BL}.
compute_next_state([],_,_) ->
[];
compute_next_state([{M,X,Y,VX,VY}|Stars],[{AX,AY}|Accs],Time) ->
VX0 = VX + (AX * Time),
VY0 = VY + (AY * Time),
[{M,X+(VX*Time),Y+(VY*Time),VX0,VY0} | compute_next_state(Stars,Accs,Time)].
advance_time(Time,Stars,L) ->
Tree = create_tree(Stars),
{Acc,NL} = compute_star_accelerations(Tree, Stars,L),
{compute_next_state(Stars, Acc, Time),NL}.
loop(0,_Time,Stars,_L) ->
Stars;
loop(N,Time,Stars,L) ->
{NS,NL} = advance_time(Time,Stars,L),
loop(N-1,Time,NS,NL).