guohanghui commited on
Commit
ca739d3
·
verified ·
1 Parent(s): 4b0ba0a

Upload 468 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. Dockerfile +18 -0
  3. README.md +26 -4
  4. app.py +45 -0
  5. rebound/mcp_output/README_MCP.md +73 -0
  6. rebound/mcp_output/analysis.json +550 -0
  7. rebound/mcp_output/diff_report.md +53 -0
  8. rebound/mcp_output/mcp_plugin/__init__.py +0 -0
  9. rebound/mcp_output/mcp_plugin/adapter.py +140 -0
  10. rebound/mcp_output/mcp_plugin/main.py +13 -0
  11. rebound/mcp_output/mcp_plugin/mcp_service.py +80 -0
  12. rebound/mcp_output/requirements.txt +7 -0
  13. rebound/mcp_output/start_mcp.py +30 -0
  14. rebound/mcp_output/workflow_summary.json +196 -0
  15. rebound/source/LICENSE +674 -0
  16. rebound/source/MANIFEST.in +66 -0
  17. rebound/source/Makefile +16 -0
  18. rebound/source/README.md +149 -0
  19. rebound/source/__init__.py +4 -0
  20. rebound/source/changelog.md +589 -0
  21. rebound/source/docs/addingparticles.md +169 -0
  22. rebound/source/docs/api.md +20 -0
  23. rebound/source/docs/binaryformat.md +172 -0
  24. rebound/source/docs/boundaryconditions.md +108 -0
  25. rebound/source/docs/c_examples/compile_emcc.bash +31 -0
  26. rebound/source/docs/c_examples/generate_c_examples.py +64 -0
  27. rebound/source/docs/c_outputfunctions.md +78 -0
  28. rebound/source/docs/c_randomsamplingfunctions.md +41 -0
  29. rebound/source/docs/changelog.md +589 -0
  30. rebound/source/docs/chaos.md +102 -0
  31. rebound/source/docs/collisions.md +246 -0
  32. rebound/source/docs/examples.md +9 -0
  33. rebound/source/docs/generate_python_docs.py +39 -0
  34. rebound/source/docs/gravity.md +29 -0
  35. rebound/source/docs/img/favicon.ico +0 -0
  36. rebound/source/docs/img/orbit.png +0 -0
  37. rebound/source/docs/img/rebound.png +0 -0
  38. rebound/source/docs/img/reboundbanner.png +3 -0
  39. rebound/source/docs/img/reboundblack.png +0 -0
  40. rebound/source/docs/img/shear.png +0 -0
  41. rebound/source/docs/index.md +103 -0
  42. rebound/source/docs/integrators.md +852 -0
  43. rebound/source/docs/ipython_examples/AdvWHFast.ipynb +440 -0
  44. rebound/source/docs/ipython_examples/ChaoticHyperion.ipynb +250 -0
  45. rebound/source/docs/ipython_examples/Cheartbeat.ipynb +300 -0
  46. rebound/source/docs/ipython_examples/Checkpoints.ipynb +120 -0
  47. rebound/source/docs/ipython_examples/Churyumov-Gerasimenko.ipynb +0 -0
  48. rebound/source/docs/ipython_examples/CloseEncounters.ipynb +332 -0
  49. rebound/source/docs/ipython_examples/EccentricComets.ipynb +0 -0
  50. rebound/source/docs/ipython_examples/EmbeddedOperatorSplittingMethods.ipynb +0 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ rebound/source/docs/img/reboundbanner.png filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+
3
+ RUN useradd -m -u 1000 user && python -m pip install --upgrade pip
4
+ USER user
5
+ ENV PATH="/home/user/.local/bin:$PATH"
6
+
7
+ WORKDIR /app
8
+
9
+ COPY --chown=user ./requirements.txt requirements.txt
10
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
+
12
+ COPY --chown=user . /app
13
+ ENV MCP_TRANSPORT=http
14
+ ENV MCP_PORT=7860
15
+
16
+ EXPOSE 7860
17
+
18
+ CMD ["python", "rebound/mcp_output/start_mcp.py"]
README.md CHANGED
@@ -1,10 +1,32 @@
1
  ---
2
- title: Rebound
3
- emoji: 🌖
4
  colorFrom: blue
5
- colorTo: green
6
  sdk: docker
 
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Rebound MCP
3
+ emoji: 🤖
4
  colorFrom: blue
5
+ colorTo: purple
6
  sdk: docker
7
+ sdk_version: "4.26.0"
8
+ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
+ # Rebound MCP Service
13
+
14
+ Auto-generated MCP service for rebound.
15
+
16
+ ## Usage
17
+
18
+ ```
19
+ https://None-rebound-mcp.hf.space/mcp
20
+ ```
21
+
22
+ ## Connect with Cursor
23
+
24
+ ```json
25
+ {
26
+ "mcpServers": {
27
+ "rebound": {
28
+ "url": "https://None-rebound-mcp.hf.space/mcp"
29
+ }
30
+ }
31
+ }
32
+ ```
app.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ import os
3
+ import sys
4
+
5
+ mcp_plugin_path = os.path.join(os.path.dirname(__file__), "rebound", "mcp_output", "mcp_plugin")
6
+ sys.path.insert(0, mcp_plugin_path)
7
+
8
+ app = FastAPI(
9
+ title="Rebound MCP Service",
10
+ description="Auto-generated MCP service for rebound",
11
+ version="1.0.0"
12
+ )
13
+
14
+ @app.get("/")
15
+ def root():
16
+ return {
17
+ "service": "Rebound MCP Service",
18
+ "version": "1.0.0",
19
+ "status": "running",
20
+ "transport": os.environ.get("MCP_TRANSPORT", "http")
21
+ }
22
+
23
+ @app.get("/health")
24
+ def health_check():
25
+ return {"status": "healthy", "service": "rebound MCP"}
26
+
27
+ @app.get("/tools")
28
+ def list_tools():
29
+ try:
30
+ from mcp_service import create_app
31
+ mcp_app = create_app()
32
+ tools = []
33
+ for tool_name, tool_func in mcp_app.tools.items():
34
+ tools.append({
35
+ "name": tool_name,
36
+ "description": tool_func.__doc__ or "No description available"
37
+ })
38
+ return {"tools": tools}
39
+ except Exception as e:
40
+ return {"error": f"Failed to load tools: {str(e)}"}
41
+
42
+ if __name__ == "__main__":
43
+ import uvicorn
44
+ port = int(os.environ.get("PORT", 7860))
45
+ uvicorn.run(app, host="0.0.0.0", port=port)
rebound/mcp_output/README_MCP.md ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # REBOUND: N-Body Simulation Service
2
+
3
+ ## Project Introduction
4
+
5
+ REBOUND is an open-source N-body integrator package designed for high-accuracy astronomical simulations. It enables the numerical integration of particle systems under gravitational forces, supporting applications ranging from planetary dynamics to galactic structure formation. The core architecture combines a high-performance C computational core with accessible Python interfaces, allowing researchers to perform complex simulations with minimal setup.
6
+
7
+ ## Installation Method
8
+
9
+ To install REBOUND, ensure you have the following dependencies:
10
+
11
+ - Required: `numpy`, `scipy`
12
+ - Optional: `matplotlib`, `mpi4py`
13
+
14
+ You can install REBOUND using pip:
15
+
16
+ ```
17
+ pip install rebound
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ Here's a basic example to get you started with REBOUND:
23
+
24
+ 1. **Initialize a Simulation:**
25
+
26
+ Create a simulation instance and add particles.
27
+
28
+ ```
29
+ from rebound import Simulation
30
+
31
+ sim = Simulation()
32
+ sim.add(m=1.0) # Add a central mass
33
+ sim.add(m=1e-3, a=1.0) # Add a particle
34
+ ```
35
+
36
+ 2. **Integrate the Simulation:**
37
+
38
+ Advance the simulation in time.
39
+
40
+ ```
41
+ sim.integrate(100.0) # Integrate to time t=100
42
+ ```
43
+
44
+ 3. **Check Simulation Status:**
45
+
46
+ Retrieve the current status of the simulation.
47
+
48
+ ```
49
+ status = sim.status()
50
+ print(status)
51
+ ```
52
+
53
+ ## Available Tools and Endpoints List
54
+
55
+ - **Simulation Class:** Manages the main simulation loop and particle states.
56
+ - **Particle Class:** Represents individual particles with kinematic and physical properties.
57
+ - **TRACE Integrator:** Implements the TRACE integrator for specific simulation scenarios.
58
+
59
+ ## Common Issues and Notes
60
+
61
+ - **Dependencies:** Ensure all required dependencies are installed. Optional dependencies enhance functionality but are not mandatory.
62
+ - **Environment:** REBOUND supports shared-memory parallelization (OpenMP) and distributed computing (MPI) for specialized cases.
63
+ - **Performance:** The system automatically optimizes for platform capabilities, including AVX512 support for the WHFast512 integrator and GPU acceleration where available.
64
+
65
+ ## Reference Links or Documentation
66
+
67
+ - [REBOUND GitHub Repository](https://github.com/hannorein/rebound)
68
+ - [Documentation](https://rebound.readthedocs.io/)
69
+ - [Numerical Integrators](https://rebound.readthedocs.io/en/latest/integrators.html)
70
+ - [Visualization Capabilities](https://rebound.readthedocs.io/en/latest/visualization.html)
71
+ - [Data Management and Reproducibility](https://rebound.readthedocs.io/en/latest/data_management.html)
72
+
73
+ For more detailed information about specific subsystems, refer to the dedicated sections on core architecture, integrators, visualization, and data management.
rebound/mcp_output/analysis.json ADDED
@@ -0,0 +1,550 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "summary": {
3
+ "repository_url": "https://github.com/hannorein/rebound",
4
+ "summary": "Imported via zip fallback, file count: 150",
5
+ "file_tree": {
6
+ ".github/ISSUE_TEMPLATE/advice.md": {
7
+ "size": 1133
8
+ },
9
+ ".github/ISSUE_TEMPLATE/bug_report.md": {
10
+ "size": 885
11
+ },
12
+ ".github/ISSUE_TEMPLATE/feature_request.md": {
13
+ "size": 370
14
+ },
15
+ ".github/ISSUE_TEMPLATE/question.md": {
16
+ "size": 209
17
+ },
18
+ ".github/codecov.yml": {
19
+ "size": 29
20
+ },
21
+ ".github/workflows/build_wheels.yml": {
22
+ "size": 1473
23
+ },
24
+ ".github/workflows/c.yml": {
25
+ "size": 934
26
+ },
27
+ ".github/workflows/cmpi.yml": {
28
+ "size": 822
29
+ },
30
+ ".github/workflows/coverage.yml": {
31
+ "size": 1085
32
+ },
33
+ ".github/workflows/emscripten.yml": {
34
+ "size": 759
35
+ },
36
+ ".github/workflows/ipynb.yml": {
37
+ "size": 1913
38
+ },
39
+ ".github/workflows/lint.yml": {
40
+ "size": 438
41
+ },
42
+ ".github/workflows/python.yml": {
43
+ "size": 1713
44
+ },
45
+ ".github/workflows/reboundx.yml": {
46
+ "size": 1214
47
+ },
48
+ "README.md": {
49
+ "size": 9665
50
+ },
51
+ "changelog.md": {
52
+ "size": 35767
53
+ },
54
+ "docs/addingparticles.md": {
55
+ "size": 7967
56
+ },
57
+ "docs/api.md": {
58
+ "size": 1472
59
+ },
60
+ "docs/binaryformat.md": {
61
+ "size": 6173
62
+ },
63
+ "docs/boundaryconditions.md": {
64
+ "size": 3807
65
+ },
66
+ "docs/c_examples/generate_c_examples.py": {
67
+ "size": 2860
68
+ },
69
+ "docs/c_outputfunctions.md": {
70
+ "size": 2750
71
+ },
72
+ "docs/c_randomsamplingfunctions.md": {
73
+ "size": 1747
74
+ },
75
+ "docs/changelog.md": {
76
+ "size": 15
77
+ },
78
+ "docs/chaos.md": {
79
+ "size": 4461
80
+ },
81
+ "docs/collisions.md": {
82
+ "size": 9313
83
+ },
84
+ "docs/examples.md": {
85
+ "size": 564
86
+ },
87
+ "docs/generate_python_docs.py": {
88
+ "size": 1054
89
+ },
90
+ "docs/gravity.md": {
91
+ "size": 1154
92
+ },
93
+ "docs/index.md": {
94
+ "size": 7523
95
+ },
96
+ "docs/integrators.md": {
97
+ "size": 42853
98
+ },
99
+ "docs/javascripts/config.js": {
100
+ "size": 300
101
+ },
102
+ "docs/miscellaneous.md": {
103
+ "size": 714
104
+ },
105
+ "docs/mpi.md": {
106
+ "size": 2809
107
+ },
108
+ "docs/namingconvention.md": {
109
+ "size": 2965
110
+ },
111
+ "docs/orbitalelements.md": {
112
+ "size": 3948
113
+ },
114
+ "docs/particleoperators.md": {
115
+ "size": 2663
116
+ },
117
+ "docs/particles.md": {
118
+ "size": 1924
119
+ },
120
+ "docs/quickstart_firstexample.md": {
121
+ "size": 3432
122
+ },
123
+ "docs/quickstart_installation.md": {
124
+ "size": 9025
125
+ },
126
+ "docs/quickstart_whereto.md": {
127
+ "size": 743
128
+ },
129
+ "docs/removingparticles.md": {
130
+ "size": 3025
131
+ },
132
+ "docs/requirements.txt": {
133
+ "size": 119
134
+ },
135
+ "docs/simulation.md": {
136
+ "size": 2958
137
+ },
138
+ "docs/simulationarchive.md": {
139
+ "size": 4157
140
+ },
141
+ "docs/simulationbinaryfiles.md": {
142
+ "size": 1221
143
+ },
144
+ "docs/simulationdiagnostics.md": {
145
+ "size": 1568
146
+ },
147
+ "docs/simulationoperators.md": {
148
+ "size": 3368
149
+ },
150
+ "docs/simulationreferenceframes.md": {
151
+ "size": 2020
152
+ },
153
+ "docs/simulationtimestepping.md": {
154
+ "size": 3657
155
+ },
156
+ "docs/simulationvariables.md": {
157
+ "size": 13898
158
+ },
159
+ "docs/units.md": {
160
+ "size": 3266
161
+ },
162
+ "docs/visualization.md": {
163
+ "size": 7417
164
+ },
165
+ "ipython_examples/ipynb2py.py": {
166
+ "size": 642
167
+ },
168
+ "mkdocs.yml": {
169
+ "size": 7045
170
+ },
171
+ "pyproject.toml": {
172
+ "size": 91
173
+ },
174
+ "python_examples/dragforce/problem.py": {
175
+ "size": 1062
176
+ },
177
+ "python_examples/horizons/problem.py": {
178
+ "size": 1715
179
+ },
180
+ "python_examples/longtermtest/problem.py": {
181
+ "size": 6149
182
+ },
183
+ "python_examples/megno/problem.py": {
184
+ "size": 3505
185
+ },
186
+ "python_examples/megno_simple/problem.py": {
187
+ "size": 1024
188
+ },
189
+ "python_examples/orbital_elements/problem.py": {
190
+ "size": 776
191
+ },
192
+ "python_examples/outersolarsystem/problem.py": {
193
+ "size": 1797
194
+ },
195
+ "python_examples/simple_orbit/problem.py": {
196
+ "size": 495
197
+ },
198
+ "python_examples/simulationarchive/problem.py": {
199
+ "size": 729
200
+ },
201
+ "rebound/__init__.py": {
202
+ "size": 3714
203
+ },
204
+ "rebound/binary_field_descriptor.py": {
205
+ "size": 1166
206
+ },
207
+ "rebound/citations.py": {
208
+ "size": 15301
209
+ },
210
+ "rebound/data.py": {
211
+ "size": 3504
212
+ },
213
+ "rebound/frequency_analysis.py": {
214
+ "size": 3332
215
+ },
216
+ "rebound/hash.py": {
217
+ "size": 824
218
+ },
219
+ "rebound/horizons.py": {
220
+ "size": 11212
221
+ },
222
+ "rebound/integrators/__init__.py": {
223
+ "size": 14
224
+ },
225
+ "rebound/integrators/bs.py": {
226
+ "size": 2606
227
+ },
228
+ "rebound/integrators/eos.py": {
229
+ "size": 2951
230
+ },
231
+ "rebound/integrators/ias15.py": {
232
+ "size": 4176
233
+ },
234
+ "rebound/integrators/janus.py": {
235
+ "size": 766
236
+ },
237
+ "rebound/integrators/leapfrog.py": {
238
+ "size": 453
239
+ },
240
+ "rebound/integrators/mercurius.py": {
241
+ "size": 2848
242
+ },
243
+ "rebound/integrators/saba.py": {
244
+ "size": 2376
245
+ },
246
+ "rebound/integrators/sei.py": {
247
+ "size": 1201
248
+ },
249
+ "rebound/integrators/trace.py": {
250
+ "size": 4982
251
+ },
252
+ "rebound/integrators/whfast.py": {
253
+ "size": 5513
254
+ },
255
+ "rebound/integrators/whfast512.py": {
256
+ "size": 496
257
+ },
258
+ "rebound/orbit.py": {
259
+ "size": 3644
260
+ },
261
+ "rebound/particle.py": {
262
+ "size": 46115
263
+ },
264
+ "rebound/particles.py": {
265
+ "size": 2993
266
+ },
267
+ "rebound/plotting.py": {
268
+ "size": 19417
269
+ },
270
+ "rebound/rotation.py": {
271
+ "size": 10897
272
+ },
273
+ "rebound/simulation.py": {
274
+ "size": 68439
275
+ },
276
+ "rebound/simulationarchive.py": {
277
+ "size": 15852
278
+ },
279
+ "rebound/tests/__init__.py": {
280
+ "size": 1
281
+ },
282
+ "rebound/tests/test_additional_forces.py": {
283
+ "size": 3657
284
+ },
285
+ "rebound/tests/test_binary_fields.py": {
286
+ "size": 498
287
+ },
288
+ "rebound/tests/test_boundary.py": {
289
+ "size": 2750
290
+ },
291
+ "rebound/tests/test_bs.py": {
292
+ "size": 13794
293
+ },
294
+ "rebound/tests/test_collisions.py": {
295
+ "size": 6869
296
+ },
297
+ "rebound/tests/test_copy.py": {
298
+ "size": 9362
299
+ },
300
+ "rebound/tests/test_data.py": {
301
+ "size": 516
302
+ },
303
+ "rebound/tests/test_eos.py": {
304
+ "size": 3340
305
+ },
306
+ "rebound/tests/test_eos_megno.py": {
307
+ "size": 3119
308
+ },
309
+ "rebound/tests/test_fpcontract.py": {
310
+ "size": 407
311
+ },
312
+ "rebound/tests/test_frequency_analysis.py": {
313
+ "size": 2497
314
+ },
315
+ "rebound/tests/test_gravity.py": {
316
+ "size": 3278
317
+ },
318
+ "rebound/tests/test_hash.py": {
319
+ "size": 5188
320
+ },
321
+ "rebound/tests/test_horizons.py": {
322
+ "size": 1220
323
+ },
324
+ "rebound/tests/test_import.py": {
325
+ "size": 330
326
+ },
327
+ "rebound/tests/test_integrator.py": {
328
+ "size": 6243
329
+ },
330
+ "rebound/tests/test_janus.py": {
331
+ "size": 3642
332
+ },
333
+ "rebound/tests/test_leapfrog.py": {
334
+ "size": 1929
335
+ },
336
+ "rebound/tests/test_megno.py": {
337
+ "size": 3445
338
+ },
339
+ "rebound/tests/test_mercurius.py": {
340
+ "size": 10962
341
+ },
342
+ "rebound/tests/test_modify_orbital_parameters.py": {
343
+ "size": 8039
344
+ },
345
+ "rebound/tests/test_orbital_elements.py": {
346
+ "size": 17384
347
+ },
348
+ "rebound/tests/test_particle.py": {
349
+ "size": 12833
350
+ },
351
+ "rebound/tests/test_pickle.py": {
352
+ "size": 1690
353
+ },
354
+ "rebound/tests/test_plotting.py": {
355
+ "size": 1412
356
+ },
357
+ "rebound/tests/test_post_timestep_modifications.py": {
358
+ "size": 2300
359
+ },
360
+ "rebound/tests/test_random.py": {
361
+ "size": 2794
362
+ },
363
+ "rebound/tests/test_restart_mercurius.py": {
364
+ "size": 1484
365
+ },
366
+ "rebound/tests/test_rotations.py": {
367
+ "size": 7131
368
+ },
369
+ "rebound/tests/test_saba.py": {
370
+ "size": 5099
371
+ },
372
+ "rebound/tests/test_serialize.py": {
373
+ "size": 2026
374
+ },
375
+ "rebound/tests/test_server.py": {
376
+ "size": 1835
377
+ },
378
+ "rebound/tests/test_shearingsheet.py": {
379
+ "size": 2361
380
+ },
381
+ "rebound/tests/test_simulation.py": {
382
+ "size": 10588
383
+ },
384
+ "rebound/tests/test_simulationarchive.py": {
385
+ "size": 21397
386
+ },
387
+ "rebound/tests/test_simulationarchive_matrix.py": {
388
+ "size": 5113
389
+ },
390
+ "rebound/tests/test_size_of_simulation.py": {
391
+ "size": 432
392
+ },
393
+ "rebound/tests/test_tponly_encounter.py": {
394
+ "size": 1818
395
+ },
396
+ "rebound/tests/test_trace.py": {
397
+ "size": 17042
398
+ },
399
+ "rebound/tests/test_trace_basic.py": {
400
+ "size": 1798
401
+ },
402
+ "rebound/tests/test_trace_full_bs.py": {
403
+ "size": 15149
404
+ },
405
+ "rebound/tests/test_trace_full_ias15.py": {
406
+ "size": 14914
407
+ },
408
+ "rebound/tests/test_transformations.py": {
409
+ "size": 5691
410
+ },
411
+ "rebound/tests/test_units.py": {
412
+ "size": 2331
413
+ },
414
+ "rebound/tests/test_variational.py": {
415
+ "size": 13967
416
+ },
417
+ "rebound/tests/test_whfast.py": {
418
+ "size": 12075
419
+ },
420
+ "rebound/tests/test_whfast_advanced.py": {
421
+ "size": 6299
422
+ },
423
+ "rebound/tests/test_whfast_testparticles.py": {
424
+ "size": 7007
425
+ },
426
+ "rebound/tools.py": {
427
+ "size": 2412
428
+ },
429
+ "rebound/units.py": {
430
+ "size": 4762
431
+ },
432
+ "rebound/variation.py": {
433
+ "size": 6870
434
+ },
435
+ "rebound/vectors.py": {
436
+ "size": 4253
437
+ },
438
+ "rebound/widget.py": {
439
+ "size": 26664
440
+ },
441
+ "requirements.txt": {
442
+ "size": 17
443
+ },
444
+ "setup.py": {
445
+ "size": 5482
446
+ },
447
+ "style.txt": {
448
+ "size": 2237
449
+ },
450
+ "update_version.py": {
451
+ "size": 3902
452
+ },
453
+ "version.txt": {
454
+ "size": 6
455
+ }
456
+ },
457
+ "processed_by": "zip_fallback",
458
+ "success": true
459
+ },
460
+ "structure": {
461
+ "packages": [
462
+ "source.rebound",
463
+ "source.rebound.integrators",
464
+ "source.rebound.tests"
465
+ ]
466
+ },
467
+ "dependencies": {
468
+ "has_environment_yml": false,
469
+ "has_requirements_txt": true,
470
+ "pyproject": true,
471
+ "setup_cfg": false,
472
+ "setup_py": true
473
+ },
474
+ "entry_points": {
475
+ "imports": [],
476
+ "cli": [],
477
+ "modules": []
478
+ },
479
+ "llm_analysis": {
480
+ "core_modules": [
481
+ {
482
+ "package": "source.rebound",
483
+ "module": "simulation",
484
+ "functions": [
485
+ "integrate",
486
+ "add",
487
+ "status"
488
+ ],
489
+ "classes": [
490
+ "Simulation"
491
+ ],
492
+ "description": "Handles the main simulation loop and manages particle states."
493
+ },
494
+ {
495
+ "package": "source.rebound",
496
+ "module": "particle",
497
+ "functions": [],
498
+ "classes": [
499
+ "Particle"
500
+ ],
501
+ "description": "Represents individual particles with kinematic and physical properties."
502
+ },
503
+ {
504
+ "package": "source.rebound.integrators",
505
+ "module": "trace",
506
+ "functions": [],
507
+ "classes": [],
508
+ "description": "Implements the TRACE integrator for specific simulation scenarios."
509
+ }
510
+ ],
511
+ "cli_commands": [],
512
+ "import_strategy": {
513
+ "primary": "import",
514
+ "fallback": "blackbox",
515
+ "confidence": 0.8
516
+ },
517
+ "dependencies": {
518
+ "required": [
519
+ "numpy",
520
+ "scipy"
521
+ ],
522
+ "optional": [
523
+ "matplotlib",
524
+ "mpi4py"
525
+ ]
526
+ },
527
+ "risk_assessment": {
528
+ "import_feasibility": 0.8,
529
+ "intrusiveness_risk": "low",
530
+ "complexity": "medium"
531
+ }
532
+ },
533
+ "deepwiki_analysis": {
534
+ "repo_url": "https://github.com/hannorein/rebound",
535
+ "repo_name": "rebound",
536
+ "content": "hannorein/rebound\nCore Architecture\nSimulation Engine\nParticle System\nBuild System\nPython Interface\nSimulation Class\nParticle Management\nData Sources and Units\nNumerical Integrators\nWHFast Integrator\nHybrid Integrators\nSpecialized Integrators\nVisualization\nReal-time Visualization\nStatic Plotting\nData Management\nSimulation Archives\nAnalysis Tools\nExamples and Tutorials\nBasic Examples\nPhysics Applications\nPerformance and Accuracy\nAdvanced Topics\nParallel Computing\nVariational Equations\nTesting and Validation\nchangelog.md\ndocs/index.md\ndocs/integrators.md\ndocs/mpi.md\ndocs/visualization.md\nipython_examples/Holmberg.ipynb\nipython_examples/WHFast.ipynb\nrebound/__init__.py\nrebound/integrators/trace.py\nrebound/particle.py\nrebound/simulation.py\nrebound/tests/test_trace.py\nsrc/input.c\nsrc/input.h\nsrc/integrator_ias15.c\nsrc/integrator_trace.c\nsrc/integrator_whfast.c\nsrc/output.c\nsrc/output.h\nsrc/rebound.c\nsrc/rebound.h\nsrc/tools.c\nsrc/tools.h\nupdate_version.py\nversion.txt\nweb_client/shell_rebound.html\nweb_client/shell_rebound_console.html\nweb_client/shell_rebound_webgl.html\nThis document provides a comprehensive overview of REBOUND, an open-source N-body integrator package designed for high-accuracy astronomical simulations. REBOUND enables the numerical integration of particle systems under gravitational forces, supporting applications ranging from planetary dynamics to galactic structure formation.\nFor information about specific integrators and their configuration, seeNumerical Integrators. For visualization capabilities, seeVisualization. For data management and reproducibility features, seeData Management.\nPurpose and Architecture\nREBOUND is designed as a multi-layered system combining a high-performance C computational core with accessible Python interfaces. The architecture prioritizes both computational efficiency and ease of use, enabling researchers to perform complex N-body simulations with minimal setup while maintaining the flexibility to customize integrators, force calculations, and analysis workflows.\nSystem Architecture Overview\nThe system follows a layered architecture where thereb_simulationstructure serves as the central coordination point for all simulation activities. Each simulation maintains its own particle array, integrator state, and physics configuration.\nreb_simulation\nSources:src/rebound.h489-647src/rebound.c77-185rebound/simulation.py52-94\nCore Data Structures\nREBOUND's functionality centers around two primary data structures that bridge the natural language concepts of \"simulation\" and \"particle\" with concrete code implementations:\nPython InterfaceC ImplementationConceptual LayerN-body SimulationCelestial Bodystruct reb_simulationrebound.h:489struct reb_particlerebound.h:112• t (time)• dt (timestep)• N (particle count)• integrator• x,y,z (position)• vx,vy,vz (velocity)• m (mass)• r (radius)class Simulationsimulation.py:52class Particleparticle.py:11• integrate()• add()• status()• orbital elements• coordinate access\nPython Interface\nC Implementation\nConceptual Layer\nN-body Simulation\nCelestial Body\nstruct reb_simulationrebound.h:489\nstruct reb_particlerebound.h:112\n• t (time)• dt (timestep)• N (particle count)• integrator\n• x,y,z (position)• vx,vy,vz (velocity)• m (mass)• r (radius)\nclass Simulationsimulation.py:52\nclass Particleparticle.py:11\n• integrate()• add()• status()\n• orbital elements• coordinate access\nThereb_simulationstructure contains all simulation state including time evolution parameters, particle arrays, integrator configurations, and physics settings. Thereb_particlestructure represents individual bodies with their kinematic and physical properties.\nreb_simulation\nreb_particle\nSources:src/rebound.h112-141src/rebound.h489-647rebound/simulation.py52-94rebound/particle.py11-48\nIntegration Engine\nThe heart of REBOUND is its integration engine, which advances particle positions and velocities through time using sophisticated numerical methods. The main integration loop coordinates between force calculations, integrator steps, and auxiliary operations:\nEach integrator implements thereb_integrator_part1()andreb_integrator_part2()interface, allowing for modular swapping of numerical methods. The force calculation supports both built-in gravity models and user-defined additional forces.\nreb_integrator_part1()\nreb_integrator_part2()\nSources:src/rebound.c82-185src/integrator.hsrc/gravity.c\nMemory and Data Management\nREBOUND employs dynamic memory management to handle varying particle counts and simulation complexity. The system automatically resizes internal arrays and manages integrator-specific storage:\nreb_simulation_add()\nreb_integrator_*_reset()\nreb_tree_delete()\nreb_simulation_update_tree()\nreb_simulationarchive_*()\nTheN_allocatedfields throughout the codebase track memory allocation sizes separately from active counts, enabling efficient reuse without frequent reallocation.\nN_allocated\nSources:src/rebound.h508src/particle.csrc/tree.csrc/simulationarchive.c\nBuild System and Distribution\nREBOUND supports multiple deployment scenarios through a flexible build system:\nDistribution ChannelsBuild TargetsSource OrganizationC Source Filessrc/.c, src/.hPython Modulesrebound/*.pyExample Problemsexamples/*/librebound.so/.dllShared LibraryPython Extensionctypes InterfaceStandalone C ProgramsWebGL TargetsEmscriptenpip install reboundSource Repositoryconda install reboundBrowser Examples\nDistribution Channels\nBuild Targets\nSource Organization\nC Source Filessrc/.c, src/.h\nPython Modulesrebound/*.py\nExample Problemsexamples/*/\nlibrebound.so/.dllShared Library\nPython Extensionctypes Interface\nStandalone C Programs\nWebGL TargetsEmscripten\npip install rebound\nSource Repository\nconda install rebound\nBrowser Examples\nThe build system detects platform capabilities and optimizes compilation accordingly, including AVX512 support for the WHFast512 integrator and GPU acceleration where available.\nSources:setup.py52-87Makefile entriesREADME.md51-56\nKey Features and Capabilities\nREBOUND provides a comprehensive suite of capabilities for N-body simulations:\nNumerical Integration: Multiple high-precision integrators including adaptive timestep methods (IAS15), symplectic methods (WHFast, SABA), and hybrid approaches (MERCURIUS, TRACE) for different physical scenarios.\nCoordinate Systems: Support for multiple coordinate systems including Jacobi, heliocentric, barycentric, and democratic heliocentric coordinates, with automatic transformations between systems.\nCollision Handling: Sophisticated collision detection using spatial trees or direct methods, with customizable collision resolution including merging, bouncing, and user-defined responses.\nData Reproducibility: The SimulationArchive system enables bit-perfect reproduction of simulation results through binary serialization of complete simulation state.\nVisualization: Real-time 3D visualization supporting both OpenGL (native) and WebGL (browser-based) rendering with interactive controls for simulation monitoring.\nParallelization: Support for shared-memory parallelization (OpenMP), distributed computing (MPI for specialized cases), and SIMD vectorization (AVX512 for WHFast512).\nSources:src/rebound.h1-100README.md25-44docs/integrators.md\nThis overview establishes the foundation for understanding REBOUND's architecture and capabilities. For detailed information about specific subsystems, refer to the dedicated sections on core architecture, integrators, visualization, and data management.\nRefresh this wiki\nOn this page\nPurpose and Architecture\nSystem Architecture Overview\nCore Data Structures\nIntegration Engine\nMemory and Data Management\nBuild System and Distribution\nKey Features and Capabilities",
537
+ "model": "gpt-4o-2024-08-06",
538
+ "source": "selenium",
539
+ "success": true
540
+ },
541
+ "deepwiki_options": {
542
+ "enabled": true,
543
+ "model": "gpt-4o-2024-08-06"
544
+ },
545
+ "risk": {
546
+ "import_feasibility": 0.8,
547
+ "intrusiveness_risk": "low",
548
+ "complexity": "medium"
549
+ }
550
+ }
rebound/mcp_output/diff_report.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Difference Report for Rebound Project
2
+
3
+ ## Project Overview
4
+
5
+ **Repository:** Rebound
6
+ **Project Type:** Python Library
7
+ **Main Features:** Basic functionality
8
+ **Report Generated On:** February 4, 2026, 19:55:00
9
+
10
+ The Rebound project is a Python library designed to provide basic functionality for its users. The project is currently under development, with recent updates aimed at enhancing its capabilities.
11
+
12
+ ## Difference Analysis
13
+
14
+ ### Summary of Changes
15
+
16
+ - **New Files Added:** 8
17
+ - **Modified Files:** 0
18
+ - **Workflow Status:** Success
19
+ - **Test Status:** Failed
20
+
21
+ The recent update to the Rebound project involved the addition of eight new files. There were no modifications to existing files. The workflow for these changes was successfully executed, but the test suite did not pass, indicating potential issues with the new additions.
22
+
23
+ ## Technical Analysis
24
+
25
+ ### New Files
26
+
27
+ The addition of eight new files suggests a significant expansion of the project's functionality. However, without modifications to existing files, it appears that these new files are standalone additions rather than enhancements or fixes to current features.
28
+
29
+ ### Workflow and Testing
30
+
31
+ - **Workflow Status:** The workflow executed successfully, indicating that the integration of new files into the project did not encounter any immediate technical issues.
32
+ - **Test Status:** The failure of the test suite suggests that the new files may contain errors or that they do not integrate seamlessly with the existing codebase.
33
+
34
+ ## Recommendations and Improvements
35
+
36
+ 1. **Review New Files:** Conduct a thorough review of the newly added files to identify any coding errors or integration issues.
37
+ 2. **Enhance Testing:** Update the test suite to cover the new functionalities introduced by the new files. Ensure that all edge cases are considered.
38
+ 3. **Code Integration:** Evaluate how the new files interact with the existing codebase. Consider refactoring if necessary to improve compatibility and performance.
39
+ 4. **Documentation:** Update project documentation to reflect the new features and provide guidance on their usage.
40
+
41
+ ## Deployment Information
42
+
43
+ Given the current test failures, it is not recommended to deploy the latest changes to a production environment. Addressing the issues identified in the test suite should be prioritized before any deployment.
44
+
45
+ ## Future Planning
46
+
47
+ 1. **Bug Fixes:** Focus on resolving the issues identified in the test suite to ensure the stability and reliability of the new features.
48
+ 2. **Feature Expansion:** Once the current issues are resolved, consider expanding the library's functionality further, based on user feedback and project goals.
49
+ 3. **Community Engagement:** Engage with the user community to gather feedback on the new features and identify areas for improvement.
50
+
51
+ ## Conclusion
52
+
53
+ The recent update to the Rebound project has introduced new functionalities through the addition of eight new files. While the workflow was successful, the test failures indicate that further work is needed to ensure these new features are robust and integrate well with the existing codebase. By addressing the identified issues and enhancing the test suite, the project can move towards a stable release in the future.
rebound/mcp_output/mcp_plugin/__init__.py ADDED
File without changes
rebound/mcp_output/mcp_plugin/adapter.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+
4
+ # Path settings
5
+ source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
6
+ sys.path.insert(0, source_path)
7
+
8
+ # Import statements
9
+ try:
10
+ from rebound.simulation import Simulation
11
+ from rebound.particle import Particle
12
+ from rebound.integrators.trace import TraceIntegrator
13
+ from rebound.tests.test_trace import test_trace_function
14
+ import numpy as np
15
+ import scipy
16
+ import matplotlib
17
+ import mpi4py
18
+ except ImportError as e:
19
+ print(f"Import failed: {e}. Ensure all dependencies are installed and the source path is correct.")
20
+
21
+ # Adapter class
22
+ class Adapter:
23
+ """
24
+ Adapter class for the MCP plugin, providing access to REBOUND's core functionalities.
25
+ """
26
+
27
+ def __init__(self):
28
+ self.mode = "import"
29
+
30
+ # Simulation Module
31
+ # -------------------------------------------------------------------------
32
+ def create_simulation_instance(self, *args, **kwargs):
33
+ """
34
+ Create an instance of the Simulation class.
35
+
36
+ Parameters:
37
+ *args: Positional arguments for Simulation.
38
+ **kwargs: Keyword arguments for Simulation.
39
+
40
+ Returns:
41
+ dict: Status and instance of Simulation.
42
+ """
43
+ try:
44
+ simulation = Simulation(*args, **kwargs)
45
+ return {"status": "success", "simulation": simulation}
46
+ except Exception as e:
47
+ return {"status": "error", "message": str(e)}
48
+
49
+ # Particle Module
50
+ # -------------------------------------------------------------------------
51
+ def create_particle_instance(self, *args, **kwargs):
52
+ """
53
+ Create an instance of the Particle class.
54
+
55
+ Parameters:
56
+ *args: Positional arguments for Particle.
57
+ **kwargs: Keyword arguments for Particle.
58
+
59
+ Returns:
60
+ dict: Status and instance of Particle.
61
+ """
62
+ try:
63
+ particle = Particle(*args, **kwargs)
64
+ return {"status": "success", "particle": particle}
65
+ except Exception as e:
66
+ return {"status": "error", "message": str(e)}
67
+
68
+ # Integrator Module
69
+ # -------------------------------------------------------------------------
70
+ def create_trace_integrator_instance(self, *args, **kwargs):
71
+ """
72
+ Create an instance of the TraceIntegrator class.
73
+
74
+ Parameters:
75
+ *args: Positional arguments for TraceIntegrator.
76
+ **kwargs: Keyword arguments for TraceIntegrator.
77
+
78
+ Returns:
79
+ dict: Status and instance of TraceIntegrator.
80
+ """
81
+ try:
82
+ integrator = TraceIntegrator(*args, **kwargs)
83
+ return {"status": "success", "integrator": integrator}
84
+ except Exception as e:
85
+ return {"status": "error", "message": str(e)}
86
+
87
+ # Test Module
88
+ # -------------------------------------------------------------------------
89
+ def call_test_trace_function(self, *args, **kwargs):
90
+ """
91
+ Call the test_trace_function.
92
+
93
+ Parameters:
94
+ *args: Positional arguments for test_trace_function.
95
+ **kwargs: Keyword arguments for test_trace_function.
96
+
97
+ Returns:
98
+ dict: Status and result of test_trace_function.
99
+ """
100
+ try:
101
+ result = test_trace_function(*args, **kwargs)
102
+ return {"status": "success", "result": result}
103
+ except Exception as e:
104
+ return {"status": "error", "message": str(e)}
105
+
106
+ # Utility Methods
107
+ # -------------------------------------------------------------------------
108
+ def check_dependencies(self):
109
+ """
110
+ Check for the presence of required dependencies.
111
+
112
+ Returns:
113
+ dict: Status and list of missing dependencies, if any.
114
+ """
115
+ missing_dependencies = []
116
+ try:
117
+ import numpy
118
+ except ImportError:
119
+ missing_dependencies.append("numpy")
120
+ try:
121
+ import scipy
122
+ except ImportError:
123
+ missing_dependencies.append("scipy")
124
+ try:
125
+ import matplotlib
126
+ except ImportError:
127
+ missing_dependencies.append("matplotlib")
128
+ try:
129
+ import mpi4py
130
+ except ImportError:
131
+ missing_dependencies.append("mpi4py")
132
+
133
+ if missing_dependencies:
134
+ return {"status": "error", "missing_dependencies": missing_dependencies}
135
+ return {"status": "success", "message": "All dependencies are installed."}
136
+
137
+ # End of Adapter class
138
+ # -------------------------------------------------------------------------
139
+ # This adapter provides a comprehensive interface to the REBOUND library,
140
+ # ensuring all functionalities are accessible with error handling and status reporting.
rebound/mcp_output/mcp_plugin/main.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MCP Service Auto-Wrapper - Auto-generated
3
+ """
4
+ from mcp_service import create_app
5
+
6
+ def main():
7
+ """Main entry point"""
8
+ app = create_app()
9
+ return app
10
+
11
+ if __name__ == "__main__":
12
+ app = main()
13
+ app.run()
rebound/mcp_output/mcp_plugin/mcp_service.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+
4
+ # Add the local source directory to sys.path
5
+ source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
6
+ if source_path not in sys.path:
7
+ sys.path.insert(0, source_path)
8
+
9
+ from fastmcp import FastMCP
10
+ from rebound.simulation import Simulation
11
+ from rebound.particle import Particle
12
+
13
+ # Create the FastMCP service application
14
+ mcp = FastMCP("rebound_service")
15
+
16
+ @mcp.tool(name="create_simulation", description="Create a new simulation instance")
17
+ def create_simulation() -> dict:
18
+ """
19
+ Creates a new simulation instance.
20
+
21
+ Returns:
22
+ dict: A dictionary containing the success status and the simulation instance.
23
+ """
24
+ try:
25
+ sim = Simulation()
26
+ return {"success": True, "result": sim, "error": None}
27
+ except Exception as e:
28
+ return {"success": False, "result": None, "error": str(e)}
29
+
30
+ @mcp.tool(name="add_particle", description="Add a particle to the simulation")
31
+ def add_particle(sim: Simulation, mass: float, x: float, y: float, z: float, vx: float, vy: float, vz: float) -> dict:
32
+ """
33
+ Adds a particle to the given simulation.
34
+
35
+ Parameters:
36
+ sim (Simulation): The simulation instance.
37
+ mass (float): Mass of the particle.
38
+ x (float): X position.
39
+ y (float): Y position.
40
+ z (float): Z position.
41
+ vx (float): X velocity.
42
+ vy (float): Y velocity.
43
+ vz (float): Z velocity.
44
+
45
+ Returns:
46
+ dict: A dictionary containing the success status and the updated simulation.
47
+ """
48
+ try:
49
+ particle = Particle(mass=mass, x=x, y=y, z=z, vx=vx, vy=vy, vz=vz)
50
+ sim.add(particle)
51
+ return {"success": True, "result": sim, "error": None}
52
+ except Exception as e:
53
+ return {"success": False, "result": None, "error": str(e)}
54
+
55
+ @mcp.tool(name="integrate_simulation", description="Integrate the simulation over a given time")
56
+ def integrate_simulation(sim: Simulation, time: float) -> dict:
57
+ """
58
+ Integrates the simulation over the specified time.
59
+
60
+ Parameters:
61
+ sim (Simulation): The simulation instance.
62
+ time (float): The time to integrate over.
63
+
64
+ Returns:
65
+ dict: A dictionary containing the success status and the updated simulation.
66
+ """
67
+ try:
68
+ sim.integrate(time)
69
+ return {"success": True, "result": sim, "error": None}
70
+ except Exception as e:
71
+ return {"success": False, "result": None, "error": str(e)}
72
+
73
+ def create_app() -> FastMCP:
74
+ """
75
+ Creates and returns the FastMCP application instance.
76
+
77
+ Returns:
78
+ FastMCP: The FastMCP application instance.
79
+ """
80
+ return mcp
rebound/mcp_output/requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastmcp
2
+ fastapi
3
+ uvicorn[standard]
4
+ pydantic>=2.0.0
5
+ matplotlib
6
+ numpy
7
+ scipy
rebound/mcp_output/start_mcp.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ """
3
+ MCP Service Startup Entry
4
+ """
5
+ import sys
6
+ import os
7
+
8
+ project_root = os.path.dirname(os.path.abspath(__file__))
9
+ mcp_plugin_dir = os.path.join(project_root, "mcp_plugin")
10
+ if mcp_plugin_dir not in sys.path:
11
+ sys.path.insert(0, mcp_plugin_dir)
12
+
13
+ from mcp_service import create_app
14
+
15
+ def main():
16
+ """Start FastMCP service"""
17
+ app = create_app()
18
+ # Use environment variable to configure port, default 8000
19
+ port = int(os.environ.get("MCP_PORT", "8000"))
20
+
21
+ # Choose transport mode based on environment variable
22
+ transport = os.environ.get("MCP_TRANSPORT", "stdio")
23
+ if transport == "http":
24
+ app.run(transport="http", host="0.0.0.0", port=port)
25
+ else:
26
+ # Default to STDIO mode
27
+ app.run()
28
+
29
+ if __name__ == "__main__":
30
+ main()
rebound/mcp_output/workflow_summary.json ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "repository": {
3
+ "name": "rebound",
4
+ "url": "https://github.com/hannorein/rebound",
5
+ "local_path": "/export/zxcpu1/shiweijie/code/ghh/Code2MCP/workspace/rebound",
6
+ "description": "Python library",
7
+ "features": "Basic functionality",
8
+ "tech_stack": "Python",
9
+ "stars": 0,
10
+ "forks": 0,
11
+ "language": "Python",
12
+ "last_updated": "",
13
+ "complexity": "medium",
14
+ "intrusiveness_risk": "low"
15
+ },
16
+ "execution": {
17
+ "start_time": 1770205945.9813013,
18
+ "end_time": 1770206036.978772,
19
+ "duration": 90.99747085571289,
20
+ "status": "success",
21
+ "workflow_status": "success",
22
+ "nodes_executed": [
23
+ "download",
24
+ "analysis",
25
+ "env",
26
+ "generate",
27
+ "run",
28
+ "review",
29
+ "finalize"
30
+ ],
31
+ "total_files_processed": 3,
32
+ "environment_type": "unknown",
33
+ "llm_calls": 0,
34
+ "deepwiki_calls": 0
35
+ },
36
+ "tests": {
37
+ "original_project": {
38
+ "passed": false,
39
+ "details": {},
40
+ "test_coverage": "100%",
41
+ "execution_time": 0,
42
+ "test_files": []
43
+ },
44
+ "mcp_plugin": {
45
+ "passed": true,
46
+ "details": {},
47
+ "service_health": "healthy",
48
+ "startup_time": 0,
49
+ "transport_mode": "stdio",
50
+ "fastmcp_version": "unknown",
51
+ "mcp_version": "unknown"
52
+ }
53
+ },
54
+ "analysis": {
55
+ "structure": {
56
+ "packages": [
57
+ "source.rebound",
58
+ "source.rebound.integrators",
59
+ "source.rebound.tests"
60
+ ]
61
+ },
62
+ "dependencies": {
63
+ "has_environment_yml": false,
64
+ "has_requirements_txt": true,
65
+ "pyproject": true,
66
+ "setup_cfg": false,
67
+ "setup_py": true
68
+ },
69
+ "entry_points": {
70
+ "imports": [],
71
+ "cli": [],
72
+ "modules": []
73
+ },
74
+ "risk_assessment": {
75
+ "import_feasibility": 0.8,
76
+ "intrusiveness_risk": "low",
77
+ "complexity": "medium"
78
+ },
79
+ "deepwiki_analysis": {
80
+ "repo_url": "https://github.com/hannorein/rebound",
81
+ "repo_name": "rebound",
82
+ "content": "hannorein/rebound\nCore Architecture\nSimulation Engine\nParticle System\nBuild System\nPython Interface\nSimulation Class\nParticle Management\nData Sources and Units\nNumerical Integrators\nWHFast Integrator\nHybrid Integrators\nSpecialized Integrators\nVisualization\nReal-time Visualization\nStatic Plotting\nData Management\nSimulation Archives\nAnalysis Tools\nExamples and Tutorials\nBasic Examples\nPhysics Applications\nPerformance and Accuracy\nAdvanced Topics\nParallel Computing\nVariational Equations\nTesting and Validation\nchangelog.md\ndocs/index.md\ndocs/integrators.md\ndocs/mpi.md\ndocs/visualization.md\nipython_examples/Holmberg.ipynb\nipython_examples/WHFast.ipynb\nrebound/__init__.py\nrebound/integrators/trace.py\nrebound/particle.py\nrebound/simulation.py\nrebound/tests/test_trace.py\nsrc/input.c\nsrc/input.h\nsrc/integrator_ias15.c\nsrc/integrator_trace.c\nsrc/integrator_whfast.c\nsrc/output.c\nsrc/output.h\nsrc/rebound.c\nsrc/rebound.h\nsrc/tools.c\nsrc/tools.h\nupdate_version.py\nversion.txt\nweb_client/shell_rebound.html\nweb_client/shell_rebound_console.html\nweb_client/shell_rebound_webgl.html\nThis document provides a comprehensive overview of REBOUND, an open-source N-body integrator package designed for high-accuracy astronomical simulations. REBOUND enables the numerical integration of particle systems under gravitational forces, supporting applications ranging from planetary dynamics to galactic structure formation.\nFor information about specific integrators and their configuration, seeNumerical Integrators. For visualization capabilities, seeVisualization. For data management and reproducibility features, seeData Management.\nPurpose and Architecture\nREBOUND is designed as a multi-layered system combining a high-performance C computational core with accessible Python interfaces. The architecture prioritizes both computational efficiency and ease of use, enabling researchers to perform complex N-body simulations with minimal setup while maintaining the flexibility to customize integrators, force calculations, and analysis workflows.\nSystem Architecture Overview\nThe system follows a layered architecture where thereb_simulationstructure serves as the central coordination point for all simulation activities. Each simulation maintains its own particle array, integrator state, and physics configuration.\nreb_simulation\nSources:src/rebound.h489-647src/rebound.c77-185rebound/simulation.py52-94\nCore Data Structures\nREBOUND's functionality centers around two primary data structures that bridge the natural language concepts of \"simulation\" and \"particle\" with concrete code implementations:\nPython InterfaceC ImplementationConceptual LayerN-body SimulationCelestial Bodystruct reb_simulationrebound.h:489struct reb_particlerebound.h:112• t (time)• dt (timestep)• N (particle count)• integrator• x,y,z (position)• vx,vy,vz (velocity)• m (mass)• r (radius)class Simulationsimulation.py:52class Particleparticle.py:11• integrate()• add()• status()• orbital elements• coordinate access\nPython Interface\nC Implementation\nConceptual Layer\nN-body Simulation\nCelestial Body\nstruct reb_simulationrebound.h:489\nstruct reb_particlerebound.h:112\n• t (time)• dt (timestep)• N (particle count)• integrator\n• x,y,z (position)• vx,vy,vz (velocity)• m (mass)• r (radius)\nclass Simulationsimulation.py:52\nclass Particleparticle.py:11\n• integrate()• add()• status()\n• orbital elements• coordinate access\nThereb_simulationstructure contains all simulation state including time evolution parameters, particle arrays, integrator configurations, and physics settings. Thereb_particlestructure represents individual bodies with their kinematic and physical properties.\nreb_simulation\nreb_particle\nSources:src/rebound.h112-141src/rebound.h489-647rebound/simulation.py52-94rebound/particle.py11-48\nIntegration Engine\nThe heart of REBOUND is its integration engine, which advances particle positions and velocities through time using sophisticated numerical methods. The main integration loop coordinates between force calculations, integrator steps, and auxiliary operations:\nEach integrator implements thereb_integrator_part1()andreb_integrator_part2()interface, allowing for modular swapping of numerical methods. The force calculation supports both built-in gravity models and user-defined additional forces.\nreb_integrator_part1()\nreb_integrator_part2()\nSources:src/rebound.c82-185src/integrator.hsrc/gravity.c\nMemory and Data Management\nREBOUND employs dynamic memory management to handle varying particle counts and simulation complexity. The system automatically resizes internal arrays and manages integrator-specific storage:\nreb_simulation_add()\nreb_integrator_*_reset()\nreb_tree_delete()\nreb_simulation_update_tree()\nreb_simulationarchive_*()\nTheN_allocatedfields throughout the codebase track memory allocation sizes separately from active counts, enabling efficient reuse without frequent reallocation.\nN_allocated\nSources:src/rebound.h508src/particle.csrc/tree.csrc/simulationarchive.c\nBuild System and Distribution\nREBOUND supports multiple deployment scenarios through a flexible build system:\nDistribution ChannelsBuild TargetsSource OrganizationC Source Filessrc/.c, src/.hPython Modulesrebound/*.pyExample Problemsexamples/*/librebound.so/.dllShared LibraryPython Extensionctypes InterfaceStandalone C ProgramsWebGL TargetsEmscriptenpip install reboundSource Repositoryconda install reboundBrowser Examples\nDistribution Channels\nBuild Targets\nSource Organization\nC Source Filessrc/.c, src/.h\nPython Modulesrebound/*.py\nExample Problemsexamples/*/\nlibrebound.so/.dllShared Library\nPython Extensionctypes Interface\nStandalone C Programs\nWebGL TargetsEmscripten\npip install rebound\nSource Repository\nconda install rebound\nBrowser Examples\nThe build system detects platform capabilities and optimizes compilation accordingly, including AVX512 support for the WHFast512 integrator and GPU acceleration where available.\nSources:setup.py52-87Makefile entriesREADME.md51-56\nKey Features and Capabilities\nREBOUND provides a comprehensive suite of capabilities for N-body simulations:\nNumerical Integration: Multiple high-precision integrators including adaptive timestep methods (IAS15), symplectic methods (WHFast, SABA), and hybrid approaches (MERCURIUS, TRACE) for different physical scenarios.\nCoordinate Systems: Support for multiple coordinate systems including Jacobi, heliocentric, barycentric, and democratic heliocentric coordinates, with automatic transformations between systems.\nCollision Handling: Sophisticated collision detection using spatial trees or direct methods, with customizable collision resolution including merging, bouncing, and user-defined responses.\nData Reproducibility: The SimulationArchive system enables bit-perfect reproduction of simulation results through binary serialization of complete simulation state.\nVisualization: Real-time 3D visualization supporting both OpenGL (native) and WebGL (browser-based) rendering with interactive controls for simulation monitoring.\nParallelization: Support for shared-memory parallelization (OpenMP), distributed computing (MPI for specialized cases), and SIMD vectorization (AVX512 for WHFast512).\nSources:src/rebound.h1-100README.md25-44docs/integrators.md\nThis overview establishes the foundation for understanding REBOUND's architecture and capabilities. For detailed information about specific subsystems, refer to the dedicated sections on core architecture, integrators, visualization, and data management.\nRefresh this wiki\nOn this page\nPurpose and Architecture\nSystem Architecture Overview\nCore Data Structures\nIntegration Engine\nMemory and Data Management\nBuild System and Distribution\nKey Features and Capabilities",
83
+ "model": "gpt-4o-2024-08-06",
84
+ "source": "selenium",
85
+ "success": true
86
+ },
87
+ "code_complexity": {
88
+ "cyclomatic_complexity": "medium",
89
+ "cognitive_complexity": "medium",
90
+ "maintainability_index": 75
91
+ },
92
+ "security_analysis": {
93
+ "vulnerabilities_found": 0,
94
+ "security_score": 85,
95
+ "recommendations": []
96
+ }
97
+ },
98
+ "plugin_generation": {
99
+ "files_created": [
100
+ "mcp_output/start_mcp.py",
101
+ "mcp_output/mcp_plugin/__init__.py",
102
+ "mcp_output/mcp_plugin/mcp_service.py",
103
+ "mcp_output/mcp_plugin/adapter.py",
104
+ "mcp_output/mcp_plugin/main.py",
105
+ "mcp_output/requirements.txt",
106
+ "mcp_output/README_MCP.md"
107
+ ],
108
+ "main_entry": "start_mcp.py",
109
+ "requirements": [
110
+ "fastmcp>=0.1.0",
111
+ "pydantic>=2.0.0"
112
+ ],
113
+ "readme_path": "/export/zxcpu1/shiweijie/code/ghh/Code2MCP/workspace/rebound/mcp_output/README_MCP.md",
114
+ "adapter_mode": "import",
115
+ "total_lines_of_code": 0,
116
+ "generated_files_size": 0,
117
+ "tool_endpoints": 0,
118
+ "supported_features": [
119
+ "Basic functionality"
120
+ ],
121
+ "generated_tools": [
122
+ "Basic tools",
123
+ "Health check tools",
124
+ "Version info tools"
125
+ ]
126
+ },
127
+ "code_review": {},
128
+ "errors": [],
129
+ "warnings": [],
130
+ "recommendations": [
131
+ "Improve test coverage by adding more unit tests for critical modules",
132
+ "streamline the build process by consolidating configuration files",
133
+ "enhance documentation with more detailed examples and tutorials",
134
+ "optimize performance by profiling and refactoring computationally intensive functions",
135
+ "implement continuous integration to automate testing and deployment",
136
+ "improve dependency management by using a single configuration file",
137
+ "enhance code readability by adhering to consistent coding standards",
138
+ "increase community engagement by addressing open issues and pull requests",
139
+ "explore opportunities for parallelization to improve simulation speed",
140
+ "ensure compatibility with the latest versions of dependencies."
141
+ ],
142
+ "performance_metrics": {
143
+ "memory_usage_mb": 0,
144
+ "cpu_usage_percent": 0,
145
+ "response_time_ms": 0,
146
+ "throughput_requests_per_second": 0
147
+ },
148
+ "deployment_info": {
149
+ "supported_platforms": [
150
+ "Linux",
151
+ "Windows",
152
+ "macOS"
153
+ ],
154
+ "python_versions": [
155
+ "3.8",
156
+ "3.9",
157
+ "3.10",
158
+ "3.11",
159
+ "3.12"
160
+ ],
161
+ "deployment_methods": [
162
+ "Docker",
163
+ "pip",
164
+ "conda"
165
+ ],
166
+ "monitoring_support": true,
167
+ "logging_configuration": "structured"
168
+ },
169
+ "execution_analysis": {
170
+ "success_factors": [
171
+ "Comprehensive workflow execution with all nodes successfully completed",
172
+ "Efficient processing of repository with medium complexity and low intrusiveness risk"
173
+ ],
174
+ "failure_reasons": [],
175
+ "overall_assessment": "excellent",
176
+ "node_performance": {
177
+ "download_time": "Efficient download process, completed without issues",
178
+ "analysis_time": "Completed successfully, providing detailed insights into the repository structure and dependencies",
179
+ "generation_time": "Code generation was successful, with all necessary files created",
180
+ "test_time": "MCP plugin tests passed successfully, although original project tests did not run"
181
+ },
182
+ "resource_usage": {
183
+ "memory_efficiency": "Memory usage was not explicitly measured, but no issues reported",
184
+ "cpu_efficiency": "CPU usage was not explicitly measured, but no issues reported",
185
+ "disk_usage": "Disk usage was efficient, with generated files size being minimal"
186
+ }
187
+ },
188
+ "technical_quality": {
189
+ "code_quality_score": 85,
190
+ "architecture_score": 80,
191
+ "performance_score": 75,
192
+ "maintainability_score": 75,
193
+ "security_score": 85,
194
+ "scalability_score": 80
195
+ }
196
+ }
rebound/source/LICENSE ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
622
+
623
+ How to Apply These Terms to Your New Programs
624
+
625
+ If you develop a new program, and you want it to be of the greatest
626
+ possible use to the public, the best way to achieve this is to make it
627
+ free software which everyone can redistribute and change under these terms.
628
+
629
+ To do so, attach the following notices to the program. It is safest
630
+ to attach them to the start of each source file to most effectively
631
+ state the exclusion of warranty; and each file should have at least
632
+ the "copyright" line and a pointer to where the full notice is found.
633
+
634
+ <one line to give the program's name and a brief idea of what it does.>
635
+ Copyright (C) <year> <name of author>
636
+
637
+ This program is free software: you can redistribute it and/or modify
638
+ it under the terms of the GNU General Public License as published by
639
+ the Free Software Foundation, either version 3 of the License, or
640
+ (at your option) any later version.
641
+
642
+ This program is distributed in the hope that it will be useful,
643
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
+ GNU General Public License for more details.
646
+
647
+ You should have received a copy of the GNU General Public License
648
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
649
+
650
+ Also add information on how to contact you by electronic and paper mail.
651
+
652
+ If the program does terminal interaction, make it output a short
653
+ notice like this when it starts in an interactive mode:
654
+
655
+ <program> Copyright (C) <year> <name of author>
656
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+ This is free software, and you are welcome to redistribute it
658
+ under certain conditions; type `show c' for details.
659
+
660
+ The hypothetical commands `show w' and `show c' should show the appropriate
661
+ parts of the General Public License. Of course, your program's commands
662
+ might be different; for a GUI interface, you would use an "about box".
663
+
664
+ You should also get your employer (if you work as a programmer) or school,
665
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+ For more information on this, and how to apply and follow the GNU GPL, see
667
+ <http://www.gnu.org/licenses/>.
668
+
669
+ The GNU General Public License does not permit incorporating your program
670
+ into proprietary programs. If your program is a subroutine library, you
671
+ may consider it more useful to permit linking proprietary applications with
672
+ the library. If this is what you want to do, use the GNU Lesser General
673
+ Public License instead of this License. But first, please read
674
+ <http://www.gnu.org/philosophy/why-not-lgpl.html>.
rebound/source/MANIFEST.in ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ include src/integrator_ias15.c
2
+ include src/integrator_whfast.c
3
+ include src/integrator_whfast512.c
4
+ include src/integrator_saba.c
5
+ include src/integrator_leapfrog.c
6
+ include src/integrator_bs.c
7
+ include src/integrator_sei.c
8
+ include src/integrator_mercurius.c
9
+ include src/integrator_trace.c
10
+ include src/integrator_eos.c
11
+ include src/integrator_janus.c
12
+ include src/integrator.c
13
+ include src/gravity.c
14
+ include src/server.c
15
+ include src/frequency_analysis.c
16
+ include src/collision.c
17
+ include src/boundary.c
18
+ include src/binarydiff.c
19
+ include src/output.c
20
+ include src/input.c
21
+ include src/display.c
22
+ include src/rebound.c
23
+ include src/tools.c
24
+ include src/fmemopen.c
25
+ include src/rotations.c
26
+ include src/derivatives.c
27
+ include src/particle.c
28
+ include src/simulationarchive.c
29
+ include src/integrator_ias15.h
30
+ include src/integrator_whfast.h
31
+ include src/integrator_whfast512.h
32
+ include src/integrator_saba.h
33
+ include src/integrator_leapfrog.h
34
+ include src/integrator_bs.h
35
+ include src/integrator_sei.h
36
+ include src/integrator_mercurius.h
37
+ include src/integrator_trace.h
38
+ include src/integrator_eos.h
39
+ include src/integrator_janus.h
40
+ include src/integrator.h
41
+ include src/collision.h
42
+ include src/boundary.h
43
+ include src/gravity.h
44
+ include src/server.h
45
+ include src/frequency_analysis.h
46
+ include src/tree.h
47
+ include src/tree.c
48
+ include src/tools.h
49
+ include src/fmemopen.h
50
+ include src/rotations.h
51
+ include src/derivatives.h
52
+ include src/particle.h
53
+ include src/rebound.h
54
+ include src/input.h
55
+ include src/display.h
56
+ include src/binarydiff.h
57
+ include src/output.h
58
+ include src/simulationarchive.h
59
+ include src/transformations.h
60
+ include src/transformations.c
61
+ include README.md
62
+ include LICENSE
63
+ include version.txt
64
+ include pyproject.toml
65
+ recursive-include rebound/tests *.py
66
+ include rebound/rebound.h
rebound/source/Makefile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This Makefile compiles the shared dynamic library librebound.so
2
+ include src/Makefile.defs
3
+
4
+ librebound:
5
+ $(MAKE) -C src
6
+ @$(LINKORCOPYLIBREBOUNDMAIN)
7
+ @echo "To compile the example problems, go to a subdirectory of examples/ and execute make there."
8
+
9
+ .PHONY: pythoncopy
10
+ pythoncopy:
11
+ -cp librebound.so `python -c "import rebound; print(rebound.__libpath__)"`
12
+
13
+ all: librebound pythoncopy
14
+
15
+ clean:
16
+ $(MAKE) -C src clean
rebound/source/README.md ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [![Version](https://img.shields.io/badge/rebound-v4.5.1-green.svg?style=flat)](https://rebound.hanno-rein.de)
2
+ [![codecov](https://codecov.io/github/hannorein/rebound/graph/badge.svg?token=Zmynoi99Vl)](https://codecov.io/github/hannorein/rebound)
3
+ [![PyPI](https://badge.fury.io/py/rebound.svg)](https://badge.fury.io/py/rebound)
4
+ [![GPL](https://img.shields.io/badge/license-GPL-green.svg?style=flat)](https://github.com/hannorein/rebound/blob/main/LICENSE)
5
+ [![Paper](https://img.shields.io/badge/arXiv-1110.4876-green.svg?style=flat)](https://arxiv.org/abs/1110.4876)
6
+ [![Paper](https://img.shields.io/badge/arXiv-1409.4779-green.svg?style=flat)](https://arxiv.org/abs/1409.4779)
7
+ [![Paper](https://img.shields.io/badge/arXiv-1506.01084-green.svg?style=flat)](https://arxiv.org/abs/1506.01084)
8
+ [![Paper](https://img.shields.io/badge/arXiv-1603.03424-green.svg?style=flat)](https://arxiv.org/abs/1603.03424)
9
+ [![Paper](https://img.shields.io/badge/arXiv-1701.07423-green.svg?style=flat)](https://arxiv.org/abs/1701.07423)
10
+ [![Paper](https://img.shields.io/badge/arXiv-1704.07715-green.svg?style=flat)](https://arxiv.org/abs/1704.07715)
11
+ [![Paper](https://img.shields.io/badge/arXiv-1903.04972-green.svg?style=flat)](https://arxiv.org/abs/1903.04972)
12
+ [![Paper](https://img.shields.io/badge/arXiv-1907.11335-green.svg?style=flat)](https://arxiv.org/abs/1907.11335)
13
+ [![Docs](https://img.shields.io/badge/Documentation-green.svg?style=flat)](https://rebound.hanno-rein.de/)
14
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/hannorein/rebound/main)
15
+ [![REBOUND (C)](https://github.com/hannorein/rebound/actions/workflows/c.yml/badge.svg)](https://github.com/hannorein/rebound/actions/workflows/c.yml)
16
+ [![REBOUND (python)](https://github.com/hannorein/rebound/actions/workflows/python.yml/badge.svg)](https://github.com/hannorein/rebound/actions/workflows/python.yml)
17
+
18
+
19
+ # Welcome to REBOUND
20
+
21
+ ![REBOUND Examples](https://github.com/hannorein/rebound/raw/main/docs/img/reboundbanner.png)
22
+
23
+ REBOUND is an N-body integrator, i.e. a software package that can integrate the motion of particles under the influence of gravity. The particles can represent stars, planets, moons, ring or dust particles. REBOUND is very flexible and can be customized to accurately and efficiently solve many problems in astrophysics.
24
+
25
+ ## Features
26
+
27
+ * No dependencies on external libraries.
28
+ * Runs natively on Linux, MacOS, and Windows.
29
+ * Symplectic integrators WHFast, SEI, LEAPFROG, EOS.
30
+ * Hybrid symplectic integrators for planetary dynamics with close encounters MERCURIUS
31
+ * Hybrid reversible integrators for planetary dynamics with arbitrary close encounters TRACE
32
+ * High order symplectic integrators for integrating planetary systems SABA, WH Kernel methods.
33
+ * High accuracy non-symplectic integrator with adaptive time-stepping IAS15.
34
+ * Can integrate arbitrary user-defined ODEs that are coupled to N-body dynamics for tides, spin, etc
35
+ * Support for collisional/granular dynamics, various collision detection routines
36
+ * The computationally intensive parts of the code are written entirely in C, conforming to the ISO standard C99, and can be used as a thread-safe shared library
37
+ * Easy-to-use Python module, installation in 3 words: `pip install rebound`
38
+ * Real-time, 3D visualization, for both C and Python.
39
+ * Extensive set of example problems for both C and Python. You can run examples directly from your browser without the need to download or install anything.
40
+ * Parallelized WHFast512 integrator for super fast integrations of planetary systems with SIMD AVX512 instructions
41
+ * Parallelized with OpenMP (for shared memory systems)
42
+ * Parallelized with MPI is supported for some special use cases only (using an essential tree for gravity and collisions)
43
+ * The code is 100% open-source. All features are included in the public repository on github.
44
+
45
+ ## Try out REBOUND
46
+
47
+ You can try out REBOUND without installing it.
48
+ Simply head over to [the documentation](https://rebound.hanno-rein.de/).
49
+ All the C examples have been compiled with emscripten and can run directly in your browser.
50
+
51
+ ## One minute installation
52
+
53
+ You can install REBOUND with pip if you want to only use the python version of REBOUND:
54
+
55
+ pip install rebound
56
+
57
+ Then, you can run a simple REBOUND simulation such as
58
+
59
+ ```python
60
+ import rebound
61
+ sim = rebound.Simulation()
62
+ sim.add(m=1.0)
63
+ sim.add(m=1.0e-3, a=1.0)
64
+ sim.integrate(1000.)
65
+ sim.status()
66
+ ```
67
+
68
+ If you want to use the C version of REBOUND simply copy and paste this line into your terminal (it won't do anything bad, we promise):
69
+
70
+ ```bash
71
+ git clone https://github.com/hannorein/rebound && cd rebound/examples/shearing_sheet && make && ./rebound
72
+ ```
73
+
74
+
75
+ ## Documentation
76
+ The full documentation with many examples, changelogs and tutorials can be found at
77
+
78
+ <https://rebound.hanno-rein.de>
79
+
80
+ If you have trouble installing or using REBOUND, please open an issue on github and we'll try to help as much as we can.
81
+
82
+ There are also short YouTube videos describing various aspects of REBOUND available at https://www.youtube.com/channel/UCNmrCzxcmWVTBwtDPPLxkkw .
83
+
84
+ ## Related projects
85
+
86
+ ### Additional physics
87
+ To easily incorporate additional physics modules such as migration forces, GR effects and spin into your REBOUND simulations, see REBOUNDx at https://github.com/dtamayo/reboundx
88
+
89
+ ### Analytical and semianalytical tools
90
+ If you're interested in comparing numerical simulations to analytical and semianalytical tools for celestial mechanics, see Celmech at https://github.com/shadden/celmech
91
+
92
+ ### Ephemeris-quality integrations of test particles
93
+ To generate ephemeris-quality integrations of test particles in the Solar System with a precision on par with JPL's small body integrator, see ASSIST at https://github.com/matthewholman/assist
94
+
95
+ ## Papers
96
+
97
+ There are several papers describing the functionality of REBOUND.
98
+
99
+ 1. Rein & Liu 2012 (Astronomy and Astrophysics, Volume 537, A128) describes the code structure and the main feature including the gravity and collision routines for many particle systems. <http://adsabs.harvard.edu/abs/2012A%26A...537A.128R>
100
+
101
+ 2. Rein & Tremaine 2011 (Monthly Notices of the Royal Astronomical Society, Volume 415, Issue 4, pp. 3168-3176) describes the Symplectic Epicycle integrator for shearing sheet simulations. <https://ui.adsabs.harvard.edu/abs/2011MNRAS.415.3168R>
102
+
103
+ 3. Rein & Spiegel 2015 (Monthly Notices of the Royal Astronomical Society, Volume 446, Issue 2, p.1424-1437) describes the versatile high order integrator IAS15 which is now part of REBOUND. <http://adsabs.harvard.edu/abs/2015MNRAS.446.1424R>
104
+
105
+ 4. Rein & Tamayo 2015 (Monthly Notices of the Royal Astronomical Society, Volume 452, Issue 1, p.376-388) describes WHFast, the fast and unbiased implementation of a symplectic Wisdom-Holman integrator for long term gravitational simulations. <http://adsabs.harvard.edu/abs/2015MNRAS.452..376R>
106
+
107
+ 5. Rein & Tamayo 2016 (Monthly Notices of the Royal Astronomical Society, Volume 459, Issue 3, p.2275-2285) develop the framework for second order variational equations. <https://ui.adsabs.harvard.edu/abs/2016MNRAS.459.2275R>
108
+
109
+ 6. Rein & Tamayo 2017 (Monthly Notices of the Royal Astronomical Society, Volume 467, Issue 2, p.2377-2383) describes the Simulationarchive for exact reproducibility of N-body simulations. <https://ui.adsabs.harvard.edu/abs/2017MNRAS.467.2377R>
110
+
111
+ 7. Rein & Tamayo 2018 (Monthly Notices of the Royal Astronomical Society, Volume 473, Issue 3, p.3351–3357) describes the integer based JANUS integrator. <https://ui.adsabs.harvard.edu/abs/2018MNRAS.473.3351R>
112
+
113
+ 8. Rein, Hernandez, Tamayo, Brown, Eckels, Holmes, Lau, Leblanc & Silburt 2019 (Monthly Notices of the Royal Astronomical Society, Volume 485, Issue 4, p.5490-5497) describes the hybrid symplectic integrator MERCURIUS. <https://ui.adsabs.harvard.edu/abs/2019MNRAS.485.5490R>
114
+
115
+ 9. Rein, Tamayo & Brown 2019 (Monthly Notices of the Royal Astronomical Society, Volume 489, Issue 4, November 2019, Pages 4632-4640) describes the implementation of the high order symplectic integrators SABA, SABAC, SABACL, WHCKL, WHCKM, and WHCKC. <https://ui.adsabs.harvard.edu/abs/2019MNRAS.489.4632R/>
116
+
117
+ ## Acknowledgments
118
+
119
+ If you use this code or parts of this code for results presented in a scientific publication, we would greatly appreciate a citation.
120
+ The simplest way to find the citations relevant to the specific setup of your REBOUND simulation is:
121
+
122
+ ```python
123
+ sim = rebound.Simulation()
124
+ -your setup-
125
+ sim.cite()
126
+ ```
127
+
128
+
129
+ ## Contributors
130
+
131
+ * Hanno Rein, University of Toronto, <hanno@hanno-rein.de>
132
+ * Dan Tamayo, Harvey Mudd College, <dtamayo@hmc.edu>
133
+ * David S. Spiegel, Institute for Advanced Study Princeton, <dave@ias.edu>
134
+ * Garett Brown, University of Toronto, <garett.brown@mail.utoronto.ca>
135
+ * Shangfei Liu, Kavli Institute for Astronomy and Astrophysics at Peking University, <liushangfei@pku.edu.cn>
136
+ * Ari Silburt, Penn State University, <ajs725@psu.edu>
137
+ * and many others! Check the git history to find out who contributed to the code.
138
+
139
+ REBOUND is open source and you are invited to contribute to this project!
140
+
141
+
142
+ ## License
143
+
144
+ 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.
145
+
146
+ 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.
147
+
148
+ You should have received a copy of the GNU General Public License along with REBOUND. If not, see <http://www.gnu.org/licenses/>.
149
+
rebound/source/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ rebound Project Package Initialization File
4
+ """
rebound/source/changelog.md ADDED
@@ -0,0 +1,589 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Changelog
2
+
3
+ This changelog only includes the most important changes in recent updates. For a full log of all changes, please refer to git.
4
+
5
+ ## Version 4.x
6
+
7
+ ### Version 4.5.1
8
+ * Added leapfrog integrators of order 4, 6, and 8. Order can be set with `r->ri_leapfrog->order`.
9
+ * Heartbeat function is now also called when using `reb_simulation_steps()`.
10
+ * OrbitPlot supports more colours.
11
+ * Fixed an alignment issue when comparing binary snapshots which could have triggered a segfault.
12
+
13
+ ### Version 4.5.0
14
+ * Added support for (Frequency) Modified Fourier Transforms. Heavily based on David Nesvorny's code. The new functions are `reb_frequency_analysis()` in C and `rebound.frequency_analysis()` in python. For usage, see C examples `secular_frequencies` and `frequency_analysis` as well as the iPython notebook `FrequencyAnalysis`.
15
+ * Support for Jacobi coordinates added when using WHFast with OpenMP.
16
+ * Allow negative periods when initializing hyperbolic orbits.
17
+
18
+ ### Version 4.4.11
19
+ * The collision resolve function now returns a type `enum REB_COLLISION_RESOLVE_OUTCOME`. The actual integer values remain unchanged.
20
+ * Bug in TRACE was fixed.
21
+ * Convergence check for M_to_E function.
22
+ * New API example that shows how to use the Kepler solver without a REBOUND simulation. Updated other examples.
23
+
24
+ ### Version 4.4.10
25
+ * Version bump to rerun github workflows for pypi uploads
26
+
27
+ ### Version 4.4.9
28
+ * Fixes a bug that affected collisions searches with a tree code.
29
+ * Support for mid-timestep add/remove of particles with TRACE.
30
+ * Various small improvements and bugfixes for TRACE.
31
+ * IAS15's `adaptive_mode` is now an ENUM.
32
+ * Some OpenMP improvements.
33
+
34
+ ### Version 4.4.8
35
+ * Added support for symplectic correctors with barycentric coordinates in WHFast.
36
+
37
+ ### Version 4.4.7
38
+ * Added option to disable SSL checks for Horizon queries with `rebound.horizons.SSL_CONTEXT = 'unverified'.`
39
+ * Added unit tests.
40
+ * Added barycentric coordinates for WHFast.
41
+ * Bug fix for when MEGNO is used with adaptive timestepping.
42
+ * Added more error messages.
43
+ * Fixed various issues in documentation.
44
+
45
+ ### Version 4.4.6
46
+ * When initializing particles with "uniform" in python, REBOUND now uses its own `reb_random_uniform()` function. This avoids importing the "random" library and makes results reproducible as the random seed of the simulation is used when generating random numbers.
47
+ * More cracefull interrupt handling. REBOUND now stop the integration after the next timestep when CTRL-C is pressed the first time. If CTRL-C s pressed twice, then long loops (during gravity, collision calculations) are terminated immediately. Continuing an integration after one CTRL-C press should be easier with this change as the simulation does not get corrupted.
48
+ * Fixed typos in documentation.
49
+
50
+ ### Version 4.4.5
51
+ * Version updated to test github workflows
52
+
53
+ ### Version 4.4.4
54
+ * Fixed several memory leaks and other memory issues. It is unlikely that any of those bugs did affect an simulation.
55
+ * When converting units of a particle, the particle radius is now also converted.
56
+ * Added getter/setters for Pal coordinates to the particle structure in python. Syntax is `sim.particles[1].pal_h`, `sim.particles[1].pal_ix`, etc.
57
+
58
+ ### Version 4.4.3
59
+ * REBOUND now raises ImportError if it detects a size mismatch between the C and python Simulation structures.
60
+ * Fixes a bug in the WHFast512 synchronization on non-AVX512 systems.
61
+ * Fixes a bug in the SimulationArchive in cases where there are multiple snapshots with t=0.
62
+ * Updates TRACE switching condition to match Lu et al (2024).
63
+ * TRACE binary file size has been reduced.
64
+ * Pericenter passage time is now calculated even if particles are not in a Simulation.
65
+
66
+ ### Version 4.4.2
67
+ * Fixed bug in TRACE when adding particles.
68
+ * Added WHFast fallback for synchronizing WHFast512 simulations with `N_systems` > 1.
69
+ * Output version number used to create Simulationarchive if there is a version mismatch.
70
+ * Added C example `simulationarchive_fields` which outputs all fields in a simulationarchive for debugging purposes.
71
+
72
+ ### Version 4.4.1
73
+ * Fixed bug in TRACE for FULL PERI modes.
74
+
75
+ ### Version 4.4.0
76
+ * Added TRACE integrator. See Lu, Hernandez & Rein (2024) for details on this implementation.
77
+
78
+ ### Version 4.3.2
79
+ * No longer clipping particles and orbits in visualization.
80
+ * Added a scale to visualization. Hide by pressing `t`.
81
+ * Option to take a screenshow manually in png (WebGL) or tga (OpenGL) format by pressing `e`.
82
+ * Improved `plane` visualization mode. Now supporting hyperbolic orbits.
83
+ * Fixed a memory leak in `reb_simulation_copy`.
84
+
85
+ ### Version 4.3.1
86
+ * Added new `plane` visualization mode for orbits. Press `w` to toggle through available orbit visualization modes.
87
+ * Added python interface for screenshot API.
88
+ * Fixed an issue where no python exception was raised when a particle was added outside a simulation box.
89
+ * Renamed `past_N` to breadcrumbs in visualization module.
90
+
91
+ ### Version 4.3.0
92
+ * Take screenshots of WebGL based visualizations using the `reb_simulation_output_screenshot()` function. You need to connect one web browser to the simulation in order to take screenshots.
93
+ * Improved synchronization of visualization and simulation on Windows with mutex.
94
+ * Fixes an issue that might lead to NaN values when less than the maximum number of planets are used in WHFast512.
95
+
96
+ ### Version 4.2.0
97
+ * It is now possible to programmatically change all aspects of a REBOUND visualization. This can be used to set up default viewing options or to render animations. See the C examples in `animation_solar_system` and `animation_saturn_rings`.
98
+ * Reworked matrix operations in visualization routines to follow the Model-View-Projection paradigm.
99
+ * Fixed an issues where unit tests would fail because a binary file was not deleted.
100
+
101
+ ### Version 4.1.1
102
+ * Fixed python wheels for windows.
103
+
104
+ ### Version 4.1.0
105
+ * New visualization feature that allows you to show past particle positions and orbits (keyboard commands p, u, and i).
106
+ * After pausing a simulation, you can now advance it by a single timestep by pressing the down arrow or 50 timesteps by pressing the page down key.
107
+ * Visualization now supports scroll to zoom.
108
+ * Fixed memory leaks when using custom ODEs.
109
+ * Fixed broken links in documentations.
110
+
111
+ ### Version 4.0.3
112
+ * Default IAS15 timestepping criterion is now `adaptive_mode=2`. See Pham, Rein, and Spiegel (2024) for details. To use the old default timestepping criterion, set `adaptive_mode=1`.
113
+ * Fixed a race condition that should improve the responsiveness of web based visualizations.
114
+ * Removed the glad dependency from emscripten builds which reduces filesize and improves performance.
115
+
116
+ ### Version 4.0.2
117
+ * Fixes an issue where the default Makefiles included white spaces after the SERVER and OPENGL variable definitions. This caused the main Makefile to ignore these settings.
118
+ * Added `key_callback` function for customizing user interaction in visualizations.
119
+ * Added `simulationarchive_viewer` example.
120
+ * Included `-sGL_ENABLE_GET_PROC_ADDRESS` flag that is now needed for the latest version of emscripten.
121
+
122
+ ### Version 4.0.1
123
+ * Include missing python packages
124
+
125
+ ### Version 4.0.0
126
+ * Major API changes and new features! If you have used a previous version of REBOUND, then you will need to update your code. If you have trouble with the migration, open a GitHub issue!
127
+ * Many function and variable names have changed. They now follow a coherent naming convention. See the naming convention section in the documentation for more information.
128
+ * New visualization module! Previously, using OpenGL visualization required the GLFW library which led to problems on various operating systems. The new visualization module no longer requires ANY dependencies and is compatible with MacOS, Linux, and Windows. It works by running a local web server to which you can point your browser to. In your web browser, an emscripten compiled version of REBOUND handles the WebGL visualization while constantly updating simulation data over HTTP. You can use ssh and port forwarding to visualize simulations on remote servers. Check out the documentation for more details on this new module.
129
+ * OpenGL for all the examples has been turned off by default so that new users don't get stuck at this step. To turn on OPENGL simply change the flag in the Makefile.
130
+ * Added emscripten support. All C examples (including those using visualizations) are now automatically compiled with emscripten on readthedocs.org so you can run from within the browser. No download or installation required.
131
+ * A race condition in OpenGL visualization has been removed. Visualizations run much smoother.
132
+ * `reb_random` functions now callable with `r=NULL`. If `r=NULL` then the time and PID is used as a seed.
133
+ * Removed support for Simulationarchives with version 2. Added some additional support for reading corrupt/old archives.
134
+ * Fixed memory leak in `reb_simulation_copy`.
135
+ * Consistent integer sizes for 32/64bit. This includes padding for `reb_particle` which is stored in the Simulationarchive.
136
+
137
+
138
+ ## Version 3.x
139
+
140
+ ### Version 3.28.4
141
+ * WHFast512 now support the integration of 2 and 4 planet systems in parallel. Providing a speed up of up to 10x.
142
+ * The sqrt7 function used by IAS15 now support a wider range of input arguments.
143
+
144
+ ### Version 3.28.3
145
+ * Removed distutils requirement in preparation for python 3.12.
146
+ * Removed rebound.InterruptiblePool as it no longer works with recent python version. Updated examples.
147
+ * Added Holmberg example.
148
+ * Added `adaptive_mode==3` for IAS15 (Aarseth 1985).
149
+
150
+ ### Version 3.28.2
151
+ * Implemented own fmemopen implementation on MacOS. This is mainly to appease conda-forge builds.
152
+ * Improved sqrt7 algorithm allows larger convergence interval.
153
+
154
+ ### Version 3.28.1
155
+ * Improved support for reading old and corrupted Simulationarchives.
156
+ * Renamed `ri_ias15.epsilon_global` to `ri_ias15.adaptive_mode`.
157
+ * Added new timestep method for IAS15 `ri_ias15.adaptive_mode = 2`. This is experimental for now. Details to be described in Pham, Rein & Spiegel (in prep).
158
+ * Added unit tests to check for fused multiply add instruction (these break reproducibility).
159
+ * Added phony target in C Makefile to force rebuilding librebound whenever building examples.
160
+
161
+ ### Version 3.28.0
162
+ - Native Windows support. REBOUND can now be built natively on Windows (without WSL) using the Microsoft Visual Studio Compiler.
163
+ - Python Wheels are now provided for Linux, MacOS, and Windows. This should significantly speed up the installation process on a wide variety of systems.
164
+
165
+ ### Version 3.27.0
166
+ * 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.
167
+ * The difference between simulations can now be printed out in a human readable form. Python syntax: `sim.diff(sim2)`. C syntax: `reb_simulation_diff(sim2, sim1, 1)`.
168
+ * Reading Simulationarchives with version < 2 is no longer supported.
169
+ * 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).
170
+ * Internal changes on how Simulationarchives are written.
171
+ * Internal variable names that represent the size of allocated buffers now consistently include the name `N_allocated`.
172
+ * The TES (Terrestrial Exoplanet Integrator) has been removed. If you wish to use TES, you will need checkout an earlier version.
173
+
174
+ ### Version 3.26.3
175
+ * A few more changes to reduce the number of compiler warnings. This should not affect any calculation.
176
+
177
+ ### Version 3.26.2
178
+ * Fixed various signed/unsigned int issues. This should reduce the number of compiler warnings but not affect any calculation.
179
+
180
+ ### Version 3.26.1
181
+ * Added support for `AVX512` and `FFP_CONTRACT_OFF` environment variables when using pip to install REBOUND.
182
+
183
+ ### Version 3.26.0
184
+ * Added WHFast512 integrator (Javaheri, Rein, Tamayo 2023)
185
+
186
+ ### Version 3.25.1
187
+ * Bug fixed that prevented the installation via PyPi
188
+
189
+ ### Version 3.25.0
190
+ * MPI parts updated and unit tests added
191
+ * Fixed machine independence bug in TES.
192
+
193
+ ### Version 3.24.3
194
+ * Updated unit tests so they work on 32bit machines
195
+
196
+ ### Version 3.24.2
197
+ * Fixed bug in TES ctypes structure
198
+
199
+ ### Version 3.24.1
200
+ * Added CORS proxy for Horizons request in pyodide
201
+ * Smoother OpenGL animations when using usleep
202
+ * TES calculates orbital period automatically
203
+
204
+ ### Version 3.24.0
205
+ * Added support for Simulationarchive larger than 4 GB.
206
+ * Updated documentation for Lyapunov characteristic number.
207
+
208
+ ### Version 3.23.5
209
+ * Added new units shortcuts (year,years,massist)
210
+ * Rearranged some loops and switch statements (doesn't affect floating point numbers).
211
+
212
+ ### Version 3.23.4
213
+ * Added pyproject.toml file
214
+
215
+ ### Version 3.23.3
216
+ * Changed the way REBOUND reverses the integration direction when the sign of the timestep is inconsistent with respect to the requested final time.
217
+ * Fixes a memory leak when a tree code is used
218
+ * Fixes an issue where MERCURIUS was not bit-wise reproducible when safe mode was turned off.
219
+
220
+ ### Version 3.23.2
221
+ * Minor changes to the python side of Vec3d to make it more compatible with numpy.
222
+
223
+ ### Version 3.23.1
224
+ * Minor changes related to the REBOUND Rotations framework.
225
+
226
+ ### Version 3.23.0
227
+ * Added the REBOUND Rotations framework.
228
+ * Fixes an issue with showing an incorrect periastron location in OrbitPlot for high mass-ratio systems.
229
+ * Adds pre and post timestep calls to the ode framework.
230
+
231
+ ### Version 3.22.0
232
+ * OrbitPlot is now a class. Checkout the OrbitPlot.ipynb tutorial. This change allows for interactive plots and much faster updates to existing plots. This is great for rendering animations!
233
+
234
+ ### Version 3.21.0
235
+ * Automatic rescaling of first order variational particles has been added. This will allow you to integrate chaotic systems for longer and obtain a more accruate measure of MEGNO and the Lyapunoc exponent.
236
+ * Added `sim.stop()` / `reb_simulation_stop()` to end an integration from within the heartbeat function.
237
+
238
+ ### Version 3.20.1
239
+ * Pal coordinates have been added to the `reb_orbit` struct.
240
+
241
+ ### Version 3.20.0
242
+ * A new integrator has been added, the Terrestrial Exoplanet Simulation (TES).
243
+
244
+ ### Version 3.19.10
245
+ * Fixes another bug int he BS integrator when additional forces are used.
246
+
247
+ ### Version 3.19.9
248
+ * Two bugs fixed in the BS integrator. One was related to unitialized memory and the other to issues when the particle number changed.
249
+
250
+ ### Version 3.19.5
251
+ * Workaround for urllib support in pyodide added
252
+ * Silent warning when InterruptiblePool is not available
253
+
254
+ ### Version 3.19.4
255
+ * InterruptiblePool is optional.
256
+ * Fixed an issue that occured when switching integrators while using the Simulationarchive.
257
+ * Renamed `srand_seed` to make it user accessible.
258
+
259
+ ### Version 3.19.3
260
+ * Added several examples.
261
+ * Changed how pypi is rendering the documentation.
262
+
263
+ ### Version 3.19.2
264
+ * Fixes a bug relates to test particles of type 0 in MERCURIUS.
265
+
266
+ ### Version 3.19.1
267
+ * Some compilers seem to complain that a constant cannot be initialized from a constant. Fixed this so that REBOUND works on colaboratory.
268
+
269
+ ### Version 3.19.0
270
+ * Added a Gragg-Bulirsch-Stoer integrator (short BS for Bulirsch-Stoer). This is an adaptive integrator which uses Richardson extrapolation and the modified midpoint method to obtain solutions to ordinary differential equations. The version in REBOUND is based on the method described in Hairer, Norsett, and Wanner 1993 (see section II.9, page 224ff).
271
+ * Added the ability to integrate arbitrary ordinary differential equations with REBOUND. The ODEs can be couple to the N-body simulation. This can be used to simulate spin, tides, and other physical effects. The user-defined ODEs are integrated with the new BS integrator.
272
+
273
+ ### Version 3.18.1
274
+ * Various improvements and fixes relates to NASA Horizons: small bodies are retrieved correctly, the dates now work with fractional JD values and dates in the format YYYY-MM-DD HH:MM:SS are now supported.
275
+
276
+ ### Version 3.18.0
277
+ * Fixes an issue in the Simulationarchive that prevented REBOUND from seeing more than one snapshot. This only affected simulations with a large number of particles.
278
+
279
+ ### Version 3.17.5
280
+ * REBOUND will now uses the new HTTP API from NASA Horizons. This is significantly faster than the old telnet version. Thanks to Lukas Winkler for implementing this.
281
+
282
+ ### Version 3.17.4
283
+ * REBOUND will now attempt to recover binary files and Simulationarchives which have been corrupted. Simulations can be restarted from corrupt files and in most cases the corrupt files will fix themselves.
284
+
285
+ ### Version 3.17.3
286
+ * Allow for Horizon queries with future JD dates.
287
+
288
+ ### Version 3.17.2
289
+ * Moved some function declarations to rebound.h. This is a temporary fix for REBOUNDx.
290
+
291
+ ### Version 3.17.1
292
+ * Fixed an issue where the simulation struct in python did not match the one in C. This might have lead to unexpected behaviour in rare cases.
293
+ * Fixed various typos in the documentation
294
+ * MERCURIUS switching functions can now be set from Python. Also inluded more built-in switching functions from Hernandez (2019).
295
+
296
+ ### Version 3.17.0
297
+ * Added new 'reb_simulation_add_fmt()' function. This makes adding particles in C as easy as in python.
298
+ * Orbits can now also be initialized using the eccentric anomaly.
299
+ * Fixed an issue which prevented one loop in the gravity routine form being parallelized with OpenMP.
300
+ * Added a warning message when test particles have finite mass.
301
+ * More reliable reading of corrupt Simulationarchive files.
302
+
303
+ ### Version 3.16.0
304
+ * MERCURIUS: If encounters only involve test-particles (type 0), then the algorithm is now resetting the coordinates of all massive particles after the encounter step. This only changes the outcome at the machine precision, but it makes the trajectories of massive particles independent of the close encounter history. Thanks to Kat Deck for this feature!
305
+ * MERCURIUS: The gravity routine is now $O(0.5 \cdot N^2)$ instead of $O(N^2)$ for non-OPENMP runs. This should lead to a noticable improvement in runtime.
306
+
307
+ ### Version 3.15.0
308
+ * Orbital parameters of particles can now be changed in-place. For example: 'sim.particles[1].e += 0.1'.
309
+ * Implemented more chatty repr functions for most object. Printing REBOUND objects should now give some useful information.
310
+ * Improved support for adding/removing particle in MERCURIUS during collisions.
311
+ * REBOUND now outputs an error message when one is trying to remove a particle with a negative index.
312
+ * Small updates to the documentation.
313
+ * New ipython example added, showing how to use a python collision resolve function.
314
+
315
+ ### Version 3.14.0
316
+ * Due to a bug, WHFast was not thread-safe. It is now.
317
+ * Random number generator seed is now stored in the Simulationarchive.
318
+ This allows you to get reproducible random number even after restarting a simulation.
319
+ * Random numbers generated with the `reb_rand_*()` functions were not thread-safe.
320
+ They are thread-safe now. Note that this required an API change. All `reb_rand_*()`
321
+ functions now require the simulation structure as an argument. This is because the
322
+ random number generator seed is now stored in the simulation structure.
323
+
324
+ ### Version 3.13.2
325
+ * Correct handling of test particles in reb_transformations.
326
+ * Small bug fixes
327
+
328
+ ### Version 3.13.1
329
+ * WHFast: Fixes multiple issues with testparticles in WHFast.
330
+
331
+ ### Version 3.13.0
332
+ * IAS15: Fixes a bug which leads to a biased energy error in long term integrations with fixed timesteps (see Hernandez and Holman 2020). The old version of IAS15 can still be used for the time being by setting ri_ias15.neworder=0.
333
+ * IAS15: Does not take variational particles into account when predicting new timesteps. This should be beneficial during close encounters.
334
+ * A few improvements have been made to the Simulationarchives code including a more efficient loading procedure for large datasets.
335
+
336
+ ### Version 3.12.3
337
+ * Various small bug fixes
338
+ * Added a new function sim.cite() to automatically generate citations depending on the current simulation settings.
339
+
340
+ ### Version 3.12.2
341
+ * Various bug fixes to MERCURIUS
342
+ * Performance increase when using the BASIC Gravity Routine with OpenMP
343
+
344
+ ### Version 3.12.1
345
+ * Bug fixes to LINE and LINETREE algorithms
346
+
347
+ ### Version 3.12.0
348
+ * Added LINETREE collision search algorithm.
349
+ This algorithm uses a tree to check if any two particle trajectories overlapped during the last timestep. This
350
+ should be beneficial in large N, low density situation as it allows for much larger timesteps. A modification of the
351
+ collision resolve routine might be necessary to allow for multiple collisions of the same particle during one timestep.
352
+ This depends on the application and the default is to only allow one collision per timestep.
353
+
354
+ ### Version 3.11.1
355
+ * Added support for test particles and first-order variational particles to the Embedded Operator Splitting (EOS).
356
+ * BASIC Gravity routine changed from O(N^2) to O(0.5 N^2). This should lead to a speed-up in most cases but will break bit-wise reproducibility from earlier versions as the ordering of floating point operations has changed.
357
+
358
+ ### Version 3.11.0
359
+ * This version adds the new Embedded Operator Splitting methods from Rein (2019). See the tutorial in the ipython_examples folder for how to use them.
360
+
361
+ ### Version 3.10.2
362
+ * Updates to OrbitPlot. Includes better layout of plot and some syntax changes. See OrbitPlot documentation for the new syntax.
363
+
364
+ ### Version 3.10.1
365
+ * Small syntax changes for SABA integrator family.
366
+ * Includes high order integrators by Blanes et al. (2013).
367
+
368
+ ### Version 3.10.0
369
+ * Changes for the new version of REBOUNDx.
370
+
371
+ ### Version 3.9.0
372
+ * Added new high order symplectic integrators from Wisdom et al. (1996) and Laskar & Robutel (2001). The implementation of these integrators are discussed in Rein, Tamayo & Brown (2019).
373
+ * Implemented new bit-wise comparison functions for simulations. Python syntax is simply sim1==sim2.
374
+ * Fixed a bug in IAS15 which prevented a restarted simulation to reproduce the original simulation exactly.
375
+
376
+ ### Version 3.8.3
377
+ * Improves and fixes various issues related to variational equations and MEGNO.
378
+
379
+ ### Version 3.8.2
380
+ * Fixes a bug which resulted in duplicate snapshots in Simulationarchives when restarting simulations.
381
+
382
+ ### Version 3.8.1
383
+ * Syntax change on the python side to create a simulation from a binary file or Simulationarchive:
384
+
385
+ ```python
386
+ rebound.Simulation.from_file("test.bin") becomes rebound.Simulation("test.bin")
387
+ rebound.Simulation.from_archive("test.bin",5) becomes rebound.Simulation("test.bin",5)
388
+ ```
389
+
390
+ ### Version 3.8.0
391
+ * The hybrid integrator MERCURIUS has been completely rewritten. It can now much more easily be used in simulations where physical collisions occur. There are no more hidden particle arrays in the background, meaning adding and removing particles can occur in the same way as for other integrators. It also works reliably with any additional forces.
392
+ * The old hybrid integrator HERMES has been removed. MERCURIUS should always be equal or better in performance and accuracy.
393
+
394
+ ### Version 3.7.1
395
+ * Added getBezierPaths to Simulationarchive to allow for easy plotting of complicated trajectories. To do this, store a lot of snapshots in the Simulationarchive (several per orbit!).
396
+ * Added functionality to add, subtract, multiply and divide simulations. This might be useful when developing new algorithms, but is most likely not useful for most users.
397
+
398
+ ### Version 3.7.0
399
+ * Added a deep copy functionality: reb_simulation_copy() in C, and sim.copy() in python.
400
+ * Refactored WHFast to enable calling only certain substeps.
401
+
402
+ ### Version 3.6.8
403
+ * Added the rhill property to reb_orbit in C and the Orbit and Particle classes in Python. This parameter corresponds to the circular Hill radius of the particle: $ a (m/(3M)^{1/3}$.
404
+
405
+ ### Version 3.6.7
406
+ * Fixes an issue related to collisions and the Mercurius integrator that prevented the last_collision property to be updated.
407
+
408
+ ### Version 3.6.6
409
+ * New: Fancy plotting routine. Usage: rebound.OrbitPlot(sim, fancy=True)
410
+
411
+ ### Version 3.6.5
412
+ * One can now add particles from NASA Horizons using Julian Days. For example: sim.add("Earth", date="JD2458327.500000")
413
+
414
+ ### Version 3.6.4
415
+ * Fixes a memory leak when using the old Simulationarchive version. Thanks to Ian Rabago for reporting the issue.
416
+
417
+ ### Version 3.6.2
418
+ * Fixes a memory leak in the Simulationarchive read function.
419
+
420
+ ### Version 3.6.1
421
+ * Removed function calls to open_memstream and fmemopen which might not work on older Mac OSX versions. This only affects the internals and there are no changes to user interface.
422
+ * Minor bug fixes
423
+
424
+ ### Version 3.6.0
425
+ * Simulationarchive Version 2. With the new version of the Simulationarchive file format, you can now create snapshots of your simulations without any restrictions. You can change the number of particles, the timestep, even the integrator used during the integration. REBOUND automatically detects what has changed and only stores the differences in incremental snaphots. This reduces the filesize while keeping the format as flexible as possible. The old Simulationarchive Version 1 is still supported for now but might become deprecated in the future. All examples have been updated. As usual these are as usual good starting points for understanding the functionality and the syntax.
426
+
427
+ ### Version 3.5.12
428
+ * Added REB_COLLISION_LINE. This is a collision detection routine which serves for collisions during the last timestep, assuming that all particles travel along straight lines. This can be useful in cases where not every collision needs to be detected exactly, but the overall collision rate should be reproduced. The algorithm is O(N**2).
429
+ * Bug related to N_active and variational particles has been fixed.
430
+ * A bug where WHFast might not converge in rare cases involving negative timesteps has been fixed.
431
+
432
+ ### Version 3.5.11
433
+ * Changed default collision behaviour from hardsphere bouncing to halting the simulation. An exception is raised when using the python version. In C, you need to check the status flag after integrating the simulation.
434
+
435
+ ### Version 3.5.10
436
+ * Refactored OrbitPlot.
437
+
438
+ ### Version 3.5.9
439
+ * SIGINT handler added. Allows for garceful exit and keyboard interrupts (even from python).
440
+
441
+ ### Version 3.5.8
442
+ * WebGL widget text overlay added.
443
+
444
+ ### Version 3.5.7
445
+ * Bug fixes related to WebGL widget and ipywidgets version 6
446
+
447
+ ### Version 3.5.6
448
+ * Updated WebGL widget to work with ipywidgets version 7
449
+
450
+ ### Version 3.5.5
451
+ * Various fixed for Mercurius
452
+
453
+ ### Version 3.5.4
454
+ * Bug fix for N_active=-1 (default)
455
+
456
+ ### Version 3.5.3
457
+ * Allow for better parallelization of WHFast with OpenMP.
458
+ * Addded example of the Solar System with Testparticles.
459
+ * Made simulationarchive_append a public function (might be useful for some hacking projects).
460
+
461
+ ### Version 3.5.2
462
+ * Fixes an issue with the WebGL widget.
463
+ * Fixes an issue with external forces and MERCURIUS.
464
+
465
+ ### Version 3.5.1
466
+ * MERCURIUS is not compatible with binary files and the Simulationarchive.
467
+
468
+ ### Version 3.5.0
469
+ * The WHFast integrator now supports Jacobi coordinates (default), democratic heliocentric coordinates and WHDS coordinates. The previously separate WHFastHelio integrator has been removed. The coordinate system can now be changed by simply setting the coordinates flag in the ri_whfast struct.
470
+ * Included an experimental new integrator MERCURIUS. This is similar to the hybrid integrator in Mercury but uses WHFast and IAS15. Not ready for production yet.
471
+
472
+ ### Version 3.4.0
473
+ * Added a screenshot functionality for the WebGL ipython widget. This lets you take screenshots programmatically which is useful to create movies of simulations.
474
+
475
+ ### Version 3.3.1
476
+ * Removed the march=native compiler flag as it seems to be problematic for some OSX/Sierra compilers.
477
+
478
+ ### Version 3.3.0
479
+ * JANUS integrator added. This is a bit-wise reversible high-order symplectic integrator. At this time, it remains experimental. Details about this integrator will be published in an upcoming paper.
480
+
481
+ ### Version 3.2.4
482
+ * Changes to the WHFastHelio integrator. This integrator now uses democratic heliocentric coordinates and a Hamiltonian splitted as proposed by Hernandez and Dehnen (2017), WHDS, which splits the Hamiltonian into three parts. It has the advantage that the integrator solves the two body problem exactly. It is not compatible with symplectic correctors, this functionality has been removed for WHFastHelio. For very high accuracy integrations of stable planetary systems, the WHFast integrator in Jacobi coordinated (and potentially symplectic correctors) should be better suited.
483
+
484
+ ### Version 3.2.3
485
+ * Various minor bug fixes. Added pre-timestep modifications for REBOUNDx.
486
+
487
+ ### Version 3.2.2
488
+ * Various minor bug fixes. One related to exact_finish_time=1.
489
+
490
+ ### Version 3.2.0
491
+ * Added real-time interactive 3D visualizations using WebGL for Jupyter notebooks. This is an early release. Not everything might be working yet and new feature will be added to the widget class. To try it out, simply run `sim.widget()` in a Jupyter notebook. Note that you need to have ipywidgets installed and enabled.
492
+ * Minor changes to the Visualization backend. This should not have any consequences for users.
493
+
494
+
495
+ ### Version 3.1.1
496
+ * Now stores the first characters of the current githash in binary files. This is helpful when trying to restart simulations from a binary file and making sure one uses the same version of REBOUND than in the original run. Currently, the git hash is not automatically compared when reloading a binary file. To view the githash, use e.g. hexdump. The hash appears between the first and second zero character in the first 64 bytes of the file.
497
+
498
+ ### Version 3.1.0
499
+ * Updated visualization. REBOUND now uses a modern version of OpenGL (3.3) that allows for custom shaders and therefore better looking visualizations. However, REBOUND now requires glfw3 to compile the visualization module. If you are on a Mac, then the easiest way to install the glfw3 library is with homebrew: `brew tap homebrew/versions && brew install glfw3`. If you are on Linux, you can install it with your package manager, for example with `sudo apt-get install libglfw3-dev`.
500
+
501
+ ### Version 3.0.0
502
+ * Introducing the Simulationarchive. The Simulationarchive allows for exact (bit-by-bit) reproducibility in N-body simulations and a completely new way of analyzing simulations. See Rein&Tamayo (2017) for details.
503
+ * The binary format has changed. Binary files created with an earlier version of REBOUND can not be loaded with this version. However, future binary files will be backwards compatible from this point forward.
504
+
505
+
506
+ ## Version 2.x
507
+ ### Version 2.20.6
508
+ * Minor bug fixes in HERMES integrator and some examples.
509
+
510
+ ### Version 2.20.5
511
+ * NASA Horizons changed a telnet command. This update implements those changes and restores access to NASA Horizons from within REBOUND.
512
+
513
+ ### Version 2.20.4
514
+ * Improvements to the Kepler solver. This is typically only relevant for extremly long simulation (1e11 timesteps or more) and extremely accurate simulation with symplectic correctors and a relative energy error of less than 1e-10.
515
+
516
+ ### Version 2.20.3
517
+ * Small changes to HERMES integrator. It now has a Solar Switch Factor SSF to allow for close encounters with the central object.
518
+
519
+ ### Version 2.20.2
520
+ * Added adaptive HSF for HERMES integrator. More documentation and paper to follow.
521
+
522
+ ### Version 2.20.1
523
+ * Added symplectic correctors for WHFastHelio integrator. See Wisdom (2006).
524
+ * Improved accuracy of symplectic corrector coefficients for WHFast and WHFastHelio.
525
+
526
+ ### Version 2.20.0
527
+ * Added new WHFastHelio integrator. This integrator uses the WHFast Kepler solver, but uses democratic heliocentric coordinates (WHFast itself uses Jacobi coordinates). Heliocentric coordinates are advantages if planets swap positions.
528
+
529
+ ### Version 2.19.2
530
+ * Changes to how particle hashes are handled.
531
+
532
+ ### Version 2.19.1
533
+ * This version removes the old SWIFTER based Wisdom-Holman routine, INTEGRATOR_WH. It wasn't working correctly for a while and the WHFast (INTEGRATOR_WHFAST) should be superior in any possible case we can think of.
534
+
535
+ ### Version 2.19.0
536
+ * Added warning/error message system. This allows warning messages to be shown directly in iPython/python programs, rather than being shown on the console. To hide the warning messages, use a filter, e.g.
537
+ .. code:: python
538
+
539
+ with warnings.catch_warnings(record=True) as w:
540
+ warnings.simplefilter("always")
541
+ # Execute a command which triggers a warning message.
542
+ # The message will not show up.
543
+ * Improvements regarding the WHFast logic for hyperbolic orbis. No changes should be noticeable to users.
544
+
545
+ ### Version 2.18.9
546
+ * Added the reb_simulation_get_serialized_particle_data function for fast access to particle data via numpy array. The full syntax is explained in the documentation. Here is a short example:
547
+ .. code:: python
548
+
549
+ import numpy as np
550
+ a = np.zeros((sim.N,3),dtype="float64")
551
+ sim.serialize_particle_data(xyz=a)
552
+ print(a)
553
+
554
+
555
+ ### Version 2.18.5
556
+ * When loading a simulation from a binary file, REBOUND now checks if the version of the binary file is the same as the current version.
557
+ * When saving a simulation to a binary file, all the auxiliary arrays for IAS15 are now stored. This allows for bit-by-bit reproducibility in simulations that are making use of checkpoints.
558
+
559
+
560
+ ### Version 2.18.0
561
+ * We replaced the old HYBRID integrator with the new and better HERMES integrator. Details of the HERMES integrator will be explained in an upcoming paper Silburt et al (2016, in prep).
562
+
563
+ ### Version 2.17.0
564
+ * What used to be called ``id`` in the particle structure is now called ``hash``. This can be used to uniquely identify particles in a simulation. In many cases, one can just identify particles by their position in the particle array, e.g. using ``sim.particles[5]``. However, in cases where particles might get reordered in the particle array (e.g. when using a tree code), when particles can merge (by using the ``collision_resolve_merge`` routine), or when particles get added or removed manually.
565
+ * The syntax is as follows:
566
+ .. code:: python
567
+
568
+ sim = rebound.Simulation()
569
+ sim.add(m=1)
570
+ sim.add(m=1e-3,a=1)
571
+ # Setting a hash using a string:
572
+ sim.particles[1].hash = "planet1"
573
+ # Finding a particle using a string:
574
+ p = sim.get_particle_by_hash("planet1")
575
+ # Setting a random unique hash:
576
+ sim.particles[1].hash = sim.generate_unique_hash()
577
+ # Save unique hash to find particle later
578
+ uhash = sim.particles[1].hash
579
+ # Find particle using the hash
580
+ p = sim.get_particle_by_hash(uhash)
581
+
582
+
583
+
584
+ ### Version 2.0.0
585
+ * We made many changes to the code. Most importantly, REBOUND is now thread-safe and does not use global variables anymore. All the variables that were previously global, are now contained in the ``reb_simulation`` structure. This has many advantages, for example, you can run separate simulations in parallel from within one process.
586
+ * We also made it possible to choose all modules at runtime (compared to the selection in the ``Makefile`` that was used before). This is much more in line with standard UNIX coding practice and does not severely impact performance (it might even help making REBOUND a tiny bit faster). This makes REBOUND a fully functional shared library. We added a prefix to all public functions and struct definitions: ``reb_``.
587
+ * There are still some features that haven't been fully ported. Most importantly, the MPI parallelization and the SWEEP collision detection routine.
588
+ * The best way to get an idea of the changes we made is to look at some of the example problems and the new REBOUND documentation. If you have trouble using the new version or find a bug, please submit an issue or a pull request on github.
589
+
rebound/source/docs/addingparticles.md ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adding particles
2
+
3
+ ![type:video](https://www.youtube.com/embed/FoTwDtAeJyk)
4
+
5
+ Once you've created a [simulation object](simulation.md), you can add particles to it.
6
+ REBOUND supports several different ways to do that.
7
+ Also check out the [discussion on particle operators](particleoperators.md).
8
+
9
+ ## Adding particles manually
10
+ One way to add a particle to a simulation is to first manually create a particle object, then calling a function to add the particle to the simulation.
11
+ Because the function will make a copy of the particle, you can safely delete the original particle object after you've added it to a simulation.
12
+ The following code shows an example on how to add particles this way:
13
+
14
+ === "C"
15
+ ```c
16
+ struct reb_simulation* r = reb_simulation_create();
17
+ struct reb_particle p = {0};
18
+ p.m = 1.;
19
+ p.x = 1.;
20
+ reb_simulation_add(r, p);
21
+ ```
22
+ !!! Important
23
+ The `= {0}` syntax above ensures that the struct is initialized with zeros.
24
+ Otherwise, you need to set every member of the struct to ensure that there are no
25
+ uninitialized values.
26
+
27
+
28
+ === "Python"
29
+ ```python
30
+ sim = rebound.Simulation()
31
+ p = rebound.Particle()
32
+ p.m = 1.
33
+ p.x = 1.
34
+ sim.add(p)
35
+ ```
36
+
37
+ You can also use orbital parameters to initialize the particle object.
38
+ === "C"
39
+ In C, this is done by calling the `reb_particle_from_orbit` function. Its arguments are gravitational constant, primary object, mass, semi-major axis, eccentricity, inclination, longitude of ascending node, argument of pericenter, and true anomaly.
40
+ It returns an initialized particle object which you can then add to the simulation.
41
+ ```c
42
+ struct reb_simulation* r = reb_simulation_create();
43
+ struct reb_particle primary = {0};
44
+ primary.m = 1;
45
+ reb_simulation_add(r, primary);
46
+ struct reb_particle planet = reb_particle_from_orbit(r->G, primary, 1e-3, 1., 0., 0., 0., 0., 0.);
47
+ reb_simulation_add(r, planet);
48
+ ```
49
+
50
+ You can also the coordinates described by [Pal 2009](https://ui.adsabs.harvard.edu/abs/2009MNRAS.396.1737P/abstract) to initialize orbits using the following function:
51
+
52
+ ```c
53
+ 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);
54
+ ```
55
+ Here, `lambda` is the longitude, `h` is $e\cos(\omega)$, `k` is $e\sin(\omega)$, `ix` and `iy` are the x and y components of the inclination respectively.
56
+
57
+ === "Python"
58
+ In python, you can create and initialize particles using the constructor of the `Particle` class.
59
+ ```python
60
+ sim = rebound.Simulation()
61
+ primary = rebound.Particle(m=1., x=1.)
62
+ sim.add(primary)
63
+ ```
64
+ If you want to use orbital parameters, you need to pass the primary and the simulation to the constructor:
65
+ ```python
66
+ planet = rebound.Particle(simulation=sim, primary=primary, m=1e-3, a=1., e=0.1)
67
+ ```
68
+ You can use any combination of orbital parameters that makes physically sense.
69
+ See [the discussion on orbital elements](orbitalelements.md) for more details.
70
+
71
+ !!! Note
72
+ In most cases you can simply use the convience function described below.
73
+ This way you don't have to create a particle object just to add it to the simulation.
74
+
75
+ ## Convenience functions
76
+ By far the easiest way to add particles to REBOUND is to use a convenience function.
77
+ === "C"
78
+ In C, the function is called `reb_simulation_add_fmt` and has the following syntax:
79
+ ```c
80
+ void reb_simulation_add_fmt(struct reb_simulation* r, const char* fmt, ...);
81
+ ```
82
+ This is a [variadic function](https://en.cppreference.com/w/c/variadic) which takes a variable number of arguments similar to the `printf` function.
83
+ The following code shows how this function is used.
84
+ ```c
85
+ struct reb_simulation* r = reb_simulation_create();
86
+ reb_simulation_add_fmt(r, "m", 1.0); // star at origin with mass 1
87
+ reb_simulation_add_fmt(r, "m a", 1e-3, 1.0); // planet with mass 1e-3 and semi-major axis 1
88
+ reb_simulation_add_fmt(r, "m a e", 1e-3, 2.0, 0.1); // planet with mass 1e-3, semi-major axis 2, and eccentricity 0.1
89
+ reb_simulation_add_fmt(r, "m x vy", 1e-6, 1., 1.); // planet with mass 1e-6, cartesian coordinates
90
+ ```
91
+
92
+ The first argument is the simulation to which you want to add the particle.
93
+ The second argument is a format string and it determines how many other arguments the function expects.
94
+
95
+ !!! Danger
96
+ You need to pass exactly the right number of arguments to `reb_simulation_add_fmt` as indicated by your format string.
97
+ Each argument also has to be the right type (mostly double floating point numbers).
98
+ The latter is particularly important. If you call the function like this:
99
+ ```c
100
+ reb_simulation_add_fmt(r, "m a", 1, 1);
101
+ ```
102
+ then the arguments are integers, not doubles. This can lead to unexpected behaviour that is very difficult to debug.
103
+ The correct way to call the function is by making sure the arguments are doubles (by adding a `.`):
104
+ ```c
105
+ reb_simulation_add_fmt(r, "m a", 1.0, 1.0);
106
+ ```
107
+
108
+ The following parameters are supported:
109
+
110
+ Parameter | Description
111
+ --------- | -----------
112
+ `m`| mass (default: 0)
113
+ `x, y, z`| positions in Cartesian coordinates (default: 0)
114
+ `vx, vy, vz`| velocities in Cartesian coordinates (default: 0)
115
+ `primary`| primary body for converting orbital elements to cartesian (default: center of mass of the particles in the passed simulation, i.e., this will yield Jacobi coordinates as one progressively adds particles)
116
+ `a`| semi-major axis (a or P required if passing orbital elements)
117
+ `P`| orbital period (a or P required if passing orbital elements)
118
+ `e`| eccentricity (default: 0)
119
+ `inc`| inclination (default: 0)
120
+ `Omega`| longitude of ascending node (default: 0)
121
+ `omega`| argument of pericenter (default: 0)
122
+ `pomega`| longitude of pericenter (default: 0)
123
+ `f`| true anomaly (default: 0)
124
+ `M`| mean anomaly (default: 0)
125
+ `E`| eccentric anomaly (default: 0)
126
+ `l`| mean longitude (default: 0)
127
+ `theta`| true longitude (default: 0)
128
+ `T`| time of pericenter passage
129
+ `h, k, ix, iy`| See [Pal 2009](https://ui.adsabs.harvard.edu/abs/2009MNRAS.396.1737P/abstract) for a definition (default: 0)
130
+ `r`| physical particle radius
131
+
132
+ You can use any combination of these parameters at the same time.
133
+ If a combination is unphysical, no particle will be added and an error will be outputted.
134
+ For example, you can only specify one longitude or anomaly.
135
+
136
+ === "Python"
137
+ ```python
138
+ sim = rebound.Simulation()
139
+ sim.add(m=1) # star at origin with mass 1
140
+ sim.add(m=1e-3, a=1.) # planet with mass 1e-3 and semi-major axis 1
141
+ sim.add(m=1e-3, a=2., e=0.1) # planet with mass 1e-3, semi-major axis 2, and eccentricity 0.1
142
+ sim.add(m=1e-6, x=1., vy=1.) # planet with mass 1e-6, cartesian coordinates
143
+ ```
144
+
145
+ See [the discussion on orbital elements](orbitalelements.md) for more details.
146
+
147
+
148
+ ## Solar System planets
149
+ If you want to quickly try something out, you can use a set of initial conditions for the Solar System that come with REBOUND:
150
+
151
+ ```python
152
+ sim = rebound.Simulation()
153
+ rebound.data.add_solar_system(sim)
154
+ ```
155
+
156
+ and similarly for the outer Solar System:
157
+
158
+ ```python
159
+ sim = rebound.Simulation()
160
+ rebound.data.add_outer_solar_system(sim)
161
+ ```
162
+
163
+
164
+ This is currently only supported in python.
165
+
166
+ !!! Note
167
+ These initial conditions are intended for testing integration methods. They might not be very accurate and should not be used for detailed dynamical studies of the Solar System.
168
+
169
+
rebound/source/docs/api.md ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # REBOUND API
2
+ These pages describe the main features of REBOUND and its API.
3
+
4
+ There are two structures (*objects* in Python) which you will encounter frequently when working with REBOUND.
5
+ The first is the [Simulation structure](simulation.md) which contains all the configuration, status and particle data of one REBOUND simulation.
6
+ The second is the [Particle structure](particles.md) which represents one particle in a simulation.
7
+
8
+ REBOUND is a modular code.
9
+ You can combine different [gravity solvers](gravity.md), [collision detection algorithms](collisions.md), [boundary conditions](boundaryconditions.md), and [integration methods](integrators.md).
10
+ Not all combinations make physically sense, and not all combinations are supported.
11
+ We describe the different modules and their configuration in this section.
12
+
13
+ Also make sure to some of the other concepts documented in this section.
14
+ They will help you understand the [units](units.md) used in REBOUND, how REBOUND handles [orbital elements](orbitalelements.md), how to save and load simulations to [Simulationarchive](simulationarchive.md) files, how to use [chaos indicators](chaos.md), how to use the [browser based 3D visualization](visualization.md), and several other topics.
15
+
16
+
17
+ !!! Info
18
+ Because the C and Python versions of REBOUND are very similar, we describe both languages in one documentation.
19
+ The syntax and examples are provided in both C and Python.
20
+ Use the tabs to switch between them.
rebound/source/docs/binaryformat.md ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Binary Format
2
+
3
+ REBOUND comes with its own binary format.
4
+ The binary format allows you to store a current simulation state to a file or to memory.
5
+ The binary format is also used when you make a copy of a simulation or when you compare two simulations with each other.
6
+ The Simulationarchive is an extension of the binary format which allows you to store multiple snapshots of a simulation in one file.
7
+ This page explains the details of the binary format.
8
+ It is mainly intended for people who wish to extend the built-in REBOUND functionality.
9
+ You do not need to know those details if you're only working with binary files to save and load simulations.
10
+
11
+ REBOUND uses two structures for the binary files:
12
+
13
+ ```c
14
+ struct reb_binary_field {
15
+ uint32_t type;
16
+ uint64_t size;
17
+ };
18
+ ```
19
+
20
+ and
21
+
22
+ ```c
23
+ struct reb_simulationarchive_blob {
24
+ int32_t index;
25
+ int32_t offset_prev;
26
+ int32_t offset_next;
27
+ };
28
+ ```
29
+
30
+ !!! note
31
+ Before version 3.18, the offset datatype was `int16_t`. This caused problems for simulations with a large number of particles and has since been change to `int32_t`.
32
+
33
+ ## Binary file (one snapshot)
34
+ You create a binary file if you save a simulation
35
+ === "C"
36
+ ```c
37
+ struct reb_simulation* r = reb_simulation_create();
38
+ // ... setup simulation ...
39
+ reb_simulation_save_to_file(r, "snapshot.bin");
40
+ ```
41
+
42
+ === "Python"
43
+ ```python
44
+ sim = rebound.Simulation()
45
+ // ... setup simulation ...
46
+ sim.save_to_file("snapshot.bin")
47
+ ```
48
+ 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:
49
+
50
+ ```
51
+ reb_binary_field:
52
+ type: DT
53
+ size: 8 bytes
54
+
55
+ 8 bytes of data representing the value of DT
56
+
57
+ reb_binary_field:
58
+ type: PARTICLES
59
+ size: 128 bytes
60
+
61
+ 128 bytes of data representing the values of PARTICLES
62
+
63
+ ...
64
+
65
+ reb_binary_field:
66
+ type: END
67
+ size: 0
68
+
69
+ reb_simulationarchive_blob:
70
+ index: 0
71
+ offset_prev: 0
72
+ offset_next: 0
73
+ ```
74
+
75
+ Each of the binary fields provides the context (type and size) for the data that immediately follows the field.
76
+ The type is an integer defined in the `reb_binary_field_descriptor_list` (see below).
77
+ The last binary field of type `9999` (`end`) to indicate that the snapshot ends here.
78
+
79
+ !!! note
80
+ Before version 3.27 data was encoded using the enum `REB_BINARY_FIELD_TYPE` instead of `reb_binary_field_descriptor_list`.
81
+
82
+
83
+ ## Simulationarchive file (multiple snapshots)
84
+ The binary file above can also be interpreted as a Simulationarchive with one snapshot.
85
+ You can append many (millions!) of snapshots to a binary file.
86
+ REBOUND only stores data that has changed since the original snapshot (typically the particle data, time, etc).
87
+ This allows for a very compact file size, while still maintaining bit-wise reproducibility.
88
+
89
+ Each snapshot is separated by a `reb_simulationarchive_blob`.
90
+ The blob contains the offset to the previous and next blobs.
91
+ This allows REBOUND to quickly jump from one blob in the archive to the next.
92
+ Between the blobs are the same `reb_binary_field`s we already encountered for a binary file with one snapshot.
93
+ Thus, a Simulationarchive file with multiple snapshots looks something like this:
94
+
95
+ ```
96
+ reb_binary_field:
97
+ type: DT
98
+ size: 8 bytes
99
+
100
+ 8 bytes of data representing the value of DT
101
+
102
+ ... more reb_binary_fields ...
103
+
104
+ reb_binary_field:
105
+ type: END
106
+ size: 0
107
+
108
+ reb_simulationarchive_blob:
109
+ index: 0
110
+ offset_prev: 0
111
+ offset_next: 256 (offset to the next blob)
112
+
113
+ reb_binary_field:
114
+ type: DT
115
+ size: 8 bytes
116
+
117
+ 8 bytes of data representing the value of DT
118
+
119
+ ... more reb_binary_fields ...
120
+
121
+ reb_binary_field:
122
+ type: END
123
+ size: 0
124
+
125
+ reb_simulationarchive_blob:
126
+ index: 1
127
+ offset_prev: 256 (offset to the previous blob)
128
+ offset_next: 256 (offset to the next blob)
129
+
130
+ reb_binary_field:
131
+ type: DT
132
+ size: 8 bytes
133
+
134
+ 8 bytes of data representing the value of DT
135
+
136
+ ... more reb_binary_fields ...
137
+
138
+ reb_binary_field:
139
+ type: END
140
+ size: 0
141
+
142
+ reb_simulationarchive_blob:
143
+ index: 2
144
+ offset_prev: 256 (offset to the previous blob)
145
+ offset_next: 0
146
+ ```
147
+
148
+ 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).
149
+ If a binary file is corrupted, REBOUND attempts some magic and will recover the last snapshot which does not appear corrupted.
150
+ You will see a warning message when that happens and should proceed with caution (make a backup!).
151
+
152
+
153
+ ## Binary Field Descriptor
154
+
155
+ REBOUND maintains a list of fields it needs to input/output in order to restore a simulation.
156
+ This list is of type `struct reb_binary_field_descriptor[]` and defined in `output.c` as `reb_binary_field_descriptor_list`.
157
+ A single struct `reb_binary_field_descriptor` contains the information to input/output one REBOUND field, for example the current simulation time `t`:
158
+
159
+ ```c
160
+ struct reb_binary_field_descriptor fd_t = { 0, REB_DOUBLE, "t", offsetof(struct reb_simulation, t), 0, 0};
161
+ ```
162
+ 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.
163
+
164
+ REBOUND also supports array like fields. For example consider the `particles` field:
165
+ ```c
166
+ 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)};
167
+ ```
168
+
169
+ 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 particles. The last entry is the size of a single element. In this case, the size of one `reb_particle`.
170
+
171
+ 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`.
172
+
rebound/source/docs/boundaryconditions.md ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Boundary conditions
2
+
3
+ You can use different boundary conditions with REBOUND.
4
+
5
+ ## No boundaries
6
+ By default, REBOUND doesn't use boundary conditions.
7
+ This means particle can have arbitrary coordinates in all three dimensions (as long as they can be represented as floating point numbers).
8
+ Because this is the default setting, you don't need to do anything if you don't want boundary conditions.
9
+ Nevertheless, here is the syntax to set this manually:
10
+ === "C"
11
+ ```c
12
+ struct reb_simulation* r = reb_simulation_create();
13
+ r->boundary = REB_BOUNDARY_NONE;
14
+ ```
15
+
16
+ === "Python"
17
+ ```python
18
+ sim = rebound.Simulation()
19
+ sim.boundary = "none"
20
+ ```
21
+
22
+ ## Open
23
+ When open boundary conditions are selected, particles are removed from the simulation if they leave the simulation box.
24
+ You therefore also need to set the size of the simulation box whenever you use open boundary conditions.
25
+ The syntax is as follows:
26
+
27
+ === "C"
28
+ ```c
29
+ struct reb_simulation* r = reb_simulation_create();
30
+ reb_simulation_configure_box(r, 10., 1, 1, 1); # confine the simulation to a box of size 10
31
+ r->boundary = REB_BOUNDARY_OPEN;
32
+ ```
33
+
34
+ === "Python"
35
+ ```python
36
+ sim = rebound.Simulation()
37
+ sim.configure_box(10.) # confine the simulation to a box of size 10
38
+ sim.boundary = "open"
39
+ ```
40
+
41
+ ## Periodic
42
+ When periodic boundary conditions are uses, particles are reinserted on the opposite side if they leave a simulation box.
43
+ You can use an arbitrary number of ghost-boxes with this module.
44
+ The syntax is as follows:
45
+
46
+ === "C"
47
+ ```c
48
+ struct reb_simulation* r = reb_simulation_create();
49
+ reb_simulation_configure_box(r, 10., 1, 2, 3); # confine the simulation to a box of size 10x20x30
50
+ r->boundary = reb_boundary_periodic;
51
+ ```
52
+
53
+ === "python"
54
+ ```python
55
+ sim = rebound.simulation()
56
+ sim.configure_box(10., 1, 2, 3) # confine the simulation to a box of size 10x20x30
57
+ sim.boundary = "periodic"
58
+ ```
59
+
60
+ Ghost boxes are supported for both periodic and shear-periodic boundary conditions.
61
+ Ghost boxes can be used to allow particle collisions across boundaries and include gravitational forces from outside the box boundaries.
62
+ This is particularly useful when simulating rings and disks.
63
+ The following code sets up two rings of ghost boxes in the x and y directions.
64
+
65
+ === "C"
66
+ ```c
67
+ r->N_ghost_x = 2;
68
+ r->N_ghost_y = 2;
69
+ r->N_ghost_z = 0;
70
+ ```
71
+
72
+ === "python"
73
+ ```python
74
+ sim.N_ghost_x = 2
75
+ sim.N_ghost_y = 2
76
+ sim.N_ghost_z = 0
77
+ ```
78
+
79
+ See [Rein & Liu](https://ui.adsabs.harvard.edu/abs/2012A%26A...537A.128R/abstract) for details on the ghost box implementation.
80
+
81
+ You might encounter the `reb_vec6d` structure in various parts of the code, for example in function related to gravity calculation and collision detection.
82
+ It often contains the relative position and velocity of a ghost-box.
83
+ If there are no ghost-boxes used, then all elements of this structure will be zero.
84
+
85
+ ## Shear
86
+ ![Shearing sheet](img/shear.png)
87
+
88
+ These are shear periodic boundary conditions.
89
+ They are similar to periodic boundary conditions, but ghost-boxes are moving with constant speed, set by the shear.
90
+ This is useful when simulation a small patch in a ring or disk.
91
+ You also need to set the `OMEGA` variable in the simulation which set the epicyclic frequency.
92
+ For more information on how to setup simulations of planetary rings in REBOUND, see [Rein & Liu](https://ui.adsabs.harvard.edu/abs/2012A%26A...537A.128R/abstract).
93
+
94
+ === "C"
95
+ ```c
96
+ struct reb_simulation* r = reb_simulation_create();
97
+ reb_simulation_configure_box(r, 10., 1, 1, 1);
98
+ r->OMEGA = 1.0;
99
+ r->boundary = REB_BOUNDARY_SHEAR;
100
+ ```
101
+
102
+ === "Python"
103
+ ```python
104
+ sim = rebound.Simulation()
105
+ sim.configure_box(10.)
106
+ sim.OMEGA = 1.0
107
+ sim.boundary = "shear"
108
+ ```
rebound/source/docs/c_examples/compile_emcc.bash ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ source emsdk/emsdk_env.sh
4
+ READTHEDOCS_OUTPUT="${READTHEDOCS_OUTPUT:-.}"
5
+ OPTIMI="${1:-3}"
6
+
7
+ echo "Compiling C examples with emscripten."
8
+ echo "Output dir: $READTHEDOCS_OUTPUT"
9
+ echo ""
10
+
11
+ for dir in examples/*/
12
+ do
13
+ echo "Working on $dir ..."
14
+ mpi_enabled=$(cat $dir/Makefile | grep -c "export MPI=1")
15
+ openmp_enabled=$(cat $dir/Makefile | grep -c "export OPENMP=1")
16
+ server_used=$(cat $dir/problem.c | grep -c "reb_simulation_start_server")
17
+ if [ $mpi_enabled -eq 0 ] && [ $openmp_enabled -eq 0 ]; then
18
+ mkdir -p $READTHEDOCS_OUTPUT/html/emscripten_c_$dir/
19
+ echo "Compiling... "
20
+ if [ $server_used -eq 0 ]; then
21
+ emcc -O$OPTIMI -Isrc/ src/*.c $dir/problem.c -DSERVERHIDEWARNING -sSTACK_SIZE=655360 -s -sASYNCIFY -sALLOW_MEMORY_GROWTH -sEXPORTED_RUNTIME_METHODS="callMain" --shell-file web_client/shell_rebound_console.html -o $READTHEDOCS_OUTPUT/html/emscripten_c_$dir/index.html || exit 1
22
+ else
23
+ emcc -O$OPTIMI -Isrc/ src/*.c $dir/problem.c -DSERVERHIDEWARNING -DOPENGL=1 -sSTACK_SIZE=655360 -s USE_GLFW=3 -s FULL_ES3=1 -sASYNCIFY -sALLOW_MEMORY_GROWTH -sEXPORTED_RUNTIME_METHODS="callMain" --shell-file web_client/shell_rebound_webgl.html -o $READTHEDOCS_OUTPUT/html/emscripten_c_$dir/index.html || exit 1
24
+ fi
25
+ echo "Done. "
26
+ else
27
+ echo "Skipping."
28
+ fi
29
+ echo ""
30
+
31
+ done
rebound/source/docs/c_examples/generate_c_examples.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ import glob
3
+
4
+ # C Example update
5
+ def run(*args, **kwargs):
6
+ print("Generating C examples.")
7
+ count = 0
8
+ for problemc in glob.glob("examples/*/problem.c"):
9
+ count += 1
10
+ cname = problemc.split("/")[1]
11
+ with open("docs/c_examples/"+cname+".md","w") as fd:
12
+ will_output = 0
13
+ livepreview=1
14
+ # Manual exception for file viewer
15
+ if "_viewer" in cname:
16
+ livepreview=0
17
+ if "screenshots" in cname:
18
+ livepreview=0
19
+ try:
20
+ with open("examples/"+cname+"/Makefile","r") as mfd:
21
+ Makefile = mfd.read()
22
+ if "export MPI=1" in Makefile:
23
+ livepreview=0
24
+ if "export OPENMP=1" in Makefile:
25
+ livepreview=0
26
+ except:
27
+ print("Warning: Makefile error in "+problemc)
28
+
29
+ with open(problemc) as pf:
30
+ did_output=0
31
+ empty_lines = 0
32
+ for line in pf:
33
+ if line[0:3] == "/**":
34
+ will_output += 1
35
+ if line[0:3] == " */":
36
+ will_output = -1
37
+ line = ""
38
+ fd.write("\n\n```c\n")
39
+ if will_output>1:
40
+ if will_output == 2:
41
+ line = " # "+line[3:].strip() + " (C)\n"
42
+ if livepreview == 1:
43
+ line += "!!! example \"Try it out this example!\"\n"
44
+ line += " REBOUND has been compiled with emscripten to WebAssembly.\n"
45
+ line += " This lets you run this example interactively from within your browser at almost native speed.\n"
46
+ line += " No installation is required.\n"
47
+ line += " [Click here](../../emscripten_c_examples/"+cname+"/) to try it out.\n"
48
+ will_output = 2
49
+ if len(line[3:].strip())==0:
50
+ fd.write("\n\n"+line[3:].strip())
51
+ else:
52
+ fd.write(line[3:].strip() + " " )
53
+ if will_output==-1:
54
+ fd.write("" +line.rstrip() + "\n" )
55
+ did_output = 1
56
+ if will_output>0:
57
+ will_output += 1
58
+ fd.write("```\n")
59
+ fd.write("\n\nThis example is located in the directory `examples/"+problemc.split("/")[1]+"`\n\n")
60
+ if did_output==0:
61
+ print("Warning: Did not find description in "+problemc)
62
+ print("Converted %d C examples."%count)
63
+ if __name__ == "__main__":
64
+ run()
rebound/source/docs/c_outputfunctions.md ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # C output functions
2
+
3
+ The functions listed here provide various output functionality.
4
+
5
+ ## Output check
6
+
7
+ ```c
8
+ int reb_simulation_output_check(struct reb_simulation* r, double interval);
9
+ ```
10
+
11
+ This function can be used to trigger outputs at regular time intervals.
12
+ The function returns 1 if an output is required and 0 otherwise.
13
+ Typically, you would use this within the heartbeat function to generate equally spaced outputs as in this example:
14
+
15
+ ```c
16
+ void heartbeat(struct reb_simulation* const r){
17
+ if (reb_simulation_output_check(r, 100.)){
18
+ printf("t = %f\n", r->t); // Will print current time every 100 time units.
19
+ }
20
+ }
21
+ ```
22
+
23
+ ## Timing
24
+
25
+ ```c
26
+ void reb_simulation_output_timing(struct reb_simulation* r, const double tmax);
27
+ ```
28
+
29
+ This function outputs various status information on the screen. An example output looks as follows
30
+
31
+ ```
32
+ N_tot= 10 t= 4610.00 dt= 4.000 cpu= 0.002472 [s] t/tmax= 0.01%
33
+ ```
34
+
35
+ It shows the number of particles, the current time and time-step, as well as the time since the last output. If `tmax` is non-zero, then the last number indicates how far the simulation has progressed.
36
+
37
+ ## ASCII orbits
38
+ ```c
39
+ void reb_simulation_output_orbits(struct reb_simulation* r, char* filename);
40
+ ```
41
+ This function creates or appends an ASCII file with orbital parameters of all particles.
42
+ The orbital parameters are calculated in Jacobi coordinates.
43
+ Particles are assumed to be sorted from the inside out, the central object having index 0.
44
+ Each time the function is called N-1 rows are appended to the file with name filename.
45
+ Each row in the file corresponds to one particle and contains the following columns (tab separated):
46
+
47
+ - time
48
+ - semi-major axis
49
+ - eccentricity
50
+ - inclination
51
+ - Omega (longitude ascending node)
52
+ - omega (argument of pericenter)
53
+ - lambda (mean longitude)
54
+ - orbital period,
55
+ - f (true anomaly)
56
+
57
+ ## ASCII coordinates
58
+ ```c
59
+ void reb_simulation_output_ascii(struct reb_simulation* r, char* filename);
60
+ ```
61
+ This function creates or appends an ASCII file with the positions and velocities of all particles to an ASCII file.
62
+
63
+ ## Velocity dispersion
64
+ ```c
65
+ void reb_simulation_output_velocity_dispersion(struct reb_simulation* r, char* filename);
66
+ ```
67
+ This function creates or appends an ASCII file with the current velocity dispersion of all particles.
68
+ This is useful for ring simulations where one wants to monitor that the system has reached an equilibrium.
69
+
70
+ ## Binary snapshot
71
+ ```c
72
+ void reb_simulation_save_to_file(struct reb_simulation* r, const char* filename);
73
+ ```
74
+
75
+ These functions save the `reb_simulation` structure as a binary file.
76
+ It can be used to save the current status of a REBOUND simulation and later restart the simulation.
77
+ If the file exists, this function will append a snapshot.
78
+
rebound/source/docs/c_randomsamplingfunctions.md ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Random sampling
2
+
3
+ REBOUND includes several functions which help sampling random numbers from various distributions.
4
+ Each function takes a pointer to a `struct reb_simulation` as a first argument.
5
+ This is because the simulation structure stores the random number generator state in the member `rand_seed`.
6
+ When a simulation is created, `rand_seed` is initialized using the current time and process id.
7
+ These functions are thread safe.
8
+ The `rand_seed` variable is stored in binary files. This makes the random number generator reproducible which can be very helpful when debugging simulations that use random numbers.
9
+
10
+ The following example draws a number in the interval between 0 and $2\pi$ from a uniform distribution.
11
+ ```c
12
+ struct reb_simulation* r = reb_simulation_create();
13
+ double phi = reb_random_uniform(r, 0., 2.*M_PI);
14
+ ```
15
+
16
+ # Uniform
17
+ This function returns a uniformly distributed random variable between `min` and `max`.
18
+ ```c
19
+ double reb_random_uniform(struct reb_simulation* r, double min, double max);
20
+ ```
21
+
22
+ # Power law
23
+ This function returns a random variable drawn form a power law distribution with slope `slope` between `min` and `max`.
24
+ ```c
25
+ double reb_random_powerlaw(struct reb_simulation* r, double min, double max, double slope);
26
+ ```
27
+
28
+ # Normal
29
+ This function returns a random number drawn from a normal distribution centerd on zero and with variance `variance`.
30
+ It uses the algorithm by D.E. Knut, 1997, The Art of Computer Programming, Addison-Wesley.
31
+ ```c
32
+ double reb_random_normal(struct reb_simulation* r, double variance);
33
+ ```
34
+
35
+ # Rayleigh
36
+ This function returns a random variable drawn form a Rayleigh distribution with scale parameter `sigma`.
37
+ ```c
38
+ double reb_random_rayleigh(struct reb_simulation* r, double sigma);
39
+ ```
40
+
41
+
rebound/source/docs/changelog.md ADDED
@@ -0,0 +1,589 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Changelog
2
+
3
+ This changelog only includes the most important changes in recent updates. For a full log of all changes, please refer to git.
4
+
5
+ ## Version 4.x
6
+
7
+ ### Version 4.5.1
8
+ * Added leapfrog integrators of order 4, 6, and 8. Order can be set with `r->ri_leapfrog->order`.
9
+ * Heartbeat function is now also called when using `reb_simulation_steps()`.
10
+ * OrbitPlot supports more colours.
11
+ * Fixed an alignment issue when comparing binary snapshots which could have triggered a segfault.
12
+
13
+ ### Version 4.5.0
14
+ * Added support for (Frequency) Modified Fourier Transforms. Heavily based on David Nesvorny's code. The new functions are `reb_frequency_analysis()` in C and `rebound.frequency_analysis()` in python. For usage, see C examples `secular_frequencies` and `frequency_analysis` as well as the iPython notebook `FrequencyAnalysis`.
15
+ * Support for Jacobi coordinates added when using WHFast with OpenMP.
16
+ * Allow negative periods when initializing hyperbolic orbits.
17
+
18
+ ### Version 4.4.11
19
+ * The collision resolve function now returns a type `enum REB_COLLISION_RESOLVE_OUTCOME`. The actual integer values remain unchanged.
20
+ * Bug in TRACE was fixed.
21
+ * Convergence check for M_to_E function.
22
+ * New API example that shows how to use the Kepler solver without a REBOUND simulation. Updated other examples.
23
+
24
+ ### Version 4.4.10
25
+ * Version bump to rerun github workflows for pypi uploads
26
+
27
+ ### Version 4.4.9
28
+ * Fixes a bug that affected collisions searches with a tree code.
29
+ * Support for mid-timestep add/remove of particles with TRACE.
30
+ * Various small improvements and bugfixes for TRACE.
31
+ * IAS15's `adaptive_mode` is now an ENUM.
32
+ * Some OpenMP improvements.
33
+
34
+ ### Version 4.4.8
35
+ * Added support for symplectic correctors with barycentric coordinates in WHFast.
36
+
37
+ ### Version 4.4.7
38
+ * Added option to disable SSL checks for Horizon queries with `rebound.horizons.SSL_CONTEXT = 'unverified'.`
39
+ * Added unit tests.
40
+ * Added barycentric coordinates for WHFast.
41
+ * Bug fix for when MEGNO is used with adaptive timestepping.
42
+ * Added more error messages.
43
+ * Fixed various issues in documentation.
44
+
45
+ ### Version 4.4.6
46
+ * When initializing particles with "uniform" in python, REBOUND now uses its own `reb_random_uniform()` function. This avoids importing the "random" library and makes results reproducible as the random seed of the simulation is used when generating random numbers.
47
+ * More cracefull interrupt handling. REBOUND now stop the integration after the next timestep when CTRL-C is pressed the first time. If CTRL-C s pressed twice, then long loops (during gravity, collision calculations) are terminated immediately. Continuing an integration after one CTRL-C press should be easier with this change as the simulation does not get corrupted.
48
+ * Fixed typos in documentation.
49
+
50
+ ### Version 4.4.5
51
+ * Version updated to test github workflows
52
+
53
+ ### Version 4.4.4
54
+ * Fixed several memory leaks and other memory issues. It is unlikely that any of those bugs did affect an simulation.
55
+ * When converting units of a particle, the particle radius is now also converted.
56
+ * Added getter/setters for Pal coordinates to the particle structure in python. Syntax is `sim.particles[1].pal_h`, `sim.particles[1].pal_ix`, etc.
57
+
58
+ ### Version 4.4.3
59
+ * REBOUND now raises ImportError if it detects a size mismatch between the C and python Simulation structures.
60
+ * Fixes a bug in the WHFast512 synchronization on non-AVX512 systems.
61
+ * Fixes a bug in the SimulationArchive in cases where there are multiple snapshots with t=0.
62
+ * Updates TRACE switching condition to match Lu et al (2024).
63
+ * TRACE binary file size has been reduced.
64
+ * Pericenter passage time is now calculated even if particles are not in a Simulation.
65
+
66
+ ### Version 4.4.2
67
+ * Fixed bug in TRACE when adding particles.
68
+ * Added WHFast fallback for synchronizing WHFast512 simulations with `N_systems` > 1.
69
+ * Output version number used to create Simulationarchive if there is a version mismatch.
70
+ * Added C example `simulationarchive_fields` which outputs all fields in a simulationarchive for debugging purposes.
71
+
72
+ ### Version 4.4.1
73
+ * Fixed bug in TRACE for FULL PERI modes.
74
+
75
+ ### Version 4.4.0
76
+ * Added TRACE integrator. See Lu, Hernandez & Rein (2024) for details on this implementation.
77
+
78
+ ### Version 4.3.2
79
+ * No longer clipping particles and orbits in visualization.
80
+ * Added a scale to visualization. Hide by pressing `t`.
81
+ * Option to take a screenshow manually in png (WebGL) or tga (OpenGL) format by pressing `e`.
82
+ * Improved `plane` visualization mode. Now supporting hyperbolic orbits.
83
+ * Fixed a memory leak in `reb_simulation_copy`.
84
+
85
+ ### Version 4.3.1
86
+ * Added new `plane` visualization mode for orbits. Press `w` to toggle through available orbit visualization modes.
87
+ * Added python interface for screenshot API.
88
+ * Fixed an issue where no python exception was raised when a particle was added outside a simulation box.
89
+ * Renamed `past_N` to breadcrumbs in visualization module.
90
+
91
+ ### Version 4.3.0
92
+ * Take screenshots of WebGL based visualizations using the `reb_simulation_output_screenshot()` function. You need to connect one web browser to the simulation in order to take screenshots.
93
+ * Improved synchronization of visualization and simulation on Windows with mutex.
94
+ * Fixes an issue that might lead to NaN values when less than the maximum number of planets are used in WHFast512.
95
+
96
+ ### Version 4.2.0
97
+ * It is now possible to programmatically change all aspects of a REBOUND visualization. This can be used to set up default viewing options or to render animations. See the C examples in `animation_solar_system` and `animation_saturn_rings`.
98
+ * Reworked matrix operations in visualization routines to follow the Model-View-Projection paradigm.
99
+ * Fixed an issues where unit tests would fail because a binary file was not deleted.
100
+
101
+ ### Version 4.1.1
102
+ * Fixed python wheels for windows.
103
+
104
+ ### Version 4.1.0
105
+ * New visualization feature that allows you to show past particle positions and orbits (keyboard commands p, u, and i).
106
+ * After pausing a simulation, you can now advance it by a single timestep by pressing the down arrow or 50 timesteps by pressing the page down key.
107
+ * Visualization now supports scroll to zoom.
108
+ * Fixed memory leaks when using custom ODEs.
109
+ * Fixed broken links in documentations.
110
+
111
+ ### Version 4.0.3
112
+ * Default IAS15 timestepping criterion is now `adaptive_mode=2`. See Pham, Rein, and Spiegel (2024) for details. To use the old default timestepping criterion, set `adaptive_mode=1`.
113
+ * Fixed a race condition that should improve the responsiveness of web based visualizations.
114
+ * Removed the glad dependency from emscripten builds which reduces filesize and improves performance.
115
+
116
+ ### Version 4.0.2
117
+ * Fixes an issue where the default Makefiles included white spaces after the SERVER and OPENGL variable definitions. This caused the main Makefile to ignore these settings.
118
+ * Added `key_callback` function for customizing user interaction in visualizations.
119
+ * Added `simulationarchive_viewer` example.
120
+ * Included `-sGL_ENABLE_GET_PROC_ADDRESS` flag that is now needed for the latest version of emscripten.
121
+
122
+ ### Version 4.0.1
123
+ * Include missing python packages
124
+
125
+ ### Version 4.0.0
126
+ * Major API changes and new features! If you have used a previous version of REBOUND, then you will need to update your code. If you have trouble with the migration, open a GitHub issue!
127
+ * Many function and variable names have changed. They now follow a coherent naming convention. See the naming convention section in the documentation for more information.
128
+ * New visualization module! Previously, using OpenGL visualization required the GLFW library which led to problems on various operating systems. The new visualization module no longer requires ANY dependencies and is compatible with MacOS, Linux, and Windows. It works by running a local web server to which you can point your browser to. In your web browser, an emscripten compiled version of REBOUND handles the WebGL visualization while constantly updating simulation data over HTTP. You can use ssh and port forwarding to visualize simulations on remote servers. Check out the documentation for more details on this new module.
129
+ * OpenGL for all the examples has been turned off by default so that new users don't get stuck at this step. To turn on OPENGL simply change the flag in the Makefile.
130
+ * Added emscripten support. All C examples (including those using visualizations) are now automatically compiled with emscripten on readthedocs.org so you can run from within the browser. No download or installation required.
131
+ * A race condition in OpenGL visualization has been removed. Visualizations run much smoother.
132
+ * `reb_random` functions now callable with `r=NULL`. If `r=NULL` then the time and PID is used as a seed.
133
+ * Removed support for Simulationarchives with version 2. Added some additional support for reading corrupt/old archives.
134
+ * Fixed memory leak in `reb_simulation_copy`.
135
+ * Consistent integer sizes for 32/64bit. This includes padding for `reb_particle` which is stored in the Simulationarchive.
136
+
137
+
138
+ ## Version 3.x
139
+
140
+ ### Version 3.28.4
141
+ * WHFast512 now support the integration of 2 and 4 planet systems in parallel. Providing a speed up of up to 10x.
142
+ * The sqrt7 function used by IAS15 now support a wider range of input arguments.
143
+
144
+ ### Version 3.28.3
145
+ * Removed distutils requirement in preparation for python 3.12.
146
+ * Removed rebound.InterruptiblePool as it no longer works with recent python version. Updated examples.
147
+ * Added Holmberg example.
148
+ * Added `adaptive_mode==3` for IAS15 (Aarseth 1985).
149
+
150
+ ### Version 3.28.2
151
+ * Implemented own fmemopen implementation on MacOS. This is mainly to appease conda-forge builds.
152
+ * Improved sqrt7 algorithm allows larger convergence interval.
153
+
154
+ ### Version 3.28.1
155
+ * Improved support for reading old and corrupted Simulationarchives.
156
+ * Renamed `ri_ias15.epsilon_global` to `ri_ias15.adaptive_mode`.
157
+ * Added new timestep method for IAS15 `ri_ias15.adaptive_mode = 2`. This is experimental for now. Details to be described in Pham, Rein & Spiegel (in prep).
158
+ * Added unit tests to check for fused multiply add instruction (these break reproducibility).
159
+ * Added phony target in C Makefile to force rebuilding librebound whenever building examples.
160
+
161
+ ### Version 3.28.0
162
+ - Native Windows support. REBOUND can now be built natively on Windows (without WSL) using the Microsoft Visual Studio Compiler.
163
+ - Python Wheels are now provided for Linux, MacOS, and Windows. This should significantly speed up the installation process on a wide variety of systems.
164
+
165
+ ### Version 3.27.0
166
+ * 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.
167
+ * The difference between simulations can now be printed out in a human readable form. Python syntax: `sim.diff(sim2)`. C syntax: `reb_simulation_diff(sim2, sim1, 1)`.
168
+ * Reading Simulationarchives with version < 2 is no longer supported.
169
+ * 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).
170
+ * Internal changes on how Simulationarchives are written.
171
+ * Internal variable names that represent the size of allocated buffers now consistently include the name `N_allocated`.
172
+ * The TES (Terrestrial Exoplanet Integrator) has been removed. If you wish to use TES, you will need checkout an earlier version.
173
+
174
+ ### Version 3.26.3
175
+ * A few more changes to reduce the number of compiler warnings. This should not affect any calculation.
176
+
177
+ ### Version 3.26.2
178
+ * Fixed various signed/unsigned int issues. This should reduce the number of compiler warnings but not affect any calculation.
179
+
180
+ ### Version 3.26.1
181
+ * Added support for `AVX512` and `FFP_CONTRACT_OFF` environment variables when using pip to install REBOUND.
182
+
183
+ ### Version 3.26.0
184
+ * Added WHFast512 integrator (Javaheri, Rein, Tamayo 2023)
185
+
186
+ ### Version 3.25.1
187
+ * Bug fixed that prevented the installation via PyPi
188
+
189
+ ### Version 3.25.0
190
+ * MPI parts updated and unit tests added
191
+ * Fixed machine independence bug in TES.
192
+
193
+ ### Version 3.24.3
194
+ * Updated unit tests so they work on 32bit machines
195
+
196
+ ### Version 3.24.2
197
+ * Fixed bug in TES ctypes structure
198
+
199
+ ### Version 3.24.1
200
+ * Added CORS proxy for Horizons request in pyodide
201
+ * Smoother OpenGL animations when using usleep
202
+ * TES calculates orbital period automatically
203
+
204
+ ### Version 3.24.0
205
+ * Added support for Simulationarchive larger than 4 GB.
206
+ * Updated documentation for Lyapunov characteristic number.
207
+
208
+ ### Version 3.23.5
209
+ * Added new units shortcuts (year,years,massist)
210
+ * Rearranged some loops and switch statements (doesn't affect floating point numbers).
211
+
212
+ ### Version 3.23.4
213
+ * Added pyproject.toml file
214
+
215
+ ### Version 3.23.3
216
+ * Changed the way REBOUND reverses the integration direction when the sign of the timestep is inconsistent with respect to the requested final time.
217
+ * Fixes a memory leak when a tree code is used
218
+ * Fixes an issue where MERCURIUS was not bit-wise reproducible when safe mode was turned off.
219
+
220
+ ### Version 3.23.2
221
+ * Minor changes to the python side of Vec3d to make it more compatible with numpy.
222
+
223
+ ### Version 3.23.1
224
+ * Minor changes related to the REBOUND Rotations framework.
225
+
226
+ ### Version 3.23.0
227
+ * Added the REBOUND Rotations framework.
228
+ * Fixes an issue with showing an incorrect periastron location in OrbitPlot for high mass-ratio systems.
229
+ * Adds pre and post timestep calls to the ode framework.
230
+
231
+ ### Version 3.22.0
232
+ * OrbitPlot is now a class. Checkout the OrbitPlot.ipynb tutorial. This change allows for interactive plots and much faster updates to existing plots. This is great for rendering animations!
233
+
234
+ ### Version 3.21.0
235
+ * Automatic rescaling of first order variational particles has been added. This will allow you to integrate chaotic systems for longer and obtain a more accruate measure of MEGNO and the Lyapunoc exponent.
236
+ * Added `sim.stop()` / `reb_simulation_stop()` to end an integration from within the heartbeat function.
237
+
238
+ ### Version 3.20.1
239
+ * Pal coordinates have been added to the `reb_orbit` struct.
240
+
241
+ ### Version 3.20.0
242
+ * A new integrator has been added, the Terrestrial Exoplanet Simulation (TES).
243
+
244
+ ### Version 3.19.10
245
+ * Fixes another bug int he BS integrator when additional forces are used.
246
+
247
+ ### Version 3.19.9
248
+ * Two bugs fixed in the BS integrator. One was related to unitialized memory and the other to issues when the particle number changed.
249
+
250
+ ### Version 3.19.5
251
+ * Workaround for urllib support in pyodide added
252
+ * Silent warning when InterruptiblePool is not available
253
+
254
+ ### Version 3.19.4
255
+ * InterruptiblePool is optional.
256
+ * Fixed an issue that occured when switching integrators while using the Simulationarchive.
257
+ * Renamed `srand_seed` to make it user accessible.
258
+
259
+ ### Version 3.19.3
260
+ * Added several examples.
261
+ * Changed how pypi is rendering the documentation.
262
+
263
+ ### Version 3.19.2
264
+ * Fixes a bug relates to test particles of type 0 in MERCURIUS.
265
+
266
+ ### Version 3.19.1
267
+ * Some compilers seem to complain that a constant cannot be initialized from a constant. Fixed this so that REBOUND works on colaboratory.
268
+
269
+ ### Version 3.19.0
270
+ * Added a Gragg-Bulirsch-Stoer integrator (short BS for Bulirsch-Stoer). This is an adaptive integrator which uses Richardson extrapolation and the modified midpoint method to obtain solutions to ordinary differential equations. The version in REBOUND is based on the method described in Hairer, Norsett, and Wanner 1993 (see section II.9, page 224ff).
271
+ * Added the ability to integrate arbitrary ordinary differential equations with REBOUND. The ODEs can be couple to the N-body simulation. This can be used to simulate spin, tides, and other physical effects. The user-defined ODEs are integrated with the new BS integrator.
272
+
273
+ ### Version 3.18.1
274
+ * Various improvements and fixes relates to NASA Horizons: small bodies are retrieved correctly, the dates now work with fractional JD values and dates in the format YYYY-MM-DD HH:MM:SS are now supported.
275
+
276
+ ### Version 3.18.0
277
+ * Fixes an issue in the Simulationarchive that prevented REBOUND from seeing more than one snapshot. This only affected simulations with a large number of particles.
278
+
279
+ ### Version 3.17.5
280
+ * REBOUND will now uses the new HTTP API from NASA Horizons. This is significantly faster than the old telnet version. Thanks to Lukas Winkler for implementing this.
281
+
282
+ ### Version 3.17.4
283
+ * REBOUND will now attempt to recover binary files and Simulationarchives which have been corrupted. Simulations can be restarted from corrupt files and in most cases the corrupt files will fix themselves.
284
+
285
+ ### Version 3.17.3
286
+ * Allow for Horizon queries with future JD dates.
287
+
288
+ ### Version 3.17.2
289
+ * Moved some function declarations to rebound.h. This is a temporary fix for REBOUNDx.
290
+
291
+ ### Version 3.17.1
292
+ * Fixed an issue where the simulation struct in python did not match the one in C. This might have lead to unexpected behaviour in rare cases.
293
+ * Fixed various typos in the documentation
294
+ * MERCURIUS switching functions can now be set from Python. Also inluded more built-in switching functions from Hernandez (2019).
295
+
296
+ ### Version 3.17.0
297
+ * Added new 'reb_simulation_add_fmt()' function. This makes adding particles in C as easy as in python.
298
+ * Orbits can now also be initialized using the eccentric anomaly.
299
+ * Fixed an issue which prevented one loop in the gravity routine form being parallelized with OpenMP.
300
+ * Added a warning message when test particles have finite mass.
301
+ * More reliable reading of corrupt Simulationarchive files.
302
+
303
+ ### Version 3.16.0
304
+ * MERCURIUS: If encounters only involve test-particles (type 0), then the algorithm is now resetting the coordinates of all massive particles after the encounter step. This only changes the outcome at the machine precision, but it makes the trajectories of massive particles independent of the close encounter history. Thanks to Kat Deck for this feature!
305
+ * MERCURIUS: The gravity routine is now $O(0.5 \cdot N^2)$ instead of $O(N^2)$ for non-OPENMP runs. This should lead to a noticable improvement in runtime.
306
+
307
+ ### Version 3.15.0
308
+ * Orbital parameters of particles can now be changed in-place. For example: 'sim.particles[1].e += 0.1'.
309
+ * Implemented more chatty repr functions for most object. Printing REBOUND objects should now give some useful information.
310
+ * Improved support for adding/removing particle in MERCURIUS during collisions.
311
+ * REBOUND now outputs an error message when one is trying to remove a particle with a negative index.
312
+ * Small updates to the documentation.
313
+ * New ipython example added, showing how to use a python collision resolve function.
314
+
315
+ ### Version 3.14.0
316
+ * Due to a bug, WHFast was not thread-safe. It is now.
317
+ * Random number generator seed is now stored in the Simulationarchive.
318
+ This allows you to get reproducible random number even after restarting a simulation.
319
+ * Random numbers generated with the `reb_rand_*()` functions were not thread-safe.
320
+ They are thread-safe now. Note that this required an API change. All `reb_rand_*()`
321
+ functions now require the simulation structure as an argument. This is because the
322
+ random number generator seed is now stored in the simulation structure.
323
+
324
+ ### Version 3.13.2
325
+ * Correct handling of test particles in reb_transformations.
326
+ * Small bug fixes
327
+
328
+ ### Version 3.13.1
329
+ * WHFast: Fixes multiple issues with testparticles in WHFast.
330
+
331
+ ### Version 3.13.0
332
+ * IAS15: Fixes a bug which leads to a biased energy error in long term integrations with fixed timesteps (see Hernandez and Holman 2020). The old version of IAS15 can still be used for the time being by setting ri_ias15.neworder=0.
333
+ * IAS15: Does not take variational particles into account when predicting new timesteps. This should be beneficial during close encounters.
334
+ * A few improvements have been made to the Simulationarchives code including a more efficient loading procedure for large datasets.
335
+
336
+ ### Version 3.12.3
337
+ * Various small bug fixes
338
+ * Added a new function sim.cite() to automatically generate citations depending on the current simulation settings.
339
+
340
+ ### Version 3.12.2
341
+ * Various bug fixes to MERCURIUS
342
+ * Performance increase when using the BASIC Gravity Routine with OpenMP
343
+
344
+ ### Version 3.12.1
345
+ * Bug fixes to LINE and LINETREE algorithms
346
+
347
+ ### Version 3.12.0
348
+ * Added LINETREE collision search algorithm.
349
+ This algorithm uses a tree to check if any two particle trajectories overlapped during the last timestep. This
350
+ should be beneficial in large N, low density situation as it allows for much larger timesteps. A modification of the
351
+ collision resolve routine might be necessary to allow for multiple collisions of the same particle during one timestep.
352
+ This depends on the application and the default is to only allow one collision per timestep.
353
+
354
+ ### Version 3.11.1
355
+ * Added support for test particles and first-order variational particles to the Embedded Operator Splitting (EOS).
356
+ * BASIC Gravity routine changed from O(N^2) to O(0.5 N^2). This should lead to a speed-up in most cases but will break bit-wise reproducibility from earlier versions as the ordering of floating point operations has changed.
357
+
358
+ ### Version 3.11.0
359
+ * This version adds the new Embedded Operator Splitting methods from Rein (2019). See the tutorial in the ipython_examples folder for how to use them.
360
+
361
+ ### Version 3.10.2
362
+ * Updates to OrbitPlot. Includes better layout of plot and some syntax changes. See OrbitPlot documentation for the new syntax.
363
+
364
+ ### Version 3.10.1
365
+ * Small syntax changes for SABA integrator family.
366
+ * Includes high order integrators by Blanes et al. (2013).
367
+
368
+ ### Version 3.10.0
369
+ * Changes for the new version of REBOUNDx.
370
+
371
+ ### Version 3.9.0
372
+ * Added new high order symplectic integrators from Wisdom et al. (1996) and Laskar & Robutel (2001). The implementation of these integrators are discussed in Rein, Tamayo & Brown (2019).
373
+ * Implemented new bit-wise comparison functions for simulations. Python syntax is simply sim1==sim2.
374
+ * Fixed a bug in IAS15 which prevented a restarted simulation to reproduce the original simulation exactly.
375
+
376
+ ### Version 3.8.3
377
+ * Improves and fixes various issues related to variational equations and MEGNO.
378
+
379
+ ### Version 3.8.2
380
+ * Fixes a bug which resulted in duplicate snapshots in Simulationarchives when restarting simulations.
381
+
382
+ ### Version 3.8.1
383
+ * Syntax change on the python side to create a simulation from a binary file or Simulationarchive:
384
+
385
+ ```python
386
+ rebound.Simulation.from_file("test.bin") becomes rebound.Simulation("test.bin")
387
+ rebound.Simulation.from_archive("test.bin",5) becomes rebound.Simulation("test.bin",5)
388
+ ```
389
+
390
+ ### Version 3.8.0
391
+ * The hybrid integrator MERCURIUS has been completely rewritten. It can now much more easily be used in simulations where physical collisions occur. There are no more hidden particle arrays in the background, meaning adding and removing particles can occur in the same way as for other integrators. It also works reliably with any additional forces.
392
+ * The old hybrid integrator HERMES has been removed. MERCURIUS should always be equal or better in performance and accuracy.
393
+
394
+ ### Version 3.7.1
395
+ * Added getBezierPaths to Simulationarchive to allow for easy plotting of complicated trajectories. To do this, store a lot of snapshots in the Simulationarchive (several per orbit!).
396
+ * Added functionality to add, subtract, multiply and divide simulations. This might be useful when developing new algorithms, but is most likely not useful for most users.
397
+
398
+ ### Version 3.7.0
399
+ * Added a deep copy functionality: reb_simulation_copy() in C, and sim.copy() in python.
400
+ * Refactored WHFast to enable calling only certain substeps.
401
+
402
+ ### Version 3.6.8
403
+ * Added the rhill property to reb_orbit in C and the Orbit and Particle classes in Python. This parameter corresponds to the circular Hill radius of the particle: $ a (m/(3M)^{1/3}$.
404
+
405
+ ### Version 3.6.7
406
+ * Fixes an issue related to collisions and the Mercurius integrator that prevented the last_collision property to be updated.
407
+
408
+ ### Version 3.6.6
409
+ * New: Fancy plotting routine. Usage: rebound.OrbitPlot(sim, fancy=True)
410
+
411
+ ### Version 3.6.5
412
+ * One can now add particles from NASA Horizons using Julian Days. For example: sim.add("Earth", date="JD2458327.500000")
413
+
414
+ ### Version 3.6.4
415
+ * Fixes a memory leak when using the old Simulationarchive version. Thanks to Ian Rabago for reporting the issue.
416
+
417
+ ### Version 3.6.2
418
+ * Fixes a memory leak in the Simulationarchive read function.
419
+
420
+ ### Version 3.6.1
421
+ * Removed function calls to open_memstream and fmemopen which might not work on older Mac OSX versions. This only affects the internals and there are no changes to user interface.
422
+ * Minor bug fixes
423
+
424
+ ### Version 3.6.0
425
+ * Simulationarchive Version 2. With the new version of the Simulationarchive file format, you can now create snapshots of your simulations without any restrictions. You can change the number of particles, the timestep, even the integrator used during the integration. REBOUND automatically detects what has changed and only stores the differences in incremental snaphots. This reduces the filesize while keeping the format as flexible as possible. The old Simulationarchive Version 1 is still supported for now but might become deprecated in the future. All examples have been updated. As usual these are as usual good starting points for understanding the functionality and the syntax.
426
+
427
+ ### Version 3.5.12
428
+ * Added REB_COLLISION_LINE. This is a collision detection routine which serves for collisions during the last timestep, assuming that all particles travel along straight lines. This can be useful in cases where not every collision needs to be detected exactly, but the overall collision rate should be reproduced. The algorithm is O(N**2).
429
+ * Bug related to N_active and variational particles has been fixed.
430
+ * A bug where WHFast might not converge in rare cases involving negative timesteps has been fixed.
431
+
432
+ ### Version 3.5.11
433
+ * Changed default collision behaviour from hardsphere bouncing to halting the simulation. An exception is raised when using the python version. In C, you need to check the status flag after integrating the simulation.
434
+
435
+ ### Version 3.5.10
436
+ * Refactored OrbitPlot.
437
+
438
+ ### Version 3.5.9
439
+ * SIGINT handler added. Allows for garceful exit and keyboard interrupts (even from python).
440
+
441
+ ### Version 3.5.8
442
+ * WebGL widget text overlay added.
443
+
444
+ ### Version 3.5.7
445
+ * Bug fixes related to WebGL widget and ipywidgets version 6
446
+
447
+ ### Version 3.5.6
448
+ * Updated WebGL widget to work with ipywidgets version 7
449
+
450
+ ### Version 3.5.5
451
+ * Various fixed for Mercurius
452
+
453
+ ### Version 3.5.4
454
+ * Bug fix for N_active=-1 (default)
455
+
456
+ ### Version 3.5.3
457
+ * Allow for better parallelization of WHFast with OpenMP.
458
+ * Addded example of the Solar System with Testparticles.
459
+ * Made simulationarchive_append a public function (might be useful for some hacking projects).
460
+
461
+ ### Version 3.5.2
462
+ * Fixes an issue with the WebGL widget.
463
+ * Fixes an issue with external forces and MERCURIUS.
464
+
465
+ ### Version 3.5.1
466
+ * MERCURIUS is not compatible with binary files and the Simulationarchive.
467
+
468
+ ### Version 3.5.0
469
+ * The WHFast integrator now supports Jacobi coordinates (default), democratic heliocentric coordinates and WHDS coordinates. The previously separate WHFastHelio integrator has been removed. The coordinate system can now be changed by simply setting the coordinates flag in the ri_whfast struct.
470
+ * Included an experimental new integrator MERCURIUS. This is similar to the hybrid integrator in Mercury but uses WHFast and IAS15. Not ready for production yet.
471
+
472
+ ### Version 3.4.0
473
+ * Added a screenshot functionality for the WebGL ipython widget. This lets you take screenshots programmatically which is useful to create movies of simulations.
474
+
475
+ ### Version 3.3.1
476
+ * Removed the march=native compiler flag as it seems to be problematic for some OSX/Sierra compilers.
477
+
478
+ ### Version 3.3.0
479
+ * JANUS integrator added. This is a bit-wise reversible high-order symplectic integrator. At this time, it remains experimental. Details about this integrator will be published in an upcoming paper.
480
+
481
+ ### Version 3.2.4
482
+ * Changes to the WHFastHelio integrator. This integrator now uses democratic heliocentric coordinates and a Hamiltonian splitted as proposed by Hernandez and Dehnen (2017), WHDS, which splits the Hamiltonian into three parts. It has the advantage that the integrator solves the two body problem exactly. It is not compatible with symplectic correctors, this functionality has been removed for WHFastHelio. For very high accuracy integrations of stable planetary systems, the WHFast integrator in Jacobi coordinated (and potentially symplectic correctors) should be better suited.
483
+
484
+ ### Version 3.2.3
485
+ * Various minor bug fixes. Added pre-timestep modifications for REBOUNDx.
486
+
487
+ ### Version 3.2.2
488
+ * Various minor bug fixes. One related to exact_finish_time=1.
489
+
490
+ ### Version 3.2.0
491
+ * Added real-time interactive 3D visualizations using WebGL for Jupyter notebooks. This is an early release. Not everything might be working yet and new feature will be added to the widget class. To try it out, simply run `sim.widget()` in a Jupyter notebook. Note that you need to have ipywidgets installed and enabled.
492
+ * Minor changes to the Visualization backend. This should not have any consequences for users.
493
+
494
+
495
+ ### Version 3.1.1
496
+ * Now stores the first characters of the current githash in binary files. This is helpful when trying to restart simulations from a binary file and making sure one uses the same version of REBOUND than in the original run. Currently, the git hash is not automatically compared when reloading a binary file. To view the githash, use e.g. hexdump. The hash appears between the first and second zero character in the first 64 bytes of the file.
497
+
498
+ ### Version 3.1.0
499
+ * Updated visualization. REBOUND now uses a modern version of OpenGL (3.3) that allows for custom shaders and therefore better looking visualizations. However, REBOUND now requires glfw3 to compile the visualization module. If you are on a Mac, then the easiest way to install the glfw3 library is with homebrew: `brew tap homebrew/versions && brew install glfw3`. If you are on Linux, you can install it with your package manager, for example with `sudo apt-get install libglfw3-dev`.
500
+
501
+ ### Version 3.0.0
502
+ * Introducing the Simulationarchive. The Simulationarchive allows for exact (bit-by-bit) reproducibility in N-body simulations and a completely new way of analyzing simulations. See Rein&Tamayo (2017) for details.
503
+ * The binary format has changed. Binary files created with an earlier version of REBOUND can not be loaded with this version. However, future binary files will be backwards compatible from this point forward.
504
+
505
+
506
+ ## Version 2.x
507
+ ### Version 2.20.6
508
+ * Minor bug fixes in HERMES integrator and some examples.
509
+
510
+ ### Version 2.20.5
511
+ * NASA Horizons changed a telnet command. This update implements those changes and restores access to NASA Horizons from within REBOUND.
512
+
513
+ ### Version 2.20.4
514
+ * Improvements to the Kepler solver. This is typically only relevant for extremly long simulation (1e11 timesteps or more) and extremely accurate simulation with symplectic correctors and a relative energy error of less than 1e-10.
515
+
516
+ ### Version 2.20.3
517
+ * Small changes to HERMES integrator. It now has a Solar Switch Factor SSF to allow for close encounters with the central object.
518
+
519
+ ### Version 2.20.2
520
+ * Added adaptive HSF for HERMES integrator. More documentation and paper to follow.
521
+
522
+ ### Version 2.20.1
523
+ * Added symplectic correctors for WHFastHelio integrator. See Wisdom (2006).
524
+ * Improved accuracy of symplectic corrector coefficients for WHFast and WHFastHelio.
525
+
526
+ ### Version 2.20.0
527
+ * Added new WHFastHelio integrator. This integrator uses the WHFast Kepler solver, but uses democratic heliocentric coordinates (WHFast itself uses Jacobi coordinates). Heliocentric coordinates are advantages if planets swap positions.
528
+
529
+ ### Version 2.19.2
530
+ * Changes to how particle hashes are handled.
531
+
532
+ ### Version 2.19.1
533
+ * This version removes the old SWIFTER based Wisdom-Holman routine, INTEGRATOR_WH. It wasn't working correctly for a while and the WHFast (INTEGRATOR_WHFAST) should be superior in any possible case we can think of.
534
+
535
+ ### Version 2.19.0
536
+ * Added warning/error message system. This allows warning messages to be shown directly in iPython/python programs, rather than being shown on the console. To hide the warning messages, use a filter, e.g.
537
+ .. code:: python
538
+
539
+ with warnings.catch_warnings(record=True) as w:
540
+ warnings.simplefilter("always")
541
+ # Execute a command which triggers a warning message.
542
+ # The message will not show up.
543
+ * Improvements regarding the WHFast logic for hyperbolic orbis. No changes should be noticeable to users.
544
+
545
+ ### Version 2.18.9
546
+ * Added the reb_simulation_get_serialized_particle_data function for fast access to particle data via numpy array. The full syntax is explained in the documentation. Here is a short example:
547
+ .. code:: python
548
+
549
+ import numpy as np
550
+ a = np.zeros((sim.N,3),dtype="float64")
551
+ sim.serialize_particle_data(xyz=a)
552
+ print(a)
553
+
554
+
555
+ ### Version 2.18.5
556
+ * When loading a simulation from a binary file, REBOUND now checks if the version of the binary file is the same as the current version.
557
+ * When saving a simulation to a binary file, all the auxiliary arrays for IAS15 are now stored. This allows for bit-by-bit reproducibility in simulations that are making use of checkpoints.
558
+
559
+
560
+ ### Version 2.18.0
561
+ * We replaced the old HYBRID integrator with the new and better HERMES integrator. Details of the HERMES integrator will be explained in an upcoming paper Silburt et al (2016, in prep).
562
+
563
+ ### Version 2.17.0
564
+ * What used to be called ``id`` in the particle structure is now called ``hash``. This can be used to uniquely identify particles in a simulation. In many cases, one can just identify particles by their position in the particle array, e.g. using ``sim.particles[5]``. However, in cases where particles might get reordered in the particle array (e.g. when using a tree code), when particles can merge (by using the ``collision_resolve_merge`` routine), or when particles get added or removed manually.
565
+ * The syntax is as follows:
566
+ .. code:: python
567
+
568
+ sim = rebound.Simulation()
569
+ sim.add(m=1)
570
+ sim.add(m=1e-3,a=1)
571
+ # Setting a hash using a string:
572
+ sim.particles[1].hash = "planet1"
573
+ # Finding a particle using a string:
574
+ p = sim.get_particle_by_hash("planet1")
575
+ # Setting a random unique hash:
576
+ sim.particles[1].hash = sim.generate_unique_hash()
577
+ # Save unique hash to find particle later
578
+ uhash = sim.particles[1].hash
579
+ # Find particle using the hash
580
+ p = sim.get_particle_by_hash(uhash)
581
+
582
+
583
+
584
+ ### Version 2.0.0
585
+ * We made many changes to the code. Most importantly, REBOUND is now thread-safe and does not use global variables anymore. All the variables that were previously global, are now contained in the ``reb_simulation`` structure. This has many advantages, for example, you can run separate simulations in parallel from within one process.
586
+ * We also made it possible to choose all modules at runtime (compared to the selection in the ``Makefile`` that was used before). This is much more in line with standard UNIX coding practice and does not severely impact performance (it might even help making REBOUND a tiny bit faster). This makes REBOUND a fully functional shared library. We added a prefix to all public functions and struct definitions: ``reb_``.
587
+ * There are still some features that haven't been fully ported. Most importantly, the MPI parallelization and the SWEEP collision detection routine.
588
+ * The best way to get an idea of the changes we made is to look at some of the example problems and the new REBOUND documentation. If you have trouble using the new version or find a bug, please submit an issue or a pull request on github.
589
+
rebound/source/docs/chaos.md ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Chaos indicators
2
+ REBOUND supports different chaos indicators.
3
+ All of these make use of variational equations, but most of the complexity is hidden.
4
+
5
+ ## Initialization
6
+ If you want to use a chaos indicator in REBOUND, first add all the particles to your simulations.
7
+ Then, initialize the variational particles and MEGNO variables with
8
+ === "C"
9
+ ```c
10
+ struct reb_simulation* r = reb_simulation_create();
11
+ // ... add particles ...
12
+ reb_simulation_init_megno(r);
13
+ ```
14
+ === "Python"
15
+ ```python
16
+ sim = rebound.Simulation()
17
+ # ... add particles ...
18
+ sim.init_megno()
19
+ ```
20
+
21
+ REBOUND uses random numbers to initialize the variational particles.
22
+ The initial seed is chosen based on the current time and the process id.
23
+ This ensures the seed is different every time you run the simulation.
24
+ See the discussion on [random sampling](c_randomsamplingfunctions.md) for more details.
25
+
26
+ If you want to have reproducible result, you can specify the seed manually:
27
+ === "C"
28
+ ```c
29
+ struct reb_simulation* r = reb_simulation_create();
30
+ // ... add particles ...
31
+ reb_simulation_init_megno_seed(r, 0); // 0 is the initial seed
32
+ ```
33
+ === "Python"
34
+ ```python
35
+ sim = rebound.Simulation()
36
+ # ... add particles ...
37
+ sim.init_megno(seed=0) # 0 is the initial seed
38
+ ```
39
+ ## Accessing chaos indicators
40
+ Once you've initialized the chaos indicators, you can integrate the simulation normally.
41
+ To print out the MEGNO value or the largest Lyapunov characteristic number (LCN), use the following syntax:
42
+
43
+ === "C"
44
+ ```c
45
+ struct reb_simulation* r = reb_simulation_create();
46
+ // ... add particles ...
47
+ reb_simulation_init_megno_seed(r);
48
+ // ... integrate ...
49
+ printf("MEGNO = %f\n", reb_simulation_megno(r));
50
+ printf("LCN = %f\n", reb_simulation_lyapunov(r));
51
+ ```
52
+ === "Python"
53
+ ```python
54
+ sim = rebound.Simulation()
55
+ # ... add particles ...
56
+ sim.init_megno()
57
+ # ... integrate ...
58
+ print("MEGNO", sim.calculate_megno())
59
+ print("LCN", sim.lyapunov())
60
+ ```
61
+ !!! Note
62
+ Using chaos indicators is not always straightforward.
63
+ It can be particularly tricky to figure out how long to integrate for.
64
+ If the integration time is too short, you might not capture the Lyapunov timescale accurately.
65
+ On the other hand, if the integration time is too long, you can run into problems as well because quantities tend to grow exponentially with time in chaotic systems.
66
+
67
+ !!! Note
68
+ There are different definitions of the LCN which might differ by a factor of order unity.
69
+ Here, we're following Eq. 24 of [Cincotta and Simo (2000)](https://aas.aanda.org/articles/aas/abs/2000/20/h1686/h1686.html).
70
+
71
+ ## Re-scaling of variational equations
72
+
73
+ !!! Important
74
+ This is a new feature, first implemented in version 3.21
75
+
76
+ REBOUND will automatically re-scale first order variational equation once any coordinate of a variational particle becomes larger than $10^{100}$.
77
+ This is only possible for first order variational equations because they are linear.
78
+ It is not possible to re-scale second order equations.
79
+ For the calculation of MEGNO, all this is done behind the scenes and no user intervention is needed.
80
+ However, should you be interested in the actual value of the variational particles, for example to calculate a Lyapunov exponent manually, then you need to take the value of the `lrescale` variable into account.
81
+ This variable contains the natural logarithm of all re-scaling factors that have been applied throughout the integration to a given set of variational particles.
82
+
83
+ === "C"
84
+ ```c
85
+ struct reb_simulation* r = reb_simulation_create();
86
+ // ... add particles ...
87
+ reb_simulation_init_megno_seed(r);
88
+ // ... integrate ...
89
+ struct reb_variational_configuration* vc = &(r->var_config[0]);
90
+ double log_x = log(r->particles[vc->index].x) + vc->lrescale; // log of x coordinate of variational particle
91
+ ```
92
+ === "Python"
93
+ ```python
94
+ sim = rebound.Simulation()
95
+ # ... add particles ...
96
+ sim.init_megno()
97
+ # ... integrate ...
98
+ vc = sim.var_config[0]
99
+ log_x = vc.particles[0] + vc.lrescale // log of x coordinate of variational particle
100
+
101
+ Note that above the calculations involving the rescaling factors have been done in log space as floating point numbers cannot be used to represent a number larger than $10^{308}$.
102
+ For a more complete example, check out the [iPython Variational Equation example](ipython_examples/VariationalEquations.ipynb).
rebound/source/docs/collisions.md ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Collisions
2
+
3
+ ## Detecting collisions
4
+
5
+ REBOUND comes with several collision detection modules.
6
+ These modules check for physical collisions (the distance between two particles is closer than the sum of the radii), not close encounters.
7
+ For a collision to occur between two particles, at least one of them needs to have a finite radius and collision detection needs to be turned on (it is turned off by default).
8
+
9
+
10
+ ### No collisions
11
+ By default REBOUND does not search for collisions.
12
+ You can manually set the collision routine to NONE with the following code:
13
+ === "C"
14
+ ```c
15
+ struct reb_simulation* r = reb_simulation_create();
16
+ r->collision = REB_COLLISION_NONE;
17
+ ```
18
+
19
+ === "Python"
20
+ ```python
21
+ sim = rebound.Simulation()
22
+ sim.collision = "none"
23
+ ```
24
+
25
+ ### Direct
26
+ The direct collision detection module is a brute force collision search and scales as $O(N^2)$.
27
+ It checks for instantaneous overlaps between every particle pair.
28
+ The following code enables this module:
29
+ === "C"
30
+ ```c
31
+ struct reb_simulation* r = reb_simulation_create();
32
+ r->collision = REB_COLLISION_DIRECT;
33
+ ```
34
+
35
+ === "Python"
36
+ ```python
37
+ sim = rebound.Simulation()
38
+ sim.collision = "direct"
39
+ ```
40
+
41
+ !!! Important
42
+ This method checks for instantaneous overlaps. It does this only after each timestep.
43
+ This means that if the timestep is large enough for particles to pass completely through each other, then the collision will be missed.
44
+
45
+
46
+
47
+ ### Line
48
+ This is a brute force collision search and scales as $O(N^2)$ but compared to the direct method described above, this algorithm checks for overlapping particles during the timestep (not just at the end).
49
+ It assumes particles travelled along straight lines during the timestep and might therefore miss some collisions.
50
+
51
+ === "C"
52
+ ```c
53
+ struct reb_simulation* r = reb_simulation_create();
54
+ r->collision = REB_COLLISION_LINE;
55
+ ```
56
+
57
+ === "Python"
58
+ ```python
59
+ sim = rebound.Simulation()
60
+ sim.collision = "line"
61
+ ```
62
+
63
+ ### Tree
64
+ This method uses an oct-tree to check for overlapping particles at the end of the timestep.
65
+ When a large number of particles $N$ is used, this method scales as $O(N log(N))$, rather than $O(N^2)$ for the direct search.
66
+ Note that you need to initialize the simulation box whenever you want to use the tree.
67
+ Below is an example on how to enable the tree based collision search.
68
+
69
+ === "C"
70
+ ```c
71
+ struct reb_simulation* r = reb_simulation_create();
72
+ reb_simulation_configure_box(r, 10, 1, 1, 1); # confine the simulation to a box of size 10
73
+ r->collision = REB_COLLISION_TREE;
74
+ ```
75
+
76
+ === "Python"
77
+ ```python
78
+ sim = rebound.Simulation()
79
+ sim.configure_box(10) # confine the simulation to a box of size 10
80
+ sim.collision = "tree"
81
+ ```
82
+
83
+
84
+ ### Linetree
85
+ Similar to the tree method, this method also uses an oct-tree and has a scaling of $O(N log(N))$.
86
+ It checks for overlapping trajectories during the last timestep, not only for overlapping particles at the end of the timestep.
87
+ It might still miss some collisions because it assumes that particles travel along straight lines.
88
+
89
+
90
+ Below is an example on how to enable the line-tree collision search.
91
+
92
+ === "C"
93
+ ```c
94
+ struct reb_simulation* r = reb_simulation_create();
95
+ reb_simulation_configure_box(r, 10, 1, 1, 1); # confine the simulation to a box of size 10
96
+ r->collision = REB_COLLISION_LINETREE;
97
+ ```
98
+
99
+ === "Python"
100
+ ```python
101
+ sim = rebound.Simulation()
102
+ sim.configure_box(10) # confine the simulation to a box of size 10
103
+ sim.collision = "linetree"
104
+ ```
105
+
106
+ ## Resolving collisions
107
+
108
+ Once a collision has been detected, you have a choice on what to do next.
109
+ You might just want to merge particles, let them bounce off each other, or simply keep a log of all collisions that occurred.
110
+
111
+ REBOUND comes with several built-in collision resolve functions.
112
+ You can also write your own.
113
+
114
+ Internally this functionality is implemented using a [function pointer](https://www.cprogramming.com/tutorial/function-pointers.html).
115
+ You can set this pointer to a function that should be called when a collision occurs, whether it be a built-in function or your own.
116
+
117
+ ### Halt
118
+
119
+ This function resolves a collision by simply halting the integration and setting the `status` flag in the simulation to `REB_STATUS_COLLISION`.
120
+ In python this will raise the `Collision` exception.
121
+ This is the default.
122
+ It can also be set manually using the following syntax:
123
+
124
+ === "C"
125
+ ```c
126
+ struct reb_simulation* r = reb_simulation_create();
127
+ r->collision = REB_COLLISION_DIRECT;
128
+ r->collision_resolve = reb_collision_resolve_halt;
129
+ ```
130
+
131
+ === "Python"
132
+ ```python
133
+ sim = rebound.Simulation()
134
+ sim.collision = "direct"
135
+ sim.collision_resolve = "halt"
136
+ ```
137
+
138
+ ### Hard-sphere
139
+
140
+ This assumes a hard-sphere collision and uses the `coefficient_of_restitution` function pointer in `struct reb_simulation` to determine coefficient of restitution which can be velocity dependent
141
+ It conserves momentum and mass.
142
+ Depending on the coefficient of restitution, it also conserves energy.
143
+
144
+ The following example shows how to set up a hard-sphere collision resolve function and a direct collision detection routine.
145
+
146
+ === "C"
147
+ ```c
148
+ double coefficient_of_restitution_constant(const struct reb_simulation* const r, double v){
149
+ // v is the normal impact velocity.
150
+ // Here, we just use a constant coefficient of restitution
151
+ return 0.5;
152
+ }
153
+ struct reb_simulation* r = reb_simulation_create();
154
+ r->collision = REB_COLLISION_DIRECT;
155
+ r->coefficient_of_restitution = coefficient_of_restitution_constant;
156
+ r->collision_resolve = reb_collision_resolve_hardsphere;
157
+ ```
158
+
159
+ === "Python"
160
+ ```python
161
+ def coefficient_of_restitution_constant(r, v):
162
+ # v is the normal impact velocity.
163
+ # Here, we just use a constant coefficient of restitution
164
+ return 0.5
165
+ sim = rebound.Simulation()
166
+ sim.collision = "direct"
167
+ sim.coefficient_of_restitution = coefficient_of_restitution_constant
168
+ sim.collision_resolve = "hardsphere"
169
+ ```
170
+
171
+
172
+ ### Merge
173
+
174
+ This function merges the two colliding particles.
175
+ It conserves mass, momentum and volume, but not energy.
176
+ The particle with the higher index will be removed.
177
+
178
+ The following example shows how to set up a hard-sphere collision resolve function and a direct collision detection routine.
179
+
180
+ === "C"
181
+ ```c
182
+ struct reb_simulation* r = reb_simulation_create();
183
+ r->collision = REB_COLLISION_DIRECT;
184
+ r->collision_resolve = reb_collision_resolve_merge;
185
+ ```
186
+
187
+ === "Python"
188
+ ```python
189
+ sim = rebound.Simulation()
190
+ sim.collision = "direct"
191
+ sim.collision_resolve = "merge"
192
+ ```
193
+
194
+ ### Custom function
195
+ You can write your own collision resolve function.
196
+ In your function, you can update the properties of the particles involved in the collision.
197
+ The return value of your function (of type `enum REB_COLLISION_RESOLVE_OUTCOME`) determines if a particle gets removed.
198
+
199
+ - `REB_COLLISION_RESOLVE_OUTCOME_REMOVE_NONE` or `0`: don't remove either particle from the simulation
200
+ - `REB_COLLISION_RESOLVE_OUTCOME_REMOVE_P1` or `1`: remove the first particle (`p1`) from the simulation
201
+ - `REB_COLLISION_RESOLVE_OUTCOME_REMOVE_P2` or `2`: remove the second particle (`p2`) from the simulation
202
+ - `REB_COLLISION_RESOLVE_OUTCOME_REMOVE_BOTH` or `3`: remove both particles from the simulation
203
+
204
+ Here is a short example on how to write a simple custom collision resolve function:
205
+
206
+ === "C"
207
+ ```c
208
+ enum REB_COLLISION_RESOLVE_OUTCOME collision_print_only(struct reb_simulation* const r, struct reb_collision c){
209
+ printf("%f\t", r->p);
210
+ printf("%f\t", r->particles[c.p1].x); // x position of particle 1
211
+ printf("%f\n", r->particles[c.p2].x); // x position of particle 2
212
+ return REB_COLLISION_RESOLVE_OUTCOME_REMOVE_NONE; // Don't remove either particle
213
+ }
214
+
215
+ int main(int argc, char* argv[]){
216
+ struct reb_simulation* r = reb_simulation_create();
217
+ r->collision = REB_COLLISION_DIRECT;
218
+ r->collision_resolve = collision_print_only;
219
+ }
220
+ ```
221
+
222
+ === "Python"
223
+ ```python
224
+ def collision_print_only(sim_pointer, collision):
225
+ sim = sim_pointer.contents # get simulation object from pointer
226
+ print(sim.t) # print time
227
+ print(sim.particles[collision.p1].x) # x position of particle 1
228
+ print(sim.particles[collision.p2].x) # x position of particle 2
229
+ return 0 # Don't remove either particle
230
+
231
+ sim = rebound.Simulation()
232
+ sim.collision = "direct"
233
+ sim.collision_resolve = collision_print_only
234
+ ```
235
+ The first argument of the collision resolve function is a pointer to the simulation.
236
+ The second argument is a `reb_collision` structure.
237
+ It contains information about which particles are involved in the collision and, for periodic or shear-periodic [boundary conditions](boundaryconditions.md), if the collision occurred across a boundary:
238
+
239
+ `int p1`
240
+ : Index corresponding to one of the colliding particles
241
+
242
+ `int p2`
243
+ : Index corresponding to one of the colliding particles
244
+
245
+ `struct reb_vec6d gb`
246
+ : Shift of particle p1 due to a collision across periodic and shearing sheet boundaries. All entries are zero if a normal collision occurs.
rebound/source/docs/examples.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Examples in REBOUND
2
+ We provide a lot of examples for REBOUND. We think examples are the easiest way to learn how to use REBOUND.
3
+ This page contains a list of all examples that come with REBOUND.
4
+ The examples are sorted by topic.
5
+ Note that some examples use the C version, other the python version of REBOUND.
6
+ Often, the syntax is very similar and you might want to look at the C examples even if you want to write python code and vice verse.
7
+ !!! Info
8
+ You can find the source code for all examples in the `examples/` and `ipython_examples/` directories.
9
+
rebound/source/docs/generate_python_docs.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import rebound
2
+ import inspect
3
+ import docstring_to_markdown
4
+ def convert_code_blocks(doc):
5
+ new_doc = ""
6
+ lines = doc.split("\n")
7
+ first = True
8
+ for line in lines:
9
+ if first:
10
+ if line[:3]==">>>":
11
+ first = False
12
+ new_doc += "```python\n"
13
+ new_doc += line[3:]+"\n"
14
+ else:
15
+ new_doc += line+"\n"
16
+ else:
17
+ if line[:3]==">>>":
18
+ new_doc += line[3:]+"\n"
19
+ else:
20
+ new_doc += "```\n"
21
+ new_doc += line+"\n"
22
+ first = True
23
+ if first==False:
24
+ new_doc += "```\n"
25
+
26
+ return new_doc
27
+
28
+ def render_class(cls, functions=None):
29
+ d = "## Class `"+cls+"`\n"
30
+ d += convert_code_blocks(inspect.cleandoc(eval(cls).__doc__))
31
+ for function in functions:
32
+ f = getattr(eval(cls),function)
33
+ d += "## Function `"+cls+"."+function+"`\n"
34
+ d += convert_code_blocks(inspect.cleandoc(f.__doc__))
35
+
36
+ return d
37
+
38
+ print(render_class("rebound.Simulation",["copy"]))
39
+
rebound/source/docs/gravity.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gravity solvers
2
+
3
+ ## Basic
4
+ `REB_GRAVITY_BASIC`
5
+
6
+ The basic gravity routine works is the default. It works in most cases.
7
+ It uses direct summation to calculate gravitational forces between all particle pairs.
8
+ OpenMP parallelization is implemented. If OpenMP is turned on, the scaling is $O(N^2)$, otherwise, it is $O(\frac12 N^2)$, where $N$ is the number of particles.
9
+
10
+ ## Compensated
11
+ `REB_GRAVITY_COMPENSATED`
12
+
13
+ This routine also uses direct summation but in addition makes use of compensated summation to minimize round-off errors.
14
+ There are only a few special cases where the round-off error in force calculations has a dominant effect. In most cases, the basic gravity routine is faster and equally accurate.
15
+
16
+ ## Tree
17
+ `REB_GRAVITY_TREE`
18
+
19
+ This method uses an oct tree (Barnes and Hut 1986) to approximate self-gravity. It scales as $O(N \log(N))$.
20
+
21
+ ## Tree
22
+ `REB_GRAVITY_JACOBI`
23
+
24
+ Direct summation, scales as $O(N^2)$, includes special terms needed for some symplectic integrators.
25
+
26
+ ## None
27
+ `REB_GRAVITY_NONE`
28
+
29
+ By using this gravity routine, no self-gravity calculated. It is still possible to include additional forces.
rebound/source/docs/img/favicon.ico ADDED
rebound/source/docs/img/orbit.png ADDED
rebound/source/docs/img/rebound.png ADDED
rebound/source/docs/img/reboundbanner.png ADDED

Git LFS Details

  • SHA256: 296d298b253a126e4803c81f9025b4ccbdceb65e3b5e3f8be6b0723a4ad04a90
  • Pointer size: 131 Bytes
  • Size of remote file: 710 kB
rebound/source/docs/img/reboundblack.png ADDED
rebound/source/docs/img/shear.png ADDED
rebound/source/docs/index.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Welcome to REBOUND
2
+
3
+ ![REBOUND Examples](img/reboundbanner.png)
4
+
5
+ REBOUND is an N-body integrator, i.e. a software package that can integrate the motion of particles under the influence of gravity. The particles can represent stars, planets, moons, ring or dust particles. REBOUND is very flexible and can be customized to accurately and efficiently solve many problems in astrophysics.
6
+
7
+ ## Features
8
+
9
+
10
+ * No dependencies on external libraries.
11
+ * Runs natively on Linux, MacOS, and Windows.
12
+ * Symplectic integrators ([WHFast](integrators/#whfast), [SEI](integrators/#sei), [LEAPFROG](integrators/#leapfrog), [EOS](integrators/#embedded-operator-splitting-method-eos))
13
+ * Hybrid reversible integrators for planetary dynamics with arbitrary close encounters ([TRACE](integrators/#trace))
14
+ * Hybrid symplectic integrators for planetary dynamics with close encounters ([MERCURIUS](integrators/#mercurius))
15
+ * High order symplectic integrators for integrating planetary systems ([SABA](integrators/#saba), WH Kernel methods)
16
+ * High accuracy non-symplectic integrator with adaptive time-stepping ([IAS15](integrators/#ias15))
17
+ * Can integrate arbitrary user-defined ODEs that are coupled to N-body dynamics for tides, spin, etc
18
+ * Support for collisional/granular dynamics, various collision detection routines
19
+ * The computationally intensive parts of the code are written entirely in C, conforming to the ISO standard C99, and can be used as a thread-safe shared library
20
+ * Easy-to-use Python module, installation in 3 words: `pip install rebound`
21
+ * Real-time, 3D visualization, for both C and Python.
22
+ * Extensive set of example problems for both C and Python. You can run examples directly from your browser without the need to download or install anything.
23
+ * Parallelized [WHFast512](integrators/#whfast512) integrator for super fast integrations of planetary systems with SIMD AVX512 instructions
24
+ * Parallelized with OpenMP (for shared memory systems)
25
+ * Parallelized with [MPI](mpi/) is supported for some special use cases only (using an essential tree for gravity and collisions)
26
+ * The code is 100% open-source. All features are included in the public repository on [github](https://github.com/hannorein/rebound)
27
+
28
+ ## Contributors
29
+
30
+ * Hanno Rein, University of Toronto, <hanno@hanno-rein.de>
31
+ * Dan Tamayo, Harvey Mudd College <dtamayo@hmc.edu>
32
+ * David S. Spiegel, Institute for Advanced Study Princeton, <dave@ias.edu>
33
+ * Garett Brown, University of Toronto, <garett.brown@mail.utoronto.ca>
34
+ * Shangfei Liu, Kavli Institute for Astronomy and Astrophysics at Peking University, <liushangfei@pku.edu.cn>
35
+ * Ari Silburt, Penn State University, <ajs725@psu.edu>
36
+ * Pejvak Javaheri, University of Toronto, <pejvak.javaheri@mail.utoronto.ca>
37
+ * Ruth Huang, University of Toronto, <ruth.huang@mail.utoronto.ca>
38
+ * and many others! Check the git history to find out who contributed to the code.
39
+
40
+ REBOUND is open source and you are invited to contribute to this project!
41
+
42
+ ## YouTube tutorials
43
+
44
+ There are several short YouTube videos describing various aspects of REBOUND available at <https://www.youtube.com/channel/UCNmrCzxcmWVTBwtDPPLxkkw>.
45
+
46
+ ## Related projects
47
+
48
+ ### Additional physics
49
+ To easily incorporate additional physics modules such as migration forces, GR effects and spin into your REBOUND simulations, see REBOUNDx at <https://github.com/dtamayo/reboundx>.
50
+
51
+ ### Analytical and semianalytical tools
52
+ If you're interested in comparing numerical simulations to analytical and semianalytical tools for celestial mechanics, see Celmech at <https://github.com/shadden/celmech>.
53
+
54
+ ### Ephemeris-quality integrations of test particles
55
+ To generate ephemeris-quality integrations of test particles in the Solar System with a precision on par with JPL's small body integrator, see ASSIST at <https://github.com/matthewholman/assist>.
56
+
57
+
58
+ ## Papers
59
+
60
+ There are several papers describing the functionality of REBOUND.
61
+
62
+ 1. Rein & Liu 2012 (Astronomy and Astrophysics, Volume 537, A128) describes the code structure and the main feature including the gravity and collision routines for many particle systems. <http://adsabs.harvard.edu/abs/2012A%26A...537A.128R>
63
+
64
+ 2. Rein & Tremaine 2011 (Monthly Notices of the Royal Astronomical Society, Volume 415, Issue 4, pp. 3168-3176) describes the Symplectic Epicycle integrator for shearing sheet simulations. <https://ui.adsabs.harvard.edu/abs/2011MNRAS.415.3168R>
65
+
66
+ 3. Rein & Spiegel 2015 (Monthly Notices of the Royal Astronomical Society, Volume 446, Issue 2, p.1424-1437) describes the versatile high order integrator IAS15 which is now part of REBOUND. <http://adsabs.harvard.edu/abs/2015MNRAS.446.1424R>
67
+
68
+ 4. Rein & Tamayo 2015 (Monthly Notices of the Royal Astronomical Society, Volume 452, Issue 1, p.376-388) describes WHFast, the fast and unbiased implementation of a symplectic Wisdom-Holman integrator for long term gravitational simulations. <http://adsabs.harvard.edu/abs/2015MNRAS.452..376R>
69
+
70
+ 5. Rein & Tamayo 2016 (Monthly Notices of the Royal Astronomical Society, Volume 459, Issue 3, p.2275-2285) develop the framework for second order variational equations. <https://ui.adsabs.harvard.edu/abs/2016MNRAS.459.2275R>
71
+
72
+ 6. Rein & Tamayo 2017 (Monthly Notices of the Royal Astronomical Society, Volume 467, Issue 2, p.2377-2383) describes the Simulationarchive for exact reproducibility of N-body simulations. <https://ui.adsabs.harvard.edu/abs/2017MNRAS.467.2377R>
73
+
74
+ 7. Rein & Tamayo 2018 (Monthly Notices of the Royal Astronomical Society, Volume 473, Issue 3, p.3351–3357) describes the integer based JANUS integrator. <https://ui.adsabs.harvard.edu/abs/2018MNRAS.473.3351R>
75
+
76
+ 8. Rein, Hernandez, Tamayo, Brown, Eckels, Holmes, Lau, Leblanc & Silburt 2019 (Monthly Notices of the Royal Astronomical Society, Volume 485, Issue 4, p.5490-5497) describes the hybrid symplectic integrator MERCURIUS. <https://ui.adsabs.harvard.edu/abs/2019MNRAS.485.5490R>
77
+
78
+ 9. Rein, Tamayo & Brown 2019 (Monthly Notices of the Royal Astronomical Society, Volume 489, Issue 4, November 2019, Pages 4632-4640) describes the implementation of the high order symplectic integrators SABA, SABAC, SABACL, WHCKL, WHCKM, and WHCKC. <https://ui.adsabs.harvard.edu/abs/2019MNRAS.489.4632R/abstract>
79
+
80
+ 10. Javaheri, Rein & Tamayo 2023 (The Open Journal of Astrophysics, Volume 6, July 2023) describes the WHFast512 integrator which uses AVX512 instructions. <https://ui.adsabs.harvard.edu/abs/2023OJAp....6E..29J/abstract>
81
+
82
+ ## Acknowledgements
83
+
84
+ If you use this code or parts of this code for results presented in a scientific publication, we would greatly appreciate a citation.
85
+ The simplest way to find the citations relevant to the specific setup of your REBOUND simulation is:
86
+
87
+ ```python
88
+ sim = rebound.Simulation()
89
+ -your setup-
90
+ sim.cite()
91
+ ```
92
+
93
+ !!! Info
94
+ When you cite one of the REBOUND papers, your paper will receive an automatic shout-out from the [REBOUND Citation Bot](https://botsin.space/@reboundbot).
95
+
96
+ ## License
97
+
98
+ 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.
99
+
100
+ 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.
101
+
102
+ You should have received a copy of the GNU General Public License along with REBOUND. If not, see <http://www.gnu.org/licenses/>.
103
+
rebound/source/docs/integrators.md ADDED
@@ -0,0 +1,852 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Integrators
2
+
3
+ ![type:video](https://www.youtube.com/embed/QW5a-iH62dQ)
4
+
5
+ Numerical integrators are the backbone of any N-body package.
6
+ A numerical integrator evolves particles forward in time, one timestep at a time.
7
+ To do that, the integrator needs to know the current position and velocity coordinates of the particles, and the equations of motion which come in the form of a set of ordinary differential equations.
8
+
9
+ Because an exact solution to these differential equations is in general unknown, each integrator attempts to approximate the true solution numerically.
10
+ Different integrators do this differently and each of them has some advantages and some disadvantages.
11
+ Each of the built-in integrators of REBOUND is described in this section.
12
+
13
+ ## IAS15
14
+
15
+ ![type:video](https://www.youtube.com/embed/UILEgdZt-fw)
16
+
17
+ IAS15 stands for **I**ntegrator with **A**daptive **S**tep-size control, **15**th order. It is a very high order, non-symplectic integrator which can handle arbitrary forces (including those who are velocity dependent).
18
+ It is in most cases accurate down to machine precision (16 significant decimal digits).
19
+ The IAS15 implementation in REBOUND can integrate variational equations.
20
+ The algorithm is described in detail in [Rein & Spiegel 2015](https://ui.adsabs.harvard.edu/abs/2015MNRAS.446.1424R/abstract) and also in the original paper by [Everhart 1985](https://ui.adsabs.harvard.edu/abs/1985ASSL..115..185E/abstract).
21
+
22
+
23
+ IAS15 is the default integrator of REBOUND, so if you want to use it, you don't need to do anything.
24
+ However, you can also set it explicitly:
25
+
26
+ === "C"
27
+ ```c
28
+ struct reb_simulation* r = reb_simulation_create();
29
+ r->integrator = REB_INTEGRATOR_IAS15;
30
+ ```
31
+
32
+ === "Python"
33
+ ```python
34
+ sim = rebound.Simulation()
35
+ sim.integrator = "ias15"
36
+ ```
37
+
38
+ The setting for IAS15 are stored in the `reb_integrator_ias15` structure.
39
+
40
+ `epsilon` (`double`)
41
+ : IAS15 is an adaptive integrator. It chooses its timesteps automatically. This parameter controls the accuracy of the integrator. The default value is $10^{-9}$. Setting this parameter to 0 turns off adaptive timestepping and a constant timestep will is used. Turning off adaptive time-stepping is rarely useful.
42
+
43
+ !!! Important
44
+ It is tempting to change `epsilon` to achieve a speedup at the loss of some accuracy. However, that makes rarely sense. The reason is that IAS15 is a very high (15th!) order integrator. Suppose we increase the timestep by a factor of 10. This will increase the error by a factor of $10^{15}$. In other words, a simulation that previously was converged to machine precision will now have an error of order unity.
45
+
46
+ `min_dt` (`double`)
47
+ : This sets the minimum allowed timestep. The default value is 0. Set this to a finite value if the adaptive timestep becomes excessively small, for example during close encounters or because of finite floating point precision. Use with caution and make sure the simulation results still make physically sense as you might be in danger of ignoring small timescales in the problem.
48
+ The following code sets the smallest timestep to $10^{-3}$ time units:
49
+ === "C"
50
+ ```c
51
+ struct reb_simulation* r = reb_simulation_create();
52
+ r->ri_ias15.min_dt = 1e-3;
53
+ ```
54
+
55
+ === "Python"
56
+ ```python
57
+ sim = rebound.Simulation()
58
+ sim.ri_ias15.min_dt = 1e-3
59
+ ```
60
+
61
+ `adaptive_mode` `(unsigned int`)
62
+ : This flag determines how the adaptive timestep is chosen. The previous name of this flag was `epsilon_global`.
63
+ The default is 2 which corresponds to the timestep criterion described in Pham, Rein, and Spiegel (2024).
64
+ This should be optimal in almost all cases.
65
+ If set to 0, the fractional error is estimated via `max(acceleration_error/acceleration)` and the timestep criterion of Rein and Spiegel (2015) is used.
66
+ If set to 1, IAS15 estimates the fractional error via `max(acceleration_error)/max(acceleration)` where the maximum is taken over all particles. As before, the timestep criterion of Rein and Spiegel (2015) is used. This was the default until January 2024.
67
+ If set to 3, then the criterion of [Aarseth 1985](https://ui.adsabs.harvard.edu/abs/1985IAUS..113..251A/abstract) is used.
68
+
69
+ All other members of this structure are only for internal IAS15 use.
70
+
71
+
72
+ ## WHFast
73
+
74
+ ![type:video](https://www.youtube.com/embed/ttLUhtNj1Lc)
75
+
76
+ WHFast is an implementation of the symplectic [Wisdom-Holman](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract) integrator.
77
+ It is the best choice for systems in which there is a dominant central object and perturbations to the Keplerian orbits are small.
78
+ It supports first and second symplectic correctors as well as the kernel method of [Wisdom et al. 1996](https://ui.adsabs.harvard.edu/abs/1996FIC....10..217W/abstract) with various different kernels.
79
+ The basic implementation of WHFast is described in detail in [Rein & Tamayo 2015](https://ui.adsabs.harvard.edu/abs/2015MNRAS.452..376R/abstract).
80
+ The higher order aspects of it are described in [Rein, Tamayo & Brown 2019](https://ui.adsabs.harvard.edu/abs/2019MNRAS.489.4632R/abstract).
81
+ WHFast also supports first order variational equations which can be used in chaos estimators ([Rein & Tamayo 2016](https://ui.adsabs.harvard.edu/abs/2016MNRAS.459.2275R/abstract)).
82
+ The user can choose between Jacobi, Democratic Heliocentric, WHDS, and barycentric coordinates.
83
+
84
+ The following code enables the WHFast integrator.
85
+ Because WHFast is not an adaptive integrator, you also need to set a timestep.
86
+ Typically, this should be a small fraction (a few percent) of the smallest dynamical timescale in the problem.
87
+ === "C"
88
+ ```c
89
+ struct reb_simulation* r = reb_simulation_create();
90
+ r->integrator = REB_INTEGRATOR_WHFAST;
91
+ r->dt = 0.1;
92
+ ```
93
+
94
+ === "Python"
95
+ ```python
96
+ sim = rebound.Simulation()
97
+ sim.integrator = "whfast"
98
+ sim.dt = 0.1
99
+ ```
100
+
101
+
102
+ The setting for WHFast are stored in the `reb_integrator_whfast` structure, which itself is part of the simulation structure.
103
+
104
+ `unsigned int corrector`
105
+ : This variable turns on/off different first symplectic correctors for WHFast.
106
+ By default, it is set to zero and symplectic correctors are turned off.
107
+
108
+ First symplectic correctors remove error terms up to $O(\epsilon \cdot dt^p)$, where $p$ is the order of the symplectic corrector, and $\epsilon$ is the mass ratio in the system.
109
+ The following first correctors are implemented in REBOUND:
110
+
111
+ Order | Number of stages
112
+ ------- | ----------------
113
+ 0 | Correctors turned off (default)
114
+ 3 | 2
115
+ 5 | 4
116
+ 7 | 6
117
+ 11 | 10
118
+ 17 | 16
119
+
120
+ For most cases you want to choose the 17th order corrector.
121
+ You only want to consider lower order correctors if frequent outputs are required and speed is an issue.
122
+ Symplectic correctors are turned on as follows.
123
+
124
+
125
+ === "C"
126
+ ```c
127
+ r->ri_whfast.corrector = 17;
128
+ r->ri_whfast.safe_mode = 0;
129
+ ```
130
+
131
+ === "Python"
132
+ ```python
133
+ sim.ri_whfast.corrector = 17
134
+ sim.ri_whfast.safe_mode = 0
135
+ ```
136
+
137
+ Note that the above code also turns off the safe mode.
138
+ Most likely, you want to do that too (see below for a description of the safe mode).
139
+
140
+ `unsigned int corrector2`
141
+ : This variable turns on/off second symplectic correctors for WHFast.
142
+ By default, second symplectic correctors are off (0).
143
+ Set to 1 to use second symplectic correctors.
144
+
145
+ !!! Info
146
+ The nomenclature can be a bit confusing.
147
+ First symplectic correctors are different from second symplectic correctors.
148
+ And in REBOUND first symplectic correctors have different orders (see above).
149
+ Second symplectic correctors on the other hand can only be turned on or off.
150
+ See [Rein, Tamayo & Brown 2019](https://ui.adsabs.harvard.edu/abs/2019MNRAS.489.4632R/abstract) for more on high order symplectic integrators.
151
+
152
+ `unsigned int kernel`
153
+ : This variable determines the kernel of the WHFast integrator.
154
+ The following options are currently supported:
155
+
156
+ - The standard Wisdom-Holman kick step. This is the default.
157
+ - Exact modified kick. This works for Newtonian gravity only. Not additional forces.
158
+ - The composition kernel.
159
+ - Lazy implementer's modified kick. This is often the best option.
160
+
161
+ Check [Rein, Tamayo & Brown 2019](https://ui.adsabs.harvard.edu/abs/2019MNRAS.489.4632R/abstract) for details on what these kernel methods are.
162
+ The syntax to use them is
163
+
164
+ === "C"
165
+ ```c
166
+ r->ri_whfast.kernel = REB_WHFAST_KERNEL_DEFAULT; // or
167
+ r->ri_whfast.kernel = REB_WHFAST_KERNEL_MODIFIEDKICK; // or
168
+ r->ri_whfast.kernel = REB_WHFAST_KERNEL_COMPOSITION; // or
169
+ r->ri_whfast.kernel = REB_WHFAST_KERNEL_LAZY;
170
+ ```
171
+
172
+ === "Python"
173
+ ```python
174
+ sim.ri_whfast.kernel = "default" # or
175
+ sim.ri_whfast.kernel = "modifiedkick" # or
176
+ sim.ri_whfast.kernel = "composition" # or
177
+ sim.ri_whfast.kernel = "lazy"
178
+ ```
179
+
180
+ `unsigned int coordinates`
181
+ : WHFast supports different coordinate systems.
182
+ Default are Jacobi Coordinates.
183
+ Other options are democratic heliocentric coordinates, and the WHDS coordinates ([Hernandez & Dehnen, 2017](https://ui.adsabs.harvard.edu/abs/2017MNRAS.468.2614H/abstract))
184
+ The syntax to use them is
185
+
186
+ === "C"
187
+ ```c
188
+ r->ri_whfast.coordinates = REB_WHFAST_COORDINATES_JACOBI; // or
189
+ r->ri_whfast.coordinates = REB_WHFAST_COORDINATES_DEMOCRATICHELIOCENTRIC; // or
190
+ r->ri_whfast.coordinates = REB_WHFAST_COORDINATES_WHDS; // or
191
+ r->ri_whfast.coordinates = REB_WHFAST_COORDINATES_BARYCENTRIC;
192
+ ```
193
+
194
+ === "Python"
195
+ ```python
196
+ sim.ri_whfast.coordinates = "jacobi" # or
197
+ sim.ri_whfast.coordinates = "democraticheliocentric" # or
198
+ sim.ri_whfast.coordinates = "whds" # or
199
+ sim.ri_whfast.coordinates = "barycentric"
200
+ ```
201
+
202
+ `unsigned int recalculate_coordinates_this_timestep`
203
+ : Setting this flag to one will recalculate the internal coordinates from the particle structure in the next timestep.
204
+ After the timestep, the flag gets set back to 0. If you want to change particles after every timestep, you also need to set this flag to 1 before every timestep. Default is 0.
205
+
206
+ `unsigned int safe_mode`
207
+ : If this flag is set (the default), WHFast will recalculate the internal coordinates (Jacobi/heliocentric/WHDS/barycentric) and synchronize every timestep, to avoid problems with outputs or particle modifications between timesteps.
208
+ Setting it to 0 will result in a speedup, but care must be taken to synchronize and recalculate the internal coordinates when needed. See also the AdvWHFast.ipynb tutorial.
209
+
210
+ `unsigned int keep_unsynchronized`
211
+ : This flag determines if the inertial coordinates generated are discarded in subsequent timesteps (cached Jacobi/heliocentric/WHDS/barycentric coordinates are used instead). The default is 0. Set this flag to 1 if you require outputs and bit-wise reproducibility
212
+
213
+ All other members of the `reb_integrator_whfast` structure are for internal use only.
214
+
215
+ ## Gragg-Bulirsch-Stoer (BS)
216
+ The Gragg-Bulirsch-Stoer integrator (short BS for Bulirsch-Stoer) is an adaptive integrator which uses Richardson extrapolation and the modified midpoint method to obtain solutions to ordinary differential equations.
217
+
218
+ The version in REBOUND is based on the method described in Hairer, Norsett, and Wanner 1993 (see section II.9, page 224ff), specifically the JAVA implementation available in the [Hipparchus package](https://github.com/Hipparchus-Math/hipparchus/blob/master/hipparchus-ode/src/main/java/org/hipparchus/ode/nonstiff/GraggBulirschStoerIntegrator.java). The Hipparchus as well as the REBOUND version are adaptive in both the timestep and the order of the method for optimal performance.
219
+ The BS implementation in REBOUND can integrate first and second order variational equations.
220
+
221
+ The BS integrator is particularly useful for short integrations where only medium accuracy is required. For long integrations a symplectic integrator such as WHFast performs better. For high accuracy integrations the IAS15 integrator performs better. Because BS is adaptive, it can handle close encounters. Currently a collision search is only performed after every timestep, i.e. not after a sub-timestep.
222
+
223
+ The following code enables the BS integrator and sets both the relative and absolute tolerances to 0.0001 (the default is $10^{-8}$):
224
+
225
+ === "C"
226
+ ```c
227
+ struct reb_simulation* r = reb_simulation_create();
228
+ r->integrator = REB_INTEGRATOR_BS;
229
+ r->ri_bs.eps_rel = 1e-4;
230
+ r->ri_bs.eps_abs = 1e-4;
231
+ ```
232
+
233
+ === "Python"
234
+ ```python
235
+ sim = rebound.Simulation()
236
+ sim.integrator = "BS"
237
+ sim.ri_bs.eps_rel = 1e-4
238
+ sim.ri_bs.eps_abs = 1e-4
239
+ ```
240
+
241
+ The BS integrator tries to keep the error of each coordinate $y$ below $\epsilon_{abs} + \epsilon_{rel} \cdot \left|y\right|$. Note that this applies to both position and velocity coordinates of all particles which implies that the code units you're choosing for the integration matter. If you need fine control over the scales used internally, you can set the `getscale` function pointer in `r->ri_bs.nbody_ode` (this is currently undocumented, search the source code for `getscale` to find out more).
242
+
243
+ !!! Info
244
+ The code does not guarantee that the errors remain below the tolerances. In particular, note that BS is not a symplectic integrator which results in errors growing linearly in time (phase errors grow quadratically in time). It requires some experimentation to find the tolerances that offer the best compromise between accuracy and speed for your specific problem.
245
+
246
+
247
+ You can limit the timestep with both a maximum and minimum timestep:
248
+
249
+ === "C"
250
+ ```c
251
+ r->ri_bs.min_dt = 1e-5;
252
+ r->ri_bs.max_dt = 1e-2;
253
+ ```
254
+
255
+ === "Python"
256
+ ```python
257
+ sim.ri_bs.min_dt = 1e-5
258
+ sim.ri_bs.max_dt = 1e-2
259
+ ```
260
+
261
+ Compared to the other integrators in REBOUND, BS can be used to integrate arbitrary ordinary differential equations (ODEs), not just the N-body problem. We expose an ODE-API in REBOUND which allows you to make use of this. User-defined ODEs are always integrated with BS. You can choose to integrate the N-body equations with BS as well, or any of the other integrators.
262
+
263
+ If you choose BS for the N-body equations, then BS will treat all ODEs (N-body + all user-defined ones) as one big system of coupled ODEs. This means your timestep will be set by either the N-body problem or the user-defined ODEs, whichever involves the shorter timescale.
264
+
265
+ If you choose IAS15 or WHFast for the N-body equation but also have user-defined ODEs, then they cannot be treated as one big coupled system of ODEs anymore. In that case the N-body integration is done first. Then the user-defined ODEs are advanced to the exact same time as the N-body system using BS using whatever timestep is required to achieve the tolerance set in the `ri_bs` struct. During the integration of the user-defined ODEs, the coordinates of the particles in the N-body simulation are assumed to be fixed at their final position and velocity. This introduces an error. However, if the system evolves adiabatically (the timescales in the user-defined ODEs are much longer than in the N-body problem), then the error will be small.
266
+
267
+ The following code sets up a REBOUND simulation in which a harmonic oscillator is driven by the phase of a planet orbiting a star:
268
+
269
+ === "C"
270
+ ```c
271
+ void derivatives(struct reb_ode* const ode, double* const yDot, const double* const y, const double t){
272
+ struct reb_orbit o = reb_orbit_from_particle(ode->r->G, ode->r->particles[1], ode->r->particles[0]);
273
+ const double omega = 1;
274
+ double forcing = sin(o.f);
275
+ yDot[0] = y[1];
276
+ yDot[1] = -omega*omega*y[0] + forcing;
277
+ }
278
+
279
+ void run(){
280
+ struct reb_simulation* r = reb_simulation_create();
281
+ reb_simulation_add_fmt(r, "m", 1.);
282
+ reb_simulation_add_fmt(r, "m a e", 1e-3, 1., 0.1);
283
+
284
+ r->integrator = REB_INTEGRATOR_BS;
285
+
286
+ struct reb_ode* ho = reb_ode_create(r,2); // Add an ODE with 2 dimensions
287
+ ho->derivatives = derivatives; // Right hand side of the ODE
288
+ ho->y[0] = 1; // Initial conditions
289
+ ho->y[1] = 0;
290
+ }
291
+ ```
292
+
293
+ === "Python"
294
+ ```python
295
+ import numpy as np
296
+
297
+ def derivatives(ode, yDot, y, t):
298
+ omega = 1.0
299
+ sim_pointer = ode.contents.r
300
+ orbit = sim_pointer.contents.particles[1]
301
+ forcing = np.sin(orbit.f)
302
+ yDot[0] = y[1]
303
+ yDot[1] = -omega*omega*y[0] + forcing
304
+
305
+ sim = rebound.Simulation()
306
+ sim.add(m=1)
307
+ sim.add(m=1e-3, a=1, e=0.1)
308
+
309
+ sim.integrator = "BS"
310
+
311
+ ho = sim.create_ode(length=2) # Add an ODE with 2 dimensions
312
+ ho.derivatives = derivatives # Right hand side of the ODE
313
+ ho.y[0] = 1.0 # Initial conditions
314
+ ho.y[1] = 0.0
315
+ ```
316
+
317
+
318
+ ## Mercurius
319
+
320
+ MERCURIUS is a hybrid symplectic integrator very similar to MERCURY ([Chambers 1999](https://ui.adsabs.harvard.edu/abs/1999MNRAS.304..793C/abstract)).
321
+ It uses WHFast for long term integrations but switches over smoothly to IAS15 for close encounters.
322
+ The MERCURIUS implementation is described in [Rein et al 2019](https://ui.adsabs.harvard.edu/abs/2019MNRAS.485.5490R/abstract).
323
+
324
+
325
+ The following code enables MERCURIUS and sets the critical radius to 4 Hill radii
326
+ === "C"
327
+ ```c
328
+ struct reb_simulation* r = reb_simulation_create();
329
+ r->integrator = REB_INTEGRATOR_MERCURIUS;
330
+ r->ri_mercurius.r_crit_hill = 4.;
331
+ ```
332
+
333
+ === "Python"
334
+ ```python
335
+ sim = rebound.Simulation()
336
+ sim.integrator = "mercurius"
337
+ sim.ri_mercurius.r_crit_hill = 4.
338
+ ```
339
+
340
+ The `reb_integrator_mercurius` structure contains the configuration and data structures used by the hybrid symplectic MERCURIUS integrator.
341
+
342
+ `double (*L) (const struct reb_simulation* const r, double d, double dcrit)`
343
+ : This is a function pointer to the force switching function.
344
+ If NULL (the default), the MERCURY switching function will be used.
345
+ The argument `d` is the distance between two particles.
346
+ The argument `dcrit` is the maximum critical distances of the two particles.
347
+ The return value is a scalar between 0 and 1.
348
+ If this function always returns 1, then the integrator effectively becomes the standard Wisdom-Holman integrator.
349
+
350
+ The following switching functions are available:
351
+
352
+
353
+ - Mercury switching function
354
+
355
+ This is the same polynomial switching function as used in MERCURY.
356
+
357
+ ```c
358
+ double reb_integrator_mercurius_L_mercury(const struct reb_simulation* const r, double d, double dcrit);
359
+ ```
360
+ - Smooth switching functions
361
+
362
+ These two polynomials switching functions are 4 and 5 times differentiable.
363
+ Using smooth switching functions can improve the accuracy.
364
+ For a detailed discussion see [Hernandez 2019](https://ui.adsabs.harvard.edu/abs/2019MNRAS.490.4175H/abstract).
365
+
366
+ ```c
367
+ double reb_integrator_mercurius_L_C4(const struct reb_simulation* const r, double d, double dcrit);
368
+ double reb_integrator_mercurius_L_C5(const struct reb_simulation* const r, double d, double dcrit);
369
+ ```
370
+
371
+ - Infinitely differentiable switching function
372
+
373
+ This is an infinitely differentiable switching function.
374
+
375
+ ```c
376
+ double reb_integrator_mercurius_L_infinity(const struct reb_simulation* const r, double d, double dcrit);
377
+ ```
378
+
379
+ The switching function can be set using this syntax:
380
+
381
+ === "C"
382
+ ```c
383
+ struct reb_simulation* r = reb_simulation_create();
384
+ r->ri_mercurius.L = reb_integrator_mercurius_L_infinity;
385
+ ```
386
+
387
+ === "Python"
388
+ ```python
389
+ sim = rebound.Simulation()
390
+ sim.ri_mercurius.L = "infinity"
391
+ ```
392
+
393
+ `double r_crit_hill`
394
+ : The critical switchover radii of particles are calculated automatically based on multiple criteria. One criterion calculates the Hill radius of particles and then multiplies it with the `r_crit_hill` parameter. The parameter is in units of the Hill radius. The default value is 3.
395
+
396
+ `unsigned int recalculate_coordinates_this_timestep`
397
+ : Setting this flag to one will recalculate heliocentric coordinates from the particle structure at the beginning of the next timestep. After a single timestep, the flag gets set back to 0. If one changes a particle manually after a timestep, then one needs to set this flag to 1 before the next timestep.
398
+
399
+ `unsigned int recalculate_r_crit_this_timestep`
400
+ : Setting this flag to one will recalculate the critical switchover distances dcrit at the beginning of the next timestep. After one timestep, the flag gets set back to 0. If you want to recalculate `dcrit` at every timestep, you also need to set this flag to 1 before every timestep.
401
+
402
+ `unsigned int safe_mode`
403
+ : If this flag is set to 1 (the default), the integrator will recalculate heliocentric coordinates and synchronize after every timestep to avoid problems with outputs or particle modifications between timesteps. Setting this flag to 0 will result in a speedup, but care must be taken to synchronize and recalculate coordinates manually if needed.
404
+
405
+ ## TRACE
406
+
407
+ TRACE is a hybrid time-reversible integrator, based on the algorithm described in [Hernandez & Dehnen 2023](https://ui.adsabs.harvard.edu/abs/2023MNRAS.522.4639H/abstract).
408
+ It uses WHFast for long term integrations but switches time-reversibly to BS or IAS15 for all close encounters. TRACE is appropriate for systems with a dominant central mass that will occasionally have close encounters.
409
+ The TRACE implementation is described in [Lu, Hernandez & Rein](https://ui.adsabs.harvard.edu/abs/2024MNRAS.533.3708L/abstract).
410
+
411
+
412
+ The following code enables TRACE and sets the critical radius to 4 Hill radii
413
+ === "C"
414
+ ```c
415
+ struct reb_simulation* r = reb_create_simulation();
416
+ r->integrator = REB_INTEGRATOR_TRACE;
417
+ r->ri_trace.r_crit_hill = 4;
418
+ ```
419
+
420
+ === "Python"
421
+ ```python
422
+ sim = rebound.Simulation()
423
+ sim.integrator = "trace"
424
+ sim.ri_trace.r_crit_hill = 4
425
+ ```
426
+
427
+ The `reb_integrator_trace` structure contains the configuration and data structures used by the hybrid symplectic TRACE integrator.
428
+
429
+ `int (*S) (const struct reb_simulation* const r, const unsigned int i, const unsigned int j)`
430
+ : This is a function pointer to the switching function for close encounters between non-central bodies.
431
+ If NULL (the default), the default switching function will be used.
432
+ The arguments `i` and `j` are the indices of the two particles considered.
433
+ The return value is either 0 or 1.
434
+ A return value of 1 means a close encounter has been flagged.
435
+ If the return values of both this function and the central switching function below are always 0, then the integrator effectively becomes the standard Wisdom-Holman integrator.
436
+
437
+ - Default switching function
438
+
439
+ This is a similar (but slightly modified) switching function used in MERCURY. It uses a modified Hill radius criteria, with heliocentric distance replacing semimajor axis
440
+
441
+ ```c
442
+ int reb_integrator_trace_switch_default(const struct reb_simulation* const r, const unsigned int i, const unsigned int j);
443
+ ```
444
+
445
+ The switching function can be manually set using this syntax:
446
+
447
+ === "C"
448
+ ```c
449
+ struct reb_simulation* r = reb_create_simulation();
450
+ r->ri_trace.S = reb_integrator_trace_switch_default;
451
+ ```
452
+
453
+ === "Python"
454
+ ```python
455
+ sim = rebound.Simulation()
456
+ sim.ri_trace.S = "default"
457
+ ```
458
+
459
+ `int (*S_peri) (const struct reb_simulation* const r, const unsigned int j)`
460
+ : This is a function pointer to the switching function for close encounters involving the central body.
461
+ If NULL (the default), the default switching function will be used.
462
+ The argument `j` is the index of the non-central particle considered.
463
+ The return value is either 0 or 1.
464
+ A return value of 1 means a close encounter has been flagged.
465
+
466
+ - Default switching function
467
+
468
+ This switching function checks if a body is close to its pericenter by considering a timescale derived from high-order derivatives of the particle's herliocentric position, inspired by [Pham, Rein, and Spiegel 2024](https://ui.adsabs.harvard.edu/abs/2024OJAp....7E...1P/abstract).
469
+
470
+ ```c
471
+ int reb_integrator_trace_switch_peri_default(const struct reb_simulation* const r, const unsigned int j);
472
+ ```
473
+ The switching function can be manually set using this syntax:
474
+
475
+ === "C"
476
+ ```c
477
+ struct reb_simulation* r = reb_create_simulation();
478
+ r->ri_trace.S_peri = reb_integrator_trace_switch_peri_default; // default
479
+ r->ri_trace.S_peri = reb_integrator_trace_switch_peri_none; // Turn off pericenter switching
480
+ ```
481
+
482
+ === "Python"
483
+ ```python
484
+ sim = rebound.Simulation()
485
+ sim.ri_trace.S_peri = "default" # Following Pham et al 2024
486
+ sim.ri_trace.S_peri = "none" # Turn off pericenter switching
487
+ ```
488
+
489
+ `double r_crit_hill`
490
+ : The critical switchover radii of non-central particles are calculated based on a modified Hill radii criteria. This modified Hill radius for each particle is calculated and then multiplied by the `hillfac` parameter. The parameter is in units of the modified Hill radius. This value is used by the `default` switching function. The default value is 4.
491
+
492
+ `double peri_crit_eta`
493
+ : The criteria for a pericenter approach with the central body. This criteria is used in the `default` pericenter switching condition. It flags a particle as in a close pericenter approach if the ratio of the timestep to the condition described in [Pham, Rein, and Spiegel 2024](https://ui.adsabs.harvard.edu/abs/2024OJAp....7E...1P/abstract). The default value is 1.
494
+
495
+ The switching criteria can be manually set using this syntax:
496
+
497
+ === "C"
498
+ ```c
499
+ struct reb_simulation* r = reb_create_simulation();
500
+ r->ri_trace.peri_crit_eta = 0.5; // or
501
+ ```
502
+
503
+ === "Python"
504
+ ```python
505
+ sim = rebound.Simulation()
506
+ sim.ri_trace.peri_crit_eta = 0.5 # or
507
+ ```
508
+ `unsigned int peri_mode`
509
+ : This variable determines how TRACE integrates close approaches with the central star.
510
+ The following options are currently supported:
511
+
512
+ - Integrating the entire system with BS. This is the default.
513
+ - Integrating only the Kepler Step with BS.
514
+ - Integrating the entire system with IAS15.
515
+
516
+ Check [Lu, Hernandez & Rein 2024](https://ui.adsabs.harvard.edu/abs/2024MNRAS.533.3708L/abstract) for details on what these pericenter switching modes entail.
517
+ The syntax to use them is
518
+
519
+ === "C"
520
+ ```c
521
+ r->ri_trace.peri_mode = REB_TRACE_PERI_PARTIAL_BS; // or
522
+ r->ri_trace.peri_mode = REB_TRACE_PERI_FULL_BS; // or
523
+ r->ri_trace.peri_mode = REB_TRACE_PERI_FULL_IAS15; // or
524
+ ```
525
+
526
+ === "Python"
527
+ ```python
528
+ sim.ri_trace.peri_mode = "PARTIAL_BS" # or
529
+ sim.ri_trace.peri_mode = "FULL_BS" # or
530
+ sim.ri_trace.peri_mode = "FULL_IAS15" # or
531
+ ```
532
+ ## SABA
533
+
534
+ SABA are symplectic integrators developed by [Laskar & Robutel 2001](https://ui.adsabs.harvard.edu/abs/2001CeMDA..80...39L/abstract) and [Blanes et al. 2013](https://ui.adsabs.harvard.edu/abs/2012arXiv1208.0689B/abstract).
535
+ The implementation in REBOUND supports SABA1, SABA2, SABA3, and SABA4 as well as the corrected versions SABAC1, SABAC2, SABAC3, and SABAC4.
536
+ Different correctors can be selected.
537
+ In addition, the following methods with various generalized orders are supported: SABA(8,4,4), SABA(8,6,4), SABA(10,6,4).
538
+ See [Rein, Tamayo & Brown 2019](https://ui.adsabs.harvard.edu/abs/2019MNRAS.489.4632R/abstract) for details on how these methods work.
539
+
540
+ The `reb_integrator_saba` structure contains the configuration and data structures used by the SABA integrator family.
541
+
542
+ `unsigned int type`
543
+ : This parameter specifies which SABA integrator type is used.
544
+ The following SABA integrators are supported:
545
+
546
+ Numerical value | C constant name | Description
547
+ ------------------- | ------------------- | ----------------------------------
548
+ 0x0 | `REB_SABA_1` | SABA1 (Wisdom-Holman)
549
+ 0x1 | `REB_SABA_2` | SABA2
550
+ 0x2 | `REB_SABA_3` | SABA3
551
+ 0x3 | `REB_SABA_4` | SABA4
552
+ 0x100 | `REB_SABA_CM_1` | SABACM1 (Modified kick corrector)
553
+ 0x101 | `REB_SABA_CM_2` | SABACM2 (Modified kick corrector)
554
+ 0x102 | `REB_SABA_CM_3` | SABACM3 (Modified kick corrector)
555
+ 0x103 | `REB_SABA_CM_4` | SABACM4 (Modified kick corrector)
556
+ 0x200 | `REB_SABA_CL_1` | SABACL1 (lazy corrector)
557
+ 0x201 | `REB_SABA_CL_2` | SABACL2 (lazy corrector)
558
+ 0x202 | `REB_SABA_CL_3` | SABACL3 (lazy corrector)
559
+ 0x203 | `REB_SABA_CL_4` | SABACL4 (lazy corrector)
560
+ 0x4 | `REB_SABA_10_4` | SABA(10,4), 7 stages
561
+ 0x5 | `REB_SABA_8_6_4` | SABA(8,6,4), 7 stages
562
+ 0x6 | `REB_SABA_10_6_4` | SABA(10,6,4), 8 stages, default
563
+ 0x7 | `REB_SABA_H_8_4_4` | SABAH(8,4,4), 6 stages
564
+ 0x8 | `REB_SABA_H_8_6_4` | SABAH(8,6,4), 8 stages
565
+ 0x9 | `REB_SABA_H_10_6_4` | SABAH(10,6,4), 9 stages
566
+
567
+ SABA(10,6,4) is the default integrator. It has a generalized order of $O(\epsilon dt^{10} + \epsilon^2 dt^6 + \epsilon^3 dt^4)$.
568
+
569
+ Below is an example on how to enable the SABA integrators in REBOUND and set a specific type.
570
+
571
+ === "C"
572
+ ```c
573
+ struct reb_simulation* r = reb_simulation_create();
574
+ r->integrator = REB_INTEGRATOR_SABA;
575
+ r->ri_saba.type = REB_SABA_10_6_4;
576
+ ```
577
+
578
+ === "Python"
579
+ ```python
580
+ sim = rebound.Simulation()
581
+ sim.integrator = "saba"
582
+ sim.ri_saba.type = "(10,6,4)"
583
+ ```
584
+ One can also use the following shorthand:
585
+ ```python
586
+ sim = rebound.Simulation()
587
+ sim.integrator = "SABA(10,6,4)"
588
+ ```
589
+
590
+ `unsigned int safe_mode`
591
+ : This flag has the same functionality as in WHFast. Default is 1. Setting this to 0 will provide a speedup, but care must be taken with synchronizing integration steps and modifying particles.
592
+
593
+ `unsigned int keep_unsynchronized`
594
+ : This flag determines if the inertial coordinates generated are discarded in subsequent timesteps (cached Jacobi coordinates are used instead). The default is 0. Set this flag to 1 if you require outputs and bit-wise reproducibility
595
+
596
+
597
+
598
+
599
+ ## JANUS
600
+ Janus is a bit-wise time-reversible high-order symplectic integrator using a mix of floating point and integer arithmetic.
601
+ It is described in [Rein & Tamayo 2018](https://ui.adsabs.harvard.edu/abs/2018MNRAS.473.3351R/abstract).
602
+
603
+ The following code shows how to enable JANUS and set the length and velocity scales.
604
+ === "C"
605
+ ```c
606
+ struct reb_simulation* r = reb_simulation_create();
607
+ r->integrator = REB_INTEGRATOR_JANUS;
608
+ r->ri_janus.scale_pos = 1e-10;
609
+ r->ri_janus.scale_vel = 1e-10;
610
+ ```
611
+
612
+ === "Python"
613
+ ```python
614
+ sim = rebound.Simulation()
615
+ sim.integrator = "janus"
616
+ sim.ri_janus.scale_pos = 1e-10
617
+ sim.ri_janus.scale_vel = 1e-10
618
+ ```
619
+
620
+
621
+ The `reb_integrator_janus` structure contains the configuration and data structures used by the bib-wise reversible JANUS integrator.
622
+
623
+ `double scale_pos`
624
+ : Scale of the problem. Positions get divided by this number before the conversion to an integer. Default: $10^{-16}$.
625
+
626
+ `double scale_vel`
627
+ : Scale of the problem. Velocities get divided by this number before the conversion to an integer. Default: $10^{-16}$.
628
+
629
+ `unsigned int order`
630
+ : The order of the scheme. Default is 6.
631
+
632
+ `unsigned int recalculate_integer_coordinates_this_timestep`
633
+ : If this flag is set, then JANUS will recalculate the integer coordinates from floating point coordinates at the next timestep.
634
+
635
+ All other members of this structure are only for internal use and should not be changed manually.
636
+
637
+
638
+ ## Embedded Operator Splitting Method (EOS)
639
+ This is the Embedded Operator Splitting (EOS) methods described in [Rein 2019](https://ui.adsabs.harvard.edu/abs/2020MNRAS.492.5413R/abstract).
640
+
641
+ The `reb_integrator_eos` structure contains the configuration and data structures used by EOS.
642
+
643
+ `unsigned int phi0`
644
+ : Outer operator splitting scheme (see below for options)
645
+
646
+ `unsigned int phi1`
647
+ : Inner operator splitting scheme (see below for options)
648
+
649
+ `unsigned int n`
650
+ : Number of sub-timesteps. Default: 2.
651
+
652
+ `unsigned int safe_mode`
653
+ : If set to 0, always combine drift steps at the beginning and end of `phi0`. If set to 1, `n` needs to be bigger than 1.
654
+
655
+
656
+
657
+ The following operator splitting methods for `phi0` and `phi1` are supported in the EOS integrator.
658
+
659
+ Numerical value | Constant name | Description
660
+ --------------- | --------------------- | -------------------------------------------------
661
+ 0x00 | `REB_EOS_LF` | 2nd order, standard leap-frog
662
+ 0x01 | `REB_EOS_LF4` | 4th order, three function evaluations
663
+ 0x02 | `REB_EOS_LF6` | 6th order, nine function evaluations
664
+ 0x03 | `REB_EOS_LF8` | 8th order, seventeen function evaluations, see Blanes & Casa (2016), p91
665
+ 0x04 | `REB_EOS_LF4_2` | generalized order (4,2), two force evaluations, McLachlan 1995
666
+ 0x05 | `REB_EOS_LF8_6_4` | generalized order (8,6,4), seven force evaluations
667
+ 0x06 | `REB_EOS_PLF7_6_4` | generalized order (7,6,4), three force evaluations, pre- and post-processors
668
+ 0x07 | `REB_EOS_PMLF4` | 4th order, one modified force evaluation, pre- and post-processors, Blanes et al. (1999)
669
+ 0x08 | `REB_EOS_PMLF6` | 6th order, three modified force evaluations, pre- and post-processors, Blanes et al. (1999)
670
+
671
+
672
+ The following code shows how to enable EOS and set the embedded methods.
673
+ === "C"
674
+ ```c
675
+ struct reb_simulation* r = reb_simulation_create();
676
+ r->integrator = REB_INTEGRATOR_EOS;
677
+ r->ri_eos.phi0 = REB_EOS_LF4;
678
+ r->ri_eos.phi1 = REB_EOS_LF4;
679
+ r->ri_eos.n = 6;
680
+ ```
681
+
682
+ === "Python"
683
+ ```python
684
+ sim = rebound.Simulation()
685
+ sim.integrator = "eos"
686
+ sim.ri_eos.phi0 = "LF4"
687
+ sim.ri_eos.phi1 = "LF4"
688
+ sim.ri_eos.n = 6
689
+ ```
690
+
691
+ ## Leapfrog
692
+ `REB_INTEGRATOR_LEAPFROG`
693
+
694
+ This is the standard leap frog integrator. It is symplectic. By default it is second order with one force evaluation per step. Higher orders of 4, 6, and 8 can be selected as well. These correspond to the 4th order Yoshida integrator and the 8th order by Blanes & Casa (2016), p91. The higher order methods have more function evaluations and are therefore slower. Note that some substeps of the higher order methods move particles backwards. Therefore higher order methods might not give accurate results when a collision search is turned on.
695
+
696
+ `unsigned int order`
697
+ : Set the order of the leapfrog integrator:
698
+ === "C"
699
+ ```c
700
+ struct reb_simulation* r = reb_simulation_create();
701
+ r->integrator = REB_INTEGRATOR_LEAPFROG;
702
+ r->ri_leapfrog.order = 8; // 2, 4, 6, or 8
703
+ ```
704
+
705
+ === "Python"
706
+ ```python
707
+ sim = rebound.Simulation()
708
+ sim.integrator = "leapfrog"
709
+ sim.ri_leapfrog.order = 8 # 2, 4, 6, or 8
710
+ ```
711
+
712
+ ## Symplectic Epicycle Integrator (SEI)
713
+ `REB_INTEGRATOR_SEI`
714
+
715
+ Symplectic Epicycle Integrator (SEI), mixed variable symplectic integrator for the shearing sheet, second order, Rein & Tremaine 2011. The `reb_integrator_sei` structure contains the configuration and data structures used by the Symplectic Epicycle Integrator (SEI).
716
+
717
+ `double OMEGA`
718
+ : Epicyclic/orbital frequency. This can be set as follows:
719
+ === "C"
720
+ ```c
721
+ struct reb_simulation* r = reb_simulation_create();
722
+ r->integrator = REB_INTEGRATOR_SEI;
723
+ r->ri_sei.OMEGA = 1.0;
724
+ ```
725
+
726
+ === "Python"
727
+ ```python
728
+ sim = rebound.Simulation()
729
+ sim.integrator = "sei"
730
+ sim.ri_sei.OMEGA = 1.0
731
+ ```
732
+
733
+ `double OMEGAZ`
734
+ : Epicyclic frequency in vertical direction. Defaults to `OMEGA` if not set.
735
+
736
+ All other members of this structure are only for internal use and should not be changed manually.
737
+
738
+
739
+ ## No integrator
740
+ Sometimes it might make sense to simply not advance any particle positions or velocities. By selecting this integrator, one can still perform integration steps, but particles will not move.
741
+
742
+ Here is how to do that:
743
+ === "C"
744
+ ```c
745
+ struct reb_simulation* r = reb_simulation_create();
746
+ r->integrator = REB_INTEGRATOR_NONE;
747
+ ```
748
+
749
+ === "Python"
750
+ ```python
751
+ sim = rebound.Simulation()
752
+ sim.integrator = "none"
753
+ ```
754
+
755
+ ## WHFast512
756
+
757
+ WHFast512 is a symplectic Wisdom-Holman integrator.
758
+ It is using Single Instruction Multiple Data (SIMD) parallelism and 512-bit Advanced Vector Extensions (AVX512) to speed up the integration of planetary systems by up to 4.7x compared to the standard version of WHFast.
759
+
760
+ !!! warning "Important"
761
+
762
+ To use WHFast512 you need to compile and run REBOUND on a computer that has a CPU which supports AVX512 instructions.
763
+ You will see an error message if you try to use WHFast512 but have not compiled REBOUND with the AVX512 flag.
764
+ We describe below how to do this for both the C and python versions of REBOUND below.
765
+
766
+ To find out if your CPU supports AVX512 instructions, check for the AVX512 flags by running
767
+ ```bash
768
+ cat /proc/cpuinfo | grep avx512
769
+ ```
770
+
771
+ Note that you can read Simulationarchives of simulations which used WHFast512 on machines that do not support AVX512 instruction.
772
+ If a synchronization is required, it will be performed with the standard WHFast integrator.
773
+
774
+
775
+ === "C"
776
+ To turn on the AVX512 flag, go to the Makefile in problem directory. Add this line at the top:
777
+ ```
778
+ export AVX512=1
779
+ ```
780
+ To explicitly turn AVX512 off, add
781
+ ```
782
+ export AVX512=0
783
+ ```
784
+ Also make sure to add the `-march=native` flag to the compiler. This will optimize your code (and enable AVX512 instruction) for the specific CPU you're using.
785
+ ```
786
+ export OPT=-march=native
787
+ ```
788
+ Then, clean your build directory and (re)-build REBOUND with
789
+ ```bash
790
+ make clean
791
+ make
792
+ ```
793
+
794
+ === "Python"
795
+ To use WHFast512 from python, you need to compile REBOUND with AVX512 instructions enabled.
796
+ They are disabled by default and enabled with the AVX512 environment variable.
797
+ To install the latest release of REBOUND on pypi use:
798
+ ```bash
799
+ export AVX512=1
800
+ pip install rebound
801
+ ```
802
+ Alternatively, you can download the latest development version of REBOUND.
803
+ Then set the AVX512 environment variable and install REBOUND by running
804
+ ```bash
805
+ export AVX512=1
806
+ pip install -e .
807
+ ```
808
+ from the main directory.
809
+
810
+ Once you have compiled REBOUND with AVX512 enabled, you can use WHFast512 like any other integrator:
811
+
812
+ === "C"
813
+ ```c
814
+ struct reb_simulation* r = reb_simulation_create();
815
+ r->integrator = REB_INTEGRATOR_WHFAST512;
816
+ ```
817
+
818
+ === "Python"
819
+ ```python
820
+ sim = rebound.Simulation()
821
+ sim.integrator = "whfast512"
822
+ ```
823
+
824
+ See also [this example](../c_examples/whfast512_solar_system) on how to use WHFast512.
825
+ If you are interested in integrating 2 or 4 planet systems in parallel, see [this example](../c_examples/whfast512_2_planets).
826
+
827
+ To allow for the best performance, WHFast512 has certain limitations that WHFast does not have.
828
+
829
+ - The number of particles cannot exceed 9 (1 star and 8 planets) and needs to be constant.
830
+ - Although you can use WHFast512 with any number of planets (up to 8), the performance is best if the system has either 2, 4, or 8 planets.
831
+ - The gravitational constant needs to be exactly equal to 1. Note that you can always [rescale](../units/) your system such that G=1.
832
+ - The integrator always combines the first and last drift step (`safe_mode=0` for WHFast).
833
+ - No variational or test particles are supported (although a particle can have mass 0).
834
+ - MEGNO and other chaos indicators are not supported.
835
+ - WHFast512 always uses democratic heliocentric coordinates. Jacobi coordinates are not supported.
836
+ - The timestep needs to be constant and the `exact_finish_time` flag needs to be set to 0. To change the timestep, first synchronize the simulation, then call `reb_simulation_reset_integrator()`.
837
+ - The masses of all particles need to be constant. To change the masses, first synchronize the simulation, then call `reb_simulation_reset_integrator()`.
838
+ - Additional forces (other than the GR potential) and REBOUNDx are not supported.
839
+
840
+
841
+ The setting for WHFast512 are stored in the `reb_integrator_whfast512` structure, which itself is part of the simulation structure.
842
+ The following settings are available:
843
+
844
+ `unsigned int keep_unsynchronized`
845
+ : This flag determines if democratic heliocentric coordinates are re-used after subsequent calls to `reb_simulation_integrate()`. The default is 0. This makes WHFast512 recalculate democratic heliocentric coordinates at the beginning of each `reb_simulation_integrate()` call. Set this flag to 1 if you want to continue an integration using unsynchronized democratic heliocentric coordinates. This is useful if you require outputs (and therefore synchronization) but don't want the integration to be affected by the output to allow for bit-wise reproducibility.
846
+
847
+ `unsigned int gr_potential`
848
+ : This flag determines if an additional $1/r^2$ potential is included in the force calculation. The default is 0. Set to 1 to turn on the potential. This can be used to mimic general relativistic precession. Note that this feature assumes [units](../units/) of AU and year/2pi.
849
+
850
+ `unsigned int N_systems`
851
+ : This flag determines how many systems are integrated in parallel. Possible values are 1, 2, or 4. By default this is set to 1 which means WHFast512 is integrating only one system at a time. If your system has fewer than 5 planets, then you can use WHFast512 to integrate 2 systems in parallel. If your system has fewer than 3 planets, then you can use WHFast512 to integrate 4 systems in parallel. If multiple systems are integrated at the same time, particles must be added in the following order: Star 1, Planet, Planet, Star 2, Planet, Planet, ... For more information see the [this example](../c_examples/whfast512_2_planets).
852
+
rebound/source/docs/ipython_examples/AdvWHFast.ipynb ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {
6
+ "deletable": true,
7
+ "editable": true
8
+ },
9
+ "source": [
10
+ "# Advanced settings for WHFast: Extra speed, accuracy, and additional forces\n",
11
+ "\n",
12
+ "There are several performance enhancements one can make to WHFast. However, each one has pitfalls that an inexperienced user can unwittingly fall into. We therefore chose safe default settings that make the integrator difficult to misuse. **This makes the default WHFast substantially slower and less accurate than it can be**. Here we describe how to alter the integrator settings to improve WHFast's performance.\n",
13
+ "\n",
14
+ "**TL;DR**\n",
15
+ "\n",
16
+ "As long as \n",
17
+ "\n",
18
+ "1. you don't add, remove or otherwise modify particles between timesteps\n",
19
+ "2. you get your outputs by passing a list of output times ahead of time and access the `particles` pointer between calls to `sim.integrate()` (see, e.g., the Visualization section of [WHFast.ipynb](../WHFast))\n",
20
+ "\n",
21
+ "you can set `sim.ri_whfast.safe_mode = 0` to get a substantial performance boost. Under the same stipulations, you can set `sim.ri_whfast.corrector = 11` to get much higher accuracy, at a nearly negligible loss of performance (as long as there are many timesteps between outputs).\n",
22
+ "\n",
23
+ "If you want to modify particles, or if the code breaks with these advanced settings, read below for details, and check out the Common mistake with WHFast section at the bottom of [WHFast.ipynb](../WHFast)."
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "markdown",
28
+ "metadata": {
29
+ "deletable": true,
30
+ "editable": true
31
+ },
32
+ "source": [
33
+ "**The Wisdom-Holman algorithm**\n",
34
+ "\n",
35
+ "In order to understand and apply the various integrator flags, we need to first understand the Wisdom-Holman scheme (see, e.g., Wisdom & Holman 1991, or Rein & Tamayo 2015 for more details).\n",
36
+ "\n",
37
+ "The Wisdom-Holman algorithm consists of alternating *Keplerian* steps that evolve particles on their two-body Keplerian orbits around the star with *interaction* steps that apply impulses to the particles' velocities from the interactions between bodies. The basic algorithm for a single timestep $dt$ is a Leapfrog Drift-Kick-Drift scheme with an *interaction* kick over the full $dt$ sandwiched between half timesteps of *Keplerian* drift:\n",
38
+ "\n",
39
+ "$H_{Kepler}(dt/2)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt/2)$\n",
40
+ "\n",
41
+ "Timesteps like the one above are then concatenated over the full integration:\n",
42
+ "\n",
43
+ "$H_{Kepler}(dt/2)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt/2)$ $H_{Kepler}(dt/2)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt/2)$ ... $H_{Kepler}(dt/2)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt/2)$"
44
+ ]
45
+ },
46
+ {
47
+ "cell_type": "markdown",
48
+ "metadata": {
49
+ "deletable": true,
50
+ "editable": true
51
+ },
52
+ "source": [
53
+ "**Combining Kepler steps and synchronizing**\n",
54
+ "\n",
55
+ "It turns out that Kepler steps take longer than interaction steps as long as you don't have many planets, so an obvious and important performance boost would be to combine adjacent Kepler half-steps into full ones, i.e.:\n",
56
+ "\n",
57
+ "$H_{Kepler}(dt/2)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt) ... \\:H_{Interaction}(dt)\\:H_{Kepler}(dt/2)$\n",
58
+ "\n",
59
+ "The issue is that if you were to, say, output the state of the particles as the simulation progressed, the positions would not correspond to anything real, since the beginning (or end) of one of the full $H_{Kepler}(dt)$ steps corresponds to some intermediate step in an abstract sequence of calculations for a given timestep. In order to get the particles' actual positions, we would have to calculate to the end the timestep we want the output for by splitting a full *Kepler* step back into two half-steps, e.g.,\n",
60
+ "\n",
61
+ "$H_{Kepler}(dt/2)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt)\\:H_{Interaction}(dt)\\:H_{Kepler}(dt/2) \\text{**PRINT OUTPUT**} H_{Kepler}(dt/2) H_{Interaction}(dt)\\:H_{Kepler}(dt)$...\n",
62
+ "\n",
63
+ "We call this step of reinserting half-Kepler steps to obtain the physical state of the particles *synchronizing*. This must be done whenever the **actual** states of the particles are required, e.g., before every output, or if one wanted to use the particles' states to compute additional changes to the particle orbits between timesteps. It is also necessary to synchronize each timestep whenever the MEGNO chaos indicator is being computed.\n",
64
+ "\n",
65
+ "**Conversions between Jacobi and Inertial Coordinates**\n",
66
+ "\n",
67
+ "It turns out that the most convenient coordinate system to work in for performing the Kepler steps is often Jacobi coordinates (see, e.g., 9.5.4 of Murray & Dermott). WHFast therefore works in Jacobi coordinates by default, converting to inertial coordinates when it needs to (e.g. for output, and for doing the direct gravity calculation in the interaction step, which is most easily done in inertial coordinates).\n",
68
+ "\n",
69
+ "One feature of WHFast is that it works in whatever inertial coordinate system you choose for your initial conditions. This means that whatever happens behind the scenes, the user always gets the particles' inertial coordinates at the front end. At the beginning of every timestep, WHFast therefore has to somehow obtain the Jacobi coordinates. The straightforward thing would be to convert from the inertial coordinates to Jacobi coordinates every timestep, but these conversions slow things down, and they represent extra operations that grow the round-off error.\n",
70
+ "\n",
71
+ "WHFast therefore stores the Jacobi coordinates internally throughout the time it is running, and only recalculates Jacobi coordinates from the inertial ones if told to do so. Since Jacobi coordinates reference particles to the center of mass of all the particles with indices lower than their own (typically all the particles interior to them), the main reason you would have to recalculate Jacobi coordinates is if between timesteps you choose to somehow change the particles' positions or velocities (give them kicks in addition to their mutual gravity), or change the particles' masses. \n",
72
+ "\n",
73
+ "**Overriding the defaults**\n",
74
+ "\n",
75
+ "Let's begin by importing rebound, and defining a simple function to reset rebound and initialize a new simulation with a test case,"
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "code",
80
+ "execution_count": 2,
81
+ "metadata": {
82
+ "collapsed": false,
83
+ "deletable": true,
84
+ "editable": true
85
+ },
86
+ "outputs": [],
87
+ "source": [
88
+ "import rebound\n",
89
+ "import numpy as np\n",
90
+ "def test_case():\n",
91
+ " sim = rebound.Simulation()\n",
92
+ " sim.integrator = 'whfast'\n",
93
+ " sim.add(m=1.) # add the Sun\n",
94
+ " sim.add(m=3.e-6,e=0.99, a=1.) # add Earth\n",
95
+ " sim.move_to_com()\n",
96
+ " sim.dt = 0.2\n",
97
+ " return sim"
98
+ ]
99
+ },
100
+ {
101
+ "cell_type": "markdown",
102
+ "metadata": {
103
+ "deletable": true,
104
+ "editable": true
105
+ },
106
+ "source": [
107
+ "By default WHFast synchronizes and recalculates the Jacobi coordinates from the inertial ones every timestep. This guarantees that the user always gets physical particle states for output, and ensures reliable output if the user decides to, e.g., grow the particles' masses between timesteps. \n",
108
+ "\n",
109
+ "Now that you understand the pitfalls, if you want to boost WHFast's performance, you simply set"
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "code",
114
+ "execution_count": 3,
115
+ "metadata": {
116
+ "collapsed": false,
117
+ "deletable": true,
118
+ "editable": true
119
+ },
120
+ "outputs": [],
121
+ "source": [
122
+ "sim = test_case()\n",
123
+ "sim.ri_whfast.safe_mode = 0"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "markdown",
128
+ "metadata": {
129
+ "deletable": true,
130
+ "editable": true
131
+ },
132
+ "source": [
133
+ "Now it becomes the user's responsibility to appropriately synchronize and recalculate jacobi coordinates when needed. You can tell WHFast to recalculate Jacobi coordinates for a given timestep (say after you change a particle's mass) with the `sim.ri_whfast.recalculate_coordinates_this_timestep` flag. After it recalculates Jacobi coordinates, WHFast will reset this flag to zero, so you just set it each time you mess with the particles."
134
+ ]
135
+ },
136
+ {
137
+ "cell_type": "code",
138
+ "execution_count": 4,
139
+ "metadata": {
140
+ "collapsed": false,
141
+ "deletable": true,
142
+ "editable": true
143
+ },
144
+ "outputs": [
145
+ {
146
+ "name": "stdout",
147
+ "output_type": "stream",
148
+ "text": [
149
+ "safe_mode = 1\n",
150
+ "---------------------------------\n",
151
+ "REBOUND version: \t3.4.0\n",
152
+ "REBOUND built on: \tMay 31 2017 11:53:50\n",
153
+ "Number of particles: \t2\n",
154
+ "Selected integrator: \twhfast\n",
155
+ "Simulation time: \t6.2831853071795858e+05\n",
156
+ "Current timestep: \t0.200000\n",
157
+ "---------------------------------\n",
158
+ "<rebound.Particle object, m=1.0 x=3.8952737650111065e-06 y=-4.025686466113066e-07 z=0.0 vx=2.1862005456099384e-06 vy=9.999414128270949e-08 vz=0.0>\n",
159
+ "<rebound.Particle object, m=3e-06 x=-1.2984227143844442 y=0.1341896612527594 z=0.0 vx=-0.7287335151973472 vy=-0.0333313804272124 vz=0.0>\n",
160
+ "---------------------------------\n",
161
+ "Safe integration took 1.4043679237365723 seconds\n",
162
+ "---------------------------------\n",
163
+ "REBOUND version: \t3.4.0\n",
164
+ "REBOUND built on: \tMay 31 2017 11:53:50\n",
165
+ "Number of particles: \t2\n",
166
+ "Selected integrator: \twhfast\n",
167
+ "Simulation time: \t6.2831853071795858e+05\n",
168
+ "Current timestep: \t0.200000\n",
169
+ "---------------------------------\n",
170
+ "<rebound.Particle object, m=1.0 x=3.89491388755522e-06 y=-4.0258518356289257e-07 z=0.0 vx=2.18648433924743e-06 vy=9.996480978405334e-08 vz=0.0>\n",
171
+ "<rebound.Particle object, m=3e-06 x=-1.298304629185073 y=0.13419506118763086 z=0.0 vx=-0.7288281130824766 vy=-0.03332160326135111 vz=0.0>\n",
172
+ "---------------------------------\n",
173
+ "Manual integration took 0.8836901187896729 seconds\n"
174
+ ]
175
+ }
176
+ ],
177
+ "source": [
178
+ "import time\n",
179
+ "Porb = 2*np.pi # orbital period for Earth, using units of G = 1, solar masses, AU and yr/2pi\n",
180
+ "\n",
181
+ "sim = test_case()\n",
182
+ "print(\"safe_mode = {0}\".format(sim.ri_whfast.safe_mode))\n",
183
+ "start_time = time.time()\n",
184
+ "sim.integrate(1.e5*Porb)\n",
185
+ "sim.status()\n",
186
+ "print(\"Safe integration took {0} seconds\".format(time.time() - start_time))\n",
187
+ "\n",
188
+ "sim = test_case()\n",
189
+ "sim.ri_whfast.safe_mode = 0\n",
190
+ "start_time = time.time()\n",
191
+ "sim.integrate(1.e5*Porb)\n",
192
+ "sim.status()\n",
193
+ "print(\"Manual integration took {0} seconds\".format(time.time() - start_time))"
194
+ ]
195
+ },
196
+ {
197
+ "cell_type": "markdown",
198
+ "metadata": {
199
+ "collapsed": true,
200
+ "deletable": true,
201
+ "editable": true
202
+ },
203
+ "source": [
204
+ "In our test case with a single planet, there is effectively no interaction step, and by combining Kepler steps we get almost the full factor of 2 speedup we expect. Because Kepler steps are expensive (by virtue of having to solve the transcendental Kepler equation), this will always be an important performance boost for few-planet cases.\n",
205
+ "\n",
206
+ "Note that one case where REBOUND needs to synchronize every timestep is if you're using the MEGNO chaos indicator. So if you call"
207
+ ]
208
+ },
209
+ {
210
+ "cell_type": "code",
211
+ "execution_count": 5,
212
+ "metadata": {
213
+ "collapsed": true,
214
+ "deletable": true,
215
+ "editable": true
216
+ },
217
+ "outputs": [],
218
+ "source": [
219
+ "sim.init_megno()"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "markdown",
224
+ "metadata": {
225
+ "deletable": true,
226
+ "editable": true
227
+ },
228
+ "source": [
229
+ "REBOUND will synchronize every timestep even if you set `sim.ri_whfast.safe_mode = 0` and never explicitly call `sim.synchronize()`."
230
+ ]
231
+ },
232
+ {
233
+ "cell_type": "markdown",
234
+ "metadata": {
235
+ "collapsed": true,
236
+ "deletable": true,
237
+ "editable": true
238
+ },
239
+ "source": [
240
+ "**Modifying particles/forces**\n",
241
+ "\n",
242
+ "Again, if performance is a factor in your simulations, you would not want to write a custom stepper in python that modifies the particles, since this will be very slow. You could either write a modified C version of `reb_simulation_integrate` in `src/librebound.c` (the flags are defined in `librebound.h`, and have the same name as the python ones, just without `sim.` in front), or you can use the REBOUNDXF library, which takes care of this for you and supports many typically used modifications. We again illustrate a simple scheme with python code:"
243
+ ]
244
+ },
245
+ {
246
+ "cell_type": "code",
247
+ "execution_count": 6,
248
+ "metadata": {
249
+ "collapsed": true,
250
+ "deletable": true,
251
+ "editable": true
252
+ },
253
+ "outputs": [],
254
+ "source": [
255
+ "sim = test_case()\n",
256
+ "sim.ri_whfast.safe_mode = 0\n",
257
+ "def integrate_mod(sim, t_final):\n",
258
+ " while sim.t < t_final:\n",
259
+ " sim.step()\n",
260
+ " sim.particles[1].m += 1.e-10\n",
261
+ " sim.ri_whfast.recalculate_coordinates_this_timestep = 1\n",
262
+ " sim.synchronize()"
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "markdown",
267
+ "metadata": {
268
+ "deletable": true,
269
+ "editable": true
270
+ },
271
+ "source": [
272
+ "Here, because we grow the mass of the planet every timestep, we have to recalculate Jacobi coordinates every timestep (since they depend on the masses of the particles). We therefore manually set the flag to recalculate them the next timestep every time we make a change. Here we would actually get the same result if we just left `sim.ri_whfast.safe_mode = 1`, since when recalculating Jacobi coordinates, WHFast automatically has to synchronize in order to get real positions and velocities for the planets. In this case WHFast is therefore synchronizing and recalculating Jacobi coordinates every timestep.\n",
273
+ "\n",
274
+ "But imagine now that instead of growing the mass, we continually add an impulse to vx:"
275
+ ]
276
+ },
277
+ {
278
+ "cell_type": "code",
279
+ "execution_count": 7,
280
+ "metadata": {
281
+ "collapsed": false,
282
+ "deletable": true,
283
+ "editable": true
284
+ },
285
+ "outputs": [],
286
+ "source": [
287
+ "sim = test_case()\n",
288
+ "sim.ri_whfast.safe_mode = 0\n",
289
+ "def integrate_mod(sim, t_final):\n",
290
+ " while sim.t < t_final:\n",
291
+ " sim.step()\n",
292
+ " sim.particles[1].vx += 1.e-10*sim.dt\n",
293
+ " sim.ri_whfast.recalculate_coordinates_this_timestep = 1\n",
294
+ " sim.synchronize()"
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {
300
+ "deletable": true,
301
+ "editable": true
302
+ },
303
+ "source": [
304
+ "This would not give accurate results, because the `sim.particles[1].vx` we access after `sim.step()` isn't a physical velocity (it's missing a half-Kepler step). It's basically at an intermediate point in the calculation. In order to make this work, one would call `sim.synchronize()` between `sim.step()` and accessing `sim.particles[1].vx`, to ensure the velocity is physical."
305
+ ]
306
+ },
307
+ {
308
+ "cell_type": "markdown",
309
+ "metadata": {
310
+ "deletable": true,
311
+ "editable": true
312
+ },
313
+ "source": [
314
+ "**Symplectic correctors**\n",
315
+ "\n",
316
+ "Symplectic correctors make the Wisdom-Holman scheme higher order (without symplectic correctors it's second order). The great thing about them is that they only need to get applied when you synchronize. So if you just need to synchronize to output, and there are many timesteps between outputs, they represent a very small performance loss for a huge boost in accuracy (compare for example the green line (11th order corrector) to the red line (no corrector) in Fig. 4 of Rein & Tamayo 2015--beyond the right of the plot, where the round-off errors dominate, the two lines would rise in unison). We have implemented symplectic correctors up to order 11. You can set the order with (must be an odd number), e.g.,"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": 8,
322
+ "metadata": {
323
+ "collapsed": true,
324
+ "deletable": true,
325
+ "editable": true
326
+ },
327
+ "outputs": [],
328
+ "source": [
329
+ "sim.ri_whfast.corrector = 11"
330
+ ]
331
+ },
332
+ {
333
+ "cell_type": "markdown",
334
+ "metadata": {
335
+ "deletable": true,
336
+ "editable": true
337
+ },
338
+ "source": [
339
+ "By default, WHFast does not use correctors, i.e., sim.integrator_whfast_corrector = 0. This is because the default is also to synchronize every timestep. An Nth order corrector does N-1 Kepler steps of various sizes, so an 11th order corrector done every timestep would increase the number of Kepler steps by an order of magnitude, making WHFast unacceptably slow. So keep in mind that if you're doing modifications that require recalculating jacobi coordinates or synchronizing every timestep, you should turn off symplectic correctors (the default) unless you really need the accuracy."
340
+ ]
341
+ },
342
+ {
343
+ "cell_type": "markdown",
344
+ "metadata": {},
345
+ "source": [
346
+ "**Changing the internal coordinate system**\n",
347
+ "\n",
348
+ "WHFast by default uses Jacobi coordinates internally. This works well for planetary systems which are stable and orbits are not crossing. However, in some cases a different coordinate system might perform better. WHFast also support so-called democratic heliocentric coordinates and the so called WHDS coordinates. For more information on these coordinates systems [see Hernandez and Dehnen (2016)](https://arxiv.org/abs/1612.05329). To select a different coordinate system, use the following syntax:"
349
+ ]
350
+ },
351
+ {
352
+ "cell_type": "code",
353
+ "execution_count": 9,
354
+ "metadata": {
355
+ "collapsed": false
356
+ },
357
+ "outputs": [],
358
+ "source": [
359
+ "sim.ri_whfast.coordinates = 'jacobi' #default\n",
360
+ "sim.ri_whfast.coordinates = 'democraticheliocentric' \n",
361
+ "sim.ri_whfast.coordinates = 'whds' "
362
+ ]
363
+ },
364
+ {
365
+ "cell_type": "markdown",
366
+ "metadata": {},
367
+ "source": [
368
+ "Note that symplectic corrector are only compatible with Jacobi coordinates because both democratic heliocentric and WHDS include a so called jump step."
369
+ ]
370
+ },
371
+ {
372
+ "cell_type": "markdown",
373
+ "metadata": {
374
+ "deletable": true,
375
+ "editable": true
376
+ },
377
+ "source": [
378
+ "**Warning messages**\n",
379
+ "\n",
380
+ "If you choose a timestep that is larger than the smallest dynamical timescale and WHFast has difficulties to solve the Kepler problem, you will receive a warning message."
381
+ ]
382
+ },
383
+ {
384
+ "cell_type": "code",
385
+ "execution_count": 8,
386
+ "metadata": {
387
+ "collapsed": false,
388
+ "deletable": true,
389
+ "editable": true
390
+ },
391
+ "outputs": [
392
+ {
393
+ "name": "stderr",
394
+ "output_type": "stream",
395
+ "text": [
396
+ "/Users/rein/git/rebound/rebound/simulation.py:305: RuntimeWarning: WHFast convergence issue. Timestep is larger than at least one orbital period.\n",
397
+ " warnings.warn(msg[1:], RuntimeWarning)\n"
398
+ ]
399
+ }
400
+ ],
401
+ "source": [
402
+ "sim = test_case()\n",
403
+ "sim.dt = 1000.\n",
404
+ "sim.integrate(1000.)"
405
+ ]
406
+ },
407
+ {
408
+ "cell_type": "code",
409
+ "execution_count": null,
410
+ "metadata": {
411
+ "collapsed": true,
412
+ "deletable": true,
413
+ "editable": true
414
+ },
415
+ "outputs": [],
416
+ "source": []
417
+ }
418
+ ],
419
+ "metadata": {
420
+ "kernelspec": {
421
+ "display_name": "Python 3",
422
+ "language": "python",
423
+ "name": "python3"
424
+ },
425
+ "language_info": {
426
+ "codemirror_mode": {
427
+ "name": "ipython",
428
+ "version": 3
429
+ },
430
+ "file_extension": ".py",
431
+ "mimetype": "text/x-python",
432
+ "name": "python",
433
+ "nbconvert_exporter": "python",
434
+ "pygments_lexer": "ipython3",
435
+ "version": "3.5.2"
436
+ }
437
+ },
438
+ "nbformat": 4,
439
+ "nbformat_minor": 0
440
+ }
rebound/source/docs/ipython_examples/ChaoticHyperion.ipynb ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "6882e778",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Chaotic Hyperion\n",
9
+ "In this example, we simulate the spin of Hyperion. The spin evolution is governed by an ordinary differential equation that is coupled to the moon's orbit. \n",
10
+ "\n",
11
+ "We start by importing REBOUND, numpy and matplotlib."
12
+ ]
13
+ },
14
+ {
15
+ "cell_type": "code",
16
+ "execution_count": 1,
17
+ "id": "e350dbbb",
18
+ "metadata": {
19
+ "scrolled": true
20
+ },
21
+ "outputs": [],
22
+ "source": [
23
+ "import rebound\n",
24
+ "import numpy as np\n",
25
+ "import matplotlib.pyplot as plt"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "markdown",
30
+ "id": "0bc568b2",
31
+ "metadata": {},
32
+ "source": [
33
+ "The right hand side of ODEs can be implemented in either python or in C. Although not absolutely necessary for this example, we here show how to implement the RHS in C. This is often significantly faster than using a python callback function. \n",
34
+ "\n",
35
+ "We use a simple spin model which is one second order ODE, or a set of two coupled first order ODEs. For more details on the physics behind this model, see Danby (1962), Goldreich and Peale (1966), and Wisdom and Peale (1983). The RHS of this set of ODEs implemented in C is:"
36
+ ]
37
+ },
38
+ {
39
+ "cell_type": "code",
40
+ "execution_count": 2,
41
+ "id": "79a48333",
42
+ "metadata": {},
43
+ "outputs": [
44
+ {
45
+ "name": "stdout",
46
+ "output_type": "stream",
47
+ "text": [
48
+ "Overwriting rhs.c\n"
49
+ ]
50
+ }
51
+ ],
52
+ "source": [
53
+ "%%writefile rhs.c\n",
54
+ "#include \"rebound.h\"\n",
55
+ "void derivatives(struct reb_ode* const ode, double* const yDot, const double* const y, const double t){\n",
56
+ " struct reb_orbit o = reb_orbit_from_particle(ode->r->G, ode->r->particles[1], ode->r->particles[0]);\n",
57
+ " \n",
58
+ " double omega2 = 3.*0.26; \n",
59
+ " yDot[0] = y[1];\n",
60
+ " yDot[1] = -omega2/(2.*o.d*o.d*o.d)*sin(2.*(y[0]-o.f));\n",
61
+ "}\n"
62
+ ]
63
+ },
64
+ {
65
+ "cell_type": "markdown",
66
+ "id": "33cd1c9c",
67
+ "metadata": {},
68
+ "source": [
69
+ "We now compile this into a shared library. We need the REBOUND headers and library for this. The following is a bit of hack: we just copy the files into the current folder. This works if you've installed REBOUND from the git repository. Otherwise, you'll need to find these files manually (which might depend on your python environment). "
70
+ ]
71
+ },
72
+ {
73
+ "cell_type": "code",
74
+ "execution_count": 3,
75
+ "id": "7d3c176a",
76
+ "metadata": {},
77
+ "outputs": [],
78
+ "source": [
79
+ "!cp ../src/librebound.so .\n",
80
+ "!cp ../src/rebound.h .\n",
81
+ "!gcc -c -O3 -fPIC rhs.c -o rhs.o\n",
82
+ "!gcc -L. -shared rhs.o -o rhs.so -lrebound "
83
+ ]
84
+ },
85
+ {
86
+ "cell_type": "markdown",
87
+ "id": "2421c0e7",
88
+ "metadata": {},
89
+ "source": [
90
+ "Using ctypes, we can load the library into python"
91
+ ]
92
+ },
93
+ {
94
+ "cell_type": "code",
95
+ "execution_count": null,
96
+ "id": "11736a91",
97
+ "metadata": {},
98
+ "outputs": [],
99
+ "source": [
100
+ "from ctypes import cdll\n",
101
+ "clibrhs = cdll.LoadLibrary(\"rhs.so\")"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "markdown",
106
+ "id": "37ac5371",
107
+ "metadata": {},
108
+ "source": [
109
+ "The following function is setting up the N-body simulation as well as the ODE system that governs the spin evolution. Note that we set the `derivatives` function pointer to the C function we've just compiled. You could also set this function pointer to a python function and avoid all the C complications."
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "code",
114
+ "execution_count": 133,
115
+ "id": "18043d1d",
116
+ "metadata": {},
117
+ "outputs": [],
118
+ "source": [
119
+ "def setup():\n",
120
+ " sim = rebound.Simulation()\n",
121
+ " sim.add(m=1) # Saturn\n",
122
+ " sim.add(a=1, e=0.123233) # Hyperion, massless, semi-major axis of 1\n",
123
+ " sim.integrator = \"BS\"\n",
124
+ " sim.ri_bs.eps_rel = 1e-12 # tolerance\n",
125
+ " sim.ri_bs.eps_abs = 1e-12\n",
126
+ " \n",
127
+ " ode_spin = sim.create_ode(length=2, needs_nbody=True)\n",
128
+ " ode_spin.y[0] = 0.01 # initial conditions that lead to chaos\n",
129
+ " ode_spin.y[1] = 1\n",
130
+ " ode_spin.derivatives = clibrhs.derivatives\n",
131
+ " \n",
132
+ " return sim, ode_spin"
133
+ ]
134
+ },
135
+ {
136
+ "cell_type": "markdown",
137
+ "id": "85c097cf",
138
+ "metadata": {},
139
+ "source": [
140
+ "We will create two simulations that are slightly offset from each other."
141
+ ]
142
+ },
143
+ {
144
+ "cell_type": "code",
145
+ "execution_count": null,
146
+ "id": "8182b908",
147
+ "metadata": {},
148
+ "outputs": [],
149
+ "source": [
150
+ "sim, ode_spin = setup()\n",
151
+ "sim2, ode_spin2 = setup()\n",
152
+ "ode_spin2.y[0] += 1e-8 # small perturbation"
153
+ ]
154
+ },
155
+ {
156
+ "cell_type": "markdown",
157
+ "id": "c597773f",
158
+ "metadata": {},
159
+ "source": [
160
+ "With these two simulations, we can measure the growing divergence of nearby trajectories, a key feature of chaos."
161
+ ]
162
+ },
163
+ {
164
+ "cell_type": "code",
165
+ "execution_count": 149,
166
+ "id": "4eb25927",
167
+ "metadata": {},
168
+ "outputs": [],
169
+ "source": [
170
+ "times = 2.*np.pi*np.linspace(0,30,100) # a couple of orbits\n",
171
+ "obliq = np.zeros((len(times)))\n",
172
+ "obliq2 = obliq.copy()\n",
173
+ "\n",
174
+ "for i, t in enumerate(times):\n",
175
+ " sim.integrate(t, exact_finish_time=1)\n",
176
+ " sim2.integrate(t, exact_finish_time=1) \n",
177
+ " obliq[i] = ode_spin.y[0]\n",
178
+ " obliq2[i] = ode_spin2.y[0]"
179
+ ]
180
+ },
181
+ {
182
+ "cell_type": "markdown",
183
+ "id": "98a92abf",
184
+ "metadata": {},
185
+ "source": [
186
+ "Finally, let us plot the divergence as a function of time."
187
+ ]
188
+ },
189
+ {
190
+ "cell_type": "code",
191
+ "execution_count": 150,
192
+ "id": "13ac8f3a",
193
+ "metadata": {},
194
+ "outputs": [
195
+ {
196
+ "data": {
197
+ "image/png": "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\n",
198
+ "text/plain": [
199
+ "<Figure size 432x288 with 1 Axes>"
200
+ ]
201
+ },
202
+ "metadata": {
203
+ "needs_background": "light"
204
+ },
205
+ "output_type": "display_data"
206
+ }
207
+ ],
208
+ "source": [
209
+ "fig, ax = plt.subplots(1,1)\n",
210
+ "ax.set_xlabel(\"time [orbits]\")\n",
211
+ "ax.set_ylabel(\"obliquity difference [degrees]\")\n",
212
+ "ax.set_yscale(\"log\")\n",
213
+ "ax.set_ylim([1e-8,1e2])\n",
214
+ "o1 = np.remainder((obliq-obliq2)*180/np.pi,360.)\n",
215
+ "o2 = np.remainder((obliq2-obliq)*180/np.pi,360.)\n",
216
+ "ax.scatter(times/np.pi/2.,np.minimum(o1,o2))\n",
217
+ "ax.plot(times/np.pi/2.,1e-8/np.pi*180.*np.exp(times/(np.pi*2.)/1.2),color=\"black\");"
218
+ ]
219
+ },
220
+ {
221
+ "cell_type": "markdown",
222
+ "id": "c2bc381f",
223
+ "metadata": {},
224
+ "source": [
225
+ "On a log-linear scale, we see that the divergence follows a straight line, indicating exponential growth. The Lyapunov timescale is approximately 1.2 orbits. About 25 days! (Wikipedia says ~30 days which is close enough given the very simplistic model)"
226
+ ]
227
+ }
228
+ ],
229
+ "metadata": {
230
+ "kernelspec": {
231
+ "display_name": "Python 3",
232
+ "language": "python",
233
+ "name": "python3"
234
+ },
235
+ "language_info": {
236
+ "codemirror_mode": {
237
+ "name": "ipython",
238
+ "version": 3
239
+ },
240
+ "file_extension": ".py",
241
+ "mimetype": "text/x-python",
242
+ "name": "python",
243
+ "nbconvert_exporter": "python",
244
+ "pygments_lexer": "ipython3",
245
+ "version": "3.8.9"
246
+ }
247
+ },
248
+ "nbformat": 4,
249
+ "nbformat_minor": 5
250
+ }
rebound/source/docs/ipython_examples/Cheartbeat.ipynb ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Using a C Heartbeat function\n",
8
+ "The heartbeat function of a REBOUND simulation gets called after every timestep. There are many different things you can do in a heartbeat function, for example creating outputs, adding particles, adjusting parameters that depend on time, etc. REBOUND supports heartbeat functions in both its C and python interface. \n",
9
+ "\n",
10
+ "A python heartbeat function can sometimes become the bottleneck of a simulation because it gets called every single timestep. This tutorial shows you how to implement the heartbeat function in C, then link it to REBOUND using python. Note that alternatively you can of course always just use the C version of REBOUND directly and never bother with python at all.\n",
11
+ "\n",
12
+ "We start by creating a REBOUND simulation which contains the planets of our Solar System as a test case."
13
+ ]
14
+ },
15
+ {
16
+ "cell_type": "code",
17
+ "execution_count": 1,
18
+ "metadata": {},
19
+ "outputs": [],
20
+ "source": [
21
+ "import rebound\n",
22
+ "sim = rebound.Simulation()\n",
23
+ "rebound.data.add_solar_system(sim)\n",
24
+ "sim.integrator = \"whfast\"\n",
25
+ "sim.dt = sim.particles[1].P/30.13 # About 30 steps for each Mercury Orbit"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "markdown",
30
+ "metadata": {},
31
+ "source": [
32
+ "Let us first create a simple heartbeat function in python. It simply calculates the eccentricity of Mercury (you could do something with it, here we just calculate it and then ignore it)."
33
+ ]
34
+ },
35
+ {
36
+ "cell_type": "code",
37
+ "execution_count": 3,
38
+ "metadata": {},
39
+ "outputs": [
40
+ {
41
+ "name": "stdout",
42
+ "output_type": "stream",
43
+ "text": [
44
+ "Eccentricity: 0.205636 \n"
45
+ ]
46
+ }
47
+ ],
48
+ "source": [
49
+ "# We use a global variable to store the value of the eccentricity\n",
50
+ "e = 0 \n",
51
+ "def heartbeat(sim_pointer):\n",
52
+ " global e\n",
53
+ " # The function argument is a pointer to the simulation:\n",
54
+ " # Here we get its contents:\n",
55
+ " sim = sim_pointer.contents \n",
56
+ " e = sim.particles[1].e\n",
57
+ "sim.heartbeat = heartbeat\n",
58
+ "sim.integrate(sim.t+1)\n",
59
+ "print(\"Eccentricity: %f \" %e)"
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "markdown",
64
+ "metadata": {},
65
+ "source": [
66
+ "Let's measure how long it takes to integrate 1000 orbits:"
67
+ ]
68
+ },
69
+ {
70
+ "cell_type": "code",
71
+ "execution_count": 4,
72
+ "metadata": {},
73
+ "outputs": [
74
+ {
75
+ "name": "stdout",
76
+ "output_type": "stream",
77
+ "text": [
78
+ "Runtime: 0.474900 s\n"
79
+ ]
80
+ }
81
+ ],
82
+ "source": [
83
+ "import time\n",
84
+ "start = time.time()\n",
85
+ "sim.integrate(sim.t + sim.particles[1].P*1000)\n",
86
+ "stop = time.time()\n",
87
+ "print(\"Runtime: %f s\"%(stop-start))"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "markdown",
92
+ "metadata": {},
93
+ "source": [
94
+ "We now implement this in C. For this to work, it is best to download and work with a full REBOUND repository (download the package from github, rather than just installing the python package with pip install). \n",
95
+ "\n",
96
+ "We first write our heartbeat function in C. The following cell writes to a new file in the current directory, `heartbeat.c` (you can also use an external editor and terminal window to do the same without the jupyter magic commands):"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "code",
101
+ "execution_count": 6,
102
+ "metadata": {},
103
+ "outputs": [
104
+ {
105
+ "name": "stdout",
106
+ "output_type": "stream",
107
+ "text": [
108
+ "Overwriting heartbeat.c\n"
109
+ ]
110
+ }
111
+ ],
112
+ "source": [
113
+ "%%writefile heartbeat.c\n",
114
+ "#include \"rebound.h\"\n",
115
+ "double e =0; // global variable\n",
116
+ "void heartbeat(struct reb_simulation* sim_pointer){\n",
117
+ " struct reb_orbit orbit = reb_orbit_from_particle(sim_pointer->G, sim_pointer->particles[0], sim_pointer->particles[1]);\n",
118
+ " e = orbit.e;\n",
119
+ "}"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "Before we compile and link our heartbeat function as a shared library, we need the REBOUND header file and the shared library file. Different operating systems and compilers handles the paths to shared libraries differently. This can quickly get rather frustrating. If you're familiar with C, by all means go ahead and do it the proper way. A hack to get around most of these difficulties is to simply copy the REBOUND header and library to the current folder."
127
+ ]
128
+ },
129
+ {
130
+ "cell_type": "code",
131
+ "execution_count": 7,
132
+ "metadata": {},
133
+ "outputs": [],
134
+ "source": [
135
+ "!cp ../src/librebound.so .\n",
136
+ "!cp ../src/rebound.h ."
137
+ ]
138
+ },
139
+ {
140
+ "cell_type": "markdown",
141
+ "metadata": {},
142
+ "source": [
143
+ "If you installed REBOUND with pip, you can look up the paths to the two files in python and e.g. create symlinks to them into your working directory."
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": 8,
149
+ "metadata": {},
150
+ "outputs": [
151
+ {
152
+ "name": "stdout",
153
+ "output_type": "stream",
154
+ "text": [
155
+ "/path/to/your/venv/lib/python3.9/site-packages/rebound/../librebound.cpython-39-x86_64-linux-gnu.so\n",
156
+ "/path/to/your/venv/lib/python3.9/site-packages/rebound/rebound.h\n"
157
+ ]
158
+ }
159
+ ],
160
+ "source": [
161
+ "from pathlib import Path\n",
162
+ "print(rebound.__libpath__)\n",
163
+ "print(Path(rebound.__file__).parent / \"rebound.h\")"
164
+ ]
165
+ },
166
+ {
167
+ "cell_type": "markdown",
168
+ "metadata": {},
169
+ "source": [
170
+ "Next we can compile and link the code. `-fPIC` instructs gcc to create Position Independent Code, which might not be needed on your operating system."
171
+ ]
172
+ },
173
+ {
174
+ "cell_type": "code",
175
+ "execution_count": 9,
176
+ "metadata": {},
177
+ "outputs": [],
178
+ "source": [
179
+ "!gcc -c -O3 -fPIC heartbeat.c -o heartbeat.o"
180
+ ]
181
+ },
182
+ {
183
+ "cell_type": "code",
184
+ "execution_count": 10,
185
+ "metadata": {},
186
+ "outputs": [],
187
+ "source": [
188
+ "!gcc -L. -shared heartbeat.o -o heartbeat.so -lrebound "
189
+ ]
190
+ },
191
+ {
192
+ "cell_type": "markdown",
193
+ "metadata": {},
194
+ "source": [
195
+ "Now we load the library using ctypes."
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": 11,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "from ctypes import cdll\n",
205
+ "clibheartbeat = cdll.LoadLibrary(\"heartbeat.so\")"
206
+ ]
207
+ },
208
+ {
209
+ "cell_type": "markdown",
210
+ "metadata": {},
211
+ "source": [
212
+ "We can now finally set the function pointer in our simulation to the new heartbeat function and then run the simulation."
213
+ ]
214
+ },
215
+ {
216
+ "cell_type": "code",
217
+ "execution_count": 12,
218
+ "metadata": {},
219
+ "outputs": [],
220
+ "source": [
221
+ "sim.heartbeat = clibheartbeat.heartbeat"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": 13,
227
+ "metadata": {},
228
+ "outputs": [
229
+ {
230
+ "name": "stdout",
231
+ "output_type": "stream",
232
+ "text": [
233
+ "Runtime: 0.153589 s\n"
234
+ ]
235
+ }
236
+ ],
237
+ "source": [
238
+ "start = time.time()\n",
239
+ "sim.integrate(sim.t + sim.particles[1].P*1000)\n",
240
+ "stop = time.time()\n",
241
+ "print(\"Runtime: %f s\"%(stop-start))"
242
+ ]
243
+ },
244
+ {
245
+ "cell_type": "markdown",
246
+ "metadata": {},
247
+ "source": [
248
+ "Note that the simulation runs significantly faster using the C heartbeat function as we avoid all the python overhead.\n",
249
+ "\n",
250
+ "We can print out the value of the global variable `e` in the heartbeat library (using global variables in a shared library is not the best way to store data - all simulations will see the same variable and you could end up with unexpected behaviour if you are running multiple simulations in one python program)."
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": 14,
256
+ "metadata": {},
257
+ "outputs": [
258
+ {
259
+ "name": "stdout",
260
+ "output_type": "stream",
261
+ "text": [
262
+ "0.2057293010348337\n"
263
+ ]
264
+ }
265
+ ],
266
+ "source": [
267
+ "from ctypes import c_double\n",
268
+ "print(c_double.in_dll(clibheartbeat,\"e\").value)"
269
+ ]
270
+ },
271
+ {
272
+ "cell_type": "code",
273
+ "execution_count": null,
274
+ "metadata": {},
275
+ "outputs": [],
276
+ "source": []
277
+ }
278
+ ],
279
+ "metadata": {
280
+ "kernelspec": {
281
+ "display_name": "Python 3",
282
+ "language": "python",
283
+ "name": "python3"
284
+ },
285
+ "language_info": {
286
+ "codemirror_mode": {
287
+ "name": "ipython",
288
+ "version": 3
289
+ },
290
+ "file_extension": ".py",
291
+ "mimetype": "text/x-python",
292
+ "name": "python",
293
+ "nbconvert_exporter": "python",
294
+ "pygments_lexer": "ipython3",
295
+ "version": "3.7.7"
296
+ }
297
+ },
298
+ "nbformat": 4,
299
+ "nbformat_minor": 2
300
+ }
rebound/source/docs/ipython_examples/Checkpoints.ipynb ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Checkpoints\n",
8
+ "You can easily save and load a REBOUND simulation to a binary file. The binary file includes all information about the particles (mass, position, velocity, etc), as well as the current simulation settings such as time, integrator choice, etc.\n",
9
+ "\n",
10
+ "Let's add three particles to REBOUND and save them to a file."
11
+ ]
12
+ },
13
+ {
14
+ "cell_type": "code",
15
+ "execution_count": 1,
16
+ "metadata": {
17
+ "collapsed": false
18
+ },
19
+ "outputs": [
20
+ {
21
+ "name": "stdout",
22
+ "output_type": "stream",
23
+ "text": [
24
+ "---------------------------------\n",
25
+ "REBOUND version: \t3.8.0\n",
26
+ "REBOUND built on: \tFeb 3 2019 13:37:32\n",
27
+ "Number of particles: \t3\n",
28
+ "Selected integrator: \twhfast\n",
29
+ "Simulation time: \t0.0000000000000000e+00\n",
30
+ "Current timestep: \t0.001000\n",
31
+ "---------------------------------\n",
32
+ "<rebound.Particle object, m=1.0 x=0.0 y=0.0 z=0.0 vx=0.0 vy=0.0 vz=0.0>\n",
33
+ "<rebound.Particle object, m=1e-06 x=1.0 y=0.0 z=0.0 vx=0.0 vy=1.000000499999875 vz=0.0>\n",
34
+ "<rebound.Particle object, m=0.0 x=2.000000999999 y=0.0 z=0.0 vx=0.0 vy=0.7071081347393496 vz=0.0>\n",
35
+ "---------------------------------\n"
36
+ ]
37
+ }
38
+ ],
39
+ "source": [
40
+ "import rebound\n",
41
+ "sim = rebound.Simulation()\n",
42
+ "sim.add(m=1.)\n",
43
+ "sim.add(m=1e-6, a=1.)\n",
44
+ "sim.add(a=2.)\n",
45
+ "sim.integrator = \"whfast\"\n",
46
+ "sim.save_to_file(\"checkpoint.bin\")\n",
47
+ "sim.status()"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "The binary files are small in size and store every floating point number exactly, so you don't have to worry about efficiency or losing precision. You can make lots of checkpoints if you want!\n",
55
+ "\n",
56
+ "Let's delete the old REBOUND simulation (that frees up the memory from that simulation) and then read the binary file we just saved."
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "code",
61
+ "execution_count": 2,
62
+ "metadata": {
63
+ "collapsed": false
64
+ },
65
+ "outputs": [
66
+ {
67
+ "name": "stdout",
68
+ "output_type": "stream",
69
+ "text": [
70
+ "---------------------------------\n",
71
+ "REBOUND version: \t3.8.0\n",
72
+ "REBOUND built on: \tFeb 3 2019 13:37:32\n",
73
+ "Number of particles: \t3\n",
74
+ "Selected integrator: \twhfast\n",
75
+ "Simulation time: \t0.0000000000000000e+00\n",
76
+ "Current timestep: \t0.001000\n",
77
+ "---------------------------------\n",
78
+ "<rebound.Particle object, m=1.0 x=0.0 y=0.0 z=0.0 vx=0.0 vy=0.0 vz=0.0>\n",
79
+ "<rebound.Particle object, m=1e-06 x=1.0 y=0.0 z=0.0 vx=0.0 vy=1.000000499999875 vz=0.0>\n",
80
+ "<rebound.Particle object, m=0.0 x=2.000000999999 y=0.0 z=0.0 vx=0.0 vy=0.7071081347393496 vz=0.0>\n",
81
+ "---------------------------------\n"
82
+ ]
83
+ }
84
+ ],
85
+ "source": [
86
+ "del sim\n",
87
+ "sim = rebound.Simulation(\"checkpoint.bin\")\n",
88
+ "sim.status()"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type": "markdown",
93
+ "metadata": {},
94
+ "source": [
95
+ "Note that you will have to re-set any function pointers manually (if you're using them)"
96
+ ]
97
+ }
98
+ ],
99
+ "metadata": {
100
+ "kernelspec": {
101
+ "display_name": "Python 3",
102
+ "language": "python",
103
+ "name": "python3"
104
+ },
105
+ "language_info": {
106
+ "codemirror_mode": {
107
+ "name": "ipython",
108
+ "version": 3
109
+ },
110
+ "file_extension": ".py",
111
+ "mimetype": "text/x-python",
112
+ "name": "python",
113
+ "nbconvert_exporter": "python",
114
+ "pygments_lexer": "ipython3",
115
+ "version": "3.6.5"
116
+ }
117
+ },
118
+ "nbformat": 4,
119
+ "nbformat_minor": 2
120
+ }
rebound/source/docs/ipython_examples/Churyumov-Gerasimenko.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
rebound/source/docs/ipython_examples/CloseEncounters.ipynb ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Catching close encounters using exceptions\n",
8
+ "Sometimes one is interested in catching a close encounter between two planets. This can easily be done with REBOUND. What you do when a close encounter happens is up to you.\n",
9
+ "\n",
10
+ "Some integrators are better suited to simulate close encounters than others. For example, the non-symplectic integrator IAS15 has an adaptive timestep scheme that resolves close encounters very well. Integrators that use a fixed timestep like WHFast are more likely to miss close encounters.\n",
11
+ "\n",
12
+ "Let's start by setting up a two-planet system that will go unstable on a short timescale:"
13
+ ]
14
+ },
15
+ {
16
+ "cell_type": "code",
17
+ "execution_count": 1,
18
+ "metadata": {},
19
+ "outputs": [],
20
+ "source": [
21
+ "import rebound\n",
22
+ "import numpy as np\n",
23
+ "def setupSimulation():\n",
24
+ " sim = rebound.Simulation()\n",
25
+ " sim.integrator = \"ias15\" # IAS15 is the default integrator, so we don't need this line\n",
26
+ " sim.add(m=1.)\n",
27
+ " sim.add(m=1e-3,a=1.)\n",
28
+ " sim.add(m=5e-3,a=1.25)\n",
29
+ " sim.move_to_com()\n",
30
+ " return sim"
31
+ ]
32
+ },
33
+ {
34
+ "cell_type": "markdown",
35
+ "metadata": {},
36
+ "source": [
37
+ "Let's integrate this system for 100 orbital periods."
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": 2,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "sim = setupSimulation()\n",
47
+ "sim.integrate(100.*2.*np.pi)"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "Rebound exits the integration routine normally. We can now explore the final particle orbits:"
55
+ ]
56
+ },
57
+ {
58
+ "cell_type": "code",
59
+ "execution_count": 3,
60
+ "metadata": {},
61
+ "outputs": [
62
+ {
63
+ "name": "stdout",
64
+ "output_type": "stream",
65
+ "text": [
66
+ "<rebound.Orbit instance, a=4.725537568103762 e=0.7145243085874022 inc=0.0 Omega=0.0 omega=2.7372774231509887 f=4.39210305882742>\n",
67
+ "<rebound.Orbit instance, a=1.0429076415181782 e=0.12110823999615411 inc=0.0 Omega=0.0 omega=5.927708717019177 f=4.786502097969678>\n"
68
+ ]
69
+ }
70
+ ],
71
+ "source": [
72
+ "for o in sim.orbits():\n",
73
+ " print(o)"
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "markdown",
78
+ "metadata": {},
79
+ "source": [
80
+ "We see that the orbits of both planets changed significantly and we can already speculate that there was a close encounter.\n",
81
+ "\n",
82
+ "Let's redo the simulation, but this time set the `sim.exit_min_distance` flag for the simulation. If this flag is set, then REBOUND calculates the minimum distance between all particle pairs each timestep. If the distance is less than `sim.exit_min_distance`, then the integration is stopped and an exception thrown. Here, we'll use the [Hill radius](https://en.wikipedia.org/wiki/Hill_sphere) as the criteria for a close encounter. It is given by $r_{\\rm Hill} \\approx a \\sqrt{\\frac{m}{3M}}$, which is approximately 0.15 AU in our case. \n",
83
+ "\n",
84
+ "This setup allows us to catch the exception and deal with it in a customized way. As a first example, let's catch the exception with a `try`-`except` block, and simply print out the error message. Additionally, let's store the particles' separations while we're integrating:"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "code",
89
+ "execution_count": 4,
90
+ "metadata": {},
91
+ "outputs": [
92
+ {
93
+ "name": "stdout",
94
+ "output_type": "stream",
95
+ "text": [
96
+ "Two particles had a close encounter (d<exit_min_distance).\n"
97
+ ]
98
+ }
99
+ ],
100
+ "source": [
101
+ "sim = setupSimulation() # Resets everything\n",
102
+ "sim.exit_min_distance = 0.15\n",
103
+ "Noutputs = 1000\n",
104
+ "times = np.linspace(0,100.*2.*np.pi,Noutputs)\n",
105
+ "distances = np.zeros(Noutputs)\n",
106
+ "ps = sim.particles # ps is now an array of pointers. It will update as the simulation runs.\n",
107
+ "try:\n",
108
+ " for i,time in enumerate(times):\n",
109
+ " sim.integrate(time)\n",
110
+ " dp = ps[1] - ps[2] # Calculates the coponentwise difference between particles \n",
111
+ " distances[i] = np.sqrt(dp.x*dp.x+dp.y*dp.y+dp.z*dp.z)\n",
112
+ "except rebound.Encounter as error:\n",
113
+ " print(error)"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "markdown",
118
+ "metadata": {},
119
+ "source": [
120
+ "The `Encounter` does currently not tell you which particles had a close encounter. But you can easily search for the pair yourself (see below). \n",
121
+ "\n",
122
+ "Here, we already know which bodies had a close encounter (the two planets) and we can plot their separation as a function of time."
123
+ ]
124
+ },
125
+ {
126
+ "cell_type": "code",
127
+ "execution_count": 5,
128
+ "metadata": {},
129
+ "outputs": [
130
+ {
131
+ "data": {
132
+ "image/png": "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AMyfPx+zZs1C//79MXDgQLz33nuora3F7NmzAQAzZ85EaGgo3nzzTQDAU089hREjRuCdd97BxIkTsXz5chw+fBiffvqpyB+DiIiIiIhsmPDCafr06SgpKcFLL72EwsJC9OnTBxs3bmweAJGbmwuF4n8LY0OGDMG3336Lv/71r/jLX/6C7t27Y82aNYiLixP1IxARERERkY0Tvo9TZ+M+TkREREREBFjRPk5ERERERETWgIUTERERERFRC1g4ERERERERtYCFExERERERUQtYOBEREREREbWAhRMREREREVELWDgRERERERG1gIUTERERERFRC1g4ERERERERtYCFExERERERUQtUogN0NlmWAQBVVVWCkxARERERkUhNNUFTjXAtdlc4lZWVAQDCw8MFJyEiIiIiIktQXV0NT0/Pa97G7gonHx8fAEBubm6LfzlEIlRVVSE8PBx5eXnw8PAQHYfoivh7SpaOv6Nk6fg7ahlkWUZ1dTVCQkJavK3dFU4Khem0Lk9PT/6SkkXz8PDg7yhZPP6ekqXj7yhZOv6OitfaxRQOhyAiIiIiImoBCyciIiIiIqIW2F3h5OjoiJdffhmOjo6ioxBdEX9HyRrw95QsHX9HydLxd9T6SHJrZu8RERERERHZMbtbcSIiIiIiImorFk5EREREREQtYOFERERERETUAhZORERERERELbC7wumjjz5CZGQknJycMGjQIBw8eFB0JKJmO3fuxKRJkxASEgJJkrBmzRrRkYiavfnmmxgwYADc3d0REBCAKVOm4PTp06JjEV1m4cKFSEhIaN5UNDk5Gb/88ovoWERX9NZbb0GSJDz99NOio1Ar2FXhtGLFCsyfPx8vv/wyjh49isTERIwbNw7FxcWioxEBAGpra5GYmIiPPvpIdBSiP9ixYwfmzZuH/fv3Y9OmTdDpdLjppptQW1srOhpRs7CwMLz11ls4cuQIDh8+jBtvvBGTJ0/GyZMnRUcjusyhQ4fwySefICEhQXQUaiW7Gkc+aNAgDBgwAB9++CEAwGg0Ijw8HE888QReeOEFwemILidJElavXo0pU6aIjkJ0RSUlJQgICMCOHTswfPhw0XGIrsrHxwf//ve/MXfuXNFRiAAANTU16Nu3Lz7++GO8/vrr6NOnD9577z3RsagFdrPipNVqceTIEYwZM6b5OoVCgTFjxmDfvn0CkxERWafKykoApg+lRJbIYDBg+fLlqK2tRXJysug4RM3mzZuHiRMnXva5lCyfSnSAzlJaWgqDwYDAwMDLrg8MDERGRoagVERE1sloNOLpp5/G0KFDERcXJzoO0WVSU1ORnJyMhoYGuLm5YfXq1YiNjRUdiwgAsHz5chw9ehSHDh0SHYXayG4KJyIiMp958+YhLS0Nu3fvFh2F6A969uyJlJQUVFZW4scff8SsWbOwY8cOFk8kXF5eHp566ils2rQJTk5OouNQG9lN4eTn5welUomioqLLri8qKkJQUJCgVERE1ufxxx/HunXrsHPnToSFhYmOQ/QHarUa3bp1AwD069cPhw4dwvvvv49PPvlEcDKyd0eOHEFxcTH69u3bfJ3BYMDOnTvx4YcfQqPRQKlUCkxI12I35zip1Wr069cPW7Zsab7OaDRiy5Yt7HsmImoFWZbx+OOPY/Xq1di6dSuioqJERyJqFaPRCI1GIzoGEUaPHo3U1FSkpKQ0X/r374977rkHKSkpLJosnN2sOAHA/PnzMWvWLPTv3x8DBw7Ee++9h9raWsyePVt0NCIApik7Z8+ebf46OzsbKSkp8PHxQUREhMBkRKb2vG+//RY//fQT3N3dUVhYCADw9PSEs7Oz4HREJgsWLMCECRMQERGB6upqfPvtt9i+fTt+/fVX0dGI4O7u/ofzQl1dXeHr68vzRa2AXRVO06dPR0lJCV566SUUFhaiT58+2Lhx4x8GRhCJcvjwYYwaNar56/nz5wMAZs2ahaVLlwpKRWSycOFCAMDIkSMvu37JkiW4//77Oz8Q0RUUFxdj5syZKCgogKenJxISEvDrr79i7NixoqMRkZWzq32ciIiIiIiI2sNuznEiIiIiIiJqLxZORERERERELWDhRERERERE1AIWTkRERERERC1g4URERERERNQCFk5EREREREQtYOFERERERETUAhZORETUKbZv3w5JklBRUdHpzy1JEiRJgpeX13U/Vmt+jqVLl173c40cObI5d0pKynU9FhERXT8WTkREZHYjR47E008/fdl1Q4YMQUFBATw9PYVkWrJkCTIzMzvluaZPn37Zc73yyivo06dPmx5j1apVOHjwoJmTERFRe6lEByAiIvugVqsRFBQk7Pm9vLwQEBBwXY+h0+ladTtnZ2c4Oztf13P5+Pigqqrquh6DiIjMhytORERkVvfffz927NiB999/v7nVLCcn5w8tbk3tbOvWrUPPnj3h4uKC22+/HXV1dVi2bBkiIyPh7e2NJ598EgaDofnxNRoNnnvuOYSGhsLV1RWDBg3C9u3b25V14cKF6Nq1K9RqNXr27Imvvvrqsu9LkoSFCxfi1ltvhaurK/7xj380f2/Pnj1ISEiAk5MTBg8ejLS0tObv/b5Vb+nSpXj11Vdx/Pjx5r+PpUuXQpZlvPLKK4iIiICjoyNCQkLw5JNPtuvnICKijscVJyIiMqv3338fmZmZiIuLw2uvvQYA8Pf3R05Ozh9uW1dXhw8++ADLly9HdXU1brvtNkydOhVeXl7YsGEDsrKyMG3aNAwdOhTTp08HADz++OM4deoUli9fjpCQEKxevRrjx49Hamoqunfv3uqcq1evxlNPPYX33nsPY8aMwbp16zB79myEhYVh1KhRzbd75ZVX8NZbb+G9996DSqVCVlYWAOBPf/oT3n//fQQFBeEvf/kLJk2ahMzMTDg4OFz2PNOnT0daWho2btyIzZs3AwA8PT2xcuVKvPvuu1i+fDl69+6NwsJCHD9+vE1/10RE1HlYOBERkVl5enpCrVbDxcWlxdY8nU7XvOoDALfffju++uorFBUVwc3NDbGxsRg1ahS2bduG6dOnIzc3F0uWLEFubi5CQkIAAM899xw2btyIJUuW4I033mh1zrfffhv3338/HnvsMQDA/PnzsX//frz99tuXFU4zZszA7Nmzm79uKpxefvlljB07FgCwbNkyhIWFYfXq1bjzzjsvex5nZ2e4ublBpVJd9veRm5uLoKAgjBkzBg4ODoiIiMDAgQNbnZ+IiDoXW/WIiEgYFxeX5qIJAAIDAxEZGQk3N7fLrisuLgYApKamwmAwoEePHnBzc2u+7NixA+fOnWvTc6enp2Po0KGXXTd06FCkp6dfdl3//v2veP/k5OTmP/v4+KBnz55/uO+13HHHHaivr0d0dDQefPBBrF69Gnq9vg0/ARERdSauOBERkTD/v61NkqQrXmc0GgEANTU1UCqVOHLkCJRK5WW3+32xZU6urq4d8rjh4eE4ffo0Nm/ejE2bNuGxxx7Dv//9b+zYseMPfwdERCQeV5yIiMjs1Gr1ZQMdzCUpKQkGgwHFxcXo1q3bZZe2Tuzr1asX9uzZc9l1e/bsQWxsbKvuv3///uY/X7p0CZmZmejVq9cVb3u1vw9nZ2dMmjQJH3zwAbZv3459+/YhNTW1DT8FERF1Fq44ERGR2UVGRuLAgQPIycmBm5sbfHx8zPK4PXr0wD333IOZM2finXfeQVJSEkpKSrBlyxYkJCRg4sSJrX6sP/3pT7jzzjuRlJSEMWPGYO3atVi1alXzAIeWvPbaa/D19UVgYCBefPFF+Pn5YcqUKVe8bWRkJLKzs5GSkoKwsDC4u7vju+++g8FgwKBBg+Di4oKvv/4azs7O6NKlS6t/BiIi6jxccSIiIrN77rnnoFQqERsbC39/f+Tm5prtsZcsWYKZM2fi2WefRc+ePTFlyhQcOnQIERERbXqcKVOm4P3338fbb7+N3r1745NPPsGSJUswcuTIVt3/rbfewlNPPYV+/fqhsLAQa9euhVqtvuJtp02bhvHjx2PUqFHw9/fHd999By8vL3z22WcYOnQoEhISsHnzZqxduxa+vr5t+jmIiKhzSLIsy6JDEBERdSRJkrB69eqrrghZqpycHERFReHYsWPo06eP6DhERHaNK05ERGQX7r77boSFhYmO0WoTJkxA7969RccgIqJGXHEiIiKbd/bsWQCAUqlEVFSU4DStk5+fj/r6egBARETEVdsAiYioc7BwIiIiIiIiagFb9YiIiIiIiFrAwomIiIiIiKgFLJyIiIiIiIhawMKJiIiIiIioBSyciIiIiIiIWsDCiYiIiIiIqAUsnIiIiIiIiFrAwomIiIiIiKgFLJyIiIiIiIha8H+/QDSADQAPxwAAAABJRU5ErkJggg==\n",
133
+ "text/plain": [
134
+ "<Figure size 1000x500 with 1 Axes>"
135
+ ]
136
+ },
137
+ "metadata": {},
138
+ "output_type": "display_data"
139
+ }
140
+ ],
141
+ "source": [
142
+ "%matplotlib inline\n",
143
+ "import matplotlib.pyplot as plt\n",
144
+ "fig = plt.figure(figsize=(10,5))\n",
145
+ "ax = plt.subplot(111)\n",
146
+ "ax.set_xlabel(\"time [orbits]\")\n",
147
+ "ax.set_xlim([0,sim.t/(2.*np.pi)])\n",
148
+ "ax.set_ylabel(\"distance\")\n",
149
+ "plt.plot(times/(2.*np.pi), distances);\n",
150
+ "plt.plot([0.0,12],[0.2,0.2]); # Plot our close encounter criteria;"
151
+ ]
152
+ },
153
+ {
154
+ "cell_type": "markdown",
155
+ "metadata": {},
156
+ "source": [
157
+ "We did indeed find the close encounter correctly. We can now search for the two particles that collided and, for this example, merge them. To do that we'll first calculate our new merged planet coordinates, then remove the two particles that collided from REBOUND and finally add the new particle."
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": 6,
163
+ "metadata": {},
164
+ "outputs": [
165
+ {
166
+ "name": "stdout",
167
+ "output_type": "stream",
168
+ "text": [
169
+ "Number of particles at the beginning of the simulation: 3.\n",
170
+ "Two particles had a close encounter (d<exit_min_distance).\n",
171
+ "Number of particles at the end of the simulation: 2.\n"
172
+ ]
173
+ }
174
+ ],
175
+ "source": [
176
+ "from itertools import combinations\n",
177
+ "def mergeParticles(sim):\n",
178
+ " # Find two closest particles\n",
179
+ " min_d2 = 1e9 # large number\n",
180
+ " ps = sim.particles\n",
181
+ " for i1, i2 in combinations(range(sim.N),2): # get all pairs of indices\n",
182
+ " dp = ps[i1] - ps[i2] # Calculates the coponentwise difference between particles \n",
183
+ " d2 = dp.x*dp.x+dp.y*dp.y+dp.z*dp.z\n",
184
+ " if d2<min_d2:\n",
185
+ " min_d2 = d2\n",
186
+ " col_i1 = i1\n",
187
+ " col_i2 = i2\n",
188
+ " \n",
189
+ " cp1 = ps[col_i1]\n",
190
+ " cp2 = ps[col_i2]\n",
191
+ " # Merge two closest particles\n",
192
+ " \n",
193
+ " sum_mass = cp1.m + cp2.m\n",
194
+ " mergedPlanet = (cp1*cp1.m + cp2*cp2.m)/sum_mass \n",
195
+ " mergedPlanet.m = sum_mass\n",
196
+ " sim.remove(index=col_i2) # Note: Removing a particle changes the sim.particles\n",
197
+ " sim.remove(index=col_i1) # array and the particle indicies.\n",
198
+ " sim.add(mergedPlanet, assignHash=True)\n",
199
+ "\n",
200
+ "sim = setupSimulation() # Resets everything\n",
201
+ "sim.exit_min_distance = 0.15\n",
202
+ "print(\"Number of particles at the beginning of the simulation: %d.\"%sim.N)\n",
203
+ "for i,time in enumerate(times):\n",
204
+ " try:\n",
205
+ " sim.integrate(time)\n",
206
+ " except rebound.Encounter as error:\n",
207
+ " print(error)\n",
208
+ " mergeParticles(sim)\n",
209
+ "print(\"Number of particles at the end of the simulation: %d.\"%sim.N)"
210
+ ]
211
+ },
212
+ {
213
+ "cell_type": "markdown",
214
+ "metadata": {
215
+ "collapsed": true,
216
+ "jupyter": {
217
+ "outputs_hidden": true
218
+ }
219
+ },
220
+ "source": [
221
+ "We can achieve the same outcome by using more of the built-in functionality of REBOUND. For that, we set the radius of the particles to their Hill radius. In practice, you might want to use the physical radius, but for this example, we want the collision to occur in a short amount of time and therefore inflate the particle radii. We set the collision detection routine to `direct` which will do a $O(N^2)$ collision search between all particles. The `collisions_resolve` call-back function is set to `merge`, which will merge the particles together, assuming mass and momentum conservation."
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": 7,
227
+ "metadata": {},
228
+ "outputs": [],
229
+ "source": [
230
+ "def setupSimulation():\n",
231
+ " sim = rebound.Simulation()\n",
232
+ " sim.integrator = \"ias15\" # IAS15 is the default integrator, so we don't really need this line\n",
233
+ " sim.add(m=1.)\n",
234
+ " sim.add(m=1e-3, a=1., r=np.sqrt(1e-3/3.)) # we now set collision radii!\n",
235
+ " sim.add(m=5e-3, a=1.25, r=1.25*np.sqrt(5e-3/3.))\n",
236
+ " sim.move_to_com()\n",
237
+ " return sim"
238
+ ]
239
+ },
240
+ {
241
+ "cell_type": "code",
242
+ "execution_count": 8,
243
+ "metadata": {},
244
+ "outputs": [
245
+ {
246
+ "name": "stdout",
247
+ "output_type": "stream",
248
+ "text": [
249
+ "Particles in the simulation at t= 0.0: 3\n",
250
+ "Particles in the simulation at t= 100.0: 2\n"
251
+ ]
252
+ }
253
+ ],
254
+ "source": [
255
+ "sim = setupSimulation()\n",
256
+ "sim.collision = \"direct\"\n",
257
+ "sim.collision_resolve = \"merge\"\n",
258
+ "\n",
259
+ "print(\"Particles in the simulation at t=%6.1f: %d\"%(sim.t,sim.N))\n",
260
+ "sim.integrate(100.)\n",
261
+ "print(\"Particles in the simulation at t=%6.1f: %d\"%(sim.t,sim.N))"
262
+ ]
263
+ },
264
+ {
265
+ "cell_type": "markdown",
266
+ "metadata": {},
267
+ "source": [
268
+ "We can also use the built-in collision detection and apply our own function to resolve the collision. By default, if we don't set the sim.collision function pointer, `REBOUND` will raise a `Collision` exception when a collision occurs, which we can catch. \n",
269
+ "\n",
270
+ "An indirect way of checking which particles collided is to check which ones have a `last_collision` time equal to the current simulation time."
271
+ ]
272
+ },
273
+ {
274
+ "cell_type": "code",
275
+ "execution_count": 9,
276
+ "metadata": {},
277
+ "outputs": [
278
+ {
279
+ "name": "stdout",
280
+ "output_type": "stream",
281
+ "text": [
282
+ "Particles [1, 2] collided\n"
283
+ ]
284
+ }
285
+ ],
286
+ "source": [
287
+ "sim = setupSimulation()\n",
288
+ "sim.collision = \"direct\"\n",
289
+ "# we don't set sim.collision_resolve this time\n",
290
+ "\n",
291
+ "try:\n",
292
+ " sim.integrate(100.)\n",
293
+ "except rebound.Collision:\n",
294
+ " collided = []\n",
295
+ " for p in sim.particles:\n",
296
+ " if p.last_collision == sim.t:\n",
297
+ " collided.append(p.index)\n",
298
+ " # Custom resolution\n",
299
+ "\n",
300
+ "print(\"Particles {0} collided\".format(collided))"
301
+ ]
302
+ },
303
+ {
304
+ "cell_type": "code",
305
+ "execution_count": null,
306
+ "metadata": {},
307
+ "outputs": [],
308
+ "source": []
309
+ }
310
+ ],
311
+ "metadata": {
312
+ "kernelspec": {
313
+ "display_name": "Python 3 (ipykernel)",
314
+ "language": "python",
315
+ "name": "python3"
316
+ },
317
+ "language_info": {
318
+ "codemirror_mode": {
319
+ "name": "ipython",
320
+ "version": 3
321
+ },
322
+ "file_extension": ".py",
323
+ "mimetype": "text/x-python",
324
+ "name": "python",
325
+ "nbconvert_exporter": "python",
326
+ "pygments_lexer": "ipython3",
327
+ "version": "3.9.6"
328
+ }
329
+ },
330
+ "nbformat": 4,
331
+ "nbformat_minor": 4
332
+ }
rebound/source/docs/ipython_examples/EccentricComets.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
rebound/source/docs/ipython_examples/EmbeddedOperatorSplittingMethods.ipynb ADDED
The diff for this file is too large to render. See raw diff