rebound-bind 5.0.0

Low-level Rust FFI bindings for the REBOUND N-body simulation C library.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
/**
 * @file    rebound.h
 * @brief   REBOUND API definition.
 * @author  Hanno Rein <hanno@hanno-rein.de>
 * 
 * @section     LICENSE
 * Copyright (c) 2015 Hanno Rein, Shangfei Liu
 *
 * This file is part of rebound.
 *
 * rebound is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * rebound is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rebound.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef _MAIN_H
#define _MAIN_H

#define REB_API     // Public REBOUND API definitions

// Helper macros for padding structures
#if defined(_WIN64) || defined(_LP64)
#define REB_PAD(s) // 64 bit pointers require no padding
#else // 32 bit pointers
#define REB_PAD_CONCAT(a, b) a ## b
#define REB_PAD_EVAL(a, b) REB_PAD_CONCAT(a, b)
#define REB_PAD(s) char REB_PAD_EVAL(_pad_, __LINE__)[s];
#endif

// The restrict keyword has different spellings in different compilers
#if defined(_MSC_VER)
#define REB_RESTRICT __restrict
#pragma comment(lib, "legacy_stdio_definitions.lib") // for printf, etc
#elif defined(__GNUC__) || defined(__clang__)
#define REB_RESTRICT __restrict__
#else
#define REB_RESTRICT restrict
#endif

// Windows requires special treatment.
#ifdef _WIN32
#undef REB_API
#define _USE_MATH_DEFINES // Windows (MVSC) does not include math constants by default.
#ifdef BUILDINGLIBREBOUND // Windows needs different declarations depending on whether the library is built or used.
#define REB_API __declspec(dllexport)
#else
#define REB_API __declspec(dllimport)
#endif
#endif // _WIN32

#include <stdlib.h> // for size_t
#include <stdint.h> // for integer types
#include <stddef.h> // for offsetof

// Maximum length string for most strings used by REBOUND,
// including names of binary fields.
#define REB_STRING_SIZE_MAX 256

// Macros to generate enums whose name can also be read by python
#define REB_AS_ENUM_MEMBER(prefix, value, name)  prefix ## _ ## name = value,
#define REB_GENERATE_ENUM(LIST) LIST(REB_AS_ENUM_MEMBER,LIST)

// Forward declarations
struct reb_simulationarchive;   // Opaque pointer. Implemented in simulationarchive.h
struct reb_server_data;         // Opaque pointer. Implemented in server.h
struct reb_treecell;            // Opaque pointer. Implemented in tree.h
struct reb_display_data;        // Opaque pointer. Implemented in display.h
struct reb_particle_int;        // Opaque pointer. Implemented in integrator_janus.h
struct reb_name_hash_item;      // Opaque pointer. Implemented in particle.h
struct reb_simulation;          // Implemented below.
struct reb_display_settings;    // Implemented below.
struct reb_variational_configuration;  // Implemented below.
struct reb_ode; // Implemented below.

// Particle structure
struct reb_particle {
    double x;                   // Cartesian coordinates
    double y;
    double z;
    double vx;
    double vy;
    double vz;
    double ax;
    double ay;
    double az;
    double m;                   // Mass in code units
    double r;                   // Physical radius in code units
    const char* name;           // Pointer to a NULL terminated string with the particle's name. Memory owned by simulation.
    REB_PAD(4)
    void* ap;                   // This pointer allows REBOUNDx to add additional properties to the particle.
    REB_PAD(4)
    struct reb_simulation* sim; // Pointer to the parent simulation.
    REB_PAD(4)
};

// Possible datatypes for reb_binarydata_field.
enum REB_BINARYDATA_DTYPE {
    REB_FIELD_NOT_FOUND = 0,     // Special type used to throw error messages
    REB_DOUBLE = 1,
    REB_INT = 2,
    REB_UINT = 3,                // Same as UINT32
    REB_UINT32 = 4,
    REB_INT64 = 5,
    REB_UINT64 = 6,
    REB_SIZE_T = 7,
    REB_VEC3D = 8,
    REB_PARTICLE = 9,
    REB_POINTER = 10,
    REB_POINTER_ALIGNED = 11,    // memory aligned to 64 bit boundary for AVX512
    REB_OTHER = 12,              // Fields that need special treatment during input and/or output
    REB_CHARP_LIST = 13,         // A list of NULL terminated strings (char**).
    REB_FUNCTIONPOINTER = 14,    // A function pointer. Will not be saved to Simulationarchive.
    REB_STRING = 20,             // NULL character terminated string
};

// Generic 3d vector
struct reb_vec3d {
    double x;
    double y;
    double z;
};

// Generic 6d vector
struct reb_vec6d{
    double x;
    double y;
    double z;
    double vx;
    double vy;
    double vz;
};

// Structure representing one particle-particle collision
struct reb_collision{
    size_t p1;              // Index of first particle involved in collision
    size_t p2;              // Index of second particle
    struct reb_vec6d gb;    // Offset due to boundary conditions
    size_t ri;              // Root cell index (MPI only)
};

// Dictionary element to provide human readable name for enums. Used by python.
struct reb_binarydata_enum_descriptor{
    int value;
    char name[REB_STRING_SIZE_MAX];
};

// Binary field descriptors are used to identify data blobs in simulationarchives.
struct reb_binarydata_field_descriptor {
    char* documentation;             // Documentation of this field. Optional, can be NULL or "" for internal fields.
    enum REB_BINARYDATA_DTYPE dtype; // Datatype (note: not the same as type)
    char name[REB_STRING_SIZE_MAX];  // Null terminated, unique, human readable name.
    size_t offset;                   // Offset of the storage location relative to the beginning of reb_simulation
    size_t offset_N;                 // Offset of the storage location for the size relative to the beginning of reb_simulation
    size_t element_size;             // Size in bytes of each element (only used for pointers, dp7, etc).
    struct reb_binarydata_enum_descriptor* enum_descriptor; // Null terminated list that allows enums to be set/read by string in python.
};

// Generic integrator callbacks.
// This can be used to implement a user provided integrator.
struct reb_integrator {
    char* documentation;    // Documentation of the integrator. Optional, can be NULL or "".
    void (*step)(struct reb_simulation* r, void* p);        // Performs one timestep. Timestep should be r->dt for a non-adaptive integrator. Need to update r->t in this routine.
    void (*synchronize)(struct reb_simulation* r, void* p); // Synchronizes particle state. Optional. Set to NULL if not used.
    void* (*create)();                                      // Allocate memory for integrator and set default values. Return pointer to the new integrator state.
    void (*free)(void* p);                                  // Free all memory owned by integrator. p points to the integrator's state.
    void (*did_add_particle)(struct reb_simulation* r);                     // Gets called after a particle was added.
    void (*will_remove_particle)(struct reb_simulation* r, size_t index);   // Gets called before a particle will be removed.
    const struct reb_binarydata_field_descriptor* field_descriptor_list;    // Information on how to safe/load the integrator state from restart files for this integrator.
};


// A current integrator configuration. Internal use only.
struct reb_integrator_configuration {
    const char* name;
    struct reb_integrator callbacks;
    void* state;
};

// Available built-in integrators
// See individual files for configuration options.
#include "integrator_ias15.h"        /* IAS15 integrator, 15th order, non-symplectic (default)                             */
#include "integrator_whfast.h"       /* WHFast integrator, symplectic, 2nd order, up to 11th order correctors              */
#include "integrator_sei.h"          /* SEI integrator for shearing sheet simulations, symplectic, needs OMEGA variable    */
#include "integrator_leapfrog.h"     /* LEAPFROG integrator, simple, 2nd order, symplectic                                 */
#include "integrator_janus.h"        /* Bit-wise reversible JANUS integrator.                                              */
#include "integrator_mercurius.h"    /* MERCURIUS integrator                                                               */
#include "integrator_saba.h"         /* SABA integrator family (Laskar and Robutel 2001)                                   */
#include "integrator_eos.h"          /* Embedded Operator Splitting (EOS) integrator family (Rein 2019)                    */
#include "integrator_bs.h"           /* Gragg-Bulirsch-Stoer                                                               */
#include "integrator_whfast512.h"    /* WHFast integrator, optimized for AVX512                                            */
#include "integrator_trace.h"        /* TRACE integrator (Lu, Hernandez and Rein 2024)                                     */
extern const struct reb_integrator reb_integrator_none; /* Does nothing other than advance time. Defined in rebound.c      */

// List of built-in integrators for X macros
#define REB_BUILTIN_INTEGRATORS X(ias15) X(whfast) X(sei) X(leapfrog) X(janus) X(mercurius) X(saba) X(eos) X(bs) X(whfast512) X(trace) X(none) 


// Available return values for collision resolve functions
enum REB_COLLISION_RESOLVE_OUTCOME {
    REB_COLLISION_RESOLVE_OUTCOME_REMOVE_NONE = 0,
    REB_COLLISION_RESOLVE_OUTCOME_REMOVE_P1 = 1,
    REB_COLLISION_RESOLVE_OUTCOME_REMOVE_P2 = 2,
    REB_COLLISION_RESOLVE_OUTCOME_REMOVE_BOTH = 3,
};

// Possible return values of rebound_integrate
enum REB_STATUS {
    // Any status less than SINGLE_STEP get incremented once every timestep until SINGLE_STEP is reached.
    REB_STATUS_SINGLE_STEP = -10, // Performing a single step, then switching to PAUSED.
    REB_STATUS_SCREENSHOT_READY=-5,// Screenshot is ready, send back, then finish integration
    REB_STATUS_SCREENSHOT = -4,   // Pause until visualization has taken a screenshot.
    REB_STATUS_PAUSED = -3,       // Simulation is paused by visualization.
    REB_STATUS_LAST_STEP = -2,    // Current timestep is the last one. Needed to ensure that t=tmax exactly.
    REB_STATUS_RUNNING = -1,      // Simulation is current running, no error occurred.
    REB_STATUS_SUCCESS = 0,       // Integration finished successfully.
    REB_STATUS_GENERIC_ERROR = 1, // A generic error occurred and the integration was not successful.
    REB_STATUS_NO_PARTICLES = 2,  // The integration ends early because no particles are left in the simulation.
    REB_STATUS_ENCOUNTER = 3,     // The integration ends early because two particles had a close encounter (see exit_min_distance)
    REB_STATUS_ESCAPE = 4,        // The integration ends early because a particle escaped (see exit_max_distance)  
    REB_STATUS_USER = 5,          // User caused exit, simulation did not finish successfully.
    REB_STATUS_SIGINT = 6,        // SIGINT received. Simulation stopped.
    REB_STATUS_COLLISION = 7,     // The integration ends early because two particles collided. 
};


// Main REBOUND Simulation structure
// Note: only variables that should be accessed by users are documented here.
struct reb_simulation {
    double  t;                      // Current simulation time. Default: 0.
    double  G;                      // Gravitational constant. Default: 1.
    double  softening;              // Gravitational softening. Default: 0.
    double  OMEGA;                  // Epicyclic frequency
    double  OMEGAZ;                 // Epicyclic frequency in z direction (if not set, use OMEGA)
    double  dt;                     // Timestep. Default: 0.001.
    double  dt_last_done;           // Last successful timestep.
    uint64_t steps_done;            // Number of timesteps done.
    unsigned int is_synchronized;   // Positions and velocities of particles are in inertial frame if 1. Otherwise call reb_simulation_synchronize().
    unsigned int did_modify_particles; // Should be set to 1 if a particle got modified manually in-between timesteps.

    // Main particles array
    size_t  N;                      // Number of particles (includes variational particles). Default: 0.
    size_t  N_allocated;            // Current maximum space allocated in the particles array on this node. 
    struct reb_particle* particles; // Main particle array with active, variational, and test particles.

    // Collision routines and some integrators can operate on only some particles.
    // This array r->map defines which ones. Set to NULL to operate on all particles.
    size_t N_map;                   // If map is not NULL, use map to operate on only N_map particles
    size_t* map;                    // Note: memory not owned and thus not freed by simulation.

    // Variational particles array
    size_t  N_var;                  // Number of variational particles. Default 0.
    struct reb_particle* particles_var;

    size_t  N_var_config; 
    struct  reb_variational_configuration* var_config;   // Configuration structs. These contain details on variational particles. 

    size_t  N_active;               // Number of active (i.e. not test-particle) particles. Default: SIZE_MAX (all particles are active). 
    int     testparticle_type;      // 0 (default): active particles do not feel test-particles, 1: active particles feel test-particles
    int     testparticle_hidewarnings;
    char**  name_list;              // List of names used to identify particles. Managed by REBOUND. Do not directly edit/access.
    size_t  N_name_list;            // Number of entries in reb_name_list.
    struct reb_name_hash_item*    name_hash_table;        // Internal use only. Speeds up name search.
    struct reb_vec3d* gravity_cs; 
    size_t N_allocated_gravity_cs;
    struct reb_treecell** tree_root;// Pointer to the temporary tree structure.
    double opening_angle2;          // Opening angle for tree-based gravity calculation. Default 0.25.
    enum REB_STATUS status;         // Current simulation status
    int     exact_finish_time;      // 1 (default): integrate exactly to the time requested and adjust timestep if needed, 0: may overshoot by one timestep

    int force_is_velocity_dependent; // 0 (default): force only depends on position, 1: force also depends on velocities
    enum {
        REB_GRAVITY_IGNORE_TERMS_NONE = 0,              // Include all pairwise interactions in gravity calculations.
        REB_GRAVITY_IGNORE_TERMS_BETWEEN_0_AND_1 = 1,   // Ignore interactions between particles 0 and 1 in gravity calculations (used for WHFast)
        REB_GRAVITY_IGNORE_TERMS_INVOLVING_0 = 2,       // Ignore all interactions with particle 0 in gravity calculations (used for WHFast)
    } gravity_ignore_terms;         // This flag determines which interactions are included in the gravity calculation.
    double output_timing_last;      // Time when reb_simulation_output_timing() was called the last time. 

    int save_messages;              // 0 (default): print messages on screen, 1: ignore messages (used in python interface).
    char** messages;                // Array of strings containing last messages (only used if save_messages==1). 

    // Flags to avoid repeated warning messages
    int messages_var_rescale_warning;    
    int messages_timestep_warning;    

    double exit_max_distance;       // Exit simulation if a particle is this far away from the origin.
    double exit_min_distance;       // Exit simulation if two particles come this close to each other.
    double usleep;                  // Artificially slow down simulations by this many microseconds each timestep.
    struct reb_display_settings* display_settings;// Optional. Will overwrite settings for visualization. If NULL, UI will determine settings.
    struct reb_display_data* display_data; // Datastructure stores visualization related data. Does not have to be modified by the user. 
    struct reb_server_data* server_data; // Datastructure stores server related data. Does not have to be modified by the user. 
    int track_energy_offset;        // 0 (default): do not track energy offset due to merging/lost particles, 1: track offset
    double energy_offset;           // Only used if track_energy_offset = 1
    double walltime;                // Cumulative walltime of entire integration.
    double walltime_last_step;      // Wall time of last step.
    double walltime_last_steps;     // Average wall time of last step (updated every 0.1s).
    double walltime_last_steps_sum;
    int walltime_last_steps_N;
    uint32_t python_unit_l;         // Only used when working with units in python.
    uint32_t python_unit_m;         // Only used when working with units in python.
    uint32_t python_unit_t;         // Only used when working with units in python.

    // Simulation domain and ghost boxes 
    double  root_size;              // Size of a root box. 
    size_t  N_root_x;               // Number of ghost boxes in x direction. Do not change manually.
    size_t  N_root_y;
    size_t  N_root_z;
    int  N_ghost_x;              // Number of ghost boxes in x direction.
    int  N_ghost_y;
    int  N_ghost_z;

    // MPI Parallelization
#ifdef MPI
    int    mpi_id;                              // Unique id of this node (starting at 0). Used for MPI only.
    int    mpi_num;                             // Number of MPI nodes. Used for MPI only.
    struct reb_particle** particles_send;       // Send buffer for particles. There is one buffer per node.
    int*   N_particles_send;                    // Current length of particle send buffer.
    int*   N_particles_send_max;                // Maximal length of particle send buffer before realloc() is needed.
    struct reb_particle** particles_recv;       // Receive buffer for particles. There is one buffer per node.
    int*   N_particles_recv;                    // Current length of particle receive buffer.
    int*   N_particles_recv_max;                // Maximal length of particle receive buffer before realloc() is needed. */

    struct reb_treecell** tree_essential_send;  // Send buffer for cells. There is one buffer per node.
    int*   N_tree_essential_send;               // Current length of cell send buffer.
    int*   N_tree_essential_send_max;           // Maximal length of cell send buffer before realloc() is needed.
    struct reb_treecell** tree_essential_recv;  // Receive buffer for cells. There is one buffer per node.
    int*   N_tree_essential_recv;               // Current length of cell receive buffer.
    int*   N_tree_essential_recv_max;           // Maximal length of cell receive buffer before realloc() is needed.
#endif // MPI

    // Collision related variables
    struct reb_collision* collisions;       // Array of current collisions. Do not change manually
    size_t N_allocated_collisions;
    size_t N_collisions;                    // Number of collisions found during last collision search.
    size_t N_targets;                       // Number of particles which can be a target in collisions. Default is SIZE_MAX, corresponding to r->N targets. There are always r->N projectiles.
    double minimum_collision_velocity;      // Ensure relative velocity during collisions is at least this much (to avoid particles sinking into each other)
    double collisions_plog;                 // Keeping track of momentum transfer in collisions (for ring simulations)
    int64_t collisions_log_n;               // Cumulative number of collisions in entire simulation.

    // MEGNO Chaos indicator. These variables should not be accessed directly. Use functions provided instead.
    int calculate_megno;    // Do not change manually. Internal flag that determines if megno is calculated (default=0, but megno_init() sets it to the index of variational particles used for megno)
    double megno_Ys;        // Running megno sum (internal use)
    double megno_Yss;       // Running megno sum (internal use)
    double megno_cov_Yt;    // covariance of MEGNO Y and t
    double megno_var_t;     // variance of t 
    double megno_mean_t;    // mean of t
    double megno_mean_Y;    // mean of MEGNO Y
    double megno_initial_t; // Time when MENGO was initialized
    int64_t megno_n;        // number of covariance updates

    unsigned int rand_seed; // seed for random number generator, used by MEGNO and other random number generators in REBOUND.

    // Simulationarchive. These variables should not be accessed directly. Use functions provided instead. 
    int    simulationarchive_version;               // Version of the SA binary format (1,2=legacy format, 3=modern format)
    double simulationarchive_auto_interval;         // Current sampling cadence, in code units
    double simulationarchive_auto_walltime;         // Current sampling cadence, in wall time
    uint64_t simulationarchive_auto_step;           // Current sampling cadence, in time steps
    double simulationarchive_next;                  // Next output time (simulation time or wall time, depending on whether auto_interval or auto_walltime is set)
    uint64_t simulationarchive_next_step;           // Next output step (only used if auto_steps is set)
    char*  simulationarchive_filename;              // Name of output file

    // Available modules in REBOUND
    enum {
        REB_COLLISION_NONE = 0,         // Do not search for collisions (default)
        REB_COLLISION_DIRECT = 1,       // Direct collision search O(N^2)
        REB_COLLISION_TREE = 2,         // Tree based collision search O(N log(N))
        REB_COLLISION_LINE = 4,         // Direct collision search O(N^2), looks for collisions by assuming a linear path over the last timestep
        REB_COLLISION_LINETREE = 5,     // Tree-based collision search O(N log(N)), looks for collisions by assuming a linear path over the last timestep
    } collision;
    struct reb_integrator_configuration integrator;
    enum {
        REB_BOUNDARY_NONE = 0,          // Do not check for anything (default)
        REB_BOUNDARY_OPEN = 1,          // Open boundary conditions. Removes particles if they leave the box 
        REB_BOUNDARY_PERIODIC = 2,      // Periodic boundary conditions
        REB_BOUNDARY_SHEAR = 3,         // Shear periodic boundary conditions, needs OMEGA variable
    } boundary;
    enum {
        REB_GRAVITY_NONE = 0,           // Do not calculate graviational forces
        REB_GRAVITY_BASIC = 1,          // Basic O(N^2) direct summation algorithm, choose this for shearing sheet and periodic boundary conditions
        REB_GRAVITY_COMPENSATED = 2,    // Direct summation algorithm O(N^2) but with compensated summation, slightly slower than BASIC but more accurate
        REB_GRAVITY_TREE = 3,           // Use the tree to calculate gravity, O(N log(N)), set opening_angle2 to adjust accuracy.
        REB_GRAVITY_JACOBI = 5,         // Special gravity routine which includes the Jacobi terms for WH integrators 
        REB_GRAVITY_CUSTOM = 7,         // Custom, user or integrator provided gravity routine
    } gravity;

    void (*gravity_custom) (struct reb_simulation* const r);  // Used with REB_GRAVITY_CUSTOM

    // ODEs. Do not access these variables directly. Use functions provided instead.
    struct reb_ode** odes;      // all ode sets (includes nbody if BS is set as integrator)
    size_t N_odes;                 // number of ode sets
    size_t N_allocated_odes;

    // Callback functions
    void (*additional_forces) (struct reb_simulation* const r);             // Implement any additional (non-gravitational) forces here.
    void (*pre_timestep_modifications) (struct reb_simulation* const r);    // Executed just before eaach timestep. Used by REBOUNDx.
    void (*post_timestep_modifications) (struct reb_simulation* const r);   // Executed just after each timestep. Used by REBOUNDx.
    void (*heartbeat) (struct reb_simulation* r);                           // Executed at each timestep once. Use this to do extra output/work during a simulation.
    int (*key_callback) (struct reb_simulation* r, int key);                // Used when SERVER or OPENGL visualization is on. Gets called after completed timestep and if a key has been pressed. Return 1 if you want to skip default key commands.
    double (*coefficient_of_restitution) (const struct reb_simulation* const r, double v);  // Allows for a velocity dependent coefficient of restitution (used for ring simulations)
    enum REB_COLLISION_RESOLVE_OUTCOME (*collision_resolve) (struct reb_simulation* const r, struct reb_collision);        // Determines what happens when two particles collide.
    void (*free_particle_ap) (struct reb_particle* p);                      // Used by REBOUNDx.
    void (*extras_cleanup) (struct reb_simulation* r);                      // Used by REBOUNDx.
    void* extras;                                                           // Pointer to link to any additional (optional) libraries, e.g., REBOUNDx, ASSIST.
};


//////////////////////////////////////////////////////////////////////////////////////////////////////////
// REBOUND API Functions
//////////////////////////////////////////////////////////////////////////////////////////////////////////

// Simulation life cycle

// Allocates memory for reb_simulation and initializes it.
REB_API struct reb_simulation* reb_simulation_create(void);
// Create a simulation object from a file. Set snapshot=-1 to load last snapshot.
REB_API struct reb_simulation* reb_simulation_create_from_file(char* filename, int64_t snapshot);
// Create a simulation object from a simulationarchive. Set snapshot=-1 to load last snapshot.
REB_API struct reb_simulation* reb_simulation_create_from_simulationarchive(struct reb_simulationarchive* sa, int64_t snapshot);
// Free simulation and all associated memory.
REB_API void reb_simulation_free(struct reb_simulation* const r);
// Make a deep copy of simulation.
REB_API struct reb_simulation* reb_simulation_copy(struct reb_simulation* r);
// Compare r1 to r2. If exactly equal then 0 is returned, otherwise 1. No output if output_options=0. If output_option=1, then difference is also printed on screen.
REB_API int reb_simulation_diff(struct reb_simulation* r1, struct reb_simulation* r2, int output_option);

// Start webserver for visualization. Returns 0 on success.
REB_API int reb_simulation_start_server(struct reb_simulation* r, int port);
// Stop webserver.
REB_API void reb_simulation_stop_server(struct reb_simulation* r);


// Integrator selelection

// This function sets the integrator of the simulation to the one with the matching name. 
REB_API void* reb_simulation_set_integrator(struct reb_simulation* r, const char* name);
// This function registers a user provided integrator with a unique name. A user provided integrator must be called before the integrator is set.
REB_API void reb_integrator_register(const struct reb_integrator integrator, const char* name);


// Errors, warnings

// For fatal errors only. Print out an error message, then exit immediately and kill the process. Does no clean up memory.
REB_API void reb_exit(const char* const msg);
// Stop current integration in a nice way. Can be called from within heartbeat function.
REB_API void reb_simulation_stop(struct reb_simulation* const r);
// Print or store an info message, then continue.
REB_API void reb_simulation_info(struct reb_simulation* const r, const char* const msg);
// Print or store a warning message, then continue.
REB_API void reb_simulation_warning(struct reb_simulation* const r, const char* const msg);
// Print or store an error message, then continue.
REB_API void reb_simulation_error(struct reb_simulation* const r, const char* const msg);


// Output functions

// Write the simulation to file (simulationarchive format). Appends a snapshot if file exists.
REB_API void reb_simulation_save_to_file(struct reb_simulation* r, const char* filename);
// Schedule regular outputs to a file based on simulation time.
REB_API void reb_simulation_save_to_file_interval(struct reb_simulation* const r, const char* filename, double interval);
// Schedule regular outputs to a file based on wall time.
REB_API void reb_simulation_save_to_file_walltime(struct reb_simulation* const r, const char* filename, double walltime);
// Schedule regular outputs to a file based on number of steps taken.
REB_API void reb_simulation_save_to_file_step(struct reb_simulation* const r, const char* filename, uint64_t step);
// Output timing data to file. Appends file if it exists.
REB_API void reb_simulation_output_timing(struct reb_simulation* r, const double tmax);
// Output orbits to file. Appends file if it exists.
REB_API void reb_simulation_output_orbits(struct reb_simulation* r, char* filename);
// Output cartesian coordinates to file. Appends file if it exists.
REB_API void reb_simulation_output_ascii(struct reb_simulation* r, char* filename);
// Output velocity dispersion tensor to file. Used for ring simulations. Appends file if it exists.
REB_API void reb_simulation_output_velocity_dispersion(struct reb_simulation* r, char* filename);
// Function to allow for periodic outputs in heartbeat function. See examples on how to use it.
REB_API int reb_simulation_output_check(struct reb_simulation* r, double interval);
// Write a screenshot of the current simulation to a file. Requires that a server was started with reb_simulation_start_server() and one client web browser is connected. Returns 0 if successful.
REB_API int reb_simulation_output_screenshot(struct reb_simulation* r, const char* filename);


// Timestepping

// Advance simulation by N_steps timesteps.
REB_API void reb_simulation_steps(struct reb_simulation* const r, size_t N_steps);
// Integrate simulation to at least time tmax (see exact_finish_time).
REB_API enum REB_STATUS reb_simulation_integrate(struct reb_simulation* const r, double tmax);
// Synchronize simulation if safe_mode is turned off by integrator to get physical coordinates.
REB_API void reb_simulation_synchronize(struct reb_simulation* r);


// Functions to operate on simulations

// Move the simulation to the heliocentric frame (particle with index 0 will be at the origin and at rest after calling this function).
REB_API void reb_simulation_move_to_hel(struct reb_simulation* const r);
// Move the simultion to the center of mass frame (the center of mass will be at the origin and at rest after calling this function).
REB_API void reb_simulation_move_to_com(struct reb_simulation* const r);
// Multiply x,y,z,vx,vy,vz of each particle in r with given scalars.
REB_API void reb_simulation_imul(struct reb_simulation* r, double scalar_pos, double scalar_vel);
// Add cartesian components of each particle of r2 to cartesian components in r. r2 and r must have same number of particles.
REB_API int reb_simulation_iadd(struct reb_simulation* r, struct reb_simulation* r2);
// Same as above but subtract r2 from r component wise.
REB_API int reb_simulation_isub(struct reb_simulation* r, struct reb_simulation* r2);
// Updates the acceleration of all particles but does not perform a step. Used by REBOUNDx.
REB_API void reb_simulation_update_acceleration(struct reb_simulation* r);


// Diangnostic functions

// Return the sum of potential and kinetic energy
REB_API double reb_simulation_energy(struct reb_simulation* const r);
// Returns the angular momentum.
REB_API struct reb_vec3d reb_simulation_angular_momentum(const struct reb_simulation* const r);
// Returns the center of mass of a simulation.
REB_API struct reb_particle reb_simulation_com(struct reb_simulation* r);
// Returns the center of mass of two particles.
REB_API struct reb_particle reb_particle_com_of_pair(struct reb_particle p1, struct reb_particle p2);
// Returns the center of mass of particles in the simulation within a given range.
REB_API struct reb_particle reb_simulation_com_range(struct reb_simulation* r, size_t first, size_t last);


// Functions to add and initialize particles

// Use this function to add particle pt to simulation r.
REB_API void reb_simulation_add(struct reb_simulation* const r, struct reb_particle pt);
// Use this function to add a particle to a simulation using orbital parameters or cartesian coordinates. See examples on usage.
REB_API void reb_simulation_add_fmt(struct reb_simulation* r, const char* fmt, ...);
// This function sets up a Plummer sphere, N=number of particles, M=total mass, R=characteristic radius. Particles get added to simulation.
REB_API void reb_simulation_add_plummer(struct reb_simulation* r, size_t _N, double M, double R); 
// Returns a particle given a set of orbital parameters. Also sets err to error code if initialization failed.
REB_API struct reb_particle reb_particle_from_orbit_err(double G, struct reb_particle primary, double m, double a, double e, double i, double Omega, double omega, double f, int* err);
// Same as above but without error code.
REB_API struct reb_particle reb_particle_from_orbit(double G, struct reb_particle primary, double m, double a, double e, double i, double Omega, double omega, double f);
// Returns a particle given a set of Pal orbital parameters.
REB_API struct reb_particle reb_particle_from_pal(double G, struct reb_particle primary, double m, double a, double lambda, double k, double h, double ix, double iy);
// Returns a reb_particle structure with fields/name/ptrs initialized to nan/0/NULL. 
REB_API struct reb_particle reb_particle_nan(void);


// Functions to access, remove, and operate on particles

// Remove all particles
REB_API void reb_simulation_remove_all_particles(struct reb_simulation* const r);
// Remove one particle. Remaining particle will keep order. Returns 0 if successful.
REB_API int reb_simulation_remove_particle(struct reb_simulation* const r, size_t index);
// Remove one particle by name. If multiple particles share the name, one particle will be remove. Which one is undetermined. Returns 0 if successful.
REB_API int reb_simulation_remove_particle_by_name(struct reb_simulation* r, const char* const name); 
// Returns a particle's index in the simulation given a pointer to the particle. Returns -1 if not found. 
REB_API int reb_simulation_particle_index(struct reb_particle* p); 
// Returns a variational particle's index in the simulation given a pointer to the particle. Returns -1 if not found. 
REB_API int reb_simulation_particle_var_index(struct reb_particle* p); 
// Subtract particle p2 from p1
REB_API void reb_particle_isub(struct reb_particle* p1, struct reb_particle* p2);
// Add particle p2 to p1
REB_API void reb_particle_iadd(struct reb_particle* p1, struct reb_particle* p2);
// Multiply x,y,z,vx,vy,vz,m of p1 with given value.
REB_API void reb_particle_imul(struct reb_particle* p1, double value);
// Return the distance between particle p1 and p2
REB_API double reb_particle_distance(struct reb_particle* p1, struct reb_particle* p2);
// Compares two particles, ignoring pointers. Returns 1 if particles differ, 0 if they are exactly equal.
REB_API int reb_particle_cmp(struct reb_particle p1, struct reb_particle p2); 
// Sets a particle's name. This function should be used instead of directly setting the name in the particle's structure as it
// registers the name, allowing for faster lookup and storing of name in binary files.
REB_API void reb_particle_set_name(struct reb_particle* p, const char* const name);
/// Register a string. This copies the string, returns the new pointer. REBOUND will manage the memory of the copy. Used by REBOUNDx.
REB_API const char* reb_simulation_register_name(struct reb_simulation* r, const char* const name);
// Returns a pointer to a particle given its name. Returns NULL if not found.
REB_API struct reb_particle* reb_simulation_get_particle_by_name(struct reb_simulation* r, const char* const name);
#ifdef MPI
// When MPI is used, particles cannot be accessed by name. Need to use id instead.
REB_API struct reb_particle reb_simulation_particle_by_id(struct reb_simulation* const r, size_t id);
#endif // MPI



// Chaos indicators

// Turn on MEGNO/Lyapunov calculation. Uses random seen in simulation.
REB_API void reb_simulation_init_megno(struct reb_simulation* const r);
// Same as above but used given random seed. Useful to reproduce same results every time.
REB_API void reb_simulation_init_megno_seed(struct reb_simulation* const r, unsigned int seed);
// Returns the current MEGNO value,
REB_API double reb_simulation_megno(struct reb_simulation* r);
// Returns the largest Lyapunov characteristic number (LCN).
REB_API double reb_simulation_lyapunov(struct reb_simulation* r);


// Built in collision resolve functions

REB_API enum REB_COLLISION_RESOLVE_OUTCOME reb_collision_resolve_halt(struct reb_simulation* const r, struct reb_collision c); // halts a simulation when a collision occurs
REB_API enum REB_COLLISION_RESOLVE_OUTCOME reb_collision_resolve_hardsphere(struct reb_simulation* const r, struct reb_collision c);
REB_API enum REB_COLLISION_RESOLVE_OUTCOME reb_collision_resolve_merge(struct reb_simulation* const r, struct reb_collision c);

// Random sampling - These functions only use the simulation object for a seed. If r=NULL, time and PID are used as a seed.

REB_API double reb_random_uniform(struct reb_simulation* r, double min, double max);
REB_API double reb_random_powerlaw(struct reb_simulation* r, double min, double max, double slope);
REB_API double reb_random_normal(struct reb_simulation* r, double variance);
REB_API double reb_random_rayleigh(struct reb_simulation* r, double sigma);


// Miscellaneous functions

// Returns the angle f wrapped in the interval from 0 to 2*pi
REB_API double reb_mod2pi(double f);
// True anomaly for a given eccentricity and mean anomaly
REB_API double reb_M_to_f(double e, double M);
// True anomaly for a given eccentricity and eccentric anomaly
REB_API double reb_E_to_f(double e, double M);
// Eccentric anomaly for a given eccentricity and mean anomaly
REB_API double reb_M_to_E(double e, double M);
// Returns the hash for a given string. 
REB_API uint32_t reb_hash(const char* c);


// Simulationarchive

// Allocate memory for a simulationarchive and initialize it with a file.
REB_API struct reb_simulationarchive* reb_simulationarchive_create_from_file(const char* filename);
// Free memory allocated by simulationarchive
REB_API void reb_simulationarchive_free(struct reb_simulationarchive* sa);


// Orbit calculation

// Structure containing orbital elements for Keplerian orbits.
struct reb_orbit {
    double d;               // Radial distance from central object
    double v;               // velocity relative to central object's velocity
    double h;               // Specific angular momentum
    double P;               // Orbital period
    double n;               // Mean motion
    double a;               // Semi-major axis
    double e;               // Eccentricity
    double inc;             // Inclination
    double Omega;           // Longitude of ascending node
    double omega;           // Argument of pericenter
    double pomega;          // Longitude of pericenter
    double f;               // True anomaly
    double M;               // Mean anomaly
    double l;               // Mean Longitude
    double theta;           // True Longitude
    double T;               // Time of pericenter passage
    double rhill;           // Circular Hill radius 
    double pal_h;           // Cartesian component of the eccentricity, h = e*sin(pomega) 
    double pal_k;           // Cartesian component of the eccentricity, k = e*cos(pomega) 
    double pal_ix;          // Cartesian component of the inclination, ix = 2*sin(i/2)*cos(Omega)
    double pal_iy;          // Cartesian component of the inclination, ix = 2*sin(i/2)*sin(Omega)
    struct reb_vec3d hvec;  // specific angular momentum vector
    struct reb_vec3d evec;  // eccentricity vector (mag=ecc, points toward peri)
};
// Calculates all orbital elements of the particle p, assuming gravitational constant G and the given primary.
REB_API struct reb_orbit reb_orbit_from_particle(double G, struct reb_particle p, struct reb_particle primary);
// Same as above but returns sets an error code if not successful.
REB_API struct reb_orbit reb_orbit_from_particle_err(double G, struct reb_particle p, struct reb_particle primary, int* err);


// ODE functions

// Defines one Ordinary Differential Equation (ODE) so that it can be integrated with REBOUND
struct reb_ode{
    unsigned int length;        // number of components / dimension
    double* y;                  // Pointer to current state 
    unsigned int needs_nbody;   // 1: ODE needs N-body particles to calculate RHS
    void* ref;                  // Optional pointer to any additional data needed for derivative calculation
    void (*derivatives)(struct reb_ode* const ode, double* const yDot, const double* const y, const double t);  // Function pointer to right hand side of ODE
    void (*getscale)(struct reb_ode* const ode, const double* const y0, const double* const y1);                // Function pointer, sets scales for components (optional) 
    void (*pre_timestep)(struct reb_ode* const ode, const double* const y0);                                    // Function pointer, gets called just before the ODE integration (optional)
    void (*post_timestep)(struct reb_ode* const ode, const double* const y0);                                   // Function pointer, gets called just after the ODE integration (optional)

    // Internal use
    size_t N_allocated;   
    double* scale;
    double* C;                  // Temporary internal array (extrapolation) 
    double** D;                 // Temporary internal array (extrapolation) 
    double* y1;                 // Temporary internal array (state during the step) 
    double* y0Dot;              // Temporary internal array (derivatives at beginning of step)
    double* yDot;               // Temporary internal array (derivatives)
    double* yTmp;               // Temporary internal array (midpoint method)
    struct reb_simulation* r;   // weak reference to main simulation 
};
// Allocate memory for an ODE struct, initialize it, and attach it to the simulation. See examples for details on usage.
REB_API struct reb_ode* reb_ode_create(struct reb_simulation* r, unsigned int length);
// Free an ODE struct.
REB_API void reb_ode_free(struct reb_ode* ode);


// Variational equations

// Struct describing the properties of a set of variational equations.
// If testparticle is set to -1, then it is assumed that all particles are massive
// and all particles influence all other particles. If testparticle is >=0 then 
// the particle with that index is assumed to be a testparticle, i.e. it does not 
// influence other particles. For second order variational equation, index_1st_order_a/b 
// is the index in the particle array that corresponds to the 1st order variational 
// equations.
struct reb_variational_configuration{
    struct reb_simulation* sim; // Reference to the simulation.
    int order;                  // Order of the variational equation. 1 or 2. 
    int index;                  // Index of the first variational particle in the particles array.
    int testparticle;           // Is this variational configuration describe a test particle? -1 if not.
    int index_1st_order_a;      // Used for 2nd order variational particles only: Index of the first order variational particle in the particles array.
    int index_1st_order_b;      // Used for 2nd order variational particles only: Index of the first order variational particle in the particles array.
    double lrescale;            // Accumulates the logarithm of rescalings
};

// Add and initialize a set of first order variational particles
// If testparticle is >= 0, then only one variational particle (the test particle) will be added.
// If testparticle is -1, one variational particle for each real particle will be added.
// Returns the index of the first variational particle added
REB_API int reb_simulation_add_variation_1st_order(struct reb_simulation* const r, int testparticle);

// Add and initialize a set of second order variational particles
// Note: a set of second order variational particles requires two sets of first order variational equations.
// If testparticle is >= 0, then only one variational particle (the test particle) will be added.
// If testparticle is -1, one variational particle for each real particle will be added.
// index_1st_order_a is the index of the corresponding first variational particles.
// index_1st_order_b is the index of the corresponding first variational particles.
// Returns the index of the first variational particle added
REB_API int reb_simulation_add_variation_2nd_order(struct reb_simulation* const r, int testparticle, size_t index_1st_order_a, size_t index_1st_order_b);

// Rescale all sets of variational particles if their size gets too large (>1e100).
// This can prevent an overflow in floating point numbers. The logarithm of the rescaling
// factor is stored in the reb_variational_configuration's lrescale variable. 
// This function is called automatically every timestep. To avoid automatic rescaling,
// set the reb_variational_configuration's lrescale variable to -1.
// For this function to work, the positions and velocities needs to be synchronized. 
// A warning is presented if the integrator is not synchronized. 
REB_API void reb_simulation_rescale_var(struct reb_simulation* const r);

// These functions calculates the first/second derivative of a Keplerian orbit. 
//   Derivatives of Keplerian orbits are required for variational equations, in particular
//   for optimization problems. 
//   The derivative is calculated with respect to the variables that appear in the function name.
//   One variable implies that a first derivative is returned, two variables implies that a second
//   derivate is returned. Classical orbital parameters and those introduced by Pal (2009) are 
//   supported. Pal coordinates have the advantage of being analytical (i.e. infinite differentiable).
//   Classical orbital parameters may have singularities, for example when e is close to 0.
//   Note that derivatives with respect to Cartesian coordinates are trivial and therefore not
//   implemented as separate functions. 
//   The following variables are supported: a, e, inc, f, omega, Omega, h, k, ix, iy and m (mass). 
// The functions return the derivative as a particle structure. Each structure element is a derivative.
// The parameter po is the original particle for which the derivative is to be calculated.
REB_API struct reb_particle reb_particle_derivative_lambda(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_h(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_k(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_k_k(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_h_h(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_lambda_lambda(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_k_lambda(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_h_lambda(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_k_h(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_a(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_ix_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_iy_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_k_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_h_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_lambda_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_lambda_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_h_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_k_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_ix_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_lambda(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_h(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_k(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_a(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_lambda(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_h(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_k(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_ix(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_iy(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_m(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_e(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_e_e(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_inc(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_inc_inc(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_Omega_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_omega_omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_f_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_e(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_inc(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_a_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_e_inc(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_e_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_e_omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_e_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_e(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_inc_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_inc_omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_inc_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_inc(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_omega_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_Omega_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_Omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_omega_f(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_omega(double G, struct reb_particle primary, struct reb_particle po);
REB_API struct reb_particle reb_particle_derivative_m_f(double G, struct reb_particle primary, struct reb_particle po);

// Functions for Frequency Analysis, MFT, FMFT
enum REB_FREQUENCY_ANALYSIS_TYPE {
    REB_FREQUENCY_ANALYSIS_MFT = 0,
    REB_FREQUENCY_ANALYSIS_FMFT = 1,
    REB_FREQUENCY_ANALYSIS_FMFT2 = 2,
};
// Returns 0 on success
REB_API int reb_frequency_analysis(double *output, size_t nfreq, double minfreq, double maxfreq, enum REB_FREQUENCY_ANALYSIS_TYPE type, double *input, size_t ndata);

// Functions to convert between coordinate systems

// Rotations

// Rotation struct (implemented as a quaternion)
struct reb_rotation {
    double ix;
    double iy;
    double iz;
    double r;
};

REB_API struct reb_rotation reb_rotation_inverse(const struct reb_rotation q);
REB_API struct reb_rotation reb_rotation_mul(const struct reb_rotation p, const struct reb_rotation q);

REB_API struct reb_rotation reb_rotation_identity();
REB_API struct reb_rotation reb_rotation_normalize(const struct reb_rotation q);
REB_API struct reb_rotation reb_rotation_conjugate(const struct reb_rotation q);
REB_API struct reb_rotation reb_rotation_init_angle_axis(const double angle, struct reb_vec3d axis);
REB_API struct reb_rotation reb_rotation_init_from_to(struct reb_vec3d from, struct reb_vec3d to);
REB_API struct reb_rotation reb_rotation_init_orbit(const double Omega, const double inc, const double omega);
REB_API struct reb_rotation reb_rotation_init_to_new_axes(struct reb_vec3d newz, struct reb_vec3d newx);
REB_API struct reb_rotation reb_rotation_slerp(struct reb_rotation q1, struct reb_rotation q2, double t);

// transformations to/from vec3d
REB_API struct reb_vec3d reb_tools_spherical_to_xyz(const double mag, const double theta, const double phi);
REB_API void reb_tools_xyz_to_spherical(struct reb_vec3d const xyz, double* mag, double* theta, double* phi);

REB_API struct reb_vec3d reb_vec3d_mul(const struct reb_vec3d v, const double s);
REB_API struct reb_vec3d reb_vec3d_add(const struct reb_vec3d v, const struct reb_vec3d w);
REB_API double reb_vec3d_length_squared(const struct reb_vec3d v);
REB_API double reb_vec3d_dot(const struct reb_vec3d a, const struct reb_vec3d b);
REB_API struct reb_vec3d reb_vec3d_cross(const struct reb_vec3d a, const struct reb_vec3d b);
REB_API struct reb_vec3d reb_vec3d_normalize(const struct reb_vec3d v);
REB_API struct reb_vec3d reb_vec3d_rotate(struct reb_vec3d v, const struct reb_rotation q);
REB_API void reb_vec3d_irotate(struct reb_vec3d *v, const struct reb_rotation q);
REB_API void reb_particle_irotate(struct reb_particle* p, const struct reb_rotation q);
REB_API void reb_simulation_irotate(struct reb_simulation* const sim, const struct reb_rotation q);

REB_API void reb_rotation_to_orbital(struct reb_rotation q, double* Omega, double* inc, double* omega);

#ifdef MPI
void reb_mpi_init(struct reb_simulation* const r);
void reb_mpi_finalize(struct reb_simulation* const r);
#endif // MPI


// The following structures are related to OpenGL/WebGL visualization.

// Generic 3d vector
struct reb_vec3df {
    float x,y,z;
};

// Generic 4d matrix (single precision)
struct reb_mat4df {
    float m[16];
};

// Structures and functions used for programmatic animations.
// Current display orientation, settings, etc
struct reb_display_settings {
    struct reb_mat4df view;
    int spheres;                    // Switches between point sprite and real spheres.
    int pause;                      // Pauses visualization, but keep simulation running
    int wire;                       // Shows/hides orbit wires.
    unsigned int breadcrumbs;       // Number of past particle positions.
    int onscreentext;               // Shows/hides onscreen text.
    int onscreenhelp;               // Shows/hides onscreen help.
    int multisample;                // Turn off/on multisampling.
    int ghostboxes;                 // Shows/hides ghost boxes.
    size_t reference;                  // reb_particle used as a reference for centering.
};

// Display settings initialization. Overwrites user interactions.
REB_API void reb_simulation_add_display_settings(struct reb_simulation* r);

// Matrix/vector methods for single precision operations. Used for graphics only
REB_API struct reb_mat4df reb_mat4df_identity();
REB_API struct reb_mat4df reb_mat4df_scale(struct reb_mat4df m, float x, float y, float z);
REB_API void reb_mat4df_print(struct reb_mat4df m);
REB_API int reb_mat4df_eq(struct reb_mat4df A, struct reb_mat4df B);
REB_API struct reb_vec3df reb_mat4df_get_scale(struct reb_mat4df m);
REB_API struct reb_mat4df reb_mat4df_translate(struct reb_mat4df m, float x, float y, float z);
REB_API struct reb_mat4df reb_mat4df_multiply(struct reb_mat4df A, struct reb_mat4df B);
REB_API struct reb_mat4df reb_rotation_to_mat4df(struct reb_rotation A);
REB_API struct reb_mat4df reb_mat4df_ortho(float l, float r, float b, float t, float n, float f);


#endif // _MAIN_H