Nbody6
 All Files Functions Variables
ksterm.f
Go to the documentation of this file.
1  SUBROUTINE ksterm
2 *
3 *
4 * Termination of KS regularization.
5 * ---------------------------------
6 *
7  include 'common6.h'
8  common/slow0/ range,islow(10)
9  common/binary/ cm(4,mmax),xrel(3,mmax),vrel(3,mmax),
10  & hm(mmax),um(4,mmax),umdot(4,mmax),tmdis(mmax),
11  & namem(mmax),nameg(mmax),kstarm(mmax),iflag(mmax)
12  REAL*8 SAVE(15)
13 *
14 *
15 * Copy pair index from COMMON save and define KS components & c.m.
16  ipair = kspair
17  i1 = 2*ipair - 1
18  i2 = i1 + 1
19  icm = n + ipair
20  jmin = 0
21 *
22 * Prepare termination at block time (KS, triple, quad, chain or merge).
23  IF (time.LE.tblock.AND.iphase.LT.9) THEN
24  time0 = tblock
25 * Skip KS integration for unperturbed orbit or T0(I1) at end of block.
26  IF (list(1,i1).EQ.0.OR.t0(i1).EQ.time0) go to 3
27 *
28 * See whether the time interval should be modified by KSLOW procedure.
29  IF (kslow(ipair).GT.1) THEN
30  imod = kslow(ipair)
31  zmod = float(islow(imod))
32  ELSE
33  zmod = 1.0
34  END IF
35 *
36  1 dt0 = time0 - t0(i1)
37 * Integrate up to current block time in case interval is too large.
38  IF (dt0.GT.step(i1)) THEN
39  time = t0(i1) + step(i1)
40  h0(ipair) = h(ipair)
41  z = -0.5d0*h(ipair)*dtau(ipair)**2
42  CALL stumpf(ipair,z)
43  CALL ksint(i1)
44  dtu = dtau(ipair)
45  step(i1) = ((one6*tdot3(ipair)*dtu + 0.5*tdot2(ipair))*dtu
46  & + r(ipair))*dtu
47  step(i1) = zmod*step(i1)
48 * Restrict increase of R for superfast particles in one block-step.
49  IF (h(ipair).GT.100.0.AND.r(ipair).GT.rmin) go to 3
50  go to 1
51  END IF
52 *
53 * Determine the last regularized step by Newton-Raphson iteration.
54  dtu = dt0/(r(ipair)*zmod)
55  dtu = min(dtu,dtau(ipair))
56 * Include rare case of zero interval due to subtracting large values.
57  dtu = max(dtu,1.0d-10)
58  iter = 0
59  2 y0 = dt0 - zmod*((one6*tdot3(ipair)*dtu +
60  & 0.5*tdot2(ipair))*dtu + r(ipair))*dtu
61  ypr = -((0.5*tdot3(ipair)*dtu + tdot2(ipair))*dtu + r(ipair))
62  ypr = zmod*ypr
63  dtu = dtu - y0/ypr
64  dt1 = ((one6*tdot3(ipair)*dtu + 0.5*tdot2(ipair))*dtu +
65  & r(ipair))*dtu
66  dt1 = zmod*dt1
67  iter = iter + 1
68  IF (abs(dt0 - dt1).GT.1.0e-10*step(i1).AND.iter.LT.10) go to 2
69 *
70 * Advance the KS solution to next block time and terminate at TIME0.
71  dtau(ipair) = dtu
72  step(i1) = dt1
73  time = t0(i1) + dt1
74  h0(ipair) = h(ipair)
75  z = -0.5d0*h(ipair)*dtu**2
76  CALL stumpf(ipair,z)
77  CALL ksint(i1)
78  3 time = time0
79 *
80 * Predict X & XDOT for body #JCOMP (note TIME = TBLOCK if second call).
81  IF (jcomp.GE.ifirst) THEN
82  CALL xvpred(jcomp,-1)
83  IF (gamma(ipair).GT.0.2.AND.jcomp.LE.n) THEN
84  jmin = jcomp
85 * Initialize T0, X0 & X0DOT for XVPRED & FPOLY on large perturbation.
86  t0(jcomp) = time
87  DO 4 k = 1,3
88  x0(k,jcomp) = x(k,jcomp)
89  x0dot(k,jcomp) = xdot(k,jcomp)
90  4 CONTINUE
91  END IF
92  END IF
93  END IF
94 *
95 * Predict coordinates and evaluate potential energy w.r.t. perturbers.
96  CALL ksres(ipair,j1,j2,0.0d0)
97  np = list(1,i1)
98  DO 5 l = 1,np
99  jpert(l) = list(l+1,i1)
100  5 CONTINUE
101  jlist(1) = i1
102  jlist(2) = i2
103  CALL nbpot(2,np,pot1)
104 *
105 * Rectify the orbit to yield U & UDOT consistent with binding energy.
106  CALL ksrect(ipair)
107 *
108 * Retain final KS variables for explicit restart at merge termination.
109  IF (time.LE.tblock.AND.iphase.EQ.6) THEN
110  hm(nmerge) = h(ipair)
111  DO 6 k = 1,4
112  um(k,nmerge) = u(k,ipair)
113  umdot(k,nmerge) = udot(k,ipair)
114  6 CONTINUE
115  END IF
116 *
117 * Check optional diagnostic output for disrupted new hard binary.
118  IF (kz(8).EQ.0) go to 10
119  IF (list(2,i1+1).NE.0.OR.h(ipair).GT.0.0) go to 10
120  IF (gamma(ipair).GT.0.5.AND.jcomp.GT.0.OR.iphase.EQ.7) THEN
121  IF (jcomp.EQ.0.OR.iphase.EQ.7) jcomp = i1
122  k = 0
123  IF (jcomp.GT.n) THEN
124  j2 = 2*(jcomp - n)
125  k = list(2,j2)
126  END IF
127  semi = -0.5*body(icm)/h(ipair)
128  eb = -0.5*body(i1)*body(i2)/semi
129  ri = sqrt((x(1,icm) - rdens(1))**2 +
130  & (x(2,icm) - rdens(2))**2 +
131  & (x(3,icm) - rdens(3))**2)
132  WRITE (8,8) time+toff, name(i1), name(i2), k, name(jcomp),
133  & body(jcomp), eb, semi, r(ipair), gamma(ipair), ri
134  8 FORMAT (' END BINARY T =',f8.1,' NAME = ',2i6,i3,i6,
135  & ' M(J) =',f8.4,' EB =',f10.5,' A =',f8.5,
136  & ' R =',f8.5,' G =',f5.2,' RI =',f5.2)
137  END IF
138 *
139  10 IF (kz(10).GT.1) THEN
140  ri = sqrt((x(1,icm) - rdens(1))**2 +
141  & (x(2,icm) - rdens(2))**2 +
142  & (x(3,icm) - rdens(3))**2)
143 * Include error of the bilinear relation (cf. Book Eqn.(4.30)).
144  err = u(4,ipair)*udot(1,ipair) - u(3,ipair)*udot(2,ipair) +
145  & u(2,ipair)*udot(3,ipair) - u(1,ipair)*udot(4,ipair)
146  WRITE (6,15) time+toff, body(i1), body(i1+1), dtau(ipair),
147  & r(ipair), ri, h(ipair), ipair, gamma(ipair),
148  & step(i1), list(1,i1), list(1,icm), err
149  15 FORMAT (/,' END KSREG TIME =',f8.2,1p,2e9.1,0p,f6.3,1p,
150  & e10.1,0p,f7.2,f9.2,i5,f8.3,1p,e10.1,2i5,1p,e10.2)
151  END IF
152 *
153 * Obtain global coordinates & velocities.
154  CALL resolv(ipair,2)
155 *
156 * Correct for differential potential energy due to rectification.
157  CALL nbpot(2,np,pot2)
158 * Add correction term with opposite sign for conservation.
159 * ECOLL = ECOLL + (POT2 - POT1)
160 * IF (ABS(POT1-POT2).GT.0.0001) WRITE (6,16) POT1,BE(3),POT1-POT2
161 * 16 FORMAT (' CORRECT: POT1 BE3 POT1-POT2 ',2F10.6,F10.6)
162 *
163 * Modify c.m. neighbour radius by density contrast and set new values.
164  nnb = list(1,icm) + 1
165 * Check predicted neighbour number and form volume ratio.
166  nbp = min(alpha*sqrt(float(nnb)*rs(icm))/(rs(icm)**2),znbmax)
167  nbp = max(nbp,int(znbmin))
168  a0 = float(nbp)/float(nnb)
169 * Re-determine neighbour list on zero membership for distant binary.
170  IF (list(1,icm).EQ.0) THEN
171  rs0 = 0.1*(abs(x(1,icm)) + abs(x(2,icm)))
172  CALL nblist(icm,rs0)
173  nnb = list(1,icm) + 1
174  END IF
175 * Copy all neighbours in the case of merger.
176  IF (iphase.EQ.6) THEN
177  a0 = 1.0
178  nbp = nnb - 1
179  END IF
180  IF (rs(icm).GT.-100.0*body(icm)/h(ipair)) a0 = 1.0
181 * Accept old c.m. values for small length scale ratio or H > 0.
182  rs(i1) = rs(icm)*a0**0.3333
183  rs(i1+1) = rs(i1)
184  rs2 = rs(i1)**2
185 *
186 * Select neighbours for components inside the modified c.m. sphere.
187  20 nnb1 = 1
188  DO 25 l = 2,nnb
189  j = list(l,icm)
190  rij2 = (x(1,icm) - x(1,j))**2 + (x(2,icm) - x(2,j))**2 +
191  & (x(3,icm) - x(3,j))**2
192 * Ensure that at least the predicted neighbour number is reached.
193  IF (rij2.LT.rs2.OR.(nnb1 + nnb - l.LE.nbp.AND.
194  & nnb1.LT.nnbmax-1)) THEN
195  nnb1 = nnb1 + 1
196  ilist(nnb1) = j
197  END IF
198  25 CONTINUE
199 *
200 * Check that there is space for adding dominant component later.
201  IF (nnb1.GE.nnbmax.AND.iphase.NE.6) THEN
202  rs2 = 0.9*rs2
203  go to 20
204  END IF
205 *
206 * Reduce pair index, total number & single particle index.
207  npairs = npairs - 1
208  ntot = n + npairs
209  ifirst = 2*npairs + 1
210 *
211 * Save name of components & flag for modifying LISTD in UPDATE.
212  jlist(1) = name(i1)
213  jlist(2) = name(i1+1)
214  jlist(3) = list(2,i1+1)
215 *
216 * Skip adjustment of tables if last or only pair being treated.
217  IF (ipair.EQ.npairs + 1) go to 60
218 *
219 * Move the second component before the first.
220  DO 50 kcomp = 2,1,-1
221  i = 2*ipair - 2 + kcomp
222 *
223  DO 30 k = 1,3
224  save(k) = x(k,i)
225  save(k+3) = x0dot(k,i)
226  30 CONTINUE
227 * Current velocity has been set in routine RESOLV.
228  save(7) = body(i)
229  save(8) = rs(i)
230  save(9) = radius(i)
231  save(10) = tev(i)
232  save(11) = body0(i)
233  save(12) = tev0(i)
234  save(13) = epoch(i)
235  save(14) = spin(i)
236  save(15) = zlmsty(i)
237  namei = name(i)
238  ksi = kstar(i)
239  last = 2*npairs - 1 + kcomp
240 *
241 * Move up global variables of other components.
242  DO 40 j = i,last
243  j1 = j + 1
244  DO 35 k = 1,3
245  x(k,j) = x(k,j1)
246 * Copy latest X & X0DOT (= 0) of single components for predictor.
247  x0(k,j) = x(k,j)
248  x0dot(k,j) = x0dot(k,j1)
249  35 CONTINUE
250  body(j) = body(j1)
251  rs(j) = rs(j1)
252  radius(j) = radius(j1)
253  tev(j) = tev(j1)
254  tev0(j) = tev0(j1)
255  body0(j) = body0(j1)
256  epoch(j) = epoch(j1)
257  spin(j) = spin(j1)
258  zlmsty(j) = zlmsty(j1)
259  name(j) = name(j1)
260  kstar(j) = kstar(j1)
261  step(j) = step(j1)
262  t0(j) = t0(j1)
263  k = list(1,j1) + 1
264  IF (k.EQ.1) k = 2
265 * Transfer unmodified neighbour lists (include flag in 2nd comp).
266  DO 38 l = 1,k
267  list(l,j) = list(l,j1)
268  38 CONTINUE
269  40 CONTINUE
270 *
271 * Set new component index and copy basic variables.
272  i = last + 1
273  DO 45 k = 1,3
274  x(k,i) = save(k)
275  x0dot(k,i) = save(k+3)
276  xdot(k,i) = save(k+3)
277  45 CONTINUE
278  body(i) = save(7)
279  rs(i) = save(8)
280  radius(i) = save(9)
281  tev(i) = save(10)
282  body0(i) = save(11)
283  tev0(i) = save(12)
284  epoch(i) = save(13)
285  spin(i) = save(14)
286  zlmsty(i) = save(15)
287  name(i) = namei
288  kstar(i) = ksi
289  50 CONTINUE
290 *
291 * Include removal of the circularization name NAMEC from chaos table.
292  IF (kstar(icm).GE.10.AND.nchaos.GT.0.AND.iphase.NE.6) THEN
293 * Note that NAMEC may remain dormant for hierarchical systems.
294  ii = -icm
295  CALL spiral(ii)
296  END IF
297 *
298 * Update all regularized variables.
299  CALL remove(ipair,2)
300 *
301 * Remove old c.m. from all COMMON tables (no F & FDOT correction).
302  CALL remove(icm,3)
303 *
304 * Set new global index of first & second component.
305  60 icomp = 2*npairs + 1
306  jcomp = icomp + 1
307 *
308 * Save c.m. neighbour list for routine FPOLY1/2 (may be renamed below).
309  ilist(1) = nnb1 - 1
310  DO 65 l = 1,nnb1
311  list(l,icomp) = ilist(l)
312  65 CONTINUE
313 *
314 * Modify all relevant COMMON list arrays.
315  CALL update(ipair)
316 *
317 * Check replacing of single KS component by corresponding c.m.
318  70 IF (list(2,icomp).LT.icomp) THEN
319  j2 = list(2,icomp)
320  j = kvec(j2) + n
321  DO 80 l = 2,nnb1
322  IF (l.LT.nnb1.AND.list(l+1,icomp).LT.j) THEN
323  list(l,icomp) = list(l+1,icomp)
324  ELSE
325  list(l,icomp) = j
326  END IF
327  80 CONTINUE
328 * Check again until first neighbour > ICOMP.
329  go to 70
330  END IF
331 *
332 * Make space for dominant component and copy members to JCOMP list.
333  DO 90 l = nnb1,2,-1
334  list(l+1,icomp) = list(l,icomp)
335  list(l+1,jcomp) = list(l,icomp)
336  90 CONTINUE
337 *
338 * Set dominant component in first location and specify membership.
339  list(2,icomp) = jcomp
340  list(2,jcomp) = icomp
341  list(1,icomp) = nnb1
342  list(1,jcomp) = nnb1
343 *
344 * Initialize T0, T0R, X0 & X0DOT for both components.
345  t0(icomp) = time
346  t0(jcomp) = time
347  t0r(icomp) = time
348  t0r(jcomp) = time
349  DO 95 k = 1,3
350  x0(k,icomp) = x(k,icomp)
351  x0(k,jcomp) = x(k,jcomp)
352  x0dot(k,icomp) = xdot(k,icomp)
353  x0dot(k,jcomp) = xdot(k,jcomp)
354  95 CONTINUE
355 *
356 * Form new force polynomials (skip triple, quad, merge & chain).
357  IF (iphase.LT.4) THEN
358 * Predict current coordinates & velocities for the neighbours.
359  CALL xvpred(icomp,nnb1)
360 *
361 * Obtain new polynomials & steps.
362  CALL fpoly1(icomp,jcomp,2)
363  CALL fpoly2(icomp,jcomp,2)
364 *
365 * Improve force polynomials of strong perturber after rectification.
366  IF (jmin.GE.ifirst) THEN
367  CALL fpoly1(jmin,jmin,0)
368  CALL fpoly2(jmin,jmin,0)
369  END IF
370  END IF
371 *
372 * Check updating of global index for chain c.m.
373  IF (nch.GT.0) THEN
374  CALL chfind
375  END IF
376 *
377  RETURN
378 *
379  END