Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An improved adaptive timestep for IAS15 #711

Closed
wants to merge 105 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
88f4bf4
Squashed commit of the following:
hannorein Jul 20, 2023
7d0e7f3
stricter unit test
hannorein Jul 20, 2023
1c49cb4
do not calculat dtmode_zeta if not needed
hannorein Jul 20, 2023
571ff3e
style to avoid large diff
hannorein Jul 20, 2023
d4a05e1
refactoring, should take care of more edge cases
hannorein Jul 20, 2023
5fcfc0e
minor style for short diff
hannorein Jul 20, 2023
97d1ad6
minor style
hannorein Jul 20, 2023
9df6bdb
fabs
hannorein Jul 20, 2023
427d07d
syntax
hannorein Jul 20, 2023
9d2c8a7
Merge branch 'main' into newias
hannorein Jul 20, 2023
ef121a9
slightly relatex unit test
hannorein Jul 20, 2023
44cec2a
Merge branch 'main' into newias
hannorein Aug 7, 2023
d1617bb
Added fp contract test
hannorein Aug 7, 2023
c0806c2
backwards
hannorein Aug 7, 2023
6f27dfd
match old scaling
hannorein Aug 7, 2023
f5c26ff
sqrt7
hannorein Aug 7, 2023
fa73261
notebook for timestep check
hannorein Aug 7, 2023
d1727e3
scaling in sqrt7
hannorein Aug 7, 2023
4bf9444
notebook
hannorein Aug 8, 2023
d0ea34e
snap
hannorein Aug 8, 2023
d873038
numerical factor analytic:
hannorein Aug 9, 2023
e34aca8
direction fix
hannorein Aug 10, 2023
a479cf5
comment
hannorein Aug 10, 2023
2e202c5
mix snap + jerk
hannorein Aug 10, 2023
943c976
same safety
hannorein Aug 14, 2023
bfb5734
bench
hannorein Aug 23, 2023
fb496f5
basic c version working.
hannorein Aug 23, 2023
635c67d
field descriptor test
hannorein Aug 23, 2023
94e88f5
in prog
hannorein Aug 24, 2023
46ac666
in prog
hannorein Aug 24, 2023
f3ca282
prog
hannorein Aug 24, 2023
c7ed324
prog
hannorein Aug 24, 2023
45f6e3b
all variables
hannorein Aug 24, 2023
8bc66ce
double now written using list
hannorein Aug 24, 2023
f2af9be
minor
hannorein Aug 24, 2023
925fdd8
ints from list
hannorein Aug 24, 2023
26e37fd
compact
hannorein Aug 24, 2023
6ab561f
long
hannorein Aug 24, 2023
01374d0
vec3d
hannorein Aug 24, 2023
8f02fcd
input side
hannorein Aug 24, 2023
15360cf
old saba removed
hannorein Aug 24, 2023
5ec8a00
more
hannorein Aug 24, 2023
d8bb90e
working on var config
hannorein Aug 24, 2023
a686f5a
var_config ok
hannorein Aug 25, 2023
ef93306
Pointers
hannorein Aug 25, 2023
0227998
pointers
hannorein Aug 25, 2023
96621e5
cleanup
hannorein Aug 25, 2023
14f2793
cleanup
hannorein Aug 25, 2023
4879381
cleanup
hannorein Aug 25, 2023
e9c14be
cleanup
hannorein Aug 25, 2023
5033c6c
cleanup
hannorein Aug 25, 2023
2bd85c1
removed simulationarchive version 1
hannorein Aug 25, 2023
610ff50
max radius
hannorein Aug 25, 2023
8435e88
end
hannorein Aug 25, 2023
46f07ad
REB_POINTER_ALIGNED
hannorein Aug 25, 2023
bc18c1a
cleanup
hannorein Aug 25, 2023
b44c34d
tes start
hannorein Aug 25, 2023
594906f
more tes
hannorein Aug 25, 2023
d118da6
removed statevectorlength from tes. Rely on allocated_N
hannorein Aug 25, 2023
c828e9d
tes
hannorein Aug 25, 2023
da54210
working needs cleanup
hannorein Aug 25, 2023
5b89794
descriptor helper functions
hannorein Aug 25, 2023
10fc269
getting rid of END
hannorein Aug 25, 2023
7768e36
removing maging numbers
hannorein Aug 25, 2023
a956f46
getting rid of BINARY_FIELD_ ...
hannorein Aug 25, 2023
1f85be0
reb_input_fields
hannorein Aug 26, 2023
820d964
cleanup
hannorein Aug 26, 2023
f66b54e
output
hannorein Aug 26, 2023
1bf52c9
python unit test
hannorein Aug 26, 2023
7fa5a80
diff
hannorein Aug 26, 2023
031bbe4
python diff
hannorein Aug 26, 2023
b609817
python show diff
hannorein Aug 26, 2023
7b804f5
Make simulations picklable
hannorein Aug 28, 2023
4bd74cb
pickle tests
hannorein Aug 28, 2023
b0081ee
changelog
hannorein Aug 28, 2023
ef566f8
const qualifiers
hannorein Aug 28, 2023
58f2bf1
padding
hannorein Aug 28, 2023
c34800b
added additional init field
hannorein Aug 28, 2023
f74bb45
moved list to output, doc
hannorein Aug 28, 2023
06257b2
doc
hannorein Aug 28, 2023
a13bab2
support pickling of particles
hannorein Aug 28, 2023
e227903
doc
hannorein Aug 28, 2023
fd48864
issue with null terminated arrays
hannorein Aug 28, 2023
8b0e005
fixed diff
hannorein Aug 28, 2023
9a12dec
binary fmmemopen
hannorein Aug 28, 2023
ab3bb80
temporarily added
hannorein Aug 29, 2023
d634854
Merge branch 'show_settings' of github.com:/hannorein/rebound into sh…
hannorein Aug 29, 2023
80a4dad
problem
hannorein Aug 29, 2023
42d4413
make
hannorein Aug 29, 2023
8e4bf9b
use field size instead of hard coded size
hannorein Aug 29, 2023
5d033b1
fixed memory issue
hannorein Aug 29, 2023
158c537
space
hannorein Aug 30, 2023
d5a1f6e
Merge branch 'show_settings' into newias
hannorein Aug 30, 2023
ded85a5
dt_mode
hannorein Aug 30, 2023
2c5e4eb
dt_mode=1 if particles have no acceleration
hannorein Aug 30, 2023
7257a6f
removing TES runtime comparison
hannorein Aug 30, 2023
e0f9d05
Consistent name allocated_N
hannorein Aug 30, 2023
65efb0a
change log
hannorein Aug 30, 2023
565b7c3
using fmemopen and removed reb_fread workaround
hannorein Aug 31, 2023
94795f8
Merge branch 'show_settings' into newias
hannorein Aug 31, 2023
ea31f3c
Merge branch 'main' into show_settings
hannorein Sep 1, 2023
0d5f25d
Merge branch 'show_settings' into newias
hannorein Sep 1, 2023
a43d810
mpi test
hannorein Sep 1, 2023
0cb91b9
MPI unit tests
hannorein Sep 1, 2023
49913ec
Merge branch 'show_settings' into newias
hannorein Sep 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ This changelog only includes the most important changes in recent updates. For a

## Version 3.x

### Version 3.27.0
* In python, Simulation and Particle objects are now picklable. Just like loading Simulations from a binary file, function pointers will need to be re-set manually after unpickling.
* The difference between simulations can now be printed out in a human readable form. Python syntax: `sim.diff(sim2)`. C syntax: `reb_diff_simulations(sim2, sim1, 1)`.
* Reading SimulationArchives with version < 2 is no longer supported.
* The POSIX function fmemopen() is now required to compile REBOUND. This should not affect many users. However, if you are using macOS, the version needs to be >= 10.13 (this version of macOS, High Sierra, was released in 2017).
* Internal changes on how SimulationArchives are written.
* Internal variable names that represent the size of allocated buffers now consistently include the name `allocated_N`.

### Version 3.26.3
* A few more changes to reduce the number of compiler warnings. This should not affect any calculation.

Expand Down
874 changes: 874 additions & 0 deletions derivatives.ipynb

Large diffs are not rendered by default.

39 changes: 33 additions & 6 deletions docs/binaryformat.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Binary Format

REBOUND comes with its one binary format.
The binary format allows you to store a current simulation state to a file.
The Simulation Archive is an extension of that format which allows you to store multiple snapshots in one file.
REBOUND comes with its own binary format.
The binary format allows you to store a current simulation state to a file or to memory.
The binary format is also used when you make a copy of a simulation or when you compare two similations with each other.
The Simulation Archive is an extension of the binary format which allows you to store multiple snapshots of a simulation in one file.
This page explains the details of the binary format.
It is mainly intended for people who wish to extend the built-in REBOUND functionality.
You do not need to know those details if you're only working with binary files to save and load simulations.

REBOUND uses two structures for the binary files:
Expand Down Expand Up @@ -43,7 +45,7 @@ You create a binary file if you save a simulation
// ... setup simulation ...
sim.save("snapshot.bin")
```
Such a binary file with one snapshot is simply a set of `reb_binaryfield`s followed by one `reb_simulationarchive_blob` at the end:
Such a binary file with one snapshot is simply a set of `reb_binaryfield`s followed by one `reb_simulationarchive_blob` at the end, for example:

```
reb_binary_field:
Expand Down Expand Up @@ -71,8 +73,11 @@ reb_simulationarchive_blob:
```

Each of the binary fields provides the context (type and size) for the data that immediately follows the field.
The type is an integer defined in the `rebound.h` file as `enum REB_BINARY_FIELD_TYPE`.
The last binary field is of type `END` to indicate that the snapshot ends here.
The type is an integer defined in the `reb_binary_field_descriptor_list` (see below).
The last binary field of type `9999` (`end`) to indicate that the snapshot ends here.

!!! note
Before version 3.27 data was encoded using the enum `REB_BINARY_FIELD_TYPE` instead of `reb_binary_field_descriptor_list`.


## SimulationArchive file (multiple snapshots)
Expand Down Expand Up @@ -143,3 +148,25 @@ reb_simulationarchive_blob:
The offsets are also used as a sort of checksum to detect if a binary file has been corrupted (for example because a user ran out of disk space).
If a binary file is corrupted, REBOUND attempts some magic and will recover the last snapshot which does not appear corrupted.
You will see a warning message when that happens and should proceed with caution (make a backup!).


## Binary Field Descriptor

REBOUND maintains a list of fields it needs to input/output in order to restore a simulation.
This list is of type `struct reb_binary_field_descriptor[]` and defined in `output.c` as `reb_binary_field_descriptor_list`.
A single struct `reb_binary_field_descriptor` contains the information to input/output one REBOUND field, for example the current simulation time `t`:

```c
struct reb_binary_field_descriptor fd_t = { 0, REB_DOUBLE, "t", offsetof(struct reb_simulation, t), 0, 0};
```
The first number is a unique identifier (in this case 0). The second entry is the type of data, in this case a single double precision floating point number. The third entry is a string used to identify the field. This is only used when generating human-readable output and is typically the same as the variable name in C. The next entry is the offset of where this variable is stored relative to the beginning of the simulation structure.

REBOUND also supports array like fields. For example consider the `particles` field:
```c
struct reb_binary_field_descriptor fd_particles = { 85, REB_POINTER, "particles", offsetof(struct reb_simulation, particles), offsetof(struct reb_simulation, N), sizeof(struct reb_particle)};
```

The second to last entry lists the offset of the a variable in the `reb_simulation` structure that determines the number of array elements. In this case the number of partiles. The last entry is the size of a single element. In this case, the size of one `reb_particle`.

If you add an additional field to the `reb_simulation` struct and you want to write it to a binary file and read it back in, then you need to add an entry to `reb_binary_field_descriptor_list`.

22 changes: 22 additions & 0 deletions examples/binary_field_type_reverse/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export OPENGL=0
include ../../src/Makefile.defs

all: librebound
@echo ""
@echo "Compiling problem file ..."
$(CC) -I../../src/ -Wl,-rpath,./ $(OPT) $(PREDEF) problem.c -L. -lrebound $(LIB) -o rebound
@echo ""
@echo "REBOUND compiled successfully."

librebound:
@echo "Compiling shared library librebound.so ..."
$(MAKE) -C ../../src/
@-rm -f librebound.so
@ln -s ../../src/librebound.so .

clean:
@echo "Cleaning up shared library librebound.so ..."
@-rm -f librebound.so
$(MAKE) -C ../../src/ clean
@echo "Cleaning up local directory ..."
@-rm -vf rebound
43 changes: 43 additions & 0 deletions examples/binary_field_type_reverse/problem.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* A very simple test problem
*
* We first create a REBOUND simulation, then we add
* two particles and integrate the system for 100 time
* units.
*/
#include "rebound.h"
#include "output.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
struct reb_simulation* r = reb_create_simulation();

reb_add_fmt(r, "m", 1.); // Central object
reb_add_fmt(r, "m a e", 1e-3, 1., 0.1); // Jupiter mass planet
reb_add_fmt(r, "a e", 1.4, 0.1); // Massless test particle

reb_steps(r,1);

char* buf = NULL;
size_t size = 0;
reb_output_binary_to_stream(r, &buf, &size);



struct reb_simulationarchive* sa = malloc(sizeof(struct reb_simulationarchive));
reb_read_simulationarchive_from_buffer_with_messages(sa, buf, size, NULL, NULL);


struct reb_simulation* r2 = reb_create_simulation();
enum reb_input_binary_messages w =0;
reb_create_simulation_from_simulationarchive_with_messages(r2,sa,-1,&w);

reb_close_simulationarchive(sa);
free(buf);
printf("sizeof(size_t)= %ld\n", sizeof(unsigned int));

reb_free_simulation(r);
reb_free_simulation(r2);
}

5 changes: 4 additions & 1 deletion examples/closeencounter/problem.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "rebound.h"

void heartbeat(struct reb_simulation* r);

double E0;
int main(int argc, char* argv[]){
struct reb_simulation* r = reb_create_simulation();
r->dt = 0.01*2.*M_PI; // initial timestep
Expand All @@ -40,11 +40,14 @@ int main(int argc, char* argv[]){
reb_add(r, planet);
}
reb_move_to_com(r); // This makes sure the planetary systems stays within the computational domain and doesn't drift.
E0 = reb_tools_energy(r);
reb_integrate(r, INFINITY);
}

void heartbeat(struct reb_simulation* r){
if (reb_output_check(r, 10.*2.*M_PI)){
reb_output_timing(r, 0);
}
double E1 = reb_tools_energy(r);
printf("%e\n", fabs((E1-E0)/E0));
}
41 changes: 41 additions & 0 deletions examples/mpi_unittests/problem.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,50 @@ void test_twobody(){
assert(fabs(o.a-1.)<1e-3);
assert(fabs(o.e-0.1)<1e-2);

printf("Checking input/output...\n");

com = reb_get_com(r); // Need to call this on all machines.
if (r->mpi_id==0){
for (int i=0; i<10; i++){
reb_add_fmt(r, "m a primary hash", 0.01, 2.0+0.1*i, com, i);
}
}
reb_steps(r, 1);
{
// Delete any previous files
char filename[1024];
sprintf(filename, "out.bin_%d", r->mpi_id);
remove(filename);
}
reb_simulationarchive_snapshot(r, "out.bin");
reb_steps(r, 1);
reb_simulationarchive_snapshot(r, "out.bin");
reb_steps(r, 10);

struct reb_simulationarchive* sa = reb_open_simulationarchive("out.bin");
assert(sa->nblobs==2);
struct reb_simulation* r2 = reb_create_simulation_from_simulationarchive(sa,-1);
reb_steps(r2, 10);

assert(r->N == r2->N);
assert(r->t == r2->t);

// Order of particles will be different. Need to compare them by hash
for(int i=0; i<10; i++){
struct reb_particle p1 = reb_get_remote_particle_by_hash(r, i);
struct reb_particle p2 = reb_get_remote_particle_by_hash(r2, i);
assert(p1.x==p2.x);
assert(p1.y==p2.y);
assert(p1.z==p2.z);
}




printf("Cleanup...\n");
reb_mpi_finalize(r);
reb_free_simulation(r);
reb_free_simulation(r2);


}
Expand Down
4 changes: 2 additions & 2 deletions examples/selfgravity_disc_mpi/problem.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ int main(int argc, char* argv[]){
#ifdef OPENGL
// Hack to artificially increase particle array.
// This cannot be done once OpenGL is activated.
r->allocatedN *=8;
r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocatedN);
r->allocated_N *=8;
r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocated_N);
#endif // OPENGL

// Start the integration
Expand Down
4 changes: 2 additions & 2 deletions examples/shearing_sheet_mpi/problem.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ int main(int argc, char* argv[]) {
#ifdef OPENGL
// Hack to artificially increase particle array.
// This cannot be done once OpenGL is activated.
r->allocatedN *=8;
r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocatedN);
r->allocated_N *=8;
r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocated_N);
#endif // OPENGL

// Start the integration
Expand Down
4 changes: 2 additions & 2 deletions rebound/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class ParticleNotFound(Exception):
pass

from .tools import hash, mod2pi, M_to_f, E_to_f, M_to_E, spherical_to_xyz, xyz_to_spherical
from .simulation import Simulation, Orbit, Variation, reb_simulation_integrator_saba, reb_simulation_integrator_whfast, reb_simulation_integrator_sei, reb_simulation_integrator_mercurius, reb_simulation_integrator_ias15, ODE, Rotation, Vec3d, _Vec3d
from .simulation import Simulation, Orbit, Variation, reb_simulation_integrator_saba, reb_simulation_integrator_whfast, reb_simulation_integrator_sei, reb_simulation_integrator_mercurius, reb_simulation_integrator_ias15, ODE, Rotation, Vec3d, _Vec3d, binary_field_descriptor_list
from .particle import Particle
from .plotting import OrbitPlot, OrbitPlotSet
from .simulationarchive import SimulationArchive
Expand All @@ -97,4 +97,4 @@ def __init__(self, processes=None, initializer=None, initargs=(), **kwargs):
else:
from .interruptible_pool import InterruptiblePool

__all__ = ["__libpath__", "__version__", "__build__", "__githash__", "SimulationArchive", "Simulation", "Orbit", "OrbitPlot", "OrbitPlotSet", "Particle", "SimulationError", "Encounter", "Collision", "Escape", "NoParticles", "ParticleNotFound", "InterruptiblePool","Variation", "reb_simulation_integrator_whfast", "reb_simulation_integrator_ias15", "reb_simulation_integrator_saba", "reb_simulation_integrator_sei","reb_simulation_integrator_mercurius", "clibrebound", "mod2pi", "M_to_f", "E_to_f", "M_to_E", "ODE", "Rotation", "Vec3d", "spherical_to_xyz", "xyz_to_spherical"]
__all__ = ["__libpath__", "__version__", "__build__", "__githash__", "SimulationArchive", "Simulation", "Orbit", "OrbitPlot", "OrbitPlotSet", "Particle", "SimulationError", "Encounter", "Collision", "Escape", "NoParticles", "ParticleNotFound", "InterruptiblePool","Variation", "reb_simulation_integrator_whfast", "reb_simulation_integrator_ias15", "reb_simulation_integrator_saba", "reb_simulation_integrator_sei","reb_simulation_integrator_mercurius", "clibrebound", "mod2pi", "M_to_f", "E_to_f", "M_to_E", "ODE", "Rotation", "Vec3d", "spherical_to_xyz", "xyz_to_spherical","binary_field_descriptor_list"]
33 changes: 32 additions & 1 deletion rebound/particle.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ctypes import Structure, c_double, c_int, byref, memmove, sizeof, c_uint32, c_uint, c_ulong
from ctypes import Structure, c_double, c_int, byref, memmove, sizeof, c_uint32, c_uint, c_ulong, c_char_p, string_at, POINTER, c_char
from . import clibrebound, E_to_f, M_to_f, mod2pi
import math
import ctypes.util
Expand Down Expand Up @@ -156,6 +156,25 @@ def __init__(self, simulation=None, particle=None, m=None, x=None, y=None, z=Non

"""

# Unpickling
binarydata = None
if isinstance(simulation, bytes):
# simulation is actually a bytes array with the particle data
binarydata = simulation
if isinstance(particle, bytes):
# simulation is actually a bytes array with the particle data
binarydata = particle
if binarydata is not None:
if len(binarydata) != sizeof(self):
raise ValueError("Binary particle data does not have the right size.")
buft = c_char * len(binarydata)
buf = buft.from_buffer_copy(binarydata)
memmove(byref(self), byref(buf), sizeof(self))
self.c = 0
self.sim = 0
self.ap = 0
return

if Omega == "uniform":
Omega = random.vonmisesvariate(0.,0.)
if omega == "uniform":
Expand Down Expand Up @@ -401,6 +420,10 @@ def copy(self):
memmove(byref(np), byref(self), sizeof(self))
return np

# Pickling method
def __reduce__(self):
return (Particle, (string_at(byref(self), size=sizeof(self)),))

def calculate_orbit(self, primary=None, G=None):
"""
Returns a rebound.Orbit object with the keplerian orbital elements
Expand Down Expand Up @@ -572,6 +595,14 @@ def sample_orbit(self, Npts=100, primary=None, samplingAngle=None, duplicateEndp

# Simple operators for particles.

def __eq__(self, other):
# This ignores the pointer values
if not isinstance(other,Particle):
return NotImplemented
clibrebound.reb_diff_particles.restype = c_int
ret = clibrebound.reb_diff_particles(self, other)
return not ret

def __pow__(self, other):
if not isinstance(other, Particle):
return NotImplemented
Expand Down
Loading