diff --git a/changelog.md b/changelog.md index a2737ff82..395580f3d 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,14 @@ This changelog only includes the most important changes in recent updates. For a ## Version 3.x +### Version 3.27.0 +* In python, Simulation and Particle objects are now picklable. Just like loading Simulations from a binary file, function pointers will need to be re-set manually after unpickling. +* The difference between simulations can now be printed out in a human readable form. Python syntax: `sim.diff(sim2)`. C syntax: `reb_diff_simulations(sim2, sim1, 1)`. +* Reading SimulationArchives with version < 2 is no longer supported. +* The POSIX function fmemopen() is now required to compile REBOUND. This should not affect many users. However, if you are using macOS, the version needs to be >= 10.13 (this version of macOS, High Sierra, was released in 2017). +* Internal changes on how SimulationArchives are written. +* Internal variable names that represent the size of allocated buffers now consistently include the name `allocated_N`. + ### Version 3.26.3 * A few more changes to reduce the number of compiler warnings. This should not affect any calculation. diff --git a/derivatives.ipynb b/derivatives.ipynb new file mode 100644 index 000000000..874da81f9 --- /dev/null +++ b/derivatives.ipynb @@ -0,0 +1,874 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 132, + "id": "c5aaccd9", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:21:54.426504Z", + "start_time": "2023-08-08T12:21:54.415875Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Aug 7 2023 15:46:31'" + ] + }, + "execution_count": 132, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from sympy import symbols, diff, cos, sin, sqrt, lambdify, simplify, Q, refine, nsolve, solve, pi\n", + "import rebound\n", + "rebound.__build__" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4d04f1c8", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T19:46:45.110979Z", + "start_time": "2023-08-07T19:46:45.061731Z" + } + }, + "outputs": [], + "source": [ + "x,y, tau = symbols('x y tau', real=True)\n", + "e, E, epsilon = symbols('e E epsilon', positive=True)\n", + "dEdt = 1/(1-e*cos(E)) # Solar System Dynamics Eq. 2.50" + ] + }, + { + "cell_type": "code", + "execution_count": 145, + "id": "fdc37a8b", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:26:08.498668Z", + "start_time": "2023-08-08T12:26:07.085156Z" + } + }, + "outputs": [], + "source": [ + "dxs = [cos(E)-e] # Solar System Dynamics Eq. 2.41\n", + "dys = [sqrt(1-e*e)*sin(E)]\n", + "dxs_apo = []\n", + "dys_apo = []\n", + "for i in range(9):\n", + " dxs.append(diff(dxs[-1],E) * dEdt)\n", + " dys.append(diff(dys[-1],E) * dEdt) \n", + "for i in range(len(dxs)):\n", + " dxs_apo.append( dxs[i].subs(E, pi) )\n", + " dys_apo.append( dys[i].subs(E, pi) )\n", + " dxs[i] = dxs[i].subs(E, 0)\n", + " dys[i] = dys[i].subs(E, 0)\n", + "dxs = lambdify(e,dxs)\n", + "dys = lambdify(e,dys)\n", + "dxs_apo = lambdify(e,dxs_apo)\n", + "dys_apo = lambdify(e,dys_apo)" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "id": "7d4e3623", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:25:43.138344Z", + "start_time": "2023-08-08T12:25:43.123816Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{\\frac{e}{\\left(e + 1\\right)^{3}} + \\frac{\\frac{3 e}{\\left(e + 1\\right)^{2}} - \\frac{1}{e + 1}}{e + 1}}{\\left(e + 1\\right)^{2}}$" + ], + "text/plain": [ + "(e/(e + 1)**3 + (3*e/(e + 1)**2 - 1/(e + 1))/(e + 1))/(e + 1)**2" + ] + }, + "execution_count": 143, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dxs_apo[4]" + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "id": "281f56d4", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:26:10.217472Z", + "start_time": "2023-08-08T12:26:09.916912Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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9ViWZZ544gmefPJJunbtio+PD3V1dZhMJmpqaqiqqgIaVhR999139OnTx3rbrKwsevfufVNx3DD5VwDkzz//3KZt8ODB8iOPPGI9NpvNckhIiPzyyy/bXLdjxw555syZNm16vV4eMWKE/OGHH173sRctWiQDl/1UVFTc/C8kNIvFYpEtFov1eNu2bfKiRYvkNWvW2FxXVFRkc53QfHWnT8t1Gaetx4YLF+STvXrL5++5Vy777HPZXFNjx+jaRkXFMXnb9kh51+5BsslUa+9wrquu2mj9t9lklj9/JV3+cfcl2Wwy2y2mdy4WyoHfHZEnp50Rr8kWUldXJ588eVKuq6u77NyiRYvkRYsWydXV1da2Xbt2yYsWLZK/+OILm2sXL14sL1q0SC4tLbW2paamyosWLZLXrVtnc+3f//53edGiRbJOp7O2HT58+Kbi/8c//iH36dPHevy///1PDgoKkquqqqxt9913n/z999/LZ8+elWNjY+XY2Fi5T58+8muvvWZzX6+++qq8fPnyKz7OtZ6nioqKG/78btE5LUajkbS0NJ599llrm0KhICUl5brLoGRZ5oEHHmDMmDHcd999132sZ599lvnz51uPKysrxXBSG/vlPIMBAwbg5uaGf5PCaXV1dSxfvhwPDw9+//vft3rXYUfl3MO2Jkjt4TSQJGoPH6b28GF0ixfjOXEiXrNm4hwb227ngPwaJlMVLi4ReGkTUCob/47q68tRN9k+oL1wdmssqHfmoI7c02Xkni7j2HeXGDo9iq79fNv8/ynQSY2vWsXtQd4d8m9EaL6kpCQWLFhAdXU1kiSxcOFCFi9ejLu7u/WaefPmsWLFCt566y2OHTt21fvauHEj69ata9V4f1VxOUmS+Pzzz5k2bRoAeXl5hIaGkpqaypCfdsIFeOaZZ9i1axcHDhwAICUlhWPHjlFTU4OPjw9r167FbDYzcuRI64QegI8++oh+/frdUCyiuFz7dP78eT755BO8vb2ZN2+etf3o0aOoVCqbPZKE5qkvKKBiwwbK139GfU6Otd0pujuh//53h9y0UZbNmM21qFQN21QYjcWk7huNr88oYmL+gVLZPgurmest/Lg7l0ObsjHUNAwLhPbwYujM7gR0bdv3q/J6E54qpXXI6GR1HedqDUzy14pE5iZcq2ia0dgwH0utVlufW5PJhMViuWz15s/X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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1,1)\n", + "ax.set_title(\"peri\")\n", + "ax.set_xlabel(\"1-e\")\n", + "ax.set_xscale(\"log\")\n", + "ax.set_yscale(\"log\")\n", + "oneminuses = np.logspace(-2,-0.00001,1000)\n", + "_dxs = dxs(1.-oneminuses)\n", + "_dys = dys(1.-oneminuses)\n", + "for i in range(0,10,2):\n", + " ax.plot(oneminuses, np.abs(_dxs[i]), ls=\"--\", label=\"$x^{(%d)}$\"%i)\n", + "for i in range(1,10,2):\n", + " ax.plot(oneminuses, np.abs(_dys[i]), ls=\":\", label=\"$y^{(%d)}$\"%i)\n", + "ax.legend();" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "id": "ee9465b7", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:34:56.658749Z", + "start_time": "2023-08-08T15:34:56.321238Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1,1)\n", + "ax.set_title(\"apo\")\n", + "ax.set_xlabel(\"1-e\")\n", + "ax.set_xscale(\"log\")\n", + "ax.set_yscale(\"log\")\n", + "oneminuses = np.logspace(-2,-0.00001,1000)\n", + "_dxs = dxs_apo(1.-oneminuses)\n", + "_dys = dys_apo(1.-oneminuses)\n", + "for i in range(0,8,2):\n", + " ax.plot(oneminuses, np.abs(_dxs[i]), ls=\"--\", label=\"$x^{(%d)}$\"%i)\n", + "for i in range(1,8,2):\n", + " ax.plot(oneminuses, np.abs(_dys[i]), ls=\":\", label=\"$y^{(%d)}$\"%i)\n", + "ax.legend();" + ] + }, + { + "cell_type": "code", + "execution_count": 234, + "id": "94fd339a", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:37:00.778128Z", + "start_time": "2023-08-08T15:37:00.472352Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1,1)\n", + "ax.set_xlabel(\"1-e\")\n", + "ax.set_xscale(\"log\")\n", + "ax.set_yscale(\"log\")\n", + "oneminuses = np.logspace(-5,-0.00001,10000)\n", + "_dxs_apo = dxs_apo(1.-oneminuses)\n", + "_dys_apo = dys_apo(1.-oneminuses)\n", + "_dxs = dxs(1.-oneminuses)\n", + "_dys = dys(1.-oneminuses)\n", + "\n", + "ax.plot(oneminuses, np.abs(_dxs[2]/_dys[3]), ls=\"--\", label=\"acc/jerk @ peri\")\n", + "ax.plot(oneminuses, np.abs(_dxs_apo[2]/_dys_apo[3]), ls=\"--\", label=\"acc/jerk @ apo\")\n", + "ax.plot(oneminuses, np.sqrt(np.abs(_dxs[2]/_dxs[4])), ls=\"--\", label=\"acc/snap @ peri\")\n", + "ax.plot(oneminuses, np.sqrt(np.abs(_dxs_apo[2]/_dxs_apo[4])), ls=\"--\", label=\"acc/snap @ apo\")\n", + "ax.legend();" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "9d934b69", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T19:46:58.261179Z", + "start_time": "2023-08-07T19:46:58.232927Z" + } + }, + "outputs": [], + "source": [ + "dxs = [cos(E)-e] # Solar System Dynamics Eq. 2.41\n", + "dys = [sqrt(1-e*e)*sin(E)]\n", + "for i in range(4):\n", + " dxs.append(diff(dxs[-1],E) * dEdt)\n", + " dys.append(diff(dys[-1],E) * dEdt) \n", + "acc = sqrt(dxs[2]**2+dys[2]**2)\n", + "jerk = sqrt(dxs[3]**2+dys[3]**2)\n", + "timescale = acc/jerk\n", + "anal_dt = timescale*epsilon\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6556defc", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T19:46:58.270097Z", + "start_time": "2023-08-07T19:46:58.263731Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle 1$" + ], + "text/plain": [ + "1" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "jerk.subs(e,0.0).subs(E,0.)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "191ae625", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T19:47:01.187924Z", + "start_time": "2023-08-07T19:46:58.271315Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{\\epsilon}{\\sqrt{\\frac{\\left(1 - e^{2}\\right) \\left(- 2 e \\sin^{2}{\\left(E \\right)} - e + \\cos{\\left(E \\right)}\\right)^{2} + \\left(3 e^{2} - 2 e \\cos{\\left(E \\right)} - 1\\right)^{2} \\sin^{2}{\\left(E \\right)}}{\\left(e \\cos{\\left(E \\right)} - 1\\right)^{10}}} \\left(e \\cos{\\left(E \\right)} - 1\\right)^{2}}$" + ], + "text/plain": [ + "epsilon/(sqrt(((1 - e**2)*(-2*e*sin(E)**2 - e + cos(E))**2 + (3*e**2 - 2*e*cos(E) - 1)**2*sin(E)**2)/(e*cos(E) - 1)**10)*(e*cos(E) - 1)**2)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anal_dt = simplify(anal_dt)\n", + "anal_dt" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "665ccbef", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T19:47:01.194317Z", + "start_time": "2023-08-07T19:47:01.189066Z" + } + }, + "outputs": [], + "source": [ + "anal_dt_f = lambdify((e,E,epsilon),anal_dt)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "25a6046e", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T21:23:03.517546Z", + "start_time": "2023-08-07T21:23:03.389206Z" + } + }, + "outputs": [], + "source": [ + "d_anal_dt = diff(anal_dt,E)*dEdt\n", + "d_anal_dt_f = lambdify((e,E,epsilon), d_anal_dt)\n", + "dd_anal_dt = diff(d_anal_dt,E)*dEdt\n", + "dd_anal_dt_f = lambdify((e,E,epsilon), dd_anal_dt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7e94cec", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9aef986c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6fba32f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c3394c08", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-07T19:47:02.670241Z", + "start_time": "2023-08-07T19:47:01.195397Z" + } + }, + "outputs": [], + "source": [ + "dxs = [cos(E)-e] # Solar System Dynamics Eq. 2.41\n", + "dys = [sqrt(1-e*e)*sin(E)]\n", + "for i in range(9):\n", + " dxs.append(diff(dxs[-1],E) * dEdt)\n", + " dys.append(diff(dys[-1],E) * dEdt) \n", + "a = lambdify((e,E),sqrt(dxs[2]**2+dys[2]**2))\n", + "j = lambdify((e,E),sqrt(dxs[3]**2+dys[3]**2))" + ] + }, + { + "cell_type": "code", + "execution_count": 222, + "id": "680c24a2", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:22:23.583028Z", + "start_time": "2023-08-08T15:22:23.276041Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.17092266441463\n" + ] + } + ], + "source": [ + "_epsilon = 3.3*np.power(1e-9,1./7.)\n", + "print(_epsilon)\n", + "_safety = 0.85\n", + "_e = 0.99\n", + "\n", + "_dtaus = []\n", + "_dtau = 0.2\n", + "_tau = np.pi\n", + "_failed = []\n", + "_Es = []\n", + "fail = 0\n", + "\n", + "while _tau<5.0*np.pi:\n", + " # try new timestep\n", + " _E = nsolve((E-e*sin(E)-(_tau+_dtau)).subs(e,_e),_E,prec=10)\n", + " _ndtau = anal_dt_f(_e, float(_E), _epsilon)\n", + " if _ndtau > _dtau/_safety:\n", + " _ndtau = _dtau/_safety\n", + " fail = _ndtau\n", + " if _ndtau < _dtau * _safety:\n", + " fail = _ndtau\n", + " pass\n", + " \n", + " else:\n", + " _tau += _dtau\n", + " _dtaus.append(_dtau)\n", + " _Es.append(float(_E))\n", + " _failed.append(fail)\n", + " fail = np.nan\n", + " _dtau = _ndtau\n" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "id": "a05d5a06", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:22:23.597485Z", + "start_time": "2023-08-08T15:22:23.584387Z" + } + }, + "outputs": [], + "source": [ + "jerk_f = lambdify((e,E),jerk)\n", + "acc_f = lambdify((e,E),acc)" + ] + }, + { + "cell_type": "code", + "execution_count": 224, + "id": "ea3f5852", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:22:23.730062Z", + "start_time": "2023-08-08T15:22:23.721378Z" + } + }, + "outputs": [], + "source": [ + "mindt = np.zeros(100000)\n", + "mindt[:] = np.nan\n", + "count = 0\n", + "dt_last_done = 0. \n", + "def hb(simp):\n", + " global mindt\n", + " global count, dt_last_done\n", + " if dt_last_done != simp.contents.dt_last_done: \n", + " mindt[count] = simp.contents.dt_last_done\n", + " count +=1 \n", + " dt_last_done = simp.contents.dt_last_done\n", + " \n", + "sim = rebound.Simulation()\n", + "sim.ri_ias15.dt_mode = 1\n", + "sim.ri_ias15.epsilon_global = 0\n", + "sim.add(m=1)\n", + "sim.add(a=1,e=_e,f=np.pi)\n", + "sim.dt=0.2\n", + "sim.heartbeat = hb\n", + "sim.integrate(np.pi*4.,exact_finish_time=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 225, + "id": "5261025d", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:22:24.195883Z", + "start_time": "2023-08-08T15:22:24.171114Z" + } + }, + "outputs": [], + "source": [ + "d_dts = []\n", + "dts = []\n", + "for i in range(len(_Es)):\n", + " d_dts.append((d_anal_dt_f(_e, _Es[i], _epsilon)))\n", + " dts.append((anal_dt_f(_e, _Es[i], _epsilon)))\n", + "d_dts = np.array(d_dts)\n", + "dts = np.array(dts)" + ] + }, + { + "cell_type": "code", + "execution_count": 235, + "id": "62d6a2df", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T15:37:54.321703Z", + "start_time": "2023-08-08T15:37:54.094242Z" + }, + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 235, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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5wHhqamprFmzxrO9Mc9pJWbNxOuvv8706dOZO3cu//73v0lKSmLIkCEcO3bM102Ty9C7d28KCgo8r08//dSz7eGHH+af//wnb775JuvXr+fIkSOMHj3ah62VS1FWVkZSUhLLli075/ZFixbxwgsv8NJLL7F582ZatWrFkCFDqKys9JQZP348X375JWvXruW9995jw4YN3HfffY11CFJPF4s1wNChQ73O9ddee81ru2LdPKxfv56pU6eyadMm1q5dS01NDYMHD6asrMxT5mJ9d11dHcOHD6e6uprPPvuMV155hZUrVzJnzhxfHJKcR31iDXDvvfd6nduLFi3ybFOsm4f27dvz9NNPk5OTQ3Z2NrfeeisjRozgyy+/BBr5nDbSLPTv399MnTrVs1xXV2diY2PNwoULfdgquRxz5841SUlJ59xWXFxs/P39zZtvvulZt3v3bgOYrKysRmqhXCmAWb16tWfZ5XKZ6Ohos3jxYs+64uJiExAQYF577TVjjDG7du0ygNmyZYunzJo1a4zFYjGHDx9utLbLpflxrI0xZsKECWbEiBHnfY9i3XwdO3bMAGb9+vXGmPr13R988IGxWq2msLDQU2b58uXG4XCYqqqqxj0Aqbcfx9oYY26++Wbzm9/85rzvUaybrzZt2piXX3650c9pXTFrBqqrq8nJySE9Pd2zzmq1kp6eTlZWlg9bJpdr7969xMbG0qlTJ8aPH09+fj4AOTk51NTUeMW8R48edOjQQTG/CuTl5VFYWOgV39atW5OSkuKJb1ZWFk6nk379+nnKpKenY7Va2bx5c6O3WS5PZmYmkZGRdO/enfvvv5+ioiLPNsW6+Tp16hQAYWFhQP367qysLBITE4mKivKUGTJkCCUlJZ5v6KXp+XGsz/jb3/5GREQE11xzDbNnz6a8vNyzTbFufurq6li1ahVlZWWkpqY2+jntd2UOQxrSiRMnqKur8wo4QFRUFF999ZWPWiWXKyUlhZUrV9K9e3cKCgqYP38+N954Izt37qSwsBC73Y7T6fR6T1RUFIWFhb5psFwxZ2J4rnP6zLbCwkIiIyO9tvv5+REWFqa/gWZm6NChjB49moSEBPbv389vf/tbhg0bRlZWFjabTbFuplwuFw899BADBw7kmmuuAahX311YWHjOc//MNml6zhVrgHHjxhEfH09sbCzbt2/nkUceITc3l7fffhtQrJuTHTt2kJqaSmVlJSEhIaxevZpevXqxbdu2Rj2nlZiJ+MiwYcM8P/fp04eUlBTi4+N54403CAoK8mHLRORKuvPOOz0/JyYm0qdPHzp37kxmZiZpaWk+bJlcjqlTp7Jz506ve4Pl6nS+WP/wPtDExERiYmJIS0tj//79dO7cubGbKZehe/fubNu2jVOnTvHWW28xYcIE1q9f3+jt0FDGZiAiIgKbzXbWDDBHjx4lOjraR62SK83pdNKtWzf27dtHdHQ01dXVFBcXe5VRzK8OZ2J4oXM6Ojr6rMl9amtrOXnypP4GmrlOnToRERHBvn37AMW6OZo2bRrvvfce69ato3379p719em7o6Ojz3nun9kmTcv5Yn0uKSkpAF7ntmLdPNjtdrp06UJycjILFy4kKSmJ3//+941+TisxawbsdjvJyclkZGR41rlcLjIyMkhNTfVhy+RKKi0tZf/+/cTExJCcnIy/v79XzHNzc8nPz1fMrwIJCQlER0d7xbekpITNmzd74puamkpxcTE5OTmeMh9//DEul8vzn780T4cOHaKoqIiYmBhAsW5OjDFMmzaN1atX8/HHH5OQkOC1vT59d2pqKjt27PBKxteuXYvD4aBXr16NcyByUReL9bls27YNwOvcVqybJ5fLRVVVVeOf01di5hJpeKtWrTIBAQFm5cqVZteuXea+++4zTqfTawYYaV5mzJhhMjMzTV5entm4caNJT083ERER5tixY8YYYyZPnmw6dOhgPv74Y5OdnW1SU1NNamqqj1st9XX69GmzdetWs3XrVgOY559/3mzdutV88803xhhjnn76aeN0Os27775rtm/fbkaMGGESEhJMRUWFp46hQ4eavn37ms2bN5tPP/3UdO3a1YwdO9ZXhyTncaFYnz592sycOdNkZWWZvLw8869//ctcd911pmvXrqaystJTh2LdPNx///2mdevWJjMz0xQUFHhe5eXlnjIX67tra2vNNddcYwYPHmy2bdtmPvzwQ9O2bVsze/ZsXxySnMfFYr1v3z7z+OOPm+zsbJOXl2feffdd06lTJ3PTTTd56lCsm4dHH33UrF+/3uTl5Znt27ebRx991FgsFvPRRx8ZYxr3nFZi1owsXbrUdOjQwdjtdtO/f3+zadMmXzdJLsOYMWNMTEyMsdvtpl27dmbMmDFm3759nu0VFRVmypQppk2bNiY4ONiMGjXKFBQU+LDFcinWrVtngLNeEyZMMMa4p8x/7LHHTFRUlAkICDBpaWkmNzfXq46ioiIzduxYExISYhwOh5k0aZI5ffq0D45GLuRCsS4vLzeDBw82bdu2Nf7+/iY+Pt7ce++9Z32pplg3D+eKM2BWrFjhKVOfvvvAgQNm2LBhJigoyERERJgZM2aYmpqaRj4auZCLxTo/P9/cdNNNJiwszAQEBJguXbqYWbNmmVOnTnnVo1g3fXfffbeJj483drvdtG3b1qSlpXmSMmMa95y2GGPMpV1jExERERERkStJ95iJiIiIiIj4mBIzERERERERH1NiJiIiIiIi4mNKzERERERERHxMiZmIiIiIiIiPKTETERERERHxMSVmIiIiIiIiPqbETERERERExMeUmImISIs1ceJERo4c6etmiIiIKDETERERERHxNSVmIiJy1XvrrbdITEwkKCiI8PBw0tPTmTVrFq+88grvvvsuFosFi8VCZmYmAAcPHuSXv/wlTqeTsLAwRowYwYEDBzz1nbnSNn/+fNq2bYvD4WDy5MlUV1dfcJ9lZWWNfOQiItJc+Pm6ASIiIg2poKCAsWPHsmjRIkaNGsXp06f55JNPuOuuu8jPz6ekpIQVK1YAEBYWRk1NDUOGDCE1NZVPPvkEPz8/nnzySYYOHcr27dux2+0AZGRkEBgYSGZmJgcOHGDSpEmEh4ezYMGC8+7TGOPLX4WIiDRhSsxEROSqVlBQQG1tLaNHjyY+Ph6AxMREAIKCgqiqqiI6OtpT/tVXX8XlcvHyyy9jsVgAWLFiBU6nk8zMTAYPHgyA3W7nz3/+M8HBwfTu3ZvHH3+cWbNm8cQTT1xwnyIiIueioYwiInJVS0pKIi0tjcTERO644w7++Mc/8u233563/BdffMG+ffsIDQ0lJCSEkJAQwsLCqKysZP/+/V71BgcHe5ZTU1MpLS3l4MGDl7xPERERJWYiInJVs9lsrF27ljVr1tCrVy+WLl1K9+7dycvLO2f50tJSkpOT2bZtm9drz549jBs3rkH2KSIiosRMRESuehaLhYEDBzJ//ny2bt2K3W5n9erV2O126urqvMped9117N27l8jISLp06eL1at26tafcF198QUVFhWd506ZNhISEEBcXd8F9ioiInIsSMxERuapt3ryZp556iuzsbPLz83n77bc5fvw4PXv2pGPHjmzfvp3c3FxOnDhBTU0N48ePJyIighEjRvDJJ5+Ql5dHZmYmDz74IIcOHfLUW11dzT333MOuXbv44IMPmDt3LtOmTcNqtV5wnyIiIueiyT9EROSq5nA42LBhA0uWLKGkpIT4+Hiee+45hg0bRr9+/cjMzKRfv36Ulpaybt06Bg0axIYNG3jkkUcYPXo0p0+fpl27dqSlpeFwODz1pqWl0bVrV2666SaqqqoYO3Ys8+bNu+g+RUREzsViNHeviIjIJZk4cSLFxcW88847vm6KiIhcJTSUUURERERExMeUmImIiIiIiPiYhjKKiIiIiIj4mK6YiYiIiIiI+JgSMxERERERER9TYiYiIiIiIuJjSsxERERERER8TImZiIiIiIiIjykxExERERER8TElZiIiIiIiIj6mxExERERERMTHlJiJiIiIiIj42P8HmYnxYYQ+MWkAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(10,4))\n", + "ax.set_xlabel(\"steps\")\n", + "ax.set_ylabel(\"dt\")\n", + "ax.set_yscale(\"log\")\n", + "#ax.plot(mindt)\n", + "ax.plot(np.arange(len(dts))+1,dts,label=\"anal_dt\",ls=\"--\",c=\"black\")\n", + "ax.fill_between(np.arange(len(d_dts)), 1e-4, 1, where=(d_dts+1) < 0.85, color='green', alpha=0.5)\n", + "ax.fill_between(np.arange(len(d_dts)), 1e-4, 1, where=(d_dts+1) > 1./0.85, color='red', alpha=0.5)\n", + "\n", + "ax.scatter(np.arange(len(_failed)),np.array(_failed),label=\"failed\",s=49)\n", + "#ax.scatter(np.arange(len(mindt)),mindt,label=\"n-body\",alpha=0.4)\n", + "ax.scatter(np.arange(len(_dtaus)),np.array(_dtaus),label=\"anal step\",s=9,alpha=0.4)\n", + "ax.legend()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "id": "6bc5d70a", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:18:34.450813Z", + "start_time": "2023-08-08T12:18:34.275826Z" + } + }, + "outputs": [], + "source": [ + "Es = np.linspace(0.,np.pi*2.,1000)\n", + "dts = np.zeros(len(Es))\n", + "d_dts = np.zeros(len(Es))\n", + "dd_dts = np.zeros(len(Es))\n", + "for i in range(len(Es)):\n", + " d_dts[i] = (d_anal_dt_f(_e, Es[i], _epsilon))\n", + " dd_dts[i] = (dd_anal_dt_f(_e, Es[i], _epsilon))\n", + " dts[i] = anal_dt_f(_e, Es[i], _epsilon)" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "id": "9ea49577", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:19:04.829801Z", + "start_time": "2023-08-08T12:19:04.629528Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 130, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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ubm5uuWWW9ShQwe1adNGAwYM0ObNm42O5RIoWS5iyZIlmjlzpmbPnq0tW7YoNjZWY8eOVWFhodHRcBaVlZWKjY1VSkqK0VFwHtauXasZM2Zow4YN+uKLL1RXV6fLL79clZWVRkdDE0REROhvf/ub0tPTtXnzZl166aW65pprtHPnTqOj4RylpaXpxRdf1MCBA42OgnPQr18/HT16tPH27bffGh0JTXTixAkNHz5cnp6e+vTTT7Vr1y49/fTTat++vdHRXAIj3F1EcnKyEhMTtWDBAkmSzWZTZGSkHnjgAT3++OMGp0NTmUwmrVixQtdee63RUXCeioqK1KlTJ61du1YjR440Og7OQ1BQkObOnas77rjD6ChoooqKCg0ePFjPPfec/vKXvyguLk7z5s0zOhbO4oknntDKlSuVkZFhdBSch8cff1zfffedvvnmG6OjuCTOZLmA2tpapaena/To0Y3HzGazRo8erfXr1xuYDHA/paWlkhpeqMO1WK1WLV68WJWVlRo6dKjRcXAOZsyYoauuuuqUv4NwDfv371fnzp3VtWtX3XzzzTpy5IjRkdBEH3zwgRISEnT99derU6dOGjRokF5++WWjY7kMSpYLKC4ultVqVUhIyCnHQ0JClJ+fb1AqwP3YbDY9/PDDGj58uPr37290HDTR9u3b1bZtW3l7e+uee+7RihUr1LdvX6NjoYkWL16sLVu2aM6cOUZHwTlKTk7WwoUL9dlnn+n5559XZmamRowYofLycqOjoQkOHTqk559/Xj169NCqVat077336sEHH9SiRYuMjuYSPIwOAACuYsaMGdqxYwfXFLiYXr16KSMjQ6WlpXr33Xc1depUrV27lqLlArKzs/XQQw/piy++kI+Pj9FxcI7GjRvX+L8HDhyo5ORkRUdHa+nSpSzXdQE2m00JCQl66qmnJEmDBg3Sjh079MILL2jq1KkGp3N+nMlyAcHBwbJYLCooKDjleEFBgUJDQw1KBbiX+++/Xx999JG+/vprRUREGB0H58DLy0vdu3dXfHy85syZo9jYWP373/82OhaaID09XYWFhRo8eLA8PDzk4eGhtWvXav78+fLw8JDVajU6Is5Bu3bt1LNnTx04cMDoKGiCsLCw096M6tOnD0s+m4iS5QK8vLwUHx+v1atXNx6z2WxavXo11xUAzcxut+v+++/XihUr9NVXX6lLly5GR8IFstlsqqmpMToGmuCyyy7T9u3blZGR0XhLSEjQzTffrIyMDFksFqMj4hxUVFTo4MGDCgsLMzoKmmD48OGnbVmyb98+RUdHG5TItbBc0EXMnDlTU6dOVUJCgpKSkjRv3jxVVlZq+vTpRkfDWVRUVJzyrl1mZqYyMjIUFBSkqKgoA5OhKWbMmKG3335b77//vvz9/RuvgwwMDFSbNm0MToezmTVrlsaNG6eoqCiVl5fr7bff1po1a7Rq1Sqjo6EJ/P39T7v+0c/PTx06dOC6SBfw2GOPafz48YqOjlZeXp5mz54ti8WiKVOmGB0NTfDII49o2LBheuqppzR58mRt2rRJL730kl566SWjo7kESpaLuOGGG1RUVKQ//vGPys/PV1xcnD777LPThmHA+WzevFmjRo1q/HjmzJmSpKlTp2rhwoUGpUJTPf/885KkSy655JTjr7/+uqZNm9bygXBOCgsLddttt+no0aMKDAzUwIEDtWrVKo0ZM8boaECrl5OToylTpujYsWPq2LGjLrroIm3YsEEdO3Y0OhqaIDExUStWrNCsWbP0pz/9SV26dNG8efN08803Gx3NJbBPFgAAAAA4ENdkAQAAAIADUbIAAAAAwIEoWQAAAADgQJQsAAAAAHAgShYAAAAAOBAlCwAAAAAciJIFAAAAAA5EyQIAAAAAB6JkAQAAAIADUbIAADiDadOmyWQynXa74oorjI4GAHBiHkYHAADAmV1xxRV6/fXXTznm7e1tUBoAgCugZAEA8Au8vb0VGhpqdAwAgAthuSAAAAAAOBAlCwCAX/DRRx+pbdu2p9yeeuopo2MBAJwYywUBAPgFo0aN0vPPP3/KsaCgIIPSAABcASULAIBf4Ofnp+7duxsdAwDgQlguCAAAAAAOxJksAAB+QU1NjfLz80855uHhoeDgYIMSAQCcHSULAIBf8NlnnyksLOyUY7169dKePXsMSgQAcHYmu91uNzoEAAAAALQWXJMFAAAAAA5EyQIAAAAAB6JkAQAAAIADUbIAAAAAwIEoWQAAAADgQJQsAAAAAHAgShYAAAAAOBAlCwAAAAAciJIFAAAAAA5EyQIAAAAAB6JkAQAAAIAD/X9DOiQVBMMnrgAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(10,4))\n", + "ax.set_xlabel(\"E\")\n", + "ax.set_ylabel(\"dt\")\n", + "ax.set_yscale(\"log\")\n", + "#ax.set_ylim([1e-2,1e2])\n", + "ax.plot(Es, dts)" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "id": "66793fb1", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-08T12:18:34.592907Z", + "start_time": "2023-08-08T12:18:34.451916Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(10,4))\n", + "ax.set_xlabel(\"E\")\n", + "ax.set_ylabel(\"dt_new/dt_old\")\n", + "ax.set_yscale(\"log\")\n", + "ax.axhline(0.85)\n", + "ax.axhline(1)\n", + "ax.axhline(1./0.85)\n", + "\n", + "ax.set_ylim([1e-2,1e2])\n", + "ax.plot(Es, (d_dts)+1)\n", + "#ax.plot(Es, dd_dts)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36fbb027", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "939fdf33", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9157db3c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f63f42c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8abbfee", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d4e8f28", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce93f57d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8c345a8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ff8634b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f28037c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "9dd789b4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAG1CAYAAAAV2Js8AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy89olMNAAAACXBIWXMAAA9hAAAPYQGoP6dpAABb30lEQVR4nO3dZ3RU5f728W96SKcTIPROKAKCICogCKHbQP2riIqigEhEihA6SJcWReWoqOd4UFR6b1KlSeihl1ADBFJJm9nPi2iegyImIcmeyVyftVjLJJOZK0X2xb73vn9OhmEYiIiIiDggZ7MDiIiIiJhFRUhEREQcloqQiIiIOCwVIREREXFYKkIiIiLisFSERERExGGpCImIiIjDUhESERERh+VqdgBbZrVauXTpEr6+vjg5OZkdR0RERLLAMAzi4+MpXbo0zs73PuejInQPly5dIigoyOwYIiIikgNRUVGULVv2no9REboHX19fIOMb6efnZ3IaERERyYq4uDiCgoIyj+P3oiJ0D38sh/n5+akIiYiI2JmsXNaii6VFRETEYakIiYiIiMPS0lgusFgspKWlmR1Dfufm5oaLi4vZMURExA6oCN0HwzC4cuUKt27dMjuK/ElAQAClSpXStgciInJPKkL34Y8SVKJECby8vHTQtQGGYZCUlER0dDQAgYGBJicSERFbpiKUQxaLJbMEFS1a1Ow48j8KFSoEQHR0NCVKlNAymYiI/C1dLJ1Df1wT5OXlZXISuZs/fi66dktERO5FReg+aTnMNunnIiIiWaEiJCIiIg5LRUhEREQcloqQ2KVNmzbh5OSkrQtEROS+qAg5oM2bN9OpUydKly6Nk5MTixYt+stjpk6dSokSJShRogTTpk2742M7d+6kYcOGpKen51Piv2rWrBmXL1/G39/ftAwiInJ/DMMgzWI1NYOKkANKTEykXr16hIeH3/XjBw4cYMSIEfz3v//lu+++Y/jw4Rw8eBCA9PR0evfuzdy5c3F1NWf3hbS0NNzd3bVhooiIHYtLTuPtf//GyCWHTc2hIpSLDMMgMTXRlD+GYWQ5Z0hICOPGjePJJ5+868cjIyOpW7curVq14vHHH6du3bpERkYCMGXKFB599FEefPDBf3ydr776ioCAABYtWkTVqlXx9PSkbdu2REVF3fG4xYsX06BBAzw9PalUqRKjR4++42yT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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.set_xlabel(\"1-e\")\n", + "ax.set_ylabel(\"mindt\")\n", + "ax.set_xscale(\"log\")\n", + "ax.set_yscale(\"log\")\n", + "es = 1.-np.logspace(-1,0,100)\n", + "\n", + "anal_dt = np.zeros(len(es))\n", + "\n", + "for i in range(len(es)):\n", + " Es = np.linspace(0, np.pi*2.,10000)\n", + " _a = np.zeros(len(Es))\n", + " _j = np.zeros(len(Es))\n", + " for k in range(len(Es)):\n", + " _a[k] = np.abs(a(es[i], Es[k]))\n", + " _j[k] = np.abs(j(es[i], Es[k]))\n", + " epsilon = 1e-9\n", + " b0 = _j \n", + " errork = _j/_a\n", + " _anal_dt = 1./errork*2.4*np.power(1e-9,1./7.)\n", + " anal_dt[i] = np.min(_anal_dt)\n", + "\n", + "\n", + "ax.plot(1.-es,1e-2*2*np.pi*(1-es)**2/np.sqrt(1-es**2),label=\"1% peri\",color=\"green\",zorder=4)\n", + "ax.plot(1.-es,anal_dt,label=\"anal dt\")\n", + "\n", + "\n", + "ax.legend()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cff22c1a", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa4beb65", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82226932", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5d4d6a1", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f9c846c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d995fb0", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/binaryformat.md b/docs/binaryformat.md index 9fa7ea362..f2be128ea 100644 --- a/docs/binaryformat.md +++ b/docs/binaryformat.md @@ -1,9 +1,11 @@ # Binary Format -REBOUND comes with its one binary format. -The binary format allows you to store a current simulation state to a file. -The Simulation Archive is an extension of that format which allows you to store multiple snapshots in one file. +REBOUND comes with its own binary format. +The binary format allows you to store a current simulation state to a file or to memory. +The binary format is also used when you make a copy of a simulation or when you compare two similations with each other. +The Simulation Archive is an extension of the binary format which allows you to store multiple snapshots of a simulation in one file. This page explains the details of the binary format. +It is mainly intended for people who wish to extend the built-in REBOUND functionality. You do not need to know those details if you're only working with binary files to save and load simulations. REBOUND uses two structures for the binary files: @@ -43,7 +45,7 @@ You create a binary file if you save a simulation // ... setup simulation ... sim.save("snapshot.bin") ``` -Such a binary file with one snapshot is simply a set of `reb_binaryfield`s followed by one `reb_simulationarchive_blob` at the end: +Such a binary file with one snapshot is simply a set of `reb_binaryfield`s followed by one `reb_simulationarchive_blob` at the end, for example: ``` reb_binary_field: @@ -71,8 +73,11 @@ reb_simulationarchive_blob: ``` Each of the binary fields provides the context (type and size) for the data that immediately follows the field. -The type is an integer defined in the `rebound.h` file as `enum REB_BINARY_FIELD_TYPE`. -The last binary field is of type `END` to indicate that the snapshot ends here. +The type is an integer defined in the `reb_binary_field_descriptor_list` (see below). +The last binary field of type `9999` (`end`) to indicate that the snapshot ends here. + +!!! note + Before version 3.27 data was encoded using the enum `REB_BINARY_FIELD_TYPE` instead of `reb_binary_field_descriptor_list`. ## SimulationArchive file (multiple snapshots) @@ -143,3 +148,25 @@ reb_simulationarchive_blob: The offsets are also used as a sort of checksum to detect if a binary file has been corrupted (for example because a user ran out of disk space). If a binary file is corrupted, REBOUND attempts some magic and will recover the last snapshot which does not appear corrupted. You will see a warning message when that happens and should proceed with caution (make a backup!). + + +## Binary Field Descriptor + +REBOUND maintains a list of fields it needs to input/output in order to restore a simulation. +This list is of type `struct reb_binary_field_descriptor[]` and defined in `output.c` as `reb_binary_field_descriptor_list`. +A single struct `reb_binary_field_descriptor` contains the information to input/output one REBOUND field, for example the current simulation time `t`: + +```c + struct reb_binary_field_descriptor fd_t = { 0, REB_DOUBLE, "t", offsetof(struct reb_simulation, t), 0, 0}; +``` +The first number is a unique identifier (in this case 0). The second entry is the type of data, in this case a single double precision floating point number. The third entry is a string used to identify the field. This is only used when generating human-readable output and is typically the same as the variable name in C. The next entry is the offset of where this variable is stored relative to the beginning of the simulation structure. + +REBOUND also supports array like fields. For example consider the `particles` field: +```c + struct reb_binary_field_descriptor fd_particles = { 85, REB_POINTER, "particles", offsetof(struct reb_simulation, particles), offsetof(struct reb_simulation, N), sizeof(struct reb_particle)}; +``` + +The second to last entry lists the offset of the a variable in the `reb_simulation` structure that determines the number of array elements. In this case the number of partiles. The last entry is the size of a single element. In this case, the size of one `reb_particle`. + +If you add an additional field to the `reb_simulation` struct and you want to write it to a binary file and read it back in, then you need to add an entry to `reb_binary_field_descriptor_list`. + diff --git a/examples/binary_field_type_reverse/Makefile b/examples/binary_field_type_reverse/Makefile new file mode 100644 index 000000000..718d53cb2 --- /dev/null +++ b/examples/binary_field_type_reverse/Makefile @@ -0,0 +1,22 @@ +export OPENGL=0 +include ../../src/Makefile.defs + +all: librebound + @echo "" + @echo "Compiling problem file ..." + $(CC) -I../../src/ -Wl,-rpath,./ $(OPT) $(PREDEF) problem.c -L. -lrebound $(LIB) -o rebound + @echo "" + @echo "REBOUND compiled successfully." + +librebound: + @echo "Compiling shared library librebound.so ..." + $(MAKE) -C ../../src/ + @-rm -f librebound.so + @ln -s ../../src/librebound.so . + +clean: + @echo "Cleaning up shared library librebound.so ..." + @-rm -f librebound.so + $(MAKE) -C ../../src/ clean + @echo "Cleaning up local directory ..." + @-rm -vf rebound diff --git a/examples/binary_field_type_reverse/problem.c b/examples/binary_field_type_reverse/problem.c new file mode 100644 index 000000000..9dedea095 --- /dev/null +++ b/examples/binary_field_type_reverse/problem.c @@ -0,0 +1,43 @@ +/** + * A very simple test problem + * + * We first create a REBOUND simulation, then we add + * two particles and integrate the system for 100 time + * units. + */ +#include "rebound.h" +#include "output.h" +#include +#include + +int main(int argc, char* argv[]) { + struct reb_simulation* r = reb_create_simulation(); + + reb_add_fmt(r, "m", 1.); // Central object + reb_add_fmt(r, "m a e", 1e-3, 1., 0.1); // Jupiter mass planet + reb_add_fmt(r, "a e", 1.4, 0.1); // Massless test particle + + reb_steps(r,1); + + char* buf = NULL; + size_t size = 0; + reb_output_binary_to_stream(r, &buf, &size); + + + + struct reb_simulationarchive* sa = malloc(sizeof(struct reb_simulationarchive)); + reb_read_simulationarchive_from_buffer_with_messages(sa, buf, size, NULL, NULL); + + + struct reb_simulation* r2 = reb_create_simulation(); + enum reb_input_binary_messages w =0; + reb_create_simulation_from_simulationarchive_with_messages(r2,sa,-1,&w); + + reb_close_simulationarchive(sa); + free(buf); + printf("sizeof(size_t)= %ld\n", sizeof(unsigned int)); + + reb_free_simulation(r); + reb_free_simulation(r2); +} + diff --git a/examples/closeencounter/problem.c b/examples/closeencounter/problem.c index 9ddab7d38..b07a714c3 100644 --- a/examples/closeencounter/problem.c +++ b/examples/closeencounter/problem.c @@ -15,7 +15,7 @@ #include "rebound.h" void heartbeat(struct reb_simulation* r); - +double E0; int main(int argc, char* argv[]){ struct reb_simulation* r = reb_create_simulation(); r->dt = 0.01*2.*M_PI; // initial timestep @@ -40,6 +40,7 @@ int main(int argc, char* argv[]){ reb_add(r, planet); } reb_move_to_com(r); // This makes sure the planetary systems stays within the computational domain and doesn't drift. + E0 = reb_tools_energy(r); reb_integrate(r, INFINITY); } @@ -47,4 +48,6 @@ void heartbeat(struct reb_simulation* r){ if (reb_output_check(r, 10.*2.*M_PI)){ reb_output_timing(r, 0); } + double E1 = reb_tools_energy(r); + printf("%e\n", fabs((E1-E0)/E0)); } diff --git a/examples/mpi_unittests/problem.c b/examples/mpi_unittests/problem.c index a516ab37c..462b20b26 100644 --- a/examples/mpi_unittests/problem.c +++ b/examples/mpi_unittests/problem.c @@ -60,9 +60,50 @@ void test_twobody(){ assert(fabs(o.a-1.)<1e-3); assert(fabs(o.e-0.1)<1e-2); + printf("Checking input/output...\n"); + + com = reb_get_com(r); // Need to call this on all machines. + if (r->mpi_id==0){ + for (int i=0; i<10; i++){ + reb_add_fmt(r, "m a primary hash", 0.01, 2.0+0.1*i, com, i); + } + } + reb_steps(r, 1); + { + // Delete any previous files + char filename[1024]; + sprintf(filename, "out.bin_%d", r->mpi_id); + remove(filename); + } + reb_simulationarchive_snapshot(r, "out.bin"); + reb_steps(r, 1); + reb_simulationarchive_snapshot(r, "out.bin"); + reb_steps(r, 10); + + struct reb_simulationarchive* sa = reb_open_simulationarchive("out.bin"); + assert(sa->nblobs==2); + struct reb_simulation* r2 = reb_create_simulation_from_simulationarchive(sa,-1); + reb_steps(r2, 10); + + assert(r->N == r2->N); + assert(r->t == r2->t); + + // Order of particles will be different. Need to compare them by hash + for(int i=0; i<10; i++){ + struct reb_particle p1 = reb_get_remote_particle_by_hash(r, i); + struct reb_particle p2 = reb_get_remote_particle_by_hash(r2, i); + assert(p1.x==p2.x); + assert(p1.y==p2.y); + assert(p1.z==p2.z); + } + + + + printf("Cleanup...\n"); reb_mpi_finalize(r); reb_free_simulation(r); + reb_free_simulation(r2); } diff --git a/examples/selfgravity_disc_mpi/problem.c b/examples/selfgravity_disc_mpi/problem.c index 2635f3485..ee3c30209 100644 --- a/examples/selfgravity_disc_mpi/problem.c +++ b/examples/selfgravity_disc_mpi/problem.c @@ -76,8 +76,8 @@ int main(int argc, char* argv[]){ #ifdef OPENGL // Hack to artificially increase particle array. // This cannot be done once OpenGL is activated. - r->allocatedN *=8; - r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocatedN); + r->allocated_N *=8; + r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocated_N); #endif // OPENGL // Start the integration diff --git a/examples/shearing_sheet_mpi/problem.c b/examples/shearing_sheet_mpi/problem.c index 25c9016e9..d08e7886c 100644 --- a/examples/shearing_sheet_mpi/problem.c +++ b/examples/shearing_sheet_mpi/problem.c @@ -88,8 +88,8 @@ int main(int argc, char* argv[]) { #ifdef OPENGL // Hack to artificially increase particle array. // This cannot be done once OpenGL is activated. - r->allocatedN *=8; - r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocatedN); + r->allocated_N *=8; + r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocated_N); #endif // OPENGL // Start the integration diff --git a/rebound/__init__.py b/rebound/__init__.py index 1315d7d3e..580b356c0 100644 --- a/rebound/__init__.py +++ b/rebound/__init__.py @@ -84,7 +84,7 @@ class ParticleNotFound(Exception): pass from .tools import hash, mod2pi, M_to_f, E_to_f, M_to_E, spherical_to_xyz, xyz_to_spherical -from .simulation import Simulation, Orbit, Variation, reb_simulation_integrator_saba, reb_simulation_integrator_whfast, reb_simulation_integrator_sei, reb_simulation_integrator_mercurius, reb_simulation_integrator_ias15, ODE, Rotation, Vec3d, _Vec3d +from .simulation import Simulation, Orbit, Variation, reb_simulation_integrator_saba, reb_simulation_integrator_whfast, reb_simulation_integrator_sei, reb_simulation_integrator_mercurius, reb_simulation_integrator_ias15, ODE, Rotation, Vec3d, _Vec3d, binary_field_descriptor_list from .particle import Particle from .plotting import OrbitPlot, OrbitPlotSet from .simulationarchive import SimulationArchive @@ -97,4 +97,4 @@ def __init__(self, processes=None, initializer=None, initargs=(), **kwargs): else: from .interruptible_pool import InterruptiblePool -__all__ = ["__libpath__", "__version__", "__build__", "__githash__", "SimulationArchive", "Simulation", "Orbit", "OrbitPlot", "OrbitPlotSet", "Particle", "SimulationError", "Encounter", "Collision", "Escape", "NoParticles", "ParticleNotFound", "InterruptiblePool","Variation", "reb_simulation_integrator_whfast", "reb_simulation_integrator_ias15", "reb_simulation_integrator_saba", "reb_simulation_integrator_sei","reb_simulation_integrator_mercurius", "clibrebound", "mod2pi", "M_to_f", "E_to_f", "M_to_E", "ODE", "Rotation", "Vec3d", "spherical_to_xyz", "xyz_to_spherical"] +__all__ = ["__libpath__", "__version__", "__build__", "__githash__", "SimulationArchive", "Simulation", "Orbit", "OrbitPlot", "OrbitPlotSet", "Particle", "SimulationError", "Encounter", "Collision", "Escape", "NoParticles", "ParticleNotFound", "InterruptiblePool","Variation", "reb_simulation_integrator_whfast", "reb_simulation_integrator_ias15", "reb_simulation_integrator_saba", "reb_simulation_integrator_sei","reb_simulation_integrator_mercurius", "clibrebound", "mod2pi", "M_to_f", "E_to_f", "M_to_E", "ODE", "Rotation", "Vec3d", "spherical_to_xyz", "xyz_to_spherical","binary_field_descriptor_list"] diff --git a/rebound/particle.py b/rebound/particle.py index e8c4f0a15..25fa6b376 100644 --- a/rebound/particle.py +++ b/rebound/particle.py @@ -1,4 +1,4 @@ -from ctypes import Structure, c_double, c_int, byref, memmove, sizeof, c_uint32, c_uint, c_ulong +from ctypes import Structure, c_double, c_int, byref, memmove, sizeof, c_uint32, c_uint, c_ulong, c_char_p, string_at, POINTER, c_char from . import clibrebound, E_to_f, M_to_f, mod2pi import math import ctypes.util @@ -156,6 +156,25 @@ def __init__(self, simulation=None, particle=None, m=None, x=None, y=None, z=Non """ + # Unpickling + binarydata = None + if isinstance(simulation, bytes): + # simulation is actually a bytes array with the particle data + binarydata = simulation + if isinstance(particle, bytes): + # simulation is actually a bytes array with the particle data + binarydata = particle + if binarydata is not None: + if len(binarydata) != sizeof(self): + raise ValueError("Binary particle data does not have the right size.") + buft = c_char * len(binarydata) + buf = buft.from_buffer_copy(binarydata) + memmove(byref(self), byref(buf), sizeof(self)) + self.c = 0 + self.sim = 0 + self.ap = 0 + return + if Omega == "uniform": Omega = random.vonmisesvariate(0.,0.) if omega == "uniform": @@ -401,6 +420,10 @@ def copy(self): memmove(byref(np), byref(self), sizeof(self)) return np +# Pickling method + def __reduce__(self): + return (Particle, (string_at(byref(self), size=sizeof(self)),)) + def calculate_orbit(self, primary=None, G=None): """ Returns a rebound.Orbit object with the keplerian orbital elements @@ -572,6 +595,14 @@ def sample_orbit(self, Npts=100, primary=None, samplingAngle=None, duplicateEndp # Simple operators for particles. + def __eq__(self, other): + # This ignores the pointer values + if not isinstance(other,Particle): + return NotImplemented + clibrebound.reb_diff_particles.restype = c_int + ret = clibrebound.reb_diff_particles(self, other) + return not ret + def __pow__(self, other): if not isinstance(other, Particle): return NotImplemented diff --git a/rebound/simulation.py b/rebound/simulation.py index fc4d2ef59..b59e1781e 100644 --- a/rebound/simulation.py +++ b/rebound/simulation.py @@ -1,4 +1,4 @@ -from ctypes import Structure, c_double, POINTER, c_uint32, c_float, c_int, c_uint, c_uint32, c_int64, c_long, c_ulong, c_ulonglong, c_void_p, c_char_p, CFUNCTYPE, byref, create_string_buffer, addressof, pointer, cast +from ctypes import Structure, c_double, POINTER, c_uint32, c_float, c_int, c_uint, c_uint32, c_int64, c_long, c_ulong, c_ulonglong, c_void_p, c_char_p, CFUNCTYPE, byref, create_string_buffer, addressof, pointer, cast, c_char, c_size_t, string_at from . import clibrebound, Escape, NoParticles, Encounter, Collision, SimulationError, ParticleNotFound, M_to_E from .citations import cite from .particle import Particle @@ -59,12 +59,36 @@ (False, 128, "Encountered unkown field in file. File might have been saved with a different version of REBOUND."), (True, 256, "Integrator type is not supported by this simulation archive version."), (False, 512, "The binary file seems to be corrupted. An attempt has been made to read the uncorrupted parts of it."), + (True, 1024, "Reading old SimulationArchives (version < 2) is no longer supported. If you need to read such an archive, use a REBOUND version <= 3.26.3"), ] class reb_hash_pointer_pair(Structure): _fields_ = [("hash", c_uint32), ("index", c_int)] +class reb_binary_field_descriptor(Structure): + def __repr__(self): + return '<{0}.{1} object at {2}, type={3}, dtype={4}, name=\'{5}\'>'.format(self.__module__, type(self).__name__, hex(id(self)), self.type, self.dtype, self.name.decode("ascii")) + _fields_ = [("type", c_uint), + ("dtype", c_int), + ("name", c_char*1024), + ("offset", c_size_t), + ("offset_N", c_size_t), + ("element_size", c_size_t), + ] +def binary_field_descriptor_list(): + fd_pointer_t = POINTER(reb_binary_field_descriptor) + fd_pointer = (reb_binary_field_descriptor*3).in_dll(clibrebound, "reb_binary_field_descriptor_list") + fd_pointer = cast(fd_pointer, fd_pointer_t) # not sure why I have to do it this way + l = [] + i=0 + while True: + l.append(fd_pointer[i]) + if fd_pointer[i].name == b'end': + break + i += 1 + return l + class Rotation(Structure): """ @@ -450,13 +474,18 @@ class reb_simulation_integrator_ias15(Structure): """ def __repr__(self): - return '<{0}.{1} object at {2}, epsilon={3}, min_dt={4}>'.format(self.__module__, type(self).__name__, hex(id(self)), self.epsilon, self.min_dt) - + return '<{0}.{1} object at {2}, dt_mode={3}, epsilon={4}, min_dt={5}>'.format(self.__module__, type(self).__name__, hex(id(self)), self.dt_mode, self.epsilon, self.min_dt) + + _fields_ = [("epsilon", c_double), ("min_dt", c_double), ("epsilon_global", c_uint), + ("dt_mode", c_uint), + ("rejected", c_long), + ("mindt", c_double), + ("safety", c_double), ("_iterations_max_exceeded", c_ulong), - ("_allocatedN", c_uint), + ("_allocated_N", c_uint), ("_at", POINTER(c_double)), ("_x0", POINTER(c_double)), ("_v0", POINTER(c_double)), @@ -589,8 +618,8 @@ class reb_simulation_integrator_whfast(Structure): ("_p_jh", POINTER(Particle)), ("_p_temp", POINTER(Particle)), ("is_synchronized", c_uint), - ("_allocatedN", c_uint), - ("_allocatedNtmp", c_uint), + ("_allocated_N", c_uint), + ("_allocated_Ntmp", c_uint), ("_timestep_warning", c_uint), ("_recalculate_coordinates_but_not_synchronized_warning", c_uint)] @@ -790,11 +819,39 @@ class Simulation(Structure): >>> sim = rebound.Simulation(filename="archive.bin", snapshot=34) + Finally, you can also create a new Simulation by passing a bytes object of a + SimulationArchive to Simulation(): + + >>> sim = rebound.Simulation(open("archive.bin","rb").read()) + """ def __new__(cls, *args, **kw): # Handle arguments filename = None if len(args)>0: + # If first argument is of type bytes, then this is unpickling a Simulation + if isinstance(args[0], bytes): + l = len(args[0]) + buft = c_char * l + buf = buft.from_buffer_copy(args[0]) + # Note: Not calling SimulationArchive. + # Doing this manually here because we need to keep the reference to buf. + # So we can later access the contents of the archive to get the simulation. + sa = SimulationArchive.__new__(SimulationArchive, None, None) + w = c_int(0) + clibrebound.reb_read_simulationarchive_from_buffer_with_messages(byref(sa), byref(buf), c_size_t(l), None, byref(w)) + sim = super(Simulation,cls).__new__(cls) + clibrebound.reb_init_simulation(byref(sim)) + clibrebound.reb_create_simulation_from_simulationarchive_with_messages(byref(sim),byref(sa),c_int(-1),byref(w)) + for majorerror, value, message in BINARY_WARNINGS: + if w.value & value: + if majorerror: + raise RuntimeError(message) + else: + # Just a warning + warnings.warn(message, RuntimeWarning) + return sim + # Otherwise assume first argument is filename filename = args[0] if "filename" in kw: filename = kw["filename"] @@ -803,7 +860,7 @@ def __new__(cls, *args, **kw): snapshot = args[1] if "snapshot" in kw: snapshot = kw["snapshot"] - + # Create simulation if filename is None: # Create a new simulation @@ -1034,10 +1091,21 @@ def process_messages(self): elif msg[0]=='e': raise RuntimeError(msg[1:]) +# Pickling methods: return SimulationArchive binary + def __reduce__(self): + buf = c_char_p() + size = c_size_t() + clibrebound.reb_output_binary_to_stream(byref(self), byref(buf), byref(size)) + s = bytes(string_at(buf, size=size.value)) #make copy + clibrebound.reb_output_free_stream(buf) # free original + return (Simulation, (s,)) + +# Other operators def __del__(self): if self._b_needsfree_ == 1: # to avoid, e.g., sim.particles[1]._sim.contents.G creating a Simulation instance to get G, and then freeing the C simulation when it immediately goes out of scope clibrebound.reb_free_pointers(byref(self)) + def __eq__(self, other): # This ignores the walltime parameter if not isinstance(other,Simulation): @@ -1045,6 +1113,13 @@ def __eq__(self, other): clibrebound.reb_diff_simulations.restype = c_int ret = clibrebound.reb_diff_simulations(byref(self), byref(other),c_int(2)) return not ret + + def diff(self, other): + if not isinstance(other,Simulation): + return NotImplemented + clibrebound.reb_diff_simulations_char.restype = c_char_p + output = clibrebound.reb_diff_simulations_char(byref(other), byref(self)) + print(output.decode("utf-8")) def __add__(self, other): if not isinstance(other,Simulation): @@ -1150,7 +1225,7 @@ def create_ode(self, length, needs_nbody=True): return ODE.from_address(ctypes.addressof(ode_p.contents)) # Status functions - def status(self): + def status(self, showParticles=True, showAllFields=True): """ Prints a summary of the current status of the simulation. @@ -1164,12 +1239,20 @@ def status(self): s += "Selected integrator: \t" + self.integrator + "\n" s += "Simulation time: \t%.16e\n" %self.t s += "Current timestep: \t%f\n" %self.dt - if self.N>0: - s += "---------------------------------\n" + s += "---------------------------------\n" + if self.N>0 and showParticles: for p in self.particles: s += str(p) + "\n" - s += "---------------------------------" - print(s) + s += "---------------------------------\n" + print(s, end="") + if showAllFields: + print("The following fields have non-default values:") + newsim = Simulation() + clibrebound.reb_diff_simulations_char.restype = c_char_p + output = clibrebound.reb_diff_simulations_char(byref(newsim), byref(self)) + print(output.decode("utf-8")) + + # Set function pointer for additional forces @property @@ -2424,9 +2507,9 @@ def __repr__(self): ("_encounterN", c_uint), ("_encounterNactive", c_uint), ("_tponly_encounter", c_uint), - ("_allocatedN", c_uint), - ("_allocatedN_additionalforces", c_uint), - ("_dcrit_allocatedN", c_uint), + ("_allocated_N", c_uint), + ("_allocated_N_additionalforces", c_uint), + ("_dcrit_allocated_N", c_uint), ("_dcrit", POINTER(c_double)), ("_particles_backup", POINTER(Particle)), ("_particles_backup_additionalforces", POINTER(Particle)), @@ -2466,7 +2549,7 @@ def update_particles(self): ODE._fields_ = [ ("length", c_uint), - ("allocatedN", c_uint), + ("allocated_N", c_uint), ("needs_nbody", c_int), ("y", POINTER(c_double)), ("_scale", POINTER(c_double)), @@ -2576,7 +2659,7 @@ class reb_display_data(Structure): class reb_simulation_integrator_whfast512(Structure): _fields_ = [("is_synchronized", c_uint), ("keep_unsynchronized", c_uint), - ("_allocatedN", c_uint), + ("_allocated_N", c_uint), ("gr_potential", c_uint), ("recalculate_constants", c_uint), ("_p_jh", POINTER(Particle)), @@ -2601,11 +2684,11 @@ class reb_simulation_integrator_whfast512(Structure): ("_particle_lookup_table", POINTER(reb_hash_pointer_pair)), ("hash_ctr", c_int), ("N_lookup", c_int), - ("allocatedN_lookup", c_int), - ("allocatedN", c_uint), + ("allocated_N_lookup", c_int), + ("allocated_N", c_uint), ("_particles", POINTER(Particle)), ("gravity_cs", POINTER(_Vec3d)), - ("gravity_cs_allocatedN", c_int), + ("gravity_cs_allocated_N", c_int), ("_tree_root", c_void_p), ("_tree_needs_update", c_int), ("opening_angle2", c_double), @@ -2639,7 +2722,7 @@ class reb_simulation_integrator_whfast512(Structure): ("nghostz", c_int), ("collision_resolve_keep_sorted", c_int), ("collisions", c_void_p), - ("collisions_allocatedN", c_int), + ("collisions_allocated_N", c_int), ("minimum_collision_velocity", c_double), ("collisions_plog", c_double), ("max_radius", c_double*2), @@ -2679,7 +2762,7 @@ class reb_simulation_integrator_whfast512(Structure): ("ri_tes", reb_simulation_integrator_tes), ("_odes", POINTER(POINTER(ODE))), ("_odes_N", c_int), - ("_odes_allocatedN", c_int), + ("_odes_allocated_N", c_int), ("_odes_warnings", c_int), ("_additional_forces", CFUNCTYPE(None,POINTER(Simulation))), ("_pre_timestep_modifications", CFUNCTYPE(None,POINTER(Simulation))), diff --git a/rebound/simulationarchive.py b/rebound/simulationarchive.py index 4aae8ca3d..3b3841fd3 100644 --- a/rebound/simulationarchive.py +++ b/rebound/simulationarchive.py @@ -1,4 +1,4 @@ -from ctypes import Structure, c_double, POINTER, c_float, c_int, c_uint, c_uint32, c_int64, c_uint64, c_long, c_ulong, c_ulonglong, c_void_p, c_char_p, CFUNCTYPE, byref, create_string_buffer, addressof, pointer, cast +from ctypes import Structure, c_double, POINTER, c_float, c_int, c_uint, c_uint32, c_int64, c_uint64, c_long, c_ulong, c_ulonglong, c_void_p, c_char_p, CFUNCTYPE, byref, create_string_buffer, addressof, pointer, cast, c_size_t, c_char from .simulation import Simulation, BINARY_WARNINGS from . import clibrebound import os @@ -64,8 +64,9 @@ def __init__(self,filename,setup=None, setup_args=(), process_warnings=True, reu """ Arguments --------- - filename : str + filename : str or bytes Filename of the SimulationArchive file to be opened. + Can also be of type bytes to read from memory (uses fmemopen). setup : function Function to be called everytime a simulation object is created In this function, the user can setup additional forces @@ -87,6 +88,7 @@ def __init__(self,filename,setup=None, setup_args=(), process_warnings=True, reu if reuse_index: # Optimized loading clibrebound.reb_read_simulationarchive_with_messages(byref(self),c_char_p(filename.encode("ascii")), byref(reuse_index), byref(w)) + else: clibrebound.reb_read_simulationarchive_with_messages(byref(self),c_char_p(filename.encode("ascii")), None, byref(w)) for majorerror, value, message in BINARY_WARNINGS: @@ -97,7 +99,7 @@ def __init__(self,filename,setup=None, setup_args=(), process_warnings=True, reu # Just a warning if process_warnings: warnings.warn(message, RuntimeWarning) - else: + if not process_warnings: # Store for later self.warnings = w if self.nblobs<1: diff --git a/rebound/tests/test_binary_fields.py b/rebound/tests/test_binary_fields.py new file mode 100644 index 000000000..0347b86f9 --- /dev/null +++ b/rebound/tests/test_binary_fields.py @@ -0,0 +1,18 @@ +import rebound +import unittest + +class TestBinaryFields(unittest.TestCase): + def test_unique(self): + l = rebound.binary_field_descriptor_list() + types = [] + names = [] + for i in l: + types.append(i.type) + names.append(i.name) + self.assertEqual(len(types), len(set(types))) + self.assertEqual(len(names), len(set(names))) + + +if __name__ == "__main__": + unittest.main() + diff --git a/rebound/tests/test_fpcontract.py b/rebound/tests/test_fpcontract.py new file mode 100644 index 000000000..a73de7ac1 --- /dev/null +++ b/rebound/tests/test_fpcontract.py @@ -0,0 +1,16 @@ +import rebound +import unittest +from ctypes import c_int + +class TestFPContract(unittest.TestCase): + + def test_fp_off(self): + cl = rebound.clibrebound + cl.reb_check_fp_contract.res_type = c_int + fp_contract = cl.reb_check_fp_contract() + + # make sure floating point contraction are off + self.assertEqual(fp_contract, 0) + +if __name__ == "__main__": + unittest.main() diff --git a/rebound/tests/test_ias15_mode1.py b/rebound/tests/test_ias15_mode1.py new file mode 100644 index 000000000..f438a04ba --- /dev/null +++ b/rebound/tests/test_ias15_mode1.py @@ -0,0 +1,65 @@ +import rebound +import unittest +import math +import rebound.data +import warnings + +class TestIAS15mode1(unittest.TestCase): + + def test_safe_and_load(self): + sim = rebound.Simulation() + rebound.data.add_outer_solar_system(sim) + sim.move_to_com() + sim.integrator = "ias15" + sim.ri_ias15.dt_mode = 1 + jupyr = 11.86*2.*math.pi + sim.integrate(1e1*jupyr) + sim.save("sim.bin") + sim.integrate(1e3*jupyr) + + sim2 = rebound.Simulation("sim.bin") + sim2.integrate(1e3*jupyr) + + for i in range(sim.N): + self.assertEqual(sim2.particles[i].x,sim.particles[i].x) + self.assertEqual(sim2.particles[i].y,sim.particles[i].y) + self.assertEqual(sim2.particles[i].z,sim.particles[i].z) + + def test_backwards(self): + sim = rebound.Simulation() + rebound.data.add_outer_solar_system(sim) + sim.move_to_com() + sim.integrator = "ias15" + sim.ri_ias15.dt_mode = 1 + sim2 = sim.copy() + jupyr = 11.86*2.*math.pi + sim.integrate(1e3*jupyr) + + for p in sim2.particles: + p.vx *= -1 + p.vy *= -1 + p.vz *= -1 + sim2.dt *= -1 + sim2.integrate(-1e3*jupyr) + + for i in range(sim.N): + self.assertEqual(sim2.particles[i].x,sim.particles[i].x) + self.assertEqual(sim2.particles[i].y,sim.particles[i].y) + self.assertEqual(sim2.particles[i].z,sim.particles[i].z) + + def test_outer_solar_system(self): + sim = rebound.Simulation() + rebound.data.add_outer_solar_system(sim) + sim.move_to_com() + sim.integrator = "ias15" + sim.ri_ias15.dt_mode = 1 + jupyr = 11.86*2.*math.pi + e0 = sim.energy() + self.assertNotEqual(e0,0.) + sim.integrate(1e3*jupyr) + e1 = sim.energy() + self.assertLess(math.fabs((e0-e1)/e1),3e-15) + + +if __name__ == "__main__": + unittest.main() diff --git a/rebound/tests/test_pickle.py b/rebound/tests/test_pickle.py new file mode 100644 index 000000000..147509f43 --- /dev/null +++ b/rebound/tests/test_pickle.py @@ -0,0 +1,65 @@ +import rebound +import unittest +import pickle +import os +import warnings + +class TestPickle(unittest.TestCase): + def test_pickle_basic(self): + sim = rebound.Simulation() + sim.add(m=1) + sim.add(m=1,a=1) + sim.step() + + with open("test.pickle", "wb") as f: + pickle.dump(sim, f) + + with open("test.pickle", "rb") as f: + sim2 = pickle.load(f) + + self.assertEqual(sim,sim2) + sim.step() + sim2.step() + self.assertEqual(sim,sim2) + + def test_pickle_warning(self): + sim = rebound.Simulation() + sim.add(m=1) + sim.collision_resolve = "merge" + sim.step() + + with open("test.pickle", "wb") as f: + pickle.dump(sim, f) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + with open("test.pickle", "rb") as f: + sim2 = pickle.load(f) + + self.assertEqual(1, len(w)) + self.assertNotEqual(sim,sim2) + sim2.collision_resolve = "merge" + sim.step() + sim2.step() + self.assertEqual(sim,sim2) + + def test_pickle_particle(self): + sim = rebound.Simulation() + sim.add(m=1) + sim.add(m=1,a=1) + sim.step() + + with open("test.pickle", "wb") as f: + pickle.dump(sim.particles[1], f) + + with open("test.pickle", "rb") as f: + p2 = pickle.load(f) + + self.assertEqual(sim.particles[1], p2) + + # Pointers are set to zero when unpickling + self.assertNotEqual(sim.particles[1]._sim, p2._sim) + self.assertEqual(p2.sim, 0) + +if __name__ == "__main__": + unittest.main() diff --git a/rebound/tests/test_simulationarchive.py b/rebound/tests/test_simulationarchive.py index 5a8d27670..532ad0f22 100644 --- a/rebound/tests/test_simulationarchive.py +++ b/rebound/tests/test_simulationarchive.py @@ -590,17 +590,16 @@ def test_tree(self): sim.add(m=1.) sim.add(m=1e-3,a=1.) sim.add(m=5e-3,a=2.25) - - sim.automateSimulationArchive("out.bin", interval=100,deletefile=True) + + sim.automateSimulationArchive("out.bin", interval=100,deletefile=True) sim.integrate(305) sa = rebound.SimulationArchive("out.bin") self.assertEqual(sa.nblobs, 4) - + sim2 = sa[-1] sim2.integrate(305) self.assertEqual(sim, sim2) - if __name__ == "__main__": unittest.main() diff --git a/rebound/tests/test_simulationarchive_matrix.py b/rebound/tests/test_simulationarchive_matrix.py index f3f4066ab..57782f11f 100644 --- a/rebound/tests/test_simulationarchive_matrix.py +++ b/rebound/tests/test_simulationarchive_matrix.py @@ -94,10 +94,7 @@ def doTest2(self): for G in [1.,0.9]: for testparticle in [0,1,2]: # no test particle, passive, semi-active for keep_unsynchronized in [1,0]: - for simulationarchive_version in [1,3]: - if simulationarchive_version==1: - if integrator=="leapfrog" or integrator=="saba" or integrator=="mercurius" or integrator=="sabacl4" or integrator=="saba(10,6,4)": - continue + for simulationarchive_version in [2,3]: # no longer testing version 1! params = {'safe_mode':safe_mode, 'integrator':integrator, 'G':G, diff --git a/rebound/tests/test_tes.py b/rebound/tests/test_tes.py index c6183739a..a2d3b38f5 100644 --- a/rebound/tests/test_tes.py +++ b/rebound/tests/test_tes.py @@ -88,53 +88,56 @@ def test_integration_output_particles(self): self.assertLess(error, 5e-6) self.assertLess(de, 1e-15) - - def test_timing_with_ias15(self): - orbits = 100 - problem = GetApophis1979 - output_samples=1 - samples = 1 - tol=1e-6 - recti_per_orbit = 1.61803398875 - - G_au_kg_dy = 1.4881806877180788e-34 - Q,V,mass,period,_ = problem() - mass /= G_au_kg_dy - - sim = rebound.Simulation() - sim.G = G_au_kg_dy - for i in range(3): - sim.add(m=mass[i], x=Q[i,0], y=Q[i,1], z=Q[i,2], vx=V[i,0], vy=V[i,1], vz=V[i,2]) - - sim.move_to_com() - sim.dt = period/100 - sim.integrator = "tes" - sim.ri_tes.dq_max = 1e-3 - sim.ri_tes.recti_per_orbit = recti_per_orbit - sim.ri_tes.epsilon = tol - sim.ri_tes.output_samples = output_samples - sim.ri_tes.orbits = orbits - - t0_tes = time.time() - sim.integrate(period*orbits) - t1_tes = time.time() - - sim2 = rebound.Simulation() - sim2.G = G_au_kg_dy - for i in range(3): - sim2.add(m=mass[i], x=Q[i,0], y=Q[i,1], z=Q[i,2], vx=V[i,0], vy=V[i,1], vz=V[i,2]) - - sim2.move_to_com() - sim2.integrator = "ias15" - - t0_ias = time.time() - sim2.integrate(period*orbits) - t1_ias = time.time() + # As of 2023 Aug 30, TES no longer seems + # to be faster than IAS15 for this test. + # Commenting it out for now. + # + #def test_timing_with_ias15(self): + # orbits = 100 + # problem = GetApophis1979 + # output_samples=1 + # samples = 1 + # tol=1e-6 + # recti_per_orbit = 1.61803398875 + # + # G_au_kg_dy = 1.4881806877180788e-34 + # Q,V,mass,period,_ = problem() + # mass /= G_au_kg_dy + # + # sim = rebound.Simulation() + # sim.G = G_au_kg_dy + # for i in range(3): + # sim.add(m=mass[i], x=Q[i,0], y=Q[i,1], z=Q[i,2], vx=V[i,0], vy=V[i,1], vz=V[i,2]) + # + # sim.move_to_com() + # sim.dt = period/100 + # sim.integrator = "tes" + # sim.ri_tes.dq_max = 1e-3 + # sim.ri_tes.recti_per_orbit = recti_per_orbit + # sim.ri_tes.epsilon = tol + # sim.ri_tes.output_samples = output_samples + # sim.ri_tes.orbits = orbits + # + # t0_tes = time.time() + # sim.integrate(period*orbits) + # t1_tes = time.time() + # + # sim2 = rebound.Simulation() + # sim2.G = G_au_kg_dy + # for i in range(3): + # sim2.add(m=mass[i], x=Q[i,0], y=Q[i,1], z=Q[i,2], vx=V[i,0], vy=V[i,1], vz=V[i,2]) + # + # sim2.move_to_com() + # sim2.integrator = "ias15" + # + # t0_ias = time.time() + # sim2.integrate(period*orbits) + # t1_ias = time.time() - rt_ias = t1_ias-t0_ias - rt_tes = t1_tes-t0_tes - print('\nruntime tes/ias15:', rt_tes/rt_ias) - self.assertGreater(rt_ias, rt_tes) + # rt_ias = t1_ias-t0_ias + # rt_tes = t1_tes-t0_tes + # print('\nruntime tes/ias15:', rt_tes/rt_ias) + # self.assertGreater(rt_ias, rt_tes) def test_piecewise_integration(self): orbits = 100 diff --git a/src/binarydiff.c b/src/binarydiff.c index 089429b18..d374b5582 100644 --- a/src/binarydiff.c +++ b/src/binarydiff.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "particle.h" #include "rebound.h" @@ -36,7 +37,7 @@ #include "binarydiff.h" -static inline int reb_binary_diff_particle(struct reb_particle p1, struct reb_particle p2){ +int reb_diff_particles(struct reb_particle p1, struct reb_particle p2){ int differ = 0; differ = differ || (p1.x != p2.x); differ = differ || (p1.y != p2.y); @@ -60,6 +61,69 @@ void reb_binary_diff(char* buf1, size_t size1, char* buf2, size_t size2, char** reb_binary_diff_with_options(buf1, size1, buf2, size2, bufp, sizep, 0); } +struct reb_binary_field_descriptor reb_binary_field_descriptor_for_type(int type){ + int i=-1; + do{ + i++; + if (reb_binary_field_descriptor_list[i].type==type){ + return reb_binary_field_descriptor_list[i]; + } + } while (reb_binary_field_descriptor_list[i].dtype!=REB_FIELD_END); + struct reb_binary_field_descriptor bfd = {0}; + bfd.dtype = REB_FIELD_NOT_FOUND; + return bfd; +} + +struct reb_binary_field_descriptor reb_binary_field_descriptor_for_name(const char* name){ + int i=-1; + do{ + i++; + if (strcmp(reb_binary_field_descriptor_list[i].name, name)==0){ + return reb_binary_field_descriptor_list[i]; + } + } while (reb_binary_field_descriptor_list[i].dtype!=REB_FIELD_END); + struct reb_binary_field_descriptor bfd = {0}; + bfd.dtype = REB_FIELD_NOT_FOUND; + return bfd; +} + +static void output_stream_reb_type(int dtype, char* pointer, size_t dsize, char** buf){ + char* newbuf = NULL; + switch (dtype){ + case REB_DOUBLE: + asprintf(&newbuf,"%e",*(double*)(pointer)); + break; + case REB_INT: + asprintf(&newbuf,"%d",*(int*)(pointer)); + break; + case REB_UINT: + asprintf(&newbuf,"%u",*(unsigned int*)(pointer)); + break; + case REB_UINT32: + asprintf(&newbuf,"%"PRIu32,*(uint32_t*)(pointer)); // PRIu32 defined in inttypes.h + break; + case REB_LONG: + asprintf(&newbuf,"%ld",*(long*)(pointer)); + break; + case REB_ULONG: + asprintf(&newbuf,"%lu",*(unsigned long*)(pointer)); + break; + case REB_ULONGLONG: + asprintf(&newbuf,"%llu",*(unsigned long long*)(pointer)); + break; + default: + asprintf(&newbuf,"(%zu bytes, values not printed)", dsize); + break; + } + if (buf){ + *buf = realloc(*buf, strlen(*buf) + strlen(newbuf) + sizeof(char)); + strcat(*buf,newbuf); + }else{ + printf("%s",newbuf); + } + free(newbuf); +} + int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t size2, char** bufp, size_t* sizep, int output_option){ if (!buf1 || !buf2 || size1<64 || size2<64){ printf("Cannot read input buffers.\n"); @@ -72,6 +136,10 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si *bufp = NULL; *sizep = 0; } + if (output_option==3){ + *bufp = malloc(sizeof(char)); + *bufp[0] = '\0'; + } size_t allocatedsize = 0; // Header. @@ -82,11 +150,13 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si size_t pos1 = 64; size_t pos2 = 64; + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); + while(1){ if (pos1+sizeof(struct reb_binary_field)>size1) break; struct reb_binary_field field1 = *(struct reb_binary_field*)(buf1+pos1); pos1 += sizeof(struct reb_binary_field); - if (field1.type==REB_BINARY_FIELD_TYPE_END){ + if (field1.type==fd_end.type){ break; } if (pos2+sizeof(struct reb_binary_field)>size2) pos2 = 64; @@ -106,7 +176,7 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si } field2 = *(struct reb_binary_field*)(buf2+pos2); pos2 += sizeof(struct reb_binary_field); - if(field2.type==REB_BINARY_FIELD_TYPE_END){ + if(field2.type==fd_end.type){ notfound = 1; break; } @@ -120,18 +190,31 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si // Output field with size 0 pos1 += field1.size; // For next search pos2 = 64; // For next search - field1.size = 0; are_different = 1.; - switch(output_option){ - case 0: - reb_output_stream_write(bufp, &allocatedsize, sizep, &field1,sizeof(struct reb_binary_field)); - break; - case 1: - printf("Field %d not in simulation 2.\n",field1.type); - break; - default: - break; + if (output_option==0){ + reb_output_stream_write(bufp, &allocatedsize, sizep, &field1,sizeof(struct reb_binary_field)); + }else if (output_option==1 || output_option==3){ + const struct reb_binary_field_descriptor fd = reb_binary_field_descriptor_for_type(field1.type); + char* buf; + asprintf(&buf, "%s:\n\033[31m< ",fd.name); + if (bufp){ + *bufp = realloc(*bufp, strlen(*bufp) + strlen(buf) + sizeof(char)); + strcat(*bufp,buf); + }else{ + printf("%s",buf); + } + free(buf); + output_stream_reb_type(fd.dtype, buf1+pos1, field1.size, bufp); + asprintf(&buf, "\033[0m\n"); + if (bufp){ + *bufp = realloc(*bufp, strlen(*bufp) + strlen(buf) + sizeof(char)); + strcat(*bufp,buf); + }else{ + printf("%s",buf); + } + free(buf); } + field1.size = 0; continue; } } @@ -140,41 +223,62 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si if (pos2+field2.size>size2) printf("Corrupt binary file buf2.\n"); int fields_differ = 0; if (field1.size==field2.size){ - switch (field1.type){ - case REB_BINARY_FIELD_TYPE_PARTICLES: - { - struct reb_particle* pb1 = (struct reb_particle*)(buf1+pos1); - struct reb_particle* pb2 = (struct reb_particle*)(buf2+pos2); - for (unsigned int i=0;i "); + if (bufp){ + *bufp = realloc(*bufp, strlen(*bufp) + strlen(buf) + sizeof(char)); + strcat(*bufp,buf); + }else{ + printf("%s",buf); + } + output_stream_reb_type(fd.dtype, buf2+pos2, field2.size, bufp); + asprintf(&buf, "\033[0m\n"); + if (bufp){ + *bufp = realloc(*bufp, strlen(*bufp) + strlen(buf) + sizeof(char)); + strcat(*bufp,buf); + }else{ + printf("%s",buf); + } } } pos1 += field1.size; @@ -187,7 +291,7 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si if (pos2+sizeof(struct reb_binary_field)>size2) break; struct reb_binary_field field2 = *(struct reb_binary_field*)(buf2+pos2); pos2 += sizeof(struct reb_binary_field); - if (field2.type==REB_BINARY_FIELD_TYPE_END){ + if (field2.type==fd_end.type){ break; } if (pos1+sizeof(struct reb_binary_field)>size1) pos1 = 64; @@ -211,7 +315,7 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si } field1 = *(struct reb_binary_field*)(buf1+pos1); pos1 += sizeof(struct reb_binary_field); - if(field1.type==REB_BINARY_FIELD_TYPE_END){ + if(field1.type==fd_end.type){ notfound = 1; break; } @@ -230,19 +334,31 @@ int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t si } are_different = 1.; - switch(output_option){ - case 0: - reb_output_stream_write(bufp, &allocatedsize, sizep, &field2,sizeof(struct reb_binary_field)); - reb_output_stream_write(bufp, &allocatedsize, sizep, buf2+pos2,field2.size); - break; - case 1: - printf("Field %d not in simulation 1.\n",field2.type); - break; - default: - break; + if (output_option==0){ + reb_output_stream_write(bufp, &allocatedsize, sizep, &field2,sizeof(struct reb_binary_field)); + reb_output_stream_write(bufp, &allocatedsize, sizep, buf2+pos2,field2.size); + }else if (output_option==1 || output_option==3){ + const struct reb_binary_field_descriptor fd = reb_binary_field_descriptor_for_type(field2.type); + char* buf; + asprintf(&buf, "%s:\n\033[32m> ",fd.name); + if (bufp){ + *bufp = realloc(*bufp, strlen(*bufp) + strlen(buf) + sizeof(char)); + strcat(*bufp,buf); + }else{ + printf("%s",buf); + } + output_stream_reb_type(fd.dtype, buf2+pos2, field2.size, bufp); + asprintf(&buf, "\033[0m\n"); + if (bufp){ + *bufp = realloc(*bufp, strlen(*bufp) + strlen(buf) + sizeof(char)); + strcat(*bufp,buf); + }else{ + printf("%s",buf); + } } pos1 = 64; pos2 += field2.size; } + return are_different; } diff --git a/src/binarydiff.h b/src/binarydiff.h index 6c3c48641..33faa3924 100644 --- a/src/binarydiff.h +++ b/src/binarydiff.h @@ -25,5 +25,9 @@ #ifndef _BINARYDIFF_H #define _BINARYDIFF_H +// Compares two particles, ignoring pointers. +// Returns 1 if particles differ +int reb_diff_particles(struct reb_particle p1, struct reb_particle p2); + #endif // _BINARYDIFF_H diff --git a/src/collision.c b/src/collision.c index d54f4c226..c2cd67b6d 100644 --- a/src/collision.c +++ b/src/collision.c @@ -118,11 +118,11 @@ void reb_collision_search(struct reb_simulation* const r){ // Check if particles are approaching each other if (dvx*dx + dvy*dy + dvz*dz >0) continue; // Add particles to collision array. - if (r->collisions_allocatedN<=collisions_N){ + if (r->collisions_allocated_N<=collisions_N){ // Allocate memory if there is no space in array. // Init to 32 if no space has been allocated yet, otherwise double it. - r->collisions_allocatedN = r->collisions_allocatedN ? r->collisions_allocatedN * 2 : 32; - r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocatedN); + r->collisions_allocated_N = r->collisions_allocated_N ? r->collisions_allocated_N * 2 : 32; + r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocated_N); } r->collisions[collisions_N].p1 = ip; r->collisions[collisions_N].p2 = jp; @@ -188,11 +188,11 @@ void reb_collision_search(struct reb_simulation* const r){ if (rmin2_ab>rsum*rsum) continue; // Add particles to collision array. - if (r->collisions_allocatedN<=collisions_N){ + if (r->collisions_allocated_N<=collisions_N){ // Allocate memory if there is no space in array. // Init to 32 if no space has been allocated yet, otherwise double it. - r->collisions_allocatedN = r->collisions_allocatedN ? r->collisions_allocatedN * 2 : 32; - r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocatedN); + r->collisions_allocated_N = r->collisions_allocated_N ? r->collisions_allocated_N * 2 : 32; + r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocated_N); } r->collisions[collisions_N].p1 = i; r->collisions[collisions_N].p2 = j; @@ -533,10 +533,10 @@ static void reb_tree_get_nearest_neighbour_in_cell(struct reb_simulation* const // Save collision in collisions array. #pragma omp critical { - if (r->collisions_allocatedN<=(*collisions_N)){ + if (r->collisions_allocated_N<=(*collisions_N)){ // Init to 32 if no space has been allocated yet, otherwise double it. - r->collisions_allocatedN = r->collisions_allocatedN ? r->collisions_allocatedN * 2 : 32; - r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocatedN); + r->collisions_allocated_N = r->collisions_allocated_N ? r->collisions_allocated_N * 2 : 32; + r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocated_N); } r->collisions[(*collisions_N)] = *collision_nearest; (*collisions_N)++; @@ -548,7 +548,7 @@ static void reb_tree_get_nearest_neighbour_in_cell(struct reb_simulation* const double dy = gb.shifty - c->y; double dz = gb.shiftz - c->z; double r2 = dx*dx + dy*dy + dz*dz; - double rp = p1_r + r->max_radius[1] + 0.86602540378443*c->w; + double rp = p1_r + r->max_radius1 + 0.86602540378443*c->w; // Check if we need to decent into daughter cells if (r2 < rp*rp ){ for (int o=0;o<8;o++){ @@ -598,10 +598,10 @@ static void reb_tree_check_for_overlapping_trajectories_in_cell(struct reb_simul // Save collision in collisions array. #pragma omp critical { - if (r->collisions_allocatedN<=(*collisions_N)){ + if (r->collisions_allocated_N<=(*collisions_N)){ // Init to 32 if no space has been allocated yet, otherwise double it. - r->collisions_allocatedN = r->collisions_allocatedN ? r->collisions_allocatedN * 2 : 32; - r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocatedN); + r->collisions_allocated_N = r->collisions_allocated_N ? r->collisions_allocated_N * 2 : 32; + r->collisions = realloc(r->collisions,sizeof(struct reb_collision)*r->collisions_allocated_N); } r->collisions[(*collisions_N)] = *collision_nearest; (*collisions_N)++; diff --git a/src/communication_mpi.c b/src/communication_mpi.c index 0132adba8..b7ef247d5 100644 --- a/src/communication_mpi.c +++ b/src/communication_mpi.c @@ -244,7 +244,7 @@ void reb_communication_mpi_prepare_essential_cell_for_collisions_for_proc(struct r->particles_send_N[proc]++; }else{ // Not a leaf. Check if we need to transfer daughters. double distance2 = reb_communication_distance2_of_proc_to_node(r, proc,node); - double rp = 2.*r->max_radius[0] + 0.86602540378443*node->w; + double rp = 2.*r->max_radius0 + 0.86602540378443*node->w; if (distance2 < rp*rp ){ for (int o=0;o<8;o++){ struct reb_treecell* d = node->oct[o]; diff --git a/src/gravity.c b/src/gravity.c index abb21cd59..3d11deb15 100644 --- a/src/gravity.c +++ b/src/gravity.c @@ -249,9 +249,9 @@ void reb_calculate_acceleration(struct reb_simulation* r){ break; case REB_GRAVITY_COMPENSATED: { - if (r->gravity_cs_allocatedNgravity_cs_allocated_Ngravity_cs = realloc(r->gravity_cs,N*sizeof(struct reb_vec3d)); - r->gravity_cs_allocatedN = N; + r->gravity_cs_allocated_N = N; } struct reb_vec3d* restrict const cs = r->gravity_cs; #pragma omp parallel for schedule(guided) diff --git a/src/input.c b/src/input.c index bcd052390..1c746cb08 100644 --- a/src/input.c +++ b/src/input.c @@ -41,464 +41,267 @@ #include "communication_mpi.h" #endif -static size_t reb_fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream, char **restrict mem_stream){ - if (mem_stream!=NULL){ - // read from memory - memcpy(ptr,*mem_stream,size*nitems); - *mem_stream = (char*)(*mem_stream)+ size*nitems; - return size*nitems; - }else if(stream!=NULL){ - // read from file - return fread(ptr,size,nitems,stream); - } - return 0; -} - -// The reb_fseek function is currently not used, but provides functionality along the lines of reb_fread -// static int reb_fseek(FILE *stream, long offset, int whence, char **restrict mem_stream){ -// if (mem_stream!=NULL){ -// // read from memory -// if (whence==SEEK_CUR){ -// *mem_stream = (char*)(*mem_stream)+offset; -// return 0; -// } -// return -1; -// }else if(stream!=NULL){ -// // read from file -// return fseek(stream,offset,whence); -// } -// return -1; -// } - - -void reb_read_dp7(struct reb_dp7* dp7, const int N3, FILE* inf, char **restrict mem_stream){ - reb_fread(dp7->p0,sizeof(double),N3,inf,mem_stream); - reb_fread(dp7->p1,sizeof(double),N3,inf,mem_stream); - reb_fread(dp7->p2,sizeof(double),N3,inf,mem_stream); - reb_fread(dp7->p3,sizeof(double),N3,inf,mem_stream); - reb_fread(dp7->p4,sizeof(double),N3,inf,mem_stream); - reb_fread(dp7->p5,sizeof(double),N3,inf,mem_stream); - reb_fread(dp7->p6,sizeof(double),N3,inf,mem_stream); -} - // Macro to read a single field from a binary file. #define CASE(typename, value) case REB_BINARY_FIELD_TYPE_##typename: \ {\ - reb_fread(value, field.size,1,inf,mem_stream);\ - }\ - break; - -#define CASE_MALLOC(typename, valueref) case REB_BINARY_FIELD_TYPE_##typename: \ - {\ - valueref = malloc(field.size);\ - reb_fread(valueref, field.size,1,inf,mem_stream);\ - }\ - break; - -#define CASE_MALLOC_DP7(typename, valueref) case REB_BINARY_FIELD_TYPE_##typename: \ - {\ - valueref.p0 = malloc(field.size/7);\ - valueref.p1 = malloc(field.size/7);\ - valueref.p2 = malloc(field.size/7);\ - valueref.p3 = malloc(field.size/7);\ - valueref.p4 = malloc(field.size/7);\ - valueref.p5 = malloc(field.size/7);\ - valueref.p6 = malloc(field.size/7);\ - reb_fread(valueref.p0, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p1, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p2, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p3, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p4, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p5, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p6, field.size/7,1,inf,mem_stream);\ + fread(value, field.size,1,inf);\ + goto next_field;\ }\ break; -#define CASE_DP7(typename, valueref) case REB_BINARY_FIELD_TYPE_##typename: \ - {\ - reb_fread(valueref.p0, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p1, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p2, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p3, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p4, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p5, field.size/7,1,inf,mem_stream);\ - reb_fread(valueref.p6, field.size/7,1,inf,mem_stream);\ - }\ - break; - #define CASE_CONTROL_VARS(typename, valueref) case REB_BINARY_FIELD_TYPE_##typename: \ {\ - reb_fread(&valueref->size, sizeof(uint32_t),1,inf,mem_stream);\ - reb_fread(valueref->p0, valueref->size,1,inf,mem_stream);\ - reb_fread(valueref->p1, valueref->size,1,inf,mem_stream);\ - reb_fread(valueref->p2, valueref->size,1,inf,mem_stream);\ - reb_fread(valueref->p3, valueref->size,1,inf,mem_stream);\ - reb_fread(valueref->p4, valueref->size,1,inf,mem_stream);\ - reb_fread(valueref->p5, valueref->size,1,inf,mem_stream);\ - reb_fread(valueref->p6, valueref->size,1,inf,mem_stream);\ + fread(&valueref->size, sizeof(uint32_t),1,inf);\ + fread(valueref->p0, valueref->size,1,inf);\ + fread(valueref->p1, valueref->size,1,inf);\ + fread(valueref->p2, valueref->size,1,inf);\ + fread(valueref->p3, valueref->size,1,inf);\ + fread(valueref->p4, valueref->size,1,inf);\ + fread(valueref->p5, valueref->size,1,inf);\ + fread(valueref->p6, valueref->size,1,inf);\ + goto next_field;\ }\ break; - -int reb_input_field(struct reb_simulation* r, FILE* inf, enum reb_input_binary_messages* warnings, char **restrict mem_stream){ + + +void reb_input_fields(struct reb_simulation* r, FILE* inf, enum reb_input_binary_messages* warnings){ struct reb_binary_field field; - int numread = reb_fread(&field,sizeof(struct reb_binary_field),1,inf,mem_stream); - if (numread<1){ - return 0; // End of file - } - switch (field.type){ - CASE(T, &r->t); - CASE(G, &r->G); - CASE(SOFTENING, &r->softening); - CASE(DT, &r->dt); - CASE(DTLASTDONE, &r->dt_last_done); - CASE(N, &r->N); - CASE(NVAR, &r->N_var); - CASE(VARCONFIGN, &r->var_config_N); - CASE(NACTIVE, &r->N_active); - CASE(TESTPARTICLETYPE, &r->testparticle_type); - CASE(TESTPARTICLEHIDEWARNINGS, &r->testparticle_hidewarnings); - CASE(HASHCTR, &r->hash_ctr); - CASE(OPENINGANGLE2, &r->opening_angle2); - CASE(STATUS, &r->status); - CASE(EXACTFINISHTIME, &r->exact_finish_time); - CASE(FORCEISVELOCITYDEP, &r->force_is_velocity_dependent); - CASE(GRAVITYIGNORETERMS, &r->gravity_ignore_terms); - CASE(OUTPUTTIMINGLAST, &r->output_timing_last); - CASE(SAVEMESSAGES, &r->save_messages); - CASE(EXITMAXDISTANCE, &r->exit_max_distance); - CASE(EXITMINDISTANCE, &r->exit_min_distance); - CASE(USLEEP, &r->usleep); - CASE(TRACKENERGYOFFSET, &r->track_energy_offset); - CASE(ENERGYOFFSET, &r->energy_offset); - CASE(BOXSIZE, &r->boxsize); - CASE(BOXSIZEMAX, &r->boxsize_max); - CASE(ROOTSIZE, &r->root_size); - CASE(ROOTN, &r->root_n); - CASE(ROOTNX, &r->root_nx); - CASE(ROOTNY, &r->root_ny); - CASE(ROOTNZ, &r->root_nz); - CASE(NGHOSTX, &r->nghostx); - CASE(NGHOSTY, &r->nghosty); - CASE(NGHOSTZ, &r->nghostz); - CASE(COLLISIONRESOLVEKEEPSORTED, &r->collision_resolve_keep_sorted); - CASE(MINIMUMCOLLISIONVELOCITY, &r->minimum_collision_velocity); - CASE(COLLISIONSPLOG, &r->collisions_plog); - CASE(MAXRADIUS, &r->max_radius); - CASE(COLLISIONSNLOG, &r->collisions_Nlog); - CASE(CALCULATEMEGNO, &r->calculate_megno); - CASE(MEGNOYS, &r->megno_Ys); - CASE(MEGNOYSS, &r->megno_Yss); - CASE(MEGNOCOVYT, &r->megno_cov_Yt); - CASE(MEGNOVART, &r->megno_var_t); - CASE(MEGNOMEANT, &r->megno_mean_t); - CASE(MEGNOMEANY, &r->megno_mean_Y); - CASE(MEGNON, &r->megno_n); - CASE(SAVERSION, &r->simulationarchive_version); - CASE(SASIZEFIRST, &r->simulationarchive_size_first); - CASE(SASIZESNAPSHOT, &r->simulationarchive_size_snapshot); - CASE(SAAUTOINTERVAL, &r->simulationarchive_auto_interval); - CASE(SAAUTOWALLTIME, &r->simulationarchive_auto_walltime); - CASE(SANEXT, &r->simulationarchive_next); - CASE(WALLTIME, &r->walltime); - CASE(COLLISION, &r->collision); - CASE(VISUALIZATION, &r->visualization); - CASE(INTEGRATOR, &r->integrator); - CASE(BOUNDARY, &r->boundary); - CASE(GRAVITY, &r->gravity); - CASE(SEI_OMEGA, &r->ri_sei.OMEGA); - CASE(SEI_OMEGAZ, &r->ri_sei.OMEGAZ); - CASE(SEI_LASTDT, &r->ri_sei.lastdt); - CASE(SEI_SINDT, &r->ri_sei.sindt); - CASE(SEI_TANDT, &r->ri_sei.tandt); - CASE(SEI_SINDTZ, &r->ri_sei.sindtz); - CASE(SEI_TANDTZ, &r->ri_sei.tandtz); - CASE(WHFAST_CORRECTOR, &r->ri_whfast.corrector); - CASE(WHFAST_RECALCJAC, &r->ri_whfast.recalculate_coordinates_this_timestep); - CASE(WHFAST_SAFEMODE, &r->ri_whfast.safe_mode); - CASE(WHFAST_KEEPUNSYNC, &r->ri_whfast.keep_unsynchronized); - CASE(WHFAST_ISSYNCHRON, &r->ri_whfast.is_synchronized); - CASE(WHFAST_TIMESTEPWARN,&r->ri_whfast.timestep_warning); - CASE(WHFAST_COORDINATES, &r->ri_whfast.coordinates); - CASE(IAS15_EPSILON, &r->ri_ias15.epsilon); - CASE(IAS15_MINDT, &r->ri_ias15.min_dt); - CASE(IAS15_EPSILONGLOBAL,&r->ri_ias15.epsilon_global); - CASE(IAS15_ITERATIONSMAX,&r->ri_ias15.iterations_max_exceeded); - CASE(IAS15_ALLOCATEDN, &r->ri_ias15.allocatedN); - CASE(JANUS_SCALEPOS, &r->ri_janus.scale_pos); - CASE(JANUS_SCALEVEL, &r->ri_janus.scale_vel); - CASE(JANUS_ORDER, &r->ri_janus.order); - CASE(JANUS_ALLOCATEDN, &r->ri_janus.allocated_N); - CASE(JANUS_RECALC, &r->ri_janus.recalculate_integer_coordinates_this_timestep); - CASE(MERCURIUS_HILLFAC, &r->ri_mercurius.hillfac); - CASE(MERCURIUS_SAFEMODE, &r->ri_mercurius.safe_mode); - CASE(MERCURIUS_ISSYNCHRON, &r->ri_mercurius.is_synchronized); - CASE(MERCURIUS_RECALCULATE_COORD, &r->ri_mercurius.recalculate_coordinates_this_timestep); - CASE(MERCURIUS_COMPOS, &r->ri_mercurius.com_pos); - CASE(MERCURIUS_COMVEL, &r->ri_mercurius.com_vel); - CASE(PYTHON_UNIT_L, &r->python_unit_l); - CASE(PYTHON_UNIT_M, &r->python_unit_m); - CASE(PYTHON_UNIT_T, &r->python_unit_t); - CASE(STEPSDONE, &r->steps_done); - CASE(SAAUTOSTEP, &r->simulationarchive_auto_step); - CASE(SANEXTSTEP, &r->simulationarchive_next_step); - CASE(SABA_TYPE, &r->ri_saba.type); - CASE(SABA_KEEPUNSYNC, &r->ri_saba.keep_unsynchronized); - CASE(EOS_PHI0, &r->ri_eos.phi0); - CASE(EOS_PHI1, &r->ri_eos.phi1); - CASE(EOS_N, &r->ri_eos.n); - CASE(EOS_SAFEMODE, &r->ri_eos.safe_mode); - CASE(EOS_ISSYNCHRON, &r->ri_eos.is_synchronized); - CASE(RAND_SEED, &r->rand_seed); - CASE(BS_EPSABS, &r->ri_bs.eps_abs); - CASE(BS_EPSREL, &r->ri_bs.eps_rel); - CASE(BS_MINDT, &r->ri_bs.min_dt); - CASE(BS_MAXDT, &r->ri_bs.max_dt); - CASE(BS_FIRSTORLASTSTEP, &r->ri_bs.firstOrLastStep); - CASE(BS_PREVIOUSREJECTED,&r->ri_bs.previousRejected); - CASE(BS_TARGETITER, &r->ri_bs.targetIter); - // temporary solution for depreciated SABA k and corrector variables. - // can be removed in future versions - case 138: - { - unsigned int k = 0; - reb_fread(&k, field.size,1,inf,mem_stream); - r->ri_saba.type/=0x100; - r->ri_saba.type += k-1; - } - break; - case 139: - { - unsigned int corrector = 0; - reb_fread(&corrector, field.size,1,inf,mem_stream); - r->ri_saba.type%=0x100; - r->ri_saba.type += 0x100*corrector; - } - break; + // A few fields need special treatment. Find their descriptors first. + struct reb_binary_field_descriptor fd_header = reb_binary_field_descriptor_for_name("header"); + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); + struct reb_binary_field_descriptor fd_sa_size_first = reb_binary_field_descriptor_for_name("simulationarchive_size_first"); + struct reb_binary_field_descriptor fd_functionpointers = reb_binary_field_descriptor_for_name("functionpointers"); + +next_field: + // Loop over all fields + while(1){ - CASE(SABA_SAFEMODE, &r->ri_saba.safe_mode); - CASE(SABA_ISSYNCHRON, &r->ri_saba.is_synchronized); - CASE(WHFAST_CORRECTOR2, &r->ri_whfast.corrector2); - CASE(WHFAST_KERNEL, &r->ri_whfast.kernel); - case REB_BINARY_FIELD_TYPE_PARTICLES: - if(r->particles){ - free(r->particles); - reb_tree_delete(r); - } - r->allocatedN = (int)(field.size/sizeof(struct reb_particle)); - if (field.size){ - r->particles = malloc(field.size); - reb_fread(r->particles, field.size,1,inf,mem_stream); - } - if (r->allocatedNN && warnings){ - *warnings |= REB_INPUT_BINARY_WARNING_PARTICLES; - } - for (unsigned int l=0;lallocatedN;l++){ - r->particles[l].c = NULL; - r->particles[l].ap = NULL; - r->particles[l].sim = r; - } - if (r->gravity==REB_GRAVITY_TREE || r->collision==REB_COLLISION_TREE || r->collision==REB_COLLISION_LINETREE){ - for (unsigned int l=0;lallocatedN;l++){ - reb_tree_add_particle_to_tree(r, l); - } - } - break; - case REB_BINARY_FIELD_TYPE_WHFAST_PJ: - if(r->ri_whfast.p_jh){ - free(r->ri_whfast.p_jh); - } - r->ri_whfast.allocated_N = (int)(field.size/sizeof(struct reb_particle)); - if (field.size){ - r->ri_whfast.p_jh = malloc(field.size); - reb_fread(r->ri_whfast.p_jh, field.size,1,inf,mem_stream); - } - break; - case REB_BINARY_FIELD_TYPE_JANUS_PINT: - if(r->ri_janus.p_int){ - free(r->ri_janus.p_int); + int numread = fread(&field,sizeof(struct reb_binary_field),1,inf); + if (numread<1){ + goto finish_fields; // End of file + } + if (field.type==fd_end.type){ + goto finish_fields; // End of snapshot + } + // only here for testing. delete TODO + if (field.type==REB_BINARY_FIELD_TYPE_TES_ALLOCATED_N){ + fread(&r->ri_tes.allocated_N, field.size, 1, inf); + // Allocate all memory for loading the simulation archive. + if (r->ri_tes.allocated_N) { + reb_integrator_tes_allocate_memory(r); } - r->ri_janus.allocated_N = (int)(field.size/sizeof(struct reb_particle_int)); - if (field.size){ - r->ri_janus.p_int = malloc(field.size); - reb_fread(r->ri_janus.p_int, field.size,1,inf,mem_stream); - } - break; - case REB_BINARY_FIELD_TYPE_VARCONFIG: - if (r->var_config){ - free(r->var_config); - } - if (r->var_config_N>0){ - r->var_config = malloc(field.size); - reb_fread(r->var_config, field.size,1,inf,mem_stream); - for (int l=0;lvar_config_N;l++){ - r->var_config[l].sim = r; + goto next_field; + } + int i=0; + + // Loop over field descriptor list. Simple datatypes and pointers will be read in this loop. + while (reb_binary_field_descriptor_list[i].dtype!=REB_FIELD_END){ + struct reb_binary_field_descriptor fd = reb_binary_field_descriptor_list[i]; + if (fd.type==field.type){ + // Read simple data types + if (fd.dtype == REB_DOUBLE || fd.dtype == REB_INT || fd.dtype == REB_UINT + || fd.dtype == REB_UINT32 || fd.dtype == REB_LONG + || fd.dtype == REB_ULONG || fd.dtype == REB_ULONGLONG + || fd.dtype == REB_PARTICLE || fd.dtype == REB_VEC3D ){ + char* pointer = (char*)r + reb_binary_field_descriptor_list[i].offset; + fread(pointer, field.size, 1, inf); + goto next_field; } - } - break; - case REB_BINARY_FIELD_TYPE_MERCURIUS_DCRIT: - if(r->ri_mercurius.dcrit){ - free(r->ri_mercurius.dcrit); - } - r->ri_mercurius.dcrit_allocatedN = (int)(field.size/sizeof(double)); - if (field.size){ - r->ri_mercurius.dcrit = malloc(field.size); - reb_fread(r->ri_mercurius.dcrit, field.size,1,inf,mem_stream); - } - break; - CASE_MALLOC(IAS15_AT, r->ri_ias15.at); - CASE_MALLOC(IAS15_X0, r->ri_ias15.x0); - CASE_MALLOC(IAS15_V0, r->ri_ias15.v0); - CASE_MALLOC(IAS15_A0, r->ri_ias15.a0); - CASE_MALLOC(IAS15_CSX, r->ri_ias15.csx); - CASE_MALLOC(IAS15_CSV, r->ri_ias15.csv); - CASE_MALLOC(IAS15_CSA0, r->ri_ias15.csa0); - CASE_MALLOC_DP7(IAS15_G, r->ri_ias15.g); - CASE_MALLOC_DP7(IAS15_B, r->ri_ias15.b); - CASE_MALLOC_DP7(IAS15_CSB,r->ri_ias15.csb); - CASE_MALLOC_DP7(IAS15_E, r->ri_ias15.e); - CASE_MALLOC_DP7(IAS15_BR, r->ri_ias15.br); - CASE_MALLOC_DP7(IAS15_ER, r->ri_ias15.er); - case REB_BINARY_FIELD_TYPE_END: - return 0; - case REB_BINARY_FIELD_TYPE_FUNCTIONPOINTERS: - { - int fpwarn; - reb_fread(&fpwarn, field.size,1,inf,mem_stream); - if (fpwarn && warnings){ - *warnings |= REB_INPUT_BINARY_WARNING_POINTERS; + // Read a pointer data type. + // 1) reallocate memory + // 2) read data into memory + // 3) set allocated_N variable + if (fd.dtype == REB_POINTER || fd.dtype == REB_POINTER_ALIGNED){ + if (field.size % reb_binary_field_descriptor_list[i].element_size){ + reb_warning(r, "Inconsistent size encountered in binary field."); + } + char* pointer = (char*)r + reb_binary_field_descriptor_list[i].offset; + if (fd.dtype == REB_POINTER_ALIGNED){ + if (*(char**)pointer) free(*(char**)pointer); + *(char**)pointer = aligned_alloc(64,sizeof(struct reb_particle_avx512)); + }else{ // normal malloc + *(char**)pointer = realloc(*(char**)pointer, field.size); + } + fread(*(char**)pointer, field.size,1,inf); + + unsigned int* pointer_N = (unsigned int*)((char*)r + reb_binary_field_descriptor_list[i].offset_N); + *pointer_N = field.size/reb_binary_field_descriptor_list[i].element_size; + + goto next_field; } - } - break; - case REB_BINARY_FIELD_TYPE_HEADER: - { - long objects = 0; - // Input header. - const long bufsize = 64 - sizeof(struct reb_binary_field); - char readbuf[bufsize], curvbuf[bufsize]; - const char* header = "REBOUND Binary File. Version: "; - sprintf(curvbuf,"%s%s",header+sizeof(struct reb_binary_field), reb_version_str); - - objects += reb_fread(readbuf,sizeof(char),bufsize,inf,mem_stream); - if (objects < 1){ - *warnings |= REB_INPUT_BINARY_WARNING_CORRUPTFILE; - }else{ - // Note: following compares version, but ignores githash. - if(strncmp(readbuf,curvbuf,bufsize)!=0){ - *warnings |= REB_INPUT_BINARY_WARNING_VERSION; + // Special datatype for ias15. Similar to REB_POINTER. + if (fd.dtype == REB_DP7){ + if (field.size % reb_binary_field_descriptor_list[i].element_size){ + reb_warning(r, "Inconsistent size encountered in binary field."); } + char* pointer = (char*)r + reb_binary_field_descriptor_list[i].offset; + struct reb_dp7* dp7 = (struct reb_dp7*)pointer; + + dp7->p0 = realloc(dp7->p0,field.size/7); + dp7->p1 = realloc(dp7->p1,field.size/7); + dp7->p2 = realloc(dp7->p2,field.size/7); + dp7->p3 = realloc(dp7->p3,field.size/7); + dp7->p4 = realloc(dp7->p4,field.size/7); + dp7->p5 = realloc(dp7->p5,field.size/7); + dp7->p6 = realloc(dp7->p6,field.size/7); + fread(dp7->p0, field.size/7, 1, inf); + fread(dp7->p1, field.size/7, 1, inf); + fread(dp7->p2, field.size/7, 1, inf); + fread(dp7->p3, field.size/7, 1, inf); + fread(dp7->p4, field.size/7, 1, inf); + fread(dp7->p5, field.size/7, 1, inf); + fread(dp7->p6, field.size/7, 1, inf); + + unsigned int* pointer_N = (unsigned int*)((char*)r + reb_binary_field_descriptor_list[i].offset_N); + *pointer_N = field.size/reb_binary_field_descriptor_list[i].element_size; + + goto next_field; } + // If we're here then it was not a simple or pointer datatype. + // Can skip the iteration trough the descriptor list. + break; } - break; + i++; + } - // TES integrator variables - CASE(TES_DQ_MAX, &r->ri_tes.dq_max); - CASE(TES_RECTI_PER_ORBIT, &r->ri_tes.recti_per_orbit); - CASE(TES_EPSILON, &r->ri_tes.epsilon); - CASE(TES_PERIOD, &r->ri_tes.orbital_period); - CASE(TES_SV_LEN, &r->ri_tes.stateVectorLength); - CASE(TES_SV_SIZE, &r->ri_tes.stateVectorSize); - CASE(TES_CV_LEN, &r->ri_tes.controlVectorLength); - CASE(TES_CV_SIZE, &r->ri_tes.controlVectorSize); - CASE(TES_COM, &r->ri_tes.COM); - CASE(TES_COM_DOT, &r->ri_tes.COM_dot); - CASE(TES_MASS_STAR_LAST, &r->ri_tes.mStar_last); + // Fields with types that require special handling + if (field.type == 35){ + // Only kept for backwards compatability. Can be removed in future version. + double max_radius[2]; + fread(&max_radius, field.size,1,inf); + r->max_radius0 = max_radius[0]; + r->max_radius1 = max_radius[1]; + goto next_field; + } + if (field.type == fd_sa_size_first.type){ + // simulationarchive_size_first was manually written. reading it manually here. + fread(&r->simulationarchive_size_first, field.size,1,inf); + goto next_field; + } + if (field.type == fd_functionpointers.type){ + // Warning for when function pointers were used. + // No effect on simulation. + int fpwarn; + fread(&fpwarn, field.size,1,inf); + if (fpwarn && warnings){ + *warnings |= REB_INPUT_BINARY_WARNING_POINTERS; + } + goto next_field; + } + if (field.type == fd_header.type){ + // Check header. + long objects = 0; + const long bufsize = 64 - sizeof(struct reb_binary_field); + char readbuf[bufsize], curvbuf[bufsize]; + const char* header = "REBOUND Binary File. Version: "; + sprintf(curvbuf,"%s%s",header+sizeof(struct reb_binary_field), reb_version_str); - - case REB_BINARY_FIELD_TYPE_TES_ALLOCATED_N: - { - reb_fread(&r->ri_tes.allocated_N, field.size, 1, inf, mem_stream); - // Allocate all memory for loading the simulation archive. - if (r->ri_tes.allocated_N) { - reb_integrator_tes_allocate_memory(r); + objects += fread(readbuf,sizeof(char),bufsize,inf); + if (objects < 1){ + *warnings |= REB_INPUT_BINARY_WARNING_CORRUPTFILE; + }else{ + // Note: following compares version, but ignores githash. + if(strncmp(readbuf,curvbuf,bufsize)!=0){ + *warnings |= REB_INPUT_BINARY_WARNING_VERSION; } } - break; + goto next_field; + } - CASE(TES_PARTICLES_DH, r->ri_tes.particles_dh); - CASE(TES_MASS, r->ri_tes.mass); - CASE(TES_X_DH, r->ri_tes.X_dh); - - // TES Kepler vars - CASE(TES_UVARS_SV_SIZE, &r->ri_tes.uVars->stateVectorSize); - CASE(TES_UVARS_T0, r->ri_tes.uVars->t0); - CASE(TES_UVARS_TLAST, r->ri_tes.uVars->tLast); - CASE(TES_UVARS_CSQ, r->ri_tes.uVars->uv_csq); - CASE(TES_UVARS_CSP, r->ri_tes.uVars->uv_csp); - CASE(TES_UVARS_CSV, r->ri_tes.uVars->uv_csv); - CASE(TES_UVARS_Q0, r->ri_tes.uVars->Q0); - CASE(TES_UVARS_V0, r->ri_tes.uVars->V0); - CASE(TES_UVARS_P0, r->ri_tes.uVars->P0); - CASE(TES_UVARS_Q1, r->ri_tes.uVars->Q1); - CASE(TES_UVARS_V1, r->ri_tes.uVars->V1); - CASE(TES_UVARS_P1, r->ri_tes.uVars->P1); - CASE(TES_UVARS_X, r->ri_tes.uVars->X); - CASE(TES_UVARS_Q0_NORM, r->ri_tes.uVars->Q0_norm); - CASE(TES_UVARS_BETA, r->ri_tes.uVars->beta); - CASE(TES_UVARS_ETA, r->ri_tes.uVars->eta); - CASE(TES_UVARS_ZETA, r->ri_tes.uVars->zeta); - CASE(TES_UVARS_PERIOD, r->ri_tes.uVars->period); - CASE(TES_UVARS_XPERIOD, r->ri_tes.uVars->Xperiod); - CASE(TES_UVARS_STUMPF_C0, r->ri_tes.uVars->C.c0); - CASE(TES_UVARS_STUMPF_C1, r->ri_tes.uVars->C.c1); - CASE(TES_UVARS_STUMPF_C2, r->ri_tes.uVars->C.c2); - CASE(TES_UVARS_STUMPF_C3, r->ri_tes.uVars->C.c3); - CASE(TES_UVARS_MU, &r->ri_tes.uVars->mu); + // Only TES variables remain here. + switch(field.type){ + // TES Kepler vars + CASE(TES_UVARS_SV_SIZE, &r->ri_tes.uVars->stateVectorSize); + CASE(TES_UVARS_T0, r->ri_tes.uVars->t0); + CASE(TES_UVARS_TLAST, r->ri_tes.uVars->tLast); + CASE(TES_UVARS_CSQ, r->ri_tes.uVars->uv_csq); + CASE(TES_UVARS_CSP, r->ri_tes.uVars->uv_csp); + CASE(TES_UVARS_CSV, r->ri_tes.uVars->uv_csv); + CASE(TES_UVARS_Q0, r->ri_tes.uVars->Q0); + CASE(TES_UVARS_V0, r->ri_tes.uVars->V0); + CASE(TES_UVARS_P0, r->ri_tes.uVars->P0); + CASE(TES_UVARS_Q1, r->ri_tes.uVars->Q1); + CASE(TES_UVARS_V1, r->ri_tes.uVars->V1); + CASE(TES_UVARS_P1, r->ri_tes.uVars->P1); + CASE(TES_UVARS_X, r->ri_tes.uVars->X); + CASE(TES_UVARS_Q0_NORM, r->ri_tes.uVars->Q0_norm); + CASE(TES_UVARS_BETA, r->ri_tes.uVars->beta); + CASE(TES_UVARS_ETA, r->ri_tes.uVars->eta); + CASE(TES_UVARS_ZETA, r->ri_tes.uVars->zeta); + CASE(TES_UVARS_PERIOD, r->ri_tes.uVars->period); + CASE(TES_UVARS_XPERIOD, r->ri_tes.uVars->Xperiod); + CASE(TES_UVARS_STUMPF_C0, r->ri_tes.uVars->C.c0); + CASE(TES_UVARS_STUMPF_C1, r->ri_tes.uVars->C.c1); + CASE(TES_UVARS_STUMPF_C2, r->ri_tes.uVars->C.c2); + CASE(TES_UVARS_STUMPF_C3, r->ri_tes.uVars->C.c3); + CASE(TES_UVARS_MU, &r->ri_tes.uVars->mu); - // TES Radau vars - CASE(TES_RADAU_DX, r->ri_tes.radau->dX); - CASE(TES_RADAU_XOUT, r->ri_tes.radau->Xout); - CASE(TES_RADAU_RECTI_ARRAY, r->ri_tes.radau->rectifiedArray); - CASE(TES_RADAU_PREDICTORS, r->ri_tes.radau->predictors); - CASE(TES_RADAU_DSTATE0, r->ri_tes.radau->dState0); - CASE(TES_RADAU_DDSTATE0, r->ri_tes.radau->ddState0); - CASE(TES_RADAU_DSTATE, r->ri_tes.radau->dState); - CASE(TES_RADAU_DDSTATE, r->ri_tes.radau->ddState); - CASE(TES_RADAU_CS_DSTATE0, r->ri_tes.radau->cs_dState0); - CASE(TES_RADAU_CS_DDSTATE0, r->ri_tes.radau->cs_ddState0); - CASE(TES_RADAU_CS_DSTATE, r->ri_tes.radau->cs_dState); - CASE(TES_RADAU_CS_DDSTATE, r->ri_tes.radau->cs_ddState); - CASE(TES_RADAU_CS_DX, r->ri_tes.radau->cs_dX); - CASE(TES_RADAU_FCALLS, &r->ri_tes.radau->fCalls); - CASE(TES_RADAU_RECTIS, &r->ri_tes.radau->rectifications); - CASE(TES_RADAU_ITERS, &r->ri_tes.radau->convergenceIterations); - CASE(TES_RADAU_B6, r->ri_tes.radau->b6_store); - CASE_CONTROL_VARS(TES_RADAU_B, (&(r->ri_tes.radau->B))); - CASE_CONTROL_VARS(TES_RADAU_BLAST, (&(r->ri_tes.radau->Blast))); - CASE_CONTROL_VARS(TES_RADAU_B_1ST, (&(r->ri_tes.radau->B_1st))); - CASE_CONTROL_VARS(TES_RADAU_BLAST_1ST, (&(r->ri_tes.radau->Blast_1st))); - CASE_CONTROL_VARS(TES_RADAU_CS_B, (&(r->ri_tes.radau->cs_B))); - CASE_CONTROL_VARS(TES_RADAU_CS_B_1ST, (&(r->ri_tes.radau->cs_B1st))); - CASE_CONTROL_VARS(TES_RADAU_G, (&(r->ri_tes.radau->G))); - CASE_CONTROL_VARS(TES_RADAU_G_1ST, (&(r->ri_tes.radau->G_1st))); + // TES Radau vars + CASE(TES_RADAU_DX, r->ri_tes.radau->dX); + CASE(TES_RADAU_XOUT, r->ri_tes.radau->Xout); + CASE(TES_RADAU_RECTI_ARRAY, r->ri_tes.radau->rectifiedArray); + CASE(TES_RADAU_PREDICTORS, r->ri_tes.radau->predictors); + CASE(TES_RADAU_DSTATE0, r->ri_tes.radau->dState0); + CASE(TES_RADAU_DDSTATE0, r->ri_tes.radau->ddState0); + CASE(TES_RADAU_DSTATE, r->ri_tes.radau->dState); + CASE(TES_RADAU_DDSTATE, r->ri_tes.radau->ddState); + CASE(TES_RADAU_CS_DSTATE0, r->ri_tes.radau->cs_dState0); + CASE(TES_RADAU_CS_DDSTATE0, r->ri_tes.radau->cs_ddState0); + CASE(TES_RADAU_CS_DSTATE, r->ri_tes.radau->cs_dState); + CASE(TES_RADAU_CS_DDSTATE, r->ri_tes.radau->cs_ddState); + CASE(TES_RADAU_CS_DX, r->ri_tes.radau->cs_dX); + CASE(TES_RADAU_FCALLS, &r->ri_tes.radau->fCalls); + CASE(TES_RADAU_RECTIS, &r->ri_tes.radau->rectifications); + CASE(TES_RADAU_ITERS, &r->ri_tes.radau->convergenceIterations); + CASE(TES_RADAU_B6, r->ri_tes.radau->b6_store); + CASE_CONTROL_VARS(TES_RADAU_B, (&(r->ri_tes.radau->B))); + CASE_CONTROL_VARS(TES_RADAU_BLAST, (&(r->ri_tes.radau->Blast))); + CASE_CONTROL_VARS(TES_RADAU_B_1ST, (&(r->ri_tes.radau->B_1st))); + CASE_CONTROL_VARS(TES_RADAU_BLAST_1ST, (&(r->ri_tes.radau->Blast_1st))); + CASE_CONTROL_VARS(TES_RADAU_CS_B, (&(r->ri_tes.radau->cs_B))); + CASE_CONTROL_VARS(TES_RADAU_CS_B_1ST, (&(r->ri_tes.radau->cs_B1st))); + CASE_CONTROL_VARS(TES_RADAU_G, (&(r->ri_tes.radau->G))); + CASE_CONTROL_VARS(TES_RADAU_G_1ST, (&(r->ri_tes.radau->G_1st))); - // TES force model vars - CASE(TES_DHEM_XOSC_STORE, r->ri_tes.rhs->XoscStore); - CASE(TES_DHEM_XOSC_PRED_STORE, r->ri_tes.rhs->XoscPredStore); - CASE(TES_DHEM_XOSC_CS_STORE, r->ri_tes.rhs->XoscStore_cs); - CASE(TES_DHEM_XOSC_DOT_STORE, r->ri_tes.rhs->Xosc_dotStore); - CASE(TES_DHEM_X, r->ri_tes.rhs->X); - CASE(TES_DHEM_M_INV, r->ri_tes.rhs->m_inv); - CASE(TES_DHEM_M_TOTAL, &r->ri_tes.rhs->mTotal); - CASE(TES_DHEM_RECTI_TIME, r->ri_tes.rhs->rectifyTimeArray); - CASE(TES_DHEM_RECTI_PERIOD, r->ri_tes.rhs->rectificationPeriod); - - case REB_BINARY_FIELD_TYPE_WHFAST512_ALLOCATEDN: - reb_fread(&r->ri_whfast512.allocated_N, field.size, 1, inf, mem_stream); - if(r->ri_whfast512.p_jh){ - free(r->ri_whfast512.p_jh); - } - r->ri_whfast512.p_jh = aligned_alloc(64,sizeof(struct reb_particle_avx512)); - r->ri_whfast512.recalculate_constants = 1; - break; - - CASE(WHFAST512_KEEPUNSYNC, &r->ri_whfast512.keep_unsynchronized); - CASE(WHFAST512_ISSYNCHRON, &r->ri_whfast512.is_synchronized); - CASE(WHFAST512_GRPOTENTIAL, &r->ri_whfast512.gr_potential); - CASE(WHFAST512_PJH, r->ri_whfast512.p_jh); - CASE(WHFAST512_PJH0, &r->ri_whfast512.p_jh0); + // TES force model vars + CASE(TES_DHEM_XOSC_STORE, r->ri_tes.rhs->XoscStore); + CASE(TES_DHEM_XOSC_PRED_STORE, r->ri_tes.rhs->XoscPredStore); + CASE(TES_DHEM_XOSC_CS_STORE, r->ri_tes.rhs->XoscStore_cs); + CASE(TES_DHEM_XOSC_DOT_STORE, r->ri_tes.rhs->Xosc_dotStore); + CASE(TES_DHEM_X, r->ri_tes.rhs->X); + CASE(TES_DHEM_M_INV, r->ri_tes.rhs->m_inv); + CASE(TES_DHEM_M_TOTAL, &r->ri_tes.rhs->mTotal); + CASE(TES_DHEM_RECTI_TIME, r->ri_tes.rhs->rectifyTimeArray); + CASE(TES_DHEM_RECTI_PERIOD, r->ri_tes.rhs->rectificationPeriod); + } + // We should never get here. If so, it's an unknown field type. + *warnings |= REB_INPUT_BINARY_WARNING_FIELD_UNKOWN; + } + +finish_fields: + // Some final initialization + for (unsigned int l=0;lvar_config_N;l++){ + r->var_config[l].sim = r; } - return 1; -} + r->allocated_N = r->N; // This used to be different. Now only saving N. + for (unsigned int l=0;lallocated_N;l++){ + r->particles[l].c = NULL; + r->particles[l].ap = NULL; + r->particles[l].sim = r; + } + reb_tree_delete(r); + if (r->gravity==REB_GRAVITY_TREE || r->collision==REB_COLLISION_TREE || r->collision==REB_COLLISION_LINETREE){ + for (unsigned int l=0;lallocated_N;l++){ + reb_tree_add_particle_to_tree(r, l); + } + } + if (r->ri_ias15.at){ + // Assume that all arrays were saved whenever ri_ias15.at was saved. + // Only 3*N entries got saved. + r->ri_ias15.allocated_N = 3*r->N; + } + r->ri_whfast512.recalculate_constants = 1; +} struct reb_simulation* reb_input_process_warnings(struct reb_simulation* r, enum reb_input_binary_messages warnings){ if (warnings & REB_INPUT_BINARY_ERROR_NOFILE){ @@ -538,6 +341,11 @@ struct reb_simulation* reb_input_process_warnings(struct reb_simulation* r, enum if (r) free(r); return NULL; } + if (warnings & REB_INPUT_BINARY_ERROR_OLD){ + reb_error(r,"Reading old SimulationArchives (version < 2) is no longer supported. If you need to read such an archive, use a REBOUND version <= 3.26.3"); + if (r) free(r); + return NULL; + } if (warnings & REB_INPUT_BINARY_WARNING_CORRUPTFILE){ reb_warning(r,"The binary file seems to be corrupted. An attempt has been made to read the uncorrupted parts of it."); } diff --git a/src/input.h b/src/input.h index ceb1f3fd4..531ac40be 100644 --- a/src/input.h +++ b/src/input.h @@ -24,8 +24,7 @@ */ #ifndef _INPUT_H -void reb_read_dp7(struct reb_dp7* dp7, const int N3, FILE* inf, char **restrict mem_stream); ///< Internal function to read dp7 structs from file. -int reb_input_field(struct reb_simulation* r, FILE* inf, enum reb_input_binary_messages* warnings, char **restrict mem_stream); ///< Read one field from inf stream into r. +void reb_input_fields(struct reb_simulation* r, FILE* inf, enum reb_input_binary_messages* warnings); ///< Read all fields from inf stream into r. struct reb_simulation* reb_input_process_warnings(struct reb_simulation* r, enum reb_input_binary_messages warnings); ///< Process warning messages and print them on screen. diff --git a/src/integrator.c b/src/integrator.c index 449bf32bb..0ec2758d7 100644 --- a/src/integrator.c +++ b/src/integrator.c @@ -247,9 +247,9 @@ void reb_update_acceleration(struct reb_simulation* r){ if (r->integrator==REB_INTEGRATOR_MERCURIUS){ // shift pos and velocity so that external forces are calculated in inertial frame // Note: Copying avoids degrading floating point performance - if(r->N>r->ri_mercurius.allocatedN_additionalforces){ + if(r->N>r->ri_mercurius.allocated_N_additionalforces){ r->ri_mercurius.particles_backup_additionalforces = realloc(r->ri_mercurius.particles_backup_additionalforces, r->N*sizeof(struct reb_particle)); - r->ri_mercurius.allocatedN_additionalforces = r->N; + r->ri_mercurius.allocated_N_additionalforces = r->N; } memcpy(r->ri_mercurius.particles_backup_additionalforces,r->particles,r->N*sizeof(struct reb_particle)); reb_integrator_mercurius_dh_to_inertial(r); diff --git a/src/integrator_bs.c b/src/integrator_bs.c index 23172710c..87aa24c5e 100644 --- a/src/integrator_bs.c +++ b/src/integrator_bs.c @@ -711,9 +711,9 @@ struct reb_ode* reb_create_ode(struct reb_simulation* r, unsigned int length){ memset(ode, 0, sizeof(struct reb_ode)); // not really necessaery - if (r->odes_allocatedN <= r->odes_N){ - r->odes_allocatedN += 32; - r->odes = realloc(r->odes,sizeof(struct reb_ode*)*r->odes_allocatedN); + if (r->odes_allocated_N <= r->odes_N){ + r->odes_allocated_N += 32; + r->odes = realloc(r->odes,sizeof(struct reb_ode*)*r->odes_allocated_N); } r->odes[r->odes_N] = ode; @@ -723,7 +723,7 @@ struct reb_ode* reb_create_ode(struct reb_simulation* r, unsigned int length){ ode->r = r; // weak reference ode->length = length; ode->needs_nbody = 1; - ode->allocatedN = length; + ode->allocated_N = length; ode->getscale = NULL; ode->derivatives = NULL; ode->pre_timestep = NULL; diff --git a/src/integrator_ias15.c b/src/integrator_ias15.c index 256ddb1ea..fffadfe26 100644 --- a/src/integrator_ias15.c +++ b/src/integrator_ias15.c @@ -74,7 +74,8 @@ static void predict_next_step(double ratio, int N3, const struct reb_dpconst7 _ ///////////////////////// // Constants -static const double safety_factor = 0.25; /**< Maximum increase/deacrease of consecutve timesteps. */ +static const double safety_factor_dtmode_0 = 0.25; /**< Maximum increase/deacrease of consecutve timesteps. */ +static const double safety_factor_dtmode_1 = 0.25; /**< Maximum increase/deacrease of consecutve timesteps in dtmode 1. */ // Gauss Radau spacings static const double h[8] = { 0.0, 0.0562625605369221464656521910318, 0.180240691736892364987579942780, 0.352624717113169637373907769648, 0.547153626330555383001448554766, 0.734210177215410531523210605558, 0.885320946839095768090359771030, 0.977520613561287501891174488626}; @@ -89,12 +90,23 @@ static const double w[8] = {0.03125, 0.18535815480297927854072897280718075447981 // Machine independent implementation of pow(*,1./7.) static double sqrt7(double a){ + // Without scaling, this is only accurate for arguments in [1e-7, 1e2] + // With scaling: [1e-14, 1e8] + double scale = 1; + if (a<1e-7){ + scale = 0.1; + a *= 1e7; + } + if (a>1e-2){ + scale = 10; + a *= 1e-7; + } double x = 1.; for (int k=0; k<20;k++){ // A smaller number should be ok too. double x6 = x*x*x*x*x*x; x += (a/x6-x)/7.; } - return x; + return x*scale; } static void free_dp7(struct reb_dp7* dp7){ @@ -162,7 +174,7 @@ void reb_integrator_ias15_alloc(struct reb_simulation* r){ }else{ N3 = 3*r->N; } - if (N3 > r->ri_ias15.allocatedN) { + if (N3 > r->ri_ias15.allocated_N) { realloc_dp7(&(r->ri_ias15.g),N3); realloc_dp7(&(r->ri_ias15.b),N3); realloc_dp7(&(r->ri_ias15.csb),N3); @@ -183,7 +195,7 @@ void reb_integrator_ias15_alloc(struct reb_simulation* r){ csx[i] = 0; csv[i] = 0; } - r->ri_ias15.allocatedN = N3; + r->ri_ias15.allocated_N = N3; } if (N3/3 > r->ri_ias15.map_allocated_N){ r->ri_ias15.map = realloc(r->ri_ias15.map,sizeof(int)*(N3/3)); @@ -498,6 +510,16 @@ static int reb_integrator_ias15_step(struct reb_simulation* r) { // Find new timestep const double dt_done = r->dt; + // If dt_mode == 0: use the b6/y'' dt calculation mode + double safety_factor; + // Otherwise, use zeta * y''/y''' = dt timestep calculation method + if (r->ri_ias15.dt_mode == 0){ + safety_factor = safety_factor_dtmode_0; + }else{ + safety_factor = safety_factor_dtmode_1; + } + + double dt_new; if (r->ri_ias15.epsilon>0){ // Estimate error (given by last term in series expansion) // There are two options: @@ -507,53 +529,86 @@ static int reb_integrator_ias15_step(struct reb_simulation* r) { // r->ri_ias15.epsilon_global==0 // Here, the fractional error is calculated for each particle individually and we use the maximum of the fractional error. // This might fail in cases where a particle does not experience any (physical) acceleration besides roundoff errors. - double integrator_error = 0.0; unsigned int Nreal = N - r->N_var; - if (r->ri_ias15.epsilon_global){ - double maxak = 0.0; - double maxb6k = 0.0; - for(unsigned int i=0;idt*r->dt/x2) < 1e-16) continue; - for(unsigned int k=3*i;k<3*(i+1);k++) { - const double ak = fabs(at[k]); - if (isnormal(ak) && ak>maxak){ - maxak = ak; + if (r->ri_ias15.dt_mode==0){ + double integrator_error = 0.0; // Try to estimate integrator error based on last polynomial + if (r->ri_ias15.epsilon_global){ + double maxa = 0.0; + double maxj = 0.0; + for(unsigned int i=0;idt*r->dt/x2) < 1e-16) continue; + for(unsigned int k=3*i;k<3*(i+1);k++) { + const double ak = fabs(at[k]); + if (isnormal(ak) && ak>maxa){ + maxa = ak; + } + const double b6k = fabs(b.p6[k]); + if (isnormal(b6k) && b6k>maxj){ + maxj = b6k; + } } - const double b6k = fabs(b.p6[k]); - if (isnormal(b6k) && b6k>maxb6k){ - maxb6k = b6k; + integrator_error = maxj/maxa; + } + }else{ // epsilon_global == 1 + for(unsigned int k=0;kintegrator_error){ + integrator_error = errork; } } } - integrator_error = maxb6k/maxak; - }else{ - for(int k=0;kintegrator_error){ - integrator_error = errork; + // Use error estimate to predict new timestep + if (isnormal(integrator_error)){ + dt_new = sqrt7(r->ri_ias15.epsilon/integrator_error)*dt_done; + }else{ // In the rare case that the error estimate doesn't give a finite number (e.g. when all forces accidentally cancel up to machine precission). + dt_new = dt_done/safety_factor; // by default, increase timestep a little + }; + }else{ //dt_mode ==1 + double min_timescale2 = INFINITY; // note factor of dt_done**2 not included + for(unsigned int i=0;iri_ias15.epsilon*5040.0); + }else{ + dt_new = dt_done/safety_factor; // by default, increase timestep a little + } } - double dt_new; - if (isnormal(integrator_error)){ - // if error estimate is available increase by more educated guess - dt_new = sqrt7(r->ri_ias15.epsilon/integrator_error)*dt_done; - }else{ // In the rare case that the error estimate doesn't give a finite number (e.g. when all forces accidentally cancel up to machine precission). - dt_new = dt_done/safety_factor; // by default, increase timestep a little - } - if (fabs(dt_new)ri_ias15.min_dt) dt_new = copysign(r->ri_ias15.min_dt,dt_new); if (fabs(dt_new/dt_done) < safety_factor) { // New timestep is significantly smaller. + r->ri_ias15.rejected += 1; // Reset particles for(int k=0;k 1.0) { // New timestep is larger. - if (dt_new/dt_done > 1./safety_factor) dt_new = dt_done /safety_factor; // Don't increase the timestep by too much compared to the last one. + if (dt_new/dt_done > 1./safety_factor){ + r->ri_ias15.rejected += 1; + dt_new = dt_done /safety_factor; // Don't increase the timestep by too much compared to the last one. + } } r->dt = dt_new; + #define MIN(a, b) ((a) > (b) ? (b) : (a)) + r->ri_ias15.mindt = MIN(r->ri_ias15.mindt, r->dt); } // Find new position and velocity values at end of the sequence @@ -713,7 +773,7 @@ void reb_integrator_ias15_part2(struct reb_simulation* r){ void reb_integrator_ias15_synchronize(struct reb_simulation* r){ } void reb_integrator_ias15_clear(struct reb_simulation* r){ - const int N3 = r->ri_ias15.allocatedN; + const int N3 = r->ri_ias15.allocated_N; if (N3){ clear_dp7(&(r->ri_ias15.g),N3); clear_dp7(&(r->ri_ias15.e),N3); @@ -733,7 +793,7 @@ void reb_integrator_ias15_clear(struct reb_simulation* r){ } void reb_integrator_ias15_reset(struct reb_simulation* r){ - r->ri_ias15.allocatedN = 0; + r->ri_ias15.allocated_N = 0; r->ri_ias15.map_allocated_N = 0; free_dp7(&(r->ri_ias15.g)); free_dp7(&(r->ri_ias15.e)); diff --git a/src/integrator_mercurius.c b/src/integrator_mercurius.c index f1dafecc3..cee3c9ec5 100644 --- a/src/integrator_mercurius.c +++ b/src/integrator_mercurius.c @@ -435,22 +435,22 @@ void reb_integrator_mercurius_part1(struct reb_simulation* r){ struct reb_simulation_integrator_mercurius* const rim = &(r->ri_mercurius); const unsigned int N = r->N; - if (rim->dcrit_allocatedNdcrit_allocated_Ndcrit = realloc(rim->dcrit, sizeof(double)*N); - rim->dcrit_allocatedN = N; + rim->dcrit_allocated_N = N; // If particle number increased (or this is the first step), need to calculate critical radii rim->recalculate_dcrit_this_timestep = 1; // Heliocentric coordinates were never calculated. // This will get triggered on first step only (not when loaded from archive) rim->recalculate_coordinates_this_timestep = 1; } - if (rim->allocatedNallocated_Nparticles_backup = realloc(rim->particles_backup,sizeof(struct reb_particle)*N); rim->encounter_map = realloc(rim->encounter_map,sizeof(int)*N); - rim->allocatedN = N; + rim->allocated_N = N; } if (rim->safe_mode || rim->recalculate_coordinates_this_timestep){ if (rim->is_synchronized==0){ @@ -562,11 +562,11 @@ void reb_integrator_mercurius_reset(struct reb_simulation* r){ r->ri_mercurius.particles_backup_additionalforces = NULL; free(r->ri_mercurius.encounter_map); r->ri_mercurius.encounter_map = NULL; - r->ri_mercurius.allocatedN = 0; - r->ri_mercurius.allocatedN_additionalforces = 0; + r->ri_mercurius.allocated_N = 0; + r->ri_mercurius.allocated_N_additionalforces = 0; // dcrit array free(r->ri_mercurius.dcrit); r->ri_mercurius.dcrit = NULL; - r->ri_mercurius.dcrit_allocatedN = 0; + r->ri_mercurius.dcrit_allocated_N = 0; } diff --git a/src/integrator_tes.c b/src/integrator_tes.c index 719be067a..394226864 100644 --- a/src/integrator_tes.c +++ b/src/integrator_tes.c @@ -192,13 +192,13 @@ void reb_integrator_tes_part2(struct reb_simulation* r){ reb_transformations_inertial_to_democraticheliocentric_posvel(particles, r->ri_tes.particles_dh, r->N, r->N); // Store the COM and it's velocity as they are treated differently by TES. - r->ri_tes.COM[0] = r->ri_tes.particles_dh[0].x; - r->ri_tes.COM[1] = r->ri_tes.particles_dh[0].y; - r->ri_tes.COM[2] = r->ri_tes.particles_dh[0].z; + r->ri_tes.COM.x = r->ri_tes.particles_dh[0].x; + r->ri_tes.COM.y = r->ri_tes.particles_dh[0].y; + r->ri_tes.COM.z = r->ri_tes.particles_dh[0].z; - r->ri_tes.COM_dot[0] = r->ri_tes.particles_dh[0].vx; - r->ri_tes.COM_dot[1] = r->ri_tes.particles_dh[0].vy; - r->ri_tes.COM_dot[2] = r->ri_tes.particles_dh[0].vz; + r->ri_tes.COM_dot.x = r->ri_tes.particles_dh[0].vx; + r->ri_tes.COM_dot.y = r->ri_tes.particles_dh[0].vy; + r->ri_tes.COM_dot.z = r->ri_tes.particles_dh[0].vz; for(uint32_t i=1;iri_tes.particles_dh[0].x = r->ri_tes.COM[0]; - r->ri_tes.particles_dh[0].y = r->ri_tes.COM[1]; - r->ri_tes.particles_dh[0].z = r->ri_tes.COM[2]; + r->ri_tes.particles_dh[0].x = r->ri_tes.COM.x; + r->ri_tes.particles_dh[0].y = r->ri_tes.COM.y; + r->ri_tes.particles_dh[0].z = r->ri_tes.COM.z; - r->ri_tes.particles_dh[0].vx = r->ri_tes.COM_dot[0]; - r->ri_tes.particles_dh[0].vy = r->ri_tes.COM_dot[1]; - r->ri_tes.particles_dh[0].vz = r->ri_tes.COM_dot[2]; + r->ri_tes.particles_dh[0].vx = r->ri_tes.COM_dot.x; + r->ri_tes.particles_dh[0].vy = r->ri_tes.COM_dot.y; + r->ri_tes.particles_dh[0].vz = r->ri_tes.COM_dot.z; r->ri_tes.particles_dh[0].m = r->ri_tes.rhs->mTotal; @@ -317,20 +317,18 @@ static void reb_tes_init(struct reb_simulation* r) } // Set control variables to initial values - r->ri_tes.stateVectorLength = 2*3*r->N; - r->ri_tes.stateVectorSize = r->ri_tes.stateVectorLength * sizeof(double); r->ri_tes.controlVectorSize = r->N * sizeof(double); // Allocate memory r->ri_tes.mass = (double *)malloc(r->ri_tes.controlVectorSize); - r->ri_tes.X_dh = (double *)malloc(r->ri_tes.stateVectorSize); + r->ri_tes.X_dh = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); r->ri_tes.particles_dh = (struct reb_particle*)malloc(sizeof(struct reb_particle)*r->N); r->ri_tes.Q_dh = r->ri_tes.X_dh; - r->ri_tes.P_dh = &r->ri_tes.X_dh[r->ri_tes.stateVectorLength/2]; + r->ri_tes.P_dh = &r->ri_tes.X_dh[r->ri_tes.allocated_N*6/2]; // Ensure we are clean for each integration. memset(r->ri_tes.mass, 0, r->ri_tes.controlVectorSize); - memset(r->ri_tes.X_dh, 0, r->ri_tes.stateVectorSize); + memset(r->ri_tes.X_dh, 0, r->ri_tes.allocated_N*6*sizeof(double)); } @@ -381,7 +379,7 @@ static void reb_dhem_rhs(struct reb_simulation* r, double const * __restrict__ c double * __restrict__ Q = dhem->Q; double * __restrict__ P = dhem->P; - memset(dQ_ddot, 0, r->ri_tes.stateVectorSize/2); + memset(dQ_ddot, 0, r->ri_tes.allocated_N*6*sizeof(double)/2); #pragma GCC ivdep for(uint32_t i = 3; i < n3; i++) @@ -701,49 +699,49 @@ static void reb_dhem_init(struct reb_simulation* r, double z_rectificationPeriod memset(r->ri_tes.rhs, 0, sizeof(DHEM)); DHEM * dhem = r->ri_tes.rhs; - dhem->X = (double*)malloc(r->ri_tes.stateVectorSize); + dhem->X = (double*)malloc(r->ri_tes.allocated_N*6*sizeof(double)); dhem->rectifyTimeArray = (double*)malloc(r->ri_tes.controlVectorSize); dhem->rectificationPeriod = (double*)malloc(r->ri_tes.controlVectorSize); // Create space to allow for all of the osculating orbits for a step to be stored. - dhem->XoscStore = (double*)malloc(z_stagesPerStep*r->ri_tes.stateVectorSize); + dhem->XoscStore = (double*)malloc(z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); dhem->XoscArr = (double **)malloc(z_stagesPerStep*sizeof(double*)); - dhem->Xosc_dotStore = (double*)malloc(z_stagesPerStep*r->ri_tes.stateVectorSize); + dhem->Xosc_dotStore = (double*)malloc(z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); dhem->Xosc_dotArr = (double **)malloc(z_stagesPerStep*sizeof(double*)); // Create space to allow for all of the osculating orbits for a step to be stored. - dhem->XoscPredStore = (double*)malloc(z_stagesPerStep*r->ri_tes.stateVectorSize); + dhem->XoscPredStore = (double*)malloc(z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); dhem->XoscPredArr = (double **)malloc(z_stagesPerStep*sizeof(double*)); // Creat space for osculating orbit compensated summation variables - dhem->XoscStore_cs = (double*)malloc(z_stagesPerStep*r->ri_tes.stateVectorSize); + dhem->XoscStore_cs = (double*)malloc(z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); dhem->XoscArr_cs = (double **)malloc(z_stagesPerStep*sizeof(double*)); // Set required arrays to zero. - memset(dhem->X, 0, r->ri_tes.stateVectorSize); + memset(dhem->X, 0, r->ri_tes.allocated_N*6*sizeof(double)); memset(dhem->rectifyTimeArray, 0, r->ri_tes.controlVectorSize); memset(dhem->rectificationPeriod, 0, r->ri_tes.controlVectorSize); - memset(dhem->XoscStore, 0, z_stagesPerStep*r->ri_tes.stateVectorSize); + memset(dhem->XoscStore, 0, z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); memset(dhem->XoscArr, 0, z_stagesPerStep*sizeof(double *)); - memset(dhem->Xosc_dotStore, 0, z_stagesPerStep*r->ri_tes.stateVectorSize); + memset(dhem->Xosc_dotStore, 0, z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); memset(dhem->Xosc_dotArr, 0, z_stagesPerStep*sizeof(double *)); - memset(dhem->XoscPredStore, 0, z_stagesPerStep*r->ri_tes.stateVectorSize); + memset(dhem->XoscPredStore, 0, z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); memset(dhem->XoscPredArr, 0, z_stagesPerStep*sizeof(double *)); - memset(dhem->XoscStore_cs, 0, z_stagesPerStep*r->ri_tes.stateVectorSize); + memset(dhem->XoscStore_cs, 0, z_stagesPerStep*r->ri_tes.allocated_N*6*sizeof(double)); memset(dhem->XoscArr_cs, 0, z_stagesPerStep*sizeof(double *)); // To enable easier access to the osculating orbits. for(uint32_t i = 0; i < z_stagesPerStep; i++) { - dhem->XoscArr[i] = &dhem->XoscStore[i*r->ri_tes.stateVectorLength]; - dhem->XoscPredArr[i] = &dhem->XoscPredStore[i*r->ri_tes.stateVectorLength]; - dhem->Xosc_dotArr[i] = &dhem->Xosc_dotStore[i*r->ri_tes.stateVectorLength]; + dhem->XoscArr[i] = &dhem->XoscStore[i*r->ri_tes.allocated_N*6]; + dhem->XoscPredArr[i] = &dhem->XoscPredStore[i*r->ri_tes.allocated_N*6]; + dhem->Xosc_dotArr[i] = &dhem->Xosc_dotStore[i*r->ri_tes.allocated_N*6]; - dhem->XoscArr_cs[i] = &dhem->XoscStore_cs[i*r->ri_tes.stateVectorLength]; + dhem->XoscArr_cs[i] = &dhem->XoscStore_cs[i*r->ri_tes.allocated_N*6]; } // Setup pointers for more human readable access. @@ -830,10 +828,9 @@ static double reb_single_step(struct reb_simulation* r, double z_t, double dt) reb_analytical_continuation(r, &radau->B, &radau->Blast, dt, dt_new, radau->rectifiedArray); // Perform a linear update to the drift of the COM. - for(uint32_t i = 0; i < 3; i++) - { - r->ri_tes.COM[i] += r->ri_tes.COM_dot[i]*dt; - } + r->ri_tes.COM.x += r->ri_tes.COM_dot.x*dt; + r->ri_tes.COM.y += r->ri_tes.COM_dot.y*dt; + r->ri_tes.COM.z += r->ri_tes.COM_dot.z*dt; return dt_new; } @@ -844,29 +841,29 @@ static void reb_radau_init(struct reb_simulation* r) memset(r->ri_tes.radau, 0, sizeof(RADAU)); RADAU * radau = r->ri_tes.radau; - radau->dX = (double*)malloc(r->ri_tes.stateVectorSize); - radau->Xout = (double*)malloc(r->ri_tes.stateVectorSize); - radau->predictors = (double*)malloc(r->ri_tes.stateVectorSize); + radau->dX = (double*)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->Xout = (double*)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->predictors = (double*)malloc(r->ri_tes.allocated_N*6*sizeof(double)); - memset(radau->dX, 0, r->ri_tes.stateVectorSize); - memset(radau->Xout, 0, r->ri_tes.stateVectorSize); - memset(radau->predictors, 0, r->ri_tes.stateVectorSize); + memset(radau->dX, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->Xout, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->predictors, 0, r->ri_tes.allocated_N*6*sizeof(double)); radau->dQ = radau->dX; radau->dP = &radau->dX[3*r->N]; radau->Qout = radau->Xout; - radau->Pout = &radau->Xout[r->ri_tes.stateVectorLength/2]; + radau->Pout = &radau->Xout[r->ri_tes.allocated_N*6/2]; // Copy to here so that we are ready to output to a file before we calculate osculating orbtis. - memcpy(radau->Qout, r->ri_tes.Q_dh, r->ri_tes.stateVectorSize / 2); - memcpy(radau->Pout, r->ri_tes.P_dh, r->ri_tes.stateVectorSize / 2); + memcpy(radau->Qout, r->ri_tes.Q_dh, r->ri_tes.allocated_N*6*sizeof(double) / 2); + memcpy(radau->Pout, r->ri_tes.P_dh, r->ri_tes.allocated_N*6*sizeof(double) / 2); - radau->rectifiedArray = (uint32_t*)malloc(sizeof(uint32_t)*r->ri_tes.stateVectorLength); - memset(radau->rectifiedArray, 0, sizeof(uint32_t)*r->ri_tes.stateVectorLength); + radau->rectifiedArray = (uint32_t*)malloc(sizeof(uint32_t)*r->ri_tes.allocated_N*6); + memset(radau->rectifiedArray, 0, sizeof(uint32_t)*r->ri_tes.allocated_N*6); - radau->b6_store = (double*)malloc(r->ri_tes.stateVectorSize); + radau->b6_store = (double*)malloc(r->ri_tes.allocated_N*6*sizeof(double)); - memset(radau->b6_store, 0, r->ri_tes.stateVectorSize); + memset(radau->b6_store, 0, r->ri_tes.allocated_N*6*sizeof(double)); //@todo should be able to remove these, but test. radau->fCalls = 0; @@ -922,7 +919,7 @@ static double reb_calc_stepsize(struct reb_simulation* r, double h) static void reb_clear_rectified_b_fields(struct reb_simulation* r, controlVars * B, uint32_t * rectifiedArray) { - for(uint32_t i = 0; i < r->ri_tes.stateVectorLength; i++) + for(uint32_t i = 0; i < r->ri_tes.allocated_N*6; i++) { if(rectifiedArray[i] > 0) { @@ -968,9 +965,9 @@ static void reb_radau_step(struct reb_simulation* r, uint32_t * z_iterations, do for(uint32_t i = 1; i <= stages; i++) { reb_calc_predictors(h, hArr[i], radau->dX, radau->dState0, radau->ddState0, B, - radau->predictors, 3, r->ri_tes.stateVectorLength/2); + radau->predictors, 3, r->ri_tes.allocated_N*6/2); reb_calc_predictors_1st_order(h, hArr[i], radau->dX, radau->dState0, B_1st, radau->predictors, - (int)r->ri_tes.stateVectorLength/2, r->ri_tes.stateVectorLength); + (int)r->ri_tes.allocated_N*6/2, r->ri_tes.allocated_N*6); reb_dhem_rhs_wrapped(r, radau->predictors, &radau->predictors[3*r->N], radau->dState, &radau->dState[3*r->N], radau->ddState, i); @@ -1278,7 +1275,7 @@ static void reb_radau_step(struct reb_simulation* r, uint32_t * z_iterations, do radau->cs_dX, 0, (int)(n3)); reb_update_state_1st_order(h, radau->dState0, B_1st, radau->dX, - radau->cs_dX, (int)(n3), r->ri_tes.stateVectorLength); + radau->cs_dX, (int)(n3), r->ri_tes.allocated_N*6); // Now that we have cs_dX we can perform our correction. reb_apply_osc_orbit_corrector(r, r->ri_tes.rhs->XoscArr, t+h, 9); @@ -1330,8 +1327,8 @@ static void reb_calc_g_from_b_internal(controlVars * z_G, controlVars * z_B, uin static void reb_calc_g_from_b(struct reb_simulation* r) { - reb_calc_g_from_b_internal(&r->ri_tes.radau->G, &r->ri_tes.radau->B, 0, (int)(r->ri_tes.stateVectorLength/2)); - reb_calc_g_from_b_internal(&r->ri_tes.radau->G_1st, &r->ri_tes.radau->B_1st, (int)(r->ri_tes.stateVectorLength/2), r->ri_tes.stateVectorLength); + reb_calc_g_from_b_internal(&r->ri_tes.radau->G, &r->ri_tes.radau->B, 0, (int)(r->ri_tes.allocated_N*6/2)); + reb_calc_g_from_b_internal(&r->ri_tes.radau->G_1st, &r->ri_tes.radau->B_1st, (int)(r->ri_tes.allocated_N*6/2), r->ri_tes.allocated_N*6); } static void reb_analytical_continuation(struct reb_simulation* r, controlVars * z_B, controlVars * z_Blast, const double h, @@ -1346,7 +1343,7 @@ static void reb_analytical_continuation(struct reb_simulation* r, controlVars * const double q6 = q3 * q3; const double q7 = q3 * q4; - for(uint32_t i = 0; i < r->ri_tes.stateVectorLength; i++) + for(uint32_t i = 0; i < r->ri_tes.allocated_N*6; i++) { double dB0 = 0; double dB1 = 0; @@ -1483,42 +1480,42 @@ static void reb_update_state(double h, double * z_dState, double * z_ddState, static void reb_init_radau_step(struct reb_simulation* r) { RADAU * radau = r->ri_tes.radau; - reb_init_controlvars(&radau->G, r->ri_tes.stateVectorSize); - reb_init_controlvars(&radau->B, r->ri_tes.stateVectorSize); - reb_init_controlvars(&radau->Blast, r->ri_tes.stateVectorSize); - reb_init_controlvars(&radau->Blast_1st, r->ri_tes.stateVectorSize); - reb_init_controlvars(&radau->G_1st, r->ri_tes.stateVectorSize); - reb_init_controlvars(&radau->B_1st, r->ri_tes.stateVectorSize); + reb_init_controlvars(&radau->G, r->ri_tes.allocated_N*6*sizeof(double)); + reb_init_controlvars(&radau->B, r->ri_tes.allocated_N*6*sizeof(double)); + reb_init_controlvars(&radau->Blast, r->ri_tes.allocated_N*6*sizeof(double)); + reb_init_controlvars(&radau->Blast_1st, r->ri_tes.allocated_N*6*sizeof(double)); + reb_init_controlvars(&radau->G_1st, r->ri_tes.allocated_N*6*sizeof(double)); + reb_init_controlvars(&radau->B_1st, r->ri_tes.allocated_N*6*sizeof(double)); - reb_init_controlvars(&radau->cs_B1st, r->ri_tes.stateVectorSize); - reb_init_controlvars(&radau->cs_B, r->ri_tes.stateVectorSize); + reb_init_controlvars(&radau->cs_B1st, r->ri_tes.allocated_N*6*sizeof(double)); + reb_init_controlvars(&radau->cs_B, r->ri_tes.allocated_N*6*sizeof(double)); - radau->dState0 = (double *)malloc(r->ri_tes.stateVectorSize); - radau->ddState0 = (double *)malloc(r->ri_tes.stateVectorSize); - radau->dState = (double *)malloc(r->ri_tes.stateVectorSize); - radau->ddState = (double *)malloc(r->ri_tes.stateVectorSize); + radau->dState0 = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->ddState0 = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->dState = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->ddState = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); - memset(radau->dState0, 0, r->ri_tes.stateVectorSize); - memset(radau->ddState0, 0, r->ri_tes.stateVectorSize); - memset(radau->dState, 0, r->ri_tes.stateVectorSize); - memset(radau->ddState, 0, r->ri_tes.stateVectorSize); + memset(radau->dState0, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->ddState0, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->dState, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->ddState, 0, r->ri_tes.allocated_N*6*sizeof(double)); // Compensated summation arrays - radau->cs_dState0 = (double *)malloc(r->ri_tes.stateVectorSize); - radau->cs_ddState0 = (double *)malloc(r->ri_tes.stateVectorSize); - radau->cs_dState = (double *)malloc(r->ri_tes.stateVectorSize); - radau->cs_ddState = (double *)malloc(r->ri_tes.stateVectorSize); + radau->cs_dState0 = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->cs_ddState0 = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->cs_dState = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); + radau->cs_ddState = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); - memset(radau->cs_dState0, 0, r->ri_tes.stateVectorSize); - memset(radau->cs_ddState0, 0, r->ri_tes.stateVectorSize); - memset(radau->cs_dState, 0, r->ri_tes.stateVectorSize); - memset(radau->cs_ddState, 0, r->ri_tes.stateVectorSize); + memset(radau->cs_dState0, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->cs_ddState0, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->cs_dState, 0, r->ri_tes.allocated_N*6*sizeof(double)); + memset(radau->cs_ddState, 0, r->ri_tes.allocated_N*6*sizeof(double)); - radau->cs_dX = (double *)malloc(r->ri_tes.stateVectorSize); + radau->cs_dX = (double *)malloc(r->ri_tes.allocated_N*6*sizeof(double)); radau->cs_dq = radau->cs_dX; - radau->cs_dp = &radau->cs_dX[(int)r->ri_tes.stateVectorLength/2]; + radau->cs_dp = &radau->cs_dX[(int)r->ri_tes.allocated_N*6/2]; - memset(radau->cs_dX, 0, r->ri_tes.stateVectorSize); + memset(radau->cs_dX, 0, r->ri_tes.allocated_N*6*sizeof(double)); } static void reb_free_radau_step(struct reb_simulation* r) diff --git a/src/output.c b/src/output.c index 0a7a3bd41..c735e5222 100644 --- a/src/output.c +++ b/src/output.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "particle.h" #include "rebound.h" #include "tools.h" @@ -43,6 +44,232 @@ #include "mpi.h" #endif // MPI + +// List of REBOUND parameters to be written to a file. +// Modify this list if you wish to input/output additional fields in the reb_simulation structure. +const struct reb_binary_field_descriptor reb_binary_field_descriptor_list[]= { + { 0, REB_DOUBLE, "t", offsetof(struct reb_simulation, t), 0, 0}, + { 1, REB_DOUBLE, "G", offsetof(struct reb_simulation, G), 0, 0}, + { 2, REB_DOUBLE, "softening", offsetof(struct reb_simulation, softening), 0, 0}, + { 3, REB_DOUBLE, "dt", offsetof(struct reb_simulation, dt), 0, 0}, + { 4, REB_UINT, "N", offsetof(struct reb_simulation, N), 0, 0}, + { 5, REB_INT, "N_var", offsetof(struct reb_simulation, N_var), 0, 0}, + { 7, REB_INT, "N_active", offsetof(struct reb_simulation, N_active), 0, 0}, + { 8, REB_INT, "testparticle_type", offsetof(struct reb_simulation, testparticle_type), 0, 0}, + { 9, REB_INT, "hash_ctr", offsetof(struct reb_simulation, hash_ctr), 0, 0}, + { 10, REB_DOUBLE, "opening_angle2", offsetof(struct reb_simulation, opening_angle2), 0, 0}, + { 11, REB_INT, "status", offsetof(struct reb_simulation, status), 0, 0}, + { 12, REB_INT, "exact_finish_time", offsetof(struct reb_simulation, exact_finish_time), 0, 0}, + { 13, REB_UINT, "force_is_velocity_dependent", offsetof(struct reb_simulation, force_is_velocity_dependent), 0, 0}, + { 14, REB_UINT, "gravity_ignore_terms", offsetof(struct reb_simulation, gravity_ignore_terms), 0, 0}, + { 15, REB_DOUBLE, "output_timing_last", offsetof(struct reb_simulation, output_timing_last), 0, 0}, + { 16, REB_INT, "save_messages", offsetof(struct reb_simulation, save_messages), 0, 0}, + { 17, REB_DOUBLE, "exit_max_distance", offsetof(struct reb_simulation, exit_max_distance), 0, 0}, + { 18, REB_DOUBLE, "exit_min_distance", offsetof(struct reb_simulation, exit_min_distance), 0, 0}, + { 19, REB_DOUBLE, "usleep", offsetof(struct reb_simulation, usleep), 0, 0}, + { 20, REB_INT, "track_energ_yoffset", offsetof(struct reb_simulation, track_energy_offset), 0, 0}, + { 21, REB_DOUBLE, "energy_offset", offsetof(struct reb_simulation, energy_offset), 0, 0}, + { 22, REB_VEC3D, "boxsize", offsetof(struct reb_simulation, boxsize), 0, 0}, + { 23, REB_DOUBLE, "boxsize_max", offsetof(struct reb_simulation, boxsize_max), 0, 0}, + { 24, REB_DOUBLE, "root_size", offsetof(struct reb_simulation, root_size), 0, 0}, + { 25, REB_INT, "root_n", offsetof(struct reb_simulation, root_n), 0, 0}, + { 26, REB_INT, "root_nx", offsetof(struct reb_simulation, root_nx), 0, 0}, + { 27, REB_INT, "root_ny", offsetof(struct reb_simulation, root_ny), 0, 0}, + { 28, REB_INT, "root_nz", offsetof(struct reb_simulation, root_nz), 0, 0}, + { 29, REB_INT, "nghostx", offsetof(struct reb_simulation, nghostx), 0, 0}, + { 30, REB_INT, "nghosty", offsetof(struct reb_simulation, nghosty), 0, 0}, + { 31, REB_INT, "nghostz", offsetof(struct reb_simulation, nghostz), 0, 0}, + { 32, REB_INT, "collision_resolve_keep_sorted",offsetof(struct reb_simulation, collision_resolve_keep_sorted), 0, 0}, + { 33, REB_DOUBLE, "minimum_collision_velocity", offsetof(struct reb_simulation, minimum_collision_velocity), 0, 0}, + { 34, REB_DOUBLE, "collisions_plog", offsetof(struct reb_simulation, collisions_plog), 0, 0}, + { 36, REB_LONG, "collisions_Nlog", offsetof(struct reb_simulation, collisions_Nlog), 0, 0}, + { 37, REB_INT, "calculate_megno", offsetof(struct reb_simulation, calculate_megno), 0, 0}, + { 38, REB_DOUBLE, "megno_Ys", offsetof(struct reb_simulation, megno_Ys), 0, 0}, + { 39, REB_DOUBLE, "megno_Yss", offsetof(struct reb_simulation, megno_Yss), 0, 0}, + { 40, REB_DOUBLE, "megno_cov_Yt", offsetof(struct reb_simulation, megno_cov_Yt), 0, 0}, + { 41, REB_DOUBLE, "megno_var_t", offsetof(struct reb_simulation, megno_var_t), 0, 0}, + { 42, REB_DOUBLE, "megno_mean_t", offsetof(struct reb_simulation, megno_mean_t), 0, 0}, + { 43, REB_DOUBLE, "megno_mean_Y", offsetof(struct reb_simulation, megno_mean_Y), 0, 0}, + { 44, REB_LONG, "megno_n", offsetof(struct reb_simulation, megno_n), 0, 0}, + { 45, REB_OTHER, "simulationarchive_size_first", offsetof(struct reb_simulation, simulationarchive_size_first), 0, 0}, // Manually calculated + { 46, REB_LONG, "simulationarchive_size_snapshot", offsetof(struct reb_simulation, simulationarchive_size_snapshot), 0, 0}, + { 47, REB_DOUBLE, "simulationarchive_auto_interval", offsetof(struct reb_simulation, simulationarchive_auto_interval), 0, 0}, + { 102, REB_DOUBLE, "simulationarchive_auto_walltime", offsetof(struct reb_simulation, simulationarchive_auto_walltime), 0, 0}, + { 48, REB_DOUBLE, "simulationarchive_next", offsetof(struct reb_simulation, simulationarchive_next), 0, 0}, + { 50, REB_INT, "collision", offsetof(struct reb_simulation, collision), 0, 0}, + { 51, REB_INT, "integrator", offsetof(struct reb_simulation, integrator), 0, 0}, + { 52, REB_INT, "boundary", offsetof(struct reb_simulation, boundary), 0, 0}, + { 53, REB_INT, "gravity", offsetof(struct reb_simulation, gravity), 0, 0}, + { 54, REB_DOUBLE, "ri_sei.OMEGA", offsetof(struct reb_simulation, ri_sei.OMEGA), 0, 0}, + { 55, REB_DOUBLE, "ri_sei.OMEGAZ", offsetof(struct reb_simulation, ri_sei.OMEGAZ), 0, 0}, + { 56, REB_DOUBLE, "ri_sei.lastdt", offsetof(struct reb_simulation, ri_sei.lastdt), 0, 0}, + { 57, REB_DOUBLE, "ri_sei.sindt", offsetof(struct reb_simulation, ri_sei.sindt), 0, 0}, + { 58, REB_DOUBLE, "ri_sei.tandt", offsetof(struct reb_simulation, ri_sei.tandt), 0, 0}, + { 59, REB_DOUBLE, "ri_sei.sindtz", offsetof(struct reb_simulation, ri_sei.sindtz), 0, 0}, + { 60, REB_DOUBLE, "ri_sei.tandtz", offsetof(struct reb_simulation, ri_sei.tandtz), 0, 0}, + { 61, REB_UINT, "ri_whfast.corrector", offsetof(struct reb_simulation, ri_whfast.corrector), 0, 0}, + { 62, REB_UINT, "ri_whfast.recalculate_coordinates_this_timestep", offsetof(struct reb_simulation, ri_whfast.recalculate_coordinates_this_timestep), 0, 0}, + { 63, REB_UINT, "ri_whfast.safe_mode", offsetof(struct reb_simulation, ri_whfast.safe_mode), 0, 0}, + { 64, REB_UINT, "ri_whfast.keep_unsynchronized",offsetof(struct reb_simulation, ri_whfast.keep_unsynchronized), 0, 0}, + { 65, REB_UINT, "ri_whfast.is_synchronized", offsetof(struct reb_simulation, ri_whfast.is_synchronized), 0, 0}, + { 66, REB_UINT, "ri_whfast.timestep_warnning", offsetof(struct reb_simulation, ri_whfast.timestep_warning), 0, 0}, + { 69, REB_DOUBLE, "ri_ias15.epsilon", offsetof(struct reb_simulation, ri_ias15.epsilon), 0, 0}, + { 70, REB_DOUBLE, "ri_ias15.min_dt", offsetof(struct reb_simulation, ri_ias15.min_dt), 0, 0}, + { 71, REB_UINT, "ri_ias15.epsilon_global", offsetof(struct reb_simulation, ri_ias15.epsilon_global), 0, 0}, + { 401, REB_UINT, "ri_ias15.dt_mode", offsetof(struct reb_simulation, ri_ias15.dt_mode), 0, 0}, + { 72, REB_ULONG, "ri_ias15.iterations_max_exceeded", offsetof(struct reb_simulation, ri_ias15.iterations_max_exceeded), 0, 0}, + { 85, REB_POINTER, "particles", offsetof(struct reb_simulation, particles), offsetof(struct reb_simulation, N), sizeof(struct reb_particle)}, + { 86, REB_POINTER, "var_config", offsetof(struct reb_simulation, var_config), offsetof(struct reb_simulation, var_config_N), sizeof(struct reb_variational_configuration)}, + { 87, REB_OTHER, "functionpointers", 0, 0, 0}, + { 89, REB_POINTER, "ri_ias15.at", offsetof(struct reb_simulation, ri_ias15.at), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 90, REB_POINTER, "ri_ias15.x0", offsetof(struct reb_simulation, ri_ias15.x0), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 91, REB_POINTER, "ri_ias15.v0", offsetof(struct reb_simulation, ri_ias15.v0), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 92, REB_POINTER, "ri_ias15.a0", offsetof(struct reb_simulation, ri_ias15.a0), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 93, REB_POINTER, "ri_ias15.csx", offsetof(struct reb_simulation, ri_ias15.csx), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 94, REB_POINTER, "ri_ias15.csv", offsetof(struct reb_simulation, ri_ias15.csv), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 95, REB_POINTER, "ri_ias15.csa0", offsetof(struct reb_simulation, ri_ias15.csa0), offsetof(struct reb_simulation, ri_ias15.allocated_N), sizeof(double)}, + { 96, REB_DP7, "ri_ias15.g", offsetof(struct reb_simulation, ri_ias15.g), offsetof(struct reb_simulation, ri_ias15.allocated_N), 7*sizeof(double)}, + { 97, REB_DP7, "ri_ias15.b", offsetof(struct reb_simulation, ri_ias15.b), offsetof(struct reb_simulation, ri_ias15.allocated_N), 7*sizeof(double)}, + { 98, REB_DP7, "ri_ias15.csb", offsetof(struct reb_simulation, ri_ias15.csb), offsetof(struct reb_simulation, ri_ias15.allocated_N), 7*sizeof(double)}, + { 99, REB_DP7, "ri_ias15.e", offsetof(struct reb_simulation, ri_ias15.e), offsetof(struct reb_simulation, ri_ias15.allocated_N), 7*sizeof(double)}, + { 100, REB_DP7, "ri_ias15.br", offsetof(struct reb_simulation, ri_ias15.br), offsetof(struct reb_simulation, ri_ias15.allocated_N), 7*sizeof(double)}, + { 101, REB_DP7, "ri_ias15.er", offsetof(struct reb_simulation, ri_ias15.er), offsetof(struct reb_simulation, ri_ias15.allocated_N), 7*sizeof(double)}, + { 104, REB_POINTER, "ri_whfast.p_jh", offsetof(struct reb_simulation, ri_whfast.p_jh), offsetof(struct reb_simulation, ri_whfast.allocated_N), sizeof(struct reb_particle)}, + { 107, REB_INT, "visualization", offsetof(struct reb_simulation, visualization), 0, 0}, + { 112, REB_POINTER, "ri_janus.p_int", offsetof(struct reb_simulation, ri_janus.p_int), offsetof(struct reb_simulation, ri_janus.allocated_N), sizeof(struct reb_particle_int)}, + { 113, REB_DOUBLE, "ri_janus.scale_pos", offsetof(struct reb_simulation, ri_janus.scale_pos), 0, 0}, + { 114, REB_DOUBLE, "ri_janus.scale_vel", offsetof(struct reb_simulation, ri_janus.scale_vel), 0, 0}, + { 115, REB_UINT, "ri_janus.order", offsetof(struct reb_simulation, ri_janus.order), 0, 0}, + { 116, REB_UINT, "ri_janus.recalculate_integer_coordinates_this_timestep", offsetof(struct reb_simulation, ri_janus.recalculate_integer_coordinates_this_timestep), 0, 0}, + { 117, REB_INT, "ri_whfast.coordinates", offsetof(struct reb_simulation, ri_whfast.coordinates), 0, 0}, + { 118, REB_DOUBLE, "ri_mercurius.hillfac", offsetof(struct reb_simulation, ri_mercurius.hillfac), 0, 0}, + { 119, REB_UINT, "ri_mercurius.safe_mode", offsetof(struct reb_simulation, ri_mercurius.safe_mode), 0, 0}, + { 120, REB_UINT, "ri_mercurius.is_synchronized", offsetof(struct reb_simulation, ri_mercurius.is_synchronized), 0, 0}, + { 122, REB_POINTER, "ri_mercurius.dcrit", offsetof(struct reb_simulation, ri_mercurius.dcrit), offsetof(struct reb_simulation, ri_mercurius.dcrit_allocated_N), sizeof(double)}, + { 123, REB_UINT, "ri_mercurius.recalculate_coordinates_this_timestep", offsetof(struct reb_simulation, ri_mercurius.recalculate_coordinates_this_timestep), 0, 0}, + { 125, REB_INT, "simulationarchive_version", offsetof(struct reb_simulation, simulationarchive_version), 0, 0}, + { 126, REB_DOUBLE, "walltime", offsetof(struct reb_simulation, walltime), 0, 0}, + { 130, REB_UINT32, "python_unit_l", offsetof(struct reb_simulation, python_unit_l), 0, 0}, + { 131, REB_UINT32, "python_unit_m", offsetof(struct reb_simulation, python_unit_m), 0, 0}, + { 132, REB_UINT32, "python_unit_t", offsetof(struct reb_simulation, python_unit_t), 0, 0}, + { 133, REB_VEC3D, "ri_mercurius.com_pos", offsetof(struct reb_simulation, ri_mercurius.com_pos), 0, 0}, + { 134, REB_VEC3D, "ri_mercurius.com_vel", offsetof(struct reb_simulation, ri_mercurius.com_vel), 0, 0}, + { 135, REB_ULONGLONG, "simulationarchive_auto_step", offsetof(struct reb_simulation, simulationarchive_auto_step), 0, 0}, + { 136, REB_ULONGLONG, "simulationarchive_next_step", offsetof(struct reb_simulation, simulationarchive_next_step), 0, 0}, + { 137, REB_ULONGLONG, "steps_done", offsetof(struct reb_simulation, steps_done), 0, 0}, + { 140, REB_UINT, "ri_saba.safe_mode", offsetof(struct reb_simulation, ri_saba.safe_mode), 0, 0}, + { 141, REB_UINT, "ri_saba.is_synchronized", offsetof(struct reb_simulation, ri_saba.is_synchronized), 0, 0}, + { 143, REB_UINT, "ri_whfast.corrector2", offsetof(struct reb_simulation, ri_whfast.corrector2), 0, 0}, + { 144, REB_INT, "ri_whfast.kernel", offsetof(struct reb_simulation, ri_whfast.kernel), 0, 0}, + { 145, REB_DOUBLE, "dt_last_done", offsetof(struct reb_simulation, dt_last_done), 0, 0}, + { 146, REB_INT, "ri_saba.type", offsetof(struct reb_simulation, ri_saba.type), 0, 0}, + { 147, REB_UINT, "ri_saba.keep_unsynchronized", offsetof(struct reb_simulation, ri_saba.keep_unsynchronized), 0, 0}, + { 148, REB_INT, "ri_eos.phi0", offsetof(struct reb_simulation, ri_eos.phi0), 0, 0}, + { 149, REB_INT, "ri_eos.phi1", offsetof(struct reb_simulation, ri_eos.phi1), 0, 0}, + { 150, REB_UINT, "ri_eos.n", offsetof(struct reb_simulation, ri_eos.n), 0, 0}, + { 151, REB_UINT, "ri_eos.safe_mode", offsetof(struct reb_simulation, ri_eos.safe_mode), 0, 0}, + { 152, REB_UINT, "ri_eos.is_synchronized", offsetof(struct reb_simulation, ri_eos.is_synchronized), 0, 0}, + { 154, REB_UINT, "rand_seed", offsetof(struct reb_simulation, rand_seed), 0, 0}, + { 155, REB_INT, "testparticle_hidewarnings", offsetof(struct reb_simulation, testparticle_hidewarnings), 0, 0}, + { 156, REB_DOUBLE, "ri_bs.eps_abs", offsetof(struct reb_simulation, ri_bs.eps_abs), 0, 0}, + { 157, REB_DOUBLE, "ri_bs.eps_rel", offsetof(struct reb_simulation, ri_bs.eps_rel), 0, 0}, + { 158, REB_DOUBLE, "ri_bs.min_dt", offsetof(struct reb_simulation, ri_bs.min_dt), 0, 0}, + { 159, REB_DOUBLE, "ri_bs.max_dt", offsetof(struct reb_simulation, ri_bs.max_dt), 0, 0}, + { 160, REB_INT, "ri_bs.firstOrLastStep", offsetof(struct reb_simulation, ri_bs.firstOrLastStep), 0, 0}, + { 161, REB_INT, "ri_bs.previousRejected", offsetof(struct reb_simulation, ri_bs.previousRejected), 0, 0}, + { 162, REB_INT, "ri_bs.targetIter", offsetof(struct reb_simulation, ri_bs.targetIter), 0, 0}, +// { 163, REB_INT, "var_rescale_warning", offsetof(struct reb_simulation, var_rescale_warning), 0, 0}, + { 300, REB_DOUBLE, "ri_tes.dq_max", offsetof(struct reb_simulation, ri_tes.dq_max), 0, 0}, + { 301, REB_DOUBLE, "ri_tes.recti_per_orbit", offsetof(struct reb_simulation, ri_tes.recti_per_orbit), 0, 0}, + { 302, REB_DOUBLE, "ri_tes.epsilon", offsetof(struct reb_simulation, ri_tes.epsilon), 0, 0}, + { 303, REB_DOUBLE, "ri_tes.orbital_period", offsetof(struct reb_simulation, ri_tes.orbital_period), 0, 0}, + { 304, REB_UINT, "ri_tes.allocated_N", offsetof(struct reb_simulation, ri_tes.allocated_N), 0, 0}, // TODO! + { 305, REB_POINTER, "ri_tes.particles_dh", offsetof(struct reb_simulation, ri_tes.particles_dh), offsetof(struct reb_simulation, ri_tes.allocated_N), sizeof(struct reb_particle)}, + { 308, REB_UINT32, "ri_tes.controlVectorLength", offsetof(struct reb_simulation, ri_tes.controlVectorLength), 0, 0}, + { 309, REB_UINT32, "ri_tes.controlVectorSize", offsetof(struct reb_simulation, ri_tes.controlVectorSize), 0, 0}, + { 310, REB_POINTER, "ri_tes.mass", offsetof(struct reb_simulation, ri_tes.mass), offsetof(struct reb_simulation, ri_tes.allocated_N), sizeof(double)}, + { 311, REB_POINTER, "ri_tes.X_dh", offsetof(struct reb_simulation, ri_tes.X_dh), offsetof(struct reb_simulation, ri_tes.allocated_N), 6*sizeof(double)}, + { 312, REB_VEC3D, "ri_tes.COM", offsetof(struct reb_simulation, ri_tes.COM), 0, 0}, + { 313, REB_VEC3D, "ri_tes.COM_dot", offsetof(struct reb_simulation, ri_tes.COM_dot), 0, 0}, + { 314, REB_DOUBLE, "ri_tes.mStar_last", offsetof(struct reb_simulation, ri_tes.mStar_last), 0, 0}, + // TES Variables only implemented as REB_OTHER so far + { 320, REB_OTHER, "ri_tes.uVars->stateVectorSize", 0, 0, 0}, + { 321, REB_OTHER, "ri_tes.uVars->controlVectorSize", 0, 0, 0}, + { 322, REB_OTHER, "ri_tes.uVars->t0", 0, 0, 0}, + { 323, REB_OTHER, "ri_tes.uVars->tlast", 0, 0, 0}, + { 324, REB_OTHER, "ri_tes.uVars->csq", 0, 0, 0}, + { 325, REB_OTHER, "ri_tes.uVars->csp", 0, 0, 0}, + { 326, REB_OTHER, "ri_tes.uVars->csv", 0, 0, 0}, + { 327, REB_OTHER, "ri_tes.uVars->q0", 0, 0, 0}, + { 328, REB_OTHER, "ri_tes.uVars->v0", 0, 0, 0}, + + { 329, REB_OTHER, "ri_tes.uVars->p0", 0, 0, 0}, + { 330, REB_OTHER, "ri_tes.uVars->q1", 0, 0, 0}, + { 331, REB_OTHER, "ri_tes.uVars->v1", 0, 0, 0}, + { 332, REB_OTHER, "ri_tes.uVars->p1", 0, 0, 0}, + { 333, REB_OTHER, "ri_tes.uVars->x", 0, 0, 0}, + { 334, REB_OTHER, "ri_tes.uVars->q0_norm", 0, 0, 0}, + { 335, REB_OTHER, "ri_tes.uVars->beta", 0, 0, 0}, + { 336, REB_OTHER, "ri_tes.uVars->eta", 0, 0, 0}, + { 337, REB_OTHER, "ri_tes.uVars->zeta", 0, 0, 0}, + { 338, REB_OTHER, "ri_tes.uVars->period", 0, 0, 0}, + { 339, REB_OTHER, "ri_tes.uVars->xperiod", 0, 0, 0}, + { 340, REB_OTHER, "ri_tes.uVars->stumpf_c0", 0, 0, 0}, + { 341, REB_OTHER, "ri_tes.uVars->stumpf_c1", 0, 0, 0}, + { 342, REB_OTHER, "ri_tes.uVars->stumpf_c2", 0, 0, 0}, + { 343, REB_OTHER, "ri_tes.uVars->stumpf_c3", 0, 0, 0}, + { 344, REB_OTHER, "ri_tes.uVars->mu", 0, 0, 0}, + { 350, REB_OTHER, "ri_tes.radau->dx", 0, 0, 0}, + { 351, REB_OTHER, "ri_tes.radau->xout",0, 0, 0}, + { 352, REB_OTHER, "ri_tes.radau->recti_array",0, 0, 0}, + { 353, REB_OTHER, "ri_tes.radau->predictors",0, 0, 0}, + { 354, REB_OTHER, "ri_tes.radau->dstate0",0, 0, 0}, + { 355, REB_OTHER, "ri_tes.radau->ddstate0",0, 0, 0}, + { 356, REB_OTHER, "ri_tes.radau->dstate",0, 0, 0}, + { 357, REB_OTHER, "ri_tes.radau->ddstate",0, 0, 0}, + { 358, REB_OTHER, "ri_tes.radau->cs_dstate0",0, 0, 0}, + { 359, REB_OTHER, "ri_tes.radau->cs_ddstate0",0, 0, 0}, + { 360, REB_OTHER, "ri_tes.radau->cs_dstate",0, 0, 0}, + { 361, REB_OTHER, "ri_tes.radau->cs_ddstate",0, 0, 0}, + { 362, REB_OTHER, "ri_tes.radau->cs_dx",0, 0, 0}, + { 363, REB_OTHER, "ri_tes.radau->fcalls",0, 0, 0}, + { 364, REB_OTHER, "ri_tes.radau->rectis",0, 0, 0}, + { 365, REB_OTHER, "ri_tes.radau->iters",0, 0, 0}, + { 366, REB_OTHER, "ri_tes.radau->b6",0, 0, 0}, + { 367, REB_OTHER, "ri_tes.radau->b",0, 0, 0}, + { 368, REB_OTHER, "ri_tes.radau->blast",0, 0, 0}, + { 369, REB_OTHER, "ri_tes.radau->b_1st",0, 0, 0}, + { 370, REB_OTHER, "ri_tes.radau->blast_1st",0, 0, 0}, + { 371, REB_OTHER, "ri_tes.radau->cs_b",0, 0, 0}, + { 372, REB_OTHER, "ri_tes.radau->cs_b_1st",0, 0, 0}, + { 373, REB_OTHER, "ri_tes.radau->g",0, 0, 0}, + { 374, REB_OTHER, "ri_tes.radau->g_1st",0, 0, 0}, + { 380, REB_OTHER, "ri_tes.rhs->xosc_store",0, 0, 0}, + { 381, REB_OTHER, "ri_tes.rhs->xosc_pred_store",0, 0, 0}, + { 382, REB_OTHER, "ri_tes.rhs->xosc_cs_store",0, 0, 0}, + { 383, REB_OTHER, "ri_tes.rhs->xosc_dot_store",0, 0, 0}, + { 384, REB_OTHER, "ri_tes.rhs->x",0, 0, 0}, + { 385, REB_OTHER, "ri_tes.rhs->m_inv",0, 0, 0}, + { 386, REB_OTHER, "ri_tes.rhs->m_total",0, 0, 0}, + { 387, REB_OTHER, "ri_tes.rhs->recti_time",0, 0, 0}, + { 388, REB_OTHER, "ri_tes.rhs->recti_period",0, 0, 0}, + { 390, REB_UINT, "ri_whfast512.keep_unsynchronized", offsetof(struct reb_simulation, ri_whfast512.keep_unsynchronized), 0, 0}, + { 391, REB_UINT, "ri_whfast512.is_synchronized", offsetof(struct reb_simulation, ri_whfast512.is_synchronized), 0, 0}, + { 392, REB_UINT, "ri_whfast512.gr_potential", offsetof(struct reb_simulation, ri_whfast512.gr_potential), 0, 0}, + { 394, REB_POINTER_ALIGNED, "ri_whfast512.pjh", offsetof(struct reb_simulation, ri_whfast512.p_jh), offsetof(struct reb_simulation, ri_whfast512.allocated_N), sizeof(struct reb_particle_avx512)}, + { 395, REB_PARTICLE, "ri_whfast512.pjh0", offsetof(struct reb_simulation, ri_whfast512.p_jh0), 0, 0}, + { 396, REB_DOUBLE, "max_radius0", offsetof(struct reb_simulation, max_radius0), 0, 0}, + { 397, REB_DOUBLE, "max_radius1", offsetof(struct reb_simulation, max_radius1), 0, 0}, + { 1329743186, REB_OTHER,"header", 0, 0, 0}, + { 9998, REB_OTHER, "sablob", 0, 0, 0}, + { 9999, REB_FIELD_END, "end", 0, 0, 0} +}; + +// required for python pickling +void reb_output_free_stream(char* buf){ + free(buf); +} + /** * @brief Replacement for open_memstream */ @@ -220,16 +447,6 @@ void reb_output_orbits(struct reb_simulation* r, char* filename){ fclose(of); } -static inline void reb_save_dp7(struct reb_dp7* dp7, const int N3, char** bufp, size_t* sizep, size_t* allocatedsize){ - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p0,sizeof(double)*N3); - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p1,sizeof(double)*N3); - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p2,sizeof(double)*N3); - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p3,sizeof(double)*N3); - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p4,sizeof(double)*N3); - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p5,sizeof(double)*N3); - reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p6,sizeof(double)*N3); -} - static inline void reb_save_controlVars(controlVars* dp7, char** bufp, size_t* sizep, size_t* allocatedsize){ reb_output_stream_write(bufp, allocatedsize, sizep, &dp7->size, sizeof(uint32_t)); reb_output_stream_write(bufp, allocatedsize, sizep, dp7->p0, dp7->size); @@ -254,6 +471,15 @@ static inline void reb_save_controlVars(controlVars* dp7, char** bufp, size_t* s reb_output_stream_write(bufp, &allocatedsize, sizep, value,field.size);\ } +#define WRITE_FIELD_TYPE(typen, value, length) {\ + struct reb_binary_field field;\ + memset(&field,0,sizeof(struct reb_binary_field));\ + field.type = typen;\ + field.size = (length);\ + reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field));\ + reb_output_stream_write(bufp, &allocatedsize, sizep, value,field.size);\ + } + void reb_output_binary_to_stream(struct reb_simulation* r, char** bufp, size_t* sizep){ size_t allocatedsize = 0; @@ -267,128 +493,95 @@ void reb_output_binary_to_stream(struct reb_simulation* r, char** bufp, size_t* int cwritten = sprintf(header,"REBOUND Binary File. Version: %s",reb_version_str); snprintf(header+cwritten+1,64-cwritten-1,"%s",reb_githash_str); reb_output_stream_write(bufp, &allocatedsize, sizep, header,sizeof(char)*64); - - WRITE_FIELD(T, &r->t, sizeof(double)); - WRITE_FIELD(G, &r->G, sizeof(double)); - WRITE_FIELD(SOFTENING, &r->softening, sizeof(double)); - WRITE_FIELD(DT, &r->dt, sizeof(double)); - WRITE_FIELD(DTLASTDONE, &r->dt_last_done, sizeof(double)); - WRITE_FIELD(N, &r->N, sizeof(int)); - WRITE_FIELD(NVAR, &r->N_var, sizeof(int)); - WRITE_FIELD(VARCONFIGN, &r->var_config_N, sizeof(int)); - WRITE_FIELD(NACTIVE, &r->N_active, sizeof(int)); - WRITE_FIELD(TESTPARTICLETYPE, &r->testparticle_type, sizeof(int)); - WRITE_FIELD(TESTPARTICLEHIDEWARNINGS, &r->testparticle_hidewarnings,sizeof(int)); - WRITE_FIELD(HASHCTR, &r->hash_ctr, sizeof(int)); - WRITE_FIELD(OPENINGANGLE2, &r->opening_angle2, sizeof(double)); - WRITE_FIELD(STATUS, &r->status, sizeof(int)); - WRITE_FIELD(EXACTFINISHTIME, &r->exact_finish_time, sizeof(int)); - WRITE_FIELD(FORCEISVELOCITYDEP, &r->force_is_velocity_dependent, sizeof(unsigned int)); - WRITE_FIELD(GRAVITYIGNORETERMS, &r->gravity_ignore_terms, sizeof(unsigned int)); - WRITE_FIELD(OUTPUTTIMINGLAST, &r->output_timing_last, sizeof(double)); - WRITE_FIELD(SAVEMESSAGES, &r->save_messages, sizeof(int)); - WRITE_FIELD(EXITMAXDISTANCE, &r->exit_max_distance, sizeof(double)); - WRITE_FIELD(EXITMINDISTANCE, &r->exit_min_distance, sizeof(double)); - WRITE_FIELD(USLEEP, &r->usleep, sizeof(double)); - WRITE_FIELD(TRACKENERGYOFFSET, &r->track_energy_offset, sizeof(int)); - WRITE_FIELD(ENERGYOFFSET, &r->energy_offset, sizeof(double)); - WRITE_FIELD(BOXSIZE, &r->boxsize, sizeof(struct reb_vec3d)); - WRITE_FIELD(BOXSIZEMAX, &r->boxsize_max, sizeof(double)); - WRITE_FIELD(ROOTSIZE, &r->root_size, sizeof(double)); - WRITE_FIELD(ROOTN, &r->root_n, sizeof(int)); - WRITE_FIELD(ROOTNX, &r->root_nx, sizeof(int)); - WRITE_FIELD(ROOTNY, &r->root_ny, sizeof(int)); - WRITE_FIELD(ROOTNZ, &r->root_nz, sizeof(int)); - WRITE_FIELD(NGHOSTX, &r->nghostx, sizeof(int)); - WRITE_FIELD(NGHOSTY, &r->nghosty, sizeof(int)); - WRITE_FIELD(NGHOSTZ, &r->nghostz, sizeof(int)); - WRITE_FIELD(COLLISIONRESOLVEKEEPSORTED, &r->collision_resolve_keep_sorted, sizeof(int)); - WRITE_FIELD(MINIMUMCOLLISIONVELOCITY, &r->minimum_collision_velocity, sizeof(double)); - WRITE_FIELD(COLLISIONSPLOG, &r->collisions_plog, sizeof(double)); - WRITE_FIELD(MAXRADIUS, &r->max_radius, 2*sizeof(double)); - WRITE_FIELD(COLLISIONSNLOG, &r->collisions_Nlog, sizeof(long)); - WRITE_FIELD(CALCULATEMEGNO, &r->calculate_megno, sizeof(int)); - WRITE_FIELD(MEGNOYS, &r->megno_Ys, sizeof(double)); - WRITE_FIELD(MEGNOYSS, &r->megno_Yss, sizeof(double)); - WRITE_FIELD(MEGNOCOVYT, &r->megno_cov_Yt, sizeof(double)); - WRITE_FIELD(MEGNOVART, &r->megno_var_t, sizeof(double)); - WRITE_FIELD(MEGNOMEANT, &r->megno_mean_t, sizeof(double)); - WRITE_FIELD(MEGNOMEANY, &r->megno_mean_Y, sizeof(double)); - WRITE_FIELD(MEGNON, &r->megno_n, sizeof(long)); - WRITE_FIELD(SAVERSION, &r->simulationarchive_version, sizeof(int)); - WRITE_FIELD(SASIZESNAPSHOT, &r->simulationarchive_size_snapshot,sizeof(long)); - WRITE_FIELD(SAAUTOINTERVAL, &r->simulationarchive_auto_interval, sizeof(double)); - WRITE_FIELD(SAAUTOWALLTIME, &r->simulationarchive_auto_walltime, sizeof(double)); - WRITE_FIELD(SANEXT, &r->simulationarchive_next, sizeof(double)); - WRITE_FIELD(WALLTIME, &r->walltime, sizeof(double)); - WRITE_FIELD(COLLISION, &r->collision, sizeof(int)); - WRITE_FIELD(VISUALIZATION, &r->visualization, sizeof(int)); - WRITE_FIELD(INTEGRATOR, &r->integrator, sizeof(int)); - WRITE_FIELD(BOUNDARY, &r->boundary, sizeof(int)); - WRITE_FIELD(GRAVITY, &r->gravity, sizeof(int)); - WRITE_FIELD(SEI_OMEGA, &r->ri_sei.OMEGA, sizeof(double)); - WRITE_FIELD(SEI_OMEGAZ, &r->ri_sei.OMEGAZ, sizeof(double)); - WRITE_FIELD(SEI_LASTDT, &r->ri_sei.lastdt, sizeof(double)); - WRITE_FIELD(SEI_SINDT, &r->ri_sei.sindt, sizeof(double)); - WRITE_FIELD(SEI_TANDT, &r->ri_sei.tandt, sizeof(double)); - WRITE_FIELD(SEI_SINDTZ, &r->ri_sei.sindtz, sizeof(double)); - WRITE_FIELD(SEI_TANDTZ, &r->ri_sei.tandtz, sizeof(double)); - WRITE_FIELD(WHFAST_CORRECTOR, &r->ri_whfast.corrector, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_RECALCJAC, &r->ri_whfast.recalculate_coordinates_this_timestep, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_SAFEMODE, &r->ri_whfast.safe_mode, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_KEEPUNSYNC, &r->ri_whfast.keep_unsynchronized, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_ISSYNCHRON, &r->ri_whfast.is_synchronized, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_TIMESTEPWARN,&r->ri_whfast.timestep_warning, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_PJ, r->ri_whfast.p_jh, sizeof(struct reb_particle)*r->ri_whfast.allocated_N); - WRITE_FIELD(WHFAST_COORDINATES, &r->ri_whfast.coordinates, sizeof(int)); - WRITE_FIELD(IAS15_EPSILON, &r->ri_ias15.epsilon, sizeof(double)); - WRITE_FIELD(IAS15_MINDT, &r->ri_ias15.min_dt, sizeof(double)); - WRITE_FIELD(IAS15_EPSILONGLOBAL,&r->ri_ias15.epsilon_global, sizeof(unsigned int)); - WRITE_FIELD(IAS15_ITERATIONSMAX,&r->ri_ias15.iterations_max_exceeded,sizeof(unsigned long)); - if (r->ri_ias15.allocatedN>r->N*3){ - int N3 = 3*r->N; // Useful to avoid file size increase if particles got removed - WRITE_FIELD(IAS15_ALLOCATEDN, &N3, sizeof(int)); - }else{ - WRITE_FIELD(IAS15_ALLOCATEDN, &r->ri_ias15.allocatedN, sizeof(int)); + + // Compress data if possible + // This does not affect future calculation, but might trigger a realloc. + if (r->ri_ias15.allocated_N > 3*r->N){ + r->ri_ias15.allocated_N = 3*r->N; + } + /// Output all fields + int i=0; + while (reb_binary_field_descriptor_list[i].dtype!=REB_FIELD_END){ + int dtype = reb_binary_field_descriptor_list[i].dtype; + // Simple data types: + if (dtype == REB_DOUBLE || dtype == REB_INT || dtype == REB_UINT || dtype == REB_UINT32 || + dtype == REB_LONG || dtype == REB_ULONG || dtype == REB_ULONGLONG || + dtype == REB_PARTICLE || dtype == REB_VEC3D ){ + struct reb_binary_field field; + memset(&field,0,sizeof(struct reb_binary_field)); + field.type = reb_binary_field_descriptor_list[i].type; + switch (dtype){ + case REB_DOUBLE: + field.size = sizeof(double); + break; + case REB_INT: + field.size = sizeof(int); + break; + case REB_UINT: + field.size = sizeof(unsigned int); + break; + case REB_UINT32: + field.size = sizeof(uint32_t); + break; + case REB_LONG: + field.size = sizeof(long); + break; + case REB_ULONG: + field.size = sizeof(unsigned long); + break; + case REB_ULONGLONG: + field.size = sizeof(unsigned long long); + break; + case REB_VEC3D: + field.size = sizeof(struct reb_vec3d); + break; + case REB_PARTICLE: + field.size = sizeof(struct reb_particle); + break; + } + reb_output_stream_write(bufp, &allocatedsize, sizep, &field, sizeof(struct reb_binary_field)); + char* pointer = (char*)r + reb_binary_field_descriptor_list[i].offset; + reb_output_stream_write(bufp, &allocatedsize, sizep, pointer, field.size); + } + // Pointer data types + if (dtype == REB_POINTER || dtype == REB_POINTER_ALIGNED ){ + struct reb_binary_field field; + memset(&field,0,sizeof(struct reb_binary_field)); + field.type = reb_binary_field_descriptor_list[i].type; + unsigned int* pointer_N = (unsigned int*)((char*)r + reb_binary_field_descriptor_list[i].offset_N); + field.size = (*pointer_N) * reb_binary_field_descriptor_list[i].element_size; + + if (field.size){ + reb_output_stream_write(bufp, &allocatedsize, sizep, &field, sizeof(struct reb_binary_field)); + char* pointer = (char*)r + reb_binary_field_descriptor_list[i].offset; + pointer = *(char**)pointer; + reb_output_stream_write(bufp, &allocatedsize, sizep, pointer, field.size); + } + } + // Special datatype for IAS15. Similar to POINTER + if (dtype == REB_DP7 ){ + struct reb_binary_field field; + memset(&field,0,sizeof(struct reb_binary_field)); + field.type = reb_binary_field_descriptor_list[i].type; + unsigned int* pointer_N = (unsigned int*)((char*)r + reb_binary_field_descriptor_list[i].offset_N); + field.size = (*pointer_N) * reb_binary_field_descriptor_list[i].element_size; + + if (field.size){ + reb_output_stream_write(bufp, &allocatedsize, sizep, &field, sizeof(struct reb_binary_field)); + char* pointer = (char*)r + reb_binary_field_descriptor_list[i].offset; + struct reb_dp7* dp7 = (struct reb_dp7*)pointer; + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p0,field.size/7); + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p1,field.size/7); + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p2,field.size/7); + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p3,field.size/7); + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p4,field.size/7); + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p5,field.size/7); + reb_output_stream_write(bufp, &allocatedsize, sizep, dp7->p6,field.size/7); + } + } + i++; } - WRITE_FIELD(JANUS_SCALEPOS, &r->ri_janus.scale_pos, sizeof(double)); - WRITE_FIELD(JANUS_SCALEVEL, &r->ri_janus.scale_vel, sizeof(double)); - WRITE_FIELD(JANUS_ORDER, &r->ri_janus.order, sizeof(unsigned int)); - WRITE_FIELD(JANUS_ALLOCATEDN, &r->ri_janus.allocated_N, sizeof(unsigned int)); - WRITE_FIELD(JANUS_RECALC, &r->ri_janus.recalculate_integer_coordinates_this_timestep, sizeof(unsigned int)); - WRITE_FIELD(JANUS_PINT, r->ri_janus.p_int, sizeof(struct reb_particle_int)*r->ri_janus.allocated_N); - WRITE_FIELD(MERCURIUS_HILLFAC, &r->ri_mercurius.hillfac, sizeof(double)); - WRITE_FIELD(MERCURIUS_SAFEMODE, &r->ri_mercurius.safe_mode, sizeof(unsigned int)); - WRITE_FIELD(MERCURIUS_ISSYNCHRON, &r->ri_mercurius.is_synchronized, sizeof(unsigned int)); - WRITE_FIELD(MERCURIUS_RECALCULATE_COORD, &r->ri_mercurius.recalculate_coordinates_this_timestep, sizeof(unsigned int)); - WRITE_FIELD(MERCURIUS_DCRIT, r->ri_mercurius.dcrit, sizeof(double)*r->ri_mercurius.dcrit_allocatedN); - WRITE_FIELD(MERCURIUS_COMPOS, &(r->ri_mercurius.com_pos), sizeof(struct reb_vec3d)); - WRITE_FIELD(MERCURIUS_COMVEL, &(r->ri_mercurius.com_vel), sizeof(struct reb_vec3d)); - WRITE_FIELD(PYTHON_UNIT_L, &r->python_unit_l, sizeof(uint32_t)); - WRITE_FIELD(PYTHON_UNIT_M, &r->python_unit_m, sizeof(uint32_t)); - WRITE_FIELD(PYTHON_UNIT_T, &r->python_unit_t, sizeof(uint32_t)); - WRITE_FIELD(STEPSDONE, &r->steps_done, sizeof(unsigned long long)); - WRITE_FIELD(SAAUTOSTEP, &r->simulationarchive_auto_step, sizeof(unsigned long long)); - WRITE_FIELD(SANEXTSTEP, &r->simulationarchive_next_step, sizeof(unsigned long long)); - WRITE_FIELD(SABA_TYPE, &r->ri_saba.type, sizeof(unsigned int)); - WRITE_FIELD(SABA_SAFEMODE, &r->ri_saba.safe_mode, sizeof(unsigned int)); - WRITE_FIELD(SABA_ISSYNCHRON, &r->ri_saba.is_synchronized, sizeof(unsigned int)); - WRITE_FIELD(SABA_KEEPUNSYNC, &r->ri_saba.keep_unsynchronized, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_CORRECTOR2, &r->ri_whfast.corrector2, sizeof(unsigned int)); - WRITE_FIELD(WHFAST_KERNEL, &r->ri_whfast.kernel, sizeof(unsigned int)); - WRITE_FIELD(EOS_PHI0, &r->ri_eos.phi0, sizeof(unsigned int)); - WRITE_FIELD(EOS_PHI1, &r->ri_eos.phi1, sizeof(unsigned int)); - WRITE_FIELD(EOS_N, &r->ri_eos.n, sizeof(unsigned int)); - WRITE_FIELD(EOS_SAFEMODE, &r->ri_eos.safe_mode, sizeof(unsigned int)); - WRITE_FIELD(EOS_ISSYNCHRON, &r->ri_eos.is_synchronized, sizeof(unsigned int)); - WRITE_FIELD(RAND_SEED, &r->rand_seed, sizeof(unsigned int)); - WRITE_FIELD(BS_EPSABS, &r->ri_bs.eps_abs, sizeof(double)); - WRITE_FIELD(BS_EPSREL, &r->ri_bs.eps_rel, sizeof(double)); - WRITE_FIELD(BS_MINDT, &r->ri_bs.min_dt, sizeof(double)); - WRITE_FIELD(BS_MAXDT, &r->ri_bs.max_dt, sizeof(double)); - WRITE_FIELD(BS_FIRSTORLASTSTEP, &r->ri_bs.firstOrLastStep, sizeof(int)); - WRITE_FIELD(BS_PREVIOUSREJECTED,&r->ri_bs.previousRejected, sizeof(int)); - WRITE_FIELD(BS_TARGETITER, &r->ri_bs.targetIter, sizeof(int)); + int functionpointersused = 0; if (r->coefficient_of_restitution || r->collision_resolve || @@ -399,89 +592,10 @@ void reb_output_binary_to_stream(struct reb_simulation* r, char** bufp, size_t* functionpointersused = 1; } WRITE_FIELD(FUNCTIONPOINTERS, &functionpointersused, sizeof(int)); - { - struct reb_binary_field field; - memset(&field,0,sizeof(struct reb_binary_field)); - field.type = REB_BINARY_FIELD_TYPE_PARTICLES; - field.size = sizeof(struct reb_particle)*r->N; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - // output one particle at a time to sanitize pointers. - for (unsigned int l=0;lN;l++){ - struct reb_particle op = r->particles[l]; - op.c = NULL; - op.ap = NULL; - op.sim = NULL; - reb_output_stream_write(bufp, &allocatedsize, sizep, &op,sizeof(struct reb_particle)); - } - } - if (r->var_config){ - WRITE_FIELD(VARCONFIG, r->var_config, sizeof(struct reb_variational_configuration)*r->var_config_N); - } - if (r->ri_ias15.allocatedN){ - int N3 = 3*r->N; // Only outut useful data (useful if particles got removed) - WRITE_FIELD(IAS15_AT, r->ri_ias15.at, sizeof(double)*N3); - WRITE_FIELD(IAS15_X0, r->ri_ias15.x0, sizeof(double)*N3); - WRITE_FIELD(IAS15_V0, r->ri_ias15.v0, sizeof(double)*N3); - WRITE_FIELD(IAS15_A0, r->ri_ias15.a0, sizeof(double)*N3); - WRITE_FIELD(IAS15_CSX, r->ri_ias15.csx, sizeof(double)*N3); - WRITE_FIELD(IAS15_CSV, r->ri_ias15.csv, sizeof(double)*N3); - WRITE_FIELD(IAS15_CSA0, r->ri_ias15.csa0, sizeof(double)*N3); - { - struct reb_binary_field field = {.type = REB_BINARY_FIELD_TYPE_IAS15_G, .size = sizeof(double)*N3*7}; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - reb_save_dp7(&(r->ri_ias15.g),N3,bufp,sizep,&allocatedsize); - } - { - struct reb_binary_field field = {.type = REB_BINARY_FIELD_TYPE_IAS15_B, .size = sizeof(double)*N3*7}; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - reb_save_dp7(&(r->ri_ias15.b),N3,bufp,sizep,&allocatedsize); - } - { - struct reb_binary_field field = {.type = REB_BINARY_FIELD_TYPE_IAS15_CSB, .size = sizeof(double)*N3*7}; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - reb_save_dp7(&(r->ri_ias15.csb),N3,bufp,sizep,&allocatedsize); - } - { - struct reb_binary_field field = {.type = REB_BINARY_FIELD_TYPE_IAS15_E, .size = sizeof(double)*N3*7}; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - reb_save_dp7(&(r->ri_ias15.e),N3,bufp,sizep,&allocatedsize); - } - { - struct reb_binary_field field = {.type = REB_BINARY_FIELD_TYPE_IAS15_BR, .size = sizeof(double)*N3*7}; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - reb_save_dp7(&(r->ri_ias15.br),N3,bufp,sizep,&allocatedsize); - } - { - struct reb_binary_field field = {.type = REB_BINARY_FIELD_TYPE_IAS15_ER, .size = sizeof(double)*N3*7}; - reb_output_stream_write(bufp, &allocatedsize, sizep, &field,sizeof(struct reb_binary_field)); - reb_save_dp7(&(r->ri_ias15.er),N3,bufp,sizep,&allocatedsize); - } - } - - // Output fields for TES integrator. - WRITE_FIELD(TES_DQ_MAX, &r->ri_tes.dq_max, sizeof(double)); - WRITE_FIELD(TES_RECTI_PER_ORBIT, &r->ri_tes.recti_per_orbit, sizeof(double)); - WRITE_FIELD(TES_EPSILON, &r->ri_tes.epsilon, sizeof(double)); - WRITE_FIELD(TES_PERIOD, &r->ri_tes.orbital_period, sizeof(double)); - WRITE_FIELD(TES_SV_LEN, &r->ri_tes.stateVectorLength, sizeof(uint32_t)); - WRITE_FIELD(TES_SV_SIZE, &r->ri_tes.stateVectorSize, sizeof(uint32_t)); - WRITE_FIELD(TES_CV_LEN, &r->ri_tes.controlVectorLength, sizeof(uint32_t)); - WRITE_FIELD(TES_CV_SIZE, &r->ri_tes.controlVectorSize, sizeof(uint32_t)); - WRITE_FIELD(TES_COM, &r->ri_tes.COM, 3*sizeof(double)); - WRITE_FIELD(TES_COM_DOT, &r->ri_tes.COM_dot, 3*sizeof(double)); - WRITE_FIELD(TES_MASS_STAR_LAST, &r->ri_tes.mStar_last, sizeof(double)); - WRITE_FIELD(TES_ALLOCATED_N, &r->ri_tes.allocated_N, sizeof(uint32_t)); - if(r->ri_tes.allocated_N) { - uint32_t N = r->ri_tes.allocated_N; - WRITE_FIELD(TES_PARTICLES_DH, r->ri_tes.particles_dh, N*sizeof(struct reb_particle)); - WRITE_FIELD(TES_MASS, r->ri_tes.mass, N*sizeof(double)); - WRITE_FIELD(TES_X_DH, r->ri_tes.X_dh, 6*N*sizeof(double)); - // Kepler solver vars. - WRITE_FIELD(TES_UVARS_SV_SIZE, &r->ri_tes.uVars->stateVectorSize, sizeof(uint32_t)); WRITE_FIELD(TES_UVARS_T0, r->ri_tes.uVars->t0, r->ri_tes.uVars->controlVectorSize); WRITE_FIELD(TES_UVARS_TLAST, r->ri_tes.uVars->tLast, r->ri_tes.uVars->controlVectorSize); WRITE_FIELD(TES_UVARS_CSQ, r->ri_tes.uVars->uv_csq, r->ri_tes.uVars->stateVectorSize); @@ -507,23 +621,25 @@ void reb_output_binary_to_stream(struct reb_simulation* r, char** bufp, size_t* WRITE_FIELD(TES_UVARS_MU, &r->ri_tes.uVars->mu, sizeof(double)); // Integrator vars - WRITE_FIELD(TES_RADAU_DX, r->ri_tes.radau->dX, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_XOUT, r->ri_tes.radau->Xout, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_RECTI_ARRAY, r->ri_tes.radau->rectifiedArray, sizeof(uint32_t)*r->ri_tes.stateVectorLength); - WRITE_FIELD(TES_RADAU_PREDICTORS, r->ri_tes.radau->predictors, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_DSTATE0, r->ri_tes.radau->dState0, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_DDSTATE0, r->ri_tes.radau->ddState0, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_DSTATE, r->ri_tes.radau->dState, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_DDSTATE, r->ri_tes.radau->ddState, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_CS_DSTATE0, r->ri_tes.radau->cs_dState0, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_CS_DDSTATE0, r->ri_tes.radau->cs_ddState0, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_CS_DSTATE, r->ri_tes.radau->cs_dState, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_CS_DDSTATE, r->ri_tes.radau->cs_ddState, r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_RADAU_CS_DX, r->ri_tes.radau->cs_dX, r->ri_tes.stateVectorSize); + // + const int stateVectorSize = r->ri_tes.allocated_N*6*sizeof(double); + WRITE_FIELD(TES_RADAU_DX, r->ri_tes.radau->dX, stateVectorSize); + WRITE_FIELD(TES_RADAU_XOUT, r->ri_tes.radau->Xout, stateVectorSize); + WRITE_FIELD(TES_RADAU_RECTI_ARRAY, r->ri_tes.radau->rectifiedArray, sizeof(uint32_t)*r->ri_tes.allocated_N*6); + WRITE_FIELD(TES_RADAU_PREDICTORS, r->ri_tes.radau->predictors, stateVectorSize); + WRITE_FIELD(TES_RADAU_DSTATE0, r->ri_tes.radau->dState0, stateVectorSize); + WRITE_FIELD(TES_RADAU_DDSTATE0, r->ri_tes.radau->ddState0, stateVectorSize); + WRITE_FIELD(TES_RADAU_DSTATE, r->ri_tes.radau->dState, stateVectorSize); + WRITE_FIELD(TES_RADAU_DDSTATE, r->ri_tes.radau->ddState, stateVectorSize); + WRITE_FIELD(TES_RADAU_CS_DSTATE0, r->ri_tes.radau->cs_dState0, stateVectorSize); + WRITE_FIELD(TES_RADAU_CS_DDSTATE0, r->ri_tes.radau->cs_ddState0, stateVectorSize); + WRITE_FIELD(TES_RADAU_CS_DSTATE, r->ri_tes.radau->cs_dState, stateVectorSize); + WRITE_FIELD(TES_RADAU_CS_DDSTATE, r->ri_tes.radau->cs_ddState, stateVectorSize); + WRITE_FIELD(TES_RADAU_CS_DX, r->ri_tes.radau->cs_dX, stateVectorSize); WRITE_FIELD(TES_RADAU_FCALLS, &r->ri_tes.radau->fCalls, sizeof(uint64_t)); WRITE_FIELD(TES_RADAU_RECTIS, &r->ri_tes.radau->rectifications, sizeof(uint64_t)); WRITE_FIELD(TES_RADAU_ITERS, &r->ri_tes.radau->convergenceIterations, sizeof(uint32_t)); - WRITE_FIELD(TES_RADAU_B6, r->ri_tes.radau->b6_store, r->ri_tes.stateVectorSize); + WRITE_FIELD(TES_RADAU_B6, r->ri_tes.radau->b6_store, stateVectorSize); { uint32_t array_size = r->ri_tes.radau->B.size; @@ -574,11 +690,11 @@ void reb_output_binary_to_stream(struct reb_simulation* r, char** bufp, size_t* reb_save_controlVars(&r->ri_tes.radau->G_1st,bufp,sizep,&allocatedsize); } // force model vars - WRITE_FIELD(TES_DHEM_XOSC_STORE, r->ri_tes.rhs->XoscStore, 9*r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_DHEM_XOSC_PRED_STORE, r->ri_tes.rhs->XoscPredStore, 9*r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_DHEM_XOSC_CS_STORE, r->ri_tes.rhs->XoscStore_cs, 9*r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_DHEM_XOSC_DOT_STORE, r->ri_tes.rhs->Xosc_dotStore, 9*r->ri_tes.stateVectorSize); - WRITE_FIELD(TES_DHEM_X, r->ri_tes.rhs->X, r->ri_tes.stateVectorSize); + WRITE_FIELD(TES_DHEM_XOSC_STORE, r->ri_tes.rhs->XoscStore, 9*stateVectorSize); + WRITE_FIELD(TES_DHEM_XOSC_PRED_STORE, r->ri_tes.rhs->XoscPredStore, 9*stateVectorSize); + WRITE_FIELD(TES_DHEM_XOSC_CS_STORE, r->ri_tes.rhs->XoscStore_cs, 9*stateVectorSize); + WRITE_FIELD(TES_DHEM_XOSC_DOT_STORE, r->ri_tes.rhs->Xosc_dotStore, 9*stateVectorSize); + WRITE_FIELD(TES_DHEM_X, r->ri_tes.rhs->X, stateVectorSize); WRITE_FIELD(TES_DHEM_M_INV, r->ri_tes.rhs->m_inv, r->ri_tes.controlVectorSize); WRITE_FIELD(TES_DHEM_M_TOTAL, &r->ri_tes.rhs->mTotal, sizeof(double)); WRITE_FIELD(TES_DHEM_RECTI_TIME, r->ri_tes.rhs->rectifyTimeArray, r->ri_tes.controlVectorSize); @@ -586,26 +702,17 @@ void reb_output_binary_to_stream(struct reb_simulation* r, char** bufp, size_t* } -#ifdef AVX512 - WRITE_FIELD(WHFAST512_KEEPUNSYNC, &r->ri_whfast512.keep_unsynchronized, sizeof(unsigned int)); - WRITE_FIELD(WHFAST512_ISSYNCHRON, &r->ri_whfast512.is_synchronized, sizeof(unsigned int)); - WRITE_FIELD(WHFAST512_GRPOTENTIAL, &r->ri_whfast512.gr_potential, sizeof(unsigned int)); - WRITE_FIELD(WHFAST512_ALLOCATEDN, &r->ri_whfast512.allocated_N, sizeof(unsigned int)); - if (r->ri_whfast512.allocated_N){ - WRITE_FIELD(WHFAST512_PJH, r->ri_whfast512.p_jh, sizeof(struct reb_particle_avx512)); - WRITE_FIELD(WHFAST512_PJH0, &r->ri_whfast512.p_jh0, sizeof(struct reb_particle)); - } -#endif // AVX512 - // To output size of binary file, need to calculate it first. if (r->simulationarchive_version<3){ // to be removed in a future release r->simulationarchive_size_first = (*sizep)+sizeof(struct reb_binary_field)*2+sizeof(long)+sizeof(struct reb_simulationarchive_blob16); }else{ r->simulationarchive_size_first = (*sizep)+sizeof(struct reb_binary_field)*2+sizeof(long)+sizeof(struct reb_simulationarchive_blob); } - WRITE_FIELD(SASIZEFIRST, &r->simulationarchive_size_first, sizeof(long)); + WRITE_FIELD_TYPE( 45 , &r->simulationarchive_size_first, sizeof(long)); int end_null = 0; - WRITE_FIELD(END, &end_null, 0); + + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); + WRITE_FIELD_TYPE(fd_end.type, &end_null, 0); if (r->simulationarchive_version<3){ // to be removed in a future release struct reb_simulationarchive_blob16 blob = {0}; reb_output_stream_write(bufp, &allocatedsize, sizep, &blob, sizeof(struct reb_simulationarchive_blob16)); diff --git a/src/particle.c b/src/particle.c index bc2695ac7..a6874b205 100644 --- a/src/particle.c +++ b/src/particle.c @@ -52,9 +52,9 @@ static void reb_add_local(struct reb_simulation* const r, struct reb_particle pt reb_error(r,"Particle outside of box boundaries. Did not add particle."); return; } - while (r->allocatedN<=r->N){ - r->allocatedN = r->allocatedN ? r->allocatedN * 2 : 128; - r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocatedN); + while (r->allocated_N<=r->N){ + r->allocated_N = r->allocated_N ? r->allocated_N * 2 : 128; + r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocated_N); } r->particles[r->N] = pt; @@ -78,15 +78,15 @@ static void reb_add_local(struct reb_simulation* const r, struct reb_particle pt rim->recalculate_coordinates_this_timestep = 1; }else{ // IAS15 part reb_integrator_ias15_reset(r); - if (rim->dcrit_allocatedNN){ + if (rim->dcrit_allocated_NN){ rim->dcrit = realloc(rim->dcrit, sizeof(double)*r->N); - rim->dcrit_allocatedN = r->N; + rim->dcrit_allocated_N = r->N; } rim->dcrit[r->N-1] = reb_integrator_mercurius_calculate_dcrit_for_particle(r,r->N-1); - if (rim->allocatedNN){ + if (rim->allocated_NN){ rim->particles_backup = realloc(rim->particles_backup,sizeof(struct reb_particle)*r->N); rim->encounter_map = realloc(rim->encounter_map,sizeof(int)*r->N); - rim->allocatedN = r->N; + rim->allocated_N = r->N; } rim->encounter_map[rim->encounterN] = r->N-1; rim->encounterN++; @@ -101,12 +101,12 @@ static void reb_add_local(struct reb_simulation* const r, struct reb_particle pt void reb_add(struct reb_simulation* const r, struct reb_particle pt){ #ifndef COLLISIONS_NONE - if (pt.r>=r->max_radius[0]){ - r->max_radius[1] = r->max_radius[0]; - r->max_radius[0] = pt.r; + if (pt.r>=r->max_radius0){ + r->max_radius1 = r->max_radius0; + r->max_radius0 = pt.r; }else{ - if (pt.r>=r->max_radius[1]){ - r->max_radius[1] = pt.r; + if (pt.r>=r->max_radius1){ + r->max_radius1 = pt.r; } } #endif // COLLISIONS_NONE @@ -210,9 +210,9 @@ static void reb_update_particle_lookup_table(struct reb_simulation* const r){ int N_hash = 0; int zerohash = -1; for(unsigned int i=0; iN; i++){ - if(N_hash >= r->allocatedN_lookup){ - r->allocatedN_lookup = r->allocatedN_lookup ? r->allocatedN_lookup * 2 : 128; - r->particle_lookup_table = realloc(r->particle_lookup_table, sizeof(struct reb_hash_pointer_pair)*r->allocatedN_lookup); + if(N_hash >= r->allocated_N_lookup){ + r->allocated_N_lookup = r->allocated_N_lookup ? r->allocated_N_lookup * 2 : 128; + r->particle_lookup_table = realloc(r->particle_lookup_table, sizeof(struct reb_hash_pointer_pair)*r->allocated_N_lookup); } if(particles[i].hash == 0){ // default hash (0) special case if (zerohash == -1){ // first zero hash @@ -285,7 +285,7 @@ struct reb_particle reb_get_remote_particle_by_hash(struct reb_simulation* const void reb_remove_all(struct reb_simulation* const r){ r->N = 0; - r->allocatedN = 0; + r->allocated_N = 0; r->N_active = -1; r->N_var = 0; free(r->particles); @@ -296,7 +296,7 @@ int reb_remove(struct reb_simulation* const r, int index, int keepSorted){ if (r->integrator == REB_INTEGRATOR_MERCURIUS){ keepSorted = 1; // Force keepSorted for hybrid integrator struct reb_simulation_integrator_mercurius* rim = &(r->ri_mercurius); - if (rim->dcrit_allocatedN>0 && index<(int)rim->dcrit_allocatedN){ + if (rim->dcrit_allocated_N>0 && index<(int)rim->dcrit_allocated_N){ for (unsigned int i=0;iN-1;i++){ if ((int)i>=index){ rim->dcrit[i] = rim->dcrit[i+1]; diff --git a/src/rebound.c b/src/rebound.c index 66bc41829..8b0d2fadf 100644 --- a/src/rebound.c +++ b/src/rebound.c @@ -27,6 +27,7 @@ #include #include #include +#include // for offsetof() #include #include #include @@ -364,16 +365,16 @@ void reb_free_pointers(struct reb_simulation* const r){ void reb_reset_temporary_pointers(struct reb_simulation* const r){ // Note: this will not clear the particle array. - r->gravity_cs_allocatedN = 0; + r->gravity_cs_allocated_N = 0; r->gravity_cs = NULL; - r->collisions_allocatedN = 0; + r->collisions_allocated_N = 0; r->collisions = NULL; r->extras = NULL; r->messages = NULL; // ********** Lookup Table r->particle_lookup_table = NULL; r->N_lookup = 0; - r->allocatedN_lookup = 0; + r->allocated_N_lookup = 0; // ********** WHFAST r->ri_whfast.allocated_N = 0; r->ri_whfast.allocated_Ntemp= 0; @@ -381,7 +382,7 @@ void reb_reset_temporary_pointers(struct reb_simulation* const r){ r->ri_whfast.p_temp = NULL; r->ri_whfast.keep_unsynchronized = 0; // ********** IAS15 - r->ri_ias15.allocatedN = 0; + r->ri_ias15.allocated_N = 0; set_dp7_null(&(r->ri_ias15.g)); set_dp7_null(&(r->ri_ias15.b)); set_dp7_null(&(r->ri_ias15.csb)); @@ -399,9 +400,9 @@ void reb_reset_temporary_pointers(struct reb_simulation* const r){ r->ri_ias15.map_allocated_N = 0; r->ri_ias15.map = NULL; // ********** MERCURIUS - r->ri_mercurius.allocatedN = 0; - r->ri_mercurius.allocatedN_additionalforces = 0; - r->ri_mercurius.dcrit_allocatedN = 0; + r->ri_mercurius.allocated_N = 0; + r->ri_mercurius.allocated_N_additionalforces = 0; + r->ri_mercurius.dcrit_allocated_N = 0; r->ri_mercurius.dcrit = NULL; r->ri_mercurius.particles_backup = NULL; r->ri_mercurius.particles_backup_additionalforces = NULL; @@ -416,7 +417,7 @@ void reb_reset_temporary_pointers(struct reb_simulation* const r){ // ********** ODEs r->odes = NULL; r->odes_N = 0; - r->odes_allocatedN = 0; + r->odes_allocated_N = 0; // ********** TES r->ri_tes.particles_dh = NULL; } @@ -465,12 +466,27 @@ void reb_copy_simulation_with_messages(struct reb_simulation* r_copy, struct re // Set to old version by default. Will be overwritten if new version was used. r_copy->simulationarchive_version = 0; - char* bufp_beginning = bufp; // bufp will be changed - while(reb_input_field(r_copy, NULL, warnings, &bufp)){ } - free(bufp_beginning); + FILE* fin = fmemopen(bufp, sizep, "r"); + reb_input_fields(r_copy, fin, warnings); + fclose(fin); } +char* reb_diff_simulations_char(struct reb_simulation* r1, struct reb_simulation* r2){ + char* bufp1; + char* bufp2; + char* bufp; + size_t sizep1, sizep2, size; + reb_output_binary_to_stream(r1, &bufp1,&sizep1); + reb_output_binary_to_stream(r2, &bufp2,&sizep2); + + reb_binary_diff_with_options(bufp1, sizep1, bufp2, sizep2, &bufp, &size, 3); + + free(bufp1); + free(bufp2); + return bufp; +} + int reb_diff_simulations(struct reb_simulation* r1, struct reb_simulation* r2, int output_option){ if (output_option!=1 && output_option!=2){ // Not implemented @@ -522,13 +538,13 @@ void reb_init_simulation(struct reb_simulation* r){ r->nghosty = 0; r->nghostz = 0; r->N = 0; - r->allocatedN = 0; + r->allocated_N = 0; r->N_active = -1; r->var_rescale_warning = 0; r->particle_lookup_table = NULL; r->hash_ctr = 0; r->N_lookup = 0; - r->allocatedN_lookup = 0; + r->allocated_N_lookup = 0; r->testparticle_type = 0; r->testparticle_hidewarnings = 0; r->N_var = 0; @@ -536,8 +552,8 @@ void reb_init_simulation(struct reb_simulation* r){ r->var_config = NULL; r->exit_min_distance = 0; r->exit_max_distance = 0; - r->max_radius[0] = 0.; - r->max_radius[1] = 0.; + r->max_radius0 = 0.; + r->max_radius1 = 0.; r->status = REB_RUNNING; r->exact_finish_time = 1; r->force_is_velocity_dependent = 0; @@ -606,6 +622,10 @@ void reb_init_simulation(struct reb_simulation* r){ r->ri_ias15.min_dt = 0; r->ri_ias15.epsilon_global = 1; r->ri_ias15.iterations_max_exceeded = 0; + r->ri_ias15.dt_mode = 1; + r->ri_ias15.rejected = 0; + r->ri_ias15.mindt = 1e300; + r->ri_ias15.safety = 0.25; // ********** SEI r->ri_sei.OMEGA = 1; @@ -901,6 +921,21 @@ enum REB_STATUS reb_integrate(struct reb_simulation* const r, double tmax){ return r->status; } +int reb_check_fp_contract(){ + // Checks if floating point contractions are on. + // If so, this will prevent unit tests from passing + // and bit-wise reproducibility will fail. + double a = 1.2382309285234567; + double b = 2.123478623874623234567; + double c = 6.0284234234234567; + + double r1 = a*b+c; + double ab = a*b; + double r2 = ab+c; + + return r1 != r2; +} + #ifdef OPENMP void reb_omp_set_num_threads(int num_threads){ @@ -936,3 +971,4 @@ const char* reb_logo[26] = { " `-/oyyyssosssyso+/. ", " ``....` ", }; + diff --git a/src/rebound.h b/src/rebound.h index d1334a097..2a2d58c6b 100644 --- a/src/rebound.h +++ b/src/rebound.h @@ -52,6 +52,7 @@ extern const char* reb_build_str; ///< Date and time build string. extern const char* reb_version_str; ///< Version string. extern const char* reb_githash_str; ///< Current git hash. extern const char* reb_logo[26]; ///< Logo of rebound. +extern const char* reb_binary_field_type_reverse; ///< Dictionary to allow for reverse lookup of names of REB_BINARY_FIELD_TYPE extern volatile sig_atomic_t reb_sigint; ///< Graceful global interrupt handler // Forward declarations @@ -119,10 +120,14 @@ struct reb_simulation_integrator_ias15 { double epsilon; double min_dt; unsigned int epsilon_global; + unsigned int dt_mode; + long rejected; + double mindt; + double safety; // Internal use unsigned long iterations_max_exceeded; // Counter how many times the iteration did not converge. - unsigned int allocatedN; + unsigned int allocated_N; double* REBOUND_RESTRICT at; double* REBOUND_RESTRICT x0; double* REBOUND_RESTRICT v0; @@ -155,9 +160,9 @@ struct reb_simulation_integrator_mercurius { unsigned int encounterN; // Number of particles currently having an encounter unsigned int encounterNactive; // Number of active particles currently having an encounter unsigned int tponly_encounter; // 0 if any encounters are between two massive bodies. 1 if encounters only involve test particles - unsigned int allocatedN; - unsigned int allocatedN_additionalforces; - unsigned int dcrit_allocatedN; // Current size of dcrit arrays + unsigned int allocated_N; + unsigned int allocated_N_additionalforces; + unsigned int dcrit_allocated_N; // Current size of dcrit arrays double* dcrit; // Precalculated switching radii for particles struct reb_particle* REBOUND_RESTRICT particles_backup; // contains coordinates before Kepler step for encounter prediction struct reb_particle* REBOUND_RESTRICT particles_backup_additionalforces; // contains coordinates before Kepler step for encounter prediction @@ -262,7 +267,7 @@ struct reb_simulation_integrator_whfast512 { struct reb_ode{ // defines an ODE unsigned int length; // number of components / dimenion - unsigned int allocatedN; + unsigned int allocated_N; unsigned int needs_nbody; double* y; // Current state double* scale; @@ -446,13 +451,13 @@ struct reb_simulation_integrator_tes { double orbital_period; // The lowest initial orbital period. // Synchronisation particle storage. - uint32_t allocated_N; + unsigned int allocated_N; struct reb_particle* particles_dh; // Vector dimensions variables. - uint32_t stateVectorLength; /// Length of the state vector in doubles. - uint32_t stateVectorSize; /// Size in bytes of the state vector. uint32_t controlVectorLength; /// Length of the control vector in doubles. +// Cant delete fellowing variable. Not sure why + uint32_t statesdfsdfsfdVectorSize; /// Size in bytes of the state vector. uint32_t controlVectorSize; /// Size in bytes of n * sizeof(double). // State storage @@ -460,8 +465,8 @@ struct reb_simulation_integrator_tes { double * X_dh; /// Memory for current state in dh coords. double * Q_dh; /// Current state in dh coords. double * P_dh; /// Current state in dh coords. - double COM[3]; // Centre of mass - double COM_dot[3]; // Velocity of COM + struct reb_vec3d COM; /// Centre of mass + struct reb_vec3d COM_dot; /// Velocity of COM // Pointers to various modules comprising TES. UNIVERSAL_VARS * uVars; /// Pointer to the universal variables module @@ -537,140 +542,7 @@ enum REB_STATUS { // IDs for content of a binary field. Used to read and write binary files. enum REB_BINARY_FIELD_TYPE { - REB_BINARY_FIELD_TYPE_T = 0, - REB_BINARY_FIELD_TYPE_G = 1, - REB_BINARY_FIELD_TYPE_SOFTENING = 2, - REB_BINARY_FIELD_TYPE_DT = 3, - REB_BINARY_FIELD_TYPE_N = 4, - REB_BINARY_FIELD_TYPE_NVAR = 5, - REB_BINARY_FIELD_TYPE_VARCONFIGN = 6, - REB_BINARY_FIELD_TYPE_NACTIVE = 7, - REB_BINARY_FIELD_TYPE_TESTPARTICLETYPE = 8, - REB_BINARY_FIELD_TYPE_HASHCTR = 9, - REB_BINARY_FIELD_TYPE_OPENINGANGLE2 = 10, - REB_BINARY_FIELD_TYPE_STATUS = 11, - REB_BINARY_FIELD_TYPE_EXACTFINISHTIME = 12, - REB_BINARY_FIELD_TYPE_FORCEISVELOCITYDEP = 13, - REB_BINARY_FIELD_TYPE_GRAVITYIGNORETERMS = 14, - REB_BINARY_FIELD_TYPE_OUTPUTTIMINGLAST = 15, - REB_BINARY_FIELD_TYPE_SAVEMESSAGES = 16, - REB_BINARY_FIELD_TYPE_EXITMAXDISTANCE = 17, - REB_BINARY_FIELD_TYPE_EXITMINDISTANCE = 18, - REB_BINARY_FIELD_TYPE_USLEEP = 19, - REB_BINARY_FIELD_TYPE_TRACKENERGYOFFSET = 20, - REB_BINARY_FIELD_TYPE_ENERGYOFFSET = 21, - REB_BINARY_FIELD_TYPE_BOXSIZE = 22, - REB_BINARY_FIELD_TYPE_BOXSIZEMAX = 23, - REB_BINARY_FIELD_TYPE_ROOTSIZE = 24, - REB_BINARY_FIELD_TYPE_ROOTN = 25, - REB_BINARY_FIELD_TYPE_ROOTNX = 26, - REB_BINARY_FIELD_TYPE_ROOTNY = 27, - REB_BINARY_FIELD_TYPE_ROOTNZ = 28, - REB_BINARY_FIELD_TYPE_NGHOSTX = 29, - REB_BINARY_FIELD_TYPE_NGHOSTY = 30, - REB_BINARY_FIELD_TYPE_NGHOSTZ = 31, - REB_BINARY_FIELD_TYPE_COLLISIONRESOLVEKEEPSORTED = 32, - REB_BINARY_FIELD_TYPE_MINIMUMCOLLISIONVELOCITY = 33, - REB_BINARY_FIELD_TYPE_COLLISIONSPLOG = 34, - REB_BINARY_FIELD_TYPE_MAXRADIUS = 35, - REB_BINARY_FIELD_TYPE_COLLISIONSNLOG = 36, - REB_BINARY_FIELD_TYPE_CALCULATEMEGNO = 37, - REB_BINARY_FIELD_TYPE_MEGNOYS = 38, - REB_BINARY_FIELD_TYPE_MEGNOYSS = 39, - REB_BINARY_FIELD_TYPE_MEGNOCOVYT = 40, - REB_BINARY_FIELD_TYPE_MEGNOVART = 41, - REB_BINARY_FIELD_TYPE_MEGNOMEANT = 42, - REB_BINARY_FIELD_TYPE_MEGNOMEANY = 43, - REB_BINARY_FIELD_TYPE_MEGNON = 44, - REB_BINARY_FIELD_TYPE_SASIZEFIRST = 45, - REB_BINARY_FIELD_TYPE_SASIZESNAPSHOT = 46, - REB_BINARY_FIELD_TYPE_SAAUTOINTERVAL = 47, - REB_BINARY_FIELD_TYPE_SAAUTOWALLTIME = 102, - REB_BINARY_FIELD_TYPE_SANEXT = 48, - REB_BINARY_FIELD_TYPE_COLLISION = 50, - REB_BINARY_FIELD_TYPE_INTEGRATOR = 51, - REB_BINARY_FIELD_TYPE_BOUNDARY = 52, - REB_BINARY_FIELD_TYPE_GRAVITY = 53, - REB_BINARY_FIELD_TYPE_SEI_OMEGA = 54, - REB_BINARY_FIELD_TYPE_SEI_OMEGAZ = 55, - REB_BINARY_FIELD_TYPE_SEI_LASTDT = 56, - REB_BINARY_FIELD_TYPE_SEI_SINDT = 57, - REB_BINARY_FIELD_TYPE_SEI_TANDT = 58, - REB_BINARY_FIELD_TYPE_SEI_SINDTZ = 59, - REB_BINARY_FIELD_TYPE_SEI_TANDTZ = 60, - REB_BINARY_FIELD_TYPE_WHFAST_CORRECTOR = 61, - REB_BINARY_FIELD_TYPE_WHFAST_RECALCJAC = 62, - REB_BINARY_FIELD_TYPE_WHFAST_SAFEMODE = 63, - REB_BINARY_FIELD_TYPE_WHFAST_KEEPUNSYNC = 64, - REB_BINARY_FIELD_TYPE_WHFAST_ISSYNCHRON = 65, - REB_BINARY_FIELD_TYPE_WHFAST_TIMESTEPWARN = 66, - REB_BINARY_FIELD_TYPE_IAS15_EPSILON = 69, - REB_BINARY_FIELD_TYPE_IAS15_MINDT = 70, - REB_BINARY_FIELD_TYPE_IAS15_EPSILONGLOBAL = 71, - REB_BINARY_FIELD_TYPE_IAS15_ITERATIONSMAX = 72, - REB_BINARY_FIELD_TYPE_PARTICLES = 85, - REB_BINARY_FIELD_TYPE_VARCONFIG = 86, REB_BINARY_FIELD_TYPE_FUNCTIONPOINTERS = 87, - REB_BINARY_FIELD_TYPE_IAS15_ALLOCATEDN = 88, - REB_BINARY_FIELD_TYPE_IAS15_AT = 89, - REB_BINARY_FIELD_TYPE_IAS15_X0 = 90, - REB_BINARY_FIELD_TYPE_IAS15_V0 = 91, - REB_BINARY_FIELD_TYPE_IAS15_A0 = 92, - REB_BINARY_FIELD_TYPE_IAS15_CSX = 93, - REB_BINARY_FIELD_TYPE_IAS15_CSV = 94, - REB_BINARY_FIELD_TYPE_IAS15_CSA0 = 95, - REB_BINARY_FIELD_TYPE_IAS15_G = 96, - REB_BINARY_FIELD_TYPE_IAS15_B = 97, - REB_BINARY_FIELD_TYPE_IAS15_CSB = 98, - REB_BINARY_FIELD_TYPE_IAS15_E = 99, - REB_BINARY_FIELD_TYPE_IAS15_BR = 100, - REB_BINARY_FIELD_TYPE_IAS15_ER = 101, - REB_BINARY_FIELD_TYPE_WHFAST_PJ = 104, - REB_BINARY_FIELD_TYPE_VISUALIZATION = 107, - REB_BINARY_FIELD_TYPE_JANUS_ALLOCATEDN = 110, - REB_BINARY_FIELD_TYPE_JANUS_PINT = 112, - REB_BINARY_FIELD_TYPE_JANUS_SCALEPOS = 113, - REB_BINARY_FIELD_TYPE_JANUS_SCALEVEL = 114, - REB_BINARY_FIELD_TYPE_JANUS_ORDER = 115, - REB_BINARY_FIELD_TYPE_JANUS_RECALC = 116, - REB_BINARY_FIELD_TYPE_WHFAST_COORDINATES = 117, - REB_BINARY_FIELD_TYPE_MERCURIUS_HILLFAC = 118, - REB_BINARY_FIELD_TYPE_MERCURIUS_SAFEMODE = 119, - REB_BINARY_FIELD_TYPE_MERCURIUS_ISSYNCHRON = 120, - REB_BINARY_FIELD_TYPE_MERCURIUS_DCRIT = 122, - REB_BINARY_FIELD_TYPE_MERCURIUS_RECALCULATE_COORD = 123, - REB_BINARY_FIELD_TYPE_SAVERSION = 125, - REB_BINARY_FIELD_TYPE_WALLTIME = 126, - REB_BINARY_FIELD_TYPE_PYTHON_UNIT_L = 130, - REB_BINARY_FIELD_TYPE_PYTHON_UNIT_M = 131, - REB_BINARY_FIELD_TYPE_PYTHON_UNIT_T = 132, - REB_BINARY_FIELD_TYPE_MERCURIUS_COMPOS = 133, - REB_BINARY_FIELD_TYPE_MERCURIUS_COMVEL = 134, - REB_BINARY_FIELD_TYPE_SAAUTOSTEP = 135, - REB_BINARY_FIELD_TYPE_SANEXTSTEP = 136, - REB_BINARY_FIELD_TYPE_STEPSDONE = 137, - REB_BINARY_FIELD_TYPE_SABA_SAFEMODE = 140, - REB_BINARY_FIELD_TYPE_SABA_ISSYNCHRON = 141, - REB_BINARY_FIELD_TYPE_WHFAST_CORRECTOR2 = 143, - REB_BINARY_FIELD_TYPE_WHFAST_KERNEL = 144, - REB_BINARY_FIELD_TYPE_DTLASTDONE = 145, - REB_BINARY_FIELD_TYPE_SABA_TYPE = 146, - REB_BINARY_FIELD_TYPE_SABA_KEEPUNSYNC = 147, - REB_BINARY_FIELD_TYPE_EOS_PHI0 = 148, - REB_BINARY_FIELD_TYPE_EOS_PHI1 = 149, - REB_BINARY_FIELD_TYPE_EOS_N = 150, - REB_BINARY_FIELD_TYPE_EOS_SAFEMODE = 151, - REB_BINARY_FIELD_TYPE_EOS_ISSYNCHRON = 152, - REB_BINARY_FIELD_TYPE_RAND_SEED = 154, - REB_BINARY_FIELD_TYPE_TESTPARTICLEHIDEWARNINGS = 155, - REB_BINARY_FIELD_TYPE_BS_EPSABS = 156, - REB_BINARY_FIELD_TYPE_BS_EPSREL = 157, - REB_BINARY_FIELD_TYPE_BS_MINDT = 158, - REB_BINARY_FIELD_TYPE_BS_MAXDT = 159, - REB_BINARY_FIELD_TYPE_BS_FIRSTORLASTSTEP = 160, - REB_BINARY_FIELD_TYPE_BS_PREVIOUSREJECTED = 161, - REB_BINARY_FIELD_TYPE_BS_TARGETITER = 162, - REB_BINARY_FIELD_TYPE_VARRESCALEWARNING = 163, REB_BINARY_FIELD_TYPE_TES_DQ_MAX = 300, REB_BINARY_FIELD_TYPE_TES_RECTI_PER_ORBIT = 301, @@ -756,10 +628,6 @@ enum REB_BINARY_FIELD_TYPE { REB_BINARY_FIELD_TYPE_WHFAST512_ALLOCATEDN = 393, REB_BINARY_FIELD_TYPE_WHFAST512_PJH = 394, REB_BINARY_FIELD_TYPE_WHFAST512_PJH0 = 395, - - REB_BINARY_FIELD_TYPE_HEADER = 1329743186, // Corresponds to REBO (first characters of header text) - REB_BINARY_FIELD_TYPE_SABLOB = 9998, // SA Blob - REB_BINARY_FIELD_TYPE_END = 9999, }; // This structure is used to save and load binary files. @@ -784,7 +652,7 @@ struct reb_simulation { unsigned long long steps_done; unsigned int N; int N_var; - int var_config_N; + unsigned int var_config_N; struct reb_variational_configuration* var_config; // These configuration structs contain details on variational particles. int var_rescale_warning; int N_active; @@ -793,11 +661,11 @@ struct reb_simulation { struct reb_hash_pointer_pair* particle_lookup_table; // Array of pairs that map particles' hashes to their index in the particles array. int hash_ctr; // Counter for number of assigned hashes to assign unique values. int N_lookup; // Number of entries in the particle lookup table. - int allocatedN_lookup; // Number of lookup table entries allocated. - unsigned int allocatedN; // Current maximum space allocated in the particles array on this node. + int allocated_N_lookup; // Number of lookup table entries allocated. + unsigned int allocated_N; // Current maximum space allocated in the particles array on this node. struct reb_particle* particles; struct reb_vec3d* gravity_cs; // Containing the information for compensated gravity summation - int gravity_cs_allocatedN; + int gravity_cs_allocated_N; struct reb_treecell** tree_root;// Pointer to the roots of the trees. int tree_needs_update; // Flag to force a tree update (after boundary check) double opening_angle2; @@ -853,10 +721,11 @@ struct reb_simulation { int collision_resolve_keep_sorted; struct reb_collision* collisions; ///< Array of all collisions. - int collisions_allocatedN; + int collisions_allocated_N; double minimum_collision_velocity; double collisions_plog; - double max_radius[2]; // Two largest particle radii, set automatically, needed for collision search. + double max_radius0; // Two largest particle radii, set automatically, needed for collision search. + double max_radius1; // Two largest particle radii, set automatically, needed for collision search. long collisions_Nlog; // MEGNO @@ -938,7 +807,7 @@ struct reb_simulation { // ODEs struct reb_ode** odes; // all ode sets (includes nbody if BS set as integrator) int odes_N; // number of ode sets - int odes_allocatedN; // number of ode sets allocated + int odes_allocated_N; // number of ode sets allocated int ode_warnings; // Callback functions @@ -999,6 +868,7 @@ void reb_exit(const char* const msg); // Print out an error message, then exit i void reb_warning(struct reb_simulation* const r, const char* const msg); // Print or store a warning message, then continue. void reb_error(struct reb_simulation* const r, const char* const msg); // Print or store an error message, then continue. int reb_get_next_message(struct reb_simulation* const r, char* const buf); // Get the next stored warning message. Used only if save_messages==1. Return value is 0 if no messages are present, 1 otherwise. +int reb_check_fp_contract(); // Returns 1 if floating point contraction are enabled. 0 otherwise. // Timestepping void reb_step(struct reb_simulation* const r); @@ -1013,6 +883,8 @@ void reb_stop(struct reb_simulation* const r); // Stop current integration // If r1 and r2 are exactly equal to each other then 0 is returned, otherwise 1. Walltime is ignored. // If output_option=1, then output is printed on the screen. If 2, only return value os given. int reb_diff_simulations(struct reb_simulation* r1, struct reb_simulation* r2, int output_option); +// Same but return value is string to human readable difference. Needs to be freed. +char* reb_diff_simulations_char(struct reb_simulation* r1, struct reb_simulation* r2); // Mercurius switching functions double reb_integrator_mercurius_L_mercury(const struct reb_simulation* const r, double d, double dcrit); @@ -1047,9 +919,43 @@ void reb_output_velocity_dispersion(struct reb_simulation* r, char* filename); // Compares two simulations, stores difference in buffer. void reb_binary_diff(char* buf1, size_t size1, char* buf2, size_t size2, char** bufp, size_t* sizep); // Same as reb_binary_diff, but with options. -// output_option If set to 0, the differences are written to bufp. If set to 1, printed on the screen. If set to 2, then only the return value indicates any differences. -// returns 0 is returned if the simulations do not differ (are equal). 1 is return if they differ. +// output_option: +// - If set to 0, differences are written to bufp in the form of reb_binary_field structs. +// - If set to 1, differences are printed on the screen. +// - If set to 2, only the return value indicates any differences. +// - If set to 3, differences are written to bufp in a human readable form. +// returns value: 0 is returned if the simulations do not differ (are equal). 1 is return if they differ. int reb_binary_diff_with_options(char* buf1, size_t size1, char* buf2, size_t size2, char** bufp, size_t* sizep, int output_option); +// Returns the name fora given binary field type or name +struct reb_binary_field_descriptor reb_binary_field_descriptor_for_type(int type); +struct reb_binary_field_descriptor reb_binary_field_descriptor_for_name(const char* name); + +struct reb_binary_field_descriptor { + uint32_t type; // Unique id for each field. Should not change between versions. Ids should not be reused. + enum { + REB_DOUBLE, + REB_INT, + REB_UINT, + REB_UINT32, + REB_LONG, + REB_ULONG, + REB_ULONGLONG, + REB_VEC3D, + REB_PARTICLE, + REB_POINTER, + REB_POINTER_ALIGNED, // memory aligned to 64 bit boundary for AVX512 + REB_DP7, // Special datatype for IAS15 + REB_OTHER, // Fields that need special treatment during input and/or output + REB_FIELD_END, // Special type to indicate end of blob + REB_FIELD_NOT_FOUND, // Special type used to throw error messages + } dtype; + char name[1024]; + size_t offset; // Offset of the storage location relative to the beginning of reb_simulation + size_t offset_N; // Offset of the storage location for the size relative to the beginning of reb_simulation + size_t element_size; // Size in bytes of each element (only used for pointers, dp7, etc) +}; + +extern const struct reb_binary_field_descriptor reb_binary_field_descriptor_list[]; // Input functions struct reb_simulation* reb_create_simulation_from_binary(char* filename); @@ -1067,6 +973,7 @@ enum reb_input_binary_messages { REB_INPUT_BINARY_WARNING_FIELD_UNKOWN = 128, REB_INPUT_BINARY_ERROR_INTEGRATOR = 256, REB_INPUT_BINARY_WARNING_CORRUPTFILE = 512, + REB_INPUT_BINARY_ERROR_OLD = 1024, }; // ODE functions @@ -1272,7 +1179,7 @@ struct reb_simulationarchive_blob16 { // For backwards compatability only. Will struct reb_simulationarchive{ FILE* inf; // File pointer (will be kept open) - char* filename; // Filename of open file + char* filename; // Filename of open file. This is NULL if this is a memory-mapped file (using fmemopen) int version; // SimulationArchive version long size_first; // Size of first snapshot (only used for version 1) long size_snapshot; // Size of snapshot (only used for version 1) @@ -1292,7 +1199,7 @@ void reb_simulationarchive_automate_interval(struct reb_simulation* const r, con void reb_simulationarchive_automate_walltime(struct reb_simulation* const r, const char* filename, double walltime); void reb_simulationarchive_automate_step(struct reb_simulation* const r, const char* filename, unsigned long long step); void reb_free_simulationarchive_pointers(struct reb_simulationarchive* sa); - +void reb_read_simulationarchive_from_buffer_with_messages(struct reb_simulationarchive* sa, char* buf, size_t size, struct reb_simulationarchive* sa_index, enum reb_input_binary_messages* warnings); // Functions to convert between coordinate systems diff --git a/src/simulationarchive.c b/src/simulationarchive.c index b61f1b889..0772d2f67 100644 --- a/src/simulationarchive.c +++ b/src/simulationarchive.c @@ -60,6 +60,9 @@ void reb_create_simulation_from_simulationarchive_with_messages(struct reb_simul reb_free_pointers(r); memset(r,0,sizeof(struct reb_simulation)); reb_init_simulation(r); +#ifdef MPI + reb_communication_mpi_init(r, 0, NULL); +#endif //MPI r->simulationarchive_filename = NULL; // reb_create_simulation sets simulationarchive_version to 3 by default. // This will break reading in old version. @@ -67,7 +70,7 @@ void reb_create_simulation_from_simulationarchive_with_messages(struct reb_simul r->simulationarchive_version = 0; fseek(inf, 0, SEEK_SET); - while(reb_input_field(r, inf, warnings,NULL)){ } + reb_input_fields(r, inf, warnings); // Done? if (snapshot==0) return; @@ -79,153 +82,16 @@ void reb_create_simulation_from_simulationarchive_with_messages(struct reb_simul return; } if (r->simulationarchive_version<2){ - fread(&(r->t),sizeof(double),1,inf); - fread(&(r->walltime),sizeof(double),1,inf); - if (r->simulationarchive_auto_interval){ - while (r->simulationarchive_next<=r->t){ - r->simulationarchive_next += r->simulationarchive_auto_interval; - } - } - if (r->simulationarchive_auto_walltime){ - r->simulationarchive_next = r->walltime + r->simulationarchive_auto_interval; - } - switch (r->integrator){ - case REB_INTEGRATOR_JANUS: - { - if (r->ri_janus.allocated_N<(unsigned int)r->N){ - if (r->ri_janus.p_int){ - free(r->ri_janus.p_int); - } - r->ri_janus.p_int= malloc(sizeof(struct reb_particle)*r->N); - r->ri_janus.allocated_N = r->N; - } - fread(r->ri_janus.p_int,sizeof(struct reb_particle_int)*r->N,1,inf); - reb_integrator_synchronize(r); // get floating point coordinates - } - break; - case REB_INTEGRATOR_WHFAST: - case REB_INTEGRATOR_SABA: - { - // Recreate Jacobi arrrays - struct reb_particle* ps = r->particles; - if (r->ri_whfast.safe_mode==0){ - // If same mode is off, store unsynchronized Jacobi coordinates - if (r->ri_whfast.allocated_N<(unsigned int)r->N){ - if (r->ri_whfast.p_jh){ - free(r->ri_whfast.p_jh); - } - r->ri_whfast.p_jh= malloc(sizeof(struct reb_particle)*r->N); - r->ri_whfast.allocated_N = r->N; - } - ps = r->ri_whfast.p_jh; - } - for(unsigned int i=0;iN;i++){ - fread(&(r->particles[i].m),sizeof(double),1,inf); - fread(&(ps[i].x),sizeof(double),1,inf); - fread(&(ps[i].y),sizeof(double),1,inf); - fread(&(ps[i].z),sizeof(double),1,inf); - fread(&(ps[i].vx),sizeof(double),1,inf); - fread(&(ps[i].vy),sizeof(double),1,inf); - fread(&(ps[i].vz),sizeof(double),1,inf); - } - if (r->ri_whfast.safe_mode==0){ - // Assume we are not synchronized - r->ri_whfast.is_synchronized=0.; - // Recalculate total mass - double msum = r->particles[0].m; - for (unsigned int i=1;iN;i++){ - r->ri_whfast.p_jh[i].m = r->particles[i].m; - r->ri_whfast.p_jh[i].r = r->particles[i].r; - msum += r->particles[i].m; - } - r->ri_whfast.p_jh[0].m = msum; - r->ri_whfast.p_jh[0].r = r->particles[0].r; - } - } - break; - case REB_INTEGRATOR_MERCURIUS: - { - // Recreate heliocentric arrrays - struct reb_particle* ps = r->particles; - if (r->ri_mercurius.safe_mode==0){ - // If same mode is off, store unsynchronized Jacobi coordinates - if (r->ri_whfast.allocated_N<(unsigned int)r->N){ - if (r->ri_whfast.p_jh){ - free(r->ri_whfast.p_jh); - } - r->ri_whfast.p_jh= malloc(sizeof(struct reb_particle)*r->N); - r->ri_whfast.allocated_N = r->N; - } - ps = r->ri_whfast.p_jh; - } - for(unsigned int i=0;iN;i++){ - fread(&(r->particles[i].m),sizeof(double),1,inf); - fread(&(ps[i].x),sizeof(double),1,inf); - fread(&(ps[i].y),sizeof(double),1,inf); - fread(&(ps[i].z),sizeof(double),1,inf); - fread(&(ps[i].vx),sizeof(double),1,inf); - fread(&(ps[i].vy),sizeof(double),1,inf); - fread(&(ps[i].vz),sizeof(double),1,inf); - } - if (r->ri_mercurius.dcrit){ - free(r->ri_mercurius.dcrit); - } - r->ri_mercurius.dcrit = malloc(sizeof(double)*r->N); - r->ri_mercurius.dcrit_allocatedN = r->N; - fread(r->ri_mercurius.dcrit,sizeof(double),r->N,inf); - if (r->ri_mercurius.safe_mode==0){ - // Assume we are not synchronized - r->ri_mercurius.is_synchronized=0.; - // Recalculate total mass - double msum = r->particles[0].m; - for (unsigned int i=1;iN;i++){ - r->ri_whfast.p_jh[i].m = r->particles[i].m; - r->ri_whfast.p_jh[i].r = r->particles[i].r; - msum += r->particles[i].m; - } - r->ri_whfast.p_jh[0].m = msum; - r->ri_whfast.p_jh[0].r = r->particles[0].r; - } - } - break; - case REB_INTEGRATOR_IAS15: - { - fread(&(r->dt),sizeof(double),1,inf); - fread(&(r->dt_last_done),sizeof(double),1,inf); - struct reb_particle* ps = r->particles; - for(unsigned int i=0;iN;i++){ - fread(&(ps[i].m),sizeof(double),1,inf); - fread(&(ps[i].x),sizeof(double),1,inf); - fread(&(ps[i].y),sizeof(double),1,inf); - fread(&(ps[i].z),sizeof(double),1,inf); - fread(&(ps[i].vx),sizeof(double),1,inf); - fread(&(ps[i].vy),sizeof(double),1,inf); - fread(&(ps[i].vz),sizeof(double),1,inf); - } - reb_integrator_ias15_alloc(r); - const int N3 = r->N*3; - reb_read_dp7(&(r->ri_ias15.b) ,N3,inf,NULL); - reb_read_dp7(&(r->ri_ias15.csb),N3,inf,NULL); - reb_read_dp7(&(r->ri_ias15.e) ,N3,inf,NULL); - reb_read_dp7(&(r->ri_ias15.br) ,N3,inf,NULL); - reb_read_dp7(&(r->ri_ias15.er) ,N3,inf,NULL); - fread((r->ri_ias15.csx),sizeof(double)*N3,1,inf); - fread((r->ri_ias15.csv),sizeof(double)*N3,1,inf); - } - break; - default: - *warnings |= REB_INPUT_BINARY_ERROR_INTEGRATOR; - reb_free_simulation(r); - return; - } + *warnings |= REB_INPUT_BINARY_ERROR_OLD; + reb_free_simulation(r); + return; }else{ // Version 2 or higher - while(reb_input_field(r, inf, warnings,NULL)){ } + reb_input_fields(r, inf, warnings); } return; } - struct reb_simulation* reb_create_simulation_from_simulationarchive(struct reb_simulationarchive* sa, long snapshot){ if (sa==NULL) return NULL; enum reb_input_binary_messages warnings = REB_INPUT_BINARY_WARNING_NONE; @@ -235,108 +101,78 @@ struct reb_simulation* reb_create_simulation_from_simulationarchive(struct reb_s return r; // might be null if error occured } -void reb_read_simulationarchive_with_messages(struct reb_simulationarchive* sa, const char* filename, struct reb_simulationarchive* sa_index, enum reb_input_binary_messages* warnings){ +void reb_read_simulationarchive_from_stream_with_messages(struct reb_simulationarchive* sa, struct reb_simulationarchive* sa_index, enum reb_input_binary_messages* warnings){ + // Assumes sa->inf is set to an open stream const int debug = 0; -#ifdef MPI - int initialized; - MPI_Initialized(&initialized); - if (!initialized){ - int argc = 0; - char** argv = NULL; - MPI_Init(&argc, &argv); - } - int mpi_id=0; - MPI_Comm_rank(MPI_COMM_WORLD,&mpi_id); - char filename_mpi[1024]; - sprintf(filename_mpi,"%s_%d",filename,mpi_id); - sa->inf = fopen(filename_mpi,"r"); -#else // MPI - sa->inf = fopen(filename,"r"); -#endif // MPI if (sa->inf==NULL){ *warnings |= REB_INPUT_BINARY_ERROR_NOFILE; return; } - sa->filename = malloc(strlen(filename)+1); - strcpy(sa->filename,filename); // Get version fseek(sa->inf, 0, SEEK_SET); struct reb_binary_field field = {0}; sa->version = 0; double t0 = 0; + + // Cache descriptors + struct reb_binary_field_descriptor fd_header = reb_binary_field_descriptor_for_name("header"); + struct reb_binary_field_descriptor fd_t = reb_binary_field_descriptor_for_name("t"); + struct reb_binary_field_descriptor fd_sa_version = reb_binary_field_descriptor_for_name("simulationarchive_version"); + struct reb_binary_field_descriptor fd_sa_size_snapshot = reb_binary_field_descriptor_for_name("simulationarchive_size_snapshot"); + struct reb_binary_field_descriptor fd_sa_size_first = reb_binary_field_descriptor_for_name("simulationarchive_size_first"); + struct reb_binary_field_descriptor fd_sa_auto_walltime = reb_binary_field_descriptor_for_name("simulationarchive_auto_walltime"); + struct reb_binary_field_descriptor fd_sa_auto_interval = reb_binary_field_descriptor_for_name("simulationarchive_auto_interval"); + struct reb_binary_field_descriptor fd_sa_auto_step = reb_binary_field_descriptor_for_name("simulationarchive_auto_step"); + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); + + do{ fread(&field,sizeof(struct reb_binary_field),1,sa->inf); - switch (field.type){ - case REB_BINARY_FIELD_TYPE_HEADER: - //fseek(sa->inf,64 - sizeof(struct reb_binary_field),SEEK_CUR); - { - long objects = 0; - // Input header. - const long bufsize = 64 - sizeof(struct reb_binary_field); - char readbuf[bufsize], curvbuf[bufsize]; - const char* header = "REBOUND Binary File. Version: "; - sprintf(curvbuf,"%s%s",header+sizeof(struct reb_binary_field), reb_version_str); - - objects += fread(readbuf,sizeof(char),bufsize,sa->inf); - if (objects < 1){ - *warnings |= REB_INPUT_BINARY_WARNING_CORRUPTFILE; - }else{ - // Note: following compares version, but ignores githash. - if(strncmp(readbuf,curvbuf,bufsize)!=0){ - *warnings |= REB_INPUT_BINARY_WARNING_VERSION; - } - } + if (field.type == fd_header.type){ + long objects = 0; + // Input header. + const long bufsize = 64 - sizeof(struct reb_binary_field); + char readbuf[bufsize], curvbuf[bufsize]; + const char* header = "REBOUND Binary File. Version: "; + sprintf(curvbuf,"%s%s",header+sizeof(struct reb_binary_field), reb_version_str); + + objects += fread(readbuf,sizeof(char),bufsize,sa->inf); + if (objects < 1){ + *warnings |= REB_INPUT_BINARY_WARNING_CORRUPTFILE; + }else{ + // Note: following compares version, but ignores githash. + if(strncmp(readbuf,curvbuf,bufsize)!=0){ + *warnings |= REB_INPUT_BINARY_WARNING_VERSION; } - break; - case REB_BINARY_FIELD_TYPE_T: - fread(&t0, sizeof(double),1,sa->inf); - break; - case REB_BINARY_FIELD_TYPE_SAVERSION: - fread(&(sa->version), sizeof(int),1,sa->inf); - break; - case REB_BINARY_FIELD_TYPE_SASIZESNAPSHOT: - fread(&(sa->size_snapshot), sizeof(long),1,sa->inf); - break; - case REB_BINARY_FIELD_TYPE_SASIZEFIRST: - fread(&(sa->size_first), sizeof(long),1,sa->inf); - break; - case REB_BINARY_FIELD_TYPE_SAAUTOWALLTIME: - fread(&(sa->auto_walltime), sizeof(double),1,sa->inf); - break; - case REB_BINARY_FIELD_TYPE_SAAUTOINTERVAL: - fread(&(sa->auto_interval), sizeof(double),1,sa->inf); - break; - case REB_BINARY_FIELD_TYPE_SAAUTOSTEP: - fread(&(sa->auto_step), sizeof(unsigned long long),1,sa->inf); - break; - default: - fseek(sa->inf,field.size,SEEK_CUR); - break; + } + + }else if (field.type == fd_t.type){ + fread(&t0, field.size, 1, sa->inf); + }else if (field.type == fd_sa_version.type){ + fread(&(sa->version), field.size, 1, sa->inf); + }else if (field.type == fd_sa_size_snapshot.type){ + fread(&(sa->size_snapshot), field.size, 1, sa->inf); + }else if (field.type == fd_sa_size_first.type){ + fread(&(sa->size_first), field.size, 1, sa->inf); + }else if (field.type == fd_sa_auto_walltime.type){ + fread(&(sa->auto_walltime), field.size, 1, sa->inf); + }else if (field.type == fd_sa_auto_interval.type){ + fread(&(sa->auto_interval), field.size, 1, sa->inf); + }else if (field.type == fd_sa_auto_step.type){ + fread(&(sa->auto_step), field.size, 1, sa->inf); + }else{ + fseek(sa->inf,field.size,SEEK_CUR); } - }while(field.type!=REB_BINARY_FIELD_TYPE_END); + }while(field.type!=fd_end.type); // Make index if (sa->version<2){ - // Old version - if (sa->size_first==-1 || sa->size_snapshot==-1){ - free(sa->filename); - fclose(sa->inf); - *warnings |= REB_INPUT_BINARY_ERROR_OUTOFRANGE; - return; - } - fseek(sa->inf, 0, SEEK_END); - sa->nblobs = (ftell(sa->inf)-sa->size_first)/sa->size_snapshot+1; // +1 accounts for first binary - sa->t = malloc(sizeof(double)*sa->nblobs); - sa->offset64 = malloc(sizeof(uint64_t)*sa->nblobs); - sa->t[0] = t0; - sa->offset64[0] = 0; - for(long i=1;inblobs;i++){ - double offset = sa->size_first+(i-1)*sa->size_snapshot; - fseek(sa->inf, offset, SEEK_SET); - fread(&(sa->t[i]),sizeof(double), 1, sa->inf); - sa->offset64[i] = offset; - } + // Version 1 no longer supported + free(sa->filename); + fclose(sa->inf); + *warnings |= REB_INPUT_BINARY_ERROR_OLD; + return; }else{ // New version if (debug) printf("=============\n"); @@ -348,6 +184,9 @@ void reb_read_simulationarchive_with_messages(struct reb_simulationarchive* sa, fseek(sa->inf, 0, SEEK_SET); sa->nblobs = 0; int read_error = 0; + struct reb_binary_field_descriptor fd_header = reb_binary_field_descriptor_for_name("header"); + struct reb_binary_field_descriptor fd_t = reb_binary_field_descriptor_for_name("t"); + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); for(long i=0;ioffset64[i] = ftell(sa->inf); @@ -355,40 +194,27 @@ void reb_read_simulationarchive_with_messages(struct reb_simulationarchive* sa, do{ size_t r1 = fread(&field,sizeof(struct reb_binary_field),1,sa->inf); if (r1==1){ - switch (field.type){ - case REB_BINARY_FIELD_TYPE_HEADER: - { - if (debug) printf("SA Field. type=HEADER\n"); - int s1 = fseek(sa->inf,64 - sizeof(struct reb_binary_field),SEEK_CUR); - if (s1){ - read_error = 1; - } - } - break; - case REB_BINARY_FIELD_TYPE_T: - { - size_t r2 = fread(&(sa->t[i]), sizeof(double),1,sa->inf); - if (debug) printf("SA Field. type=TIME value=%.10f\n",sa->t[1]); - if (r2!=1){ - read_error = 1; - } - } - break; - case REB_BINARY_FIELD_TYPE_END: - { - if (debug) printf("SA Field. type=END =====\n"); - blob_finished = 1; - } - break; - default: - { - int s2 = fseek(sa->inf,field.size,SEEK_CUR); - if (debug) printf("SA Field. type=%-6d size=%llu\n",field.type,(unsigned long long)field.size); - if (s2){ - read_error = 1; - } - } - break; + if (field.type == fd_header.type){ + if (debug) printf("SA Field. type=HEADER\n"); + int s1 = fseek(sa->inf,64 - sizeof(struct reb_binary_field),SEEK_CUR); + if (s1){ + read_error = 1; + } + }else if (field.type == fd_t.type){ + size_t r2 = fread(&(sa->t[i]), field.size,1,sa->inf); + if (debug) printf("SA Field. type=TIME value=%.10f\n",sa->t[1]); + if (r2!=1){ + read_error = 1; + } + }else if (field.type == fd_end.type){ + if (debug) printf("SA Field. type=END =====\n"); + blob_finished = 1; + }else{ + int s2 = fseek(sa->inf,field.size,SEEK_CUR); + if (debug) printf("SA Field. type=%-6d size=%llu\n",field.type,(unsigned long long)field.size); + if (s2){ + read_error = 1; + } } }else{ read_error = 1; @@ -489,6 +315,36 @@ void reb_read_simulationarchive_with_messages(struct reb_simulationarchive* sa, } } +void reb_read_simulationarchive_with_messages(struct reb_simulationarchive* sa, const char* filename, struct reb_simulationarchive* sa_index, enum reb_input_binary_messages* warnings){ + // Somewhat complicated calls for backwards compatability. +#ifdef MPI + int initialized; + MPI_Initialized(&initialized); + if (!initialized){ + int argc = 0; + char** argv = NULL; + MPI_Init(&argc, &argv); + } + int mpi_id=0; + MPI_Comm_rank(MPI_COMM_WORLD,&mpi_id); + char filename_mpi[1024]; + sprintf(filename_mpi,"%s_%d",filename,mpi_id); + sa->inf = fopen(filename_mpi,"r"); +#else // MPI + sa->inf = fopen(filename,"r"); +#endif // MPI + sa->filename = malloc(strlen(filename)+1); + strcpy(sa->filename,filename); + reb_read_simulationarchive_from_stream_with_messages(sa, sa_index, warnings); +} + +void reb_read_simulationarchive_from_buffer_with_messages(struct reb_simulationarchive* sa, char* buf, size_t size, struct reb_simulationarchive* sa_index, enum reb_input_binary_messages* warnings){ + // Somewhat complicated calls for backwards compatability. + sa->inf = fmemopen(buf,size,"rb"); + sa->filename = NULL; + reb_read_simulationarchive_from_stream_with_messages(sa, sa_index, warnings); +} + struct reb_simulationarchive* reb_open_simulationarchive(const char* filename){ struct reb_simulationarchive* sa = malloc(sizeof(struct reb_simulationarchive)); enum reb_input_binary_messages warnings = REB_INPUT_BINARY_WARNING_NONE; @@ -518,32 +374,6 @@ void reb_free_simulationarchive_pointers(struct reb_simulationarchive* sa){ free(sa->offset64); } -static int reb_simulationarchive_snapshotsize(struct reb_simulation* const r){ - int size_snapshot = 0; - switch (r->integrator){ - case REB_INTEGRATOR_JANUS: - size_snapshot = sizeof(double)*2+sizeof(struct reb_particle_int)*r->N; - break; - case REB_INTEGRATOR_WHFAST: - case REB_INTEGRATOR_SABA: - size_snapshot = sizeof(double)*2+sizeof(double)*7*r->N; - break; - case REB_INTEGRATOR_MERCURIUS: - size_snapshot = sizeof(double)*2+sizeof(double)*8*r->N; - break; - case REB_INTEGRATOR_IAS15: - size_snapshot = sizeof(double)*4 // time, walltime, dt, dt_last_done - +sizeof(double)*3*r->N*5*7 // dp7 arrays - +sizeof(double)*7*r->N // particle m, pos, vel - +sizeof(double)*3*r->N*2; // csx, csv - break; - default: - reb_error(r,"Simulation archive not implemented for this integrator."); - break; - } - return size_snapshot; -} - void reb_simulationarchive_heartbeat(struct reb_simulation* const r){ if (r->simulationarchive_filename!=NULL){ int modes = 0; @@ -577,17 +407,12 @@ void reb_simulationarchive_heartbeat(struct reb_simulation* const r){ } } } -static inline void reb_save_dp7_old(struct reb_dp7* dp7, const int N3, FILE* of){ - fwrite(dp7->p0,sizeof(double),N3,of); - fwrite(dp7->p1,sizeof(double),N3,of); - fwrite(dp7->p2,sizeof(double),N3,of); - fwrite(dp7->p3,sizeof(double),N3,of); - fwrite(dp7->p4,sizeof(double),N3,of); - fwrite(dp7->p5,sizeof(double),N3,of); - fwrite(dp7->p6,sizeof(double),N3,of); -} void reb_simulationarchive_snapshot(struct reb_simulation* const r, const char* filename){ + if (r->simulationarchive_version<2){ + reb_error(r, "Writing SimulationArchives with version < 2 are no longer supported.\n"); + return; + } if (filename==NULL) filename = r->simulationarchive_filename; struct stat buffer; #ifdef MPI @@ -598,352 +423,270 @@ void reb_simulationarchive_snapshot(struct reb_simulation* const r, const char* if (stat(filename, &buffer) < 0){ #endif // MPI // File does not exist. Output binary. - if (r->simulationarchive_version<2){ - // Old version - r->simulationarchive_size_snapshot = reb_simulationarchive_snapshotsize(r); - } reb_output_binary(r,filename); }else{ // File exists, append snapshot. - if (r->simulationarchive_version<2){ - // Old version - FILE* of = fopen(filename,"r+"); - fseek(of, 0, SEEK_END); - fwrite(&(r->t),sizeof(double),1, of); - fwrite(&(r->walltime),sizeof(double),1, of); - switch (r->integrator){ - case REB_INTEGRATOR_JANUS: - { - fwrite(r->ri_janus.p_int,sizeof(struct reb_particle_int)*r->N,1,of); - } - break; - case REB_INTEGRATOR_WHFAST: - { - struct reb_particle* ps = r->particles; - if (r->ri_whfast.safe_mode==0){ - ps = r->ri_whfast.p_jh; - } - for(unsigned int i=0;iN;i++){ - fwrite(&(r->particles[i].m),sizeof(double),1,of); - fwrite(&(ps[i].x),sizeof(double),1,of); - fwrite(&(ps[i].y),sizeof(double),1,of); - fwrite(&(ps[i].z),sizeof(double),1,of); - fwrite(&(ps[i].vx),sizeof(double),1,of); - fwrite(&(ps[i].vy),sizeof(double),1,of); - fwrite(&(ps[i].vz),sizeof(double),1,of); - } - } - break; - case REB_INTEGRATOR_MERCURIUS: - { - struct reb_particle* ps = r->particles; - if (r->ri_mercurius.safe_mode==0){ - ps = r->ri_whfast.p_jh; - } - for(unsigned int i=0;iN;i++){ - fwrite(&(r->particles[i].m),sizeof(double),1,of); - fwrite(&(ps[i].x),sizeof(double),1,of); - fwrite(&(ps[i].y),sizeof(double),1,of); - fwrite(&(ps[i].z),sizeof(double),1,of); - fwrite(&(ps[i].vx),sizeof(double),1,of); - fwrite(&(ps[i].vy),sizeof(double),1,of); - fwrite(&(ps[i].vz),sizeof(double),1,of); - } - fwrite(r->ri_mercurius.dcrit,sizeof(double),r->N,of); - } - break; - case REB_INTEGRATOR_IAS15: - { - fwrite(&(r->dt),sizeof(double),1,of); - fwrite(&(r->dt_last_done),sizeof(double),1,of); - struct reb_particle* ps = r->particles; - const int N3 = r->N*3; - for(unsigned int i=0;iN;i++){ - fwrite(&(ps[i].m),sizeof(double),1,of); - fwrite(&(ps[i].x),sizeof(double),1,of); - fwrite(&(ps[i].y),sizeof(double),1,of); - fwrite(&(ps[i].z),sizeof(double),1,of); - fwrite(&(ps[i].vx),sizeof(double),1,of); - fwrite(&(ps[i].vy),sizeof(double),1,of); - fwrite(&(ps[i].vz),sizeof(double),1,of); - } - reb_save_dp7_old(&(r->ri_ias15.b) ,N3,of); - reb_save_dp7_old(&(r->ri_ias15.csb),N3,of); - reb_save_dp7_old(&(r->ri_ias15.e) ,N3,of); - reb_save_dp7_old(&(r->ri_ias15.br) ,N3,of); - reb_save_dp7_old(&(r->ri_ias15.er) ,N3,of); - fwrite((r->ri_ias15.csx),sizeof(double)*N3,1,of); - fwrite((r->ri_ias15.csv),sizeof(double)*N3,1,of); - } - break; - default: - reb_error(r,"Simulation archive not implemented for this integrator."); - break; + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); + if (r->simulationarchive_version<3){ // duplicate for working with old files. Will be removed in future release + // Create buffer containing original binary file + FILE* of = fopen(filename,"r+b"); + fseek(of, 64, SEEK_SET); // Header + struct reb_binary_field field = {0}; + struct reb_simulationarchive_blob16 blob = {0}; + int bytesread; + do{ + bytesread = fread(&field,sizeof(struct reb_binary_field),1,of); + fseek(of, field.size, SEEK_CUR); + }while(field.type!=fd_end.type && bytesread); + long size_old = ftell(of); + if (bytesread!=1){ + reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); + return; } - fclose(of); - }else{ - // New version with incremental outputs - if (r->simulationarchive_version<3){ // duplicate for working with old files. Will be removed in future release - // Create buffer containing original binary file - FILE* of = fopen(filename,"r+b"); - fseek(of, 64, SEEK_SET); // Header - struct reb_binary_field field = {0}; - struct reb_simulationarchive_blob16 blob = {0}; - int bytesread; - do{ - bytesread = fread(&field,sizeof(struct reb_binary_field),1,of); - fseek(of, field.size, SEEK_CUR); - }while(field.type!=REB_BINARY_FIELD_TYPE_END && bytesread); - long size_old = ftell(of); - if (bytesread!=1){ - reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); - return; - } - - bytesread = fread(&blob,sizeof(struct reb_simulationarchive_blob16),1,of); - if (bytesread!=1){ - reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); - return; - } - int archive_contains_more_than_one_blob = 0; - if (blob.offset_next>0){ - archive_contains_more_than_one_blob = 1; - } - - char* buf_old = malloc(size_old); - fseek(of, 0, SEEK_SET); - fread(buf_old, size_old,1,of); - - // Create buffer containing current binary file - char* buf_new; - size_t size_new; - reb_output_binary_to_stream(r, &buf_new, &size_new); - - // Create buffer containing diff - char* buf_diff; - size_t size_diff; - reb_binary_diff(buf_old, size_old, buf_new, size_new, &buf_diff, &size_diff); - - int file_corrupt = 0; - int seek_ok = fseek(of, -sizeof(struct reb_simulationarchive_blob16), SEEK_END); - int blobs_read = fread(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); - if (seek_ok !=0 || blobs_read != 1){ // cannot read blob + bytesread = fread(&blob,sizeof(struct reb_simulationarchive_blob16),1,of); + if (bytesread!=1){ + reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); + return; + } + int archive_contains_more_than_one_blob = 0; + if (blob.offset_next>0){ + archive_contains_more_than_one_blob = 1; + } + + char* buf_old = malloc(size_old); + fseek(of, 0, SEEK_SET); + fread(buf_old, size_old,1,of); + + // Create buffer containing current binary file + char* buf_new; + size_t size_new; + reb_output_binary_to_stream(r, &buf_new, &size_new); + + // Create buffer containing diff + char* buf_diff; + size_t size_diff; + reb_binary_diff(buf_old, size_old, buf_new, size_new, &buf_diff, &size_diff); + + int file_corrupt = 0; + int seek_ok = fseek(of, -sizeof(struct reb_simulationarchive_blob16), SEEK_END); + int blobs_read = fread(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); + if (seek_ok !=0 || blobs_read != 1){ // cannot read blob + file_corrupt = 1; + } + if ( (archive_contains_more_than_one_blob && blob.offset_prev <=0) || blob.offset_next != 0){ // blob contains unexpected data. Note: First blob is all zeros. + file_corrupt = 1; + } + if (file_corrupt==0 && archive_contains_more_than_one_blob ){ + // Check if last two blobs are consistent. + seek_ok = fseek(of, - sizeof(struct reb_simulationarchive_blob16) - sizeof(struct reb_binary_field), SEEK_CUR); + bytesread = fread(&field, sizeof(struct reb_binary_field), 1, of); + if (seek_ok!=0 || bytesread!=1){ + file_corrupt = 1; + } + if (field.type != fd_end.type || field.size !=0){ + // expected an END field file_corrupt = 1; } - if ( (archive_contains_more_than_one_blob && blob.offset_prev <=0) || blob.offset_next != 0){ // blob contains unexpected data. Note: First blob is all zeros. + seek_ok = fseek(of, -blob.offset_prev - sizeof(struct reb_simulationarchive_blob16), SEEK_CUR); + struct reb_simulationarchive_blob16 blob2 = {0}; + blobs_read = fread(&blob2, sizeof(struct reb_simulationarchive_blob16), 1, of); + if (seek_ok!=0 || blobs_read!=1 || blob2.offset_next != blob.offset_prev){ file_corrupt = 1; } - if (file_corrupt==0 && archive_contains_more_than_one_blob ){ - // Check if last two blobs are consistent. - seek_ok = fseek(of, - sizeof(struct reb_simulationarchive_blob16) - sizeof(struct reb_binary_field), SEEK_CUR); + } + + if (file_corrupt){ + // Find last valid snapshot to allow for restarting and appending to archives where last snapshot was cut off + reb_warning(r, "SimulationArchive appears to be corrupted. REBOUND will attempt to fix it before appending more snapshots.\n"); + int seek_ok; + seek_ok = fseek(of, size_old, SEEK_SET); + long last_blob = size_old + sizeof(struct reb_simulationarchive_blob16); + struct reb_binary_field_descriptor fd_end = reb_binary_field_descriptor_for_name("end"); + do + { + seek_ok = fseek(of, -sizeof(struct reb_binary_field), SEEK_CUR); + if (seek_ok != 0){ + break; + } bytesread = fread(&field, sizeof(struct reb_binary_field), 1, of); - if (seek_ok!=0 || bytesread!=1){ - file_corrupt = 1; + if (bytesread != 1 || field.type != fd_end.type){ // could be EOF or corrupt snapshot + break; } - if (field.type != REB_BINARY_FIELD_TYPE_END || field.size !=0){ - // expected an END field - file_corrupt = 1; + bytesread = fread(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); + if (bytesread != 1){ + break; } - seek_ok = fseek(of, -blob.offset_prev - sizeof(struct reb_simulationarchive_blob16), SEEK_CUR); - struct reb_simulationarchive_blob16 blob2 = {0}; - blobs_read = fread(&blob2, sizeof(struct reb_simulationarchive_blob16), 1, of); - if (seek_ok!=0 || blobs_read!=1 || blob2.offset_next != blob.offset_prev){ - file_corrupt = 1; + last_blob = ftell(of); + if (blob.offset_next>0){ + seek_ok = fseek(of, blob.offset_next, SEEK_CUR); + }else{ + break; } - } + if (seek_ok != 0){ + break; + } + } while(1); - if (file_corrupt){ - // Find last valid snapshot to allow for restarting and appending to archives where last snapshot was cut off - reb_warning(r, "SimulationArchive appears to be corrupted. REBOUND will attempt to fix it before appending more snapshots.\n"); - int seek_ok; - seek_ok = fseek(of, size_old, SEEK_SET); - long last_blob = size_old + sizeof(struct reb_simulationarchive_blob16); - do - { - seek_ok = fseek(of, -sizeof(struct reb_binary_field), SEEK_CUR); - if (seek_ok != 0){ - break; - } - bytesread = fread(&field, sizeof(struct reb_binary_field), 1, of); - if (bytesread != 1 || field.type != REB_BINARY_FIELD_TYPE_END){ // could be EOF or corrupt snapshot - break; - } - bytesread = fread(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); - if (bytesread != 1){ - break; - } - last_blob = ftell(of); - if (blob.offset_next>0){ - seek_ok = fseek(of, blob.offset_next, SEEK_CUR); - }else{ - break; - } - if (seek_ok != 0){ - break; - } - } while(1); + // To append diff, seek to last valid location (=EOF if all snapshots valid) + fseek(of, last_blob, SEEK_SET); + }else{ + // File is not corrupt. Start at end to save time. + fseek(of, 0, SEEK_END); + } - // To append diff, seek to last valid location (=EOF if all snapshots valid) - fseek(of, last_blob, SEEK_SET); - }else{ - // File is not corrupt. Start at end to save time. - fseek(of, 0, SEEK_END); - } + // Update blob info and Write diff to binary file + fseek(of, -sizeof(struct reb_simulationarchive_blob16), SEEK_CUR); + fread(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); + blob.offset_next = size_diff+sizeof(struct reb_binary_field); + fseek(of, -sizeof(struct reb_simulationarchive_blob16), SEEK_CUR); + fwrite(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); + fwrite(buf_diff, size_diff, 1, of); + field.type = fd_end.type; + field.size = 0; + fwrite(&field,sizeof(struct reb_binary_field), 1, of); + blob.index++; + blob.offset_prev = blob.offset_next; + blob.offset_next = 0; + fwrite(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); - // Update blob info and Write diff to binary file - fseek(of, -sizeof(struct reb_simulationarchive_blob16), SEEK_CUR); - fread(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); - blob.offset_next = size_diff+sizeof(struct reb_binary_field); - fseek(of, -sizeof(struct reb_simulationarchive_blob16), SEEK_CUR); - fwrite(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); - fwrite(buf_diff, size_diff, 1, of); - field.type = REB_BINARY_FIELD_TYPE_END; - field.size = 0; - fwrite(&field,sizeof(struct reb_binary_field), 1, of); - blob.index++; - blob.offset_prev = blob.offset_next; - blob.offset_next = 0; - fwrite(&blob, sizeof(struct reb_simulationarchive_blob16), 1, of); - - fclose(of); - free(buf_new); - free(buf_old); - free(buf_diff); - }else{ // Duplicate (version 3 of SimulationArchive. This is the part that will remain. Above duplicate will be removed in future release. - // Create buffer containing original binary file + fclose(of); + free(buf_new); + free(buf_old); + free(buf_diff); + }else{ // Duplicate (version 3 of SimulationArchive. This is the part that will remain. Above duplicate will be removed in future release. + // Create buffer containing original binary file #ifdef MPI - char filename_mpi[1024]; - sprintf(filename_mpi,"%s_%d",filename,r->mpi_id); - FILE* of = fopen(filename_mpi,"r+b"); + char filename_mpi[1024]; + sprintf(filename_mpi,"%s_%d",filename,r->mpi_id); + FILE* of = fopen(filename_mpi,"r+b"); #else // MPI - FILE* of = fopen(filename,"r+b"); + FILE* of = fopen(filename,"r+b"); #endif // MPI - fseek(of, 64, SEEK_SET); // Header - struct reb_binary_field field = {0}; - struct reb_simulationarchive_blob blob = {0}; - int bytesread; - do{ - bytesread = fread(&field,sizeof(struct reb_binary_field),1,of); - fseek(of, field.size, SEEK_CUR); - }while(field.type!=REB_BINARY_FIELD_TYPE_END && bytesread); - long size_old = ftell(of); - if (bytesread!=1){ - reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); - return; - } - - bytesread = fread(&blob,sizeof(struct reb_simulationarchive_blob),1,of); - if (bytesread!=1){ - reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); - return; - } - int archive_contains_more_than_one_blob = 0; - if (blob.offset_next>0){ - archive_contains_more_than_one_blob = 1; - } + fseek(of, 64, SEEK_SET); // Header + struct reb_binary_field field = {0}; + struct reb_simulationarchive_blob blob = {0}; + int bytesread; + do{ + bytesread = fread(&field,sizeof(struct reb_binary_field),1,of); + fseek(of, field.size, SEEK_CUR); + }while(field.type!=fd_end.type && bytesread); + long size_old = ftell(of); + if (bytesread!=1){ + reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); + return; + } + + bytesread = fread(&blob,sizeof(struct reb_simulationarchive_blob),1,of); + if (bytesread!=1){ + reb_warning(r, "SimulationArchive appears to be corrupted. A recovery attempt has failed. No snapshot has been saved.\n"); + return; + } + int archive_contains_more_than_one_blob = 0; + if (blob.offset_next>0){ + archive_contains_more_than_one_blob = 1; + } + + + char* buf_old = malloc(size_old); + fseek(of, 0, SEEK_SET); + fread(buf_old, size_old,1,of); - - char* buf_old = malloc(size_old); - fseek(of, 0, SEEK_SET); - fread(buf_old, size_old,1,of); - - // Create buffer containing current binary file - char* buf_new; - size_t size_new; - reb_output_binary_to_stream(r, &buf_new, &size_new); - - // Create buffer containing diff - char* buf_diff; - size_t size_diff; - reb_binary_diff(buf_old, size_old, buf_new, size_new, &buf_diff, &size_diff); - - int file_corrupt = 0; - int seek_ok = fseek(of, -sizeof(struct reb_simulationarchive_blob), SEEK_END); - int blobs_read = fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); - if (seek_ok !=0 || blobs_read != 1){ // cannot read blob + // Create buffer containing current binary file + char* buf_new; + size_t size_new; + reb_output_binary_to_stream(r, &buf_new, &size_new); + + // Create buffer containing diff + char* buf_diff; + size_t size_diff; + reb_binary_diff(buf_old, size_old, buf_new, size_new, &buf_diff, &size_diff); + + int file_corrupt = 0; + int seek_ok = fseek(of, -sizeof(struct reb_simulationarchive_blob), SEEK_END); + int blobs_read = fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); + if (seek_ok !=0 || blobs_read != 1){ // cannot read blob + file_corrupt = 1; + } + if ( (archive_contains_more_than_one_blob && blob.offset_prev <=0) || blob.offset_next != 0){ // blob contains unexpected data. Note: First blob is all zeros. + file_corrupt = 1; + } + if (file_corrupt==0 && archive_contains_more_than_one_blob ){ + // Check if last two blobs are consistent. + seek_ok = fseek(of, - sizeof(struct reb_simulationarchive_blob) - sizeof(struct reb_binary_field), SEEK_CUR); + bytesread = fread(&field, sizeof(struct reb_binary_field), 1, of); + if (seek_ok!=0 || bytesread!=1){ + file_corrupt = 1; + } + if (field.type != fd_end.type || field.size !=0){ + // expected an END field file_corrupt = 1; } - if ( (archive_contains_more_than_one_blob && blob.offset_prev <=0) || blob.offset_next != 0){ // blob contains unexpected data. Note: First blob is all zeros. + seek_ok = fseek(of, -blob.offset_prev - sizeof(struct reb_simulationarchive_blob), SEEK_CUR); + struct reb_simulationarchive_blob blob2 = {0}; + blobs_read = fread(&blob2, sizeof(struct reb_simulationarchive_blob), 1, of); + if (seek_ok!=0 || blobs_read!=1 || blob2.offset_next != blob.offset_prev){ file_corrupt = 1; } - if (file_corrupt==0 && archive_contains_more_than_one_blob ){ - // Check if last two blobs are consistent. - seek_ok = fseek(of, - sizeof(struct reb_simulationarchive_blob) - sizeof(struct reb_binary_field), SEEK_CUR); + } + + if (file_corrupt){ + // Find last valid snapshot to allow for restarting and appending to archives where last snapshot was cut off + reb_warning(r, "SimulationArchive appears to be corrupted. REBOUND will attempt to fix it before appending more snapshots.\n"); + int seek_ok; + seek_ok = fseek(of, size_old, SEEK_SET); + long last_blob = size_old + sizeof(struct reb_simulationarchive_blob); + do + { + seek_ok = fseek(of, -sizeof(struct reb_binary_field), SEEK_CUR); + if (seek_ok != 0){ + break; + } bytesread = fread(&field, sizeof(struct reb_binary_field), 1, of); - if (seek_ok!=0 || bytesread!=1){ - file_corrupt = 1; + if (bytesread != 1 || field.type != fd_end.type){ // could be EOF or corrupt snapshot + break; } - if (field.type != REB_BINARY_FIELD_TYPE_END || field.size !=0){ - // expected an END field - file_corrupt = 1; + bytesread = fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); + if (bytesread != 1){ + break; } - seek_ok = fseek(of, -blob.offset_prev - sizeof(struct reb_simulationarchive_blob), SEEK_CUR); - struct reb_simulationarchive_blob blob2 = {0}; - blobs_read = fread(&blob2, sizeof(struct reb_simulationarchive_blob), 1, of); - if (seek_ok!=0 || blobs_read!=1 || blob2.offset_next != blob.offset_prev){ - file_corrupt = 1; + last_blob = ftell(of); + if (blob.offset_next>0){ + seek_ok = fseek(of, blob.offset_next, SEEK_CUR); + }else{ + break; } - } + if (seek_ok != 0){ + break; + } + } while(1); - if (file_corrupt){ - // Find last valid snapshot to allow for restarting and appending to archives where last snapshot was cut off - reb_warning(r, "SimulationArchive appears to be corrupted. REBOUND will attempt to fix it before appending more snapshots.\n"); - int seek_ok; - seek_ok = fseek(of, size_old, SEEK_SET); - long last_blob = size_old + sizeof(struct reb_simulationarchive_blob); - do - { - seek_ok = fseek(of, -sizeof(struct reb_binary_field), SEEK_CUR); - if (seek_ok != 0){ - break; - } - bytesread = fread(&field, sizeof(struct reb_binary_field), 1, of); - if (bytesread != 1 || field.type != REB_BINARY_FIELD_TYPE_END){ // could be EOF or corrupt snapshot - break; - } - bytesread = fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); - if (bytesread != 1){ - break; - } - last_blob = ftell(of); - if (blob.offset_next>0){ - seek_ok = fseek(of, blob.offset_next, SEEK_CUR); - }else{ - break; - } - if (seek_ok != 0){ - break; - } - } while(1); + // To append diff, seek to last valid location (=EOF if all snapshots valid) + fseek(of, last_blob, SEEK_SET); + }else{ + // File is not corrupt. Start at end to save time. + fseek(of, 0, SEEK_END); + } - // To append diff, seek to last valid location (=EOF if all snapshots valid) - fseek(of, last_blob, SEEK_SET); - }else{ - // File is not corrupt. Start at end to save time. - fseek(of, 0, SEEK_END); - } + // Update blob info and Write diff to binary file + fseek(of, -sizeof(struct reb_simulationarchive_blob), SEEK_CUR); + fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); + blob.offset_next = size_diff+sizeof(struct reb_binary_field); + fseek(of, -sizeof(struct reb_simulationarchive_blob), SEEK_CUR); + fwrite(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); + fwrite(buf_diff, size_diff, 1, of); + field.type = fd_end.type; + field.size = 0; + fwrite(&field,sizeof(struct reb_binary_field), 1, of); + blob.index++; + blob.offset_prev = blob.offset_next; + blob.offset_next = 0; + fwrite(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); - // Update blob info and Write diff to binary file - fseek(of, -sizeof(struct reb_simulationarchive_blob), SEEK_CUR); - fread(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); - blob.offset_next = size_diff+sizeof(struct reb_binary_field); - fseek(of, -sizeof(struct reb_simulationarchive_blob), SEEK_CUR); - fwrite(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); - fwrite(buf_diff, size_diff, 1, of); - field.type = REB_BINARY_FIELD_TYPE_END; - field.size = 0; - fwrite(&field,sizeof(struct reb_binary_field), 1, of); - blob.index++; - blob.offset_prev = blob.offset_next; - blob.offset_next = 0; - fwrite(&blob, sizeof(struct reb_simulationarchive_blob), 1, of); - - fclose(of); - free(buf_new); - free(buf_old); - free(buf_diff); - } + fclose(of); + free(buf_new); + free(buf_old); + free(buf_diff); } } }