https://github.com/florentrenaud/nbody6tt
Tip revision: 8a4716382ead3ece116c48a4ae5c65f8c9534437 authored by Florent on 29 January 2015, 12:19:28 UTC
Nbody6 - 29 January 2015 (added GPU2/Build/.gitkeep)
Nbody6 - 29 January 2015 (added GPU2/Build/.gitkeep)
Tip revision: 8a47163
ksinit.f
SUBROUTINE KSINIT
*
*
* Initialization of KS regularization.
* ------------------------------------
*
INCLUDE 'common6.h'
COMMON/FSAVE/ SAVEIT(6)
REAL*8 Q(3),RDOT(3),UI(4),VI(4),A1(3,4)
REAL*8 A(9),F1(3),F1DOT(3)
INTEGER IPIPE(9)
SAVE IPIPE
DATA IPIPE /9*0/
*
*
* Set new global indices of the components and current pair index.
ICOMP = 2*NPAIRS - 1
JCOMP = ICOMP + 1
IPAIR = NPAIRS
*
* Add body #N in case the only neighbour was removed in KSREG.
IF (LIST(1,ICOMP).EQ.0) THEN
LIST(2,ICOMP) = N
LIST(2,JCOMP) = N
LIST(1,ICOMP) = 1
LIST(1,JCOMP) = 1
END IF
*
* Specify mass, neighbour radius, name, radius & type for new c.m.
BODY(NTOT) = BODY(ICOMP) + BODY(JCOMP)
RS(NTOT) = RS(ICOMP)
NAME(NTOT) = NZERO + NAME(ICOMP)
RADIUS(NTOT) = 0.0
TEV(NTOT) = 1.0E+10
TEV0(NTOT) = 1.0E+10
BODY0(NTOT) = BODY(NTOT)
EPOCH(NTOT) = TIME*TSTAR
KSTAR(NTOT) = 0
IMOD = 1
*
* Define c.m. coordinates & velocities and set XDOT for components.
DO 10 K = 1,3
X(K,NTOT) = (BODY(ICOMP)*X(K,ICOMP) + BODY(JCOMP)*X(K,JCOMP))/
& BODY(NTOT)
X0DOT(K,NTOT) = (BODY(ICOMP)*X0DOT(K,ICOMP) + BODY(JCOMP)*
& X0DOT(K,JCOMP))/BODY(NTOT)
XDOT(K,NTOT) = X0DOT(K,NTOT)
XDOT(K,ICOMP) = X0DOT(K,ICOMP)
XDOT(K,JCOMP) = X0DOT(K,JCOMP)
X0(K,NTOT) = X(K,NTOT)
X0(K,JCOMP) = X(K,JCOMP)
10 CONTINUE
*
* Obtain force polynomial for c.m. with components ICOMP & JCOMP.
NNB = LIST(1,ICOMP)
*
* Predict current coordinates & velocities for the neighbours.
CALL XVPRED(ICOMP,NNB)
*
* Choose between full FPOLY1/2 or just neighbours (skip non-standard).
IF (N.LT.5000.OR.IPHASE.NE.1) THEN
*
* Obtain new polynomials & steps (first F & FDOT, then F2DOT & F3DOT).
CALL FPOLY1(ICOMP,JCOMP,1)
CALL FPOLY2(NTOT,NTOT,1)
*
ELSE
*
* Treat each component in turn (initialize, then evaluate F & FDOT).
I = ICOMP
ICM = NTOT
110 DO 115 K = 1,3
FI(K,I) = 0.0
D1(K,I) = 0.0
115 CONTINUE
*
* Obtain irregular force & first derivative for body #I.
KDUM = 0
NNB = LIST(1,ICM)
* Loop over neighbours only using c.m. list (cf. FPOLY1).
DO 140 L = 2,NNB+1
J = LIST(L,ICM)
IF (J.GT.N) THEN
JPAIR = J - N
* Use c.m. approximation for unperturbed binary.
IF (LIST(1,2*JPAIR-1).GT.0) THEN
KDUM = 2*JPAIR - 1
J = KDUM
END IF
END IF
*
120 DO 125 K = 1,3
A(K) = X(K,J) - X(K,I)
A(K+3) = XDOT(K,J) - XDOT(K,I)
125 CONTINUE
*
A(7) = 1.0/(A(1)*A(1) + A(2)*A(2) + A(3)*A(3))
A(8) = BODY(J)*A(7)*SQRT(A(7))
A(9) = 3.0*(A(1)*A(4) + A(2)*A(5) + A(3)*A(6))*A(7)
*
* Accumulate irregular force and first derivative.
DO 130 K = 1,3
F1(K) = A(K)*A(8)
F1DOT(K) = (A(K+3) - A(K)*A(9))*A(8)
FI(K,I) = FI(K,I) + F1(K)
D1(K,I) = D1(K,I) + F1DOT(K)
130 CONTINUE
*
* Check for KS component.
IF (J.EQ.KDUM) THEN
J = J + 1
GO TO 120
END IF
140 CONTINUE
*
* Check option for external force (note FR already done).
IF (KZ(14).GT.0) THEN
CALL XTRNLD(I,I,1)
END IF
*
* Treat second component in the same way.
IF (I.EQ.ICOMP) THEN
I = JCOMP
GO TO 110
END IF
*
* Form c.m. force and derivative from mass-weighted terms.
FIRR = 0.0
FDIRR = 0.0
DO 150 K = 1,3
FI(K,ICM) = (BODY(ICOMP)*FI(K,ICOMP) +
& BODY(JCOMP)*FI(K,JCOMP))/BODY(ICM)
D1(K,ICM) = (BODY(ICOMP)*D1(K,ICOMP) +
& BODY(JCOMP)*D1(K,JCOMP))/BODY(ICM)
FIRR = FIRR + FI(K,ICM)**2
FDIRR = FDIRR + D1(K,ICM)**2
150 CONTINUE
*
* Obtain irregular time-step and check commensurability.
DT = ETAI*SQRT(FIRR/FDIRR)
CALL STEPK(DT,DTN)
STEP(ICM) = DTN
ITER = 0
160 IF (DMOD(TIME,STEP(ICM)).NE.0.0D0) THEN
STEP(ICM) = 0.5D0*STEP(ICM)
ITER = ITER + 1
IF (ITER.LT.16.OR.STEP(ICM).GT.DTK(40)) GO TO 160
STEP(ICM) = DTK(40)
END IF
* Include reduction due to missing higher derivatives.
STEP(ICM) = 0.25*STEP(ICM)
T0(ICM) = TIME
T0R(ICM) = TIME
TNEW(ICM) = TIME + STEP(ICM)
*
* Form force components and first derivatives for c.m.
DO 170 K = 1,3
FR(K,ICM) = SAVEIT(K)
D1R(K,ICM) = SAVEIT(K+3)
FRDOT(K,ICM) = SAVEIT(K+3)
F(K,ICM) = FI(K,ICM) + FR(K,ICM)
FDOT(K,ICM) = D1(K,ICM) + D1R(K,ICM)
F(K,ICM) = 0.5*F(K,ICM)
FDOT(K,ICM) = ONE6*FDOT(K,ICM)
D0(K,ICM) = FI(K,ICM)
D2(K,ICM) = 0.0
D3(K,ICM) = 0.0
D2R(K,ICM) = 0.0
D3R(K,ICM) = 0.0
170 CONTINUE
*
* Assign regular time-step and perform commensurability check.
FIRR = 0.0
FDIRR = 0.0
DO 175 K = 1,3
FIRR = FIRR + FR(K,ICM)**2
FDIRR = FDIRR + D1R(K,ICM)**2
175 CONTINUE
DT = ETAR*SQRT(FIRR/FDIRR)
CALL STEPK(DT,DTN)
STEPR(ICM) = 0.25*DTN
ITER = 0
180 IF (DMOD(TIME,STEPR(ICM)).NE.0.0D0) THEN
STEPR(ICM) = 0.5D0*STEPR(ICM)
ITER = ITER + 1
IF (ITER.LT.16.OR.STEPR(ICM).GT.DTK(40)) GO TO 180
STEPR(ICM) = DTK(40)
END IF
END IF
*
* Skip KS initialization at merger termination (H, U & UDOT in RESET).
IF (IPHASE.EQ.7) THEN
EB = 2.0*EBH
GO TO 50
END IF
*
* Define relative coordinates and velocities in physical scaled units.
DO 20 K = 1,3
Q(K) = X(K,ICOMP) - X(K,JCOMP)
RDOT(K) = X0DOT(K,ICOMP) - X0DOT(K,JCOMP)
20 CONTINUE
*
* Introduce regularized variables using definition of Book.
R(IPAIR) = SQRT(Q(1)**2 + Q(2)**2 + Q(3)**2)
*
* Initialize the regularized coordinates according to sign of Q(1).
IF (Q(1).LE.0.0D0) THEN
UI(3) = 0.0D0
UI(2) = SQRT(0.5D0*(R(IPAIR) - Q(1)))
UI(1) = 0.5D0*Q(2)/UI(2)
UI(4) = 0.5D0*Q(3)/UI(2)
ELSE
UI(4) = 0.0D0
UI(1) = SQRT(0.5D0*(R(IPAIR) + Q(1)))
UI(2) = 0.5D0*Q(2)/UI(1)
UI(3) = 0.5D0*Q(3)/UI(1)
END IF
*
* Set current transformation matrix.
CALL MATRIX(UI,A1)
*
* Form regularized velocity and set initial KS coordinates.
TDOT2(IPAIR) = 0.0
DO 30 K = 1,4
UDOT(K,IPAIR) = 0.50D0*(A1(1,K)*RDOT(1) + A1(2,K)*RDOT(2) +
& A1(3,K)*RDOT(3))
* Note that A1(J,K) is the transpose of A1(K,J).
U(K,IPAIR) = UI(K)
U0(K,IPAIR) = U(K,IPAIR)
TDOT2(IPAIR) = TDOT2(IPAIR) + 2.0D0*UI(K)*UDOT(K,IPAIR)
30 CONTINUE
*
* Evaluate initial binding energy per unit mass (singular form).
H(IPAIR) = (2.0D0*(UDOT(1,IPAIR)**2 + UDOT(2,IPAIR)**2 +
& UDOT(3,IPAIR)**2 + UDOT(4,IPAIR)**2) -
& BODY(NTOT))/R(IPAIR)
EB = H(IPAIR)*BODY(ICOMP)*BODY(JCOMP)/BODY(NTOT)
*
* Form perturber list.
50 CALL KSLIST(IPAIR)
*
* Transform any unperturbed hard binary to apocentre and set time-step.
SEMI = -0.5*BODY(NTOT)/H(IPAIR)
IF (LIST(1,ICOMP).EQ.0.AND.EB.LT.EBH.AND.SEMI.LT.RMIN) THEN
TK = TWOPI*SEMI*SQRT(SEMI/BODY(NTOT))
* Note TIME is not commensurate after KSPERI (cf. CHTERM & STEPS).
IF (IPHASE.NE.7.AND.IPHASE.NE.8) THEN
DO 55 K = 1,4
VI(K) = UDOT(K,IPAIR)
55 CONTINUE
* Determine pericentre time (TP < 0 if TDOT2 < 0) and add TK/2.
CALL TPERI(SEMI,UI,VI,BODY(NTOT),TP)
* Note: apocentre to apocentre gives almost zero step.
STEP(ICOMP) = 0.5*MIN(TK,STEP(NTOT)) - TP
* Transform KS variables to peri and by pi/2 to apocentre (skip apo).
IF (ABS(TDOT2(IPAIR)).GT.1.0E-12.OR.R(IPAIR).LT.SEMI) THEN
TIME0 = TIME
CALL KSPERI(IPAIR)
CALL KSAPO(IPAIR)
* Reset TIME to quantized value (small > 0 or < 0 possible initially).
TIME = TIME0
TIME = MAX(TIME,0.0D0)
ELSE IF (TDOT2(IPAIR).GT.0.0) THEN
TDOT2(IPAIR) = -1.0E-20
END IF
END IF
END IF
*
* Estimate an appropriate KS slow-down index for G < GMIN.
IF (LIST(1,ICOMP).EQ.0.AND.SEMI.GT.0.0) THEN
TK = TWOPI*SEMI*SQRT(SEMI/BODY(NTOT))
IF (KZ(26).GT.0.AND.STEP(NTOT).GT.TK) THEN
IMOD = 1 + LOG(STEP(NTOT)/TK)/0.69
IMOD = MIN(IMOD,5)
END IF
END IF
*
* Specify zero membership and set large steps for second component.
LIST(1,JCOMP) = 0
* Set large step for second component to avoid detection.
STEP(JCOMP) = 1.0E+06
STEPR(JCOMP) = 1.0E+06
*
* Obtain polynomials for perturbed KS motion (standard case & merger).
CALL KSPOLY(IPAIR,IMOD)
*
* Obtain apocentre distance.
SEMI = -0.5*BODY(NTOT)/H(IPAIR)
ECC2 = (1.0-R(IPAIR)/SEMI)**2 + TDOT2(IPAIR)**2/(BODY(NTOT)*SEMI)
RAP = SEMI*(1.0 + SQRT(ECC2))
*
* Include suggestion for monitoring hyperbolic encounters (suppressed).
* IF (SEMI.LT.0.0) THEN
* PMIN = SEMI*(1.0 - SQRT(ECC2))
* WRITE (31,56) TIME+TOFF, NAME(ICOMP), NAME(JCOMP), PMIN
* 56 FORMAT (' HYPERBOLIC T NAM PMIN ',F8.2,2I6,1P,E10.2)
* END IF
*
* Set 2*SEMI as termination scale for hard binary if 2*SEMI < RS/20.
IF (EB.LT.EBH.AND.RAP.LT.0.05*RS(NTOT)) THEN
R0(IPAIR) = MAX(RMIN,-BODY(NTOT)/H(IPAIR))
R0(IPAIR) = MIN(R0(IPAIR),5.0*RMIN)
ELSE
R0(IPAIR) = R(IPAIR)
END IF
*
* Increase regularization counters (#9 & NKSHYP for hyperbolic orbits).
NKSREG = NKSREG + 1
IF (H(IPAIR).GT.0.0) NKSHYP = NKSHYP + 1
*
* Check optional output for new KS.
IF (KZ(10).GT.0) THEN
RI = SQRT((X(1,NTOT) - RDENS(1))**2 +
& (X(2,NTOT) - RDENS(2))**2 +
& (X(3,NTOT) - RDENS(3))**2)
WRITE (6,60) TIME+TOFF, NAME(ICOMP), NAME(JCOMP),DTAU(IPAIR),
& R(IPAIR), RI, H(IPAIR), IPAIR, GAMMA(IPAIR),
& STEP(NTOT), LIST(1,ICOMP), LIST(1,NTOT)
60 FORMAT (/,' NEW KSREG TIME =',F8.2,2I6,F12.3,1P,E10.1,
& 0P,F7.2,F9.2,I5,F8.3,1P,E10.1,2I5)
END IF
*
* Include limited diagnostics for NS or BH hard binary formation.
IF (MAX(KSTAR(ICOMP),KSTAR(JCOMP)).GE.13.AND.EB.LT.EBH.AND.
& IPHASE.NE.7) THEN
ID = 0
NP = IPIPE(1)
* See whether at least one component was recorded in previous pair.
DO 62 J = 2,NP+1
IF (IPIPE(J).EQ.NAME(ICOMP).OR.
& IPIPE(J).EQ.NAME(JCOMP)) ID = ID + 1
62 CONTINUE
* Print diagnostics if NS/BH binary not listed among four last pairs.
IF (ID.LE.1) THEN
PD = DAYS*SEMI*SQRT(ABS(SEMI)/BODY(NTOT))
WRITE (6,65) TIME+TOFF, NAME(ICOMP), NAME(JCOMP),
& KSTAR(ICOMP), KSTAR(JCOMP), KSTAR(NTOT),
& SQRT(ECC2), PD, EB
65 FORMAT (' NS/BH BINARY T NM K* E P EB ',
& F8.1,2I6,3I4,F7.3,1P,E9.1,E11.2)
END IF
* Update table and membership by removing first two.
IF (NP.GE.8) THEN
* Note there are at most 4 pairs with entries in IPIPE(2:9).
DO 66 J = 2,6
IPIPE(J) = IPIPE(J+2)
IPIPE(J+1) = IPIPE(J+3)
66 CONTINUE
NP = NP - 2
END IF
* Add NAME of each component in NP+2/3 and increase membership by 2.
IPIPE(NP+2) = NAME(ICOMP)
IPIPE(NP+3) = NAME(JCOMP)
IPIPE(1) = NP + 2
END IF
*
* Modify the termination criterion according to value of NPAIRS.
IF (NPAIRS.GT.KMAX - 3) GMAX = 0.8*GMAX
IF (NPAIRS.LT.KMAX - 5.AND.GMAX.LT.0.001) GMAX = 1.2*GMAX
IF (NPAIRS.EQ.KMAX) WRITE (6,70) NPAIRS, TIME+TOFF
70 FORMAT (5X,'WARNING! MAXIMUM KS PAIRS NPAIRS TIME',I5,F9.2)
*
* Initialize prediction variables to avoid skipping KS components.
DO 75 KCOMP = 1,2
JDUM = 2*NPAIRS - 2 + KCOMP
DO 72 K = 1,3
X0(K,JDUM) = X(K,JDUM)
X0DOT(K,JDUM) = 0.0D0
F(K,JDUM) = 0.0D0
FDOT(K,JDUM) = 0.0D0
D2(K,JDUM) = 0.0D0
D3(K,JDUM) = 0.0D0
D2R(K,JDUM) = 0.0D0
D3R(K,JDUM) = 0.0D0
72 CONTINUE
75 CONTINUE
*
* See whether either component has been regularized recently.
NNB = LISTD(1) + 1
K = 0
* Check case of initial binary and loop over disrupted pairs.
IF (IABS(NAME(ICOMP) - NAME(JCOMP)).EQ.1) THEN
IF (NAME(ICOMP).LE.2*NBIN0) K = -1
END IF
DO 80 L = 2,NNB
IF (NAME(ICOMP).EQ.LISTD(L).OR.NAME(JCOMP).EQ.LISTD(L)) K = -1
80 CONTINUE
IF (H(IPAIR).GT.0.0) K = 0
*
* Treat mergers as new binaries and ensure chain/hard KS as standard.
IF (IPHASE.EQ.6) THEN
K = 0
ELSE IF (K.EQ.0) THEN
IF (IPHASE.EQ.8.OR.EB.LT.EBH) K = -1
END IF
* Set flag to distinguish between existing and new binaries (K = -1/0).
LIST(2,JCOMP) = K
*
* Check diagnostic output of new hard binary.
IF (KZ(8).GT.0.AND.K.EQ.0) THEN
IF (EB.GT.EBH) GO TO 100
SEMI = -0.5*BODY(NTOT)/H(IPAIR)
RI = SQRT((X(1,NTOT) - RDENS(1))**2 +
& (X(2,NTOT) - RDENS(2))**2 +
& (X(3,NTOT) - RDENS(3))**2)
WRITE (8,90) TIME+TOFF, NAME(ICOMP), NAME(JCOMP), K,
& BODY(ICOMP),BODY(JCOMP), EB, SEMI, R(IPAIR),
& GAMMA(IPAIR), RI
90 FORMAT (' NEW BINARY T =',F7.1,' NAME = ',2I6,I3,
& ' M =',1P,2E9.1,' EB =',E9.1,
& ' A =',E9.1,' R =',E9.1,' G =',E9.1,
& ' RI =',E9.1)
CALL FLUSH(8)
END IF
*
100 RETURN
*
END