Skip to content

usnistgov/steppyngstounes

Repository files navigation

steppyngstounes / ˈstɛp ɪŋˌstoʊnz /

1. pl. n. [Middle English] Stones used as steps of a stairway; also, stones in a stream used for crossing.1

...while at Calais in 1474 we find 40 'steppyngstounes' bought for the stairways of the town.2

2. n. [chiefly Pythonic] A package that provides iterators for advancing from start to stop, subject to algorithms that depend on user-defined value or error.

Testing Documentation Linting GitHub Codacy

Computations that evolve in time or sweep a variable often boil down to a control loop like

for step in range(steps):
    do_something(step)

or

t = 0
while t < totaltime:
    t += dt
    do_something(dt)

which works well enough, until the size of the steps needs to change. This can be to save or plot results at some fixed points, or because the computation becomes either harder or easier to perform. The control loop then starts to dominate the script, obscuring the interesting parts of the computation, particularly as different edge cases are accounted for.

Packages like odeint address many of these issues, but do so through callback functions, which effectively turn the computation of interest inside out, again obscuring the interesting bits. Further, because they are often tailored for applications like solving ordinary differential equations, applying them to other stepping problems, even solving partial differential equations, can be rather opaque.

The steppyngstounes package is designed to retain the simplicity of the original control loop, while allowing great flexibility in how steps are taken and automating all of the aspects of increasing and decreasing the step size.

A steppyngstounes control loop can be as simple as

from steppyngstounes import FixedStepper

for step in FixedStepper(start=0., stop=totaltime, size=dt):
    do_something(step.size)

    _ = step.succeeded()

which replicates the while construct above, but further ensures that totaltime is not overshot if it isn't evenly divisible by dt.

Attention

The call to ~steppyngstounes.stepper.Step.succeeded informs the ~steppyngstounes.stepper.Stepper to advance, otherwise it will iterate on the same step indefinitely.

Rather than manually incrementing the control variable (e.g., t), the values of the control variable before and after the step are available as the ~steppyngstounes.stepper.Step attributes ~steppyngstounes.stepper.Step.begin and ~steppyngstounes.stepper.Step.end. The attribute ~steppyngstounes.stepper.Step.size is a shorthand for step.end - step.begin.

If the size of the steps should be adjusted by some characteristic of the calculation, such as the change in the value since the last solution, the error (normalized to 1) can be passed to ~steppyngstounes.stepper.Step.succeeded, causing the ~steppyngstounes.stepper.Stepper to advance (possibly adjusting the next step size) or to retry the step with a smaller step size.

from steppyngstounes import SomeStepper

old = initial_condition
for step in SomeStepper(start=0., stop=totaltime, size=dt):
    new = do_something_else(step.begin, step.end, step.size)

    err = (new - old) / scale

    if step.succeeded(error=err):
        old = new
        # do happy things
    else:
        # do sad things

A hierarchy of ~steppyngstounes.stepper.Stepper iterations enables saving or plotting results at fixed, possibly irregular, points, while allowing an adaptive ~steppyngstounes.stepper.Stepper to find the most efficient path between those checkpoints.

from steppyngstounes import CheckpointStepper, SomeStepper

old = initial_condition
for checkpoint in CheckpointStepper(start=0.,
                                    stops=[1e-3, 1, 1e3, 1e6]):

    for step in SomeStepper(start=checkpoint.begin,
                            stop=checkpoint.end,
                            size=checkpoint.size):

        new = do_something_else(step.begin, step.end, step.size)

        err = (new - old) / scale

        if step.succeeded(error=err):
            old = new
            # do happy things
        else:
            # do sad things

    save_or_plot()

    _ = checkpoint.succeeded()

A variety of stepping algorithms are described and demonstrated in the documentation of the individual steppyngstounes classes.



  1. Middle English Dictionary, Ed. Robert E. Lewis, et al., Ann Arbor: University of Michigan Press, 1952-2001. Online edition in Middle English Compendium, Ed. Frances McSparran, et al., Ann Arbor: University of Michigan Library, 2000-2018. <https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED42815>. Accessed 16 December 2020.

  2. Building in England, Down to 1540: A Documentary History, L. F. Salzman, Clarenden Press, Oxford, 1952. <https://books.google.com/books?id=WtZPAAAAMAAJ&focus=searchwithinvolume&q=steppyngstounes>. Accessed 16 December 2020.