Skip to content

Commit

Permalink
Read simulationarchives version < 3.18 (#778)
Browse files Browse the repository at this point in the history
* Support Simulationarchive files with version < 3.18
* Fixed TRACE citation character error
* Relaxed timing test for CI
* Fixed typo
  • Loading branch information
hannorein authored Jun 25, 2024
1 parent 67b629d commit 198527f
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 10 deletions.
2 changes: 1 addition & 1 deletion rebound/citations.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def cite(sim):
"""

if sim.integrator == "trace":
txt += """The simulations were integrated using the hybrid time-reversible TRACE integrator \citep{reboundtrace}. """
txt += """The simulations were integrated using the hybrid time-reversible TRACE integrator \\citep{reboundtrace}. """
bib += """@ARTICLE{reboundtrace,
author = {{Lu}, Tiger and {Hernandez}, David M. and {Rein}, Hanno},
title = "{TRACE: a Time Reversible Algorithm for Close Encounters}",
Expand Down
2 changes: 1 addition & 1 deletion rebound/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
(True, 16, "Error while reading binary file (file was closed).",),
(True, 32, "Index out of range.",),
(True, 64, "Error while trying to seek file.",),
(False, 128, "Encountered unkown field in file. File might have been saved with a different version of REBOUND."),
(False, 128, "Encountered unknown field in file. File might have been saved with a different version of REBOUND."),
(True, 256, "Integrator type is not supported by this simulationarchive version."),
(False, 512, "The binary file seems to be corrupted. An attempt has been made to read the uncorrupted parts of it."),
(True, 1024, "Reading old Simulationarchives (version < 2) is no longer supported. If you need to read such an archive, use a REBOUND version <= 3.26.3"),
Expand Down
2 changes: 1 addition & 1 deletion rebound/tests/test_mercurius.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ def get_sim():
# and are therefore machine dependent.
self.assertLess(dE_mercurius,5e-6) # reasonable precision for mercurius
self.assertLess(dE_mercurius/dE_whfast,1e-4) # at least 1e4 times better than whfast
self.assertLess(time_mercurius,time_ias15) # faster than ias15
self.assertLess(time_mercurius,5.0*time_ias15) # not much slower than ias15 (often fails in unit tests)
if sys.maxsize > 2**32: # 64 bit
self.assertEqual(7060.644251181158, sim.particles[5].x) # Check if bitwise unchanged

Expand Down
68 changes: 61 additions & 7 deletions src/simulationarchive.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ void reb_simulation_create_from_simulationarchive_with_messages(struct reb_simul
// Read SA snapshot
if(fseek(inf, sa->offset[snapshot], SEEK_SET)){
*warnings |= REB_SIMULATION_BINARY_ERROR_SEEK;
reb_simulation_free(r);
//reb_simulation_free(r);
return;
}
if (r->simulationarchive_version<3){
if (r->simulationarchive_version<2){
*warnings |= REB_SIMULATION_BINARY_ERROR_OLD;
reb_simulation_free(r);
//reb_simulation_free(r);
return;
}else{
// Version 2 or higher
Expand All @@ -98,6 +98,13 @@ struct reb_simulation* reb_simulation_create_from_simulationarchive(struct reb_s
return r; // might be null if error occured
}

// Old 16 bit offsets. Used only to read old files.
struct reb_simulationarchive_blob16 {
int32_t index;
int16_t offset_prev;
int16_t offset_next;
};

void reb_read_simulationarchive_from_stream_with_messages(struct reb_simulationarchive* sa, struct reb_simulationarchive* sa_index, enum reb_simulation_binary_error_codes* warnings){
// Assumes sa->inf is set to an open stream
const int debug = 0;
Expand All @@ -111,7 +118,9 @@ void reb_read_simulationarchive_from_stream_with_messages(struct reb_simulationa
struct reb_binary_field field = {0};
sa->version = 0;
double t0 = 0;

int version_major = 0; // will be overwritten unless there is an error
int version_minor = 0;
int uses32bitoffsets = 1;
// Cache descriptors
struct reb_binary_field_descriptor fd_header = reb_binary_field_descriptor_for_name("header");
struct reb_binary_field_descriptor fd_t = reb_binary_field_descriptor_for_name("t");
Expand All @@ -137,6 +146,35 @@ void reb_read_simulationarchive_from_stream_with_messages(struct reb_simulationa
sprintf(curvbuf,"%s%s",header+sizeof(struct reb_binary_field), reb_version_str);

objects += fread(readbuf,sizeof(char),bufsize,sa->inf);
// Finding version_major/version_minor version
int c1=0, c2=0, c3=0;
for (int c=0; c<bufsize; c++){
if (c2 != 0 && c3 == 0 && readbuf[c] == '.'){
c3 = c;
}
if (c1 != 0 && c2 == 0 && readbuf[c] == '.'){
c2 = c;
}
if (c1 == 0 && readbuf[c] == ':'){
c1 = c;
}
}
if (c1==0 || c2==0 || c3==0){
if (debug) printf("SA Error. Cannot determine version.\n");
*warnings |= REB_SIMULATION_BINARY_WARNING_CORRUPTFILE;
}else{
char cminor[64];
char cmajor[64];
strncpy(cminor, readbuf+c2+1, c3-c2-1);
cminor[c3-c2-1] = '\0';
strncpy(cmajor, readbuf+c1+1, c2-c1-1);
cmajor[c2-c1-1] = '\0';
version_minor = atoi(cminor);
version_major = atoi(cmajor);
if (version_major <= 3 && version_minor < 18){
uses32bitoffsets = 0; // fallback to 16 bit
}
}
if (objects < 1){
*warnings |= REB_SIMULATION_BINARY_WARNING_CORRUPTFILE;
}else{
Expand Down Expand Up @@ -224,7 +262,17 @@ void reb_read_simulationarchive_from_stream_with_messages(struct reb_simulationa
}
// Everything looks normal so far. Attempt to read next blob
struct reb_simulationarchive_blob blob = {0};
size_t r3 = fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, sa->inf);
size_t r3;
if (uses32bitoffsets){
r3 = fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, sa->inf);
}else{
// Workaround for versions < 3.18
struct reb_simulationarchive_blob16 blob16 = {0};
r3 = fread(&blob16, sizeof(struct reb_simulationarchive_blob16), 1, sa->inf);
blob.index = blob16.index;
blob.offset_prev = blob16.offset_prev;
blob.offset_next = blob16.offset_next;
}
int next_blob_is_corrupted = 0;
if (r3!=1){ // Next snapshot is definitly corrupted.
// Assume we have reached the end of the file.
Expand All @@ -234,10 +282,16 @@ void reb_read_simulationarchive_from_stream_with_messages(struct reb_simulationa
*warnings |= REB_SIMULATION_BINARY_WARNING_CORRUPTFILE;
}
if (i>0){
size_t blobsize;
if (uses32bitoffsets){
blobsize = sizeof(struct reb_simulationarchive_blob);
}else{
blobsize = sizeof(struct reb_simulationarchive_blob16);
}
// Checking the offsets. Acts like a checksum.
if (((int64_t)blob.offset_prev )+ ((int64_t)sizeof(struct reb_simulationarchive_blob)) != ftell(sa->inf) - ((int64_t)sa->offset[i]) ){
if (((int64_t)blob.offset_prev )+ ((int64_t)blobsize) != ftell(sa->inf) - ((int64_t)sa->offset[i]) ){
// Offsets don't work. Next snapshot is definitly corrupted. Assume current one as well.
if (debug) printf("SA Error. Offset mismatch: %lu != %" PRIu64 ".\n",blob.offset_prev + sizeof(struct reb_simulationarchive_blob), (uint64_t)(ftell(sa->inf) - sa->offset[i]) );
if (debug) printf("SA Error. Offset mismatch: %lu != %" PRIu64 ".\n",blob.offset_prev + blobsize, (uint64_t)(ftell(sa->inf) - sa->offset[i]) );
read_error = 1;
break;
}
Expand Down

0 comments on commit 198527f

Please sign in to comment.