Previous | ToC | Up | Next |

** Alice**: We have seen that constant time steps allow you to stop and
restart, and to get exactly the same results as you would have gotten,
had you done one single integration from being to end. But when we
tried to do the same thing with adaptive, shared time steps, we found
that we could not reproduce the same orbits.

** Bob**: And we knew why. In fact, we had predicted that we couldn't.

** Alice**: Yes. Now the question is: can we regain our reproducibility?

** Bob**: How?

** Alice**: What did * not* work was to force an output at exactly the right
time. That had the side effect of forcing the last step to be smaller
than it would have otherwise been.

However, there is an alternative. How about letting the system overshoot, so that it can do an output a time it is happy with. When we then restart the system, the integration should happen just like it would have otherwise.

** Bob**: I see what you mean. Well, let's test it!

** Alice**: Here is what we did before, but this time without the
`--exact_time` option:

|gravity> kali nbody_sh1.rb -t 1 < test.in > test01n.out ==> Shared Time Step Code <== Integration method : method = hermite Parameter to determine time step size: dt_param = 0.01 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 1.0 Duration of the integration : t = 1.0 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 1.00035, after 1927 steps : E_kin = 0.312 , E_pot = -0.562 , E_tot = -0.25 E_tot - E_init = -2.26e-10 (E_tot - E_init) / E_init = 9.03e-10 |gravity> kali nbody_sh1.rb -t 1 < test01n.out > test12n.out ==> Shared Time Step Code <== Integration method : method = hermite Parameter to determine time step size: dt_param = 0.01 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 1.0 Duration of the integration : t = 1.0 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 1.00035, after 0 steps : E_kin = 0.312 , E_pot = -0.562 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 2.00117, after 1224 steps : E_kin = 0.171 , E_pot = -0.421 , E_tot = -0.25 E_tot - E_init = 2.83e-10 (E_tot - E_init) / E_init = -1.13e-09 |gravity> kali nbody_sh1.rb -t 2 -o 2 < test.in > test02n.out ==> Shared Time Step Code <== Integration method : method = hermite Parameter to determine time step size: dt_param = 0.01 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 2.0 Duration of the integration : t = 2.0 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 1.00035, after 1927 steps : E_kin = 0.312 , E_pot = -0.562 , E_tot = -0.25 E_tot - E_init = -2.26e-10 (E_tot - E_init) / E_init = 9.03e-10 at time t = 2.00117, after 3151 steps : E_kin = 0.171 , E_pot = -0.421 , E_tot = -0.25 E_tot - E_init = 5.76e-11 (E_tot - E_init) / E_init = -2.31e-10

** Alice**: As close to zero as we can!

** Bob**: Well, let's hope for the best:

|gravity> cat test12n.out test02n.out | kali nbody_diff.rb ==> 6N-dimensional phase space distance between two N-body systems <== Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 6N-dim. phase space dist. for two 4-body systems: 0.0000000000000000e+00

** Alice**: Hmmm, that's not good at all. What did we do to deserve that!

** Bob**: If we look at the diagnostics output, we see that we needed the same
number of steps to reach time 1, exactly 1263 in each case. Then in
the continued run, we took another 669 steps. This gives us a total
number of 1932 steps. Aha! That is * not* the number of steps that
the second run took.

** Alice**: Good catch! The second run stopped too early. And yes, of course,
we could have noticed that directly, had we looked at the final time: the
second run indeed shows an earlier ending time than the first one.

** Bob**: And that makes sense, too: we ask each run to go fro one or two time
units, or slightly more if they overshoot. Now asking a code to overshoot
twice in a row is likely to produce a larger overshoot than doing it
only once.

** Alice**: Again, you must be right. Going from time 0 to 1, with an
overshoot, and then adding one more time unit plus a new overshoot is
* not* the same as going from 0 to 2 immediately, with whatever overshoot
that gives.

** Bob**: Well, shall we try to let the long run proceed a little further,
to match up with the previous one?

** Alice**: You can certainly try. So this means adding the difference
of the two ending times to the desired duration; or in fact slightly
less, since we'll produce an overshoot anyway.

** Bob**: Okay, how about this:

|gravity> kali nbody_sh1.rb -t 2.0037 -o 2.0037 < test.in > test02n.out ==> Shared Time Step Code <== Integration method : method = hermite Parameter to determine time step size: dt_param = 0.01 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 2.0037 Duration of the integration : t = 2.0037 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 1.00035, after 1927 steps : E_kin = 0.312 , E_pot = -0.562 , E_tot = -0.25 E_tot - E_init = -2.26e-10 (E_tot - E_init) / E_init = 9.03e-10 at time t = 2.00117, after 3151 steps : E_kin = 0.171 , E_pot = -0.421 , E_tot = -0.25 E_tot - E_init = 5.76e-11 (E_tot - E_init) / E_init = -2.31e-10 |gravity> cat test12n.out test02n.out | kali nbody_diff.rb ==> 6N-dimensional phase space distance between two N-body systems <== Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 6N-dim. phase space dist. for two 4-body systems: 9.2780296991970546e-03

** Alice**: The right distance, this time, namely zero. Perfect!

** Bob**: It literally couldn't have been better.

** Alice**: Wait, wait: we still have only 1927 steps, and we still stop at
too early a time. What is going on? According to the diagnostics, nothing
has changed from the previous run.

** Bob**: Now * that* is strange. Obviously, the phase space distance is zero.
So something has changed. Yet I see your point. This is a real paradox.

** Alice**: What could possibly be . . . .

** Bob**: . . . Ahaha! Of course! We changed the ending time and output
time, by a slight amount, but we did not change the diagnostics output
time!

** Alice**: Of course, of course! Ah, that is a relief. Good! Mystery solved,
hopefully. You'd better check, though!

** Bob**: Okay, here we go again:

|gravity> kali nbody_sh1.rb -t 2.0037 -d 2.0037 -o 2.0037 < test.in > test02n.out ==> Shared Time Step Code <== Integration method : method = hermite Parameter to determine time step size: dt_param = 0.01 Interval between diagnostics output: dt_dia = 2.0037 Time interval between snapshot output: dt_out = 2.0037 Duration of the integration : t = 2.0037 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 2.00395, after 3152 steps : E_kin = 0.171 , E_pot = -0.421 , E_tot = -0.25 E_tot - E_init = 5.75e-11 (E_tot - E_init) / E_init = -2.3e-10 |gravity> cat test12n.out test02n.out | kali nbody_diff.rb ==> 6N-dimensional phase space distance between two N-body systems <== Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 6N-dim. phase space dist. for two 4-body systems: 9.2780296991970546e-03

** Bob**: How easy to get confused!

** Alice**: And how nice to be reassured, afterwards, that the world is still
logical, after all.

** Bob**: You know, there is a better solution for the problem we encountered,
when we had to deal with an output file that had more than one
snapshot in it.

** Alice**: You mean in the case in which we ran a code for two time steps,
but we had forgotten that we get by default an output at every time step,
so that when we looked at the start of the file, we found the output for
time 1, rather than for time 2?

** Bob**: Yes, that was the problem. I'm sure we'll run into this again,
often, and what we really need is a tool that picks up the * last* ACS
object from a file, not the first one. Normally, if you open a file
and start reading, you would read in the first ACS file first, but
instead, we need to do something like what in Unix the command ` tail`
does, showing the end of a file.

** Alice**: The Unix command ` tail` has a default of showing you ten lines,
but you can ask it to show more or fewer lines, with the option `-n`
as in:

|gravity> tail -n 3 test02n.out Float time 2.0039487382209993e+00 SCAwhich shows the last three lines.

** Bob**: Okay, let us call the file `acstail.rb`. How about this?

#!/usr/local/bin/ruby -w require "acs" options_text= <<-END Description: Returns the last n chunks of ACS data Long description: This program accepts ACS data, in the form of a series of chunks, each chunk starting with "ACS" on the first line, and ending with "SCA" on the last line. Like the Unix program `tail', it returns the last n chunks. (c) 2004, Piet Hut, Jun Makino; see ACS at www.artcompsi.org example: kali #{$0} -n 5 Short name: -n Long name: --number Value type: int Default value: 1 Description: Number of last ACS data chunks returned Variable name: n Long description: This option allows the user to choose the number of ACS chunks that will be returned by this program, after a series of ACS chunks have been read in. END clop = parse_command_line(options_text) chunk = [] a = ACS_IO.acs_read while a chunk.push(a) chunk.shift if chunk.length > clop.n a = ACS_IO.acs_read end while chunk[0] chunk.shift.acs_write end

** Alice**: Looks fine to me. How about doing our previous experiment,
without adjusting the output frequency, and using `acstail.rb`
instead?

** Bob**: Good idea! Here you go. Let's be systematic. We know that this
works:

|gravity> kali nbody_cst1.rb -t 2 -o 2 < test.in > test02.out ==> Constant Time Step Code <== Integration method : method = hermite Softening length : eps = 0.0 Time step size : dt = 0.001 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 2.0 Duration of the integration : t = 2.0 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 1, after 1000 steps : E_kin = 0.248 , E_pot = -0.613 , E_tot = -0.365 E_tot - E_init = -0.115 (E_tot - E_init) / E_init = 0.461 at time t = 2, after 2000 steps : E_kin = 1.3 , E_pot = -2.12 , E_tot = -0.815 E_tot - E_init = -0.565 (E_tot - E_init) / E_init = 2.26 |gravity> cat test12.out test02.out | kali nbody_diff.rb ==> 6N-dimensional phase space distance between two N-body systems <== Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 6N-dim. phase space dist. for two 4-body systems: 0.0000000000000000e+00and we also know that this doesn't work:

|gravity> kali nbody_cst1.rb -t 2 < test.in > test02.out ==> Constant Time Step Code <== Integration method : method = hermite Softening length : eps = 0.0 Time step size : dt = 0.001 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 1.0 Duration of the integration : t = 2.0 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 1, after 1000 steps : E_kin = 0.248 , E_pot = -0.613 , E_tot = -0.365 E_tot - E_init = -0.115 (E_tot - E_init) / E_init = 0.461 at time t = 2, after 2000 steps : E_kin = 1.3 , E_pot = -2.12 , E_tot = -0.815 E_tot - E_init = -0.565 (E_tot - E_init) / E_init = 2.26 |gravity> cat test12.out test02.out | kali nbody_diff.rb ==> 6N-dimensional phase space distance between two N-body systems <== Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 6N-dim. phase space dist. for two 4-body systems: 2.7562194398214426e+00And if all is well, our new tool should be able to repair the last problem, as follows:

|gravity> kali nbody_cst1.rb -t 2 < test.in | kali acstail.rb > test02.out ==> Returns the last n chunks of ACS data <== Number of last ACS data chunks returned: n = 1 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 ==> Constant Time Step Code <== Integration method : method = hermite Softening length : eps = 0.0 Time step size : dt = 0.001 Interval between diagnostics output: dt_dia = 1.0 Time interval between snapshot output: dt_out = 1.0 Duration of the integration : t = 2.0 Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 at time t = 0, after 0 steps : E_kin = 0.25 , E_pot = -0.5 , E_tot = -0.25 E_tot - E_init = 0 (E_tot - E_init) / E_init = -0 at time t = 1, after 1000 steps : E_kin = 0.248 , E_pot = -0.613 , E_tot = -0.365 E_tot - E_init = -0.115 (E_tot - E_init) / E_init = 0.461 at time t = 2, after 2000 steps : E_kin = 1.3 , E_pot = -2.12 , E_tot = -0.815 E_tot - E_init = -0.565 (E_tot - E_init) / E_init = 2.26 |gravity> cat test12.out test02.out | kali nbody_diff.rb ==> 6N-dimensional phase space distance between two N-body systems <== Screen Output Verbosity Level : verbosity = 1 ACS Output Verbosity Level : acs_verbosity = 1 Floating point precision : precision = 16 Incremental indentation : add_indent = 2 6N-dim. phase space dist. for two 4-body systems: 0.0000000000000000e+00

Previous | ToC | Up | Next |