diff --git a/examples/rmvs_swifter_comparison/1pl_1tp_encounter/swiftest_vs_swifter.ipynb b/examples/rmvs_swifter_comparison/1pl_1tp_encounter/swiftest_vs_swifter.ipynb index 52568fd84..98b32fc30 100644 --- a/examples/rmvs_swifter_comparison/1pl_1tp_encounter/swiftest_vs_swifter.ipynb +++ b/examples/rmvs_swifter_comparison/1pl_1tp_encounter/swiftest_vs_swifter.ipynb @@ -81,8 +81,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 6, diff --git a/examples/whm_gr_test/init_cond.py b/examples/whm_gr_test/init_cond.py index 57b0fb534..8d197c6f4 100755 --- a/examples/whm_gr_test/init_cond.py +++ b/examples/whm_gr_test/init_cond.py @@ -13,7 +13,7 @@ sim.param['DU2M'] = swiftest.AU2M sim.param['T0'] = 0.0 sim.param['DT'] = 0.25 * swiftest.JD2S / swiftest.YR2S -sim.param['TSTOP'] = 100.0 +sim.param['TSTOP'] = 1000.0 sim.param['ISTEP_OUT'] = 1461 sim.param['ISTEP_DUMP'] = 1461 sim.param['CHK_QMIN_COORD'] = "HELIO" diff --git a/examples/whm_gr_test/param.swifter.in b/examples/whm_gr_test/param.swifter.in index 6addd694c..789250f41 100644 --- a/examples/whm_gr_test/param.swifter.in +++ b/examples/whm_gr_test/param.swifter.in @@ -1,6 +1,6 @@ ! VERSION Swifter parameter file converted from Swiftest T0 0.0 -TSTOP 100.0 +TSTOP 1000.0 DT 0.0006844626967830253 ISTEP_OUT 1461 ISTEP_DUMP 1461 diff --git a/examples/whm_gr_test/param.swiftest.in b/examples/whm_gr_test/param.swiftest.in index c9b7462f0..ace6f3cad 100644 --- a/examples/whm_gr_test/param.swiftest.in +++ b/examples/whm_gr_test/param.swiftest.in @@ -1,6 +1,6 @@ ! VERSION Swiftest parameter input T0 0.0 -TSTOP 100.0 +TSTOP 1000.0 DT 0.0006844626967830253 ISTEP_OUT 1461 ISTEP_DUMP 1461 diff --git a/examples/whm_gr_test/pl.swifter.in b/examples/whm_gr_test/pl.swifter.in index e0ef4e881..782e57140 100644 --- a/examples/whm_gr_test/pl.swifter.in +++ b/examples/whm_gr_test/pl.swifter.in @@ -2,35 +2,35 @@ 0 39.476926408897625196 0.0 0.0 0.0 0.0 0.0 0.0 -1 6.5537098095653139645e-06 0.0014751243077781048702 +1 6.5537098095653139645e-06 0.0014751234419554511911 1.6306381826061645943e-05 -0.33206272695596028566 0.07436707001147663254 -0.02438290851908785084 --4.2340114788918336805 10.486553514018327622 1.2453138107251555947 -2 9.663313399581537916e-05 0.006759104275397271956 +0.13267502226188271353 0.2786606257975073886 0.010601098875389479426 +-11.331978934667442676 4.8184460126705647045 1.4332264599878684131 +2 9.663313399581537916e-05 0.00675908960945781479 4.0453784346544178454e-05 --0.7188115337296047125 -0.0118554711069603201795 0.041316403191083782287 -0.07826338813583945357 -7.419533988988633545 -0.10634201014368884618 -3 0.000120026935827952453094 0.010044787321379672528 +-0.69398700025820403425 -0.19235393648106968723 0.03740673057980103272 +1.9245789988923785786 -7.1528261190002948057 -0.20922405362759749996 +3 0.000120026935827952453094 0.010044837538502923644 4.25875607065040958e-05 -0.35677088372527121507 -0.95189300879814897627 4.4027442504036787155e-05 -5.7819217550992820422 2.18192814489641851 -0.00012230072278352209966 -4 1.2739802010675941456e-05 0.007246743835971885302 +0.49463573470256239073 -0.8874896493821613497 4.051630875713834232e-05 +5.386704768180099809 3.0357508899436080915 -0.00016218409216515533796 +4 1.2739802010675941456e-05 0.0072467236860282326973 2.265740805092889601e-05 --1.5233712071242269115 0.6723825347339112968 0.051459143378398922164 --1.8728417739956807141 -4.239719661832373223 -0.042909557750301418264 -5 0.037692251088985676735 0.35527126534549128905 +-1.5655322071100350456 0.56626121192188216824 0.050269397991054412533 +-1.5477080637857006753 -4.370087697214287981 -0.05361768768801557225 +5 0.037692251088985676735 0.35527094075555771578 0.00046732617030490929307 -4.049944927347420176 -2.9910878677758190314 -0.078187280837353656526 -1.6060801375519682711 2.349356876761497338 -0.045690062807172619064 -6 0.011285899820091272997 0.4376527512949726007 +4.0891378954287338487 -2.9329188614380639066 -0.07930573161132697946 +1.575024788882753283 2.3719591091996699917 -0.045089307261129988257 +6 0.011285899820091272997 0.43765464106459166412 0.00038925687730393611812 -6.298929503477405767 -7.706413024510769816 -0.11669919842191249504 -1.4661378456572359413 1.2872251175075805794 -0.08070991686100478242 -7 0.0017236589478267730203 0.4695362423191493196 +6.3349788609660162564 -7.674600716671800882 -0.11868650931385750502 +1.4598618704191345578 1.2948691245181617393 -0.080593167691228835176 +7 0.0017236589478267730203 0.46956055286931676728 0.00016953449859497231466 -14.856082147529010129 13.007589275314199284 -0.14417795763685259391 --0.9554310497290159123 1.0161753499437922057 0.016099529164307530124 -8 0.0020336100526728302319 0.7812870996943599397 +14.832516206189200858 13.032608531076540714 -0.14378102535616668622 +-0.9573374666934839659 1.014553546383260322 0.016118112341773867214 +8 0.0020336100526728302319 0.7813163071687303693 0.000164587904124493665 -29.55744967800954015 -4.629377558152945049 -0.58590957207831262377 -0.17162147939801157335 1.1422848961108499101 -0.027445465472921385952 +29.561664938083289655 -4.6012285192418387325 -0.586585578731106283 +0.17051705220469790965 1.1424784769020628332 -0.027423757798549895085 diff --git a/examples/whm_gr_test/pl.swiftest.in b/examples/whm_gr_test/pl.swiftest.in index 9d49cc3da..10d425453 100644 --- a/examples/whm_gr_test/pl.swiftest.in +++ b/examples/whm_gr_test/pl.swiftest.in @@ -1,33 +1,33 @@ 8 1 6.5537098095653139645e-06 1.6306381826061645943e-05 -0.33206272695596028566 0.07436707001147663254 -0.02438290851908785084 --4.2340114788918336805 10.486553514018327622 1.2453138107251555947 +0.13267502226188271353 0.2786606257975073886 0.010601098875389479426 +-11.331978934667442676 4.8184460126705647045 1.4332264599878684131 2 9.663313399581537916e-05 4.0453784346544178454e-05 --0.7188115337296047125 -0.0118554711069603201795 0.041316403191083782287 -0.07826338813583945357 -7.419533988988633545 -0.10634201014368884618 +-0.69398700025820403425 -0.19235393648106968723 0.03740673057980103272 +1.9245789988923785786 -7.1528261190002948057 -0.20922405362759749996 3 0.000120026935827952453094 4.25875607065040958e-05 -0.35677088372527121507 -0.95189300879814897627 4.4027442504036787155e-05 -5.7819217550992820422 2.18192814489641851 -0.00012230072278352209966 +0.49463573470256239073 -0.8874896493821613497 4.051630875713834232e-05 +5.386704768180099809 3.0357508899436080915 -0.00016218409216515533796 4 1.2739802010675941456e-05 2.265740805092889601e-05 --1.5233712071242269115 0.6723825347339112968 0.051459143378398922164 --1.8728417739956807141 -4.239719661832373223 -0.042909557750301418264 +-1.5655322071100350456 0.56626121192188216824 0.050269397991054412533 +-1.5477080637857006753 -4.370087697214287981 -0.05361768768801557225 5 0.037692251088985676735 0.00046732617030490929307 -4.049944927347420176 -2.9910878677758190314 -0.078187280837353656526 -1.6060801375519682711 2.349356876761497338 -0.045690062807172619064 +4.0891378954287338487 -2.9329188614380639066 -0.07930573161132697946 +1.575024788882753283 2.3719591091996699917 -0.045089307261129988257 6 0.011285899820091272997 0.00038925687730393611812 -6.298929503477405767 -7.706413024510769816 -0.11669919842191249504 -1.4661378456572359413 1.2872251175075805794 -0.08070991686100478242 +6.3349788609660162564 -7.674600716671800882 -0.11868650931385750502 +1.4598618704191345578 1.2948691245181617393 -0.080593167691228835176 7 0.0017236589478267730203 0.00016953449859497231466 -14.856082147529010129 13.007589275314199284 -0.14417795763685259391 --0.9554310497290159123 1.0161753499437922057 0.016099529164307530124 +14.832516206189200858 13.032608531076540714 -0.14378102535616668622 +-0.9573374666934839659 1.014553546383260322 0.016118112341773867214 8 0.0020336100526728302319 0.000164587904124493665 -29.55744967800954015 -4.629377558152945049 -0.58590957207831262377 -0.17162147939801157335 1.1422848961108499101 -0.027445465472921385952 +29.561664938083289655 -4.6012285192418387325 -0.586585578731106283 +0.17051705220469790965 1.1424784769020628332 -0.027423757798549895085 diff --git a/examples/whm_gr_test/swiftest_relativity.ipynb b/examples/whm_gr_test/swiftest_relativity.ipynb index 0d8111fea..53c4e5453 100644 --- a/examples/whm_gr_test/swiftest_relativity.ipynb +++ b/examples/whm_gr_test/swiftest_relativity.ipynb @@ -22,9 +22,9 @@ "output_type": "stream", "text": [ "Reading Swifter file param.swifter.in\n", - "Reading in time 1.000e+02\n", + "Reading in time 1.000e+03\n", "Creating Dataset\n", - "Successfully converted 101 output frames.\n", + "Successfully converted 1001 output frames.\n", "Swifter simulation data stored as xarray DataSet .ds\n" ] } @@ -45,9 +45,9 @@ "output_type": "stream", "text": [ "Reading Swiftest file param.swiftest.in\n", - "Reading in time 1.000e+02\n", + "Reading in time 1.000e+03\n", "Creating Dataset\n", - "Successfully converted 101 output frames.\n", + "Successfully converted 1001 output frames.\n", "Swiftest simulation data stored as xarray DataSet .ds\n" ] } @@ -70,12 +70,12 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "obj = Horizons(id='1', id_type='majorbody',location='@sun',\n", - " epochs={'start':'2021-01-28', 'stop':'2121-02-05',\n", + " epochs={'start':'2021-01-28', 'stop':'3021-02-05',\n", " 'step':'1y'})\n", "el = obj.elements()\n", "t = (el['datetime_jd']-el['datetime_jd'][0]) / 365.25\n", @@ -84,7 +84,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -95,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -106,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -114,17 +114,17 @@ "output_type": "stream", "text": [ "Mean precession rate for Mercury long. peri. (arcsec/100 y)\n", - "JPL Horizons : 573.8351991142854\n", - "Swifter GR : 579.5897815748845\n", - "Swiftest GR : 579.5897815748845\n", - "Obs - Swifter : -5.754582460598964\n", - "Obs - Swiftest : -5.754582460598964\n", - "Swiftest - Swifter: 0.0\n" + "JPL Horizons : 571.3210506300043\n", + "Swifter GR : 571.6183105524942\n", + "Swiftest GR : 571.6183105392645\n", + "Obs - Swifter : -0.2972599224899675\n", + "Obs - Swiftest : -0.29725990926022927\n", + "Swiftest - Swifter: -1.3229737305664457e-08\n" ] }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYwAAAEGCAYAAAB2EqL0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAA4zklEQVR4nO3deZxN9f/A8df7zm4XWiRbi2JiMLasocUQkUKUJSEtaNW3UvmmVCpaJHtFKHvKksj2k2VQCIksg6+yxixmue/fH/fSGIN7mZkzy/v5eNyHez73fM55f64xb+fzOefzEVXFGGOMuRiX0wEYY4zJGSxhGGOM8YklDGOMMT6xhGGMMcYnljCMMcb4JNDpADJT8eLFtWzZsk6HYYwxOUZ0dPQhVS2R3me5OmGULVuWtWvXOh2GMcbkGCKy+3yfWZeUMcYYn1jCMMYY4xNLGMYYY3ySq8cw0pOUlERMTAwJCQlOh5LnhIaGUqpUKYKCgpwOxRhzCfJcwoiJiaFgwYKULVsWEXE6nDxDVTl8+DAxMTGUK1fO6XCMMZcgz3VJJSQkUKxYMUsWWUxEKFasmF3ZGZOD5bmEAViycIh978bkbHkyYRhjTG419cdPeGviI7hTUjL82JYwHFCgQAF27dpFWFgYERERVKxYkV69euF2u9m1axfh4eEXrP/aa68xZMiQs8rKli3LoUOH/IojKiqKY8eO+Ru+MSYbSjx1gj7jGvB6zAgWx6/i+MkjGX6OPDfonZ1cf/31bNiwgeTkZBo3bszMmTOpVq1app9XVVFVvv/++0w/lzEm801ZMIRvd03il5BEap4sStd6L1G0cLqze1wWu8LIBgIDA7ntttv4448/MuR477//PuHh4YSHhzN06FAAdu3axS233ELv3r2pVq0ae/fuPXNVMmLECCIiIoiIiKBcuXLcfvvtAEyaNIlbb72V8PBwXnjhhTPHL1CgAC+99BJVqlShdu3aHDx4EIBvvvmG8PBwqlSpQoMGDTKkLcaY8/v9z9X0HlOPNw58zi8hiTRJLMnwnoupV+WuTDlfnr7CeP3bzfy2/58MPWbFkoV49Z5KftWJi4vjxx9/ZODAgT7X+eCDD5gwYcKZ7f379wMQHR3NuHHjWLVqFapKrVq1aNiwIUWLFmXbtm2MGzeO4cOHn3WsXr160atXL5KSkmjcuDFPP/00+/fv54UXXiA6OpqiRYty5513MnPmTO69915iY2OpXbs2gwYN4vnnn2fUqFG8/PLLDBw4kPnz53PttddaV5cxmcidksyS9bN5c8MADgZC5LGreKLpM1S75W7ElXnXAXaF4aAdO3YQERFB3bp1ad68Oc2aNfO5br9+/diwYcOZV8mSJQFYvnw5rVu3Jn/+/BQoUIA2bdqwbNkyAMqUKUPt2rXPe8w+ffrQuHFj7rnnHtasWUOjRo0oUaIEgYGBdOzYkaVLlwIQHBxMixYtAKhevTq7du0CoG7dunTp0oVRo0aRkgkDbsYYWPnrAjqNrcFTm1/lf0FCj4JteLPLHKpXisrUZAF5/ArD3yuBjHZ6DCMjqep5P8ufP/95Pxs/fjy7d+/m448/vuhxgoKCztwiGxAQQHJyMgAjRoxg1apVfPfdd0RERLBhwwaKFSt2Kc0wxqSRnJTA7GXjeXXvJxAMNWMLc3vZunSK8r1n4nLZFUYu06BBA2bOnElcXByxsbHMmDGD+vXrX7BOdHQ0Q4YMYcKECbi8/0OpVasWS5Ys4dChQ6SkpDBp0iQaNmx4wePs2LGDWrVqMXDgQIoXL87evXszrF3G5FWqyvYdC6k3oTqv7v2EQFUecN3DGx1/oFPU21kaS5ZdYYhIBWBKqqLywABgMTACKADsAjqq6jkDCyJyNzAMCABGq+rgzI45MyQnJxMSEnLBfbZt20apUqXObH/wwQfcf//9Ph2/WrVqdOnShZo1awLQvXt3qlateqbbKD0ff/wxR44cOTPYHRkZyejRo3nrrbe4/fbbUVWioqJo1arVBc/93HPPsX37dlSVJk2aUKVKFZ9iNsac39OjmrMwZC+4XFSJDeOBit1o2aiXI7HIhboeMu2kIgHAPqAWMBV4VlWXiEg3oJyqvpLO/r8DdwAxwBqgg6r+dqHzREZGatoFlLZs2cItt9ySYW3x1y+//MKjjz7K6tWrHYvBSU5//8bkFJ/O6MHsw/9HTJAQqMp9AbV5qdOoTJ8xQUSiVTUyvc+cGsNoAuxQ1d3eK4+l3vIfgPnAK2n2rwn8oao7AURkMtAKuGDCyG5GjBjBhx9+eOZWV2OMSWvnnrV8OO8VfgyJgSCh5vGreKfrTIoVLOB0aI4ljPbAJO/7TUBLYBZwP3BdOvtfC6TuEI/Bc3VyDhHpAfQAKF26dAaFmzFO375qjDFpJSenMO67Vxl9ZAZxIS4CVHnvlte4rWprwoIDnA4PcGDQW0SC8SSIb7xF3YDHRSQaKAgkplctnbJ0+9JUdaSqRqpqZIkSGf+kozHGZLSt2+fz3PgoPjw2iziXizvjazOl/jCa1GqbbZIFOHOF0QxYp6oHAVR1K3AngIjcBDRPp04MZ195lAL2Z3KcxhiTqZJT3Gza9j1dVvcnJUi4NknpeN0T3FO/G0XyBTsd3jmcSBgd+Lc7ChG5UlX/EhEX8DKeO6bSWgPcKCLl8AyWtwcezIpgjTEmo6nbTVzcXwz46jGWBG0nAGgYX4m+LV6h3HXOPh92IVmaMEQkH547nXqmKu4gIo97308Hxnn3LYnn9tkoVU0WkSfwDIgHAGNVdXMWhm6MMRlmzJzeDDu6AkLghkQXjYo+wJOdX8Llyt5rxmTpGIaqxqlqMVU9nqpsmKre5H31V+99vqq6X1WjUu33vXef61V1UFbGndEGDRpEpUqVqFy5MhEREaxatcqnegMGDGDhwoUALFu2jEqVKhEREcHKlSszZObZgwcP8uCDD1K+fHmqV69OnTp1mDFjBgA//fQThQsXpmrVqtx88808++yzl30+Y/Kaw0f28PzIrow+vIxQt9IypRoTHlpJn7YvZ/tkAXl8ahAnrFy5kjlz5rBu3TpCQkI4dOgQiYnpjfOfK/XkhBMnTuTZZ5+la9eujB8/nrVr1xIVFXWB2mdLTk4mMPDfv35V5d5776Vz58589dVXAOzevZvZs2ef2ad+/frMmTOH+Ph4qlatSuvWralbt67P5zQmr3KnpND/i2b8xD7iQ1wUT4aXK79Fkxr3OB2aXyxhZLEDBw5QvHjxM097Fy9eHIDVq1czePBgpk+fzqxZs2jfvj3Hjx/H7XZTsWJFdu7cSZcuXWjRogXHjh3j66+/Zv78+SxYsIAVK1YQHx/P8uXLefHFF2nRogVPPvkkGzduJDk5mddee41WrVoxfvx4vvvuOxISEoiNjWXRokVn4lq0aBHBwcFn3fZbpkwZnnzyyXPacHrhp3379mXyt2VMzvfjyo+ZvWkmi4IPEqhCx6D7eL7Ty7gCct6v35wXcUaa2x/+tzFjj3n1rdDs/LOW3HnnnQwcOJCbbrqJpk2b0q5dOxo2bEi1atVYv3494OluCg8PZ82aNSQnJ1Or1tmPnHTv3p3ly5fTokUL2rZte+YK4/TEgf/5z39o3LgxY8eO5dixY9SsWZOmTZsCniucX3/9lSuuuOKsY27evNnnxZuOHj3K9u3bbc0LYy5g/5GjfDnvZSYkLYVgCD8VyGcdV1Aofz6nQ7tkNvlgFitQoADR0dGMHDmSEiVK0K5dO8aPH09gYCA33HADW7ZsYfXq1Tz99NMsXbqUZcuWXXTywLQWLFjA4MGDiYiIoFGjRiQkJLBnzx4A7rjjjnOSRXoef/xxqlSpQo0aNc6ULVu2jMqVK3P11VfTokULrr76av8ab0we4E5JZueu5Tz7dVMmJC2lcIqbZ4u354uu/5ejkwXk9SuMC1wJZKaAgAAaNWpEo0aNuPXWW/n888/p0qUL9evXZ+7cuQQFBdG0aVO6dOlCSkrKOet3X4yqMm3aNCpUqHBW+apVq847xXmlSpWYNm3ame1PPvmEQ4cOERn575Qyp8cwfv/9d+rVq0fr1q2JiIjwKzZjcjN1u3nmyyYslCMQBk0TbqR7sw+oVLqM06FlCLvCyGLbtm1j+/btZ7Y3bNhAmTKeH6YGDRowdOhQ6tSpQ4kSJTh8+DBbt26lUqUL35ddsGBBTpw4cWb7rrvu4qOPPjqzpsXprq4Lady4MQkJCXz66adnyuLi4tLd96abbuLFF1/k7bezdmplY7KzFeum8fCIWiyUI1SKD+SZYg/wQc/puSZZgCWMLHfy5Ek6d+5MxYoVqVy5Mr/99huvvfYa4FmD4uDBg2fGBipXrkzlypUvOjvl7bffzm+//UZERARTpkzhlVdeISkpicqVKxMeHs4rr6Sdy/FcIsLMmTNZsmQJ5cqVo2bNmnTu3Pm8SaFXr14sXbqUP//8078vwJhc5tg/f/Py563o+8ur/B4WR1RKGUZ1XkWXFhf/d5fTODK9eVbJjtOb53X2/ZvcZPGq8by7cQh7g4QqJ8PoVucdGldr5HRYlyU7Tm9ujDE5VmxCIh/PfJgJpzZDkPBwcH26dxlK0fzZb/6njGQJwxhjfKRuNwv+7zPe2fYxfwW6CI8LpmfkczSq0d7p0LKEJQxjjPFB0qlYek9ows+BsRDoop2rHvdEvUaVMlc5HVqWsYRhjDEX8eX3g5mwfwL7g4TacUW499auNK/XzemwspwlDGOMOY/ftv/IKz89ze/BbiQQmp4qzaudZ2TLtSqygiUMY4xJI/HUST6e+RKzYheSFADVj1zHM63e49by2Xetiqxgz2E4IDtNb37s2DGGDx9+3s9tynOT14yfM4D2X9zGuIRFHAlw0alIU8b2mZvnkwVYwshyqac3//XXX1m4cCHXXXfdxSvimd789CSCp6c337BhA9u2bcuUhHF6yvMGDRqwc+dOoqOjmTx5MjExMWf2qV+/PuvXr2f9+vXMmTOHFStWXFIcxjhtw+ZpDJncnfcOz2B7sFLnn5JMr/cBvdsMyxFrVWSFLEsYIlJBRDakev0jIn1FJEJEfvaWrRWRmuep309ENovIJhGZJCKhWRV7RkpvevOSJUuyevVq2rRpA8CsWbMICwsjMTGRhIQEypcvD0CXLl2YOnUqo0eP5uuvv2bgwIF06NCBAQMGMGXKlDNPesfGxtKtWzdq1KhB1apVmTVrFuCZkbZmzZpERERQuXJltm/fTv/+/dmxYwcRERE899xzZ8VqU56bvCApKZnvl39B99Wv8vmpVbhU6X/dIP7beRY3Xt/U6fCylSwbw1DVbUAEgIgE4FmbewYwCnhdVeeKSBTwDtAodV0RuRZ4CqioqvEi8jWedb3HX05Mb69+m61Htl7OIc5x8xU380LNF877uZPTm48YMYI+ffrQsWNHEhMTSUlJYfDgwWzatIkNGzacE6tNeW5yuxP/7OPtqc8yK2ATuIS6J6/h3ir3cXe9lk6Hli05NejdBNihqrtFRIFC3vLCwP7z1AkEwkQkCch3gf2ytdPTmy9btozFixfTrl07Bg8eTJcuXdKd3jwlJeWSpjefPXv2mVluT09vXqdOHQYNGkRMTAxt2rThxhtv9Ou4jz/+OMuXLyc4OJg1a9YA/055vm3bNvr3729Tnpsc44vv+vDuoUUQ4Nl+KLgufXsOJzjQeurPx6mE0R6Y5H3fF5gvIkPwdJHdlnZnVd3n/XwPEA8sUNUF6R1YRHoAPQBKly59wSAudCWQmZya3vyWW26hVq1afPfdd9x1112MHj36THdXemzKc5Mbxcf/w7Oft2Fp2EEKpLipfqoMTzb/iAqlr3c6tGwvy1OpiAQDLYFvvEWPAf1U9TqgHzAmnTpFgVZAOaAkkF9EOqV3fFUdqaqRqhpZokSJzGjCZXFyevOdO3dSvnx5nnrqKVq2bMmvv/56Tt3UbMpzk9uMmd2Pe766jaVhBymY4ubFG/ry8WPfW7LwkRPXXs2Adap60LvdGZjuff8NkN6gd1PgT1X9W1WTvPufcyWSEzg5vfmUKVMIDw8nIiKCrVu38vDDD1OsWDHq1q1LeHj4OYPeNuW5yS1W/zqTPiPvYujRhRwMFOr+cyNLO2+kZYNHnQ4tR8ny6c1FZDIwX1XHebe3AI+p6k8i0gR4R1Wrp6lTCxgL1MDTJTUeWKuqH13oXDa9efZj37/JSkkpbqYvHsXHez7kWICLK5PdvNNgJhXLlCcsOMDp8LKlbDO9uYjkA+4AeqYqfhQYJiKBQALe8QcRKQmMVtUoVV0lIlOBdUAysB4YmZWxG2NylkUrhzF74zx+DIkh0CV0CGrHE217Uyj/xde0N+nL0oShqnFAsTRly4Hq6ey7H4hKtf0q8Gpmx2iMydlS3Mr85cN44c8xEAIVEwJpdcNLtG3Yxu6Aukx5ci4pVb3ouIDJeLl5dUfjvOSkBI6dOMjLkx9hVb7/EQS0C25E77ZvUjB/oYvWNxeX5xJGaGgohw8fplixYpY0spCqcvjwYUJDc+QD+iabU7ebx75oyM+BcZAfqiXko3P1ATSObOF0aLlKnksYpUqVIiYmhr///tvpUPKc0NBQSpUq5XQYJpf5bsnbfLN1OtGhcVyTpEQVbkPfzgOdDitXynMJIygoiHLlyjkdhjHmMh06foiPZj7BdDZDKNQ6VYAPH15EvtAwp0PLtfJcwjDG5GzqdrNi3VhGRH/KL6GJ3BTvome1d7mz5p1Oh5brWcIwxuQYCYmJvPJVFPPkIIRCq5TKPNVxDFcWtLGxrGAJwxiTI2zfvZZX5j3K5tBkwuODuO/GzrRt0sfpsPIUSxjGmGzt2PF9vDG9M/NdBwkLdtNWqtHnodEUyR/idGh5jiUMY0y2NfunoYz7fSx/BrupeqIgLcOfpG2jB50OK8+yhGGMyXb+3LeNMQufYxZ/Qgh0DIrghce/tGenHGYJwxiTbSSeOsHo757h0xMrAah8Ioznmo0l4vpwhyMzYAnDGJNNHIuL57lJd/BzYCwA3fO1pGmT56hUqoizgZkzLGEYYxx1/NguvlkykjGHZ3Ey0EWd2GJ0qtGNBjUedjo0k4YlDGOMY37/4wc6LutHgksoDLR2V+WxDiO4pmg+p0Mz6bCEYYzJcslJCbzweRsWBe4hAKh5rBQd6z5B48jmTodmLsAShjEmS42e9QRjDy/mRJALEDqF1eSZrmOcDsv4IMsShohUAKakKioPDAB+AkYAoXhW0+utqqvTqV8EGA2EAwp0U9WVmRu1MSajrFo/genrJ/N9wG4IcFHreEne6z6HwvmCnA7N+CjLEoaqbgMiAEQkANgHzABGAa+r6lwRiQLeARqlc4hhwDxVbSsiwYB1chqTA7hTUhg/902G/z2FUwGCqPJOhZepW/U+CoZasshJnOqSagLsUNXdIqLA6eWwCgP70+4sIoWABkAXAFVNBBKzJlRjzKXauGUm32+YxYTEteASmifVol3t5lQNb+10aOYS+J0wRCQ/kKCqKZdx3vbAJO/7vsB8ERkCuIDb0tm/PPA3ME5EqgDRQB9VjU0nvh5AD4DSpUtfRojGmEuVkJTCop9H8MLOEQAUSXHzZJnnadWwEyGBAQ5HZy7VRVdEFxGXiDwoIt+JyF/AVuCAiGwWkXdF5EZ/TujtTmoJfOMtegzop6rXAf2A9Ea/AoFqwKeqWhWIBfqnd3xVHamqkaoaWaJECX9CM8ZkkP7jmp9JFo3jbuC9Wp/xQJPOlixyOF+uMBYDC4EXgU2q6gYQkSuA24HBIjJDVSf4eM5mwDpVPejd7gycnqP4GzwD22nFADGqusq7PZXzJAxjjHNGz36CLw4t5miIi5JJSrcyvWl3R2+nwzIZxJeE0VRVk9IWquoRYBowTUT8GbnqwL/dUeAZs2iI526pxsD2dM71PxHZKyIVvIPnTYDf/DinMSYTbfp9MR8sHMDafEe5QqHBybK83ulLihcu4nRoJgNdNGGklywuZR8AEckH3AH0TFX8KDBMRAKBBLzjDyJSEhitqlHe/Z4EJnq7tHYCXX05pzEm87hTUnhnSg/mJPzM8fwuyiYKgxqOoPJN9ZwOzWQCnwe9ReTpdIqPA9GqusGXY6hqHFAsTdlyoHo6++4HolJtbwAifY3XGJN51O3m4xmd2XT4T/4v5DihItwnD/Dao684HZrJRP7cJRXpfX3r3W4OrAF6icg3qvpORgdnjMl+4hNT+OL7Vxl5cgOEQKWEQF5vuZCbrr7C6dBMJvMnYRQDqqnqSQAReRXP4HMDPLe5WsIwJhdLSoojeuNXjF09npVhxymW7KbHdU9y/+2dCQoKczo8kwX8SRilOfthuSSgjKrGi8ipjA3LGJPdPD+xGQvlCIRBg/ir6d74XareFOF0WCYL+ZMwvgJ+FpFZ3u17gEneB/nsjiVjcqm5y97nq82T2BCWQIUEF81KPsgj97zgdFjGAT4nDFX9r4h8D9QDBOilqmu9H3fMjOCMMc6JS4jjrSkdmKU70DDhruRreenBrylasNDFK5tcyZ+7pAS4BSisqgNFpLSI1ExvZlljTM7lTknmh//7kAm/fcWG0FNExOane4NRNLy1stOhGYf50yU1HHDjebhuIHACz4N7NTIhLmOMA47GxvL65Hv4MfBvCIVWlOWVnjNtSg8D+JcwaqlqNRFZD6CqR70P0RljcoEt25fy8uIn+T3ETeSJIrSv1p07az+EuC465ZzJI/xJGEnedSwUQERK4LniMMbkYCdjj9Nv0l38HBQLIdAhoB6PdHqPq4rYkjPmbP4kjA/xLHh0lYgMAtoCL2dKVMaYLPH5nJeY+L9ZHAgSIk8Wpun1beh4d3qTOhjj311SE0UkGs/EfwD3quqWzAnLGJOZtu5YwXuLn+HnoFiuEKVDQDWe7Tme4EDrfjLnd9GEcZ45pACaiUgzVX0/g2MyxmSS2Ni/GfjNQ3wv+wgMVKodvYqnWk2gerlrnA7N5AC+XGEU9P5ZAc8dUbO92/cASzMjKGNMxpu7YiKTfvuA9cGeiRl6X3EPbe9/naL57d4V4xtfpjd/HUBEFuCZS+qEd/s1/l01zxiTTW3aMocZa79kWspmUoKF2/4pw6tt36TkNfZchfHP5cwllQiUzdBojDEZxu1WfvtzI91+foF4lwtE6F24Pa1a9qVk0fxOh2dyIH8SxpfAahGZgefW2tbA55kSlTHmsqjbzfNj72F+0B5wuaj7T1nuq/Egd9Tu4HRoJgfz5y6pQSIyF6jvLeqqqut9rS8iFYApqYrKAwPwLM06AggFkoHe55tuxPscyFpgn6q28PXcxuQlc356mxd3T4AguDpJiSpYlz4PjcDlEqdDMzmcL3dJiaoqgKquA9ZdaJ/z8a7FHeHdPwDYh+e5jlHA66o6V0Si8Kyr0eg8h+kDbAFs9jNj0jh2/AADv36EJYF7wCU0iC3Hi+0nUuqKghevbIwPfLnperGIPCkipVMXikiwiDQWkc+Bzn6etwmwQ1V34+neOp0ACgP706sgIqXwrPI32s9zGZPrfTS1Fy2nNeWH4L0kCzxTrDWf9J5tycJkKF+6pO4GuuFZ+6IccAwIw5NsFgAf+LqmdyrtgUne932B+SIyxHvM285TZyjwPP/e5psuEekB9AAoXbr0hXY1Jsdb++sUZkZPYZZrOwS4aHQykvce/ZjgYBvUNhnPl9tqE/DMVDtcRIKA4kC8qh67lBN6JyxsCbzoLXoM6Keq00TkAWAM0DRNnRbAX6oaLSKNLhLvSGAkQGRk5AW7yYzJqU7GJzJiVn8mJiwg2SXkc7sZUe9LbilbheAgm1nWZA5/7pJCVZOAA5d5zmbAOlU96N3ujGdsAjzPdaTX5VQXaOkd4wgFConIBFXtdJmxGJPj7N27guELhjEncAuBwP005t6691P5xmpOh2ZyOb8SRgbpwL/dUeAZs2iI526pxsD2tBVU9UW8VyTeK4xnLVmYvOavEwn8sPxNBv81AwKhVJLyQtUhNKx2F571zYzJXFmaMEQkH3AH0DNV8aPAMBEJBBLwjj+ISElgtKpGZWWMxmRH+w5s5NlZndkUlkTBFDeNtCa9Wr5B6SuvdTo0k4f4s0TrI6o65nJOpqpxQLE0ZcuB6unsux84J1mo6k94rkaMyRP+M74l38qfBIcoNeIL0q3WS9Srao8hmaznzxXGeyLSEc/DdauBSaq6OXPCMsaM/fYJlu5fTXRoPMWT3TQJuZeXurxh3U/GMf4kjMPAG0AwngfwvhaRD1X1s8wIzJi86siJWEbOfoaJySsgFKqcCuazTovIn6+w06GZPM6fhHFcVRd5388TkWHAKsAShjEZwJ2SzPwV7zJu6xS2hKRQ+pTSu+pnNK9R1+nQjAEuYdBbRF7A8yxGYeBEhkdkTB6U4laGfP0gExK3QAjcx630emA0V9u62iYbuZS7pKbhmdqjFfBmxoZjTN6zIvpLPl0zlF/CErk5PoCHKvWlZf0uTodlzDn8SRhFReQ6Vf0D+ENERgHrge8yJzRjcjd1u3n5y3uYzR6CQ5QW7nI8ef8XlCxW1OnQjEmXPwmjEPCTiBwCfgOKACmZEZQxud3sxe/yze9T2BB6iuonCtHxtve5o1otp8My5oL8SRi3A5uAWnjW91bs6sIYvxw4/BeDprVjScghCIWmySV4t9cPBAba/E8m+/NnAaVfvW9Xel/GGB+p283/rRvHO+uHsjMEIo8Xp1fjV6hZsRHi8mWVAWOc58RcUsbkKX/sj+GNOa2JDkmAYOgSUo8u3YZSrECI06EZ4xdLGMZkom8Wfcqbez4hOUSoGVeIJuVa8ODdL168ojHZkD9zST0BTFTVo5kYjzG5wh+7V/HEwkfYFyiEKDwU1pBH231AwdAgp0Mz5pL5c4VxNbBGRNYBY4H5F1vH25i8Rt1unht3N/MDD+AKgJpHS/NQo5dpFFHH6dCMuWz+DHq/LCKvAHcCXYGPReRrYIyq7sisAI3JKT6fM4DvD8zmt2DP3ebd8temTxdbgt7kHv6uuKci8j/gf3hmrS0KTBWRH1T1+cwI0JjsbvuORYxcOph5rgMQDDWOF+f9bvMoYoPaJpfxZwzjKTzLqR7Cs4zqc6qaJCIuPKvkXTBhiEgFYEqqovLAADxrW4zAs/RqMtBbVVenqXsd8AWebjE3MFJVh/kauzGZwe1WZi79ks92vMP+QCFQlffD36Rqxbspki/Y6fCMyXA+JQzxTMBfBWijqrtTf6aqbhG56GouqroNz7ToiEgAsA+YAYwCXlfVud41u98BGqWpngw8o6rrRKQgEO29qvnNl/iNyWjbdy7mq+Wjmaq/QqBwe2wlHm3Sk1sr3O50aMZkGp8ShrcrqmraZJHq8y1+nrcJsENVd4uI4pl2BDwz4O5P5/gHgAPe9ydEZAtwLZ4pSozJMqrKpq3f8fCq/iSLEOZ281iJNrS+72XrgjK5nj9jGCtFpIaqrsmA87YHJnnf9wXmi8gQwAXcdqGKIlIWqIpnLQ5jssyphOP0/6ITC0N2gQi3Ha/EU60GU6lMWadDMyZL+DuXVC8R2QXEAoLn4qOyPycUkWCgJXD66aXHgH6qOk1EHgDGAE3PU7cAnunV+6rqP+fZpwfQA6B06dL+hGbMeQ39pjtj4lZBCFyXqNxZuD59Hh5uy6WaPEV8fZRCRMqkV36+bqoLHKcV8Liq3undPg4U8XZ7CZ6V/QqlUy8ImIPn+Y/3fTlXZGSkrl271p/wjDnL5m1zGbX0fZYGHSBQldpxdXmr+3Dyh9gkCSZ3EpFoVY1M7zN/fuo7n6d8oJ/xdODf7ijwjFk0xHO3VGM8d1ydxZtIxgBbfE0WxlyOxKREnh/XipVBe4gLdhHqhveq/Jf61do4HZoxjvEnYcSmeh8KtAD8GuwWkXzAHUDPVMWPAsNEJBBIwNudJCIlgdGqGgXUBR4CNorIBm+9/6jq9/6c3xhfzPnpdeb9sYglIUcAF22lNc+1e4p8+Yo7HZoxjvK5S+qciiIhwGxVvStjQ8o41iVl/LHv6Akmz3+V8ad+AOCmUy4+abeCqwrlt7EKk2dkVJdUWvnwPHxnTI6mbjcx+1bx4ndP8UtYAoVT3HS84mEebPoohQsUcDo8Y7INf5703ohnlT2AAKAE/o9fGJPt/OfLKOawD8Kg4anidK3/OtVvaeB0WMZkO/5cYaR+mjsZOKiqyRkcjzFZZunqzxi3bhxrw2KpEB9AoxKtePzh16z7yZjz8Ge2Wr9unzUmu0pISuHjac8wOX4hp8KE+olFeavjbAoXLOJ0aMZka/50SX0O9FHVY97tosB7qtotk2IzJsN9t+RNJmydyqbQJMonurjvhrd4uElzp8MyJkfwp0uq8ulkAaCqR0WkasaHZEzGi09M4Z0p7Zjq3gah0FKu44VOUyiUv6DToRmTY/iTMFwiUvT0Eq0icoWf9Y3Jcu6UZL5d8l/G7pjOzmCIOJmPzrX+S9PIO50OzZgcx59f+O8B/yciU/HcLfUAMChTojImA7hTUnj2izv5wfU3YYFuWlOJbg+MpGyJIk6HZkyO5M96GIuBtXim7xA8a2PY9OImW5q5eBjTtk1gQ1gCtU4W5b7q/6FZ7budDsuYHM2f9TBmqmp1bA0Kk43t2L2OAfO782tIEoRBk5TiDH50AaHBQU6HZkyO50+X1M8ZuB6GMRkq8dQJRs7px+gTPxMcpFQ7dAPPtR1OeJlrnQ7NmFwjy9fDMCajfbtsAlN+G8ovoadAhK6Fm9Cz81BcLnsAz5iM5E/CaJZpURhzCQ4e/JVFG75hyP4ZJIYKtU9czcN1ulG/egenQzMmV/InYewBOgLlVXWgiJQGrgbsCXCT5fbu28j9CzoQ63IRArxwZWda3PekrattTCbyJ2EMB9x47pIaCJzAs1xqjUyIy5h0qdvNaxPuZ7r+Di4XDU9UoXWdzjSpfofToRmT6/mTMGqpajURWQ9nnvQOzqS4jDnHzEVv8d6uCRwLcFE82U2LApE80/lzp8MyJs/wJ2EkiUgA3inORaQEnisOn4hIBWBKqqLywAA8S7OOwLOKXzLQW1VXp1P/bmAYnqnVR6vqYD9iNznY0SM7eWP64ywIioEAFzX/Kc4z902jYskrnA7NmDzFn4TxITADuEpEBgFtgVd8rayq24AIAG/i2ec93ijgdVWdKyJRwDtAo9R1vft/gmd51xhgjYjMtgcHc7/PZg1k2qGvORDkuePpP1d3oEPn/zgclTF5kz/Tm08UkWigibeolapuvcTzNgF2qOpuEVGgkLe8MLA/nf1rAn+o6k4AEZkMtMIeIsy1Vq2fyITokfwUdAQChTrHbuadLh9SpPA1TodmTJ510YQhIrPTFnn/vEtEUNWWl3De9sAk7/u+wHwRGQK4gNvS2f9aYG+q7Rig1nni7QH0AChduvQlhGaclJTiZtnG1by44U3iglxckexmQOW3ubVCU4oUCnU6PGPyNF+uMOrg+WU9CVjFvwnjkngHylsCL3qLHgP6qeo0EXkAGAM0TVstnUNpOmWo6khgJEBkZGS6+5jsx52SzJLVQ/n+t0XMC9wLLhctkpvTtemD3FTGng01JjvwJWFcjWfsoAPwIPAdMElVN1/iOZsB61T1oHe7M9DH+/4bYHQ6dWKA61JtlyL9riuTQ02Y9xLvHvoeAuHmhACaXtWC7i3/S4A9rW1MtnHRhKGqKcA8YJ6IhOBJHD+JyEBV/egSztmBf7ujwPOLvyGeu6UaA9vTqbMGuFFEyuEZLG+PJ3mZHG7PnpW8Orcvv4TEUsitNKQdfdr346rCtrCRMdmNr9ObhwDN8fyyL4vnjqnp/p5MRPLhuVrpmar4UWCYiAQCCXjHH0SkJJ7bZ6NUNVlEngDm47mtduxlXOGYbEBV6T2qActDjkEoVEgIoGvFx2lev4fToRljzkNUL9zN713LOxyYC0xW1U1ZEVhGiIyM1LVr1zodhklj8vxn+GHPClYHx1IoxU0TVzNe7/wunmVXjDFOEpFoVY1M7zNfrjAewjM77U3AU6n+UZ+erbbQ+Soak9rhEyf4eHpfprIagqF8Inz54DIK5bcH8IzJCXwZw3BlRSAm91K3m1Xrx/JR9HB+DUmiWLKbJ258l/vq3Y247MfLmJzCnye9jfFbQlIK707pwNcpWyAE7koqR797R3Ft8aucDs0Y4ydLGCbT7Ni1gtfm9WVDWALhccHcXeZhHrr7KVvYyJgcyhKGyXDJyUkMnNiBb3UrwSHKvVTg2YfGUbhAYadDM8ZcBksYJkMtXPkpQzcNZ3cw3Bobxh03PEPXu9o7HZYxJgNYwjAZIjY+ng+mPskU9yoIhlaU47+PzbRBbWNyEUsY5rIkJyXw2bc9+OyfdagIN8cF0LfBOOpWqup0aMaYDGYJw1yypKRknp8QxULX3yDCw8GNaHP3QK6/qqjToRljMoElDOM3dbuZt2IoH24dS0ywUPtkMR6+7QXqV23mdGjGmExkCcP4ZXfMBnrN60RMkFAwQGkj1/PCI1PJFxrkdGjGmExmCcP4JCH+KG98/RDf6S5cAVDzSBW63P0y9W+52enQjDFZxBKGuahZS0YxcdsnbAlJ8YxVhFbnua7jnQ7LGJPFLGGY8/pjx0Km/DyCGYlbORUi1PznSt7pMo1iBYs4HZoxxgGWMEy6lm34gZfX9eVIgIsAgcHXP8ftNR8kX7D9yBiTV9m/fnOWhPijTFzwFkOPzYUAF/X/qULH+h2pG2F3QBmT12VZwhCRCsCUVEXlgQFAHaCCt6wIcExVI9Kp3w/oDiiwEeiqqgmZGHKe8/OGr3l8/UASXYKo8kSR+nR/aLhNFmiMAbIwYajqNiACQEQC8KzNPUNVh57eR0TeA46nrSsi1wJPARVVNV5Evsazrvf4TA88D0hJTqTfuCgWBx8El1D/RDnaNvgvjStXcTo0Y0w24lSXVBNgh6ruPl0gnqX8HgAan6dOIBAmIklAPmB/pkeZB4ye/QaT/57MwWChZJLS7qoounV+x+mwjDHZkFMJoz0wKU1ZfeCgqm5Pu7Oq7hORIcAeIB5YoKoL0juwiPQAegCULl06Q4POTVatn8CHa97n15AkCBRqHLuGwd1mc2XBUKdDM8ZkU1k+laiIBAMtgW/SfNSBc5PI6TpFgVZAOaAkkF9EOqW3r6qOVNVIVY0sUaJExgWei3wy/XWeW/8Wv4Ykkd/t5tNbBzG891xLFsaYC3LiCqMZsE5VD54uEJFAoA1Q/Tx1mgJ/qurf3v2nA7cBEzI51lxD3W7GzOnB+r+2sTToGAS4uCepMS91eJn8+S2xGmMuzomEkd6VRFNgq6rGnKfOHqC2iOTD0yXVBFibeSHmLrGnkpn10wcMO7oKguCGU0LvygNoXPM+AuwOKGOMj7I0YXh/4d8B9Ezz0TljGiJSEhitqlGqukpEpgLrgGRgPTAyC0LO0dTtZs/eFbw271nWhsZRJMXNA0V60K5lJ64sWszp8IwxOYyoqtMxZJrIyEhduzbvXogMmvgAk5O3AFArviD33dqDZnW7OBuUMSZbE5FoVY1M7zN70jsXWvLzUL7aNIXogBPgEjoE3Mnzj75LYIAtl2qMuXSWMHKR5BQ3gyf2YmbK/3EqSKh4KpC3mn1J+etudTo0Y0wuYAkjl1i+5lO+2PAFK4NPUjoJ7ik1kJ7N7sXzPKQxxlw+Sxg53LHYUwyb2oOprINguO1UYYZ1XkBoSD6nQzPG5DKWMHKwP/5cwSsLnmRTaBKV4oK4/5ZnaF2/Pa6AAKdDM8bkQpYwcqC4U6cY8vXDTE/ZjIRAO1dVenX8lOKFCjgdmjEmF7OEkcN8v3QoQ38fzYEgITwuhDvLPknXqC5Oh2WMyQMsYeQQfx89yPvTezMvYBvJQcL9ATfwUo+pBARa95MxJmtYwsjmkpLiePub9kxJ+hMC4daTofRsOIaG4bZWhTEma1nCyMb2/PU3H8xpx8KAvwHonq8e7Vt/wFWFbFZZY0zWs4SRDSXEH2XGkvcYemAGcQEuap8swdPNBnNL+ZpOh2aMycMsYWQzx48f4IGpd7A/UCio8FjBBjx0/7sUzGfPVRhjnGUJI5tISU7klYn3Mk/3kBQoND5ZjVb1+tK4SlWnQzPGGMASRrawZO1k3l//JjuDlYJupUVgOQY+/rnTYRljzFksYTho3761DFvwH36Q/SQHC9WPFeP5tjOpeG0Rp0MzxphzWMJwyKQfPuWL3Z8QEySA8EThpjzS6T2bgtwYk21lWcIQkQrAlFRF5YEBQB2ggresCHBMVSPSqV8EGA2EAwp0U9WVmRdx5tj55yKWbv6BDw59iztIaHDiFp5u0Y/ry9ZxOjRjjLmgLEsYqroNiAAQkQBgHzBDVYee3kdE3gOOn+cQw4B5qtpWRIKBHHXbUEJSCnN+XsTQ7X05HuAiROH165+gXmQ3CocFOR2eMcZclFNdUk2AHaq6+3SBeBZueABonHZnESkENAC6AKhqIpCYJZFmgPi4I7wx5RFmu/6AABdN4+pwe3hTmtd/wOnQjDHGZ04ljPbApDRl9YGDqro9nf3LA38D40SkChAN9FHV2LQ7ikgPoAdA6dKlMzRof6kqUxYOZ9D+EeCC8onQrlRzHmw22NG4jDHmUmT5CKu3O6kl8E2ajzpwbhI5LRCoBnyqqlWBWKB/ejuq6khVjVTVyBIlSmRQ1P7btGU2zcfc6kkWQP0TNzKk5TJLFsaYHMuJK4xmwDpVPXi6QEQCgTZA9fPUiQFiVHWVd3sq50kYTlNVBn7xKPNTVnIiyEX5ROh5yxNE1evpdGjGGHNZnEgY6V1JNAW2qmpMehVU9X8isldEKngHz5sAv2VynH77fM5j/HBgFb8EJ0GAizvjIxnSc6ytq22MyRWyNGGISD7gDiDtf7fPGdMQkZLAaFWN8hY9CUz0dmntBLpmcrg+S05xM2r2YIb/sxyCoXSi8uUDP3BF4WucDs0YYzJMliYMVY0DiqVT3iWdsv1AVKrtDUBkJoZ3SdasH8Nn0aNYFRRLqFt5pHg/ut7ZnpCQ/E6HZowxGcqe9L5Eqsr4Oc/y/pEFEAT146+kd9PBhN9Qw+nQjDEmU1jCuAQbt8zmg6VvsjH4JCXcSpsrHqVHx6cIDrRpPYwxuZclDD8NGP8AM2QLQSFKjaRCPN5wCJVvus3psIwxJtNZwvDR8jWf8uEvn7ElKIWKsUG0qPA6DzW5x+mwjDEmy1jCuIhjJ0/xxlcdmB+yHYKg5qn8fNj1R/KH2aC2MSZvsYRxASvWjmTYuuFsCUmhyskw7o94nZZ17kJcNlZhjMl7LGGk4+jJBN6b2p5ZsgNCoK3cTL+uEyiUL8Tp0IwxxjGWMNI4GptIqynVORroIiIulKblutP5bpvWwxhjLGGkUSA4mUi5hlJh1/JUx9EEBtpaFcYYA5YwzhEUlI/3uy10OgxjjMl2bPTWGGOMTyxhGGOM8YklDGOMMT6xhGGMMcYnljCMMcb4xBKGMcYYn1jCMMYY4xNLGMYYY3wiqup0DJlGRP4Gdl9i9eLAoQwMJyewNud+ea29YG32VxlVLZHeB7k6YVwOEVmrqtluDfHMZG3O/fJae8HanJGsS8oYY4xPLGEYY4zxiSWM8xvpdAAOsDbnfnmtvWBtzjA2hmGMMcYndoVhjDHGJ5YwjDHG+MQSRhoicreIbBORP0Skv9PxZBQRuU5EFovIFhHZLCJ9vOVXiMgPIrLd+2fRVHVe9H4P20TkLueiv3QiEiAi60Vkjnc7V7cXQESKiMhUEdnq/fuuk5vbLSL9vD/Tm0RkkoiE5sb2ishYEflLRDalKvO7nSJSXUQ2ej/7UETE5yBU1V7eFxAA7ADKA8HAL0BFp+PKoLZdA1Tzvi8I/A5UBN4B+nvL+wNve99X9LY/BCjn/V4CnG7HJbT7aeArYI53O1e319uWz4Hu3vfBQJHc2m7gWuBPIMy7/TXQJTe2F2gAVAM2pSrzu53AaqAOIMBcoJmvMdgVxtlqAn+o6k5VTQQmA60cjilDqOoBVV3nfX8C2ILnH1srPL9g8P55r/d9K2Cyqp5S1T+BP/B8PzmGiJQCmgOjUxXn2vYCiEghPL9YxgCoaqKqHiN3tzsQCBORQCAfsJ9c2F5VXQocSVPsVztF5BqgkKquVE/2+CJVnYuyhHG2a4G9qbZjvGW5ioiUBaoCq4CrVPUAeJIKcKV3t9zwXQwFngfcqcpyc3vBc3X8NzDO2xU3WkTyk0vbrar7gCHAHuAAcFxVF5BL25sOf9t5rfd92nKfWMI4W3p9ebnqvmMRKQBMA/qq6j8X2jWdshzzXYhIC+AvVY32tUo6ZTmmvakE4um2+FRVqwKxeLoqzidHt9vbZ98KT7dLSSC/iHS6UJV0ynJMe/1wvnZeVvstYZwtBrgu1XYpPJe3uYKIBOFJFhNVdbq3+KD3MhXvn395y3P6d1EXaCkiu/B0LTYWkQnk3vaeFgPEqOoq7/ZUPAkkt7a7KfCnqv6tqknAdOA2cm970/K3nTHe92nLfWIJ42xrgBtFpJyIBAPtgdkOx5QhvHdCjAG2qOr7qT6aDXT2vu8MzEpV3l5EQkSkHHAjnsGyHEFVX1TVUqpaFs/f4yJV7UQube9pqvo/YK+IVPAWNQF+I/e2ew9QW0TyeX/Gm+AZn8ut7U3Lr3Z6u61OiEht7/f1cKo6F+f0yH92ewFReO4g2gG85HQ8GdiuenguPX8FNnhfUUAx4Edgu/fPK1LVecn7PWzDjzspstsLaMS/d0nlhfZGAGu9f9czgaK5ud3A68BWYBPwJZ47g3Jde4FJeMZpkvBcKTxyKe0EIr3f1Q7gY7wzfvjysqlBjDHG+MS6pIwxxvjEEoYxxhifWMIwxhjjE0sYxhhjfGIJwxhjjE8sYRhzESJSTEQ2eF//E5F93vcnRWR4Jp2zr4g8fJF9JovIjZlxfmPSY7fVGuMHEXkNOKmqQzLxHIHAOjyzCydfYL+GQCdVfTSzYjEmNbvCMOYSiUijVOtsvCYin4vIAhHZJSJtROQd77oD87zTspxei2CJiESLyPzT0zqk0RhYp6rJInK9iKxLdc4bReT0/FjLgKbeBGNMprOEYUzGuR7PdOqtgAnAYlW9FYgHmnuTxkdAW1WtDowFBqVznLpANICq7gCOi0iE97OuwHjvZ24801ZXyaT2GHMW+5+JMRlnrqomichGPItxzfOWbwTKAhWAcOAH7yJnAXimekjrGjzzIZ02GugqIk8D7Th7/Ya/8MzS6uusvMZcMksYxmScU+D5n7+IJOm/A4RuPP/WBNisqnUucpx4IDTV9jTgVWAREK2qh1N9Furd35hMZ11SxmSdbUAJEakDnunmRaRSOvttAW44vaGqCcB84FNgXJp9bwI2Z064xpzNEoYxWUQ9y/62Bd4WkV/wzBh8Wzq7zsWzzGpqE/HMNrzgdIGIXAXEq3fFNWMym91Wa0w2JCIzgOdVdbt3+1mgsKq+kmqffsA/qjrGoTBNHmNjGMZkT/3xDH5v9yaP6/HcbpvaMTzrPxiTJewKwxhjjE9sDMMYY4xPLGEYY4zxiSUMY4wxPrGEYYwxxieWMIwxxvjk/wGdr7WyKk0w+gAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] @@ -153,6 +153,13 @@ "print(f'Swiftest - Swifter: {np.mean(dvarpi_swiftest - dvarpi_swifter)}')" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "code", "execution_count": null, diff --git a/examples/whm_swifter_comparison/swiftest_vs_swifter.ipynb b/examples/whm_swifter_comparison/swiftest_vs_swifter.ipynb index 82bd3d63f..7740f02c8 100644 --- a/examples/whm_swifter_comparison/swiftest_vs_swifter.ipynb +++ b/examples/whm_swifter_comparison/swiftest_vs_swifter.ipynb @@ -107,7 +107,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZAAAAEGCAYAAABLgMOSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAYbUlEQVR4nO3dfbRVdb3v8ff3bCBK8JAC8rBB0DBANAQOWJmhHbjgqQilhqilVpfqaMNux5ueGvd0HXecsjrd1OzkoCcrG3I79iAZagp67WIcJREfIorQcgsmcTIRJNjwvX+sZXez74a9mOup3Xq/xthjrznnb/7m9xe2Pvs351pzRmYiSdLh+qtmFyBJ6psMEElSIQaIJKkQA0SSVIgBIkkqpF+zC2ikoUOH5rhx45pdhiT1KT/96U9/l5nDuq9vqQAZN24ca9eubXYZktSnRMSve1rvKSxJUiEGiCSpEANEklRIS10DkaRm2Lt3Lx0dHezevbvZpRzSwIEDaW9vp3///hW1N0Akqc46OjoYPHgw48aNIyKaXU6PMpPt27fT0dHB+PHjK9rHU1iSVGe7d+/m6KOP/rMND4CI4Oijjz6sWZIBIkkN8OccHi853BoNEElSIQaIJPURr3vd63pcf9FFF3HLLbc0uBoDRJL6jPvvv7/ZJRzAT2FJUh8xaNAgXnjhBTKTD37wg6xatYrx48fTrCfLOgORpD7me9/7Hhs3buTRRx/lS1/6UtNmJgaIJPUx9913H4sXL6atrY1Ro0Zx5plnNqUOA0SS+qA/h48FGyCS1MecfvrpLFu2jH379rF161buueeeptThRXRJ6mMWLlzIqlWrOOmkkzjhhBN44xvf2JQ6DBBJ6iNeeOEFoHT66vrrr29yNZ7CkiQVZIBIkgoxQCRJhRggkqRCDBBJUiEGiCSpEANEklrEu9/9boYPH86UKVNq0p8BIkkt4qKLLuKOO+6oWX9NDZCImBcRGyNiU0Rc2cP2iIjrytsfiYhp3ba3RcS6iLitcVVLUt90+umnc9RRR9Wsv6Z9Ez0i2oAvAHOADuDBiFiemT/r0mw+MKH8Mwv4Yvn3Sy4DNgBHNqRoSarSVT94nJ9teb6mfU4edSQff8uJNe2zEs2cgcwENmXm5szcAywDFnRrswD4RpasAYZExEiAiGgH/g74ciOLliSVNPNeWKOBp7osd3Dg7OJgbUYDW4FrgI8Agw91kIhYAiwBGDt2bFUFS1K1mjFTqJdmzkB6upl99+cy9tgmIt4MPJuZP+3tIJm5NDNnZOaMYcOGFalTktSDZgZIBzCmy3I7sKXCNq8H3hoRT1I69XVmRNxUv1Ilqe9bvHgxr33ta9m4cSPt7e185Stfqaq/Zp7CehCYEBHjgaeBc4HzurVZDlwaEcsond76Q2ZuBf6x/ENEzAYuz8wLGlS3JPVJN998c037a1qAZGZnRFwK3Am0AV/NzMcj4v3l7TcAK4CzgE3ALuDiZtUrSTpQUx8olZkrKIVE13U3dHmdwCW99HEvcG8dypMkHYLfRJckFWKASJIKMUAkSYUYIJKkQgwQSWoBTz31FGeccQaTJk3ixBNP5Nprr626z6Z+CkuS1Bj9+vXjs5/9LNOmTWPHjh1Mnz6dOXPmMHny5MJ9OgORpBYwcuRIpk0rPRFj8ODBTJo0iaeffrqqPp2BSFIj3X4lPPNobfsccRLMv7ri5k8++STr1q1j1qzu9689PM5AJKmFvPDCC5xzzjlcc801HHlkdY9ScgYiSY10GDOFWtu7dy/nnHMO559/PmeffXbV/TkDkaQWkJm85z3vYdKkSXz4wx+uSZ8GiCS1gNWrV/PNb36TVatWMXXqVKZOncqKFSt63/EQPIUlSS3gtNNOo3R/2tpxBiJJKsQAkSQVYoBIkgoxQCRJhRggkqRCDBBJUiEGiCS1gN27dzNz5kxe85rXcOKJJ/Lxj3+86j79HogktYCXvexlrFq1ikGDBrF3715OO+005s+fz6mnnlq4T2cgktQCIoJBgwYBpXti7d27l4ioqk9nIJLUQJ964FP8/D9+XtM+Jx41kStmXtFru3379jF9+nQ2bdrEJZdc4u3cJUmVaWtr4+GHH6ajo4MHHniAxx57rKr+nIFIUgNVMlOotyFDhjB79mzuuOMOpkyZUrgfZyCS1AK2bdvGc889B8CLL77I3XffzcSJE6vq0xmIJLWArVu3cuGFF7Jv3z7279/PO97xDt785jdX1acBIkkt4OSTT2bdunU17dNTWJKkQgwQSVIhTQ2QiJgXERsjYlNEXNnD9oiI68rbH4mIaeX1YyLinojYEBGPR8Rlja9eklpb0wIkItqALwDzgcnA4oiY3K3ZfGBC+WcJ8MXy+k7gHzJzEnAqcEkP+0qS6qiZM5CZwKbM3JyZe4BlwIJubRYA38iSNcCQiBiZmVsz8yGAzNwBbABGN7J4SWp1zQyQ0cBTXZY7+P9DoNc2ETEOOAX499qXKEk6mGYGSE938crDaRMRg4DvAB/KzOd7PEjEkohYGxFrt23bVrhYSfpLsG/fPk455ZSqvwMCzQ2QDmBMl+V2YEulbSKiP6Xw+FZmfvdgB8nMpZk5IzNnDBs2rCaFS1Jfde211zJp0qSa9NXMAHkQmBAR4yNiAHAusLxbm+XAu8qfxjoV+ENmbo3SPYi/AmzIzP/Z2LIlqW/q6Ojghz/8Ie9973tr0l/TvomemZ0RcSlwJ9AGfDUzH4+I95e33wCsAM4CNgG7gIvLu78eeCfwaEQ8XF730cxc0cAhSNJhe+YTn+CPG2p7O/eXTZrIiI9+tNd2H/rQh/j0pz/Njh07anLcpt7KpPyGv6Lbuhu6vE7gkh72+z/0fH1EktSD2267jeHDhzN9+nTuvffemvTpvbAkqYEqmSnUw+rVq1m+fDkrVqxg9+7dPP/881xwwQXcdNNNhfv0ViaS1AI++clP0tHRwZNPPsmyZcs488wzqwoPMEAkSQV5CkuSWszs2bOZPXt21f04A5EkFWKASJIKMUAkSYUYIJKkQgwQSVIhBogkqRA/xitJLWLcuHEMHjyYtrY2+vXrx9q1a6vqzwCRpBZyzz33MHTo0Jr05SksSVIhzkAkqYF+/O1f8LunXqhpn0PHDOIN7zih13YRwdy5c4kI3ve+97FkyZKqjmuASFKLWL16NaNGjeLZZ59lzpw5TJw4kdNPP71wfwaIJDVQJTOFehk1ahQAw4cPZ+HChTzwwANVBYjXQCSpBezcufNPTyLcuXMnP/rRj5gyZUpVfToDkaQW8Nvf/paFCxcC0NnZyXnnnce8efOq6tMAkaQWcNxxx7F+/fqa9ukpLElSIQaIJKkQA0SSVIgBIkkqxACRJBVigEiSCjFAJKlFPPfccyxatIiJEycyadIkfvKTn1TVn98DkaQWcdlllzFv3jxuueUW9uzZw65du6rqzwCRpBbw/PPPc99993HjjTcCMGDAAAYMGFBVnwaIJDXQPTcu5dlfb65pn8OPPY4zLjr0rdk3b97MsGHDuPjii1m/fj3Tp0/n2muv5Ygjjih8XK+BSFIL6Ozs5KGHHuIDH/gA69at44gjjuDqq6+uqk9nIJLUQL3NFOqlvb2d9vZ2Zs2aBcCiRYuqDpBeZyAR0RYR/6Wqoxy873kRsTEiNkXElT1sj4i4rrz9kYiYVum+kqT/Z8SIEYwZM4aNGzcCsHLlSiZPnlxVn73OQDJzX0QsAD5X1ZG6iYg24AvAHKADeDAilmfmz7o0mw9MKP/MAr4IzKpwX0lSF5///Oc5//zz2bNnD8cddxxf+9rXquqv0lNYqyPieuB/ATtfWpmZD1Vx7JnApszcDBARy4AFQNcQWAB8IzMTWBMRQyJiJDCugn1r5sZ/+AQvDuhfj64ltYDpb3kDz3Y809Qa+rcFU6dOZe3atTXrs9IAeV3591Xl3wEkcGYVxx4NPNVluYPSLKO3NqMr3LdUaMQSYAnA2LFjCxW6P9p4sd++QvtKUgbsj2xuDftrf/xDBkhEfLj88jZKgRFd66ny2NHDuu59HqxNJfuWVmYuBZYCzJgxo1DN7/6XK4rsJkkAbNiwgRGjRza7jJrrbQYyuPz71cDfALdSevN+C3BflcfuAMZ0WW4HtlTYZkAF+0qS6uiQAZKZVwFExI+AaZm5o7z834F/q/LYDwITImI88DRwLnBetzbLgUvL1zhmAX/IzK0Rsa2CfSVJdVTpNZCxwJ4uy3soXcguLDM7I+JS4E6gDfhqZj4eEe8vb78BWAGcBWwCdgEXH2rfauqRJB2eSgPkm8ADEfE9StcaFgJfr/bgmbmCUkh0XXdDl9cJXFLpvpKkxqnoViaZ+c+U/vr/PfAccHFmfrKOdUmSamjjxo1MnTr1Tz9HHnkk11xzTVV9Vnwrk/J3Pqr53ockqUle/epX8/DDDwOwb98+Ro8ezcKFC6vq05spSlKLWblyJccffzzHHntsVf14M0VJaqDnfvAr9mzZ2XvDwzBg1BEMecvxFbdftmwZixcvrvq4zkAkqYXs2bOH5cuX8/a3v73qvpyBSFIDHc5MoR5uv/12pk2bxjHHHFN1X85AJKmF3HzzzTU5fQUGiCS1jF27dnHXXXdx9tln16Q/T2FJUot4xStewfbt22vWnzMQSVIhBogkqRADRJJUiAEiSSrEAJEkFWKASJIKMUAkqUV87nOf48QTT2TKlCksXryY3bt3V9WfASJJLeDpp5/muuuuY+3atTz22GPs27ePZcuWVdWnASJJLaKzs5MXX3yRzs5Odu3axahRo6rqz2+iS1ID3X777TzzzDM17XPEiBHMnz//kG1Gjx7N5ZdfztixY3n5y1/O3LlzmTt3blXHdQYiSS3g97//PbfeeitPPPEEW7ZsYefOndx0001V9ekMRJIaqLeZQr3cfffdjB8/nmHDhgFw9tlnc//993PBBRcU7tMZiCS1gLFjx7JmzRp27dpFZrJy5UomTZpUVZ8GiCS1gFmzZrFo0SKmTZvGSSedxP79+1myZElVfXoKS5JaxFVXXcVVV11Vs/6cgUiSCjFAJEmFGCCS1ACZ2ewSenW4NRogklRnAwcOZPv27X/WIZKZbN++nYEDB1a8jxfRJanO2tvb6ejoYNu2bc0u5ZAGDhxIe3t7xe0NEEmqs/79+zN+/Phml1FzTTmFFRFHRcRdEfHL8u9XHqTdvIjYGBGbIuLKLus/ExE/j4hHIuJ7ETGkYcVLkoDmXQO5EliZmROAleXlA0REG/AFYD4wGVgcEZPLm+8CpmTmycAvgH9sSNWSpD9pVoAsAL5efv114G09tJkJbMrMzZm5B1hW3o/M/FFmdpbbrQEqP2knSaqJZgXIMZm5FaD8e3gPbUYDT3VZ7iiv6+7dwO01r1CSdEh1u4geEXcDI3rY9LFKu+hh3QGfgYuIjwGdwLcOUccSYAmUbiYmSaqNugVIZv7twbZFxG8jYmRmbo2IkcCzPTTrAMZ0WW4HtnTp40LgzcCb8hAfrs7MpcBSgBkzZvz5fghbkvqYZp3CWg5cWH59IXBrD20eBCZExPiIGACcW96PiJgHXAG8NTN3NaBeSVI3zQqQq4E5EfFLYE55mYgYFRErAMoXyS8F7gQ2AN/OzMfL+18PDAbuioiHI+KGRg9AklpdU75ImJnbgTf1sH4LcFaX5RXAih7avaquBUqSeuW9sCRJhRggkqRCDBBJUiEGiCSpEANEklSIASJJKsQAkSQVYoBIkgoxQCRJhRggkqRCDBBJUiEGiCSpEANEklSIASJJKsQAkSQVYoBIkgoxQCRJhRggkqRCDBBJUiEGiCSpEANEklSIASJJKsQAkSQVYoBIkgoxQCRJhRggkqRCDBBJUiEGiCSpEANEklSIASJJKsQAkSQV0pQAiYijIuKuiPhl+fcrD9JuXkRsjIhNEXFlD9svj4iMiKH1r1qS1FWzZiBXAiszcwKwsrx8gIhoA74AzAcmA4sjYnKX7WOAOcBvGlKxJOkAzQqQBcDXy6+/DrythzYzgU2ZuTkz9wDLyvu95HPAR4CsY52SpINoVoAck5lbAcq/h/fQZjTwVJfljvI6IuKtwNOZub63A0XEkohYGxFrt23bVn3lkiQA+tWr44i4GxjRw6aPVdpFD+syIl5R7mNuJZ1k5lJgKcCMGTOcrUhSjdQtQDLzbw+2LSJ+GxEjM3NrRIwEnu2hWQcwpstyO7AFOB4YD6yPiJfWPxQRMzPzmZoNQJJ0SM06hbUcuLD8+kLg1h7aPAhMiIjxETEAOBdYnpmPZubwzByXmeMoBc00w0OSGqtZAXI1MCcifknpk1RXA0TEqIhYAZCZncClwJ3ABuDbmfl4k+qVJHVTt1NYh5KZ24E39bB+C3BWl+UVwIpe+hpX6/okSb3zm+iSpEIMEElSIQaIJKkQA0SSVIgBIkkqxACRJBVigEiSCjFAJEmFGCCSpEIMEElSIQaIJKkQA0SSVIgBIkkqxACRJBVigEiSCjFAJEmFGCCSpEIMEElSIQaIJKkQA0SSVIgBIkkqxACRJBVigEiSCjFAJEmFRGY2u4aGiYhtwK8L7j4U+F0Ny+kLHHNrcMytoZoxH5uZw7qvbKkAqUZErM3MGc2uo5Ecc2twzK2hHmP2FJYkqRADRJJUiAFSuaXNLqAJHHNrcMytoeZj9hqIJKkQZyCSpEIMEElSIQZINxExLyI2RsSmiLiyh+0REdeVtz8SEdOaUWctVTDm88tjfSQi7o+I1zSjzlrqbcxd2v1NROyLiEWNrK/WKhlvRMyOiIcj4vGI+N+NrrHWKvjv+q8j4gcRsb485oubUWctRcRXI+LZiHjsINtr+/6Vmf6Uf4A24FfAccAAYD0wuVubs4DbgQBOBf692XU3YMyvA15Zfj2/Fcbcpd0qYAWwqNl11/nfeAjwM2BseXl4s+tuwJg/Cnyq/HoY8B/AgGbXXuW4TwemAY8dZHtN37+cgRxoJrApMzdn5h5gGbCgW5sFwDeyZA0wJCJGNrrQGup1zJl5f2b+vry4BmhvcI21Vsm/M8AHge8AzzayuDqoZLznAd/NzN8AZGYrjDmBwRERwCBKAdLZ2DJrKzPvozSOg6np+5cBcqDRwFNdljvK6w63TV9yuON5D6W/YPqyXsccEaOBhcANDayrXir5Nz4BeGVE3BsRP42IdzWsuvqoZMzXA5OALcCjwGWZub8x5TVNTd+/+lVdzl+W6GFd9885V9KmL6l4PBFxBqUAOa2uFdVfJWO+BrgiM/eV/kDt0yoZbz9gOvAm4OXATyJiTWb+ot7F1UklY/5PwMPAmcDxwF0R8ePMfL7OtTVTTd+/DJADdQBjuiy3U/rr5HDb9CUVjSciTga+DMzPzO0Nqq1eKhnzDGBZOTyGAmdFRGdmfr8hFdZWpf9d/y4zdwI7I+I+4DVAXw2QSsZ8MXB1li4ObIqIJ4CJwAONKbEpavr+5SmsAz0ITIiI8RExADgXWN6tzXLgXeVPM5wK/CEztza60BrqdcwRMRb4LvDOPvwXaVe9jjkzx2fmuMwcB9wC/H0fDQ+o7L/rW4E3RES/iHgFMAvY0OA6a6mSMf+G0oyLiDgGeDWwuaFVNl5N37+cgXSRmZ0RcSlwJ6VPcXw1Mx+PiPeXt99A6RM5ZwGbgF2U/orpsyoc8z8BRwP/Wv6LvDP78J1MKxzzX4xKxpuZGyLiDuARYD/w5czs8aOgfUGF/8b/A7gxIh6ldGrniszs07d4j4ibgdnA0IjoAD4O9If6vH95KxNJUiGewpIkFWKASJIKMUAkSYUYIJKkQgwQSVIhBohUUEQMiYi/77I8KiJuqdOx3hYR/9RLm3+JiDPrcXypJ36MVyooIsYBt2XmlAYc637grYf6nkJEHAt8KTPn1rseCZyBSNW4Gji+/AyNz0TEuJeewxARF0XE98vPm3giIi6NiA9HxLqIWBMRR5XbHR8Rd5RvYPjjiJjY/SARcQLwx8z8XUQMLvfXv7ztyIh4MiL6Z+avgaMjYkQD/zdQCzNApOKuBH6VmVMz87/2sH0KpdukzwT+GdiVmacAPwFeutvtUuCDmTkduBz41x76eT3wEEBm7gDuBf6uvO1c4DuZube8/FC5vVR33spEqp97ym/4OyLiD8APyusfBU6OiEGUHtb1b13u+PuyHvoZCWzrsvxl4CPA9yndiuI/d9n2LDCqVgOQDsUAkernj11e7++yvJ/S//f+CnguM6f20s+LwF+/tJCZq8uny94ItHW7Z9XAcnup7jyFJRW3AxhcdOfycyeeiIi3w5+eV93T8+Y3AK/qtu4bwM3A17qtPwHoszdBVN9igEgFlZ+LsjoiHouIzxTs5nzgPRGxHnicnh+tex9wShz4ZKtvAa+kFCIAlC+svwpYW7AW6bD4MV6pD4iIa4EfZObd5eVFwILMfGeXNguBaZn535pUplqM10CkvuETlB7yRER8HphP6bkOXfUDPtvgutTCnIFIkgrxGogkqRADRJJUiAEiSSrEAJEkFWKASJIK+b8y4UNa7aeHlAAAAABJRU5ErkJggg==\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -167,7 +167,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] diff --git a/src/drift/drift.f90 b/src/drift/drift.f90 index 8bba1a273..4d9988f93 100644 --- a/src/drift/drift.f90 +++ b/src/drift/drift.f90 @@ -9,6 +9,81 @@ integer(I2B), parameter :: NLAG2 = 40 contains + + module subroutine drift_body(self, system, param, dt, mask) + !! author: David A. Minton + !! + !! Loop bodies and call Danby drift routine on the heliocentric position and velocities. + !! + !! Adapted from Hal Levison's Swift routine drift_tp.f + !! Adapted from David E. Kaufmann's Swifter routine whm_drift_tp.f90 + implicit none + ! Arguments + class(swiftest_body), intent(inout) :: self !! Swiftest test particle data structure + class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift. + ! Internals + integer(I4B) :: i + integer(I4B), dimension(:), allocatable :: iflag + + associate(n => self%nbody) + allocate(iflag(n)) + iflag(:) = 0 + call drift_all(self%mu, self%xh, self%vh, self%nbody, param, dt, mask, iflag) + if (any(iflag(1:n) /= 0)) then + where(iflag(1:n) /= 0) self%status(1:n) = DISCARDED_DRIFTERR + do i = 1, n + if (iflag(i) /= 0) write(*, *) " Body ", self%id(i), " lost due to error in Danby drift" + end do + end if + end associate + + return + end subroutine drift_body + + module pure subroutine drift_all(mu, x, v, n, param, dt, mask, iflag) + !! author: David A. Minton + !! + !! Loop bodies and call Danby drift routine on all bodies for the given position and velocity vector. + !! + !! Adapted from Hal Levison's Swift routine drift_tp.f + !! Adapted from David E. Kaufmann's Swifter routine whm_drift_tp.f9 + implicit none + ! Arguments + real(DP), dimension(:), intent(in) :: mu !! Vector of gravitational constants + real(DP), dimension(:,:), intent(inout) :: x, v !! Position and velocity vectors + integer(I4B), intent(in) :: n !! number of bodies + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift. + integer(I4B), dimension(:), intent(out) :: iflag !! Vector of error flags. 0 means no problem + ! Internals + integer(I4B) :: i + real(DP) :: energy, vmag2, rmag !! Variables used in GR calculation + real(DP), dimension(:), allocatable :: dtp + + if (n == 0) return + + allocate(dtp(n)) + if (param%lgr) then + do concurrent(i = 1:n, mask(i)) + rmag = norm2(x(:, i)) + vmag2 = dot_product(v(:, i), v(:, i)) + energy = 0.5_DP * vmag2 - mu(i) / rmag + dtp(i) = dt * (1.0_DP + 3 * param%inv_c2 * energy) + end do + else + where(mask(1:n)) dtp(1:n) = dt + end if + do concurrent(i = 1:n, mask(i)) + call drift_one(mu(i), x(1,i), x(2,i), x(3,i), v(1,i), v(2,i), v(3,i), dtp(i), iflag(i)) + end do + + return + end subroutine drift_all + module pure elemental subroutine drift_one(mu, px, py, pz, vx, vy, vz, dt, iflag) !! author: The Purdue Swiftest Team - David A. Minton, Carlisle A. Wishard, Jennifer L.L. Pouplin, and Jacob R. Elliott !! @@ -406,4 +481,5 @@ pure subroutine drift_kepu_stumpff(x, c0, c1, c2, c3) return end subroutine drift_kepu_stumpff + end submodule drift_implementation diff --git a/src/eucl/eucl.f90 b/src/eucl/eucl.f90 index 519a38d76..24af7fd6e 100644 --- a/src/eucl/eucl.f90 +++ b/src/eucl/eucl.f90 @@ -14,64 +14,24 @@ module subroutine eucl_dist_index_plpl(self) ! Arguments class(swiftest_pl), intent(inout) :: self !! Swiftest massive body objec ! Internals - integer(I4B) :: i, j, k, kp, p + integer(I8B) :: i, j, counter, npl - associate(npl => self%nbody, num_comparisons => self%num_comparisons, k_eucl => self%k_eucl) - num_comparisons = (npl * (npl - 1) / 2) ! number of entries in a strict lower triangle, nplm x npl, minus first column - if (allocated(self%k_eucl)) deallocate(self%k_eucl) ! Reset the index array if it's been set previously - if (allocated(self%irij3)) deallocate(self%irij3) - allocate(self%k_eucl(2, num_comparisons)) - allocate(self%irij3(num_comparisons)) - !do concurrent(k = 1:num_comparisons) !shared(num_comparisons, k_eucl, npl) local(kp, i, j, p) - do k = 1, num_comparisons - kp = npl * (npl - 1) / 2 - k - p = floor((sqrt(1._DP + 8 * kp) - 1._DP) / 2._DP) - i = k - (npl - 1) * (npl - 2) / 2 + p * (p + 1) / 2 + 1 - j = npl - 1 - p - k_eucl(1, k) = i - k_eucl(2, k) = j + npl = int(self%nbody, kind=I8B) + associate(nplpl => self%nplpl) + nplpl = (npl * (npl - 1) / 2) ! number of entries in a strict lower triangle, nplm x npl, minus first column + if (allocated(self%k_plpl)) deallocate(self%k_plpl) ! Reset the index array if it's been set previously + allocate(self%k_plpl(2, nplpl)) + do i = 1, npl + counter = (i - 1_I8B) * npl - i * (i - 1_I8B) / 2_I8B + 1_I8B + do j = i + 1_I8B, npl + self%k_plpl(1, counter) = i + self%k_plpl(2, counter) = j + counter = counter + 1_I8B + end do end do end associate return end subroutine eucl_dist_index_plpl - module subroutine eucl_dist_index_pltp(self, pl) - !! author: Jacob R. Elliott and David A. Minton - !! - !! Turns i,j indices into k index for use in the Euclidean distance matrix - !! - !! Reference: - !! - !! Mélodie Angeletti, Jean-Marie Bonny, Jonas Koko. Parallel Euclidean distance matrix computation on big datasets *. - !! 2019. hal-0204751 implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_pl), intent(inout) :: pl !! Swiftest massive body object - end subroutine eucl_dist_index_pltp - - module subroutine eucl_irij3_plpl(self) - !! author: Jacob R. Elliott and David A. Minton - !! - !! Efficient parallel loop-blocking algrorithm for evaluating the Euclidean distance matrix for planet-planet - implicit none - ! Arguments - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - ! Internals - integer(I4B) :: k, i, j - real(DP), dimension(NDIM) :: dx - real(DP) :: rji2 - - associate(k_eucl => self%k_eucl, xh => self%xh, irij3 => self%irij3, nk => self%num_comparisons) - do k = 1, nk - i = k_eucl(1, k) - j = k_eucl(2, k) - dx(:) = xh(:, j) - xh(:, i) - rji2 = dot_product(dx(:), dx(:)) - irij3(k) = 1.0_DP / (rji2 * sqrt(rji2)) - end do - end associate - - return - end subroutine eucl_irij3_plpl - end submodule s_eucl diff --git a/src/gr/gr.f90 b/src/gr/gr.f90 index 8831a93d5..7d794bf2b 100644 --- a/src/gr/gr.f90 +++ b/src/gr/gr.f90 @@ -108,7 +108,7 @@ module pure subroutine gr_pv2vh_body(self, param) implicit none ! Arguments class(swiftest_body), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters ! Internals integer(I4B) :: i real(DP), dimension(:,:), allocatable :: vh !! Temporary holder of pseudovelocity for in-place conversion @@ -207,7 +207,7 @@ module pure subroutine gr_vh2pv_body(self, param) implicit none ! Arguments class(swiftest_body), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters ! Internals integer(I4B) :: i real(DP), dimension(:,:), allocatable :: pv !! Temporary holder of pseudovelocity for in-place conversion diff --git a/src/helio/helio_drift.f90 b/src/helio/helio_drift.f90 index 40da379ee..0c146eea5 100644 --- a/src/helio/helio_drift.f90 +++ b/src/helio/helio_drift.f90 @@ -1,62 +1,75 @@ submodule (helio_classes) s_helio_drift use swiftest contains - module subroutine helio_drift_pl(self, system, param, dt) + module subroutine helio_drift_body(self, system, param, dt, mask) !! author: David A. Minton !! - !! Loop through massive bodies and call Danby drift routine - !! New vectorized version included + !! Loop through bodies and call Danby drift routine on democratic heliocentric coordinates !! !! Adapted from David E. Kaufmann's Swifter routine helio_drift.f90 !! Adapted from Hal Levison's Swift routine drift.f implicit none ! Arguments - class(helio_pl), intent(inout) :: self !! Helio massive body object - class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of - real(DP), intent(in) :: dt !! Stepsize) + class(swiftest_body), intent(inout) :: self !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift. ! Internals integer(I4B) :: i !! Loop counter real(DP) :: rmag, vmag2, energy integer(I4B), dimension(:),allocatable :: iflag !! Vectorized error code flag real(DP), dimension(:), allocatable :: dtp, mu - associate(pl => self, npl => self%nbody, cb => system%cb) - if (npl == 0) return - - allocate(iflag(npl)) + associate(n => self%nbody) + allocate(iflag(n)) iflag(:) = 0 - allocate(dtp(npl)) - allocate(mu(npl)) - mu = cb%Gmass - - if (param%lgr) then - do i = 1,npl - rmag = norm2(pl%xh(:, i)) - vmag2 = dot_product(pl%vb(:, i), pl%vb(:, i)) - energy = 0.5_DP * vmag2 - pl%mu(i) / rmag - dtp(i) = dt * (1.0_DP + 3 * param%inv_c2 * energy) - end do - else - dtp(:) = dt - end if - - call drift_one(mu(1:npl), pl%xh(1,1:npl), pl%xh(2,1:npl), pl%xh(3,1:npl), & - pl%vb(1,1:npl), pl%vb(2,1:npl), pl%vb(3,1:npl), & - dtp(1:npl), iflag(1:npl)) - if (any(iflag(1:npl) /= 0)) then - do i = 1, npl - write(*, *) " Planet ", pl%id(i), " is lost!!!!!!!!!!" - write(*, *) pl%xh(:,i) - write(*, *) pl%vb(:,i) - write(*, *) " stopping " - call util_exit(FAILURE) + allocate(mu(n)) + mu(:) = system%cb%Gmass + call drift_all(mu, self%xh, self%vb, self%nbody, param, dt, mask, iflag) + if (any(iflag(1:n) /= 0)) then + where(iflag(1:n) /= 0) self%status(1:n) = DISCARDED_DRIFTERR + do i = 1, n + if (iflag(i) /= 0) write(*, *) " Body ", self%id(i), " lost due to error in Danby drift" end do end if end associate + + return + end subroutine helio_drift_body + + module subroutine helio_drift_pl(self, system, param, dt, mask) + !! author: David A. Minton + !! + !! Wrapper function used to call the body drift routine from a helio_pl structure + implicit none + ! Arguments + class(helio_pl), intent(inout) :: self !! Helio massive body object + class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift. + + call helio_drift_body(self, system, param, dt, mask) return end subroutine helio_drift_pl + + module subroutine helio_drift_tp(self, system, param, dt, mask) + !! author: David A. Minton + !! + !! Wrapper function used to call the body drift routine from a helio_pl structure + implicit none + ! Arguments + class(helio_tp), intent(inout) :: self !! Helio massive body object + class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift. + + call helio_drift_body(self, system, param, dt, mask) + return + end subroutine helio_drift_tp module subroutine helio_drift_linear_pl(self, cb, dt, lbeg) !! author: David A. Minton @@ -93,57 +106,6 @@ module subroutine helio_drift_linear_pl(self, cb, dt, lbeg) return end subroutine helio_drift_linear_pl - module subroutine helio_drift_tp(self, system, param, dt) - !! author: David A. Minton - !! - !! Loop through test particles and call Danby drift routine - !! - !! Adapted from David E. Kaufmann's Swifter routine helio_drift_tp.f90 - !! Adapted from Hal Levison's Swift routine drift_tp.f - implicit none - ! Arguments - class(helio_tp), intent(inout) :: self !! Helio test particle object - class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of - real(DP), intent(in) :: dt !! Stepsize - ! Internals - integer(I4B) :: i !! Loop counter - real(DP) :: rmag, vmag2, energy - real(DP), dimension(:), allocatable :: dtp, mu - integer(I4B), dimension(:),allocatable :: iflag !! Vectorized error code flag - - associate(tp => self, ntp => self%nbody, cb => system%cb) - if (ntp == 0) return - allocate(iflag(ntp)) - allocate(dtp(ntp)) - iflag(:) = 0 - allocate(mu(ntp)) - mu = cb%Gmass - - if (param%lgr) then - do i = 1,ntp - rmag = norm2(tp%xh(:, i)) - vmag2 = dot_product(tp%vh(:, i), tp%vh(:, i)) - energy = 0.5_DP * vmag2 - tp%mu(i) / rmag - dtp(i) = dt * (1.0_DP + 3 * param%inv_c2 * energy) - end do - else - dtp(:) = dt - end if - call drift_one(mu(1:ntp), tp%xh(1,1:ntp), tp%xh(2,1:ntp), tp%xh(3,1:ntp), & - tp%vb(1,1:ntp), tp%vb(2,1:ntp), tp%vb(3,1:ntp), & - dtp(1:ntp), iflag(1:ntp)) - if (any(iflag(1:ntp) /= 0)) then - tp%status = DISCARDED_DRIFTERR - do i = 1, ntp - if (iflag(i) /= 0) write(*, *) "Particle ", tp%id(i), " lost due to error in Danby drift" - end do - end if - end associate - - return - end subroutine helio_drift_tp - module subroutine helio_drift_linear_tp(self, cb, dt, lbeg) !! author: David A. Minton !! diff --git a/src/helio/helio_getacch.f90 b/src/helio/helio_getacch.f90 index ca6f09fc1..098549eff 100644 --- a/src/helio/helio_getacch.f90 +++ b/src/helio/helio_getacch.f90 @@ -12,12 +12,13 @@ module subroutine helio_getacch_pl(self, system, param, t, lbeg) ! Arguments class(helio_pl), intent(inout) :: self !! Helio massive body particle data structure class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current simulation time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step associate(cb => system%cb, pl => self, npl => self%nbody) - call helio_getacch_int_pl(pl, t) + pl%ah(:,:) = 0.0_DP + call pl%accel_int() if (param%loblatecb) then cb%aoblbeg = cb%aobl call pl%accel_obl(system) @@ -46,18 +47,18 @@ module subroutine helio_getacch_tp(self, system, param, t, lbeg) ! Arguments class(helio_tp), intent(inout) :: self !! WHM test particle data structure class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step - ! Internals - logical, save :: lmalloc = .true. - integer(I4B) :: i - real(DP) :: r2, mu - real(DP), dimension(:), allocatable, save :: irh, irht - associate(tp => self, ntp => self%nbody, cb => system%cb, npl => system%pl%nbody) + associate(tp => self, cb => system%cb, pl => system%pl, npl => system%pl%nbody) + tp%ah(:,:) = 0.0_DP if (present(lbeg)) system%lbeg = lbeg - call helio_getacch_int_tp(tp, system, param, t) + if (system%lbeg) then + call tp%accel_int(pl%Gmass(:), pl%xbeg(:,:), npl) + else + call tp%accel_int(pl%Gmass(:), pl%xend(:,:), npl) + end if if (param%loblatecb) call tp%accel_obl(system) if (param%lextra_force) call tp%accel_user(system, param, t) !if (param%lgr) call tp%gr_accel(param) @@ -65,79 +66,4 @@ module subroutine helio_getacch_tp(self, system, param, t, lbeg) return end subroutine helio_getacch_tp - subroutine helio_getacch_int_pl(pl, t) - !! author: David A. Minton - !! - !! Compute direct cross term heliocentric accelerations of massive bodiese - !! - !! Adapted from David E. Kaufmann's Swifter routine helio_getacch_int.f90 - !! Adapted from Hal Levison's Swift routine getacch_ah3.f - implicit none - ! Arguments - class(helio_pl), intent(inout) :: pl !! Helio massive body particle data structure - real(DP), intent(in) :: t !! Current time - ! Internals - integer(I4B) :: i, j - real(DP) :: rji2, irij3, faci, facj - real(DP), dimension(NDIM) :: dx - - associate(npl => pl%nbody) - pl%ah(:,:) = 0.0_DP - do i = 1, npl - 1 - do j = i + 1, npl - dx(:) = pl%xh(:,j) - pl%xh(:,i) - rji2 = dot_product(dx(:), dx(:)) - irij3 = 1.0_DP / (rji2 * sqrt(rji2)) - faci = pl%Gmass(i) * irij3 - facj = pl%Gmass(j) * irij3 - pl%ah(:,i) = pl%ah(:,i) + facj * dx(:) - pl%ah(:,j) = pl%ah(:,j) - faci * dx(:) - end do - end do - end associate - - return - end subroutine helio_getacch_int_pl - - subroutine helio_getacch_int_tp(tp, system, param, t) - !! author: David A. Minton - !! - !! Compute direct cross term heliocentric accelerations of test particles - !! - !! Adapted from David E. Kaufmann's Swifter routine helio_getacch_int_tp.f90 - !! Adapted from Hal Levison's Swift routine getacch_ah3_tp.f - implicit none - ! Arguments - class(helio_tp), intent(inout) :: tp !! Helio test particle object - class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of - real(DP), intent(in) :: t !! Current times - ! Internals - integer(I4B) :: i, j - real(DP) :: r2, fac - real(DP), dimension(NDIM) :: dx - real(DP), dimension(:, :), allocatable :: xhp - - associate(ntp => tp%nbody, pl => system%pl, npl => system%pl%nbody, lbeg => system%lbeg) - if (lbeg) then - allocate(xhp, source=pl%xbeg) - else - allocate(xhp, source=pl%xend) - end if - - tp%ah(:,:) = 0.0_DP - do i = 1, ntp - if (tp%status(i) == ACTIVE) then - do j = 1, npl - dx(:) = tp%xh(:,i) - xhp(:,j) - r2 = dot_product(dx(:), dx(:)) - fac = pl%Gmass(j) / (r2 * sqrt(r2)) - tp%ah(:,i) = tp%ah(:,i) - fac * dx(:) - end do - end if - end do - end associate - return - end subroutine helio_getacch_int_tp - end submodule s_helio_getacch diff --git a/src/helio/helio_step.f90 b/src/helio/helio_step.f90 index d37b21bbb..511ffacb6 100644 --- a/src/helio/helio_step.f90 +++ b/src/helio/helio_step.f90 @@ -53,7 +53,7 @@ module subroutine helio_step_pl(self, system, param, t, dt) call pl%accel(system, param, t) call pl%kick(dth) call pl%set_beg_end(xbeg = pl%xh) - call pl%drift(system, param, dt) + call pl%drift(system, param, dt, pl%status(:) == ACTIVE) call pl%set_beg_end(xend = pl%xh) call pl%accel(system, param, t + dt) call pl%kick(dth) @@ -97,7 +97,7 @@ module subroutine helio_step_tp(self, system, param, t, dt) call tp%lindrift(cb, dth, lbeg=.true.) call tp%accel(system, param, t, lbeg=.true.) call tp%kick(dth) - call tp%drift(system, param, dt) + call tp%drift(system, param, dt, tp%status(:) == ACTIVE) call tp%accel(system, param, t + dt, lbeg=.false.) call tp%kick(dth) call tp%lindrift(cb, dth, lbeg=.false.) diff --git a/src/io/io.f90 b/src/io/io.f90 index 2bb46ae0e..cf4772a8f 100644 --- a/src/io/io.f90 +++ b/src/io/io.f90 @@ -429,14 +429,14 @@ module subroutine io_dump_system(self, param, msg) !! so that if a dump file gets corrupted during writing, the user can restart from the older one. implicit none ! Arguments - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - character(*), optional, intent(in) :: msg !! Message to display with dump operation + class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + character(*), optional, intent(in) :: msg !! Message to display with dump operation ! Internals - class(swiftest_parameters), allocatable :: dump_param !! Local parameters variable used to parameters change input file names - !! to dump file-specific values without changing the user-defined values - integer(I4B), save :: idx = 1 !! Index of current dump file. Output flips between 2 files for extra security - !! in case the program halts during writing + class(swiftest_parameters), allocatable :: dump_param !! Local parameters variable used to parameters change input file names + !! to dump file-specific values without changing the user-defined values + integer(I4B), save :: idx = 1 !! Index of current dump file. Output flips between 2 files for extra security + !! in case the program halts during writing character(len=:), allocatable :: param_file_name real(DP) :: tfrac @@ -447,6 +447,7 @@ module subroutine io_dump_system(self, param, msg) dump_param%intpfile = trim(adjustl(DUMP_TP_FILE(idx))) dump_param%out_form = XV dump_param%out_stat = 'APPEND' + dump_param%T0 = param%t call dump_param%dump(param_file_name) call self%cb%dump(dump_param) @@ -975,26 +976,6 @@ function io_read_hdr(iu, t, npl, ntp, out_form, out_type) result(ierr) return end function io_read_hdr - module subroutine io_read_initialize_system(self, param) - !! author: David A. Minton - !! - !! Wrapper method to initialize a basic Swiftest nbody system from files - !! - implicit none - ! Arguments - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - - call self%cb%initialize(param) - call self%pl%initialize(param) - if (.not.param%lrhill_present) call self%pl%set_rhill(self%cb) - call self%tp%initialize(param) - call self%set_msys() - call self%pl%set_mu(self%cb) - call self%tp%set_mu(self%cb) - - end subroutine io_read_initialize_system - module subroutine io_toupper(string) !! author: David A. Minton !! diff --git a/src/kick/kick.f90 b/src/kick/kick.f90 index a54677dcd..efad4702a 100644 --- a/src/kick/kick.f90 +++ b/src/kick/kick.f90 @@ -1,7 +1,75 @@ submodule(swiftest_classes) s_kick use swiftest contains - module subroutine kickvh_body(self, dt) + module pure subroutine kick_getacch_int_pl(self) + !! author: David A. Minton + !! + !! Compute direct cross (third) term heliocentric accelerations of massive bodies + !! + !! Adapted from Hal Levison's Swift routine getacch_ah3.f + !! Adapted from David E. Kaufmann's Swifter routine whm_getacch_ah3.f90 and helio_getacch_int.f90 + implicit none + ! Arguments + class(swiftest_pl), intent(inout) :: self + ! Internals + integer(I4B) :: k + real(DP) :: rji2, irij3, faci, facj + real(DP), dimension(NDIM) :: dx + + associate(pl => self, npl => self%nbody, nplpl => self%nplpl) + do k = 1, nplpl + associate(i => pl%k_plpl(1, k), j => pl%k_plpl(2, k)) + dx(:) = pl%xh(:, j) - pl%xh(:, i) + rji2 = dot_product(dx(:), dx(:)) + irij3 = 1.0_DP / (rji2 * sqrt(rji2)) + faci = pl%Gmass(i) * irij3 + facj = pl%Gmass(j) * irij3 + pl%ah(:, i) = pl%ah(:, i) + facj * dx(:) + pl%ah(:, j) = pl%ah(:, j) - faci * dx(:) + end associate + end do + end associate + + return + end subroutine kick_getacch_int_pl + + module pure subroutine kick_getacch_int_tp(self, GMpl, xhp, npl) + !! author: David A. Minton + !! + !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies + !! + !! Adapted from Hal Levison's Swift routine getacch_ah3_tp.f + !! Adapted from David E. Kaufmann's Swifter routine whm_getacch_ah3.f90 and helio_getacch_int_tp.f90 + implicit none + ! Arguments + class(swiftest_tp), intent(inout) :: self !! Swiftest test particle + real(DP), dimension(:), intent(in) :: GMpl !! Massive body masses + real(DP), dimension(:,:), intent(in) :: xhp !! Massive body position vectors + integer(I4B), intent(in) :: npl !! Number of active massive bodies + ! Internals + integer(I4B) :: i, j + real(DP) :: rji2, irij3, fac, r2 + real(DP), dimension(NDIM) :: dx, acc + + associate(tp => self, ntp => self%nbody) + do concurrent(i = 1:ntp, tp%status(i) == ACTIVE) + acc(:) = 0.0_DP + do j = 1, npl + dx(:) = tp%xh(:,i) - xhp(:, j) + !rji2 = dot_product(dx(:), dx(:)) + !irij3 = 1.0_DP / (rji2 * sqrt(rji2)) + !fac = GMpl(j) * irij3 + r2 = dot_product(dx(:), dx(:)) + fac = GMpl(j) / (r2 * sqrt(r2)) + acc(:) = acc(:) - fac * dx(:) + end do + tp%ah(:, i) = tp%ah(:, i) + acc(:) + end do + end associate + return + end subroutine kick_getacch_int_tp + + module subroutine kick_vh_body(self, dt) !! author: David A. Minton !! !! Kick heliocentric velocities of bodies @@ -23,6 +91,8 @@ module subroutine kickvh_body(self, dt) end associate return - end subroutine kickvh_body + end subroutine kick_vh_body + + end submodule s_kick diff --git a/src/modules/helio_classes.f90 b/src/modules/helio_classes.f90 index 190c354b7..17366e88f 100644 --- a/src/modules/helio_classes.f90 +++ b/src/modules/helio_classes.f90 @@ -52,8 +52,8 @@ module helio_classes contains procedure, public :: vh2vb => helio_coord_vh2vb_tp !! Convert test particles from heliocentric to barycentric coordinates (velocity only) procedure, public :: vb2vh => helio_coord_vb2vh_tp !! Convert test particles from barycentric to heliocentric coordinates (velocity only) - procedure, public :: drift => helio_drift_tp !! Method for Danby drift in Democratic Heliocentric coordinates procedure, public :: lindrift => helio_drift_linear_tp !! Method for linear drift of massive bodies due to barycentric momentum of Sun + procedure, public :: drift => helio_drift_tp !! Method for Danby drift in Democratic Heliocentric coordinates procedure, public :: accel => helio_getacch_tp !! Compute heliocentric accelerations of massive bodies procedure, public :: kick => helio_kickvb_tp !! Kicks the barycentric velocities procedure, public :: step => helio_step_tp !! Steps the body forward one stepsize @@ -85,25 +85,37 @@ module subroutine helio_coord_vh2vb_tp(self, vbcb) class(helio_tp), intent(inout) :: self !! Helio massive body object real(DP), dimension(:), intent(in) :: vbcb !! Barycentric velocity of the central body end subroutine helio_coord_vh2vb_tp + + module subroutine helio_drift_body(self, system, param, dt, mask) + use swiftest_classes, only : swiftest_body, swiftest_nbody_system, swiftest_parameters + implicit none + class(swiftest_body), intent(inout) :: self !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift + end subroutine helio_drift_body - module subroutine helio_drift_pl(self, system, param, dt) + module subroutine helio_drift_pl(self, system, param, dt, mask) use swiftest_classes, only : swiftest_nbody_system, swiftest_parameters implicit none class(helio_pl), intent(inout) :: self !! Helio massive body object class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift end subroutine helio_drift_pl - module subroutine helio_drift_tp(self, system, param, dt) + module subroutine helio_drift_tp(self, system, param, dt, mask) use swiftest_classes, only : swiftest_nbody_system, swiftest_parameters implicit none - class(helio_tp), intent(inout) :: self !! Helio test particle object + class(helio_tp), intent(inout) :: self !! Helio massive body object class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift end subroutine helio_drift_tp - + module subroutine helio_drift_linear_pl(self, cb, dt, lbeg) implicit none class(helio_pl), intent(inout) :: self !! Helio massive body object @@ -125,7 +137,7 @@ module subroutine helio_getacch_pl(self, system, param, t, lbeg) implicit none class(helio_pl), intent(inout) :: self !! Helio massive body object class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current simulation time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step end subroutine helio_getacch_pl @@ -165,10 +177,10 @@ end subroutine helio_step_pl module subroutine helio_step_system(self, param, t, dt) use swiftest_classes, only : swiftest_parameters implicit none - class(helio_nbody_system), intent(inout) :: self !! Helio nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Simulation time - real(DP), intent(in) :: dt !! Current stepsize + class(helio_nbody_system), intent(inout) :: self !! Helio nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! Simulation time + real(DP), intent(in) :: dt !! Current stepsize end subroutine helio_step_system module subroutine helio_step_tp(self, system, param, t, dt) diff --git a/src/modules/rmvs_classes.f90 b/src/modules/rmvs_classes.f90 index a523e8643..8d0fb1f18 100644 --- a/src/modules/rmvs_classes.f90 +++ b/src/modules/rmvs_classes.f90 @@ -54,7 +54,7 @@ module rmvs_classes !! RMVS test particle class type, public, extends(whm_tp) :: rmvs_tp !! Note to developers: If you add componenets to this class, be sure to update methods and subroutines that traverse the - !! component list, such as rmvs_setup_tp and rmvs_spill_tp + !! component list, such as rmvs_setup_tp and rmvs_util_spill_tp ! encounter steps) logical, dimension(:), allocatable :: lperi !! planetocentric pericenter passage flag (persistent for a full rmvs time step) over a full RMVS time step) integer(I4B), dimension(:), allocatable :: plperP !! index of planet associated with pericenter distance peri (persistent over a full RMVS time step) @@ -70,11 +70,11 @@ module rmvs_classes private procedure, public :: discard => rmvs_discard_tp !! Check to see if test particles should be discarded based on pericenter passage distances with respect to planets encountered procedure, public :: encounter_check => rmvs_encounter_check_tp !! Checks if any test particles are undergoing a close encounter with a massive body - procedure, public :: fill => rmvs_fill_tp !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) + procedure, public :: fill => rmvs_util_fill_tp !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) procedure, public :: accel => rmvs_getacch_tp !! Calculates either the standard or modified version of the acceleration depending if the !! if the test particle is undergoing a close encounter or not procedure, public :: setup => rmvs_setup_tp !! Constructor method - Allocates space for number of particles - procedure, public :: spill => rmvs_spill_tp !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) + procedure, public :: spill => rmvs_util_spill_tp !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) end type rmvs_tp !******************************************************************************************************************************** @@ -92,12 +92,18 @@ module rmvs_classes logical :: lplanetocentric = .false. !! Flag that indicates that the object is a planetocentric set of masive bodies used for close encounter calculations contains private - procedure, public :: fill => rmvs_fill_pl !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) + procedure, public :: fill => rmvs_util_fill_pl !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) procedure, public :: setup => rmvs_setup_pl !! Constructor method - Allocates space for number of particles - procedure, public :: spill => rmvs_spill_pl !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) + procedure, public :: spill => rmvs_util_spill_pl !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) end type rmvs_pl interface + module elemental function rmvs_chk_ind(r2, v2, vdotr, dt, r2crit) result(lflag) + implicit none + real(DP), intent(in) :: r2, v2, vdotr, dt, r2crit + logical :: lflag + end function rmvs_chk_ind + module subroutine rmvs_discard_tp(self, system, param) use swiftest_classes, only : swiftest_nbody_system, swiftest_parameters implicit none @@ -114,21 +120,21 @@ module function rmvs_encounter_check_tp(self, system, dt) result(lencounter) logical :: lencounter !! Returns true if there is at least one close encounter end function rmvs_encounter_check_tp - module subroutine rmvs_fill_pl(self, inserts, lfill_list) + module subroutine rmvs_util_fill_pl(self, inserts, lfill_list) use swiftest_classes, only : swiftest_body implicit none class(rmvs_pl), intent(inout) :: self !! RMVS massive body object class(swiftest_body), intent(inout) :: inserts !! Inserted object logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps - end subroutine rmvs_fill_pl + end subroutine rmvs_util_fill_pl - module subroutine rmvs_fill_tp(self, inserts, lfill_list) + module subroutine rmvs_util_fill_tp(self, inserts, lfill_list) use swiftest_classes, only : swiftest_body implicit none class(rmvs_tp), intent(inout) :: self !! RMVS massive body object class(swiftest_body), intent(inout) :: inserts !! Inserted object logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps - end subroutine rmvs_fill_tp + end subroutine rmvs_util_fill_tp module subroutine rmvs_getacch_tp(self, system, param, t, lbeg) use swiftest_classes, only : swiftest_nbody_system, swiftest_parameters @@ -159,21 +165,21 @@ module subroutine rmvs_setup_tp(self,n) integer, intent(in) :: n !! Number of test particles to allocate end subroutine rmvs_setup_tp - module subroutine rmvs_spill_pl(self, discards, lspill_list) + module subroutine rmvs_util_spill_pl(self, discards, lspill_list) use swiftest_classes, only : swiftest_body implicit none class(rmvs_pl), intent(inout) :: self !! RMVS massive body object class(swiftest_body), intent(inout) :: discards !! Discarded object logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discards - end subroutine rmvs_spill_pl + end subroutine rmvs_util_spill_pl - module subroutine rmvs_spill_tp(self, discards, lspill_list) + module subroutine rmvs_util_spill_tp(self, discards, lspill_list) use swiftest_classes, only : swiftest_body implicit none class(rmvs_tp), intent(inout) :: self !! RMVS test particle object class(swiftest_body), intent(inout) :: discards !! Discarded object logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discards - end subroutine rmvs_spill_tp + end subroutine rmvs_util_spill_tp module subroutine rmvs_step_system(self, param, t, dt) use swiftest_classes, only : swiftest_parameters diff --git a/src/modules/swiftest_classes.f90 b/src/modules/swiftest_classes.f90 index 13ee255cc..5c6b83bdc 100644 --- a/src/modules/swiftest_classes.f90 +++ b/src/modules/swiftest_classes.f90 @@ -7,21 +7,21 @@ module swiftest_classes implicit none private public :: discard_pl, discard_system, discard_tp - public :: drift_one - public :: eucl_dist_index_plpl, eucl_dist_index_pltp, eucl_irij3_plpl + public :: drift_all, drift_body, drift_one + public :: eucl_dist_index_plpl public :: gr_getaccb_ns_body, gr_p4_pos_kick, gr_pseudovel2vel, gr_vel2pseudovel public :: io_dump_param, io_dump_swiftest, io_dump_system, io_get_args, io_get_token, io_param_reader, io_param_writer, io_read_body_in, & - io_read_cb_in, io_read_param_in, io_read_frame_body, io_read_frame_cb, io_read_frame_system, io_read_initialize_system, & + io_read_cb_in, io_read_param_in, io_read_frame_body, io_read_frame_cb, io_read_frame_system, & io_toupper, io_write_discard, io_write_encounter, io_write_frame_body, io_write_frame_cb, io_write_frame_system - public :: kickvh_body + public :: kick_getacch_int_pl, kick_vh_body public :: obl_acc_body, obl_acc_pl, obl_acc_tp public :: orbel_el2xv_vec, orbel_xv2el_vec, orbel_scget, orbel_xv2aeq, orbel_xv2aqt - public :: setup_body, setup_construct_system, setup_pl, setup_tp + public :: setup_body, setup_construct_system, setup_initialize_system, setup_pl, setup_tp public :: tides_getacch_pl, tides_step_spin_system public :: user_getacch_body public :: util_coord_b2h_pl, util_coord_b2h_tp, util_coord_h2b_pl, util_coord_h2b_tp, util_exit, util_fill_body, util_fill_pl, util_fill_tp, & util_index, util_peri_tp, util_reverse_status, util_set_beg_end_pl, util_set_ir3h, util_set_msys, util_set_mu_pl, & - util_set_mu_tp, util_set_rhill, util_sort, util_spill_body, util_spill_pl, util_spill_tp, util_valid, util_version + util_set_mu_tp, util_set_rhill, util_set_rhill_approximate, util_sort, util_spill_body, util_spill_pl, util_spill_tp, util_valid, util_version !******************************************************************************************************************************** ! swiftest_parameters class definitions @@ -162,8 +162,6 @@ module swiftest_classes real(DP), dimension(:), allocatable :: omega !! Argument of pericenter real(DP), dimension(:), allocatable :: capm !! Mean anomaly real(DP), dimension(:), allocatable :: mu !! G * (Mcb + [m]) - integer(I4B), dimension(:,:), allocatable :: k_eucl !! Index array used to convert flattened the body-body comparison upper triangular matrix - integer(I8B) :: num_comparisons !! Number of body-body comparisons in the flattened upper triangular matrix !! Note to developers: If you add components to this class, be sure to update methods and subroutines that traverse the !! component list, such as setup_body and util_spill contains @@ -173,12 +171,13 @@ module swiftest_classes procedure(abstract_step_body), public, deferred :: step procedure(abstract_accel), public, deferred :: accel ! These are concrete because the implementation is the same for all types of particles + procedure, public :: drift => drift_body !! Loop through bodies and call Danby drift routine on heliocentric variables procedure, public :: v2pv => gr_vh2pv_body !! Converts from velocity to psudeovelocity for GR calculations using symplectic integrators procedure, public :: pv2v => gr_pv2vh_body !! Converts from psudeovelocity to velocity for GR calculations using symplectic integrators procedure, public :: initialize => io_read_body_in !! Read in body initial conditions from a file procedure, public :: read_frame => io_read_frame_body !! I/O routine for writing out a single frame of time-series data for the central body procedure, public :: write_frame => io_write_frame_body !! I/O routine for writing out a single frame of time-series data for the central body - procedure, public :: kick => kickvh_body !! Kicks the heliocentric velocities + procedure, public :: kick => kick_vh_body !! Kicks the heliocentric velocities procedure, public :: accel_obl => obl_acc_body !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure, public :: el2xv => orbel_el2xv_vec !! Convert orbital elements to position and velocity vectors procedure, public :: xv2el => orbel_xv2el_vec !! Convert position and velocity vectors to orbital elements @@ -200,7 +199,6 @@ module swiftest_classes real(DP), dimension(:), allocatable :: Gmass !! Mass gravitational term G * mass (units GU * MU) real(DP), dimension(:), allocatable :: rhill !! Body mass (units MU) real(DP), dimension(:), allocatable :: radius !! Body radius (units DU) - real(DP), dimension(:), allocatable :: irij3 !! 1.0_DP / (rji2 * sqrt(rji2)) where rji2 is the square of the Euclidean distance real(DP), dimension(:,:), allocatable :: xbeg !! Position at beginning of step real(DP), dimension(:,:), allocatable :: xend !! Position at end of step real(DP), dimension(:,:), allocatable :: vbeg !! Velocity at beginning of step @@ -209,7 +207,9 @@ module swiftest_classes real(DP), dimension(:,:), allocatable :: rot !! Body rotation vector in inertial coordinate frame (units rad / TU) real(DP), dimension(:), allocatable :: k2 !! Tidal Love number real(DP), dimension(:), allocatable :: Q !! Tidal quality factor - real(DP), dimension(:), allocatable :: tlag !! Tidal phase lag + real(DP), dimension(:), allocatable :: tlag !! Tidal phase lag + integer(I4B), dimension(:,:), allocatable :: k_plpl !! Index array used to convert flattened the body-body comparison upper triangular matrix + integer(I8B) :: nplpl !! Number of body-body comparisons in the flattened upper triangular matrix !! Note to developers: If you add components to this class, be sure to update methods and subroutines that traverse the !! component list, such as setup_pl and util_spill_pl contains @@ -218,10 +218,10 @@ module swiftest_classes ! These are concrete because they are the same implemenation for all integrators procedure, public :: discard => discard_pl !! Placeholder method for discarding massive bodies procedure, public :: eucl_index => eucl_dist_index_plpl !! Sets up the (i, j) -> k indexing used for the single-loop blocking Euclidean distance matrix - procedure, public :: eucl_irij3 => eucl_irij3_plpl !! Parallelized single loop blocking for Euclidean distance matrix calcualtion + procedure, public :: accel_int => kick_getacch_int_pl !! Compute direct cross (third) term heliocentric accelerations of massive bodies procedure, public :: accel_obl => obl_acc_pl !! Compute the barycentric accelerations of bodies due to the oblateness of the central body - procedure, public :: accel_tides => tides_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body procedure, public :: setup => setup_pl !! A base constructor that sets the number of bodies and allocates and initializes all arrays + procedure, public :: accel_tides => tides_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body procedure, public :: set_mu => util_set_mu_pl !! Method used to construct the vectorized form of the central body mass procedure, public :: set_rhill => util_set_rhill !! Calculates the Hill's radii for each body procedure, public :: h2b => util_coord_h2b_pl !! Convert massive bodies from heliocentric to barycentric coordinates (position and velocity) @@ -240,23 +240,22 @@ module swiftest_classes integer(I4B), dimension(:), allocatable :: isperi !! Perihelion passage flag real(DP), dimension(:), allocatable :: peri !! Perihelion distance real(DP), dimension(:), allocatable :: atp !! Semimajor axis following perihelion passage - real(DP), dimension(:, :), allocatable :: irij3 !! 1.0_DP / (rji2 * sqrt(rji2)) where rji2 is the square of the Euclidean distance betwen each pl-tp !! Note to developers: If you add components to this class, be sure to update methods and subroutines that traverse the !! component list, such as setup_tp and util_spill_tp contains private ! Test particle-specific concrete methods ! These are concrete because they are the same implemenation for all integrators - procedure, public :: discard => discard_tp !! Check to see if test particles should be discarded based on their positions relative to the massive bodies - procedure, public :: eucl_index => eucl_dist_index_pltp !! Sets up the (i, j) -> k indexing used for the single-loop blocking Euclidean distance matrix - procedure, public :: accel_obl => obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body - procedure, public :: setup => setup_tp !! A base constructor that sets the number of bodies and - procedure, public :: set_mu => util_set_mu_tp !! Method used to construct the vectorized form of the central body mass - procedure, public :: h2b => util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) - procedure, public :: b2h => util_coord_b2h_tp !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) - procedure, public :: fill => util_fill_tp !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) - procedure, public :: get_peri => util_peri_tp !! Determine system pericenter passages for test particles - procedure, public :: spill => util_spill_tp !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) + procedure, public :: discard => discard_tp !! Check to see if test particles should be discarded based on their positions relative to the massive bodies + procedure, public :: accel_int => kick_getacch_int_tp !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies + procedure, public :: accel_obl => obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body + procedure, public :: setup => setup_tp !! A base constructor that sets the number of bodies and + procedure, public :: set_mu => util_set_mu_tp !! Method used to construct the vectorized form of the central body mass + procedure, public :: h2b => util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) + procedure, public :: b2h => util_coord_b2h_tp !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) + procedure, public :: fill => util_fill_tp !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) + procedure, public :: get_peri => util_peri_tp !! Determine system pericenter passages for test particles + procedure, public :: spill => util_spill_tp !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) end type swiftest_tp !******************************************************************************************************************************** @@ -287,14 +286,14 @@ module swiftest_classes procedure(abstract_step_system), public, deferred :: step ! Concrete classes that are common to the basic integrator (only test particles considered for discard) - procedure, public :: discard => discard_system !! Perform a discard step on the system - procedure, public :: dump => io_dump_system !! Dump the state of the system to a file - procedure, public :: initialize => io_read_initialize_system !! Initialize the system from an input file - procedure, public :: read_frame => io_read_frame_system !! Append a frame of output data to file - procedure, public :: write_discard => io_write_discard !! Append a frame of output data to file - procedure, public :: write_frame => io_write_frame_system !! Append a frame of output data to file - procedure, public :: step_spin => tides_step_spin_system !! Steps the spins of the massive & central bodies due to tides. - procedure, public :: set_msys => util_set_msys !! Sets the value of msys from the masses of system bodies. + procedure, public :: discard => discard_system !! Perform a discard step on the system + procedure, public :: dump => io_dump_system !! Dump the state of the system to a file + procedure, public :: initialize => setup_initialize_system !! Initialize the system from input files + procedure, public :: read_frame => io_read_frame_system !! Append a frame of output data to file + procedure, public :: write_discard => io_write_discard !! Append a frame of output data to file + procedure, public :: write_frame => io_write_frame_system !! Append a frame of output data to file + procedure, public :: step_spin => tides_step_spin_system !! Steps the spins of the massive & central bodies due to tides. + procedure, public :: set_msys => util_set_msys !! Sets the value of msys from the masses of system bodies. end type swiftest_nbody_system abstract interface @@ -309,7 +308,7 @@ subroutine abstract_accel(self, system, param, t, lbeg) import swiftest_body, swiftest_nbody_system, swiftest_parameters, DP class(swiftest_body), intent(inout) :: self !! Swiftest body data structure class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current simulation time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step end subroutine abstract_accel @@ -383,6 +382,26 @@ module subroutine discard_tp(self, system, param) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine discard_tp + module pure subroutine drift_all(mu, x, v, n, param, dt, mask, iflag) + implicit none + real(DP), dimension(:), intent(in) :: mu !! Vector of gravitational constants + real(DP), dimension(:,:), intent(inout) :: x, v !! Position and velocity vectors + integer(I4B), intent(in) :: n !! number of bodies + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift. + integer(I4B), dimension(:), intent(out) :: iflag !! Vector of error flags. 0 means no problem + end subroutine drift_all + + module subroutine drift_body(self, system, param, dt, mask) + implicit none + class(swiftest_body), intent(inout) :: self !! Swiftest particle data structure + class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift + end subroutine drift_body + module pure elemental subroutine drift_one(mu, px, py, pz, vx, vy, vz, dt, iflag) implicit none real(DP), intent(in) :: mu !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body to drift @@ -396,17 +415,6 @@ module subroutine eucl_dist_index_plpl(self) class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object end subroutine - module subroutine eucl_dist_index_pltp(self, pl) - implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_pl), intent(inout) :: pl !! Swiftest massive body object - end subroutine - - module subroutine eucl_irij3_plpl(self) - implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - end subroutine eucl_irij3_plpl - module pure subroutine gr_getaccb_ns_body(self, system, param) implicit none class(swiftest_body), intent(inout) :: self !! Swiftest generic body object @@ -434,7 +442,7 @@ end subroutine gr_pseudovel2vel module pure subroutine gr_pv2vh_body(self, param) implicit none class(swiftest_body), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine gr_pv2vh_body module pure subroutine gr_vel2pseudovel(param, mu, xh, vh, pv) @@ -449,7 +457,7 @@ end subroutine gr_vel2pseudovel module pure subroutine gr_vh2pv_body(self, param) implicit none class(swiftest_body), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine gr_vh2pv_body module subroutine io_dump_param(self, param_file_name) @@ -555,12 +563,6 @@ module subroutine io_read_frame_system(self, iu, param, form, ierr) integer(I4B), intent(out) :: ierr !! Error code end subroutine io_read_frame_system - module subroutine io_read_initialize_system(self, param) - implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - end subroutine io_read_initialize_system - module subroutine io_write_discard(self, param) implicit none class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object @@ -602,11 +604,24 @@ module subroutine io_write_frame_system(self, iu, param) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine io_write_frame_system - module subroutine kickvh_body(self, dt) + module pure subroutine kick_getacch_int_pl(self) + implicit none + class(swiftest_pl), intent(inout) :: self + end subroutine kick_getacch_int_pl + + module pure subroutine kick_getacch_int_tp(self, GMpl, xhp, npl) + implicit none + class(swiftest_tp), intent(inout) :: self !! Swiftest test particle + real(DP), dimension(:), intent(in) :: GMpl !! Massive body masses + real(DP), dimension(:,:), intent(in) :: xhp !! Massive body position vectors + integer(I4B), intent(in) :: npl !! Number of active massive bodies + end subroutine kick_getacch_int_tp + + module subroutine kick_vh_body(self, dt) implicit none class(swiftest_body), intent(inout) :: self !! Swiftest body object real(DP), intent(in) :: dt !! Stepsize - end subroutine kickvh_body + end subroutine kick_vh_body module subroutine obl_acc_body(self, system) implicit none @@ -670,6 +685,12 @@ module subroutine setup_construct_system(system, param) type(swiftest_parameters), intent(in) :: param !! Swiftest parameters end subroutine setup_construct_system + module subroutine setup_initialize_system(self, param) + implicit none + class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + end subroutine setup_initialize_system + module subroutine setup_pl(self,n) implicit none class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object @@ -806,8 +827,14 @@ end subroutine util_set_mu_tp module subroutine util_set_rhill(self,cb) implicit none class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object end subroutine util_set_rhill + + module subroutine util_set_rhill_approximate(self,cb) + implicit none + class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + end subroutine util_set_rhill_approximate end interface interface util_sort diff --git a/src/modules/swiftest_globals.f90 b/src/modules/swiftest_globals.f90 index 256c4124b..a1f0d7511 100644 --- a/src/modules/swiftest_globals.f90 +++ b/src/modules/swiftest_globals.f90 @@ -100,10 +100,10 @@ module swiftest_globals !> Standard file names integer(I4B), parameter :: NDUMPFILES = 2 - character(*), dimension(2), parameter :: DUMP_CB_FILE = (/ 'dump_cb1.bin', 'dump_cb2.bin' /) - character(*), dimension(2), parameter :: DUMP_PL_FILE = (/ 'dump_pl1.bin', 'dump_pl2.bin' /) - character(*), dimension(2), parameter :: DUMP_TP_FILE = (/ 'dump_tp1.bin', 'dump_tp2.bin' /) - character(*), dimension(2), parameter :: DUMP_PARAM_FILE = (/ 'dump_param1.dat', 'dump_param2.dat' /) + character(*), dimension(2), parameter :: DUMP_CB_FILE = ['dump_cb1.bin', 'dump_cb2.bin' ] + character(*), dimension(2), parameter :: DUMP_PL_FILE = ['dump_pl1.bin', 'dump_pl2.bin' ] + character(*), dimension(2), parameter :: DUMP_TP_FILE = ['dump_tp1.bin', 'dump_tp2.bin' ] + character(*), dimension(2), parameter :: DUMP_PARAM_FILE = ['dump_param1.dat', 'dump_param2.dat'] !> Default file names that can be changed by the user in the parameters file character(*), parameter :: ENC_OUTFILE = 'encounter.out' @@ -116,11 +116,11 @@ module swiftest_globals integer(I4B), parameter :: BINUNIT = 20 !! File unit number for the binary output file !> Miscellaneous constants: - integer(I4B), parameter :: NDIM = 3 !! Number of dimensions in our reality - integer(I4B), parameter :: NDIM2 = 2 * NDIM !! 2x the number of dimensions - real(DP), parameter :: VSMALL = 4.0E-15_DP + integer(I4B), parameter :: NDIM = 3 !! Number of dimensions in our reality + integer(I4B), parameter :: NDIM2 = 2 * NDIM !! 2x the number of dimensions + real(DP), parameter :: VSMALL = 2 * epsilon(1._DP) !! Very small number used to prevent floating underflow - real(DP), parameter :: GC = 6.6743E-11_DP !! Universal gravitational constant in SI units + real(DP), parameter :: GC = 6.6743E-11_DP !! Universal gravitational constant in SI units real(DP), parameter :: einsteinC = 299792458.0_DP !! Speed of light in SI units end module swiftest_globals diff --git a/src/modules/swiftest_operators.f90 b/src/modules/swiftest_operators.f90 index b5b4ce078..2c982f09c 100644 --- a/src/modules/swiftest_operators.f90 +++ b/src/modules/swiftest_operators.f90 @@ -26,6 +26,12 @@ module pure function operator_cross_dp(A, B) result(C) real(DP), dimension(3) :: C end function operator_cross_dp + module pure function operator_cross_qp(A, B) result(C) + implicit none + real(QP), dimension(:), intent(in) :: A, B + real(QP), dimension(3) :: C + end function operator_cross_qp + module pure function operator_cross_i1b(A, B) result(C) implicit none integer(I1B), dimension(:), intent(in) :: A, B @@ -62,6 +68,12 @@ module pure function operator_cross_el_dp(A, B) result(C) real(DP), dimension(:,:), allocatable :: C end function operator_cross_el_dp + module pure function operator_cross_el_qp(A, B) result(C) + implicit none + real(QP), dimension(:,:), intent(in) :: A, B + real(QP), dimension(:,:), allocatable :: C + end function operator_cross_el_qp + module pure function operator_cross_el_i1b(A, B) result(C) implicit none integer(I1B), dimension(:,:), intent(in) :: A, B @@ -87,4 +99,46 @@ module pure function operator_cross_el_i8b(A, B) result(C) end function operator_cross_el_i8b end interface + !******************************************************************************************************************************** + ! Interfaces for .mag. operator + !******************************************************************************************************************************** + + interface operator(.mag.) + module pure function operator_mag_sp(A) result(B) + implicit none + real(SP), dimension(:), intent(in) :: A + real(SP) :: B + end function operator_mag_sp + + module pure function operator_mag_dp(A) result(B) + implicit none + real(DP), dimension(:), intent(in) :: A + real(DP) :: B + end function operator_mag_dp + + module pure function operator_mag_qp(A) result(B) + implicit none + real(QP), dimension(:), intent(in) :: A + real(QP) :: B + end function operator_mag_qp + + module pure function operator_mag_el_sp(A) result(B) + implicit none + real(SP), dimension(:,:), intent(in) :: A + real(SP), dimension(:), allocatable :: B + end function operator_mag_el_sp + + module pure function operator_mag_el_dp(A) result(B) + implicit none + real(DP), dimension(:,:), intent(in) :: A + real(DP), dimension(:), allocatable :: B + end function operator_mag_el_dp + + module pure function operator_mag_el_qp(A) result(B) + implicit none + real(QP), dimension(:,:), intent(in) :: A + real(QP), dimension(:), allocatable :: B + end function operator_mag_el_qp + end interface + end module swiftest_operators diff --git a/src/modules/symba_classes.f90 b/src/modules/symba_classes.f90 index 5b712c9de..16e8de302 100644 --- a/src/modules/symba_classes.f90 +++ b/src/modules/symba_classes.f90 @@ -6,20 +6,21 @@ module symba_classes use swiftest_globals use swiftest_classes, only : swiftest_parameters, swiftest_base use helio_classes, only : helio_cb, helio_pl, helio_tp, helio_nbody_system + use rmvs_classes, only : rmvs_chk_ind implicit none - !integer(I4B), parameter :: NENMAX = 32767 - !integer(I4B), parameter :: NTENC = 3 - !real(DP), parameter :: RHSCALE = 6.5_DP - !real(DP), parameter :: RSHELL = 0.48075_DP - character(*), parameter :: PARTICLE_OUTFILE = 'particle.dat' - integer(I4B), parameter :: PARTICLEUNIT = 44 !! File unit number for the binary particle info output file + integer(I4B), private, parameter :: NENMAX = 32767 + integer(I4B), private, parameter :: NTENC = 3 + real(DP), private, parameter :: RHSCALE = 6.5_DP + real(DP), private, parameter :: RSHELL = 0.48075_DP + character(*), parameter :: PARTICLE_OUTFILE = 'particle.dat' + integer(I4B), parameter :: PARTICLEUNIT = 44 !! File unit number for the binary particle info output file type, public, extends(swiftest_parameters) :: symba_parameters - character(STRMAX) :: particle_file = PARTICLE_OUTFILE !! Name of output particle information file - real(DP) :: MTINY = -1.0_DP !! Smallest mass that is fully gravitating - integer(I4B), dimension(:), allocatable :: seed !! Random seeds - logical :: lfragmentation = .false. !! Do fragmentation modeling instead of simple merger. + character(STRMAX) :: particle_file = PARTICLE_OUTFILE !! Name of output particle information file + real(DP) :: MTINY = -1.0_DP !! Smallest mass that is fully gravitating + integer(I4B), dimension(:), allocatable :: seed !! Random seeds + logical :: lfragmentation = .false. !! Do fragmentation modeling instead of simple merger. contains private procedure, public :: reader => symba_io_param_reader @@ -31,10 +32,10 @@ module symba_classes !******************************************************************************************************************************* !> SyMBA central body particle class type, public, extends(helio_cb) :: symba_cb - real(DP) :: M0 = 0.0_DP !! Initial mass of the central body - real(DP) :: dM = 0.0_DP !! Change in mass of the central body - real(DP) :: R0 = 0.0_DP !! Initial radius of the central body - real(DP) :: dR = 0.0_DP !! Change in the radius of the central body + real(DP) :: M0 = 0.0_DP !! Initial mass of the central body + real(DP) :: dM = 0.0_DP !! Change in mass of the central body + real(DP) :: R0 = 0.0_DP !! Initial radius of the central body + real(DP) :: dR = 0.0_DP !! Change in the radius of the central body contains private end type symba_cb @@ -62,9 +63,9 @@ module symba_classes !******************************************************************************************************************************* !> Class definition for the kinship relationships used in bookkeeping multiple collisions bodies in a single time step. type symba_kinship - integer(I4B) :: parent ! Index of parent particle - integer(I4B) :: nchild ! number of children in merger list - integer(I4B), dimension(:), allocatable :: child ! Index of children particles + integer(I4B) :: parent !! Index of parent particle + integer(I4B) :: nchild !! number of children in merger list + integer(I4B), dimension(:), allocatable :: child !! Index of children particles end type symba_kinship !******************************************************************************************************************************** @@ -72,17 +73,20 @@ module symba_classes !******************************************************************************************************************************* !> SyMBA massive body class type, public, extends(helio_pl) :: symba_pl - logical, dimension(:), allocatable :: lcollision !! flag indicating whether body has merged with another this time step - logical, dimension(:), allocatable :: lencounter !! flag indicating whether body is part of an encounter this time step - integer(I4B), dimension(:), allocatable :: nplenc !! number of encounters with other planets this time step - integer(I4B), dimension(:), allocatable :: ntpenc !! number of encounters with test particles this time step - integer(I4B), dimension(:), allocatable :: levelg !! level at which this body should be moved - integer(I4B), dimension(:), allocatable :: levelm !! deepest encounter level achieved this time step - integer(I4B), dimension(:), allocatable :: isperi !! perihelion passage flag - real(DP), dimension(:), allocatable :: peri !! perihelion distance - real(DP), dimension(:), allocatable :: atp !! semimajor axis following perihelion passage - type(symba_kinship), dimension(:), allocatable :: kin !! Array of merger relationship structures that can account for multiple pairwise mergers in a single step - type(symba_particle_info), dimension(:), allocatable :: info + logical, dimension(:), allocatable :: lcollision !! flag indicating whether body has merged with another this time step + logical, dimension(:), allocatable :: lencounter !! flag indicating whether body is part of an encounter this time step + logical, dimension(:), allocatable :: lmtiny !! flag indicating whether this body is below the MTINY cutoff value + integer(I4B) :: nplm !! number of bodies above the MTINY limit + integer(I8B) :: nplplm !! Number of body (all massive)-body (only those above MTINY) comparisons in the flattened upper triangular matrix + integer(I4B), dimension(:), allocatable :: nplenc !! number of encounters with other planets this time step + integer(I4B), dimension(:), allocatable :: ntpenc !! number of encounters with test particles this time step + integer(I4B), dimension(:), allocatable :: levelg !! level at which this body should be moved + integer(I4B), dimension(:), allocatable :: levelm !! deepest encounter level achieved this time step + integer(I4B), dimension(:), allocatable :: isperi !! perihelion passage flag + real(DP), dimension(:), allocatable :: peri !! perihelion distance + real(DP), dimension(:), allocatable :: atp !! semimajor axis following perihelion passage + type(symba_kinship), dimension(:), allocatable :: kin !! Array of merger relationship structures that can account for multiple pairwise mergers in a single step + type(symba_particle_info), dimension(:), allocatable :: info contains private procedure, public :: discard => symba_discard_pl !! Process massive body discards @@ -116,6 +120,10 @@ module symba_classes integer(I4B), dimension(:), allocatable :: level !! encounter recursion level integer(I4B), dimension(:), allocatable :: index1 !! position of the planet in encounter integer(I4B), dimension(:), allocatable :: index2 !! position of the test particle in encounter + contains + procedure, public :: setup => symba_setup_pltpenc !! A constructor that sets the number of encounters and allocates and initializes all arrays + procedure, public :: copy => symba_util_copy_pltpenc !! Copies all elements of one pltpenc list to another + procedure, public :: resize => symba_util_resize_pltpenc !! Checks the current size of the pltpenc_list against the required size and extends it by a factor of 2 more than requested if it is too small end type symba_pltpenc !******************************************************************************************************************************** @@ -127,6 +135,9 @@ module symba_classes real(DP), dimension(:,:), allocatable :: xh2 !! the heliocentric position of parent 2 in encounter real(DP), dimension(:,:), allocatable :: vb1 !! the barycentric velocity of parent 1 in encounter real(DP), dimension(:,:), allocatable :: vb2 !! the barycentric velocity of parent 2 in encounter + contains + procedure, public :: setup => symba_setup_plplenc !! A constructor that sets the number of encounters and allocates and initializes all arrays + procedure, public :: copy => symba_util_copy_plplenc !! Copies all elements of one plplenc list to another end type symba_plplenc !******************************************************************************************************************************** @@ -140,9 +151,11 @@ module symba_classes class(symba_pl), allocatable :: pl_discards !! Discarded test particle data structure contains private - procedure, public :: initialize => symba_setup_system !! Performs SyMBA-specific initilization steps - procedure, public :: step => symba_step_system !! Advance the SyMBA nbody system forward in time by one step - procedure, public :: interp => symba_step_interp_system !! Perform an interpolation step on the SymBA nbody system + procedure, public :: initialize => symba_setup_system !! Performs SyMBA-specific initilization steps + procedure, public :: step => symba_step_system !! Advance the SyMBA nbody system forward in time by one step + procedure, public :: interp => symba_step_interp_system !! Perform an interpolation step on the SymBA nbody system + procedure, public :: recursive_step => symba_step_recur_system !! Step interacting planets and active test particles ahead in democratic heliocentric coordinates at the current recursion level, if applicable, and descend to the next deeper level if necessary + procedure, public :: reset => symba_step_reset_system !! Resets pl, tp,and encounter structures at the start of a new step end type symba_nbody_system interface @@ -162,12 +175,13 @@ module subroutine symba_discard_tp(self, system, param) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine symba_discard_tp - module function symba_encounter_check_pl(self, system, dt) result(lencounter) + module function symba_encounter_check_pl(self, system, dt, irec) result(lencounter) implicit none class(symba_pl), intent(inout) :: self !! SyMBA test particle object class(symba_nbody_system), intent(inout) :: system !! SyMBA nbody system object real(DP), intent(in) :: dt !! step size logical :: lencounter !! Returns true if there is at least one close encounter + integer(I4B), intent(in) :: irec !! Current recursion level end function symba_encounter_check_pl module function symba_encounter_check_tp(self, system, dt) result(lencounter) @@ -229,8 +243,8 @@ module subroutine symba_io_write_frame_info(self, iu, param) use swiftest_classes, only : swiftest_parameters implicit none class(symba_particle_info), intent(in) :: self !! SyMBA particle info object - integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine symba_io_write_frame_info module subroutine symba_setup_pl(self,n) @@ -239,21 +253,24 @@ module subroutine symba_setup_pl(self,n) integer(I4B), intent(in) :: n !! Number of massive bodies to allocate end subroutine symba_setup_pl - module subroutine symba_setup_system(self, param) - use swiftest_classes, only : swiftest_parameters + module subroutine symba_setup_pltpenc(self,n) implicit none - class(symba_nbody_system), intent(inout) :: self !! SyMBA system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - end subroutine symba_setup_system + class(symba_pltpenc), intent(inout) :: self !! Symba pl-tp encounter structure + integer, intent(in) :: n !! Number of encounters to allocate space for + end subroutine symba_setup_pltpenc - module subroutine symba_step_system(self, param, t, dt) + module subroutine symba_setup_plplenc(self,n) + implicit none + class(symba_plplenc), intent(inout) :: self !! Symba pl-tp encounter structure + integer, intent(in) :: n !! Number of encounters to allocate space for + end subroutine symba_setup_plplenc + + module subroutine symba_setup_system(self, param) use swiftest_classes, only : swiftest_parameters implicit none - class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Simulation time - real(DP), intent(in) :: dt !! Current stepsize - end subroutine symba_step_system + class(symba_nbody_system), intent(inout) :: self !! SyMBA system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + end subroutine symba_setup_system module subroutine symba_setup_tp(self,n) implicit none @@ -261,13 +278,55 @@ module subroutine symba_setup_tp(self,n) integer(I4B), intent(in) :: n !! Number of test particles to allocate end subroutine symba_setup_tp + module subroutine symba_step_system(self, param, t, dt) + use swiftest_classes, only : swiftest_parameters + implicit none + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! Simulation time + real(DP), intent(in) :: dt !! Current stepsize + end subroutine symba_step_system + module subroutine symba_step_interp_system(self, param, t, dt) use swiftest_classes, only : swiftest_parameters implicit none - class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Simulation time - real(DP), intent(in) :: dt !! Current stepsize + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! Simulation time + real(DP), intent(in) :: dt !! Current stepsize end subroutine symba_step_interp_system + + module recursive subroutine symba_step_recur_system(self, param, t, dt, ireci) + implicit none + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! Simulation time + real(DP), intent(in) :: dt !! Current stepsize + integer(I4B), value, intent(in) :: ireci !! input recursion level + end subroutine symba_step_recur_system + + module subroutine symba_step_reset_system(self) + implicit none + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + end subroutine symba_step_reset_system + + module subroutine symba_util_copy_pltpenc(self, source) + implicit none + class(symba_pltpenc), intent(inout) :: self !! SyMBA pl-tp encounter list + class(symba_pltpenc), intent(in) :: source !! Source object to copy into + end subroutine symba_util_copy_pltpenc + + module subroutine symba_util_copy_plplenc(self, source) + implicit none + class(symba_plplenc), intent(inout) :: self !! SyMBA pl-pl encounter list + class(symba_pltpenc), intent(in) :: source !! Source object to copy into + end subroutine symba_util_copy_plplenc + + module subroutine symba_util_resize_pltpenc(self, nrequested) + implicit none + class(symba_pltpenc), intent(inout) :: self !! SyMBA pl-tp encounter list + integer(I4B), intent(in) :: nrequested !! New size of list needed + end subroutine symba_util_resize_pltpenc + end interface end module symba_classes \ No newline at end of file diff --git a/src/modules/whm_classes.f90 b/src/modules/whm_classes.f90 index 6107a719d..a1f501a10 100644 --- a/src/modules/whm_classes.f90 +++ b/src/modules/whm_classes.f90 @@ -33,7 +33,7 @@ module whm_classes procedure, public :: h2j => whm_coord_h2j_pl !! Convert position and velcoity vectors from heliocentric to Jacobi coordinates procedure, public :: j2h => whm_coord_j2h_pl !! Convert position and velcoity vectors from Jacobi to helliocentric coordinates procedure, public :: vh2vj => whm_coord_vh2vj_pl !! Convert velocity vectors from heliocentric to Jacobi coordinates - procedure, public :: drift => whm_drift_pl !! Loop through massive bodies and call Danby drift routine + procedure, public :: drift => whm_drift_pl !! Loop through massive bodies and call Danby drift routine to jacobi coordinates procedure, public :: fill => whm_fill_pl !! "Fills" bodies from one object into another depending on the results of a mask (uses the MERGE intrinsic) procedure, public :: accel => whm_getacch_pl !! Compute heliocentric accelerations of massive bodies procedure, public :: accel_gr => whm_gr_getacch_pl !! Acceleration term arising from the post-Newtonian correction @@ -55,7 +55,6 @@ module whm_classes !! component list, such as whm_setup_tp and whm_spill_tp contains private - procedure, public :: drift => whm_drift_tp !! Loop through test particles and call Danby drift routine procedure, public :: accel => whm_getacch_tp !! Compute heliocentric accelerations of test particles procedure, public :: accel_gr => whm_gr_getacch_tp !! Acceleration term arising from the post-Newtonian correction procedure, public :: gr_pos_kick => whm_gr_p4_tp !! Position kick due to p**4 term in the post-Newtonian correction @@ -97,24 +96,16 @@ module subroutine whm_coord_vh2vj_pl(self, cb) class(swiftest_cb), intent(inout) :: cb !! Swiftest central body particle data structuree end subroutine whm_coord_vh2vj_pl - module subroutine whm_drift_pl(self, system, param, dt) + module subroutine whm_drift_pl(self, system, param, dt, mask) use swiftest_classes, only : swiftest_nbody_system, swiftest_parameters implicit none class(whm_pl), intent(inout) :: self !! WHM massive body particle data structure class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift end subroutine whm_drift_pl - module subroutine whm_drift_tp(self, system, param, dt) - use swiftest_classes, only : swiftest_nbody_system, swiftest_parameters - implicit none - class(whm_tp), intent(inout) :: self !! WHM test particle data structure - class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of - real(DP), intent(in) :: dt !! Stepsize - end subroutine whm_drift_tp - module subroutine whm_fill_pl(self, inserts, lfill_list) use swiftest_classes, only : swiftest_body implicit none @@ -129,7 +120,7 @@ module subroutine whm_getacch_pl(self, system, param, t, lbeg) implicit none class(whm_pl), intent(inout) :: self !! WHM massive body particle data structure class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current simulation time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step end subroutine whm_getacch_pl @@ -140,7 +131,7 @@ module subroutine whm_getacch_tp(self, system, param, t, lbeg) implicit none class(whm_tp), intent(inout) :: self !! WHM test particle data structure class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step end subroutine whm_getacch_tp @@ -149,7 +140,7 @@ module subroutine whm_gr_getacch_pl(self, param) use swiftest_classes, only : swiftest_cb, swiftest_parameters implicit none class(whm_pl), intent(inout) :: self !! WHM massive body particle data structure - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters end subroutine whm_gr_getacch_pl module subroutine whm_gr_getacch_tp(self, param) @@ -163,7 +154,7 @@ module pure subroutine whm_gr_p4_pl(self, param, dt) use swiftest_classes, only : swiftest_parameters implicit none class(whm_pl), intent(inout) :: self !! WHM massive body object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Step size end subroutine whm_gr_p4_pl @@ -171,7 +162,7 @@ module pure subroutine whm_gr_p4_tp(self, param, dt) use swiftest_classes, only : swiftest_parameters implicit none class(whm_tp), intent(inout) :: self !! WHM test particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Step size end subroutine whm_gr_p4_tp @@ -198,7 +189,7 @@ module subroutine whm_setup_system(self, param) use swiftest_classes, only : swiftest_parameters implicit none class(whm_nbody_system), intent(inout) :: self !! WHM nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters end subroutine whm_setup_system !> Reads WHM test particle object in from file diff --git a/src/obl/obl.f90 b/src/obl/obl.f90 index 8792f2399..f027908f9 100644 --- a/src/obl/obl.f90 +++ b/src/obl/obl.f90 @@ -57,8 +57,8 @@ module subroutine obl_acc_pl(self, system) cb%aobl(i) = -sum(pl%Gmass(1:npl) * pl%aobl(i, 1:npl)) / cb%Gmass end do - do i = 1, NDIM - pl%ah(i, 1:npl) = pl%ah(i, 1:npl) + pl%aobl(i, 1:npl) - cb%aobl(i) + do i = 1, npl + pl%ah(:, i) = pl%ah(:, i) + pl%aobl(:, i) - cb%aobl(:) end do end associate @@ -89,8 +89,8 @@ module subroutine obl_acc_tp(self, system) aoblcb = cb%aoblend end if - do i = 1, NDIM - tp%ah(i, 1:ntp) = tp%ah(i, 1:ntp) + tp%aobl(i, 1:ntp) - aoblcb(i) + do i = 1, ntp + tp%ah(:, i) = tp%ah(:, i) + tp%aobl(:, i) - aoblcb(:) end do end associate diff --git a/src/operators/operator_cross.f90 b/src/operators/operator_cross.f90 index d6fd82944..736dc2696 100644 --- a/src/operators/operator_cross.f90 +++ b/src/operators/operator_cross.f90 @@ -1,4 +1,4 @@ -submodule(swiftest_operators) operator_cross_implementation +submodule(swiftest_operators) s_operator_cross use swiftest !! author: David A. Minton !! @@ -7,58 +7,99 @@ !! Vector list implementations: C(1:3, :) = A(1:3, :) .cross. B(1:3, :) contains - module procedure operator_cross_sp + module pure function operator_cross_sp(A, B) result(C) implicit none + real(SP), dimension(:), intent(in) :: A, B + real(SP), dimension(3) :: C C(1) = A(2) * B(3) - A(3) * B(2) C(2) = A(3) * B(1) - A(1) * B(3) C(3) = A(1) * B(2) - A(2) * B(1) return - end procedure operator_cross_sp + end function operator_cross_sp - module procedure operator_cross_dp + module pure function operator_cross_dp(A, B) result(C) implicit none + real(DP), dimension(:), intent(in) :: A, B + real(DP), dimension(3) :: C C(1) = A(2) * B(3) - A(3) * B(2) C(2) = A(3) * B(1) - A(1) * B(3) C(3) = A(1) * B(2) - A(2) * B(1) return - end procedure operator_cross_dp + end function operator_cross_dp - module procedure operator_cross_i1b + module pure function operator_cross_qp(A, B) result(C) implicit none + real(QP), dimension(:), intent(in) :: A, B + real(QP), dimension(3) :: C C(1) = A(2) * B(3) - A(3) * B(2) C(2) = A(3) * B(1) - A(1) * B(3) C(3) = A(1) * B(2) - A(2) * B(1) return - end procedure operator_cross_i1b + end function operator_cross_qp - module procedure operator_cross_i2b + module pure function operator_cross_i1b(A, B) result(C) implicit none + integer(I1B), dimension(:), intent(in) :: A, B + integer(I1B), dimension(3) :: C C(1) = A(2) * B(3) - A(3) * B(2) C(2) = A(3) * B(1) - A(1) * B(3) C(3) = A(1) * B(2) - A(2) * B(1) return - end procedure operator_cross_i2b + end function operator_cross_i1b - module procedure operator_cross_i4b + module pure function operator_cross_i2b(A, B) result(C) implicit none + integer(I2B), dimension(:), intent(in) :: A, B + integer(I2B), dimension(3) :: C C(1) = A(2) * B(3) - A(3) * B(2) C(2) = A(3) * B(1) - A(1) * B(3) C(3) = A(1) * B(2) - A(2) * B(1) return - end procedure operator_cross_i4b + end function operator_cross_i2b - module procedure operator_cross_i8b + module pure function operator_cross_i4b(A, B) result(C) implicit none + integer(I4B), dimension(:), intent(in) :: A, B + integer(I4B), dimension(3) :: C C(1) = A(2) * B(3) - A(3) * B(2) C(2) = A(3) * B(1) - A(1) * B(3) C(3) = A(1) * B(2) - A(2) * B(1) return - end procedure operator_cross_i8b + end function operator_cross_i4b - module procedure operator_cross_el_sp + module pure function operator_cross_i8b(A, B) result(C) implicit none + integer(I8B), dimension(:), intent(in) :: A, B + integer(I8B), dimension(3) :: C + C(1) = A(2) * B(3) - A(3) * B(2) + C(2) = A(3) * B(1) - A(1) * B(3) + C(3) = A(1) * B(2) - A(2) * B(1) + return + end function operator_cross_i8b + + module pure function operator_cross_el_sp(A, B) result(C) + implicit none + real(SP), dimension(:,:), intent(in) :: A, B + real(SP), dimension(:,:), allocatable :: C + integer(I4B) :: i, n + n = size(A, 2) + if (allocated(C)) deallocate(C) + allocate(C, mold = A) + do concurrent (i = 1:n) + C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) + C(2, i) = A(3, i) * B(1, i) - A(1, i) * B(3, i) + C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) + end do + return + end function operator_cross_el_sp + + module pure function operator_cross_el_dp(A, B) result(C) + implicit none + real(DP), dimension(:,:), intent(in) :: A, B + real(DP), dimension(:,:), allocatable :: C integer(I4B) :: i, n n = size(A, 2) + if (allocated(C)) deallocate(C) allocate(C, mold = A) do concurrent (i = 1:n) C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) @@ -66,12 +107,15 @@ C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) end do return - end procedure operator_cross_el_sp + end function operator_cross_el_dp - module procedure operator_cross_el_dp + module pure function operator_cross_el_qp(A, B) result(C) implicit none + real(QP), dimension(:,:), intent(in) :: A, B + real(QP), dimension(:,:), allocatable :: C integer(I4B) :: i, n n = size(A, 2) + if (allocated(C)) deallocate(C) allocate(C, mold = A) do concurrent (i = 1:n) C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) @@ -79,12 +123,15 @@ C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) end do return - end procedure operator_cross_el_dp + end function operator_cross_el_qp - module procedure operator_cross_el_i1b - implicit none + module pure function operator_cross_el_i1b(A, B) result(C) + implicit none + integer(I1B), dimension(:,:), intent(in) :: A, B + integer(I1B), dimension(:,:), allocatable :: C integer(I4B) :: i, n n = size(A, 2) + if (allocated(C)) deallocate(C) allocate(C, mold = A) do concurrent (i = 1:n) C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) @@ -92,12 +139,15 @@ C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) end do return - end procedure operator_cross_el_i1b + end function operator_cross_el_i1b - module procedure operator_cross_el_i2b + module pure function operator_cross_el_i2b(A, B) result(C) implicit none + integer(I2B), dimension(:,:), intent(in) :: A, B + integer(I2B), dimension(:,:), allocatable :: C integer(I4B) :: i, n n = size(A, 2) + if (allocated(C)) deallocate(C) allocate(C, mold = A) do concurrent (i = 1:n) C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) @@ -105,12 +155,15 @@ C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) end do return - end procedure operator_cross_el_i2b + end function operator_cross_el_i2b - module procedure operator_cross_el_i4b + module pure function operator_cross_el_i4b(A, B) result(C) implicit none + integer(I4B), dimension(:,:), intent(in) :: A, B + integer(I4B), dimension(:,:), allocatable :: C integer(I4B) :: i, n n = size(A, 2) + if (allocated(C)) deallocate(C) allocate(C, mold = A) do concurrent (i = 1:n) C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) @@ -118,12 +171,15 @@ C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) end do return - end procedure operator_cross_el_i4b + end function operator_cross_el_i4b - module procedure operator_cross_el_i8b + module pure function operator_cross_el_i8b(A, B) result(C) implicit none + integer(I8B), dimension(:,:), intent(in) :: A, B + integer(I8B), dimension(:,:), allocatable :: C integer(I4B) :: i, n n = size(A, 2) + if (allocated(C)) deallocate(C) allocate(C, mold = A) do concurrent (i = 1:n) C(1, i) = A(2, i) * B(3, i) - A(3, i) * B(2, i) @@ -131,6 +187,6 @@ C(3, i) = A(1, i) * B(2, i) - A(2, i) * B(1, i) end do return - end procedure operator_cross_el_i8b + end function operator_cross_el_i8b -end submodule operator_cross_implementation \ No newline at end of file +end submodule s_operator_cross \ No newline at end of file diff --git a/src/operators/operator_mag.f90 b/src/operators/operator_mag.f90 new file mode 100644 index 000000000..5a054d5ce --- /dev/null +++ b/src/operators/operator_mag.f90 @@ -0,0 +1,68 @@ +submodule(swiftest_operators) s_operator_mag + !! author: David A. Minton + !! + !! Contains implementations for the .mag. operator for all defined real types + !! Single vector implementations: B = .mag. A(1:3) + !! Vector list implementations: B(:) = .mag. A(1:3, :) + contains + + module pure function operator_mag_sp(A) result(B) + implicit none + real(SP), dimension(:), intent(in) :: A + real(SP) :: B + B = norm2(A(:)) + return + end function operator_mag_sp + + module pure function operator_mag_dp(A) result(B) + implicit none + real(DP), dimension(:), intent(in) :: A + real(DP) :: B + B = norm2(A(:)) + return + end function operator_mag_dp + + module pure function operator_mag_el_sp(A) result(B) + implicit none + real(SP), dimension(:,:), intent(in) :: A + real(SP), dimension(:), allocatable :: B + integer(I4B) :: i,n + n = size(A, 2) + if (allocated(B)) deallocate(B) + allocate(B(n)) + do concurrent (i=1:n) + B(i) = norm2(A(:, i)) + end do + return + end function operator_mag_el_sp + + module pure function operator_mag_el_dp(A) result(B) + implicit none + real(DP), dimension(:,:), intent(in) :: A + real(DP), dimension(:), allocatable :: B + integer(I4B) :: i,n + n = size(A, 2) + if (allocated(B)) deallocate(B) + allocate(B(n)) + do concurrent (i=1:n) + B(i) = norm2(A(:, i)) + end do + return + end function operator_mag_el_dp + + module pure function operator_mag_el_qp(A) result(B) + implicit none + real(QP), dimension(:,:), intent(in) :: A + real(QP), dimension(:), allocatable :: B + integer(I4B) :: i,n + n = size(A, 2) + if (allocated(B)) deallocate(B) + allocate(B(n)) + do concurrent (i=1:n) + B(i) = norm2(A(:, i)) + end do + return + end function operator_mag_el_qp + +end submodule s_operator_mag + diff --git a/src/rmvs/rmvs_encounter_check.f90 b/src/rmvs/rmvs_encounter_check.f90 index bead4c21b..64b5b59d9 100644 --- a/src/rmvs/rmvs_encounter_check.f90 +++ b/src/rmvs/rmvs_encounter_check.f90 @@ -46,7 +46,7 @@ module function rmvs_encounter_check_tp(self, system, dt) result(lencounter) return end function rmvs_encounter_check_tp - elemental function rmvs_chk_ind(r2, v2, vdotr, dt, r2crit) result(lflag) + module elemental function rmvs_chk_ind(r2, v2, vdotr, dt, r2crit) result(lflag) !! author: David A. Minton !! !! Determine whether a test particle and planet are having or will have an encounter within the next time step diff --git a/src/rmvs/rmvs_spill_and_fill.f90 b/src/rmvs/rmvs_util.f90 similarity index 91% rename from src/rmvs/rmvs_spill_and_fill.f90 rename to src/rmvs/rmvs_util.f90 index ae0ff563b..e950ab714 100644 --- a/src/rmvs/rmvs_spill_and_fill.f90 +++ b/src/rmvs/rmvs_util.f90 @@ -1,7 +1,7 @@ -submodule(rmvs_classes) s_rmvs_spill_and_fill +submodule(rmvs_classes) s_rmvs_util use swiftest contains - module subroutine rmvs_spill_pl(self, discards, lspill_list) + module subroutine rmvs_util_spill_pl(self, discards, lspill_list) !! author: David A. Minton !! !! Move spilled (discarded) RMVS test particle structure from active list to discard list @@ -31,9 +31,9 @@ module subroutine rmvs_spill_pl(self, discards, lspill_list) return - end subroutine rmvs_spill_pl + end subroutine rmvs_util_spill_pl - module subroutine rmvs_fill_pl(self, inserts, lfill_list) + module subroutine rmvs_util_fill_pl(self, inserts, lfill_list) !! author: David A. Minton !! !! Insert new RMVS massive body structure into an old one. @@ -62,9 +62,9 @@ module subroutine rmvs_fill_pl(self, inserts, lfill_list) return - end subroutine rmvs_fill_pl + end subroutine rmvs_util_fill_pl - module subroutine rmvs_spill_tp(self, discards, lspill_list) + module subroutine rmvs_util_spill_tp(self, discards, lspill_list) !! author: David A. Minton !! !! Move spilled (discarded) RMVS test particle structure from active list to discard list @@ -98,9 +98,9 @@ module subroutine rmvs_spill_tp(self, discards, lspill_list) return - end subroutine rmvs_spill_tp + end subroutine rmvs_util_spill_tp - module subroutine rmvs_fill_tp(self, inserts, lfill_list) + module subroutine rmvs_util_fill_tp(self, inserts, lfill_list) !! author: David A. Minton !! !! Insert new RMVS test particle structure into an old one. @@ -133,6 +133,6 @@ module subroutine rmvs_fill_tp(self, inserts, lfill_list) return - end subroutine rmvs_fill_tp + end subroutine rmvs_util_fill_tp -end submodule s_rmvs_spill_and_fill +end submodule s_rmvs_util diff --git a/src/setup/setup.f90 b/src/setup/setup.f90 index dab78a875..e85f9754a 100644 --- a/src/setup/setup.f90 +++ b/src/setup/setup.f90 @@ -69,6 +69,28 @@ module subroutine setup_construct_system(system, param) return end subroutine setup_construct_system + + module subroutine setup_initialize_system(self, param) + !! author: David A. Minton + !! + !! Wrapper method to initialize a basic Swiftest nbody system from files + !! + implicit none + ! Arguments + class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + + call self%cb%initialize(param) + call self%pl%initialize(param) + if (.not.param%lrhill_present) call self%pl%set_rhill(self%cb) + call self%tp%initialize(param) + call self%set_msys() + call self%pl%set_mu(self%cb) + call self%tp%set_mu(self%cb) + call self%pl%eucl_index() + return + end subroutine setup_initialize_system + module subroutine setup_body(self,n) !! author: David A. Minton !! @@ -83,7 +105,6 @@ module subroutine setup_body(self,n) if (n <= 0) return self%lfirst = .true. - !write(*,*) 'Allocating the basic Swiftest particle' allocate(self%id(n)) allocate(self%name(n)) allocate(self%status(n)) @@ -162,7 +183,7 @@ module subroutine setup_pl(self,n) self%k2(:) = 0.0_DP self%Q(:) = 0.0_DP self%tlag(:) = 0.0_DP - self%num_comparisons = 0 + self%nplpl = 0 return end subroutine setup_pl diff --git a/src/symba/symba_encounter_check.f90 b/src/symba/symba_encounter_check.f90 index ce4b53dff..bbbb798de 100644 --- a/src/symba/symba_encounter_check.f90 +++ b/src/symba/symba_encounter_check.f90 @@ -1,16 +1,73 @@ submodule (symba_classes) s_symba_encounter_check use swiftest contains - module function symba_encounter_check_pl(self, system, dt) result(lencounter) + module function symba_encounter_check_pl(self, system, dt, irec) result(lany_encounter) implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA test particle object - class(symba_nbody_system), intent(inout) :: system !! SyMBA nbody system object - real(DP), intent(in) :: dt !! step size + class(symba_pl), intent(inout) :: self !! SyMBA test particle object + class(symba_nbody_system), intent(inout) :: system !! SyMBA nbody system object + real(DP), intent(in) :: dt !! step size + integer(I4B), intent(in) :: irec !! Current recursion level ! Result - logical :: lencounter !! Returns true if there is at least one close encounter + logical :: lany_encounter !! Returns true if there is at least one close encounter + ! Internals + real(DP) :: r2crit, vdotr, r2, v2, tmin, r2min, term2 + integer(I4B) :: j, nenc_old + integer(I8B) :: k + real(DP), dimension(NDIM) :: xr, vr + integer(I4B), dimension(:,:), allocatable :: ind + logical, dimension(:), allocatable :: lencounter, loc_lvdotr + + associate(pl => self, npl => self%nbody, nplpl => self%nplpl) + allocate(lencounter(nplpl), loc_lvdotr(nplpl)) + lencounter(:) = .false. + + term2 = RHSCALE * (RSHELL**irec) + + do k = 1, nplpl + associate(i => pl%k_plpl(1, k), j => pl%k_plpl(2, k)) + xr(:) = pl%xh(:, j) - pl%xh(:, i) + r2 = dot_product(xr(:), xr(:)) + r2crit = ((pl%rhill(i) + pl%rhill(i)) * term2)**2 + vr(:) = pl%vh(:, j) - pl%vh(:, i) + vdotr = dot_product(vr(:), xr(:)) + if (r2 < r2crit) then + lencounter(k) = .true. + loc_lvdotr(k) = (vdotr < 0.0_DP) + else + if (vdotr < 0.0_DP) then + v2 = dot_product(vr(:), vr(:)) + tmin = -vdotr / v2 + if (tmin < dt) then + r2min = r2 - vdotr * vdotr / v2 + else + r2min = r2 + 2 * vdotr * dt + v2 * dt * dt + end if + r2min = min(r2min, r2) + if (r2min <= r2crit) then + lencounter(k) = .true. + loc_lvdotr(k) = (vdotr < 0.0_DP) + end if + end if + end if + end associate + end do - lencounter = .false. + lany_encounter = any(lencounter(:)) + if (lany_encounter) then + associate(plplenc_list => system%plplenc_list, nenc => system%plplenc_list%nenc) + nenc_old = nenc + call plplenc_list%resize(nenc_old + count(lencounter(:))) + plplenc_list%status(nenc_old+1:nenc) = ACTIVE + plplenc_list%level(nenc_old+1:nenc) = irec + plplenc_list%lvdotr(nenc_old+1:nenc) = pack(loc_lvdotr(:), lencounter(:)) + plplenc_list%index1(nenc_old+1:nenc) = pack(pl%k_plpl(1,:), lencounter(:)) + plplenc_list%index2(nenc_old+1:nenc) = pack(pl%k_plpl(2,:), lencounter(:)) + pl%lencounter(plplenc_list%index1(nenc_old+1:nenc)) = .true. + pl%lencounter(plplenc_list%index2(nenc_old+1:nenc)) = .true. + end associate + end if + end associate return end function symba_encounter_check_pl diff --git a/src/symba/symba_setup.f90 b/src/symba/symba_setup.f90 index 6449013dd..5ac26c220 100644 --- a/src/symba/symba_setup.f90 +++ b/src/symba/symba_setup.f90 @@ -1,7 +1,7 @@ submodule(symba_classes) s_symba_setup use swiftest contains - module subroutine symba_setup_pl(self,n) + module subroutine symba_setup_pl(self, n) !! author: David A. Minton !! !! Allocate SyMBA test particle structure @@ -12,14 +12,93 @@ module subroutine symba_setup_pl(self,n) class(symba_pl), intent(inout) :: self !! SyMBA test particle object integer(I4B), intent(in) :: n !! Number of massive bodies to allocate ! Internals - integer(I4B) :: i,j + integer(I4B) :: i !> Call allocation method for parent class - !call helio_setup_pl(self, n) call setup_pl(self, n) if (n <= 0) return + allocate(self%lcollision(n)) + allocate(self%lencounter(n)) + allocate(self%nplenc(n)) + allocate(self%ntpenc(n)) + allocate(self%levelg(n)) + allocate(self%levelm(n)) + allocate(self%isperi(n)) + allocate(self%peri(n)) + allocate(self%atp(n)) + allocate(self%kin(n)) + allocate(self%info(n)) + + self%lcollision(:) = .false. + self%lencounter(:) = .false. + self%nplenc(:) = 0 + self%ntpenc(:) = 0 + self%levelg(:) = -1 + self%levelm(:) = -1 + self%isperi(:) = 0 + self%peri(:) = 0.0_DP + self%atp(:) = 0.0_DP + self%kin(:)%nchild = 0 + self%kin(:)%parent = [(i, i=1, n)] + return + end subroutine symba_setup_pl + + module subroutine symba_setup_pltpenc(self, n) + !! author: David A. Minton + !! + !! A constructor that sets the number of encounters and allocates and initializes all arrays + !! + implicit none + ! Arguments + class(symba_pltpenc), intent(inout) :: self !! Symba pl-tp encounter structure + integer, intent(in) :: n !! Number of encounters to allocate space for + + self%nenc = n + if (n == 0) return + if (allocated(self%lvdotr)) deallocate(self%lvdotr) + if (allocated(self%status)) deallocate(self%status) + if (allocated(self%level)) deallocate(self%level) + if (allocated(self%index1)) deallocate(self%index1) + if (allocated(self%index2)) deallocate(self%index2) + allocate(self%lvdotr(n)) + allocate(self%status(n)) + allocate(self%level(n)) + allocate(self%index1(n)) + allocate(self%index2(n)) + self%lvdotr(:) = .false. + self%status(:) = INACTIVE + self%level(:) = -1 + self%index1(:) = 0 + self%index2(:) = 0 + return + end subroutine symba_setup_pltpenc + + module subroutine symba_setup_plplenc(self,n) + !! author: David A. Minton + !! + !! A constructor that sets the number of encounters and allocates and initializes all arrays + ! + implicit none + ! Arguments + class(symba_plplenc), intent(inout) :: self !! Symba pl-tp encounter structure + integer, intent(in) :: n !! Number of encounters to allocate space for + + call symba_setup_pltpenc(self, n) + if (n == 0) return + if (allocated(self%xh1)) deallocate(self%xh1) + if (allocated(self%xh2)) deallocate(self%xh2) + if (allocated(self%vb1)) deallocate(self%vb1) + if (allocated(self%vb2)) deallocate(self%vb2) + allocate(self%xh1(NDIM,n)) + allocate(self%xh2(NDIM,n)) + allocate(self%vb1(NDIM,n)) + allocate(self%vb2(NDIM,n)) + self%xh1(:,:) = 0.0_DP + self%xh2(:,:) = 0.0_DP + self%vb1(:,:) = 0.0_DP + self%vb2(:,:) = 0.0_DP return - end subroutine symba_setup_pl + end subroutine symba_setup_plplenc module subroutine symba_setup_system(self, param) !! author: David A. Minton @@ -34,20 +113,22 @@ module subroutine symba_setup_system(self, param) integer(I4B) :: i, j ! Call parent method - call whm_setup_system(self, param) - - select type(pl => self%pl) - class is(symba_pl) - select type(cb => self%cb) - class is (symba_cb) - select type (tp => self%tp) - class is (symba_tp) - - + associate(system => self) + call whm_setup_system(system, param) + call system%mergeadd_list%setup(1) + call system%mergesub_list%setup(1) + call system%pltpenc_list%setup(1) + call system%plplenc_list%setup(1) + select type(pl => system%pl) + class is (symba_pl) + select type(param) + class is (symba_parameters) + pl%lmtiny(:) = pl%Gmass(:) > param%MTINY + pl%nplm = count(pl%lmtiny(:)) end select end select - end select - + end associate + return end subroutine symba_setup_system module subroutine symba_setup_tp(self,n) @@ -62,9 +143,14 @@ module subroutine symba_setup_tp(self,n) integer, intent(in) :: n !! Number of test particles to allocate !> Call allocation method for parent class - !call helio_setup_tp(self, n) call setup_tp(self, n) if (n <= 0) return + allocate(self%nplenc(n)) + allocate(self%levelg(n)) + allocate(self%levelm(n)) + self%nplenc(:) = 0 + self%levelg(:) = -1 + self%levelm(:) = -1 return end subroutine symba_setup_tp diff --git a/src/symba/symba_step.f90 b/src/symba/symba_step.f90 index b04caa74e..631c8c087 100644 --- a/src/symba/symba_step.f90 +++ b/src/symba/symba_step.f90 @@ -18,11 +18,12 @@ module subroutine symba_step_system(self, param, t, dt) ! Internals logical :: lencounter_pl, lencounter_tp, lencounter + call self%reset() select type(pl => self%pl) class is (symba_pl) select type(tp => self%tp) class is (symba_tp) - lencounter = pl%encounter_check(self, dt) .or. tp%encounter_check(self, dt) + lencounter = pl%encounter_check(self, dt, 0) .or. tp%encounter_check(self, dt) if (lencounter) then call self%interp(param, t, dt) else @@ -36,12 +37,148 @@ module subroutine symba_step_system(self, param, t, dt) end subroutine symba_step_system module subroutine symba_step_interp_system(self, param, t, dt) + !! author: David A. Minton + !! + !! Step planets and active test particles ahead in democratic heliocentric coordinates, calling the recursive + !! subroutine to descend to the appropriate level to handle close encounters + !! + !! Adapted from David E. Kaufmann's Swifter routine: symba_step_interp.f90 + !! Adapted from Hal Levison's Swift routine symba5_step_interp.f implicit none - class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Simulation time - real(DP), intent(in) :: dt !! Current stepsize + ! Arguments + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! Simulation time + real(DP), intent(in) :: dt !! Current stepsize + ! Internals + real(DP) :: dth !! Half step size + integer(I4B) :: irec !! Recursion level + + dth = 0.5_DP * dt + associate(system => self) + select type(pl => system%pl) + class is (symba_pl) + select type(tp => system%tp) + class is (symba_tp) + select type(cb => system%cb) + class is (symba_cb) + call pl%vh2vb(cb) + call pl%lindrift(cb, dth, lbeg=.true.) + call tp%vh2vb(vbcb = -cb%ptbeg) + call tp%lindrift(cb, dth, lbeg=.true.) + + call pl%set_beg_end(xbeg = pl%xh) + call pl%accel(system, param, t) + call tp%accel(system, param, t, lbeg=.true.) + call pl%kick(dth) + call tp%kick(dth) + + call pl%drift(system, param, dt, pl%status(:) == ACTIVE) + call tp%drift(system, param, dt, tp%status(:) == ACTIVE) + irec = 0 + call system%recursive_step(param, t, dt, irec) + + call pl%set_beg_end(xend = pl%xh) + call pl%accel(system, param, t + dt) + call tp%accel(system, param, t + dt, lbeg=.false.) + + call pl%kick(dth) + call tp%kick(dth) + + call pl%vh2vb(cb) + call pl%lindrift(cb, dth, lbeg=.false.) + call tp%vh2vb(vbcb = -cb%ptend) + call tp%lindrift(cb, dth, lbeg=.false.) + end select + end select + end select + end associate return end subroutine symba_step_interp_system + + module recursive subroutine symba_step_recur_system(self, param, t, dt, ireci) + !! author: David A. Minton + !! + !! Step interacting planets and active test particles ahead in democratic heliocentric coordinates at the current + !! recursion level, if applicable, and descend to the next deeper level if necessarys + !! + !! Adapted from David E. Kaufmann's Swifter routine: symba_step_recur.f90 + !! Adapted from Hal Levison's Swift routine symba5_step_recur.f + implicit none + ! Arguments + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! Simulation time + real(DP), intent(in) :: dt !! Current stepsize + integer(I4B), value, intent(in) :: ireci !! input recursion level + ! Internals + integer(I4B) :: i, j, irecp, icflg, index_i, index_j, index_pl, index_tp + real(DP) :: dtl, dth,sgn + + associate(plplenc_list => self%plplenc_list, pltpenc_list => self%pltpenc_list) + dtl = param%dt / (NTENC**ireci) + dth = 0.5_DP * dtl + IF (dtl / param%dt < VSMALL) THEN + WRITE(*, *) "SWIFTEST Warning:" + WRITE(*, *) " In symba_step_recur_system, local time step is too small" + WRITE(*, *) " Roundoff error will be important!" + call util_exit(FAILURE) + END IF + irecp = ireci + 1 + if (ireci == 0) then + icflg = 0 + + end if + end associate + + end subroutine symba_step_recur_system + + module subroutine symba_step_reset_system(self) + !! author: David A. Minton + !! + !! Resets pl, tp,and encounter structures at the start of a new step + !! + implicit none + ! Arguments + class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody system object + ! Internals + integer(I4B) :: i + + associate(system => self, pltpenc_list => self%pltpenc_list, plplenc_list => self%plplenc_list, mergeadd_list => self%mergeadd_list, mergesub_list => self%mergesub_list) + select type(pl => system%pl) + class is (symba_pl) + select type(tp => system%tp) + class is (symba_tp) + pl%lcollision(:) = .false. + pl%kin(:)%parent = [(i, i=1, pl%nbody)] + pl%kin(:)%nchild = 0 + do i = 1, pl%nbody + if (allocated(pl%kin(i)%child)) deallocate(pl%kin(i)%child) + end do + pl%nplenc(:) = 0 + pl%ntpenc(:) = 0 + pl%levelg(:) = 0 + pl%levelm(:) = 0 + pl%lencounter = .false. + pl%lcollision = .false. + + tp%nplenc(:) = 0 + tp%levelg(:) = 0 + tp%levelm(:) = 0 + + plplenc_list%nenc = 0 + pltpenc_list%nenc = 0 + + mergeadd_list%nbody = 0 + mergesub_list%nbody = 0 + end select + end select + end associate + + + end subroutine symba_step_reset_system + + + end submodule s_symba_step diff --git a/src/symba/symba_util.f90 b/src/symba/symba_util.f90 new file mode 100644 index 000000000..81b351e65 --- /dev/null +++ b/src/symba/symba_util.f90 @@ -0,0 +1,67 @@ +submodule(symba_classes) s_symba_util + use swiftest +contains + module subroutine symba_util_copy_pltpenc(self, source) + !! author: David A. Minton + !! + !! Copies elements from the source encounter list into self. + implicit none + ! Arguments + class(symba_pltpenc), intent(inout) :: self !! SyMBA pl-tp encounter list + class(symba_pltpenc), intent(in) :: source !! Source object to copy into + + associate(n => source%nenc) + self%nenc = n + self%lvdotr(1:n) = source%lvdotr(1:n) + self%status(1:n) = source%status(1:n) + self%level(1:n) = source%level(1:n) + self%index1(1:n) = source%index1(1:n) + self%index2(1:n) = source%index2(1:n) + end associate + end subroutine symba_util_copy_pltpenc + + module subroutine symba_util_copy_plplenc(self, source) + !! author: David A. Minton + !! + !! Copies elements from the source encounter list into self. + implicit none + ! Arguments + class(symba_plplenc), intent(inout) :: self !! SyMBA pl-pl encounter list + class(symba_pltpenc), intent(in) :: source !! Source object to copy into + + call symba_util_copy_pltpenc(self, source) + associate(n => source%nenc) + select type(source) + class is (symba_plplenc) + self%xh1(:,1:n) = source%xh1(:,1:n) + self%xh2(:,1:n) = source%xh2(:,1:n) + self%vb1(:,1:n) = source%vb1(:,1:n) + self%vb2(:,1:n) = source%vb2(:,1:n) + end select + end associate + end subroutine symba_util_copy_plplenc + + module subroutine symba_util_resize_pltpenc(self, nrequested) + !! author: David A. Minton + !! + !! Checks the current size of the encounter list against the required size and extends it by a factor of 2 more than requested if it is too small. + !! Polymorphic method works on both symba_pltpenc and symba_plplenc types + implicit none + ! Arguments + class(symba_pltpenc), intent(inout) :: self !! SyMBA pl-tp encounter list + integer(I4B), intent(in) :: nrequested !! New size of list needed + ! Internals + class(symba_pltpenc), allocatable :: enc_temp + integer(I4B) :: nold + + nold = size(self%status) + if (nrequested <= nold) return + allocate(enc_temp, source=self) + call self%setup(2 * nrequested) + call self%copy(enc_temp) + deallocate(enc_temp) + return + end subroutine symba_util_resize_pltpenc + + +end submodule s_symba_util \ No newline at end of file diff --git a/src/user/user_getacch.f90 b/src/user/user_getacch.f90 index c54c21693..16a2f0916 100644 --- a/src/user/user_getacch.f90 +++ b/src/user/user_getacch.f90 @@ -11,7 +11,7 @@ module subroutine user_getacch_body(self, system, param, t, lbeg) ! Arguments class(swiftest_body), intent(inout) :: self !! Swiftest massive body particle data structure class(swiftest_nbody_system), intent(inout) :: system !! Swiftest nbody_system_object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of user parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters user parameters real(DP), intent(in) :: t !! Current time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the ste diff --git a/src/util/util_set.f90 b/src/util/util_set.f90 index b690f37b2..2c52c86df 100644 --- a/src/util/util_set.f90 +++ b/src/util/util_set.f90 @@ -30,12 +30,37 @@ module subroutine util_set_beg_end_pl(self, xbeg, xend, vbeg) end subroutine util_set_beg_end_pl + module subroutine util_set_ir3h(self) + !! author: David A. Minton + !! + !! Sets the inverse heliocentric radius term (1/rh**3) for all bodies in a structure + implicit none + ! Arguments + class(swiftest_body), intent(inout) :: self !! Swiftest generic body object + ! Internals + integer(I4B) :: i + real(DP) :: r2, irh + + if (self%nbody > 0) then + + do i = 1, self%nbody + r2 = dot_product(self%xh(:, i), self%xh(:, i)) + irh = 1.0_DP / sqrt(r2) + self%ir3h(i) = irh / r2 + end do + end if + + return + end subroutine util_set_ir3h + module subroutine util_set_msys(self) !! author: David A. Minton !! !! Sets the value of msys and the vector mass quantities based on the total mass of the system implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system objec + ! Arguments + class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nobdy system object + self%msys = self%cb%mass + sum(self%pl%mass(1:self%pl%nbody)) return @@ -46,11 +71,11 @@ module subroutine util_set_mu_pl(self, cb) !! !! Computes G * (M + m) for each massive body implicit none + ! Arguments class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object if (self%nbody > 0) self%mu(:) = cb%Gmass + self%Gmass(:) - return end subroutine util_set_mu_pl @@ -59,6 +84,7 @@ module subroutine util_set_mu_tp(self, cb) !! !! Converts certain scalar values to arrays so that they can be used in elemental functions implicit none + ! Arguments class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object @@ -72,8 +98,9 @@ module subroutine util_set_rhill(self,cb) !! !! Sets the value of the Hill's radius implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest massive body object + ! Arguments + class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object if (self%nbody > 0) then call self%xv2el(cb) @@ -83,25 +110,23 @@ module subroutine util_set_rhill(self,cb) return end subroutine util_set_rhill - module subroutine util_set_ir3h(self) + module subroutine util_set_rhill_approximate(self,cb) !! author: David A. Minton !! - !! Sets the inverse heliocentric radius term (1/rh**3) for all bodies in a structure + !! Sets the approximate value of the Hill's radius using the heliocentric radius instead of computing the semimajor axis implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest generic body object - - integer(I4B) :: i - real(DP) :: r2, irh + ! Arguments + class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + ! Internals + real(DP), dimension(:), allocatable :: rh if (self%nbody > 0) then - - do i = 1, self%nbody - r2 = dot_product(self%xh(:, i), self%xh(:, i)) - irh = 1.0_DP / sqrt(r2) - self%ir3h(i) = irh / r2 - end do + rh(:) = .mag. self%xh(:,:) + self%rhill(:) = rh(:) * (self%Gmass(:) / cb%Gmass / 3)**THIRD end if return - end subroutine util_set_ir3h + end subroutine util_set_rhill_approximate + end submodule s_util_set \ No newline at end of file diff --git a/src/whm/whm_drift.f90 b/src/whm/whm_drift.f90 index a27897cfa..454e1bc53 100644 --- a/src/whm/whm_drift.f90 +++ b/src/whm/whm_drift.f90 @@ -1,7 +1,7 @@ submodule(whm_classes) whm_drift use swiftest contains - module subroutine whm_drift_pl(self, system, param, dt) + module subroutine whm_drift_pl(self, system, param, dt, mask) !! author: David A. Minton !! !! Loop through planets and call Danby drift routine @@ -12,46 +12,31 @@ module subroutine whm_drift_pl(self, system, param, dt) ! Arguments class(whm_pl), intent(inout) :: self !! WHM massive body particle data structure class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize + logical, dimension(:), intent(in) :: mask !! Logical mask of size self%nbody that determines which bodies to drift ! Internals integer(I4B) :: i - real(DP) :: energy, vmag2, rmag !! Variables used in GR calculation integer(I4B), dimension(:), allocatable :: iflag - real(DP), dimension(:), allocatable :: dtp associate(pl => self, npl => self%nbody) - if (npl == 0) return allocate(iflag(npl)) iflag(:) = 0 - allocate(dtp(npl)) - - if (param%lgr) then - do i = 1,npl - rmag = norm2(pl%xj(:, i)) - vmag2 = dot_product(pl%vj(:, i), pl%vj(:, i)) - energy = 0.5_DP * vmag2 - pl%muj(i) / rmag - dtp(i) = dt * (1.0_DP + 3 * param%inv_c2 * energy) - end do - else - dtp(:) = dt - end if - - call drift_one(pl%muj(1:npl), pl%xj(1,1:npl), pl%xj(2,1:npl), pl%xj(3,1:npl), & - pl%vj(1,1:npl), pl%vj(2,1:npl), pl%vj(3,1:npl), & - dtp(1:npl), iflag(1:npl)) + call drift_all(pl%muj, pl%xj, pl%vj, npl, param, dt, mask, iflag) if (any(iflag(1:npl) /= 0)) then + where(iflag(1:npl) /= 0) pl%status(1:npl) = DISCARDED_DRIFTERR do i = 1, npl - if (iflag(i) /= 0) then - write(*, *) " Planet ", self%id(i), " is lost!!!!!!!!!!" - write(*, *) pl%xj(:,i) - write(*, *) pl%vj(:,i) - write(*, *) " stopping " - call util_exit(FAILURE) + if (iflag(i) /= 0) then + write(*, *) " Planet ", pl%id(i), " is lost!!!!!!!!!!!!" + WRITE(*, *) pl%muj(i), dt + WRITE(*, *) pl%xj(:,i) + WRITE(*, *) pl%vj(:,i) + WRITE(*, *) " STOPPING " end if end do + call util_exit(FAILURE) end if end associate @@ -59,54 +44,4 @@ module subroutine whm_drift_pl(self, system, param, dt) end subroutine whm_drift_pl - module subroutine whm_drift_tp(self, system, param, dt) - !! author: David A. Minton - !! - !! Loop through test particles and call Danby drift routine - !! - !! Adapted from Hal Levison's Swift routine drift_tp.f - !! Includes - !! Adapted from David E. Kaufmann's Swifter routine whm_drift_tp.f90 - implicit none - ! Arguments - class(whm_tp), intent(inout) :: self !! WHM test particle data structure - class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of - real(DP), intent(in) :: dt !! Stepsize - ! Internals - integer(I4B) :: i - real(DP) :: energy, vmag2, rmag !! Variables used in GR calculation - integer(I4B), dimension(:), allocatable :: iflag - real(DP), dimension(:), allocatable :: dtp - - associate(tp => self, ntp => self%nbody) - if (ntp == 0) return - allocate(iflag(ntp)) - iflag(:) = 0 - allocate(dtp(ntp)) - if (param%lgr) then - do i = 1, ntp - rmag = norm2(tp%xh(:, i)) - vmag2 = dot_product(tp%vh(:, i), tp%vh(:, i)) - energy = 0.5_DP * vmag2 - tp%mu(i) / rmag - dtp(i) = dt * (1.0_DP + 3 * param%inv_c2 * energy) - end do - else - dtp(:) = dt - end if - do concurrent(i = 1:ntp, tp%status(i) == ACTIVE) - call drift_one(tp%mu(i), tp%xh(1,i), tp%xh(2,i), tp%xh(3,i), & - tp%vh(1,i), tp%vh(2,i), tp%vh(3,i), & - dtp(i), iflag(i)) - end do - if (any(iflag(1:ntp) /= 0)) then - where(iflag(1:ntp) /= 0) tp%status(1:ntp) = DISCARDED_DRIFTERR - do i = 1, ntp - if (iflag(i) /= 0) write(*, *) "Particle ", self%id(i), " lost due to error in Danby drift" - end do - end if - end associate - - return - end subroutine whm_drift_tp end submodule whm_drift diff --git a/src/whm/whm_getacch.f90 b/src/whm/whm_getacch.f90 index 4d761fc02..e950d855c 100644 --- a/src/whm/whm_getacch.f90 +++ b/src/whm/whm_getacch.f90 @@ -12,7 +12,7 @@ module subroutine whm_getacch_pl(self, system, param, t, lbeg) ! Arguments class(whm_pl), intent(inout) :: self !! WHM massive body particle data structure class(swiftest_nbody_system), intent(inout) :: system !! Swiftest central body particle data structure - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step ! Internals @@ -30,7 +30,7 @@ module subroutine whm_getacch_pl(self, system, param, t, lbeg) call whm_getacch_ah1(cb, pl) call whm_getacch_ah2(cb, pl) - call whm_getacch_ah3(pl) + call pl%accel_int() if (param%loblatecb) then cb%aoblbeg = cb%aobl @@ -61,29 +61,31 @@ module subroutine whm_getacch_tp(self, system, param, t, lbeg) ! Arguments class(whm_tp), intent(inout) :: self !! WHM test particle data structure class(swiftest_nbody_system), intent(inout) :: system !! Swiftest central body particle data structure - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current time logical, optional, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step ! Internals integer(I4B) :: i real(DP), dimension(NDIM) :: ah0 - real(DP), dimension(:,:), allocatable :: xhp associate(tp => self, ntp => self%nbody, pl => system%pl, cb => system%cb, npl => system%pl%nbody) if (ntp == 0 .or. npl == 0) return if (present(lbeg)) system%lbeg = lbeg if (system%lbeg) then - allocate(xhp, source=pl%xbeg) + ah0(:) = whm_getacch_ah0(pl%Gmass(:), pl%xbeg(:,:), npl) + do i = 1, ntp + tp%ah(:, i) = ah0(:) + end do + call tp%accel_int(pl%Gmass(:), pl%xbeg(:,:), npl) else - allocate(xhp, source=pl%xend) + ah0(:) = whm_getacch_ah0(pl%Gmass(:), pl%xend(:,:), npl) + do i = 1, ntp + tp%ah(:, i) = ah0(:) + end do + call tp%accel_int(pl%Gmass(:), pl%xend(:,:), npl) end if - ah0(:) = whm_getacch_ah0(pl%Gmass(:), xhp(:,:), npl) - do i = 1, ntp - tp%ah(:, i) = ah0(:) - end do - call whm_getacch_ah3_tp(system, xhp) if (param%loblatecb) call tp%accel_obl(system) if (param%lextra_force) call tp%accel_user(system, param, t) if (param%lgr) call tp%accel_gr(param) @@ -177,75 +179,4 @@ pure subroutine whm_getacch_ah2(cb, pl) return end subroutine whm_getacch_ah2 - pure subroutine whm_getacch_ah3(pl) - !! author: David A. Minton - !! - !! Compute direct cross (third) term heliocentric accelerations of planets - !! - !! Adapted from Hal Levison's Swift routine getacch_ah3.f - !! Adapted from David E. Kaufmann's Swifter routine whm_getacch_ah3.f90 - implicit none - - class(whm_pl), intent(inout) :: pl - integer(I4B) :: i, j - real(DP) :: rji2, irij3, faci, facj - real(DP), dimension(NDIM) :: dx - real(DP), dimension(:,:), allocatable :: ah3 - - associate(npl => pl%nbody) - allocate(ah3, mold=pl%ah) - ah3(:, :) = 0.0_DP - - do i = 1, npl - 1 - do j = i + 1, npl - dx(:) = pl%xh(:, j) - pl%xh(:, i) - rji2 = dot_product(dx(:), dx(:)) - irij3 = 1.0_DP / (rji2 * sqrt(rji2)) - faci = pl%Gmass(i) * irij3 - facj = pl%Gmass(j) * irij3 - ah3(:, i) = ah3(:, i) + facj * dx(:) - ah3(:, j) = ah3(:, j) - faci * dx(:) - end do - end do - do i = 1, NDIM - pl%ah(i, 1:npl) = pl%ah(i, 1:npl) + ah3(i, 1:npl) - end do - deallocate(ah3) - end associate - - return - end subroutine whm_getacch_ah3 - - pure subroutine whm_getacch_ah3_tp(system, xhp) - !! author: David A. Minton - !! - !! Compute direct cross (third) term heliocentric accelerations of test particles - !! - !! Adapted from Hal Levison's Swift routine getacch_ah3_tp.f - !! Adapted from David E. Kaufmann's Swifter routine whm_getacch_ah3.f90 - implicit none - ! Arguments - class(swiftest_nbody_system), intent(inout) :: system !! WHM nbody system object - real(DP), dimension(:,:), intent(in) :: xhp !! Heliocentric positions of planets at the current substep - ! Internals - integer(I4B) :: i, j - real(DP) :: rji2, irij3, fac - real(DP), dimension(NDIM) :: dx, acc - - associate(ntp => system%tp%nbody, npl => system%pl%nbody, tp => system%tp, pl => system%pl) - if (ntp == 0) return - do i = 1, ntp - acc(:) = 0.0_DP - do j = 1, npl - dx(:) = tp%xh(:, i) - xhp(:, j) - rji2 = dot_product(dx(:), dx(:)) - irij3 = 1.0_DP / (rji2 * sqrt(rji2)) - fac = pl%Gmass(j) * irij3 - acc(:) = acc(:) - fac * dx(:) - end do - tp%ah(:, i) = tp%ah(:, i) + acc(:) - end do - end associate - return - end subroutine whm_getacch_ah3_tp end submodule s_whm_getacch diff --git a/src/whm/whm_gr.f90 b/src/whm/whm_gr.f90 index 3cf159504..62c7fb2b5 100644 --- a/src/whm/whm_gr.f90 +++ b/src/whm/whm_gr.f90 @@ -10,7 +10,7 @@ module subroutine whm_gr_getacch_pl(self, param) !! author: David A. Minton implicit none ! Arguments class(whm_pl), intent(inout) :: self !! WHM massive body particle data structure - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters ! Internals integer(I4B) :: i real(DP), dimension(NDIM) :: suma @@ -71,7 +71,7 @@ module pure subroutine whm_gr_p4_pl(self, param, dt) implicit none ! Arguments class(whm_pl), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Step size ! Internals integer(I4B) :: i @@ -96,7 +96,7 @@ module pure subroutine whm_gr_p4_tp(self, param, dt) implicit none ! Arguments class(whm_tp), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Step size ! Internals integer(I4B) :: i diff --git a/src/whm/whm_setup.f90 b/src/whm/whm_setup.f90 index 9f0f9b1b7..1f098df26 100644 --- a/src/whm/whm_setup.f90 +++ b/src/whm/whm_setup.f90 @@ -79,9 +79,9 @@ module subroutine whm_setup_system(self, param) implicit none ! Arguments class(whm_nbody_system), intent(inout) :: self !! Swiftest system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - call io_read_initialize_system(self, param) + call setup_initialize_system(self, param) ! Make sure that the discard list gets allocated initially call self%tp_discards%setup(self%tp%nbody) call self%pl%set_mu(self%cb) diff --git a/src/whm/whm_step.f90 b/src/whm/whm_step.f90 index 22dd16387..64415f15d 100644 --- a/src/whm/whm_step.f90 +++ b/src/whm/whm_step.f90 @@ -12,7 +12,7 @@ module subroutine whm_step_system(self, param, t, dt) implicit none ! Arguments class(whm_nbody_system), intent(inout) :: self !! WHM nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters of on parameters + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters real(DP), intent(in) :: t !! Current simulation time real(DP), intent(in) :: dt !! Current stepsize @@ -56,7 +56,7 @@ module subroutine whm_step_pl(self, system, param, t, dt) call pl%kick(dth) call pl%vh2vj(cb) if (param%lgr) call pl%gr_pos_kick(param, dth) - call pl%drift(system, param, dt) + call pl%drift(system, param, dt, pl%status(:) == ACTIVE) if (param%lgr) call pl%gr_pos_kick(param, dth) call pl%j2h(cb) call pl%accel(system, param, t + dt) @@ -95,7 +95,7 @@ module subroutine whm_step_tp(self, system, param, t, dt) end if call tp%kick(dth) if (param%lgr) call tp%gr_pos_kick(param, dth) - call tp%drift(system, param, dt) + call tp%drift(system, param, dt, tp%status(:) == ACTIVE) if (param%lgr) call tp%gr_pos_kick(param, dth) call tp%accel(system, param, t + dt, lbeg=.false.) call tp%kick(dth)