From b31255e522b61ad49260874d976ca846192b5b16 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 19 Apr 2023 12:37:18 -0400 Subject: [PATCH 001/324] started rotation subroutine --- calc_ring_mass.py | 28 + copy_setup_sim_ring_capture.py | 180 +++++ read_nc_sim.ipynb | 1334 ++++++++++++++++++++++++++++++++ scatter_movie.ipynb | 877 +++++++++++++++++++++ setup_sim.py | 62 ++ setup_sim_ring_capture.py | 222 ++++++ src/swiftest/swiftest_obl.f90 | 25 + 7 files changed, 2728 insertions(+) create mode 100644 calc_ring_mass.py create mode 100644 copy_setup_sim_ring_capture.py create mode 100644 read_nc_sim.ipynb create mode 100644 scatter_movie.ipynb create mode 100644 setup_sim.py create mode 100644 setup_sim_ring_capture.py diff --git a/calc_ring_mass.py b/calc_ring_mass.py new file mode 100644 index 000000000..dacbb372a --- /dev/null +++ b/calc_ring_mass.py @@ -0,0 +1,28 @@ +""" +Calculate the approx. mass of a ring given the central body observed parameters + +""" +import numpy as np + +simdir = '/scratch/bell/anand43/swiftest_runs/' + +# ring parameters (in SI units) +density = 2000 # kg / m^3 +width = 3.5e3 # m +radius = 404.8e3 # m # assume inner radius +outer_rad = radius + width +height = 0.1e3 # assume height of 100 m thick + +# central body parameters (in SI units) +cb_mass = 3.874e20 # kg +cb_name = 'Chariklo' + +vol = np.pi * (outer_rad**2 - radius**2) * height # ring volume +ring_mass = vol * density # ring mass + +print_msg = f'\nMass of Ring around {cb_name} = {ring_mass} kg = {ring_mass / cb_mass} M_{cb_name}' +print(print_msg) +print(f'Assuming a ring thickness of {height} m') + +file = open(simdir + cb_name + f'/{cb_name}_ring_mass.txt', 'w') +file.write(print_msg) \ No newline at end of file diff --git a/copy_setup_sim_ring_capture.py b/copy_setup_sim_ring_capture.py new file mode 100644 index 000000000..b76b55fc6 --- /dev/null +++ b/copy_setup_sim_ring_capture.py @@ -0,0 +1,180 @@ +import numpy as np +import swiftest +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import axes3d + +seed = None +rng = np.random.default_rng(seed=seed) +n_bodies = int(1e4) # number of planet bodies +array_shift = np.random.randint(0, n_bodies) +tstop = 500 # rotation periods +dt = 1.0e-3 +dt_unit = 'Haumea_rot_period' +# dt_unit = 'd' +dt_max = 0 +G = 6.6743e-11 # SI Units +scratch_dr = '/scratch/bell/anand43/swiftest_runs/' +simdir = 'haumea_1e4_part' +simdir = scratch_dr + simdir + +# unit conversion factors +S2DAY = 1 / (60.0 * 60 * 24) +S2YR = S2DAY / 365.25 +KG2MSUN = 1 / 1.98847e30 +M2AU = 1 / 1.496e11 + +# initial central body parameters +# Haumea parameters taken from P. S. Jean Carvalho (2019) + +cb_mass = 4.006e21 # kg +cb_radius = 711.9097e3 # m +mass = cb_mass / cb_mass +radius = cb_radius / cb_radius +longest_axis = 1161e3 # m +rmin = longest_axis / cb_radius +volume = 4.0 / 3.0 * np.pi * radius**3 +density = mass / volume # kg/m^3 +T_rotation = 3.915341 * 60 * 60 # hours to sec +rot = 2 * np.pi / T_rotation # rad/s +rot = [[0, 0, rot]] +J2 = 0.305 +J4 = -0.216 +time_unit = T_rotation +print(f'R_min = {rmin}') + +# set up swiftest simulation + +sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e5, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", rmin = rmin, MU2KG = mass, DU2M = radius, TU2S = T_rotation, init_cond_format = 'XV') # TU = dt_unit, MU_name = 'M_Haumea', DU_name = 'R_Haumea' + +#initial ring particle orbital parameters + +id_start = 100 # starting ID for bodies + +random_radius = rng.random(n_bodies) * (50 - 5) + 5 # randomize the radii of the ring particles between 5 and 50 (m) +random_mass = np.power(random_radius, 3) * 4.0 * np.pi / 3.0 * density # randomize the mass + +z_sign = rng.random(n_bodies) - 0.5 # randomize the sign of the z-component + +# set up the position vectors +random_pos_mag = (rng.random(n_bodies) * (3 - 1.65) + 1.65) # randomize the distance between 1.65 and 3 Haumea Radii +random_phi = np.deg2rad((rng.random(n_bodies)) * 90.0) +random_theta = np.deg2rad((rng.random(n_bodies)) * (30.0 - (-30)) - 30) # equatorial zone +x = random_pos_mag * np.sin(random_theta) * np.cos(random_phi) +y = random_pos_mag * np.sin(random_theta) * np.sin(random_phi) +z = random_pos_mag * np.cos(random_theta) * np.sign(z_sign) +random_pos_vec = np.array([x, y, z]).T + +# set up the velocity vectors +random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (2.0 - 0.5) + 0.5) # randomize the velocity by 0.5 - 2.0 about the keplerian velocity +random_phi = np.deg2rad((rng.random(n_bodies)) * 90.0) +random_theta = np.deg2rad((rng.random(n_bodies)) * (30.0 - (-30)) - 30) # equatorial zone +x = random_vel_mag * np.sin(random_theta) * np.cos(random_phi) +y = random_vel_mag * np.sin(random_theta) * np.sin(random_phi) +z = random_vel_mag * np.cos(random_theta) * np.sign(z_sign) +random_vel_vec = np.array([x, y, z]).T + +print(f'Shape of pos vec = {random_pos_vec.shape}') +print(f'Shape of vel vec = {random_vel_vec.shape}') + +# random_rot = 0 * [0, 0, 1.0] * rng.random(n_bodies) # rad/s +# CHECK and FIX random_rot (sequence multiplication issue) + +random_radius = random_radius / radius +random_mass = random_mass / mass + +ring_mass_tot = np.sum(random_mass) + +print(f'Total ring mass = {ring_mass_tot} {sim.MU_name}') +print(f'sim.GU = {sim.GU}') + +sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2, J4 = J4) +sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), mass = random_mass, radius = random_radius, rh = random_pos_vec, vh = random_vel_vec)#, rot = random_rot) + +# check that dt < dt_max + +dt_max = 2.0 * np.pi / np.sqrt(G * mass) +dt_max = dt_max * np.power(np.min(random_pos_mag) * sim.DU2M, 3/2) +dt_max = dt_max / 10.0 +dt_max = dt_max / sim.TU2S # convert s to time units + +print(f'\ndt_max = {dt_max} {dt_unit}') +print(f'Current dt = {dt} {dt_unit}\n') + +if(dt > dt_max): + print("dt is TOO BIG!") + raise Exception + +sim.write_param() +sim.save() +# sim.run() + +# Make initial plots + +fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) + +plt.scatter(np.linalg.norm(sim.data.isel(time = 0)['rh'], axis = 1), np.linalg.norm(sim.data.isel(time = 0)['vh'], axis = 1)) +plt.xlabel('rh') +plt.ylabel('vh') +# plot longest axis +cb_ax_long = rmin +ymin = np.min(random_vel_mag) +ymax = np.max(random_vel_mag) +plt.ylim([0, ymax]) +plt.plot([cb_ax_long, cb_ax_long], [0, ymax], '-', color = 'orange') +plt.text(cb_ax_long - 0.1, ymax / 5, s = r'Longest CB Axis', color = 'orange', rotation = 'vertical') + +plt.savefig(simdir + '/r_vs_v_initial.png') + +plt.clf() +fig = plt.figure(dpi = 300) +ax = fig.add_subplot(projection = '3d') +ax.scatter(random_pos_vec[:, 0], random_pos_vec[:, 1], random_pos_vec[:, 2], marker = 'o') +ax.set_xlabel('x') +ax.set_ylabel('y') +ax.set_zlabel('z') +ax.set_zlim([-5, 5]) +plt.savefig(simdir + '/pos_vector.png') + +ax.view_init(elev = 0, azim = 0) +plt.savefig(simdir + '/pos_vector_eq.png') + + +# Extra code + +# random_2pi = 360 * np.random.rand(n_bodies) # 360 degrees +# random_pi = 180 * np.random.rand(n_bodies) # 180 degrees +# random_a = (rng.random(n_bodies) * (4 - 1.65) + 1.65) # randomize the semi-major axis between 1.65 and 4 (Haumea Radii) +# # Haumea's longest axis = 1.63 * R_Haumea (1161 km = 1.63 * 711.9097 km) +# random_e = rng.random(n_bodies) * 0.8 # randomize eccentricity between 0 and 0.8 +# random_i = np.random.rand(n_bodies) * (30 - (-30)) + (-30) # between (-30, 30) (degrees) (equatorial zone) +# random_capom = random_2pi +# random_omega = np.roll(random_2pi, array_shift) +# array_shift = np.random.randint(0, n_bodies) # compute another random shift +# random_capm = np.roll(random_2pi, array_shift) + + + +# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) + +# plt.scatter(sim.data['a'], sim.data['e']) +# plt.xlabel('a') +# plt.ylabel('e') +# plt.savefig(simdir + '/a_vs_e_initial.png') + +# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) + +# plt.scatter(sim.data['a'], sim.data['inc']) +# plt.xlabel('a') +# plt.ylabel('inc') +# plt.savefig(simdir + '/a_vs_i_initial.png') + +# print(f'sim.MU2KG = {sim.MU2KG}') +# print(f'sim.param["MU2KG"] = {sim.param["MU2KG"]}') +# print(f'sim.MU_name = {sim.MU_name}') +# sim.add_solar_system_body(["Sun", "Mercury", "Venus", "Earth", "Mars"]) +# random_radius = random_radius / sim.DU2M +# random_mass = random_mass / sim.MU2KG +# sim.add_body(name = 'Centaur', id = 0, mass = mass / mass, rot = rot, radius = radius / radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, J2 = J2, J4 = J4) +# sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius)#, rot = random_rot) + +# sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e5, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", TU = dt_unit, rmin = rmin, MU2KG = mass, DU2M = radius, init_cond_format = 'XV',)# MU_name = 'M_Haumea', DU_name = 'R_Haumea') diff --git a/read_nc_sim.ipynb b/read_nc_sim.ipynb new file mode 100644 index 000000000..1db018833 --- /dev/null +++ b/read_nc_sim.ipynb @@ -0,0 +1,1334 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "env: HDF5_USE_FILE_LOCKING=FALSE\n", + "Reading Swiftest file /scratch/bell/anand43/swiftest/ring_capture_sph_rot/param.in\n", + "\n", + "Creating Dataset from NetCDF file\n", + "Successfully converted 1 output frames.\n", + "\n", + "Creating Dataset from NetCDF file\n", + "Successfully converted 36526 output frames.\n", + "Swiftest simulation data stored as xarray DataSet .data\n", + "Reading initial conditions file as .init_cond\n", + "Reading collisions history file as .collisions\n", + "Finished reading Swiftest dataset files.\n" + ] + } + ], + "source": [ + "#!/usr/bin/env python3\n", + "\n", + "%env HDF5_USE_FILE_LOCKING=FALSE\n", + "\n", + "import numpy as np\n", + "import swiftest \n", + "\n", + "sim = swiftest.Simulation(simdir = 'ring_capture_sph_rot', read_data = True, dask = True)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:  (name: 1001, space: 3, time: 1)\n",
+       "Coordinates:\n",
+       "  * name     (name) <U32 'Centaur' '100' '101' '102' ... '1097' '1098' '1099'\n",
+       "  * space    (space) <U1 'x' 'y' 'z'\n",
+       "  * time     (time) float64 0.0\n",
+       "Data variables: (12/14)\n",
+       "    a        (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
+       "    e        (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
+       "    inc      (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
+       "    capom    (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
+       "    omega    (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
+       "    capm     (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
+       "    ...       ...\n",
+       "    rot      (time, name, space) float64 dask.array<chunksize=(1, 1001, 3), meta=np.ndarray>\n",
+       "    Ip       (time, name, space) float64 dask.array<chunksize=(1, 1001, 3), meta=np.ndarray>\n",
+       "    id       (name) int64 dask.array<chunksize=(1001,), meta=np.ndarray>\n",
+       "    ntp      (time) int64 dask.array<chunksize=(1,), meta=np.ndarray>\n",
+       "    npl      (time) int64 dask.array<chunksize=(1,), meta=np.ndarray>\n",
+       "    nplm     (time) int64 dask.array<chunksize=(1,), meta=np.ndarray>
" + ], + "text/plain": [ + "\n", + "Dimensions: (name: 1001, space: 3, time: 1)\n", + "Coordinates:\n", + " * name (name) \n", + " e (time, name) float64 dask.array\n", + " inc (time, name) float64 dask.array\n", + " capom (time, name) float64 dask.array\n", + " omega (time, name) float64 dask.array\n", + " capm (time, name) float64 dask.array\n", + " ... ...\n", + " rot (time, name, space) float64 dask.array\n", + " Ip (time, name, space) float64 dask.array\n", + " id (name) int64 dask.array\n", + " ntp (time) int64 dask.array\n", + " npl (time) int64 dask.array\n", + " nplm (time) int64 dask.array" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sim.init_cond\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (My minton_lab_packages Kernel)", + "language": "python", + "name": "minton_lab_packages" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/scatter_movie.ipynb b/scatter_movie.ipynb new file mode 100644 index 000000000..aedaf11e8 --- /dev/null +++ b/scatter_movie.ipynb @@ -0,0 +1,877 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import swiftest \n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib import animation\n", + "import matplotlib.colors as mcolors\n", + "from collections import namedtuple\n", + "plt.switch_backend('agg')" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "env: HDF5_USE_FILE_LOCKING=FALSE\n", + "Reading Swiftest file /scratch/bell/anand43/swiftest/haumea/param.in\n", + "\n", + "Creating Dataset from NetCDF file\n", + "Successfully converted 1 output frames.\n", + "\n", + "Creating Dataset from NetCDF file\n", + "Successfully converted 16 output frames.\n", + "Swiftest simulation data stored as xarray DataSet .data\n", + "Reading initial conditions file as .init_cond\n", + "Finished reading Swiftest dataset files.\n", + "Making animation\n", + "Finished writing haumea-aescatter.mp4\n", + "Animation finished\n", + "Making animation\n", + "Finished writing haumea-aiscatter.mp4\n", + "Animation finished\n" + ] + } + ], + "source": [ + "#!/usr/bin/env python3\n", + "\n", + "\"\"\"\n", + " Copyright 2023 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh\n", + " This file is part of Swiftest.\n", + " Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License \n", + " as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n", + " Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty \n", + " of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n", + " You should have received a copy of the GNU General Public License along with Swiftest. \n", + " If not, see: https://www.gnu.org/licenses. \n", + "\"\"\"\n", + "\n", + "\"\"\"\n", + "Creates a movie from a set of Swiftest output files. All simulation \n", + "outputs are stored in the /simdata subdirectory.\n", + "\n", + "Input\n", + "------\n", + "param.in : ASCII Swiftest parameter input file.\n", + "data.nc : A NetCDF file containing the simulation output.\n", + "\n", + "Output\n", + "------\n", + "Chambers2013-aescatter.mp4 : A .mp4 file plotting eccentricity vs semimajor axis. \n", + "OR \n", + "Chambers2013-aiscatter.mp4 : A .mp4 file plotting inclination vs semimajor axis. \n", + "\"\"\"\n", + "%env HDF5_USE_FILE_LOCKING=FALSE\n", + "\n", + "import swiftest \n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib import animation\n", + "import matplotlib.colors as mcolors\n", + "from collections import namedtuple\n", + "plt.switch_backend('agg')\n", + "\n", + "titletext = 'haumea'\n", + "valid_plot_styles = [\"aescatter\", \"aiscatter\"]#, \"arotscatter\"]\n", + "xlim={\"aescatter\" : (0.0, 5.0),\n", + " \"aiscatter\" : (0.0, 5.0), \n", + " \"arotscatter\" : (0.0, 2.5)}\n", + "ylim={\"aescatter\" : (0.0, 1.0),\n", + " \"aiscatter\" : (0.0, 40.0),\n", + " \"arotscatter\" : (1.0, 10000.0)}\n", + "xlabel={\"aescatter\": r\"Semimajor axis ($R_{Haumea}$)\",\n", + " \"aiscatter\": r\"Semimajor axis ($R_{Haumea}$)\",\n", + " \"arotscatter\": \"Semimajor axis (AU)\"}\n", + "ylabel={\"aescatter\": \"Eccentricity\",\n", + " \"aiscatter\": \"Inclination (deg)\",\n", + " \"arotscatter\": \"Rotation period (h)\"}\n", + "\n", + "cb_ax_long = 1.63 # longest axis of the central body\n", + "\n", + "YR2HR = 365.25 * 24\n", + "ROT2PERIOD = YR2HR * 360.0\n", + "\n", + "framejump = 1\n", + "origin_types = [\"Initial conditions\", \"Merger\", \"Disruption\", \"Supercatastrophic\", \"Hit and run fragmentation\"]\n", + "\n", + "\n", + "class AnimatedScatter(object):\n", + " \"\"\"An animated scatter plot using matplotlib.animations.FuncAnimation.\"\"\"\n", + " def __init__(self, ds, param):\n", + "\n", + " self.radscale = 2e6\n", + " nframes = int(ds['time'].size / framejump)\n", + " ds['rot_mag'] = swiftest.tool.magnitude(ds,\"rot\")\n", + " ds['rot_mag'] = ROT2PERIOD / ds['rot_mag']\n", + " self.Rcb = ds['radius'].sel(name=\"Centaur\").isel(time=0).values[()]\n", + " self.ds = ds\n", + " self.param = param\n", + " colors = [\"k\", \"xkcd:faded blue\", \"xkcd:marigold\", \"xkcd:shocking pink\", \"xkcd:baby poop green\"]\n", + " self.clist = dict(zip(origin_types,colors))\n", + "\n", + " # Setup the figure and axes...\n", + " fig = plt.figure(figsize=(8,4.5), dpi=300)\n", + " plt.tight_layout(pad=0)\n", + " # set up the figure\n", + " self.ax = plt.Axes(fig, [0.1, 0.15, 0.8, 0.75])\n", + " fig.add_axes(self.ax)\n", + "\n", + " self.make_artists()\n", + " \n", + " self.ani = animation.FuncAnimation(fig, func=self.update, interval=1, frames=nframes, init_func=self.init_plot, blit=True)\n", + " self.ani.save(animation_file, fps=60, dpi=300, extra_args=['-vcodec', 'libx264'])\n", + " print(f'Finished writing {animation_file}')\n", + " \n", + " def make_artists(self):\n", + " scatter_names = [f\"s{i}\" for i,k in enumerate(origin_types)]\n", + " self.scatter_artist_names = dict(zip(origin_types,scatter_names))\n", + " \n", + " animated_elements = [self.ax.text(0.50, 1.05, \"\", bbox={'facecolor': 'w', 'alpha': 0.5, 'pad': 5}, transform=self.ax.transAxes,ha=\"center\", animated=True)]\n", + " element_names = [\"title\"]\n", + " for key, value in self.clist.items():\n", + " animated_elements.append(self.ax.scatter([], [], marker='o', s=[], c=value, alpha=0.75, label=key, animated=True))\n", + " element_names.append(self.scatter_artist_names[key])\n", + " \n", + " Artists = namedtuple(\"Artists\",tuple(element_names))\n", + " self.artists = Artists(*animated_elements)\n", + " return \n", + "\n", + " def init_plot(self):\n", + " self.ax.set_xlim(xlim[plot_style])\n", + " self.ax.set_ylim(ylim[plot_style])\n", + " \n", + " # set up the figure\n", + " self.ax.margins(x=10, y=1)\n", + " self.ax.set_xlabel(xlabel[plot_style], fontsize='16', labelpad=1)\n", + " self.ax.set_ylabel(ylabel[plot_style], fontsize='16', labelpad=1) \n", + " \n", + " leg = plt.legend(loc=\"upper left\", scatterpoints=1, fontsize=10)\n", + " for i,l in enumerate(leg.legendHandles):\n", + " leg.legendHandles[i]._sizes = [20]\n", + " \n", + " if plot_style == \"arotscatter\":\n", + " self.ax.set_yscale('log')\n", + " \n", + " # plot longest axis\n", + " self.ax.plot([cb_ax_long, cb_ax_long], ylim[plot_style], '-', color = 'orange')\n", + " self.ax.text(cb_ax_long - 0.1, ylim[plot_style][-1] / 5, s = r'Longest Haumea Axis', color = 'orange', rotation = 'vertical')\n", + "\n", + " return self.artists\n", + "\n", + " def get_data(self, frame=0):\n", + " d = self.ds.isel(time = frame)\n", + " n=len(d['name'])\n", + " d = d.isel(name=range(1,n))\n", + " d['radmarker'] = (d['radius'] / self.Rcb) * self.radscale\n", + "\n", + " t = d['time'].values\n", + " npl = d['npl'].values\n", + " radmarker = d['radmarker'].values\n", + " origin = d['origin_type'].values\n", + "\n", + " # print(radmarker)\n", + "\n", + " # Check for test particles\n", + " # radmarker = np.where(np.isnan(radmarker), 2.0, radmarker)\n", + "\n", + " if plot_style == \"aescatter\":\n", + " pl = np.c_[d['a'].values,d['e'].values]\n", + " elif plot_style == \"aiscatter\":\n", + " pl = np.c_[d['a'].values,d['inc'].values]\n", + " elif plot_style == \"arotscatter\":\n", + " pl = np.c_[d['a'].values,d['rot_mag'].values]\n", + "\n", + " return t, npl, pl, radmarker, origin\n", + "\n", + " def update(self,frame):\n", + " \"\"\"Update the scatter plot.\"\"\"\n", + " t, npl, pl, radmarker, origin = self.get_data(framejump * frame)\n", + "\n", + " self.artists.title.set_text(f\"{titletext} - Time = ${t / 365.25:6.3f}$ years with ${npl:4.0f}$ particles\")\n", + "\n", + " for key,name in self.scatter_artist_names.items():\n", + " idx = origin == key\n", + " if any(idx) and any(~np.isnan(radmarker[idx])):\n", + " scatter = self.artists._asdict()[name]\n", + " scatter.set_sizes(radmarker[idx])\n", + " scatter.set_offsets(pl[idx,:])\n", + " scatter.set_facecolor(self.clist[key])\n", + "\n", + " return self.artists\n", + "\n", + "sim = swiftest.Simulation(simdir = \"\", read_data=True, read_collisions=False, dask=True)\n", + "for plot_style in valid_plot_styles:\n", + " animation_file = titletext+f\"-{plot_style}.mp4\"\n", + " print('Making animation')\n", + " anim = AnimatedScatter(sim.data,sim.param)\n", + " print('Animation finished')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading Swiftest file /scratch/bell/anand43/swiftest/haumea/param.in\n", + "\n", + "Creating Dataset from NetCDF file\n", + "Successfully converted 1 output frames.\n", + "\n", + "Creating Dataset from NetCDF file\n", + "Successfully converted 16 output frames.\n", + "Swiftest simulation data stored as xarray DataSet .data\n", + "Reading initial conditions file as .init_cond\n", + "Finished reading Swiftest dataset files.\n", + "number of bodies = 1001\n", + "[2.86707 2.26437611 3.6405438 3.93954489 2.94934881 3.08719425\n", + " 2.95619724 1.9315956 3.35814933 2.77744476 2.20363536 1.80574104\n", + " 2.71574397 3.49343986 2.03069888 3.5347133 2.46825806 2.71661343\n", + " 3.93758726 2.97675649 2.92302706 3.14238838 2.01017286 3.05107946\n", + " 2.9221084 3.83691596 2.32825779 2.63754725 3.33224001 2.45594668\n", + " 2.16867971 3.54655207 3.26450524 2.49896467 3.51590433 2.76106804\n", + " 1.9547691 2.74151039 3.94052577 2.13224769 3.36147178 2.53802787\n", + " 3.94673846 2.55988291 2.61847283 3.7620777 2.74105637 2.26478436\n", + " 1.81292722 2.76747095 2.29839042 3.80990784 3.62667666 3.71100367\n", + " 3.1725749 2.8574224 3.10210675 2.62842282 3.83353877 2.33035236\n", + " 3.6922478 2.22235092 3.15121301 2.77698703 2.5148019 2.91196748\n", + " 2.92627535 2.01706855 3.37747333 2.01111034 2.23898296 1.99306054\n", + " 1.90765108 3.2891204 3.25774258 2.30690781 3.24247923 3.49395891\n", + " 3.0314892 3.41474591 2.35703199 2.47902128 3.5086045 2.34151029\n", + " 3.12357904 3.57508057 1.92484951 1.88433176 2.95554871 3.92998504\n", + " 3.64213516 2.25213735 2.64555628 3.84748461 2.83338406 3.10835355\n", + " 3.65517402 1.90442769 3.08798552 2.61461352 2.98027672 2.07129231\n", + " 2.68607562 2.17261436 3.51264548 3.79854977 2.85469106 3.32746676\n", + " 2.01795376 3.78517184 2.20546773 3.86126769 2.95116322 2.8668133\n", + " 3.69375314 3.01422846 3.41030877 3.23427886 3.08542127 2.48789476\n", + " 1.9695036 3.16060334 1.93368786 2.89096413 2.45437467 3.4528045\n", + " 2.62510114 1.82658788 2.49568697 2.26774026 2.04158516 1.88707444\n", + " 3.09190663 3.98298489 2.38626218 3.91507248 1.81577043 3.79586533\n", + " 2.9173471 2.5917093 2.23717457 3.20106058 2.47275269 3.38695918\n", + " 2.89263554 3.24748083 3.94279254 3.15227637 2.87201905 3.88772146\n", + " 2.9251222 3.04232266 1.94950256 3.16333805 2.33424485 1.99481516\n", + " 3.54275327 3.08652743 2.84501543 3.7911194 3.02218081 3.84373384\n", + " 3.82582263 2.85336618 2.37761213 3.29034402 2.78529209 3.08157623\n", + " 2.93255092 2.66888596 3.20623023 3.12431925 2.57489376 2.91916641\n", + " 3.05397871 2.6213803 3.87089633 2.67114345 3.17434139 3.70503684\n", + " 2.36710633 3.0933641 3.50999258 3.63232575 2.62702814 3.44950602\n", + " 2.90155466 1.81862977 3.2113113 2.40571088 3.95325113 2.35675543\n", + " 2.81512142 2.98604457 2.65486392 2.8245242 3.25293944 2.77414958\n", + " 3.82444089 3.22822059 3.32508177 1.82926629 2.81615423 1.81170231\n", + " 3.2672492 3.66426422 3.79924248 3.05292133 2.41273786 1.93866512\n", + " 3.56331393 3.24915661 2.17261353 2.63877867 3.63978883 2.96951823\n", + " 3.02056263 3.53162077 3.29459515 1.8125504 3.26264535 3.26224581\n", + " 2.38075792 2.5874306 2.97279996 1.82845238 2.95132374 2.52939867\n", + " 2.72506068 3.07242353 3.06259972 3.76134273 2.45985533 2.85088455\n", + " 2.98108016 3.16893004 3.17572645 2.83419379 2.49490167 3.15893129\n", + " 2.55465139 3.21692659 3.65046901 2.54691214 3.92232599 1.90958515\n", + " 2.76641704 2.8996368 3.67097629 2.60807588 3.12486695 2.20398682\n", + " 2.51193867 3.03699266 3.34614604 3.47813301 2.48616203 2.95904923\n", + " 3.95076906 2.09013407 2.46546473 2.92228685 3.90430466 2.98769887\n", + " 3.86698362 1.9651921 3.53736777 3.78755373 3.87982806 1.80143241\n", + " 3.43573073 2.42122902 2.85072899 2.94483093 1.90562571 3.39627757\n", + " 3.88608514 2.97870912 2.15747184 2.59056916 1.97813882 3.76969048\n", + " 1.98673351 3.10073135 2.06670634 2.47180573 2.91704473 3.38474023\n", + " 3.59892043 3.54560466 3.22105973 2.45655225 3.76339075 3.63990026\n", + " 1.93323891 3.3077368 3.39426961 3.78948283 1.87036916 3.18943426\n", + " 2.06981414 3.20476601 1.89480136 3.30862502 3.00625902 3.10245457\n", + " 2.41632241 2.46760789 1.94693533 3.28405791 3.66079823 2.18920077\n", + " 2.67134882 2.06354222 2.11375689 3.64315927 3.96539447 2.58131973\n", + " 2.52675495 2.75691604 2.45845913 1.80666773 3.37788197 3.97650716\n", + " 1.8235495 2.87197387 2.26808226 3.10342701 3.89444171 2.35452286\n", + " 2.58154931 2.28054829 3.1362631 2.31722063 3.89073682 2.46557629\n", + " 2.41433102 2.31849176 3.85388787 3.83029776 2.22969765 2.83333593\n", + " 3.03842192 3.88408149 1.82667596 3.78208815 2.98501615 2.80479459\n", + " 2.96955749 2.22692875 3.00685847 2.11053991 3.03634502 3.99170556\n", + " 3.51732555 2.60407546 1.80112911 1.96796986 2.38454603 3.62566359\n", + " 3.9638863 2.33239881 3.46270587 3.42062892 2.05200829 3.71034592\n", + " 2.10742192 1.80845964 3.94865965 3.15339175 2.81418708 2.05396828\n", + " 2.39173238 2.12492795 2.45152201 3.867548 3.07707988 3.7839497\n", + " 3.60964604 3.18482216 2.43783162 3.68016789 2.23005874 3.56402737\n", + " 2.94331073 2.6951672 3.70254548 3.10568974 2.53914057 3.50781026\n", + " 2.10783249 2.72856534 2.70905719 3.38752398 2.74695416 2.44868168\n", + " 3.19457252 2.25116169 3.27183918 2.93629542 3.70012443 2.08910313\n", + " 1.85172104 1.80322834 2.93547433 2.33389348 3.74602895 3.98087291\n", + " 3.09040941 3.71433261 2.23642677 2.49318031 2.34909762 3.83081933\n", + " 2.499303 3.8342502 3.99044316 3.76237752 2.48457904 2.37214914\n", + " 1.98573256 1.89494674 2.21747754 2.1654547 3.22252898 3.54409441\n", + " 2.04831539 3.89704498 1.84586618 3.43563908 2.26839343 3.95813064\n", + " 1.99456985 3.58463229 1.82591801 2.38386884 2.7182952 2.89195448\n", + " 3.23887658 3.03382594 3.09723279 2.19107386 3.99924422 3.83343698\n", + " 2.60833875 2.72747379 2.39127566 3.72958697 2.09058244 2.58853849\n", + " 3.94192955 2.35107722 2.87111745 2.4799833 3.46839085 2.3263921\n", + " 2.91418045 2.1592128 2.52342638 2.99301811 2.66753894 2.85138794\n", + " 2.31609956 3.63879729 1.82785488 2.52281426 2.31571043 2.73430988\n", + " 2.03591542 3.57678249 3.9467535 2.40015656 3.21001766 1.95069303\n", + " 3.76710942 2.94092702 3.59669815 2.55784566 2.73363482 2.7431271\n", + " 2.88747775 3.29540831 3.5841192 2.10522076 1.93837456 3.39399095\n", + " 3.17707757 2.63953918 3.01295314 1.95973882 1.98780649 2.18197849\n", + " 3.81403775 3.54935395 3.78923295 3.76379051 2.38450664 3.04698007\n", + " 2.45577138 2.88636479 2.33312543 2.74517056 2.29531488 3.57665951\n", + " 2.96855176 2.45710483 2.85845093 2.04415776 3.55368151 1.95701192\n", + " 3.59110225 3.68504318 3.20134106 2.27306975 3.78164712 2.92344475\n", + " 2.39614455 3.67152363 3.98144479 2.06543455 2.42466762 2.30068764\n", + " 1.93226954 3.64158746 3.75782464 3.18548846 1.8167459 3.67493525\n", + " 3.63721934 3.91427937 1.86744532 3.70223565 2.23369345 2.52431285\n", + " 2.98225363 2.17265534 2.67917271 2.62715229 3.93284723 2.51821012\n", + " 3.53714754 3.38447755 3.04831115 2.81751676 2.83742262 3.72240774\n", + " 2.69589499 2.44771722 3.56481535 3.97168904 3.97450669 3.32535339\n", + " 2.2380867 3.96860887 3.10118483 2.28384777 3.99534556 2.81954312\n", + " 3.48427296 2.10313325 3.14784073 2.27634883 2.56291701 3.25150434\n", + " 2.80893276 2.76251536 3.0881402 3.58281511 3.00737753 3.40792374\n", + " 3.86495002 3.18281984 3.61989202 2.59449528 3.37882132 2.04958984\n", + " 3.84105445 3.00721393 1.94106032 2.187152 3.22459746 2.17636862\n", + " 2.60611682 1.80062892 3.50569036 2.82453039 1.97646818 3.35170039\n", + " 2.83263403 3.18868638 2.91313879 3.14404854 2.41328239 3.20123104\n", + " 3.69885294 3.30177181 1.99099318 3.57844773 2.53213969 2.97900973\n", + " 3.55369678 3.34219435 3.08626794 2.39239569 3.42891466 2.95054151\n", + " 3.83927607 1.8605209 3.72710113 3.72464167 2.9484406 3.08286897\n", + " 3.09456901 3.49361857 2.63007237 2.88181073 3.31759219 1.8136873\n", + " 3.51587449 1.88055712 2.27291034 2.61512479 2.21706371 3.88106042\n", + " 3.36743163 3.20090707 2.56376552 3.39817264 2.10839002 2.58872065\n", + " 3.81129539 3.96253473 3.43698527 2.92952744 2.71526314 3.03716288\n", + " 1.91486291 3.08129312 2.98193717 2.39349587 3.99411614 1.93554448\n", + " 3.71261072 2.46968171 2.01140301 2.646433 2.88644449 2.25227174\n", + " 2.72064543 3.30272203 3.25046027 2.73967233 1.91165722 2.90768238\n", + " 1.86529355 2.96070399 2.77314104 3.72156093 3.24757593 3.21269682\n", + " 3.59713754 1.93076813 2.03294904 3.98167812 2.57785141 3.74349092\n", + " 1.92491038 3.68708838 3.25856293 3.19631964 3.14665325 2.62639443\n", + " 2.3519243 3.55784453 2.31817522 3.92597621 3.40730456 3.80860323\n", + " 1.88132235 2.68782942 2.01852222 3.47610733 2.36079137 1.9152418\n", + " 2.50151756 3.34228421 3.27762915 3.96814843 3.20270105 3.59971596\n", + " 3.23440836 3.41171567 2.90759424 2.09586371 2.76016933 2.73706659\n", + " 2.56430649 1.91228857 3.13940309 1.99505674 2.4495765 2.73543595\n", + " 2.30020448 2.88536265 3.68797496 2.51733565 2.07561723 3.19322504\n", + " 3.4988761 3.45408619 3.65600111 2.0457678 3.24858436 3.46355762\n", + " 2.46219727 2.06914063 2.11572774 2.31653463 3.04936642 3.92949049\n", + " 2.54717756 3.55758675 3.09722771 3.96115502 3.60451308 3.55259832\n", + " 3.19157466 3.26707393 2.30452338 3.82926449 2.70137852 3.32993463\n", + " 2.35270965 3.65899762 2.44267372 2.17109822 2.88132051 3.69422536\n", + " 3.66478365 3.04108579 3.95722544 3.86754083 3.9452419 3.97303988\n", + " 2.66637405 2.703648 2.01049446 2.56522475 3.20930447 3.37231218\n", + " 1.80665703 2.34981361 2.09583017 3.61212815 3.67365765 2.26366423\n", + " 2.76547929 3.32779797 3.99094811 2.33452816 2.79944165 3.01708238\n", + " 2.51050538 3.8618905 2.4355322 2.95129246 3.79840371 2.36200969\n", + " 2.05297058 1.91790903 2.42212044 2.44991786 2.07671169 3.29651237\n", + " 3.02724494 2.14206015 3.60893401 3.39960394 3.79869304 2.89272848\n", + " 3.84640706 2.28135138 2.39743776 2.54691734 1.84793483 3.9941595\n", + " 3.79309174 2.56536888 2.7670722 2.78647629 2.46724476 3.60274147\n", + " 3.83808844 2.08904839 2.10507857 2.13993358 2.26780496 2.41006664\n", + " 3.38797231 3.68618741 3.87216351 3.50803263 3.60099257 1.84205323\n", + " 2.33480771 2.13537323 2.6844391 3.86176135 3.19226279 3.22994065\n", + " 3.26581745 2.13998923 2.95792414 3.67193679 2.17423711 2.36280443\n", + " 2.07320183 3.76343418 2.33929475 2.12256853 3.61380039 2.8397601\n", + " 2.51283272 2.40853597 3.10570901 3.76907137 3.81436411 3.08522357\n", + " 1.87052446 2.65874975 1.83167597 3.29162079 2.96645609 3.46543259\n", + " 2.36287837 1.93341339 3.25257021 2.86125788 2.55045433 3.19096205\n", + " 2.24275342 1.96898378 2.41902642 3.24559458 2.09302917 3.06796238\n", + " 1.8595801 3.57768904 3.79539807 3.31841467 3.84063807 2.54290415\n", + " 3.9964343 2.65958935 2.43079074 1.92168518 3.34742871 2.93598793\n", + " 3.88435081 2.19268651 3.68853517 3.21140077 2.82282989 2.88055579\n", + " 2.23598795 2.27071968 3.15294119 1.99187389 2.96157153 3.35418985\n", + " 2.60196447 3.92242802 2.11143474 2.88154167 2.62208341 2.00842219\n", + " 2.20177275 3.63912038 2.15842531 2.176082 2.2979445 2.63698812\n", + " 3.631226 2.37458011 2.76343393 2.81399883 1.87149717 2.08717025\n", + " 2.70466618 2.01076977 2.32513266 3.87136979 3.41143461 3.4436919\n", + " 2.22666205 3.39007452 2.51170985 2.70019198 2.9332926 2.76436306\n", + " 3.45840216 2.04462722 3.88097606 2.80816941 3.72714885 2.65577947\n", + " 3.0420142 2.39700357 2.49124778 2.28532874 3.35348657 3.55607459\n", + " 3.85484511 2.36635014 2.078835 1.97163928 3.3332229 3.25306239\n", + " 2.24946841 2.14731298 2.46008678 2.76557381 3.72928254 2.98678591\n", + " 2.29296018 2.55564527 2.45633322 3.73649969 3.40508584 1.91503421\n", + " 2.80703053 2.9436633 3.86673948 2.82083929 3.48102901 1.81771352\n", + " 3.41822223 2.8824315 2.62430958 1.91248179 2.77392087 3.71577566\n", + " 3.50027084 2.78720951 3.40126586 3.72384478 3.8499088 3.6974411\n", + " 3.87919812 3.41157506 3.37837488 3.42786854 2.80472621 2.39567393\n", + " 3.69122758 2.52232265 3.81514334 2.18473321 2.99300448 3.23635012\n", + " 2.71998862 3.79243906 3.07194063 3.58787382 3.97846799 3.8784\n", + " 3.79397454 2.26333523 2.41389923 2.55515131 2.64889664 3.66548684\n", + " 3.55362427 3.36000855 3.2232391 3.38112289 3.73708105 3.50241592\n", + " 2.03974955 2.29111594 2.74884721 2.81526728 3.4725525 1.85137256\n", + " 2.83037433 3.65856226 2.43504443 2.82765201 2.00917454 2.86610845\n", + " 3.04238655 2.22190092 3.03751911 2.16339026 2.07270532 3.15675046\n", + " 2.37574886 3.33400854 1.9299132 3.27721295]\n" + ] + } + ], + "source": [ + "# Plot inital a vs e to see initial conditions\n", + "sim = swiftest.Simulation(simdir = \"\", read_param=True, read_collisions=False)#, dask=True)\n", + "\n", + "d = sim.data.isel(time = 0)\n", + "n=len(d['name'])\n", + "d = d.isel(name=range(1,n))\n", + "\n", + "a = d['a'].values\n", + "e = d['e'].values\n", + "inc = d['inc'].values\n", + "\n", + "fig, ax = plt.subplots(figsize=(8,4.5), dpi=300)\n", + "\n", + "print(f\"number of bodies = {n}\")\n", + "print(a)\n", + "# print(e)\n", + "\n", + "plt.scatter(a, e)\n", + "plt.xlabel('a')\n", + "plt.ylabel('e')\n", + "plt.savefig(\"a_vs_e_init.png\")\n", + "\n", + "plt.clf()\n", + "plt.scatter(a, inc)\n", + "plt.xlabel('a')\n", + "plt.ylabel('inc')\n", + "plt.savefig(\"a_vs_i_init.png\")\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'inc' (name: 1001)>\n",
+       "array([        nan, 10.17878648,  9.06981385, ...,  7.7303241 ,\n",
+       "        6.73890149,  9.62794807])\n",
+       "Coordinates:\n",
+       "    time     float64 0.0\n",
+       "  * name     (name) <U32 'Centaur' '100' '101' '102' ... '1097' '1098' '1099'\n",
+       "Attributes:\n",
+       "    _FillValue:  nan
" + ], + "text/plain": [ + "\n", + "array([ nan, 10.17878648, 9.06981385, ..., 7.7303241 ,\n", + " 6.73890149, 9.62794807])\n", + "Coordinates:\n", + " time float64 0.0\n", + " * name (name) dt_max): +# print("dt is TOO BIG!") +# raise Exception + +# set up swiftest simulation + +sim = swiftest.Simulation(simdir = "kaustub_test", integrator = "symba", tstop = tstop, dt = dt, istep_out = 500, dump_cadence = 1000, rotation = False, collision_model = "FRAGGLE")#, MU = 'kg', DU = 'm', TU = 'd', rmin = radius + 1e4) +sim.add_solar_system_body(["Sun", "Mercury", "Venus", "Earth", "Mars"]) +# sim.add_body(name = 'Centaur', id = 1, mass = density * volume, radius = radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0) +sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius) +# sim.get_parameter() +# sim.set_parameter() +sim.write_param() +sim.save() +# sim.run() diff --git a/setup_sim_ring_capture.py b/setup_sim_ring_capture.py new file mode 100644 index 000000000..994b1a368 --- /dev/null +++ b/setup_sim_ring_capture.py @@ -0,0 +1,222 @@ +import numpy as np +import swiftest +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import axes3d +import pandas as pd + +seed = None +rng = np.random.default_rng(seed=seed) +n_bodies = int(2e1) # number of planet bodies +array_shift = np.random.randint(0, n_bodies) +tstop = 50 # rotation periods +dt = 1.0e-5 +dt_unit = 'Haumea_rot_period' +# dt_unit = 'd' +dt_max = 0 +G = 6.6743e-11 # SI Units +scratch_dr = '/scratch/bell/anand43/swiftest_runs/' +body_dr = 'Haumea/' +simdir = 'test' # '2e3_part_radial' +simdir = scratch_dr + body_dr + simdir + +# initial central body parameters +# Haumea parameters taken from P. S. Jean Carvalho (2019) + +cb_mass = 4.006e21 # kg +cb_radius = 711.9097e3 # m +T_rotation = 3.915341 * 60 * 60 # hours to sec + +mass = cb_mass / cb_mass +radius = cb_radius / cb_radius +longest_axis = 1161e3 # m +rmin = longest_axis / cb_radius +volume = 4.0 / 3.0 * np.pi * radius**3 +density = mass / volume +rot = 2 * np.pi / T_rotation # rad/s +rot = [[0, 0, rot]] +J2 = 0.305 +J4 = -0.216 +print(f'R_min = {rmin}') + +# set up swiftest simulation + +sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e4, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", rmin = rmin, rmax = 50 * rmin, MU2KG = cb_mass, DU2M = cb_radius, TU2S = T_rotation, init_cond_format = 'XV') # TU = dt_unit, MU_name = 'M_Haumea', DU_name = 'R_Haumea' + +#initial ring particle orbital parameters + +id_start = 100 # starting ID for bodies + +random_radius = rng.random(n_bodies) * (500 - 100) + 100 # randomize the radii of the ring particles between 100 and 500 (m) +random_radius = random_radius / sim.DU2M +random_mass = np.power(random_radius, 3) * 4.0 * np.pi / 3.0 * density # randomize the mass + +z_sign = rng.random(n_bodies) - 0.5 # randomize the sign of the z-component + +# set up the position vectors +random_pos_mag = (rng.random(n_bodies) * (2 - 1.65) + 1.65) # randomize the distance/position vector(s) between 1.65 and 3 (R_Haumea) +random_phi = np.deg2rad((rng.random(n_bodies)) * 60.0) # cone of spilled regolith +random_theta = np.deg2rad((rng.random(n_bodies)) * (120.0 - 60) + 60) # equatorial zone +x = random_pos_mag * np.sin(random_theta) * np.cos(random_phi) +y = random_pos_mag * np.sin(random_theta) * np.sin(random_phi) +z = random_pos_mag * np.cos(random_theta) * np.sign(z_sign) +random_pos_vec = np.array([x, y, z]).T + +# set up the velocity vectors pointing radially away from the central body. + +# random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (1.15 - 0.85) + 0.85) # randomize the velocity by 0.9 - 1.1 times the keplerian velocity + +v_escape = np.sqrt(2 * sim.GU * mass / radius) +alpha = rng.random(n_bodies) * (0.90 - 0.80) + 0.80 # numerical scaling for initial velocity +random_vel_mag = np.sqrt(alpha * v_escape**2 + 2 * sim.GU * mass * (1 / random_pos_mag - 1 / radius)) # scale the velocity with distance + +x = x * random_vel_mag / random_pos_mag +y = y * random_vel_mag / random_pos_mag +z = z * random_vel_mag / random_pos_mag + +# rotate the velocity vectors (degrees) +# 85 - 95 degrees to represent orbiting particles for tangential motion +rot_angle = np.deg2rad(rng.random(n_bodies) * (5 - (-5)) + (-5)) # rotate by <> degrees randomly + +x_tmp = x +y_tmp = y + +x = x_tmp * np.cos(rot_angle) - y_tmp * np.sin(rot_angle) +y = x_tmp * np.sin(rot_angle) + y_tmp * np.cos(rot_angle) + +random_vel_vec = np.array([x, y, z]).T + +print(f'Shape of pos vec = {random_pos_vec.shape}') +print(f'Shape of vel vec = {random_vel_vec.shape}') + +# random_rot = 0 * [0, 0, 1.0] * rng.random(n_bodies) # rad/s +# CHECK and FIX random_rot (sequence multiplication issue) + +ring_mass_tot = np.sum(random_mass) + +print(f'Total ring mass = {ring_mass_tot} M_Haumea') +print(f'sim.GU = {sim.GU}') + +sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2, J4 = J4) +sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), mass = random_mass, radius = random_radius, rh = random_pos_vec, vh = random_vel_vec)#, rot = random_rot) + +# check that dt < dt_max + +dt_max = 2.0 * np.pi / np.sqrt(sim.GU * mass) +dt_max = dt_max * np.power(np.min(random_pos_mag), 3/2) +dt_max = dt_max / 10.0 # in time units + +print(f'\ndt_max = {dt_max} {dt_unit}') +print(f'Current dt = {dt} {dt_unit}\n') + +if(dt > dt_max): + print("dt is TOO BIG!") + raise Exception + +sim.write_param() +sim.save() +print(f'\nsim.GU after save() and write_param() = {sim.GU}') +# sim.run() + +# Edit param.in for ascii only keywords + +param = pd.read_csv(simdir + '/param.in', sep = '\t') + +# make QMIN = -1.0 +param.loc[9][0] = param.loc[9][0][0:-17] + '-1.0' + +# make QMIN_RANGE start at -1.0 +param.loc[23][0] = param.loc[23][0][0:-34] + '-1.0' + param.loc[23][0][-17:] + +# export new param.in +param.to_csv(simdir + '/param.in', sep = '\t', index = False) + +# Make initial plots + +fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) + +plt.scatter(np.linalg.norm(sim.data.isel(time = 0)['rh'], axis = 1), np.linalg.norm(sim.data.isel(time = 0)['vh'], axis = 1)) +plt.xlabel('rh') +plt.ylabel('vh') +# plot longest axis +cb_ax_long = rmin +ymin = np.min(random_vel_mag) +ymax = v_escape + 2 #np.max(random_vel_mag) +plt.ylim([0, ymax]) +plt.xlim([0, np.max(random_pos_mag) + 2]) +plt.plot([cb_ax_long, cb_ax_long], [0, ymax], '-', color = 'orange') +plt.text(cb_ax_long + 0.1, ymax / 5, s = r'Longest CB Axis', color = 'orange', rotation = 'vertical') +plt.plot([-7, 7], [v_escape, v_escape], '-', color = 'black') +plt.text(1, v_escape + 0.5, s = 'Escape Velocity', color = 'black') + +plt.savefig(simdir + '/r_vs_v_initial.png') + +plt.clf() +fig = plt.figure(dpi = 300) +ax = fig.add_subplot(projection = '3d') +ax.scatter(random_pos_vec[:, 0], random_pos_vec[:, 1], random_pos_vec[:, 2], marker = 'o') +ax.set_xlabel('x') +ax.set_ylabel('y') +ax.set_zlabel('z') +ax.set_zlim([-5, 5]) +ax.set_xlim([-5, 5]) +ax.set_ylim([-5, 5]) +plt.savefig(simdir + '/pos_vector.png') + +ax.view_init(elev = 0, azim = 0) +plt.savefig(simdir + '/pos_vector_eq.png') + +ax.view_init(elev = 90, azim = 0) +plt.savefig(simdir + '/pos_vector_top.png') + + +# Extra code + +# random_2pi = 360 * np.random.rand(n_bodies) # 360 degrees +# random_pi = 180 * np.random.rand(n_bodies) # 180 degrees +# random_a = (rng.random(n_bodies) * (4 - 1.65) + 1.65) # randomize the semi-major axis between 1.65 and 4 (Haumea Radii) +# # Haumea's longest axis = 1.63 * R_Haumea (1161 km = 1.63 * 711.9097 km) +# random_e = rng.random(n_bodies) * 0.8 # randomize eccentricity between 0 and 0.8 +# random_i = np.random.rand(n_bodies) * (30 - (-30)) + (-30) # between (-30, 30) (degrees) (equatorial zone) +# random_capom = random_2pi +# random_omega = np.roll(random_2pi, array_shift) +# array_shift = np.random.randint(0, n_bodies) # compute another random shift +# random_capm = np.roll(random_2pi, array_shift) + + + +# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) + +# plt.scatter(sim.data['a'], sim.data['e']) +# plt.xlabel('a') +# plt.ylabel('e') +# plt.savefig(simdir + '/a_vs_e_initial.png') + +# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) + +# plt.scatter(sim.data['a'], sim.data['inc']) +# plt.xlabel('a') +# plt.ylabel('inc') +# plt.savefig(simdir + '/a_vs_i_initial.png') + +# print(f'sim.MU2KG = {sim.MU2KG}') +# print(f'sim.param["MU2KG"] = {sim.param["MU2KG"]}') +# print(f'sim.MU_name = {sim.MU_name}') +# sim.add_solar_system_body(["Sun", "Mercury", "Venus", "Earth", "Mars"]) +# random_radius = random_radius / sim.DU2M +# random_mass = random_mass / sim.MU2KG +# sim.add_body(name = 'Centaur', id = 0, mass = mass / mass, rot = rot, radius = radius / radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, J2 = J2, J4 = J4) +# sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius)#, rot = random_rot) + +# sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e5, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", TU = dt_unit, rmin = rmin, MU2KG = mass, DU2M = radius, init_cond_format = 'XV',)# MU_name = 'M_Haumea', DU_name = 'R_Haumea') + +# # unit conversion factors +# S2DAY = 1 / (60.0 * 60 * 24) +# S2YR = S2DAY / 365.25 +# KG2MSUN = 1 / 1.98847e30 +# M2AU = 1 / 1.496e11 + +# x = random_vel_mag * np.sin(random_theta) * np.cos(random_phi) +# y = random_vel_mag * np.sin(random_theta) * np.sin(random_phi) +# z = random_vel_mag * np.cos(random_theta) * np.sign(z_sign) + +# random_vel_mag = np.sqrt(2 * mass * sim.GU / radius) * (rng.random(n_bodies) * (0.4 - 0.0) + 0.0) # randomize the velocity by 0.0 - 0.4 times the escape velocity diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 2b87b7264..0edbd2fc2 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -9,6 +9,31 @@ submodule (swiftest) s_swiftest_obl contains + + module subroutine swiftest_obl_rot_rotate(self, nbody_system) + !! author: Kaustub P. Anand + !! + !! Rotate the coordiante frame to make the rotation axis along the z axis for correct spin calculation + !! + + implicit none + ! Arguments + class(swiftest_body), intent(inout) :: self !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + ! Internals + real(DP) :: theta ! angle to rotate it through + real(DP), dimension(NDIM) :: u ! unit vector about which we rotate + + if (self%nbody == 0) return + + associate(n => self%nbody, cb => nbody_system%cb) + if (cb%rot(0) == 0 .and. cb%rot(1) == 0) + return ! rotation axis is about the z-axis + end associate + + return + end subroutine swiftest_obl_rot_rotate + module subroutine swiftest_obl_acc_body(self, nbody_system) !! author: David A. Minton !! From 42142aebcf3286d3be17a2a6f93e1b45ebaad27a Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 19 Apr 2023 16:39:39 -0400 Subject: [PATCH 002/324] updated rotation algorithm; testing and matrix multiplication left --- src/swiftest/swiftest_obl.f90 | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 0edbd2fc2..87708e59a 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -23,12 +23,41 @@ module subroutine swiftest_obl_rot_rotate(self, nbody_system) ! Internals real(DP) :: theta ! angle to rotate it through real(DP), dimension(NDIM) :: u ! unit vector about which we rotate + real(DP), dimension(NDIM, NDIM) :: rot_matrix ! rotation matrix + + !! WHAT/WHERE is NDIM? if (self%nbody == 0) return associate(n => self%nbody, cb => nbody_system%cb) - if (cb%rot(0) == 0 .and. cb%rot(1) == 0) + if (cb%rot(0) == 0 .and. cb%rot(1) == 0) then return ! rotation axis is about the z-axis + end if + + cb%rot_initial = cb%rot + rot_mag = sqrt(dot_product(cb%rot, cb%rot)) + u = cross_product(cb%rot, [0, 0, 1]) / rot_mag !! WRITE cross-product + theta = acos(dot_product(cb%rot, [0, 0, 1]) / rot_mag) + + rot_matrix = zeros(NDIM, NDIM) + S_matrix = [[0, -u[3], u[2]], [u[3], 0, -u[1]], [-u[2], u[1], 0]] ! assume NDIM = 3 + ! CHECK for a general formula for the skew-symmetric matrix + + do (i = 1, NDIM) + do (j = 1, NDIM) + if (i == j) then + rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) + continue + end if + + rot_matrix(i, j) = rot_matrix(i, j) + u[i] * u[j] * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) + + end do + end do + + do concurrent(i = 1:n, self%lmask(i)) !! WHAT is lmask !! DOES this include the CB? + self%rh(: ,i) = rot_matrix * self%rh(:, i) + end do end associate return From 6f7d832a34ce297f2eb79afaa4e8717fb87b9609 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Thu, 20 Apr 2023 15:13:13 -0400 Subject: [PATCH 003/324] written rotation matrix algorithm; cross-product and testing left --- src/swiftest/swiftest_module.f90 | 10 ++++- src/swiftest/swiftest_obl.f90 | 66 ++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 4ac6cb3c3..c60fdc675 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -185,7 +185,7 @@ module swiftest real(DP) :: radius = 0.0_DP !! Central body radius (units DU) real(DP) :: density = 1.0_DP !! Central body mass density - calculated internally (units MU / DU**3) real(DP) :: j2rp2 = 0.0_DP !! J2*R^2 term for central body - real(DP) :: j4rp4 = 0.0_DP !! J4*R^2 term for central body + real(DP) :: j4rp4 = 0.0_DP !! J4*R^4 term for central body real(DP), dimension(NDIM) :: aobl = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: atide = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: aoblbeg = 0.0_DP !! Barycentric acceleration due to central body oblatenes at beginning of step @@ -966,6 +966,14 @@ pure module subroutine swiftest_kick_getacch_int_one_tp(rji2, xr, yr, zr, Gmpl, real(DP), intent(inout) :: ax, ay, az !! Acceleration vector components of test particle end subroutine swiftest_kick_getacch_int_one_tp + module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_matrix_inv) + implicit none + class(swiftest_body), intent(inout) :: self !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix ! rotation matrix and its inverse + real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix_inv ! inverse of the rotation matrix + end subroutine swiftest_obl_rot_matrix + module subroutine swiftest_obl_acc_body(self, nbody_system) implicit none class(swiftest_body), intent(inout) :: self !! Swiftest body object diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 87708e59a..5bf684f1f 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -10,37 +10,70 @@ submodule (swiftest) s_swiftest_obl contains - module subroutine swiftest_obl_rot_rotate(self, nbody_system) + pure function matinv3(A) result(B) + !! Performs a direct calculation of the inverse of a 3×3 matrix. + !! from https://fortranwiki.org/fortran/show/Matrix+inversion + !! + + complex(wp), intent(in) :: A(3,3) !! Matrix + complex(wp) :: B(3,3) !! Inverse matrix + complex(wp) :: detinv + + ! Calculate the inverse determinant of the matrix + detinv = 1/(A(1,1)*A(2,2)*A(3,3) - A(1,1)*A(2,3)*A(3,2)& + - A(1,2)*A(2,1)*A(3,3) + A(1,2)*A(2,3)*A(3,1)& + + A(1,3)*A(2,1)*A(3,2) - A(1,3)*A(2,2)*A(3,1)) + + ! Calculate the inverse of the matrix + B(1,1) = +detinv * (A(2,2)*A(3,3) - A(2,3)*A(3,2)) + B(2,1) = -detinv * (A(2,1)*A(3,3) - A(2,3)*A(3,1)) + B(3,1) = +detinv * (A(2,1)*A(3,2) - A(2,2)*A(3,1)) + B(1,2) = -detinv * (A(1,2)*A(3,3) - A(1,3)*A(3,2)) + B(2,2) = +detinv * (A(1,1)*A(3,3) - A(1,3)*A(3,1)) + B(3,2) = -detinv * (A(1,1)*A(3,2) - A(1,2)*A(3,1)) + B(1,3) = +detinv * (A(1,2)*A(2,3) - A(1,3)*A(2,2)) + B(2,3) = -detinv * (A(1,1)*A(2,3) - A(1,3)*A(2,1)) + B(3,3) = +detinv * (A(1,1)*A(2,2) - A(1,2)*A(2,1)) + end function + + module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_matrix_inv) !! author: Kaustub P. Anand !! - !! Rotate the coordiante frame to make the rotation axis along the z axis for correct spin calculation + !! Generate a rotation matrix and its inverse to rotate the coordinate frame to align the rotation axis along the z axis for correct spin calculation !! implicit none ! Arguments class(swiftest_body), intent(inout) :: self !! Swiftest body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix ! rotation matrix and its inverse + real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix_inv ! inverse of the rotation matrix + ! Internals real(DP) :: theta ! angle to rotate it through real(DP), dimension(NDIM) :: u ! unit vector about which we rotate - real(DP), dimension(NDIM, NDIM) :: rot_matrix ! rotation matrix - !! WHAT/WHERE is NDIM? + rot_matrix(:, :) = 0.0_DP + rot_matrix_inv(:, :) = 0.0_DP if (self%nbody == 0) return associate(n => self%nbody, cb => nbody_system%cb) if (cb%rot(0) == 0 .and. cb%rot(1) == 0) then + do (i = 1, NDIM) + rot_matrix(i, i) = 1.0 + rot_matrix_inv(i, i) = 1.0 + end do + return ! rotation axis is about the z-axis end if - cb%rot_initial = cb%rot rot_mag = sqrt(dot_product(cb%rot, cb%rot)) u = cross_product(cb%rot, [0, 0, 1]) / rot_mag !! WRITE cross-product theta = acos(dot_product(cb%rot, [0, 0, 1]) / rot_mag) - rot_matrix = zeros(NDIM, NDIM) - S_matrix = [[0, -u[3], u[2]], [u[3], 0, -u[1]], [-u[2], u[1], 0]] ! assume NDIM = 3 + S_matrix = [[0, -u[3], u[2]], [u[3], 0, -u[1]], [-u[2], u[1], 0]] ! skew-symmetric matrix + ! assuming NDIM = 3 ! CHECK for a general formula for the skew-symmetric matrix do (i = 1, NDIM) @@ -55,9 +88,8 @@ module subroutine swiftest_obl_rot_rotate(self, nbody_system) end do end do - do concurrent(i = 1:n, self%lmask(i)) !! WHAT is lmask !! DOES this include the CB? - self%rh(: ,i) = rot_matrix * self%rh(:, i) - end do + rot_matrix_inv = matinv3(rot_matrix) + end associate return @@ -78,13 +110,21 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) ! Internals integer(I4B) :: i real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac1, fac2 + real(DP), dimension(NDIM) :: rh_transformed ! rotated position vector + real(DP), dimension(NDIM, NDIM) :: rot_matrix, rot_matrix_inv ! rotation matrix and its inverse if (self%nbody == 0) return + ! generate the rotation matrix + call swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_matrix_inv) + associate(n => self%nbody, cb => nbody_system%cb) self%aobl(:,:) = 0.0_DP do concurrent(i = 1:n, self%lmask(i)) - r2 = dot_product(self%rh(:, i), self%rh(:, i)) + ! rotate the position vectors + rh_transformed = MATMUL(self%rot_matrix, self%rh(:, i)) ! 3x3 matrix * 3:1 vector + + r2 = dot_product(rh_transformed, rh_transformed) irh = 1.0_DP / sqrt(r2) rinv2 = irh**2 t0 = -cb%Gmass * rinv2 * rinv2 * irh @@ -95,6 +135,10 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) self%aobl(:, i) = fac1 * self%rh(:, i) self%aobl(3, i) = fac2 * self%rh(3, i) + self%aobl(3, i) + + ! rotate the acceleration and position vectors back to the original coordinate frame + self%aobl(:, i) = MATMUL(self%rot_matrix_inv, self%aobl(:, i)) + end do end associate return From efa53b203f2713ab3a1b990b26c19f1a00719080 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Fri, 21 Apr 2023 13:57:56 -0400 Subject: [PATCH 004/324] Completed rotation for J2 and J4 terms; testing needed --- setup_sim_ring_capture.py | 2 +- src/swiftest/swiftest_obl.f90 | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/setup_sim_ring_capture.py b/setup_sim_ring_capture.py index 994b1a368..3fc2da2d1 100644 --- a/setup_sim_ring_capture.py +++ b/setup_sim_ring_capture.py @@ -96,7 +96,7 @@ print(f'Total ring mass = {ring_mass_tot} M_Haumea') print(f'sim.GU = {sim.GU}') -sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2, J4 = J4) +sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2 * radius**2, J4 = J4 * radius**4) sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), mass = random_mass, radius = random_radius, rh = random_pos_vec, vh = random_vel_vec)#, rot = random_rot) # check that dt < dt_max diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 5bf684f1f..2fdef4627 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -65,25 +65,26 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma rot_matrix_inv(i, i) = 1.0 end do - return ! rotation axis is about the z-axis + return ! rotation axis is about the z-axis, no need to change end if rot_mag = sqrt(dot_product(cb%rot, cb%rot)) - u = cross_product(cb%rot, [0, 0, 1]) / rot_mag !! WRITE cross-product - theta = acos(dot_product(cb%rot, [0, 0, 1]) / rot_mag) + ! u = cross_product(cb%rot, (0, 0, 1)) / rot_mag !! WRITE cross-product + u(:) = cb%rot(:) .cross. (0, 0, 1) / rot_mag + theta = acos(dot_product(cb%rot(:), (0, 0, 1)) / rot_mag) - S_matrix = [[0, -u[3], u[2]], [u[3], 0, -u[1]], [-u[2], u[1], 0]] ! skew-symmetric matrix + S_matrix = ((0, -u(3), u(2)), (u(3), 0, -u(1)), (-u(2), u(1), 0)) ! skew-symmetric matrix ! assuming NDIM = 3 ! CHECK for a general formula for the skew-symmetric matrix do (i = 1, NDIM) do (j = 1, NDIM) if (i == j) then - rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) + rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) ! identity matrix continue end if - rot_matrix(i, j) = rot_matrix(i, j) + u[i] * u[j] * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) + rot_matrix(i, j) = rot_matrix(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) ! Skew-symmetric matrix + Tensor product matrix end do end do From 184cf4f53965abb451ed8ea65db3bef988dae841 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 24 Apr 2023 11:52:18 -0400 Subject: [PATCH 005/324] Fixed a typo --- src/swiftest/swiftest_obl.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 2fdef4627..e95df9bf2 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -130,12 +130,12 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) rinv2 = irh**2 t0 = -cb%Gmass * rinv2 * rinv2 * irh t1 = 1.5_DP * cb%j2rp2 - t2 = self%rh(3, i) * self%rh(3, i) * rinv2 + t2 = rh_transformed(3) * rh_transformed(3) * rinv2 t3 = 1.875_DP * cb%j4rp4 * rinv2 fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) - self%aobl(:, i) = fac1 * self%rh(:, i) - self%aobl(3, i) = fac2 * self%rh(3, i) + self%aobl(3, i) + self%aobl(:, i) = fac1 * rh_transformed(:) + self%aobl(3, i) = fac2 * rh_transformed(3) + self%aobl(3, i) ! rotate the acceleration and position vectors back to the original coordinate frame self%aobl(:, i) = MATMUL(self%rot_matrix_inv, self%aobl(:, i)) From fc185f7b82dfdc19ce0d6ccbcf7ad528b073a0be Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 24 Apr 2023 12:08:38 -0400 Subject: [PATCH 006/324] Reformatted some calculations --- src/swiftest/swiftest_obl.f90 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index e95df9bf2..2d6e19f7d 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -68,10 +68,9 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma return ! rotation axis is about the z-axis, no need to change end if - rot_mag = sqrt(dot_product(cb%rot, cb%rot)) - ! u = cross_product(cb%rot, (0, 0, 1)) / rot_mag !! WRITE cross-product - u(:) = cb%rot(:) .cross. (0, 0, 1) / rot_mag - theta = acos(dot_product(cb%rot(:), (0, 0, 1)) / rot_mag) + unit_rot = .unit. cb%rot(:) + u(:) = unit_rot .cross. (0, 0, 1) + theta = acos(dot_product(unit_rot, (0, 0, 1))) S_matrix = ((0, -u(3), u(2)), (u(3), 0, -u(1)), (-u(2), u(1), 0)) ! skew-symmetric matrix ! assuming NDIM = 3 @@ -94,7 +93,7 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma end associate return - end subroutine swiftest_obl_rot_rotate + end subroutine swiftest_obl_rot_matrix module subroutine swiftest_obl_acc_body(self, nbody_system) !! author: David A. Minton From 9ef98152d32198b1204b84221069884e1c263177 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 24 Apr 2023 12:26:12 -0400 Subject: [PATCH 007/324] rearranged unit vector calculations --- src/swiftest/swiftest_obl.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 2d6e19f7d..117f4380b 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -12,6 +12,7 @@ pure function matinv3(A) result(B) !! Performs a direct calculation of the inverse of a 3×3 matrix. + !! !! from https://fortranwiki.org/fortran/show/Matrix+inversion !! @@ -68,9 +69,8 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma return ! rotation axis is about the z-axis, no need to change end if - unit_rot = .unit. cb%rot(:) - u(:) = unit_rot .cross. (0, 0, 1) - theta = acos(dot_product(unit_rot, (0, 0, 1))) + u(:) = .unit. (cb%rot(:) .cross. (0, 0, 1)) + theta = acos(dot_product((.unit. cb%rot(:)), (0, 0, 1))) S_matrix = ((0, -u(3), u(2)), (u(3), 0, -u(1)), (-u(2), u(1), 0)) ! skew-symmetric matrix ! assuming NDIM = 3 From 6448e284fe72bfc9accd681caf88311f705a80ac Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 25 Apr 2023 11:21:01 -0400 Subject: [PATCH 008/324] Reordered MATMUL terms --- setup_sim_ring_capture.py | 28 ++++++++++++++++++++++------ src/swiftest/swiftest_obl.f90 | 9 ++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/setup_sim_ring_capture.py b/setup_sim_ring_capture.py index 3fc2da2d1..e82fb9f5f 100644 --- a/setup_sim_ring_capture.py +++ b/setup_sim_ring_capture.py @@ -3,20 +3,21 @@ import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import axes3d import pandas as pd +from astropy import constants as const seed = None rng = np.random.default_rng(seed=seed) -n_bodies = int(2e1) # number of planet bodies +n_bodies = int(1e4) # number of planet bodies array_shift = np.random.randint(0, n_bodies) tstop = 50 # rotation periods -dt = 1.0e-5 +dt = 1.0e-4 dt_unit = 'Haumea_rot_period' # dt_unit = 'd' dt_max = 0 G = 6.6743e-11 # SI Units scratch_dr = '/scratch/bell/anand43/swiftest_runs/' body_dr = 'Haumea/' -simdir = 'test' # '2e3_part_radial' +simdir = 'moons' # '2e3_part_radial' simdir = scratch_dr + body_dr + simdir # initial central body parameters @@ -38,6 +39,20 @@ J4 = -0.216 print(f'R_min = {rmin}') +# moons parameters +# values taken from JPL Horizons + +moon_name = ['Hi\'iaka', 'Namaka'] +moon_id = np.arange(10, len(moon_name) + 10, step = 1) +moon_mass = np.array([1.151e9, 0.036e9]) / const.G / cb_mass +moon_radius = np.array([160e3, 85e3]) / cb_radius +moon_rh = np.array([[-2.3446616e7, -3.6088243e7, -2.9864834e7], [-8.6355596e6, 1.5824178e7, 2.4140061e7]]) / cb_radius +moon_vh = np.array([[-5.6613699e1, 3.5390515e0, 3.8830064e1], [6.6949687e1, 5.157315e1, -1.0614025e1]]) / cb_radius * T_rotation +moon_T_rotation = np.array([9.8, np.inf]) * 60 * 60 # h to seconds +moon_rot = [] +for i in range(len(moon_T_rotation)): + moon_rot.append([0, 0, 2 * np.pi / moon_T_rotation[i]]) # rad/s + # set up swiftest simulation sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e4, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", rmin = rmin, rmax = 50 * rmin, MU2KG = cb_mass, DU2M = cb_radius, TU2S = T_rotation, init_cond_format = 'XV') # TU = dt_unit, MU_name = 'M_Haumea', DU_name = 'R_Haumea' @@ -53,7 +68,7 @@ z_sign = rng.random(n_bodies) - 0.5 # randomize the sign of the z-component # set up the position vectors -random_pos_mag = (rng.random(n_bodies) * (2 - 1.65) + 1.65) # randomize the distance/position vector(s) between 1.65 and 3 (R_Haumea) +random_pos_mag = (rng.random(n_bodies) * (3 - 1.65) + 1.65) # randomize the distance/position vector(s) between 1.65 and 3 (R_Haumea) random_phi = np.deg2rad((rng.random(n_bodies)) * 60.0) # cone of spilled regolith random_theta = np.deg2rad((rng.random(n_bodies)) * (120.0 - 60) + 60) # equatorial zone x = random_pos_mag * np.sin(random_theta) * np.cos(random_phi) @@ -66,7 +81,7 @@ # random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (1.15 - 0.85) + 0.85) # randomize the velocity by 0.9 - 1.1 times the keplerian velocity v_escape = np.sqrt(2 * sim.GU * mass / radius) -alpha = rng.random(n_bodies) * (0.90 - 0.80) + 0.80 # numerical scaling for initial velocity +alpha = rng.random(n_bodies) * (0.90 - 0.75) + 0.75 # numerical scaling for initial velocity random_vel_mag = np.sqrt(alpha * v_escape**2 + 2 * sim.GU * mass * (1 / random_pos_mag - 1 / radius)) # scale the velocity with distance x = x * random_vel_mag / random_pos_mag @@ -75,7 +90,7 @@ # rotate the velocity vectors (degrees) # 85 - 95 degrees to represent orbiting particles for tangential motion -rot_angle = np.deg2rad(rng.random(n_bodies) * (5 - (-5)) + (-5)) # rotate by <> degrees randomly +rot_angle = np.deg2rad(rng.random(n_bodies) * (10 - (-10)) + (-10)) # rotate by <> degrees randomly x_tmp = x y_tmp = y @@ -97,6 +112,7 @@ print(f'sim.GU = {sim.GU}') sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2 * radius**2, J4 = J4 * radius**4) +sim.add_body(name = moon_name, id = moon_id, mass = moon_mass, rot = moon_rot, radius = moon_radius, rh = moon_rh, vh = moon_vh) sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), mass = random_mass, radius = random_radius, rh = random_pos_vec, vh = random_vel_vec)#, rot = random_rot) # check that dt < dt_max diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 117f4380b..6e077bb88 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -47,8 +47,8 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma ! Arguments class(swiftest_body), intent(inout) :: self !! Swiftest body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix ! rotation matrix and its inverse - real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix_inv ! inverse of the rotation matrix + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix ! rotation matrix and its inverse + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv ! inverse of the rotation matrix ! Internals real(DP) :: theta ! angle to rotate it through @@ -122,8 +122,7 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) self%aobl(:,:) = 0.0_DP do concurrent(i = 1:n, self%lmask(i)) ! rotate the position vectors - rh_transformed = MATMUL(self%rot_matrix, self%rh(:, i)) ! 3x3 matrix * 3:1 vector - + rh_transformed = MATMUL(self%rh(:, i), self%rot_matrix) ! 1x3 vector * 3x3 matrix r2 = dot_product(rh_transformed, rh_transformed) irh = 1.0_DP / sqrt(r2) rinv2 = irh**2 @@ -137,7 +136,7 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) self%aobl(3, i) = fac2 * rh_transformed(3) + self%aobl(3, i) ! rotate the acceleration and position vectors back to the original coordinate frame - self%aobl(:, i) = MATMUL(self%rot_matrix_inv, self%aobl(:, i)) + self%aobl(:, i) = MATMUL(self%aobl(:, i), self%rot_matrix_inv) end do end associate From 3a5fb6a8bd34627cfa55590edc798ce8c749d490 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 25 Apr 2023 15:40:07 -0400 Subject: [PATCH 009/324] Removed parantheses in do loop --- src/swiftest/swiftest_obl.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 6e077bb88..ae2bda056 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -76,8 +76,8 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma ! assuming NDIM = 3 ! CHECK for a general formula for the skew-symmetric matrix - do (i = 1, NDIM) - do (j = 1, NDIM) + do i = 1, NDIM + do j = 1, NDIM if (i == j) then rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) ! identity matrix continue From 9d5306c01103ffe042c18d653ba9d51a3dcb9f30 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 1 May 2023 16:22:21 -0400 Subject: [PATCH 010/324] Found a typo in simulation_class.py --- python/swiftest/swiftest/simulation_class.py | 2 +- setup_sim.py | 76 ++++++++++++++++---- setup_sim_ring_capture.py | 11 +-- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/python/swiftest/swiftest/simulation_class.py b/python/swiftest/swiftest/simulation_class.py index 991758441..8a0f27bdf 100644 --- a/python/swiftest/swiftest/simulation_class.py +++ b/python/swiftest/swiftest/simulation_class.py @@ -2414,7 +2414,7 @@ def add_body(self, Hill's radius values if these are massive bodies rot: (3) or (n,3) array-like of float, optional Rotation rate vectors if these are massive bodies with rotation enabled. - Ip: (3) or (n,3) array-like of flaot, optional + Ip: (3) or (n,3) array-like of float, optional Principal axes moments of inertia vectors if these are massive bodies with rotation enabled. Returns diff --git a/setup_sim.py b/setup_sim.py index 53568e093..f9b297e30 100644 --- a/setup_sim.py +++ b/setup_sim.py @@ -1,13 +1,20 @@ import numpy as np import swiftest +from astropy import constants as const +from astroquery.jplhorizons import Horizons +import datetime seed = None rng = np.random.default_rng(seed=seed) -tstop = 2e6 # years -dt = 8 / 365.25 # 8 DAYS +tstop = 10 * 365.25 # 1e3 * 365.25 # years +dt = 90.0 / 60.0 / 24 / 10 # 1/10 * 90 min to days dt_unit = 'Years' dt_max = 0 -G = 6.6743e-11 # SI Units + +scratch_dr = '/scratch/bell/anand43/swiftest_runs/' +body_dr = 'tests/' +simdir = 'test' # '2e3_part_radial' +simdir = scratch_dr + body_dr + simdir # unit conversion factors S2DAY = 1 / (60.0 * 60 * 24) @@ -23,18 +30,49 @@ #initial ring particle orbital parameters -n_bodies = 500 # number of bodies +n_bodies = 1 # number of bodies id_start = 100 # starting ID for bodies random_2pi = 360 * np.random.rand(n_bodies) # 360 degrees random_pi = 180 * np.random.rand(n_bodies) # 180 degrees -random_a = (rng.random(n_bodies) * (3.0 - 0.5) + 0.5) # randomize the semi-major axis between 0.5 and 3.0 (AU)) -random_e = rng.random(n_bodies) # randomize eccentricity between 0 and 1 -random_i = random_pi / 2 + (np.pi/2 - np.pi/3) # between (-pi/3, pi/3) + pi/2 (equatorial) -random_capom = random_2pi -random_omega = random_2pi -random_capm = random_2pi -random_radius = (rng.random(n_bodies) * (10.0 - 1.0) + 1.0) * M2AU # randomize the radii of the ring particles between 1 and 10 m -random_mass = (np.power(random_radius, 3) * 4.0 * np.pi / 3.0 * density) * KG2MSUN # randomize the mass +# ISS parameters on 4/28/23 +# random_a = 6.7999524e3 # (rng.random(n_bodies) * (3.0 - 0.5) + 0.5) # randomize the semi-major axis between 0.5 and 3.0 (AU)) +# random_e = 4.3357182e-4 # rng.random(n_bodies) # randomize eccentricity between 0 and 1 +# random_i = 6.7813805e1 # random_pi / 2 + (np.pi/2 - np.pi/3) # between (-pi/3, pi/3) + pi/2 (equatorial) +# random_capom = 2.2163223e2 # random_2pi +# random_omega = 4.4320487e1 # random_2pi +# random_capm = 3.2698275e2 # random_2pi +# random_radius = 100e-3 # km # (rng.random(n_bodies) * (10.0 - 1.0) + 1.0) * M2AU # randomize the radii of the ring particles between 1 and 10 m +# random_mass = 419725 # kg # (np.power(random_radius, 3) * 4.0 * np.pi / 3.0 * density) * KG2MSUN # randomize the mass + +# use JPL Horizons for ISS details +# date = '2023-04-27' +ephemerides_start_date = '2023-04-27' +tstart = datetime.date.fromisoformat(ephemerides_start_date) +tstep = datetime.timedelta(days=1) +tend = tstart + tstep +ephemerides_end_date = tend.isoformat() +ephemerides_step = '1d' +iss_obj = Horizons(id = '-125544', location = '399', epochs={'start': ephemerides_start_date, 'stop': ephemerides_end_date, + 'step': ephemerides_step}) # 399 = Earth geocenter; -125544 = ISS + +iss_el = iss_obj.elements() +iss_el['a'].convert_unit_to('km') +random_a = iss_el['a'][0] +random_e = iss_el['e'][0] +random_i = iss_el['incl'][0] +random_capom = iss_el['Omega'][0] +random_omega = iss_el['w'][0] +random_capm = iss_el['M'][0] +random_radius = 100e-3 # km +random_mass = 419725 # km + +earth_radius = 6371.01 # km +earth_mass = 5.97219e24 # kg +earth_J2 = 1083e-6 # from Murray and Dermott txt. bk. +earth_J4 = -2e-6 # from Murray and Dermott txt. bk. +earth_tilt = np.deg2rad(23.4392811) +earth_rot = np.array([0.0, np.sin(earth_tilt), np.cos(earth_tilt)]) * 2 * np.pi / (24 * 60 * 60.0) +earth_rot = [earth_rot] # # check that dt < dt_max @@ -51,12 +89,20 @@ # set up swiftest simulation -sim = swiftest.Simulation(simdir = "kaustub_test", integrator = "symba", tstop = tstop, dt = dt, istep_out = 500, dump_cadence = 1000, rotation = False, collision_model = "FRAGGLE")#, MU = 'kg', DU = 'm', TU = 'd', rmin = radius + 1e4) -sim.add_solar_system_body(["Sun", "Mercury", "Venus", "Earth", "Mars"]) +sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e7, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", MU = 'kg', DU2M = 1e3, TU = 'd', rmin = earth_radius) +# sim.add_solar_system_body(["Earth"], date = ephemerides_start_date) +# Manually add Earth as a CB because no J2 or J4 term is added otherwise +sim.add_body(name = "Earth", id = 1, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, mass = earth_mass, radius = earth_radius, J2 = earth_J2 * earth_radius**2, J4 = earth_J4 * earth_radius**4, rot = earth_rot) + # sim.add_body(name = 'Centaur', id = 1, mass = density * volume, radius = radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0) -sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius) +sim.add_body(name = "ISS", id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius) # sim.get_parameter() # sim.set_parameter() sim.write_param() sim.save() # sim.run() + +print(f'total number of steps ={int(tstop / dt)}') +d = sim.data.isel(name = 0) +J2 = d['J2'].values +print(f'J2 for central body = {J2}') diff --git a/setup_sim_ring_capture.py b/setup_sim_ring_capture.py index e82fb9f5f..970d44913 100644 --- a/setup_sim_ring_capture.py +++ b/setup_sim_ring_capture.py @@ -9,8 +9,8 @@ rng = np.random.default_rng(seed=seed) n_bodies = int(1e4) # number of planet bodies array_shift = np.random.randint(0, n_bodies) -tstop = 50 # rotation periods -dt = 1.0e-4 +tstop = 10 # rotation periods +dt = 1.0e-5 dt_unit = 'Haumea_rot_period' # dt_unit = 'd' dt_max = 0 @@ -69,7 +69,7 @@ # set up the position vectors random_pos_mag = (rng.random(n_bodies) * (3 - 1.65) + 1.65) # randomize the distance/position vector(s) between 1.65 and 3 (R_Haumea) -random_phi = np.deg2rad((rng.random(n_bodies)) * 60.0) # cone of spilled regolith +random_phi = np.deg2rad((rng.random(n_bodies)) * (60.0) + 90.0) # cone of spilled regolith random_theta = np.deg2rad((rng.random(n_bodies)) * (120.0 - 60) + 60) # equatorial zone x = random_pos_mag * np.sin(random_theta) * np.cos(random_phi) y = random_pos_mag * np.sin(random_theta) * np.sin(random_phi) @@ -81,7 +81,7 @@ # random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (1.15 - 0.85) + 0.85) # randomize the velocity by 0.9 - 1.1 times the keplerian velocity v_escape = np.sqrt(2 * sim.GU * mass / radius) -alpha = rng.random(n_bodies) * (0.90 - 0.75) + 0.75 # numerical scaling for initial velocity +alpha = rng.random(n_bodies) * (0.95 - 0.8) + 0.8 # numerical scaling for initial velocity random_vel_mag = np.sqrt(alpha * v_escape**2 + 2 * sim.GU * mass * (1 / random_pos_mag - 1 / radius)) # scale the velocity with distance x = x * random_vel_mag / random_pos_mag @@ -90,7 +90,8 @@ # rotate the velocity vectors (degrees) # 85 - 95 degrees to represent orbiting particles for tangential motion -rot_angle = np.deg2rad(rng.random(n_bodies) * (10 - (-10)) + (-10)) # rotate by <> degrees randomly +angle = 20 +rot_angle = np.deg2rad(rng.random(n_bodies) * (angle - (-1.0 * angle)) + (-1.0 * angle)) # rotate by <> degrees randomly x_tmp = x y_tmp = y From fb2471c343200eab772463c0c3c0942741feed02 Mon Sep 17 00:00:00 2001 From: Kaustub Anand Date: Tue, 2 May 2023 15:13:47 -0400 Subject: [PATCH 011/324] Changed 'J2' and 'J4' keys in python to 'j2rp2' and 'j4rp4' --- python/swiftest/swiftest/init_cond.py | 4 ++-- python/swiftest/swiftest/simulation_class.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/swiftest/swiftest/init_cond.py b/python/swiftest/swiftest/init_cond.py index 30fb46c6d..a4c47548c 100644 --- a/python/swiftest/swiftest/init_cond.py +++ b/python/swiftest/swiftest/init_cond.py @@ -277,8 +277,8 @@ def vec2xr(param: Dict, **kwargs: Any): space_coords = np.array(["x","y","z"]) vector_vars = ["rh","vh","Ip","rot"] - scalar_vars = ["name","a","e","inc","capom","omega","capm","Gmass","radius","rhill","J2","J4"] - time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","J2","J4"] + scalar_vars = ["name","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] + time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] # Check for valid keyword arguments kwargs = {k:kwargs[k] for k,v in kwargs.items() if v is not None} diff --git a/python/swiftest/swiftest/simulation_class.py b/python/swiftest/swiftest/simulation_class.py index 8a0f27bdf..b1c0c3b02 100644 --- a/python/swiftest/swiftest/simulation_class.py +++ b/python/swiftest/swiftest/simulation_class.py @@ -2203,9 +2203,9 @@ def add_solar_system_body(self, values = list(np.hsplit(np.array(body_list[0],dtype=np.dtype(object)),17)) else: values = list(np.squeeze(np.hsplit(np.array(body_list,np.dtype(object)),17))) - keys = ["id","name","a","e","inc","capom","omega","capm","rh","vh","Gmass","radius","rhill","Ip","rot","J2","J4"] + keys = ["id","name","a","e","inc","capom","omega","capm","rh","vh","Gmass","radius","rhill","Ip","rot","j2rp2","j4rp4"] kwargs = dict(zip(keys,values)) - scalar_floats = ["a","e","inc","capom","omega","capm","Gmass","radius","rhill","J2","J4"] + scalar_floats = ["a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] vector_floats = ["rh","vh","Ip","rot"] scalar_ints = ["id"] @@ -2531,7 +2531,7 @@ def input_to_array_3d(val,n=None): Gmass = self.GU * mass dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, - Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, J2=J2, J4=J4, time=time) + Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, time=time) dsnew = self._combine_and_fix_dsnew(dsnew) self.save(verbose=False) From 0400f7a8f9ea04d36805c0a2530a31a3a46a6a56 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 3 May 2023 17:04:54 -0400 Subject: [PATCH 012/324] Fixed errors with swiftest_obl --- setup_sim.py | 2 ++ src/swiftest/swiftest_module.f90 | 4 ++-- src/swiftest/swiftest_obl.f90 | 32 ++++++++++++++++++++++---------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/setup_sim.py b/setup_sim.py index f9b297e30..59f138a71 100644 --- a/setup_sim.py +++ b/setup_sim.py @@ -103,6 +103,8 @@ # sim.run() print(f'total number of steps ={int(tstop / dt)}') +J2 = sim.init_cond.isel(name = 0)['J2'].values +print(f'J2 in init_cond = {J2}') d = sim.data.isel(name = 0) J2 = d['J2'].values print(f'J2 for central body = {J2}') diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index c60fdc675..0f1baf98f 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -970,8 +970,8 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma implicit none class(swiftest_body), intent(inout) :: self !! Swiftest body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix ! rotation matrix and its inverse - real(DP), dimension(NDIM, NDIM), intent(out) :: rot_matrix_inv ! inverse of the rotation matrix + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix ! rotation matrix and its inverse + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv ! inverse of the rotation matrix end subroutine swiftest_obl_rot_matrix module subroutine swiftest_obl_acc_body(self, nbody_system) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index ae2bda056..4754ea8ee 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -8,6 +8,9 @@ !! If not, see: https://www.gnu.org/licenses. submodule (swiftest) s_swiftest_obl + use swiftest + use operators + contains pure function matinv3(A) result(B) @@ -16,9 +19,9 @@ pure function matinv3(A) result(B) !! from https://fortranwiki.org/fortran/show/Matrix+inversion !! - complex(wp), intent(in) :: A(3,3) !! Matrix - complex(wp) :: B(3,3) !! Inverse matrix - complex(wp) :: detinv + real(DP), intent(in) :: A(3,3) !! Matrix + real(DP) :: B(3,3) !! Inverse matrix + real(DP) :: detinv ! Calculate the inverse determinant of the matrix detinv = 1/(A(1,1)*A(2,2)*A(3,3) - A(1,1)*A(2,3)*A(3,2)& @@ -52,16 +55,21 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma ! Internals real(DP) :: theta ! angle to rotate it through - real(DP), dimension(NDIM) :: u ! unit vector about which we rotate + real(DP), dimension(3) :: u, z_hat ! unit vector about which we rotate and z_hat + real(DP), dimension(3, 3) :: S_matrix ! rotation matrices + integer :: i, j ! dummy variable + + ! Assumed that NDIM = 3 rot_matrix(:, :) = 0.0_DP rot_matrix_inv(:, :) = 0.0_DP + z_hat(:) = [0, 0, 1] if (self%nbody == 0) return associate(n => self%nbody, cb => nbody_system%cb) if (cb%rot(0) == 0 .and. cb%rot(1) == 0) then - do (i = 1, NDIM) + do i = 1, NDIM rot_matrix(i, i) = 1.0 rot_matrix_inv(i, i) = 1.0 end do @@ -69,10 +77,14 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma return ! rotation axis is about the z-axis, no need to change end if - u(:) = .unit. (cb%rot(:) .cross. (0, 0, 1)) - theta = acos(dot_product((.unit. cb%rot(:)), (0, 0, 1))) + u(:) = cb%rot(:) .cross. z_hat(:) + u(:) = .unit. u(:) + theta = acos(dot_product((.unit. cb%rot(:)), z_hat(:))) - S_matrix = ((0, -u(3), u(2)), (u(3), 0, -u(1)), (-u(2), u(1), 0)) ! skew-symmetric matrix + ! S_matrix(:, :) = [[0.0_DP, -u(3), u(2)], [u(3), 0.0_DP, -u(1)], [-u(2), u(1), 0.0_DP]] ! skew-symmetric matrix + S_matrix(1, :) = [0.0_DP, -u(3), u(2)] + S_matrix(2, :) = [u(3), 0.0_DP, -u(1)] + S_matrix(3, :) = [-u(2), u(1), 0.0_DP] ! assuming NDIM = 3 ! CHECK for a general formula for the skew-symmetric matrix @@ -122,7 +134,7 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) self%aobl(:,:) = 0.0_DP do concurrent(i = 1:n, self%lmask(i)) ! rotate the position vectors - rh_transformed = MATMUL(self%rh(:, i), self%rot_matrix) ! 1x3 vector * 3x3 matrix + rh_transformed = MATMUL(self%rh(:, i), rot_matrix) ! 1x3 vector * 3x3 matrix r2 = dot_product(rh_transformed, rh_transformed) irh = 1.0_DP / sqrt(r2) rinv2 = irh**2 @@ -136,7 +148,7 @@ module subroutine swiftest_obl_acc_body(self, nbody_system) self%aobl(3, i) = fac2 * rh_transformed(3) + self%aobl(3, i) ! rotate the acceleration and position vectors back to the original coordinate frame - self%aobl(:, i) = MATMUL(self%aobl(:, i), self%rot_matrix_inv) + self%aobl(:, i) = MATMUL(self%aobl(:, i), rot_matrix_inv) end do end associate From 120d23d619b7b5b7ca60600b7cdde49cdc93adec Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Thu, 4 May 2023 16:55:14 -0400 Subject: [PATCH 013/324] fixed some typos, edited 'np.str' to 'str' in simulation_class.py --- python/swiftest/swiftest/simulation_class.py | 2 +- setup_sim.py | 4 ++-- src/swiftest/swiftest_obl.f90 | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/swiftest/swiftest/simulation_class.py b/python/swiftest/swiftest/simulation_class.py index b1c0c3b02..a61d05a35 100644 --- a/python/swiftest/swiftest/simulation_class.py +++ b/python/swiftest/swiftest/simulation_class.py @@ -2431,7 +2431,7 @@ def input_to_array(val,t,n=None): elif t == "i": t = np.int64 elif t == "s": - t = np.str + t = str if val is None: return None, n diff --git a/setup_sim.py b/setup_sim.py index 59f138a71..38c92a3ed 100644 --- a/setup_sim.py +++ b/setup_sim.py @@ -103,8 +103,8 @@ # sim.run() print(f'total number of steps ={int(tstop / dt)}') -J2 = sim.init_cond.isel(name = 0)['J2'].values +J2 = sim.init_cond.isel(name = 0)['j2rp2'].values print(f'J2 in init_cond = {J2}') d = sim.data.isel(name = 0) -J2 = d['J2'].values +J2 = d['j2rp2'].values print(f'J2 for central body = {J2}') diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 4754ea8ee..f18815201 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -68,7 +68,7 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma if (self%nbody == 0) return associate(n => self%nbody, cb => nbody_system%cb) - if (cb%rot(0) == 0 .and. cb%rot(1) == 0) then + if (cb%rot(1) == 0 .and. cb%rot(2) == 0) then do i = 1, NDIM rot_matrix(i, i) = 1.0 rot_matrix_inv(i, i) = 1.0 From 386a082669d9be8f7e1df16e376b5eaaf1c6ea0c Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 15 May 2023 10:15:37 -0400 Subject: [PATCH 014/324] Fixed bug where the aobl arrays were not being allocated when oblateness was turned on --- src/swiftest/swiftest_io.f90 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index d63a1a95d..8cb720ec0 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2930,6 +2930,15 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (.not.param%loblatecb) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) + else + if (self%pl%nbody > 0) then + if (.not. allocated(self%pl%aobl)) allocate(self%pl%aobl(NDIM,self%pl%nbody)) + self%pl%aobl(:,:) = 0.0_DP + end if + if (self%tp%nbody > 0) then + if (.not. allocated(self%tp%aobl)) allocate(self%tp%aobl(NDIM,self%tp%nbody)) + self%tp%aobl(:,:) = 0.0_DP + end if end if return From a4549586c791a1c0fae17f65fdd079624aea4983 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 13 Jun 2023 12:49:56 -0400 Subject: [PATCH 015/324] changed rot matrix calculation; passing extra arg to obl_acc --- setup_sim.py | 6 +- src/rmvs/rmvs_step.f90 | 4 +- src/swiftest/swiftest_module.f90 | 9 +- src/swiftest/swiftest_obl.f90 | 148 ++++++++++++++++--------------- 4 files changed, 87 insertions(+), 80 deletions(-) diff --git a/setup_sim.py b/setup_sim.py index 38c92a3ed..59ae0e69d 100644 --- a/setup_sim.py +++ b/setup_sim.py @@ -6,7 +6,7 @@ seed = None rng = np.random.default_rng(seed=seed) -tstop = 10 * 365.25 # 1e3 * 365.25 # years +tstop = 1e3 * 365.25 # 1e3 * 365.25 # years dt = 90.0 / 60.0 / 24 / 10 # 1/10 * 90 min to days dt_unit = 'Years' dt_max = 0 @@ -26,7 +26,7 @@ density = 2000 # kg/m^3 radius = 1.5e6 # m volume = 4.0 / 3.0 * np.pi * radius**3 -rot = [0, 0, 0.00058] # rad/s +rot = [[0, 0, 0.00058]] # rad/s #initial ring particle orbital parameters @@ -46,7 +46,7 @@ # use JPL Horizons for ISS details # date = '2023-04-27' -ephemerides_start_date = '2023-04-27' +ephemerides_start_date = '2023-05-18' tstart = datetime.date.fromisoformat(ephemerides_start_date) tstep = datetime.timedelta(days=1) tend = tstart + tstep diff --git a/src/rmvs/rmvs_step.f90 b/src/rmvs/rmvs_step.f90 index 11f7d2756..4cb112f0b 100644 --- a/src/rmvs/rmvs_step.f90 +++ b/src/rmvs/rmvs_step.f90 @@ -203,8 +203,8 @@ subroutine rmvs_step_out(cb, pl, tp, nbody_system, param, t, dt) tp%lfirst = lfirsttp else if (param%loblatecb) then - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rbeg, pl%lmask, pl%outer(outer_index-1)%aobl, pl%Gmass, cb%aoblbeg) - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rend, pl%lmask, pl%outer(outer_index)%aobl, pl%Gmass, cb%aoblend) + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rbeg, pl%lmask, pl%outer(outer_index-1)%aobl, cb%rot, pl%Gmass, cb%aoblbeg) + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rend, pl%lmask, pl%outer(outer_index)%aobl, cb%rot, pl%Gmass, cb%aoblend) end if call tp%step(nbody_system, param, outer_time, dto) end if diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 40078f04b..d7ea36e3f 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -994,15 +994,15 @@ pure module subroutine swiftest_kick_getacch_int_one_tp(rji2, xr, yr, zr, Gmpl, real(DP), intent(inout) :: ax, ay, az !! Acceleration vector components of test particle end subroutine swiftest_kick_getacch_int_one_tp - module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_matrix_inv) + module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + integer(I4B), intent(in) :: n !! Number of bodies + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix ! rotation matrix and its inverse real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv ! inverse of the rotation matrix end subroutine swiftest_obl_rot_matrix - module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, GMpl, aoblcb) + module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, GMpl, aoblcb) implicit none integer(I4B), intent(in) :: n !! Number of bodies real(DP), intent(in) :: GMcb !! Central body G*Mass @@ -1011,6 +1011,7 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, GMpl, real(DP), dimension(:,:), intent(in) :: rh !! Heliocentric positions of bodies logical, dimension(:), intent(in) :: lmask !! Logical mask of bodies to compute aobl real(DP), dimension(:,:), intent(out) :: aobl !! Barycentric acceleration of bodies due to central body oblateness + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles real(DP), dimension(:), intent(out), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) end subroutine swiftest_obl_acc diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index fb2046eaa..be2e68196 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -40,7 +40,7 @@ pure function matinv3(A) result(B) B(3,3) = +detinv * (A(1,1)*A(2,2) - A(1,2)*A(2,1)) end function - module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_matrix_inv) + module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) !! author: Kaustub P. Anand !! !! Generate a rotation matrix and its inverse to rotate the coordinate frame to align the rotation axis along the z axis for correct spin calculation @@ -48,16 +48,18 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma implicit none ! Arguments - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix ! rotation matrix and its inverse - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv ! inverse of the rotation matrix + !! class(swiftest_body), intent(inout) :: self !! Swiftest body object + !! class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + integer(I4B), intent(in) :: n !! Number of bodies + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix !! rotation matrix and its inverse + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv !! inverse of the rotation matrix ! Internals - real(DP) :: theta ! angle to rotate it through - real(DP), dimension(3) :: u, z_hat ! unit vector about which we rotate and z_hat - real(DP), dimension(3, 3) :: S_matrix ! rotation matrices - integer :: i, j ! dummy variable + real(DP) :: theta !! angle to rotate it through + real(DP), dimension(3) :: u, z_hat !! unit vector about which we rotate and z_hat + real(DP), dimension(3, 3) :: S_matrix !! rotation matrices + integer :: i, j !! dummy variable ! Assumed that NDIM = 3 @@ -65,50 +67,47 @@ module subroutine swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_ma rot_matrix_inv(:, :) = 0.0_DP z_hat(:) = [0, 0, 1] - if (self%nbody == 0) return - - associate(n => self%nbody, cb => nbody_system%cb) - if (cb%rot(1) == 0 .and. cb%rot(2) == 0) then - do i = 1, NDIM - rot_matrix(i, i) = 1.0 - rot_matrix_inv(i, i) = 1.0 - end do - - return ! rotation axis is about the z-axis, no need to change - end if - - u(:) = cb%rot(:) .cross. z_hat(:) - u(:) = .unit. u(:) - theta = acos(dot_product((.unit. cb%rot(:)), z_hat(:))) - - ! S_matrix(:, :) = [[0.0_DP, -u(3), u(2)], [u(3), 0.0_DP, -u(1)], [-u(2), u(1), 0.0_DP]] ! skew-symmetric matrix - S_matrix(1, :) = [0.0_DP, -u(3), u(2)] - S_matrix(2, :) = [u(3), 0.0_DP, -u(1)] - S_matrix(3, :) = [-u(2), u(1), 0.0_DP] - ! assuming NDIM = 3 - ! CHECK for a general formula for the skew-symmetric matrix + if (n == 0) return + if (rot(1) == 0 .and. rot(2) == 0) then do i = 1, NDIM - do j = 1, NDIM - if (i == j) then - rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) ! identity matrix - continue - end if + rot_matrix(i, i) = 1.0 + rot_matrix_inv(i, i) = 1.0 + end do - rot_matrix(i, j) = rot_matrix(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) ! Skew-symmetric matrix + Tensor product matrix + return ! rotation axis is about the z-axis, no need to change + end if + + u(:) = rot(:) .cross. z_hat(:) + u(:) = .unit. u(:) + theta = acos(dot_product((.unit. rot(:)), z_hat(:))) + + ! S_matrix(:, :) = [[0.0_DP, -u(3), u(2)], [u(3), 0.0_DP, -u(1)], [-u(2), u(1), 0.0_DP]] ! skew-symmetric matrix + S_matrix(1, :) = [0.0_DP, -u(3), u(2)] + S_matrix(2, :) = [u(3), 0.0_DP, -u(1)] + S_matrix(3, :) = [-u(2), u(1), 0.0_DP] + ! assuming NDIM = 3 + ! CHECK for a general formula for the skew-symmetric matrix + + do i = 1, NDIM + do j = 1, NDIM + if (i == j) then + rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) ! identity matrix + continue + end if + + rot_matrix(i, j) = rot_matrix(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) ! Skew-symmetric matrix + Tensor product matrix - end do end do + end do - rot_matrix_inv = matinv3(rot_matrix) - - end associate + rot_matrix_inv = matinv3(rot_matrix) return end subroutine swiftest_obl_rot_matrix - module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, GMpl, aoblcb) - !! author: David A. Minton + module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, GMpl, aoblcb) + !! author: David A. Minton, Kaustub Anand (2023) !! !! Compute the barycentric accelerations of bodies due to the oblateness of the central body !! Returned values do not include monopole term or terms higher than J4 @@ -124,8 +123,10 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, GMpl, real(DP), dimension(:,:), intent(in) :: rh !! Heliocentric positions of bodies logical, dimension(:), intent(in) :: lmask !! Logical mask of bodies to compute aobl real(DP), dimension(:,:), intent(out) :: aobl !! Barycentric acceleration of bodies due to central body oblateness + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles real(DP), dimension(:), intent(out), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + ! Internals integer(I4B) :: i real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac1, fac2 @@ -134,43 +135,48 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, GMpl, if (n == 0) return - ! generate the rotation matrix - call swiftest_obl_rot_matrix(self, nbody_system, rot_matrix, rot_matrix_inv) + aobl(:,:) = 0.0_DP + + ! If the rotation axis is along the z-axis, skip calculating the rotation matrix + if (rot(1) == 0 .and. rot(2) == 0) then + do concurrent(i = 1:n, lmask(i)) + r2 = dot_product(rh(:, i), rh(:, i)) + irh = 1.0_DP / sqrt(r2) + rinv2 = irh**2 + t0 = -GMcb * rinv2 * rinv2 * irh + t1 = 1.5_DP * j2rp2 + t2 = rh(3, i) * rh(3, i) * rinv2 + t3 = 1.875_DP * j4rp4 * rinv2 + fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) + fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) + aobl(:, i) = fac1 * rh(:, i) + aobl(3, i) = fac2 * rh(3, i) + aobl(3, i) + end do + else + ! generate the rotation matrix + call swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) - associate(n => self%nbody, cb => nbody_system%cb) - self%aobl(:,:) = 0.0_DP - do concurrent(i = 1:n, self%lmask(i)) + do concurrent(i = 1:n, lmask(i)) ! rotate the position vectors - rh_transformed = MATMUL(self%rh(:, i), rot_matrix) ! 1x3 vector * 3x3 matrix + rh_transformed = MATMUL(rh(:, i), rot_matrix) ! 1x3 vector * 3x3 matrix r2 = dot_product(rh_transformed, rh_transformed) irh = 1.0_DP / sqrt(r2) rinv2 = irh**2 - t0 = -cb%Gmass * rinv2 * rinv2 * irh - t1 = 1.5_DP * cb%j2rp2 + t0 = -GMcb * rinv2 * rinv2 * irh + t1 = 1.5_DP * j2rp2 t2 = rh_transformed(3) * rh_transformed(3) * rinv2 - t3 = 1.875_DP * cb%j4rp4 * rinv2 + t3 = 1.875_DP * j4rp4 * rinv2 fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) - self%aobl(:, i) = fac1 * rh_transformed(:) - self%aobl(3, i) = fac2 * rh_transformed(3) + self%aobl(3, i) + aobl(:, i) = fac1 * rh_transformed(:) + aobl(3, i) = fac2 * rh_transformed(3) + aobl(3, i) ! rotate the acceleration and position vectors back to the original coordinate frame - self%aobl(:, i) = MATMUL(self%aobl(:, i), rot_matrix_inv) + aobl(:, i) = MATMUL(aobl(:, i), rot_matrix_inv) + end do + end if - aobl(:,:) = 0.0_DP - do concurrent(i = 1:n, lmask(i)) - r2 = dot_product(rh(:, i), rh(:, i)) - irh = 1.0_DP / sqrt(r2) - rinv2 = irh**2 - t0 = -GMcb * rinv2 * rinv2 * irh - t1 = 1.5_DP * j2rp2 - t2 = rh(3, i) * rh(3, i) * rinv2 - t3 = 1.875_DP * j4rp4 * rinv2 - fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) - fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) - aobl(:, i) = fac1 * rh(:, i) - aobl(3, i) = fac2 * rh(3, i) + aobl(3, i) - end do + if (present(GMpl) .and. present(aoblcb)) then aoblcb(:) = 0.0_DP @@ -201,7 +207,7 @@ module subroutine swiftest_obl_acc_pl(self, nbody_system) if (self%nbody == 0) return associate(pl => self, npl => self%nbody, cb => nbody_system%cb) - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rh, pl%lmask, pl%aobl, pl%Gmass, cb%aobl) + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rh, pl%lmask, pl%aobl, cb%rot, pl%Gmass, cb%aobl) do concurrent(i = 1:npl, pl%lmask(i)) pl%ah(:, i) = pl%ah(:, i) + pl%aobl(:, i) - cb%aobl(:) @@ -231,7 +237,7 @@ module subroutine swiftest_obl_acc_tp(self, nbody_system) if (self%nbody == 0) return associate(tp => self, ntp => self%nbody, cb => nbody_system%cb) - call swiftest_obl_acc(ntp, cb%Gmass, cb%j2rp2, cb%j4rp4, tp%rh, tp%lmask, tp%aobl) + call swiftest_obl_acc(ntp, cb%Gmass, cb%j2rp2, cb%j4rp4, tp%rh, tp%lmask, tp%aobl, cb%rot) if (nbody_system%lbeg) then aoblcb = cb%aoblbeg else From 850d691022b028b225d93307cf900e47948a4f8c Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 13 Jun 2023 16:47:21 -0400 Subject: [PATCH 016/324] changed 'rotation' to 'ROTATION' in vec2xr in init_cond.py to ensure default Ip and rot is set --- python/swiftest/swiftest/init_cond.py | 2 +- src/swiftest/swiftest_obl.f90 | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/python/swiftest/swiftest/init_cond.py b/python/swiftest/swiftest/init_cond.py index efaa6429f..1b140f119 100644 --- a/python/swiftest/swiftest/init_cond.py +++ b/python/swiftest/swiftest/init_cond.py @@ -283,7 +283,7 @@ def vec2xr(param: Dict, **kwargs: Any): # Check for valid keyword arguments kwargs = {k:kwargs[k] for k,v in kwargs.items() if v is not None} - if "rotation" in param and param['rotation'] == True: + if "ROTATION" in param and param['ROTATION'] == True: if "rot" not in kwargs and "Gmass" in kwargs: kwargs['rot'] = np.zeros((len(kwargs['Gmass']),3)) if "Ip" not in kwargs and "Gmass" in kwargs: diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index be2e68196..ed66dd5d1 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -48,10 +48,8 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) implicit none ! Arguments - !! class(swiftest_body), intent(inout) :: self !! Swiftest body object - !! class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object integer(I4B), intent(in) :: n !! Number of bodies - real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix !! rotation matrix and its inverse real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv !! inverse of the rotation matrix @@ -123,7 +121,7 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, real(DP), dimension(:,:), intent(in) :: rh !! Heliocentric positions of bodies logical, dimension(:), intent(in) :: lmask !! Logical mask of bodies to compute aobl real(DP), dimension(:,:), intent(out) :: aobl !! Barycentric acceleration of bodies due to central body oblateness - real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles real(DP), dimension(:), intent(out), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) From 1771e2b808bf695d46f566518d9819340b1ceb34 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 13 Jun 2023 17:10:10 -0400 Subject: [PATCH 017/324] J2 and J4 key change completed and tested --- setup_sim.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup_sim.py b/setup_sim.py index 59ae0e69d..ec1e69345 100644 --- a/setup_sim.py +++ b/setup_sim.py @@ -6,7 +6,7 @@ seed = None rng = np.random.default_rng(seed=seed) -tstop = 1e3 * 365.25 # 1e3 * 365.25 # years +tstop = 1e1 * 365.25 # 1e3 * 365.25 # years dt = 90.0 / 60.0 / 24 / 10 # 1/10 * 90 min to days dt_unit = 'Years' dt_max = 0 From 49808344b9fd1b80a790f09040ad112c80e60658 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 20 Jun 2023 17:28:47 -0400 Subject: [PATCH 018/324] Fixed a typo in comments; tested and checked a non-z-axis central body rotation vector. Precession works --- setup_sim.py | 56 ++++++++++++++++++-------------- setup_sim_ring_capture.py | 25 +++++++++----- src/swiftest/swiftest_module.f90 | 8 ++--- src/swiftest/swiftest_obl.f90 | 4 +-- 4 files changed, 53 insertions(+), 40 deletions(-) diff --git a/setup_sim.py b/setup_sim.py index ec1e69345..4b1324c2f 100644 --- a/setup_sim.py +++ b/setup_sim.py @@ -6,14 +6,14 @@ seed = None rng = np.random.default_rng(seed=seed) -tstop = 1e1 * 365.25 # 1e3 * 365.25 # years -dt = 90.0 / 60.0 / 24 / 10 # 1/10 * 90 min to days +tstop = 1e3 * 365.25 # years to days +dt = 90.0 / 60.0 / 24 / 10 # 1/10 * 90 min to days dt_unit = 'Years' dt_max = 0 scratch_dr = '/scratch/bell/anand43/swiftest_runs/' body_dr = 'tests/' -simdir = 'test' # '2e3_part_radial' +simdir = 'moon_0inc_rotated_obl_test2' # '2e3_part_radial' simdir = scratch_dr + body_dr + simdir # unit conversion factors @@ -52,26 +52,26 @@ tend = tstart + tstep ephemerides_end_date = tend.isoformat() ephemerides_step = '1d' -iss_obj = Horizons(id = '-125544', location = '399', epochs={'start': ephemerides_start_date, 'stop': ephemerides_end_date, - 'step': ephemerides_step}) # 399 = Earth geocenter; -125544 = ISS - -iss_el = iss_obj.elements() -iss_el['a'].convert_unit_to('km') -random_a = iss_el['a'][0] -random_e = iss_el['e'][0] -random_i = iss_el['incl'][0] -random_capom = iss_el['Omega'][0] -random_omega = iss_el['w'][0] -random_capm = iss_el['M'][0] +obj = Horizons(id = '301', location = '399', epochs={'start': ephemerides_start_date, 'stop': ephemerides_end_date, + 'step': ephemerides_step}) # IDs: 399 = Earth geocenter; -125544 = ISS; 301 = Moon/Luna + +obj_el = obj.elements() +obj_el['a'].convert_unit_to('km') +random_a = obj_el['a'][0] +random_e = obj_el['e'][0] +random_i = 23.4392811 #obj_el['incl'][0] +random_capom = obj_el['Omega'][0] +random_omega = obj_el['w'][0] +random_capm = obj_el['M'][0] random_radius = 100e-3 # km -random_mass = 419725 # km +random_mass = 419725 # kg earth_radius = 6371.01 # km earth_mass = 5.97219e24 # kg earth_J2 = 1083e-6 # from Murray and Dermott txt. bk. earth_J4 = -2e-6 # from Murray and Dermott txt. bk. -earth_tilt = np.deg2rad(23.4392811) -earth_rot = np.array([0.0, np.sin(earth_tilt), np.cos(earth_tilt)]) * 2 * np.pi / (24 * 60 * 60.0) +earth_tilt = np.deg2rad(-23.4392811) +earth_rot = np.array([0.0, np.sin(earth_tilt), np.cos(earth_tilt)]) * 2 * np.pi / (24 * 60 * 60.0) # rad/s earth_rot = [earth_rot] # # check that dt < dt_max @@ -91,20 +91,26 @@ sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e7, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", MU = 'kg', DU2M = 1e3, TU = 'd', rmin = earth_radius) # sim.add_solar_system_body(["Earth"], date = ephemerides_start_date) + # Manually add Earth as a CB because no J2 or J4 term is added otherwise sim.add_body(name = "Earth", id = 1, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, mass = earth_mass, radius = earth_radius, J2 = earth_J2 * earth_radius**2, J4 = earth_J4 * earth_radius**4, rot = earth_rot) # sim.add_body(name = 'Centaur', id = 1, mass = density * volume, radius = radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0) -sim.add_body(name = "ISS", id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius) -# sim.get_parameter() -# sim.set_parameter() + +sim.add_body(name = "Moon", id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius) + sim.write_param() sim.save() # sim.run() print(f'total number of steps ={int(tstop / dt)}') -J2 = sim.init_cond.isel(name = 0)['j2rp2'].values -print(f'J2 in init_cond = {J2}') -d = sim.data.isel(name = 0) -J2 = d['j2rp2'].values -print(f'J2 for central body = {J2}') +# J2 = sim.init_cond.isel(name = 0)['j2rp2'].values +# print(f'J2 in init_cond = {J2}') +# d = sim.data.isel(name = 0) +# J2 = d['j2rp2'].values +# print(f'J2 for central body = {J2}') +print(f'lon_asc_node = {random_capom}') +print(f'arg_peri = {random_omega}') +print(f'inclination = {random_i}') +print(f'mean anomaly = {random_capm}') +print(f'earth rot = {earth_rot}') diff --git a/setup_sim_ring_capture.py b/setup_sim_ring_capture.py index 970d44913..77410955e 100644 --- a/setup_sim_ring_capture.py +++ b/setup_sim_ring_capture.py @@ -9,8 +9,8 @@ rng = np.random.default_rng(seed=seed) n_bodies = int(1e4) # number of planet bodies array_shift = np.random.randint(0, n_bodies) -tstop = 10 # rotation periods -dt = 1.0e-5 +tstop = 100 # rotation periods +dt = 1.0e-4 dt_unit = 'Haumea_rot_period' # dt_unit = 'd' dt_max = 0 @@ -76,22 +76,29 @@ z = random_pos_mag * np.cos(random_theta) * np.sign(z_sign) random_pos_vec = np.array([x, y, z]).T -# set up the velocity vectors pointing radially away from the central body. - -# random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (1.15 - 0.85) + 0.85) # randomize the velocity by 0.9 - 1.1 times the keplerian velocity +# set up the velocity vectors (pointing radially away from the central body if needed) +# Radial Velocity v_escape = np.sqrt(2 * sim.GU * mass / radius) alpha = rng.random(n_bodies) * (0.95 - 0.8) + 0.8 # numerical scaling for initial velocity random_vel_mag = np.sqrt(alpha * v_escape**2 + 2 * sim.GU * mass * (1 / random_pos_mag - 1 / radius)) # scale the velocity with distance +# # Tangential velocity +# # random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (1.15 - 0.85) + 0.85) # randomize the velocity by 0.9 - 1.1 times the keplerian velocity + +# v_orbital = np.sqrt(sim.GU * mass / (radius + np.average(random_pos_mag))) +# alpha = rng.random(n_bodies) * (1.1 - 0.85) + 0.85 # numerical scaling for initial velocity +# random_vel_mag = np.sqrt(alpha * v_orbital) + x = x * random_vel_mag / random_pos_mag y = y * random_vel_mag / random_pos_mag z = z * random_vel_mag / random_pos_mag # rotate the velocity vectors (degrees) -# 85 - 95 degrees to represent orbiting particles for tangential motion -angle = 20 -rot_angle = np.deg2rad(rng.random(n_bodies) * (angle - (-1.0 * angle)) + (-1.0 * angle)) # rotate by <> degrees randomly + # 85 - 95 degrees to represent orbiting particles for tangential motion +angle = 0.0 +range = 40 +rot_angle = np.deg2rad(rng.random(n_bodies) * (range) + (angle - range/2)) # rotate by "angle" degrees randomly with a "range" variation about the "angle" x_tmp = x y_tmp = y @@ -163,7 +170,7 @@ plt.plot([cb_ax_long, cb_ax_long], [0, ymax], '-', color = 'orange') plt.text(cb_ax_long + 0.1, ymax / 5, s = r'Longest CB Axis', color = 'orange', rotation = 'vertical') plt.plot([-7, 7], [v_escape, v_escape], '-', color = 'black') -plt.text(1, v_escape + 0.5, s = 'Escape Velocity', color = 'black') +# plt.text(1, v_escape + 0.5, s = 'Escape Velocity', color = 'black') plt.savefig(simdir + '/r_vs_v_initial.png') diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index d7ea36e3f..6607816df 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -996,10 +996,10 @@ end subroutine swiftest_kick_getacch_int_one_tp module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) implicit none - integer(I4B), intent(in) :: n !! Number of bodies - real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix ! rotation matrix and its inverse - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv ! inverse of the rotation matrix + integer(I4B), intent(in) :: n !! Number of bodies + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation vector + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix !! rotation matrix + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv !! inverse of the rotation matrix end subroutine swiftest_obl_rot_matrix module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, GMpl, aoblcb) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index ed66dd5d1..f3656050e 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -49,8 +49,8 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) implicit none ! Arguments integer(I4B), intent(in) :: n !! Number of bodies - real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix !! rotation matrix and its inverse + real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation vector + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix !! rotation matrix real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv !! inverse of the rotation matrix ! Internals From f87b3968206c67c56ec75ba80d017c9d0489e2a7 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 21 Jun 2023 15:27:16 -0400 Subject: [PATCH 019/324] Moved extra files to folder misc. NOT to be included in pull request --- calc_ring_mass.py | 28 - copy_setup_sim_ring_capture.py | 180 ----- read_nc_sim.ipynb | 1334 -------------------------------- scatter_movie.ipynb | 877 --------------------- setup_sim.py | 116 --- setup_sim_ring_capture.py | 246 ------ 6 files changed, 2781 deletions(-) delete mode 100644 calc_ring_mass.py delete mode 100644 copy_setup_sim_ring_capture.py delete mode 100644 read_nc_sim.ipynb delete mode 100644 scatter_movie.ipynb delete mode 100644 setup_sim.py delete mode 100644 setup_sim_ring_capture.py diff --git a/calc_ring_mass.py b/calc_ring_mass.py deleted file mode 100644 index dacbb372a..000000000 --- a/calc_ring_mass.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -Calculate the approx. mass of a ring given the central body observed parameters - -""" -import numpy as np - -simdir = '/scratch/bell/anand43/swiftest_runs/' - -# ring parameters (in SI units) -density = 2000 # kg / m^3 -width = 3.5e3 # m -radius = 404.8e3 # m # assume inner radius -outer_rad = radius + width -height = 0.1e3 # assume height of 100 m thick - -# central body parameters (in SI units) -cb_mass = 3.874e20 # kg -cb_name = 'Chariklo' - -vol = np.pi * (outer_rad**2 - radius**2) * height # ring volume -ring_mass = vol * density # ring mass - -print_msg = f'\nMass of Ring around {cb_name} = {ring_mass} kg = {ring_mass / cb_mass} M_{cb_name}' -print(print_msg) -print(f'Assuming a ring thickness of {height} m') - -file = open(simdir + cb_name + f'/{cb_name}_ring_mass.txt', 'w') -file.write(print_msg) \ No newline at end of file diff --git a/copy_setup_sim_ring_capture.py b/copy_setup_sim_ring_capture.py deleted file mode 100644 index b76b55fc6..000000000 --- a/copy_setup_sim_ring_capture.py +++ /dev/null @@ -1,180 +0,0 @@ -import numpy as np -import swiftest -import matplotlib.pyplot as plt -from mpl_toolkits.mplot3d import axes3d - -seed = None -rng = np.random.default_rng(seed=seed) -n_bodies = int(1e4) # number of planet bodies -array_shift = np.random.randint(0, n_bodies) -tstop = 500 # rotation periods -dt = 1.0e-3 -dt_unit = 'Haumea_rot_period' -# dt_unit = 'd' -dt_max = 0 -G = 6.6743e-11 # SI Units -scratch_dr = '/scratch/bell/anand43/swiftest_runs/' -simdir = 'haumea_1e4_part' -simdir = scratch_dr + simdir - -# unit conversion factors -S2DAY = 1 / (60.0 * 60 * 24) -S2YR = S2DAY / 365.25 -KG2MSUN = 1 / 1.98847e30 -M2AU = 1 / 1.496e11 - -# initial central body parameters -# Haumea parameters taken from P. S. Jean Carvalho (2019) - -cb_mass = 4.006e21 # kg -cb_radius = 711.9097e3 # m -mass = cb_mass / cb_mass -radius = cb_radius / cb_radius -longest_axis = 1161e3 # m -rmin = longest_axis / cb_radius -volume = 4.0 / 3.0 * np.pi * radius**3 -density = mass / volume # kg/m^3 -T_rotation = 3.915341 * 60 * 60 # hours to sec -rot = 2 * np.pi / T_rotation # rad/s -rot = [[0, 0, rot]] -J2 = 0.305 -J4 = -0.216 -time_unit = T_rotation -print(f'R_min = {rmin}') - -# set up swiftest simulation - -sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e5, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", rmin = rmin, MU2KG = mass, DU2M = radius, TU2S = T_rotation, init_cond_format = 'XV') # TU = dt_unit, MU_name = 'M_Haumea', DU_name = 'R_Haumea' - -#initial ring particle orbital parameters - -id_start = 100 # starting ID for bodies - -random_radius = rng.random(n_bodies) * (50 - 5) + 5 # randomize the radii of the ring particles between 5 and 50 (m) -random_mass = np.power(random_radius, 3) * 4.0 * np.pi / 3.0 * density # randomize the mass - -z_sign = rng.random(n_bodies) - 0.5 # randomize the sign of the z-component - -# set up the position vectors -random_pos_mag = (rng.random(n_bodies) * (3 - 1.65) + 1.65) # randomize the distance between 1.65 and 3 Haumea Radii -random_phi = np.deg2rad((rng.random(n_bodies)) * 90.0) -random_theta = np.deg2rad((rng.random(n_bodies)) * (30.0 - (-30)) - 30) # equatorial zone -x = random_pos_mag * np.sin(random_theta) * np.cos(random_phi) -y = random_pos_mag * np.sin(random_theta) * np.sin(random_phi) -z = random_pos_mag * np.cos(random_theta) * np.sign(z_sign) -random_pos_vec = np.array([x, y, z]).T - -# set up the velocity vectors -random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (2.0 - 0.5) + 0.5) # randomize the velocity by 0.5 - 2.0 about the keplerian velocity -random_phi = np.deg2rad((rng.random(n_bodies)) * 90.0) -random_theta = np.deg2rad((rng.random(n_bodies)) * (30.0 - (-30)) - 30) # equatorial zone -x = random_vel_mag * np.sin(random_theta) * np.cos(random_phi) -y = random_vel_mag * np.sin(random_theta) * np.sin(random_phi) -z = random_vel_mag * np.cos(random_theta) * np.sign(z_sign) -random_vel_vec = np.array([x, y, z]).T - -print(f'Shape of pos vec = {random_pos_vec.shape}') -print(f'Shape of vel vec = {random_vel_vec.shape}') - -# random_rot = 0 * [0, 0, 1.0] * rng.random(n_bodies) # rad/s -# CHECK and FIX random_rot (sequence multiplication issue) - -random_radius = random_radius / radius -random_mass = random_mass / mass - -ring_mass_tot = np.sum(random_mass) - -print(f'Total ring mass = {ring_mass_tot} {sim.MU_name}') -print(f'sim.GU = {sim.GU}') - -sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2, J4 = J4) -sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), mass = random_mass, radius = random_radius, rh = random_pos_vec, vh = random_vel_vec)#, rot = random_rot) - -# check that dt < dt_max - -dt_max = 2.0 * np.pi / np.sqrt(G * mass) -dt_max = dt_max * np.power(np.min(random_pos_mag) * sim.DU2M, 3/2) -dt_max = dt_max / 10.0 -dt_max = dt_max / sim.TU2S # convert s to time units - -print(f'\ndt_max = {dt_max} {dt_unit}') -print(f'Current dt = {dt} {dt_unit}\n') - -if(dt > dt_max): - print("dt is TOO BIG!") - raise Exception - -sim.write_param() -sim.save() -# sim.run() - -# Make initial plots - -fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) - -plt.scatter(np.linalg.norm(sim.data.isel(time = 0)['rh'], axis = 1), np.linalg.norm(sim.data.isel(time = 0)['vh'], axis = 1)) -plt.xlabel('rh') -plt.ylabel('vh') -# plot longest axis -cb_ax_long = rmin -ymin = np.min(random_vel_mag) -ymax = np.max(random_vel_mag) -plt.ylim([0, ymax]) -plt.plot([cb_ax_long, cb_ax_long], [0, ymax], '-', color = 'orange') -plt.text(cb_ax_long - 0.1, ymax / 5, s = r'Longest CB Axis', color = 'orange', rotation = 'vertical') - -plt.savefig(simdir + '/r_vs_v_initial.png') - -plt.clf() -fig = plt.figure(dpi = 300) -ax = fig.add_subplot(projection = '3d') -ax.scatter(random_pos_vec[:, 0], random_pos_vec[:, 1], random_pos_vec[:, 2], marker = 'o') -ax.set_xlabel('x') -ax.set_ylabel('y') -ax.set_zlabel('z') -ax.set_zlim([-5, 5]) -plt.savefig(simdir + '/pos_vector.png') - -ax.view_init(elev = 0, azim = 0) -plt.savefig(simdir + '/pos_vector_eq.png') - - -# Extra code - -# random_2pi = 360 * np.random.rand(n_bodies) # 360 degrees -# random_pi = 180 * np.random.rand(n_bodies) # 180 degrees -# random_a = (rng.random(n_bodies) * (4 - 1.65) + 1.65) # randomize the semi-major axis between 1.65 and 4 (Haumea Radii) -# # Haumea's longest axis = 1.63 * R_Haumea (1161 km = 1.63 * 711.9097 km) -# random_e = rng.random(n_bodies) * 0.8 # randomize eccentricity between 0 and 0.8 -# random_i = np.random.rand(n_bodies) * (30 - (-30)) + (-30) # between (-30, 30) (degrees) (equatorial zone) -# random_capom = random_2pi -# random_omega = np.roll(random_2pi, array_shift) -# array_shift = np.random.randint(0, n_bodies) # compute another random shift -# random_capm = np.roll(random_2pi, array_shift) - - - -# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) - -# plt.scatter(sim.data['a'], sim.data['e']) -# plt.xlabel('a') -# plt.ylabel('e') -# plt.savefig(simdir + '/a_vs_e_initial.png') - -# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) - -# plt.scatter(sim.data['a'], sim.data['inc']) -# plt.xlabel('a') -# plt.ylabel('inc') -# plt.savefig(simdir + '/a_vs_i_initial.png') - -# print(f'sim.MU2KG = {sim.MU2KG}') -# print(f'sim.param["MU2KG"] = {sim.param["MU2KG"]}') -# print(f'sim.MU_name = {sim.MU_name}') -# sim.add_solar_system_body(["Sun", "Mercury", "Venus", "Earth", "Mars"]) -# random_radius = random_radius / sim.DU2M -# random_mass = random_mass / sim.MU2KG -# sim.add_body(name = 'Centaur', id = 0, mass = mass / mass, rot = rot, radius = radius / radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, J2 = J2, J4 = J4) -# sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius)#, rot = random_rot) - -# sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e5, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", TU = dt_unit, rmin = rmin, MU2KG = mass, DU2M = radius, init_cond_format = 'XV',)# MU_name = 'M_Haumea', DU_name = 'R_Haumea') diff --git a/read_nc_sim.ipynb b/read_nc_sim.ipynb deleted file mode 100644 index 1db018833..000000000 --- a/read_nc_sim.ipynb +++ /dev/null @@ -1,1334 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "env: HDF5_USE_FILE_LOCKING=FALSE\n", - "Reading Swiftest file /scratch/bell/anand43/swiftest/ring_capture_sph_rot/param.in\n", - "\n", - "Creating Dataset from NetCDF file\n", - "Successfully converted 1 output frames.\n", - "\n", - "Creating Dataset from NetCDF file\n", - "Successfully converted 36526 output frames.\n", - "Swiftest simulation data stored as xarray DataSet .data\n", - "Reading initial conditions file as .init_cond\n", - "Reading collisions history file as .collisions\n", - "Finished reading Swiftest dataset files.\n" - ] - } - ], - "source": [ - "#!/usr/bin/env python3\n", - "\n", - "%env HDF5_USE_FILE_LOCKING=FALSE\n", - "\n", - "import numpy as np\n", - "import swiftest \n", - "\n", - "sim = swiftest.Simulation(simdir = 'ring_capture_sph_rot', read_data = True, dask = True)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:  (name: 1001, space: 3, time: 1)\n",
-       "Coordinates:\n",
-       "  * name     (name) <U32 'Centaur' '100' '101' '102' ... '1097' '1098' '1099'\n",
-       "  * space    (space) <U1 'x' 'y' 'z'\n",
-       "  * time     (time) float64 0.0\n",
-       "Data variables: (12/14)\n",
-       "    a        (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
-       "    e        (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
-       "    inc      (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
-       "    capom    (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
-       "    omega    (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
-       "    capm     (time, name) float64 dask.array<chunksize=(1, 1001), meta=np.ndarray>\n",
-       "    ...       ...\n",
-       "    rot      (time, name, space) float64 dask.array<chunksize=(1, 1001, 3), meta=np.ndarray>\n",
-       "    Ip       (time, name, space) float64 dask.array<chunksize=(1, 1001, 3), meta=np.ndarray>\n",
-       "    id       (name) int64 dask.array<chunksize=(1001,), meta=np.ndarray>\n",
-       "    ntp      (time) int64 dask.array<chunksize=(1,), meta=np.ndarray>\n",
-       "    npl      (time) int64 dask.array<chunksize=(1,), meta=np.ndarray>\n",
-       "    nplm     (time) int64 dask.array<chunksize=(1,), meta=np.ndarray>
" - ], - "text/plain": [ - "\n", - "Dimensions: (name: 1001, space: 3, time: 1)\n", - "Coordinates:\n", - " * name (name) \n", - " e (time, name) float64 dask.array\n", - " inc (time, name) float64 dask.array\n", - " capom (time, name) float64 dask.array\n", - " omega (time, name) float64 dask.array\n", - " capm (time, name) float64 dask.array\n", - " ... ...\n", - " rot (time, name, space) float64 dask.array\n", - " Ip (time, name, space) float64 dask.array\n", - " id (name) int64 dask.array\n", - " ntp (time) int64 dask.array\n", - " npl (time) int64 dask.array\n", - " nplm (time) int64 dask.array" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sim.init_cond\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python (My minton_lab_packages Kernel)", - "language": "python", - "name": "minton_lab_packages" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scatter_movie.ipynb b/scatter_movie.ipynb deleted file mode 100644 index aedaf11e8..000000000 --- a/scatter_movie.ipynb +++ /dev/null @@ -1,877 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import swiftest \n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from matplotlib import animation\n", - "import matplotlib.colors as mcolors\n", - "from collections import namedtuple\n", - "plt.switch_backend('agg')" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "env: HDF5_USE_FILE_LOCKING=FALSE\n", - "Reading Swiftest file /scratch/bell/anand43/swiftest/haumea/param.in\n", - "\n", - "Creating Dataset from NetCDF file\n", - "Successfully converted 1 output frames.\n", - "\n", - "Creating Dataset from NetCDF file\n", - "Successfully converted 16 output frames.\n", - "Swiftest simulation data stored as xarray DataSet .data\n", - "Reading initial conditions file as .init_cond\n", - "Finished reading Swiftest dataset files.\n", - "Making animation\n", - "Finished writing haumea-aescatter.mp4\n", - "Animation finished\n", - "Making animation\n", - "Finished writing haumea-aiscatter.mp4\n", - "Animation finished\n" - ] - } - ], - "source": [ - "#!/usr/bin/env python3\n", - "\n", - "\"\"\"\n", - " Copyright 2023 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh\n", - " This file is part of Swiftest.\n", - " Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License \n", - " as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n", - " Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty \n", - " of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n", - " You should have received a copy of the GNU General Public License along with Swiftest. \n", - " If not, see: https://www.gnu.org/licenses. \n", - "\"\"\"\n", - "\n", - "\"\"\"\n", - "Creates a movie from a set of Swiftest output files. All simulation \n", - "outputs are stored in the /simdata subdirectory.\n", - "\n", - "Input\n", - "------\n", - "param.in : ASCII Swiftest parameter input file.\n", - "data.nc : A NetCDF file containing the simulation output.\n", - "\n", - "Output\n", - "------\n", - "Chambers2013-aescatter.mp4 : A .mp4 file plotting eccentricity vs semimajor axis. \n", - "OR \n", - "Chambers2013-aiscatter.mp4 : A .mp4 file plotting inclination vs semimajor axis. \n", - "\"\"\"\n", - "%env HDF5_USE_FILE_LOCKING=FALSE\n", - "\n", - "import swiftest \n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from matplotlib import animation\n", - "import matplotlib.colors as mcolors\n", - "from collections import namedtuple\n", - "plt.switch_backend('agg')\n", - "\n", - "titletext = 'haumea'\n", - "valid_plot_styles = [\"aescatter\", \"aiscatter\"]#, \"arotscatter\"]\n", - "xlim={\"aescatter\" : (0.0, 5.0),\n", - " \"aiscatter\" : (0.0, 5.0), \n", - " \"arotscatter\" : (0.0, 2.5)}\n", - "ylim={\"aescatter\" : (0.0, 1.0),\n", - " \"aiscatter\" : (0.0, 40.0),\n", - " \"arotscatter\" : (1.0, 10000.0)}\n", - "xlabel={\"aescatter\": r\"Semimajor axis ($R_{Haumea}$)\",\n", - " \"aiscatter\": r\"Semimajor axis ($R_{Haumea}$)\",\n", - " \"arotscatter\": \"Semimajor axis (AU)\"}\n", - "ylabel={\"aescatter\": \"Eccentricity\",\n", - " \"aiscatter\": \"Inclination (deg)\",\n", - " \"arotscatter\": \"Rotation period (h)\"}\n", - "\n", - "cb_ax_long = 1.63 # longest axis of the central body\n", - "\n", - "YR2HR = 365.25 * 24\n", - "ROT2PERIOD = YR2HR * 360.0\n", - "\n", - "framejump = 1\n", - "origin_types = [\"Initial conditions\", \"Merger\", \"Disruption\", \"Supercatastrophic\", \"Hit and run fragmentation\"]\n", - "\n", - "\n", - "class AnimatedScatter(object):\n", - " \"\"\"An animated scatter plot using matplotlib.animations.FuncAnimation.\"\"\"\n", - " def __init__(self, ds, param):\n", - "\n", - " self.radscale = 2e6\n", - " nframes = int(ds['time'].size / framejump)\n", - " ds['rot_mag'] = swiftest.tool.magnitude(ds,\"rot\")\n", - " ds['rot_mag'] = ROT2PERIOD / ds['rot_mag']\n", - " self.Rcb = ds['radius'].sel(name=\"Centaur\").isel(time=0).values[()]\n", - " self.ds = ds\n", - " self.param = param\n", - " colors = [\"k\", \"xkcd:faded blue\", \"xkcd:marigold\", \"xkcd:shocking pink\", \"xkcd:baby poop green\"]\n", - " self.clist = dict(zip(origin_types,colors))\n", - "\n", - " # Setup the figure and axes...\n", - " fig = plt.figure(figsize=(8,4.5), dpi=300)\n", - " plt.tight_layout(pad=0)\n", - " # set up the figure\n", - " self.ax = plt.Axes(fig, [0.1, 0.15, 0.8, 0.75])\n", - " fig.add_axes(self.ax)\n", - "\n", - " self.make_artists()\n", - " \n", - " self.ani = animation.FuncAnimation(fig, func=self.update, interval=1, frames=nframes, init_func=self.init_plot, blit=True)\n", - " self.ani.save(animation_file, fps=60, dpi=300, extra_args=['-vcodec', 'libx264'])\n", - " print(f'Finished writing {animation_file}')\n", - " \n", - " def make_artists(self):\n", - " scatter_names = [f\"s{i}\" for i,k in enumerate(origin_types)]\n", - " self.scatter_artist_names = dict(zip(origin_types,scatter_names))\n", - " \n", - " animated_elements = [self.ax.text(0.50, 1.05, \"\", bbox={'facecolor': 'w', 'alpha': 0.5, 'pad': 5}, transform=self.ax.transAxes,ha=\"center\", animated=True)]\n", - " element_names = [\"title\"]\n", - " for key, value in self.clist.items():\n", - " animated_elements.append(self.ax.scatter([], [], marker='o', s=[], c=value, alpha=0.75, label=key, animated=True))\n", - " element_names.append(self.scatter_artist_names[key])\n", - " \n", - " Artists = namedtuple(\"Artists\",tuple(element_names))\n", - " self.artists = Artists(*animated_elements)\n", - " return \n", - "\n", - " def init_plot(self):\n", - " self.ax.set_xlim(xlim[plot_style])\n", - " self.ax.set_ylim(ylim[plot_style])\n", - " \n", - " # set up the figure\n", - " self.ax.margins(x=10, y=1)\n", - " self.ax.set_xlabel(xlabel[plot_style], fontsize='16', labelpad=1)\n", - " self.ax.set_ylabel(ylabel[plot_style], fontsize='16', labelpad=1) \n", - " \n", - " leg = plt.legend(loc=\"upper left\", scatterpoints=1, fontsize=10)\n", - " for i,l in enumerate(leg.legendHandles):\n", - " leg.legendHandles[i]._sizes = [20]\n", - " \n", - " if plot_style == \"arotscatter\":\n", - " self.ax.set_yscale('log')\n", - " \n", - " # plot longest axis\n", - " self.ax.plot([cb_ax_long, cb_ax_long], ylim[plot_style], '-', color = 'orange')\n", - " self.ax.text(cb_ax_long - 0.1, ylim[plot_style][-1] / 5, s = r'Longest Haumea Axis', color = 'orange', rotation = 'vertical')\n", - "\n", - " return self.artists\n", - "\n", - " def get_data(self, frame=0):\n", - " d = self.ds.isel(time = frame)\n", - " n=len(d['name'])\n", - " d = d.isel(name=range(1,n))\n", - " d['radmarker'] = (d['radius'] / self.Rcb) * self.radscale\n", - "\n", - " t = d['time'].values\n", - " npl = d['npl'].values\n", - " radmarker = d['radmarker'].values\n", - " origin = d['origin_type'].values\n", - "\n", - " # print(radmarker)\n", - "\n", - " # Check for test particles\n", - " # radmarker = np.where(np.isnan(radmarker), 2.0, radmarker)\n", - "\n", - " if plot_style == \"aescatter\":\n", - " pl = np.c_[d['a'].values,d['e'].values]\n", - " elif plot_style == \"aiscatter\":\n", - " pl = np.c_[d['a'].values,d['inc'].values]\n", - " elif plot_style == \"arotscatter\":\n", - " pl = np.c_[d['a'].values,d['rot_mag'].values]\n", - "\n", - " return t, npl, pl, radmarker, origin\n", - "\n", - " def update(self,frame):\n", - " \"\"\"Update the scatter plot.\"\"\"\n", - " t, npl, pl, radmarker, origin = self.get_data(framejump * frame)\n", - "\n", - " self.artists.title.set_text(f\"{titletext} - Time = ${t / 365.25:6.3f}$ years with ${npl:4.0f}$ particles\")\n", - "\n", - " for key,name in self.scatter_artist_names.items():\n", - " idx = origin == key\n", - " if any(idx) and any(~np.isnan(radmarker[idx])):\n", - " scatter = self.artists._asdict()[name]\n", - " scatter.set_sizes(radmarker[idx])\n", - " scatter.set_offsets(pl[idx,:])\n", - " scatter.set_facecolor(self.clist[key])\n", - "\n", - " return self.artists\n", - "\n", - "sim = swiftest.Simulation(simdir = \"\", read_data=True, read_collisions=False, dask=True)\n", - "for plot_style in valid_plot_styles:\n", - " animation_file = titletext+f\"-{plot_style}.mp4\"\n", - " print('Making animation')\n", - " anim = AnimatedScatter(sim.data,sim.param)\n", - " print('Animation finished')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading Swiftest file /scratch/bell/anand43/swiftest/haumea/param.in\n", - "\n", - "Creating Dataset from NetCDF file\n", - "Successfully converted 1 output frames.\n", - "\n", - "Creating Dataset from NetCDF file\n", - "Successfully converted 16 output frames.\n", - "Swiftest simulation data stored as xarray DataSet .data\n", - "Reading initial conditions file as .init_cond\n", - "Finished reading Swiftest dataset files.\n", - "number of bodies = 1001\n", - "[2.86707 2.26437611 3.6405438 3.93954489 2.94934881 3.08719425\n", - " 2.95619724 1.9315956 3.35814933 2.77744476 2.20363536 1.80574104\n", - " 2.71574397 3.49343986 2.03069888 3.5347133 2.46825806 2.71661343\n", - " 3.93758726 2.97675649 2.92302706 3.14238838 2.01017286 3.05107946\n", - " 2.9221084 3.83691596 2.32825779 2.63754725 3.33224001 2.45594668\n", - " 2.16867971 3.54655207 3.26450524 2.49896467 3.51590433 2.76106804\n", - " 1.9547691 2.74151039 3.94052577 2.13224769 3.36147178 2.53802787\n", - " 3.94673846 2.55988291 2.61847283 3.7620777 2.74105637 2.26478436\n", - " 1.81292722 2.76747095 2.29839042 3.80990784 3.62667666 3.71100367\n", - " 3.1725749 2.8574224 3.10210675 2.62842282 3.83353877 2.33035236\n", - " 3.6922478 2.22235092 3.15121301 2.77698703 2.5148019 2.91196748\n", - " 2.92627535 2.01706855 3.37747333 2.01111034 2.23898296 1.99306054\n", - " 1.90765108 3.2891204 3.25774258 2.30690781 3.24247923 3.49395891\n", - " 3.0314892 3.41474591 2.35703199 2.47902128 3.5086045 2.34151029\n", - " 3.12357904 3.57508057 1.92484951 1.88433176 2.95554871 3.92998504\n", - " 3.64213516 2.25213735 2.64555628 3.84748461 2.83338406 3.10835355\n", - " 3.65517402 1.90442769 3.08798552 2.61461352 2.98027672 2.07129231\n", - " 2.68607562 2.17261436 3.51264548 3.79854977 2.85469106 3.32746676\n", - " 2.01795376 3.78517184 2.20546773 3.86126769 2.95116322 2.8668133\n", - " 3.69375314 3.01422846 3.41030877 3.23427886 3.08542127 2.48789476\n", - " 1.9695036 3.16060334 1.93368786 2.89096413 2.45437467 3.4528045\n", - " 2.62510114 1.82658788 2.49568697 2.26774026 2.04158516 1.88707444\n", - " 3.09190663 3.98298489 2.38626218 3.91507248 1.81577043 3.79586533\n", - " 2.9173471 2.5917093 2.23717457 3.20106058 2.47275269 3.38695918\n", - " 2.89263554 3.24748083 3.94279254 3.15227637 2.87201905 3.88772146\n", - " 2.9251222 3.04232266 1.94950256 3.16333805 2.33424485 1.99481516\n", - " 3.54275327 3.08652743 2.84501543 3.7911194 3.02218081 3.84373384\n", - " 3.82582263 2.85336618 2.37761213 3.29034402 2.78529209 3.08157623\n", - " 2.93255092 2.66888596 3.20623023 3.12431925 2.57489376 2.91916641\n", - " 3.05397871 2.6213803 3.87089633 2.67114345 3.17434139 3.70503684\n", - " 2.36710633 3.0933641 3.50999258 3.63232575 2.62702814 3.44950602\n", - " 2.90155466 1.81862977 3.2113113 2.40571088 3.95325113 2.35675543\n", - " 2.81512142 2.98604457 2.65486392 2.8245242 3.25293944 2.77414958\n", - " 3.82444089 3.22822059 3.32508177 1.82926629 2.81615423 1.81170231\n", - " 3.2672492 3.66426422 3.79924248 3.05292133 2.41273786 1.93866512\n", - " 3.56331393 3.24915661 2.17261353 2.63877867 3.63978883 2.96951823\n", - " 3.02056263 3.53162077 3.29459515 1.8125504 3.26264535 3.26224581\n", - " 2.38075792 2.5874306 2.97279996 1.82845238 2.95132374 2.52939867\n", - " 2.72506068 3.07242353 3.06259972 3.76134273 2.45985533 2.85088455\n", - " 2.98108016 3.16893004 3.17572645 2.83419379 2.49490167 3.15893129\n", - " 2.55465139 3.21692659 3.65046901 2.54691214 3.92232599 1.90958515\n", - " 2.76641704 2.8996368 3.67097629 2.60807588 3.12486695 2.20398682\n", - " 2.51193867 3.03699266 3.34614604 3.47813301 2.48616203 2.95904923\n", - " 3.95076906 2.09013407 2.46546473 2.92228685 3.90430466 2.98769887\n", - " 3.86698362 1.9651921 3.53736777 3.78755373 3.87982806 1.80143241\n", - " 3.43573073 2.42122902 2.85072899 2.94483093 1.90562571 3.39627757\n", - " 3.88608514 2.97870912 2.15747184 2.59056916 1.97813882 3.76969048\n", - " 1.98673351 3.10073135 2.06670634 2.47180573 2.91704473 3.38474023\n", - " 3.59892043 3.54560466 3.22105973 2.45655225 3.76339075 3.63990026\n", - " 1.93323891 3.3077368 3.39426961 3.78948283 1.87036916 3.18943426\n", - " 2.06981414 3.20476601 1.89480136 3.30862502 3.00625902 3.10245457\n", - " 2.41632241 2.46760789 1.94693533 3.28405791 3.66079823 2.18920077\n", - " 2.67134882 2.06354222 2.11375689 3.64315927 3.96539447 2.58131973\n", - " 2.52675495 2.75691604 2.45845913 1.80666773 3.37788197 3.97650716\n", - " 1.8235495 2.87197387 2.26808226 3.10342701 3.89444171 2.35452286\n", - " 2.58154931 2.28054829 3.1362631 2.31722063 3.89073682 2.46557629\n", - " 2.41433102 2.31849176 3.85388787 3.83029776 2.22969765 2.83333593\n", - " 3.03842192 3.88408149 1.82667596 3.78208815 2.98501615 2.80479459\n", - " 2.96955749 2.22692875 3.00685847 2.11053991 3.03634502 3.99170556\n", - " 3.51732555 2.60407546 1.80112911 1.96796986 2.38454603 3.62566359\n", - " 3.9638863 2.33239881 3.46270587 3.42062892 2.05200829 3.71034592\n", - " 2.10742192 1.80845964 3.94865965 3.15339175 2.81418708 2.05396828\n", - " 2.39173238 2.12492795 2.45152201 3.867548 3.07707988 3.7839497\n", - " 3.60964604 3.18482216 2.43783162 3.68016789 2.23005874 3.56402737\n", - " 2.94331073 2.6951672 3.70254548 3.10568974 2.53914057 3.50781026\n", - " 2.10783249 2.72856534 2.70905719 3.38752398 2.74695416 2.44868168\n", - " 3.19457252 2.25116169 3.27183918 2.93629542 3.70012443 2.08910313\n", - " 1.85172104 1.80322834 2.93547433 2.33389348 3.74602895 3.98087291\n", - " 3.09040941 3.71433261 2.23642677 2.49318031 2.34909762 3.83081933\n", - " 2.499303 3.8342502 3.99044316 3.76237752 2.48457904 2.37214914\n", - " 1.98573256 1.89494674 2.21747754 2.1654547 3.22252898 3.54409441\n", - " 2.04831539 3.89704498 1.84586618 3.43563908 2.26839343 3.95813064\n", - " 1.99456985 3.58463229 1.82591801 2.38386884 2.7182952 2.89195448\n", - " 3.23887658 3.03382594 3.09723279 2.19107386 3.99924422 3.83343698\n", - " 2.60833875 2.72747379 2.39127566 3.72958697 2.09058244 2.58853849\n", - " 3.94192955 2.35107722 2.87111745 2.4799833 3.46839085 2.3263921\n", - " 2.91418045 2.1592128 2.52342638 2.99301811 2.66753894 2.85138794\n", - " 2.31609956 3.63879729 1.82785488 2.52281426 2.31571043 2.73430988\n", - " 2.03591542 3.57678249 3.9467535 2.40015656 3.21001766 1.95069303\n", - " 3.76710942 2.94092702 3.59669815 2.55784566 2.73363482 2.7431271\n", - " 2.88747775 3.29540831 3.5841192 2.10522076 1.93837456 3.39399095\n", - " 3.17707757 2.63953918 3.01295314 1.95973882 1.98780649 2.18197849\n", - " 3.81403775 3.54935395 3.78923295 3.76379051 2.38450664 3.04698007\n", - " 2.45577138 2.88636479 2.33312543 2.74517056 2.29531488 3.57665951\n", - " 2.96855176 2.45710483 2.85845093 2.04415776 3.55368151 1.95701192\n", - " 3.59110225 3.68504318 3.20134106 2.27306975 3.78164712 2.92344475\n", - " 2.39614455 3.67152363 3.98144479 2.06543455 2.42466762 2.30068764\n", - " 1.93226954 3.64158746 3.75782464 3.18548846 1.8167459 3.67493525\n", - " 3.63721934 3.91427937 1.86744532 3.70223565 2.23369345 2.52431285\n", - " 2.98225363 2.17265534 2.67917271 2.62715229 3.93284723 2.51821012\n", - " 3.53714754 3.38447755 3.04831115 2.81751676 2.83742262 3.72240774\n", - " 2.69589499 2.44771722 3.56481535 3.97168904 3.97450669 3.32535339\n", - " 2.2380867 3.96860887 3.10118483 2.28384777 3.99534556 2.81954312\n", - " 3.48427296 2.10313325 3.14784073 2.27634883 2.56291701 3.25150434\n", - " 2.80893276 2.76251536 3.0881402 3.58281511 3.00737753 3.40792374\n", - " 3.86495002 3.18281984 3.61989202 2.59449528 3.37882132 2.04958984\n", - " 3.84105445 3.00721393 1.94106032 2.187152 3.22459746 2.17636862\n", - " 2.60611682 1.80062892 3.50569036 2.82453039 1.97646818 3.35170039\n", - " 2.83263403 3.18868638 2.91313879 3.14404854 2.41328239 3.20123104\n", - " 3.69885294 3.30177181 1.99099318 3.57844773 2.53213969 2.97900973\n", - " 3.55369678 3.34219435 3.08626794 2.39239569 3.42891466 2.95054151\n", - " 3.83927607 1.8605209 3.72710113 3.72464167 2.9484406 3.08286897\n", - " 3.09456901 3.49361857 2.63007237 2.88181073 3.31759219 1.8136873\n", - " 3.51587449 1.88055712 2.27291034 2.61512479 2.21706371 3.88106042\n", - " 3.36743163 3.20090707 2.56376552 3.39817264 2.10839002 2.58872065\n", - " 3.81129539 3.96253473 3.43698527 2.92952744 2.71526314 3.03716288\n", - " 1.91486291 3.08129312 2.98193717 2.39349587 3.99411614 1.93554448\n", - " 3.71261072 2.46968171 2.01140301 2.646433 2.88644449 2.25227174\n", - " 2.72064543 3.30272203 3.25046027 2.73967233 1.91165722 2.90768238\n", - " 1.86529355 2.96070399 2.77314104 3.72156093 3.24757593 3.21269682\n", - " 3.59713754 1.93076813 2.03294904 3.98167812 2.57785141 3.74349092\n", - " 1.92491038 3.68708838 3.25856293 3.19631964 3.14665325 2.62639443\n", - " 2.3519243 3.55784453 2.31817522 3.92597621 3.40730456 3.80860323\n", - " 1.88132235 2.68782942 2.01852222 3.47610733 2.36079137 1.9152418\n", - " 2.50151756 3.34228421 3.27762915 3.96814843 3.20270105 3.59971596\n", - " 3.23440836 3.41171567 2.90759424 2.09586371 2.76016933 2.73706659\n", - " 2.56430649 1.91228857 3.13940309 1.99505674 2.4495765 2.73543595\n", - " 2.30020448 2.88536265 3.68797496 2.51733565 2.07561723 3.19322504\n", - " 3.4988761 3.45408619 3.65600111 2.0457678 3.24858436 3.46355762\n", - " 2.46219727 2.06914063 2.11572774 2.31653463 3.04936642 3.92949049\n", - " 2.54717756 3.55758675 3.09722771 3.96115502 3.60451308 3.55259832\n", - " 3.19157466 3.26707393 2.30452338 3.82926449 2.70137852 3.32993463\n", - " 2.35270965 3.65899762 2.44267372 2.17109822 2.88132051 3.69422536\n", - " 3.66478365 3.04108579 3.95722544 3.86754083 3.9452419 3.97303988\n", - " 2.66637405 2.703648 2.01049446 2.56522475 3.20930447 3.37231218\n", - " 1.80665703 2.34981361 2.09583017 3.61212815 3.67365765 2.26366423\n", - " 2.76547929 3.32779797 3.99094811 2.33452816 2.79944165 3.01708238\n", - " 2.51050538 3.8618905 2.4355322 2.95129246 3.79840371 2.36200969\n", - " 2.05297058 1.91790903 2.42212044 2.44991786 2.07671169 3.29651237\n", - " 3.02724494 2.14206015 3.60893401 3.39960394 3.79869304 2.89272848\n", - " 3.84640706 2.28135138 2.39743776 2.54691734 1.84793483 3.9941595\n", - " 3.79309174 2.56536888 2.7670722 2.78647629 2.46724476 3.60274147\n", - " 3.83808844 2.08904839 2.10507857 2.13993358 2.26780496 2.41006664\n", - " 3.38797231 3.68618741 3.87216351 3.50803263 3.60099257 1.84205323\n", - " 2.33480771 2.13537323 2.6844391 3.86176135 3.19226279 3.22994065\n", - " 3.26581745 2.13998923 2.95792414 3.67193679 2.17423711 2.36280443\n", - " 2.07320183 3.76343418 2.33929475 2.12256853 3.61380039 2.8397601\n", - " 2.51283272 2.40853597 3.10570901 3.76907137 3.81436411 3.08522357\n", - " 1.87052446 2.65874975 1.83167597 3.29162079 2.96645609 3.46543259\n", - " 2.36287837 1.93341339 3.25257021 2.86125788 2.55045433 3.19096205\n", - " 2.24275342 1.96898378 2.41902642 3.24559458 2.09302917 3.06796238\n", - " 1.8595801 3.57768904 3.79539807 3.31841467 3.84063807 2.54290415\n", - " 3.9964343 2.65958935 2.43079074 1.92168518 3.34742871 2.93598793\n", - " 3.88435081 2.19268651 3.68853517 3.21140077 2.82282989 2.88055579\n", - " 2.23598795 2.27071968 3.15294119 1.99187389 2.96157153 3.35418985\n", - " 2.60196447 3.92242802 2.11143474 2.88154167 2.62208341 2.00842219\n", - " 2.20177275 3.63912038 2.15842531 2.176082 2.2979445 2.63698812\n", - " 3.631226 2.37458011 2.76343393 2.81399883 1.87149717 2.08717025\n", - " 2.70466618 2.01076977 2.32513266 3.87136979 3.41143461 3.4436919\n", - " 2.22666205 3.39007452 2.51170985 2.70019198 2.9332926 2.76436306\n", - " 3.45840216 2.04462722 3.88097606 2.80816941 3.72714885 2.65577947\n", - " 3.0420142 2.39700357 2.49124778 2.28532874 3.35348657 3.55607459\n", - " 3.85484511 2.36635014 2.078835 1.97163928 3.3332229 3.25306239\n", - " 2.24946841 2.14731298 2.46008678 2.76557381 3.72928254 2.98678591\n", - " 2.29296018 2.55564527 2.45633322 3.73649969 3.40508584 1.91503421\n", - " 2.80703053 2.9436633 3.86673948 2.82083929 3.48102901 1.81771352\n", - " 3.41822223 2.8824315 2.62430958 1.91248179 2.77392087 3.71577566\n", - " 3.50027084 2.78720951 3.40126586 3.72384478 3.8499088 3.6974411\n", - " 3.87919812 3.41157506 3.37837488 3.42786854 2.80472621 2.39567393\n", - " 3.69122758 2.52232265 3.81514334 2.18473321 2.99300448 3.23635012\n", - " 2.71998862 3.79243906 3.07194063 3.58787382 3.97846799 3.8784\n", - " 3.79397454 2.26333523 2.41389923 2.55515131 2.64889664 3.66548684\n", - " 3.55362427 3.36000855 3.2232391 3.38112289 3.73708105 3.50241592\n", - " 2.03974955 2.29111594 2.74884721 2.81526728 3.4725525 1.85137256\n", - " 2.83037433 3.65856226 2.43504443 2.82765201 2.00917454 2.86610845\n", - " 3.04238655 2.22190092 3.03751911 2.16339026 2.07270532 3.15675046\n", - " 2.37574886 3.33400854 1.9299132 3.27721295]\n" - ] - } - ], - "source": [ - "# Plot inital a vs e to see initial conditions\n", - "sim = swiftest.Simulation(simdir = \"\", read_param=True, read_collisions=False)#, dask=True)\n", - "\n", - "d = sim.data.isel(time = 0)\n", - "n=len(d['name'])\n", - "d = d.isel(name=range(1,n))\n", - "\n", - "a = d['a'].values\n", - "e = d['e'].values\n", - "inc = d['inc'].values\n", - "\n", - "fig, ax = plt.subplots(figsize=(8,4.5), dpi=300)\n", - "\n", - "print(f\"number of bodies = {n}\")\n", - "print(a)\n", - "# print(e)\n", - "\n", - "plt.scatter(a, e)\n", - "plt.xlabel('a')\n", - "plt.ylabel('e')\n", - "plt.savefig(\"a_vs_e_init.png\")\n", - "\n", - "plt.clf()\n", - "plt.scatter(a, inc)\n", - "plt.xlabel('a')\n", - "plt.ylabel('inc')\n", - "plt.savefig(\"a_vs_i_init.png\")\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'inc' (name: 1001)>\n",
-       "array([        nan, 10.17878648,  9.06981385, ...,  7.7303241 ,\n",
-       "        6.73890149,  9.62794807])\n",
-       "Coordinates:\n",
-       "    time     float64 0.0\n",
-       "  * name     (name) <U32 'Centaur' '100' '101' '102' ... '1097' '1098' '1099'\n",
-       "Attributes:\n",
-       "    _FillValue:  nan
" - ], - "text/plain": [ - "\n", - "array([ nan, 10.17878648, 9.06981385, ..., 7.7303241 ,\n", - " 6.73890149, 9.62794807])\n", - "Coordinates:\n", - " time float64 0.0\n", - " * name (name) dt_max): -# print("dt is TOO BIG!") -# raise Exception - -# set up swiftest simulation - -sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e7, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", MU = 'kg', DU2M = 1e3, TU = 'd', rmin = earth_radius) -# sim.add_solar_system_body(["Earth"], date = ephemerides_start_date) - -# Manually add Earth as a CB because no J2 or J4 term is added otherwise -sim.add_body(name = "Earth", id = 1, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, mass = earth_mass, radius = earth_radius, J2 = earth_J2 * earth_radius**2, J4 = earth_J4 * earth_radius**4, rot = earth_rot) - -# sim.add_body(name = 'Centaur', id = 1, mass = density * volume, radius = radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0) - -sim.add_body(name = "Moon", id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius) - -sim.write_param() -sim.save() -# sim.run() - -print(f'total number of steps ={int(tstop / dt)}') -# J2 = sim.init_cond.isel(name = 0)['j2rp2'].values -# print(f'J2 in init_cond = {J2}') -# d = sim.data.isel(name = 0) -# J2 = d['j2rp2'].values -# print(f'J2 for central body = {J2}') -print(f'lon_asc_node = {random_capom}') -print(f'arg_peri = {random_omega}') -print(f'inclination = {random_i}') -print(f'mean anomaly = {random_capm}') -print(f'earth rot = {earth_rot}') diff --git a/setup_sim_ring_capture.py b/setup_sim_ring_capture.py deleted file mode 100644 index 77410955e..000000000 --- a/setup_sim_ring_capture.py +++ /dev/null @@ -1,246 +0,0 @@ -import numpy as np -import swiftest -import matplotlib.pyplot as plt -from mpl_toolkits.mplot3d import axes3d -import pandas as pd -from astropy import constants as const - -seed = None -rng = np.random.default_rng(seed=seed) -n_bodies = int(1e4) # number of planet bodies -array_shift = np.random.randint(0, n_bodies) -tstop = 100 # rotation periods -dt = 1.0e-4 -dt_unit = 'Haumea_rot_period' -# dt_unit = 'd' -dt_max = 0 -G = 6.6743e-11 # SI Units -scratch_dr = '/scratch/bell/anand43/swiftest_runs/' -body_dr = 'Haumea/' -simdir = 'moons' # '2e3_part_radial' -simdir = scratch_dr + body_dr + simdir - -# initial central body parameters -# Haumea parameters taken from P. S. Jean Carvalho (2019) - -cb_mass = 4.006e21 # kg -cb_radius = 711.9097e3 # m -T_rotation = 3.915341 * 60 * 60 # hours to sec - -mass = cb_mass / cb_mass -radius = cb_radius / cb_radius -longest_axis = 1161e3 # m -rmin = longest_axis / cb_radius -volume = 4.0 / 3.0 * np.pi * radius**3 -density = mass / volume -rot = 2 * np.pi / T_rotation # rad/s -rot = [[0, 0, rot]] -J2 = 0.305 -J4 = -0.216 -print(f'R_min = {rmin}') - -# moons parameters -# values taken from JPL Horizons - -moon_name = ['Hi\'iaka', 'Namaka'] -moon_id = np.arange(10, len(moon_name) + 10, step = 1) -moon_mass = np.array([1.151e9, 0.036e9]) / const.G / cb_mass -moon_radius = np.array([160e3, 85e3]) / cb_radius -moon_rh = np.array([[-2.3446616e7, -3.6088243e7, -2.9864834e7], [-8.6355596e6, 1.5824178e7, 2.4140061e7]]) / cb_radius -moon_vh = np.array([[-5.6613699e1, 3.5390515e0, 3.8830064e1], [6.6949687e1, 5.157315e1, -1.0614025e1]]) / cb_radius * T_rotation -moon_T_rotation = np.array([9.8, np.inf]) * 60 * 60 # h to seconds -moon_rot = [] -for i in range(len(moon_T_rotation)): - moon_rot.append([0, 0, 2 * np.pi / moon_T_rotation[i]]) # rad/s - -# set up swiftest simulation - -sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e4, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", rmin = rmin, rmax = 50 * rmin, MU2KG = cb_mass, DU2M = cb_radius, TU2S = T_rotation, init_cond_format = 'XV') # TU = dt_unit, MU_name = 'M_Haumea', DU_name = 'R_Haumea' - -#initial ring particle orbital parameters - -id_start = 100 # starting ID for bodies - -random_radius = rng.random(n_bodies) * (500 - 100) + 100 # randomize the radii of the ring particles between 100 and 500 (m) -random_radius = random_radius / sim.DU2M -random_mass = np.power(random_radius, 3) * 4.0 * np.pi / 3.0 * density # randomize the mass - -z_sign = rng.random(n_bodies) - 0.5 # randomize the sign of the z-component - -# set up the position vectors -random_pos_mag = (rng.random(n_bodies) * (3 - 1.65) + 1.65) # randomize the distance/position vector(s) between 1.65 and 3 (R_Haumea) -random_phi = np.deg2rad((rng.random(n_bodies)) * (60.0) + 90.0) # cone of spilled regolith -random_theta = np.deg2rad((rng.random(n_bodies)) * (120.0 - 60) + 60) # equatorial zone -x = random_pos_mag * np.sin(random_theta) * np.cos(random_phi) -y = random_pos_mag * np.sin(random_theta) * np.sin(random_phi) -z = random_pos_mag * np.cos(random_theta) * np.sign(z_sign) -random_pos_vec = np.array([x, y, z]).T - -# set up the velocity vectors (pointing radially away from the central body if needed) - -# Radial Velocity -v_escape = np.sqrt(2 * sim.GU * mass / radius) -alpha = rng.random(n_bodies) * (0.95 - 0.8) + 0.8 # numerical scaling for initial velocity -random_vel_mag = np.sqrt(alpha * v_escape**2 + 2 * sim.GU * mass * (1 / random_pos_mag - 1 / radius)) # scale the velocity with distance - -# # Tangential velocity -# # random_vel_mag = np.sqrt(mass * sim.GU / random_pos_mag) * (rng.random(n_bodies) * (1.15 - 0.85) + 0.85) # randomize the velocity by 0.9 - 1.1 times the keplerian velocity - -# v_orbital = np.sqrt(sim.GU * mass / (radius + np.average(random_pos_mag))) -# alpha = rng.random(n_bodies) * (1.1 - 0.85) + 0.85 # numerical scaling for initial velocity -# random_vel_mag = np.sqrt(alpha * v_orbital) - -x = x * random_vel_mag / random_pos_mag -y = y * random_vel_mag / random_pos_mag -z = z * random_vel_mag / random_pos_mag - -# rotate the velocity vectors (degrees) - # 85 - 95 degrees to represent orbiting particles for tangential motion -angle = 0.0 -range = 40 -rot_angle = np.deg2rad(rng.random(n_bodies) * (range) + (angle - range/2)) # rotate by "angle" degrees randomly with a "range" variation about the "angle" - -x_tmp = x -y_tmp = y - -x = x_tmp * np.cos(rot_angle) - y_tmp * np.sin(rot_angle) -y = x_tmp * np.sin(rot_angle) + y_tmp * np.cos(rot_angle) - -random_vel_vec = np.array([x, y, z]).T - -print(f'Shape of pos vec = {random_pos_vec.shape}') -print(f'Shape of vel vec = {random_vel_vec.shape}') - -# random_rot = 0 * [0, 0, 1.0] * rng.random(n_bodies) # rad/s -# CHECK and FIX random_rot (sequence multiplication issue) - -ring_mass_tot = np.sum(random_mass) - -print(f'Total ring mass = {ring_mass_tot} M_Haumea') -print(f'sim.GU = {sim.GU}') - -sim.add_body(name = 'Centaur', id = 0, mass = mass, rot = rot, radius = radius, rh=[np.array([0,0,0])], vh = [np.array([0,0,0])], J2 = J2 * radius**2, J4 = J4 * radius**4) -sim.add_body(name = moon_name, id = moon_id, mass = moon_mass, rot = moon_rot, radius = moon_radius, rh = moon_rh, vh = moon_vh) -sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), mass = random_mass, radius = random_radius, rh = random_pos_vec, vh = random_vel_vec)#, rot = random_rot) - -# check that dt < dt_max - -dt_max = 2.0 * np.pi / np.sqrt(sim.GU * mass) -dt_max = dt_max * np.power(np.min(random_pos_mag), 3/2) -dt_max = dt_max / 10.0 # in time units - -print(f'\ndt_max = {dt_max} {dt_unit}') -print(f'Current dt = {dt} {dt_unit}\n') - -if(dt > dt_max): - print("dt is TOO BIG!") - raise Exception - -sim.write_param() -sim.save() -print(f'\nsim.GU after save() and write_param() = {sim.GU}') -# sim.run() - -# Edit param.in for ascii only keywords - -param = pd.read_csv(simdir + '/param.in', sep = '\t') - -# make QMIN = -1.0 -param.loc[9][0] = param.loc[9][0][0:-17] + '-1.0' - -# make QMIN_RANGE start at -1.0 -param.loc[23][0] = param.loc[23][0][0:-34] + '-1.0' + param.loc[23][0][-17:] - -# export new param.in -param.to_csv(simdir + '/param.in', sep = '\t', index = False) - -# Make initial plots - -fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) - -plt.scatter(np.linalg.norm(sim.data.isel(time = 0)['rh'], axis = 1), np.linalg.norm(sim.data.isel(time = 0)['vh'], axis = 1)) -plt.xlabel('rh') -plt.ylabel('vh') -# plot longest axis -cb_ax_long = rmin -ymin = np.min(random_vel_mag) -ymax = v_escape + 2 #np.max(random_vel_mag) -plt.ylim([0, ymax]) -plt.xlim([0, np.max(random_pos_mag) + 2]) -plt.plot([cb_ax_long, cb_ax_long], [0, ymax], '-', color = 'orange') -plt.text(cb_ax_long + 0.1, ymax / 5, s = r'Longest CB Axis', color = 'orange', rotation = 'vertical') -plt.plot([-7, 7], [v_escape, v_escape], '-', color = 'black') -# plt.text(1, v_escape + 0.5, s = 'Escape Velocity', color = 'black') - -plt.savefig(simdir + '/r_vs_v_initial.png') - -plt.clf() -fig = plt.figure(dpi = 300) -ax = fig.add_subplot(projection = '3d') -ax.scatter(random_pos_vec[:, 0], random_pos_vec[:, 1], random_pos_vec[:, 2], marker = 'o') -ax.set_xlabel('x') -ax.set_ylabel('y') -ax.set_zlabel('z') -ax.set_zlim([-5, 5]) -ax.set_xlim([-5, 5]) -ax.set_ylim([-5, 5]) -plt.savefig(simdir + '/pos_vector.png') - -ax.view_init(elev = 0, azim = 0) -plt.savefig(simdir + '/pos_vector_eq.png') - -ax.view_init(elev = 90, azim = 0) -plt.savefig(simdir + '/pos_vector_top.png') - - -# Extra code - -# random_2pi = 360 * np.random.rand(n_bodies) # 360 degrees -# random_pi = 180 * np.random.rand(n_bodies) # 180 degrees -# random_a = (rng.random(n_bodies) * (4 - 1.65) + 1.65) # randomize the semi-major axis between 1.65 and 4 (Haumea Radii) -# # Haumea's longest axis = 1.63 * R_Haumea (1161 km = 1.63 * 711.9097 km) -# random_e = rng.random(n_bodies) * 0.8 # randomize eccentricity between 0 and 0.8 -# random_i = np.random.rand(n_bodies) * (30 - (-30)) + (-30) # between (-30, 30) (degrees) (equatorial zone) -# random_capom = random_2pi -# random_omega = np.roll(random_2pi, array_shift) -# array_shift = np.random.randint(0, n_bodies) # compute another random shift -# random_capm = np.roll(random_2pi, array_shift) - - - -# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) - -# plt.scatter(sim.data['a'], sim.data['e']) -# plt.xlabel('a') -# plt.ylabel('e') -# plt.savefig(simdir + '/a_vs_e_initial.png') - -# fig, ax = plt.subplots(figsize=(8,4.5), dpi=300) - -# plt.scatter(sim.data['a'], sim.data['inc']) -# plt.xlabel('a') -# plt.ylabel('inc') -# plt.savefig(simdir + '/a_vs_i_initial.png') - -# print(f'sim.MU2KG = {sim.MU2KG}') -# print(f'sim.param["MU2KG"] = {sim.param["MU2KG"]}') -# print(f'sim.MU_name = {sim.MU_name}') -# sim.add_solar_system_body(["Sun", "Mercury", "Venus", "Earth", "Mars"]) -# random_radius = random_radius / sim.DU2M -# random_mass = random_mass / sim.MU2KG -# sim.add_body(name = 'Centaur', id = 0, mass = mass / mass, rot = rot, radius = radius / radius, a = 0, e = 0, inc = 0, capom = 0, omega = 0, capm = 0, J2 = J2, J4 = J4) -# sim.add_body(name = np.arange(id_start, n_bodies + id_start, step = 1), id = np.arange(id_start, n_bodies + id_start, step = 1), a = random_a, e = random_e, inc = random_i, capom = random_capom, omega = random_omega, capm = random_capm, mass = random_mass, radius = random_radius)#, rot = random_rot) - -# sim = swiftest.Simulation(simdir = simdir, integrator = "symba", tstop = tstop, dt = dt, istep_out = 1e5, dump_cadence = 10, rotation = True, collision_model = "FRAGGLE", TU = dt_unit, rmin = rmin, MU2KG = mass, DU2M = radius, init_cond_format = 'XV',)# MU_name = 'M_Haumea', DU_name = 'R_Haumea') - -# # unit conversion factors -# S2DAY = 1 / (60.0 * 60 * 24) -# S2YR = S2DAY / 365.25 -# KG2MSUN = 1 / 1.98847e30 -# M2AU = 1 / 1.496e11 - -# x = random_vel_mag * np.sin(random_theta) * np.cos(random_phi) -# y = random_vel_mag * np.sin(random_theta) * np.sin(random_phi) -# z = random_vel_mag * np.cos(random_theta) * np.sign(z_sign) - -# random_vel_mag = np.sqrt(2 * mass * sim.GU / radius) * (rng.random(n_bodies) * (0.4 - 0.0) + 0.0) # randomize the velocity by 0.0 - 0.4 times the escape velocity From 156556d50b118475d292f391110f6006a638d817 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 26 Jun 2023 15:10:47 -0400 Subject: [PATCH 020/324] started python functions for spherical harmonics --- .../swiftest/sph_harmonics_gravity.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 python/swiftest/swiftest/sph_harmonics_gravity.py diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py new file mode 100644 index 000000000..484cee84c --- /dev/null +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -0,0 +1,45 @@ +""" + Copyright 2023 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, Dana Singh, & Kaustub Anand + This file is part of Swiftest. + Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with Swiftest. + If not, see: https://www.gnu.org/licenses. +""" + +# python functions to read in and set up spherical harmonics coefficients for non-standard gravity terms +# using pySHTOOLS (in python) by Mark W. +# + +import swiftest +import numpy as np +from astroquery.jplhorizons import Horizons +import astropy.units as u +from astropy.coordinates import SkyCoord +import datetime +import xarray as xr +import pyshtools as pysh +from typing import ( + Literal, + Dict, + List, + Any +) + +def clm_from_ellipsoid(): + """ + Initializes a Swiftest dataset containing the major planets of the Solar System at a particular data from JPL/Horizons + + Parameters + ---------- + param : dict + Swiftest paramuration parameters. This method uses the unit conversion factors to convert from JPL's AU-day system into the system specified in the param file + ephemerides_start_date : string + Date to use when obtaining the ephemerides in the format YYYY-MM-DD. + + Returns + ------- + ds : xarray dataset + """ \ No newline at end of file From 1c12eacafd19afd1eb1b3a7efc1269445b16f540 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 26 Jun 2023 17:12:47 -0400 Subject: [PATCH 021/324] Wrote a function to calculate the grav clm values for an ellipsoid --- .../swiftest/sph_harmonics_gravity.py | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index 484cee84c..52bdbe9c4 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -28,18 +28,49 @@ Any ) -def clm_from_ellipsoid(): +def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): """ - Initializes a Swiftest dataset containing the major planets of the Solar System at a particular data from JPL/Horizons + Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. Uses pyshtools. + No units necessary for a, b, & c. However, they need to be in the same units (DU). Parameters ---------- - param : dict - Swiftest paramuration parameters. This method uses the unit conversion factors to convert from JPL's AU-day system into the system specified in the param file - ephemerides_start_date : string - Date to use when obtaining the ephemerides in the format YYYY-MM-DD. + lmax : int + The maximum spherical harmonic degree resolvable by the grid. + mass : float + mass of the central body + density : float + density of the central body + a : float + length of the pricipal axis aligned with the x axis + b : float, optional, default = a + length of the pricipal axis aligned with the y axis + c : float, optional, default = b + length of the pricipal axis aligned with the z axis Returns ------- - ds : xarray dataset - """ \ No newline at end of file + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + G = swiftest.constants.GC + Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass + # FIND A BETTER WAY TO CHANGE UNITS + + # cap lmax to 20 to ensure fast performance + lmax_limit = 20 + if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # create shape grid and convert to Spherical Harmonics (.expand()) + shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c).expand() + + # get coefficients + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) + clm = clm_class.to_array() + + return clm \ No newline at end of file From 9fb991134cc0c65aa387d2026cb409d0f25f9345 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 26 Jun 2023 17:29:05 -0400 Subject: [PATCH 022/324] added function for general surface relief grids too --- .../swiftest/sph_harmonics_gravity.py | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index 52bdbe9c4..7ba6a6be5 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -30,8 +30,8 @@ def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): """ - Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. Uses pyshtools. - No units necessary for a, b, & c. However, they need to be in the same units (DU). + Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. + Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). Parameters ---------- @@ -73,4 +73,49 @@ def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) clm = clm_class.to_array() + return clm + +def clm_from_relief(lmax, mass, density, grid): + """ + Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. + Uses pyshtools. + + Parameters + ---------- + lmax : int + The maximum spherical harmonic degree resolvable by the grid. + mass : float + mass of the central body + density : float + density of the central body + grid : array, shape [] + DH grid of the surface relief of the body + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + + G = swiftest.constants.GC + Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass + # FIND A BETTER WAY TO CHANGE UNITS + + # cap lmax to 20 to ensure fast performance + lmax_limit = 20 + if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # convert to spherical harmonics + shape_SH = pysh.SHGrid.from_array(grid).expand() + # shape_SH = SHExpandDH(grid) + + # get coefficients + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) + clm = clm_class.to_array() + return clm \ No newline at end of file From b564e69fcfa448bf7332c5d6504515274f813060 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 26 Jul 2023 13:15:06 -0400 Subject: [PATCH 023/324] started work on coding spherical harmonics for gravitational acceleration --- src/swiftest/swiftest_sph.f90 | 106 ++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/swiftest/swiftest_sph.f90 diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 new file mode 100644 index 000000000..8335d6989 --- /dev/null +++ b/src/swiftest/swiftest_sph.f90 @@ -0,0 +1,106 @@ +!! Copyright 2022 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh +!! This file is part of Swiftest. +!! Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +!! as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +!! Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +!! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +!! You should have received a copy of the GNU General Public License along with Swiftest. +!! If not, see: https://www.gnu.org/licenses. + + +!! Swiftest submodule to calculate higher order terms for gravitational acceleration given spherical harmonic coefficients (c_lm) + +submodule (swiftest) s_swiftest_sph +use swiftest +use operators + +contains + + module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) + !! author: Kaustub P. Anand + !! + !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r + !! + + implicit none + ! Arguments + real(DP), intent(in) :: gm !! GMass of the central body + real(DP), intent(in) :: r_0 !! radius of the central body + real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) + real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) + real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body + real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + + ! Internals + integer :: l, m !! SPH coefficients + real(DP) :: r_mag !! magnitude of rh + + r_mag = sqrt(dot_product(rh(:), rh(:))) + + ! WHAT DO I DO WITH THE COMPLEX TERM???? + + do l = 1, l_max + do m = 1, l + + swiftest_sph_dylm_dtheta(ylm, ylm1, theta, phi, l, m, dylm_dtheta, dyl_m_dtheta) + ! m > 0 + g_sph(1) += gm * r_0**l / r_mag**(l + 1) * c_lm[0, l, m] * (dylm_dtheta / (rh(3) * cos(phi)) - (l + 1) * rh(1) * ylm / r_mag**2 - i * m * ylm / rh(2)) ! i = sqrt(-1) + g_sph(2) += gm * r_0**l / r_mag**(l + 1) * c_lm[0, l, m] * (dylm_dtheta / (rh(3) * sin(phi)) - (l + 1) * rh(2) * ylm / r_mag**2 + i * m * ylm / rh(1)) + g_sph(3) += gm * r_0**l / r_mag**(l + 1) * c_lm[0, l, m] * (dylm_dtheta / sqrt(rh(1)**2 + rh(2)**2) - (l + 1) * rh(3) * ylm / r_mag**2) + + ! m < 0 + g_sph(1) += gm * r_0**l / r_mag**(l + 1) * c_lm[1, l, m] * (dyl_m_dtheta / (rh(3) * cos(phi)) - (l + 1) * rh(1) * ylm * (-1)**m / r_mag**2 - i * m * ylm / rh(2)) ! i = sqrt(-1) + g_sph(2) += gm * r_0**l / r_mag**(l + 1) * c_lm[1, l, m] * (dyl_m_dtheta / (rh(3) * sin(phi)) - (l + 1) * rh(2) * ylm * (-1)**m / r_mag**2 + i * m * ylm / rh(1)) + g_sph(3) += gm * r_0**l / r_mag**(l + 1) * c_lm[1, l, m] * (dyl_m_dtheta / sqrt(rh(1)**2 + rh(2)**2) - (l + 1) * rh(3) * ylm * (-1)**m / r_mag**2) + + end do + end do + + return + end subroutine swiftest_sph_g_acc_one + + module subroutine swiftest_sph_g_acc_all() + !! author: Kaustub P. Anand + !! + !! Calculate the acceleration terms for all bodies given c_lm + !! + + end subroutine swiftest_sph_g_acc_all + + module subroutine swiftest_sph_dylm_dtheta(ylm, ylm1, theta, phi, l, m, dylm_dtheta, dyl_m_dtheta) + !! author: Kaustub P. Anand + !! + !! Calculate the derivative of Y_lm with respect to theta dY_lm / dtheta term + !! + + ! Arguments + real(DP), intent(in) :: ylm ! Y_l,m + real(DP), intent(in) :: ylm1 ! Y_l,m+1 + real(DP), intent(in) :: theta ! Zenith angle + real(DP), intent(in) :: phi ! Azimuthal angle + integer, intent(in) :: l, m ! spherical harmonics numbers + real(DP), intent(out) :: dylm_dtheta ! derivative for +m + real(DP), intent(out) :: dyl_m_dtheta ! derivative for -m + + + ! Internals + + dylm_dtheta = m * cotan(theta) * ylm + sqrt((l - m) * (l + m + 1)) * ylm1 * exp(i * phi) + dyl_m_dtheta = -m * cotan(theta) * ylm * (-1)**m + sqrt((l + m) * (l - m + 1)) * ylm1 * exp(i * phi) + + return + end subroutine swiftest_sph_dylm_dtheta + + module subroutine swiftest_sph_ylm(l, m, phi, theta) + !! author: Kaustub P. Anand + !! + !! Calculate the Y_lm for a given l, m, phi, and theta + !! + + integer, intent(in) :: l, m ! spherical harmonics numbers + real(DP), intent(in) :: theta ! Zenith angle + real(DP), intent(in) :: phi ! Azimuthal angle + + return + end subroutine swiftest_sph_ylm \ No newline at end of file From 6bee96a8ea2d7726cf93ea73106091d699a50ebc Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Fri, 4 Aug 2023 12:09:51 -0400 Subject: [PATCH 024/324] Edited the normalization for C_lm. Rewrite the g formula --- .../swiftest/sph_harmonics_gravity.py | 4 +- src/swiftest/swiftest_sph.f90 | 58 ++++++++++++------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index 7ba6a6be5..98a4c8692 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -70,7 +70,7 @@ def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c).expand() # get coefficients - clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization clm = clm_class.to_array() return clm @@ -115,7 +115,7 @@ def clm_from_relief(lmax, mass, density, grid): # shape_SH = SHExpandDH(grid) # get coefficients - clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization clm = clm_class.to_array() return clm \ No newline at end of file diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 8335d6989..a620317e1 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -13,10 +13,11 @@ submodule (swiftest) s_swiftest_sph use swiftest use operators +use SHTOOLS contains - module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) + module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph, l_max) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -24,35 +25,43 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) implicit none ! Arguments - real(DP), intent(in) :: gm !! GMass of the central body - real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) - real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) - real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body - real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), intent(in) :: gm !! GMass of the central body + real(DP), intent(in) :: r_0 !! radius of the central body + real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) + real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) + real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body + real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector ! Internals - integer :: l, m !! SPH coefficients - real(DP) :: r_mag !! magnitude of rh + integer :: l, m !! SPH coefficients + real(DP) :: r_mag !! magnitude of rh + real(DP) :: p !! Associated Lengendre Polynomials at a given cos(theta) + integer :: l_max !! max Spherical Harmonic l order value r_mag = sqrt(dot_product(rh(:), rh(:))) - - ! WHAT DO I DO WITH THE COMPLEX TERM???? + l_max = size(c_lm, 2) + PlBar(p, lmax, cos(theta)) ! Associated Legendre Polynomials do l = 1, l_max do m = 1, l - swiftest_sph_dylm_dtheta(ylm, ylm1, theta, phi, l, m, dylm_dtheta, dyl_m_dtheta) - ! m > 0 - g_sph(1) += gm * r_0**l / r_mag**(l + 1) * c_lm[0, l, m] * (dylm_dtheta / (rh(3) * cos(phi)) - (l + 1) * rh(1) * ylm / r_mag**2 - i * m * ylm / rh(2)) ! i = sqrt(-1) - g_sph(2) += gm * r_0**l / r_mag**(l + 1) * c_lm[0, l, m] * (dylm_dtheta / (rh(3) * sin(phi)) - (l + 1) * rh(2) * ylm / r_mag**2 + i * m * ylm / rh(1)) - g_sph(3) += gm * r_0**l / r_mag**(l + 1) * c_lm[0, l, m] * (dylm_dtheta / sqrt(rh(1)**2 + rh(2)**2) - (l + 1) * rh(3) * ylm / r_mag**2) + ! Associated Legendre Polynomials + plm = p(PlmIndex(l, m)) ! p_l,m + plm1 = p(PlmIndex(l, m+1)) ! p_l,m+1 - ! m < 0 - g_sph(1) += gm * r_0**l / r_mag**(l + 1) * c_lm[1, l, m] * (dyl_m_dtheta / (rh(3) * cos(phi)) - (l + 1) * rh(1) * ylm * (-1)**m / r_mag**2 - i * m * ylm / rh(2)) ! i = sqrt(-1) - g_sph(2) += gm * r_0**l / r_mag**(l + 1) * c_lm[1, l, m] * (dyl_m_dtheta / (rh(3) * sin(phi)) - (l + 1) * rh(2) * ylm * (-1)**m / r_mag**2 + i * m * ylm / rh(1)) - g_sph(3) += gm * r_0**l / r_mag**(l + 1) * c_lm[1, l, m] * (dyl_m_dtheta / sqrt(rh(1)**2 + rh(2)**2) - (l + 1) * rh(3) * ylm * (-1)**m / r_mag**2) + ! Normalization = 4*pi normalized + N = sqrt((2 * l + 1) * gamma(l - m + 1) / gamma(l + m + 1)) + + ! C_lm and S_lm with Cos and Sin of m * phi + ccss = c_lm(1, l, m) * cos(m * phi) + c_lm(2, l, m) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) + cssc = -1.0 * c_lm(1, l, m) * sin(m * phi) + c_lm(2, l, m) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) + ! cssc * m = first derivative of ccss with respect to phi + + ! m > 0 + g_sph(1) -= gm * r_0**l / r_mag**(l + 1) * N * (-1.0 * m * plm * cssc / rh(2) + ccss * (plm * (m * cotan(theta) / (rh(3) * cos(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * cos(phi)))) ! g_x + g_sph(2) -= gm * r_0**l / r_mag**(l + 1) * N * (m * plm * cssc / rh(1) + ccss * (plm * (m * cotan(theta) / (rh(3) * sin(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * sin(phi)))) + g_sph(3) -= gm * r_0**l / r_mag**(l + 1) * N * (ccss * (plm * (m * cotan(theta) / sqrt(r_mag**2 - rh(3)**3) - (l + 1) * rh(1) / r_mag**2) + plm1 / sqrt(r_mag**2 - rh(3)**2))) end do end do @@ -92,7 +101,7 @@ module subroutine swiftest_sph_dylm_dtheta(ylm, ylm1, theta, phi, l, m, dylm_dth return end subroutine swiftest_sph_dylm_dtheta - module subroutine swiftest_sph_ylm(l, m, phi, theta) + module subroutine swiftest_sph_ylm(l, m, phi, theta, ylm) !! author: Kaustub P. Anand !! !! Calculate the Y_lm for a given l, m, phi, and theta @@ -101,6 +110,11 @@ module subroutine swiftest_sph_ylm(l, m, phi, theta) integer, intent(in) :: l, m ! spherical harmonics numbers real(DP), intent(in) :: theta ! Zenith angle real(DP), intent(in) :: phi ! Azimuthal angle + real(DP), dimension(:), intent(out) :: ylm ! Spherical Harmonics for phi and theta + + PlBar(p, lmax, cos(theta)) ! 4*pi normalized + + ylm(:) = p(PlmIndex(l, m)) * sqrt((2 * l + 1) * gamma(l - m + 1) / gamma(l + m + 1)) * exp(i * m * phi) return end subroutine swiftest_sph_ylm \ No newline at end of file From 27e5b25e7db84d4e388d117be9edc18e67e6130e Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Fri, 4 Aug 2023 12:17:01 -0400 Subject: [PATCH 025/324] Removed extra submodules --- src/swiftest/swiftest_sph.f90 | 48 +++-------------------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index a620317e1..f44d1c705 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -50,7 +50,7 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph, l plm = p(PlmIndex(l, m)) ! p_l,m plm1 = p(PlmIndex(l, m+1)) ! p_l,m+1 - ! Normalization = 4*pi normalized + ! Normalization = 4*pi (geodesy) normalized N = sqrt((2 * l + 1) * gamma(l - m + 1) / gamma(l + m + 1)) ! C_lm and S_lm with Cos and Sin of m * phi @@ -60,8 +60,8 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph, l ! m > 0 g_sph(1) -= gm * r_0**l / r_mag**(l + 1) * N * (-1.0 * m * plm * cssc / rh(2) + ccss * (plm * (m * cotan(theta) / (rh(3) * cos(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * cos(phi)))) ! g_x - g_sph(2) -= gm * r_0**l / r_mag**(l + 1) * N * (m * plm * cssc / rh(1) + ccss * (plm * (m * cotan(theta) / (rh(3) * sin(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * sin(phi)))) - g_sph(3) -= gm * r_0**l / r_mag**(l + 1) * N * (ccss * (plm * (m * cotan(theta) / sqrt(r_mag**2 - rh(3)**3) - (l + 1) * rh(1) / r_mag**2) + plm1 / sqrt(r_mag**2 - rh(3)**2))) + g_sph(2) -= gm * r_0**l / r_mag**(l + 1) * N * (m * plm * cssc / rh(1) + ccss * (plm * (m * cotan(theta) / (rh(3) * sin(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * sin(phi)))) ! g_y + g_sph(3) -= gm * r_0**l / r_mag**(l + 1) * N * (ccss * (plm * (m * cotan(theta) / sqrt(r_mag**2 - rh(3)**3) - (l + 1) * rh(1) / r_mag**2) + plm1 / sqrt(r_mag**2 - rh(3)**2))) ! g_z end do end do @@ -76,45 +76,3 @@ module subroutine swiftest_sph_g_acc_all() !! end subroutine swiftest_sph_g_acc_all - - module subroutine swiftest_sph_dylm_dtheta(ylm, ylm1, theta, phi, l, m, dylm_dtheta, dyl_m_dtheta) - !! author: Kaustub P. Anand - !! - !! Calculate the derivative of Y_lm with respect to theta dY_lm / dtheta term - !! - - ! Arguments - real(DP), intent(in) :: ylm ! Y_l,m - real(DP), intent(in) :: ylm1 ! Y_l,m+1 - real(DP), intent(in) :: theta ! Zenith angle - real(DP), intent(in) :: phi ! Azimuthal angle - integer, intent(in) :: l, m ! spherical harmonics numbers - real(DP), intent(out) :: dylm_dtheta ! derivative for +m - real(DP), intent(out) :: dyl_m_dtheta ! derivative for -m - - - ! Internals - - dylm_dtheta = m * cotan(theta) * ylm + sqrt((l - m) * (l + m + 1)) * ylm1 * exp(i * phi) - dyl_m_dtheta = -m * cotan(theta) * ylm * (-1)**m + sqrt((l + m) * (l - m + 1)) * ylm1 * exp(i * phi) - - return - end subroutine swiftest_sph_dylm_dtheta - - module subroutine swiftest_sph_ylm(l, m, phi, theta, ylm) - !! author: Kaustub P. Anand - !! - !! Calculate the Y_lm for a given l, m, phi, and theta - !! - - integer, intent(in) :: l, m ! spherical harmonics numbers - real(DP), intent(in) :: theta ! Zenith angle - real(DP), intent(in) :: phi ! Azimuthal angle - real(DP), dimension(:), intent(out) :: ylm ! Spherical Harmonics for phi and theta - - PlBar(p, lmax, cos(theta)) ! 4*pi normalized - - ylm(:) = p(PlmIndex(l, m)) * sqrt((2 * l + 1) * gamma(l - m + 1) / gamma(l + m + 1)) * exp(i * m * phi) - - return - end subroutine swiftest_sph_ylm \ No newline at end of file From 7742abbafb1e2d4122e6c6352cc56015f2ed3658 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 8 Aug 2023 11:41:04 -0400 Subject: [PATCH 026/324] Added a maximum order for the SpH coefficients --- python/swiftest/swiftest/sph_harmonics_gravity.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index 98a4c8692..9f7337134 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -28,15 +28,13 @@ Any ) -def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): +def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6): """ Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). Parameters ---------- - lmax : int - The maximum spherical harmonic degree resolvable by the grid. mass : float mass of the central body density : float @@ -47,6 +45,8 @@ def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): length of the pricipal axis aligned with the y axis c : float, optional, default = b length of the pricipal axis aligned with the z axis + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. Returns ------- @@ -60,9 +60,10 @@ def clm_from_ellipsoid(lmax, mass, density, a, b = None, c = None): Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass # FIND A BETTER WAY TO CHANGE UNITS - # cap lmax to 20 to ensure fast performance - lmax_limit = 20 - if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + # cap lmax to ensure fast performance without giving up accuracy + + lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law by taking the characteristic wavelength as the radius of the CB + if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients lmax = lmax_limit print(f'Setting maximum spherical harmonic degree to {lmax_limit}') @@ -118,4 +119,4 @@ def clm_from_relief(lmax, mass, density, grid): clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization clm = clm_class.to_array() - return clm \ No newline at end of file + return clm From e47cd6c1509fc7e66c0faf1c7e4ae23b68cfeadb Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 8 Aug 2023 15:26:43 -0400 Subject: [PATCH 027/324] Added framework for spherical harmonic gravity --- src/swiftest/swiftest_sph.f90 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index f44d1c705..6f4c3d249 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -17,7 +17,7 @@ contains - module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph, l_max) + module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -75,4 +75,15 @@ module subroutine swiftest_sph_g_acc_all() !! Calculate the acceleration terms for all bodies given c_lm !! + associate(pl => self, npl => self%nbody, cb => nbody_system%cb) + do concurrent(i = 1:npl, pl%lmask(i)) + gm = pl%Gmass(i) + rh = pl%rh(:, i) ! CHECK pl%rh shape + r = sqrt(rh(1)**2 + rh(2)**2 + rh(3)**2) ! mag of vector function??? + theta = acos(rh(3) / r) + phi = acos(rh(1) / sqrt(rh(1)**2 + rh(2)**2)) * sign(1, rh(2)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI + + call swiftest_sph_g_acc_one(gm, r, phi, theta, rh, cb%c_lm, g_sph) + pl%ah(:, i) = pl%ah(:, i) + g_sph + end subroutine swiftest_sph_g_acc_all From ee384719b58695282d600d363187b73e5cc99d24 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Fri, 11 Aug 2023 11:59:56 -0400 Subject: [PATCH 028/324] Cleaned up and completed python SpH functions --- .../swiftest/sph_harmonics_gravity.py | 55 ++++++++++++------- src/swiftest/swiftest_sph.f90 | 11 +++- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index 9f7337134..e7f28e8fe 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -28,7 +28,7 @@ Any ) -def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6): +def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radius = False): """ Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). @@ -47,6 +47,8 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6): length of the pricipal axis aligned with the z axis lmax : int, optional, default = 6 The maximum spherical harmonic degree resolvable by the grid. + ref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS Returns ------- @@ -57,40 +59,47 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6): """ G = swiftest.constants.GC - Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass - # FIND A BETTER WAY TO CHANGE UNITS + Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS # cap lmax to ensure fast performance without giving up accuracy - - lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law by taking the characteristic wavelength as the radius of the CB - if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law by taking the characteristic wavelength as the radius of the CB + if(lmax > lmax_limit): lmax = lmax_limit print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - # create shape grid and convert to Spherical Harmonics (.expand()) - shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c).expand() + # create shape grid + shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) # get coefficients clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array() + clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization - return clm + # Return reference radius EQUALS the radius of the Central Body + print(f'Ensure that the Central Body radius equals the reference radius') -def clm_from_relief(lmax, mass, density, grid): + if(ref_radius == True): + ref_radius = shape_SH.expand(normalization = 'ortho').coeffs[0, 0, 0] + return clm, ref_radius + else: + return clm + +def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): """ Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. Uses pyshtools. Parameters ---------- - lmax : int - The maximum spherical harmonic degree resolvable by the grid. mass : float mass of the central body density : float density of the central body grid : array, shape [] DH grid of the surface relief of the body + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + ref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS Returns ------- @@ -102,21 +111,27 @@ def clm_from_relief(lmax, mass, density, grid): """ G = swiftest.constants.GC - Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass - # FIND A BETTER WAY TO CHANGE UNITS + Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS # cap lmax to 20 to ensure fast performance - lmax_limit = 20 + lmax_limit = 6 if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients lmax = lmax_limit print(f'Setting maximum spherical harmonic degree to {lmax_limit}') # convert to spherical harmonics - shape_SH = pysh.SHGrid.from_array(grid).expand() - # shape_SH = SHExpandDH(grid) + shape_SH = pysh.SHGrid.from_array(grid) # get coefficients clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array() + clm = clm_class.to_array(normalization = 'ortho') # change to orthogonal normalization + + # Return reference radius EQUALS the radius of the Central Body + + print(f'Ensure that the Central Body radius equals the reference radius') - return clm + if(ref_radius == True): + ref_radius = shape_SH.expand(normalization = 'ortho').coeffs[0, 0, 0] + return clm, ref_radius + else: + return clm diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 6f4c3d249..fa38a4f9c 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -59,9 +59,14 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) -= gm * r_0**l / r_mag**(l + 1) * N * (-1.0 * m * plm * cssc / rh(2) + ccss * (plm * (m * cotan(theta) / (rh(3) * cos(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * cos(phi)))) ! g_x - g_sph(2) -= gm * r_0**l / r_mag**(l + 1) * N * (m * plm * cssc / rh(1) + ccss * (plm * (m * cotan(theta) / (rh(3) * sin(phi)) - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * sin(phi)))) ! g_y - g_sph(3) -= gm * r_0**l / r_mag**(l + 1) * N * (ccss * (plm * (m * cotan(theta) / sqrt(r_mag**2 - rh(3)**3) - (l + 1) * rh(1) / r_mag**2) + plm1 / sqrt(r_mag**2 - rh(3)**2))) ! g_z + g_sph(1) -= gm * r_0**l / r_mag**(l + 1) * N * (-1.0 * m * plm * cssc / rh(2) & + + ccss * (plm * (m * cotan(theta) / (rh(3) * cos(phi)) & + - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * cos(phi)))) ! g_x + g_sph(2) -= gm * r_0**l / r_mag**(l + 1) * N * (m * plm * cssc / rh(1) & + + ccss * (plm * (m * cotan(theta) / (rh(3) * sin(phi)) & + - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * sin(phi)))) ! g_y + g_sph(3) -= gm * r_0**l / r_mag**(l + 1) * N * (ccss * (plm * (m * cotan(theta) / sqrt(r_mag**2 - rh(3)**3) & + - (l + 1) * rh(1) / r_mag**2) + plm1 / sqrt(r_mag**2 - rh(3)**2))) ! g_z end do end do From 0ba79072e37674e5a6a9b81ae3963b92d660b59d Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Fri, 11 Aug 2023 12:10:54 -0400 Subject: [PATCH 029/324] typo fixed --- python/swiftest/swiftest/sph_harmonics_gravity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index e7f28e8fe..ab0b7ebf8 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -70,7 +70,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu # create shape grid shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) - # get coefficients + # get gravity coefficients clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization @@ -78,7 +78,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu print(f'Ensure that the Central Body radius equals the reference radius') if(ref_radius == True): - ref_radius = shape_SH.expand(normalization = 'ortho').coeffs[0, 0, 0] + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius else: return clm From aebe98a46085d5985e5ae56e28feafacf7c580a8 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Fri, 11 Aug 2023 14:40:04 -0400 Subject: [PATCH 030/324] Finished up the acceleration calculation from C_lm. Final lookover/test needed --- src/swiftest/swiftest_obl.f90 | 2 - src/swiftest/swiftest_sph.f90 | 118 ++++++++++++++++++++++++---------- 2 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index f3656050e..c487eb6ba 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -174,8 +174,6 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, end do end if - - if (present(GMpl) .and. present(aoblcb)) then aoblcb(:) = 0.0_DP do i = n, 1, -1 diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index fa38a4f9c..f27d694f7 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -17,7 +17,7 @@ contains - module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -25,33 +25,34 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) implicit none ! Arguments - real(DP), intent(in) :: gm !! GMass of the central body - real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) - real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) - real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body - real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector - + real(DP), intent(in) :: GMcb !! GMass of the central body + real(DP), intent(in) :: r_0 !! radius of the central body + real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) + real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) + real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body + real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles + real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + ! Internals integer :: l, m !! SPH coefficients real(DP) :: r_mag !! magnitude of rh - real(DP) :: p !! Associated Lengendre Polynomials at a given cos(theta) + real(DP), dimension(2, :, :) :: p, dp !! Associated Lengendre Polynomials at a given cos(theta) integer :: l_max !! max Spherical Harmonic l order value + real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m + g_sph(:) = 0.0_DP r_mag = sqrt(dot_product(rh(:), rh(:))) - l_max = size(c_lm, 2) - PlBar(p, lmax, cos(theta)) ! Associated Legendre Polynomials + l_max = size(c_lm, 2) - 1 + PlmON_d1(p, dp, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative - do l = 1, l_max - do m = 1, l + do l = 0, l_max + do m = 0, l ! Associated Legendre Polynomials plm = p(PlmIndex(l, m)) ! p_l,m - plm1 = p(PlmIndex(l, m+1)) ! p_l,m+1 - - ! Normalization = 4*pi (geodesy) normalized - N = sqrt((2 * l + 1) * gamma(l - m + 1) / gamma(l + m + 1)) + dplm = dp(PlmIndex(l, m)) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(1, l, m) * cos(m * phi) + c_lm(2, l, m) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) @@ -59,14 +60,14 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) -= gm * r_0**l / r_mag**(l + 1) * N * (-1.0 * m * plm * cssc / rh(2) & - + ccss * (plm * (m * cotan(theta) / (rh(3) * cos(phi)) & - - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * cos(phi)))) ! g_x - g_sph(2) -= gm * r_0**l / r_mag**(l + 1) * N * (m * plm * cssc / rh(1) & - + ccss * (plm * (m * cotan(theta) / (rh(3) * sin(phi)) & - - (l + 1) * rh(1) / r_mag**2) + plm1 / (rh(3) * sin(phi)))) ! g_y - g_sph(3) -= gm * r_0**l / r_mag**(l + 1) * N * (ccss * (plm * (m * cotan(theta) / sqrt(r_mag**2 - rh(3)**3) & - - (l + 1) * rh(1) / r_mag**2) + plm1 / sqrt(r_mag**2 - rh(3)**2))) ! g_z + g_sph(1) -= GMcb * r_0**l / r_mag**(l + 1) * (-1.0 * m * plm * cssc / rh(2) & + - ccss * (dplm * sin(theta) / (rh(3) * cos(phi)) + plm * (l + 1) * rh(1) / r_mag**2)) ! g_x + g_sph(2) -= GMcb * r_0**l / r_mag**(l + 1) * (m * plm * cssc / rh(1) & + - ccss * (dplm * sin(theta) / (rh(3) * sin(phi)) + plm * (l + 1) * rh(2) / r_mag**2)) ! g_y + g_sph(3) += GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) + plm * (l + 1) * rh(3) / r_mag**2) ! g_z + + if (present(GMpl) .and. present(aoblcb)) then + aoblcb(:) = aoblcb(:) - GMpl * g_sph(:) / GMcb end do end do @@ -74,21 +75,68 @@ module subroutine swiftest_sph_g_acc_one(gm, r_0, phi, theta, rh, c_lm, g_sph) return end subroutine swiftest_sph_g_acc_one - module subroutine swiftest_sph_g_acc_all() + module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) !! author: Kaustub P. Anand !! - !! Calculate the acceleration terms for all bodies given c_lm + !! Calculate the acceleration terms for all massive bodies given c_lm !! + implicit none + ! Arguments + class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + ! Internals + integer(I4B) :: i + real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle + real(DP), dimension(NDIM) :: rh !! Position vector of the test particle + real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics associate(pl => self, npl => self%nbody, cb => nbody_system%cb) + cb%aobl(:) = 0.0_DP do concurrent(i = 1:npl, pl%lmask(i)) - gm = pl%Gmass(i) rh = pl%rh(:, i) ! CHECK pl%rh shape - r = sqrt(rh(1)**2 + rh(2)**2 + rh(3)**2) ! mag of vector function??? - theta = acos(rh(3) / r) + r_mag = .mag. rh(1:3) + theta = acos(rh(3) / r_mag) + phi = acos(rh(1) / sqrt(rh(1)**2 + rh(2)**2)) * sign(1, rh(2)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI + + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh, cb%c_lm, g_sph, pl%Gmass, cb%aobl) + pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) + pl%aobl(:, i) = g_sph(:) + return + end subroutine swiftest_sph_g_acc_pl_all + + module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) + !! author: Kaustub P. Anand + !! + !! Calculate the acceleration terms for all test particles given c_lm + !! + implicit none + ! Arguments + class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + ! Internals + integer(I4B) :: i + real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle + real(DP), dimension(NDIM) :: rh !! Position vector of the test particle + real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics + real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration + + associate(tp => self, ntp => self%nbody, cb => nbody_system%cb) + + if (nbody_system%lbeg) then + aoblcb = cb%aoblbeg + else + aoblcb = cb%aoblend + end if + + do concurrent(i = 1:ntp, tp%lmask(i)) + rh = tp%rh(:, i) + r_mag = .mag. rh(1:3) + theta = acos(rh(3) / r_mag) phi = acos(rh(1) / sqrt(rh(1)**2 + rh(2)**2)) * sign(1, rh(2)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI - call swiftest_sph_g_acc_one(gm, r, phi, theta, rh, cb%c_lm, g_sph) - pl%ah(:, i) = pl%ah(:, i) + g_sph - - end subroutine swiftest_sph_g_acc_all + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh, cb%c_lm, g_sph) + tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) + tp%aobl(:, i) = g_sph(:) + return + end subroutine swiftest_sph_g_acc_tp_all + From 61a2f520ab2a70586d08c21169e7171edb3a31b3 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 14 Aug 2023 10:13:58 -0400 Subject: [PATCH 031/324] Fixed a typo --- python/swiftest/swiftest/sph_harmonics_gravity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/python/swiftest/swiftest/sph_harmonics_gravity.py index ab0b7ebf8..e2ddcd345 100644 --- a/python/swiftest/swiftest/sph_harmonics_gravity.py +++ b/python/swiftest/swiftest/sph_harmonics_gravity.py @@ -62,7 +62,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS # cap lmax to ensure fast performance without giving up accuracy - lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law by taking the characteristic wavelength as the radius of the CB + lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB if(lmax > lmax_limit): lmax = lmax_limit print(f'Setting maximum spherical harmonic degree to {lmax_limit}') @@ -71,7 +71,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) # get gravity coefficients - clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization # Return reference radius EQUALS the radius of the Central Body From c492866901023934714a5716f64253f1f4e9877e Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 14 Aug 2023 11:24:56 -0400 Subject: [PATCH 032/324] added subroutines to swiftest_module --- src/swiftest/swiftest_module.f90 | 51 ++++++++++++++++++++++++++++++++ src/swiftest/swiftest_sph.f90 | 17 ++++++----- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 6607816df..de6c7059a 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -43,6 +43,7 @@ module swiftest use io_progress_bar use netcdf_io use solver + use SHTOOLS #ifdef COARRAY use coarray #endif @@ -1818,6 +1819,56 @@ end subroutine swiftest_coarray_cocollect_tp #endif + interface + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + !! author: Kaustub P. Anand + !! + !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r + !! + + implicit none + ! Arguments + real(DP), intent(in) :: GMcb !! GMass of the central body + real(DP), intent(in) :: r_0 !! radius of the central body + real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) + real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) + real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body + real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles + real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + end module subroutine swiftest_sph_g_acc_one + + module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) + !! author: Kaustub P. Anand + !! + !! Calculate the acceleration terms for all massive bodies given c_lm + !! + implicit none + ! Arguments + class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + end module subroutine swiftest_sph_g_acc_pl_all + + module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) + !! author: Kaustub P. Anand + !! + !! Calculate the acceleration terms for all test particles given c_lm + !! + implicit none + ! Arguments + class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + ! Internals + integer(I4B) :: i + real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle + real(DP), dimension(NDIM) :: rh !! Position vector of the test particle + real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics + real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration + end module subroutine swiftest_sph_g_acc_tp_all + + end interface + contains subroutine swiftest_final_kin(self) !! author: David A. Minton diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index f27d694f7..0f1f031f8 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -55,16 +55,19 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, dplm = dp(PlmIndex(l, m)) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi - ccss = c_lm(1, l, m) * cos(m * phi) + c_lm(2, l, m) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) - cssc = -1.0 * c_lm(1, l, m) * sin(m * phi) + c_lm(2, l, m) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) + ccss = c_lm(1, l+1, m+1) * cos(m * phi) + c_lm(2, l+1, m+1) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) + cssc = -1.0 * c_lm(1, l+1, m+1) * sin(m * phi) + c_lm(2, l+1, m+1) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) -= GMcb * r_0**l / r_mag**(l + 1) * (-1.0 * m * plm * cssc / rh(2) & - - ccss * (dplm * sin(theta) / (rh(3) * cos(phi)) + plm * (l + 1) * rh(1) / r_mag**2)) ! g_x - g_sph(2) -= GMcb * r_0**l / r_mag**(l + 1) * (m * plm * cssc / rh(1) & - - ccss * (dplm * sin(theta) / (rh(3) * sin(phi)) + plm * (l + 1) * rh(2) / r_mag**2)) ! g_y - g_sph(3) += GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) + plm * (l + 1) * rh(3) / r_mag**2) ! g_z + g_sph(1) -= GMcb * r_0**l / r_mag**(l + 1) * (cssc * -1.0 * m * plm / rh(2) & + - ccss * (dplm * sin(theta) / (rh(3) * cos(phi)) & + + plm * (l + 1) * rh(1) / r_mag**2)) ! g_x + g_sph(2) -= GMcb * r_0**l / r_mag**(l + 1) * (cssc * m * plm / rh(1) & + - ccss * (dplm * sin(theta) / (rh(3) * sin(phi)) & + + plm * (l + 1) * rh(2) / r_mag**2)) ! g_y + g_sph(3) += GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) & + + plm * (l + 1) * rh(3) / r_mag**2) ! g_z if (present(GMpl) .and. present(aoblcb)) then aoblcb(:) = aoblcb(:) - GMpl * g_sph(:) / GMcb From bce1ea1bf2bc610edd8bbe3dd583c41b2afa1236 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 23 Aug 2023 12:37:00 -0400 Subject: [PATCH 033/324] Adding Spherical Harmonics flags and functionality --- python/swiftest/swiftest/simulation_class.py | 18 ++++++++++++++++-- src/base/base_module.f90 | 1 + src/swiftest/swiftest_io.f90 | 6 +++++- src/whm/whm_kick.f90 | 4 ++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/python/swiftest/swiftest/simulation_class.py b/python/swiftest/swiftest/simulation_class.py index 804eee651..fa61d6430 100644 --- a/python/swiftest/swiftest/simulation_class.py +++ b/python/swiftest/swiftest/simulation_class.py @@ -2405,7 +2405,8 @@ def add_body(self, rot: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None=None, Ip: List[float] | npt.NDArray[np.float_] | None=None, J2: float | List[float] | npt.NDArray[np.float_] | None=None, - J4: float | List[float] | npt.NDArray[np.float_] | None=None): + J4: float | List[float] | npt.NDArray[np.float_] | None=None, + c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None): """ Adds a body (test particle or massive body) to the internal DataSet given a set up 6 vectors (orbital elements or cartesian state vectors, depending on the value of self.param). Input all angles in degress. @@ -2447,6 +2448,12 @@ def add_body(self, Rotation rate vectors if these are massive bodies with rotation enabled. Ip: (3) or (n,3) array-like of float, optional Principal axes moments of inertia vectors if these are massive bodies with rotation enabled. + J2: float, optional + J2 term of (central) body oblateness multiplied by radius^2. + J4: float, optional + J4 term of (central) body oblateness multiplied by radius^4. + c_lm: (2, l + 1, l + 1) array-like of float, optional + Gravitational spherical harmonics coefficients (ortho-normalization) Returns ------- @@ -2515,6 +2522,11 @@ def input_to_array_3d(val,n=None): val = val.T return val, n + + def input_to_ND_array(val, shape): + # Create function to convert c_lm array to numpy + + return val, n nbodies = None name,nbodies = input_to_array(name,"s",nbodies) @@ -2537,6 +2549,8 @@ def input_to_array_3d(val,n=None): rot,nbodies = input_to_array_3d(rot,nbodies) Ip,nbodies = input_to_array_3d(Ip,nbodies) + c_lm, nbodies = c_lm, nbodies + if len(self.data) == 0: maxid = -1 else: @@ -2562,7 +2576,7 @@ def input_to_array_3d(val,n=None): Gmass = self.GU * mass dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, - Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, time=time) + Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm = c_lm, time=time) dsnew = self._combine_and_fix_dsnew(dsnew) self.save(verbose=False) diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index 01c111661..21813278d 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -90,6 +90,7 @@ module base logical :: loblatecb = .false. !! Calculate acceleration from oblate central body (automatically turns true if nonzero J2 is input) logical :: lrotation = .false. !! Include rotation states of big bodies logical :: ltides = .false. !! Include tidal dissipation + logical :: lshgrav = .false. !! Calculate acceleration from spherical harmonics terms for the central body (automatically turns true if clm array is input) ! Initial values to pass to the energy report subroutine (usually only used in the case of a restart, otherwise these will be updated with initial conditions values) real(DP) :: E_orbit_orig = 0.0_DP !! Initial orbital energy diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 96f974362..724e85547 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2924,7 +2924,9 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (ierr /=0) call base_util_exit(FAILURE) end if - param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) + param%lshgrav = (size(self%cb%c_lm) /= 0.0_DP) + + param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (param%lshgrav == .FALSE.) if (.not.param%loblatecb) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) @@ -2937,6 +2939,8 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (.not. allocated(self%tp%aobl)) allocate(self%tp%aobl(NDIM,self%tp%nbody)) self%tp%aobl(:,:) = 0.0_DP end if + + end if return diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index 403678ed6..15b2803b4 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -58,6 +58,9 @@ module subroutine whm_kick_getacch_pl(self, nbody_system, param, t, lbeg) ! end if end if + if(param%lshgrav) then + call pl%swiftest_sph_g_acc_pl_all(nbody_system) + if (param%lgr) call pl%accel_gr(param) if (param%lextra_force) call pl%accel_user(nbody_system, param, t, lbeg) @@ -104,6 +107,7 @@ module subroutine whm_kick_getacch_tp(self, nbody_system, param, t, lbeg) end if if (param%loblatecb) call tp%accel_obl(nbody_system) + if (param%lshgrav) call tp%swiftest_sph_g_acc_tp_all(nbody_system) if (param%lextra_force) call tp%accel_user(nbody_system, param, t, lbeg) if (param%lgr) call tp%accel_gr(param) end associate From 9aa99f392dce8246badb9c06179f7cb31b1dedad Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:33:48 -0400 Subject: [PATCH 034/324] Restructured spherical harmonics module --- {python/swiftest/swiftest => swiftest}/sph_harmonics_gravity.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {python/swiftest/swiftest => swiftest}/sph_harmonics_gravity.py (100%) diff --git a/python/swiftest/swiftest/sph_harmonics_gravity.py b/swiftest/sph_harmonics_gravity.py similarity index 100% rename from python/swiftest/swiftest/sph_harmonics_gravity.py rename to swiftest/sph_harmonics_gravity.py From 8671be1810d5129b932eecfa7460059b9932a3d8 Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:35:21 -0400 Subject: [PATCH 035/324] Added pyshtools as a requirement --- environment.yml | 1 + requirements.txt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 933cb3fe1..34c6c6c3a 100644 --- a/environment.yml +++ b/environment.yml @@ -21,3 +21,4 @@ dependencies: - x264>=1!157.20191217 - ffmpeg>=4.3.2 - cython>=3.0.0 + - pyshtools diff --git a/requirements.txt b/requirements.txt index 79d85b58b..9519f962d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,4 +11,5 @@ matplotlib>=3.7.1 astropy>=5.1 astroquery>=0.4.6 tqdm>=4.65.0 -cython>=3.0.0 \ No newline at end of file +cython>=3.0.0 +pyshtools \ No newline at end of file From 8f8d7f4b34366f7ff3d1ec9becc7bfc3e4bf3c73 Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:57:58 -0400 Subject: [PATCH 036/324] Fixed some issues with syntax and code organization --- src/swiftest/swiftest_io.f90 | 2 +- src/swiftest/swiftest_module.f90 | 37 ++++-------------- src/swiftest/swiftest_sph.f90 | 62 ++++++++++++++++--------------- src/swiftest/swiftest_util.f90 | 1 + swiftest/sph_harmonics_gravity.py | 3 +- 5 files changed, 43 insertions(+), 62 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 4f338c6d7..d0ab59c7f 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2948,7 +2948,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) param%lshgrav = (size(self%cb%c_lm) /= 0.0_DP) - param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (param%lshgrav == .FALSE.) + param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not.param%lshgrav) if (.not.param%loblatecb) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index a154842c3..33be475c8 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -211,6 +211,7 @@ module swiftest real(DP), dimension(NDIM) :: agr = 0.0_DP !! Acceleration due to post-Newtonian correction real(DP), dimension(NDIM) :: Ip = 0.0_DP !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. real(DP), dimension(NDIM) :: rot = 0.0_DP !! Body rotation vector in inertial coordinate frame (units rad / TU) + real(DP) :: rotphase = 0.0_DP !! Body rotation phase about the rotation pole real(DP) :: k2 = 0.0_DP !! Tidal Love number real(DP) :: Q = 0.0_DP !! Tidal quality factor real(DP) :: tlag = 0.0_DP !! Tidal phase lag angle @@ -1827,13 +1828,11 @@ module subroutine swiftest_coarray_coclone_system(self) end subroutine swiftest_coarray_coclone_system module subroutine swiftest_coarray_cocollect_body(self) - !! Collects all body object array components from all images and combines them into the image 1 body object implicit none class(swiftest_body),intent(inout), codimension[*] :: self !! Swiftest body object end subroutine swiftest_coarray_cocollect_body module subroutine swiftest_coarray_cocollect_tp(self) - !! Collects all body object array components from all images and combines them into the image 1 body object implicit none class(swiftest_tp),intent(inout), codimension[*] :: self !! Swiftest tp object end subroutine swiftest_coarray_cocollect_tp @@ -1843,51 +1842,29 @@ end subroutine swiftest_coarray_cocollect_tp interface module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) - !! author: Kaustub P. Anand - !! - !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r - !! - implicit none - ! Arguments real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) - real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body - real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), intent(in), dimension(:) :: rh !! distance vector of body + real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) - end module subroutine swiftest_sph_g_acc_one + end subroutine swiftest_sph_g_acc_one module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) - !! author: Kaustub P. Anand - !! - !! Calculate the acceleration terms for all massive bodies given c_lm - !! implicit none - ! Arguments class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - end module subroutine swiftest_sph_g_acc_pl_all + end subroutine swiftest_sph_g_acc_pl_all module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) - !! author: Kaustub P. Anand - !! - !! Calculate the acceleration terms for all test particles given c_lm - !! implicit none - ! Arguments class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - ! Internals - integer(I4B) :: i - real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle - real(DP), dimension(NDIM) :: rh !! Position vector of the test particle - real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics - real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration - end module subroutine swiftest_sph_g_acc_tp_all + end subroutine swiftest_sph_g_acc_tp_all end interface diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 0f1f031f8..e73bed29d 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -29,54 +29,57 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in) :: r_0 !! radius of the central body real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) - real(DP), intent(in), dimension(NDIM) :: rh !! distance vector of body - real(DP), intent(in), dimension(2, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), intent(in), dimension(:) :: rh !! distance vector of body + real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) ! Internals integer :: l, m !! SPH coefficients real(DP) :: r_mag !! magnitude of rh - real(DP), dimension(2, :, :) :: p, dp !! Associated Lengendre Polynomials at a given cos(theta) + real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) integer :: l_max !! max Spherical Harmonic l order value real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m + integer(I4B) :: N g_sph(:) = 0.0_DP r_mag = sqrt(dot_product(rh(:), rh(:))) l_max = size(c_lm, 2) - 1 - PlmON_d1(p, dp, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative + N = (l_max + 1) * (l_max + 2) / 2 + allocate(p(N),p_deriv(N)) + PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative - do l = 0, l_max + do l = 1, l_max do m = 0, l ! Associated Legendre Polynomials plm = p(PlmIndex(l, m)) ! p_l,m - dplm = dp(PlmIndex(l, m)) ! d(p_l,m) + dplm = p_deriv(PlmIndex(l, m)) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(1, l+1, m+1) * cos(m * phi) + c_lm(2, l+1, m+1) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) - cssc = -1.0 * c_lm(1, l+1, m+1) * sin(m * phi) + c_lm(2, l+1, m+1) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) + cssc = -1 * c_lm(1, l+1, m+1) * sin(m * phi) + c_lm(2, l+1, m+1) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) -= GMcb * r_0**l / r_mag**(l + 1) * (cssc * -1.0 * m * plm / rh(2) & + g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 1) * (cssc * -1 * m * plm / rh(2) & - ccss * (dplm * sin(theta) / (rh(3) * cos(phi)) & + plm * (l + 1) * rh(1) / r_mag**2)) ! g_x - g_sph(2) -= GMcb * r_0**l / r_mag**(l + 1) * (cssc * m * plm / rh(1) & + g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 1) * (cssc * m * plm / rh(1) & - ccss * (dplm * sin(theta) / (rh(3) * sin(phi)) & + plm * (l + 1) * rh(2) / r_mag**2)) ! g_y - g_sph(3) += GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) & + g_sph(3) = g_sph(3) + GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) & + plm * (l + 1) * rh(3) / r_mag**2) ! g_z - - if (present(GMpl) .and. present(aoblcb)) then - aoblcb(:) = aoblcb(:) - GMpl * g_sph(:) / GMcb - end do end do + if (present(GMpl) .and. present(aoblcb)) then + aoblcb(:) = aoblcb(:) - GMpl * g_sph(:) / GMcb + end if + return - end subroutine swiftest_sph_g_acc_one + end subroutine swiftest_sph_g_acc_one module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) !! author: Kaustub P. Anand @@ -90,20 +93,20 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) ! Internals integer(I4B) :: i real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle - real(DP), dimension(NDIM) :: rh !! Position vector of the test particle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics - associate(pl => self, npl => self%nbody, cb => nbody_system%cb) + associate(pl => self, npl => self%nbody, cb => nbody_system%cb, rh => self%rh) cb%aobl(:) = 0.0_DP do concurrent(i = 1:npl, pl%lmask(i)) - rh = pl%rh(:, i) ! CHECK pl%rh shape - r_mag = .mag. rh(1:3) - theta = acos(rh(3) / r_mag) - phi = acos(rh(1) / sqrt(rh(1)**2 + rh(2)**2)) * sign(1, rh(2)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI + r_mag = .mag. rh(1:3,i) + theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) + phi = atan2(rh(2,i), rh(1,i)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh, cb%c_lm, g_sph, pl%Gmass, cb%aobl) + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) pl%aobl(:, i) = g_sph(:) + end do + end associate return end subroutine swiftest_sph_g_acc_pl_all @@ -123,7 +126,7 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration - associate(tp => self, ntp => self%nbody, cb => nbody_system%cb) + associate(tp => self, ntp => self%nbody, cb => nbody_system%cb, rh => self%rh) if (nbody_system%lbeg) then aoblcb = cb%aoblbeg @@ -132,14 +135,15 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) end if do concurrent(i = 1:ntp, tp%lmask(i)) - rh = tp%rh(:, i) - r_mag = .mag. rh(1:3) - theta = acos(rh(3) / r_mag) - phi = acos(rh(1) / sqrt(rh(1)**2 + rh(2)**2)) * sign(1, rh(2)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI + r_mag = .mag. rh(1:3,i) + theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) + phi = atan2(rh(2,i), rh(1,i)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh, cb%c_lm, g_sph) + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) tp%aobl(:, i) = g_sph(:) + end do + end associate return end subroutine swiftest_sph_g_acc_tp_all diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 94813be38..7290b4b29 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -2455,6 +2455,7 @@ module subroutine swiftest_util_setup_initialize_system(self, system_history, pa nc%file_name = param%outfile call nbody_system%initialize_output_file(nc, param) call nc%close() + end associate return diff --git a/swiftest/sph_harmonics_gravity.py b/swiftest/sph_harmonics_gravity.py index e2ddcd345..8e77ca684 100644 --- a/swiftest/sph_harmonics_gravity.py +++ b/swiftest/sph_harmonics_gravity.py @@ -110,8 +110,7 @@ def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): """ - G = swiftest.constants.GC - Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS # cap lmax to 20 to ensure fast performance lmax_limit = 6 From 09046871a0211bff0cba889bbeea5ea5c8f6478a Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:58:19 -0400 Subject: [PATCH 037/324] Fixed name of variable that got refactored --- src/swiftest/swiftest_sph.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index e73bed29d..da9dc036e 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -100,7 +100,7 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) do concurrent(i = 1:npl, pl%lmask(i)) r_mag = .mag. rh(1:3,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI + phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) From 8395276579d10febd4430b70ffdb09258430fa04 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 5 Sep 2023 14:48:59 -0400 Subject: [PATCH 038/324] fixed a typo in the normalization for reference radius --- swiftest/sph_harmonics_gravity.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swiftest/sph_harmonics_gravity.py b/swiftest/sph_harmonics_gravity.py index 8e77ca684..6eae17373 100644 --- a/swiftest/sph_harmonics_gravity.py +++ b/swiftest/sph_harmonics_gravity.py @@ -75,7 +75,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization # Return reference radius EQUALS the radius of the Central Body - print(f'Ensure that the Central Body radius equals the reference radius') + print(f'Ensure that the Central Body radius equals the reference radius.') if(ref_radius == True): ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] @@ -127,10 +127,10 @@ def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): # Return reference radius EQUALS the radius of the Central Body - print(f'Ensure that the Central Body radius equals the reference radius') + print(f'Ensure that the Central Body radius equals the reference radius.') if(ref_radius == True): - ref_radius = shape_SH.expand(normalization = 'ortho').coeffs[0, 0, 0] + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius else: return clm From 1b7d9b9812c3d2cd9c26e15ec79ac23920efce1c Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 5 Sep 2023 16:37:33 -0400 Subject: [PATCH 039/324] added c_lm to xarray dataset in init_cond.vec2xr --- swiftest/init_cond.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 978fe9808..c1f702432 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -455,6 +455,8 @@ def vec2xr(param: Dict, **kwargs: Any): instead of passing Ip1, Ip2, and Ip3 separately time : array of floats Time at start of simulation + c_lm : (2, lmax + 1, lmax + 1) array of floats, optional + Spherical Harmonics coefficients; lmax = max spherical harmonics order Returns ------- ds : xarray dataset @@ -462,10 +464,12 @@ def vec2xr(param: Dict, **kwargs: Any): scalar_dims = ['id'] vector_dims = ['id','space'] space_coords = np.array(["x","y","z"]) + sph_dims = ['positive', 'l', 'm'] # Spherical Harmonics dimensions vector_vars = ["rh","vh","Ip","rot"] scalar_vars = ["name","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] - time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] + sph_vars = ["c_lm"] + time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4", "c_lm"] # Check for valid keyword arguments kwargs = {k:kwargs[k] for k,v in kwargs.items() if v is not None} @@ -479,12 +483,13 @@ def vec2xr(param: Dict, **kwargs: Any): if "time" not in kwargs: kwargs["time"] = np.array([0.0]) - valid_arguments = vector_vars + scalar_vars + ['time','id'] + valid_arguments = vector_vars + scalar_vars + sph_vars + ['time','id'] kwargs = {k:v for k,v in kwargs.items() if k in valid_arguments} data_vars = {k:(scalar_dims,v) for k,v in kwargs.items() if k in scalar_vars} data_vars.update({k:(vector_dims,v) for k,v in kwargs.items() if k in vector_vars}) + data_vars.update({k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}) ds = xr.Dataset(data_vars=data_vars, coords={ "id":(["id"],kwargs['id']), From 70a7c7d4d0a9b5feb08db0f3c5d98ac1c0e956c5 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 6 Sep 2023 13:21:24 -0400 Subject: [PATCH 040/324] write function to convert c_lm array to numpy array " " --- swiftest/simulation_class.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index f306fed0b..2c6c4daee 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2443,9 +2443,20 @@ def input_to_array_3d(val,n=None): return val, n - def input_to_ND_array(val, shape): - # Create function to convert c_lm array to numpy - + def input_to_clm_array(val, n): + # Create function to convert c_lm array to numpy array + if val is None: + return None, n + elif isinstance(val, np.ndarray): + pass + else: + try: + val = np.array(val,dtype=np.float64) + except: + raise ValueError(f"{val} cannot be converted to a numpy array") + ndims = len(val.shape) + if ndims != 3 or val.shape[0] != 2: + raise ValueError(f'C_lm is an incorrect shape. Expected (2, l_max + 1, l_max + 1). got {val.shape} instead.') return val, n nbodies = None @@ -2469,7 +2480,7 @@ def input_to_ND_array(val, shape): rot,nbodies = input_to_array_3d(rot,nbodies) Ip,nbodies = input_to_array_3d(Ip,nbodies) - c_lm, nbodies = c_lm, nbodies + c_lm, nbodies = input_to_clm_array(c_lm, nbodies) if len(self.data) == 0: maxid = -1 @@ -2496,7 +2507,7 @@ def input_to_ND_array(val, shape): Gmass = self.GU * mass dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, - Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm = c_lm, time=time) + Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, time=time) dsnew = self._combine_and_fix_dsnew(dsnew) self.save(verbose=False) From 514e5ddf1edda4f45d6ee4585ce0868b2c691769 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Thu, 7 Sep 2023 14:33:28 -0400 Subject: [PATCH 041/324] added c_lm to the xarray dataset --- swiftest/init_cond.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index c1f702432..190f9ce11 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -464,12 +464,12 @@ def vec2xr(param: Dict, **kwargs: Any): scalar_dims = ['id'] vector_dims = ['id','space'] space_coords = np.array(["x","y","z"]) - sph_dims = ['positive', 'l', 'm'] # Spherical Harmonics dimensions + sph_dims = ['sign', 'l', 'm'] # Spherical Harmonics dimensions vector_vars = ["rh","vh","Ip","rot"] scalar_vars = ["name","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] sph_vars = ["c_lm"] - time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4", "c_lm"] + time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] # Check for valid keyword arguments kwargs = {k:kwargs[k] for k,v in kwargs.items() if v is not None} @@ -489,7 +489,6 @@ def vec2xr(param: Dict, **kwargs: Any): data_vars = {k:(scalar_dims,v) for k,v in kwargs.items() if k in scalar_vars} data_vars.update({k:(vector_dims,v) for k,v in kwargs.items() if k in vector_vars}) - data_vars.update({k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}) ds = xr.Dataset(data_vars=data_vars, coords={ "id":(["id"],kwargs['id']), @@ -500,4 +499,15 @@ def vec2xr(param: Dict, **kwargs: Any): for v in time_vars: ds[v] = ds[v].expand_dims({"time":1}).assign_coords({"time": kwargs['time']}) + # create a C_lm Dataset and combine + + clm_xr = xr.Dataset(data_vars = {k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}, + coords = { + 'sign':(['sign'], [1, -1]), + 'l': (['l'], range(0, kwargs['c_lm'].shape[1])), + 'm':(['m'], range(0, kwargs['c_lm'].shape[2])) + } + ) + ds = xr.combine_by_coords([ds, clm_xr]) + return ds \ No newline at end of file From bd825074ccd9aa472bfcd9066b62a44a981e4201 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Thu, 7 Sep 2023 14:49:53 -0400 Subject: [PATCH 042/324] Fixed an error with no c_lm input --- swiftest/init_cond.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 190f9ce11..5ffc2c78e 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -501,13 +501,14 @@ def vec2xr(param: Dict, **kwargs: Any): # create a C_lm Dataset and combine - clm_xr = xr.Dataset(data_vars = {k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}, - coords = { - 'sign':(['sign'], [1, -1]), - 'l': (['l'], range(0, kwargs['c_lm'].shape[1])), - 'm':(['m'], range(0, kwargs['c_lm'].shape[2])) - } - ) - ds = xr.combine_by_coords([ds, clm_xr]) + if(kwargs['c_lm'] is not None): + clm_xr = xr.Dataset(data_vars = {k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}, + coords = { + 'sign':(['sign'], [1, -1]), + 'l': (['l'], range(0, kwargs['c_lm'].shape[1])), + 'm':(['m'], range(0, kwargs['c_lm'].shape[2])) + } + ) + ds = xr.combine_by_coords([ds, clm_xr]) return ds \ No newline at end of file From 35ae7b15061a684cd482a76e4b72cb99271de802 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 11 Sep 2023 12:30:45 -0400 Subject: [PATCH 043/324] Changed kwargs clm check conditions in vec2xr. Fixed a typo in add_body --- swiftest/init_cond.py | 2 +- swiftest/simulation_class.py | 2 +- swiftest/sph_harmonics_gravity.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 5ffc2c78e..4bab13234 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -501,7 +501,7 @@ def vec2xr(param: Dict, **kwargs: Any): # create a C_lm Dataset and combine - if(kwargs['c_lm'] is not None): + if "c_lm" in kwargs: clm_xr = xr.Dataset(data_vars = {k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}, coords = { 'sign':(['sign'], [1, -1]), diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 2c6c4daee..dcbe6d7d7 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2455,7 +2455,7 @@ def input_to_clm_array(val, n): except: raise ValueError(f"{val} cannot be converted to a numpy array") ndims = len(val.shape) - if ndims != 3 or val.shape[0] != 2: + if ndims != 3 or val.shape[0] != 2 or val.shape[1] != val.shape[2]: raise ValueError(f'C_lm is an incorrect shape. Expected (2, l_max + 1, l_max + 1). got {val.shape} instead.') return val, n diff --git a/swiftest/sph_harmonics_gravity.py b/swiftest/sph_harmonics_gravity.py index 6eae17373..4fd249600 100644 --- a/swiftest/sph_harmonics_gravity.py +++ b/swiftest/sph_harmonics_gravity.py @@ -58,8 +58,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu where i=0 corresponds to positive orders and i=1 to negative orders. """ - G = swiftest.constants.GC - Gmass = G * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS # cap lmax to ensure fast performance without giving up accuracy lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB From a944ce843b0ed299313ecf6f6649d085ee2a9c21 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 13 Sep 2023 15:49:36 -0400 Subject: [PATCH 044/324] added preliminary c_lm parameters for netcdf --- src/netcdf_io/netcdf_io_module.f90 | 2 ++ src/swiftest/swiftest_io.f90 | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index bb2ddb55b..6fb2dcadd 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -99,6 +99,8 @@ module netcdf_io integer(I4B) :: j2rp2_varid !! ID for the j2 variable character(NAMELEN) :: j4rp4_varname = "j4rp4" !! name of the j4pr4 variable integer(I4B) :: j4rp4_varid !! ID for the j4 variable + character(NAMELEN) :: c_lm_varname = "c_lm" !! name for the c_lm array + integer(I4B) :: c_lm_varid !! ID for the c_lm aqrray character(NAMELEN) :: k2_varname = "k2" !! name of the Love number variable integer(I4B) :: k2_varid !! ID for the Love number variable character(NAMELEN) :: q_varname = "Q" !! name of the energy dissipation variable diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index d0ab59c7f..88e5d6f8c 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1322,6 +1322,13 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier cb%j4rp4 = 0.0_DP end if + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, START = [ASK_DAVE] count = [2, l (ASK_DAVE), ASK_DAVE ]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + else + cb%c_lm = 0.0_DP + end if + call self%read_particle_info(nc, param, plmask, tpmask) if (param%in_form == "EL") then From f0a0c10c91c7af14dd7d4790a16842d859c52fce Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Thu, 14 Sep 2023 10:40:46 -0400 Subject: [PATCH 045/324] Extended CB class to include c_lm. Added c_lm to netcdf --- src/swiftest/swiftest_module.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 33be475c8..a3f6ac3d1 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -200,6 +200,7 @@ module swiftest real(DP) :: density = 1.0_DP !! Central body mass density - calculated internally (units MU / DU**3) real(DP) :: j2rp2 = 0.0_DP !! J2*R^2 term for central body real(DP) :: j4rp4 = 0.0_DP !! J4*R^4 term for central body + real(DP), dimension(:,:,:) :: c_lm = 0.0_DP !! Spherical Harmonics coefficients for the central body real(DP), dimension(NDIM) :: aobl = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: atide = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: aoblbeg = 0.0_DP !! Barycentric acceleration due to central body oblatenes at beginning of step From 25fbdda2c64a68b192fa04bc66b5e2d7ddd23702 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Thu, 14 Sep 2023 15:17:42 -0400 Subject: [PATCH 046/324] Fixed some typos --- src/swiftest/swiftest_io.f90 | 4 +++- src/swiftest/swiftest_module.f90 | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 88e5d6f8c..f804b8db7 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1324,7 +1324,9 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, START = [ASK_DAVE] count = [2, l (ASK_DAVE), ASK_DAVE ]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%name_dimid, len=idmax), "netcdf_io_read_frame_system nf90_inquire_dimension name_dimid" ) ! CHECK + allocate(cb%c_lm(shape_from_above)) + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, start = [ASK_DAVE] count = [2, l (ASK_DAVE), ASK_DAVE ]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") else cb%c_lm = 0.0_DP end if diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index a3f6ac3d1..70614edcd 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -200,7 +200,7 @@ module swiftest real(DP) :: density = 1.0_DP !! Central body mass density - calculated internally (units MU / DU**3) real(DP) :: j2rp2 = 0.0_DP !! J2*R^2 term for central body real(DP) :: j4rp4 = 0.0_DP !! J4*R^4 term for central body - real(DP), dimension(:,:,:) :: c_lm = 0.0_DP !! Spherical Harmonics coefficients for the central body + real(DP), dimension(:,:,:), allocatable :: c_lm = 0.0_DP !! Spherical Harmonics coefficients for the central body real(DP), dimension(NDIM) :: aobl = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: atide = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: aoblbeg = 0.0_DP !! Barycentric acceleration due to central body oblatenes at beginning of step From 9ea4b0643efd3b5c6410673884ac84aefdec5ec5 Mon Sep 17 00:00:00 2001 From: Kaustub Anand Date: Sun, 17 Sep 2023 16:18:44 -0400 Subject: [PATCH 047/324] Added nf90 inquire dimensions for read_frame --- src/netcdf_io/netcdf_io_module.f90 | 7 +++++++ src/swiftest/swiftest_io.f90 | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index 6fb2dcadd..24e3d6948 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -43,6 +43,13 @@ module netcdf_io integer(I4B) :: space_dimid !! ID for the space dimension integer(I4B) :: space_varid !! ID for the space variable character(len=1), dimension(3) :: space_coords = ["x","y","z"] !! The space dimension coordinate labels + character(NAMELEN) :: l_dimname = "l" !! name of l dimension for c_lm + integer(I4B) :: l_dimid !! ID for the l dimension for c_lm + integer(I4B) :: l_varid !! ID for the l variable + character(NAMELEN) :: m_dimname = "m" !! name of m dimension for c_lm + integer(I4B) :: m_dimid !! ID for the m dimension for c_lm + integer(I4B) :: m_varid !! ID for the m variable + ! Non-dimension ids and variable names character(NAMELEN) :: id_varname = "id" !! name of the particle id variable diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index f804b8db7..0219db28e 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1141,6 +1141,7 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier integer(I4B) :: ierr !! Error code: returns 0 if the read is successful ! Internals integer(I4B) :: i, idmax, npl_check, ntp_check, str_max, status, npl, ntp + integer(I4B) :: l_dim_max, m_dim_max ! dimensions for c_lm array real(DP), dimension(:), allocatable :: rtemp real(DP), dimension(:,:), allocatable :: vectemp integer(I4B), dimension(:), allocatable :: itemp @@ -1324,9 +1325,11 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%name_dimid, len=idmax), "netcdf_io_read_frame_system nf90_inquire_dimension name_dimid" ) ! CHECK - allocate(cb%c_lm(shape_from_above)) - call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, start = [ASK_DAVE] count = [2, l (ASK_DAVE), ASK_DAVE ]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") + + allocate(cb%c_lm(2, l_dim_max, m_dim_max)) + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = (2, l_dim_max, m_dim_max)), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") else cb%c_lm = 0.0_DP end if From a2f0a077800a1a77dfe08dc72c7050959aa39512 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 18 Sep 2023 12:19:27 -0400 Subject: [PATCH 048/324] added framework for I/O for c_lm for netcdf files. ASCII next --- src/swiftest/swiftest_io.f90 | 38 +++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 8fe8884ea..7f260adee 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -982,6 +982,12 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%j4rp4_varname, nc%out_type, nc%time_dimid, nc%j4rp4_varid), & "netcdf_io_initialize_output nf90_def_var j4rp4_varid" ) + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [2, nc%l_dimid, nc%m_dimid], nc%c_lm_varid), & + "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) + end if + ! Set fill mode to NaN for all variables call netcdf_io_check( nf90_inquire(nc%id, nVariables=nvar), "netcdf_io_initialize_output nf90_inquire nVariables" ) do varid = 1, nvar @@ -1072,6 +1078,14 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) call netcdf_io_check( nf90_inq_dimid(nc%id, nc%str_dimname, nc%str_dimid), & "swiftest_io_netcdf_open nf90_inq_dimid str_dimid" ) + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, cs%l_dimid), & + "swiftest_io_netcdf_open nf90_inq_dimid l_dimid") + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, cs%m_dimid), & + "swiftest_io_netcdf_open nf90_inq_dimid m_dimid") + end if + ! Dimension coordinates call netcdf_io_check( nf90_inq_varid(nc%id, nc%time_dimname, nc%time_varid), & "swiftest_io_netcdf_open nf90_inq_varid time_varid" ) @@ -1079,6 +1093,13 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) "swiftest_io_netcdf_open nf90_inq_varid space_varid" ) call netcdf_io_check( nf90_inq_varid(nc%id, nc%name_dimname, nc%name_varid), & "swiftest_io_netcdf_open nf90_inq_varid name_varid" ) + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, cs%l_varid), & + "swiftest_io_netcdf_open nf90_inq_dimid l_varid") + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, cs%m_varid), & + "swiftest_io_netcdf_open nf90_inq_dimid m_varid") + end if ! Required Variables call netcdf_io_check( nf90_inq_varid(nc%id, nc%id_varname, nc%id_varid), & @@ -1181,6 +1202,8 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) status = nf90_inq_varid(nc%id, nc%GMescape_varname, nc%GMescape_varid) end if + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + end associate return @@ -2019,6 +2042,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals integer(I4B) :: idslot, old_mode, tmp + integer(I4B) :: l_dim_max, m_dim_max associate(tslot => nc%tslot) call self%write_info(nc, param) @@ -2050,6 +2074,18 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cby nf90_put_var cb rot_varid" ) end if + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") + + !! allocate(cb%c_lm(2, l_dim_max, m_dim_max)) + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, cb%c_lm, count = (2, l_dim_max, m_dim_max)), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + else + cb%c_lm = 0.0_DP + end if + !!end if + call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp), & "swiftest_io_netcdf_write_frame_cb nf90_set_fill old_mode" ) end associate @@ -3271,7 +3307,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) param%lshgrav = (size(self%cb%c_lm) /= 0.0_DP) - param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not.param%lshgrav) + param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) if (.not.param%loblatecb) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) From 4e239c641571f94b5fd7da51dce3306cbf968acc Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 18 Sep 2023 15:26:16 -0400 Subject: [PATCH 049/324] fixed compilation error of defualt value for c_lm --- src/swiftest/swiftest_module.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 70614edcd..c7a08c139 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -200,7 +200,7 @@ module swiftest real(DP) :: density = 1.0_DP !! Central body mass density - calculated internally (units MU / DU**3) real(DP) :: j2rp2 = 0.0_DP !! J2*R^2 term for central body real(DP) :: j4rp4 = 0.0_DP !! J4*R^4 term for central body - real(DP), dimension(:,:,:), allocatable :: c_lm = 0.0_DP !! Spherical Harmonics coefficients for the central body + real(DP), dimension(:,:,:), allocatable :: c_lm !! Spherical Harmonics coefficients for the central body real(DP), dimension(NDIM) :: aobl = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: atide = 0.0_DP !! Barycentric acceleration due to central body oblatenes real(DP), dimension(NDIM) :: aoblbeg = 0.0_DP !! Barycentric acceleration due to central body oblatenes at beginning of step From c0228df949fa0c0e388aa804b07380322db64610 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 18 Sep 2023 15:27:37 -0400 Subject: [PATCH 050/324] fixed allocation error for c_lm --- src/swiftest/swiftest_io.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 7f260adee..311a21aca 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1526,7 +1526,8 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier allocate(cb%c_lm(2, l_dim_max, m_dim_max)) call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = (2, l_dim_max, m_dim_max)), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") else - cb%c_lm = 0.0_DP + allocate(cb%c_lm(1, 0, 0)) + cb%c_lm(:) = 0.0_DP end if call self%read_particle_info(nc, param, plmask, tpmask) From 341920672e78d355e0e1e6bde47a06f36a7037d4 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Mon, 18 Sep 2023 15:54:03 -0400 Subject: [PATCH 051/324] changed param%lshgrav flag --- src/swiftest/swiftest_io.f90 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 311a21aca..0ab86f5c0 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1525,9 +1525,7 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier allocate(cb%c_lm(2, l_dim_max, m_dim_max)) call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = (2, l_dim_max, m_dim_max)), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") - else - allocate(cb%c_lm(1, 0, 0)) - cb%c_lm(:) = 0.0_DP + end if call self%read_particle_info(nc, param, plmask, tpmask) @@ -3306,7 +3304,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (ierr /=0) call base_util_exit(FAILURE,param%display_unit) end if - param%lshgrav = (size(self%cb%c_lm) /= 0.0_DP) + param%lshgrav = allocated(cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) if (.not.param%loblatecb) then From b45ab0e468e12f6c4502140222c0fb78aa72c78c Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 18 Sep 2023 16:10:55 -0400 Subject: [PATCH 052/324] Added basic SHTOOLS cmake find script (not done) --- cmake/Modules/FindSHTOOLS.cmake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cmake/Modules/FindSHTOOLS.cmake diff --git a/cmake/Modules/FindSHTOOLS.cmake b/cmake/Modules/FindSHTOOLS.cmake new file mode 100644 index 000000000..60ef8362f --- /dev/null +++ b/cmake/Modules/FindSHTOOLS.cmake @@ -0,0 +1,17 @@ +# Copyright 2023 - David Minton +# This file is part of Swiftest. +# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with Swiftest. +# If not, see: https://www.gnu.org/licenses. + +# - Finds the SHTOOLS library +find_path(SHTOOLS_INCLUDE_DIR NAMES shtools.h HINTS ENV SHTOOLS_HOME PATH_SUFFIXES include) +find_library(SHTOOLS_LIBRARY NAMES libSHTOOLS-mp.a libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) + +set(SHTOOLS_FOUND TRUE) +set(SHTOOLS_INCLUDE_DIRS ${SHTOOLS_INCLUDE_DIR}) +set(SHTOOLS_LIBRARIES ${SHTOOLS_LIBRARY}) +mark_as_advanced(SHTOOLS_LIBRARY SHTOOLS_INCLUDE_DIR) \ No newline at end of file From 84d9ca3be12657299a7392835a4330497deda5ed Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 18 Sep 2023 18:19:41 -0400 Subject: [PATCH 053/324] Fleshed out the cmake module files for SHTOOLS and its FFTW dependency --- cmake/Modules/FindFFTW3.cmake | 15 +++++++++++++++ cmake/Modules/FindSHTOOLS.cmake | 7 +++---- src/CMakeLists.txt | 16 ++++++++++++---- 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 cmake/Modules/FindFFTW3.cmake diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake new file mode 100644 index 000000000..9c68201f1 --- /dev/null +++ b/cmake/Modules/FindFFTW3.cmake @@ -0,0 +1,15 @@ +# Copyright 2023 - David Minton +# This file is part of Swiftest. +# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with Swiftest. +# If not, see: https://www.gnu.org/licenses. + +# - Finds the FFTW3 library +find_path(FFTW3_INCLUDE_DIR NAMES fftw3.h HINTS ENV FFTW3_HOME PATH_SUFFIXES include) +find_library(FFTW3_LIBRARY NAMES libfftw.a HINTS ENV FFTW3_HOME PATH_SUFFIXES lib) + +set(FFTW3_FOUND TRUE) +mark_as_advanced(FFTW3_LIBRARY FFTW3_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/FindSHTOOLS.cmake b/cmake/Modules/FindSHTOOLS.cmake index 60ef8362f..c6bb08a14 100644 --- a/cmake/Modules/FindSHTOOLS.cmake +++ b/cmake/Modules/FindSHTOOLS.cmake @@ -9,9 +9,8 @@ # - Finds the SHTOOLS library find_path(SHTOOLS_INCLUDE_DIR NAMES shtools.h HINTS ENV SHTOOLS_HOME PATH_SUFFIXES include) -find_library(SHTOOLS_LIBRARY NAMES libSHTOOLS-mp.a libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) +find_library(SHTOOLS_LIBRARY NAMES libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) +find_library(SHTOOLS_LIBRARY_MP NAMES libSHTOOLS-mp.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) set(SHTOOLS_FOUND TRUE) -set(SHTOOLS_INCLUDE_DIRS ${SHTOOLS_INCLUDE_DIR}) -set(SHTOOLS_LIBRARIES ${SHTOOLS_LIBRARY}) -mark_as_advanced(SHTOOLS_LIBRARY SHTOOLS_INCLUDE_DIR) \ No newline at end of file +mark_as_advanced(SHTOOLS_LIBRARY SHTOOLS_LIBRARY_MP SHTOOLS_INCLUDE_DIR) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88b197744..b75dd43c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,8 @@ INCLUDE(SetUpNetCDF) IF (COMPILER_OPTIONS STREQUAL "Intel" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") INCLUDE(SetMKL) ENDIF () +FIND_PACKAGE(SHTOOLS REQUIRED) +FIND_PACKAGE(FFTW3 REQUIRED) # Add the source files SET(STRICT_MATH_FILES @@ -141,14 +143,20 @@ IF (NOT BUILD_SHARED_LIBS) SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} PROPERTY POSITION_INDEPENDENT_CODE) ENDIF () -TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_INCLUDE_DIR}) -TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_DRIVER} PUBLIC ${NETCDF_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_LIBRARIES}) -TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY} ${NETCDF_LIBRARIES}) +TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_INCLUDE_DIR} ${SHTOOLS_INCLUDE_DIR} ${FFTW3_INCLUDE_DIR}) +TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_DRIVER} PUBLIC ${NETCDF_INCLUDE_DIR} ${SHTOOLS_INCLUDE_DIR} ${FFTW3_INCLUDE_DIR}) +TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_LIBRARIES} ${FFTW3_LIBRARY}) +TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY} ${NETCDF_LIBRARIES} ${FFTW3_LIBRARY}) IF(USE_OPENMP OR USE_SIMD) + TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${SHTOOLS_LIBRARY_MP}) + TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SHTOOLS_LIBRARY_MP}) + SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} APPEND_STRING PROPERTY COMPILE_FLAGS "${OpenMP_Fortran_FLAGS} ") SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} APPEND_STRING PROPERTY LINK_FLAGS "${OpenMP_Fortran_FLAGS} ") +ELSE () + TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${SHTOOLS_LIBRARY}) + TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SHTOOLS_LIBRARY}) ENDIF() IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") From 89a3f68898fe501c0b7f1b64163781d7a63b14cd Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 18 Sep 2023 18:59:48 -0400 Subject: [PATCH 054/324] Got rid of dedicated FFTW finder --- cmake/Modules/FindFFTW3.cmake | 15 --------------- src/CMakeLists.txt | 5 ++--- 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 cmake/Modules/FindFFTW3.cmake diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake deleted file mode 100644 index 9c68201f1..000000000 --- a/cmake/Modules/FindFFTW3.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2023 - David Minton -# This file is part of Swiftest. -# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# You should have received a copy of the GNU General Public License along with Swiftest. -# If not, see: https://www.gnu.org/licenses. - -# - Finds the FFTW3 library -find_path(FFTW3_INCLUDE_DIR NAMES fftw3.h HINTS ENV FFTW3_HOME PATH_SUFFIXES include) -find_library(FFTW3_LIBRARY NAMES libfftw.a HINTS ENV FFTW3_HOME PATH_SUFFIXES lib) - -set(FFTW3_FOUND TRUE) -mark_as_advanced(FFTW3_LIBRARY FFTW3_INCLUDE_DIR) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b75dd43c8..702648d50 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,7 +22,6 @@ IF (COMPILER_OPTIONS STREQUAL "Intel" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Window INCLUDE(SetMKL) ENDIF () FIND_PACKAGE(SHTOOLS REQUIRED) -FIND_PACKAGE(FFTW3 REQUIRED) # Add the source files SET(STRICT_MATH_FILES @@ -145,8 +144,8 @@ ENDIF () TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_INCLUDE_DIR} ${SHTOOLS_INCLUDE_DIR} ${FFTW3_INCLUDE_DIR}) TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_DRIVER} PUBLIC ${NETCDF_INCLUDE_DIR} ${SHTOOLS_INCLUDE_DIR} ${FFTW3_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_LIBRARIES} ${FFTW3_LIBRARY}) -TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY} ${NETCDF_LIBRARIES} ${FFTW3_LIBRARY}) +TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${NETCDF_LIBRARIES}) +TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY} ${NETCDF_LIBRARIES}) IF(USE_OPENMP OR USE_SIMD) TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC ${SHTOOLS_LIBRARY_MP}) From 2187347ea1b1c8675a6e00fbbac9d1de8eda041e Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 19 Sep 2023 07:56:13 -0400 Subject: [PATCH 055/324] Added SHTOOLS to the CI dependency build scripts --- buildscripts/build_dependencies.sh | 1 + buildscripts/build_shtools.sh | 52 ++++++++++++++++++++++++++++++ pyproject.toml | 4 +-- 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100755 buildscripts/build_shtools.sh diff --git a/buildscripts/build_dependencies.sh b/buildscripts/build_dependencies.sh index 8d8027aa6..701552c47 100755 --- a/buildscripts/build_dependencies.sh +++ b/buildscripts/build_dependencies.sh @@ -35,6 +35,7 @@ ${SCRIPT_DIR}/build_zlib.sh ${ARGS} ${SCRIPT_DIR}/build_hdf5.sh ${ARGS} ${SCRIPT_DIR}/build_netcdf-c.sh ${ARGS} ${SCRIPT_DIR}/build_netcdf-fortran.sh ${ARGS} +${SCRIPT_DIR}/build_shtools.sh ${ARGS} printf "\n" printf "*********************************************************\n" diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh new file mode 100755 index 000000000..546663ea0 --- /dev/null +++ b/buildscripts/build_shtools.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Builds the following from source: SHTOOLS +# +# Copyright 2023 - David Minton +# This file is part of Swiftest. +# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with Swiftest. +# If not, see: https://www.gnu.org/licenses. +SCRIPT_DIR=$(realpath $(dirname $0)) +set -a +ARGS=$@ +. ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} + +SHTOOLS_VER="4.10.4" + +printf "*********************************************************\n" +printf "* FETCHING SHTOOLS SOURCE *\n" +printf "*********************************************************\n" +printf "Copying files to ${DEPENDENCY_DIR}\n" +mkdir -p ${DEPENDENCY_DIR} +if [ ! -d ${DEPENDENCY_DIR}/SHTOOLS-${SHTOOLS_VER} ]; then + [ -d ${DEPENDENCY_DIR}/SHTOOLS-* ] && rm -rf ${DEPENDENCY_DIR}/SHTOOLS-* + curl -L https://github.com/SHTOOLS/SHTOOLS/releases/download/v${SHTOOLS_VER}/SHTOOLS-${SHTOOLS_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} +fi + +printf "*********************************************************\n" +printf "* BUILDING SHTOOLS LIBRARY *\n" +printf "*********************************************************\n" +printf "LIBS: ${LIBS}\n" +printf "CFLAGS: ${CFLAGS}\n" +printf "CPPFLAGS: ${CPPFLAGS}\n" +printf "CPATH: ${CPATH}\n" +printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" +printf "LDFLAGS: ${LDFLAGS}\n" +printf "*********************************************************\n" + +cd ${DEPENDENCY_DIR}/SHTOOLS-* +make F95="${FC}" CXX="${CXX}" fortran +make F95="${FC}" CXX="${CXX}" fortran-mp +if [ -w ${PREFIX} ]; then + make PREFIX="${PREFIX}" install +else + sudo make PREFIX="${PREFIX}" install +fi + +if [ $? -ne 0 ]; then + printf "SHTOOLS could not be compiled.\n" + exit 1 +fi \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index a66de5da9..941d9078f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,13 +96,13 @@ RANLIB="/usr/bin/ranlib" [tool.cibuildwheel.macos] before-all = [ - "brew install coreutils", + "brew install coreutils shtools", "LIBS=\"\" buildscripts/build_dependencies.sh -p ${PREFIX} -d ${PREFIX}/build -m ${MACOSX_DEPLOYMENT_TARGET}" ] [tool.cibuildwheel.linux] before-all = [ - "yum install doxygen libxml2-devel libcurl-devel -y", + "yum install doxygen libxml2-devel libcurl-devel libfftw3-dev libblas-dev liblapack-dev -y", "buildscripts/build_dependencies.sh -p /usr/local" ] [tool.cibuildwheel.linux.environment] From bc2123fb09261d26a8d565bf832b2ef9d8b5c28e Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Tue, 19 Sep 2023 09:19:10 -0400 Subject: [PATCH 056/324] Fixed names of rpm packages --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 941d9078f..c03f56773 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,7 +102,7 @@ before-all = [ [tool.cibuildwheel.linux] before-all = [ - "yum install doxygen libxml2-devel libcurl-devel libfftw3-dev libblas-dev liblapack-dev -y", + "yum install doxygen libxml2-devel libcurl-devel ftw3-devel libblas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] [tool.cibuildwheel.linux.environment] From b6e85fc5dcd40692d0dc6b8bde919086b70cab54 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 19 Sep 2023 09:47:22 -0400 Subject: [PATCH 057/324] Cleaned up build scripts and made the cmake script outputs more useful and consistent --- buildscripts/_build_getopts.sh | 4 +++- buildscripts/get_platform.sh | 2 -- buildscripts/set_compilers.sh | 7 +++++-- cmake/Modules/FindNETCDF.cmake | 9 ++------- cmake/Modules/FindSHTOOLS.cmake | 13 ++++++++----- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/buildscripts/_build_getopts.sh b/buildscripts/_build_getopts.sh index ac9e9586b..2bec70cb1 100755 --- a/buildscripts/_build_getopts.sh +++ b/buildscripts/_build_getopts.sh @@ -15,7 +15,9 @@ ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) # Parse arguments USTMT="Usage: ${0} [-d /path/to/dependency/source] [-p /prefix/path] [-m MACOSX_DEPLOYMENT_TARGET]" -MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-"$(sw_vers --ProductVersion)"} +if [ $OS = "MacOSX" ]; then + MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-"$(sw_vers --ProductVersion)"} +fi while getopts ":d:p:m:h" ARG; do case "${ARG}" in diff --git a/buildscripts/get_platform.sh b/buildscripts/get_platform.sh index 4ad7d8aeb..583510fb3 100755 --- a/buildscripts/get_platform.sh +++ b/buildscripts/get_platform.sh @@ -21,7 +21,6 @@ OS=$(uname -s) ARCH=$(uname -m) - case $ARCH in x86_64) ;; @@ -44,7 +43,6 @@ case $ARCH in ;; esac - case $OS in Linux) ;; diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index 7523628ee..94cbf1511 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -13,7 +13,10 @@ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # You should have received a copy of the GNU General Public License along with Swiftest. # If not, see: https://www.gnu.org/licenses. -# Parse arguments +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +read -r OS ARCH < <($SCRIPT_DIR/get_platform.sh) case "$OS" in Linux|MacOSX) ;; @@ -25,7 +28,6 @@ case "$OS" in ;; esac - set -a # Only replace compiler definitions if they are not already set case $OS in @@ -59,5 +61,6 @@ case $OS in ;; esac F77=${FC} +F95=${FC} printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n\n" \ No newline at end of file diff --git a/cmake/Modules/FindNETCDF.cmake b/cmake/Modules/FindNETCDF.cmake index 05f91e77c..cee2fabad 100644 --- a/cmake/Modules/FindNETCDF.cmake +++ b/cmake/Modules/FindNETCDF.cmake @@ -51,7 +51,6 @@ IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") ENDIF() ENDIF() -MESSAGE(STATUS "\nNETCDF_INCLUDE: $ENV{NETCDF_INCLUDE}\nNETCDF_FORTRAN_HOME: $ENV{NETCDF_FORTRAN_HOME}\n") FIND_PATH(NETCDF_INCLUDE_DIR NAMES netcdf.mod HINTS @@ -66,8 +65,6 @@ FIND_PATH(NETCDF_INCLUDE_DIR REQUIRED ) -MESSAGE(STATUS "NetCDF-Fortran include directory: ${NETCDF_INCLUDE_DIR}") - IF (BUILD_SHARED_LIBS) SET(NETCDFF "netcdff") ELSE () @@ -102,8 +99,6 @@ FIND_LIBRARY(NETCDF_FORTRAN_LIBRARY REQUIRED ) -MESSAGE(STATUS "NetCDF-Fortran Library: ${NETCDF_FORTRAN_LIBRARY}") - IF (BUILD_SHARED_LIBS) SET(NETCDF_LIBRARIES ${NETCDF_FORTRAN_LIBRARY} CACHE STRING "NetCDF Fortran library") ELSE () @@ -119,7 +114,6 @@ ELSE () REQUIRED ) - MESSAGE(STATUS "NetCDF-C Library: ${NETCDF_LIBRARY}") IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") FIND_LIBRARY(HDF5_LIBRARY NAMES ${HDF5} @@ -201,7 +195,8 @@ ELSE () # Note for posterity: When building static libraries, NETCDF_FORTRAN_LIBRARY must come *before* NETCDF_LIBRARY. Otherwise you get a bunch of "undefined reference to" errors SET(NETCDF_LIBRARIES ${NETCDF_FORTRAN_LIBRARY} ${NETCDF_LIBRARY} ${EXTRA_FLAGS} CACHE STRING "NetCDF Fortran and dependant static libraries") ENDIF () -MESSAGE(STATUS "NetCDF dependencies: ${NETCDF_LIBRARIES}") +MESSAGE(STATUS "NetCDF libraries: ${NETCDF_LIBRARIES}") +MESSAGE(STATUS "NetCDF include directory: ${NETCDF_INCLUDE_DIR}") SET(NETCDF_FOUND TRUE) MARK_AS_ADVANCED(NETCDF_LIBRARIES NETCDF_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/FindSHTOOLS.cmake b/cmake/Modules/FindSHTOOLS.cmake index c6bb08a14..13e3531b2 100644 --- a/cmake/Modules/FindSHTOOLS.cmake +++ b/cmake/Modules/FindSHTOOLS.cmake @@ -8,9 +8,12 @@ # If not, see: https://www.gnu.org/licenses. # - Finds the SHTOOLS library -find_path(SHTOOLS_INCLUDE_DIR NAMES shtools.h HINTS ENV SHTOOLS_HOME PATH_SUFFIXES include) -find_library(SHTOOLS_LIBRARY NAMES libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) -find_library(SHTOOLS_LIBRARY_MP NAMES libSHTOOLS-mp.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) +FIND_PATH(SHTOOLS_INCLUDE_DIR NAMES shtools.h HINTS ENV SHTOOLS_HOME PATH_SUFFIXES include) +FIND_LIBRARY(SHTOOLS_LIBRARY NAMES libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) +FIND_LIBRARY(SHTOOLS_LIBRARY_MP NAMES libSHTOOLS-mp.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) -set(SHTOOLS_FOUND TRUE) -mark_as_advanced(SHTOOLS_LIBRARY SHTOOLS_LIBRARY_MP SHTOOLS_INCLUDE_DIR) \ No newline at end of file +SET(SHTOOLS_FOUND TRUE) +MARK_AS_ADVANCED(SHTOOLS_LIBRARY SHTOOLS_LIBRARY_MP SHTOOLS_INCLUDE_DIR) +MESSAGE(STATUS "SHTOOLS library: ${SHTOOLS_LIBRARY}") +MESSAGE(STATUS "SHTOOLS OpenMP library: ${SHTOOLS_LIBRARY_MP}") +MESSAGE(STATUS "SHTOOLS include dir: ${SHTOOLS_INCLUDE_DIR}") From 9c0e7fbd10ae0e5ea8b39936df4c0334881e384f Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 19 Sep 2023 14:17:07 -0400 Subject: [PATCH 058/324] fixed array brakcets --- src/swiftest/swiftest_io.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 0ab86f5c0..da86be907 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1524,7 +1524,7 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") allocate(cb%c_lm(2, l_dim_max, m_dim_max)) - call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = (2, l_dim_max, m_dim_max)), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") end if @@ -2079,7 +2079,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") !! allocate(cb%c_lm(2, l_dim_max, m_dim_max)) - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, cb%c_lm, count = (2, l_dim_max, m_dim_max)), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") else cb%c_lm = 0.0_DP end if From 669313a1d51d92d036203bd3b4faae8265f59ff3 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Tue, 19 Sep 2023 15:08:00 -0400 Subject: [PATCH 059/324] debugged swiftest_io --- src/swiftest/swiftest_io.f90 | 21 ++++++++++----------- src/swiftest/swiftest_module.f90 | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index da86be907..536ef7a4d 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -785,6 +785,7 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters ! Internals integer(I4B) :: nvar, varid, vartype + integer(I4B) :: status real(DP) :: dfill real(SP) :: sfill integer(I4B), parameter :: NO_FILL = 0 @@ -1080,9 +1081,9 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, cs%l_dimid), & + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, nc%l_dimid), & "swiftest_io_netcdf_open nf90_inq_dimid l_dimid") - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, cs%m_dimid), & + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, nc%m_dimid), & "swiftest_io_netcdf_open nf90_inq_dimid m_dimid") end if @@ -1095,9 +1096,9 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) "swiftest_io_netcdf_open nf90_inq_varid name_varid" ) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, cs%l_varid), & + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, nc%l_varid), & "swiftest_io_netcdf_open nf90_inq_dimid l_varid") - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, cs%m_varid), & + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, nc%m_varid), & "swiftest_io_netcdf_open nf90_inq_dimid m_varid") end if @@ -2036,12 +2037,13 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) !! Write a frame of output of the central body implicit none ! Arguments - class(swiftest_cb), intent(in) :: self !! Swiftest base object + class(swiftest_cb), intent(inout) :: self !! Swiftest base object class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals integer(I4B) :: idslot, old_mode, tmp integer(I4B) :: l_dim_max, m_dim_max + integer(I4B) :: status associate(tslot => nc%tslot) call self%write_info(nc, param) @@ -2078,12 +2080,9 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") - !! allocate(cb%c_lm(2, l_dim_max, m_dim_max)) - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") - else - cb%c_lm = 0.0_DP + allocate(self%c_lm(2, l_dim_max, m_dim_max)) + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") end if - !!end if call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp), & "swiftest_io_netcdf_write_frame_cb nf90_set_fill old_mode" ) @@ -3304,7 +3303,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (ierr /=0) call base_util_exit(FAILURE,param%display_unit) end if - param%lshgrav = allocated(cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) + param%lshgrav = allocated(self%cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) if (.not.param%loblatecb) then diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index c7a08c139..2d0f1c7b4 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -742,7 +742,7 @@ end subroutine swiftest_io_netcdf_write_frame_body module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) implicit none - class(swiftest_cb), intent(in) :: self !! Swiftest base object + class(swiftest_cb), intent(inout) :: self !! Swiftest base object class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_frame_cb From 0c578dd61155e57f2fe67f713cd16552955252c3 Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 20 Sep 2023 10:12:24 -0400 Subject: [PATCH 060/324] debugging pt. 2. Fixed arguments in obl.f90 and typos --- src/swiftest/swiftest_io.f90 | 6 +++--- src/swiftest/swiftest_obl.f90 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 536ef7a4d..40405901b 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2077,11 +2077,11 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension l_dimid") + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension m_dimid") allocate(self%c_lm(2, l_dim_max, m_dim_max)) - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_write_frame_cb nf90_getvar c_lm_varid") end if call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp), & diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index dee331e26..fd0260fc4 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -256,7 +256,7 @@ module subroutine swiftest_obl_acc_tp(self, nbody_system) associate(tp => self, cb => nbody_system%cb) ntp = self%nbody - call swiftest_obl_acc(ntp, cb%Gmass, cb%j2rp2, cb%j4rp4, tp%rh, tp%lmask, tp%aobl) + call swiftest_obl_acc(ntp, cb%Gmass, cb%j2rp2, cb%j4rp4, tp%rh, tp%lmask, tp%aobl, cb%rot) if (nbody_system%lbeg) then aoblcb = cb%aoblbeg else From 4e4b1560306f8e383dd3f68d018f2748d6544d5c Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 20 Sep 2023 10:30:39 -0400 Subject: [PATCH 061/324] Added accel_sph (spherical harmonicsc acceleration) to whm_module for pl and tps --- src/whm/whm_kick.f90 | 5 +++-- src/whm/whm_module.f90 | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index 7d236ef4f..9c6a2a248 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -59,7 +59,8 @@ module subroutine whm_kick_getacch_pl(self, nbody_system, param, t, lbeg) end if if(param%lshgrav) then - call pl%swiftest_sph_g_acc_pl_all(nbody_system) + call pl%accel_sph(nbody_system) + end if if (param%lgr) call pl%accel_gr(param) @@ -117,7 +118,7 @@ module subroutine whm_kick_getacch_tp(self, nbody_system, param, t, lbeg) end if if (param%loblatecb) call tp%accel_obl(nbody_system) - if (param%lshgrav) call tp%swiftest_sph_g_acc_tp_all(nbody_system) + if (param%lshgrav) call tp%accel_sph(nbody_system) if (param%lextra_force) call tp%accel_user(nbody_system, param, t, lbeg) if (param%lgr) call tp%accel_gr(param) end associate diff --git a/src/whm/whm_module.f90 b/src/whm/whm_module.f90 index 38e73f190..09932ed0b 100644 --- a/src/whm/whm_module.f90 +++ b/src/whm/whm_module.f90 @@ -38,6 +38,7 @@ module whm procedure :: drift => whm_drift_pl !! Loop through massive bodies and call Danby drift routine to jacobi coordinates procedure :: accel_gr => whm_gr_kick_getacch_pl !! Acceleration term arising from the post-Newtonian correction procedure :: gr_pos_kick => whm_gr_p4_pl !! Position kick due to p**4 term in the post-Newtonian correction + procedure :: accel_sph => swiftest_sph_g_acc_pl_all !! Acceleration due ot spherical harmonics terms procedure :: accel => whm_kick_getacch_pl !! Compute heliocentric accelerations of massive bodies procedure :: kick => whm_kick_vh_pl !! Kick heliocentric velocities of massive bodies procedure :: append => whm_util_append_pl !! Appends elements from one structure to another @@ -66,6 +67,7 @@ module whm procedure :: accel_gr => whm_gr_kick_getacch_tp !! Acceleration term arising from the post-Newtonian correction procedure :: gr_pos_kick => whm_gr_p4_tp !! Position kick due to p**4 term in the post-Newtonian correction procedure :: accel => whm_kick_getacch_tp !! Compute heliocentric accelerations of test particles + procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics procedure :: kick => whm_kick_vh_tp !! Kick heliocentric velocities of test particles procedure :: step => whm_step_tp !! Steps the particle forward one stepsize final :: whm_final_tp !! Finalizes the WHM test particle object - deallocates all allocatables From 2c62fed5d634b19c65848ce48242e948e34cb9ff Mon Sep 17 00:00:00 2001 From: Kaustub Parvir Anand Date: Wed, 20 Sep 2023 10:33:19 -0400 Subject: [PATCH 062/324] Moved accel_sph to swiftest_module from whm_module --- src/swiftest/swiftest_module.f90 | 4 +++- src/whm/whm_module.f90 | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 2d0f1c7b4..915931f02 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -268,7 +268,8 @@ module swiftest procedure :: accel_int => swiftest_kick_getacch_int_pl !! Compute direct cross (third) term heliocentric accelerations of massive bodies procedure :: accel_obl => swiftest_obl_acc_pl !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure :: setup => swiftest_util_setup_pl !! A base constructor that sets the number of bodies and allocates and initializes all arrays - ! procedure :: accel_tides => tides_kick_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body + procedure :: accel_sph => swiftest_sph_g_acc_pl_all !! Acceleration due ot spherical harmonics terms + ! procedure :: accel_tides => tides_kick_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body procedure :: append => swiftest_util_append_pl !! Appends elements from one structure to another procedure :: h2b => swiftest_util_coord_h2b_pl !! Convert massive bodies from heliocentric to barycentric coordinates (position and velocity) procedure :: b2h => swiftest_util_coord_b2h_pl !! Convert massive bodies from barycentric to heliocentric coordinates (position and velocity) @@ -309,6 +310,7 @@ module swiftest procedure :: discard => swiftest_discard_tp !! Check to see if test particles should be discarded based on their positions relative to the massive bodies procedure :: accel_int => swiftest_kick_getacch_int_tp !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies procedure :: accel_obl => swiftest_obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body + procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and procedure :: append => swiftest_util_append_tp !! Appends elements from one structure to another procedure :: h2b => swiftest_util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) diff --git a/src/whm/whm_module.f90 b/src/whm/whm_module.f90 index 09932ed0b..38e73f190 100644 --- a/src/whm/whm_module.f90 +++ b/src/whm/whm_module.f90 @@ -38,7 +38,6 @@ module whm procedure :: drift => whm_drift_pl !! Loop through massive bodies and call Danby drift routine to jacobi coordinates procedure :: accel_gr => whm_gr_kick_getacch_pl !! Acceleration term arising from the post-Newtonian correction procedure :: gr_pos_kick => whm_gr_p4_pl !! Position kick due to p**4 term in the post-Newtonian correction - procedure :: accel_sph => swiftest_sph_g_acc_pl_all !! Acceleration due ot spherical harmonics terms procedure :: accel => whm_kick_getacch_pl !! Compute heliocentric accelerations of massive bodies procedure :: kick => whm_kick_vh_pl !! Kick heliocentric velocities of massive bodies procedure :: append => whm_util_append_pl !! Appends elements from one structure to another @@ -67,7 +66,6 @@ module whm procedure :: accel_gr => whm_gr_kick_getacch_tp !! Acceleration term arising from the post-Newtonian correction procedure :: gr_pos_kick => whm_gr_p4_tp !! Position kick due to p**4 term in the post-Newtonian correction procedure :: accel => whm_kick_getacch_tp !! Compute heliocentric accelerations of test particles - procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics procedure :: kick => whm_kick_vh_tp !! Kick heliocentric velocities of test particles procedure :: step => whm_step_tp !! Steps the particle forward one stepsize final :: whm_final_tp !! Finalizes the WHM test particle object - deallocates all allocatables From 42b95d89ea4a85b6f42507637f5e0c580abccaae Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 20 Sep 2023 10:45:52 -0400 Subject: [PATCH 063/324] 'fixed a typo' --- src/swiftest/swiftest_module.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 915931f02..dd70fc6fb 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -311,7 +311,7 @@ module swiftest procedure :: accel_int => swiftest_kick_getacch_int_tp !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies procedure :: accel_obl => swiftest_obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics - procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and + procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and procedure :: append => swiftest_util_append_tp !! Appends elements from one structure to another procedure :: h2b => swiftest_util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) procedure :: b2h => swiftest_util_coord_b2h_tp !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) From de5609005353c24f5b86aeafed7573c79d072006 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 20 Sep 2023 10:49:29 -0400 Subject: [PATCH 064/324] 'fixed a typo' --- src/swiftest/swiftest_module.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index dd70fc6fb..c2d554e94 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -312,7 +312,7 @@ module swiftest procedure :: accel_obl => swiftest_obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and - procedure :: append => swiftest_util_append_tp !! Appends elements from one structure to another + procedure :: append => swiftest_util_append_tp git !! Appends elements from one structure to another procedure :: h2b => swiftest_util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) procedure :: b2h => swiftest_util_coord_b2h_tp !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) procedure :: vb2vh => swiftest_util_coord_vb2vh_tp !! Convert test particles from barycentric to heliocentric coordinates (velocity only) From 9274cec71b7c6875f1bf88b40a0d3948dc6d5165 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 20 Sep 2023 15:38:11 -0400 Subject: [PATCH 065/324] debugging pt 3; changed cmakelists.txt --- src/CMakeLists.txt | 1 + src/swiftest/swiftest_module.f90 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 702648d50..f426dd6fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,7 @@ SET(STRICT_MATH_FILES ${SRC}/swiftest/swiftest_user.f90 ${SRC}/swiftest/swiftest_obl.f90 ${SRC}/swiftest/swiftest_orbel.f90 + ${SRC}/swiftest/swiftest_sph.f90 ${SRC}/symba/symba_drift.f90 ${SRC}/symba/symba_gr.f90 ${SRC}/symba/symba_kick.f90 diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index c2d554e94..dd70fc6fb 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -312,7 +312,7 @@ module swiftest procedure :: accel_obl => swiftest_obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and - procedure :: append => swiftest_util_append_tp git !! Appends elements from one structure to another + procedure :: append => swiftest_util_append_tp !! Appends elements from one structure to another procedure :: h2b => swiftest_util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) procedure :: b2h => swiftest_util_coord_b2h_tp !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) procedure :: vb2vh => swiftest_util_coord_vb2vh_tp !! Convert test particles from barycentric to heliocentric coordinates (velocity only) From 8a9c9aa8f9c9389ea572d7530f3f730d5c4369bb Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 21 Sep 2023 10:02:10 -0400 Subject: [PATCH 066/324] debugging pt 4 --- src/swiftest/swiftest_drift.f90 | 1 + src/swiftest/swiftest_module.f90 | 8 ++++---- src/swiftest/swiftest_sph.f90 | 34 ++++++++++++++++++-------------- src/whm/whm_step.f90 | 3 +++ 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 82239e452..67d61e312 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -49,6 +49,7 @@ module subroutine swiftest_drift_body(self, nbody_system, param, dt) end if end do end if + end associate deallocate(iflag) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index dd70fc6fb..42d11aa84 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -212,7 +212,7 @@ module swiftest real(DP), dimension(NDIM) :: agr = 0.0_DP !! Acceleration due to post-Newtonian correction real(DP), dimension(NDIM) :: Ip = 0.0_DP !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. real(DP), dimension(NDIM) :: rot = 0.0_DP !! Body rotation vector in inertial coordinate frame (units rad / TU) - real(DP) :: rotphase = 0.0_DP !! Body rotation phase about the rotation pole + real(DP) :: rotphase = 0.0_DP !! Body rotation phase about the rotation pole (0 to 2*pi) real(DP) :: k2 = 0.0_DP !! Tidal Love number real(DP) :: Q = 0.0_DP !! Tidal quality factor real(DP) :: tlag = 0.0_DP !! Tidal phase lag angle @@ -1850,11 +1850,11 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in) :: r_0 !! radius of the central body real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) - real(DP), intent(in), dimension(:) :: rh !! distance vector of body + real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector + real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles - real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) end subroutine swiftest_sph_g_acc_one module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index da9dc036e..d34935f1c 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -29,41 +29,45 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in) :: r_0 !! radius of the central body real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) - real(DP), intent(in), dimension(:) :: rh !! distance vector of body + real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector + real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles - real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) ! Internals integer :: l, m !! SPH coefficients - real(DP) :: r_mag !! magnitude of rh - real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) integer :: l_max !! max Spherical Harmonic l order value + integer(I4B) :: N, lmindex !! Length of Legendre polynomials and index at a given l, m + real(DP) :: r_mag !! magnitude of rh real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m - integer(I4B) :: N + real(DP) :: ccss, cssc !! See definition in source code + real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) g_sph(:) = 0.0_DP r_mag = sqrt(dot_product(rh(:), rh(:))) l_max = size(c_lm, 2) - 1 N = (l_max + 1) * (l_max + 2) / 2 allocate(p(N),p_deriv(N)) - PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative + call PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative do l = 1, l_max do m = 0, l - ! Associated Legendre Polynomials - plm = p(PlmIndex(l, m)) ! p_l,m - dplm = p_deriv(PlmIndex(l, m)) ! d(p_l,m) + ! Associated Legendre Polynomials + lmindex = PlmIndex(l, m) + plm = p(lmindex) ! p_l,m + dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi - ccss = c_lm(1, l+1, m+1) * cos(m * phi) + c_lm(2, l+1, m+1) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) - cssc = -1 * c_lm(1, l+1, m+1) * sin(m * phi) + c_lm(2, l+1, m+1) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) - ! cssc * m = first derivative of ccss with respect to phi + ccss = c_lm(1, l+1, m+1) * cos(m * phi) & + + c_lm(2, l+1, m+1) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) + cssc = -1.0_DP * c_lm(1, l+1, m+1) * sin(m * phi) & + + c_lm(2, l+1, m+1) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) + ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 1) * (cssc * -1 * m * plm / rh(2) & + g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 1) * (-1.0_DP * cssc * m * plm / rh(2) & - ccss * (dplm * sin(theta) / (rh(3) * cos(phi)) & + plm * (l + 1) * rh(1) / r_mag**2)) ! g_x g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 1) * (cssc * m * plm / rh(1) & @@ -137,7 +141,7 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) do concurrent(i = 1:ntp, tp%lmask(i)) r_mag = .mag. rh(1:3,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%phase ! CALCULATE CB PHASE VALUE FOR PHI + phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) diff --git a/src/whm/whm_step.f90 b/src/whm/whm_step.f90 index 02812b428..96d181bc2 100644 --- a/src/whm/whm_step.f90 +++ b/src/whm/whm_step.f90 @@ -30,6 +30,9 @@ module subroutine whm_step_system(self, param, t, dt) call pl%step(nbody_system, param, t, dt) call tp%step(nbody_system, param, t, dt) ! if (param%ltides) call nbody_system%step_spin(param, t, dt) + + ! ! Update central body rotation phase + ! cb%rotphase = (.mag. cb%rot) * dt * param%TU2S end associate return end subroutine whm_step_system From 4ed92b04c306c06353dcbd471b7098209dce8f10 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 21 Sep 2023 10:57:46 -0400 Subject: [PATCH 067/324] added the 'cb rot phase update' after system step --- src/swiftest/swiftest_drift.f90 | 15 +++++++++++++++ src/swiftest/swiftest_module.f90 | 13 +++++++++++++ src/whm/whm_step.f90 | 3 +-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 67d61e312..f83bb413a 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -580,5 +580,20 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) return end subroutine swiftest_drift_kepu_stumpff + module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) + !! Author : Kaustub Anand + !! subroutine to update the rotation phase of the central body + !! Units: Radians + !! initial 0 is set at the x-axis + + ! Arguments + class(swiftest_cb), intent(inout) :: self !! Swiftest central body data structure + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + + self%rotphase = MOD((.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) ! radians + + end subroutine swiftest_drift_cb_rotphase_update + end submodule s_swiftest_drift diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 42d11aa84..103af911e 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -223,6 +223,7 @@ module swiftest 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 + procedure :: rotphase_update => swiftest_drift_cb_rotphase_update !! updates the central body rotation phase procedure :: dealloc => swiftest_util_dealloc_cb !! Deallocates all allocatables and resets all values to defaults procedure :: read_in => swiftest_io_read_in_cb !! Read in central body initial conditions from an ASCII file procedure :: write_frame => swiftest_io_netcdf_write_frame_cb !! I/O routine for writing out a single frame of time-series data for all bodies in the system in NetCDF format @@ -543,6 +544,18 @@ pure elemental module subroutine swiftest_drift_one(mu, rx, ry, rz, vx, vy, vz, integer(I4B), intent(out) :: iflag !! iflag : error status flag for Danby drift (0 = OK, nonzero = ERROR) end subroutine swiftest_drift_one + module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) + !! Author : Kaustub Anand + !! subroutine to update the rotation phase of the central body + !! Units: Radians + !! initial 0 is set at the x-axis + + ! Arguments + class(swiftest_cb), intent(inout) :: self !! Swiftest central body data structure + class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + real(DP), intent(in) :: dt !! Stepsize + end subroutine + module subroutine swiftest_driver(integrator, param_file_name, display_style) implicit none character(len=:), intent(in), allocatable :: integrator !! Symbolic code of the requested integrator diff --git a/src/whm/whm_step.f90 b/src/whm/whm_step.f90 index 96d181bc2..5b751b699 100644 --- a/src/whm/whm_step.f90 +++ b/src/whm/whm_step.f90 @@ -29,10 +29,9 @@ module subroutine whm_step_system(self, param, t, dt) tp%lfirst = pl%lfirst call pl%step(nbody_system, param, t, dt) call tp%step(nbody_system, param, t, dt) + call cb%rotphase_update(param, dt) ! if (param%ltides) call nbody_system%step_spin(param, t, dt) - ! ! Update central body rotation phase - ! cb%rotphase = (.mag. cb%rot) * dt * param%TU2S end associate return end subroutine whm_step_system From e3153bfbaf7ab4ae08bc499786e98b49fd964cc5 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 21 Sep 2023 14:27:49 -0400 Subject: [PATCH 068/324] debugging pt 5. In swiftest_sph.f90 --- src/swiftest/swiftest_module.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 103af911e..ad9374262 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -1857,7 +1857,7 @@ end subroutine swiftest_coarray_cocollect_tp #endif interface - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + pure module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) implicit none real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index d34935f1c..f5a281f3b 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -13,11 +13,11 @@ submodule (swiftest) s_swiftest_sph use swiftest use operators -use SHTOOLS +use SHTOOLS, only : PlmIndex, PlmON_d1 contains - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + pure module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -95,7 +95,7 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals - integer(I4B) :: i + integer(I4B) :: i real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics @@ -138,7 +138,7 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) aoblcb = cb%aoblend end if - do concurrent(i = 1:ntp, tp%lmask(i)) + do concurrent (i = 1:ntp, tp%lmask(i)) r_mag = .mag. rh(1:3,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI @@ -151,3 +151,4 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) return end subroutine swiftest_sph_g_acc_tp_all +end submodule s_swiftest_sph \ No newline at end of file From 60a564126fa89c87e354e8f6c94519fd1d1f7859 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 21 Sep 2023 15:02:56 -0400 Subject: [PATCH 069/324] Pulled the -fPIC flag out of the static lib only build config due to SHTOOLS requirement. --- cmake/Modules/SetSwiftestFlags.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index e6166d787..887eefefa 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -122,10 +122,13 @@ ELSEIF (COMPILER_OPTIONS STREQUAL "Intel") ENDIF () ENDIF () -IF (NOT BUILD_SHARED_LIBS AND NOT WINOPT) +IF (NOT WINOPT) SET_COMPILE_FLAG(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS}" Fortran "-fPIC" ) +ENDIF() + +IF (NOT BUILD_SHARED_LIBS AND NOT WINOPT) IF (COMPILER_OPTIONS STREQUAL "Intel") # Use static Intel libraries SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" From 6540a372979ff645533afdd82c52c32a60f5a6d1 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 21 Sep 2023 15:04:57 -0400 Subject: [PATCH 070/324] debugging pt 6 --- src/swiftest/swiftest_module.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index ad9374262..103af911e 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -1857,7 +1857,7 @@ end subroutine swiftest_coarray_cocollect_tp #endif interface - pure module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) implicit none real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index f5a281f3b..e01853a45 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -17,7 +17,7 @@ contains - pure module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -95,13 +95,15 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals - integer(I4B) :: i + integer(I4B) :: i = 1 real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics associate(pl => self, npl => self%nbody, cb => nbody_system%cb, rh => self%rh) cb%aobl(:) = 0.0_DP - do concurrent(i = 1:npl, pl%lmask(i)) + + ! do i = 1, npl, pl%lmask(i) + do while ((i .lt. npl) .and. pl%lmask(i)) r_mag = .mag. rh(1:3,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI @@ -109,6 +111,8 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) pl%aobl(:, i) = g_sph(:) + + i = i + 1 end do end associate return @@ -124,7 +128,7 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals - integer(I4B) :: i + integer(I4B) :: i = 1 real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle real(DP), dimension(NDIM) :: rh !! Position vector of the test particle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics @@ -138,14 +142,17 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) aoblcb = cb%aoblend end if - do concurrent (i = 1:ntp, tp%lmask(i)) + ! do i = 1, ntp, tp%lmask(i) + do while ((i .lt. ntp) .and. tp%lmask(i)) r_mag = .mag. rh(1:3,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI + phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) tp%aobl(:, i) = g_sph(:) + + i = i + 1 end do end associate return From 06a76527c2b578827ba39773b44291bd87dd571a Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 21 Sep 2023 16:30:17 -0400 Subject: [PATCH 071/324] debugging pt. 7; rearranged module calls --- src/swiftest/swiftest_sph.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index e01853a45..fec09873a 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -11,9 +11,8 @@ !! Swiftest submodule to calculate higher order terms for gravitational acceleration given spherical harmonic coefficients (c_lm) submodule (swiftest) s_swiftest_sph -use swiftest use operators -use SHTOOLS, only : PlmIndex, PlmON_d1 +use SHTOOLS contains From cb2faa45dc7e8b12ce5c0020b294413f55bbc629 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sun, 24 Sep 2023 15:43:55 -0400 Subject: [PATCH 072/324] Made sph_harmonnics_gravity a class for users to call it --- swiftest/sph_harmonics_gravity.py | 211 +++++++++++++++--------------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/swiftest/sph_harmonics_gravity.py b/swiftest/sph_harmonics_gravity.py index 4fd249600..e5a1d9b71 100644 --- a/swiftest/sph_harmonics_gravity.py +++ b/swiftest/sph_harmonics_gravity.py @@ -28,108 +28,109 @@ Any ) -def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radius = False): - """ - Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. - Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). - - Parameters - ---------- - mass : float - mass of the central body - density : float - density of the central body - a : float - length of the pricipal axis aligned with the x axis - b : float, optional, default = a - length of the pricipal axis aligned with the y axis - c : float, optional, default = b - length of the pricipal axis aligned with the z axis - lmax : int, optional, default = 6 - The maximum spherical harmonic degree resolvable by the grid. - ref_radius : boolean, optional, default = False - Boolean value to return the reference radius calculated by SHTOOLS - - Returns - ------- - clm : ndarry, shape (2, lmax+1, lmax+1) - numpy ndarray of the gravitational potential spherical harmonic coefficients. - This is a three-dimensional array formatted as coeffs[i, degree, order], - where i=0 corresponds to positive orders and i=1 to negative orders. - - """ - Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS - - # cap lmax to ensure fast performance without giving up accuracy - lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB - if(lmax > lmax_limit): - lmax = lmax_limit - print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - - # create shape grid - shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) - - # get gravity coefficients - clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization - - # Return reference radius EQUALS the radius of the Central Body - print(f'Ensure that the Central Body radius equals the reference radius.') - - if(ref_radius == True): - ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] - return clm, ref_radius - else: - return clm - -def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): - """ - Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. - Uses pyshtools. - - Parameters - ---------- - mass : float - mass of the central body - density : float - density of the central body - grid : array, shape [] - DH grid of the surface relief of the body - lmax : int, optional, default = 6 - The maximum spherical harmonic degree resolvable by the grid. - ref_radius : boolean, optional, default = False - Boolean value to return the reference radius calculated by SHTOOLS - - Returns - ------- - clm : ndarry, shape (2, lmax+1, lmax+1) - numpy ndarray of the gravitational potential spherical harmonic coefficients. - This is a three-dimensional array formatted as coeffs[i, degree, order], - where i=0 corresponds to positive orders and i=1 to negative orders. - - """ - - Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS - - # cap lmax to 20 to ensure fast performance - lmax_limit = 6 - if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients - lmax = lmax_limit - print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - - # convert to spherical harmonics - shape_SH = pysh.SHGrid.from_array(grid) - - # get coefficients - clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = 'ortho') # change to orthogonal normalization - - # Return reference radius EQUALS the radius of the Central Body - - print(f'Ensure that the Central Body radius equals the reference radius.') - - if(ref_radius == True): - ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] - return clm, ref_radius - else: - return clm +class Sph_Harmonics(object): + def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radius = False): + """ + Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. + Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). + + Parameters + ---------- + mass : float + mass of the central body + density : float + density of the central body + a : float + length of the pricipal axis aligned with the x axis + b : float, optional, default = a + length of the pricipal axis aligned with the y axis + c : float, optional, default = b + length of the pricipal axis aligned with the z axis + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + ref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + + # cap lmax to ensure fast performance without giving up accuracy + lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB + if(lmax > lmax_limit): + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # create shape grid + shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) + + # get gravity coefficients + clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization + + # Return reference radius EQUALS the radius of the Central Body + print(f'Ensure that the Central Body radius equals the reference radius.') + + if(ref_radius == True): + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] + return clm, ref_radius + else: + return clm + + def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): + """ + Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. + Uses pyshtools. + + Parameters + ---------- + mass : float + mass of the central body + density : float + density of the central body + grid : array, shape [] + DH grid of the surface relief of the body + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + ref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + + Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + + # cap lmax to 20 to ensure fast performance + lmax_limit = 6 + if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # convert to spherical harmonics + shape_SH = pysh.SHGrid.from_array(grid) + + # get coefficients + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm = clm_class.to_array(normalization = 'ortho') # change to orthogonal normalization + + # Return reference radius EQUALS the radius of the Central Body + + print(f'Ensure that the Central Body radius equals the reference radius.') + + if(ref_radius == True): + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] + return clm, ref_radius + else: + return clm From be8e2b55a930fcc617649e97c55f29e370896cf0 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sun, 24 Sep 2023 15:47:26 -0400 Subject: [PATCH 073/324] Importing Sph_Harmonics in __init__.py --- swiftest/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/swiftest/__init__.py b/swiftest/__init__.py index 3b8bf6179..3e313512d 100644 --- a/swiftest/__init__.py +++ b/swiftest/__init__.py @@ -10,4 +10,5 @@ """ from .constants import * -from .simulation_class import Simulation \ No newline at end of file +from .simulation_class import Simulation +from .sph_harmonics_gravity import Sph_Harmonics \ No newline at end of file From 200791e2c24a30d2d3777c39c3ba1edee9075ffb Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 25 Sep 2023 11:18:40 -0400 Subject: [PATCH 074/324] renamed sph_harmonics_gravity to sph_harmonics --- swiftest/__init__.py | 2 +- swiftest/{sph_harmonics_gravity.py => sph_harmonics.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename swiftest/{sph_harmonics_gravity.py => sph_harmonics.py} (100%) diff --git a/swiftest/__init__.py b/swiftest/__init__.py index 3e313512d..8e1a9ab57 100644 --- a/swiftest/__init__.py +++ b/swiftest/__init__.py @@ -11,4 +11,4 @@ from .constants import * from .simulation_class import Simulation -from .sph_harmonics_gravity import Sph_Harmonics \ No newline at end of file +from .sph_harmonics import Sph_Harmonics \ No newline at end of file diff --git a/swiftest/sph_harmonics_gravity.py b/swiftest/sph_harmonics.py similarity index 100% rename from swiftest/sph_harmonics_gravity.py rename to swiftest/sph_harmonics.py From f8299c227aeb594617e4c3dc3e7c3af5a5d85bcd Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 25 Sep 2023 15:11:02 -0400 Subject: [PATCH 075/324] Added sign as a dimension in netcdf; debugging to see why c_lm isn t read in fortran --- src/netcdf_io/netcdf_io_module.f90 | 3 +++ src/swiftest/swiftest_io.f90 | 37 ++++++++++++++++++++++++++---- swiftest/init_cond.py | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index 24e3d6948..41ba763d7 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -43,6 +43,9 @@ module netcdf_io integer(I4B) :: space_dimid !! ID for the space dimension integer(I4B) :: space_varid !! ID for the space variable character(len=1), dimension(3) :: space_coords = ["x","y","z"] !! The space dimension coordinate labels + character(NAMELIN) :: sign_dimname = "sign" !! name of the sign dimension for c_lm + integer(I4B) :: sign_dimid !! ID for sign dimension + integer(I4B) :: sign_varid !! ID for sign variable character(NAMELEN) :: l_dimname = "l" !! name of l dimension for c_lm integer(I4B) :: l_dimid !! ID for the l dimension for c_lm integer(I4B) :: l_varid !! ID for the l variable diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 40405901b..b04d37499 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -764,6 +764,15 @@ module subroutine swiftest_io_netcdf_get_t0_values_system(self, nc, param) call netcdf_io_check( nf90_get_var(nc%id, nc%E_untracked_varid, self%E_untracked, start=[tslot]), & "netcdf_io_get_t0_values_system E_untracked_varid" ) + ! ! SH gravity variable dimensions + + ! call netcdf_io_check( nf90_get_var(nc%id, nc%sign_dimname, nc%sign_dimid), & + ! "swiftest_io_netcdf_open nf90_inq_dimid sign_dimid") + ! call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, nc%l_dimid), & + ! "swiftest_io_netcdf_open nf90_inq_dimid l_dimid") + ! call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, nc%m_dimid), & + ! "swiftest_io_netcdf_open nf90_inq_dimid m_dimid") + end if deallocate(vals) @@ -827,6 +836,13 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) "netcdf_io_initialize_output nf90_def_dim name_dimid" ) ! dimension to store particle id numbers call netcdf_io_check( nf90_def_dim(nc%id, nc%str_dimname, NAMELEN, nc%str_dimid), & "netcdf_io_initialize_output nf90_def_dim str_dimid" ) ! Dimension for string variables + + call netcdf_io_check( nf90_def_dim(nc%id, nc%sign_dimname, NF90_UNLIMITED, nc%sign_dimid), & + "swiftest_io_netcdf_open nf90_def_dim sign_dimid") + call netcdf_io_check( nf90_def_dim(nc%id, nc%l_dimname, NF90_UNLIMITED, nc%l_dimid), & + "swiftest_io_netcdf_open nf90_def_dim l_dimid") + call netcdf_io_check( nf90_def_dim(nc%id, nc%m_dimname, NF90_UNLIMITED, nc%m_dimid), & + "swiftest_io_netcdf_open nf90_def_dim m_dimid") ! Dimension coordinates call netcdf_io_check( nf90_def_var(nc%id, nc%time_dimname, nc%out_type, nc%time_dimid, nc%time_varid), & @@ -836,6 +852,13 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, [nc%str_dimid, nc%name_dimid], nc%name_varid), & "netcdf_io_initialize_output nf90_def_var name_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%sign_dimname, NF90_INT, nc%sign_dimid, nc%sign_varid), & + "swiftest_io_netcdf_open nf90_def_var sign_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%l_dimname, NF90_INT, nc%l_dimid nc%l_varid), & + "swiftest_io_netcdf_open nf90_def_var l_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%m_dimname, NF90_INT, nc%m_dimid, nc%m_varid), & + "swiftest_io_netcdf_open nf90_def_var m_varid") + ! Variables call netcdf_io_check( nf90_def_var(nc%id, nc%id_varname, NF90_INT, nc%name_dimid, nc%id_varid), & "netcdf_io_initialize_output nf90_def_var id_varid" ) @@ -985,7 +1008,7 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [2, nc%l_dimid, nc%m_dimid], nc%c_lm_varid), & + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%sign_dimid, nc%l_dimid, nc%m_dimid], nc%c_lm_varid), & "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) end if @@ -1081,6 +1104,8 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%sign_dimname, nc%sign_dimid), & + "swiftest_io_netcdf_open nf90_inq_dimid sign_dimid") call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, nc%l_dimid), & "swiftest_io_netcdf_open nf90_inq_dimid l_dimid") call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, nc%m_dimid), & @@ -1096,10 +1121,12 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) "swiftest_io_netcdf_open nf90_inq_varid name_varid" ) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, nc%l_varid), & - "swiftest_io_netcdf_open nf90_inq_dimid l_varid") - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, nc%m_varid), & - "swiftest_io_netcdf_open nf90_inq_dimid m_varid") + call netcdf_io_check( nf90_inq_varid(nc%id, nc%sign_dimname, nc%sign_varid), & + "swiftest_io_netcdf_open nf90_inq_varid sign_varid") + call netcdf_io_check( nf90_inq_varid(nc%id, nc%l_dimname, nc%l_varid), & + "swiftest_io_netcdf_open nf90_inq_varid l_varid") + call netcdf_io_check( nf90_inq_varid(nc%id, nc%m_dimname, nc%m_varid), & + "swiftest_io_netcdf_open nf90_inq_varid m_varid") end if ! Required Variables diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 9422ca6ec..004af16cc 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -505,7 +505,7 @@ def vec2xr(param: Dict, **kwargs: Any): # create a C_lm Dataset and combine if "c_lm" in kwargs: - clm_xr = xr.Dataset(data_vars = {k:(sph_dims, v) for k,v in kwargs.item() if k in sph_vars}, + clm_xr = xr.Dataset(data_vars = {k:(sph_dims, v) for k,v in kwargs.items() if k in sph_vars}, coords = { 'sign':(['sign'], [1, -1]), 'l': (['l'], range(0, kwargs['c_lm'].shape[1])), From 144c76f9c976c9f045aba212c65422627fa72c98 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 25 Sep 2023 15:14:23 -0400 Subject: [PATCH 076/324] adjusting text line length --- src/base/base_module.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index 735e60638..495051f5e 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -99,7 +99,8 @@ module base !! is input) logical :: lrotation = .false. !! Include rotation states of big bodies logical :: ltides = .false. !! Include tidal dissipation - logical :: lshgrav = .false. !! Calculate acceleration from spherical harmonics terms for the central body (automatically turns true if clm array is input) + logical :: lshgrav = .false. !! Calculate acceleration from spherical harmonics terms for the central body + !! (automatically turns true if clm array is inputted) ! Initial values to pass to the energy report subroutine (usually only used in the case of a restart, otherwise these will be ! updated with initial conditions values) From 2a06490e10e5a256c071dd556449db7829658a71 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 25 Sep 2023 15:15:21 -0400 Subject: [PATCH 077/324] fixed typo --- src/netcdf_io/netcdf_io_module.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index 41ba763d7..92ba6464f 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -43,7 +43,7 @@ module netcdf_io integer(I4B) :: space_dimid !! ID for the space dimension integer(I4B) :: space_varid !! ID for the space variable character(len=1), dimension(3) :: space_coords = ["x","y","z"] !! The space dimension coordinate labels - character(NAMELIN) :: sign_dimname = "sign" !! name of the sign dimension for c_lm + character(NAMELEN) :: sign_dimname = "sign" !! name of the sign dimension for c_lm integer(I4B) :: sign_dimid !! ID for sign dimension integer(I4B) :: sign_varid !! ID for sign variable character(NAMELEN) :: l_dimname = "l" !! name of l dimension for c_lm From d855dab92d553c264c2484a6fe6dd2070faf8090 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 25 Sep 2023 15:26:42 -0400 Subject: [PATCH 078/324] fixed a typo --- src/swiftest/swiftest_io.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index b04d37499..a95586000 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -852,11 +852,11 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, [nc%str_dimid, nc%name_dimid], nc%name_varid), & "netcdf_io_initialize_output nf90_def_var name_varid" ) - call netcdf_io_check( nf90_def_var(nc%id, nc%sign_dimname, NF90_INT, nc%sign_dimid, nc%sign_varid), & + call netcdf_io_check( nf90_def_var(nc%id, nc%sign_dimname, nc%out_type, nc%sign_dimid, nc%sign_varid), & "swiftest_io_netcdf_open nf90_def_var sign_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%l_dimname, NF90_INT, nc%l_dimid nc%l_varid), & + call netcdf_io_check( nf90_def_var(nc%id, nc%l_dimname, nc%out_type, nc%l_dimid, nc%l_varid), & "swiftest_io_netcdf_open nf90_def_var l_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%m_dimname, NF90_INT, nc%m_dimid, nc%m_varid), & + call netcdf_io_check( nf90_def_var(nc%id, nc%m_dimname, nc%out_type, nc%m_dimid, nc%m_varid), & "swiftest_io_netcdf_open nf90_def_var m_varid") ! Variables From cdbe4a60743790d7db6cefbb2139e0ffb7c38e95 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 25 Sep 2023 16:07:34 -0400 Subject: [PATCH 079/324] edited netcdf calls to c_lm dimensions --- src/swiftest/swiftest_io.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index a95586000..d83504642 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1006,11 +1006,11 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%j4rp4_varname, nc%out_type, nc%time_dimid, nc%j4rp4_varid), & "netcdf_io_initialize_output nf90_def_var j4rp4_varid" ) - status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) - if (status == NF90_NOERR) then - call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%sign_dimid, nc%l_dimid, nc%m_dimid], nc%c_lm_varid), & + ! status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + ! if (status == NF90_NOERR) then + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%sign_dimid, nc%l_dimid, nc%m_dimid], nc%c_lm_varid), & "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) - end if + ! end if ! Set fill mode to NaN for all variables call netcdf_io_check( nf90_inquire(nc%id, nVariables=nvar), "netcdf_io_initialize_output nf90_inquire nVariables" ) From 09a75e965293eb32454a3e8afc456eabde913d0d Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 26 Sep 2023 11:34:22 -0400 Subject: [PATCH 080/324] reversed clm dimensions' allocation order to avoid netcdf error. Seen on stackoverflow --- src/swiftest/swiftest_io.f90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index d83504642..2c937ec93 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1551,9 +1551,10 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") - allocate(cb%c_lm(2, l_dim_max, m_dim_max)) - call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") - + allocate(cb%c_lm(m_dim_max, l_dim_max, 2)) + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + + ! ordering of dimensions above seen to stackoverflow to prevent error 'NetCDF: Start + count exceeds dimension bound' end if call self%read_particle_info(nc, param, plmask, tpmask) From 40e683b58bea5e0e05679a287cebf438da5d8271 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 26 Sep 2023 15:42:52 -0400 Subject: [PATCH 081/324] Added pyshtools to the list of requirements --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 04719aa6a..40935d3f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ dependencies = [ 'astroquery>=0.4.6', 'tqdm>=4.65.0', 'cython>=3.0.0', + 'pyshtools>=4.10' ] [project.urls] From 1cb9c92161118b1de0afc5f24659bfdb49f1d726 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 26 Sep 2023 15:43:26 -0400 Subject: [PATCH 082/324] Made a number of changes to get the new SHTOOLS into the build and get the libraries found --- CMakeLists.txt | 5 ++--- buildscripts/install_editable_debug.sh | 11 ++++++++++- cmake/Modules/SetMKL.cmake | 14 -------------- cmake/Modules/SetSwiftestFlags.cmake | 2 +- 4 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 cmake/Modules/SetMKL.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 17de0780e..a3386e552 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ LIST(APPEND CMAKE_MODULE_PATH ${LOCAL_MODULE_PATH}) IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") + FIND_PACKAGE(MKL) ELSEIF (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") SET(COMPILER_OPTIONS "GNU" CACHE STRING "Compiler identified as gfortran") ELSE () @@ -73,6 +74,7 @@ FIND_PACKAGE(SHTOOLS REQUIRED) # Ensure scikit-build modules FIND_PACKAGE(Python COMPONENTS Interpreter Development.Module REQUIRED) + # Define some directories that are important to the build SET(SRC "${CMAKE_SOURCE_DIR}/src") SET(PY "${CMAKE_SOURCE_DIR}/swiftest") @@ -102,9 +104,6 @@ IF(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90) ENDIF(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90) INCLUDE(SetParallelizationLibrary) -IF (COMPILER_OPTIONS STREQUAL "Intel" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") - INCLUDE(SetMKL) -ENDIF () INCLUDE(SetSwiftestFlags) # The source for the SWIFTEST binary and have it placed in the bin folder diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index 62abedf5d..e82d60933 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -15,4 +15,13 @@ pip install --config-settings=editable.rebuild=true \ --config-settings=cmake.args="-DUSE_SIMD=ON" \ --config-settings=cmake.args="-DUSE_OPENMP=ON" \ --no-build-isolation \ - -ve . \ No newline at end of file + -ve . + +PACKAGE_PATH=$(realpath ${VENV_DIR}/lib/python*/site-packages/swiftest) + +libdiradd () { + if [ -d "$1" ] && [[ ":$LD_LIBRARY_PATH:" != *":$1:"* ]]; then + LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+"$LD_LIBRARY_PATH:"}$1" + fi +} +libdiradd $PACKAGE_PATH \ No newline at end of file diff --git a/cmake/Modules/SetMKL.cmake b/cmake/Modules/SetMKL.cmake deleted file mode 100644 index e58c9f51a..000000000 --- a/cmake/Modules/SetMKL.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2022 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh -# This file is part of Swiftest. -# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# You should have received a copy of the GNU General Public License along with Swiftest. -# If not, see: https://www.gnu.org/licenses. - -# Find MKL if not already found -IF(NOT MKL_FOUND) - ENABLE_LANGUAGE(C) # Some libraries need a C compiler to find - FIND_PACKAGE(MKL REQUIRED) -ENDIF(NOT MKL_FOUND) diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 968f86ff1..8cbc0de29 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -613,7 +613,7 @@ IF (COMPILER_OPTIONS STREQUAL "Intel") ELSE () # Some subroutines require more strict floating point operation optimizations for repeatability SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-fp-module=precise" # Intel + Fortran "-fp-model=precise" # Intel ) SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" Fortran "-prec-div" # Intel From 044249117e908a30eaccfb0b06512672cd17f656 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 26 Sep 2023 15:54:20 -0400 Subject: [PATCH 083/324] Fixed typo in package install --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 40935d3f6..07a5d4b96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ before-all = [ [tool.cibuildwheel.linux] skip = "cp312-*" before-all = [ - "yum install doxygen libxml2-devel libcurl-devel ftw3-devel libblas-devel lapack-devel -y", + "yum install doxygen libxml2-devel libcurl-devel ftw-devel libblas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] [tool.cibuildwheel.linux.environment] From 993176bfd3a83fb36bb6afdba4df94532fa96c84 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 26 Sep 2023 15:56:24 -0400 Subject: [PATCH 084/324] Fixed typo from last typo fix --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 07a5d4b96..c0aba8e97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ before-all = [ [tool.cibuildwheel.linux] skip = "cp312-*" before-all = [ - "yum install doxygen libxml2-devel libcurl-devel ftw-devel libblas-devel lapack-devel -y", + "yum install doxygen libxml2-devel libcurl-devel fftw-devel libblas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] [tool.cibuildwheel.linux.environment] From 719b06d2540a9e2cfa227a2644f0bf8d13cf65bf Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Tue, 26 Sep 2023 17:21:21 -0400 Subject: [PATCH 085/324] Made adjustments to build scripts --- buildscripts/build_shtools.sh | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index 546663ea0..a7aa6b76c 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -13,6 +13,7 @@ SCRIPT_DIR=$(realpath $(dirname $0)) set -a ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} +. ${SCRIPT_DIR}/set_compilers.sh SHTOOLS_VER="4.10.4" @@ -38,7 +39,6 @@ printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/SHTOOLS-* -make F95="${FC}" CXX="${CXX}" fortran make F95="${FC}" CXX="${CXX}" fortran-mp if [ -w ${PREFIX} ]; then make PREFIX="${PREFIX}" install diff --git a/pyproject.toml b/pyproject.toml index c0aba8e97..222986c82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ before-all = [ [tool.cibuildwheel.linux] skip = "cp312-*" before-all = [ - "yum install doxygen libxml2-devel libcurl-devel fftw-devel libblas-devel lapack-devel -y", + "yum install doxygen libxml2-devel libcurl-devel fftw-devel blas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] [tool.cibuildwheel.linux.environment] From 1bd44ad6af71ba33cc127e4df1b109fe80968545 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 10:37:15 -0400 Subject: [PATCH 086/324] fixed typo --- swiftest/simulation_class.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index dcbe6d7d7..baa59c04d 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -14,7 +14,7 @@ from swiftest import init_cond from swiftest import tool from swiftest import constants -from swiftest._bindings import driver +# from swiftest._bindings import driver from swiftest import __file__ as _pyfile import json import os From cbe7f9fdaaccb38c46ff075863911a5e1dee8e83 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 14:10:11 -0400 Subject: [PATCH 087/324] avoided allocation error for a pre-allocated c_lm array --- src/swiftest/swiftest_io.f90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 2c937ec93..cc74d75ee 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2108,7 +2108,9 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension l_dimid") call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension m_dimid") - allocate(self%c_lm(2, l_dim_max, m_dim_max)) + if(.not. allocated(self%c_lm)) then + allocate(self%c_lm(2, l_dim_max, m_dim_max)) + end if call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_write_frame_cb nf90_getvar c_lm_varid") end if From 31364df2712c978da6638d5c098deaf944a893aa Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 14:14:44 -0400 Subject: [PATCH 088/324] rearranged allocation order in write_frame_cb; Changed order of indices in gravity calculation --- src/swiftest/swiftest_io.f90 | 4 ++-- src/swiftest/swiftest_sph.f90 | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index cc74d75ee..555a5156c 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2109,9 +2109,9 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension m_dimid") if(.not. allocated(self%c_lm)) then - allocate(self%c_lm(2, l_dim_max, m_dim_max)) + allocate(self%c_lm(m_dim_max, l_dim_max, 2)) end if - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [2, l_dim_max, m_dim_max]), "netcdf_io_write_frame_cb nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_write_frame_cb nf90_getvar c_lm_varid") end if call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp), & diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index fec09873a..7846292f4 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -59,10 +59,10 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi - ccss = c_lm(1, l+1, m+1) * cos(m * phi) & - + c_lm(2, l+1, m+1) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) - cssc = -1.0_DP * c_lm(1, l+1, m+1) * sin(m * phi) & - + c_lm(2, l+1, m+1) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) + ccss = c_lm(m+1, l+1, 1) * cos(m * phi) & + + c_lm(m+1, l+1, 2) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) + cssc = -1.0_DP * c_lm(m+1, l+1, 1) * sin(m * phi) & + + c_lm(m+1, l+1, 2) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 From 09515b3c5aa5710ea3ee9fc14d50a6809e4e0c25 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 14:43:18 -0400 Subject: [PATCH 089/324] cchanged indexing of "ah" and "aobl" to prevent seg fault --- src/swiftest/swiftest_io.f90 | 4 +++- src/swiftest/swiftest_sph.f90 | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 555a5156c..d27653064 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1551,7 +1551,9 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") - allocate(cb%c_lm(m_dim_max, l_dim_max, 2)) + if(.not. allocated(cb%c_lm)) then + allocate(cb%c_lm(m_dim_max, l_dim_max, 2)) + end if call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") ! ordering of dimensions above seen to stackoverflow to prevent error 'NetCDF: Start + count exceeds dimension bound' diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 7846292f4..4b89c56ba 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -50,7 +50,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, allocate(p(N),p_deriv(N)) call PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative - do l = 1, l_max + do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term do m = 0, l ! Associated Legendre Polynomials @@ -108,8 +108,8 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) - pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) - pl%aobl(:, i) = g_sph(:) + pl%ah(i, :) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) + pl%aobl(i, :) = g_sph(:) i = i + 1 end do @@ -148,8 +148,8 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) - tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) - tp%aobl(:, i) = g_sph(:) + tp%ah(i, :) = tp%ah(:, i) + g_sph(:) - aoblcb(:) + tp%aobl(i, :) = g_sph(:) i = i + 1 end do From 1da0860796d90373169a15ea481e9ee586afadf5 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 15:05:32 -0400 Subject: [PATCH 090/324] added lshgrav to allocation criteria to aobl --- src/swiftest/swiftest_io.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index d27653064..9dccfe128 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -3338,7 +3338,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) param%lshgrav = allocated(self%cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) - if (.not.param%loblatecb) then + if (.not.param%loblatecb .or. .not.param%lshgrav) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) else diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 4b89c56ba..55c4c771c 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -108,8 +108,8 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) - pl%ah(i, :) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) - pl%aobl(i, :) = g_sph(:) + pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) + pl%aobl(:, i) = g_sph(:) i = i + 1 end do @@ -148,8 +148,8 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) - tp%ah(i, :) = tp%ah(:, i) + g_sph(:) - aoblcb(:) - tp%aobl(i, :) = g_sph(:) + tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) + tp%aobl(:, i) = g_sph(:) i = i + 1 end do From d420ad6efcdd3dcb469e73cd42ab528d53ccf2a7 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 28 Sep 2023 15:22:05 -0400 Subject: [PATCH 091/324] Added a force flag to the soft link creation in the install script --- buildscripts/install_editable_debug.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index d3d1fe721..3e6409ac9 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -18,4 +18,4 @@ pip install --config-settings=editable.rebuild=true \ -ve . mkdir -p $HOME/.local/lib LIBFILE=$(realpath ${ROOT_DIR}/build/*/bin/*swiftest.*) -ln -s $LIBFILE $HOME/.local/lib \ No newline at end of file +ln -fs $LIBFILE $HOME/.local/lib \ No newline at end of file From f859be1d35843e7b239b832cc82ca519eee1115b Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 28 Sep 2023 16:00:35 -0400 Subject: [PATCH 092/324] Converted while loop into a do loop --- src/swiftest/swiftest_sph.f90 | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 55c4c771c..2b25ab412 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -141,17 +141,16 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) aoblcb = cb%aoblend end if - ! do i = 1, ntp, tp%lmask(i) - do while ((i .lt. ntp) .and. tp%lmask(i)) - r_mag = .mag. rh(1:3,i) - theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase - - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) - tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) - tp%aobl(:, i) = g_sph(:) - - i = i + 1 + do i = 1, ntp + if (tp%lmask(i)) then + r_mag = .mag. rh(:,i) + theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) + phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase + + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) + tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) + tp%aobl(:, i) = g_sph(:) + end if end do end associate return From 4a6b2f860240220d8a21c9519ce3e851f6647abd Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 28 Sep 2023 16:01:42 -0400 Subject: [PATCH 093/324] Converted another while loop to a do --- src/swiftest/swiftest_sph.f90 | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 2b25ab412..3a561e89a 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -101,17 +101,16 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) associate(pl => self, npl => self%nbody, cb => nbody_system%cb, rh => self%rh) cb%aobl(:) = 0.0_DP - ! do i = 1, npl, pl%lmask(i) - do while ((i .lt. npl) .and. pl%lmask(i)) - r_mag = .mag. rh(1:3,i) - theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI - - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) - pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) - pl%aobl(:, i) = g_sph(:) - - i = i + 1 + do i = 1, npl + if (pl%lmask(i)) then + r_mag = .mag. rh(:,i) + theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) + phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI + + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) + pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) + pl%aobl(:, i) = g_sph(:) + end if end do end associate return From 2987b3d87b33705533aa4387dc248799c1a886bf Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 16:14:55 -0400 Subject: [PATCH 094/324] Added extra clarification for aobl allocation --- src/swiftest/swiftest_util.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 7290b4b29..d7696abc2 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -2539,7 +2539,7 @@ module subroutine swiftest_util_setup_body(self, n, param) self%peri(:) = 0.0_DP self%atp(:) = 0.0_DP - if (param%loblatecb) then + if (param%loblatecb .or. param%lshgrav) then allocate(self%aobl(NDIM, n)) self%aobl(:,:) = 0.0_DP end if From 6b3f3a7dce47834f1b6c30d5eeebccb2a56a5373 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 16:37:24 -0400 Subject: [PATCH 095/324] fixed a typo. Changed dimension of GMpl --- src/swiftest/swiftest_module.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 103af911e..dab54a4ea 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -1866,7 +1866,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector - real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles + real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) end subroutine swiftest_sph_g_acc_one diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 3a561e89a..1c0f5962d 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -31,7 +31,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector - real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles + real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) ! Internals From bfbb41e7d399f59a31b23239ddcd2b40fca4e9e6 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 16:38:45 -0400 Subject: [PATCH 096/324] fixed typo with g_Sph dimensions --- src/swiftest/swiftest_sph.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 1c0f5962d..726948177 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -30,7 +30,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) From 3ffd1a057e2236680587c8817a87566f551ea754 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 28 Sep 2023 16:49:44 -0400 Subject: [PATCH 097/324] changed and fixed dimensions being passed --- src/swiftest/swiftest_module.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index dab54a4ea..817388bbd 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -1865,7 +1865,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(:) :: g_sph !! acceleration vector + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) end subroutine swiftest_sph_g_acc_one diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 726948177..7fc6bb4b7 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -107,7 +107,7 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass, cb%aobl) + call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) pl%aobl(:, i) = g_sph(:) end if From 4efa637892220cb93b08ff91d3494f42c5d2a0a5 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 29 Sep 2023 07:26:31 -0400 Subject: [PATCH 098/324] fixed typo that was leading pl%aobl to not being allocated --- src/swiftest/swiftest_io.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 9dccfe128..5535758cd 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -3338,7 +3338,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) param%lshgrav = allocated(self%cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) - if (.not.param%loblatecb .or. .not.param%lshgrav) then + if (.not.param%loblatecb .and. .not.param%lshgrav) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) else From 66cee2cb3b900c671dc7883884f8bf2093e557c9 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 29 Sep 2023 07:49:48 -0400 Subject: [PATCH 099/324] added framework to I/O cb%rotphase to netcdf --- src/swiftest/swiftest_io.f90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 5535758cd..e885708df 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2102,7 +2102,10 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cb nf90_put_var cb Ip_varid" ) call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, self%rot(:) * RAD2DEG, start=[1, idslot, tslot], & count=[NDIM,1,1]), & - "swiftest_io_netcdf_write_frame_cby nf90_put_var cb rot_varid" ) + "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rot_varid" ) + ! ADD + ! call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase(:), start = [1, idslot, tslot]), & + ! "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") end if status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) From 592bba865ed2f15c5bffbdd39395da803b2e62d5 Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:38:21 -0500 Subject: [PATCH 100/324] Updated dependency version minimums --- pyproject.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7de757846..5e76778a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,17 +26,17 @@ keywords=['astronomy','astrophysics', 'planetary', 'nbody integrator', 'symplect dependencies = [ 'numpy>=1.24.3', 'scipy>=1.10.1', - 'xarray>=2022.11.0', - 'dask>=2022.1', - 'distributed>=2022.1', - 'bottleneck>=1.3.5', - 'h5netcdf', - 'h5py', - 'netcdf4', - 'matplotlib>=3.7.1', - 'astropy>=5.1', + 'xarray>=2023.1', + 'dask>=2023.5', + 'distributed>=2023.5', + 'bottleneck>=1.3', + 'h5netcdf>=1.1', + 'h5py>=3.9', + 'netcdf4>=1.6.4', + 'matplotlib>=3.7', + 'astropy>=5.2', 'astroquery>=0.4.6', - 'tqdm>=4.65.0', + 'tqdm>=4.66', 'cython>=3.0.0', 'pyshtools>=4.10' ] From 7699c91fc88f535eef0a07c4dd294d6bbbfe9676 Mon Sep 17 00:00:00 2001 From: MintoDA1 <51412913+MintoDA1@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:44:25 -0500 Subject: [PATCH 101/324] Cleaned up the Chambers2013 example and added a new run_simulation script that can generate a short test case. --- examples/Chambers2013/.gitignore | 3 +- examples/Chambers2013/README.txt | 7 ++- .../{init_cond.py => initial_conditions.py} | 57 +++++++++---------- examples/Chambers2013/run_simulation.py | 33 +++++++++++ examples/Chambers2013/scattermovie.py | 15 ++++- 5 files changed, 79 insertions(+), 36 deletions(-) rename examples/Chambers2013/{init_cond.py => initial_conditions.py} (77%) create mode 100755 examples/Chambers2013/run_simulation.py diff --git a/examples/Chambers2013/.gitignore b/examples/Chambers2013/.gitignore index 64af50e94..0ea510e82 100644 --- a/examples/Chambers2013/.gitignore +++ b/examples/Chambers2013/.gitignore @@ -1,5 +1,6 @@ * !.gitignore -!init_cond.py +!initial_conditions.py !scattermovie.py +!run_simulation.py !README.txt diff --git a/examples/Chambers2013/README.txt b/examples/Chambers2013/README.txt index aeb95fc1f..c281be7fc 100644 --- a/examples/Chambers2013/README.txt +++ b/examples/Chambers2013/README.txt @@ -15,9 +15,10 @@ Date : December 6, 2022 Included in the Chambers2013 example directory are the following files: - - README.txt : This file - - init_cond.py : A Python Script that generates a set of initial conditions. - - scattermovie.py : A Python Script that processes data.nc and generates Chambers2013-aescatter.mp4 or Chambers2013-aiscatter.mp4 + - README.txt : This file + - init_cond.py : A Python script that generates a set of initial conditions. + - run_simulation.py : A Python script that will run the simulation. + - scattermovie.py : A Python script that processes data.nc and generates Chambers2013-aescatter.mp4 or Chambers2013-aiscatter.mp4 This example is intended to be run with Swiftest SyMBA. For details on how to generate, run, and analyze this example, see the Swiftest User Manual. \ No newline at end of file diff --git a/examples/Chambers2013/init_cond.py b/examples/Chambers2013/initial_conditions.py similarity index 77% rename from examples/Chambers2013/init_cond.py rename to examples/Chambers2013/initial_conditions.py index d5c9f9f19..596d6829c 100755 --- a/examples/Chambers2013/init_cond.py +++ b/examples/Chambers2013/initial_conditions.py @@ -32,7 +32,8 @@ import matplotlib.pyplot as plt # Initialize simulation object -sim = swiftest.Simulation(compute_conservation_values=True, rotation=True, init_cond_format="EL",collision_model="fraggle",encounter_save="none") +sim = swiftest.Simulation(compute_conservation_values=True, rotation=True, init_cond_format="EL",collision_model="fraggle",encounter_save="none") +sim.clean() # Add bodies described in Chambers (2013) Sec. 2.1, with the uniform spatial distribution and two bodies sizes (big and small) Nb = 14 @@ -40,6 +41,7 @@ Mb = 2.8e-7 * 14 / Nb Ms = 2.8e-8 * 140 / Ns dens = 3000.0 * sim.KG2MU / sim.M2DU**3 +rot = 1e-6 / sim.TU2S # Use a small but non-zero value for the initial rotation state to prevent divide-by-zero errors in analysis mtiny = 1e-2 * Ms minimum_fragment_mass = 1e-5 * Ms @@ -55,37 +57,33 @@ def a_profile(n_bodies): The region with a < 0.7 AU deviates from this law, declining linearly with decreasing distance until R = 0 at 0.3 AU. The outer edge of the disk is 2 AU in all cases. """ - def sample(r_inner, r_break, r_outer, slope1, slope2): - """ - Define the functions to pull random semi-major axes from a distribution using a rejection sampling method - This defines a 2-slope model with a break at r_break - Based on (https://stackoverflow.com/questions/66874819/random-numbers-with-user-defined-continuous-probability-distribution) - """ - while True: - x = rng.uniform(r_inner, r_outer, size=1) + def sample(r_inner, r_break, r_outer, slope1, slope2, size): + """ + Define the functions to pull random semi-major axes from a distribution using a rejection sampling method + This defines a 2-slope model with a break at r_break + Based on (https://stackoverflow.com/questions/66874819/random-numbers-with-user-defined-continuous-probability-distribution) + """ + y=np.ones([size]) + pdf=np.zeros([size]) + x=np.empty_like(y) + while np.any(y>pdf): + x = np.where(y>pdf,rng.uniform(r_inner, r_outer, size=size),x) - # The proportionality factor A ensures that the PDF approaches the same value on either side of the break point - # Assumes the break point is the max of the PDF - if x < r_break: - slope = slope1 + 1 - A = 1.0 - else: - slope = slope2 + 1 - A = r_break**(slope1-slope2) - y = rng.uniform(0, A*r_break**slope, size=1) - pdf = A*x**(slope) - if (y < pdf): - return x - + # The proportionality factor A ensures that the PDF approaches the same value on either side of the break point + # Assumes the break point is the max of the PDF + A=np.where(x < r_break,1.0,r_break**(slope1-slope2)) + slope=np.where(x < r_break,slope1+1,slope2+1) + y = np.where(y>pdf,rng.uniform(0, A*r_break**slope, size=size),y) + pdf = np.where(y>pdf,A*x**(slope),pdf) + return x + a_inner = 0.3 a_break = 0.7 a_outer = 2.0 slope1 = 1.0 slope2 = -1.5 - - a_vals = np.zeros(n_bodies) - for k in range(n_bodies): - a_vals[k] = sample(a_inner, a_break, a_outer, slope1, slope2) + + a_vals = sample(a_inner, a_break, a_outer, slope1, slope2, n_bodies) return a_vals # Define the initial orbital elements of the big and small bodies @@ -107,8 +105,8 @@ def sample(r_inner, r_break, r_outer, slope1, slope2): capmvals = rng.uniform(0.0, 360.0, Ns) Ipvalb = np.full((Nb,3), 0.4) Ipvals = np.full((Ns,3), 0.4) -rotvalb = np.zeros_like(Ipvalb) -rotvals = np.zeros_like(Ipvals) +rotvalb = np.full_like(Ipvalb,rot) +rotvals = np.full_like(Ipvals,rot) noise_digits = 4 # Approximately the number of digits of precision to vary the mass values to avoid duplicate masses epsilon = np.finfo(float).eps @@ -132,8 +130,7 @@ def sample(r_inner, r_break, r_outer, slope1, slope2): sim.set_parameter(mtiny=mtiny, minimum_fragment_mass=minimum_fragment_mass, nfrag_reduction=nfrag_reduction) sim.set_parameter(tstop=3e8, dt=6.0875/365.25, istep_out=60000, dump_cadence=10) -sim.clean() -sim.write_param() +sim.save() # Plot the initial conditions fig = plt.figure(figsize=(8.5, 11)) diff --git a/examples/Chambers2013/run_simulation.py b/examples/Chambers2013/run_simulation.py new file mode 100755 index 000000000..5ae2fb2a3 --- /dev/null +++ b/examples/Chambers2013/run_simulation.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +""" + Copyright 2023 - David Minton + This file is part of Swiftest. + Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with Swiftest. + If not, see: https://www.gnu.org/licenses. +""" + +""" +This will run the simulation from a set of initial conditions. The simulation parameters in this file are set to generate +a very short simulation for testing purposes. Edit the values passed to the run() function as necessary. + +Input +------ +simdata/param.in : ASCII Swiftest parameter input file. + +Output +------ +Outputs are stored in the /simdata subdirectory. + +""" +import swiftest +sim = swiftest.Simulation(read_param=True) + +# Original run parameters +# sim.run(tstop=3e8, dt=6.0875/365.25, istep_out=60000, dump_cadence=10,integreator="symba") +# +sim.run(tstop=10000.0, dt=6.0875/365.25, istep_out=10000, dump_cadence=0, integrator="symba") diff --git a/examples/Chambers2013/scattermovie.py b/examples/Chambers2013/scattermovie.py index 98b0645ef..e1eda643a 100755 --- a/examples/Chambers2013/scattermovie.py +++ b/examples/Chambers2013/scattermovie.py @@ -15,6 +15,15 @@ Creates a movie from a set of Swiftest output files. All simulation outputs are stored in the /simdata subdirectory. +**NOTE: You must have ffmpeg installed on your system before running this script. For instance, on MacOS: + +```brew install ffmpeg``` + +on Ubuntu: + +```sudo apt-get install ffmpeg``` + + Input ------ param.in : ASCII Swiftest parameter input file. @@ -33,6 +42,8 @@ from matplotlib import animation import matplotlib.colors as mcolors from collections import namedtuple + + plt.switch_backend('agg') titletext = "Chambers (2013)" @@ -108,8 +119,8 @@ def init_plot(self): self.ax.set_ylabel(ylabel[plot_style], fontsize='16', labelpad=1) leg = plt.legend(loc="upper left", scatterpoints=1, fontsize=10) - for i,l in enumerate(leg.legendHandles): - leg.legendHandles[i]._sizes = [20] + for i,l in enumerate(leg.legend_handles): + leg.legend_handles[i]._sizes = [20] if plot_style == "arotscatter": self.ax.set_yscale('log') From 9494ed4a7fc6bfd66de66ccd7e78d20b29dbd7ad Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 24 Oct 2023 14:40:04 -0400 Subject: [PATCH 102/324] Corrected c_lm dimension length allocation in write_frame_cb --- src/swiftest/swiftest_io.f90 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index bce34f3aa..05770e2b5 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2110,13 +2110,16 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension l_dimid") - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension m_dimid") + ! call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension l_dimid") + ! call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension m_dimid") + + m_dim_max = size(self%c_lm, 1) + l_dim_max = size(self%c_lm, 2) if(.not. allocated(self%c_lm)) then allocate(self%c_lm(m_dim_max, l_dim_max, 2)) end if - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_write_frame_cb nf90_getvar c_lm_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") end if call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp), & From 236c3837b5337ce6d400405d7d7bba1816c07638 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 24 Oct 2023 16:06:39 -0400 Subject: [PATCH 103/324] export c_lm dimension-coordinates to file --- src/swiftest/swiftest_io.f90 | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 05770e2b5..4b785879e 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1008,7 +1008,7 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) ! status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) ! if (status == NF90_NOERR) then - call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%sign_dimid, nc%l_dimid, nc%m_dimid], nc%c_lm_varid), & + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], nc%c_lm_varid), & "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) ! end if @@ -2073,6 +2073,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) ! Internals integer(I4B) :: idslot, old_mode, tmp integer(I4B) :: l_dim_max, m_dim_max + integer(I4B), dimension(:), allocatable :: lm_coords integer(I4B) :: status associate(tslot => nc%tslot) @@ -2110,11 +2111,20 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - ! call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension l_dimid") - ! call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_write_frame_cb nf90_inquire_dimension m_dimid") - m_dim_max = size(self%c_lm, 1) l_dim_max = size(self%c_lm, 2) + + ! Populate coordinate values for l and m and export to hdf file + allocate(lm_coords(l_dim_max)) + do i = 0, l_dim_max + lm_coords(i + 1) = i + end do + + call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var l_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var m_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1, -1]), "netcdf_io_write_frame_cb nf90_put_var sign_varid") + + ! Write dimension-coordinates to file if(.not. allocated(self%c_lm)) then allocate(self%c_lm(m_dim_max, l_dim_max, 2)) From 68dd60dfaf03a9a8fbf6a03e0d3586da24425679 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 24 Oct 2023 16:08:39 -0400 Subject: [PATCH 104/324] fixed a typo --- src/swiftest/swiftest_io.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 4b785879e..5d79f5969 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2071,7 +2071,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals - integer(I4B) :: idslot, old_mode, tmp + integer(I4B) :: idslot, old_mode, tmp, i integer(I4B) :: l_dim_max, m_dim_max integer(I4B), dimension(:), allocatable :: lm_coords integer(I4B) :: status From 91f0daf1bfbf59a5ed0ca0eb4efee78180141e93 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 24 Oct 2023 16:13:13 -0400 Subject: [PATCH 105/324] Fixed a typo in do loop condition --- src/swiftest/swiftest_io.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 5d79f5969..657a80033 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2116,7 +2116,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) ! Populate coordinate values for l and m and export to hdf file allocate(lm_coords(l_dim_max)) - do i = 0, l_dim_max + do i = 0, l_dim_max - 1 lm_coords(i + 1) = i end do From d5b7aec1d4f2fad74bbde41e32e1cd04a2122f87 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 24 Oct 2023 16:37:46 -0400 Subject: [PATCH 106/324] Fixed missing sum in rotphase --- src/swiftest/swiftest_drift.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index f83bb413a..08da848af 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -591,7 +591,7 @@ module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize - self%rotphase = MOD((.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) ! radians + self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) ! radians end subroutine swiftest_drift_cb_rotphase_update diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 7fc6bb4b7..933d716e1 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -105,7 +105,7 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) if (pl%lmask(i)) then r_mag = .mag. rh(:,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase ! CALCULATE CB PHASE VALUE FOR PHI + phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) From 3994b09f61455fcd5c7c6081b2eeef108fb8298d Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 25 Oct 2023 13:15:21 -0400 Subject: [PATCH 107/324] No changes made. Accidental change was fixed --- buildscripts/install_editable_debug.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index 3e6409ac9..bd1098bd4 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -8,7 +8,7 @@ cd ${ROOT_DIR} python3 -m venv ${VENV_DIR} . ${VENV_DIR}/bin/activate python3 -m pip install --upgrade pip -pip install scikit-build-core pyproject-metadata pathspec ninja cython +pip install scikit-build-core pyproject-metadata pathspec ninja cython ffmpeg-python pip install --config-settings=editable.rebuild=true \ --config-settings=build-dir="build/{wheel_tag}" \ --config-settings=cmake.build-type="Debug" \ From db4a0d420aed74fad15075b64626d495f0de86dc Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 30 Oct 2023 12:26:07 -0400 Subject: [PATCH 108/324] Fixed floating underflow error. Fixed typo where rot vector was not passed --- src/swiftest/swiftest_obl.f90 | 2 +- src/swiftest/swiftest_sph.f90 | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index fd0260fc4..273a97c5e 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -221,7 +221,7 @@ module subroutine swiftest_obl_acc_pl(self, nbody_system) associate(pl => self, cb => nbody_system%cb) npl = self%nbody - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rh, pl%lmask, pl%aobl, pl%Gmass, cb%aobl) + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rh, pl%lmask, pl%aobl, cb%rot, pl%Gmass, cb%aobl) #ifdef DOCONLOC do concurrent(i = 1:npl, pl%lmask(i)) shared(cb,pl) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 933d716e1..a981d099c 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -48,7 +48,12 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, l_max = size(c_lm, 2) - 1 N = (l_max + 1) * (l_max + 2) / 2 allocate(p(N),p_deriv(N)) - call PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative + + if(cos(theta) > epsilon(0.0_DP)) then + call PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative + else + call PlmON_d1(p, p_deriv, l_max, 0.0_DP) + end if do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term do m = 0, l From 80d2cfd0e8c55b74b9eb6b1d8c41c4e89a5af470 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 30 Oct 2023 13:18:28 -0400 Subject: [PATCH 109/324] Fixed typo. Was passing the wrong central body radius --- src/swiftest/swiftest_sph.f90 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index a981d099c..ca31611bc 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -100,7 +100,7 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals integer(I4B) :: i = 1 - real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle + real(DP) :: theta, phi !! zenith angle, and azimuthal angle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics associate(pl => self, npl => self%nbody, cb => nbody_system%cb, rh => self%rh) @@ -108,11 +108,10 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) do i = 1, npl if (pl%lmask(i)) then - r_mag = .mag. rh(:,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) + call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) pl%aobl(:, i) = g_sph(:) end if @@ -132,7 +131,7 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals integer(I4B) :: i = 1 - real(DP) :: r_mag, theta, phi !! magnitude of the position vector, zenith angle, and azimuthal angle + real(DP) :: theta, phi !! zenith angle, and azimuthal angle real(DP), dimension(NDIM) :: rh !! Position vector of the test particle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration @@ -147,11 +146,10 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) do i = 1, ntp if (tp%lmask(i)) then - r_mag = .mag. rh(:,i) theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase - call swiftest_sph_g_acc_one(cb%Gmass, r_mag, phi, theta, rh(:,i), cb%c_lm, g_sph) + call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, phi, theta, rh(:,i), cb%c_lm, g_sph) tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) tp%aobl(:, i) = g_sph(:) end if From 7b194269f43d8fe63a7dde7856f9d8f47bef0f6b Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 30 Oct 2023 16:11:15 -0400 Subject: [PATCH 110/324] fixed typos --- src/swiftest/swiftest_sph.f90 | 2 +- src/whm/whm_kick.f90 | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index ca31611bc..69c57b5be 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -78,7 +78,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, - ccss * (dplm * sin(theta) / (rh(3) * sin(phi)) & + plm * (l + 1) * rh(2) / r_mag**2)) ! g_y g_sph(3) = g_sph(3) + GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) & - + plm * (l + 1) * rh(3) / r_mag**2) ! g_z + + plm * (l + 1) * rh(3) / r_mag**2) ! g_z end do end do diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index 9c6a2a248..93b448967 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -237,6 +237,7 @@ module subroutine whm_kick_vh_pl(self, nbody_system, param, t, dt, lbeg) logical, intent(in) :: lbeg !! Logical flag indicating whether this is the beginning of the half step or not. ! Internals integer(I4B) :: i, npl + real(DP) :: tmp ! to check the acceleration kick due to the CB associate(pl => self, cb => nbody_system%cb) npl = self%nbody @@ -260,6 +261,7 @@ module subroutine whm_kick_vh_pl(self, nbody_system, param, t, dt, lbeg) do concurrent(i = 1:npl, pl%lmask(i)) #endif pl%vh(:, i) = pl%vh(:, i) + pl%ah(:, i) * dt + ! tmp = .mag.(pl%ah(:, i) - pl%aobl(:, i)) end do end associate From 25fcfac18482aef67d44d4bebf17bba72027be15 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 30 Oct 2023 19:30:34 -0400 Subject: [PATCH 111/324] New expression for g_sph. I had the wrong conversion from spherical to cartesian. --- src/swiftest/swiftest_sph.f90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 69c57b5be..02412d207 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -71,14 +71,14 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 1) * (-1.0_DP * cssc * m * plm / rh(2) & - - ccss * (dplm * sin(theta) / (rh(3) * cos(phi)) & - + plm * (l + 1) * rh(1) / r_mag**2)) ! g_x - g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 1) * (cssc * m * plm / rh(1) & - - ccss * (dplm * sin(theta) / (rh(3) * sin(phi)) & - + plm * (l + 1) * rh(2) / r_mag**2)) ! g_y - g_sph(3) = g_sph(3) + GMcb * r_0**l / r_mag**(l + 1) * ccss * (dplm * sin(theta) / sqrt(r_mag**2 - rh(3)**2) & - + plm * (l + 1) * rh(3) / r_mag**2) ! g_z + g_sph(1) = g_sph(1) + GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & + - ccss * sin(theta) * cos(phi) & + * (dplm * cos(theta) + plm * (l + 1))) ! g_x + g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * cos(phi) / sin(theta) & + - ccss * sin(theta) * sin(phi) & + * (dplm * cos(theta) + plm * (l + 1))) ! g_y + g_sph(3) = g_sph(3) + GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & + + plm * (l + 1) * cos(theta)) ! g_z end do end do From 27f24ab300a54ff775b112d679ba8e06e4ca0e29 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 1 Nov 2023 09:41:31 -0400 Subject: [PATCH 112/324] Fixed sign typos --- src/swiftest/swiftest_sph.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 02412d207..aed6d4f0a 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -72,10 +72,10 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! m > 0 g_sph(1) = g_sph(1) + GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & - - ccss * sin(theta) * cos(phi) & + + ccss * sin(theta) * cos(phi) & * (dplm * cos(theta) + plm * (l + 1))) ! g_x - g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * cos(phi) / sin(theta) & - - ccss * sin(theta) * sin(phi) & + g_sph(2) = g_sph(2) + GMcb * r_0**l / r_mag**(l + 2) * (-1.0_DP * cssc * m * plm * cos(phi) / sin(theta) & + + ccss * sin(theta) * sin(phi) & * (dplm * cos(theta) + plm * (l + 1))) ! g_y g_sph(3) = g_sph(3) + GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & + plm * (l + 1) * cos(theta)) ! g_z From c0afdf119399604fb074ecd47902579af36fe73d Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 1 Nov 2023 11:14:29 -0400 Subject: [PATCH 113/324] Flipped sign --- src/swiftest/swiftest_sph.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index aed6d4f0a..32187c62a 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -71,13 +71,13 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) = g_sph(1) + GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & + g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & + ccss * sin(theta) * cos(phi) & * (dplm * cos(theta) + plm * (l + 1))) ! g_x - g_sph(2) = g_sph(2) + GMcb * r_0**l / r_mag**(l + 2) * (-1.0_DP * cssc * m * plm * cos(phi) / sin(theta) & + g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-1.0_DP * cssc * m * plm * cos(phi) / sin(theta) & + ccss * sin(theta) * sin(phi) & * (dplm * cos(theta) + plm * (l + 1))) ! g_y - g_sph(3) = g_sph(3) + GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & + g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & + plm * (l + 1) * cos(theta)) ! g_z end do end do From e32bfa60cdddabf80230bb4d05feef28c1067ffd Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 1 Nov 2023 15:18:45 -0400 Subject: [PATCH 114/324] Changed the normalization of the Legendre polynomial --- src/swiftest/swiftest_sph.f90 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 32187c62a..eb1c2dbc1 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -50,9 +50,9 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, allocate(p(N),p_deriv(N)) if(cos(theta) > epsilon(0.0_DP)) then - call PlmON_d1(p, p_deriv, l_max, cos(theta)) ! Orthonormalized Associated Legendre Polynomials and the 1st Derivative + call PLegendreA_d1(p, p_deriv, l_max, cos(theta)) ! Unnormalized Associated Legendre Polynomials and the 1st Derivative else - call PlmON_d1(p, p_deriv, l_max, 0.0_DP) + call PLegendreA_d1(p, p_deriv, l_max, 0.0_DP) end if do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term @@ -60,8 +60,8 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! Associated Legendre Polynomials lmindex = PlmIndex(l, m) - plm = p(lmindex) ! p_l,m - dplm = p_deriv(lmindex) ! d(p_l,m) + plm = p(lmindex) ! p_l,m + dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(m+1, l+1, 1) * cos(m * phi) & @@ -79,6 +79,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, * (dplm * cos(theta) + plm * (l + 1))) ! g_y g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & + plm * (l + 1) * cos(theta)) ! g_z + end do end do From f239c2e05ed81c5a87792ea3cf378c30c7b1cbcf Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 2 Nov 2023 13:54:48 -0400 Subject: [PATCH 115/324] Added temporary trial code to reduce error --- src/swiftest/swiftest_sph.f90 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index eb1c2dbc1..5a57e82f5 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -42,6 +42,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) + real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac0, fac1, fac2, j2rp2, j4rp4, r_fac g_sph(:) = 0.0_DP r_mag = sqrt(dot_product(rh(:), rh(:))) @@ -49,6 +50,19 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, N = (l_max + 1) * (l_max + 2) / 2 allocate(p(N),p_deriv(N)) + ! to compare w s_obl.f90 + j2rp2 = -c_lm(1, 3, 1) * r_0**2 + j4rp4 = -c_lm(1, 4, 1) * r_0**4 + r2 = dot_product(rh(:), rh(:)) + irh = 1.0_DP / sqrt(r2) + rinv2 = irh**2 + t0 = -GMcb * rinv2 * rinv2 * irh + t1 = 1.5_DP * j2rp2 + t2 = rh(3) * rh(3) * rinv2 + t3 = 1.875_DP * j4rp4 * rinv2 + fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) + fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) + if(cos(theta) > epsilon(0.0_DP)) then call PLegendreA_d1(p, p_deriv, l_max, cos(theta)) ! Unnormalized Associated Legendre Polynomials and the 1st Derivative else @@ -79,6 +93,17 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, * (dplm * cos(theta) + plm * (l + 1))) ! g_y g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & + plm * (l + 1) * cos(theta)) ! g_z + + ! !! Condensed form ???? (to reduce floating point error) + ! fac0 = -GMcb / r_mag**2 + ! fac1 = cssc * m * plm / sin(theta) + ! fac2 = ccss * sin(theta) * (dplm * cos(theta) + plm * (l + 1)) + ! r_fac = (r_0 / r_mag)**l + + ! g_sph(1) = g_sph(1) + fac0 * r_fac * (fac1 * sin(phi) + fac2 * cos(phi)) + ! g_sph(2) = g_sph(2) + fac0 * r_fac * (fac1 * cos(phi) + fac2 * sin(phi)) + ! g_sph(3) = g_sph(3) + fac0 * r_fac * ccss * (-1.0_DP * dplm * sin(theta)**2 & + ! + plm * (l + 1) * cos(theta)) ! g_z end do end do From 7b297d4df0f3f752be74905a68d15ae5fe217925 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sun, 5 Nov 2023 15:53:41 -0500 Subject: [PATCH 116/324] rearranged calculations to reduce floating point error --- src/swiftest/swiftest_sph.f90 | 71 ++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 5a57e82f5..b70d9e69b 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -42,7 +42,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) - real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac0, fac1, fac2, j2rp2, j4rp4, r_fac + real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac0, fac1, fac2, fac3, fac4, j2rp2, j4rp4, r_fac, cos_tmp, sin_tmp, sin2_tmp, plm1, sin_phi, cos_phi g_sph(:) = 0.0_DP r_mag = sqrt(dot_product(rh(:), rh(:))) @@ -80,31 +80,60 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(m+1, l+1, 1) * cos(m * phi) & + c_lm(m+1, l+1, 2) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) - cssc = -1.0_DP * c_lm(m+1, l+1, 1) * sin(m * phi) & + cssc = -1 * c_lm(m+1, l+1, 1) * sin(m * phi) & + c_lm(m+1, l+1, 2) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & - + ccss * sin(theta) * cos(phi) & - * (dplm * cos(theta) + plm * (l + 1))) ! g_x - g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-1.0_DP * cssc * m * plm * cos(phi) / sin(theta) & - + ccss * sin(theta) * sin(phi) & - * (dplm * cos(theta) + plm * (l + 1))) ! g_y - g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1.0_DP * dplm * sin(theta)**2 & - + plm * (l + 1) * cos(theta)) ! g_z - - ! !! Condensed form ???? (to reduce floating point error) - ! fac0 = -GMcb / r_mag**2 + ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & + ! + ccss * sin(theta) * cos(phi) & + ! * (dplm * cos(theta) + plm * (l + 1))) ! g_x + ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-1 * cssc * m * plm * cos(phi) / sin(theta) & + ! + ccss * sin(theta) * sin(phi) & + ! * (dplm * cos(theta) + plm * (l + 1))) ! g_y + ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1 * dplm * sin(theta)**2 & + ! + plm * (l + 1) * cos(theta)) ! g_z + + ! cos_tmp = cos(theta) + ! sin_tmp = sin(theta) + ! sin2_tmp = sin(2 * theta) + ! sin_phi = sin(phi) + ! cos_phi = cos(phi) + ! g_sph(:) = 0.0_DP + + ! !! Condensed form to reduce floating point error + ! ! fac0 = -GMcb / r_mag**2 ! fac1 = cssc * m * plm / sin(theta) - ! fac2 = ccss * sin(theta) * (dplm * cos(theta) + plm * (l + 1)) - ! r_fac = (r_0 / r_mag)**l - - ! g_sph(1) = g_sph(1) + fac0 * r_fac * (fac1 * sin(phi) + fac2 * cos(phi)) - ! g_sph(2) = g_sph(2) + fac0 * r_fac * (fac1 * cos(phi) + fac2 * sin(phi)) - ! g_sph(3) = g_sph(3) + fac0 * r_fac * ccss * (-1.0_DP * dplm * sin(theta)**2 & - ! + plm * (l + 1) * cos(theta)) ! g_z - + ! fac2 = ccss * sin(theta) + ! fac3 = dplm * cos(theta) + plm * (l + 1) + ! r_fac = -GMcb * r_0**l / r_mag**(l + 2) + + ! g_sph(1) = g_sph(1) + r_fac * (fac1 * sin(phi) + fac2 * fac3 * cos(phi)) + ! g_sph(2) = g_sph(2) + r_fac * (fac1 * cos(phi) + fac2 * fac3 * sin(phi)) + ! g_sph(3) = g_sph(3) + r_fac * ccss * (fac3 * cos(theta) - dplm) + ! (-1 * dplm * sin(theta)**2 + plm * (l + 1) * cos(theta)) ! g_z + + ! Condensed form with alternative form for g_sph + if ((m+1) .le. l) then + lmindex = PlmIndex(l, m+1) + plm1 = p(lmindex) + else + plm1 = 0.0_DP + end if + + ! fac0 = -(m * cos_tmp * plm / sin_tmp - plm1) / sin_tmp ! dplm + fac1 = m / sin(theta) * plm + fac2 = plm * (l + m + 1) * sin(theta) + plm1 * cos(theta) + fac3 = fac2 - fac1 + ! fac3 = plm * (l + m + 1) * cos(theta) + ! fac4 = plm1 * sin(theta) + r_fac = -GMcb * r_0**l / r_mag**(l + 2) + + ! g_sph(:) = 0.0_DP + g_sph(1) = g_sph(1) + r_fac * (cssc * fac1 * sin(phi) + ccss * (fac2 - fac1) * cos(phi)) + g_sph(2) = g_sph(2) + r_fac * (-cssc * fac1 * cos(phi) + ccss * (fac2 - fac1) * sin(phi)) + g_sph(3) = g_sph(3) + r_fac * ccss * (plm * (l + m + 1) * cos(theta) - plm1 * sin(theta)) + end do end do From 6b2c4966678fb368fc325325af339a7263b39b00 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 10 Nov 2023 11:49:44 -0500 Subject: [PATCH 117/324] Changed normalisation to 4pi to be consistent everywhere --- src/swiftest/swiftest_sph.f90 | 4 ++-- swiftest/sph_harmonics.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index b70d9e69b..cda7d617f 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -64,9 +64,9 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) if(cos(theta) > epsilon(0.0_DP)) then - call PLegendreA_d1(p, p_deriv, l_max, cos(theta)) ! Unnormalized Associated Legendre Polynomials and the 1st Derivative + call PlmBar_d1(p, p_deriv, l_max, cos(theta)) ! Unnormalized Associated Legendre Polynomials and the 1st Derivative else - call PLegendreA_d1(p, p_deriv, l_max, 0.0_DP) + call PlmBar_d1(p, p_deriv, l_max, 0.0_DP) end if do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index e5a1d9b71..79f0abf03 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -72,7 +72,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu # get gravity coefficients clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = 'ortho') # Change to orthonormal normalization + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization # Return reference radius EQUALS the radius of the Central Body print(f'Ensure that the Central Body radius equals the reference radius.') @@ -123,7 +123,7 @@ def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): # get coefficients clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = 'ortho') # change to orthogonal normalization + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization # Return reference radius EQUALS the radius of the Central Body From 36bc720f51f261cc93eb834b740a2b3a351cac11 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 10 Nov 2023 16:21:22 -0500 Subject: [PATCH 118/324] Changed to 4pi normalisation. Scaled C_lm in python by 4pi for correct C00 terms.UNSURE, STILL TESTING --- src/swiftest/swiftest_sph.f90 | 6 ++++-- swiftest/sph_harmonics.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index cda7d617f..aba2148a7 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -62,9 +62,11 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, t3 = 1.875_DP * j4rp4 * rinv2 fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) + fac0 = 4 * PI if(cos(theta) > epsilon(0.0_DP)) then - call PlmBar_d1(p, p_deriv, l_max, cos(theta)) ! Unnormalized Associated Legendre Polynomials and the 1st Derivative + ! call PlmBar_d1(p, p_deriv, l_max, cos(theta)) ! Associated Legendre Polynomials and the 1st Derivative + call PlmBar(p, l_max, cos(theta)) else call PlmBar_d1(p, p_deriv, l_max, 0.0_DP) end if @@ -75,7 +77,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! Associated Legendre Polynomials lmindex = PlmIndex(l, m) plm = p(lmindex) ! p_l,m - dplm = p_deriv(lmindex) ! d(p_l,m) + ! dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(m+1, l+1, 1) * cos(m * phi) & diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index 79f0abf03..832abc8d3 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -72,7 +72,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu # get gravity coefficients clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization + clm = clm_class.to_array(normalization = '4pi') * 4 * np.pi # export as array with 4pi normalization and scaling by 4*pi to match normalisation # Return reference radius EQUALS the radius of the Central Body print(f'Ensure that the Central Body radius equals the reference radius.') From ad6fbcc097d7e496ec8e2f37310fd10f74e5646f Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 14 Nov 2023 16:21:31 -0500 Subject: [PATCH 119/324] Had to renormalise plm1. Acceleration matches swiftest_obl.f90 --- src/swiftest/swiftest_sph.f90 | 51 ++++++++++++++++++++--------------- swiftest/sph_harmonics.py | 2 +- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index aba2148a7..81f474388 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -68,7 +68,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! call PlmBar_d1(p, p_deriv, l_max, cos(theta)) ! Associated Legendre Polynomials and the 1st Derivative call PlmBar(p, l_max, cos(theta)) else - call PlmBar_d1(p, p_deriv, l_max, 0.0_DP) + call PlmBar(p, l_max, 0.0_DP) end if do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term @@ -96,32 +96,38 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1 * dplm * sin(theta)**2 & ! + plm * (l + 1) * cos(theta)) ! g_z - ! cos_tmp = cos(theta) - ! sin_tmp = sin(theta) - ! sin2_tmp = sin(2 * theta) - ! sin_phi = sin(phi) - ! cos_phi = cos(phi) + cos_tmp = cos(theta) + sin_tmp = sin(theta) + sin2_tmp = sin(2 * theta) + sin_phi = sin(phi) + cos_phi = cos(phi) ! g_sph(:) = 0.0_DP - - ! !! Condensed form to reduce floating point error - ! ! fac0 = -GMcb / r_mag**2 - ! fac1 = cssc * m * plm / sin(theta) - ! fac2 = ccss * sin(theta) - ! fac3 = dplm * cos(theta) + plm * (l + 1) - ! r_fac = -GMcb * r_0**l / r_mag**(l + 2) - - ! g_sph(1) = g_sph(1) + r_fac * (fac1 * sin(phi) + fac2 * fac3 * cos(phi)) - ! g_sph(2) = g_sph(2) + r_fac * (fac1 * cos(phi) + fac2 * fac3 * sin(phi)) - ! g_sph(3) = g_sph(3) + r_fac * ccss * (fac3 * cos(theta) - dplm) - ! (-1 * dplm * sin(theta)**2 + plm * (l + 1) * cos(theta)) ! g_z - - ! Condensed form with alternative form for g_sph + + ! Alternative form for g_sph + if ((m+1) .le. l) then lmindex = PlmIndex(l, m+1) - plm1 = p(lmindex) + plm1 = p(lmindex) + if(m .eq. 0) then + plm1 = plm1 * sqrt(((l + m + 1) * (l - m)) / 2.0) ! renormalize plm1 to the norm of plm + else + plm1 = plm1 * sqrt((l + m + 1) * (l - m) * 1.0) ! renormalize plm1 to the norm of plm + end if else plm1 = 0.0_DP end if + + ! !! Alternative form of dplm + + ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m / sin(theta) * plm * sin(phi) & + ! + ccss * cos(phi) * (plm * ((l + m + 1) * sin(theta) - m / sin(theta)) & + ! + plm1 * cos(theta))) + ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-cssc * m / sin(theta) * plm * cos(phi) & + ! + ccss * sin(phi) * (plm * ((l + m + 1) * sin(theta) - m / sin(theta)) & + ! + plm1 * cos(theta))) + ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (plm * (l + m +1) * cos(theta) - plm1 * sin(theta)) + + ! Condensed form ! fac0 = -(m * cos_tmp * plm / sin_tmp - plm1) / sin_tmp ! dplm fac1 = m / sin(theta) * plm @@ -135,6 +141,9 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, g_sph(1) = g_sph(1) + r_fac * (cssc * fac1 * sin(phi) + ccss * (fac2 - fac1) * cos(phi)) g_sph(2) = g_sph(2) + r_fac * (-cssc * fac1 * cos(phi) + ccss * (fac2 - fac1) * sin(phi)) g_sph(3) = g_sph(3) + r_fac * ccss * (plm * (l + m + 1) * cos(theta) - plm1 * sin(theta)) + + fac0 = (.mag. g_sph(:)) + ! fac3 = 3 * c_lm(m+1, l+1, 1) / 2 * r_0**2 / r_mag**4 * (3*(cos(theta))**2 - 1) * GMcb ! g_sph for J2 end do end do diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index 832abc8d3..6daa4f93c 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -72,7 +72,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu # get gravity coefficients clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = '4pi') * 4 * np.pi # export as array with 4pi normalization and scaling by 4*pi to match normalisation + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization and not scaling by 4*pi to match normalisation # Return reference radius EQUALS the radius of the Central Body print(f'Ensure that the Central Body radius equals the reference radius.') From 39ef3af656d2e194e07a2b286dbd08342315efb7 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 15 Nov 2023 14:27:26 -0500 Subject: [PATCH 120/324] edited to give the user to option to set a refernce radius for the CB --- swiftest/sph_harmonics.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index 6daa4f93c..25f74202a 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -29,7 +29,7 @@ ) class Sph_Harmonics(object): - def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radius = False): + def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radius = False, ref_radius = None): """ Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). @@ -48,8 +48,10 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu length of the pricipal axis aligned with the z axis lmax : int, optional, default = 6 The maximum spherical harmonic degree resolvable by the grid. - ref_radius : boolean, optional, default = False + lref_radius : boolean, optional, default = False Boolean value to return the reference radius calculated by SHTOOLS + ref_radius : float, optional, default = None + Reference radius to scale the gravitational coefficients to Returns ------- @@ -77,13 +79,16 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, ref_radiu # Return reference radius EQUALS the radius of the Central Body print(f'Ensure that the Central Body radius equals the reference radius.') - if(ref_radius == True): + if(lref_radius == True and ref_radius is None): ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius + else if(lref_radius == True and ref_radius is not None): + clm = clm.change_ref(r0 = ref_radius) + return clm, ref_radius else: return clm - def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): + def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radius = None): """ Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. Uses pyshtools. @@ -98,8 +103,10 @@ def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): DH grid of the surface relief of the body lmax : int, optional, default = 6 The maximum spherical harmonic degree resolvable by the grid. - ref_radius : boolean, optional, default = False + lref_radius : boolean, optional, default = False Boolean value to return the reference radius calculated by SHTOOLS + ref_radius : float, optional, default = None + Reference radius to scale the gravitational coefficients to Returns ------- @@ -129,8 +136,11 @@ def clm_from_relief(mass, density, grid, lmax = 6, ref_radius = True): print(f'Ensure that the Central Body radius equals the reference radius.') - if(ref_radius == True): + if(lref_radius == True and ref_radius is None): ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius + else if(lref_radius == True and ref_radius is not None): + clm = clm.change_ref(r0 = ref_radius) + return clm, ref_radius else: return clm From f52809ee7c240abac9b80bf21aa83c2ce36db961 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 15 Nov 2023 14:41:45 -0500 Subject: [PATCH 121/324] fixed a typo --- swiftest/sph_harmonics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index 25f74202a..0f1f0b8c9 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -82,7 +82,7 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radi if(lref_radius == True and ref_radius is None): ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius - else if(lref_radius == True and ref_radius is not None): + elif(lref_radius == True and ref_radius is not None): clm = clm.change_ref(r0 = ref_radius) return clm, ref_radius else: @@ -139,7 +139,7 @@ def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radi if(lref_radius == True and ref_radius is None): ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius - else if(lref_radius == True and ref_radius is not None): + elif(lref_radius == True and ref_radius is not None): clm = clm.change_ref(r0 = ref_radius) return clm, ref_radius else: From 137e73b07b7991da5fba8e78db8ac365e70d3175 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 15 Nov 2023 15:24:55 -0500 Subject: [PATCH 122/324] fixed a typo --- swiftest/sph_harmonics.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index 0f1f0b8c9..2f192e86d 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -83,7 +83,8 @@ def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radi ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius elif(lref_radius == True and ref_radius is not None): - clm = clm.change_ref(r0 = ref_radius) + clm_class = clm_class.change_ref(r0 = ref_radius) + clm = clm_class.to_array(normalization = '4pi') return clm, ref_radius else: return clm @@ -140,7 +141,8 @@ def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radi ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] return clm, ref_radius elif(lref_radius == True and ref_radius is not None): - clm = clm.change_ref(r0 = ref_radius) + clm_class = clm_class.change_ref(r0 = ref_radius) + clm = clm_class.to_array(normalization = '4pi') return clm, ref_radius else: return clm From 9675e1435ed137fa6f8e7af7cdf2eb03b8fa7173 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 15 Nov 2023 17:09:23 -0500 Subject: [PATCH 123/324] defined a variable for sin and cos theta. Checks for tiny number too --- src/swiftest/swiftest_sph.f90 | 68 +++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 81f474388..cf2916260 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -41,6 +41,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP) :: r_mag !! magnitude of rh real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code + real(DP) :: cos_theta, sin_theta !! cos(theta) and sin(theta) real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac0, fac1, fac2, fac3, fac4, j2rp2, j4rp4, r_fac, cos_tmp, sin_tmp, sin2_tmp, plm1, sin_phi, cos_phi @@ -64,12 +65,19 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) fac0 = 4 * PI - if(cos(theta) > epsilon(0.0_DP)) then - ! call PlmBar_d1(p, p_deriv, l_max, cos(theta)) ! Associated Legendre Polynomials and the 1st Derivative - call PlmBar(p, l_max, cos(theta)) - else - call PlmBar(p, l_max, 0.0_DP) - end if + cos_theta = cos(theta) + sin_theta = sin(theta) + + + + if(abs(cos_theta) < epsilon(0.0_DP)) then + cos_theta = 0.0_DP + if(abs(sin_theta) < epsilon(0.0_DP)) then + sin_theta = 0.0_DP + + ! call PlmBar_d1(p, p_deriv, l_max, cos_theta) ! Associated Legendre Polynomials and the 1st Derivative + call PlmBar(p, l_max, cos_theta) + do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term do m = 0, l @@ -87,17 +95,17 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! cssc * m = first derivative of ccss with respect to phi ! m > 0 - ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin(theta) & - ! + ccss * sin(theta) * cos(phi) & - ! * (dplm * cos(theta) + plm * (l + 1))) ! g_x - ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-1 * cssc * m * plm * cos(phi) / sin(theta) & - ! + ccss * sin(theta) * sin(phi) & - ! * (dplm * cos(theta) + plm * (l + 1))) ! g_y - ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1 * dplm * sin(theta)**2 & - ! + plm * (l + 1) * cos(theta)) ! g_z - - cos_tmp = cos(theta) - sin_tmp = sin(theta) + ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin_theta & + ! + ccss * sin_theta * cos(phi) & + ! * (dplm * cos_theta + plm * (l + 1))) ! g_x + ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-1 * cssc * m * plm * cos(phi) / sin_theta & + ! + ccss * sin_theta * sin(phi) & + ! * (dplm * cos_theta + plm * (l + 1))) ! g_y + ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1 * dplm * sin_theta**2 & + ! + plm * (l + 1) * cos_theta) ! g_z + + cos_tmp = cos_theta + sin_tmp = sin_theta sin2_tmp = sin(2 * theta) sin_phi = sin(phi) cos_phi = cos(phi) @@ -119,31 +127,31 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! !! Alternative form of dplm - ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m / sin(theta) * plm * sin(phi) & - ! + ccss * cos(phi) * (plm * ((l + m + 1) * sin(theta) - m / sin(theta)) & - ! + plm1 * cos(theta))) - ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-cssc * m / sin(theta) * plm * cos(phi) & - ! + ccss * sin(phi) * (plm * ((l + m + 1) * sin(theta) - m / sin(theta)) & - ! + plm1 * cos(theta))) - ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (plm * (l + m +1) * cos(theta) - plm1 * sin(theta)) + ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m / sin_theta * plm * sin(phi) & + ! + ccss * cos(phi) * (plm * ((l + m + 1) * sin_theta - m / sin_theta) & + ! + plm1 * cos_theta)) + ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-cssc * m / sin_theta * plm * cos(phi) & + ! + ccss * sin(phi) * (plm * ((l + m + 1) * sin_theta - m / sin_theta) & + ! + plm1 * cos_theta)) + ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (plm * (l + m +1) * cos_theta - plm1 * sin_theta) ! Condensed form ! fac0 = -(m * cos_tmp * plm / sin_tmp - plm1) / sin_tmp ! dplm - fac1 = m / sin(theta) * plm - fac2 = plm * (l + m + 1) * sin(theta) + plm1 * cos(theta) + fac1 = m * plm / sin_theta + fac2 = plm * (l + m + 1) * sin_theta + plm1 * cos_theta fac3 = fac2 - fac1 - ! fac3 = plm * (l + m + 1) * cos(theta) - ! fac4 = plm1 * sin(theta) + ! fac3 = plm * (l + m + 1) * cos_theta + ! fac4 = plm1 * sin_theta r_fac = -GMcb * r_0**l / r_mag**(l + 2) ! g_sph(:) = 0.0_DP g_sph(1) = g_sph(1) + r_fac * (cssc * fac1 * sin(phi) + ccss * (fac2 - fac1) * cos(phi)) g_sph(2) = g_sph(2) + r_fac * (-cssc * fac1 * cos(phi) + ccss * (fac2 - fac1) * sin(phi)) - g_sph(3) = g_sph(3) + r_fac * ccss * (plm * (l + m + 1) * cos(theta) - plm1 * sin(theta)) + g_sph(3) = g_sph(3) + r_fac * ccss * (plm * (l + m + 1) * cos_theta - plm1 * sin_theta) fac0 = (.mag. g_sph(:)) - ! fac3 = 3 * c_lm(m+1, l+1, 1) / 2 * r_0**2 / r_mag**4 * (3*(cos(theta))**2 - 1) * GMcb ! g_sph for J2 + ! fac3 = 3 * c_lm(m+1, l+1, 1) / 2 * r_0**2 / r_mag**4 * (3*(cos_theta)**2 - 1) * GMcb ! g_sph for J2 end do end do From d8e23dcd119e3e1173410f262e2f159fde6f267a Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 16 Nov 2023 11:17:10 -0500 Subject: [PATCH 124/324] Checked for 1/0 term when sin_theta = 0 --- src/swiftest/swiftest_sph.f90 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index cf2916260..bce58bfcb 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -138,11 +138,16 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! Condensed form ! fac0 = -(m * cos_tmp * plm / sin_tmp - plm1) / sin_tmp ! dplm - fac1 = m * plm / sin_theta - fac2 = plm * (l + m + 1) * sin_theta + plm1 * cos_theta - fac3 = fac2 - fac1 ! fac3 = plm * (l + m + 1) * cos_theta ! fac4 = plm1 * sin_theta + if(sin_theta .eq. 0) then + fac1 = 0.0_DP + else + fac1 = m * plm / sin_theta + end if + + fac2 = plm * (l + m + 1) * sin_theta + plm1 * cos_theta + fac3 = fac2 - fac1 r_fac = -GMcb * r_0**l / r_mag**(l + 2) ! g_sph(:) = 0.0_DP From ae69ef59c34270e408fc21333b8e7fe5b6f81521 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 16 Nov 2023 11:18:57 -0500 Subject: [PATCH 125/324] fixed typo --- src/swiftest/swiftest_sph.f90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index bce58bfcb..7eff7e16a 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -72,8 +72,10 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, if(abs(cos_theta) < epsilon(0.0_DP)) then cos_theta = 0.0_DP + end if if(abs(sin_theta) < epsilon(0.0_DP)) then sin_theta = 0.0_DP + end if ! call PlmBar_d1(p, p_deriv, l_max, cos_theta) ! Associated Legendre Polynomials and the 1st Derivative call PlmBar(p, l_max, cos_theta) @@ -145,7 +147,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, else fac1 = m * plm / sin_theta end if - + fac2 = plm * (l + m + 1) * sin_theta + plm1 * cos_theta fac3 = fac2 - fac1 r_fac = -GMcb * r_0**l / r_mag**(l + 2) From f1eaf07c0f9bb8550e07810f7d15483eb06c47e6 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 16 Nov 2023 14:54:24 -0500 Subject: [PATCH 126/324] reorganized passing of variables. Adjusted the rotation to account for cb%rotphase --- src/swiftest/swiftest_module.f90 | 9 ++++----- src/swiftest/swiftest_sph.f90 | 32 +++++++++++++++++--------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 817388bbd..cf0cd771e 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -1857,17 +1857,16 @@ end subroutine swiftest_coarray_cocollect_tp #endif interface - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) implicit none real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) - real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) + real(DP), intent(in) :: phi_cb !! rotation phase of the central body real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle - real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) + real(DP), dimension(:), intent(inout), optional :: aoblcb!! Barycentric acceleration of central body (only for massive input bodies) end subroutine swiftest_sph_g_acc_one module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 7eff7e16a..e3ac80815 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -16,7 +16,7 @@ contains - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -26,19 +26,20 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! Arguments real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi !! Azimuthal/Phase angle (radians) - real(DP), intent(in) :: theta !! Inclination/Zenith angle (radians) + real(DP), intent(in) :: phi_cb !! rotation phase of the central body real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector + real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle - real(DP), dimension(:), intent(inout), optional :: aoblcb !! Barycentric acceleration of central body (only for massive input bodies) + real(DP), dimension(:), intent(inout), optional :: aoblcb!! Barycentric acceleration of central body (only for massive input bodies) ! Internals integer :: l, m !! SPH coefficients integer :: l_max !! max Spherical Harmonic l order value integer(I4B) :: N, lmindex !! Length of Legendre polynomials and index at a given l, m real(DP) :: r_mag !! magnitude of rh + real(DP) :: phi, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase + real(DP) :: theta !! Inclination/Zenith angle (radians) real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code real(DP) :: cos_theta, sin_theta !! cos(theta) and sin(theta) @@ -46,6 +47,9 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac0, fac1, fac2, fac3, fac4, j2rp2, j4rp4, r_fac, cos_tmp, sin_tmp, sin2_tmp, plm1, sin_phi, cos_phi g_sph(:) = 0.0_DP + theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) + phi = atan2(rh(2), rh(1)) + phi_bar = MOD(phi - phi_cb, 2 * PI) r_mag = sqrt(dot_product(rh(:), rh(:))) l_max = size(c_lm, 2) - 1 N = (l_max + 1) * (l_max + 2) / 2 @@ -90,10 +94,10 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi, theta, rh, c_lm, g_sph, ! dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi - ccss = c_lm(m+1, l+1, 1) * cos(m * phi) & - + c_lm(m+1, l+1, 2) * sin(m * phi) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) - cssc = -1 * c_lm(m+1, l+1, 1) * sin(m * phi) & - + c_lm(m+1, l+1, 2) * cos(m * phi) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) + ccss = c_lm(m+1, l+1, 1) * cos(m * phi_bar) & + + c_lm(m+1, l+1, 2) * sin(m * phi_bar) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) + cssc = -1 * c_lm(m+1, l+1, 1) * sin(m * phi_bar) & + + c_lm(m+1, l+1, 2) * cos(m * phi_bar) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) ! cssc * m = first derivative of ccss with respect to phi ! m > 0 @@ -189,10 +193,10 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) do i = 1, npl if (pl%lmask(i)) then - theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase + ! theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) + ! phi = atan2(rh(2,i), rh(1,i)) ! - cb%rotphase - call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, phi, theta, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) + call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) pl%aobl(:, i) = g_sph(:) end if @@ -227,10 +231,8 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) do i = 1, ntp if (tp%lmask(i)) then - theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - phi = atan2(rh(2,i), rh(1,i)) - cb%rotphase - call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, phi, theta, rh(:,i), cb%c_lm, g_sph) + call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, rh(:,i), cb%c_lm, g_sph) tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) tp%aobl(:, i) = g_sph(:) end if From 87d6d44e2937fe44c0fd19460359af86d22da6f2 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 16 Nov 2023 15:20:50 -0500 Subject: [PATCH 127/324] rearranged some terms --- src/swiftest/swiftest_sph.f90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index e3ac80815..af89a74f6 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -49,7 +49,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp g_sph(:) = 0.0_DP theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) phi = atan2(rh(2), rh(1)) - phi_bar = MOD(phi - phi_cb, 2 * PI) + phi_bar = MOD(phi - phi_cb, 2 * PI) ! represents the phase difference between the central body's and the particle's phase r_mag = sqrt(dot_product(rh(:), rh(:))) l_max = size(c_lm, 2) - 1 N = (l_max + 1) * (l_max + 2) / 2 @@ -90,15 +90,15 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp ! Associated Legendre Polynomials lmindex = PlmIndex(l, m) - plm = p(lmindex) ! p_l,m + plm = p(lmindex) ! p_l,m ! dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(m+1, l+1, 1) * cos(m * phi_bar) & - + c_lm(m+1, l+1, 2) * sin(m * phi_bar) ! C_lm * cos(m * phi) + S_lm * sin(m * phi) + + c_lm(m+1, l+1, 2) * sin(m * phi_bar) ! C_lm * cos(m * phi_bar) + S_lm * sin(m * phi_bar) cssc = -1 * c_lm(m+1, l+1, 1) * sin(m * phi_bar) & - + c_lm(m+1, l+1, 2) * cos(m * phi_bar) ! - C_lm * sin(m * phi) + S_lm * cos(m * phi) - ! cssc * m = first derivative of ccss with respect to phi + + c_lm(m+1, l+1, 2) * cos(m * phi_bar) ! - C_lm * sin(m * phi_bar) + S_lm * cos(m * phi_bar) + ! cssc * m = first derivative of ccss with respect to phi ! m > 0 ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin_theta & From d7ed97e5978a96ec4e39c636d7e2d217a4d9e1f8 Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 20 Nov 2023 16:24:19 -0500 Subject: [PATCH 128/324] defined all values of c_lm less than epsilon as 0.0_DP to reduce extra calculations --- src/swiftest/swiftest_io.f90 | 7 +++++++ src/swiftest/swiftest_sph.f90 | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 657a80033..d32077b16 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -3353,6 +3353,13 @@ module subroutine swiftest_io_read_in_system(self, nc, param) param%lshgrav = allocated(self%cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) + if(param%lshgrav) then + ! Replace elements of c_lm smaller than epsilon with 0.0 + WHERE (abs(self%cb%c_lm) < EPSILON(0.0_DP)) + self%cb%c_lm = 0.0_DP + END WHERE + end if + param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) if (.not.param%loblatecb .and. .not.param%lshgrav) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index af89a74f6..42d7bb59e 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -185,7 +185,6 @@ module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals integer(I4B) :: i = 1 - real(DP) :: theta, phi !! zenith angle, and azimuthal angle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics associate(pl => self, npl => self%nbody, cb => nbody_system%cb, rh => self%rh) @@ -216,8 +215,6 @@ module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object ! Internals integer(I4B) :: i = 1 - real(DP) :: theta, phi !! zenith angle, and azimuthal angle - real(DP), dimension(NDIM) :: rh !! Position vector of the test particle real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration From b1417b115d768078107d748c35413682ec9940ce Mon Sep 17 00:00:00 2001 From: anand43 Date: Mon, 27 Nov 2023 11:08:34 -0500 Subject: [PATCH 129/324] testing overflow error --- src/swiftest/swiftest_drift.f90 | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 08da848af..fe315fc74 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -460,6 +460,12 @@ pure subroutine swiftest_drift_kepu_new(s, dt, r0, mu, alpha, u, fp, c1, c2, c3, do nc = 0, 6 x = s*s*alpha + + ! for debugging overflow error + if (abs(x) .ge. HUGE(0.0_DP)) then + write(*,*) "big x" + end if + call swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) c1 = c1*s c2 = c2*s*s @@ -553,6 +559,28 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) integer(I4B) :: i, n real(DP) :: xm + + ! for debugging Floating overflow error + if (abs(x) .ge. HUGE(0.0_DP)) then + write(*,*) "big x" + end if + + if (abs(c0) .ge. HUGE(0.0_DP)) then + write(*,*) "big c0" + end if + + if (abs(c1) .ge. HUGE(0.0_DP)) then + write(*,*) "big c1" + end if + + if (abs(c2) .ge. HUGE(0.0_DP)) then + write(*,*) "big c2" + end if + + if (abs(c3) .ge. HUGE(0.0_DP)) then + write(*,*) "big c3" + end if + n = 0 xm = 0.1_DP do while (abs(x) >= xm) From c94bd9aea417f0d4beb6a598057551f4443c49bc Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 29 Nov 2023 15:20:59 -0500 Subject: [PATCH 130/324] Temporary debugging edits --- src/swiftest/swiftest_drift.f90 | 57 +++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index fe315fc74..0fdb0f63f 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -207,6 +207,12 @@ pure subroutine swiftest_drift_dan(mu, rx0, ry0, rz0, vx0, vy0, vz0, dt0, iflag) end if end if + ! For debugging overflow error + + if(r0 .ge. 11970204779.00) then + f = 1.0_DP + end if + call swiftest_drift_kepu(dt, r0, mu, alpha, u, fp, c1, c2, c3, iflag) if (iflag == 0) then f = 1.0_DP - mu / r0 * c2 @@ -462,10 +468,10 @@ pure subroutine swiftest_drift_kepu_new(s, dt, r0, mu, alpha, u, fp, c1, c2, c3, x = s*s*alpha ! for debugging overflow error - if (abs(x) .ge. HUGE(0.0_DP)) then - write(*,*) "big x" + if (abs(x) .ge. HUGE(0.0_DP) .or. x < 0) then + f = 1.0_DP ! "big x" end if - + call swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) c1 = c1*s c2 = c2*s*s @@ -559,28 +565,12 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) integer(I4B) :: i, n real(DP) :: xm - - ! for debugging Floating overflow error - if (abs(x) .ge. HUGE(0.0_DP)) then - write(*,*) "big x" - end if - - if (abs(c0) .ge. HUGE(0.0_DP)) then - write(*,*) "big c0" - end if - - if (abs(c1) .ge. HUGE(0.0_DP)) then - write(*,*) "big c1" - end if - - if (abs(c2) .ge. HUGE(0.0_DP)) then - write(*,*) "big c2" - end if - - if (abs(c3) .ge. HUGE(0.0_DP)) then - write(*,*) "big c3" + ! for debugging overflow error + if (abs(x) .ge. HUGE(0.0_DP) .or. x < 0) then + x = x ! "big x" + n = 0 end if - + n = 0 xm = 0.1_DP do while (abs(x) >= xm) @@ -605,6 +595,25 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) end do end if + ! for debugging Floating overflow error + + if (abs(c0) .ge. HUGE(0.0_DP)) then + xm = 0.1_DP ! "big c0" + end if + + if (abs(c1) .ge. HUGE(0.0_DP)) then + xm = 0.1_DP ! "big c1" + end if + + if (abs(c2) .ge. HUGE(0.0_DP)) then + xm = 0.1_DP ! "big c2" + end if + + if (abs(c3) .ge. HUGE(0.0_DP)) then + xm = 0.1_DP ! "big c3" + end if + + return end subroutine swiftest_drift_kepu_stumpff From 124e737977faf5760f3e5dc32de0cea054ca09ab Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 5 Dec 2023 14:01:38 -0500 Subject: [PATCH 131/324] debugging temp changes --- src/swiftest/swiftest_drift.f90 | 43 ++++++++++++--------------------- swiftest/CMakeLists.txt | 1 + 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 0fdb0f63f..b03a3ef70 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -209,9 +209,9 @@ pure subroutine swiftest_drift_dan(mu, rx0, ry0, rz0, vx0, vy0, vz0, dt0, iflag) ! For debugging overflow error - if(r0 .ge. 11970204779.00) then - f = 1.0_DP - end if + ! if(r0 .ge. 11970204779.00) then + ! f = 1.0_DP + ! end if call swiftest_drift_kepu(dt, r0, mu, alpha, u, fp, c1, c2, c3, iflag) if (iflag == 0) then @@ -467,11 +467,6 @@ pure subroutine swiftest_drift_kepu_new(s, dt, r0, mu, alpha, u, fp, c1, c2, c3, do nc = 0, 6 x = s*s*alpha - ! for debugging overflow error - if (abs(x) .ge. HUGE(0.0_DP) .or. x < 0) then - f = 1.0_DP ! "big x" - end if - call swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) c1 = c1*s c2 = c2*s*s @@ -564,12 +559,6 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) ! Internals integer(I4B) :: i, n real(DP) :: xm - - ! for debugging overflow error - if (abs(x) .ge. HUGE(0.0_DP) .or. x < 0) then - x = x ! "big x" - n = 0 - end if n = 0 xm = 0.1_DP @@ -595,23 +584,23 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) end do end if - ! for debugging Floating overflow error + ! ! for debugging Floating overflow error - if (abs(c0) .ge. HUGE(0.0_DP)) then - xm = 0.1_DP ! "big c0" - end if + ! if (abs(c0) .ge. HUGE(0.0_DP)) then + ! xm = 0.1_DP ! "big c0" + ! end if - if (abs(c1) .ge. HUGE(0.0_DP)) then - xm = 0.1_DP ! "big c1" - end if + ! if (abs(c1) .ge. HUGE(0.0_DP)) then + ! xm = 0.1_DP ! "big c1" + ! end if - if (abs(c2) .ge. HUGE(0.0_DP)) then - xm = 0.1_DP ! "big c2" - end if + ! if (abs(c2) .ge. HUGE(0.0_DP)) then + ! xm = 0.1_DP ! "big c2" + ! end if - if (abs(c3) .ge. HUGE(0.0_DP)) then - xm = 0.1_DP ! "big c3" - end if + ! if (abs(c3) .ge. HUGE(0.0_DP)) then + ! xm = 0.1_DP ! "big c3" + ! end if return diff --git a/swiftest/CMakeLists.txt b/swiftest/CMakeLists.txt index 2a53718f2..ae6ef5247 100644 --- a/swiftest/CMakeLists.txt +++ b/swiftest/CMakeLists.txt @@ -18,6 +18,7 @@ FIND_PROGRAM(CYTHON NO_CMAKE_FIND_ROOT_PATH ) MESSAGE(STATUS "Cython executable path: ${CYTHON}") +# MESSAGE(STATUS "LD_LIBRARY_PATH: $ENV{LD_LIBRARY_PATH}") SET(CYTHON_ARGS "${CMAKE_CURRENT_SOURCE_DIR}/${SWIFTEST_BINDINGS}.pyx" "--output-file" "${CMAKE_CURRENT_BINARY_DIR}/${SWIFTEST_BINDINGS}.c") STRING(TOUPPER "${CMAKE_BUILD_TYPE}" BT) IF (BT STREQUAL "DEBUG") From 20047537eaf67902a8714810c9a0a179cd5f9416 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 12 Dec 2023 14:45:23 -0500 Subject: [PATCH 132/324] Changed lshgrav flag for planetocentric param file to false --- src/rmvs/rmvs_kick.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rmvs/rmvs_kick.f90 b/src/rmvs/rmvs_kick.f90 index 82d19463e..2b3bb4faa 100644 --- a/src/rmvs/rmvs_kick.f90 +++ b/src/rmvs/rmvs_kick.f90 @@ -53,6 +53,7 @@ module subroutine rmvs_kick_getacch_tp(self, nbody_system, param, t, lbeg) ! Temporarily turn off the heliocentric-dependent acceleration terms during an inner encounter using a copy of the parameter list with all of the heliocentric-specific acceleration terms turned off allocate(param_planetocen, source=param) param_planetocen%loblatecb = .false. + param_planetocen%lshgrav = .false. param_planetocen%lextra_force = .false. param_planetocen%lgr = .false. From c7efd6862b76c052e6e1d7425fc4343bbf503663 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 12 Dec 2023 15:13:36 -0500 Subject: [PATCH 133/324] Cleaned up the subroutine --- src/swiftest/swiftest_sph.f90 | 60 ++--------------------------------- 1 file changed, 3 insertions(+), 57 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 42d7bb59e..2def11b02 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -40,11 +40,11 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp real(DP) :: r_mag !! magnitude of rh real(DP) :: phi, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase real(DP) :: theta !! Inclination/Zenith angle (radians) - real(DP) :: plm, dplm !! Associated Legendre polynomials at a given l, m + real(DP) :: plm, plm1 !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code real(DP) :: cos_theta, sin_theta !! cos(theta) and sin(theta) real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) - real(DP) :: r2, irh, rinv2, t0, t1, t2, t3, fac0, fac1, fac2, fac3, fac4, j2rp2, j4rp4, r_fac, cos_tmp, sin_tmp, sin2_tmp, plm1, sin_phi, cos_phi + real(DP) :: fac1, fac2, r_fac !! calculation factors g_sph(:) = 0.0_DP theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) @@ -55,25 +55,9 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp N = (l_max + 1) * (l_max + 2) / 2 allocate(p(N),p_deriv(N)) - ! to compare w s_obl.f90 - j2rp2 = -c_lm(1, 3, 1) * r_0**2 - j4rp4 = -c_lm(1, 4, 1) * r_0**4 - r2 = dot_product(rh(:), rh(:)) - irh = 1.0_DP / sqrt(r2) - rinv2 = irh**2 - t0 = -GMcb * rinv2 * rinv2 * irh - t1 = 1.5_DP * j2rp2 - t2 = rh(3) * rh(3) * rinv2 - t3 = 1.875_DP * j4rp4 * rinv2 - fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) - fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) - fac0 = 4 * PI - cos_theta = cos(theta) sin_theta = sin(theta) - - if(abs(cos_theta) < epsilon(0.0_DP)) then cos_theta = 0.0_DP end if @@ -100,25 +84,6 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp + c_lm(m+1, l+1, 2) * cos(m * phi_bar) ! - C_lm * sin(m * phi_bar) + S_lm * cos(m * phi_bar) ! cssc * m = first derivative of ccss with respect to phi - ! m > 0 - ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m * plm * sin(phi) / sin_theta & - ! + ccss * sin_theta * cos(phi) & - ! * (dplm * cos_theta + plm * (l + 1))) ! g_x - ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-1 * cssc * m * plm * cos(phi) / sin_theta & - ! + ccss * sin_theta * sin(phi) & - ! * (dplm * cos_theta + plm * (l + 1))) ! g_y - ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (-1 * dplm * sin_theta**2 & - ! + plm * (l + 1) * cos_theta) ! g_z - - cos_tmp = cos_theta - sin_tmp = sin_theta - sin2_tmp = sin(2 * theta) - sin_phi = sin(phi) - cos_phi = cos(phi) - ! g_sph(:) = 0.0_DP - - ! Alternative form for g_sph - if ((m+1) .le. l) then lmindex = PlmIndex(l, m+1) plm1 = p(lmindex) @@ -131,21 +96,6 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp plm1 = 0.0_DP end if - ! !! Alternative form of dplm - - ! g_sph(1) = g_sph(1) - GMcb * r_0**l / r_mag**(l + 2) * (cssc * m / sin_theta * plm * sin(phi) & - ! + ccss * cos(phi) * (plm * ((l + m + 1) * sin_theta - m / sin_theta) & - ! + plm1 * cos_theta)) - ! g_sph(2) = g_sph(2) - GMcb * r_0**l / r_mag**(l + 2) * (-cssc * m / sin_theta * plm * cos(phi) & - ! + ccss * sin(phi) * (plm * ((l + m + 1) * sin_theta - m / sin_theta) & - ! + plm1 * cos_theta)) - ! g_sph(3) = g_sph(3) - GMcb * r_0**l / r_mag**(l + 2) * ccss * (plm * (l + m +1) * cos_theta - plm1 * sin_theta) - - ! Condensed form - - ! fac0 = -(m * cos_tmp * plm / sin_tmp - plm1) / sin_tmp ! dplm - ! fac3 = plm * (l + m + 1) * cos_theta - ! fac4 = plm1 * sin_theta if(sin_theta .eq. 0) then fac1 = 0.0_DP else @@ -153,17 +103,13 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp end if fac2 = plm * (l + m + 1) * sin_theta + plm1 * cos_theta - fac3 = fac2 - fac1 r_fac = -GMcb * r_0**l / r_mag**(l + 2) ! g_sph(:) = 0.0_DP g_sph(1) = g_sph(1) + r_fac * (cssc * fac1 * sin(phi) + ccss * (fac2 - fac1) * cos(phi)) g_sph(2) = g_sph(2) + r_fac * (-cssc * fac1 * cos(phi) + ccss * (fac2 - fac1) * sin(phi)) g_sph(3) = g_sph(3) + r_fac * ccss * (plm * (l + m + 1) * cos_theta - plm1 * sin_theta) - - fac0 = (.mag. g_sph(:)) - ! fac3 = 3 * c_lm(m+1, l+1, 1) / 2 * r_0**2 / r_mag**4 * (3*(cos_theta)**2 - 1) * GMcb ! g_sph for J2 - + end do end do From e3a478e091faec573eba4723c08e972d22bfcf80 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 12 Dec 2023 15:19:04 -0500 Subject: [PATCH 134/324] cleaning up --- src/swiftest/swiftest_drift.f90 | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index b03a3ef70..21119cca8 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -207,12 +207,6 @@ pure subroutine swiftest_drift_dan(mu, rx0, ry0, rz0, vx0, vy0, vz0, dt0, iflag) end if end if - ! For debugging overflow error - - ! if(r0 .ge. 11970204779.00) then - ! f = 1.0_DP - ! end if - call swiftest_drift_kepu(dt, r0, mu, alpha, u, fp, c1, c2, c3, iflag) if (iflag == 0) then f = 1.0_DP - mu / r0 * c2 @@ -584,25 +578,6 @@ pure subroutine swiftest_drift_kepu_stumpff(x, c0, c1, c2, c3) end do end if - ! ! for debugging Floating overflow error - - ! if (abs(c0) .ge. HUGE(0.0_DP)) then - ! xm = 0.1_DP ! "big c0" - ! end if - - ! if (abs(c1) .ge. HUGE(0.0_DP)) then - ! xm = 0.1_DP ! "big c1" - ! end if - - ! if (abs(c2) .ge. HUGE(0.0_DP)) then - ! xm = 0.1_DP ! "big c2" - ! end if - - ! if (abs(c3) .ge. HUGE(0.0_DP)) then - ! xm = 0.1_DP ! "big c3" - ! end if - - return end subroutine swiftest_drift_kepu_stumpff From dea961a2b1cd9aea9e410792308ab257762387a9 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 12 Dec 2023 15:38:52 -0500 Subject: [PATCH 135/324] Changed the condition from "or" to "and" to allow test particles to get a kick --- src/whm/whm_kick.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index 93b448967..2e70a431e 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -92,7 +92,7 @@ module subroutine whm_kick_getacch_tp(self, nbody_system, param, t, lbeg) associate(tp => self, pl => nbody_system%pl, cb => nbody_system%cb) npl = nbody_system%pl%nbody ntp = self%nbody - if (ntp == 0 .or. npl == 0) return + if (ntp == 0 .and. npl == 0) return nbody_system%lbeg = lbeg if (lbeg) then From 9ba8f74c53e3b7eecd66484a52fac8b2a4cbdee4 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 12 Dec 2023 16:20:07 -0500 Subject: [PATCH 136/324] edited kick to account for no massive bodies --- src/whm/whm_kick.f90 | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index 2e70a431e..090457f60 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -92,29 +92,31 @@ module subroutine whm_kick_getacch_tp(self, nbody_system, param, t, lbeg) associate(tp => self, pl => nbody_system%pl, cb => nbody_system%cb) npl = nbody_system%pl%nbody ntp = self%nbody - if (ntp == 0 .and. npl == 0) return + if (ntp == 0) return nbody_system%lbeg = lbeg - if (lbeg) then - ah0(:) = whm_kick_getacch_ah0(pl%Gmass(1:npl), pl%rbeg(:, 1:npl), npl) + if(npl > 0) then + if (lbeg) then + ah0(:) = whm_kick_getacch_ah0(pl%Gmass(1:npl), pl%rbeg(:, 1:npl), npl) #ifdef DOCONLOC - do concurrent(i = 1:ntp, tp%lmask(i)) shared(tp,ah0) + do concurrent(i = 1:ntp, tp%lmask(i)) shared(tp,ah0) #else - do concurrent(i = 1:ntp, tp%lmask(i)) + do concurrent(i = 1:ntp, tp%lmask(i)) #endif - tp%ah(:, i) = tp%ah(:, i) + ah0(:) - end do - call tp%accel_int(param, pl%Gmass(1:npl), pl%rbeg(:, 1:npl), npl) - else - ah0(:) = whm_kick_getacch_ah0(pl%Gmass(1:npl), pl%rend(:, 1:npl), npl) + tp%ah(:, i) = tp%ah(:, i) + ah0(:) + end do + call tp%accel_int(param, pl%Gmass(1:npl), pl%rbeg(:, 1:npl), npl) + else + ah0(:) = whm_kick_getacch_ah0(pl%Gmass(1:npl), pl%rend(:, 1:npl), npl) #ifdef DOCONLOC - do concurrent(i = 1:ntp, tp%lmask(i)) shared(tp,ah0) + do concurrent(i = 1:ntp, tp%lmask(i)) shared(tp,ah0) #else - do concurrent(i = 1:ntp, tp%lmask(i)) + do concurrent(i = 1:ntp, tp%lmask(i)) #endif - tp%ah(:, i) = tp%ah(:, i) + ah0(:) - end do - call tp%accel_int(param, pl%Gmass(1:npl), pl%rend(:, 1:npl), npl) + tp%ah(:, i) = tp%ah(:, i) + ah0(:) + end do + call tp%accel_int(param, pl%Gmass(1:npl), pl%rend(:, 1:npl), npl) + end if end if if (param%loblatecb) call tp%accel_obl(nbody_system) From 7efe2ae3a996eb47639344db9192ebdaa8996384 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 18 Jan 2024 12:22:15 -0500 Subject: [PATCH 137/324] Changed the virtual environment folder to be the more standard venv instead of env --- buildscripts/install_editable_debug.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index bd1098bd4..c55668ac0 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -3,7 +3,7 @@ set -a SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -VENV_DIR=${ROOT_DIR}/env +VENV_DIR=${ROOT_DIR}/venv cd ${ROOT_DIR} python3 -m venv ${VENV_DIR} . ${VENV_DIR}/bin/activate @@ -18,4 +18,4 @@ pip install --config-settings=editable.rebuild=true \ -ve . mkdir -p $HOME/.local/lib LIBFILE=$(realpath ${ROOT_DIR}/build/*/bin/*swiftest.*) -ln -fs $LIBFILE $HOME/.local/lib \ No newline at end of file +ln -fs $LIBFILE $HOME/.local/lib From a333dbb20101800ede3c76e0363de541018cff16 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 18 Jan 2024 12:54:54 -0500 Subject: [PATCH 138/324] Added back missing SetMKL.cmake file --- cmake/Modules/SetMKL.cmake | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 cmake/Modules/SetMKL.cmake diff --git a/cmake/Modules/SetMKL.cmake b/cmake/Modules/SetMKL.cmake new file mode 100644 index 000000000..e58c9f51a --- /dev/null +++ b/cmake/Modules/SetMKL.cmake @@ -0,0 +1,14 @@ +# Copyright 2022 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh +# This file is part of Swiftest. +# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with Swiftest. +# If not, see: https://www.gnu.org/licenses. + +# Find MKL if not already found +IF(NOT MKL_FOUND) + ENABLE_LANGUAGE(C) # Some libraries need a C compiler to find + FIND_PACKAGE(MKL REQUIRED) +ENDIF(NOT MKL_FOUND) From 969f72cb5e812b0320ec1bb1b81a1815ce34c4a5 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 18 Jan 2024 12:55:50 -0500 Subject: [PATCH 139/324] Added cmake to the list of pre-build dependencies in the editable install script --- buildscripts/install_editable_debug.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index c55668ac0..f7a9b0259 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -8,7 +8,7 @@ cd ${ROOT_DIR} python3 -m venv ${VENV_DIR} . ${VENV_DIR}/bin/activate python3 -m pip install --upgrade pip -pip install scikit-build-core pyproject-metadata pathspec ninja cython ffmpeg-python +pip install scikit-build-core pyproject-metadata pathspec ninja cython cmake ffmpeg-python pip install --config-settings=editable.rebuild=true \ --config-settings=build-dir="build/{wheel_tag}" \ --config-settings=cmake.build-type="Debug" \ From c170a72f7dbb99ab3aca16354635ef796eb92531 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 18 Jan 2024 13:17:14 -0500 Subject: [PATCH 140/324] Put back some of the missing SHTOOLS stuff that got messed up in the merge --- CMakeLists.txt | 8 +++----- cmake/Modules/SetMKL.cmake | 14 -------------- pyproject.toml | 5 +++-- 3 files changed, 6 insertions(+), 21 deletions(-) delete mode 100644 cmake/Modules/SetMKL.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b2663034..ae81ba810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,11 +59,14 @@ ELSE() IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") + FIND_PACKAGE(MKL) ELSEIF (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") SET(COMPILER_OPTIONS "GNU" CACHE STRING "Compiler identified as gfortran") ELSE () MESSAGE(FATAL_ERROR "Compiler ${CMAKE_Fortran_COMPILER_ID} not recognized!") ENDIF () + FIND_PACKAGE(SHTOOLS REQUIRED) + FIND_PACKAGE(FFTW3 REQUIRED) # The following section is modified from Numpy f2py documentation IF(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) @@ -113,13 +116,8 @@ ELSE() ENDIF(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90) INCLUDE(SetParallelizationLibrary) - IF (COMPILER_OPTIONS STREQUAL "Intel" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") - INCLUDE(SetMKL) - ENDIF () INCLUDE(SetSwiftestFlags) - - # The source for the SWIFTEST binary and have it placed in the bin folder ADD_SUBDIRECTORY(${SRC} ${CMAKE_INSTALL_BINDIR}) ADD_SUBDIRECTORY(${PY}) diff --git a/cmake/Modules/SetMKL.cmake b/cmake/Modules/SetMKL.cmake deleted file mode 100644 index e58c9f51a..000000000 --- a/cmake/Modules/SetMKL.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2022 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh -# This file is part of Swiftest. -# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# You should have received a copy of the GNU General Public License along with Swiftest. -# If not, see: https://www.gnu.org/licenses. - -# Find MKL if not already found -IF(NOT MKL_FOUND) - ENABLE_LANGUAGE(C) # Some libraries need a C compiler to find - FIND_PACKAGE(MKL REQUIRED) -ENDIF(NOT MKL_FOUND) diff --git a/pyproject.toml b/pyproject.toml index 1ada4eedf..a8a3b7cf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,8 @@ dependencies = [ 'astropy>=5.2', 'astroquery>=0.4.6', 'tqdm>=4.64.1', - 'cython>=3.0.0' + 'cython>=3.0.0', + 'pyshtools>=4.10' ] [project.urls] @@ -136,7 +137,7 @@ CMAKE_INSTALL_LIBDIR="lib" [tool.cibuildwheel.linux] skip = "cp312-* pp* -manylinux_i686* *-musllinux*" before-all = [ - "yum install doxygen libxml2-devel libcurl-devel -y", + "yum install doxygen libxml2-devel libcurl-devel fftw-devel blas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] From 477adda63c5873a626081b41cc41c996254b2112 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 18 Jan 2024 13:39:48 -0500 Subject: [PATCH 141/324] Fixed issues getting SHTOOLS compiled properly. --- CMakeLists.txt | 1 - buildscripts/install_editable_debug.sh | 2 +- pyproject.toml | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae81ba810..5feb7155e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,6 @@ ELSE() MESSAGE(FATAL_ERROR "Compiler ${CMAKE_Fortran_COMPILER_ID} not recognized!") ENDIF () FIND_PACKAGE(SHTOOLS REQUIRED) - FIND_PACKAGE(FFTW3 REQUIRED) # The following section is modified from Numpy f2py documentation IF(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index f7a9b0259..10e5eb850 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -8,7 +8,7 @@ cd ${ROOT_DIR} python3 -m venv ${VENV_DIR} . ${VENV_DIR}/bin/activate python3 -m pip install --upgrade pip -pip install scikit-build-core pyproject-metadata pathspec ninja cython cmake ffmpeg-python +pip install scikit-build-core pyproject-metadata pathspec ninja cython cmake ffmpeg-python pip install --config-settings=editable.rebuild=true \ --config-settings=build-dir="build/{wheel_tag}" \ --config-settings=cmake.build-type="Debug" \ diff --git a/pyproject.toml b/pyproject.toml index a8a3b7cf8..ca161ee50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ 'astroquery>=0.4.6', 'tqdm>=4.64.1', 'cython>=3.0.0', - 'pyshtools>=4.10' + 'pyshtools==4.10.4' ] [project.urls] From 9e8d9f6a60520dcaf5d423963ed1e1f951275acd Mon Sep 17 00:00:00 2001 From: anand43 Date: Sun, 21 Jan 2024 15:11:26 -0500 Subject: [PATCH 142/324] Missing c_lm argument in add_body --- swiftest/simulation_class.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index adbc19bb9..b8218924d 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2421,7 +2421,8 @@ def add_body(self, rot: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None=None, Ip: List[float] | npt.NDArray[np.float_] | None=None, J2: float | List[float] | npt.NDArray[np.float_] | None=None, - J4: float | List[float] | npt.NDArray[np.float_] | None=None + J4: float | List[float] | npt.NDArray[np.float_] | None=None, + c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None ) -> None: """ Adds a body (test particle or massive body) to the internal DataSet given a set up 6 vectors (orbital elements From 592f1e59aa9e5dc48e20fdbac86f2d307f6c95e8 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 25 Jan 2024 13:52:18 -0500 Subject: [PATCH 143/324] Skip calculation of kick if c_lm = 0; to improve performance --- src/swiftest/swiftest_sph.f90 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 2def11b02..a84376038 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -72,6 +72,11 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term do m = 0, l + ! If c_lm is too small, skip the iteration to improve performance + if (abs(c_lm(m+1, l+1, 1)) < epsilon(0.0_DP) .and. abs(c_lm(m+1, l+1, 2)) < epsilon(0.0_DP)) then + cycle + endif + ! Associated Legendre Polynomials lmindex = PlmIndex(l, m) plm = p(lmindex) ! p_l,m From 30eedc4d6fbbf3f141da74c112d9070e7d4c1da6 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 25 Jan 2024 18:53:32 -0500 Subject: [PATCH 144/324] Rotation matrix was flipped. Inverse was being used --- src/swiftest/swiftest_obl.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index d1e309156..f8fa18105 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -69,8 +69,8 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) if (rot(1) == 0 .and. rot(2) == 0) then do i = 1, NDIM - rot_matrix(i, i) = 1.0 rot_matrix_inv(i, i) = 1.0 + rot_matrix(i, i) = 1.0 end do return ! rotation axis is about the z-axis, no need to change @@ -90,16 +90,16 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) do i = 1, NDIM do j = 1, NDIM if (i == j) then - rot_matrix(i, j) = rot_matrix(i, j) + cos(theta) ! identity matrix + rot_matrix_inv(i, j) = rot_matrix_inv(i, j) + cos(theta) ! identity matrix continue end if - rot_matrix(i, j) = rot_matrix(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) ! Skew-symmetric matrix + Tensor product matrix + rot_matrix_inv(i, j) = rot_matrix_inv(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) ! Skew-symmetric matrix + Tensor product matrix end do end do - rot_matrix_inv = matinv3(rot_matrix) + rot_matrix = matinv3(rot_matrix_inv) return end subroutine swiftest_obl_rot_matrix From 5045e39c327e43876330d94167383f61cd813d83 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 26 Jan 2024 12:21:48 -0500 Subject: [PATCH 145/324] Added an extra check for rotation matrix --- src/swiftest/swiftest_obl.f90 | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index f8fa18105..f00a95d85 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -55,8 +55,8 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) ! Internals real(DP) :: theta !! angle to rotate it through - real(DP), dimension(3) :: u, z_hat !! unit vector about which we rotate and z_hat - real(DP), dimension(3, 3) :: S_matrix !! rotation matrices + real(DP), dimension(3) :: u, z_hat, check !! unit vector about which we rotate, z_hat, and a check variable + real(DP), dimension(3, 3) :: S_matrix, temp !! rotation matrices, and a temporary variable integer :: i, j !! dummy variable ! Assumed that NDIM = 3 @@ -100,7 +100,18 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) end do rot_matrix = matinv3(rot_matrix_inv) - + + ! Check that the correct rotation matrix is used + ! rot_matrix * rot should be in the z_hat direction + check = MATMUL(rot, rot_matrix) ! 1x3 matrix x 3x3 matrix + check = .unit. check(:) + + if(abs(check(1)) .gt. EPSILON(0.0_DP) .or. abs(check(2)) .gt. EPSILON(0.0_DP)) then + temp = rot_matrix + rot_matrix = rot_matrix_inv + rot_matrix_inv = temp + end if + return end subroutine swiftest_obl_rot_matrix From 8bb2aa0cf9106a37367449892eb3a4178cb2801d Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 29 Jan 2024 08:20:29 -0500 Subject: [PATCH 146/324] Added SHTOOLS as a submodule --- .gitignore | 4 ++++ .gitmodules | 3 +++ SHTOOLS | 1 + 3 files changed, 8 insertions(+) create mode 100644 .gitmodules create mode 160000 SHTOOLS diff --git a/.gitignore b/.gitignore index a250469db..8b992dffc 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,8 @@ swiftest-* __pycache__* _cmake* _dependencies +!SHTOOLS +!SHTOOLS/** #Documentation @@ -76,3 +78,5 @@ actions-runner* env/** venv/** + +sandbox/** \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..750c35aae --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "SHTOOLS"] + path = SHTOOLS + url = https://github.com/SHTOOLS/SHTOOLS diff --git a/SHTOOLS b/SHTOOLS new file mode 160000 index 000000000..aa6767f05 --- /dev/null +++ b/SHTOOLS @@ -0,0 +1 @@ +Subproject commit aa6767f0560e66c269473904eba978ef6e3713c2 From 59d6d2fc54e3ae7ab3d2eca9e379781994e2b133 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 29 Jan 2024 09:37:11 -0500 Subject: [PATCH 147/324] Made changes to build process in an attempt to incorporate SHTOOLS into the build --- buildscripts/build_shtools.sh | 16 +++------------- buildscripts/install_editable_debug.sh | 13 +++++++++++-- pyproject.toml | 13 ++++++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index a7aa6b76c..eb37d2a8c 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -15,18 +15,6 @@ ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} . ${SCRIPT_DIR}/set_compilers.sh -SHTOOLS_VER="4.10.4" - -printf "*********************************************************\n" -printf "* FETCHING SHTOOLS SOURCE *\n" -printf "*********************************************************\n" -printf "Copying files to ${DEPENDENCY_DIR}\n" -mkdir -p ${DEPENDENCY_DIR} -if [ ! -d ${DEPENDENCY_DIR}/SHTOOLS-${SHTOOLS_VER} ]; then - [ -d ${DEPENDENCY_DIR}/SHTOOLS-* ] && rm -rf ${DEPENDENCY_DIR}/SHTOOLS-* - curl -L https://github.com/SHTOOLS/SHTOOLS/releases/download/v${SHTOOLS_VER}/SHTOOLS-${SHTOOLS_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} -fi - printf "*********************************************************\n" printf "* BUILDING SHTOOLS LIBRARY *\n" printf "*********************************************************\n" @@ -38,13 +26,15 @@ printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" -cd ${DEPENDENCY_DIR}/SHTOOLS-* +cd SHTOOLS +make F95="${FC}" CXX="${CXX}" fortran make F95="${FC}" CXX="${CXX}" fortran-mp if [ -w ${PREFIX} ]; then make PREFIX="${PREFIX}" install else sudo make PREFIX="${PREFIX}" install fi +cd .. if [ $? -ne 0 ]; then printf "SHTOOLS could not be compiled.\n" diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh index 10e5eb850..fb600a58a 100755 --- a/buildscripts/install_editable_debug.sh +++ b/buildscripts/install_editable_debug.sh @@ -5,8 +5,17 @@ SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) VENV_DIR=${ROOT_DIR}/venv cd ${ROOT_DIR} -python3 -m venv ${VENV_DIR} -. ${VENV_DIR}/bin/activate + +# Create the virtual environment if it doesn't exist +if [ ! -d "${VENV_DIR}" ]; then + python3 -m venv ${VENV_DIR} +fi + +# Activate the virtual environment only if it's not already active +if [ -z "${VIRTUAL_ENV}" ]; then + . ${VENV_DIR}/bin/activate +fi + python3 -m pip install --upgrade pip pip install scikit-build-core pyproject-metadata pathspec ninja cython cmake ffmpeg-python pip install --config-settings=editable.rebuild=true \ diff --git a/pyproject.toml b/pyproject.toml index ca161ee50..c7b1f6201 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ classifiers=[ ] keywords=['astronomy','astrophysics', 'planetary', 'n-body', 'integrator', 'symplectic', 'wisdom-holman', 'symba'] dependencies = [ - 'numpy>=1.24.3', + 'numpy>=1.26.3', 'scipy>=1.10.1', 'xarray>=2023.1', 'dask>=2023.5', @@ -36,9 +36,11 @@ dependencies = [ 'matplotlib>=3.7', 'astropy>=5.2', 'astroquery>=0.4.6', - 'tqdm>=4.64.1', - 'cython>=3.0.0', - 'pyshtools==4.10.4' + 'tqdm>=4.64', + 'cython>=3.0', + 'meson>=1.3', + 'meson-python>=0.15', + 'pyshtools==4.11.10' ] [project.urls] @@ -61,6 +63,7 @@ requires = [ "sphinxext-rediraffe", "sphinxext-opengraph", "nbsphinx", + 'meson-python>=0.15', "ford" ] build-backend = "scikit_build_core.build" @@ -112,7 +115,7 @@ netCDF-Fortran_DIR="${PREFIX}/lib/cmake/netCDF" [tool.cibuildwheel.macos] before-all = [ - "brew install coreutils", + "brew install coreutils pkg-config fftw vecLibFort", "LIBS=\"\" buildscripts/build_dependencies.sh -p ${PREFIX} -d ${HOME}/Downloads -m ${MACOSX_DEPLOYMENT_TARGET}" ] From 0fca3ca66dfab1a481ec078c4a0f6d89921a697e Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 29 Jan 2024 12:18:06 -0500 Subject: [PATCH 148/324] more updates attempting to get SHTOOLS built properly --- buildscripts/set_environment_macos.sh | 3 ++- pyproject.toml | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/buildscripts/set_environment_macos.sh b/buildscripts/set_environment_macos.sh index cd51f1865..03a333c8e 100755 --- a/buildscripts/set_environment_macos.sh +++ b/buildscripts/set_environment_macos.sh @@ -12,7 +12,7 @@ CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DI CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include -Xclang -fopenmp" LIBS="-lomp" CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" -FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" +FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -fno-underscoring" FFFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype" CXXFLAGS="${CFLAGS}" @@ -26,6 +26,7 @@ NETCDF_FORTRAN_HOME="${NFDIR}" NETCDF_FORTRAN_INCLUDE="${NFDIR}/include" FC="$(command -v gfortran-12)" F77="${FC}" +F95="${FC}" CC="/usr/bin/clang" CXX="/usr/bin/clang++" CPP="/usr/bin/cpp" diff --git a/pyproject.toml b/pyproject.toml index c7b1f6201..dc34c49c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,8 @@ dependencies = [ 'cython>=3.0', 'meson>=1.3', 'meson-python>=0.15', - 'pyshtools==4.11.10' + 'setuptools_scm', + 'pyshtools>=4.11.10' ] [project.urls] @@ -63,7 +64,6 @@ requires = [ "sphinxext-rediraffe", "sphinxext-opengraph", "nbsphinx", - 'meson-python>=0.15', "ford" ] build-backend = "scikit_build_core.build" @@ -103,8 +103,10 @@ NCDIR="${PREFIX}" NFDIR="${PREFIX}" NETCDF_FORTRAN_HOME="${NFDIR}" NETCDF_FORTRAN_INCLUDE="${NFDIR}/include" +SHTOOLS_HOME="${PREFIX}" FC="$(command -v gfortran-12)" F77="${FC}" +F95="${FC}" CC="/usr/bin/clang" CXX="/usr/bin/clang++" CPP="/usr/bin/cpp" @@ -134,6 +136,7 @@ LD_LIBRARY_PATH="${PREFIX}/lib:/project/lib:${HDF5_LIBDIR}" CPATH="${PREFIX}/include:/project/include:${HDF5_INCLUDE_DIR}" netCDF-Fortran_DIR="${PREFIX}/lib/cmake/netCDF" HDF5_DIR="${HDF5_ROOT}/cmake" +SHTOOLS_HOME="${PREFIX}" PATH="${HDF5_ROOT}/bin:${PATH}" CMAKE_INSTALL_LIBDIR="lib" From 4e8def60721b372e53e9b6ad03cc8a825cb783f9 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 30 Jan 2024 09:15:29 -0500 Subject: [PATCH 149/324] Fixed typos in environment variables and made sure the -fno-underscoring flag gets set when building SHTOOLS with gfortran --- buildscripts/build_shtools.sh | 5 +++-- buildscripts/set_compilers.sh | 2 +- buildscripts/set_environment_macos.sh | 2 +- pyproject.toml | 4 ++-- src/whm/whm_kick.f90 | 2 -- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index eb37d2a8c..c016b9d90 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -19,6 +19,7 @@ printf "*********************************************************\n" printf "* BUILDING SHTOOLS LIBRARY *\n" printf "*********************************************************\n" printf "LIBS: ${LIBS}\n" +printf "FFLAGS: ${FFLAGS}\n" printf "CFLAGS: ${CFLAGS}\n" printf "CPPFLAGS: ${CPPFLAGS}\n" printf "CPATH: ${CPATH}\n" @@ -27,8 +28,8 @@ printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" cd SHTOOLS -make F95="${FC}" CXX="${CXX}" fortran -make F95="${FC}" CXX="${CXX}" fortran-mp +make F95="${FC}" CXX="${CXX}" F95FLAGS="-m64 -fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran +make F95="${FC}" CXX="${CXX}" F95FLAGS="-m64 -fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran-mp if [ -w ${PREFIX} ]; then make PREFIX="${PREFIX}" install else diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index 70dd9f71e..eb7322334 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -39,7 +39,7 @@ case $OS in . ${SCRIPT_DIR}/set_environment_macos.sh FC=${HOMEBREW_PREFIX}/bin/gfortran-12 CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" - FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" + FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" FFLAGS=$FCFLAGS LD_LIBRARY_PATH="" CPATH="" diff --git a/buildscripts/set_environment_macos.sh b/buildscripts/set_environment_macos.sh index 03a333c8e..6c255c65c 100755 --- a/buildscripts/set_environment_macos.sh +++ b/buildscripts/set_environment_macos.sh @@ -13,7 +13,7 @@ CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include -Xclang -fopenm LIBS="-lomp" CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -fno-underscoring" -FFFLAGS="${FCFLAGS}" +FFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype" CXXFLAGS="${CFLAGS}" HDF5_ROOT="${PREFIX}" diff --git a/pyproject.toml b/pyproject.toml index dc34c49c5..1ec45f7e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,8 +91,8 @@ LDFLAGS="-Wl,-rpath,${ROOT_DIR}/lib -Wl,-no_compact_unwind -L${PREFIX}/lib -L${ CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DIR}/include" CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include" LIBS="-lomp" -FCFLAGS="-mmacos-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" -FFFLAGS="${FCFLAGS}" +FCFLAGS="-mmacos-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" +FFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype -arch ${ARCH}" CXXFLAGS="${CFLAGS}" HDF5_ROOT="${PREFIX}" diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index 2b37e4b98..e0bb2e70f 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -239,7 +239,6 @@ module subroutine whm_kick_vh_pl(self, nbody_system, param, t, dt, lbeg) logical, intent(in) :: lbeg !! Logical flag indicating whether this is the beginning of the half step or not. ! Internals integer(I4B) :: i, npl - real(DP) :: tmp ! to check the acceleration kick due to the CB associate(pl => self, cb => nbody_system%cb) npl = self%nbody @@ -263,7 +262,6 @@ module subroutine whm_kick_vh_pl(self, nbody_system, param, t, dt, lbeg) do concurrent(i = 1:npl, pl%lmask(i)) #endif pl%vh(:, i) = pl%vh(:, i) + pl%ah(:, i) * dt - ! tmp = .mag.(pl%ah(:, i) - pl%aobl(:, i)) end do end associate From dd975612a1fac45a2e82211170a54e258af3328f Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 30 Jan 2024 14:05:44 -0500 Subject: [PATCH 150/324] Fixed some minor issues with checking for small values of a sine computation --- src/swiftest/swiftest_sph.f90 | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index a84376038..4b5d8b19f 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -58,13 +58,6 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp cos_theta = cos(theta) sin_theta = sin(theta) - if(abs(cos_theta) < epsilon(0.0_DP)) then - cos_theta = 0.0_DP - end if - if(abs(sin_theta) < epsilon(0.0_DP)) then - sin_theta = 0.0_DP - end if - ! call PlmBar_d1(p, p_deriv, l_max, cos_theta) ! Associated Legendre Polynomials and the 1st Derivative call PlmBar(p, l_max, cos_theta) @@ -89,10 +82,10 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp + c_lm(m+1, l+1, 2) * cos(m * phi_bar) ! - C_lm * sin(m * phi_bar) + S_lm * cos(m * phi_bar) ! cssc * m = first derivative of ccss with respect to phi - if ((m+1) .le. l) then + if ((m+1) <= l) then lmindex = PlmIndex(l, m+1) plm1 = p(lmindex) - if(m .eq. 0) then + if(m ==. 0) then plm1 = plm1 * sqrt(((l + m + 1) * (l - m)) / 2.0) ! renormalize plm1 to the norm of plm else plm1 = plm1 * sqrt((l + m + 1) * (l - m) * 1.0) ! renormalize plm1 to the norm of plm @@ -101,7 +94,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp plm1 = 0.0_DP end if - if(sin_theta .eq. 0) then + if(abs(sin_theta) < epsilon(1.0_DP)) then fac1 = 0.0_DP else fac1 = m * plm / sin_theta @@ -110,7 +103,6 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp fac2 = plm * (l + m + 1) * sin_theta + plm1 * cos_theta r_fac = -GMcb * r_0**l / r_mag**(l + 2) - ! g_sph(:) = 0.0_DP g_sph(1) = g_sph(1) + r_fac * (cssc * fac1 * sin(phi) + ccss * (fac2 - fac1) * cos(phi)) g_sph(2) = g_sph(2) + r_fac * (-cssc * fac1 * cos(phi) + ccss * (fac2 - fac1) * sin(phi)) g_sph(3) = g_sph(3) + r_fac * ccss * (plm * (l + m + 1) * cos_theta - plm1 * sin_theta) From 58edbb0348669346f6e0cc17e57d906c5cbf1fc7 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 30 Jan 2024 14:32:31 -0500 Subject: [PATCH 151/324] Fixed typo --- src/swiftest/swiftest_sph.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 4b5d8b19f..484ac8dae 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -85,7 +85,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp if ((m+1) <= l) then lmindex = PlmIndex(l, m+1) plm1 = p(lmindex) - if(m ==. 0) then + if(m == 0) then plm1 = plm1 * sqrt(((l + m + 1) * (l - m)) / 2.0) ! renormalize plm1 to the norm of plm else plm1 = plm1 * sqrt((l + m + 1) * (l - m) * 1.0) ! renormalize plm1 to the norm of plm From b2f255683d8af27633348f1a094398064e5cd0f7 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 30 Jan 2024 14:32:47 -0500 Subject: [PATCH 152/324] Added more robust build script for SHTOOLS --- buildscripts/build_shtools.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index c016b9d90..01964da7b 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -15,6 +15,20 @@ ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} . ${SCRIPT_DIR}/set_compilers.sh + +SHTOOLS_VER="4.11.10" + + +printf "*********************************************************\n" +printf "* FETCHING SHTOOLS SOURCE *\n" +printf "*********************************************************\n" +printf "Copying files to ${DEPENDENCY_DIR}\n" +mkdir -p ${DEPENDENCY_DIR} +if [ ! -d ${DEPENDENCY_DIR}/SHTOOLS-${SHTOOLS_VER} ]; then + [ -d ${DEPENDENCY_DIR}/SHTOOLS-* ] && rm -rf ${DEPENDENCY_DIR}/SHTOOLS-* + curl -L https://github.com/SHTOOLS/SHTOOLS/archive/refs/tags/v${SHTOOLS_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} +fi + printf "*********************************************************\n" printf "* BUILDING SHTOOLS LIBRARY *\n" printf "*********************************************************\n" @@ -27,9 +41,10 @@ printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" -cd SHTOOLS -make F95="${FC}" CXX="${CXX}" F95FLAGS="-m64 -fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran -make F95="${FC}" CXX="${CXX}" F95FLAGS="-m64 -fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran-mp +cd ${DEPENDENCY_DIR}/SHTOOLS* + +make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran +make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran-mp if [ -w ${PREFIX} ]; then make PREFIX="${PREFIX}" install else From 9df92680639f21803c6dabe914924d19cefc9753 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 30 Jan 2024 14:52:48 -0500 Subject: [PATCH 153/324] fixed typo in environment variable --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1ec45f7e0..413681303 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,7 +91,7 @@ LDFLAGS="-Wl,-rpath,${ROOT_DIR}/lib -Wl,-no_compact_unwind -L${PREFIX}/lib -L${ CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DIR}/include" CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include" LIBS="-lomp" -FCFLAGS="-mmacos-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" +FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" FFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype -arch ${ARCH}" CXXFLAGS="${CFLAGS}" From 98bffb565429e8e2f77d243599e376b5e9e4d993 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 30 Jan 2024 16:18:56 -0500 Subject: [PATCH 154/324] Improved the robustness of the build by making pyshtools an optional dependency --- buildscripts/build_shtools.sh | 4 +- environment.yml | 1 - pyproject.toml | 17 ++- requirements.txt | 3 +- swiftest/sph_harmonics.py | 252 ++++++++++++++++++---------------- 5 files changed, 143 insertions(+), 134 deletions(-) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index 01964da7b..7e82b8846 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -15,9 +15,7 @@ ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} . ${SCRIPT_DIR}/set_compilers.sh - -SHTOOLS_VER="4.11.10" - +SHTOOLS_VER="4.9.1" printf "*********************************************************\n" printf "* FETCHING SHTOOLS SOURCE *\n" diff --git a/environment.yml b/environment.yml index 34c6c6c3a..933cb3fe1 100644 --- a/environment.yml +++ b/environment.yml @@ -21,4 +21,3 @@ dependencies: - x264>=1!157.20191217 - ffmpeg>=4.3.2 - cython>=3.0.0 - - pyshtools diff --git a/pyproject.toml b/pyproject.toml index 413681303..5fde1057a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,8 @@ classifiers=[ ] keywords=['astronomy','astrophysics', 'planetary', 'n-body', 'integrator', 'symplectic', 'wisdom-holman', 'symba'] dependencies = [ - 'numpy>=1.26.3', - 'scipy>=1.10.1', + 'numpy>=1.26', + 'scipy>=1.10', 'xarray>=2023.1', 'dask>=2023.5', 'distributed>=2023.5', @@ -38,33 +38,32 @@ dependencies = [ 'astroquery>=0.4.6', 'tqdm>=4.64', 'cython>=3.0', - 'meson>=1.3', - 'meson-python>=0.15', - 'setuptools_scm', - 'pyshtools>=4.11.10' ] +[project.optional-dependencies] +pyshtools = ["pyshtools"] + [project.urls] Repository = 'https://github.itap.purdue.edu/MintonGroup/swiftest' [build-system] requires = [ "scikit-build-core", - "cython>=3.0.0", + "cython>=3.0", "cmake", "pyproject_metadata", "pytest", "pathspec", "sphinx", "sphinx-autosummary-accessors", - "sphinx-book-theme >= 0.3.0", + "sphinx-book-theme >= 0.3", "sphinx-copybutton", "sphinx-design", "sphinx-inline-tabs", "sphinxext-rediraffe", "sphinxext-opengraph", "nbsphinx", - "ford" + "ford", ] build-backend = "scikit_build_core.build" diff --git a/requirements.txt b/requirements.txt index 9519f962d..79d85b58b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,4 @@ matplotlib>=3.7.1 astropy>=5.1 astroquery>=0.4.6 tqdm>=4.65.0 -cython>=3.0.0 -pyshtools \ No newline at end of file +cython>=3.0.0 \ No newline at end of file diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py index 2f192e86d..140d35e2b 100644 --- a/swiftest/sph_harmonics.py +++ b/swiftest/sph_harmonics.py @@ -20,7 +20,6 @@ from astropy.coordinates import SkyCoord import datetime import xarray as xr -import pyshtools as pysh from typing import ( Literal, Dict, @@ -28,121 +27,136 @@ Any ) -class Sph_Harmonics(object): - def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radius = False, ref_radius = None): - """ - Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. - Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). - - Parameters - ---------- - mass : float - mass of the central body - density : float - density of the central body - a : float - length of the pricipal axis aligned with the x axis - b : float, optional, default = a - length of the pricipal axis aligned with the y axis - c : float, optional, default = b - length of the pricipal axis aligned with the z axis - lmax : int, optional, default = 6 - The maximum spherical harmonic degree resolvable by the grid. - lref_radius : boolean, optional, default = False - Boolean value to return the reference radius calculated by SHTOOLS - ref_radius : float, optional, default = None - Reference radius to scale the gravitational coefficients to - - Returns - ------- - clm : ndarry, shape (2, lmax+1, lmax+1) - numpy ndarray of the gravitational potential spherical harmonic coefficients. - This is a three-dimensional array formatted as coeffs[i, degree, order], - where i=0 corresponds to positive orders and i=1 to negative orders. - - """ - Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS - - # cap lmax to ensure fast performance without giving up accuracy - lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB - if(lmax > lmax_limit): - lmax = lmax_limit - print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - - # create shape grid - shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) - - # get gravity coefficients - clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization and not scaling by 4*pi to match normalisation - - # Return reference radius EQUALS the radius of the Central Body - print(f'Ensure that the Central Body radius equals the reference radius.') - - if(lref_radius == True and ref_radius is None): - ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] - return clm, ref_radius - elif(lref_radius == True and ref_radius is not None): - clm_class = clm_class.change_ref(r0 = ref_radius) - clm = clm_class.to_array(normalization = '4pi') - return clm, ref_radius - else: - return clm - - def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radius = None): - """ - Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. - Uses pyshtools. - - Parameters - ---------- - mass : float - mass of the central body - density : float - density of the central body - grid : array, shape [] - DH grid of the surface relief of the body - lmax : int, optional, default = 6 - The maximum spherical harmonic degree resolvable by the grid. - lref_radius : boolean, optional, default = False - Boolean value to return the reference radius calculated by SHTOOLS - ref_radius : float, optional, default = None - Reference radius to scale the gravitational coefficients to - - Returns - ------- - clm : ndarry, shape (2, lmax+1, lmax+1) - numpy ndarray of the gravitational potential spherical harmonic coefficients. - This is a three-dimensional array formatted as coeffs[i, degree, order], - where i=0 corresponds to positive orders and i=1 to negative orders. - - """ - - Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS - - # cap lmax to 20 to ensure fast performance - lmax_limit = 6 - if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients - lmax = lmax_limit - print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - - # convert to spherical harmonics - shape_SH = pysh.SHGrid.from_array(grid) - - # get coefficients - clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization - - # Return reference radius EQUALS the radius of the Central Body - - print(f'Ensure that the Central Body radius equals the reference radius.') - - if(lref_radius == True and ref_radius is None): - ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] - return clm, ref_radius - elif(lref_radius == True and ref_radius is not None): - clm_class = clm_class.change_ref(r0 = ref_radius) - clm = clm_class.to_array(normalization = '4pi') - return clm, ref_radius - else: - return clm +try: + import pyshtools as pysh + PYSHTOOLS_AVAILABLE = True +except ModuleNotFoundError: + PYSHTOOLS_AVAILABLE = False + print("pyshtools is not installed. Some features will be unavailable.") + +if PYSHTOOLS_AVAILABLE: + + class Sph_Harmonics(object): + def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radius = False, ref_radius = None): + """ + Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. + Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). + + Parameters + ---------- + mass : float + mass of the central body + density : float + density of the central body + a : float + length of the pricipal axis aligned with the x axis + b : float, optional, default = a + length of the pricipal axis aligned with the y axis + c : float, optional, default = b + length of the pricipal axis aligned with the z axis + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + lref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS + ref_radius : float, optional, default = None + Reference radius to scale the gravitational coefficients to + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + + # cap lmax to ensure fast performance without giving up accuracy + lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB + if(lmax > lmax_limit): + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # create shape grid + shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) + + # get gravity coefficients + clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization and not scaling by 4*pi to match normalisation + + # Return reference radius EQUALS the radius of the Central Body + print(f'Ensure that the Central Body radius equals the reference radius.') + + if(lref_radius == True and ref_radius is None): + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] + return clm, ref_radius + elif(lref_radius == True and ref_radius is not None): + clm_class = clm_class.change_ref(r0 = ref_radius) + clm = clm_class.to_array(normalization = '4pi') + return clm, ref_radius + else: + return clm + + def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radius = None): + """ + Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. + Uses pyshtools. + + Parameters + ---------- + mass : float + mass of the central body + density : float + density of the central body + grid : array, shape [] + DH grid of the surface relief of the body + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + lref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS + ref_radius : float, optional, default = None + Reference radius to scale the gravitational coefficients to + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + + Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + + # cap lmax to 20 to ensure fast performance + lmax_limit = 6 + if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # convert to spherical harmonics + shape_SH = pysh.SHGrid.from_array(grid) + + # get coefficients + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization + + # Return reference radius EQUALS the radius of the Central Body + + print(f'Ensure that the Central Body radius equals the reference radius.') + + if(lref_radius == True and ref_radius is None): + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] + return clm, ref_radius + elif(lref_radius == True and ref_radius is not None): + clm_class = clm_class.change_ref(r0 = ref_radius) + clm = clm_class.to_array(normalization = '4pi') + return clm, ref_radius + else: + return clm + +else: + class Sph_Harmonics(object): + def clm_from_ellipsoid(*args, **kwargs): + raise NotImplementedError("Sph_Harmonics is not available because pyshtools is not installed.") + \ No newline at end of file From d4c88a1474b39084e9baf7234543ae0707a3443d Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 31 Jan 2024 11:19:31 -0500 Subject: [PATCH 155/324] Rearranged the set_parameter methods to make sure the units don't get messed up during processing of arguments --- swiftest/simulation_class.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index b8218924d..723e1c690 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -786,7 +786,7 @@ def set_parameter(self, "general_relativity": True, "collision_model": "FRAGGLE", "minimum_fragment_mass": None, - "minimum_fragment_gmass": 0.0, + "minimum_fragment_gmass": None, "rotation": True, "compute_conservation_values": False, "extra_force": False, @@ -819,8 +819,8 @@ def set_parameter(self, # Setters returning parameter dictionary values param_dict = {} - param_dict.update(self.set_integrator(**kwargs)) param_dict.update(self.set_unit_system(**kwargs)) + param_dict.update(self.set_integrator(**kwargs)) param_dict.update(self.set_simulation_time(**kwargs)) param_dict.update(self.set_init_cond_files(**kwargs)) param_dict.update(self.set_output_files(**kwargs)) @@ -851,12 +851,12 @@ def get_parameter(self, # Getters returning parameter dictionary values param_dict = {} + param_dict.update(self.get_unit_system(**kwargs)) param_dict.update(self.get_integrator(**kwargs)) param_dict.update(self.get_simulation_time(**kwargs)) param_dict.update(self.get_init_cond_files(**kwargs)) param_dict.update(self.get_output_files(**kwargs)) param_dict.update(self.get_distance_range(**kwargs)) - param_dict.update(self.get_unit_system(**kwargs)) param_dict.update(self.get_feature(**kwargs)) self.get_ephemeris_date(**kwargs) From a7ea8387f9eb5e5dfa943ba05ca01269d941683a Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 31 Jan 2024 11:19:42 -0500 Subject: [PATCH 156/324] Updated build scripts --- environment.yml | 17 +++++++++++++++++ pyproject.toml | 2 +- src/globals/globals_module.f90 | 2 +- version.txt | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/environment.yml b/environment.yml index 933cb3fe1..2ecab5d60 100644 --- a/environment.yml +++ b/environment.yml @@ -21,3 +21,20 @@ dependencies: - x264>=1!157.20191217 - ffmpeg>=4.3.2 - cython>=3.0.0 + - pkg-config + - meson-python>=0.14 + - setuptools_scm>=8 + - fftw>=3.3.8 + - blas-devel>=3.8 + - matplotlib-base>=3.7 + - requests + - pooch>=1.1 + - cartopy>=0.18.0 + - gmt>=6.1.1 + - pygmt>=0.3.0 + - ducc0>=0.15 + - palettable>=3.3 + - jupyter + - pip + - flake8 + - pyshtools diff --git a/pyproject.toml b/pyproject.toml index 5fde1057a..c8480e7b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "swiftest" -version = "2023.12.2" +version = "2024.1.0" authors=[ {name = 'David A. Minton', email='daminton@purdue.edu'}, {name = 'Carlisle Wishard'}, diff --git a/src/globals/globals_module.f90 b/src/globals/globals_module.f90 index ec79028be..ff8c91429 100644 --- a/src/globals/globals_module.f90 +++ b/src/globals/globals_module.f90 @@ -48,7 +48,7 @@ module globals integer(I4B), parameter :: UPPERCASE_OFFSET = iachar('A') - iachar('a') !! ASCII character set parameter for lower to upper !! conversion - offset between upper and lower - character(*), parameter :: VERSION = "2023.12.2" !! Swiftest version + character(*), parameter :: VERSION = "2024.1.0" !! Swiftest version !> Symbolic name for integrator types character(*), parameter :: UNKNOWN_INTEGRATOR = "UKNOWN INTEGRATOR" diff --git a/version.txt b/version.txt index dbe03d474..f96d3c435 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2023.12.2 \ No newline at end of file +2024.1.0 \ No newline at end of file From 16479d23eea529c79f5122beb15f66a7b0612c52 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 31 Jan 2024 13:19:17 -0500 Subject: [PATCH 157/324] re-added check for floating underflow error --- src/swiftest/swiftest_sph.f90 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 484ac8dae..4c7d6bd7c 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -43,7 +43,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp real(DP) :: plm, plm1 !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code real(DP) :: cos_theta, sin_theta !! cos(theta) and sin(theta) - real(DP), dimension(:), allocatable :: p, p_deriv !! Associated Lengendre Polynomials at a given cos(theta) + real(DP), dimension(:), allocatable :: p !! Associated Lengendre Polynomials at a given cos(theta) real(DP) :: fac1, fac2, r_fac !! calculation factors g_sph(:) = 0.0_DP @@ -53,14 +53,17 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp r_mag = sqrt(dot_product(rh(:), rh(:))) l_max = size(c_lm, 2) - 1 N = (l_max + 1) * (l_max + 2) / 2 - allocate(p(N),p_deriv(N)) + allocate(p(N)) cos_theta = cos(theta) sin_theta = sin(theta) - ! call PlmBar_d1(p, p_deriv, l_max, cos_theta) ! Associated Legendre Polynomials and the 1st Derivative - call PlmBar(p, l_max, cos_theta) - + ! check if cos_theta is too small to avoid floating underflow error + if (abs(cos_theta) < EPSILON(0.0_DP)) then + call PlmBar(p, l_max, 0.0_DP) + else + call PlmBar(p, l_max, cos_theta) + end if do l = 1, l_max ! skipping the l = 0 term; It is the spherical body term do m = 0, l @@ -73,7 +76,6 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp ! Associated Legendre Polynomials lmindex = PlmIndex(l, m) plm = p(lmindex) ! p_l,m - ! dplm = p_deriv(lmindex) ! d(p_l,m) ! C_lm and S_lm with Cos and Sin of m * phi ccss = c_lm(m+1, l+1, 1) * cos(m * phi_bar) & From 2f23a6157f8aae71468546c3ec50b0a8777c3f4d Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 31 Jan 2024 19:45:24 -0500 Subject: [PATCH 158/324] Fixed problem that was causing fraggle to fail when the number of fragments was reduced to find a valid solution --- src/fraggle/fraggle_generate.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fraggle/fraggle_generate.f90 b/src/fraggle/fraggle_generate.f90 index a00313abb..0e0914012 100644 --- a/src/fraggle/fraggle_generate.f90 +++ b/src/fraggle/fraggle_generate.f90 @@ -884,6 +884,7 @@ module subroutine fraggle_generate_vel_vec(collider, nbody_system, param, lfailu L_mag_factor = .mag.(collider%L_total(:,1) + collider%L_total(:,2)) L_residual(:) = (collider%L_total(:,2) / L_mag_factor - collider%L_total(:,1)) / L_mag_factor call collision_util_velocity_torque(-L_residual(:) * L_mag_factor, collider%fragments%mtot, impactors%rbcom, impactors%vbcom) + nfrag = collider%fragments%nbody #ifdef DOCONLOC do concurrent(i = 1:nfrag) shared(collider, impactors) From ba2ca2d8fe580a4da88be85a69c0237d46329da4 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 31 Jan 2024 19:45:40 -0500 Subject: [PATCH 159/324] Adjusted version of numpy to work with python 3.8 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c8480e7b2..da9638d5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ classifiers=[ ] keywords=['astronomy','astrophysics', 'planetary', 'n-body', 'integrator', 'symplectic', 'wisdom-holman', 'symba'] dependencies = [ - 'numpy>=1.26', + 'numpy>=1.23', 'scipy>=1.10', 'xarray>=2023.1', 'dask>=2023.5', From 6592a7e6c0ef10df13a11adf9bedec809bee1405 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 8 Feb 2024 16:06:45 -0500 Subject: [PATCH 160/324] removed unnecessary step setting cb%c_lm to 0.0 --- src/swiftest/swiftest_io.f90 | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 7107c6be8..25608f6e8 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -3351,14 +3351,7 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (ierr /=0) call base_util_exit(FAILURE,param%display_unit) end if - param%lshgrav = allocated(self%cb%c_lm) !! .and. (size(self%cb%c_lm) /= 0) - - if(param%lshgrav) then - ! Replace elements of c_lm smaller than epsilon with 0.0 - WHERE (abs(self%cb%c_lm) < EPSILON(0.0_DP)) - self%cb%c_lm = 0.0_DP - END WHERE - end if + param%lshgrav = allocated(self%cb%c_lm) param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) if (.not.param%loblatecb .and. .not.param%lshgrav) then From bcbf96b6805d81e79aacab025cf4c2eba99af415 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 9 Feb 2024 16:10:01 -0500 Subject: [PATCH 161/324] Allowing for I/O of cb%rotphase in .nc files --- src/swiftest/swiftest_io.f90 | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 25608f6e8..b7bfc0471 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -964,6 +964,8 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%rot_varname, nc%out_type, [nc%space_dimid, nc%name_dimid, nc%time_dimid], & nc%rot_varid), & "netcdf_io_initialize_output nf90_def_var rot_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%rotphase_varname, nc%out_type, nc%time_dimid, nc%rotphase_varid), & + "netcdf_io_initialize_output nf90_def_var rotphase_varid" ) end if ! if (param%ltides) then @@ -1179,6 +1181,14 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) "swiftest_io_netcdf_open nf90_inq_varid Ip_varid" ) call netcdf_io_check( nf90_inq_varid(nc%id, nc%rot_varname, nc%rot_varid), & "swiftest_io_netcdf_open nf90_inq_varid rot_varid" ) + + + ! rotphase may not be input by the user + status = nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid) + + ! call netcdf_io_check( nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid), & + ! "swiftest_io_netcdf_open nf90_inq_varid rotphase_varid") + end if ! if (param%ltides) then @@ -1515,7 +1525,16 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier end do ! Set initial central body angular momentum for bookkeeping - cb%L0(:) = cb%Ip(3) * cb%mass * cb%R0**2 * cb%rot(:) + cb%L0(:) = cb%Ip(3) * cb%mass * cb%R0**2 * cb%rot(:) + + ! rotphase may not be input by the user + status = nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, cb%rotphase, start=[tslot]), & + "netcdf_io_read_frame_system nf90_getvar rotphase_varid" ) + else + cb%rotphase = 0.0_DP + end if end if ! if (param%ltides) then @@ -2104,9 +2123,10 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, self%rot(:) * RAD2DEG, start=[1, idslot, tslot], & count=[NDIM,1,1]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rot_varid" ) - ! ADD - ! call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase(:), start = [1, idslot, tslot]), & - ! "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") + + ! Following the template of j2rp2 + call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase, start = [tslot]), & ! start = [1, idslot, tslot]), & + "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") end if status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) From 85c779a53b52e4a22da04022c47c4bd25935fca7 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 9 Feb 2024 16:17:41 -0500 Subject: [PATCH 162/324] added rotphase varid and varname to netcdf module --- src/netcdf_io/netcdf_io_module.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index 51b315a04..e40df8135 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -105,6 +105,8 @@ module netcdf_io integer(I4B) :: Ip_varid !! ID for the axis principal moment of inertia variable character(NAMELEN) :: rot_varname = "rot" !! name of the rotation vector variable integer(I4B) :: rot_varid !! ID for the rotation vector variable + character(NAMELEN) :: rotphase_varname = "rotphase" !! name of the rotation phase variable + integer(I4B) :: rotphase_varid !! ID for the rotation phase variable character(NAMELEN) :: j2rp2_varname = "j2rp2" !! name of the j2rp2 variable integer(I4B) :: j2rp2_varid !! ID for the j2 variable character(NAMELEN) :: j4rp4_varname = "j4rp4" !! name of the j4pr4 variable From bc38920ed84c6d1578564015d1c1fed84f65e72c Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 9 Feb 2024 16:36:11 -0500 Subject: [PATCH 163/324] Changed rotphase to be unitless (0 to 1). Edited swiftest_sph to account for this by converting the phase to radians --- src/swiftest/swiftest_drift.f90 | 6 ++++-- src/swiftest/swiftest_sph.f90 | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 864c745ec..c67e03be5 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -583,15 +583,17 @@ end subroutine swiftest_drift_kepu_stumpff module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) !! Author : Kaustub Anand !! subroutine to update the rotation phase of the central body - !! Units: Radians + !! Units: None + !! !! initial 0 is set at the x-axis + !! phase is stored and calculated in a unitless manner, i.e., a phase of 0, 0.5, 1 = 0, pi, 2pi radians = 0, 180, 360 degrees ! Arguments class(swiftest_cb), intent(inout) :: self !! Swiftest central body data structure class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize - self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) ! radians + self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) / (2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless end subroutine swiftest_drift_cb_rotphase_update diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 4c7d6bd7c..3f6b7f40c 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -26,7 +26,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp ! Arguments real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi_cb !! rotation phase of the central body + real(DP), intent(in) :: phi_cb !! rotation phase of the central body (from 0 to 1) real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector @@ -47,6 +47,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp real(DP) :: fac1, fac2, r_fac !! calculation factors g_sph(:) = 0.0_DP + phi_cb = phi_cb * 2 * PI ! scale the phase by 2pi radians theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) phi = atan2(rh(2), rh(1)) phi_bar = MOD(phi - phi_cb, 2 * PI) ! represents the phase difference between the central body's and the particle's phase From 312abf920eb8b73e332403a5d6e44ad48f12c988 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 9 Feb 2024 16:57:58 -0500 Subject: [PATCH 164/324] Fixed typos and made relevant changes to account for now unitless rotphase --- src/swiftest/swiftest_drift.f90 | 2 +- src/swiftest/swiftest_module.f90 | 8 ++++---- src/swiftest/swiftest_sph.f90 | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index c67e03be5..c6f2a4c99 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -593,7 +593,7 @@ module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize - self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) / (2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless + self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S / (2 * PI), 1.0_DP) ! phase angle calculated in radians and then scaled by 2pi to be unitless end subroutine swiftest_drift_cb_rotphase_update diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 3cc49ada3..72c029a30 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -212,7 +212,7 @@ module swiftest real(DP), dimension(NDIM) :: agr = 0.0_DP !! Acceleration due to post-Newtonian correction real(DP), dimension(NDIM) :: Ip = 0.0_DP !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. real(DP), dimension(NDIM) :: rot = 0.0_DP !! Body rotation vector in inertial coordinate frame (units rad / TU) - real(DP) :: rotphase = 0.0_DP !! Body rotation phase about the rotation pole (0 to 2*pi) + real(DP) :: rotphase = 0.0_DP !! Body rotation phase about the rotation pole (0 to 1) real(DP) :: k2 = 0.0_DP !! Tidal Love number real(DP) :: Q = 0.0_DP !! Tidal quality factor real(DP) :: tlag = 0.0_DP !! Tidal phase lag angle @@ -547,7 +547,7 @@ end subroutine swiftest_drift_one module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) !! Author : Kaustub Anand !! subroutine to update the rotation phase of the central body - !! Units: Radians + !! Units: None !! initial 0 is set at the x-axis ! Arguments @@ -1857,11 +1857,11 @@ end subroutine swiftest_coarray_cocollect_tp #endif interface - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, GMpl, aoblcb) implicit none real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi_cb !! rotation phase of the central body + real(DP), intent(in) :: rotphase !! rotation phase of the central body real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 3f6b7f40c..29eaa18b6 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -16,7 +16,7 @@ contains - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -26,7 +26,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp ! Arguments real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi_cb !! rotation phase of the central body (from 0 to 1) + real(DP), intent(in) :: rotphase !! rotation phase of the central body real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector @@ -38,7 +38,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp integer :: l_max !! max Spherical Harmonic l order value integer(I4B) :: N, lmindex !! Length of Legendre polynomials and index at a given l, m real(DP) :: r_mag !! magnitude of rh - real(DP) :: phi, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase + real(DP) :: phi, phi_cb, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase real(DP) :: theta !! Inclination/Zenith angle (radians) real(DP) :: plm, plm1 !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code @@ -47,7 +47,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp real(DP) :: fac1, fac2, r_fac !! calculation factors g_sph(:) = 0.0_DP - phi_cb = phi_cb * 2 * PI ! scale the phase by 2pi radians + phi_cb = rotphase * 2 * PI ! scale the phase to a phase angle by 2pi radians theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) phi = atan2(rh(2), rh(1)) phi_bar = MOD(phi - phi_cb, 2 * PI) ! represents the phase difference between the central body's and the particle's phase From c1ea53dcf15f06a2bdda1a9a841cbcbf1d1daaf3 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sat, 10 Feb 2024 16:36:41 -0500 Subject: [PATCH 165/324] Changing phase to radians --- src/swiftest/swiftest_drift.f90 | 6 +++--- src/swiftest/swiftest_io.f90 | 6 +++--- src/swiftest/swiftest_module.f90 | 6 +++--- src/swiftest/swiftest_sph.f90 | 7 +++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index c6f2a4c99..41713a2c8 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -583,17 +583,17 @@ end subroutine swiftest_drift_kepu_stumpff module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) !! Author : Kaustub Anand !! subroutine to update the rotation phase of the central body - !! Units: None + !! Units: radians !! !! initial 0 is set at the x-axis - !! phase is stored and calculated in a unitless manner, i.e., a phase of 0, 0.5, 1 = 0, pi, 2pi radians = 0, 180, 360 degrees + !! phase is stored and calculated in radians. Converted to degrees for output ! Arguments class(swiftest_cb), intent(inout) :: self !! Swiftest central body data structure class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize - self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S / (2 * PI), 1.0_DP) ! phase angle calculated in radians and then scaled by 2pi to be unitless + self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless end subroutine swiftest_drift_cb_rotphase_update diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index b7bfc0471..e7cf51c21 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1182,7 +1182,6 @@ module subroutine swiftest_io_netcdf_open(self, param, readonly) call netcdf_io_check( nf90_inq_varid(nc%id, nc%rot_varname, nc%rot_varid), & "swiftest_io_netcdf_open nf90_inq_varid rot_varid" ) - ! rotphase may not be input by the user status = nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid) @@ -1530,8 +1529,9 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier ! rotphase may not be input by the user status = nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, cb%rotphase, start=[tslot]), & + call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, rtemp, start=[tslot]), & "netcdf_io_read_frame_system nf90_getvar rotphase_varid" ) + cb%rotphase = rtemp * DEG2RAD else cb%rotphase = 0.0_DP end if @@ -2125,7 +2125,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rot_varid" ) ! Following the template of j2rp2 - call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase, start = [tslot]), & ! start = [1, idslot, tslot]), & + call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase * RAD2DEG, start = [tslot]), & ! start = [1, idslot, tslot]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") end if diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 72c029a30..fdefc6ec0 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -547,7 +547,7 @@ end subroutine swiftest_drift_one module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) !! Author : Kaustub Anand !! subroutine to update the rotation phase of the central body - !! Units: None + !! Units: radians !! initial 0 is set at the x-axis ! Arguments @@ -1857,11 +1857,11 @@ end subroutine swiftest_coarray_cocollect_tp #endif interface - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) implicit none real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: rotphase !! rotation phase of the central body + real(DP), intent(in) :: phi_cb !! rotation phase angle of the central body real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector diff --git a/src/swiftest/swiftest_sph.f90 b/src/swiftest/swiftest_sph.f90 index 29eaa18b6..3bdc1fceb 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/swiftest/swiftest_sph.f90 @@ -16,7 +16,7 @@ contains - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, GMpl, aoblcb) + module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r @@ -26,7 +26,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, G ! Arguments real(DP), intent(in) :: GMcb !! GMass of the central body real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: rotphase !! rotation phase of the central body + real(DP), intent(in) :: phi_cb !! rotation phase angle of the central body real(DP), intent(in), dimension(:) :: rh !! distance vector of body real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector @@ -38,7 +38,7 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, G integer :: l_max !! max Spherical Harmonic l order value integer(I4B) :: N, lmindex !! Length of Legendre polynomials and index at a given l, m real(DP) :: r_mag !! magnitude of rh - real(DP) :: phi, phi_cb, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase + real(DP) :: phi, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase real(DP) :: theta !! Inclination/Zenith angle (radians) real(DP) :: plm, plm1 !! Associated Legendre polynomials at a given l, m real(DP) :: ccss, cssc !! See definition in source code @@ -47,7 +47,6 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, rotphase, rh, c_lm, g_sph, G real(DP) :: fac1, fac2, r_fac !! calculation factors g_sph(:) = 0.0_DP - phi_cb = rotphase * 2 * PI ! scale the phase to a phase angle by 2pi radians theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) phi = atan2(rh(2), rh(1)) phi_bar = MOD(phi - phi_cb, 2 * PI) ! represents the phase difference between the central body's and the particle's phase From 99ca5f4e35f19a3276fa8a1fa22e3c1aca1cc9b3 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sat, 10 Feb 2024 17:00:24 -0500 Subject: [PATCH 166/324] fixed a typo --- src/swiftest/swiftest_io.f90 | 2 +- swiftest/simulation_class.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index e7cf51c21..70f57aebd 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1531,7 +1531,7 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier if (status == NF90_NOERR) then call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, rtemp, start=[tslot]), & "netcdf_io_read_frame_system nf90_getvar rotphase_varid" ) - cb%rotphase = rtemp * DEG2RAD + cb%rotphase = rtemp(1) * DEG2RAD else cb%rotphase = 0.0_DP end if diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 723e1c690..0511f0a50 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2422,7 +2422,8 @@ def add_body(self, Ip: List[float] | npt.NDArray[np.float_] | None=None, J2: float | List[float] | npt.NDArray[np.float_] | None=None, J4: float | List[float] | npt.NDArray[np.float_] | None=None, - c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None + c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None, + rotphase: float | List[float] | npt.NDArray[np.float_] | None=None ) -> None: """ Adds a body (test particle or massive body) to the internal DataSet given a set up 6 vectors (orbital elements @@ -2465,6 +2466,8 @@ def add_body(self, Rotation rate vectors if these are massive bodies with rotation enabled. Ip : (3) or (n,3) array-like of float, optional Principal axes moments of inertia vectors if these are massive bodies with rotation enabled. + rotphase : float, optional + rotation phase angle of the central body in degrees Returns ------- @@ -2569,6 +2572,7 @@ def input_to_clm_array(val, n): vh,nbodies = input_to_array_3d(vh,nbodies) rot,nbodies = input_to_array_3d(rot,nbodies) Ip,nbodies = input_to_array_3d(Ip,nbodies) + rotphase, nbodies = input_to_array(rotphase, "f", nbodies) c_lm, nbodies = input_to_clm_array(c_lm, nbodies) From 7eae81ce5cf7087bdc8209466861522bf2729099 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sat, 10 Feb 2024 17:23:33 -0500 Subject: [PATCH 167/324] fixed netcdf start+count error for rotphase; added rotphase to sim.add_body --- src/swiftest/swiftest_io.f90 | 4 ++-- swiftest/init_cond.py | 9 +++++++-- swiftest/simulation_class.py | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 70f57aebd..efc0a3791 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1529,9 +1529,9 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier ! rotphase may not be input by the user status = nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, rtemp, start=[tslot]), & + call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, cb%rotphase, start=[tslot]), & "netcdf_io_read_frame_system nf90_getvar rotphase_varid" ) - cb%rotphase = rtemp(1) * DEG2RAD + cb%rotphase = cb%rotphase * DEG2RAD else cb%rotphase = 0.0_DP end if diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index a4c89a90e..8f132073d 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -459,6 +459,9 @@ def vec2xr(param: Dict, **kwargs: Any): Time at start of simulation c_lm : (2, lmax + 1, lmax + 1) array of floats, optional Spherical Harmonics coefficients; lmax = max spherical harmonics order + rotphase : float + rotational phase angle of the central body in degrees + Returns ------- ds : xarray dataset @@ -470,9 +473,9 @@ def vec2xr(param: Dict, **kwargs: Any): sph_dims = ['sign', 'l', 'm'] # Spherical Harmonics dimensions vector_vars = ["rh","vh","Ip","rot"] - scalar_vars = ["name","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] + scalar_vars = ["name","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4", "rotphase"] sph_vars = ["c_lm"] - time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4"] + time_vars = ["rh","vh","Ip","rot","a","e","inc","capom","omega","capm","Gmass","radius","rhill","j2rp2","j4rp4", "rotphase"] # Check for valid keyword arguments kwargs = {k:kwargs[k] for k,v in kwargs.items() if v is not None} @@ -482,6 +485,8 @@ def vec2xr(param: Dict, **kwargs: Any): kwargs['rot'] = np.zeros((len(kwargs['Gmass']),3)) if "Ip" not in kwargs and "Gmass" in kwargs: kwargs['Ip'] = np.full((len(kwargs['Gmass']),3), 0.4) + if "rotphase" not in kwargs: + kwargs['rotphase'] = 0.0 if "time" not in kwargs: kwargs["time"] = np.array([0.0]) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 0511f0a50..3075f1609 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2601,7 +2601,7 @@ def input_to_clm_array(val, n): Gmass = self.GU * mass dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, - Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, time=time) + Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, rotphase=rotphase, time=time) dsnew = self._combine_and_fix_dsnew(dsnew) self.save(verbose=False) From 6bd45c32c85b15ba878b5ec2b1e6c04e316446df Mon Sep 17 00:00:00 2001 From: anand43 Date: Sat, 10 Feb 2024 17:54:24 -0500 Subject: [PATCH 168/324] added rotphase to sim.add_body. Tested --- swiftest/init_cond.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 8f132073d..fa84b12a7 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -485,8 +485,6 @@ def vec2xr(param: Dict, **kwargs: Any): kwargs['rot'] = np.zeros((len(kwargs['Gmass']),3)) if "Ip" not in kwargs and "Gmass" in kwargs: kwargs['Ip'] = np.full((len(kwargs['Gmass']),3), 0.4) - if "rotphase" not in kwargs: - kwargs['rotphase'] = 0.0 if "time" not in kwargs: kwargs["time"] = np.array([0.0]) From f76320c34e961f77c8aee0dcb828e6f0b7fc9dd8 Mon Sep 17 00:00:00 2001 From: anand43 Date: Sun, 11 Feb 2024 17:32:57 -0500 Subject: [PATCH 169/324] fixed a typo --- swiftest/tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swiftest/tool.py b/swiftest/tool.py index 083945dd3..1f4b959b1 100644 --- a/swiftest/tool.py +++ b/swiftest/tool.py @@ -420,7 +420,7 @@ def xv2el_one(mu,rvec,vvec): argument of periapsis (degrees) M : float mean anomaly (degrees) - varpi : flaot + varpi : float longitude of periapsis (degrees) f : float true anomaly (degrees) From 89c737f29ea93fc7ac1a43bb929af0ddb9c0a4a2 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 12 Feb 2024 09:13:50 -0500 Subject: [PATCH 170/324] Updated the remote for the SHTOOLS submodule to be my forked repo --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 750c35aae..83fc36326 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "SHTOOLS"] path = SHTOOLS - url = https://github.com/SHTOOLS/SHTOOLS + url = https://github.com/profminton/SHTOOLS From 5ca62d5c03bf80852cca4c74ddc9443134a60bf4 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 12 Feb 2024 09:47:35 -0500 Subject: [PATCH 171/324] modified: SHTOOLS --- SHTOOLS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHTOOLS b/SHTOOLS index aa6767f05..f50f58a9e 160000 --- a/SHTOOLS +++ b/SHTOOLS @@ -1 +1 @@ -Subproject commit aa6767f0560e66c269473904eba978ef6e3713c2 +Subproject commit f50f58a9e0cdadfdd100f7ebf00847813f960d77 From 1760b11dfbdd320917c68acd43cf889595e31f60 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 12:41:27 -0500 Subject: [PATCH 172/324] Updated all of the build scripts and tools to work with Negishi --- buildscripts/_build_getopts.sh | 24 ++++++++++++++---- buildscripts/build_hdf5.sh | 13 +++++----- buildscripts/build_negishi.sh | 34 ++++++++++++++++++++++++++ buildscripts/build_netcdf-c.sh | 9 +++---- buildscripts/build_netcdf-fortran.sh | 5 ++-- buildscripts/build_shtools.sh | 21 ++++++++++++---- buildscripts/build_zlib.sh | 9 ++++--- buildscripts/get_platform.sh | 12 +++++++++ buildscripts/set_compilers.sh | 29 +++++++++++++--------- buildscripts/set_environment_linux.sh | 15 +++++++----- cmake/Modules/FindNETCDF_Fortran.cmake | 20 +++++++++------ cmake/Modules/SetCompileFlag.cmake | 17 ------------- cmake/Modules/SetSwiftestFlags.cmake | 6 ++--- environment.yml | 2 +- pyproject.toml | 6 ++--- src/globals/globals_module.f90 | 2 +- version.txt | 2 +- 17 files changed, 144 insertions(+), 82 deletions(-) create mode 100755 buildscripts/build_negishi.sh diff --git a/buildscripts/_build_getopts.sh b/buildscripts/_build_getopts.sh index 113f9e526..e98f2fb9a 100755 --- a/buildscripts/_build_getopts.sh +++ b/buildscripts/_build_getopts.sh @@ -53,8 +53,22 @@ BUILD_DIR=${BUILD_DIR:-"${HOME}/Downloads"} PREFIX=${PREFIX:-"/usr/local"} DEPENDENCY_DIR=${DEPENDENCY_DIR:-${BUILD_DIR}} -mkdir -p ${DEPENDENCY_DIR} -mkdir -p ${PREFIX}/lib -mkdir -p ${PREFIX}/include -mkdir -p ${PREFIX}/share -mkdir -p ${PREFIX}/bin \ No newline at end of file + +case $OS in + Linux-gnu|Linux-ifx|Linux-ifort) + . ${SCRIPT_DIR}/set_environment_linux.sh + ;; + MacOSX) + . ${SCRIPT_DIR}/set_environment_macos.sh + ;; + + *) + printf "Unknown compiler type: ${OS}\n" + echo "Valid options are Linux-gnu, Linux-ifort, Linux-ifx, or MacOSX" + printf $USTMT + exit 1 + ;; +esac + + +mkdir -p ${DEPENDENCY_DIR} \ No newline at end of file diff --git a/buildscripts/build_hdf5.sh b/buildscripts/build_hdf5.sh index 3f93d036b..234011f69 100755 --- a/buildscripts/build_hdf5.sh +++ b/buildscripts/build_hdf5.sh @@ -11,8 +11,8 @@ # You should have received a copy of the GNU General Public License along with Swiftest. # If not, see: https://www.gnu.org/licenses. -HDF5_VER="1_14_2" -ZLIB_VER="1.3" +HDF5_VER="1_14_3" +ZLIB_VER="1.3.1" SCRIPT_DIR=$(realpath $(dirname $0)) set -a @@ -27,7 +27,7 @@ printf "*********************************************************\n" printf "* STARTING DEPENDENCY BUILD *\n" printf "*********************************************************\n" printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n" -printf "Installing to ${PREFIX}\n" +printf "Installing to ${HDF5_ROOT}\n" printf "\n" printf "*********************************************************\n" @@ -60,13 +60,11 @@ printf "CPPFLAGS: ${CPPFLAGS}\n" printf "CPATH: ${CPATH}\n" printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" printf "LDFLAGS: ${LDFLAGS}\n" +printf "INSTALL_PREFIX: ${HDF5_ROOT}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/hdfsrc -HDF5_ROOT=${PREFIX} -ZLIB_ROOT=${PREFIX} -SZIP_ROOT=${PREFIX} if [ $OS = "MacOSX" ]; then ZLIB_LIBRARY="${ZLIB_ROOT}/lib/libz.dylib" else @@ -85,6 +83,7 @@ ARGLIST="-DCMAKE_INSTALL_PREFIX:PATH=${HDF5_ROOT} \ -DHDF5_BUILD_FORTRAN:BOOL=OFF \ -DHDF5_BUILD_EXAMPLES:BOOL=ON \ -DBUILD_TESTING:BOOL=ON \ + -DBUILD_STATIC_LIBS:BOOL=OFF \ -DHDF5_BUILD_JAVA:BOOL=OFF" if [ $OS = "MacOSX" ]; then @@ -94,7 +93,7 @@ fi cmake -B build -C ./config/cmake/cacheinit.cmake -G Ninja ${ARGLIST} . cmake --build build -j${NPROC} --config Release -if [ -w ${PREFIX} ]; then +if [ -w ${HDF5_ROOT} ]; then cmake --install build else sudo cmake --install build diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh new file mode 100755 index 000000000..31a555de9 --- /dev/null +++ b/buildscripts/build_negishi.sh @@ -0,0 +1,34 @@ +#!/bin/zsh -l +# installs an editable (local) package in release mode on Negishi +# This is a convenience script for Kaustub + +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +cd ${ROOT_DIR} +BUILD_TYPE=${1:-"Release"} + +module purge +module load intel-oneapi-compilers/2023.0.0 +module load intel-oneapi-mkl/2023.0.0 +module load intel-oneapi-mpi/2021.8.0 +source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 +module use /depot/daminton/etc/modules +module load use.own +module load conda-env/mintongroup-py3.9.13 +module load netcdf-fortran/intel-oneapi/4.6.1 +module load shtools/intel-oneapi/4.11.10 +cmake -P distclean.cmake +pip install --config-settings=editable.rebuild=true \ + --config-settings=build-dir="build/{wheel_tag}" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ + --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ + --no-build-isolation \ + -ve . + + +LD_LIBRARY_PATH=$(realpath ${ROOT_DIR}/build/*/bin):$LD_LIBRARY_PATH \ No newline at end of file diff --git a/buildscripts/build_netcdf-c.sh b/buildscripts/build_netcdf-c.sh index ee7415cbf..c9ec290e3 100755 --- a/buildscripts/build_netcdf-c.sh +++ b/buildscripts/build_netcdf-c.sh @@ -22,7 +22,7 @@ printf "*********************************************************\n" printf "* STARTING DEPENDENCY BUILD *\n" printf "*********************************************************\n" printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n" -printf "Installing to ${PREFIX}\n" +printf "Installing to ${NCDIR}\n" printf "\n" NC_VER="4.9.2" @@ -48,16 +48,15 @@ printf "CPATH: ${CPATH}\n" printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" printf "LDFLAGS: ${LDFLAGS}\n" printf "HDF5_ROOT: ${HDF5_ROOT}\n" +printf "INSTALL_PREFIX: ${NCDIR}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/netcdf-c-* -NCDIR="${PREFIX}" -ZLIB_ROOT=${PREFIX} cmake -B build -S . -G Ninja \ -DCMAKE_BUILD_TYPE:STRING="Release" \ -DHDF5_DIR:PATH=${HDF5_ROOT}/cmake \ -DHDF5_ROOT:PATH=${HDF5_ROOT} \ - -DCMAKE_FIND_ROOT_PATH:PATH="${PREFIX}" \ + -DCMAKE_FIND_ROOT_PATH:PATH="${NCDIR}" \ -DCMAKE_INSTALL_PREFIX:STRING="${NCDIR}" \ -DENABLE_DAP:BOOL=OFF \ -DENABLE_BYTERANGE:BOOL=OFF \ @@ -68,7 +67,7 @@ cmake -B build -S . -G Ninja \ -DENABLE_REMOTE_FORTRAN_BOOTSTRAP:BOOL=ON cmake --build build -j${NPROC} -if [ -w ${PREFIX} ]; then +if [ -w ${NCDIR} ]; then cmake --install build else sudo cmake --install build diff --git a/buildscripts/build_netcdf-fortran.sh b/buildscripts/build_netcdf-fortran.sh index c82f24573..f3021a12a 100755 --- a/buildscripts/build_netcdf-fortran.sh +++ b/buildscripts/build_netcdf-fortran.sh @@ -22,7 +22,7 @@ printf "*********************************************************\n" printf "* STARTING DEPENDENCY BUILD *\n" printf "*********************************************************\n" printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n" -printf "Installing to ${PREFIX}\n" +printf "Installing to ${NFDIR}\n" printf "\n" NF_VER="4.6.1" @@ -49,7 +49,6 @@ printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/netcdf-fortran-* -NFDIR="${PREFIX}" NCLIBDIR=$(${NCDIR}/bin/nc-config --libdir) if [ $OS = "MacOSX" ]; then netCDF_LIBRARIES="${NCLIBDIR}/libnetcdf.dylib" @@ -62,7 +61,7 @@ cmake -B build -S . -G Ninja \ -DCMAKE_INSTALL_PREFIX:PATH=${NFDIR} \ -DCMAKE_INSTALL_LIBDIR="lib" cmake --build build -j${NPROC} -if [ -w ${PREFIX} ]; then +if [ -w ${NFDIR} ]; then cmake --install build else sudo cmake --install build diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index 7e82b8846..5ffe9f029 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -15,7 +15,7 @@ ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} . ${SCRIPT_DIR}/set_compilers.sh -SHTOOLS_VER="4.9.1" +SHTOOLS_VER="4.11.10" printf "*********************************************************\n" printf "* FETCHING SHTOOLS SOURCE *\n" @@ -41,12 +41,23 @@ printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/SHTOOLS* -make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran -make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -O3 -std=gnu -ffast-math ${FFLAGS}" fortran-mp +case $FC in + *"ifort"*|*"ifx"*) + echo "Using Intel Fortran compiler" + make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -m64 -fpp -free -O3 -Tf" fortran + make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -m64 -fpp -free -O3 -Tf" fortran-mp + ;; + *) + echo "Everything else" + make F95="${FC}" CXX="${CXX}" fortran + make F95="${FC}" CXX="${CXX}" fortran-mp + ;; +esac + if [ -w ${PREFIX} ]; then - make PREFIX="${PREFIX}" install + make F95="${FC}" PREFIX="${PREFIX}" install else - sudo make PREFIX="${PREFIX}" install + sudo make F95="${FC}" PREFIX="${PREFIX}" install fi cd .. diff --git a/buildscripts/build_zlib.sh b/buildscripts/build_zlib.sh index 337e6a839..358941e09 100755 --- a/buildscripts/build_zlib.sh +++ b/buildscripts/build_zlib.sh @@ -22,10 +22,10 @@ printf "*********************************************************\n" printf "* STARTING DEPENDENCY BUILD *\n" printf "*********************************************************\n" printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n" -printf "Installing to ${PREFIX}\n" +printf "Installing to ${ZLIB_ROOT}\n" printf "\n" -ZLIB_VER="1.3" +ZLIB_VER="1.3.1" printf "*********************************************************\n" printf "* FETCHING ZLIB SOURCE *\n" @@ -46,13 +46,14 @@ printf "CPPFLAGS: ${CPPFLAGS}\n" printf "CPATH: ${CPATH}\n" printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" printf "LDFLAGS: ${LDFLAGS}\n" +printf "INSTALL_PREFIX: ${ZLIB_ROOT}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/zlib-* -cmake -B build -S . -G Ninja -DCMAKE_INSTALL_PREFIX=${PREFIX} +cmake -B build -S . -G Ninja -DCMAKE_INSTALL_PREFIX=${ZLIB_ROOT} cmake --build build -j${NPROC} -if [ -w ${PREFIX} ]; then +if [ -w ${ZLIB_ROOT} ]; then cmake --install build else sudo cmake --install build diff --git a/buildscripts/get_platform.sh b/buildscripts/get_platform.sh index 583510fb3..2455d7f29 100755 --- a/buildscripts/get_platform.sh +++ b/buildscripts/get_platform.sh @@ -45,6 +45,18 @@ esac case $OS in Linux) + # Currently ifx support is not great + # if command -v ifx >/dev/null 2>&1; then + # OS="Linux-ifx" + + if command -v ifort >/dev/null 2>&1; then + OS="Linux-ifort" + elif command -v gfortran >/dev/null 2>&1; then + OS="Linux-gnu" + else + echo "No Fortran compiler found on Linux" + exit 1 + fi ;; Darwin) OS="MacOSX" diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index eb7322334..b04b02702 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -16,11 +16,11 @@ SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) case "$OS" in - Linux|MacOSX|Intel) + Linux-gnu|Linux-ifx|Linux-ifort|MacOSX) ;; *) echo "Unknown compiler type: $OS" - echo "Valid options are Intel, Linux, or MacOSX" + echo "Valid options are Linux-gnu, Linux-ifort, Linux-ifx, or MacOSX" echo $USTMT exit 1 ;; @@ -28,15 +28,25 @@ esac set -a case $OS in - Linux) - . ${SCRIPT_DIR}/set_environment_linux.sh + Linux-gnu) FC=$(command -v gfortran) CC=$(command -v gcc) CXX=$(command -v g++) CPP=$(command -v cpp) ;; + Linux-ifx) + FC=$(command -v ifx) + CC=$(command -v icx) + CXX=$(command -v icpx) + CPP=$(command -v cpp) + ;; + Linux-ifort) + FC=$(command -v ifort) + CC=$(command -v icx) + CXX=$(command -v icpx) + CPP=$(command -v cpp) + ;; MacOSX) - . ${SCRIPT_DIR}/set_environment_macos.sh FC=${HOMEBREW_PREFIX}/bin/gfortran-12 CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" @@ -52,15 +62,10 @@ case $OS in RANLIB=${COMPILER_PREFIX}/bin/ranlib LDFLAGS="-Wl,-no_compact_unwind" ;; - Intel) - FC=$(command -v ifx) - CC=$(command -v icx) - CXX=$(command -v icpx) - CPP=$(command -v cpp) - ;; + *) printf "Unknown compiler type: ${OS}\n" - echo "Valid options are Intel, Linux, or MacOSX" + echo "Valid options are Linux-gnu, Linux-ifort, Linux-ifx, or MacOSX" printf $USTMT exit 1 ;; diff --git a/buildscripts/set_environment_linux.sh b/buildscripts/set_environment_linux.sh index a7c566d59..6a6c055ad 100755 --- a/buildscripts/set_environment_linux.sh +++ b/buildscripts/set_environment_linux.sh @@ -1,17 +1,20 @@ #!/bin/bash # Sets environment flags on Linux set -a -PREFIX="/usr/local" -NCDIR="${PREFIX}" -NFDIR="${PREFIX}" +PREFIX=${PREFIX:-"/usr/local"} +NCDIR=${NETCDF_HOME:-"${PREFIX}"} +NFDIR=${NETCDF_FORTRAN_HOME:-"${PREFIX}"} NETCDF_FORTRAN_HOME="${NFDIR}" NETCDF_FORTRAN_INCLUDE="${NFDIR}/include" -HDF5_ROOT="${PREFIX}" +ZLIB_ROOT=${ZLIB_ROOT:-"${ZLIB_HOME}"} +ZLIB_ROOT=${ZLIB_ROOT:-"${PREFIX}"} +HDF5_ROOT=${HDF5_ROOT:-"${HDF5_HOME}"} +HDF5_ROOT=${HDF5_ROOT:-"${PREFIX}"} HDF5_LIBDIR="${HDF5_ROOT}/lib" HDF5_INCLUDE_DIR="${HDF5_ROOT}/include" HDF5_PLUGIN_PATH="${HDF5_LIBDIR}/plugin" -LD_LIBRARY_PATH="${PREFIX}/lib" -CPATH="${PREFIX}/include:" +LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH}" +CPATH="${PREFIX}/include:${CPATH}" HDF5_DIR="${HDF5_ROOT}/cmake" PATH="${HDF5_ROOT}/bin:${PATH}" CMAKE_INSTALL_LIBDIR="lib" \ No newline at end of file diff --git a/cmake/Modules/FindNETCDF_Fortran.cmake b/cmake/Modules/FindNETCDF_Fortran.cmake index ee56789a5..64ed4c923 100644 --- a/cmake/Modules/FindNETCDF_Fortran.cmake +++ b/cmake/Modules/FindNETCDF_Fortran.cmake @@ -11,14 +11,18 @@ # Tries to find the cmake config files first. Otherwise, try to find the libraries and headers by hand IF (NOT netCDF-Fortran_DIR) - IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") - FILE(GLOB LIBDIRS "C:/Program Files*/NC4F") - LIST(SORT LIBDIRS) - LIST(GET LIBDIRS -1 LIBPREFIX) - SET(netCDF-Fortran_DIR "${LIBPREFIX}/lib/cmake/netCDF" CACHE PATH "Location of provided netCDF-FortranConfig.cmake file") - ELSE() - SET(netCDF-Fortran_DIR "/usr/local/lib/cmake/netCDF" CACHE PATH "Location of provided netCDF-FortranConfig.cmake file") - ENDIF () + IF (DEFINED ENV{NETCDF_FORTRAN_DIR}) + SET(netCDF-Fortran_DIR "$ENV{NETCDF_FORTRAN_DIR}" CACHE PATH "Location of provided netCDF-FortranConfig.cmake file") + ELSE() + IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") + FILE(GLOB LIBDIRS "C:/Program Files*/NC4F") + LIST(SORT LIBDIRS) + LIST(GET LIBDIRS -1 LIBPREFIX) + SET(netCDF-Fortran_DIR "${LIBPREFIX}/lib/cmake/netCDF" CACHE PATH "Location of provided netCDF-FortranConfig.cmake file") + ELSE() + SET(netCDF-Fortran_DIR "/usr/local/lib/cmake/netCDF" CACHE PATH "Location of provided netCDF-FortranConfig.cmake file") + ENDIF () + ENDIF() ENDIF() MESSAGE(STATUS "Looking for netCDF-FortranConfig.cmake in ${netCDF-Fortran_DIR}") diff --git a/cmake/Modules/SetCompileFlag.cmake b/cmake/Modules/SetCompileFlag.cmake index f5644e266..72160fe63 100644 --- a/cmake/Modules/SetCompileFlag.cmake +++ b/cmake/Modules/SetCompileFlag.cmake @@ -40,23 +40,6 @@ INCLUDE(${CMAKE_ROOT}/Modules/CheckFortranCompilerFlag.cmake) FUNCTION(SET_COMPILE_FLAG FLAGVAR FLAGVAL LANG) - # Do some up front setup if Fortran - IF(LANG STREQUAL "Fortran") - # Create a list of error messages from compilers - SET(FAIL_REGEX - "ignoring unknown option" # Intel - "invalid argument" # Intel - "not supported" # Intel ifx - "unrecognized .*option" # GNU - "[Uu]nknown switch" # Portland Group - "ignoring unknown option" # MSVC - "warning D9002" # MSVC, any lang - "[Uu]nknown option" # HP - "[Ww]arning: [Oo]ption" # SunPro - "command option .* is not recognized" # XL - ) - ENDIF(LANG STREQUAL "Fortran") - # Make a variable holding the flags. Filter out REQUIRED if it is there SET(FLAG_REQUIRED FALSE) SET(FLAG_FOUND FALSE) diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 4c5659c79..83bf8ac5d 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -338,7 +338,7 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) Fortran "-check all" # Intel ) SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" - C "-check=conversions,stack,uninit" # Intel + C "-fcheck=conversions,stack,uninit" # Intel ) # Initializes matrices/arrays with NaN values SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" @@ -565,9 +565,7 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") ) # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-mkl=cluster" - "-mkl" - "-qmkl=cluster" + Fortran "-qmkl=cluster" "-qmkl" ) # Enables additional interprocedural optimizations for a single file compilation diff --git a/environment.yml b/environment.yml index 2ecab5d60..fd5ff0316 100644 --- a/environment.yml +++ b/environment.yml @@ -5,7 +5,7 @@ channels: - defaults dependencies: - - python>=3.8 + - python>=3.9 - numpy>=1.24.3 - scipy>=1.10.1 - xarray>=2022.11.0 diff --git a/pyproject.toml b/pyproject.toml index da9638d5a..6981cdee9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "swiftest" -version = "2024.1.0" +version = "2024.2.0" authors=[ {name = 'David A. Minton', email='daminton@purdue.edu'}, {name = 'Carlisle Wishard'}, @@ -112,7 +112,7 @@ CPP="/usr/bin/cpp" AR="/usr/bin/ar" NM="/usr/bin/nm" RANLIB="/usr/bin/ranlib" -netCDF-Fortran_DIR="${PREFIX}/lib/cmake/netCDF" +NETCDF_FORTRAN_DIR="${PREFIX}/lib/cmake/netCDF" [tool.cibuildwheel.macos] before-all = [ @@ -133,7 +133,7 @@ HDF5_INCLUDE_DIR="${HDF5_ROOT}/include" HDF5_PLUGIN_PATH="${HDF5_LIBDIR}/plugin" LD_LIBRARY_PATH="${PREFIX}/lib:/project/lib:${HDF5_LIBDIR}" CPATH="${PREFIX}/include:/project/include:${HDF5_INCLUDE_DIR}" -netCDF-Fortran_DIR="${PREFIX}/lib/cmake/netCDF" +NETCDF_FORTRAN_DIR="${PREFIX}/lib/cmake/netCDF" HDF5_DIR="${HDF5_ROOT}/cmake" SHTOOLS_HOME="${PREFIX}" PATH="${HDF5_ROOT}/bin:${PATH}" diff --git a/src/globals/globals_module.f90 b/src/globals/globals_module.f90 index ff8c91429..c17d6a2eb 100644 --- a/src/globals/globals_module.f90 +++ b/src/globals/globals_module.f90 @@ -48,7 +48,7 @@ module globals integer(I4B), parameter :: UPPERCASE_OFFSET = iachar('A') - iachar('a') !! ASCII character set parameter for lower to upper !! conversion - offset between upper and lower - character(*), parameter :: VERSION = "2024.1.0" !! Swiftest version + character(*), parameter :: VERSION = "2024.2.0" !! Swiftest version !> Symbolic name for integrator types character(*), parameter :: UNKNOWN_INTEGRATOR = "UKNOWN INTEGRATOR" diff --git a/version.txt b/version.txt index f96d3c435..032892e0c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2024.1.0 \ No newline at end of file +2024.2.0 \ No newline at end of file From ceba718a08508f582e58899feb2a4b3ef3f465ef Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 14:36:02 -0500 Subject: [PATCH 173/324] Updated more of the build scripts to get debug mode working --- CMakeLists.txt | 2 ++ SHTOOLS | 2 +- buildscripts/build_negishi.sh | 4 ++-- buildscripts/install_editable_debug.sh | 30 -------------------------- cmake/Modules/SetSwiftestFlags.cmake | 6 ++++++ 5 files changed, 11 insertions(+), 33 deletions(-) delete mode 100755 buildscripts/install_editable_debug.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 5feb7155e..09db2a050 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ ELSE() SET(INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) SET(INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) ENDIF () + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Have the .mod files placed in the include folder SET(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) diff --git a/SHTOOLS b/SHTOOLS index f50f58a9e..8b74bb7a2 160000 --- a/SHTOOLS +++ b/SHTOOLS @@ -1 +1 @@ -Subproject commit f50f58a9e0cdadfdd100f7ebf00847813f960d77 +Subproject commit 8b74bb7a27b7dab588893ab368c86ab4d735f333 diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index 31a555de9..3d0f12994 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -20,7 +20,7 @@ module load netcdf-fortran/intel-oneapi/4.6.1 module load shtools/intel-oneapi/4.11.10 cmake -P distclean.cmake pip install --config-settings=editable.rebuild=true \ - --config-settings=build-dir="build/{wheel_tag}" \ + --config-settings=build-dir="build" \ --config-settings=cmake.build-type="${BUILD_TYPE}" \ --config-settings=cmake.args="-DUSE_SIMD=ON" \ --config-settings=cmake.args="-DUSE_OPENMP=ON" \ @@ -31,4 +31,4 @@ pip install --config-settings=editable.rebuild=true \ -ve . -LD_LIBRARY_PATH=$(realpath ${ROOT_DIR}/build/*/bin):$LD_LIBRARY_PATH \ No newline at end of file +LD_LIBRARY_PATH=$(realpath ${ROOT_DIR}/build/bin):$LD_LIBRARY_PATH \ No newline at end of file diff --git a/buildscripts/install_editable_debug.sh b/buildscripts/install_editable_debug.sh deleted file mode 100755 index fb600a58a..000000000 --- a/buildscripts/install_editable_debug.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/zsh -# installs an editable (local) package in debug mode -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -VENV_DIR=${ROOT_DIR}/venv -cd ${ROOT_DIR} - -# Create the virtual environment if it doesn't exist -if [ ! -d "${VENV_DIR}" ]; then - python3 -m venv ${VENV_DIR} -fi - -# Activate the virtual environment only if it's not already active -if [ -z "${VIRTUAL_ENV}" ]; then - . ${VENV_DIR}/bin/activate -fi - -python3 -m pip install --upgrade pip -pip install scikit-build-core pyproject-metadata pathspec ninja cython cmake ffmpeg-python -pip install --config-settings=editable.rebuild=true \ - --config-settings=build-dir="build/{wheel_tag}" \ - --config-settings=cmake.build-type="Debug" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --no-build-isolation \ - -ve . -mkdir -p $HOME/.local/lib -LIBFILE=$(realpath ${ROOT_DIR}/build/*/bin/*swiftest.*) -ln -fs $LIBFILE $HOME/.local/lib diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 83bf8ac5d..638c7aff7 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -309,6 +309,12 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) Fortran "/Qopt-prefetch-" # Intel Windows ) ELSE () + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran REQUIRED "-pg -g3" + ) + SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" + C REQUIRED "-g3" + ) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran REQUIRED "-O0" # All compilers not on Windows ) From d3d50378ccdae298da5639b49cdf19a11c878b29 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 14:56:45 -0500 Subject: [PATCH 174/324] Updated the scikit-build-core options to place compiled files into the correct locations --- CMakeLists.txt | 6 +++--- buildscripts/build_negishi.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09db2a050..ba9309c1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,9 +36,9 @@ ELSE() INCLUDE(GNUInstallDirs) IF (SKBUILD) - SET(INSTALL_BINDIR ${SKBUILD_PLATLIB_DIR}/${SKBUILD_PROJECT_NAME}) - SET(INSTALL_LIBDIR ${SKBUILD_PLATLIB_DIR}/${SKBUILD_PROJECT_NAME}) - SET(INSTALL_INCLUDEDIR ${INSTALL_LIBDIR}) + SET(INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) + SET(INSTALL_LIBDIR ${SKBUILD_DATA_DIR}/lib) + SET(INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) IF (APPLE) SET(CMAKE_INSTALL_RPATH "@loader_path") ELSEIF (LINUX) diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index 3d0f12994..4624283b8 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -27,6 +27,7 @@ pip install --config-settings=editable.rebuild=true \ --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ + --config-settings=install.strip=false \ --no-build-isolation \ -ve . From 7920d41bf6c12c2d72924bdc9ab01f1c1a9496ea Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 15:06:11 -0500 Subject: [PATCH 175/324] Fixed the location of the CYthon binding file upon install --- CMakeLists.txt | 20 +++++++++++--------- swiftest/CMakeLists.txt | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba9309c1c..cbbdb3690 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,17 +34,27 @@ ELSE() OPTION(USE_SIMD "Use SIMD vectorization" ON) OPTION(BUILD_SHARED_LIBS "Build using shared libraries" ON) + # Define the paths to the source code and python files + SET(SRC "${CMAKE_SOURCE_DIR}/src") + SET(PY "${CMAKE_SOURCE_DIR}/swiftest") + + # Make sure paths are correct for Unix or Windows style + FILE(TO_CMAKE_PATH ${SRC} SRC) + FILE(TO_CMAKE_PATH ${PY} PY) + INCLUDE(GNUInstallDirs) IF (SKBUILD) - SET(INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) + SET(INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) SET(INSTALL_LIBDIR ${SKBUILD_DATA_DIR}/lib) SET(INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) + SET(INSTALL_PYPROJ ${SKBUILD_PLATLIB_DIR}/${SKBUILD_PROJECT_NAME}) IF (APPLE) SET(CMAKE_INSTALL_RPATH "@loader_path") ELSEIF (LINUX) SET(CMAKE_INSTALL_RPATH $ORIGIN) ENDIF () ELSE () + SET(INSTALL_PYPROJ ${PY}) SET(INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR}) SET(INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) SET(INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) @@ -89,9 +99,6 @@ ELSE() FIND_PACKAGE(Python COMPONENTS Interpreter Development.Module REQUIRED) - SET(SRC "${CMAKE_SOURCE_DIR}/src") - SET(PY "${CMAKE_SOURCE_DIR}/swiftest") - ##################################### # Tell how to install this executable ##################################### @@ -103,11 +110,6 @@ ELSE() SET(CMAKE_INSTALL_PREFIX /usr/local CACHE PATH "Path for install") ENDIF() - - # Make sure paths are correct for Unix or Windows style - FILE(TO_CMAKE_PATH ${SRC} SRC) - FILE(TO_CMAKE_PATH ${PY} PY) - # Set the name of the swiftest library SET(SWIFTEST_LIBRARY ${SKBUILD_PROJECT_NAME}) diff --git a/swiftest/CMakeLists.txt b/swiftest/CMakeLists.txt index ae6ef5247..579634562 100644 --- a/swiftest/CMakeLists.txt +++ b/swiftest/CMakeLists.txt @@ -46,4 +46,4 @@ ENDIF () TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_BINDINGS} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # Define the install locations -INSTALL(TARGETS ${SWIFTEST_BINDINGS} LIBRARY DESTINATION ${INSTALL_LIBDIR}) \ No newline at end of file +INSTALL(TARGETS ${SWIFTEST_BINDINGS} LIBRARY DESTINATION ${INSTALL_PYPROJ}) \ No newline at end of file From c0d84893c1e423a59aa361d3b6a926b40e99889e Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 15:08:13 -0500 Subject: [PATCH 176/324] Removed the rebuild call --- buildscripts/build_negishi.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index 4624283b8..ab25a49eb 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -19,8 +19,7 @@ module load conda-env/mintongroup-py3.9.13 module load netcdf-fortran/intel-oneapi/4.6.1 module load shtools/intel-oneapi/4.11.10 cmake -P distclean.cmake -pip install --config-settings=editable.rebuild=true \ - --config-settings=build-dir="build" \ +pip install --config-settings=build-dir="build" \ --config-settings=cmake.build-type="${BUILD_TYPE}" \ --config-settings=cmake.args="-DUSE_SIMD=ON" \ --config-settings=cmake.args="-DUSE_OPENMP=ON" \ From 8b1f16ca12b5dc45e713e5c8b3f6c8ba00954c40 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 15:09:21 -0500 Subject: [PATCH 177/324] Removed unecessary update of LD_LIBARY_PATH --- buildscripts/build_negishi.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index ab25a49eb..ff8a9c9e5 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -29,6 +29,3 @@ pip install --config-settings=build-dir="build" \ --config-settings=install.strip=false \ --no-build-isolation \ -ve . - - -LD_LIBRARY_PATH=$(realpath ${ROOT_DIR}/build/bin):$LD_LIBRARY_PATH \ No newline at end of file From 415eb69959772a394d5ccc30998a58b7b295ac66 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 18:15:25 -0500 Subject: [PATCH 178/324] Fixed what ever was causing the source code to not be found in debug mode --- .gitignore | 6 ++---- CMakeLists.txt | 4 +--- buildscripts/build_negishi.sh | 29 ++++++++++++++++++---------- cmake/Modules/SetSwiftestFlags.cmake | 6 ------ distclean.cmake | 1 + src/CMakeLists.txt | 4 ++-- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 8b992dffc..67541a087 100644 --- a/.gitignore +++ b/.gitignore @@ -67,12 +67,10 @@ docs/_static/fortran_docs/*/** !environment.yml !.dockerignore +swiftest/_bindings.cpython* bin/ build/* -hdf5-* -netcdf-c-* -netcdf-fortran-* -zlib-* +lib* actions-runner* diff --git a/CMakeLists.txt b/CMakeLists.txt index cbbdb3690..fa83859b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ ELSE() # Define the paths to the source code and python files SET(SRC "${CMAKE_SOURCE_DIR}/src") SET(PY "${CMAKE_SOURCE_DIR}/swiftest") - + MESSAGE(STATUS "CMAKE_Fortran_PREPROCESS_SOURCE: ${CMAKE_Fortran_PREPROCESS_SOURCE}") # Make sure paths are correct for Unix or Windows style FILE(TO_CMAKE_PATH ${SRC} SRC) FILE(TO_CMAKE_PATH ${PY} PY) @@ -59,8 +59,6 @@ ELSE() SET(INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) SET(INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) ENDIF () - SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Have the .mod files placed in the include folder SET(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index ff8a9c9e5..4fa08d673 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -18,14 +18,23 @@ module load use.own module load conda-env/mintongroup-py3.9.13 module load netcdf-fortran/intel-oneapi/4.6.1 module load shtools/intel-oneapi/4.11.10 +# cmake -P distclean.cmake +# pip install --config-settings=build-dir="build" \ +# --config-settings=cmake.build-type="${BUILD_TYPE}" \ +# --config-settings=cmake.args="-DUSE_SIMD=ON" \ +# --config-settings=cmake.args="-DUSE_OPENMP=ON" \ +# --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ +# --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ +# --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ +# --config-settings=install.strip=false \ +# --no-build-isolation \ +# -ve . + cmake -P distclean.cmake -pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ - --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . +cmake -B ${ROOT_DIR}/build -S . -G Ninja \ + -DMACHINE_CODE_VALUE="CORE-AVX-I" \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_Fortran_COMPILER=mpiifort \ + -DCMAKE_Fortran_FLAGS="-f90=ifort" + +cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v \ No newline at end of file diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 638c7aff7..83bf8ac5d 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -309,12 +309,6 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) Fortran "/Qopt-prefetch-" # Intel Windows ) ELSE () - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran REQUIRED "-pg -g3" - ) - SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" - C REQUIRED "-g3" - ) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran REQUIRED "-O0" # All compilers not on Windows ) diff --git a/distclean.cmake b/distclean.cmake index 683a5db35..5df5a151e 100644 --- a/distclean.cmake +++ b/distclean.cmake @@ -47,6 +47,7 @@ FILE(GLOB_RECURSE CMAKEINSTALL "${TOPDIR}/*cmake_install.cmake" "${TOPDIR}/*install_manifest.txt") FILE(GLOB_RECURSE CMAKETESTFILES "${TOPDIR}/*CTestTestfile.cmake") SET(TOPDIRECTORIES "${TOPDIR}/lib" + "${TOPDIR}/lib64" "${TOPDIR}/libexec" "${TOPDIR}/bin" "${TOPDIR}/include" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c434fcc2c..45bc1257d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,11 +103,12 @@ IF(USE_COARRAY) set(SWIFTEST_src ${SWIFTEST_src} ${COARRAY_FILES} ) ENDIF () +STRING(TOUPPER "${CMAKE_BUILD_TYPE}" BT) + # Turn preprocessor on for all files SET_SOURCE_FILES_PROPERTIES(${SWIFTEST_src} ${DRIVER_src} PROPERTIES Fortran_PREPROCESS ON) #Set strict vs fast math flags -STRING(TOUPPER "${CMAKE_BUILD_TYPE}" BT) IF(BT STREQUAL "RELEASE" OR BT STREQUAL "PROFILE") SET_PROPERTY(SOURCE ${STRICT_MATH_FILES} APPEND_STRING PROPERTY COMPILE_FLAGS "${STRICTMATH_FLAGS}") SET_PROPERTY(SOURCE ${FAST_MATH_FILES} APPEND_STRING PROPERTY COMPILE_FLAGS "${FASTMATH_FLAGS}") @@ -127,7 +128,6 @@ ADD_EXECUTABLE(${SWIFTEST_DRIVER} ${DRIVER_src}) # Add the needed libraries ##################################################### # Create a library from the source files, except the driver - ADD_LIBRARY(${SWIFTEST_LIBRARY} ${SWIFTEST_src}) IF (NOT BUILD_SHARED_LIBS) SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} PROPERTY POSITION_INDEPENDENT_CODE) From 9d37e11ac2aebee9dea734178a9e99378bac38f4 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 18:19:17 -0500 Subject: [PATCH 179/324] Fixed it so that the release mode version generates the Python install, while the debug version does not --- buildscripts/build_negishi.sh | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index 4fa08d673..588ded136 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -18,23 +18,26 @@ module load use.own module load conda-env/mintongroup-py3.9.13 module load netcdf-fortran/intel-oneapi/4.6.1 module load shtools/intel-oneapi/4.11.10 -# cmake -P distclean.cmake -# pip install --config-settings=build-dir="build" \ -# --config-settings=cmake.build-type="${BUILD_TYPE}" \ -# --config-settings=cmake.args="-DUSE_SIMD=ON" \ -# --config-settings=cmake.args="-DUSE_OPENMP=ON" \ -# --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ -# --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ -# --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ -# --config-settings=install.strip=false \ -# --no-build-isolation \ -# -ve . - cmake -P distclean.cmake -cmake -B ${ROOT_DIR}/build -S . -G Ninja \ +if [[ BUILD_TYPE == "Release" ]]; then + pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ + --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . +else + pip uninstall swiftest -y + cmake -P distclean.cmake + cmake -B ${ROOT_DIR}/build -S . -G Ninja \ -DMACHINE_CODE_VALUE="CORE-AVX-I" \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DCMAKE_Fortran_COMPILER=mpiifort \ -DCMAKE_Fortran_FLAGS="-f90=ifort" -cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v \ No newline at end of file + cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v +fi \ No newline at end of file From c64e9e2b63891b65293ac065cdfec6d66e8538ab Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 18:21:39 -0500 Subject: [PATCH 180/324] Updated machine code for release mode --- buildscripts/build_negishi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi.sh index 588ded136..5b1325e70 100755 --- a/buildscripts/build_negishi.sh +++ b/buildscripts/build_negishi.sh @@ -26,7 +26,7 @@ if [[ BUILD_TYPE == "Release" ]]; then --config-settings=cmake.args="-DUSE_OPENMP=ON" \ --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"CORE-AVX-I\" " \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ --config-settings=install.strip=false \ --no-build-isolation \ -ve . @@ -34,7 +34,7 @@ else pip uninstall swiftest -y cmake -P distclean.cmake cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DMACHINE_CODE_VALUE="CORE-AVX-I" \ + -DMACHINE_CODE_VALUE="SSE2" \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DCMAKE_Fortran_COMPILER=mpiifort \ -DCMAKE_Fortran_FLAGS="-f90=ifort" From e25aaad8c8fb7f1d166410d8a37f0ca1ac53269e Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 13 Feb 2024 20:11:54 -0500 Subject: [PATCH 181/324] Added an intel and gnu version of the build scripts --- buildscripts/build_negishi_gnu.sh | 39 +++++++++++++++++++ ...uild_negishi.sh => build_negishi_intel.sh} | 0 buildscripts/get_platform.sh | 18 +++++---- cmake/Modules/SetSwiftestFlags.cmake | 14 ++----- 4 files changed, 54 insertions(+), 17 deletions(-) create mode 100755 buildscripts/build_negishi_gnu.sh rename buildscripts/{build_negishi.sh => build_negishi_intel.sh} (100%) diff --git a/buildscripts/build_negishi_gnu.sh b/buildscripts/build_negishi_gnu.sh new file mode 100755 index 000000000..fb522bd38 --- /dev/null +++ b/buildscripts/build_negishi_gnu.sh @@ -0,0 +1,39 @@ +#!/bin/zsh -l +# installs an editable (local) package in release mode on Negishi +# This is a convenience script for Kaustub + +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +cd ${ROOT_DIR} +BUILD_TYPE=${1:-"Release"} + +module purge +module use /depot/daminton/etc/modules +module load use.own +module load conda-env/mintongroup-py3.9.13 +module load gcc/12.2.0 +module load hdf5/1.13.2 +module load netcdf-c/4.9.0 +module load netcdf-fortran/4.6.0 +module load shtools/gcc/4.11.10 +cmake -P distclean.cmake +if [[ BUILD_TYPE == "Release" ]]; then + pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . +else + pip uninstall swiftest -y + cmake -P distclean.cmake + cmake -B ${ROOT_DIR}/build -S . -G Ninja \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_Fortran_COMPILER=gfortran + + cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v +fi \ No newline at end of file diff --git a/buildscripts/build_negishi.sh b/buildscripts/build_negishi_intel.sh similarity index 100% rename from buildscripts/build_negishi.sh rename to buildscripts/build_negishi_intel.sh diff --git a/buildscripts/get_platform.sh b/buildscripts/get_platform.sh index 2455d7f29..6aaaf21bf 100755 --- a/buildscripts/get_platform.sh +++ b/buildscripts/get_platform.sh @@ -46,17 +46,21 @@ esac case $OS in Linux) # Currently ifx support is not great - # if command -v ifx >/dev/null 2>&1; then - # OS="Linux-ifx" - - if command -v ifort >/dev/null 2>&1; then + case $FC in + *ifx) + OS="Linux-ifx" + ;; + *ifort) OS="Linux-ifort" - elif command -v gfortran >/dev/null 2>&1; then + ;; + *gfortran) OS="Linux-gnu" - else + ;; + *) echo "No Fortran compiler found on Linux" exit 1 - fi + :: + esac ;; Darwin) OS="MacOSX" diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 83bf8ac5d..2f1342a7f 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -159,6 +159,9 @@ IF (NOT BUILD_SHARED_LIBS AND NOT WINOPT) Fortran "-static-libquadmath" ) ENDIF () + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + Fortran "-Wl,--verbose" + ) IF (USE_OPENMP) SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" Fortran "-lomp" @@ -419,16 +422,7 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran "-fbacktrace" # GNU (gfortran) ) - # Sanitize - IF (NOT APPLE) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fsanitize=address, undefined" # Gnu - ) - SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" - C "-fsanitize=address, undefined" # Gnu - ) - ENDIF() - # Check everything + # # Check everything SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran "-fcheck=all" # GNU ) From b8cefda520cb78e2173f699c0023a8339530aa4f Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 14 Feb 2024 09:40:54 -0500 Subject: [PATCH 182/324] Removed unneeded flag --- cmake/Modules/SetSwiftestFlags.cmake | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 2f1342a7f..41472fa4c 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -159,9 +159,6 @@ IF (NOT BUILD_SHARED_LIBS AND NOT WINOPT) Fortran "-static-libquadmath" ) ENDIF () - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-Wl,--verbose" - ) IF (USE_OPENMP) SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" Fortran "-lomp" From 653c544a4dd37a9eb77f90a18a49bbef3af1d9fc Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 14 Feb 2024 09:56:03 -0500 Subject: [PATCH 183/324] Updated the negishi build script with new name of shtools module --- buildscripts/build_negishi_gnu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/build_negishi_gnu.sh b/buildscripts/build_negishi_gnu.sh index fb522bd38..ff5b285d4 100755 --- a/buildscripts/build_negishi_gnu.sh +++ b/buildscripts/build_negishi_gnu.sh @@ -16,7 +16,7 @@ module load gcc/12.2.0 module load hdf5/1.13.2 module load netcdf-c/4.9.0 module load netcdf-fortran/4.6.0 -module load shtools/gcc/4.11.10 +module load shtools/gcc12.2.0/4.11.10 cmake -P distclean.cmake if [[ BUILD_TYPE == "Release" ]]; then pip install --config-settings=build-dir="build" \ From 04be3299c7f11db9c37fb8c337da236ec70cd900 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 14 Feb 2024 10:03:38 -0500 Subject: [PATCH 184/324] Updated build scripts for bell (not yet tested) --- buildscripts/build_bell_gnu.sh | 39 +++++++++++++++++++++++++++ buildscripts/build_bell_intel.sh | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100755 buildscripts/build_bell_gnu.sh create mode 100755 buildscripts/build_bell_intel.sh diff --git a/buildscripts/build_bell_gnu.sh b/buildscripts/build_bell_gnu.sh new file mode 100755 index 000000000..e9bece5ca --- /dev/null +++ b/buildscripts/build_bell_gnu.sh @@ -0,0 +1,39 @@ +#!/bin/zsh -l +# installs an editable (local) package in release mode on Negishi +# This is a convenience script for Kaustub + +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +cd ${ROOT_DIR} +BUILD_TYPE=${1:-"Release"} + +module purge +module use /depot/daminton/etc/modules +module load use.own +module load conda-env/mintongroup-py3.9.13 +module load gcc/10.2.0 +module load hdf5/1.10.6 +module load netcdf-c/4.4.4 +module load netcdf-fortran/4.5.3 +module load shtools/gcc10.2.0/4.11.10 +cmake -P distclean.cmake +if [[ BUILD_TYPE == "Release" ]]; then + pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . +else + pip uninstall swiftest -y + cmake -P distclean.cmake + cmake -B ${ROOT_DIR}/build -S . -G Ninja \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_Fortran_COMPILER=gfortran + + cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v +fi \ No newline at end of file diff --git a/buildscripts/build_bell_intel.sh b/buildscripts/build_bell_intel.sh new file mode 100755 index 000000000..e99ae9e60 --- /dev/null +++ b/buildscripts/build_bell_intel.sh @@ -0,0 +1,45 @@ +#!/bin/zsh -l +# installs an editable (local) package in release mode on Negishi +# This is a convenience script for Kaustub + +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +cd ${ROOT_DIR} +BUILD_TYPE=${1:-"Release"} + +module purge +module load intel/19.0.5.281 +module load intel-mkl/2019.5.281 +module load impi/2019.5.281 +source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 +module use /depot/daminton/etc/modules +module load use.own +module load conda-env/mintongroup-py3.9.13 +module load hdf5/1.10.6 +module load netcdf-c/4.4.4 +module load netcdf-fortran/4.5.3 +module load shtools/intel19.0.5.281/4.11.10 +cmake -P distclean.cmake +if [[ BUILD_TYPE == "Release" ]]; then + pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ + --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . +else + pip uninstall swiftest -y + cmake -P distclean.cmake + cmake -B ${ROOT_DIR}/build -S . -G Ninja \ + -DMACHINE_CODE_VALUE="SSE2" \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_Fortran_COMPILER=mpiifort \ + -DCMAKE_Fortran_FLAGS="-f90=ifort" + + cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v +fi \ No newline at end of file From 750575a808b537aadf4944440d7b27a8f637f685 Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 14 Feb 2024 14:10:02 -0500 Subject: [PATCH 185/324] Updated SHTOOLS --- SHTOOLS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHTOOLS b/SHTOOLS index 8b74bb7a2..aa6767f05 160000 --- a/SHTOOLS +++ b/SHTOOLS @@ -1 +1 @@ -Subproject commit 8b74bb7a27b7dab588893ab368c86ab4d735f333 +Subproject commit aa6767f0560e66c269473904eba978ef6e3713c2 From 9de6ca81287e81345ed2f60701c7248229d39b3c Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 14 Feb 2024 16:08:26 -0500 Subject: [PATCH 186/324] Updated commit tag in SHTOOLS submodule --- SHTOOLS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHTOOLS b/SHTOOLS index aa6767f05..8b74bb7a2 160000 --- a/SHTOOLS +++ b/SHTOOLS @@ -1 +1 @@ -Subproject commit aa6767f0560e66c269473904eba978ef6e3713c2 +Subproject commit 8b74bb7a27b7dab588893ab368c86ab4d735f333 From 9647c1aec304fb4b944a337853ca627a877e57ae Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 14 Feb 2024 23:57:11 -0500 Subject: [PATCH 187/324] Updated build scripts for negishi --- buildscripts/build_negishi_gnu.sh | 2 +- buildscripts/build_negishi_intel.sh | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/buildscripts/build_negishi_gnu.sh b/buildscripts/build_negishi_gnu.sh index ff5b285d4..3eebe7dff 100755 --- a/buildscripts/build_negishi_gnu.sh +++ b/buildscripts/build_negishi_gnu.sh @@ -16,7 +16,7 @@ module load gcc/12.2.0 module load hdf5/1.13.2 module load netcdf-c/4.9.0 module load netcdf-fortran/4.6.0 -module load shtools/gcc12.2.0/4.11.10 +module load shtools/gcc12/4.11.10 cmake -P distclean.cmake if [[ BUILD_TYPE == "Release" ]]; then pip install --config-settings=build-dir="build" \ diff --git a/buildscripts/build_negishi_intel.sh b/buildscripts/build_negishi_intel.sh index 5b1325e70..5a6f5bd40 100755 --- a/buildscripts/build_negishi_intel.sh +++ b/buildscripts/build_negishi_intel.sh @@ -15,7 +15,12 @@ module load intel-oneapi-mpi/2021.8.0 source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 module use /depot/daminton/etc/modules module load use.own -module load conda-env/mintongroup-py3.9.13 +if [[ BUILD_TYPE == "Release" ]]; then + module load conda-env/mintongroup-py3.9.13 +else + module load cmake/3.24.3 + module load ninja/1.11.1-negishi +fi module load netcdf-fortran/intel-oneapi/4.6.1 module load shtools/intel-oneapi/4.11.10 cmake -P distclean.cmake @@ -31,7 +36,6 @@ if [[ BUILD_TYPE == "Release" ]]; then --no-build-isolation \ -ve . else - pip uninstall swiftest -y cmake -P distclean.cmake cmake -B ${ROOT_DIR}/build -S . -G Ninja \ -DMACHINE_CODE_VALUE="SSE2" \ From 59977aa18c1c108e94e7e8799e695703f4111a62 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 15 Feb 2024 00:41:25 -0500 Subject: [PATCH 188/324] Updated build scripts --- buildscripts/build_bell_gnu.sh | 39 ------------- buildscripts/build_bell_intel.sh | 45 --------------- buildscripts/build_rcac_gnu.sh | 74 +++++++++++++++++++++++++ buildscripts/build_rcac_intel.sh | 82 ++++++++++++++++++++++++++++ cmake/Modules/SetSwiftestFlags.cmake | 14 +++-- environment.yml | 2 + 6 files changed, 167 insertions(+), 89 deletions(-) delete mode 100755 buildscripts/build_bell_gnu.sh delete mode 100755 buildscripts/build_bell_intel.sh create mode 100755 buildscripts/build_rcac_gnu.sh create mode 100755 buildscripts/build_rcac_intel.sh diff --git a/buildscripts/build_bell_gnu.sh b/buildscripts/build_bell_gnu.sh deleted file mode 100755 index e9bece5ca..000000000 --- a/buildscripts/build_bell_gnu.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/zsh -l -# installs an editable (local) package in release mode on Negishi -# This is a convenience script for Kaustub - -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -cd ${ROOT_DIR} -BUILD_TYPE=${1:-"Release"} - -module purge -module use /depot/daminton/etc/modules -module load use.own -module load conda-env/mintongroup-py3.9.13 -module load gcc/10.2.0 -module load hdf5/1.10.6 -module load netcdf-c/4.4.4 -module load netcdf-fortran/4.5.3 -module load shtools/gcc10.2.0/4.11.10 -cmake -P distclean.cmake -if [[ BUILD_TYPE == "Release" ]]; then - pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . -else - pip uninstall swiftest -y - cmake -P distclean.cmake - cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=gfortran - - cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v -fi \ No newline at end of file diff --git a/buildscripts/build_bell_intel.sh b/buildscripts/build_bell_intel.sh deleted file mode 100755 index e99ae9e60..000000000 --- a/buildscripts/build_bell_intel.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/zsh -l -# installs an editable (local) package in release mode on Negishi -# This is a convenience script for Kaustub - -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -cd ${ROOT_DIR} -BUILD_TYPE=${1:-"Release"} - -module purge -module load intel/19.0.5.281 -module load intel-mkl/2019.5.281 -module load impi/2019.5.281 -source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 -module use /depot/daminton/etc/modules -module load use.own -module load conda-env/mintongroup-py3.9.13 -module load hdf5/1.10.6 -module load netcdf-c/4.4.4 -module load netcdf-fortran/4.5.3 -module load shtools/intel19.0.5.281/4.11.10 -cmake -P distclean.cmake -if [[ BUILD_TYPE == "Release" ]]; then - pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ - --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . -else - pip uninstall swiftest -y - cmake -P distclean.cmake - cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DMACHINE_CODE_VALUE="SSE2" \ - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=mpiifort \ - -DCMAKE_Fortran_FLAGS="-f90=ifort" - - cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v -fi \ No newline at end of file diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh new file mode 100755 index 000000000..f0722967a --- /dev/null +++ b/buildscripts/build_rcac_gnu.sh @@ -0,0 +1,74 @@ +#!/bin/zsh -l +# installs an editable (local) package in release mode on Negishi +# This is a convenience script for Kaustub + + + +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +cd ${ROOT_DIR} +BUILD_TYPE=${1:-"Release"} + +MACHINE_NAME=$(uname -n | awk -F. '{ + if ($2 == "negishi" || $2 == "bell") + print $2; + else { + split($1, a, "-"); + if (length(a) > 1) + print a[1]; + else + print "Unknown"; + } +}') + +if [[ $MACHINE_NAME == "bell" ]]; then + module purge + module use /depot/daminton/etc/modules/bell + module load gcc/10.2.0 + module load hdf5/1.10.6 + module load netcdf/4.7.4 + module load netcdf-fortran/4.5.3 + module load shtools/gcc10/4.11.10 + module load cmake/3.20.6 + module load ninja/1.11.1 + if [[ $BUILD_TYPE == "Release" ]]; then + module load use.own + module load conda-env/swiftest-env-py3.8.5 + fi +elif [[ $MACHINE_NAME == "negishi" ]]; then + module purge + module use /depot/daminton/etc/modules/negishi + module load gcc/12.2.0 + module load hdf5/1.13.2 + module load netcdf-c/4.9.0 + module load netcdf-fortran/4.6.0 + module load shtools/gcc12/4.11.10 + module load cmake/3.24.3 + module load ninja/1.11.1 + if [[ $BUILD_TYPE == "Release" ]]; then + module load use.own + module load conda-env/swiftest-env-py3.9.13 + fi +fi + +cmake -P distclean.cmake +if [[ BUILD_TYPE == "Release" ]]; then + pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . +else + pip uninstall swiftest -y + cmake -P distclean.cmake + cmake -B ${ROOT_DIR}/build -S . -G Ninja \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_Fortran_COMPILER=gfortran + + cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v +fi \ No newline at end of file diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh new file mode 100755 index 000000000..cf47122e8 --- /dev/null +++ b/buildscripts/build_rcac_intel.sh @@ -0,0 +1,82 @@ +#!/bin/zsh -l +# installs an editable (local) package on Bell +# This is a convenience script for Kaustub +# To use in Release mode, be sure to create the swiftest-env module first. Using the RCAC tools it's the following commands: +# $ conda env create -f environment.yml +# $ conda-env-mod module -n swiftest-env --jupyter + + +set -a +SCRIPT_DIR=$(realpath $(dirname $0)) +ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +cd ${ROOT_DIR} +BUILD_TYPE=${1:-"Release"} + +MACHINE_NAME=$(uname -n | awk -F. '{ + if ($2 == "negishi" || $2 == "bell") + print $2; + else { + split($1, a, "-"); + if (length(a) > 1) + print a[1]; + else + print "Unknown"; + } +}') + + +if [[ $MACHINE_NAME == "bell" ]]; then + module purge + module use /depot/daminton/etc/modules/bell + module load intel/19.0.5.281 + module load intel-mkl/2019.5.281 + module load impi/2019.5.281 + module load shtools/intel19/4.11.10 + module load cmake/3.20.6 + module load ninja/1.11.1 + module load hdf5/1.10.6 + module load netcdf/4.7.4 + module load netcdf-fortran/4.5.3 + if [[ $BUILD_TYPE == "Release" ]]; then + module load use.own + module load conda-env/swiftest-env-py3.8.5 + fi +elif [[ $MACHINE_NAME == "negishi" ]]; then + module purge + module use /depot/daminton/etc/modules/negishi + module load intel-oneapi-compilers/2023.0.0 + module load intel-oneapi-mkl/2023.0.0 + module load intel-oneapi-mpi/2021.8.0 + source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 + module load netcdf-fortran/intel-oneapi/4.6.1 + module load shtools/intel-oneapi/4.11.10 + module load cmake/3.24.3 + module load ninja/1.11.1 + if [[ $BUILD_TYPE == "Release" ]]; then + module load use.own + module load conda-env/mintongroup-py3.9.13 + fi +fi + + +cmake -P distclean.cmake +if [[ $BUILD_TYPE == "Release" ]]; then + pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ + --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . +else + cmake -B ${ROOT_DIR}/build -S . -G Ninja \ + -DMACHINE_CODE_VALUE="SSE2" \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_Fortran_COMPILER=mpiifort \ + -DCMAKE_Fortran_FLAGS="-f90=ifort" + + cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v +fi \ No newline at end of file diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 41472fa4c..bcd73a0ba 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -162,7 +162,10 @@ IF (NOT BUILD_SHARED_LIBS AND NOT WINOPT) IF (USE_OPENMP) SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" Fortran "-lomp" - "-lgomp" + + ) + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + Fortran "-lgomp" ) ENDIF (USE_OPENMP) ENDIF () @@ -520,8 +523,7 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") ) # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "/Qmkl:cluster" # Intel Windows - "/Qmkl" # Intel Windows + Fortran "/Qmkl" # Intel Windows ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" @@ -556,8 +558,10 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") ) # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-qmkl=cluster" - "-qmkl" + Fortran "-mkl" + ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-qmkl" ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" diff --git a/environment.yml b/environment.yml index fd5ff0316..9c6b1d9b8 100644 --- a/environment.yml +++ b/environment.yml @@ -38,3 +38,5 @@ dependencies: - pip - flake8 - pyshtools + - scikit-build-core + - ipykernel From ee6dd0836e029dd97eae5a58b617b038f7e1c5a2 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 00:43:35 -0500 Subject: [PATCH 189/324] Removed obsolete build scripts --- buildscripts/build_negishi_gnu.sh | 39 ------------------------ buildscripts/build_negishi_intel.sh | 47 ----------------------------- 2 files changed, 86 deletions(-) delete mode 100755 buildscripts/build_negishi_gnu.sh delete mode 100755 buildscripts/build_negishi_intel.sh diff --git a/buildscripts/build_negishi_gnu.sh b/buildscripts/build_negishi_gnu.sh deleted file mode 100755 index 3eebe7dff..000000000 --- a/buildscripts/build_negishi_gnu.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/zsh -l -# installs an editable (local) package in release mode on Negishi -# This is a convenience script for Kaustub - -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -cd ${ROOT_DIR} -BUILD_TYPE=${1:-"Release"} - -module purge -module use /depot/daminton/etc/modules -module load use.own -module load conda-env/mintongroup-py3.9.13 -module load gcc/12.2.0 -module load hdf5/1.13.2 -module load netcdf-c/4.9.0 -module load netcdf-fortran/4.6.0 -module load shtools/gcc12/4.11.10 -cmake -P distclean.cmake -if [[ BUILD_TYPE == "Release" ]]; then - pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . -else - pip uninstall swiftest -y - cmake -P distclean.cmake - cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=gfortran - - cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v -fi \ No newline at end of file diff --git a/buildscripts/build_negishi_intel.sh b/buildscripts/build_negishi_intel.sh deleted file mode 100755 index 5a6f5bd40..000000000 --- a/buildscripts/build_negishi_intel.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/zsh -l -# installs an editable (local) package in release mode on Negishi -# This is a convenience script for Kaustub - -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -cd ${ROOT_DIR} -BUILD_TYPE=${1:-"Release"} - -module purge -module load intel-oneapi-compilers/2023.0.0 -module load intel-oneapi-mkl/2023.0.0 -module load intel-oneapi-mpi/2021.8.0 -source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 -module use /depot/daminton/etc/modules -module load use.own -if [[ BUILD_TYPE == "Release" ]]; then - module load conda-env/mintongroup-py3.9.13 -else - module load cmake/3.24.3 - module load ninja/1.11.1-negishi -fi -module load netcdf-fortran/intel-oneapi/4.6.1 -module load shtools/intel-oneapi/4.11.10 -cmake -P distclean.cmake -if [[ BUILD_TYPE == "Release" ]]; then - pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ - --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . -else - cmake -P distclean.cmake - cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DMACHINE_CODE_VALUE="SSE2" \ - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=mpiifort \ - -DCMAKE_Fortran_FLAGS="-f90=ifort" - - cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v -fi \ No newline at end of file From 9373b2e0b8904a4f4b71b0b0ca80aaf445d3a2ea Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 01:06:44 -0500 Subject: [PATCH 190/324] Updated the build scripts for Negishi --- buildscripts/build_rcac_intel.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index cf47122e8..08e4bae2e 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -37,10 +37,9 @@ if [[ $MACHINE_NAME == "bell" ]]; then module load hdf5/1.10.6 module load netcdf/4.7.4 module load netcdf-fortran/4.5.3 - if [[ $BUILD_TYPE == "Release" ]]; then - module load use.own - module load conda-env/swiftest-env-py3.8.5 - fi + module load use.own + module load conda-env/swiftest-env-py3.8.5 + MACHINE_CODE_VALUE="Host" elif [[ $MACHINE_NAME == "negishi" ]]; then module purge module use /depot/daminton/etc/modules/negishi @@ -52,10 +51,9 @@ elif [[ $MACHINE_NAME == "negishi" ]]; then module load shtools/intel-oneapi/4.11.10 module load cmake/3.24.3 module load ninja/1.11.1 - if [[ $BUILD_TYPE == "Release" ]]; then - module load use.own - module load conda-env/mintongroup-py3.9.13 - fi + module load use.own + module load conda-env/swiftest-env-py3.9.13 + MACHINE_CODE_VALUE="SSE2" fi @@ -67,13 +65,13 @@ if [[ $BUILD_TYPE == "Release" ]]; then --config-settings=cmake.args="-DUSE_OPENMP=ON" \ --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE" \ --config-settings=install.strip=false \ --no-build-isolation \ -ve . else cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DMACHINE_CODE_VALUE="SSE2" \ + -DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DCMAKE_Fortran_COMPILER=mpiifort \ -DCMAKE_Fortran_FLAGS="-f90=ifort" From 78d9d77e5d834e0f13afd2c83f251b596819eb10 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 09:07:29 -0500 Subject: [PATCH 191/324] Replaced OneAPI with v19 in the Intel build scripts on Negishi. Also fixed a bug in the Fortran Cmake that was preventing preprocessor flags being set properly in the library build --- buildscripts/_build_getopts.sh | 4 +++- buildscripts/build_rcac_intel.sh | 21 ++++++++++----------- buildscripts/get_platform.sh | 3 +++ buildscripts/set_compilers.sh | 12 +++++++++--- cmake/Modules/SetSwiftestFlags.cmake | 6 ------ src/CMakeLists.txt | 2 ++ src/swiftest/swiftest_util.f90 | 2 +- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/buildscripts/_build_getopts.sh b/buildscripts/_build_getopts.sh index e98f2fb9a..b2ace2e02 100755 --- a/buildscripts/_build_getopts.sh +++ b/buildscripts/_build_getopts.sh @@ -13,8 +13,10 @@ set -a SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) +echo "Getting the OS and ARCH values" # Get platform and architecture read -r OS ARCH < <($SCRIPT_DIR/get_platform.sh) +echo "Gotem! OS: $OS, ARCH: $ARCH" # Parse arguments USTMT="Usage: ${0} [-d /path/to/dependency/source] [-p /prefix/path] [-m MACOSX_DEPLOYMENT_TARGET]" @@ -55,7 +57,7 @@ DEPENDENCY_DIR=${DEPENDENCY_DIR:-${BUILD_DIR}} case $OS in - Linux-gnu|Linux-ifx|Linux-ifort) + Linux-gnu|Linux-ifx|Linux-ifort|Linux-mpiifort|MacOSX) . ${SCRIPT_DIR}/set_environment_linux.sh ;; MacOSX) diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 08e4bae2e..b12631fce 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -43,14 +43,15 @@ if [[ $MACHINE_NAME == "bell" ]]; then elif [[ $MACHINE_NAME == "negishi" ]]; then module purge module use /depot/daminton/etc/modules/negishi - module load intel-oneapi-compilers/2023.0.0 - module load intel-oneapi-mkl/2023.0.0 - module load intel-oneapi-mpi/2021.8.0 - source ${INTEL_ONEAPI_COMPILERS_HOME}/setvars.sh > /dev/null 2>&1 - module load netcdf-fortran/intel-oneapi/4.6.1 - module load shtools/intel-oneapi/4.11.10 + module load intel/19.1.3.304 + module load intel-mkl/2019.9.304 + module load impi/2019.9.304 + module load shtools/intel19/4.11.10 module load cmake/3.24.3 module load ninja/1.11.1 + module load hdf5/1.13.2 + module load netcdf-c/4.9.0 + module load netcdf-fortran/4.6.0 module load use.own module load conda-env/swiftest-env-py3.9.13 MACHINE_CODE_VALUE="SSE2" @@ -63,18 +64,16 @@ if [[ $BUILD_TYPE == "Release" ]]; then --config-settings=cmake.build-type="${BUILD_TYPE}" \ --config-settings=cmake.args="-DUSE_SIMD=ON" \ --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=mpiifort" \ - --config-settings=cmake.args="-DCMAKE_Fortran_FLAGS=\"-f90=ifort\"" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=${FC}" \ --config-settings=cmake.args="-DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE" \ --config-settings=install.strip=false \ --no-build-isolation \ -ve . else cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE \ + -DMACHINE_CODE_VALUE=${MACHINE_CODE_VALUE} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=mpiifort \ - -DCMAKE_Fortran_FLAGS="-f90=ifort" + -DCMAKE_Fortran_COMPILER=${FC} \ cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v fi \ No newline at end of file diff --git a/buildscripts/get_platform.sh b/buildscripts/get_platform.sh index 6aaaf21bf..70aa0210d 100755 --- a/buildscripts/get_platform.sh +++ b/buildscripts/get_platform.sh @@ -50,6 +50,9 @@ case $OS in *ifx) OS="Linux-ifx" ;; + *mpiifort) + OS="Linux-mpiifort" + ;; *ifort) OS="Linux-ifort" ;; diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index b04b02702..85bfa2762 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -16,7 +16,7 @@ SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) case "$OS" in - Linux-gnu|Linux-ifx|Linux-ifort|MacOSX) + Linux-gnu|Linux-ifx|Linux-ifort|Linux-mpiifort|MacOSX) ;; *) echo "Unknown compiler type: $OS" @@ -42,8 +42,14 @@ case $OS in ;; Linux-ifort) FC=$(command -v ifort) - CC=$(command -v icx) - CXX=$(command -v icpx) + CC=$(command -v icc) + CXX=$(command -v icpc) + CPP=$(command -v cpp) + ;; + Linux-mpiifort) + FC=$(command -v mpiifort) + CC=$(command -v mpiicc) + CXX=$(command -v mpiicpc) CPP=$(command -v cpp) ;; MacOSX) diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index bcd73a0ba..f4be6a6dc 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -340,9 +340,6 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran "-check all" # Intel ) - SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" - C "-fcheck=conversions,stack,uninit" # Intel - ) # Initializes matrices/arrays with NaN values SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran "-init=snan,arrays" # Intel @@ -560,9 +557,6 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-mkl" ) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-qmkl" - ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-ip" # Intel diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 45bc1257d..33612029f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,6 +174,7 @@ end program TestDoConcurrentLoc TRY_COMPILE(DOCONLOC_WORKS ${CMAKE_BINARY_DIR} ${TESTFILE} COMPILE_DEFINITIONS "${CMAKE_Fortran_FLAGS}" OUTPUT_VARIABLE OUTPUT) IF (DOCONLOC_WORKS) MESSAGE(STATUS "DO CONCURRENT supports locality-spec") + TARGET_COMPILE_DEFINITIONS(${SWIFTEST_LIBRARY} PRIVATE -DDOCONLOC) TARGET_COMPILE_DEFINITIONS(${SWIFTEST_DRIVER} PRIVATE -DDOCONLOC) ELSE () MESSAGE(STATUS "DO CONCURRENT does not support locality-spec") @@ -192,6 +193,7 @@ end program TestQuadPrecisionReal TRY_COMPILE(QUADPREC ${CMAKE_BINARY_DIR} ${TESTFILE} COMPILE_DEFINITIONS "${CMAKE_Fortran_FLAGS}" OUTPUT_VARIABLE OUTPUT) IF (QUADPREC) MESSAGE(STATUS "Quad precision real is supported") + TARGET_COMPILE_DEFINITIONS(${SWIFTEST_LIBRARY} PRIVATE -DQUADPREC) TARGET_COMPILE_DEFINITIONS(${SWIFTEST_DRIVER} PRIVATE -DQUADPREC) ELSE () MESSAGE(STATUS "Quad precision real is not supported") diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 7c6ac1964..6b6b00b65 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -1225,7 +1225,7 @@ module subroutine swiftest_util_get_energy_and_momentum_system(self, param) Lcborbit(:) = cb%mass * (cb%rb(:) .cross. cb%vb(:)) #ifdef DOCONLOC - do concurrent (i = 1:npl, pl%lmask(i)) shared(pl,Lplorbit,kepl) local(h) + do concurrent (i = 1:npl, pl%lmask(i)) shared(pl,Lplorbit,kepl,npl) local(h) #else do concurrent (i = 1:npl, pl%lmask(i)) #endif From 314655fa65f5d82c2c80dc91b2f92d9966d697bf Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 10:54:57 -0500 Subject: [PATCH 192/324] Updated build scripts with the new environment module --- buildscripts/build_rcac_gnu.sh | 26 +++++++++++++++++++++----- buildscripts/build_rcac_intel.sh | 23 ++++++++++++++++++----- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index f0722967a..28855e7fe 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -1,8 +1,8 @@ #!/bin/zsh -l -# installs an editable (local) package in release mode on Negishi +# Builds Swiftest on the Purdue RCAC cluster system using the GNU compiler # This is a convenience script for Kaustub - - +# The default build type is Release, in which case the Python package is installed in editable mode. Otherwise, only the Fortran +# library and executables are built, but not installed, so that the user can run them from the build directory. set -a SCRIPT_DIR=$(realpath $(dirname $0)) @@ -10,6 +10,13 @@ ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) cd ${ROOT_DIR} BUILD_TYPE=${1:-"Release"} +# Set the OMP_NUM_THREADS variable to be the number of CPUS if this is a compute node, or 1 if this is a frontend or login node +if { hostname | grep -E 'fe|login'; } >/dev/null 2>&1; then + OMP_NUM_THREADS=1 +else + OMP_NUM_THREADS=$(squeue -u $(whoami) | grep $SLURM_JOB_ID | awk -F' ' '{print $6}') +fi + MACHINE_NAME=$(uname -n | awk -F. '{ if ($2 == "negishi" || $2 == "bell") print $2; @@ -22,6 +29,15 @@ MACHINE_NAME=$(uname -n | awk -F. '{ } }') +if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then + print -n "The mintongroup conda environment was detected" +else + print -n "The mintongroup conda environment was not detected. Creating it now..." + /depot/daminton/apps/build_mintongroup_conda.sh +fi + + + if [[ $MACHINE_NAME == "bell" ]]; then module purge module use /depot/daminton/etc/modules/bell @@ -34,7 +50,7 @@ if [[ $MACHINE_NAME == "bell" ]]; then module load ninja/1.11.1 if [[ $BUILD_TYPE == "Release" ]]; then module load use.own - module load conda-env/swiftest-env-py3.8.5 + module load conda-env/mintongroup-py3.8.5 fi elif [[ $MACHINE_NAME == "negishi" ]]; then module purge @@ -48,7 +64,7 @@ elif [[ $MACHINE_NAME == "negishi" ]]; then module load ninja/1.11.1 if [[ $BUILD_TYPE == "Release" ]]; then module load use.own - module load conda-env/swiftest-env-py3.9.13 + module load conda-env/mintongroup-py3.9.13 fi fi diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index b12631fce..58919182f 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -1,10 +1,9 @@ #!/bin/zsh -l # installs an editable (local) package on Bell # This is a convenience script for Kaustub -# To use in Release mode, be sure to create the swiftest-env module first. Using the RCAC tools it's the following commands: +# To use in Release mode, be sure to create the mintongroup module first. Using the RCAC tools it's the following commands: # $ conda env create -f environment.yml -# $ conda-env-mod module -n swiftest-env --jupyter - +# $ conda-env-mod module -n mintongroup --jupyter set -a SCRIPT_DIR=$(realpath $(dirname $0)) @@ -12,6 +11,13 @@ ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) cd ${ROOT_DIR} BUILD_TYPE=${1:-"Release"} +# Set the OMP_NUM_THREADS variable to be the number of CPUS if this is a compute node, or 1 if this is a frontend or login node +if { hostname | grep -E 'fe|login'; } >/dev/null 2>&1; then + OMP_NUM_THREADS=1 +else + OMP_NUM_THREADS=$(squeue -u $(whoami) | grep $SLURM_JOB_ID | awk -F' ' '{print $6}') +fi + MACHINE_NAME=$(uname -n | awk -F. '{ if ($2 == "negishi" || $2 == "bell") print $2; @@ -24,6 +30,13 @@ MACHINE_NAME=$(uname -n | awk -F. '{ } }') +if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then + print -n "The mintongroup conda environment was detected" +else + print -n "The mintongroup conda environment was not detected. Creating it now..." + /depot/daminton/apps/build_mintongroup_conda.sh +fi + if [[ $MACHINE_NAME == "bell" ]]; then module purge @@ -38,7 +51,7 @@ if [[ $MACHINE_NAME == "bell" ]]; then module load netcdf/4.7.4 module load netcdf-fortran/4.5.3 module load use.own - module load conda-env/swiftest-env-py3.8.5 + module load conda-env/mintongroup-py3.8.5 MACHINE_CODE_VALUE="Host" elif [[ $MACHINE_NAME == "negishi" ]]; then module purge @@ -53,7 +66,7 @@ elif [[ $MACHINE_NAME == "negishi" ]]; then module load netcdf-c/4.9.0 module load netcdf-fortran/4.6.0 module load use.own - module load conda-env/swiftest-env-py3.9.13 + module load conda-env/mintongroup-py3.9.13 MACHINE_CODE_VALUE="SSE2" fi From 9d2e7bedb9d07b2551a7639cd3d7ff855b63aa49 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 10:59:28 -0500 Subject: [PATCH 193/324] Updated scripts --- buildscripts/build_rcac_gnu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index 28855e7fe..a41e60266 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -30,9 +30,9 @@ MACHINE_NAME=$(uname -n | awk -F. '{ }') if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then - print -n "The mintongroup conda environment was detected" + echo "The mintongroup conda environment was detected" else - print -n "The mintongroup conda environment was not detected. Creating it now..." + echo "The mintongroup conda environment was not detected. Creating it now..." /depot/daminton/apps/build_mintongroup_conda.sh fi From 679126518b0ad884e7eefb5bb365eba28e09ec33 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 15:28:35 -0500 Subject: [PATCH 194/324] fixed type conversion error that a particular version of gfortran didn't like --- src/swiftest/swiftest_drift.f90 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 41713a2c8..333294b64 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -587,13 +587,18 @@ module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) !! !! initial 0 is set at the x-axis !! phase is stored and calculated in radians. Converted to degrees for output - + implicit none ! Arguments class(swiftest_cb), intent(inout) :: self !! Swiftest central body data structure class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize - self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt * param%TU2S, 2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless + ! Internals + real(DP) :: rotmag + + rotmag = (.mag. self%rot(:)) * dt * param%TU2S + + self%rotphase = MOD(self%rotphase + rotmag, 2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless end subroutine swiftest_drift_cb_rotphase_update From 35c2339fb5df528c3ba07e94e291e94470d6f00a Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 15:43:51 -0500 Subject: [PATCH 195/324] Removed unnecessary unit conversion in the rotation phase update code --- src/swiftest/swiftest_drift.f90 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/swiftest/swiftest_drift.f90 b/src/swiftest/swiftest_drift.f90 index 333294b64..f146e2359 100644 --- a/src/swiftest/swiftest_drift.f90 +++ b/src/swiftest/swiftest_drift.f90 @@ -593,12 +593,7 @@ module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters real(DP), intent(in) :: dt !! Stepsize - ! Internals - real(DP) :: rotmag - - rotmag = (.mag. self%rot(:)) * dt * param%TU2S - - self%rotphase = MOD(self%rotphase + rotmag, 2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless + self%rotphase = MOD(self%rotphase + (.mag. self%rot(:)) * dt , 2 * PI) ! phase angle calculated in radians and then scaled by 2pi to be unitless end subroutine swiftest_drift_cb_rotphase_update From 81657abfe767e2c5858e658e2f2d4e714da3f864 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 16:05:30 -0500 Subject: [PATCH 196/324] Updated the readme to reflect correct units for rotation vectors --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d414b765..c82417c58 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ The **cb.in** includes all central body initial conditions. The str 0.0 ! J2 term, optional, set to 0.0 for a spherical body 0.0 ! J4 term, optional, set to 0.0 for a spherical body 0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only -0.0 0.0 0.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only +0.0 0.0 0.0 ! Rotational vectors in degrees per time unit, optional, leave off if not using, SyMBA only ``` The **pl.in** includes all massive body initial conditions. The structure of the **pl.in** is as follows: @@ -293,7 +293,7 @@ The **pl.in** includes all massive body initial conditions. The str 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly 0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only -1.0 1.0 1.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only +1.0 1.0 1.0 ! Rotational vectors in degrees per time unit, optional, leave off if not using, SyMBA only 2, 0.0, 0.0 0.0 1.0 1.0 1.0 From c7ebbb63ef2fe18ed5d738187c8439ed1d0c89ed Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 16:29:14 -0500 Subject: [PATCH 197/324] Updated base definition so that display_unit has an initial value set to the OUTPUT_UNIT intrinsic --- src/base/base_module.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index 605355802..9cff4cff5 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -118,7 +118,7 @@ module base logical :: lrestart = .false. !! Indicates whether or not this is a restarted run character(NAMELEN) :: display_style !! Style of the output display {["STANDARD"], "COMPACT"}). - integer(I4B) :: display_unit !! File unit number for display (either to stdout or to a log file) + integer(I4B) :: display_unit = OUTPUT_UNIT !! File unit number for display (either to stdout or to a log file) logical :: log_output = .false. !! Logs the output to file instead of displaying it on the terminal ! Future features not implemented or in development From 1c92aef26a0f02985d35b7e7379840974d1acf06 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 15 Feb 2024 16:55:36 -0500 Subject: [PATCH 198/324] Made PIC a propery of the library and driver targets even when shared libraries are built --- src/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 33612029f..1927b61d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,12 +129,10 @@ ADD_EXECUTABLE(${SWIFTEST_DRIVER} ${DRIVER_src}) ##################################################### # Create a library from the source files, except the driver ADD_LIBRARY(${SWIFTEST_LIBRARY} ${SWIFTEST_src}) -IF (NOT BUILD_SHARED_LIBS) - SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} PROPERTY POSITION_INDEPENDENT_CODE) -ENDIF () +SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} PROPERTY POSITION_INDEPENDENT_CODE) TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC netCDF::netcdff HDF5::HDF5) -TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY} netCDF::netcdff HDF5::HDF5) +TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC netCDF::netcdff HDF5::HDF5) IF(USE_OPENMP OR USE_SIMD) TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC SHTOOLS::parallel) @@ -147,6 +145,8 @@ ELSE () TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC SHTOOLS::serial) ENDIF() +TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY}) + IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} APPEND_STRING PROPERTY LINK_FLAGS "/NODEFAULTLIB") ENDIF() From 7a6ae2d87d3a6041e50f099dcc908b352abf42ad Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 16 Feb 2024 11:18:05 -0500 Subject: [PATCH 199/324] Improved handling of library imports to get SHTOOLS build reliably when building wheels. There are still issues with getting all libraries included in the final wheel --- CMakeLists.txt | 11 +++++++---- buildscripts/build_shtools.sh | 4 ++-- buildscripts/set_compilers.sh | 2 +- buildscripts/set_environment_macos.sh | 2 +- cmake/Modules/FindSHTOOLS.cmake | 7 ++++++- cmake/Modules/SetSwiftestFlags.cmake | 14 ++++++++++---- pyproject.toml | 2 +- src/CMakeLists.txt | 1 - src/bindings/bindings_module.f90 | 2 +- swiftest/CMakeLists.txt | 3 --- 10 files changed, 29 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa83859b8..5a273e21f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ ELSE() # Define the paths to the source code and python files SET(SRC "${CMAKE_SOURCE_DIR}/src") SET(PY "${CMAKE_SOURCE_DIR}/swiftest") - MESSAGE(STATUS "CMAKE_Fortran_PREPROCESS_SOURCE: ${CMAKE_Fortran_PREPROCESS_SOURCE}") + # Make sure paths are correct for Unix or Windows style FILE(TO_CMAKE_PATH ${SRC} SRC) FILE(TO_CMAKE_PATH ${PY} PY) @@ -49,9 +49,9 @@ ELSE() SET(INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) SET(INSTALL_PYPROJ ${SKBUILD_PLATLIB_DIR}/${SKBUILD_PROJECT_NAME}) IF (APPLE) - SET(CMAKE_INSTALL_RPATH "@loader_path") + SET(CMAKE_INSTALL_RPATH "@loader_path/../lib") ELSEIF (LINUX) - SET(CMAKE_INSTALL_RPATH $ORIGIN) + SET(CMAKE_INSTALL_RPATH $ORIGIN/../lib) ENDIF () ELSE () SET(INSTALL_PYPROJ ${PY}) @@ -79,7 +79,7 @@ ELSE() # The following section is modified from Numpy f2py documentation IF(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) - MESSAGE(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n") + MESSAGE(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n") ENDIF() FIND_PACKAGE(NETCDF_Fortran REQUIRED) @@ -119,6 +119,9 @@ ELSE() INCLUDE(SetSwiftestFlags) + IF (NOT BUILD_SHARED_LIBS) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + ENDIF() # The source for the SWIFTEST binary and have it placed in the bin folder ADD_SUBDIRECTORY(${SRC} ${CMAKE_INSTALL_BINDIR}) ADD_SUBDIRECTORY(${PY}) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index 5ffe9f029..2e9795275 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -49,8 +49,8 @@ case $FC in ;; *) echo "Everything else" - make F95="${FC}" CXX="${CXX}" fortran - make F95="${FC}" CXX="${CXX}" fortran-mp + make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -m64 -O3 -std=gnu -ffast-math" fortran + make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -m64 -O3 -std=gnu -ffast-math" fortran-mp ;; esac diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index 85bfa2762..d3ce4358d 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -55,7 +55,7 @@ case $OS in MacOSX) FC=${HOMEBREW_PREFIX}/bin/gfortran-12 CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" - FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" + FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" FFLAGS=$FCFLAGS LD_LIBRARY_PATH="" CPATH="" diff --git a/buildscripts/set_environment_macos.sh b/buildscripts/set_environment_macos.sh index 6c255c65c..341d3dea0 100755 --- a/buildscripts/set_environment_macos.sh +++ b/buildscripts/set_environment_macos.sh @@ -12,7 +12,7 @@ CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DI CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include -Xclang -fopenmp" LIBS="-lomp" CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" -FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -fno-underscoring" +FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" FFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype" CXXFLAGS="${CFLAGS}" diff --git a/cmake/Modules/FindSHTOOLS.cmake b/cmake/Modules/FindSHTOOLS.cmake index 5564f786e..dd9b0e581 100644 --- a/cmake/Modules/FindSHTOOLS.cmake +++ b/cmake/Modules/FindSHTOOLS.cmake @@ -11,6 +11,8 @@ FIND_PATH(SHTOOLS_INCLUDE_DIR NAMES shtools.h HINTS ENV SHTOOLS_HOME PATH_SUFFIXES include) FIND_LIBRARY(SHTOOLS_LIBRARY NAMES libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) ADD_LIBRARY(SHTOOLS::serial UNKNOWN IMPORTED PUBLIC) +FIND_PACKAGE(FFTW3 REQUIRED) +FIND_PACKAGE(BLAS REQUIRED) SET_TARGET_PROPERTIES(SHTOOLS::serial PROPERTIES IMPORTED_LOCATION "${SHTOOLS_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${SHTOOLS_INCLUDE_DIR}" @@ -22,8 +24,11 @@ SET_TARGET_PROPERTIES(SHTOOLS::parallel PROPERTIES IMPORTED_LOCATION "${SHTOOLS_LIBRARY_MP}" INTERFACE_INCLUDE_DIRECTORIES "${SHTOOLS_INCLUDE_DIR}" ) - SET(SHTOOLS_FOUND TRUE) + +# These libraries are required +# How do I get them to link to the SHTOOLS library? + MARK_AS_ADVANCED(SHTOOLS_LIBRARY SHTOOLS_LIBRARY_MP SHTOOLS_INCLUDE_DIR) MESSAGE(STATUS "SHTOOLS library: ${SHTOOLS_LIBRARY}") MESSAGE(STATUS "SHTOOLS OpenMP library: ${SHTOOLS_LIBRARY_MP}") diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index f4be6a6dc..f419a886a 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -76,10 +76,6 @@ IF (COMPILER_OPTIONS STREQUAL "GNU") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" Fortran "-ffree-form" # GNU ) - # Don't add underscores in symbols for C-compatability - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-fno-underscoring" # GNU - ) # Compile code assuming that IEEE signaling NaNs may generate user-visible traps during floating-point operations. # Setting this option disables optimizations that may change the number of exceptions visible with signaling NaNs. SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" @@ -93,6 +89,10 @@ IF (COMPILER_OPTIONS STREQUAL "GNU") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" Fortran "-std=f2018" ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-fPIC" + ) + ELSEIF (COMPILER_OPTIONS STREQUAL "Intel") # Disables right margin wrapping in list-directed output IF (WINOPT) @@ -557,6 +557,9 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-mkl" ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-qmkl" + ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-ip" # Intel @@ -572,6 +575,9 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-finline-functions" # GNU ) + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-llapack" + ) ENDIF () ENDIF () diff --git a/pyproject.toml b/pyproject.toml index 6981cdee9..e7b7f442a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,7 +90,7 @@ LDFLAGS="-Wl,-rpath,${ROOT_DIR}/lib -Wl,-no_compact_unwind -L${PREFIX}/lib -L${ CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DIR}/include" CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include" LIBS="-lomp" -FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH} -fno-underscoring" +FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" FFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype -arch ${ARCH}" CXXFLAGS="${CFLAGS}" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1927b61d9..791da694b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,7 +129,6 @@ ADD_EXECUTABLE(${SWIFTEST_DRIVER} ${DRIVER_src}) ##################################################### # Create a library from the source files, except the driver ADD_LIBRARY(${SWIFTEST_LIBRARY} ${SWIFTEST_src}) -SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} PROPERTY POSITION_INDEPENDENT_CODE) TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC netCDF::netcdff HDF5::HDF5) TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC netCDF::netcdff HDF5::HDF5) diff --git a/src/bindings/bindings_module.f90 b/src/bindings/bindings_module.f90 index 9664c87fe..6f27a091a 100644 --- a/src/bindings/bindings_module.f90 +++ b/src/bindings/bindings_module.f90 @@ -29,7 +29,7 @@ subroutine bindings_c2f_string(c_string, f_string) return end subroutine bindings_c2f_string - subroutine bindings_c_driver(c_integrator, c_param_file_name, c_display_style) bind(c) + subroutine bindings_c_driver(c_integrator, c_param_file_name, c_display_style) bind(c, name="bindings_c_driver") implicit none character(kind=c_char), dimension(*), intent(in) :: c_integrator, c_param_file_name, c_display_style character(len=:), allocatable :: integrator, param_file_name, display_style diff --git a/swiftest/CMakeLists.txt b/swiftest/CMakeLists.txt index 579634562..39a52ddea 100644 --- a/swiftest/CMakeLists.txt +++ b/swiftest/CMakeLists.txt @@ -32,9 +32,6 @@ ADD_CUSTOM_COMMAND( PYTHON_ADD_LIBRARY(${SWIFTEST_BINDINGS} MODULE "${CMAKE_CURRENT_BINARY_DIR}/${SWIFTEST_BINDINGS}.c" WITH_SOABI) -IF (NOT BUILD_SHARED_LIBS) - SET_PROPERTY(TARGET ${SWIFTEST_BINDINGS} PROPERTY POSITION_INDEPENDENT_CODE) -ENDIF () TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} PUBLIC ${SWIFTEST_LIBRARY} netCDF::netcdff HDF5::HDF5) IF(USE_OPENMP OR USE_SIMD) From 66150cdcc5ef44d55bc464bc4c27eef62df9c09c Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 16 Feb 2024 11:33:18 -0500 Subject: [PATCH 200/324] Fixed some issues with the build scripts --- buildscripts/_build_getopts.sh | 11 +++-- buildscripts/get_platform.sh | 80 ---------------------------------- buildscripts/set_compilers.sh | 60 ++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 91 deletions(-) delete mode 100755 buildscripts/get_platform.sh diff --git a/buildscripts/_build_getopts.sh b/buildscripts/_build_getopts.sh index b2ace2e02..b218da594 100755 --- a/buildscripts/_build_getopts.sh +++ b/buildscripts/_build_getopts.sh @@ -13,10 +13,9 @@ set -a SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -echo "Getting the OS and ARCH values" # Get platform and architecture -read -r OS ARCH < <($SCRIPT_DIR/get_platform.sh) -echo "Gotem! OS: $OS, ARCH: $ARCH" +OS=$(uname -s) +ARCH=$(uname -m) # Parse arguments USTMT="Usage: ${0} [-d /path/to/dependency/source] [-p /prefix/path] [-m MACOSX_DEPLOYMENT_TARGET]" @@ -57,16 +56,16 @@ DEPENDENCY_DIR=${DEPENDENCY_DIR:-${BUILD_DIR}} case $OS in - Linux-gnu|Linux-ifx|Linux-ifort|Linux-mpiifort|MacOSX) + Linux*) . ${SCRIPT_DIR}/set_environment_linux.sh ;; - MacOSX) + MacOSX|Darwin) . ${SCRIPT_DIR}/set_environment_macos.sh ;; *) printf "Unknown compiler type: ${OS}\n" - echo "Valid options are Linux-gnu, Linux-ifort, Linux-ifx, or MacOSX" + echo "Valid options are Linux, MacOSX, or Darwin" printf $USTMT exit 1 ;; diff --git a/buildscripts/get_platform.sh b/buildscripts/get_platform.sh deleted file mode 100755 index 70aa0210d..000000000 --- a/buildscripts/get_platform.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# This script will determine the platform (OS and architecture) and format them in a way that other scripts can make use of. -# -# The following combinations are valid: -# Linux x86_64 -# Linux aarch64 -# MacOSX x86_64 -# MacOSX arm64 -# -# Copyright 2023 - David Minton -# This file is part of Swiftest. -# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# You should have received a copy of the GNU General Public License along with Swiftest. -# If not, see: https://www.gnu.org/licenses. - - -# Determine the platform and architecture -OS=$(uname -s) -ARCH=$(uname -m) - -case $ARCH in - x86_64) - ;; - amd64) - ARCH="x86_64" - ;; - arm64) - if [ "$OS" = "Linux" ]; then - ARCH="aarch64" - fi - ;; - aarch64) - if [ "$OS" = "Darwin" ]; then - ARCH="arm64" - fi - ;; - *) - echo "Swiftest is currently not configured to build for platform ${OS}-${ARCH}" - exit 1 - ;; -esac - -case $OS in - Linux) - # Currently ifx support is not great - case $FC in - *ifx) - OS="Linux-ifx" - ;; - *mpiifort) - OS="Linux-mpiifort" - ;; - *ifort) - OS="Linux-ifort" - ;; - *gfortran) - OS="Linux-gnu" - ;; - *) - echo "No Fortran compiler found on Linux" - exit 1 - :: - esac - ;; - Darwin) - OS="MacOSX" - ;; - *MSYS*) - OS="Windows" - ;; - *) - echo "Swiftest is currently not configured to build for platform ${OS}-${ARCH}" - exit 1 - ;; -esac - -echo $OS $ARCH diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index d3ce4358d..c2fb07f9f 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -15,17 +15,67 @@ # If not, see: https://www.gnu.org/licenses. SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -case "$OS" in - Linux-gnu|Linux-ifx|Linux-ifort|Linux-mpiifort|MacOSX) + +# Get platform and architecture +OS=$(uname -s) +ARCH=$(uname -m) + +case $ARCH in + x86_64) + ;; + amd64) + ARCH="x86_64" + ;; + arm64) + if [ "$OS" = "Linux" ]; then + ARCH="aarch64" + fi + ;; + aarch64) + if [ "$OS" = "Darwin" ]; then + ARCH="arm64" + fi ;; *) - echo "Unknown compiler type: $OS" - echo "Valid options are Linux-gnu, Linux-ifort, Linux-ifx, or MacOSX" - echo $USTMT + echo "Swiftest is currently not configured to build for platform ${OS}-${ARCH}" + exit 1 + ;; +esac + +case $OS in + Darwin) + OS="MacOSX" + ;; + *MSYS*) + OS="Windows" + ;; + *) + echo "Swiftest is currently not configured to build for platform ${OS}-${ARCH}" exit 1 ;; esac +if [[ $OS == "Linux" ]]; then + # Check if FC is set yet, and if so, use it instead of the default + # Currently ifx support is not great + case $FC in + *ifx) + OS="Linux-ifx" + ;; + *mpiifort) + OS="Linux-mpiifort" + ;; + *ifort) + OS="Linux-ifort" + ;; + *gfortran) + OS="Linux-gnu" + ;; + *) + OS="Linux-gnu" + ;; + esac +fi set -a case $OS in Linux-gnu) From af848841d3253c1751ad1b3a719c2aadc7c962fc Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 16 Feb 2024 12:13:54 -0500 Subject: [PATCH 201/324] Put back the FFTW3 find tool and now link to the BLAS and LAPACK libraries correctly. --- buildscripts/set_environment_macos.sh | 15 +++++++++----- cmake/Modules/FindFFTW3.cmake | 29 +++++++++++++++++++++++++++ cmake/Modules/FindSHTOOLS.cmake | 2 -- cmake/Modules/SetSwiftestFlags.cmake | 14 ------------- src/CMakeLists.txt | 17 ++++++++++++++++ 5 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 cmake/Modules/FindFFTW3.cmake diff --git a/buildscripts/set_environment_macos.sh b/buildscripts/set_environment_macos.sh index 341d3dea0..18805cb62 100755 --- a/buildscripts/set_environment_macos.sh +++ b/buildscripts/set_environment_macos.sh @@ -16,14 +16,19 @@ FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" FFLAGS="${FCFLAGS}" CFLAGS="${FCFLAGS} -Wno-deprecated-non-prototype" CXXFLAGS="${CFLAGS}" -HDF5_ROOT="${PREFIX}" + +NCDIR=${NETCDF_HOME:-"${PREFIX}"} +NFDIR=${NETCDF_FORTRAN_HOME:-"${PREFIX}"} +NETCDF_FORTRAN_HOME="${NFDIR}" +NETCDF_FORTRAN_INCLUDE="${NFDIR}/include" +ZLIB_ROOT=${ZLIB_ROOT:-"${ZLIB_HOME}"} +ZLIB_ROOT=${ZLIB_ROOT:-"${PREFIX}"} +HDF5_ROOT=${HDF5_ROOT:-"${HDF5_HOME}"} +HDF5_ROOT=${HDF5_ROOT:-"${PREFIX}"} HDF5_LIBDIR="${HDF5_ROOT}/lib" HDF5_INCLUDE_DIR="${HDF5_ROOT}/include" HDF5_PLUGIN_PATH="${HDF5_LIBDIR}/plugin" -NCDIR="${PREFIX}" -NFDIR="${PREFIX}" -NETCDF_FORTRAN_HOME="${NFDIR}" -NETCDF_FORTRAN_INCLUDE="${NFDIR}/include" + FC="$(command -v gfortran-12)" F77="${FC}" F95="${FC}" diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake new file mode 100644 index 000000000..ce3bd0dcb --- /dev/null +++ b/cmake/Modules/FindFFTW3.cmake @@ -0,0 +1,29 @@ +# Copyright 2023 - David Minton +# This file is part of Swiftest. +# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with Swiftest. +# If not, see: https://www.gnu.org/licenses. + +# - Finds the FFTW3 library +MESSAGE(STATUS "Looking for FFTW3") +FIND_PATH(FFTW3_INCLUDE_DIR NAMES fftw3.h HINTS ENV FFTW3_HOME PATH_SUFFIXES include) +FIND_LIBRARY(FFTW3_LIBRARY NAMES libfftw3.a HINTS ENV FFTW3_HOME PATH_SUFFIXES lib) + +IF(NOT FFTW3_INCLUDE_DIR OR NOT FFTW3_LIBRARY) + MESSAGE(STATUS "FFTW3 not found") + SET(FFTW3_FOUND FALSE) +ELSE () + MESSAGE(STATUS "FFTW3 found") + SET(FFTW3_FOUND TRUE) + MESSAGE(STATUS "Found FFTW3: ${FFTW3_LIBRARY}") + + ADD_LIBRARY(FFTW3::FFTW3 UNKNOWN IMPORTED PUBLIC) + SET_TARGET_PROPERTIES(FFTW3::FFTW3 PROPERTIES + IMPORTED_LOCATION "${FFTW3_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIR}" + ) +ENDIF() +mark_as_advanced(FFTW3_LIBRARY FFTW3_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/FindSHTOOLS.cmake b/cmake/Modules/FindSHTOOLS.cmake index dd9b0e581..70ea0b633 100644 --- a/cmake/Modules/FindSHTOOLS.cmake +++ b/cmake/Modules/FindSHTOOLS.cmake @@ -11,8 +11,6 @@ FIND_PATH(SHTOOLS_INCLUDE_DIR NAMES shtools.h HINTS ENV SHTOOLS_HOME PATH_SUFFIXES include) FIND_LIBRARY(SHTOOLS_LIBRARY NAMES libSHTOOLS.a HINTS ENV SHTOOLS_HOME PATH_SUFFIXES lib) ADD_LIBRARY(SHTOOLS::serial UNKNOWN IMPORTED PUBLIC) -FIND_PACKAGE(FFTW3 REQUIRED) -FIND_PACKAGE(BLAS REQUIRED) SET_TARGET_PROPERTIES(SHTOOLS::serial PROPERTIES IMPORTED_LOCATION "${SHTOOLS_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${SHTOOLS_INCLUDE_DIR}" diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index f419a886a..9fb7a1faf 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -518,10 +518,6 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "/Qfma" # Intel Windows ) - # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "/Qmkl" # Intel Windows - ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "/Qip" # Intel Windows @@ -553,13 +549,6 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-fma" # Intel ) - # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-mkl" - ) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-qmkl" - ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-ip" # Intel @@ -575,9 +564,6 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" Fortran "-finline-functions" # GNU ) - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-llapack" - ) ENDIF () ENDIF () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 791da694b..fe1f4d9db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,6 +144,23 @@ ELSE () TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC SHTOOLS::serial) ENDIF() +# Add in the BLAS, LAPACK, and FFTW3 libraries +IF (COMPILER_OPTIONS STREQUAL "GNU") + IF (APPLE) + SET(BLA_VENDOR "Apple" CACHE STRING "BLAS vendor") + ELSE () + SET(BLA_VENDOR "OpenBLAS" CACHE STRING "BLAS vendor") + ENDIF () +ELSEIF (COMPILER_OPTIONS STREQUAL "INTEL") + SET(BLA_VENDOR "Intel10_64lp" CACHE STRING "BLAS vendor") +ENDIF() +SET(BLA_STATIC ON) +FIND_PACKAGE(BLAS REQUIRED) +FIND_PACKAGE(LAPACK REQUIRED) +FIND_PACKAGE(FFTW3 REQUIRED) + +TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC BLAS::BLAS LAPACK::LAPACK FFTW3::FFTW3) + TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY}) IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") From 20cb971896bc910a0bc5ebe6dd1a0bba1f186e56 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 16 Feb 2024 12:22:23 -0500 Subject: [PATCH 202/324] Fixed issue in the set_compilers.sh script that was preventing builds from happening on Linux --- buildscripts/set_compilers.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index c2fb07f9f..bbe52a2a0 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -49,10 +49,6 @@ case $OS in *MSYS*) OS="Windows" ;; - *) - echo "Swiftest is currently not configured to build for platform ${OS}-${ARCH}" - exit 1 - ;; esac if [[ $OS == "Linux" ]]; then From fcc50b5927012bb83766ba905dd2a2825454cdb6 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 16 Feb 2024 12:44:33 -0500 Subject: [PATCH 203/324] Updated the build process to use OpenBLAS on Linux --- buildscripts/build_shtools.sh | 4 ++-- pyproject.toml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/buildscripts/build_shtools.sh b/buildscripts/build_shtools.sh index 2e9795275..a20774253 100755 --- a/buildscripts/build_shtools.sh +++ b/buildscripts/build_shtools.sh @@ -49,8 +49,8 @@ case $FC in ;; *) echo "Everything else" - make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -m64 -O3 -std=gnu -ffast-math" fortran - make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -m64 -O3 -std=gnu -ffast-math" fortran-mp + make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -O3 -std=gnu -ffast-math" fortran + make F95="${FC}" CXX="${CXX}" F95FLAGS="-fPIC -O3 -std=gnu -ffast-math" fortran-mp ;; esac diff --git a/pyproject.toml b/pyproject.toml index e7b7f442a..143dafde4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,7 +142,8 @@ CMAKE_INSTALL_LIBDIR="lib" [tool.cibuildwheel.linux] skip = "cp312-* pp* -manylinux_i686* *-musllinux*" before-all = [ - "yum install doxygen libxml2-devel libcurl-devel fftw-devel blas-devel lapack-devel -y", + "yum install epel-release -y", + "yum install doxygen libxml2-devel libcurl-devel fftw-devel openblas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] From 0cf1029ee7d0f24e7c420e9f996c2326c88a5703 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 16 Feb 2024 13:47:34 -0500 Subject: [PATCH 204/324] Added module load fftw3. cmake could not find it unless I manually loaded it. Adding it to the build file as a comment for review --- buildscripts/build_rcac_intel.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 58919182f..57433581f 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -51,6 +51,7 @@ if [[ $MACHINE_NAME == "bell" ]]; then module load netcdf/4.7.4 module load netcdf-fortran/4.5.3 module load use.own + # module load fftw/3.3.8.lua module load conda-env/mintongroup-py3.8.5 MACHINE_CODE_VALUE="Host" elif [[ $MACHINE_NAME == "negishi" ]]; then From 38445eeb6eb573aa5f4b40f6e656272562f7867c Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 16 Feb 2024 14:13:07 -0500 Subject: [PATCH 205/324] changed rot units in the readme to deg/TU --- README_tables/add_body_kwargs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_tables/add_body_kwargs.md b/README_tables/add_body_kwargs.md index 59f52078f..a172cfc5a 100644 --- a/README_tables/add_body_kwargs.md +++ b/README_tables/add_body_kwargs.md @@ -15,7 +15,7 @@ | ```Gmass``` | Gravitational mass value(s) of bodies. Only for massive bodies. Only ```mass``` **OR** ```Gmass``` may be set. | float or array-like of floats | ```radius``` | Radius value(s) of bodies. Only for massive bodies. | float or array-like of floats | ```rhill``` | Hill Radius value(s) of bodies. Only for massive bodies. | float or array-like of floats -| ```rot``` | Rotation rate vector(s) of bodies in degrees/sec. Only for massive bodies. Only used if ```rotation``` is set to ```True```. | (n,3) array-like of floats +| ```rot``` | Rotation rate vector(s) of bodies in degrees/TU. Only for massive bodies. Only used if ```rotation``` is set to ```True```. | (n,3) array-like of floats | ```Ip``` | Principal axes moments of inertia vector(s) of bodies. Only for massive bodies. Only used if ```rotation``` is set to ```True```. | (n,3) array-like of floats | ```J2``` | The unitless value of the spherical harmonic term equal to J2*R^2 where R is the radius of the central body. | float or array-like of floats | ```J4``` | The unitless value of the spherical harmonic term equal to J4*R^4 where R is the radius of the central body. | float or array-like of floats From 88f7b8888277562feb20f48dd29bbb15e882701a Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 17 Feb 2024 07:16:20 -0500 Subject: [PATCH 206/324] Fixed issue that was causing delocate to fail to find libraries while building wheels on Mac --- CMakeLists.txt | 33 ++++++++++++++++++++++++++------- pyproject.toml | 11 ++++++++++- src/CMakeLists.txt | 15 --------------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a273e21f..8174241a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,11 @@ ELSE() CMAKE_POLICY(SET CMP0148 OLD) ENDIF () + # The following section is modified from Numpy f2py documentation + IF(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) + MESSAGE(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n") + ENDIF() + # Set some options the user may choose OPTION(USE_COARRAY "Use Coarray Fortran for parallelization of test particles" OFF) OPTION(USE_OPENMP "Use OpenMP for parallelization" ON) @@ -49,9 +54,9 @@ ELSE() SET(INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) SET(INSTALL_PYPROJ ${SKBUILD_PLATLIB_DIR}/${SKBUILD_PROJECT_NAME}) IF (APPLE) - SET(CMAKE_INSTALL_RPATH "@loader_path/../lib") + SET(CMAKE_INSTALL_RPATH "@loader_path;${CMAKE_BINARY_DIR}/bin") ELSEIF (LINUX) - SET(CMAKE_INSTALL_RPATH $ORIGIN/../lib) + SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib;@ORIGIN") ENDIF () ELSE () SET(INSTALL_PYPROJ ${PY}) @@ -59,6 +64,8 @@ ELSE() SET(INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) SET(INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) ENDIF () + + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Have the .mod files placed in the include folder SET(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) @@ -67,20 +74,32 @@ ELSE() FILE(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules" LOCAL_MODULE_PATH) LIST(APPEND CMAKE_MODULE_PATH ${LOCAL_MODULE_PATH}) + # Add in the external dependency libraries IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") - FIND_PACKAGE(MKL) + FIND_PACKAGE(MKL) # Possibly not needed any more due to BLAS and LAPACK being found ELSEIF (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") SET(COMPILER_OPTIONS "GNU" CACHE STRING "Compiler identified as gfortran") ELSE () MESSAGE(FATAL_ERROR "Compiler ${CMAKE_Fortran_COMPILER_ID} not recognized!") ENDIF () - FIND_PACKAGE(SHTOOLS REQUIRED) - # The following section is modified from Numpy f2py documentation - IF(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) - MESSAGE(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n") + IF (COMPILER_OPTIONS STREQUAL "GNU") + IF (APPLE) + SET(BLA_VENDOR "Apple" CACHE STRING "BLAS vendor") + ELSE () + SET(BLA_VENDOR "OpenBLAS" CACHE STRING "BLAS vendor") + ENDIF () + ELSEIF (COMPILER_OPTIONS STREQUAL "INTEL") + SET(BLA_VENDOR "Intel10_64lp" CACHE STRING "BLAS vendor") ENDIF() + SET(BLA_STATIC ON) + FIND_PACKAGE(BLAS REQUIRED) + FIND_PACKAGE(LAPACK REQUIRED) + FIND_PACKAGE(FFTW3 REQUIRED) + FIND_PACKAGE(SHTOOLS REQUIRED) + + FIND_PACKAGE(NETCDF_Fortran REQUIRED) IF (MSVC) diff --git a/pyproject.toml b/pyproject.toml index 143dafde4..c41016fd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,8 @@ PREFIX="/usr/local" HOMEBREW_PREFIX="$(brew --prefix)" ARCH="$(uname -m)" LD_LIBRARY_PATH="/usr/local/lib:${PREFIX}/lib:${HOMEBREW_PREFIX}/lib" +DYLD_LIBRARY_PATH="${LD_LIBRARY_PATH}" +REPAIR_LIBRARY_PATH="${LD_LIBRARY_PATH}" LDFLAGS="-Wl,-rpath,${ROOT_DIR}/lib -Wl,-no_compact_unwind -L${PREFIX}/lib -L${HOMEBREW_PREFIX}/lib" CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DIR}/include" CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include" @@ -119,6 +121,11 @@ before-all = [ "brew install coreutils pkg-config fftw vecLibFort", "LIBS=\"\" buildscripts/build_dependencies.sh -p ${PREFIX} -d ${HOME}/Downloads -m ${MACOSX_DEPLOYMENT_TARGET}" ] +repair-wheel-command = """\ +DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel \ +--require-archs {delocate_archs} -w {dest_dir} -v {wheel} +""" + [tool.cibuildwheel.linux.environment] @@ -143,7 +150,7 @@ CMAKE_INSTALL_LIBDIR="lib" skip = "cp312-* pp* -manylinux_i686* *-musllinux*" before-all = [ "yum install epel-release -y", - "yum install doxygen libxml2-devel libcurl-devel fftw-devel openblas-devel lapack-devel -y", + "yum install doxygen libxml2-devel libcurl-devel fftw-static openblas-devel lapack-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] @@ -151,3 +158,5 @@ before-all = [ path = "version.txt" location = "source" template = '''${version}''' + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe1f4d9db..985d2ea99 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,21 +144,6 @@ ELSE () TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC SHTOOLS::serial) ENDIF() -# Add in the BLAS, LAPACK, and FFTW3 libraries -IF (COMPILER_OPTIONS STREQUAL "GNU") - IF (APPLE) - SET(BLA_VENDOR "Apple" CACHE STRING "BLAS vendor") - ELSE () - SET(BLA_VENDOR "OpenBLAS" CACHE STRING "BLAS vendor") - ENDIF () -ELSEIF (COMPILER_OPTIONS STREQUAL "INTEL") - SET(BLA_VENDOR "Intel10_64lp" CACHE STRING "BLAS vendor") -ENDIF() -SET(BLA_STATIC ON) -FIND_PACKAGE(BLAS REQUIRED) -FIND_PACKAGE(LAPACK REQUIRED) -FIND_PACKAGE(FFTW3 REQUIRED) - TARGET_LINK_LIBRARIES(${SWIFTEST_LIBRARY} PUBLIC BLAS::BLAS LAPACK::LAPACK FFTW3::FFTW3) TARGET_LINK_LIBRARIES(${SWIFTEST_DRIVER} PUBLIC ${SWIFTEST_LIBRARY}) From 6cfd6d0af922a81fb085a9ab8a621448a00054ef Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 17 Feb 2024 07:29:12 -0500 Subject: [PATCH 207/324] Fixed issue causing libraries to not be found during linux build. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8174241a4..9b50d3d9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ ELSE() IF (APPLE) SET(CMAKE_INSTALL_RPATH "@loader_path;${CMAKE_BINARY_DIR}/bin") ELSEIF (LINUX) - SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib;@ORIGIN") + SET(CMAKE_INSTALL_RPATH "@ORIGIN;${CMAKE_BINARY_DIR}/bin") ENDIF () ELSE () SET(INSTALL_PYPROJ ${PY}) From a4e83796d3face32961beea050242286c598855f Mon Sep 17 00:00:00 2001 From: David A Minton Date: Sat, 17 Feb 2024 10:43:37 -0500 Subject: [PATCH 208/324] Prevent cb%c_lm from being accesed during the file io when it is not allocated --- src/swiftest/swiftest_io.f90 | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index efc0a3791..1e278a337 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2129,27 +2129,25 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") end if - status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) - if (status == NF90_NOERR) then - m_dim_max = size(self%c_lm, 1) - l_dim_max = size(self%c_lm, 2) + if (allocated(self%c_lm)) then + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + m_dim_max = size(self%c_lm, 1) + l_dim_max = size(self%c_lm, 2) ! Populate coordinate values for l and m and export to hdf file - allocate(lm_coords(l_dim_max)) - do i = 0, l_dim_max - 1 - lm_coords(i + 1) = i - end do + allocate(lm_coords(l_dim_max)) + do i = 0, l_dim_max - 1 + lm_coords(i + 1) = i + end do - call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var l_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var m_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1, -1]), "netcdf_io_write_frame_cb nf90_put_var sign_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var l_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var m_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1, -1]), "netcdf_io_write_frame_cb nf90_put_var sign_varid") - ! Write dimension-coordinates to file - - if(.not. allocated(self%c_lm)) then - allocate(self%c_lm(m_dim_max, l_dim_max, 2)) + ! Write dimension-coordinates to file + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") end if - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") end if call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp), & From b9729c7896f8de2fbec5fe368abac1c4d1ce4aa4 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Sat, 17 Feb 2024 10:44:31 -0500 Subject: [PATCH 209/324] Fixed build scripts for cases where Cython is not available and for alternative FFTW home directory environment variable --- buildscripts/build_rcac_gnu.sh | 1 - buildscripts/build_rcac_intel.sh | 1 - cmake/Modules/FindFFTW3.cmake | 4 ++-- swiftest/CMakeLists.txt | 18 +++++++++++------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index a41e60266..82f8cf68b 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -80,7 +80,6 @@ if [[ BUILD_TYPE == "Release" ]]; then --no-build-isolation \ -ve . else - pip uninstall swiftest -y cmake -P distclean.cmake cmake -B ${ROOT_DIR}/build -S . -G Ninja \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 57433581f..58919182f 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -51,7 +51,6 @@ if [[ $MACHINE_NAME == "bell" ]]; then module load netcdf/4.7.4 module load netcdf-fortran/4.5.3 module load use.own - # module load fftw/3.3.8.lua module load conda-env/mintongroup-py3.8.5 MACHINE_CODE_VALUE="Host" elif [[ $MACHINE_NAME == "negishi" ]]; then diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake index ce3bd0dcb..e41405eab 100644 --- a/cmake/Modules/FindFFTW3.cmake +++ b/cmake/Modules/FindFFTW3.cmake @@ -9,8 +9,8 @@ # - Finds the FFTW3 library MESSAGE(STATUS "Looking for FFTW3") -FIND_PATH(FFTW3_INCLUDE_DIR NAMES fftw3.h HINTS ENV FFTW3_HOME PATH_SUFFIXES include) -FIND_LIBRARY(FFTW3_LIBRARY NAMES libfftw3.a HINTS ENV FFTW3_HOME PATH_SUFFIXES lib) +FIND_PATH(FFTW3_INCLUDE_DIR NAMES fftw3.h HINTS ENV FFTW3_HOME FFTW_HOME PATH_SUFFIXES include) +FIND_LIBRARY(FFTW3_LIBRARY NAMES libfftw3.a HINTS ENV FFTW3_HOME FFTW_HOME PATH_SUFFIXES lib) IF(NOT FFTW3_INCLUDE_DIR OR NOT FFTW3_LIBRARY) MESSAGE(STATUS "FFTW3 not found") diff --git a/swiftest/CMakeLists.txt b/swiftest/CMakeLists.txt index 39a52ddea..1d6db80b2 100644 --- a/swiftest/CMakeLists.txt +++ b/swiftest/CMakeLists.txt @@ -17,27 +17,31 @@ FIND_PROGRAM(CYTHON NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH ) +IF (NOT CYTHON) + MESSAGE(STATUS "Cython not found. Skipping Cython build") + RETURN() +ENDIF() + MESSAGE(STATUS "Cython executable path: ${CYTHON}") -# MESSAGE(STATUS "LD_LIBRARY_PATH: $ENV{LD_LIBRARY_PATH}") SET(CYTHON_ARGS "${CMAKE_CURRENT_SOURCE_DIR}/${SWIFTEST_BINDINGS}.pyx" "--output-file" "${CMAKE_CURRENT_BINARY_DIR}/${SWIFTEST_BINDINGS}.c") STRING(TOUPPER "${CMAKE_BUILD_TYPE}" BT) IF (BT STREQUAL "DEBUG") LIST(APPEND CYTHON_ARGS "--gdb") endif () ADD_CUSTOM_COMMAND( - OUTPUT "${SWIFTEST_BINDINGS}.c" - DEPENDS "${SWIFTEST_BINDINGS}.pyx" - VERBATIM - COMMAND "${CYTHON}" ${CYTHON_ARGS} ) + OUTPUT "${SWIFTEST_BINDINGS}.c" + DEPENDS "${SWIFTEST_BINDINGS}.pyx" + VERBATIM + COMMAND "${CYTHON}" ${CYTHON_ARGS} ) PYTHON_ADD_LIBRARY(${SWIFTEST_BINDINGS} MODULE "${CMAKE_CURRENT_BINARY_DIR}/${SWIFTEST_BINDINGS}.c" WITH_SOABI) TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} PUBLIC ${SWIFTEST_LIBRARY} netCDF::netcdff HDF5::HDF5) IF(USE_OPENMP OR USE_SIMD) - TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} PUBLIC SHTOOLS::parallel) + TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} PUBLIC SHTOOLS::parallel) ELSE() - TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} PUBLIC SHTOOLS::serial) + TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} PUBLIC SHTOOLS::serial) ENDIF () TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_BINDINGS} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) From 026958e4a1c8ccc207285fbec1704ae8f0d70738 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 17 Feb 2024 16:09:56 -0500 Subject: [PATCH 210/324] Small changes to the build scripts for environment variable consistency --- buildscripts/set_environment_macos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/set_environment_macos.sh b/buildscripts/set_environment_macos.sh index 18805cb62..9f985dbdb 100755 --- a/buildscripts/set_environment_macos.sh +++ b/buildscripts/set_environment_macos.sh @@ -7,6 +7,7 @@ MACOSX_DEPLOYMENT_TARGET="$(sw_vers -productVersion)" PREFIX="/usr/local" HOMEBREW_PREFIX="$(brew --prefix)" LD_LIBRARY_PATH="/usr/local/lib:${PREFIX}/lib:${HOMEBREW_PREFIX}/lib" +DYLD_LIBRARY_PATH="${LD_LIBRARY_PATH}" LDFLAGS="-Wl,-rpath,${ROOT_DIR}/lib -Wl,-no_compact_unwind -L${PREFIX}/lib -L${HOMEBREW_PREFIX}/lib" CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DIR}/include" CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include -Xclang -fopenmp" @@ -28,7 +29,6 @@ HDF5_ROOT=${HDF5_ROOT:-"${PREFIX}"} HDF5_LIBDIR="${HDF5_ROOT}/lib" HDF5_INCLUDE_DIR="${HDF5_ROOT}/include" HDF5_PLUGIN_PATH="${HDF5_LIBDIR}/plugin" - FC="$(command -v gfortran-12)" F77="${FC}" F95="${FC}" From 1d9c7d13a76b295fd97582dbc22cbe8c94626adb Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 17 Feb 2024 23:36:30 -0500 Subject: [PATCH 211/324] Added missing locality-spec statements to do concurrent, otherwise it crashes in multiprocessor runs. Also cleaned up some of the typing and formatting --- src/swiftest/swiftest_obl.f90 | 61 ++++++++++++++++------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index f00a95d85..8b07f7b2f 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -24,7 +24,7 @@ pure function matinv3(A) result(B) real(DP) :: detinv ! Calculate the inverse determinant of the matrix - detinv = 1/(A(1,1)*A(2,2)*A(3,3) - A(1,1)*A(2,3)*A(3,2)& + detinv = 1.0_DP/(A(1,1)*A(2,2)*A(3,3) - A(1,1)*A(2,3)*A(3,2)& - A(1,2)*A(2,1)*A(3,3) + A(1,2)*A(2,3)*A(3,1)& + A(1,3)*A(2,1)*A(3,2) - A(1,3)*A(2,2)*A(3,1)) @@ -40,6 +40,7 @@ pure function matinv3(A) result(B) B(3,3) = +detinv * (A(1,1)*A(2,2) - A(1,2)*A(2,1)) end function + module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) !! author: Kaustub P. Anand !! @@ -63,14 +64,14 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) rot_matrix(:, :) = 0.0_DP rot_matrix_inv(:, :) = 0.0_DP - z_hat(:) = [0, 0, 1] + z_hat(:) = [0.0_DP, 0.0_DP, 1.0_DP] if (n == 0) return - if (rot(1) == 0 .and. rot(2) == 0) then + if ((abs(rot(1)) < 10*tiny(1.0_DP)) .and. (abs(rot(2)) < 10*tiny(1.0_DP))) then do i = 1, NDIM - rot_matrix_inv(i, i) = 1.0 - rot_matrix(i, i) = 1.0 + rot_matrix_inv(i, i) = 1.0_DP + rot_matrix(i, i) = 1.0_DP end do return ! rotation axis is about the z-axis, no need to change @@ -87,8 +88,8 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) ! assuming NDIM = 3 ! CHECK for a general formula for the skew-symmetric matrix - do i = 1, NDIM - do j = 1, NDIM + do j = 1, NDIM + do i = 1, NDIM if (i == j) then rot_matrix_inv(i, j) = rot_matrix_inv(i, j) + cos(theta) ! identity matrix continue @@ -103,17 +104,18 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) ! Check that the correct rotation matrix is used ! rot_matrix * rot should be in the z_hat direction - check = MATMUL(rot, rot_matrix) ! 1x3 matrix x 3x3 matrix + check = matmul(rot, rot_matrix) ! 1x3 matrix x 3x3 matrix check = .unit. check(:) - if(abs(check(1)) .gt. EPSILON(0.0_DP) .or. abs(check(2)) .gt. EPSILON(0.0_DP)) then - temp = rot_matrix - rot_matrix = rot_matrix_inv - rot_matrix_inv = temp + if((abs(check(1)) > epsilon(0.0_DP)) .or. (abs(check(2)) > epsilon(0.0_DP))) then + temp = rot_matrix + rot_matrix = rot_matrix_inv + rot_matrix_inv = temp end if return - end subroutine swiftest_obl_rot_matrix + end subroutine swiftest_obl_rot_matrix + module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, GMpl, aoblcb) !! author: David A. Minton, Kaustub Anand (2023) @@ -145,27 +147,15 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, if (n == 0) return aobl(:,:) = 0.0_DP -#ifdef DOCONLOC - do concurrent(i = 1:n, lmask(i)) shared(lmask,rh,aobl) local(r2,irh,rinv2,t0,t1,t2,t3,fac1,fac2) -#else - do concurrent(i = 1:n, lmask(i)) -#endif - r2 = dot_product(rh(:, i), rh(:, i)) - irh = 1.0_DP / sqrt(r2) - rinv2 = irh**2 - t0 = -GMcb * rinv2 * rinv2 * irh - t1 = 1.5_DP * j2rp2 - t2 = rh(3, i) * rh(3, i) * rinv2 - t3 = 1.875_DP * j4rp4 * rinv2 - fac1 = t0 * (t1 - t3 - (5 * t1 - (14.0_DP - 21.0_DP * t2) * t3) * t2) - fac2 = 2 * t0 * (t1 - (2.0_DP - (14.0_DP * t2 / 3.0_DP)) * t3) - aobl(:, i) = fac1 * rh(:, i) - aobl(3, i) = fac2 * rh(3, i) + aobl(3, i) - end do ! If the rotation axis is along the z-axis, skip calculating the rotation matrix - if (rot(1) == 0 .and. rot(2) == 0) then + if ((abs(rot(1)) < 10*tiny(1.0_DP)) .and. (abs(rot(2)) < 10*tiny(1.0_DP))) then +#ifdef DOCONLOC + do concurrent(i = 1:n, lmask(i)) shared(lmask,rh,aobl,j2rp2,j4rp4) & + local(r2,irh,rinv2,t0,t1,t2,t3,fac1,fac2) +#else do concurrent(i = 1:n, lmask(i)) +#endif r2 = dot_product(rh(:, i), rh(:, i)) irh = 1.0_DP / sqrt(r2) rinv2 = irh**2 @@ -182,9 +172,14 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, ! generate the rotation matrix call swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) +#ifdef DOCONLOC + do concurrent(i = 1:n, lmask(i)) shared(lmask,rh,aobl,rot_matrix,rot_matrix_inv,j2rp2,j4rp4) & + local(r2,irh,rinv2,t0,t1,t2,t3,fac1,fac2,rh_transformed) +#else do concurrent(i = 1:n, lmask(i)) +#endif ! rotate the position vectors - rh_transformed = MATMUL(rh(:, i), rot_matrix) ! 1x3 vector * 3x3 matrix + rh_transformed = matmul(rh(:, i), rot_matrix) ! 1x3 vector * 3x3 matrix r2 = dot_product(rh_transformed, rh_transformed) irh = 1.0_DP / sqrt(r2) rinv2 = irh**2 @@ -198,7 +193,7 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, aobl(3, i) = fac2 * rh_transformed(3) + aobl(3, i) ! rotate the acceleration and position vectors back to the original coordinate frame - aobl(:, i) = MATMUL(aobl(:, i), rot_matrix_inv) + aobl(:, i) = matmul(aobl(:, i), rot_matrix_inv) end do end if From a0881abe8afd0814186179807d7b13b7fba9e2df Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 18 Feb 2024 00:51:04 -0500 Subject: [PATCH 212/324] Added locality spec to do concurrent --- src/collision/collision_generate.f90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/collision/collision_generate.f90 b/src/collision/collision_generate.f90 index 5fc489f86..072dbfa0f 100644 --- a/src/collision/collision_generate.f90 +++ b/src/collision/collision_generate.f90 @@ -209,7 +209,11 @@ module subroutine collision_generate_merge(self, nbody_system, param, t) fragments%density(1) = fragments%mass(1) / volume fragments%radius(1) = (3._DP * volume / (4._DP * PI))**(THIRD) if (param%lrotation) then +#ifdef DOCONLOC + do concurrent(i = 1:NDIM) shared(impactors, fragments, L_spin_new) +#else do concurrent(i = 1:NDIM) +#endif fragments%Ip(i,1) = sum(impactors%mass(:) * impactors%Ip(i,:)) L_spin_new(i) = sum(impactors%L_orbit(i,:) + impactors%L_spin(i,:)) end do From 7ddcc30d41669ad22c4929fea0f5bcddbf1be55e Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 18 Feb 2024 01:07:17 -0500 Subject: [PATCH 213/324] Load anaconda first before checking if environment exists --- buildscripts/build_rcac_gnu.sh | 6 +++++- buildscripts/build_rcac_intel.sh | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index 82f8cf68b..3c2238690 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -28,6 +28,11 @@ MACHINE_NAME=$(uname -n | awk -F. '{ print "Unknown"; } }') +if [[ $MACHINE_NAME == "bell" ]]; then + module load anaconda/2020.11-py38 +elif [[ $MACHINE_NAME == "negishi" ]]; then + module load anaconda/2022.10-py39 +fi if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then echo "The mintongroup conda environment was detected" @@ -37,7 +42,6 @@ else fi - if [[ $MACHINE_NAME == "bell" ]]; then module purge module use /depot/daminton/etc/modules/bell diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 58919182f..968bdc60f 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -29,6 +29,11 @@ MACHINE_NAME=$(uname -n | awk -F. '{ print "Unknown"; } }') +if [[ $MACHINE_NAME == "bell" ]]; then + module load anaconda/2020.11-py38 +elif [[ $MACHINE_NAME == "negishi" ]]; then + module load anaconda/2022.10-py39 +fi if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then print -n "The mintongroup conda environment was detected" From 4111a1383ad493932a1b1d60b21421687f3804cb Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 18 Feb 2024 10:59:04 -0500 Subject: [PATCH 214/324] Rearranged rcac build scripts --- buildscripts/build_rcac_gnu.sh | 12 ++++-------- buildscripts/build_rcac_intel.sh | 8 ++++---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index 3c2238690..aefc6fc71 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -45,31 +45,27 @@ fi if [[ $MACHINE_NAME == "bell" ]]; then module purge module use /depot/daminton/etc/modules/bell + module load use.own module load gcc/10.2.0 + module load conda-env/mintongroup-py3.8.5 module load hdf5/1.10.6 module load netcdf/4.7.4 module load netcdf-fortran/4.5.3 module load shtools/gcc10/4.11.10 module load cmake/3.20.6 module load ninja/1.11.1 - if [[ $BUILD_TYPE == "Release" ]]; then - module load use.own - module load conda-env/mintongroup-py3.8.5 - fi elif [[ $MACHINE_NAME == "negishi" ]]; then module purge module use /depot/daminton/etc/modules/negishi + module load use.own module load gcc/12.2.0 + module load conda-env/mintongroup-py3.9.13 module load hdf5/1.13.2 module load netcdf-c/4.9.0 module load netcdf-fortran/4.6.0 module load shtools/gcc12/4.11.10 module load cmake/3.24.3 module load ninja/1.11.1 - if [[ $BUILD_TYPE == "Release" ]]; then - module load use.own - module load conda-env/mintongroup-py3.9.13 - fi fi cmake -P distclean.cmake diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 968bdc60f..8e7ae495e 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -46,32 +46,32 @@ fi if [[ $MACHINE_NAME == "bell" ]]; then module purge module use /depot/daminton/etc/modules/bell + module load use.own module load intel/19.0.5.281 module load intel-mkl/2019.5.281 module load impi/2019.5.281 + module load conda-env/mintongroup-py3.8.5 module load shtools/intel19/4.11.10 module load cmake/3.20.6 module load ninja/1.11.1 module load hdf5/1.10.6 module load netcdf/4.7.4 module load netcdf-fortran/4.5.3 - module load use.own - module load conda-env/mintongroup-py3.8.5 MACHINE_CODE_VALUE="Host" elif [[ $MACHINE_NAME == "negishi" ]]; then module purge module use /depot/daminton/etc/modules/negishi + module load use.own module load intel/19.1.3.304 module load intel-mkl/2019.9.304 module load impi/2019.9.304 + module load conda-env/mintongroup-py3.9.13 module load shtools/intel19/4.11.10 module load cmake/3.24.3 module load ninja/1.11.1 module load hdf5/1.13.2 module load netcdf-c/4.9.0 module load netcdf-fortran/4.6.0 - module load use.own - module load conda-env/mintongroup-py3.9.13 MACHINE_CODE_VALUE="SSE2" fi From 51810a55daa408ee2ba9402a437d9cc31d205f73 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 18 Feb 2024 12:11:53 -0500 Subject: [PATCH 215/324] Updated mkl flags and removed unnecessary FindMKL.cmake file --- CMakeLists.txt | 1 - cmake/Modules/FindMKL.cmake | 17 ----------------- cmake/Modules/SetSwiftestFlags.cmake | 7 +++++-- 3 files changed, 5 insertions(+), 20 deletions(-) delete mode 100644 cmake/Modules/FindMKL.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b50d3d9d..b71f13740 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,6 @@ ELSE() # Add in the external dependency libraries IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") - FIND_PACKAGE(MKL) # Possibly not needed any more due to BLAS and LAPACK being found ELSEIF (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") SET(COMPILER_OPTIONS "GNU" CACHE STRING "Compiler identified as gfortran") ELSE () diff --git a/cmake/Modules/FindMKL.cmake b/cmake/Modules/FindMKL.cmake deleted file mode 100644 index 9e48932c3..000000000 --- a/cmake/Modules/FindMKL.cmake +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2022 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh -# This file is part of Swiftest. -# Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -# Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# You should have received a copy of the GNU General Public License along with Swiftest. -# If not, see: https://www.gnu.org/licenses. - -# - Finds the Intel MKL libraries -find_path(MKL_INCLUDE_DIR NAMES mkl.h HINTS ENV MKLROOT PATH_SUFFIXES include) -find_library(MKL_LIBRARY NAMES libmkl_core.a HINTS ENV MKLROOT PATH_SUFFIXES lib lib/intel64 ) - -set(MKL_FOUND TRUE) -set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR}) -set(MKL_LIBRARIES ${MKL_LIBRARY}) -mark_as_advanced(MKL_LIBRARY MKL_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index 9fb7a1faf..e4dbafb68 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -101,7 +101,7 @@ ELSEIF (COMPILER_OPTIONS STREQUAL "Intel") ) # Aligns a variable to a specified boundary and offset SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "/align:all /align:array64byte" # Intel + Fortran "/align:all /align:array64byte" # Intel Windows ) # Enables changing the variable and array memory layout SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" @@ -117,7 +117,10 @@ ELSEIF (COMPILER_OPTIONS STREQUAL "Intel") ) # Enables changing the variable and array memory layout SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-pad" # Intel Windows + Fortran "-pad" # Intel + ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-mkl" # Intel ) ENDIF () ENDIF () From c34be4764c46329f03852ae7dcd693857b52b310 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Sun, 18 Feb 2024 12:22:40 -0500 Subject: [PATCH 216/324] Simplified RCAC build scripts --- buildscripts/build_rcac_gnu.sh | 34 ++++++++++++----------------- buildscripts/build_rcac_intel.sh | 37 ++++++++++++++------------------ 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index aefc6fc71..09bbbb561 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -1,8 +1,10 @@ #!/bin/zsh -l # Builds Swiftest on the Purdue RCAC cluster system using the GNU compiler # This is a convenience script for Kaustub -# The default build type is Release, in which case the Python package is installed in editable mode. Otherwise, only the Fortran -# library and executables are built, but not installed, so that the user can run them from the build directory. +# The default build type is Release. Pass other build types as a string argument. +# +# Example: +# $ buildscripts/build_rcac_gnu.sh "Debug" set -a SCRIPT_DIR=$(realpath $(dirname $0)) @@ -69,21 +71,13 @@ elif [[ $MACHINE_NAME == "negishi" ]]; then fi cmake -P distclean.cmake -if [[ BUILD_TYPE == "Release" ]]; then - pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . -else - cmake -P distclean.cmake - cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=gfortran - - cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v -fi \ No newline at end of file +pip uninstall swiftest +pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . \ No newline at end of file diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 8e7ae495e..830afd51f 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -1,9 +1,12 @@ #!/bin/zsh -l # installs an editable (local) package on Bell # This is a convenience script for Kaustub -# To use in Release mode, be sure to create the mintongroup module first. Using the RCAC tools it's the following commands: -# $ conda env create -f environment.yml -# $ conda-env-mod module -n mintongroup --jupyter +# To use in Release mode +# The default build type is Release. Pass other build types as a string argument. +# +# Example: +# $ buildscripts/build_rcac_intel.sh "Debug" + set -a SCRIPT_DIR=$(realpath $(dirname $0)) @@ -77,21 +80,13 @@ fi cmake -P distclean.cmake -if [[ $BUILD_TYPE == "Release" ]]; then - pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=${FC}" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE" \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . -else - cmake -B ${ROOT_DIR}/build -S . -G Ninja \ - -DMACHINE_CODE_VALUE=${MACHINE_CODE_VALUE} \ - -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DCMAKE_Fortran_COMPILER=${FC} \ - - cmake --build ${ROOT_DIR}/build -j${OMP_NUM_THREADS} -v -fi \ No newline at end of file +pip uninstall swiftest +pip install --config-settings=build-dir="build" \ + --config-settings=cmake.build-type="${BUILD_TYPE}" \ + --config-settings=cmake.args="-DUSE_SIMD=ON" \ + --config-settings=cmake.args="-DUSE_OPENMP=ON" \ + --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=${FC}" \ + --config-settings=cmake.args="-DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE" \ + --config-settings=install.strip=false \ + --no-build-isolation \ + -ve . \ No newline at end of file From 9fa617972f00e6f8ab5d093eacec917605e4cd32 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Sun, 18 Feb 2024 12:24:47 -0500 Subject: [PATCH 217/324] Removed need for user interaction on uninstall --- buildscripts/build_rcac_gnu.sh | 2 +- buildscripts/build_rcac_intel.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh index 09bbbb561..13f4ab923 100755 --- a/buildscripts/build_rcac_gnu.sh +++ b/buildscripts/build_rcac_gnu.sh @@ -71,7 +71,7 @@ elif [[ $MACHINE_NAME == "negishi" ]]; then fi cmake -P distclean.cmake -pip uninstall swiftest +pip uninstall swiftest -y pip install --config-settings=build-dir="build" \ --config-settings=cmake.build-type="${BUILD_TYPE}" \ --config-settings=cmake.args="-DUSE_SIMD=ON" \ diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh index 830afd51f..a38580970 100755 --- a/buildscripts/build_rcac_intel.sh +++ b/buildscripts/build_rcac_intel.sh @@ -80,7 +80,7 @@ fi cmake -P distclean.cmake -pip uninstall swiftest +pip uninstall swiftest -y pip install --config-settings=build-dir="build" \ --config-settings=cmake.build-type="${BUILD_TYPE}" \ --config-settings=cmake.args="-DUSE_SIMD=ON" \ From f5d09c2b4d7e265129769e13d63b877634f8b825 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 19 Feb 2024 15:57:18 -0500 Subject: [PATCH 218/324] Removed unnecessary rcac build scripts --- buildscripts/build_rcac_gnu.sh | 83 ---------------------------- buildscripts/build_rcac_intel.sh | 92 -------------------------------- 2 files changed, 175 deletions(-) delete mode 100755 buildscripts/build_rcac_gnu.sh delete mode 100755 buildscripts/build_rcac_intel.sh diff --git a/buildscripts/build_rcac_gnu.sh b/buildscripts/build_rcac_gnu.sh deleted file mode 100755 index 13f4ab923..000000000 --- a/buildscripts/build_rcac_gnu.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/zsh -l -# Builds Swiftest on the Purdue RCAC cluster system using the GNU compiler -# This is a convenience script for Kaustub -# The default build type is Release. Pass other build types as a string argument. -# -# Example: -# $ buildscripts/build_rcac_gnu.sh "Debug" - -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -cd ${ROOT_DIR} -BUILD_TYPE=${1:-"Release"} - -# Set the OMP_NUM_THREADS variable to be the number of CPUS if this is a compute node, or 1 if this is a frontend or login node -if { hostname | grep -E 'fe|login'; } >/dev/null 2>&1; then - OMP_NUM_THREADS=1 -else - OMP_NUM_THREADS=$(squeue -u $(whoami) | grep $SLURM_JOB_ID | awk -F' ' '{print $6}') -fi - -MACHINE_NAME=$(uname -n | awk -F. '{ - if ($2 == "negishi" || $2 == "bell") - print $2; - else { - split($1, a, "-"); - if (length(a) > 1) - print a[1]; - else - print "Unknown"; - } -}') -if [[ $MACHINE_NAME == "bell" ]]; then - module load anaconda/2020.11-py38 -elif [[ $MACHINE_NAME == "negishi" ]]; then - module load anaconda/2022.10-py39 -fi - -if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then - echo "The mintongroup conda environment was detected" -else - echo "The mintongroup conda environment was not detected. Creating it now..." - /depot/daminton/apps/build_mintongroup_conda.sh -fi - - -if [[ $MACHINE_NAME == "bell" ]]; then - module purge - module use /depot/daminton/etc/modules/bell - module load use.own - module load gcc/10.2.0 - module load conda-env/mintongroup-py3.8.5 - module load hdf5/1.10.6 - module load netcdf/4.7.4 - module load netcdf-fortran/4.5.3 - module load shtools/gcc10/4.11.10 - module load cmake/3.20.6 - module load ninja/1.11.1 -elif [[ $MACHINE_NAME == "negishi" ]]; then - module purge - module use /depot/daminton/etc/modules/negishi - module load use.own - module load gcc/12.2.0 - module load conda-env/mintongroup-py3.9.13 - module load hdf5/1.13.2 - module load netcdf-c/4.9.0 - module load netcdf-fortran/4.6.0 - module load shtools/gcc12/4.11.10 - module load cmake/3.24.3 - module load ninja/1.11.1 -fi - -cmake -P distclean.cmake -pip uninstall swiftest -y -pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=gfortran" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=\"Host\" " \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . \ No newline at end of file diff --git a/buildscripts/build_rcac_intel.sh b/buildscripts/build_rcac_intel.sh deleted file mode 100755 index a38580970..000000000 --- a/buildscripts/build_rcac_intel.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/zsh -l -# installs an editable (local) package on Bell -# This is a convenience script for Kaustub -# To use in Release mode -# The default build type is Release. Pass other build types as a string argument. -# -# Example: -# $ buildscripts/build_rcac_intel.sh "Debug" - - -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) -cd ${ROOT_DIR} -BUILD_TYPE=${1:-"Release"} - -# Set the OMP_NUM_THREADS variable to be the number of CPUS if this is a compute node, or 1 if this is a frontend or login node -if { hostname | grep -E 'fe|login'; } >/dev/null 2>&1; then - OMP_NUM_THREADS=1 -else - OMP_NUM_THREADS=$(squeue -u $(whoami) | grep $SLURM_JOB_ID | awk -F' ' '{print $6}') -fi - -MACHINE_NAME=$(uname -n | awk -F. '{ - if ($2 == "negishi" || $2 == "bell") - print $2; - else { - split($1, a, "-"); - if (length(a) > 1) - print a[1]; - else - print "Unknown"; - } -}') -if [[ $MACHINE_NAME == "bell" ]]; then - module load anaconda/2020.11-py38 -elif [[ $MACHINE_NAME == "negishi" ]]; then - module load anaconda/2022.10-py39 -fi - -if { conda env list | grep 'mintongroup'; } >/dev/null 2>&1; then - print -n "The mintongroup conda environment was detected" -else - print -n "The mintongroup conda environment was not detected. Creating it now..." - /depot/daminton/apps/build_mintongroup_conda.sh -fi - - -if [[ $MACHINE_NAME == "bell" ]]; then - module purge - module use /depot/daminton/etc/modules/bell - module load use.own - module load intel/19.0.5.281 - module load intel-mkl/2019.5.281 - module load impi/2019.5.281 - module load conda-env/mintongroup-py3.8.5 - module load shtools/intel19/4.11.10 - module load cmake/3.20.6 - module load ninja/1.11.1 - module load hdf5/1.10.6 - module load netcdf/4.7.4 - module load netcdf-fortran/4.5.3 - MACHINE_CODE_VALUE="Host" -elif [[ $MACHINE_NAME == "negishi" ]]; then - module purge - module use /depot/daminton/etc/modules/negishi - module load use.own - module load intel/19.1.3.304 - module load intel-mkl/2019.9.304 - module load impi/2019.9.304 - module load conda-env/mintongroup-py3.9.13 - module load shtools/intel19/4.11.10 - module load cmake/3.24.3 - module load ninja/1.11.1 - module load hdf5/1.13.2 - module load netcdf-c/4.9.0 - module load netcdf-fortran/4.6.0 - MACHINE_CODE_VALUE="SSE2" -fi - - -cmake -P distclean.cmake -pip uninstall swiftest -y -pip install --config-settings=build-dir="build" \ - --config-settings=cmake.build-type="${BUILD_TYPE}" \ - --config-settings=cmake.args="-DUSE_SIMD=ON" \ - --config-settings=cmake.args="-DUSE_OPENMP=ON" \ - --config-settings=cmake.args="-DCMAKE_Fortran_COMPILER=${FC}" \ - --config-settings=cmake.args="-DMACHINE_CODE_VALUE=$MACHINE_CODE_VALUE" \ - --config-settings=install.strip=false \ - --no-build-isolation \ - -ve . \ No newline at end of file From 52b41abb6d17c8a34bcf4aafb4ba7c9a8fe2a8fe Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 20 Feb 2024 08:16:42 -0500 Subject: [PATCH 219/324] Added flag that turns on ability to see value of parameters in debugging --- cmake/Modules/SetSwiftestFlags.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/Modules/SetSwiftestFlags.cmake b/cmake/Modules/SetSwiftestFlags.cmake index e4dbafb68..9353f3e26 100644 --- a/cmake/Modules/SetSwiftestFlags.cmake +++ b/cmake/Modules/SetSwiftestFlags.cmake @@ -306,6 +306,9 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" C "/debug:all" # Intel Windows ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/debug-parameters:all" # Intel Windows + ) # Disables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran "/Qip-" # Intel Windows @@ -380,6 +383,9 @@ IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) SET_COMPILE_FLAG(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" C "-debug all" # Intel ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-debug-parameters all" # Intel + ) # Disables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" Fortran "-no-ip" # Intel From 81d32d7f51c267beb33e5499840299c75f25cf5f Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 20 Feb 2024 09:45:03 -0500 Subject: [PATCH 220/324] Updated build requirements to fix issues that arise due to using older versions of scikit-build-core and cmake --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c41016fd0..8e2f5965c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,9 +48,8 @@ Repository = 'https://github.itap.purdue.edu/MintonGroup/swiftest' [build-system] requires = [ - "scikit-build-core", + "scikit-build-core>=0.8", "cython>=3.0", - "cmake", "pyproject_metadata", "pytest", "pathspec", @@ -68,6 +67,8 @@ requires = [ build-backend = "scikit_build_core.build" [tool.scikit-build] +cmake.version = ">=3.24.3" +ninja.version = ">=1.11.1" cmake.args = ["-DUSE_SIMD=OFF"] sdist.include = ["src/globals/globals_module.f90.in","swiftest/*.py","swiftest/*.pyx","swiftest/*.h"] build-dir = "build/{wheel_tag}" From f02d26ead22c54dba26caf9ef5e506b87d41ebd2 Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 21 Feb 2024 08:19:02 -0500 Subject: [PATCH 221/324] Updated version requirements. --- CMakeLists.txt | 2 +- pyproject.toml | 16 ++++++++-------- requirements.txt | 9 +++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b71f13740..fad2df6a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ ################################################## # Define the project and the depencies that it has ################################################## -CMAKE_MINIMUM_REQUIRED(VERSION 3.6.0...3.27.1) +CMAKE_MINIMUM_REQUIRED(VERSION 3.23.1...3.28.3) SET(SKBUILD_PROJECT_NAME "swiftest" CACHE STRING "Name of project set by scikit-build") # Get version stored in text file diff --git a/pyproject.toml b/pyproject.toml index 8e2f5965c..9f69d8aa4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,20 +24,20 @@ classifiers=[ ] keywords=['astronomy','astrophysics', 'planetary', 'n-body', 'integrator', 'symplectic', 'wisdom-holman', 'symba'] dependencies = [ - 'numpy>=1.23', - 'scipy>=1.10', + 'numpy>=1.24.3', + 'scipy>=1.10.1', 'xarray>=2023.1', 'dask>=2023.5', 'distributed>=2023.5', - 'bottleneck>=1.3', + 'bottleneck>=1.3.5', 'h5netcdf>=1.1', 'h5py>=3.9', - 'netcdf4>=1.6', - 'matplotlib>=3.7', + 'netcdf4>=1.6.2', + 'matplotlib>=3.7.1', 'astropy>=5.2', 'astroquery>=0.4.6', - 'tqdm>=4.64', - 'cython>=3.0', + 'tqdm>=4.65', + 'cython>=3.0.0', ] [project.optional-dependencies] @@ -67,7 +67,7 @@ requires = [ build-backend = "scikit_build_core.build" [tool.scikit-build] -cmake.version = ">=3.24.3" +cmake.version = ">=3.23.1" ninja.version = ">=1.11.1" cmake.args = ["-DUSE_SIMD=OFF"] sdist.include = ["src/globals/globals_module.f90.in","swiftest/*.py","swiftest/*.pyx","swiftest/*.h"] diff --git a/requirements.txt b/requirements.txt index 79d85b58b..d41a21895 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,12 @@ python>=3.8 numpy>=1.24.3 scipy>=1.10.1 -xarray>=2022.11.0 -dask>=2022.1 +xarray>=2023.1 +dask>=2023.5 +distributed>=2023.5 bottleneck>=1.3.5 -distributed>=2022.1 -h5netcdf>=1.0.2 +h5netcdf>=1.1 +h5py>=3.9 netcdf4>=1.6.2 matplotlib>=3.7.1 astropy>=5.1 From 9eb5246a58a61af4a46248b2cfda1b2e40f618b2 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 21 Feb 2024 13:36:43 -0500 Subject: [PATCH 222/324] Added missing pltp collision routines --- src/collision/collision_check.f90 | 8 ++------ src/collision/collision_resolve.f90 | 32 +++++++++++++++++++++++++++++ src/swiftest/swiftest_module.f90 | 4 ++-- src/swiftest/swiftest_util.f90 | 1 + src/symba/symba_step.f90 | 2 ++ src/symba/symba_util.f90 | 3 +-- 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/collision/collision_check.f90 b/src/collision/collision_check.f90 index be11ee9a8..c95547a6e 100644 --- a/src/collision/collision_check.f90 +++ b/src/collision/collision_check.f90 @@ -187,11 +187,9 @@ module subroutine collision_check_pltp(self, nbody_system, param, t, dt, irec, l lany_collision = .false. if (self%nenc == 0) return + select type(nbody_system) class is (swiftest_nbody_system) - select type(param) - class is (swiftest_parameters) - associate(pl => nbody_system%pl, tp => nbody_system%tp) nenc = self%nenc @@ -256,15 +254,13 @@ module subroutine collision_check_pltp(self, nbody_system, param, t, dt, irec, l end do ! Extract the pl-tp encounter list and return the pl-tp collision_list - allocate(tmp, mold=self) - call self%spill(tmp, lcollision, ldestructive=.true.) ! Remove this encounter pair from the encounter list + call self%extract_collisions(nbody_system, param) end if ! Take snapshots of pairs of bodies at close approach (but not collision) if requested if (lany_closest) call nbody_system%encounter_history%take_snapshot(param, nbody_system, t, "closest") end associate end select - end select return end subroutine collision_check_pltp diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index a3daf7122..ab27b72e4 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -255,6 +255,38 @@ module subroutine collision_resolve_extract_pltp(self, nbody_system, param) class(collision_list_pltp), intent(inout) :: self !! pl-tp encounter list class(base_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object class(base_parameters), intent(in) :: param !! Current run configuration parameters + ! Internals + logical, dimension(:), allocatable :: lpltp_collision + integer(I8B) :: ncollisions, index_coll, k, npltpenc + integer(I8B), dimension(:), allocatable :: collision_idx + + select type(nbody_system) + class is (swiftest_nbody_system) + select type (pl => nbody_system%pl) + class is (swiftest_pl) + select type (tp => nbody_system%tp) + class is (swiftest_tp) + associate(idx1 => self%index1, idx2 => self%index2) + npltpenc = self%nenc + allocate(lpltp_collision(npltpenc)) + lpltp_collision(:) = self%status(1_I8B:npltpenc) == COLLIDED + if (.not.any(lpltp_collision)) return + ! Collisions have been detected in this step. So we need to determine which of them are between unique bodies. + + ! Get the subset of pl-tp encounters that lead to a collision + ncollisions = count(lpltp_collision(:)) + allocate(collision_idx(ncollisions)) + collision_idx = pack([(k, k=1_I8B, npltpenc)], lpltp_collision) + + ! Create a mask that contains only the pl-tp encounters that did not result in a collision, and then discard them + lpltp_collision(:) = .false. + lpltp_collision(collision_idx(:)) = .true. + call self%spill(nbody_system%pltp_collision, lpltp_collision, ldestructive=.true.) ! Extract any encounters that are not collisions from the list. + end associate + end select + end select + end select + return end subroutine collision_resolve_extract_pltp diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index fdefc6ec0..70c49a619 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -346,10 +346,10 @@ module swiftest class(swiftest_pl), allocatable :: pl_discards !! Discarded massive body particle data structure class(swiftest_pl), allocatable :: pl_adds !! List of added bodies in mergers or collisions class(swiftest_tp), allocatable :: tp_adds !! List of added bodies in mergers or collisions - class(encounter_list), allocatable :: pltp_encounter !! List of massive body-test particle encounters in a single step + class(encounter_list), allocatable :: pltp_encounter !! List of massive body-test particle encounters in a single step class(encounter_list), allocatable :: plpl_encounter !! List of massive body-massive body encounters in a single step class(collision_list_plpl), allocatable :: plpl_collision !! List of massive body-massive body collisions in a single step - class(collision_list_plpl), allocatable :: pltp_collision !! List of massive body-massive body collisions in a single step + class(collision_list_pltp), allocatable :: pltp_collision !! List of massive body-test particle collisions in a single step class(collision_basic), allocatable :: collider !! Collision system object class(encounter_storage), allocatable :: encounter_history !! Stores encounter history for later retrieval and saving to file class(collision_storage), allocatable :: collision_history !! Stores encounter history for later retrieval and saving to file diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 6b6b00b65..78bcb7b01 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -2412,6 +2412,7 @@ module subroutine swiftest_util_setup_construct_system(nbody_system, param) allocate(symba_list_pltp :: nbody_system%pltp_encounter) allocate(symba_list_plpl :: nbody_system%plpl_encounter) allocate(collision_list_plpl :: nbody_system%plpl_collision) + allocate(collision_list_pltp :: nbody_system%pltp_collision) end select case (INT_RINGMOONS) write(*,*) 'RINGMOONS-SyMBA integrator not yet enabled' diff --git a/src/symba/symba_step.f90 b/src/symba/symba_step.f90 index e647e4d37..948eeaacc 100644 --- a/src/symba/symba_step.f90 +++ b/src/symba/symba_step.f90 @@ -305,7 +305,9 @@ module subroutine symba_step_reset_system(self, param) nenc_old = nbody_system%pltp_encounter%nenc call nbody_system%pltp_encounter%setup(0_I8B) + call nbody_system%pltp_collision%setup(0_I8B) if (ntp > 0) then + tp%lcollision(1:ntp) = .false. tp%nplenc(1:ntp) = 0 tp%levelg(1:ntp) = -1 tp%levelm(1:ntp) = -1 diff --git a/src/symba/symba_util.f90 b/src/symba/symba_util.f90 index 8ed213ba8..8e4b45e37 100644 --- a/src/symba/symba_util.f90 +++ b/src/symba/symba_util.f90 @@ -157,7 +157,6 @@ module subroutine symba_util_fill_tp(self, inserts, lfill_list) associate(keeps => self) select type(inserts) class is (symba_tp) - call util_fill(keeps%nplenc, inserts%nplenc, lfill_list) call util_fill(keeps%levelg, inserts%levelg, lfill_list) call util_fill(keeps%levelm, inserts%levelm, lfill_list) @@ -290,6 +289,7 @@ module subroutine symba_util_setup_initialize_system(self, system_history, param call nbody_system%pltp_encounter%setup(0_I8B) call nbody_system%plpl_encounter%setup(0_I8B) call nbody_system%plpl_collision%setup(0_I8B) + call nbody_system%pltp_collision%setup(0_I8B) if (param%lenc_save_trajectory .or. param%lenc_save_closest) then allocate(encounter_netcdf_parameters :: encounter_history%nc) @@ -563,7 +563,6 @@ module subroutine symba_util_spill_tp(self, discards, lspill_list, ldestructive) associate(keeps => self) select type(discards) class is (symba_tp) - call util_spill(keeps%nplenc, discards%nplenc, lspill_list, ldestructive) call util_spill(keeps%levelg, discards%levelg, lspill_list, ldestructive) call util_spill(keeps%levelm, discards%levelm, lspill_list, ldestructive) From 2f9696d362fc1e6ec0b5d1b180c6fe1937e1b276 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 21 Feb 2024 14:20:29 -0500 Subject: [PATCH 223/324] Added a rearray_tp method to the swiftest_tp class in order to better resolve pl-tp collisions --- src/collision/collision_resolve.f90 | 22 +++++--- src/swiftest/swiftest_module.f90 | 14 +++-- src/swiftest/swiftest_util.f90 | 81 ++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 12 deletions(-) diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index ab27b72e4..1586073cb 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -220,7 +220,7 @@ module subroutine collision_resolve_extract_plpl(self, nbody_system, param) unique_parent_idx = pack(collision_idx(:), lplpl_unique_parent(:)) ! Scrub all pl-pl collisions involving unique pairs of parents, which will remove all duplicates and leave behind - ! all pairs that have themselves as parents but are not part of the unique parent list. This can hapepn in rare cases + ! all pairs that have themselves as parents but are not part of the unique parent list. This can happen in rare cases ! due to restructuring of parent/child relationships when there are large numbers of multi-body collisions in a single ! step lplpl_unique_parent(:) = .true. @@ -713,13 +713,19 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) class is (swiftest_nbody_system) select type(param) class is (swiftest_parameters) - call nbody_system%pl%vb2vh(nbody_system%cb) - call nbody_system%tp%vb2vh(nbody_system%cb%vb) - call nbody_system%pl%b2h(nbody_system%cb) - call nbody_system%tp%b2h(nbody_system%cb) - - ! Discard the collider - call nbody_system%tp%discard(nbody_system, param) + associate(pltp_collision => nbody_system%pltp_collision, & + collision_history => nbody_system%collision_history, pl => nbody_system%pl, cb => nbody_system%cb, & + tp => nbody_system%tp, collider => nbody_system%collider, impactors => nbody_system%collider%impactors) + call pl%vb2vh(nbody_system%cb) + call tp%vb2vh(nbody_system%cb%vb) + call pl%b2h(nbody_system%cb) + call tp%b2h(nbody_system%cb) + + call tp%rearray(nbody_system, param) + + ! Discard the collider + !call nbody_system%tp%discard(nbody_system, param) + end associate end select end select diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 70c49a619..6350a42dd 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -321,6 +321,7 @@ module swiftest procedure :: rh2rb => swiftest_util_coord_rh2rb_tp !! Convert test particles from heliocentric to barycentric coordinates (position only) procedure :: dealloc => swiftest_util_dealloc_tp !! Deallocates all allocatable arrays procedure :: fill => swiftest_util_fill_tp !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) + procedure :: rearray => swiftest_util_rearray_tp !! Clean up the test particle structures to remove discarded bodies procedure :: resize => swiftest_util_resize_tp !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. procedure :: set_mu => swiftest_util_set_mu_tp !! Method used to construct the vectorized form of the central body mass procedure :: sort => swiftest_util_sort_tp !! Sorts body arrays by a sortable component @@ -1485,11 +1486,18 @@ end subroutine swiftest_util_peri_tp module subroutine swiftest_util_rearray_pl(self, nbody_system, param) implicit none - class(swiftest_pl), intent(inout) :: self !! SyMBA massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! SyMBA nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters with SyMBA additions + class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters end subroutine swiftest_util_rearray_pl + module subroutine swiftest_util_rearray_tp(self, nbody_system, param) + implicit none + class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + end subroutine swiftest_util_rearray_tp + module subroutine swiftest_util_rescale_system(self, param, mscale, dscale, tscale) implicit none class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 78bcb7b01..5723db82f 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -1704,10 +1704,13 @@ module subroutine swiftest_util_rearray_pl(self, nbody_system, param) if (npl == 0) then if (param%lmtiny_pl) pl%nplm = 0 + ! There are no more massive bodies. Reset the encounter lists and move on + if (allocated(nbody_system%plpl_encounter)) call nbody_system%plpl_encounter%setup(0_I8B) + if (allocated(nbody_system%pltp_encounter)) call nbody_system%pltp_encounter%setup(0_I8B) return end if - ! Reset all of the status flags for this body + ! Reset all of the status flags for the remaining bodies pl%status(1:npl) = ACTIVE do i = 1, npl call pl%info(i)%set_value(status="ACTIVE") @@ -1842,6 +1845,82 @@ module subroutine swiftest_util_rearray_pl(self, nbody_system, param) end subroutine swiftest_util_rearray_pl + + module subroutine swiftest_util_rearray_tp(self, nbody_system, param) + !! Author: David A. Minton + !! + !! Clean up the test particle structures to remove discarded bodies + use symba + implicit none + ! Arguments + class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + ! Internals + class(swiftest_tp), allocatable :: tmp !! The discarded body list. + integer(I4B) :: i, ntp + integer(I8B) :: k, nenc_old, nencmin + logical, dimension(:), allocatable :: lmask + class(encounter_list), allocatable :: pltpenc_old + logical :: lencounter + + associate(pl => self, tp => nbody_system%tp, cb => nbody_system%cb, pl_adds => nbody_system%pl_adds) + + ntp = tp%nbody + if (ntp == 0) return + + ! Remove the discards and destroy the list, as the nbody_system already tracks tp_discards elsewhere + allocate(lmask(ntp)) + lmask(1:ntp) = tp%ldiscard(1:ntp) + if (count(lmask(:)) > 0) then + allocate(tmp, mold=self) + call tp%spill(tmp, lspill_list=lmask, ldestructive=.true.) + ntp = tp%nbody + call tmp%setup(0,param) + deallocate(tmp) + deallocate(lmask) + end if + ntp = tp%nbody + if (ntp == 0) then + ! There are no more test particles. Reset the encounter list and move on + if (allocated(nbody_system%pltp_encounter)) call nbody_system%pltp_encounter%setup(0_I8B) + return + end if + + ! Reset all of thes tatus flags for the remaining bodies + tp%status(1:ntp) = ACTIVE + do i = 1, ntp + call tp%info(i)%set_value(status="ACTIVE") + end do + tp%ldiscard(1:ntp) = .false. + tp%lcollision(1:ntp) = .false. + tp%lmask(1:ntp) = .true. + + if (allocated(nbody_system%pltp_encounter)) then + ! Store the original pltpenc list so we don't remove any of the original encounters + nenc_old = nbody_system%pltp_encounter%nenc + if (nenc_old > 0_I8B) then + allocate(pltpenc_old, source=nbody_system%pltp_encounter) + call pltpenc_old%copy(nbody_system%pltp_encounter) + end if + + ! Re-build the encounter list + ! Be sure to get the level info if this is a SyMBA nbody_system + select type(nbody_system) + class is (symba_nbody_system) + select type(tp) + class is (symba_tp) + lencounter = tp%encounter_check(param, nbody_system, param%dt, nbody_system%irec) + end select + end select + end if + + end associate + + return + end subroutine swiftest_util_rearray_tp + + module subroutine swiftest_util_rescale_system(self, param, mscale, dscale, tscale) !! author: David A. Minton !! From f198460bb8ff39d6287481f6e260daa6d9c2eeb8 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 21 Feb 2024 16:06:20 -0500 Subject: [PATCH 224/324] Correctly reindex the pl-tp encounter list after a pl-tp collision --- src/collision/collision_resolve.f90 | 3 ++- src/swiftest/swiftest_util.f90 | 30 ++++++++++------------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index 1586073cb..545b882fc 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -721,10 +721,11 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) call pl%b2h(nbody_system%cb) call tp%b2h(nbody_system%cb) + ! Restructure the massive bodies based on the outcome of the collision call tp%rearray(nbody_system, param) ! Discard the collider - !call nbody_system%tp%discard(nbody_system, param) + call nbody_system%tp%discard(nbody_system, param) end associate end select end select diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 5723db82f..67cac063a 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -1845,7 +1845,6 @@ module subroutine swiftest_util_rearray_pl(self, nbody_system, param) end subroutine swiftest_util_rearray_pl - module subroutine swiftest_util_rearray_tp(self, nbody_system, param) !! Author: David A. Minton !! @@ -1858,16 +1857,16 @@ module subroutine swiftest_util_rearray_tp(self, nbody_system, param) class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals class(swiftest_tp), allocatable :: tmp !! The discarded body list. - integer(I4B) :: i, ntp - integer(I8B) :: k, nenc_old, nencmin + integer(I4B) :: i, ntp, npl + integer(I8B) :: k, nenc logical, dimension(:), allocatable :: lmask - class(encounter_list), allocatable :: pltpenc_old logical :: lencounter - associate(pl => self, tp => nbody_system%tp, cb => nbody_system%cb, pl_adds => nbody_system%pl_adds) + associate(tp => self, pl => nbody_system%pl, cb => nbody_system%cb, pl_adds => nbody_system%pl_adds) ntp = tp%nbody if (ntp == 0) return + npl = pl%nbody ! Remove the discards and destroy the list, as the nbody_system already tracks tp_discards elsewhere allocate(lmask(ntp)) @@ -1897,22 +1896,13 @@ module subroutine swiftest_util_rearray_tp(self, nbody_system, param) tp%lmask(1:ntp) = .true. if (allocated(nbody_system%pltp_encounter)) then - ! Store the original pltpenc list so we don't remove any of the original encounters - nenc_old = nbody_system%pltp_encounter%nenc - if (nenc_old > 0_I8B) then - allocate(pltpenc_old, source=nbody_system%pltp_encounter) - call pltpenc_old%copy(nbody_system%pltp_encounter) - end if + ! Index values may have changed, so re-index the encounter list + nenc = nbody_system%pltp_encounter%nenc + do k = 1_I8B, nenc + nbody_system%pltp_encounter%index1(k) = findloc(pl%id(1:npl), nbody_system%pltp_encounter%id1(k), dim=1) + nbody_system%pltp_encounter%index2(k) = findloc(tp%id(1:ntp), nbody_system%pltp_encounter%id2(k), dim=1) + end do - ! Re-build the encounter list - ! Be sure to get the level info if this is a SyMBA nbody_system - select type(nbody_system) - class is (symba_nbody_system) - select type(tp) - class is (symba_tp) - lencounter = tp%encounter_check(param, nbody_system, param%dt, nbody_system%irec) - end select - end select end if end associate From e85df57540bb649a15d9da77257adaee757c46fb Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 21 Feb 2024 19:39:53 -0500 Subject: [PATCH 225/324] Started work on having pl-tp collisions recorded in the collision.nc file. Still need to get tp snapshots saved --- src/collision/collision_io.f90 | 2 + src/collision/collision_resolve.f90 | 51 +++++++++++++ src/collision/collision_util.f90 | 109 +++++++++++++++------------- src/swiftest/swiftest_discard.f90 | 2 +- 4 files changed, 112 insertions(+), 52 deletions(-) diff --git a/src/collision/collision_io.f90 b/src/collision/collision_io.f90 index ea8675089..907eb90ec 100644 --- a/src/collision/collision_io.f90 +++ b/src/collision/collision_io.f90 @@ -389,8 +389,10 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) if (allocated(pl)) deallocate(pl) select case(stage) case(1) + if (.not. allocated(before%pl)) cycle allocate(pl, source=before%pl) case(2) + if (.not. allocated(after%pl)) cycle allocate(pl, source=after%pl) end select npl = pl%nbody diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index 545b882fc..ed676b32b 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -707,6 +707,14 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) real(DP), intent(in) :: t !! Current simulation tim real(DP), intent(in) :: dt !! Current simulation step size integer(I4B), intent(in) :: irec !! Current recursion level + ! Internals + class(swiftest_pl), allocatable :: plsub + logical :: lpltp_collision + character(len=STRMAX) :: timestr, idstr + integer(I4B) :: i, j, nnew, loop + integer(I8B) :: k, ncollisions + integer(I4B), dimension(:), allocatable :: idnew + logical, dimension(:), allocatable :: lmask ! Make sure coordinate systems are all synced up due to being inside the recursion at this point select type(nbody_system) @@ -726,6 +734,49 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) ! Discard the collider call nbody_system%tp%discard(nbody_system, param) + + associate(idx1 => pltp_collision%index1, idx2 => pltp_collision%index2) + ncollisions = pltp_collision%nenc + write(timestr,*) t + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & + "***********************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Collision between test particle and massive body detected at time t = " // & + trim(adjustl(timestr))) + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & + "***********************************************************") + + do k = 1_I8B, ncollisions + ! Advance the collision id number and save it + collider%maxid_collision = max(collider%maxid_collision, maxval(nbody_system%pl%info(:)%collision_id)) + collider%maxid_collision = collider%maxid_collision + 1 + collider%collision_id = collider%maxid_collision + write(idstr,*) collider%collision_id + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "collision_id " // trim(adjustl(idstr))) + collider%impactors%regime = COLLRESOLVE_REGIME_MERGE + allocate(lmask, mold=pl%lmask) + lmask(:) = .false. + lmask(idx1(k)) = .true. + + allocate(plsub, mold=pl) + call pl%spill(plsub, lmask, ldestructive=.false.) + + ! Save the before snapshots + select type(before => collider%before) + class is (swiftest_nbody_system) + call move_alloc(plsub, before%pl) + end select + + call collision_history%take_snapshot(param,nbody_system, t, "particle") + + call impactors%dealloc() + end do + + ! Destroy the collision list now that the collisions are resolved + call pltp_collision%setup(0_I8B) + + end associate + end associate end select end select diff --git a/src/collision/collision_util.f90 b/src/collision/collision_util.f90 index 9ce2be434..fab184281 100644 --- a/src/collision/collision_util.f90 +++ b/src/collision/collision_util.f90 @@ -756,8 +756,8 @@ end subroutine collision_util_shift_vector_to_origin module subroutine collision_util_snapshot(self, param, nbody_system, t, arg) !! author: David A. Minton !! - !! Takes a minimal snapshot of the state of the nbody_system during an encounter so that the trajectories - !! can be played back through the encounter + !! Takes a minimal snapshot of the state of the nbody_system during a collision to record the before and after states of the + !! system through the collision. implicit none ! Internals class(collision_storage), intent(inout) :: self !! Swiftest storage object @@ -791,63 +791,70 @@ module subroutine collision_util_snapshot(self, param, nbody_system, t, arg) snapshot%t = t case ("after") phase_val = 2 + case ("particle") + phase_val = -1 + allocate(collision_snapshot :: snapshot) + allocate(snapshot%collider, source=nbody_system%collider) case default - write(*,*) "collision_util_snapshot requies either 'before' or 'after' passed to 'arg'" + write(*,*) "collision_util_snapshot requies either 'before', 'after', or 'particle' passed to 'arg'" return end select - ! Get and record the energy of the system before the collision - call nbody_system%get_energy_and_momentum(param) - snapshot%collider%L_orbit(:,phase_val) = nbody_system%L_orbit(:) - snapshot%collider%L_spin(:,phase_val) = nbody_system%L_spin(:) - snapshot%collider%L_total(:,phase_val) = nbody_system%L_total(:) - snapshot%collider%ke_orbit(phase_val) = nbody_system%ke_orbit - snapshot%collider%ke_spin(phase_val) = nbody_system%ke_spin - snapshot%collider%pe(phase_val) = nbody_system%pe - snapshot%collider%be(phase_val) = nbody_system%be - snapshot%collider%te(phase_val) = nbody_system%te - - if (stage == "after") then - select type(before_snap => snapshot%collider%before ) - class is (swiftest_nbody_system) - select type(before_orig => nbody_system%collider%before) + if (stage /= "particle" ) then + ! Get and record the energy of the system before the collision + call nbody_system%get_energy_and_momentum(param) + snapshot%collider%L_orbit(:,phase_val) = nbody_system%L_orbit(:) + snapshot%collider%L_spin(:,phase_val) = nbody_system%L_spin(:) + snapshot%collider%L_total(:,phase_val) = nbody_system%L_total(:) + snapshot%collider%ke_orbit(phase_val) = nbody_system%ke_orbit + snapshot%collider%ke_spin(phase_val) = nbody_system%ke_spin + snapshot%collider%pe(phase_val) = nbody_system%pe + snapshot%collider%be(phase_val) = nbody_system%be + snapshot%collider%te(phase_val) = nbody_system%te + + if (stage == "after") then + select type(before_snap => snapshot%collider%before ) class is (swiftest_nbody_system) - select type(plsub => before_orig%pl) - class is (swiftest_pl) - ! Log the properties of the old and new bodies - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Removing bodies:") - do i = 1, plsub%nbody - write(message,*) trim(adjustl(plsub%info(i)%name)), " (", trim(adjustl(plsub%info(i)%particle_type)),")" - call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) - end do - - allocate(before_snap%pl, source=plsub) + select type(before_orig => nbody_system%collider%before) + class is (swiftest_nbody_system) + select type(plsub => before_orig%pl) + class is (swiftest_pl) + ! Log the properties of the old and new bodies + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Removing bodies:") + do i = 1, plsub%nbody + write(message,*) trim(adjustl(plsub%info(i)%name)), " (", trim(adjustl(plsub%info(i)%particle_type)),")" + call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) + end do + + allocate(before_snap%pl, source=plsub) + end select + deallocate(before_orig%pl) end select - deallocate(before_orig%pl) - end select - end select - - - select type(after_snap => snapshot%collider%after ) - class is (swiftest_nbody_system) - select type(after_orig => nbody_system%collider%after) - class is (swiftest_nbody_system) - select type(plnew => after_orig%pl) - class is (swiftest_pl) - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Adding bodies:") - do i = 1, plnew%nbody - write(message,*) trim(adjustl(plnew%info(i)%name)), " (", trim(adjustl(plnew%info(i)%particle_type)),")" - call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) - end do - call swiftest_io_log_one_message(COLLISION_LOG_OUT, & - "***********************************************************" // & - "***********************************************************") - allocate(after_snap%pl, source=plnew) end select - deallocate(after_orig%pl) - end select - end select + select type(after_snap => snapshot%collider%after ) + class is (swiftest_nbody_system) + select type(after_orig => nbody_system%collider%after) + class is (swiftest_nbody_system) + select type(plnew => after_orig%pl) + class is (swiftest_pl) + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Adding bodies:") + do i = 1, plnew%nbody + write(message,*) trim(adjustl(plnew%info(i)%name)), " (", trim(adjustl(plnew%info(i)%particle_type)),")" + call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) + end do + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "***********************************************************" // & + "***********************************************************") + allocate(after_snap%pl, source=plnew) + end select + deallocate(after_orig%pl) + end select + end select + end if + end if + + if ((stage == "after") .or. (stage == "particle")) then ! Save the snapshot for posterity call self%save(snapshot) deallocate(snapshot) diff --git a/src/swiftest/swiftest_discard.f90 b/src/swiftest/swiftest_discard.f90 index 2d7d2c7a2..311bf21f1 100644 --- a/src/swiftest/swiftest_discard.f90 +++ b/src/swiftest/swiftest_discard.f90 @@ -274,7 +274,7 @@ subroutine swiftest_discard_pl_tp(tp, nbody_system, param) write(idstri, *) tp%id(i) write(idstrj, *) pl%id(j) write(timestr, *) nbody_system%t - write(message, *) "Test particle " // trim(adjustl(tp%info(i)%name)) // " (" // trim(adjustl(idstri)) // ")" & + write(message, *) "Particle " // trim(adjustl(tp%info(i)%name)) // " (" // trim(adjustl(idstri)) // ")" & // " too close to massive body " // trim(adjustl(pl%info(j)%name)) // " (" // trim(adjustl(idstrj)) // ")" & // " at t = " // trim(adjustl(timestr)) call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) From d96884a45f773aaf60038d5296fcc676f5696005 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Wed, 21 Feb 2024 19:47:00 -0500 Subject: [PATCH 226/324] Added test particles to collision.nc file --- src/collision/collision_io.f90 | 18 +++++++++++++++++- src/collision/collision_resolve.f90 | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/collision/collision_io.f90 b/src/collision/collision_io.f90 index 907eb90ec..bae71daf5 100644 --- a/src/collision/collision_io.f90 +++ b/src/collision/collision_io.f90 @@ -365,9 +365,10 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) class(encounter_storage), intent(inout) :: history !! Collision history object class(base_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals - integer(I4B) :: i, idslot, old_mode, npl, stage, tmp + integer(I4B) :: i, idslot, old_mode, npl, stage, tmp, ntp character(len=NAMELEN) :: charstring class(swiftest_pl), allocatable :: pl + class(swiftest_tp), allocatable :: tp select type(nc => history%nc) class is (collision_netcdf_parameters) @@ -387,13 +388,16 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) class is (swiftest_nbody_system) do stage = 1,2 if (allocated(pl)) deallocate(pl) + if (allocated(tp)) deallocate(tp) select case(stage) case(1) if (.not. allocated(before%pl)) cycle allocate(pl, source=before%pl) + if (allocated(before%tp)) allocate(tp, source=before%tp) case(2) if (.not. allocated(after%pl)) cycle allocate(pl, source=after%pl) + if (allocated(after%tp)) allocate(tp, source=after%tp) end select npl = pl%nbody @@ -415,6 +419,18 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, pl%rot(:,i)*RAD2DEG, start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rotx_varid" ) end if end do + + ntp = pl%nbody + do i = 1, ntp + call nc%find_idslot(tp%id(i), idslot) + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid" ) + charstring = trim(adjustl(tp%info(i)%name)) + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid" ) + charstring = trim(adjustl(tp%info(i)%particle_type)) + call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, tp%rh(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, tp%vh(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid" ) + end do end do end select end select diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index ed676b32b..0d355f3c4 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -709,6 +709,7 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) integer(I4B), intent(in) :: irec !! Current recursion level ! Internals class(swiftest_pl), allocatable :: plsub + class(swiftest_tp), allocatable :: tpsub logical :: lpltp_collision character(len=STRMAX) :: timestr, idstr integer(I4B) :: i, j, nnew, loop @@ -767,6 +768,20 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) call move_alloc(plsub, before%pl) end select + deallocate(lmask) + allocate(lmask, mold=tp%lmask) + lmask(:) = .false. + lmask(idx2(k)) = .true. + + allocate(tpsub, mold=tp) + call tp%spill(tpsub, lmask, ldestructive=.false.) + + ! Save the before snapshots + select type(before => collider%before) + class is (swiftest_nbody_system) + call move_alloc(tpsub, before%tp) + end select + call collision_history%take_snapshot(param,nbody_system, t, "particle") call impactors%dealloc() From a6a96e989da46d6641d1050f54ee72d5150533cf Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 22 Feb 2024 08:54:15 -0500 Subject: [PATCH 227/324] Refactored to enforce line limit and started started to switch to tracking all discards through the collision module --- src/collision/collision_resolve.f90 | 62 +++++++++++++++++------------ src/collision/collision_util.f90 | 4 +- src/swiftest/swiftest_discard.f90 | 44 +++++++++++++------- 3 files changed, 68 insertions(+), 42 deletions(-) diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index 0d355f3c4..cd1661dc3 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -11,19 +11,19 @@ use swiftest contains - module subroutine collision_resolve_consolidate_impactors(self, nbody_system, param, idx_parent, lflag) !! author: David A. Minton !! - !! Loops through the pl-pl collision list and groups families together by index. Outputs the indices of all impactors%id members, - !! and pairs of quantities (x and v vectors, mass, radius, L_spin, and Ip) that can be used to resolve the collisional outcome. + !! Loops through the pl-pl collision list and groups families together by index. Outputs the indices of all impactors%id + !! members, and pairs of quantities (x and v vectors, mass, radius, L_spin, and Ip) that can be used to resolve the + !! collisional outcome. implicit none ! Arguments - class(collision_impactors), intent(out) :: self !! Collision impactors object - class(base_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(base_parameters), intent(in) :: param !! Current run configuration parameters with Swiftest additions - integer(I4B), dimension(:), intent(inout) :: idx_parent !! Index of the two bodies considered the "parents" of the collision - logical, intent(out) :: lflag !! Logical flag indicating whether a impactors%id was successfully created or not + class(collision_impactors),intent(out) :: self !! Collision impactors object + class(base_nbody_system),intent(inout) :: nbody_system !! Swiftest nbody system object + class(base_parameters), intent(in) :: param !! Current run configuration parameters with Swiftest additions + integer(I4B), dimension(:), intent(inout) :: idx_parent !! Index of the two bodies considered the "parents" of the collision + logical, intent(out) :: lflag !! Logical flag indicating whether a impactors%id was successfully created or not ! Internals type collidx_array integer(I4B), dimension(:), allocatable :: id @@ -45,7 +45,8 @@ module subroutine collision_resolve_consolidate_impactors(self, nbody_system, pa ! If all of these bodies share a parent, but this is still a unique collision, move the last child ! out of the parent's position and make it the secondary body if (idx_parent(1) == idx_parent(2)) then - if (nchild(1) == 0) then ! There is only one valid body recorded in this pair (this could happen due to restructuring of the kinship relationships, though it should be rare) + if (nchild(1) == 0) then ! There is only one valid body recorded in this pair (this could happen due to restructuring + ! of the kinship relationships, though it should be rare) lflag = .false. call pl%reset_kinship([idx_parent(1)]) return @@ -233,15 +234,16 @@ module subroutine collision_resolve_extract_plpl(self, nbody_system, param) end associate end do - ! Reassemble collision index list to include only those containing the unique pairs of parents, plus all the non-unique pairs that don't - ! contain a parent body on the unique parent list. + ! Reassemble collision index list to include only those containing the unique pairs of parents, plus all the non-unique + ! pairs that don't contain a parent body on the unique parent list. ncollisions = nunique_parent + count(lplpl_unique_parent) collision_idx = [unique_parent_idx(:), pack(collision_idx(:), lplpl_unique_parent(:))] ! Create a mask that contains only the pl-pl encounters that did not result in a collision, and then discard them lplpl_collision(:) = .false. lplpl_collision(collision_idx(:)) = .true. - call self%spill(nbody_system%plpl_collision, lplpl_collision, ldestructive=.true.) ! Extract any encounters that are not collisions from the list. + ! Extract any encounters that are not collisions from the list. + call self%spill(nbody_system%plpl_collision, lplpl_collision, ldestructive=.true.) end associate end select end select @@ -281,7 +283,8 @@ module subroutine collision_resolve_extract_pltp(self, nbody_system, param) ! Create a mask that contains only the pl-tp encounters that did not result in a collision, and then discard them lpltp_collision(:) = .false. lpltp_collision(collision_idx(:)) = .true. - call self%spill(nbody_system%pltp_collision, lpltp_collision, ldestructive=.true.) ! Extract any encounters that are not collisions from the list. + ! Extract any encounters that are not collisions from the list. + call self%spill(nbody_system%pltp_collision, lpltp_collision, ldestructive=.true.) end associate end select end select @@ -383,8 +386,9 @@ module subroutine collision_resolve_mergeaddsub(nbody_system, param, t, status) class is (swiftest_nbody_system) select type(param) class is (swiftest_parameters) - associate(pl => nbody_system%pl, pl_discards => nbody_system%pl_discards, info => nbody_system%pl%info, pl_adds => nbody_system%pl_adds, cb => nbody_system%cb, & - collider => nbody_system%collider, impactors => nbody_system%collider%impactors,fragments => nbody_system%collider%fragments) + associate(pl => nbody_system%pl, pl_discards => nbody_system%pl_discards, info => nbody_system%pl%info, & + pl_adds => nbody_system%pl_adds, cb => nbody_system%cb, collider => nbody_system%collider, & + impactors => nbody_system%collider%impactors,fragments => nbody_system%collider%fragments) ! Add the impactors%id bodies to the subtraction list nimpactors = impactors%ncoll @@ -646,10 +650,12 @@ module subroutine collision_resolve_plpl(self, nbody_system, param, t, dt, irec) allocate(idnew, source=nbody_system%pl_adds%id) mnew = sum(nbody_system%pl_adds%mass(:)) - ! Rearrange the arrays: Remove discarded bodies, add any new bodies, re-sort, and recompute all indices and encounter lists + ! Rearrange the arrays: Remove discarded bodies, add any new bodies, re-sort, and recompute all indices and + ! encounter lists call pl%rearray(nbody_system, param) - ! Destroy the add/discard list so that we don't append the same body multiple times if another collision is detected + ! Destroy the add/discard list so that we don't append the same body multiple times if another collision + ! is detected call nbody_system%pl_discards%setup(0, param) call nbody_system%pl_adds%setup(0, param) @@ -673,13 +679,17 @@ module subroutine collision_resolve_plpl(self, nbody_system, param, t, dt, irec) end if - ! Check whether or not any of the particles that were just added are themselves in a collision state. This will generate a new plpl_collision + ! Check whether or not any of the particles that were just added are themselves in a collision state. This will + ! generate a new plpl_collision call self%collision_check(nbody_system, param, t, dt, irec, lplpl_collision) if (.not.lplpl_collision) exit if (loop == MAXCASCADE) then - call swiftest_io_log_one_message(COLLISION_LOG_OUT,"A runaway collisional cascade has been detected in collision_resolve_plpl.") - call swiftest_io_log_one_message(COLLISION_LOG_OUT,"Consider reducing the step size or changing the parameters in the collisional model to reduce the number of fragments.") + call swiftest_io_log_one_message(COLLISION_LOG_OUT,"A runaway collisional cascade has been detected in " // & + "collision_resolve_plpl.") + call swiftest_io_log_one_message(COLLISION_LOG_OUT,"Consider reducing the step size or changing the " // & + "parameters in the collisional model to reduce the " // & + "number of fragments.") call base_util_exit(FAILURE,unit=param%display_unit) end if end associate @@ -740,12 +750,12 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) ncollisions = pltp_collision%nenc write(timestr,*) t call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & - "***********************************************************") - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Collision between test particle and massive body detected at time t = " // & - trim(adjustl(timestr))) - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & - "***********************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT,"***********************************************************" // & + "***********************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Collision between test particle and massive body detected " // & + "at time t = " // trim(adjustl(timestr))) + call swiftest_io_log_one_message(COLLISION_LOG_OUT,"***********************************************************" // & + "***********************************************************") do k = 1_I8B, ncollisions ! Advance the collision id number and save it diff --git a/src/collision/collision_util.f90 b/src/collision/collision_util.f90 index fab184281..49c3e1814 100644 --- a/src/collision/collision_util.f90 +++ b/src/collision/collision_util.f90 @@ -285,6 +285,7 @@ module subroutine collision_util_dealloc_snapshot(self) return end subroutine collision_util_dealloc_snapshot + module subroutine collision_util_dealloc_impactors(self) !! author: David A. Minton !! @@ -419,7 +420,8 @@ end subroutine collision_util_dealloc_basic module subroutine collision_util_reset_fragments(self) !! author: David A. Minton !! - !! Resets all position and velocity-dependent fragment quantities in order to do a fresh calculation (does not reset mass, radius, or other values that get set prior to the call to fraggle_generate) + !! Resets all position and velocity-dependent fragment quantities in order to do a fresh calculation (does not reset mass, + !! radius, or other values that get set prior to the call to fraggle_generate) implicit none ! Arguments class(collision_fragments), intent(inout) :: self diff --git a/src/swiftest/swiftest_discard.f90 b/src/swiftest/swiftest_discard.f90 index 311bf21f1..b96112e62 100644 --- a/src/swiftest/swiftest_discard.f90 +++ b/src/swiftest/swiftest_discard.f90 @@ -25,7 +25,7 @@ module subroutine swiftest_discard_system(self, param) lpl_check = allocated(self%pl_discards) ltp_check = allocated(self%tp_discards) - associate(nbody_system => self, tp => self%tp, pl => self%pl, tp_discards => self%tp_discards, pl_discards => self%pl_discards) + associate(nbody_system => self,tp => self%tp,pl => self%pl,tp_discards => self%tp_discards,pl_discards => self%pl_discards) lpl_discards = .false. ltp_discards = .false. if (lpl_check .and. pl%nbody > 0) then @@ -59,8 +59,8 @@ end subroutine swiftest_discard_system module subroutine swiftest_discard_pl(self, nbody_system, param) !! author: David A. Minton !! - !! Placeholder method for discarding massive bodies. This method does nothing except to ensure that the discard flag is set to false. - !! This method is intended to be overridden by more advanced integrators. + !! Placeholder method for discarding massive bodies. This method does nothing except to ensure that the discard flag is set + !! to false. This method is intended to be overridden by more advanced integrators. implicit none ! Arguments class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object @@ -87,14 +87,14 @@ module subroutine swiftest_discard_tp(self, nbody_system, param) class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameter ! Internals - logical, dimension(:), allocatable :: ldiscard - integer(I4B) :: npl, ntp + logical, dimension(self%nbody) :: ldiscard + integer(I4B) :: i, nstart, nend, nsub + class(swiftest_tp), allocatable :: tpsub if (self%nbody == 0) return - associate(tp => self, cb => nbody_system%cb, pl => nbody_system%pl) - ntp = tp%nbody - npl = pl%nbody + associate(tp => self, ntp => self%nbody, cb => nbody_system%cb, pl => nbody_system%pl, npl => nbody_system%pl%nbody, & + tp_discards => nbody_system%tp_discards) if ((param%rmin >= 0.0_DP) .or. (param%rmax >= 0.0_DP) .or. & (param%rmaxu >= 0.0_DP) .or. ((param%qmin >= 0.0_DP) .and. (param%qmin_coord == "BARY"))) then @@ -102,12 +102,25 @@ module subroutine swiftest_discard_tp(self, nbody_system, param) call tp%h2b(cb) end if - if ((param%rmin >= 0.0_DP) .or. (param%rmax >= 0.0_DP) .or. (param%rmaxu >= 0.0_DP)) call swiftest_discard_cb_tp(tp, nbody_system, param) - if (param%qmin >= 0.0_DP) call swiftest_discard_peri_tp(tp, nbody_system, param) - if (param%lclose) call swiftest_discard_pl_tp(tp, nbody_system, param) + if ((param%rmin >= 0.0_DP) .or. & + (param%rmax >= 0.0_DP) .or. & + (param%rmaxu >= 0.0_DP)) then + call swiftest_discard_cb_tp(tp, nbody_system, param) + end if + if (param%qmin >= 0.0_DP) then + call swiftest_discard_peri_tp(tp, nbody_system, param) + end if + if (param%lclose) then + call swiftest_discard_pl_tp(tp, nbody_system, param) + end if if (any(tp%ldiscard(1:ntp))) then - allocate(ldiscard, source=tp%ldiscard) - call tp%spill(nbody_system%tp_discards, ldiscard(1:ntp), ldestructive=.true.) + ldiscard(1:ntp) = tp%ldiscard(1:ntp) + allocate(tpsub, mold=tp) + call tp%spill(tpsub, ldiscard, ldestructive=.false.) + nsub = tpsub%nbody + nstart = tp_discards%nbody + 1 + nend = tp_discards%nbody + nsub + call tp_discards%append(tpsub, lsource_mask=[(.true., i = 1, nsub)]) end if end associate @@ -275,8 +288,9 @@ subroutine swiftest_discard_pl_tp(tp, nbody_system, param) write(idstrj, *) pl%id(j) write(timestr, *) nbody_system%t write(message, *) "Particle " // trim(adjustl(tp%info(i)%name)) // " (" // trim(adjustl(idstri)) // ")" & - // " too close to massive body " // trim(adjustl(pl%info(j)%name)) // " (" // trim(adjustl(idstrj)) // ")" & - // " at t = " // trim(adjustl(timestr)) + // " too close to massive body " // trim(adjustl(pl%info(j)%name)) // " (" & + // trim(adjustl(idstrj)) // ")" & + // " at t = " // trim(adjustl(timestr)) call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) tp%ldiscard(i) = .true. call tp%info(i)%set_value(status="DISCARDED_PLR", discard_time=nbody_system%t, discard_rh=tp%rh(:,i), & From b050701d821c12fd9f90ea4b694cf93de0446d82 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 12:46:37 -0500 Subject: [PATCH 228/324] Fixed typo --- src/collision/collision_io.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collision/collision_io.f90 b/src/collision/collision_io.f90 index bae71daf5..3ad6e332f 100644 --- a/src/collision/collision_io.f90 +++ b/src/collision/collision_io.f90 @@ -420,7 +420,7 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) end if end do - ntp = pl%nbody + ntp = tp%nbody do i = 1, ntp call nc%find_idslot(tp%id(i), idslot) call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid" ) From 7800b5fd73af2641f07b18f203738a973a5cb8a3 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 13:00:55 -0500 Subject: [PATCH 229/324] Refactored to enforce line limit --- src/collision/collision_io.f90 | 317 +++++++++++++++++++++------------ 1 file changed, 208 insertions(+), 109 deletions(-) diff --git a/src/collision/collision_io.f90 b/src/collision/collision_io.f90 index 3ad6e332f..bcb7ba058 100644 --- a/src/collision/collision_io.f90 +++ b/src/collision/collision_io.f90 @@ -125,7 +125,8 @@ end subroutine collision_io_netcdf_dump module subroutine collision_io_netcdf_initialize_output(self, param) !! author: David A. Minton !! - !! Initialize a NetCDF fragment history file system. This is a simplified version of the main simulation output NetCDF file, but with fewer variables. + !! Initialize a NetCDF fragment history file system. This is a simplified version of the main simulation output NetCDF file, + !! but with fewer variables. use, intrinsic :: ieee_arithmetic use netcdf implicit none @@ -163,102 +164,143 @@ module subroutine collision_io_netcdf_initialize_output(self, param) close(unit=LUN, status="delete") end if - call netcdf_io_check( nf90_create(nc%file_name, NF90_NETCDF4, nc%id), "collision_io_netcdf_initialize_output nf90_create" ) + call netcdf_io_check( nf90_create(nc%file_name, NF90_NETCDF4, nc%id), & + "collision_io_netcdf_initialize_output nf90_create" ) nc%lfile_is_open = .true. ! Dimensions - call netcdf_io_check( nf90_def_dim(nc%id, nc%collision_id_varname, NF90_UNLIMITED, nc%collision_id_dimid), "collision_io_netcdf_initialize_output nf90_def_dim collision_id_dimid" ) ! Dimension to store individual collision events - call netcdf_io_check( nf90_def_dim(nc%id, nc%space_dimname, NDIM, nc%space_dimid), "collision_io_netcdf_initialize_output nf90_def_dim space_dimid" ) ! 3D space dimension - call netcdf_io_check( nf90_def_dim(nc%id, nc%name_dimname, NF90_UNLIMITED, nc%name_dimid), "collision_io_netcdf_initialize_output nf90_def_dim name_dimid" ) ! Dimension to store particle id numbers - call netcdf_io_check( nf90_def_dim(nc%id, nc%str_dimname, NAMELEN, nc%str_dimid), "collision_io_netcdf_initialize_output nf90_def_dim str_dimid" ) ! Dimension for string variables (aka character arrays) - call netcdf_io_check( nf90_def_dim(nc%id, nc%stage_dimname, 2, nc%stage_dimid), "collision_io_netcdf_initialize_output nf90_def_dim stage_dimid" ) ! Dimension for stage variables (aka "before" vs. "after" + call netcdf_io_check( nf90_def_dim(nc%id, nc%collision_id_varname, NF90_UNLIMITED, nc%collision_id_dimid), & + "collision_io_netcdf_initialize_output nf90_def_dim collision_id_dimid" ) ! Dimension to store collision events + call netcdf_io_check( nf90_def_dim(nc%id, nc%space_dimname, NDIM, nc%space_dimid), & + "collision_io_netcdf_initialize_output nf90_def_dim space_dimid") ! 3D space dimension + call netcdf_io_check( nf90_def_dim(nc%id, nc%name_dimname, NF90_UNLIMITED, nc%name_dimid), & + "collision_io_netcdf_initialize_output nf90_def_dim name_dimid") ! Dimension to store particle id numbers + call netcdf_io_check( nf90_def_dim(nc%id, nc%str_dimname, NAMELEN, nc%str_dimid), & + "collision_io_netcdf_initialize_output nf90_def_dim str_dimid") ! Dimension for string variables (character arrays) + call netcdf_io_check( nf90_def_dim(nc%id, nc%stage_dimname, 2, nc%stage_dimid), & + "collision_io_netcdf_initialize_output nf90_def_dim stage_dimid" ) ! Dimension for stage variables + ! (aka "before" vs. "after") ! Dimension coordinates - call netcdf_io_check( nf90_def_var(nc%id, nc%collision_id_varname, NF90_INT, [nc%collision_id_dimid], nc%collision_id_varid), "collision_io_netcdf_initialize_output nf90_def_var collision_id_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%space_dimname, NF90_CHAR, nc%space_dimid, nc%space_varid), "collision_io_netcdf_initialize_output nf90_def_var space_varid" ) - call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, [nc%str_dimid, nc%name_dimid], nc%name_varid), "collision_io_netcdf_initialize_output nf90_def_var name_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%stage_dimname, NF90_CHAR, [nc%str_dimid, nc%stage_dimid], nc%stage_varid), "collision_io_netcdf_initialize_output nf90_def_var stage_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%collision_id_varname, NF90_INT, & + [nc%collision_id_dimid], nc%collision_id_varid), & + "collision_io_netcdf_initialize_output nf90_def_var collision_id_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%space_dimname, NF90_CHAR, nc%space_dimid, nc%space_varid), & + "collision_io_netcdf_initialize_output nf90_def_var space_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, & + [nc%str_dimid, nc%name_dimid], nc%name_varid), & + "collision_io_netcdf_initialize_output nf90_def_var name_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%stage_dimname, NF90_CHAR, & + [nc%str_dimid, nc%stage_dimid], nc%stage_varid), & + "collision_io_netcdf_initialize_output nf90_def_var stage_varid") ! Variables - call netcdf_io_check( nf90_def_var(nc%id, nc%id_varname, NF90_INT, nc%name_dimid, nc%id_varid), "collision_io_netcdf_initialize_output nf90_def_var id_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%id_varname, NF90_INT, nc%name_dimid, nc%id_varid), & + "collision_io_netcdf_initialize_output nf90_def_var id_varid" ) call netcdf_io_check( nf90_def_var(nc%id, nc%time_dimname, nc%out_type, & - nc%collision_id_dimid, nc%time_varid), "collision_io_netcdf_initialize_output nf90_def_var time_varid" ) - call netcdf_io_check( nf90_def_var(nc%id, nc%regime_varname, NF90_CHAR, & - [nc%str_dimid, nc%collision_id_dimid], nc%regime_varid), "collision_io_netcdf_initialize_output nf90_def_var regime_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%Qloss_varname, nc%out_type, & - [ nc%collision_id_dimid], nc%Qloss_varid), "collision_io_netcdf_initialize_output nf90_def_var Qloss_varid") + nc%collision_id_dimid, nc%time_varid), & + "collision_io_netcdf_initialize_output nf90_def_var time_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%regime_varname, NF90_CHAR, & + [nc%str_dimid, nc%collision_id_dimid], nc%regime_varid), & + "collision_io_netcdf_initialize_output nf90_def_var regime_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%Qloss_varname, nc%out_type, & + [nc%collision_id_dimid], nc%Qloss_varid), & + "collision_io_netcdf_initialize_output nf90_def_var Qloss_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%ptype_varname, NF90_CHAR, & - [nc%str_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%ptype_varid), "collision_io_netcdf_initialize_output nf90_def_var ptype_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%ptype_varname, NF90_CHAR, & + [nc%str_dimid, nc%name_dimid,nc%stage_dimid, nc%collision_id_dimid], nc%ptype_varid), & + "collision_io_netcdf_initialize_output nf90_def_var ptype_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%rh_varname, nc%out_type,& - [ nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%rh_varid), "collision_io_netcdf_initialize_output nf90_def_var rh_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%rh_varname, nc%out_type, & + [nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%rh_varid), & + "collision_io_netcdf_initialize_output nf90_def_var rh_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%vh_varname, nc%out_type,& - [ nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%vh_varid), "collision_io_netcdf_initialize_output nf90_def_var vh_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%vh_varname, nc%out_type, & + [nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%vh_varid), & + "collision_io_netcdf_initialize_output nf90_def_var vh_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%Gmass_varname, nc%out_type,& - [ nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%Gmass_varid), "collision_io_netcdf_initialize_output nf90_def_var Gmass_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%Gmass_varname, nc%out_type, & + [nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%Gmass_varid), & + "collision_io_netcdf_initialize_output nf90_def_var Gmass_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%radius_varname, nc%out_type,& - [ nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%radius_varid), "collision_io_netcdf_initialize_output nf90_def_var radius_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%radius_varname, nc%out_type, & + [nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%radius_varid), & + "collision_io_netcdf_initialize_output nf90_def_var radius_varid") if (param%lrotation) then call netcdf_io_check( nf90_def_var(nc%id, nc%Ip_varname, nc%out_type,& - [ nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%Ip_varid), "collision_io_netcdf_initialize_output nf90_def_var Ip_varid") + [nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%Ip_varid), & + "collision_io_netcdf_initialize_output nf90_def_var Ip_varid") call netcdf_io_check( nf90_def_var(nc%id, nc%rot_varname, nc%out_type,& - [ nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%rot_varid), "collision_io_netcdf_initialize_output nf90_def_var rot_varid") + [nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%rot_varid), & + "collision_io_netcdf_initialize_output nf90_def_var rot_varid") end if if (param%lenergy) then - call netcdf_io_check( nf90_def_var(nc%id, nc%ke_orb_varname, nc%out_type,& - [ nc%stage_dimid, nc%collision_id_dimid], nc%KE_orb_varid), "collision_io_netcdf_initialize_output nf90_def_var KE_orb_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%ke_orb_varname, nc%out_type, & + [nc%stage_dimid, nc%collision_id_dimid], nc%KE_orb_varid), & + "collision_io_netcdf_initialize_output nf90_def_var KE_orb_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%ke_spin_varname, nc%out_type,& - [ nc%stage_dimid, nc%collision_id_dimid], nc%KE_spin_varid), "collision_io_netcdf_initialize_output nf90_def_var KE_spin_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%ke_spin_varname, nc%out_type, & + [nc%stage_dimid, nc%collision_id_dimid], nc%KE_spin_varid), & + "collision_io_netcdf_initialize_output nf90_def_var KE_spin_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%pe_varname, nc%out_type,& - [ nc%stage_dimid, nc%collision_id_dimid], nc%PE_varid), "collision_io_netcdf_initialize_output nf90_def_var PE_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%pe_varname, nc%out_type, & + [nc%stage_dimid, nc%collision_id_dimid], nc%PE_varid), & + "collision_io_netcdf_initialize_output nf90_def_var PE_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%be_varname, nc%out_type,& - [ nc%stage_dimid, nc%collision_id_dimid], nc%BE_varid), "collision_io_netcdf_initialize_output nf90_def_var BE_varid" ) - call netcdf_io_check( nf90_def_var(nc%id, nc%te_varname, nc%out_type,& - [ nc%stage_dimid, nc%collision_id_dimid], nc%TE_varid), "collision_io_netcdf_initialize_output nf90_def_var TE_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%be_varname, nc%out_type, & + [nc%stage_dimid, nc%collision_id_dimid], nc%BE_varid), & + "collision_io_netcdf_initialize_output nf90_def_var BE_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%te_varname, nc%out_type, & + [nc%stage_dimid, nc%collision_id_dimid], nc%TE_varid), & + "collision_io_netcdf_initialize_output nf90_def_var TE_varid") if (param%lrotation) then - call netcdf_io_check( nf90_def_var(nc%id, nc%L_orbit_varname, nc%out_type, & - [ nc%space_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%L_orbit_varid), "collision_io_netcdf_initialize_output nf90_def_var L_orbit_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%L_orbit_varname, nc%out_type, & + [nc%space_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%L_orbit_varid), & + "collision_io_netcdf_initialize_output nf90_def_var L_orbit_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%L_spin_varname, nc%out_type,& - [ nc%space_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%L_spin_varid), "collision_io_netcdf_initialize_output nf90_def_var L_spin_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%L_spin_varname,nc%out_type, & + [nc%space_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%L_spin_varid), & + "collision_io_netcdf_initialize_output nf90_def_var L_spin_varid") end if end if - call netcdf_io_check( nf90_inquire(nc%id, nVariables=nvar), "collision_io_netcdf_initialize_output nf90_inquire nVariables" ) + call netcdf_io_check( nf90_inquire(nc%id, nVariables=nvar), & + "collision_io_netcdf_initialize_output nf90_inquire nVariables") do varid = 1, nvar - call netcdf_io_check( nf90_inquire_variable(nc%id, varid, xtype=vartype, ndims=ndims), "collision_io_netcdf_initialize_output nf90_inquire_variable" ) + call netcdf_io_check( nf90_inquire_variable(nc%id, varid, xtype=vartype, ndims=ndims), & + "collision_io_netcdf_initialize_output nf90_inquire_variable") select case(vartype) case(NF90_INT) - call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, NF90_FILL_INT), "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_INT" ) + call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, NF90_FILL_INT), & + "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_INT") case(NF90_FLOAT) - call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, sfill), "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_FLOAT" ) + call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, sfill), & + "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_FLOAT") case(NF90_DOUBLE) - call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, dfill), "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_DOUBLE" ) + call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, dfill), & + "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_DOUBLE") case(NF90_CHAR) - call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, 0), "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_CHAR" ) + call netcdf_io_check( nf90_def_var_fill(nc%id, varid, NO_FILL, 0), & + "collision_io_netcdf_initialize_output nf90_def_var_fill NF90_CHAR") end select end do ! Take the file out of define mode - call netcdf_io_check( nf90_enddef(nc%id), "collision_io_netcdf_initialize_output nf90_enddef" ) + call netcdf_io_check( nf90_enddef(nc%id), "collision_io_netcdf_initialize_output nf90_enddef") ! Add in the space and stage dimension coordinates - call netcdf_io_check( nf90_put_var(nc%id, nc%space_varid, nc%space_coords, start=[1], count=[NDIM]), "collision_io_netcdf_initialize_output nf90_put_var space" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%stage_varid, nc%stage_coords(1), start=[1,1], count=[len(nc%stage_coords(1)),1]), "collision_io_netcdf_initialize_output nf90_put_var stage 1" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%stage_varid, nc%stage_coords(2), start=[1,2], count=[len(nc%stage_coords(2)),1]), "collision_io_netcdf_initialize_output nf90_put_var stage 2" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%space_varid, nc%space_coords, start=[1], count=[NDIM]), & + "collision_io_netcdf_initialize_output nf90_put_var space" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%stage_varid, nc%stage_coords(1), start=[1,1], & + count=[len(nc%stage_coords(1)),1]), "collision_io_netcdf_initialize_output nf90_put_var stage 1") + call netcdf_io_check( nf90_put_var(nc%id, nc%stage_varid, nc%stage_coords(2), start=[1,2], & + count=[len(nc%stage_coords(2)),1]), "collision_io_netcdf_initialize_output nf90_put_var stage 2" ) end associate end select @@ -306,44 +348,72 @@ module subroutine collision_io_netcdf_open(self, param, readonly) self%lfile_is_open = .true. ! Dimensions - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%collision_id_varname, nc%collision_id_dimid), "collision_io_netcdf_open nf90_inq_dimid collision_id_dimid" ) - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%collision_id_dimid, nc%collision_id_varname, len=nc%max_idslot), "collision_io_find_idslot nf90_inquire_dimension max_idslot" ) - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%space_dimname, nc%space_dimid), "collision_io_netcdf_open nf90_inq_dimid space_dimid" ) - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%name_dimname, nc%name_dimid), "collision_io_netcdf_open nf90_inq_dimid name_dimid" ) - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%str_dimname, nc%str_dimid), "collision_io_netcdf_open nf90_inq_dimid str_dimid" ) - call netcdf_io_check( nf90_inq_dimid(nc%id, nc%stage_dimname, nc%stage_dimid), "collision_io_netcdf_open nf90_inq_dimid stage_dimid" ) + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%collision_id_varname, nc%collision_id_dimid), & + "collision_io_netcdf_open nf90_inq_dimid collision_id_dimid" ) + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%collision_id_dimid, nc%collision_id_varname, len=nc%max_idslot),& + "collision_io_find_idslot nf90_inquire_dimension max_idslot" ) + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%space_dimname, nc%space_dimid), & + "collision_io_netcdf_open nf90_inq_dimid space_dimid" ) + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%name_dimname, nc%name_dimid), & + "collision_io_netcdf_open nf90_inq_dimid name_dimid" ) + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%str_dimname, nc%str_dimid), & + "collision_io_netcdf_open nf90_inq_dimid str_dimid" ) + call netcdf_io_check( nf90_inq_dimid(nc%id, nc%stage_dimname, nc%stage_dimid), & + "collision_io_netcdf_open nf90_inq_dimid stage_dimid" ) ! Dimension coordinates - call netcdf_io_check( nf90_inq_varid(nc%id, nc%collision_id_varname, nc%collision_id_varid), "collision_io_netcdf_open nf90_inq_varid collision_id_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%space_dimname, nc%space_varid), "collision_io_netcdf_open nf90_inq_varid space_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%name_dimname, nc%name_varid), "collision_io_netcdf_open nf90_inq_varid name_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%stage_dimname, nc%stage_varid), "collision_io_netcdf_open nf90_inq_varid stage_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%collision_id_varname, nc%collision_id_varid), & + "collision_io_netcdf_open nf90_inq_varid collision_id_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%space_dimname, nc%space_varid), & + "collision_io_netcdf_open nf90_inq_varid space_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%name_dimname, nc%name_varid), & + "collision_io_netcdf_open nf90_inq_varid name_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%stage_dimname, nc%stage_varid), & + "collision_io_netcdf_open nf90_inq_varid stage_varid" ) ! Required Variables - call netcdf_io_check( nf90_inq_varid(nc%id, nc%id_varname, nc%id_varid), "collision_io_netcdf_open nf90_inq_varid name_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%time_dimname, nc%time_varid), "collision_io_netcdf_open nf90_inq_varid time_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%regime_varname, nc%regime_varid), "collision_io_netcdf_open nf90_inq_varid regime_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%Qloss_varname, nc%Qloss_varid), "collision_io_netcdf_open nf90_inq_varid Qloss_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%ptype_varname, nc%ptype_varid), "collision_io_netcdf_open nf90_inq_varid ptype_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%rh_varname, nc%rh_varid), "collision_io_netcdf_open nf90_inq_varid rh_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%vh_varname, nc%vh_varid), "collision_io_netcdf_open nf90_inq_varid vh_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%Gmass_varname, nc%Gmass_varid), "collision_io_netcdf_open nf90_inq_varid Gmass_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%radius_varname, nc%radius_varid), "collision_io_netcdf_open nf90_inq_varid radius_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%id_varname, nc%id_varid), & + "collision_io_netcdf_open nf90_inq_varid name_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%time_dimname, nc%time_varid), & + "collision_io_netcdf_open nf90_inq_varid time_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%regime_varname, nc%regime_varid), & + "collision_io_netcdf_open nf90_inq_varid regime_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%Qloss_varname, nc%Qloss_varid), & + "collision_io_netcdf_open nf90_inq_varid Qloss_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%ptype_varname, nc%ptype_varid), & + "collision_io_netcdf_open nf90_inq_varid ptype_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%rh_varname, nc%rh_varid), & + "collision_io_netcdf_open nf90_inq_varid rh_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%vh_varname, nc%vh_varid), & + "collision_io_netcdf_open nf90_inq_varid vh_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%Gmass_varname, nc%Gmass_varid), & + "collision_io_netcdf_open nf90_inq_varid Gmass_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%radius_varname, nc%radius_varid), & + "collision_io_netcdf_open nf90_inq_varid radius_varid" ) if (param%lrotation) then - call netcdf_io_check( nf90_inq_varid(nc%id, nc%Ip_varname, nc%Ip_varid), "collision_io_netcdf_open nf90_inq_varid Ip_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%rot_varname, nc%rot_varid), "collision_io_netcdf_open nf90_inq_varid rot_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%Ip_varname, nc%Ip_varid), & + "collision_io_netcdf_open nf90_inq_varid Ip_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%rot_varname, nc%rot_varid), & + "collision_io_netcdf_open nf90_inq_varid rot_varid" ) end if if (param%lenergy) then - call netcdf_io_check( nf90_inq_varid(nc%id, nc%ke_orb_varname, nc%ke_orb_varid), "collision_io_netcdf_open nf90_inq_varid ke_orb_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%pe_varname, nc%pe_varid), "collision_io_netcdf_open nf90_inq_varid pe_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%be_varname, nc%be_varid), "collision_io_netcdf_open nf90_inq_varid be_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%te_varname, nc%te_varid), "collision_io_netcdf_open nf90_inq_varid te_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%L_orbit_varname, nc%L_orbit_varid), "collision_io_netcdf_open nf90_inq_varid L_orbit_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%ke_orb_varname, nc%ke_orb_varid), & + "collision_io_netcdf_open nf90_inq_varid ke_orb_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%pe_varname, nc%pe_varid), & + "collision_io_netcdf_open nf90_inq_varid pe_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%be_varname, nc%be_varid), & + "collision_io_netcdf_open nf90_inq_varid be_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%te_varname, nc%te_varid), & + "collision_io_netcdf_open nf90_inq_varid te_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%L_orbit_varname, nc%L_orbit_varid), & + "collision_io_netcdf_open nf90_inq_varid L_orbit_varid" ) if (param%lrotation) then - call netcdf_io_check( nf90_inq_varid(nc%id, nc%ke_spin_varname, nc%ke_spin_varid), "collision_io_netcdf_open nf90_inq_varid ke_spin_varid" ) - call netcdf_io_check( nf90_inq_varid(nc%id, nc%L_spin_varname, nc%L_spin_varid), "collision_io_netcdf_open nf90_inq_varid L_spin_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%ke_spin_varname, nc%ke_spin_varid), & + "collision_io_netcdf_open nf90_inq_varid ke_spin_varid" ) + call netcdf_io_check( nf90_inq_varid(nc%id, nc%L_spin_varname, nc%L_spin_varid), & + "collision_io_netcdf_open nf90_inq_varid L_spin_varid" ) end if end if @@ -372,15 +442,21 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) select type(nc => history%nc) class is (collision_netcdf_parameters) - associate(collider => self%collider, impactors => self%collider%impactors, fragments => self%collider%fragments, eslot => self%collider%collision_id) - call netcdf_io_check( nf90_set_fill(nc%id, NF90_NOFILL, old_mode), "collision_io_netcdf_write_frame_snapshot nf90_set_fill" ) + associate(collider => self%collider, impactors => self%collider%impactors, fragments => self%collider%fragments, & + eslot => self%collider%collision_id) + call netcdf_io_check( nf90_set_fill(nc%id, NF90_NOFILL, old_mode), & + "collision_io_netcdf_write_frame_snapshot nf90_set_fill" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%collision_id_varid, eslot, start=[eslot]), "collision_io_netcdf_write_frame_snapshot nf90_put_var collision_id_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%time_varid, self%t, start=[eslot]), "collision_io_netcdf_write_frame_snapshot nf90_put_var time_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%collision_id_varid, eslot, start=[eslot]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var collision_id_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%time_varid, self%t, start=[eslot]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var time_varid" ) charstring = trim(adjustl(REGIME_NAMES(impactors%regime))) - call netcdf_io_check( nf90_put_var(nc%id, nc%regime_varid, charstring, start=[1, eslot], count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var regime_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%Qloss_varid, impactors%Qloss, start=[eslot] ), "collision_io_netcdf_write_frame_snapshot nf90_put_var Qloss_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%regime_varid, charstring, start=[1, eslot], & + count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var regime_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%Qloss_varid, impactors%Qloss, start=[eslot] ), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var Qloss_varid" ) select type(before =>self%collider%before) class is (swiftest_nbody_system) @@ -401,48 +477,71 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) end select npl = pl%nbody - ! This ensures that there first idslot will have the first body in it, not id 0 which is the default for a new idvals array + ! This ensures that there first idslot will have the first body in it, not id 0 which is the default for a new + ! idvals array if (.not.allocated(nc%idvals)) allocate(nc%idvals, source=pl%id) do i = 1, npl call nc%find_idslot(pl%id(i), idslot) - call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, pl%id(i), start=[ idslot ]), "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, pl%id(i), start=[ idslot ]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: pl") charstring = trim(adjustl(pl%info(i)%name)) - call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & + count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: pl") charstring = trim(adjustl(pl%info(i)%particle_type)) - call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, pl%rh(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, pl%vh(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%Gmass_varid, pl%Gmass(i), start=[ idslot, stage, eslot]), "collision_io_netcdf_write_frame_snapshot nf90_put_var Gmass_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%radius_varid, pl%radius(i), start=[ idslot, stage, eslot]), "collision_io_netcdf_write_frame_snapshot nf90_put_var radius_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & + count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, pl%rh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, pl%vh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%Gmass_varid, pl%Gmass(i), start=[ idslot, stage, eslot]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var Gmass_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%radius_varid, pl%radius(i), start=[ idslot, stage, eslot]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var radius_varid: pl") if (param%lrotation) then - call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, pl%Ip(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var Ip_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, pl%rot(:,i)*RAD2DEG, start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rotx_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, pl%Ip(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var Ip_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, pl%rot(:,i)*RAD2DEG, & + start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var rotx_varid: pl") end if end do ntp = tp%nbody do i = 1, ntp call nc%find_idslot(tp%id(i), idslot) - call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: tp" ) charstring = trim(adjustl(tp%info(i)%name)) - call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & + count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: tp" ) charstring = trim(adjustl(tp%info(i)%particle_type)) - call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, tp%rh(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, tp%vh(:,i), start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & + count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: tp" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, tp%rh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: tp" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, tp%vh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid: tp" ) end do end do end select end select if (param%lenergy) then - call netcdf_io_check( nf90_put_var(nc%id, nc%ke_orb_varid, collider%ke_orbit(:), start=[ 1, eslot], count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var ke_orb_varid before" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%ke_spin_varid, collider%ke_spin(:), start=[ 1, eslot], count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var ke_spin_varid before" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%pe_varid, collider%pe(:), start=[ 1, eslot], count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var pe_varid before" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%be_varid, collider%be(:), start=[ 1, eslot], count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var pe_varid before" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%te_varid, collider%te(:), start=[ 1, eslot], count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var pe_varid tefore" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%L_orbit_varid, collider%L_orbit(:,:), start=[1, 1, eslot], count=[NDIM, 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var L_orbit_varid before" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%L_spin_varid, collider%L_spin(:,:), start=[1, 1, eslot], count=[NDIM, 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var L_spin_varid before" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%ke_orb_varid, collider%ke_orbit(:), start=[ 1, eslot], & + count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var ke_orb_varid before" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%ke_spin_varid, collider%ke_spin(:), start=[ 1, eslot], & + count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var ke_spin_varid before" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%pe_varid, collider%pe(:), start=[ 1, eslot], & + count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var pe_varid before" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%be_varid, collider%be(:), start=[ 1, eslot], & + count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var pe_varid before" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%te_varid, collider%te(:), start=[ 1, eslot], & + count=[ 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var pe_varid tefore" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%L_orbit_varid, collider%L_orbit(:,:), start=[1, 1, eslot], & + count=[NDIM, 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var L_orbit_varid before" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%L_spin_varid, collider%L_spin(:,:), start=[1, 1, eslot], & + count=[NDIM, 2, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var L_spin_varid before" ) end if call netcdf_io_check( nf90_set_fill(nc%id, old_mode, tmp) ) From 7d5a7df547d7bccc0cfaca4503d977b51778bc31 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 14:43:45 -0500 Subject: [PATCH 230/324] Refactored to enforce line limit --- src/collision/collision_check.f90 | 56 ++++++++++++++++++------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/collision/collision_check.f90 b/src/collision/collision_check.f90 index c95547a6e..02173f6a0 100644 --- a/src/collision/collision_check.f90 +++ b/src/collision/collision_check.f90 @@ -30,7 +30,8 @@ pure elemental subroutine collision_check_one(xr, yr, zr, vxr, vyr, vzr, Gmtot, real(DP), intent(in) :: dt !! Step size logical, intent(in) :: lvdotr !! Logical flag indicating that these two bodies are approaching in the current substep logical, intent(out) :: lcollision !! Logical flag indicating whether these two bodies will collide or not - logical, intent(out) :: lclosest !! Logical flag indicating that, while not a collision, this is the closest approach for this pair of bodies + logical, intent(out) :: lclosest !! Logical flag indicating that, while not a collision, this is the closest approach for + !! this pair of bodies ! Internals real(DP) :: r2, rlim2, a, e, q, vdotr, tcr2, dt2 @@ -39,7 +40,8 @@ pure elemental subroutine collision_check_one(xr, yr, zr, vxr, vyr, vzr, Gmtot, lclosest = .false. if (r2 <= rlim2) then ! checks if bodies are actively colliding in this time step lcollision = .true. - else ! if they are not actively colliding in this time step, checks if they are going to collide next time step based on velocities and q + else ! if they are not actively colliding in this time step, checks if they are going to collide next time step based on + ! velocities and q lcollision = .false. vdotr = xr * vxr + yr * vyr + zr * vzr if (lvdotr .and. (vdotr > 0.0_DP)) then @@ -67,13 +69,13 @@ module subroutine collision_check_plpl(self, nbody_system, param, t, dt, irec, l !! Adapted from Hal Levison's Swift routine symba5_merge.f implicit none ! Arguments - class(collision_list_plpl), intent(inout) :: self !! SyMBA pl-tp encounter list object - class(base_nbody_system), intent(inout) :: nbody_system !! SyMBA nbody system object - class(base_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! current time - real(DP), intent(in) :: dt !! step size - integer(I4B), intent(in) :: irec !! Current recursion level - logical, intent(out) :: lany_collision !! Returns true if cany pair of encounters resulted in a collision + class(collision_list_plpl), intent(inout) :: self !! SyMBA pl-tp encounter list object + class(base_nbody_system), intent(inout) :: nbody_system !! SyMBA nbody system object + class(base_parameters),intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! current time + real(DP), intent(in) :: dt !! step size + integer(I4B), intent(in) :: irec !! Current recursion level + logical, intent(out) :: lany_collision !! Returns true if cany pair of encounters resulted in a collision ! Internals logical, dimension(:), allocatable :: lcollision, lmask real(DP), dimension(NDIM) :: xr, vr @@ -113,14 +115,16 @@ module subroutine collision_check_plpl(self, nbody_system, param, t, dt, irec, l vr(:) = pl%vb(:, i) - pl%vb(:, j) rlim = pl%radius(i) + pl%radius(j) Gmtot = pl%Gmass(i) + pl%Gmass(j) - call collision_check_one(xr(1), xr(2), xr(3), vr(1), vr(2), vr(3), Gmtot, rlim, dt, self%lvdotr(k), lcollision(k), self%lclosest(k)) + call collision_check_one(xr(1), xr(2), xr(3), vr(1), vr(2), vr(3), Gmtot, rlim, dt, self%lvdotr(k), lcollision(k), & + self%lclosest(k)) end do lany_collision = any(lcollision(:)) lany_closest = (param%lenc_save_closest .and. any(self%lclosest(:))) if (lany_collision .or. lany_closest) then - call pl%rh2rb(nbody_system%cb) ! Update the central body barycenteric position vector to get us out of DH and into bary + call pl%rh2rb(nbody_system%cb) ! Update the central body barycenteric position vector to get us out of DH and into + ! barycentric coordinates do k = 1_I8B, nenc if (.not.lcollision(k) .and. .not. self%lclosest(k)) cycle i = self%index1(k) @@ -134,10 +138,12 @@ module subroutine collision_check_plpl(self, nbody_system, param, t, dt, irec, l self%r2(:,k) = pl%rh(:,j) + nbody_system%cb%rb(:) self%v2(:,k) = pl%vb(:,j) if (lcollision(k)) then - ! Check to see if either of these bodies has been involved with a collision before, and if so, make this a collider pair + ! Check to see if either of these bodies has been involved with a collision before, and if so, make this a + ! collider pair if (pl%lcollision(i) .or. pl%lcollision(j)) call pl%make_impactors([i,j]) - ! Set the collision flag for these to bodies to true in case they become involved in another collision later in the step + ! Set the collision flag for these to bodies to true in case they become involved in another collision later in + ! the step pl%lcollision([i, j]) = .true. pl%status([i, j]) = COLLIDED call pl%info(i)%set_value(status="COLLIDED") @@ -169,13 +175,13 @@ module subroutine collision_check_pltp(self, nbody_system, param, t, dt, irec, l !! Adapted from Hal Levison's Swift routine symba5_merge.f implicit none ! Arguments - class(collision_list_pltp), intent(inout) :: self !! SyMBA pl-tp encounter list object - class(base_nbody_system), intent(inout) :: nbody_system !! SyMBA nbody system object - class(base_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! current time - real(DP), intent(in) :: dt !! step size - integer(I4B), intent(in) :: irec !! Current recursion level - logical, intent(out) :: lany_collision !! Returns true if cany pair of encounters resulted in a collision + class(collision_list_pltp),intent(inout) :: self !! SyMBA pl-tp encounter list object + class(base_nbody_system), intent(inout) :: nbody_system !! SyMBA nbody system object + class(base_parameters), intent(inout) :: param !! Current run configuration parameters + real(DP), intent(in) :: t !! current time + real(DP), intent(in) :: dt !! step size + integer(I4B), intent(in) :: irec !! Current recursion level + logical, intent(out) :: lany_collision !! Returns true if cany pair of encounters resulted in a collision ! Internals logical, dimension(:), allocatable :: lcollision, lmask real(DP), dimension(NDIM) :: xr, vr @@ -217,7 +223,8 @@ module subroutine collision_check_pltp(self, nbody_system, param, t, dt, irec, l j = self%index2(k) xr(:) = pl%rh(:, i) - tp%rh(:, j) vr(:) = pl%vb(:, i) - tp%vb(:, j) - call collision_check_one(xr(1), xr(2), xr(3), vr(1), vr(2), vr(3), pl%Gmass(i), pl%radius(i), dt, self%lvdotr(k), lcollision(k), self%lclosest(k)) + call collision_check_one(xr(1), xr(2), xr(3), vr(1), vr(2), vr(3), pl%Gmass(i), pl%radius(i), dt, self%lvdotr(k), & + lcollision(k), self%lclosest(k)) end do lany_collision = any(lcollision(:)) @@ -225,7 +232,8 @@ module subroutine collision_check_pltp(self, nbody_system, param, t, dt, irec, l if (lany_collision .or. lany_closest) then - call pl%rh2rb(nbody_system%cb) ! Update the central body barycenteric position vector to get us out of DH and into bary + call pl%rh2rb(nbody_system%cb) ! Update the central body barycenteric position vector to get us out of DH and into + ! barycentric coordiantes do k = 1, nenc if (.not.lcollision(k) .and. .not. self%lclosest(k)) cycle i = self%index1(k) @@ -247,8 +255,8 @@ module subroutine collision_check_pltp(self, nbody_system, param, t, dt, irec, l write(timestr, *) t call tp%info(j)%set_value(status="DISCARDED_PLR", discard_time=t, discard_rh=tp%rh(:,j), discard_vh=tp%vh(:,j)) write(message, *) "Particle " // trim(adjustl(tp%info(j)%name)) // " (" // trim(adjustl(idstrj)) // ")" & - // " collided with massive body " // trim(adjustl(pl%info(i)%name)) // " (" // trim(adjustl(idstri)) // ")" & - // " at t = " // trim(adjustl(timestr)) + // " collided with massive body " // trim(adjustl(pl%info(i)%name)) // " (" // trim(adjustl(idstri)) & + // ")" // " at t = " // trim(adjustl(timestr)) call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) end if end do From 9eee64132f10511b3ca911ffbf039366b72cf42a Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 16:00:59 -0500 Subject: [PATCH 231/324] Updated the swiftest_discard_system method to save all discard bodies to the collisions.nc file --- src/collision/collision_io.f90 | 111 +++++++++++++++------------- src/collision/collision_resolve.f90 | 6 +- src/helio/helio_util.f90 | 1 + src/rmvs/rmvs_discard.f90 | 1 + src/swiftest/swiftest_discard.f90 | 78 +++++++++++++------ src/swiftest/swiftest_module.f90 | 78 +++++++++++-------- src/swiftest/swiftest_util.f90 | 52 ++++++++++++- src/symba/symba_discard.f90 | 19 +++-- src/symba/symba_util.f90 | 38 +--------- src/whm/whm_util.f90 | 1 + 10 files changed, 227 insertions(+), 158 deletions(-) diff --git a/src/collision/collision_io.f90 b/src/collision/collision_io.f90 index bcb7ba058..78d4b8d0f 100644 --- a/src/collision/collision_io.f90 +++ b/src/collision/collision_io.f90 @@ -467,62 +467,69 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) if (allocated(tp)) deallocate(tp) select case(stage) case(1) - if (.not. allocated(before%pl)) cycle - allocate(pl, source=before%pl) + if (allocated(before%pl)) allocate(pl, source=before%pl) if (allocated(before%tp)) allocate(tp, source=before%tp) case(2) - if (.not. allocated(after%pl)) cycle - allocate(pl, source=after%pl) + if (allocated(after%pl)) allocate(pl, source=after%pl) if (allocated(after%tp)) allocate(tp, source=after%tp) end select - npl = pl%nbody - - ! This ensures that there first idslot will have the first body in it, not id 0 which is the default for a new - ! idvals array - if (.not.allocated(nc%idvals)) allocate(nc%idvals, source=pl%id) - do i = 1, npl - call nc%find_idslot(pl%id(i), idslot) - call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, pl%id(i), start=[ idslot ]), & - "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: pl") - charstring = trim(adjustl(pl%info(i)%name)) - call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & - count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: pl") - charstring = trim(adjustl(pl%info(i)%particle_type)) - call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & - count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: pl") - call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, pl%rh(:,i), start=[1, idslot, stage, eslot], & - count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: pl") - call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, pl%vh(:,i), start=[1, idslot, stage, eslot], & - count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid: pl") - call netcdf_io_check( nf90_put_var(nc%id, nc%Gmass_varid, pl%Gmass(i), start=[ idslot, stage, eslot]), & - "collision_io_netcdf_write_frame_snapshot nf90_put_var Gmass_varid: pl") - call netcdf_io_check( nf90_put_var(nc%id, nc%radius_varid, pl%radius(i), start=[ idslot, stage, eslot]), & - "collision_io_netcdf_write_frame_snapshot nf90_put_var radius_varid: pl") - if (param%lrotation) then - call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, pl%Ip(:,i), start=[1, idslot, stage, eslot], & - count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var Ip_varid: pl") - call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, pl%rot(:,i)*RAD2DEG, & - start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), & - "collision_io_netcdf_write_frame_snapshot nf90_put_var rotx_varid: pl") - end if - end do - - ntp = tp%nbody - do i = 1, ntp - call nc%find_idslot(tp%id(i), idslot) - call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), & - "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: tp" ) - charstring = trim(adjustl(tp%info(i)%name)) - call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & - count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: tp" ) - charstring = trim(adjustl(tp%info(i)%particle_type)) - call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & - count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: tp" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, tp%rh(:,i), start=[1, idslot, stage, eslot], & - count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: tp" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, tp%vh(:,i), start=[1, idslot, stage, eslot], & - count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid: tp" ) - end do + + if (.not. (allocated(pl) .or. allocated(tp))) cycle + + if (allocated(pl)) then + npl = pl%nbody + ! This ensures that there first idslot will have the first body in it, not id 0 which is the default for a new + ! idvals array + if (.not.allocated(nc%idvals)) allocate(nc%idvals, source=pl%id) + do i = 1, npl + call nc%find_idslot(pl%id(i), idslot) + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, pl%id(i), start=[ idslot ]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: pl") + charstring = trim(adjustl(pl%info(i)%name)) + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & + count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: pl") + charstring = trim(adjustl(pl%info(i)%particle_type)) + call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & + count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, pl%rh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, pl%vh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%Gmass_varid, pl%Gmass(i), start=[ idslot, stage, eslot]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var Gmass_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%radius_varid, pl%radius(i), start=[ idslot, stage, eslot]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var radius_varid: pl") + if (param%lrotation) then + call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, pl%Ip(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var Ip_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, pl%rot(:,i)*RAD2DEG, & + start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var rotx_varid: pl") + end if + end do + end if + + if (allocated(tp)) then + ntp = tp%nbody + ! This ensures that there first idslot will have the first body in it, not id 0 which is the default for a new + ! idvals array + if (.not.allocated(nc%idvals)) allocate(nc%idvals, source=tp%id) + do i = 1, ntp + call nc%find_idslot(tp%id(i), idslot) + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), & + "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: tp" ) + charstring = trim(adjustl(tp%info(i)%name)) + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & + count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: tp" ) + charstring = trim(adjustl(tp%info(i)%particle_type)) + call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & + count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: tp" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, tp%rh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: tp" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, tp%vh(:,i), start=[1, idslot, stage, eslot], & + count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var vh_varid: tp" ) + end do + end if end do end select end select diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index cd1661dc3..bed6f5b62 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -532,7 +532,7 @@ module subroutine collision_resolve_mergeaddsub(nbody_system, param, t, status) allocate(plsub, mold=pl) call pl%spill(plsub, lmask, ldestructive=.false.) - call pl_discards%append(plsub, lsource_mask=[(.true., i = 1, nimpactors)]) + ! call pl_discards%append(plsub, lsource_mask=[(.true., i = 1, nimpactors)]) ! Save the before/after snapshots select type(before => collider%before) @@ -644,7 +644,7 @@ module subroutine collision_resolve_plpl(self, nbody_system, param, t, dt, irec) ! Destroy the collision list now that the collisions are resolved call plpl_collision%setup(0_I8B) - if ((nbody_system%pl_adds%nbody == 0) .and. (nbody_system%pl_discards%nbody == 0)) exit + if ((nbody_system%pl_adds%nbody == 0) .and. (.not.any(pl%ldiscard(:)))) exit if (allocated(idnew)) deallocate(idnew) nnew = nbody_system%pl_adds%nbody allocate(idnew, source=nbody_system%pl_adds%id) @@ -743,7 +743,7 @@ module subroutine collision_resolve_pltp(self, nbody_system, param, t, dt, irec) ! Restructure the massive bodies based on the outcome of the collision call tp%rearray(nbody_system, param) - ! Discard the collider + ! Check for discards call nbody_system%tp%discard(nbody_system, param) associate(idx1 => pltp_collision%index1, idx2 => pltp_collision%index2) diff --git a/src/helio/helio_util.f90 b/src/helio/helio_util.f90 index 52b588148..c528d7669 100644 --- a/src/helio/helio_util.f90 +++ b/src/helio/helio_util.f90 @@ -28,6 +28,7 @@ module subroutine helio_util_setup_initialize_system(self, system_history, param call self%tp%h2b(self%cb) ! Make sure that the discard list gets allocated initially + call self%pl_discards%setup(0, param) call self%tp_discards%setup(0, param) call self%pl%set_mu(self%cb) call self%tp%set_mu(self%cb) diff --git a/src/rmvs/rmvs_discard.f90 b/src/rmvs/rmvs_discard.f90 index 0b8b7d9ba..9d3e2ac1f 100644 --- a/src/rmvs/rmvs_discard.f90 +++ b/src/rmvs/rmvs_discard.f90 @@ -44,6 +44,7 @@ module subroutine rmvs_discard_tp(self, nbody_system, param) call swiftest_io_log_one_message(COLLISION_LOG_OUT,message) tp%ldiscard(i) = .true. tp%lmask(i) = .false. + pl%ldiscard(iplperP) = .true. call tp%info(i)%set_value(status="DISCARDED_PLQ", discard_time=t, discard_rh=tp%rh(:,i), & discard_vh=tp%vh(:,i), discard_body_id=pl%id(iplperP)) end if diff --git a/src/swiftest/swiftest_discard.f90 b/src/swiftest/swiftest_discard.f90 index b96112e62..e9a19e374 100644 --- a/src/swiftest/swiftest_discard.f90 +++ b/src/swiftest/swiftest_discard.f90 @@ -21,33 +21,80 @@ module subroutine swiftest_discard_system(self, param) class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals logical :: lpl_discards, ltp_discards, lpl_check, ltp_check + logical, dimension(:), allocatable :: ldiscard + integer(I4B) :: i, nstart, nend, nsub + character(len=STRMAX) :: idstr + class(swiftest_pl), allocatable :: plsub + class(swiftest_tp), allocatable :: tpsub lpl_check = allocated(self%pl_discards) ltp_check = allocated(self%tp_discards) - associate(nbody_system => self,tp => self%tp,pl => self%pl,tp_discards => self%tp_discards,pl_discards => self%pl_discards) + associate(nbody_system => self,tp => self%tp,pl => self%pl,tp_discards => self%tp_discards,pl_discards => self%pl_discards, & + npl => self%pl%nbody, ntp => self%tp%nbody, t => self%t, collision_history => self%collision_history, & + collider => self%collider) lpl_discards = .false. ltp_discards = .false. if (lpl_check .and. pl%nbody > 0) then pl%ldiscard = pl%status(:) /= ACTIVE call pl%discard(nbody_system, param) - lpl_discards = (pl_discards%nbody > 0) + lpl_discards = any(pl%ldiscard(1:npl)) end if if (ltp_check .and. tp%nbody > 0) then tp%ldiscard = tp%status(:) /= ACTIVE call tp%discard(nbody_system, param) - ltp_discards = (tp_discards%nbody > 0) + ltp_discards = any(tp%ldiscard(1:ntp)) + lpl_discards = any(pl%ldiscard(1:npl)) end if if (ltp_discards.or.lpl_discards) then - if (lpl_discards) then - if (param%lenergy) call self%conservation_report(param, lterminal=.false.) - call pl_discards%setup(0,param) - end if if (ltp_discards) then + allocate(ldiscard, source=tp%ldiscard(:)) + allocate(tpsub, mold=tp) + call tp%spill(tpsub, ldiscard, ldestructive=.true.) + nsub = tpsub%nbody + nstart = tp_discards%nbody + 1 + nend = tp_discards%nbody + nsub + call tp_discards%append(tpsub, lsource_mask=[(.true., i = 1, nsub)]) + deallocate(ldiscard) + select type(before => collider%before) + class is (swiftest_nbody_system) + if (allocated(before%tp)) deallocate(before%tp) + allocate(before%tp, source=tp_discards) + end select call tp_discards%setup(0,param) end if + + if (lpl_discards) then ! In the base integrators, massive bodies are not true discards. The discard is + ! simply used to trigger a snapshot. + if (param%lenergy) call self%conservation_report(param, lterminal=.false.) + allocate(ldiscard, source=pl%ldiscard(:)) + allocate(plsub, mold=pl) + call pl%spill(plsub, ldiscard, ldestructive=.false.) + nsub = plsub%nbody + nstart = pl_discards%nbody + 1 + nend = pl_discards%nbody + nsub + call pl_discards%append(plsub, lsource_mask=[(.true., i = 1, nsub)]) + deallocate(ldiscard) + pl%ldiscard(1:npl) = .false. + ! Save the before snapshots + select type(before => collider%before) + class is (swiftest_nbody_system) + if (allocated(before%pl)) deallocate(before%pl) + allocate(before%pl, source=pl_discards) + end select + call pl_discards%setup(0,param) + end if + ! Advance the collision id number and save it + collider%maxid_collision = max(collider%maxid_collision, maxval(nbody_system%pl%info(:)%collision_id)) + collider%maxid_collision = collider%maxid_collision + 1 + collider%collision_id = collider%maxid_collision + collider%impactors%regime = COLLRESOLVE_REGIME_MERGE + write(idstr,*) collider%collision_id + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "collision_id " // trim(adjustl(idstr))) + + call collision_history%take_snapshot(param,nbody_system, t, "particle") end if end associate @@ -86,15 +133,11 @@ module subroutine swiftest_discard_tp(self, nbody_system, param) class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameter - ! Internals - logical, dimension(self%nbody) :: ldiscard - integer(I4B) :: i, nstart, nend, nsub - class(swiftest_tp), allocatable :: tpsub if (self%nbody == 0) return associate(tp => self, ntp => self%nbody, cb => nbody_system%cb, pl => nbody_system%pl, npl => nbody_system%pl%nbody, & - tp_discards => nbody_system%tp_discards) + tp_discards => nbody_system%tp_discards, pl_discards => nbody_system%pl_discards) if ((param%rmin >= 0.0_DP) .or. (param%rmax >= 0.0_DP) .or. & (param%rmaxu >= 0.0_DP) .or. ((param%qmin >= 0.0_DP) .and. (param%qmin_coord == "BARY"))) then @@ -113,15 +156,6 @@ module subroutine swiftest_discard_tp(self, nbody_system, param) if (param%lclose) then call swiftest_discard_pl_tp(tp, nbody_system, param) end if - if (any(tp%ldiscard(1:ntp))) then - ldiscard(1:ntp) = tp%ldiscard(1:ntp) - allocate(tpsub, mold=tp) - call tp%spill(tpsub, ldiscard, ldestructive=.false.) - nsub = tpsub%nbody - nstart = tp_discards%nbody + 1 - nend = tp_discards%nbody + nsub - call tp_discards%append(tpsub, lsource_mask=[(.true., i = 1, nsub)]) - end if end associate return @@ -242,7 +276,7 @@ subroutine swiftest_discard_peri_tp(tp, nbody_system, param) call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) tp%ldiscard(i) = .true. call tp%info(i)%set_value(status="DISCARDED_PERI", discard_time=nbody_system%t, discard_rh=tp%rh(:,i), & - discard_vh=tp%vh(:,i), discard_body_id=pl%id(j)) + discard_vh=tp%vh(:,i), discard_body_id=cb%id) end if end if end if diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 6350a42dd..e513623b7 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -10,27 +10,31 @@ module swiftest !! author: David A. Minton !! - !! This module serves to combine all of the Swiftest project modules under a single umbrella so that they can be accessed from individual submodule implementations - !! with a simple "use swiftest" line. + !! This module serves to combine all of the Swiftest project modules under a single umbrella so that they can be accessed from + !! individual submodule implementations with a simple "use swiftest" line. !! - !! The project structure is divided into a heirarchy of modules. The lowest level of the heirarchy are the modules called in the "use" statements below. Next the - !! "swiftest" !! modules (this one), and finally each individual integrator (and potential future integrators) sit at the top. This structure is a consequence of two - !! competing constraints: - !! 1) The desire that much of the basic functionality of the code is modular, such that new functionality can be easily added without altering too much of the basic code. + !! The project structure is divided into a heirarchy of modules. The lowest level of the heirarchy are the modules called in the + !! "use" statements below. Next the "swiftest" modules (this one), and finally each individual integrator (and potential future + !! integrators) sit at the top. This structure is a consequence of two competing constraints: + !! 1) The desire that much of the basic functionality of the code is modular, such that new functionality can be easily added + !! without altering too much of the basic code. !! 2) Adhering to Modern Fortran's typing rules. !! - !! A set of "base" types is defined in the base module. These define classes of objects, (i.e. central body, massive body, and test particles) and other major types - !! used throughout the project. However, none of the derived data types are defined with concrete type-bound procedures attached (only abstract procedures). - !! However, the *interfaces* of type-bound procedures are defined using the base types as arguments. Because of the typing rules of Modern Fortran's type-bound procedure overrides, any non-pass arguments - !! (i.e. arguments not named self) must be identical in all extended types. Because some of the basic functionality in the project is split across multiple modules, - !! we cannot define type-bound procedures in base class objects until the all interfaces are defined. In order to avoid these dependency issues and not end up with a - !! massive base class with every possibly type-bound procedure interface in the project (thus reducing the modularity of the project), the type-bound procedures are added - !! to the base types here. + !! A set of "base" types is defined in the base module. These define classes of objects, (i.e. central body, massive body, and + !! test particles) and other major types used throughout the project. However, none of the derived data types are defined with + !! concrete type-bound procedures attached (only abstract procedures). However, the *interfaces* of type-bound procedures are + !! defined using the base types as arguments. Because of the typing rules of Modern Fortran's type-bound procedure overrides, any + !! non-pass arguments(i.e. arguments not named self) must be identical in all extended types. Because some of the basic + !! functionality in the project is split across multiple modules, we cannot define type-bound procedures in base class objects + !! until the all interfaces are defined. In order to avoid these dependency issues and not end up with a massive base class with + !! every possibly type-bound procedure interface in the project (thus reducing the modularity of the project), the type-bound + !! procedures are added to the base types here. !! - !! Structuring this code this way adds somewhat to the verbosity of the code. The main thing that has to happen is that for any procedures where one wishes to make use of an - !! type-bound procedures defined for arguments at the swiftest-type level or higher, but that are passsed to base-level procedures, must have their arguments wrapped in - !! a select type(...); class is(...) construct in order to "reveal" the procedures. This is done throughout the project at the beginning of many procedures (along with - !! copious amounts of associate(...) statements, in order to help with code readibility) + !! Structuring this code this way adds somewhat to the verbosity of the code. The main thing that has to happen is that for any + !! procedures where one wishes to make use of an type-bound procedures defined for arguments at the swiftest-type level or + !! higher, but that are passsed to base-level procedures, must have their arguments wrapped in a select type(...); class is(...) + !! construct in order to "reveal" the procedures. This is done throughout the project at the beginning of many procedures (along + !! with copious amounts of associate(...) statements, in order to help with code readibility) !! !! Adapted from David E. Kaufmann's Swifter routine: module_swifter.f90 use globals @@ -54,10 +58,13 @@ module swiftest type, extends(netcdf_parameters) :: swiftest_netcdf_parameters contains - procedure :: initialize => swiftest_io_netcdf_initialize_output !! Initialize a set of parameters used to identify a NetCDF output object - procedure :: get_valid_masks => swiftest_io_netcdf_get_valid_masks !! Gets logical masks indicating which bodies are valid pl and tp type at the current time - procedure :: open => swiftest_io_netcdf_open !! Opens a NetCDF file and does the variable inquiries to activate variable ids - procedure :: flush => swiftest_io_netcdf_flush !! Flushes a NetCDF file by closing it then opening it again + procedure :: initialize => swiftest_io_netcdf_initialize_output !! Initialize a set of parameters used to identify a + !! NetCDF output object + procedure :: get_valid_masks => swiftest_io_netcdf_get_valid_masks !! Gets logical masks indicating which bodies are valid + !! pl and tp type at the current time + procedure :: open => swiftest_io_netcdf_open !! Opens a NetCDF file and does the variable inquiries to + !! activate variable ids + procedure :: flush => swiftest_io_netcdf_flush !! Flushes a NetCDF file by closing it then opening it again #ifdef COARRAY procedure :: coclone => swiftest_coarray_coclone_nc #endif @@ -68,15 +75,19 @@ module swiftest class(swiftest_netcdf_parameters), allocatable :: nc !! NetCDF object attached to this storage object contains procedure :: dump => swiftest_io_dump_storage !! Dumps storage object contents to file - procedure :: dealloc => swiftest_util_dealloc_storage !! Resets a storage object by deallocating all items and resetting the frame counter to 0 - procedure :: get_index_values => swiftest_util_get_vals_storage !! Gets the unique values of the indices of a storage object (i.e. body id or time value) - procedure :: make_index_map => swiftest_util_index_map_storage !! Maps body id values to storage index values so we don't have to use unlimited dimensions for id - procedure :: take_snapshot => swiftest_util_snapshot_system !! Takes a snapshot of the nbody_system for later file storage + procedure :: dealloc => swiftest_util_dealloc_storage !! Resets a storage object by deallocating all items and + !! resetting the frame counter to 0 + procedure :: get_index_values => swiftest_util_get_vals_storage !! Gets the unique values of the indices of a storage object + !! (i.e. body id or time value) + procedure :: make_index_map => swiftest_util_index_map_storage !! Maps body id values to storage index values so we don't + !! have to use unlimited dimensions for id + procedure :: take_snapshot => swiftest_util_snapshot_system !! Takes a snapshot of the nbody_system for later file storage final :: swiftest_final_storage end type swiftest_storage - ! The following extended types or their children should be used, where possible, as the base of any types defined in additional modules, such as new integrators. + ! The following extended types or their children should be used, where possible, as the base of any types defined in additional + ! modules, such as new integrators. type, extends(base_parameters) :: swiftest_parameters contains procedure :: dump => swiftest_io_dump_param @@ -95,7 +106,8 @@ module swiftest contains procedure :: dealloc => swiftest_util_dealloc_kin !! Deallocates all allocatable arrays #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_kin !! Clones the image 1 body object to all other images in the coarray structure. + procedure :: coclone => swiftest_coarray_coclone_kin !! Clones the image 1 body object to all other images in the coarray + !! structure. #endif final :: swiftest_final_kin !! Finalizes the Swiftest kinship object - deallocates all allocatables end type swiftest_kinship @@ -103,8 +115,10 @@ module swiftest type, extends(base_particle_info) :: swiftest_particle_info character(len=NAMELEN) :: name !! Non-unique name - character(len=NAMELEN) :: particle_type !! String containing a description of the particle type (e.g. Central Body, Massive Body, Test Particle) - character(len=NAMELEN) :: origin_type !! String containing a description of the origin of the particle (e.g. Initial Conditions, Supercatastrophic, Disruption, etc.) + character(len=NAMELEN) :: particle_type !! String containing a description of the particle type (e.g. Central Body, + !! Massive Body, Test Particle) + character(len=NAMELEN) :: origin_type !! String containing a description of the origin of the particle (e.g. Initial + !! Conditions, Supercatastrophic, Disruption, etc.) real(DP) :: origin_time !! The time of the particle's formation integer(I4B) :: collision_id !! The ID of the collision that formed the particle real(DP), dimension(NDIM) :: origin_rh !! The heliocentric distance vector at the time of the particle's formation @@ -115,8 +129,10 @@ module swiftest real(DP), dimension(NDIM) :: discard_vh !! The heliocentric velocity vector at the time of the particle's discard integer(I4B) :: discard_body_id !! The id of the other body involved in the discard (0 if no other body involved) contains - procedure :: copy => swiftest_util_copy_particle_info !! Copies one set of information object components into another, component-by-component - procedure :: set_value => swiftest_util_set_particle_info !! Sets one or more values of the particle information metadata object + procedure :: copy => swiftest_util_copy_particle_info !! Copies one set of information object components into another, + !! component-by-component + procedure :: set_value => swiftest_util_set_particle_info !! Sets one or more values of the particle information metadata + !! object end type swiftest_particle_info diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 67cac063a..bcc4a5398 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -1730,7 +1730,12 @@ module subroutine swiftest_util_rearray_pl(self, nbody_system, param) end if ! Reindex the new list of bodies - call pl%sort("mass", ascending=.false.) + select type(pl) + class is (helio_pl) + call pl%sort("mass", ascending=.false.) + class is (whm_pl) + call pl%sort("ir3h", ascending=.false.) + end select call pl%flatten(param) call pl%set_rhill(cb) @@ -1886,7 +1891,7 @@ module subroutine swiftest_util_rearray_tp(self, nbody_system, param) return end if - ! Reset all of thes tatus flags for the remaining bodies + ! Reset all of the status flags for the remaining bodies tp%status(1:ntp) = ACTIVE do i = 1, ntp call tp%info(i)%set_value(status="ACTIVE") @@ -2439,6 +2444,7 @@ module subroutine swiftest_util_setup_construct_system(nbody_system, param) allocate(helio_cb :: nbody_system%cb) allocate(helio_pl :: nbody_system%pl) allocate(helio_tp :: nbody_system%tp) + allocate(helio_pl :: nbody_system%pl_discards) allocate(helio_tp :: nbody_system%tp_discards) end select param%collision_model = "MERGE" @@ -2453,6 +2459,7 @@ module subroutine swiftest_util_setup_construct_system(nbody_system, param) allocate(whm_cb :: nbody_system%cb) allocate(whm_pl :: nbody_system%pl) allocate(whm_tp :: nbody_system%tp) + allocate(whm_pl :: nbody_system%pl_discards) allocate(whm_tp :: nbody_system%tp_discards) end select param%collision_model = "MERGE" @@ -2463,6 +2470,7 @@ module subroutine swiftest_util_setup_construct_system(nbody_system, param) allocate(rmvs_cb :: nbody_system%cb) allocate(rmvs_pl :: nbody_system%pl) allocate(rmvs_tp :: nbody_system%tp) + allocate(rmvs_pl :: nbody_system%pl_discards) allocate(rmvs_tp :: nbody_system%tp_discards) end select param%collision_model = "MERGE" @@ -2543,8 +2551,13 @@ module subroutine swiftest_util_setup_initialize_system(self, system_history, pa class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object class(swiftest_storage), allocatable, intent(inout) :: system_history !! Stores the system history between output dumps class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - ! Internals + type(encounter_storage) :: encounter_history + type(collision_storage) :: collision_history + + call encounter_history%setup(4096) + call collision_history%setup(4096) + if (allocated(system_history)) then call system_history%dealloc() deallocate(system_history) @@ -2577,6 +2590,39 @@ module subroutine swiftest_util_setup_initialize_system(self, system_history, pa call nbody_system%initialize_output_file(nc, param) call nc%close() + allocate(collision_basic :: nbody_system%collider) + call nbody_system%collider%setup(nbody_system) + + if (param%lenc_save_trajectory .or. param%lenc_save_closest) then + allocate(encounter_netcdf_parameters :: encounter_history%nc) + select type(nc => encounter_history%nc) + class is (encounter_netcdf_parameters) + nc%file_name = ENCOUNTER_OUTFILE + if (.not.param%lrestart) then + call nc%initialize(param) + call nc%close() + end if + end select + allocate(nbody_system%encounter_history, source=encounter_history) + end if + + allocate(collision_netcdf_parameters :: collision_history%nc) + select type(nc => collision_history%nc) + class is (collision_netcdf_parameters) + nc%file_name = COLLISION_OUTFILE + if (param%lrestart) then + call nc%open(param) ! This will find the nc%max_idslot variable + else + call nc%initialize(param) + end if + call nc%close() + nbody_system%collider%maxid_collision = nc%max_idslot + end select + + allocate(nbody_system%collision_history, source=collision_history) + + nbody_system%collider%max_rot = MAX_ROT_SI * param%TU2S + end associate return diff --git a/src/symba/symba_discard.f90 b/src/symba/symba_discard.f90 index 1d86fb637..7c95da30a 100644 --- a/src/symba/symba_discard.f90 +++ b/src/symba/symba_discard.f90 @@ -233,17 +233,16 @@ subroutine symba_discard_nonplpl(pl, nbody_system, param) call symba_discard_cb_pl(pl, nbody_system, param) end if if (param%qmin >= 0.0_DP) call symba_discard_peri_pl(pl, nbody_system, param) - if (any(pl%ldiscard(1:npl))) then - ldiscard(1:npl) = pl%ldiscard(1:npl) + ! if (any(pl%ldiscard(1:npl))) then + ! ldiscard(1:npl) = pl%ldiscard(1:npl) - allocate(plsub, mold=pl) - call pl%spill(plsub, ldiscard, ldestructive=.false.) - nsub = plsub%nbody - nstart = pl_discards%nbody + 1 - nend = pl_discards%nbody + nsub - call pl_discards%append(plsub, lsource_mask=[(.true., i = 1, nsub)]) - - end if + ! allocate(plsub, mold=pl) + ! call pl%spill(plsub, ldiscard, ldestructive=.false.) + ! nsub = plsub%nbody + ! nstart = pl_discards%nbody + 1 + ! nend = pl_discards%nbody + nsub + ! call pl_discards%append(plsub, lsource_mask=[(.true., i = 1, nsub)]) + ! end if end associate return diff --git a/src/symba/symba_util.f90 b/src/symba/symba_util.f90 index 8e4b45e37..38b13978a 100644 --- a/src/symba/symba_util.f90 +++ b/src/symba/symba_util.f90 @@ -277,12 +277,7 @@ module subroutine symba_util_setup_initialize_system(self, system_history, param class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody_system object class(swiftest_storage), allocatable, intent(inout) :: system_history !! Stores the system history between output dumps class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - ! Internals - type(encounter_storage) :: encounter_history - type(collision_storage) :: collision_history - call encounter_history%setup(4096) - call collision_history%setup(4096) ! Call parent method associate(nbody_system => self) call helio_util_setup_initialize_system(nbody_system, system_history, param) @@ -291,32 +286,7 @@ module subroutine symba_util_setup_initialize_system(self, system_history, param call nbody_system%plpl_collision%setup(0_I8B) call nbody_system%pltp_collision%setup(0_I8B) - if (param%lenc_save_trajectory .or. param%lenc_save_closest) then - allocate(encounter_netcdf_parameters :: encounter_history%nc) - select type(nc => encounter_history%nc) - class is (encounter_netcdf_parameters) - nc%file_name = ENCOUNTER_OUTFILE - if (.not.param%lrestart) then - call nc%initialize(param) - call nc%close() - end if - end select - allocate(nbody_system%encounter_history, source=encounter_history) - end if - - allocate(collision_netcdf_parameters :: collision_history%nc) - select type(nc => collision_history%nc) - class is (collision_netcdf_parameters) - nc%file_name = COLLISION_OUTFILE - if (param%lrestart) then - call nc%open(param) ! This will find the nc%max_idslot variable - else - call nc%initialize(param) - end if - call nc%close() - end select - allocate(nbody_system%collision_history, source=collision_history) - + if (allocated(nbody_system%collider)) deallocate(nbody_system%collider) select case(param%collision_model) case("MERGE") allocate(collision_basic :: nbody_system%collider) @@ -327,12 +297,6 @@ module subroutine symba_util_setup_initialize_system(self, system_history, param end select call nbody_system%collider%setup(nbody_system) - nbody_system%collider%max_rot = MAX_ROT_SI * param%TU2S - select type(nc => collision_history%nc) - class is (collision_netcdf_parameters) - nbody_system%collider%maxid_collision = nc%max_idslot - end select - end associate return diff --git a/src/whm/whm_util.f90 b/src/whm/whm_util.f90 index cb461fb03..5b1218550 100644 --- a/src/whm/whm_util.f90 +++ b/src/whm/whm_util.f90 @@ -216,6 +216,7 @@ module subroutine whm_util_setup_initialize_system(self, system_history, param) call self%pl%flatten(param) ! Make sure that the discard list gets allocated initially + call self%pl_discards%setup(0, param) call self%tp_discards%setup(0, param) call self%pl%set_mu(self%cb) call self%tp%set_mu(self%cb) From 2736a1acc1c997dace5fd2559028e3dc31d3c29c Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 16:36:16 -0500 Subject: [PATCH 232/324] Added stage and collision_id dimensions to the collision.nc output for name and id variables --- src/collision/collision_io.f90 | 44 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/collision/collision_io.f90 b/src/collision/collision_io.f90 index 78d4b8d0f..c426310df 100644 --- a/src/collision/collision_io.f90 +++ b/src/collision/collision_io.f90 @@ -185,24 +185,32 @@ module subroutine collision_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%collision_id_varname, NF90_INT, & [nc%collision_id_dimid], nc%collision_id_varid), & "collision_io_netcdf_initialize_output nf90_def_var collision_id_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%space_dimname, NF90_CHAR, nc%space_dimid, nc%space_varid), & + + call netcdf_io_check( nf90_def_var(nc%id, nc%space_dimname, NF90_CHAR, & + nc%space_dimid, nc%space_varid), & "collision_io_netcdf_initialize_output nf90_def_var space_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, & - [nc%str_dimid, nc%name_dimid], nc%name_varid), & - "collision_io_netcdf_initialize_output nf90_def_var name_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%stage_dimname, NF90_CHAR, & [nc%str_dimid, nc%stage_dimid], nc%stage_varid), & "collision_io_netcdf_initialize_output nf90_def_var stage_varid") ! Variables - call netcdf_io_check( nf90_def_var(nc%id, nc%id_varname, NF90_INT, nc%name_dimid, nc%id_varid), & - "collision_io_netcdf_initialize_output nf90_def_var id_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, & + [nc%str_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%name_varid), & + "collision_io_netcdf_initialize_output nf90_def_var name_varid") + + call netcdf_io_check( nf90_def_var(nc%id, nc%id_varname, NF90_INT, & + [nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%id_varid), & + "collision_io_netcdf_initialize_output nf90_def_var id_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%time_dimname, nc%out_type, & nc%collision_id_dimid, nc%time_varid), & - "collision_io_netcdf_initialize_output nf90_def_var time_varid" ) + "collision_io_netcdf_initialize_output nf90_def_var time_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%regime_varname, NF90_CHAR, & [nc%str_dimid, nc%collision_id_dimid], nc%regime_varid), & "collision_io_netcdf_initialize_output nf90_def_var regime_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%Qloss_varname, nc%out_type, & [nc%collision_id_dimid], nc%Qloss_varid), & "collision_io_netcdf_initialize_output nf90_def_var Qloss_varid") @@ -211,7 +219,6 @@ module subroutine collision_io_netcdf_initialize_output(self, param) [nc%str_dimid, nc%name_dimid,nc%stage_dimid, nc%collision_id_dimid], nc%ptype_varid), & "collision_io_netcdf_initialize_output nf90_def_var ptype_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%rh_varname, nc%out_type, & [nc%space_dimid, nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%rh_varid), & "collision_io_netcdf_initialize_output nf90_def_var rh_varid") @@ -224,7 +231,6 @@ module subroutine collision_io_netcdf_initialize_output(self, param) [nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%Gmass_varid), & "collision_io_netcdf_initialize_output nf90_def_var Gmass_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%radius_varname, nc%out_type, & [nc%name_dimid, nc%stage_dimid, nc%collision_id_dimid], nc%radius_varid), & "collision_io_netcdf_initialize_output nf90_def_var radius_varid") @@ -449,12 +455,14 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) call netcdf_io_check( nf90_put_var(nc%id, nc%collision_id_varid, eslot, start=[eslot]), & "collision_io_netcdf_write_frame_snapshot nf90_put_var collision_id_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%time_varid, self%t, start=[eslot]), & "collision_io_netcdf_write_frame_snapshot nf90_put_var time_varid" ) charstring = trim(adjustl(REGIME_NAMES(impactors%regime))) call netcdf_io_check( nf90_put_var(nc%id, nc%regime_varid, charstring, start=[1, eslot], & count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var regime_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%Qloss_varid, impactors%Qloss, start=[eslot] ), & "collision_io_netcdf_write_frame_snapshot nf90_put_var Qloss_varid" ) @@ -483,14 +491,14 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) if (.not.allocated(nc%idvals)) allocate(nc%idvals, source=pl%id) do i = 1, npl call nc%find_idslot(pl%id(i), idslot) - call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, pl%id(i), start=[ idslot ]), & + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, pl%id(i), start=[ idslot, stage, eslot]), & "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: pl") charstring = trim(adjustl(pl%info(i)%name)) - call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & - count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: pl") + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot, stage, eslot], & + count=[NAMELEN,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: pl") charstring = trim(adjustl(pl%info(i)%particle_type)) call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & - count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: pl") + count=[NAMELEN,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: pl") call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, pl%rh(:,i), start=[1, idslot, stage, eslot], & count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: pl") call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, pl%vh(:,i), start=[1, idslot, stage, eslot], & @@ -500,7 +508,7 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) call netcdf_io_check( nf90_put_var(nc%id, nc%radius_varid, pl%radius(i), start=[ idslot, stage, eslot]), & "collision_io_netcdf_write_frame_snapshot nf90_put_var radius_varid: pl") if (param%lrotation) then - call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, pl%Ip(:,i), start=[1, idslot, stage, eslot], & + call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, pl%Ip(:,i), start=[1, idslot, stage, eslot], & count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var Ip_varid: pl") call netcdf_io_check( nf90_put_var(nc%id, nc%rot_varid, pl%rot(:,i)*RAD2DEG, & start=[1, idslot, stage, eslot], count=[NDIM,1,1,1]), & @@ -516,14 +524,14 @@ module subroutine collision_io_netcdf_write_frame_snapshot(self, history, param) if (.not.allocated(nc%idvals)) allocate(nc%idvals, source=tp%id) do i = 1, ntp call nc%find_idslot(tp%id(i), idslot) - call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot ]), & + call netcdf_io_check( nf90_put_var(nc%id, nc%id_varid, tp%id(i), start=[ idslot, stage, eslot]), & "collision_io_netcdf_write_frame_snapshot nf90_put_var id_varid: tp" ) charstring = trim(adjustl(tp%info(i)%name)) - call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot ], & - count=[NAMELEN, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: tp" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%name_varid, charstring, start=[1, idslot, stage, eslot], & + count=[NAMELEN,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var name_varid: tp" ) charstring = trim(adjustl(tp%info(i)%particle_type)) call netcdf_io_check( nf90_put_var(nc%id, nc%ptype_varid, charstring, start=[1, idslot, stage, eslot], & - count=[NAMELEN, 1, 1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: tp" ) + count=[NAMELEN,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var particle_type_varid: tp" ) call netcdf_io_check( nf90_put_var(nc%id, nc%rh_varid, tp%rh(:,i), start=[1, idslot, stage, eslot], & count=[NDIM,1,1,1]), "collision_io_netcdf_write_frame_snapshot nf90_put_var rh_varid: tp" ) call netcdf_io_check( nf90_put_var(nc%id, nc%vh_varid, tp%vh(:,i), start=[1, idslot, stage, eslot], & From 36c92a450f09c16ee40dec14013fa5a2f7475cfd Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 17:35:40 -0500 Subject: [PATCH 233/324] Set the default collision_model to MERGE as stated in the documentation --- examples/Basic_Simulation/basic_simulation.py | 1 - swiftest/simulation_class.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/Basic_Simulation/basic_simulation.py b/examples/Basic_Simulation/basic_simulation.py index bee49ac8b..01dcc8b18 100755 --- a/examples/Basic_Simulation/basic_simulation.py +++ b/examples/Basic_Simulation/basic_simulation.py @@ -36,7 +36,6 @@ from numpy.random import default_rng # Initialize the simulation object as a variable. Arguments may be defined here or through the sim.run() method. -#sim = swiftest.Simulation(fragmentation=True, minimum_fragment_mass = 2.5e-11, mtiny=2.5e-8) sim = swiftest.Simulation() sim.clean() rng = default_rng(seed=123) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 3075f1609..5b5d8a1a3 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -784,7 +784,7 @@ def set_parameter(self, "nfrag_reduction": 30.0, "close_encounter_check": True, "general_relativity": True, - "collision_model": "FRAGGLE", + "collision_model": "MERGE", "minimum_fragment_mass": None, "minimum_fragment_gmass": None, "rotation": True, From e490e925547ab7a7f0eab9c14b05571620b6a130 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 22 Feb 2024 19:11:15 -0500 Subject: [PATCH 234/324] Simplified project requirements --- pyproject.toml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9f69d8aa4..0e754dc6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,19 +50,6 @@ Repository = 'https://github.itap.purdue.edu/MintonGroup/swiftest' requires = [ "scikit-build-core>=0.8", "cython>=3.0", - "pyproject_metadata", - "pytest", - "pathspec", - "sphinx", - "sphinx-autosummary-accessors", - "sphinx-book-theme >= 0.3", - "sphinx-copybutton", - "sphinx-design", - "sphinx-inline-tabs", - "sphinxext-rediraffe", - "sphinxext-opengraph", - "nbsphinx", - "ford", ] build-backend = "scikit_build_core.build" @@ -127,8 +114,6 @@ DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel \ --require-archs {delocate_archs} -w {dest_dir} -v {wheel} """ - - [tool.cibuildwheel.linux.environment] PREFIX="/usr/local" NCDIR="${PREFIX}" From d3c7cc9bb143a8f065ed4d0ac7309491e615d927 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 24 Feb 2024 10:36:01 -0500 Subject: [PATCH 235/324] Refactored to enforce line limit --- src/collision/collision_resolve.f90 | 9 ++++++--- src/swiftest/swiftest_io.f90 | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/collision/collision_resolve.f90 b/src/collision/collision_resolve.f90 index bed6f5b62..895fe1f54 100644 --- a/src/collision/collision_resolve.f90 +++ b/src/collision/collision_resolve.f90 @@ -587,7 +587,8 @@ module subroutine collision_resolve_plpl(self, nbody_system, param, t, dt, irec) class is (swiftest_parameters) associate(plpl_collision => nbody_system%plpl_collision, & collision_history => nbody_system%collision_history, pl => nbody_system%pl, cb => nbody_system%cb, & - collider => nbody_system%collider, fragments => nbody_system%collider%fragments, impactors => nbody_system%collider%impactors) + collider => nbody_system%collider, fragments => nbody_system%collider%fragments, & + impactors => nbody_system%collider%impactors) if (plpl_collision%nenc == 0) return ! No collisions to resolve @@ -607,11 +608,13 @@ module subroutine collision_resolve_plpl(self, nbody_system, param, t, dt, irec) ncollisions = plpl_collision%nenc write(timestr,*) t call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & + call swiftest_io_log_one_message(COLLISION_LOG_OUT,& + "***********************************************************" // & "***********************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, "Collision between massive bodies detected at time t = " // & trim(adjustl(timestr))) - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "***********************************************************" // & "***********************************************************") do k = 1_I8B, ncollisions diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 1e278a337..685954b0d 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1010,8 +1010,8 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) ! status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) ! if (status == NF90_NOERR) then - call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], nc%c_lm_varid), & - "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], & + nc%c_lm_varid), "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) ! end if ! Set fill mode to NaN for all variables @@ -2125,7 +2125,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rot_varid" ) ! Following the template of j2rp2 - call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase * RAD2DEG, start = [tslot]), & ! start = [1, idslot, tslot]), & + call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase * RAD2DEG, start = [tslot]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") end if @@ -2143,10 +2143,11 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var l_varid") call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var m_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1, -1]), "netcdf_io_write_frame_cb nf90_put_var sign_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1,-1]), "netcdf_io_write_frame_cb nf90_put_var sign_varid") ! Write dimension-coordinates to file - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), & + "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") end if end if From ba7edc5dc6b060c93dd5e0fa8eeba9b1615dede6 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 25 Feb 2024 09:40:00 -0500 Subject: [PATCH 236/324] Fixed bad docstrings in the horizons query methods --- swiftest/init_cond.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index fa84b12a7..ef19dbfde 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -39,8 +39,8 @@ def horizons_get_physical_properties(altid,**kwargs): Returns ------- - MSun_over_Mpl : float - The ratio of MSun/M of the body + GMass : float + G*Mass of the body radius : float The radius of the body in m rot: (3) float vector @@ -198,7 +198,11 @@ def get_altid(errstr,exclude_spacecraft=True): Returns ------- - MSun_over_Mpl : float + altid: string list | None + A list of alternate ids if more than one object matches the list + altname: string list | None + A list of alternate names if more than one object matches the list + """ if "ID" in errstr: altid = errstr.split('ID')[1] From 6c796ecc402656bc4bc23658f0e7155a802b5ed5 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 25 Feb 2024 09:53:37 -0500 Subject: [PATCH 237/324] Updated the save method to ensure that the init_cond Dataset gets updated on a save --- swiftest/simulation_class.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 5b5d8a1a3..42682396b 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2269,8 +2269,6 @@ def add_solar_system_body(self, if dsnew['id'].max(dim='name') > 0 and dsnew['name'].size > 0: self.save(verbose=False) - self.init_cond = self.data.copy(deep=True) - return def set_ephemeris_date(self, @@ -2605,7 +2603,6 @@ def input_to_clm_array(val, n): dsnew = self._combine_and_fix_dsnew(dsnew) self.save(verbose=False) - self.init_cond = self.data.copy(deep=True) return @@ -3067,6 +3064,7 @@ def save(self, if not self.simdir.exists(): self.simdir.mkdir(parents=True, exist_ok=True) + self.init_cond = self.data.copy(deep=True) if codename == "Swiftest": infile_name = Path(self.simdir) / param['NC_IN'] @@ -3083,7 +3081,7 @@ def save(self, return - def initial_conditions_from_bin(self, + def initial_conditions_from_data(self, framenum: int=-1, new_param: os.PathLike=None, new_param_file: os.PathLike="param.new.in", From 86122b1fc23ca173153ceaa7af50eba76b6199ac Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 25 Feb 2024 11:07:22 -0500 Subject: [PATCH 238/324] Phobos and Deimos mass is reported in a very strange way in JPL Horizons output. I added a new set of parsing instructions for this style of output. --- swiftest/init_cond.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index ef19dbfde..72d33d3ab 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -53,6 +53,22 @@ def get_Gmass(raw_response): and 'GMT' not in s and 'ANGMOM' not in s] if len(GM) == 0: + # Try an alternative name for the Mass found in some satellite queries + M = [s for s in raw_response.split('\n') if 'Mass' in s] + if len(M) > 0: + M = M[0].split('Mass')[-1].strip() + if 'kg' in M: + unit_conv_str = M.split('kg')[0].strip() + unit_conv_str = unit_conv_str.split('^')[1].strip() + unit_conv = 10**int(unit_conv_str) + mult = M.split('=')[1].strip().split(' ')[1].strip('()') + mult = 10**int(mult.split('^')[1].strip()) + M = M.split('=')[1].strip().split(' ')[0].strip() + M = float(M) * mult * unit_conv + try: + return M * swiftest.GC + except: + return None return None GM = GM[0] if len(GM) > 1: From c486412dc4d12ab15a7dd38548e1a1da2caad277 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 25 Feb 2024 17:43:29 -0500 Subject: [PATCH 239/324] Fixed units in the new edge case GMass calc --- swiftest/init_cond.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 72d33d3ab..30b292d5e 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -66,7 +66,7 @@ def get_Gmass(raw_response): M = M.split('=')[1].strip().split(' ')[0].strip() M = float(M) * mult * unit_conv try: - return M * swiftest.GC + return M * swiftest.GC * 1e-9 # Return units of km**3 / s**2 for consistency except: return None return None @@ -537,4 +537,4 @@ def vec2xr(param: Dict, **kwargs: Any): ) ds = xr.combine_by_coords([ds, clm_xr]) - return ds \ No newline at end of file + return ds From 430207a617a94ae7a4fbfbf7fdc2f911fa0d2fc1 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 26 Feb 2024 09:56:40 -0500 Subject: [PATCH 240/324] Updated the Simulation class to set the body with the largest mass as the central body (id 0) --- swiftest/simulation_class.py | 72 ++++++++++++++++++++++++++++++++++-- swiftest/tool.py | 71 ++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 5 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 42682396b..688dc07fa 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2265,7 +2265,7 @@ def add_solar_system_body(self, dsnew = init_cond.vec2xr(self.param,**kwargs) - dsnew = self._combine_and_fix_dsnew(dsnew) + dsnew = self._combine_and_fix_dsnew(dsnew,**kwargs) if dsnew['id'].max(dim='name') > 0 and dsnew['name'].size > 0: self.save(verbose=False) @@ -2421,7 +2421,8 @@ def add_body(self, J2: float | List[float] | npt.NDArray[np.float_] | None=None, J4: float | List[float] | npt.NDArray[np.float_] | None=None, c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None, - rotphase: float | List[float] | npt.NDArray[np.float_] | None=None + rotphase: float | List[float] | npt.NDArray[np.float_] | None=None, + **kwargs: Any ) -> None: """ Adds a body (test particle or massive body) to the internal DataSet given a set up 6 vectors (orbital elements @@ -2601,13 +2602,14 @@ def input_to_clm_array(val, n): dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, rotphase=rotphase, time=time) - dsnew = self._combine_and_fix_dsnew(dsnew) + dsnew = self._combine_and_fix_dsnew(dsnew,**kwargs) self.save(verbose=False) return def _combine_and_fix_dsnew(self, - dsnew: xr.Dataset + dsnew: xr.Dataset, + **kwargs: Any ) -> xr.Dataset: """ Combines the new Dataset with the old one. Also computes the values of ntp and npl and sets the proper types. @@ -2642,6 +2644,7 @@ def _combine_and_fix_dsnew(self, dsnew = io.fix_types(dsnew, ftype=np.float32) self.data = io.fix_types(self.data, ftype=np.float32) + self.set_central_body(**kwargs) def get_nvals(ds): if "name" in ds.dims: count_dim = "name" @@ -2661,6 +2664,7 @@ def get_nvals(ds): dsnew = get_nvals(dsnew) self.data = get_nvals(self.data) + self.data = self.data.sortby("id") self.data = io.reorder_dims(self.data) @@ -3064,6 +3068,7 @@ def save(self, if not self.simdir.exists(): self.simdir.mkdir(parents=True, exist_ok=True) + self.init_cond = self.data.copy(deep=True) if codename == "Swiftest": @@ -3184,3 +3189,62 @@ def clean(self): os.remove(f) return + def set_central_body(self, + align_to_rotation_pole: bool = False, + **kwargs: Any): + """ + Sets the central body to be the most massive body in the dataset. Cartesian position and velocity Cartesian coordinates are rotated If align_to_rotation_pole is True, the rotation pole is set to the z-axis. + + Parameters + ---------- + align_to_rotation_pole : bool, default False + If True, the rotation pole is set to the z-axis. + + Returns + ------- + None + + """ + + + if "Gmass" not in self.data: + warnings.warn("No bodies with Gmass values found in dataset. Cannot set central body.",stacklevel=2) + return + + cbid = self.data.Gmass.argmax().values[()] + if 'name' in self.data.dims: + cbidx = self.data.id.isel(name=cbid).values[()] + cbname = self.data.name.isel(name=cbid).values[()] + elif 'id' in self.data.dims: + cbidx = self.data.id.isel(id=cbid).values[()] + cbname = self.data.name.isel(id=cbid).values[()] + else: + raise ValueError("No 'name' or 'id' dimensions found in dataset.") + + if cbidx != 0: + if 'name' in self.data.dims: + if 0 in self.data.id.values: + name_0 = self.data.name.where(self.data.id == 0, drop=True).values[()] + self.data['id'].loc[dict(name=name_0)] = cbidx + self.data['id'].loc[dict(name=cbname)] = 0 + else: + if 0 in self.data.id.values: + self.data['id'].loc[dict(id=0)] = cbidx + self.data['id'].loc[dict(id=cbidx)] = 0 + + # Ensure that the central body is at the origin + if 'name' in self.data.dims: + cbda = self.data.sel(name=cbname) + else: + cbda = self.data.sel(id=cbidx) + + pos_skip = ['space','Ip','rot'] + for var in self.data.variables: + if var not in pos_skip: + self.data[var] -= cbda[var] + + if align_to_rotation_pole and 'rot' in cbda: + self.data = tool.rotate_to_vector(self.data,cbda.rot) + + + return \ No newline at end of file diff --git a/swiftest/tool.py b/swiftest/tool.py index 1f4b959b1..c275eff86 100644 --- a/swiftest/tool.py +++ b/swiftest/tool.py @@ -11,6 +11,8 @@ import numpy as np import xarray as xr +from scipy.spatial.transform import Rotation as R + def magnitude(ds,x): """ Computes the magnitude of a vector quantity from a Dataset. @@ -507,4 +509,71 @@ def xv2el_vec(mu, rvec, vvec): """ vecfunc = np.vectorize(xv2el_one, signature='(),(3),(3)->(),(),(),(),(),(),(),(),()') - return vecfunc(mu, rvec, vvec) \ No newline at end of file + return vecfunc(mu, rvec, vvec) + + +def rotate_to_vector(ds, new_pole, skip_vars=['space','Ip']): + """ + Rotates the coordinate system such that the z-axis is aligned with an input pole. The new pole is defined by the input vector. + This will change all variables in the Dataset that have the "space" dimension, except for those passed to the skip_vars parameter. + + Parameters + ---------- + ds : Xarray Dataset + Dataset containing the vector quantity + new_pole : (3) float array + New pole vector + skip_vars : list of str, optional + List of variable names to skip. The default is ['space','Ip']. + + Returns + ------- + ds : Xarray Dataset + Dataset with the new pole vector applied to all variables with the "space" dimension + """ + + if 'space' not in ds.dims: + print("No space dimension in Dataset") + return ds + + # Verify that the new pole is a 3-element array + if len(new_pole) != 3: + print("New pole must be a 3-element array") + return ds + + # Normalize the new pole vector to ensure it is a unit vector + pole_mag = np.linalg.norm(new_pole) + unit_pole = new_pole / pole_mag + + # Define the original and target vectors + target_vector = np.array([0, 0, 1]) # Rotate so that the z-axis is aligned with the new pole + original_vector = unit_pole.reshape(1, 3) + + # Use align_vectors to get the rotation that aligns the z-axis with Mars_rot + rotation, _ = R.align_vectors(target_vector, original_vector.reshape(1, 3)) + + # Define a function to apply the rotation, which will be used with apply_ufunc + def apply_rotation(vector, rotation): + return rotation.apply(vector) + + # Function to apply rotation to a DataArray + def rotate_dataarray(da, rotation): + return xr.apply_ufunc( + apply_rotation, + da, + kwargs={'rotation': rotation}, + input_core_dims=[['space']], + output_core_dims=[['space']], + vectorize=True, + dask='parallelized', + output_dtypes=[da.dtype] + ) + + # Loop through each variable in the dataset and apply the rotation if 'space' dimension is present + for var in ds.variables: + if 'space' in ds[var].dims and var not in skip_vars: + ds[var] = rotate_dataarray(ds[var], rotation) + + return ds + + \ No newline at end of file From c69f5e462fb5a40f30535c744b18c958df016638 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 26 Feb 2024 10:50:03 -0500 Subject: [PATCH 241/324] Refactored argument name that rotates the coordinate frame to align with the central body rotation and now explicitly pass it to the internal methods explicitly to prevent an error in the JPL Horizons call --- swiftest/simulation_class.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 688dc07fa..61f54d64a 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2150,6 +2150,7 @@ def add_solar_system_body(self, ephemeris_id: int | List[int] | None = None, date: str | None = None, source: str = "HORIZONS", + align_to_central_body_rotation: bool = False, **kwargs: Any ) -> None: """ @@ -2178,7 +2179,10 @@ def add_solar_system_body(self, set by `set_ephemeris_date`. source : str, default "Horizons" The source of the ephemerides. - Currently only the JPL Horizons ephemeris is implemented, so this is ignored. + Currently only the JPL Horizons ephemeris is implemented, so this is ignored. + align_to_central_body_rotation : bool, default False + If True, the cartesian coordinates will be aligned to the rotation pole of the central body. This is only valid for when + rotation is enabled. **kwargs : Any Additional keyword arguments to pass to the query method (i.e. astroquery.Horizons) @@ -2265,7 +2269,7 @@ def add_solar_system_body(self, dsnew = init_cond.vec2xr(self.param,**kwargs) - dsnew = self._combine_and_fix_dsnew(dsnew,**kwargs) + dsnew = self._combine_and_fix_dsnew(dsnew,align_to_central_body_rotation, **kwargs) if dsnew['id'].max(dim='name') > 0 and dsnew['name'].size > 0: self.save(verbose=False) @@ -2422,6 +2426,7 @@ def add_body(self, J4: float | List[float] | npt.NDArray[np.float_] | None=None, c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None, rotphase: float | List[float] | npt.NDArray[np.float_] | None=None, + align_to_central_body_rotation: bool = False, **kwargs: Any ) -> None: """ @@ -2467,7 +2472,9 @@ def add_body(self, Principal axes moments of inertia vectors if these are massive bodies with rotation enabled. rotphase : float, optional rotation phase angle of the central body in degrees - + align_to_central_body_rotation : bool, default False + If True, the cartesian coordinates will be aligned to the rotation pole of the central body. This is only valid for when + rotation is enabled. Returns ------- None @@ -2602,13 +2609,14 @@ def input_to_clm_array(val, n): dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, rotphase=rotphase, time=time) - dsnew = self._combine_and_fix_dsnew(dsnew,**kwargs) + dsnew = self._combine_and_fix_dsnew(dsnew,align_to_central_body_rotation,**kwargs) self.save(verbose=False) return def _combine_and_fix_dsnew(self, dsnew: xr.Dataset, + align_to_central_body_rotation: bool = False, **kwargs: Any ) -> xr.Dataset: """ @@ -2618,6 +2626,9 @@ def _combine_and_fix_dsnew(self, ---------- dsnew : xarray Dataset Dataset with new bodies + align_to_central_body_rotation : bool, default False + If True, the cartesian coordinates will be aligned to the rotation pole of the central body. This is only valid for when + rotation is enabled. Returns ------- @@ -2644,7 +2655,7 @@ def _combine_and_fix_dsnew(self, dsnew = io.fix_types(dsnew, ftype=np.float32) self.data = io.fix_types(self.data, ftype=np.float32) - self.set_central_body(**kwargs) + self.set_central_body(align_to_central_body_rotation) def get_nvals(ds): if "name" in ds.dims: count_dim = "name" @@ -3190,14 +3201,14 @@ def clean(self): return def set_central_body(self, - align_to_rotation_pole: bool = False, + align_to_central_body_rotation: bool = False, **kwargs: Any): """ - Sets the central body to be the most massive body in the dataset. Cartesian position and velocity Cartesian coordinates are rotated If align_to_rotation_pole is True, the rotation pole is set to the z-axis. + Sets the central body to be the most massive body in the dataset. Cartesian position and velocity Cartesian coordinates are rotated If align_to_central_body_rotation is True, the rotation pole is set to the z-axis. Parameters ---------- - align_to_rotation_pole : bool, default False + align_to_central_body_rotation : bool, default False If True, the rotation pole is set to the z-axis. Returns @@ -3206,7 +3217,6 @@ def set_central_body(self, """ - if "Gmass" not in self.data: warnings.warn("No bodies with Gmass values found in dataset. Cannot set central body.",stacklevel=2) return @@ -3240,11 +3250,10 @@ def set_central_body(self, pos_skip = ['space','Ip','rot'] for var in self.data.variables: - if var not in pos_skip: + if 'space' in self.data[var].dims and var not in pos_skip: self.data[var] -= cbda[var] - if align_to_rotation_pole and 'rot' in cbda: - self.data = tool.rotate_to_vector(self.data,cbda.rot) + if align_to_central_body_rotation and 'rot' in cbda: + self.data = tool.rotate_to_vector(self.data,cbda.rot.isel(time=0).values[()]) - return \ No newline at end of file From 1b7f1ba58ad3f863a73ec348c47ad2a19db5c3ba Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 26 Feb 2024 11:00:38 -0500 Subject: [PATCH 242/324] Refactored to enforce line limits --- src/swiftest/swiftest_driver.f90 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_driver.f90 b/src/swiftest/swiftest_driver.f90 index 0ed7536e4..88cab75d2 100644 --- a/src/swiftest/swiftest_driver.f90 +++ b/src/swiftest/swiftest_driver.f90 @@ -23,10 +23,11 @@ module subroutine swiftest_driver(integrator, param_file_name, display_style) ! Arguments character(len=:), intent(in), allocatable :: integrator !! Symbolic code of the requested integrator character(len=:), intent(in), allocatable :: param_file_name !! Name of the input parameters file - character(len=:), intent(in), allocatable :: display_style !! Style of the output display {"STANDARD", "COMPACT", "PROGRESS"}). Default is "STANDARD" + character(len=:), intent(in), allocatable :: display_style !! Style of the output display + !! {"STANDARD", "COMPACT", "PROGRESS"}). Default is "STANDARD" ! Internals - class(swiftest_nbody_system), allocatable :: nbody_system !! Polymorphic object containing the nbody system to be integrated + class(swiftest_nbody_system), allocatable :: nbody_system !! Polymorphic object containing the nbody system to be integrated type(swiftest_parameters) :: param !! Run configuration parameters class(swiftest_storage), allocatable :: system_history !! Stores the system history between output dumps type(walltimer) :: integration_timer !! Object used for computing elapsed wall time @@ -101,7 +102,8 @@ module subroutine swiftest_driver(integrator, param_file_name, display_style) if (param%log_output) flush(param%display_unit) #ifdef COARRAY - ! The following line lets us read in the input files one image at a time. Letting each image read the input in is faster than broadcasting all of the data + ! The following line lets us read in the input files one image at a time. Letting each image read the input in is faster + ! than broadcasting all of the data if (param%lcoarray .and. (this_image() /= 1)) sync images(this_image() - 1) #endif call nbody_system%initialize(system_history, param) @@ -112,14 +114,16 @@ module subroutine swiftest_driver(integrator, param_file_name, display_style) if (param%lcoarray) call nbody_system%coarray_distribute(param) #endif - ! If this is a new run, compute energy initial conditions (if energy tracking is turned on) and write the initial conditions to file. + ! If this is a new run, compute energy initial conditions (if energy tracking is turned on) and write the initial + ! conditions to file. call nbody_system%display_run_information(param, integration_timer, phase="first") if (param%lenergy) then if (param%lrestart) then call nbody_system%get_t0_values(system_history%nc, param) else - call nbody_system%conservation_report(param, lterminal=.false.) ! This will save the initial values of energy and momentum + call nbody_system%conservation_report(param, lterminal=.false.) ! This will save the initial values of energy and + ! momentum end if call nbody_system%conservation_report(param, lterminal=.true.) end if From cba1f772843ccf3e18581b636c4fe533657e22ee Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 26 Feb 2024 11:21:50 -0500 Subject: [PATCH 243/324] Fixed problem with unit conversion for the CHK_QMIN_RANGE value. Also set it so that the default rmin value is the central body radius, rather than the solar radius --- swiftest/simulation_class.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 61f54d64a..d4e3a4e0f 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -238,7 +238,7 @@ def __init__(self,read_param: bool = False, The name of the time unit. When setting one of the standard units via `TU` a name will be automatically set for the unit, so this argument will override the automatic name. Parameter input file equivalent is None - rmin : float, default value is the radius of the Sun in the unit system defined by the unit input arguments. + rmin : float, default value is the radius of the central body in the unit system defined by the unit input arguments. Minimum distance of the simulation Parameter input file equivalent are `CHK_QMIN`, `CHK_RMIN`, `CHK_QMIN_RANGE[0]` rmax : float, default value is 10000 AU in the unit system defined by the unit input arguments. @@ -776,7 +776,7 @@ def set_parameter(self, "MU_name": None, "DU_name": None, "TU_name": None, - "rmin": constants.RSun / constants.AU2M, + "rmin": None, "rmax": 10000.0, "qmin_coord": "HELIO", "gmtiny": 0.0, @@ -2008,7 +2008,8 @@ def _update_param_units(self, MU2KG_old, DU2M_old, TU2S_old): if CHK_QMIN_RANGE is not None: CHK_QMIN_RANGE = CHK_QMIN_RANGE.split(" ") for i, v in enumerate(CHK_QMIN_RANGE): - CHK_QMIN_RANGE[i] = float(CHK_QMIN_RANGE[i]) * self.param['DU2M'] / DU2M_old + if float(v) > 0.0: + CHK_QMIN_RANGE[i] = float(v) * DU2M_old / self.param['DU2M'] self.param['CHK_QMIN_RANGE'] = f"{CHK_QMIN_RANGE[0]} {CHK_QMIN_RANGE[1]}" if TU2S_old is not None: @@ -3255,5 +3256,8 @@ def set_central_body(self, if align_to_central_body_rotation and 'rot' in cbda: self.data = tool.rotate_to_vector(self.data,cbda.rot.isel(time=0).values[()]) - + + if self.param['CHK_CLOSE']: + if 'CHK_RMIN' not in self.param: + self.param['CHK_RMIN'] = cbda.radius.values.item() return \ No newline at end of file From 8171caa81a76e9c92fa2304cd66fc036352a318d Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 26 Feb 2024 16:00:20 -0500 Subject: [PATCH 244/324] Now correctly transform spin poles from the celestial frame to the ecliptic frame --- swiftest/init_cond.py | 4 +++- swiftest/tool.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 30b292d5e..0c57ddecf 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -140,11 +140,13 @@ def get_rotrate(raw_response): def get_rotpole(jpl): RA = jpl.ephemerides()['NPole_RA'][0] DEC = jpl.ephemerides()['NPole_DEC'][0] + if np.ma.is_masked(RA) or np.ma.is_masked(DEC): return np.array([0.0,0.0,1.0]) - rotpole = SkyCoord(ra=RA * u.degree, dec=DEC * u.degree).cartesian + rotpole = SkyCoord(ra=RA * u.degree, dec=DEC * u.degree,frame='icrs').transform_to('barycentricmeanecliptic').cartesian + return np.array([rotpole.x.value, rotpole.y.value, rotpole.z.value]) if type(altid) != list: diff --git a/swiftest/tool.py b/swiftest/tool.py index c275eff86..159e45b5b 100644 --- a/swiftest/tool.py +++ b/swiftest/tool.py @@ -550,7 +550,7 @@ def rotate_to_vector(ds, new_pole, skip_vars=['space','Ip']): original_vector = unit_pole.reshape(1, 3) # Use align_vectors to get the rotation that aligns the z-axis with Mars_rot - rotation, _ = R.align_vectors(target_vector, original_vector.reshape(1, 3)) + rotation, _ = R.align_vectors(target_vector, original_vector) # Define a function to apply the rotation, which will be used with apply_ufunc def apply_rotation(vector, rotation): From c7b95856191dd704f0def2ac77dffb9184417926 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 08:17:11 -0500 Subject: [PATCH 245/324] Refactored to enforce line limit --- src/base/base_module.f90 | 10 +++++----- src/rmvs/rmvs_step.f90 | 12 ++++++++---- swiftest/init_cond.py | 1 - 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index 9cff4cff5..8be20f9d3 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -83,9 +83,9 @@ module base ! The following are not set by the user, but instead are determined by the input value of INTERACTION_LOOPS logical :: lflatten_interactions = .false. !! Use the flattened upper triangular matrix for pl-pl interaction loops - logical :: lencounter_sas_plpl = .false. !! Use the Sort and Sweep algorithm to prune the encounter list before checking + logical :: lencounter_sas_plpl = .false. !! Use the Sort and Sweep algorithm to prune the encounter list before checking !! for close encounters - logical :: lencounter_sas_pltp = .false. !! Use the Sort and Sweep algorithm to prune the encounter list before checking + logical :: lencounter_sas_pltp = .false. !! Use the Sort and Sweep algorithm to prune the encounter list before checking !! for close encounters ! Logical flags to turn on or off various features of the code @@ -95,7 +95,7 @@ module base logical :: lbig_discard = .false. !! Save big bodies on every discard logical :: lclose = .false. !! Turn on close encounters logical :: lenergy = .false. !! Track the total energy of the system - logical :: loblatecb = .false. !! Calculate acceleration from oblate central body (automatically turns true if nonzero J2 + logical :: loblatecb = .false. !! Calculate acceleration from oblate central body (automatically turns true if nonzero J2 !! is input) logical :: lrotation = .false. !! Include rotation states of big bodies logical :: ltides = .false. !! Include tidal dissipation @@ -118,7 +118,7 @@ module base logical :: lrestart = .false. !! Indicates whether or not this is a restarted run character(NAMELEN) :: display_style !! Style of the output display {["STANDARD"], "COMPACT"}). - integer(I4B) :: display_unit = OUTPUT_UNIT !! File unit number for display (either to stdout or to a log file) + integer(I4B) :: display_unit = OUTPUT_UNIT !! File unit number for display (either to stdout or to a log file) logical :: log_output = .false. !! Logs the output to file instead of displaying it on the terminal ! Future features not implemented or in development @@ -2113,7 +2113,7 @@ subroutine base_util_unique_DP(input_array, output_array, index_map) real(DP), dimension(:), allocatable, intent(out) :: output_array !! Sorted array of unique values integer(I4B), dimension(:), allocatable, intent(out) :: index_map !! An array of the same size as input_array that such !! that any for any index i, - !! output_array(index_map(i)) = input_array(i) + !! output_array(index_map(i)) = input_array(i) ! Internals real(DP), dimension(:), allocatable :: unique_array integer(I4B) :: n diff --git a/src/rmvs/rmvs_step.f90 b/src/rmvs/rmvs_step.f90 index f7d1a87bf..04fadb74b 100644 --- a/src/rmvs/rmvs_step.f90 +++ b/src/rmvs/rmvs_step.f90 @@ -203,8 +203,10 @@ subroutine rmvs_step_out(cb, pl, tp, nbody_system, param, t, dt) tp%lfirst = lfirsttp else if (param%loblatecb) then - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rbeg, pl%lmask, pl%outer(outer_index-1)%aobl, cb%rot, pl%Gmass, cb%aoblbeg) - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rend, pl%lmask, pl%outer(outer_index)%aobl, cb%rot, pl%Gmass, cb%aoblend) + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rbeg, pl%lmask, pl%outer(outer_index-1)%aobl, cb%rot,& + pl%Gmass, cb%aoblbeg) + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rend, pl%lmask, pl%outer(outer_index)%aobl, cb%rot, & + pl%Gmass, cb%aoblend) end if call tp%step(nbody_system, param, outer_time, dto) end if @@ -268,7 +270,8 @@ subroutine rmvs_interp_in(cb, pl, nbody_system, param, dt, outer_index) if ((param%loblatecb) .or. (param%ltides)) then allocate(rh_original, source=pl%rh) allocate(ah_original, source=pl%ah) - pl%rh(:, 1:npl) = xtmp(:, 1:npl) ! Temporarily replace heliocentric position with inner substep values to calculate the oblateness terms + pl%rh(:, 1:npl) = xtmp(:, 1:npl) ! Temporarily replace heliocentric position with inner substep values to calculate the + ! oblateness terms end if if (param%loblatecb) then call pl%accel_obl(nbody_system) @@ -396,7 +399,8 @@ subroutine rmvs_step_in(cb, pl, tp, param, outer_time, dto) call rmvs_peri_tp(tpenci, pl, inner_time, dti, .true., 0, i, param) ! now step the encountering test particles fully through the inner encounter lfirsttp = .true. - do inner_index = 1, NTPHENC ! Integrate over the encounter region, using the "substitute" planetocentric systems at each level + do inner_index = 1, NTPHENC ! Integrate over the encounter region, using the "substitute" planetocentric + ! systems at each level plenci%rh(:, 1:npl) = plenci%inner(inner_index - 1)%x(:, 1:npl) call plenci%set_beg_end(rbeg = plenci%inner(inner_index - 1)%x, & rend = plenci%inner(inner_index)%x) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index 0c57ddecf..a8770328a 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -141,7 +141,6 @@ def get_rotpole(jpl): RA = jpl.ephemerides()['NPole_RA'][0] DEC = jpl.ephemerides()['NPole_DEC'][0] - if np.ma.is_masked(RA) or np.ma.is_masked(DEC): return np.array([0.0,0.0,1.0]) From 2b36b66ffd1a2eacd6ae3810f6faecb5461c32f1 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 08:28:14 -0500 Subject: [PATCH 246/324] Added a new shgrav module that will eventually contain the SHTOOLS-based central body acceleration procedures --- src/CMakeLists.txt | 1 + src/base/base_module.f90 | 40 ++++++++++++++++++------------------ src/shgrav/shgrav_module.f90 | 20 ++++++++++++++++++ 3 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 src/shgrav/shgrav_module.f90 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 985d2ea99..bec5aa743 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,6 +66,7 @@ SET(FAST_MATH_FILES ${SRC}/rmvs/rmvs_module.f90 ${SRC}/helio/helio_module.f90 ${SRC}/symba/symba_module.f90 + ${SRC}/shgrav/shgrav_module.f90 ${SRC}/collision/collision_check.f90 ${SRC}/collision/collision_regime.f90 ${SRC}/collision/collision_resolve.f90 diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index 8be20f9d3..6f0821b70 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -2249,39 +2249,39 @@ subroutine base_coclone_param(self) call coclone(self%collision_model) call coclone(self%encounter_save) call coclone(self%lenc_save_trajectory) - call coclone(self%lenc_save_closest ) - call coclone(self%interaction_loops ) + call coclone(self%lenc_save_closest) + call coclone(self%interaction_loops) call coclone(self%encounter_check_plpl) call coclone(self%encounter_check_pltp) call coclone(self%lflatten_interactions) call coclone(self%lencounter_sas_plpl) - call coclone(self%lencounter_sas_pltp ) + call coclone(self%lencounter_sas_pltp) call coclone(self%lrhill_present) - call coclone(self%lextra_force ) - call coclone(self%lbig_discard ) - call coclone(self%lclose ) - call coclone(self%lenergy ) - call coclone(self%loblatecb ) - call coclone(self%lrotation ) - call coclone(self%ltides ) - call coclone(self%E_orbit_orig ) - call coclone(self%GMtot_orig ) + call coclone(self%lextra_force) + call coclone(self%lbig_discard) + call coclone(self%lclose) + call coclone(self%lenergy) + call coclone(self%loblatecb) + call coclone(self%lrotation) + call coclone(self%ltides) + call coclone(self%E_orbit_orig) + call coclone(self%GMtot_orig) call coclonevec(self%L_total_orig) call coclonevec(self%L_orbit_orig) call coclonevec(self%L_spin_orig) call coclonevec(self%L_escape) - call coclone(self%GMescape ) - call coclone(self%E_collisions ) - call coclone(self%E_untracked ) + call coclone(self%GMescape) + call coclone(self%E_collisions) + call coclone(self%E_untracked) call coclone(self%lfirstenergy) - call coclone(self%lfirstkick ) - call coclone(self%lrestart ) + call coclone(self%lfirstkick) + call coclone(self%lrestart) call coclone(self%display_style) - call coclone(self%display_unit ) + call coclone(self%display_unit) call coclone(self%log_output ) - call coclone(self%lgr ) + call coclone(self%lgr) call coclone(self%lyarkovsky) - call coclone(self%lyorp ) + call coclone(self%lyorp) call coclone(self%seed) call coclone(self%lcoarray) diff --git a/src/shgrav/shgrav_module.f90 b/src/shgrav/shgrav_module.f90 new file mode 100644 index 000000000..0007bb2af --- /dev/null +++ b/src/shgrav/shgrav_module.f90 @@ -0,0 +1,20 @@ +! Copyight 2024 - The Minton Group at Purdue University +! This file is part of Swiftest. +! Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License +! as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +! Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +! You should have received a copy of the GNU General Public License along with Swiftest. +! If not, see: https://www.gnu.org/licenses. + +module shgrav + !! author: David A. Minton and Kaustub Anand + !! + !! This module defines functions used for the computation of accelerations based on spherical harmonics representation of the + !! gravitational potential of the central body. It uses the SHTOOLS library https://shtools.github.io/SHTOOLS/ + use swiftest + implicit none + public + +end module shgrav + \ No newline at end of file From 63e9f228fbda453c0ac511e0e65b3315352a55bc Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 09:07:42 -0500 Subject: [PATCH 247/324] Refactored to Ford documentation strings for readability and to enforce line limts --- src/netcdf_io/netcdf_io_module.f90 | 451 +++++++++++++++++++---------- 1 file changed, 300 insertions(+), 151 deletions(-) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index e40df8135..c9d0df68e 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -11,195 +11,344 @@ module netcdf_io !! author: The Purdue Swiftest Team - David A. Minton, Carlisle A. Wishard, Jennifer L.L. Pouplin, and Jacob R. Elliott !! !! Base type definitions. This allows the collision and encounter modules to be defined before the swiftest module. - !! use globals use base implicit none public - !! This derived datatype stores the NetCDF ID values for each of the variables included in the NetCDF data file. This is used as the base class defined in base + !! This derived datatype stores the NetCDF ID values for each of the variables included in the NetCDF data file. This is used as + !! the base class defined in base type, abstract :: netcdf_parameters - character(STRMAX) :: file_name !! Name of the output file - logical :: lfile_is_open = .false. !! Flag indicating that the linked file is currently open - integer(I4B) :: out_type !! output type (will be assigned either NF90_DOUBLE or NF90_FLOAT, depending on the user parameter) - integer(I4B) :: id !! ID for the output file - integer(I4B) :: tslot = 1 !! The current time slot that gets passed to the NetCDF reader/writer - integer(I4B) :: max_tslot = 0 !! Records the last index value of time in the NetCDF file - integer(I4B), dimension(:), allocatable :: idvals !! Array of id values in this NetCDF file - integer(I4B) :: idslot = 1 !! The current id slot that gets passed to the NetCDF reader/writer - integer(I4B) :: max_idslot = 0 !! Records the last index value of id in the NetCDF file + character(STRMAX) :: file_name + !! Name of the output file + logical :: lfile_is_open = .false. + !! Flag indicating that the linked file is currently open + integer(I4B) :: out_type + !! output type (will be assigned either NF90_DOUBLE or NF90_FLOAT, depending on the user parameter) + integer(I4B) :: id + !! ID for the output file + integer(I4B) :: tslot = 1 + !! The current time slot that gets passed to the NetCDF reader/writer + integer(I4B) :: max_tslot = 0 + !! Records the last index value of time in the NetCDF file + integer(I4B), dimension(:), allocatable :: idvals + !! Array of id values in this NetCDF file + integer(I4B) :: idslot = 1 + !! The current id slot that gets passed to the NetCDF reader/writer + integer(I4B) :: max_idslot = 0 + !! Records the last index value of id in the NetCDF file ! Dimension ids and variable names - character(NAMELEN) :: str_dimname = "string32" !! name of the character string dimension - integer(I4B) :: str_dimid !! ID for the character string dimension - character(NAMELEN) :: time_dimname = "time" !! name of the time dimension - integer(I4B) :: time_dimid !! ID for the time dimension - integer(I4B) :: time_varid !! ID for the time variable - character(NAMELEN) :: name_dimname = "name" !! name of the particle name dimension - integer(I4B) :: name_dimid !! ID for the particle name dimension - integer(I4B) :: name_varid !! ID for the particle name variable - character(NAMELEN) :: space_dimname = "space" !! name of the space dimension - integer(I4B) :: space_dimid !! ID for the space dimension - integer(I4B) :: space_varid !! ID for the space variable - character(len=1), dimension(3) :: space_coords = ["x","y","z"] !! The space dimension coordinate labels - character(NAMELEN) :: sign_dimname = "sign" !! name of the sign dimension for c_lm - integer(I4B) :: sign_dimid !! ID for sign dimension - integer(I4B) :: sign_varid !! ID for sign variable - character(NAMELEN) :: l_dimname = "l" !! name of l dimension for c_lm - integer(I4B) :: l_dimid !! ID for the l dimension for c_lm - integer(I4B) :: l_varid !! ID for the l variable - character(NAMELEN) :: m_dimname = "m" !! name of m dimension for c_lm - integer(I4B) :: m_dimid !! ID for the m dimension for c_lm - integer(I4B) :: m_varid !! ID for the m variable + character(NAMELEN) :: str_dimname = "string32" + !! name of the character string dimension + integer(I4B) :: str_dimid + !! ID for the character string dimension + character(NAMELEN) :: time_dimname = "time" + !! name of the time dimension + integer(I4B) :: time_dimid + !! ID for the time dimension + integer(I4B) :: time_varid + !! ID for the time variable + character(NAMELEN) :: name_dimname = "name" + !! name of the particle name dimension + integer(I4B) :: name_dimid + !! ID for the particle name dimension + integer(I4B) :: name_varid + !! ID for the particle name variable + character(NAMELEN) :: space_dimname = "space" + !! name of the space dimension + integer(I4B) :: space_dimid + !! ID for the space dimension + integer(I4B) :: space_varid + !! ID for the space variable + character(len=1), dimension(3) :: space_coords = ["x","y","z"] + !! The space dimension coordinate labels + character(NAMELEN) :: sign_dimname = "sign" + !! name of the sign dimension for c_lm + integer(I4B) :: sign_dimid + !! ID for sign dimension + integer(I4B) :: sign_varid + !! ID for sign variable + character(NAMELEN) :: l_dimname = "l" + !! name of l dimension for c_lm + integer(I4B) :: l_dimid + !! ID for the l dimension for c_lm + integer(I4B) :: l_varid + !! ID for the l variable + character(NAMELEN) :: m_dimname = "m" + !! name of m dimension for c_lm + integer(I4B) :: m_dimid + !! ID for the m dimension for c_lm + integer(I4B) :: m_varid + !! ID for the m variable ! Non-dimension ids and variable names - character(NAMELEN) :: id_varname = "id" !! name of the particle id variable - integer(I4B) :: id_varid !! ID for the id variable - character(NAMELEN) :: status_varname = "status" !! name of the particle status variable - integer(I4B) :: status_varid !! ID for the status variable - character(NAMELEN) :: ptype_varname = "particle_type" !! name of the particle type variable - integer(I4B) :: ptype_varid !! ID for the particle type variable - character(NAMELEN) :: npl_varname = "npl" !! name of the number of active massive bodies variable - integer(I4B) :: npl_varid !! ID for the number of active massive bodies variable - character(NAMELEN) :: ntp_varname = "ntp" !! name of the number of active test particles variable - integer(I4B) :: ntp_varid !! ID for the number of active test particles variable - character(NAMELEN) :: nplm_varname = "nplm" !! name of the number of active fully interacting massive bodies variable (SyMBA) - integer(I4B) :: nplm_varid !! ID for the number of active fully interacting massive bodies variable (SyMBA) - character(NAMELEN) :: a_varname = "a" !! name of the semimajor axis variable - integer(I4B) :: a_varid !! ID for the semimajor axis variable - character(NAMELEN) :: e_varname = "e" !! name of the eccentricity variable - integer(I4B) :: e_varid !! ID for the eccentricity variable - character(NAMELEN) :: inc_varname = "inc" !! name of the inclination variable - integer(I4B) :: inc_varid !! ID for the inclination variable - character(NAMELEN) :: capom_varname = "capom" !! name of the long. asc. node variable - integer(I4B) :: capom_varid !! ID for the long. asc. node variable - character(NAMELEN) :: omega_varname = "omega" !! name of the arg. of periapsis variable - integer(I4B) :: omega_varid !! ID for the arg. of periapsis variable - character(NAMELEN) :: capm_varname = "capm" !! name of the mean anomaly variable - integer(I4B) :: capm_varid !! ID for the mean anomaly variable - character(NAMELEN) :: varpi_varname = "varpi" !! name of the long. of periapsis variable - integer(I4B) :: varpi_varid !! ID for the long. of periapsis variable - character(NAMELEN) :: lam_varname = "lam" !! name of the mean longitude variable - integer(I4B) :: lam_varid !! ID for the mean longitude variable - character(NAMELEN) :: f_varname = "f" !! name of the true anomaly variable - integer(I4B) :: f_varid !! ID for the true anomaly variable - character(NAMELEN) :: cape_varname = "cape" !! name of the eccentric anomaly variable - integer(I4B) :: cape_varid !! ID for the eccentric anomaly variable - character(NAMELEN) :: rh_varname = "rh" !! name of the heliocentric position vector variable - integer(I4B) :: rh_varid !! ID for the heliocentric position vector variable - character(NAMELEN) :: vh_varname = "vh" !! name of the heliocentric velocity vector variable - integer(I4B) :: vh_varid !! ID for the heliocentric velocity vector variable - character(NAMELEN) :: gr_pseudo_vh_varname = "gr_pseudo_vh" !! name of the heliocentric pseudovelocity vector variable (used in GR only) - integer(I4B) :: gr_pseudo_vh_varid !! ID for the heliocentric pseudovelocity vector variable (used in GR) - character(NAMELEN) :: Gmass_varname = "Gmass" !! name of the G*mass variable - integer(I4B) :: Gmass_varid !! ID for the G*mass variable - character(NAMELEN) :: mass_varname = "mass" !! name of the mass variable - integer(I4B) :: mass_varid !! ID for the mass variable - character(NAMELEN) :: rhill_varname = "rhill" !! name of the hill radius variable - integer(I4B) :: rhill_varid !! ID for the hill radius variable - character(NAMELEN) :: radius_varname = "radius" !! name of the radius variable - integer(I4B) :: radius_varid !! ID for the radius variable - character(NAMELEN) :: Ip_varname = "Ip" !! name of the principal moment of inertial variable - integer(I4B) :: Ip_varid !! ID for the axis principal moment of inertia variable - character(NAMELEN) :: rot_varname = "rot" !! name of the rotation vector variable - integer(I4B) :: rot_varid !! ID for the rotation vector variable - character(NAMELEN) :: rotphase_varname = "rotphase" !! name of the rotation phase variable - integer(I4B) :: rotphase_varid !! ID for the rotation phase variable - character(NAMELEN) :: j2rp2_varname = "j2rp2" !! name of the j2rp2 variable - integer(I4B) :: j2rp2_varid !! ID for the j2 variable - character(NAMELEN) :: j4rp4_varname = "j4rp4" !! name of the j4pr4 variable - integer(I4B) :: j4rp4_varid !! ID for the j4 variable - character(NAMELEN) :: c_lm_varname = "c_lm" !! name for the c_lm array - integer(I4B) :: c_lm_varid !! ID for the c_lm aqrray - character(NAMELEN) :: k2_varname = "k2" !! name of the Love number variable - integer(I4B) :: k2_varid !! ID for the Love number variable - character(NAMELEN) :: q_varname = "Q" !! name of the energy dissipation variable - integer(I4B) :: Q_varid !! ID for the energy dissipation variable - character(NAMELEN) :: ke_orb_varname = "KE_orb" !! name of the system orbital kinetic energy variable - integer(I4B) :: KE_orb_varid !! ID for the system orbital kinetic energy variable - character(NAMELEN) :: ke_spin_varname = "KE_spin" !! name of the system spin kinetic energy variable - integer(I4B) :: KE_spin_varid !! ID for the system spin kinetic energy variable - character(NAMELEN) :: pe_varname = "PE" !! name of the system potential energy variable - integer(I4B) :: PE_varid !! ID for the system potential energy variable - character(NAMELEN) :: be_varname = "BE" !! name of the system binding energy variable - integer(I4B) :: BE_varid !! ID for the system binding energy variable - character(NAMELEN) :: te_varname = "TE" !! name of the system binding energy variable - integer(I4B) :: TE_varid !! ID for the system binding energy variable - character(NAMELEN) :: L_orbit_varname = "L_orbit" !! name of the orbital angular momentum vector variable - integer(I4B) :: L_orbit_varid !! ID for the system orbital angular momentum vector variable - character(NAMELEN) :: L_spin_varname = "L_spin" !! name of the spin angular momentum vector variable - integer(I4B) :: L_spin_varid !! ID for the system spin angular momentum vector variable - character(NAMELEN) :: L_escape_varname = "L_escape" !! name of the escaped angular momentum vector variable - integer(I4B) :: L_escape_varid !! ID for the escaped angular momentum vector variable - character(NAMELEN) :: E_collisions_varname = "E_collisions" !! name of the escaped angular momentum y variable - integer(I4B) :: E_collisions_varid !! ID for the energy lost in collisions variable - character(NAMELEN) :: E_untracked_varname = "E_untracked" !! name of the energy that is untracked due to loss (untracked potential energy due to mergers and body energy for escaped bodies) - integer(I4B) :: E_untracked_varid !! ID for the energy that is untracked due to loss (untracked potential energy due to mergers and body energy for escaped bodies) - character(NAMELEN) :: GMescape_varname = "GMescape" !! name of the G*Mass of bodies that escape the system - integer(I4B) :: GMescape_varid !! ID for the G*Mass of bodies that escape the system - character(NAMELEN) :: origin_type_varname = "origin_type" !! name of the origin type variable (Initial Conditions, Disruption, etc.) - integer(I4B) :: origin_type_varid !! ID for the origin type - character(NAMELEN) :: origin_time_varname = "origin_time" !! name of the time of origin variable - integer(I4B) :: origin_time_varid !! ID for the origin time - character(NAMELEN) :: collision_id_varname = "collision_id" !! name of the collision id variable - integer(I4B) :: collision_id_varid !! Netcdf ID for the origin collision ID - character(NAMELEN) :: origin_rh_varname = "origin_rh" !! name of the heliocentric position vector of the body at the time of origin variable - integer(I4B) :: origin_rh_varid !! ID for the origin position vector variable - character(NAMELEN) :: origin_vh_varname = "origin_vh" !! name of the heliocentric velocity vector of the body at the time of origin variable - integer(I4B) :: origin_vh_varid !! ID for the origin velocity vector component - character(NAMELEN) :: discard_time_varname = "discard_time" !! name of the time of discard variable - integer(I4B) :: discard_time_varid !! ID for the time of discard variable - character(NAMELEN) :: discard_rh_varname = "discard_rh" !! name of the heliocentric position vector of the body at the time of discard variable - integer(I4B) :: discard_rh_varid !! ID for the heliocentric position vector of the body at the time of discard variable - character(NAMELEN) :: discard_vh_varname = "discard_vh" !! name of the heliocentric velocity vector of the body at the time of discard variable - integer(I4B) :: discard_vh_varid !! ID for the heliocentric velocity vector of the body at the time of discard variable - character(NAMELEN) :: discard_body_id_varname = "discard_body_id" !! name of the id of the other body involved in the discard - integer(I4B) :: discard_body_id_varid !! ID for the id of the other body involved in the discard - logical :: lpseudo_vel_exists = .false. !! Logical flag to indicate whether or not the pseudovelocity vectors were present in an old file. + character(NAMELEN) :: id_varname = "id" + !! name of the particle id variable + integer(I4B) :: id_varid + !! ID for the id variable + character(NAMELEN) :: status_varname = "status" + !! name of the particle status variable + integer(I4B) :: status_varid + !! ID for the status variable + character(NAMELEN) :: ptype_varname = "particle_type" + !! name of the particle type variable + integer(I4B) :: ptype_varid + !! ID for the particle type variable + character(NAMELEN) :: npl_varname = "npl" + !! name of the number of active massive bodies variable + integer(I4B) :: npl_varid + !! ID for the number of active massive bodies variable + character(NAMELEN) :: ntp_varname = "ntp" + !! name of the number of active test particles variable + integer(I4B) :: ntp_varid + !! ID for the number of active test particles variable + character(NAMELEN) :: nplm_varname = "nplm" + !! name of the number of active fully interacting massive bodies variable (SyMBA) + integer(I4B) :: nplm_varid + !! ID for the number of active fully interacting massive bodies variable (SyMBA) + character(NAMELEN) :: a_varname = "a" + !! name of the semimajor axis variable + integer(I4B) :: a_varid + !! ID for the semimajor axis variable + character(NAMELEN) :: e_varname = "e" + !! name of the eccentricity variable + integer(I4B) :: e_varid + !! ID for the eccentricity variable + character(NAMELEN) :: inc_varname = "inc" + !! name of the inclination variable + integer(I4B) :: inc_varid + !! ID for the inclination variable + character(NAMELEN) :: capom_varname = "capom" + !! name of the long. asc. node variable + integer(I4B) :: capom_varid + !! ID for the long. asc. node variable + character(NAMELEN) :: omega_varname = "omega" + !! name of the arg. of periapsis variable + integer(I4B) :: omega_varid + !! ID for the arg. of periapsis variable + character(NAMELEN) :: capm_varname = "capm" + !! name of the mean anomaly variable + integer(I4B) :: capm_varid + !! ID for the mean anomaly variable + character(NAMELEN) :: varpi_varname = "varpi" + !! name of the long. of periapsis variable + integer(I4B) :: varpi_varid + !! ID for the long. of periapsis variable + character(NAMELEN) :: lam_varname = "lam" + !! name of the mean longitude variable + integer(I4B) :: lam_varid + !! ID for the mean longitude variable + character(NAMELEN) :: f_varname = "f" + !! name of the true anomaly variable + integer(I4B) :: f_varid + !! ID for the true anomaly variable + character(NAMELEN) :: cape_varname = "cape" + !! name of the eccentric anomaly variable + integer(I4B) :: cape_varid + !! ID for the eccentric anomaly variable + character(NAMELEN) :: rh_varname = "rh" + !! name of the heliocentric position vector variable + integer(I4B) :: rh_varid + !! ID for the heliocentric position vector variable + character(NAMELEN) :: vh_varname = "vh" + !! name of the heliocentric velocity vector variable + integer(I4B) :: vh_varid + !! ID for the heliocentric velocity vector variable + character(NAMELEN) :: gr_pseudo_vh_varname = "gr_pseudo_vh" + !! name of the heliocentric pseudovelocity vector variable (GR) + integer(I4B) :: gr_pseudo_vh_varid + !! ID for the heliocentric pseudovelocity vector variable (used in GR) + character(NAMELEN) :: Gmass_varname = "Gmass" + !! name of the G*mass variable + integer(I4B) :: Gmass_varid + !! ID for the G*mass variable + character(NAMELEN) :: mass_varname = "mass" + !! name of the mass variable + integer(I4B) :: mass_varid + !! ID for the mass variable + character(NAMELEN) :: rhill_varname = "rhill" + !! name of the hill radius variable + integer(I4B) :: rhill_varid + !! ID for the hill radius variable + character(NAMELEN) :: radius_varname = "radius" + !! name of the radius variable + integer(I4B) :: radius_varid + !! ID for the radius variable + character(NAMELEN) :: Ip_varname = "Ip" + !! name of the principal moment of inertial variable + integer(I4B) :: Ip_varid + !! ID for the axis principal moment of inertia variable + character(NAMELEN) :: rot_varname = "rot" + !! name of the rotation vector variable + integer(I4B) :: rot_varid + !! ID for the rotation vector variable + character(NAMELEN) :: rotphase_varname = "rotphase" + !! name of the rotation phase variable + integer(I4B) :: rotphase_varid + !! ID for the rotation phase variable + character(NAMELEN) :: j2rp2_varname = "j2rp2" + !! name of the j2rp2 variable + integer(I4B) :: j2rp2_varid + !! ID for the j2 variable + character(NAMELEN) :: j4rp4_varname = "j4rp4" + !! name of the j4pr4 variable + integer(I4B) :: j4rp4_varid + !! ID for the j4 variable + character(NAMELEN) :: c_lm_varname = "c_lm" + !! name for the c_lm array + integer(I4B) :: c_lm_varid + !! ID for the c_lm aqrray + character(NAMELEN) :: k2_varname = "k2" + !! name of the Love number variable + integer(I4B) :: k2_varid + !! ID for the Love number variable + character(NAMELEN) :: q_varname = "Q" + !! name of the energy dissipation variable + integer(I4B) :: Q_varid + !! ID for the energy dissipation variable + character(NAMELEN) :: ke_orb_varname = "KE_orb" + !! name of the system orbital kinetic energy variable + integer(I4B) :: KE_orb_varid + !! ID for the system orbital kinetic energy variable + character(NAMELEN) :: ke_spin_varname = "KE_spin" + !! name of the system spin kinetic energy variable + integer(I4B) :: KE_spin_varid + !! ID for the system spin kinetic energy variable + character(NAMELEN) :: pe_varname = "PE" + !! name of the system potential energy variable + integer(I4B) :: PE_varid + !! ID for the system potential energy variable + character(NAMELEN) :: be_varname = "BE" + !! name of the system binding energy variable + integer(I4B) :: BE_varid + !! ID for the system binding energy variable + character(NAMELEN) :: te_varname = "TE" + !! name of the system binding energy variable + integer(I4B) :: TE_varid + !! ID for the system binding energy variable + character(NAMELEN) :: L_orbit_varname = "L_orbit" + !! name of the orbital angular momentum vector variable + integer(I4B) :: L_orbit_varid + !! ID for the system orbital angular momentum vector variable + character(NAMELEN) :: L_spin_varname = "L_spin" + !! name of the spin angular momentum vector variable + integer(I4B) :: L_spin_varid + !! ID for the system spin angular momentum vector variable + character(NAMELEN) :: L_escape_varname = "L_escape" + !! name of the escaped angular momentum vector variable + integer(I4B) :: L_escape_varid + !! ID for the escaped angular momentum vector variable + character(NAMELEN) :: E_collisions_varname = "E_collisions" + !! name of the escaped angular momentum y variable + integer(I4B) :: E_collisions_varid + !! ID for the energy lost in collisions variable + character(NAMELEN) :: E_untracked_varname = "E_untracked" + !! name of the energy that is untracked due to loss (due to mergers and body energy for escaped bodies) + integer(I4B) :: E_untracked_varid + !! ID for the energy that is untracked due to loss (due to mergers and body energy for escaped bodies) + character(NAMELEN) :: GMescape_varname = "GMescape" + !! name of the G*Mass of bodies that escape the system + integer(I4B) :: GMescape_varid + !! ID for the G*Mass of bodies that escape the system + character(NAMELEN) :: origin_type_varname = "origin_type" + !! name of the origin type variable + integer(I4B) :: origin_type_varid + !! ID for the origin type + character(NAMELEN) :: origin_time_varname = "origin_time" + !! name of the time of origin variable + integer(I4B) :: origin_time_varid + !! ID for the origin time + character(NAMELEN) :: collision_id_varname = "collision_id" + !! name of the collision id variable + integer(I4B) :: collision_id_varid + !! Netcdf ID for the origin collision ID + character(NAMELEN) :: origin_rh_varname = "origin_rh" + !! name of the heliocentric position vector of the body at the time of origin variable + integer(I4B) :: origin_rh_varid + !! ID for the origin position vector variable + character(NAMELEN) :: origin_vh_varname = "origin_vh" + !! name of the heliocentric velocity vector of the body at the time of origin variable + integer(I4B) :: origin_vh_varid + !! ID for the origin velocity vector component + character(NAMELEN) :: discard_time_varname = "discard_time" + !! name of the time of discard variable + integer(I4B) :: discard_time_varid + !! ID for the time of discard variable + character(NAMELEN) :: discard_rh_varname = "discard_rh" + !! name of the heliocentric position vector of the body at the time of discard variable + integer(I4B) :: discard_rh_varid + !! ID for the heliocentric position vector of the body at the time of discard variable + character(NAMELEN) :: discard_vh_varname = "discard_vh" + !! name of the heliocentric velocity vector of the body at the time of discard variable + integer(I4B) :: discard_vh_varid + !! ID for the heliocentric velocity vector of the body at the time of discard variable + character(NAMELEN) :: discard_body_id_varname = "discard_body_id" + !! name of the id of the other body involved in the discard + integer(I4B) :: discard_body_id_varid + !! ID for the id of the other body involved in the discard + logical :: lpseudo_vel_exists = .false. + !! Logical flag to indicate whether or not the pseudovelocity vectors were present in an old file. contains - procedure :: close => netcdf_io_close !! Closes an open NetCDF file - procedure :: find_tslot => netcdf_io_find_tslot !! Finds the time dimension index for a given value of t - procedure :: find_idslot => netcdf_io_find_idslot !! Finds the id dimension index for a given value of id - procedure :: get_idvals => netcdf_io_get_idvals !! Gets the valid id numbers currently stored in this dataset - procedure :: sync => netcdf_io_sync !! Syncrhonize the disk and memory buffer of the NetCDF file (e.g. commit the frame files stored in memory to disk) + procedure :: close => netcdf_io_close + !! Closes an open NetCDF file + procedure :: find_tslot => netcdf_io_find_tslot + !! Finds the time dimension index for a given value of t + procedure :: find_idslot => netcdf_io_find_idslot + !! Finds the id dimension index for a given value of id + procedure :: get_idvals => netcdf_io_get_idvals + !! Gets the valid id numbers currently stored in this dataset + procedure :: sync => netcdf_io_sync + !! Syncrhonize the disk and memory buffer of the NetCDF file (e.g. commit the frame files stored in memory to disk) end type netcdf_parameters interface module subroutine netcdf_io_check(status, call_identifier) implicit none - integer, intent (in) :: status !! The status code returned by a NetCDF function - character(len=*), intent(in), optional :: call_identifier !! String that indicates which calling function caused the error for diagnostic purposes + integer, intent (in) :: status + !! The status code returned by a NetCDF function + character(len=*), intent(in), optional :: call_identifier + !! String that indicates which calling function caused the error for diagnostic purposes end subroutine netcdf_io_check module subroutine netcdf_io_close(self) implicit none - class(netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset + class(netcdf_parameters),intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset end subroutine netcdf_io_close module subroutine netcdf_io_get_idvals(self) implicit none - class(netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset + class(netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset end subroutine netcdf_io_get_idvals module subroutine netcdf_io_find_tslot(self, t, tslot) implicit none - class(netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset - real(DP), intent(in) :: t !! The value of time to search for - integer(I4B), intent(out) :: tslot !! The index of the time slot where this data belongs + class(netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset + real(DP),intent(in) :: t + !! The value of time to search for + integer(I4B), intent(out) :: tslot + !! The index of the time slot where this data belongs end subroutine netcdf_io_find_tslot module subroutine netcdf_io_find_idslot(self, id, idslot) implicit none - class(netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset - integer(I4B), intent(in) :: id !! The value of id to search for - integer(I4B), intent(out) :: idslot !! The index of the id slot where this data belongs + class(netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset + integer(I4B), intent(in) :: id + !! The value of id to search for + integer(I4B), intent(out) :: idslot + !! The index of the id slot where this data belongs end subroutine netcdf_io_find_idslot module subroutine netcdf_io_sync(self) implicit none - class(netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset + class(netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset end subroutine netcdf_io_sync end interface From 044db276a4921cef209423bed02a4d6b6f95fe8e Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 11:17:47 -0500 Subject: [PATCH 248/324] Refactored for readability and to enforce line limits --- src/swiftest/swiftest_module.f90 | 2551 +++++++++++++++++++----------- 1 file changed, 1668 insertions(+), 883 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index e513623b7..3e0e091a5 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -47,7 +47,6 @@ module swiftest use io_progress_bar use netcdf_io use solver - use SHTOOLS #ifdef COARRAY use coarray #endif @@ -58,13 +57,14 @@ module swiftest type, extends(netcdf_parameters) :: swiftest_netcdf_parameters contains - procedure :: initialize => swiftest_io_netcdf_initialize_output !! Initialize a set of parameters used to identify a - !! NetCDF output object - procedure :: get_valid_masks => swiftest_io_netcdf_get_valid_masks !! Gets logical masks indicating which bodies are valid - !! pl and tp type at the current time - procedure :: open => swiftest_io_netcdf_open !! Opens a NetCDF file and does the variable inquiries to - !! activate variable ids - procedure :: flush => swiftest_io_netcdf_flush !! Flushes a NetCDF file by closing it then opening it again + procedure :: initialize => swiftest_io_netcdf_initialize_output + !! Initialize a set of parameters used to identify a NetCDF output object + procedure :: get_valid_masks => swiftest_io_netcdf_get_valid_masks + !! Gets logical masks indicating which bodies are valid pl and tp type at the current time + procedure :: open => swiftest_io_netcdf_open + !! Opens a NetCDF file and does the variable inquiries to activate variable ids + procedure :: flush => swiftest_io_netcdf_flush + !! Flushes a NetCDF file by closing it then opening it again #ifdef COARRAY procedure :: coclone => swiftest_coarray_coclone_nc #endif @@ -72,16 +72,19 @@ module swiftest type, extends(base_storage) :: swiftest_storage - class(swiftest_netcdf_parameters), allocatable :: nc !! NetCDF object attached to this storage object + class(swiftest_netcdf_parameters), allocatable :: nc + !! NetCDF object attached to this storage object contains - procedure :: dump => swiftest_io_dump_storage !! Dumps storage object contents to file - procedure :: dealloc => swiftest_util_dealloc_storage !! Resets a storage object by deallocating all items and - !! resetting the frame counter to 0 - procedure :: get_index_values => swiftest_util_get_vals_storage !! Gets the unique values of the indices of a storage object - !! (i.e. body id or time value) - procedure :: make_index_map => swiftest_util_index_map_storage !! Maps body id values to storage index values so we don't - !! have to use unlimited dimensions for id - procedure :: take_snapshot => swiftest_util_snapshot_system !! Takes a snapshot of the nbody_system for later file storage + procedure :: dump => swiftest_io_dump_storage + !! Dumps storage object contents to file + procedure :: dealloc => swiftest_util_dealloc_storage + !! Resets a storage object by deallocating all items and resetting the frame counter to 0 + procedure :: get_index_values => swiftest_util_get_vals_storage + !! Gets the unique values of the indices of a storage object (i.e. body id or time value) + procedure :: make_index_map => swiftest_util_index_map_storage + !! Maps body id values to storage index values so we don't have to use unlimited dimensions for id + procedure :: take_snapshot => swiftest_util_snapshot_system + !! Takes a snapshot of the nbody_system for later file storage final :: swiftest_final_storage end type swiftest_storage @@ -100,76 +103,118 @@ module swiftest !> Class definition for the kinship relationships used in bookkeeping multiple collisions bodies in a single time step. type, extends(base_kinship) :: swiftest_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 contains - procedure :: dealloc => swiftest_util_dealloc_kin !! Deallocates all allocatable arrays + procedure :: dealloc => swiftest_util_dealloc_kin + !! Deallocates all allocatable arrays #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_kin !! Clones the image 1 body object to all other images in the coarray - !! structure. + procedure :: coclone => swiftest_coarray_coclone_kin + !! Clones the image 1 body object to all other images in the coarray structure. #endif - final :: swiftest_final_kin !! Finalizes the Swiftest kinship object - deallocates all allocatables + final :: swiftest_final_kin + !! Finalizes the Swiftest kinship object - deallocates all allocatables end type swiftest_kinship type, extends(base_particle_info) :: swiftest_particle_info - character(len=NAMELEN) :: name !! Non-unique name - character(len=NAMELEN) :: particle_type !! String containing a description of the particle type (e.g. Central Body, - !! Massive Body, Test Particle) - character(len=NAMELEN) :: origin_type !! String containing a description of the origin of the particle (e.g. Initial - !! Conditions, Supercatastrophic, Disruption, etc.) - real(DP) :: origin_time !! The time of the particle's formation - integer(I4B) :: collision_id !! The ID of the collision that formed the particle - real(DP), dimension(NDIM) :: origin_rh !! The heliocentric distance vector at the time of the particle's formation - real(DP), dimension(NDIM) :: origin_vh !! The heliocentric velocity vector at the time of the particle's formation - real(DP) :: discard_time !! The time of the particle's discard - character(len=NAMELEN) :: status !! Particle status description: Active, Merged, Fragmented, etc. - real(DP), dimension(NDIM) :: discard_rh !! The heliocentric distance vector at the time of the particle's discard - real(DP), dimension(NDIM) :: discard_vh !! The heliocentric velocity vector at the time of the particle's discard - integer(I4B) :: discard_body_id !! The id of the other body involved in the discard (0 if no other body involved) + character(len=NAMELEN) :: name + !! Non-unique name + character(len=NAMELEN) :: particle_type + !! String containing a description of the particle type (e.g. Central Body, Massive Body, Test Particle) + character(len=NAMELEN) :: origin_type + !! String containing a description of the origin of the particle (e.g. Initial Conditions, Disruption, etc.) + real(DP) :: origin_time + !! The time of the particle's formation + integer(I4B) :: collision_id + !! The ID of the collision that formed the particle + real(DP), dimension(NDIM) :: origin_rh + !! The heliocentric distance vector at the time of the particle's formation + real(DP), dimension(NDIM) :: origin_vh + !! The heliocentric velocity vector at the time of the particle's formation + real(DP) :: discard_time + !! The time of the particle's discard + character(len=NAMELEN) :: status + !! Particle status description: Active, Merged, Fragmented, etc. + real(DP), dimension(NDIM) :: discard_rh + !! The heliocentric distance vector at the time of the particle's discard + real(DP), dimension(NDIM) :: discard_vh + !! The heliocentric velocity vector at the time of the particle's discard + integer(I4B) :: discard_body_id + !! The id of the other body involved in the discard (0 if no other body involved) contains - procedure :: copy => swiftest_util_copy_particle_info !! Copies one set of information object components into another, - !! component-by-component - procedure :: set_value => swiftest_util_set_particle_info !! Sets one or more values of the particle information metadata - !! object + procedure :: copy => swiftest_util_copy_particle_info + !! Copies one set of information object components into another, component-by-component + procedure :: set_value => swiftest_util_set_particle_info + !! Sets one or more values of the particle information metadata object end type swiftest_particle_info !> An abstract class for a generic collection of Swiftest bodies type, abstract, extends(base_object) :: swiftest_body - !! Superclass that defines the generic elements of a Swiftest particle - logical :: lfirst = .true. !! Run the current step as a first - integer(I4B) :: nbody = 0 !! Number of bodies - integer(I4B), dimension(:), allocatable :: id !! Identifier - type(swiftest_particle_info), dimension(:), allocatable :: info !! Particle metadata information - logical, dimension(:), allocatable :: lmask !! Logical mask used to select a subset of bodies when performing certain operations (drift, kick, accel, etc.) - integer(I4B), dimension(:), allocatable :: status !! An integrator-specific status indicator - logical, dimension(:), allocatable :: ldiscard !! Body should be discarded - 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 - real(DP), dimension(:), allocatable :: mu !! G * (Mcb + [m]) - real(DP), dimension(:,:), allocatable :: rh !! Heliocentric position - real(DP), dimension(:,:), allocatable :: vh !! Heliocentric velocity - real(DP), dimension(:,:), allocatable :: rb !! Barycentric position - real(DP), dimension(:,:), allocatable :: vb !! Barycentric velocity - real(DP), dimension(:,:), allocatable :: ah !! Total heliocentric acceleration - real(DP), dimension(:,:), allocatable :: aobl !! Barycentric accelerations of bodies due to central body oblatenes - real(DP), dimension(:,:), allocatable :: agr !! Acceleration due to post-Newtonian correction - real(DP), dimension(:,:), allocatable :: atide !! Tanngential component of acceleration of bodies due to tides - real(DP), dimension(:), allocatable :: ir3h !! Inverse heliocentric radius term (1/rh**3) - 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 :: a !! Semimajor axis (pericentric distance for a parabolic orbit) - real(DP), dimension(:), allocatable :: e !! Eccentricity - real(DP), dimension(:), allocatable :: inc !! Inclination - real(DP), dimension(:), allocatable :: capom !! Longitude of ascending node - real(DP), dimension(:), allocatable :: omega !! Argument of pericenter - real(DP), dimension(:), allocatable :: capm !! Mean anomaly - - !! 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 + !! Superclass that defines the generic elements of a Swiftest particle + logical :: lfirst = .true. + !! Run the current step as a first + integer(I4B) :: nbody = 0 + !! Number of bodies + integer(I4B), dimension(:), allocatable :: id + !! Identifier + type(swiftest_particle_info), dimension(:), allocatable :: info + !! Particle metadata information + logical, dimension(:), allocatable :: lmask + !! Logical mask used to select a subset of bodies when performing certain operations (drift, kick, accel, etc.) + integer(I4B), dimension(:), allocatable :: status + !! An integrator-specific status indicator + logical, dimension(:), allocatable :: ldiscard + !! Body should be discarded + 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 + real(DP), dimension(:), allocatable :: mu + !! G * (Mcb + [m]) + real(DP), dimension(:,:), allocatable :: rh + !! Heliocentric position + real(DP), dimension(:,:), allocatable :: vh + !! Heliocentric velocity + real(DP), dimension(:,:), allocatable :: rb + !! Barycentric position + real(DP), dimension(:,:), allocatable :: vb + !! Barycentric velocity + real(DP), dimension(:,:), allocatable :: ah + !! Total heliocentric acceleration + real(DP), dimension(:,:), allocatable :: aobl + !! Barycentric accelerations of bodies due to central body oblatenes + real(DP), dimension(:,:), allocatable :: agr + !! Acceleration due to post-Newtonian correction + real(DP), dimension(:,:), allocatable :: atide + !! Tanngential component of acceleration of bodies due to tides + real(DP), dimension(:), allocatable :: ir3h + !! Inverse heliocentric radius term (1/rh**3) + 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 :: a + !! Semimajor axis (pericentric distance for a parabolic orbit) + real(DP), dimension(:), allocatable :: e + !! Eccentricity + real(DP), dimension(:), allocatable :: inc + !! Inclination + real(DP), dimension(:), allocatable :: capom + !! Longitude of ascending node + real(DP), dimension(:), allocatable :: omega + !! Argument of pericenter + real(DP), dimension(:), allocatable :: capm + !! Mean anomaly + ! 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 procedure(abstract_discard_body), deferred :: discard procedure(abstract_kick_body), deferred :: kick @@ -178,226 +223,401 @@ module swiftest procedure(abstract_accel), deferred :: accel ! These are concrete because the implementation is the same for all types of particles - procedure :: drift => swiftest_drift_body !! Loop through bodies and call Danby drift routine on heliocentric variables - procedure :: v2pv => swiftest_gr_vh2pv_body !! Converts from velocity to psudeovelocity for GR calculations using symplectic integrators - procedure :: pv2v => swiftest_gr_pv2vh_body !! Converts from psudeovelocity to velocity for GR calculations using symplectic integrators - procedure :: read_frame_bin => swiftest_io_read_frame_body !! I/O routine for writing out a single frame of time-series data for the central body - procedure :: read_in => swiftest_io_read_in_body !! Read in body initial conditions from an ascii file - procedure :: write_frame => swiftest_io_netcdf_write_frame_body !! I/O routine for writing out a single frame of time-series data for all bodies in the nbody_system in NetCDF format - procedure :: write_info => swiftest_io_netcdf_write_info_body !! Dump contents of particle information metadata to file - procedure :: el2xv => swiftest_orbel_el2xv_vec !! Convert orbital elements to position and velocity vectors - procedure :: xv2el => swiftest_orbel_xv2el_vec !! Convert position and velocity vectors to orbital elements - procedure :: setup => swiftest_util_setup_body !! A constructor that sets the number of bodies and allocates all allocatable arrays - procedure :: accel_user => swiftest_user_kick_getacch_body !! Add user-supplied heliocentric accelerations to planets - procedure :: append => swiftest_util_append_body !! Appends elements from one structure to another - procedure :: dealloc => swiftest_util_dealloc_body !! Deallocates all allocatable arrays - procedure :: fill => swiftest_util_fill_body !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) - procedure :: get_peri => swiftest_util_peri_body !! Determine nbody_system pericenter passages for test particles - procedure :: resize => swiftest_util_resize_body !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. - procedure :: set_ir3 => swiftest_util_set_ir3h !! Sets the inverse heliocentric radius term (1/rh**3) - procedure :: sort => swiftest_util_sort_body !! Sorts body arrays by a sortable componen - procedure :: rearrange => swiftest_util_sort_rearrange_body !! Rearranges the order of array elements of body based on an input index array. Used in sorting methods - procedure :: spill => swiftest_util_spill_body !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) - generic :: read_frame => read_frame_bin !! Add the generic read frame for Fortran binary files + procedure :: drift => swiftest_drift_body + !! Loop through bodies and call Danby drift routine on heliocentric variables + procedure :: v2pv => swiftest_gr_vh2pv_body + !! Converts from velocity to psudeovelocity for GR calculations using symplectic integrators + procedure :: pv2v => swiftest_gr_pv2vh_body + !! Converts from psudeovelocity to velocity for GR calculations using symplectic integrators + procedure :: read_frame_bin => swiftest_io_read_frame_body + !! I/O routine for writing out a single frame of time-series data for the central body + procedure :: read_in => swiftest_io_read_in_body + !! Read in body initial conditions from an ascii file + procedure :: write_frame => swiftest_io_netcdf_write_frame_body + !! I/O routine for writing out a single frame of time-series data for all bodies in the nbody_system in NetCDF format + procedure :: write_info => swiftest_io_netcdf_write_info_body + !! Dump contents of particle information metadata to file + procedure :: el2xv => swiftest_orbel_el2xv_vec + !! Convert orbital elements to position and velocity vectors + procedure :: xv2el => swiftest_orbel_xv2el_vec + !! Convert position and velocity vectors to orbital elements + procedure :: setup => swiftest_util_setup_body + !! A constructor that sets the number of bodies and allocates all allocatable arrays + procedure :: accel_user => swiftest_user_kick_getacch_body + !! Add user-supplied heliocentric accelerations to planets + procedure :: append => swiftest_util_append_body + !! Appends elements from one structure to another + procedure :: dealloc => swiftest_util_dealloc_body + !! Deallocates all allocatable arrays + procedure :: fill => swiftest_util_fill_body + !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) + procedure :: get_peri => swiftest_util_peri_body + !! Determine nbody_system pericenter passages for test particles + procedure :: resize => swiftest_util_resize_body + !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. + procedure :: set_ir3 => swiftest_util_set_ir3h + !! Sets the inverse heliocentric radius term (1/rh**3) + procedure :: sort => swiftest_util_sort_body + !! Sorts body arrays by a sortable componen + procedure :: rearrange => swiftest_util_sort_rearrange_body + !! Rearranges the order of array elements of body based on an input index array. Used in sorting methods + procedure :: spill => swiftest_util_spill_body + !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) + generic :: read_frame => read_frame_bin + !! Add the generic read frame for Fortran binary files #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_body !! Clones the image 1 body object to all other images in the coarray structure. - procedure :: cocollect => swiftest_coarray_cocollect_body !! Collects all body object array components from all images and combines them into the image 1 body object + procedure :: coclone => swiftest_coarray_coclone_body + !! Clones the image 1 body object to all other images in the coarray structure. + procedure :: cocollect => swiftest_coarray_cocollect_body + !! Collects all body object array components from all images and combines them into the image 1 body object #endif end type swiftest_body type, abstract, extends(base_object) :: swiftest_cb !> An abstract class for a generic central body in a Swiftest simulation - class(swiftest_particle_info), allocatable :: info !! Particle metadata information - integer(I4B) :: id = 0 !! External identifier (unique) - real(DP) :: mass = 0.0_DP !! Central body mass (units MU) - real(DP) :: Gmass = 0.0_DP !! Central mass gravitational term G * mass (units GU * MU) - real(DP) :: radius = 0.0_DP !! Central body radius (units DU) - real(DP) :: density = 1.0_DP !! Central body mass density - calculated internally (units MU / DU**3) - real(DP) :: j2rp2 = 0.0_DP !! J2*R^2 term for central body - real(DP) :: j4rp4 = 0.0_DP !! J4*R^4 term for central body - real(DP), dimension(:,:,:), allocatable :: c_lm !! Spherical Harmonics coefficients for the central body - real(DP), dimension(NDIM) :: aobl = 0.0_DP !! Barycentric acceleration due to central body oblatenes - real(DP), dimension(NDIM) :: atide = 0.0_DP !! Barycentric acceleration due to central body oblatenes - real(DP), dimension(NDIM) :: aoblbeg = 0.0_DP !! Barycentric acceleration due to central body oblatenes at beginning of step - real(DP), dimension(NDIM) :: aoblend = 0.0_DP !! Barycentric acceleration due to central body oblatenes at end of step - real(DP), dimension(NDIM) :: atidebeg = 0.0_DP !! Barycentric acceleration due to central body oblatenes at beginning of step - real(DP), dimension(NDIM) :: atideend = 0.0_DP !! Barycentric acceleration due to central body oblatenes at end of step - real(DP), dimension(NDIM) :: rb = 0.0_DP !! Barycentric position (units DU) - real(DP), dimension(NDIM) :: vb = 0.0_DP !! Barycentric velocity (units DU / TU) - real(DP), dimension(NDIM) :: agr = 0.0_DP !! Acceleration due to post-Newtonian correction - real(DP), dimension(NDIM) :: Ip = 0.0_DP !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. - real(DP), dimension(NDIM) :: rot = 0.0_DP !! Body rotation vector in inertial coordinate frame (units rad / TU) - real(DP) :: rotphase = 0.0_DP !! Body rotation phase about the rotation pole (0 to 1) - real(DP) :: k2 = 0.0_DP !! Tidal Love number - real(DP) :: Q = 0.0_DP !! Tidal quality factor - real(DP) :: tlag = 0.0_DP !! Tidal phase lag angle - real(DP), dimension(NDIM) :: L0 = 0.0_DP !! Initial angular momentum of the central body - real(DP), dimension(NDIM) :: dL = 0.0_DP !! Change in angular momentum of the central body - real(DP) :: GM0 = 0.0_DP !! Initial G*mass of the central body - real(DP) :: dGM = 0.0_DP !! Change in G*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 + class(swiftest_particle_info), allocatable :: info + !! Particle metadata information + integer(I4B) :: id = 0 + !! External identifier (unique) + real(DP) :: mass = 0.0_DP + !! Central body mass (units MU) + real(DP) :: Gmass = 0.0_DP + !! Central mass gravitational term G * mass (units GU * MU) + real(DP) :: radius = 0.0_DP + !! Central body radius (units DU) + real(DP) :: density = 1.0_DP + !! Central body mass density - calculated internally (units MU / DU**3) + real(DP) :: j2rp2 = 0.0_DP + !! J2*R^2 term for central body + real(DP) :: j4rp4 = 0.0_DP + !! J4*R^4 term for central body + real(DP), dimension(:,:,:), allocatable :: c_lm + !! Spherical Harmonics coefficients for the central body + real(DP), dimension(NDIM) :: aobl = 0.0_DP + !! Barycentric acceleration due to central body oblatenes + real(DP), dimension(NDIM) :: atide = 0.0_DP + !! Barycentric acceleration due to central body oblatenes + real(DP), dimension(NDIM) :: aoblbeg = 0.0_DP + !! Barycentric acceleration due to central body oblatenes at beginning of step + real(DP), dimension(NDIM) :: aoblend = 0.0_DP + !! Barycentric acceleration due to central body oblatenes at end of step + real(DP), dimension(NDIM) :: atidebeg = 0.0_DP + !! Barycentric acceleration due to central body oblatenes at beginning of step + real(DP), dimension(NDIM) :: atideend = 0.0_DP + !! Barycentric acceleration due to central body oblatenes at end of step + real(DP), dimension(NDIM) :: rb = 0.0_DP + !! Barycentric position (units DU) + real(DP), dimension(NDIM) :: vb = 0.0_DP + !! Barycentric velocity (units DU / TU) + real(DP), dimension(NDIM) :: agr = 0.0_DP + !! Acceleration due to post-Newtonian correction + real(DP), dimension(NDIM) :: Ip = 0.0_DP + !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. + real(DP), dimension(NDIM) :: rot = 0.0_DP + !! Body rotation vector in inertial coordinate frame (units rad / TU) + real(DP) :: rotphase = 0.0_DP + !! Body rotation phase about the rotation pole (0 to 1) + real(DP) :: k2 = 0.0_DP + !! Tidal Love number + real(DP) :: Q = 0.0_DP + !! Tidal quality factor + real(DP) :: tlag = 0.0_DP + !! Tidal phase lag angle + real(DP), dimension(NDIM) :: L0 = 0.0_DP + !! Initial angular momentum of the central body + real(DP), dimension(NDIM) :: dL = 0.0_DP + !! Change in angular momentum of the central body + real(DP) :: GM0 = 0.0_DP + !! Initial G*mass of the central body + real(DP) :: dGM = 0.0_DP + !! Change in G*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 - procedure :: rotphase_update => swiftest_drift_cb_rotphase_update !! updates the central body rotation phase - procedure :: dealloc => swiftest_util_dealloc_cb !! Deallocates all allocatables and resets all values to defaults - procedure :: read_in => swiftest_io_read_in_cb !! Read in central body initial conditions from an ASCII file - procedure :: write_frame => swiftest_io_netcdf_write_frame_cb !! I/O routine for writing out a single frame of time-series data for all bodies in the system in NetCDF format - procedure :: write_info => swiftest_io_netcdf_write_info_cb !! Dump contents of particle information metadata to file + procedure :: rotphase_update => swiftest_drift_cb_rotphase_update + !! updates the central body rotation phase + procedure :: dealloc => swiftest_util_dealloc_cb + !! Deallocates all allocatables and resets all values to defaults + procedure :: read_in => swiftest_io_read_in_cb + !! Read in central body initial conditions from an ASCII file + procedure :: write_frame => swiftest_io_netcdf_write_frame_cb + !! I/O routine for writing out a single frame of time-series data for all bodies in the system in NetCDF format + procedure :: write_info => swiftest_io_netcdf_write_info_cb + !! Dump contents of particle information metadata to file #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_cb !! Clones the image 1 body object to all other images in the coarray structure. + procedure :: coclone => swiftest_coarray_coclone_cb + !! Clones the image 1 body object to all other images in the coarray structure. #endif end type swiftest_cb type, abstract, extends(swiftest_body) :: swiftest_pl - !! Superclass that defines the generic elements of a Swiftest particle - real(DP), dimension(:), allocatable :: mass !! Body mass (units MU) - 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 :: renc !! Critical radius for close encounters - real(DP), dimension(:), allocatable :: radius !! Body radius (units DU) - real(DP), dimension(:), allocatable :: density !! Body mass density - calculated internally (units MU / DU**3) - real(DP), dimension(:,:), allocatable :: rbeg !! Position at beginning of step - real(DP), dimension(:,:), allocatable :: rend !! Position at end of step - real(DP), dimension(:,:), allocatable :: vbeg !! Velocity at beginning of step - real(DP), dimension(:,:), allocatable :: Ip !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. - 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 - 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 - type(swiftest_kinship), dimension(:), allocatable :: kin !! Array of merger relationship structures that can account for multiple pairwise mergers in a single step - logical, dimension(:), allocatable :: lmtiny !! flag indicating whether this body is below the GMTINY cutoff value - integer(I4B) :: nplm = 0 !! number of bodies above the GMTINY limit - integer(I8B) :: nplplm !! Number of body (all massive)-body (only those above GMTINY) 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 - !! 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 + !! Superclass that defines the generic elements of a Swiftest particle + real(DP), dimension(:), allocatable :: mass + !! Body mass (units MU) + 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 :: renc + !! Critical radius for close encounters + real(DP), dimension(:), allocatable :: radius + !! Body radius (units DU) + real(DP), dimension(:), allocatable :: density + !! Body mass density - calculated internally (units MU / DU**3) + real(DP), dimension(:,:), allocatable :: rbeg + !! Position at beginning of step + real(DP), dimension(:,:), allocatable :: rend + !! Position at end of step + real(DP), dimension(:,:), allocatable :: vbeg + !! Velocity at beginning of step + real(DP), dimension(:,:), allocatable :: Ip + !! Unitless principal moments of inertia (I1, I2, I3) / (MR**2). Principal axis rotation assumed. + 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 + 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 + type(swiftest_kinship), dimension(:), allocatable :: kin + !! Array of merger relationship structures that can account for multiple pairwise mergers in a single step + logical, dimension(:), allocatable :: lmtiny + !! flag indicating whether this body is below the GMTINY cutoff value + integer(I4B) :: nplm = 0 + !! number of bodies above the GMTINY limit + integer(I8B) :: nplplm + !! Number of body (all massive)-body (only those above GMTINY) 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 + + ! 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 ! Massive body-specific concrete methods ! These are concrete because they are the same implemenation for all integrators - procedure :: make_impactors => swiftest_util_make_impactors_pl !! Make impactors out of the current kinship relationships - procedure :: discard => swiftest_discard_pl !! Placeholder method for discarding massive bodies - procedure :: accel_int => swiftest_kick_getacch_int_pl !! Compute direct cross (third) term heliocentric accelerations of massive bodies - procedure :: accel_obl => swiftest_obl_acc_pl !! Compute the barycentric accelerations of bodies due to the oblateness of the central body - procedure :: setup => swiftest_util_setup_pl !! A base constructor that sets the number of bodies and allocates and initializes all arrays - procedure :: accel_sph => swiftest_sph_g_acc_pl_all !! Acceleration due ot spherical harmonics terms - ! procedure :: accel_tides => tides_kick_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body - procedure :: append => swiftest_util_append_pl !! Appends elements from one structure to another - procedure :: h2b => swiftest_util_coord_h2b_pl !! Convert massive bodies from heliocentric to barycentric coordinates (position and velocity) - procedure :: b2h => swiftest_util_coord_b2h_pl !! Convert massive bodies from barycentric to heliocentric coordinates (position and velocity) - procedure :: vh2vb => swiftest_util_coord_vh2vb_pl !! Convert massive bodies from heliocentric to barycentric coordinates (velocity only) - procedure :: vb2vh => swiftest_util_coord_vb2vh_pl !! Convert massive bodies from barycentric to heliocentric coordinates (velocity only) - procedure :: rh2rb => swiftest_util_coord_rh2rb_pl !! Convert massive bodies from heliocentric to barycentric coordinates (position only) - procedure :: dealloc => swiftest_util_dealloc_pl !! Deallocates all allocatable arrays - procedure :: fill => swiftest_util_fill_pl !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) - procedure :: flatten => swiftest_util_flatten_eucl_plpl !! Sets up the (i, j) -> k indexing used for the single-loop blocking Euclidean distance matrix - procedure :: rearray => swiftest_util_rearray_pl !! Clean up the massive body structures to remove discarded bodies and add new bodies - procedure :: resize => swiftest_util_resize_pl !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. - procedure :: reset_kinship => swiftest_util_reset_kinship_pl !! Resets the kinship status of bodies - procedure :: set_beg_end => swiftest_util_set_beg_end_pl !! Sets the beginning and ending positions and velocities of planets. - procedure :: set_mu => swiftest_util_set_mu_pl !! Method used to construct the vectorized form of the central body mass - procedure :: set_rhill => swiftest_util_set_rhill !! Calculates the Hill's radii for each body - procedure :: set_renc_I4B => swiftest_util_set_renc_I4B !! Sets the critical radius for encounter given an inpput integer scale factor - procedure :: set_renc_DP => swiftest_util_set_renc_DP !! Sets the critical radius for encounter given an input real scale factor - procedure :: sort => swiftest_util_sort_pl !! Sorts body arrays by a sortable component - procedure :: rearrange => swiftest_util_sort_rearrange_pl !! Rearranges the order of array elements of body based on an input index array. Used in sorting methods - procedure :: spill => swiftest_util_spill_pl !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) + procedure :: make_impactors => swiftest_util_make_impactors_pl + !! Make impactors out of the current kinship relationships + procedure :: discard => swiftest_discard_pl + !! Placeholder method for discarding massive bodies + procedure :: accel_int => swiftest_kick_getacch_int_pl + !! Compute direct cross (third) term heliocentric accelerations of massive bodies + procedure :: accel_obl => swiftest_obl_acc_pl + !! Compute the barycentric accelerations of bodies due to the oblateness of the central body + procedure :: setup => swiftest_util_setup_pl + !! A base constructor that sets the number of bodies and allocates and initializes all arrays + !procedure :: accel_sph => shgrav_g_acc_pl_all + !! Acceleration due ot spherical harmonics terms + ! procedure :: accel_tides => tides_kick_getacch_pl + !! Compute the accelerations of bodies due to tidal interactions with the central body + procedure :: append => swiftest_util_append_pl + !! Appends elements from one structure to another + procedure :: h2b => swiftest_util_coord_h2b_pl + !! Convert massive bodies from heliocentric to barycentric coordinates (position and velocity) + procedure :: b2h => swiftest_util_coord_b2h_pl + !! Convert massive bodies from barycentric to heliocentric coordinates (position and velocity) + procedure :: vh2vb => swiftest_util_coord_vh2vb_pl + !! Convert massive bodies from heliocentric to barycentric coordinates (velocity only) + procedure :: vb2vh => swiftest_util_coord_vb2vh_pl + !! Convert massive bodies from barycentric to heliocentric coordinates (velocity only) + procedure :: rh2rb => swiftest_util_coord_rh2rb_pl + !! Convert massive bodies from heliocentric to barycentric coordinates (position only) + procedure :: dealloc => swiftest_util_dealloc_pl + !! Deallocates all allocatable arrays + procedure :: fill => swiftest_util_fill_pl + !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) + procedure :: flatten => swiftest_util_flatten_eucl_plpl + !! Sets up the (i, j) -> k indexing used for the single-loop blocking Euclidean distance matrix + procedure :: rearray => swiftest_util_rearray_pl + !! Clean up the massive body structures to remove discarded bodies and add new bodies + procedure :: resize => swiftest_util_resize_pl + !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. + procedure :: reset_kinship => swiftest_util_reset_kinship_pl + !! Resets the kinship status of bodies + procedure :: set_beg_end => swiftest_util_set_beg_end_pl + !! Sets the beginning and ending positions and velocities of planets. + procedure :: set_mu => swiftest_util_set_mu_pl + !! Method used to construct the vectorized form of the central body mass + procedure :: set_rhill => swiftest_util_set_rhill + !! Calculates the Hill's radii for each body + procedure :: set_renc_I4B => swiftest_util_set_renc_I4B + !! Sets the critical radius for encounter given an inpput integer scale factor + procedure :: set_renc_DP => swiftest_util_set_renc_DP + !! Sets the critical radius for encounter given an input real scale factor + procedure :: sort => swiftest_util_sort_pl + !! Sorts body arrays by a sortable component + procedure :: rearrange => swiftest_util_sort_rearrange_pl + !! Rearranges the order of array elements of body based on an input index array. Used in sorting methods + procedure :: spill => swiftest_util_spill_pl + !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) generic :: set_renc => set_renc_I4B, set_renc_DP #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_pl !! Clones the image 1 body object to all other images in the coarray structure. + procedure :: coclone => swiftest_coarray_coclone_pl + !! Clones the image 1 body object to all other images in the coarray structure. #endif end type swiftest_pl type, abstract, extends(swiftest_body) :: swiftest_tp - !! Superclass that defines the generic elements of a Swiftest test particle - integer(I4B), dimension(:,:), allocatable :: k_pltp !! Index array used to convert flattened the body-body comparison upper triangular matrix - integer(I8B) :: npltp !! Number of pl-tp comparisons in the flattened upper triangular matrix - integer(I4B), dimension(:), allocatable :: nplenc !! number of encounters with planets this time step - !! Note to developers: If you add components to this class, be sure to update methods and subroutines that traverse the - !! component list, such as swiftest_util_setup_tp and util_spill_tp + + !! Superclass that defines the generic elements of a Swiftest test particle + integer(I4B), dimension(:,:), allocatable :: k_pltp + !! Index array used to convert flattened the body-body comparison upper triangular matrix + integer(I8B) :: npltp + !! Number of pl-tp comparisons in the flattened upper triangular matrix + integer(I4B), dimension(:), allocatable :: nplenc + !! number of encounters with planets this time step + + ! Note to developers: If you add components to this class, be sure to update methods and subroutines that traverse the + ! component list, such as swiftest_util_setup_tp and util_spill_tp contains ! Test particle-specific concrete methods ! These are concrete because they are the same implemenation for all integrators - procedure :: discard => swiftest_discard_tp !! Check to see if test particles should be discarded based on their positions relative to the massive bodies - procedure :: accel_int => swiftest_kick_getacch_int_tp !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies - procedure :: accel_obl => swiftest_obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body - procedure :: accel_sph => swiftest_sph_g_acc_tp_all !! acceleration due to spherical harmonics - procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and - procedure :: append => swiftest_util_append_tp !! Appends elements from one structure to another - procedure :: h2b => swiftest_util_coord_h2b_tp !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) - procedure :: b2h => swiftest_util_coord_b2h_tp !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) - procedure :: vb2vh => swiftest_util_coord_vb2vh_tp !! Convert test particles from barycentric to heliocentric coordinates (velocity only) - procedure :: vh2vb => swiftest_util_coord_vh2vb_tp !! Convert test particles from heliocentric to barycentric coordinates (velocity only) - procedure :: rh2rb => swiftest_util_coord_rh2rb_tp !! Convert test particles from heliocentric to barycentric coordinates (position only) - procedure :: dealloc => swiftest_util_dealloc_tp !! Deallocates all allocatable arrays - procedure :: fill => swiftest_util_fill_tp !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) - procedure :: rearray => swiftest_util_rearray_tp !! Clean up the test particle structures to remove discarded bodies - procedure :: resize => swiftest_util_resize_tp !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. - procedure :: set_mu => swiftest_util_set_mu_tp !! Method used to construct the vectorized form of the central body mass - procedure :: sort => swiftest_util_sort_tp !! Sorts body arrays by a sortable component - procedure :: rearrange => swiftest_util_sort_rearrange_tp !! Rearranges the order of array elements of body based on an input index array. Used in sorting methods - procedure :: spill => swiftest_util_spill_tp !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) + procedure :: discard => swiftest_discard_tp + !! Check to see if test particles should be discarded based on their positions relative to the massive bodies + procedure :: accel_int => swiftest_kick_getacch_int_tp + !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies + procedure :: accel_obl => swiftest_obl_acc_tp + !! Compute the barycentric accelerations of bodies due to the oblateness of the central body + !procedure :: accel_sph => shgrav_g_acc_tp_all + !! acceleration due to spherical harmonics + procedure :: setup => swiftest_util_setup_tp + !! A base constructor that sets the number of bodies and + procedure :: append => swiftest_util_append_tp + !! Appends elements from one structure to another + procedure :: h2b => swiftest_util_coord_h2b_tp + !! Convert test particles from heliocentric to barycentric coordinates (position and velocity) + procedure :: b2h => swiftest_util_coord_b2h_tp + !! Convert test particles from barycentric to heliocentric coordinates (position and velocity) + procedure :: vb2vh => swiftest_util_coord_vb2vh_tp + !! Convert test particles from barycentric to heliocentric coordinates (velocity only) + procedure :: vh2vb => swiftest_util_coord_vh2vb_tp + !! Convert test particles from heliocentric to barycentric coordinates (velocity only) + procedure :: rh2rb => swiftest_util_coord_rh2rb_tp + !! Convert test particles from heliocentric to barycentric coordinates (position only) + procedure :: dealloc => swiftest_util_dealloc_tp + !! Deallocates all allocatable arrays + procedure :: fill => swiftest_util_fill_tp + !! "Fills" bodies from one object into another depending on the results of a mask (uses the UNPACK intrinsic) + procedure :: rearray => swiftest_util_rearray_tp + !! Clean up the test particle structures to remove discarded bodies + procedure :: resize => swiftest_util_resize_tp + !! Checks the current size of a Swiftest body against the requested size and resizes it if it is too small. + procedure :: set_mu => swiftest_util_set_mu_tp + !! Method used to construct the vectorized form of the central body mass + procedure :: sort => swiftest_util_sort_tp + !! Sorts body arrays by a sortable component + procedure :: rearrange => swiftest_util_sort_rearrange_tp + !! Rearranges the order of array elements of body based on an input index array. Used in sorting methods + procedure :: spill => swiftest_util_spill_tp + !! "Spills" bodies from one object to another depending on the results of a mask (uses the PACK intrinsic) #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_tp !! Clones the image 1 object to all other images in the coarray structure. - procedure :: cocollect => swiftest_coarray_cocollect_tp !! Collects all object array components from all images and combines them into the image 1 object + procedure :: coclone => swiftest_coarray_coclone_tp + !! Clones the image 1 object to all other images in the coarray structure. + procedure :: cocollect => swiftest_coarray_cocollect_tp + !! Collects all object array components from all images and combines them into the image 1 object #endif end type swiftest_tp !> An abstract class for a basic Swiftest nbody system type, abstract, extends(base_nbody_system) :: swiftest_nbody_system - !! This superclass contains a minimial nbody_system of a set of test particles (tp), massive bodies (pl), and a central body (cb) - !! The full swiftest_nbody_system type that is used as the parent class of all integrators is defined in collision - - class(swiftest_cb), allocatable :: cb !! Central body data structure - class(swiftest_pl), allocatable :: pl !! Massive body data structure - class(swiftest_tp), allocatable :: tp !! Test particle data structure - - class(swiftest_tp), allocatable :: tp_discards !! Discarded test particle data structure - class(swiftest_pl), allocatable :: pl_discards !! Discarded massive body particle data structure - class(swiftest_pl), allocatable :: pl_adds !! List of added bodies in mergers or collisions - class(swiftest_tp), allocatable :: tp_adds !! List of added bodies in mergers or collisions - class(encounter_list), allocatable :: pltp_encounter !! List of massive body-test particle encounters in a single step - class(encounter_list), allocatable :: plpl_encounter !! List of massive body-massive body encounters in a single step - class(collision_list_plpl), allocatable :: plpl_collision !! List of massive body-massive body collisions in a single step - class(collision_list_pltp), allocatable :: pltp_collision !! List of massive body-test particle collisions in a single step - class(collision_basic), allocatable :: collider !! Collision system object - class(encounter_storage), allocatable :: encounter_history !! Stores encounter history for later retrieval and saving to file - class(collision_storage), allocatable :: collision_history !! Stores encounter history for later retrieval and saving to file - - integer(I4B) :: maxid = -1 !! The current maximum particle id number - real(DP) :: t = -1.0_DP !! Integration current time - real(DP) :: GMtot = 0.0_DP !! Total nbody_system mass - used for barycentric coordinate conversion - real(DP) :: ke_orbit = 0.0_DP !! nbody_system orbital kinetic energy - real(DP) :: ke_spin = 0.0_DP !! nbody_system spin kinetic energy - real(DP) :: pe = 0.0_DP !! nbody_system potential energy - real(DP) :: be = 0.0_DP !! nbody_system binding energy of all bodies - real(DP) :: te = 0.0_DP !! nbody_system total energy - real(DP) :: oblpot = 0.0_DP !! nbody_system potential energy due to oblateness of the central body - real(DP), dimension(NDIM) :: L_orbit = 0.0_DP !! nbody_system orbital angular momentum vector - real(DP), dimension(NDIM) :: L_spin = 0.0_DP !! nbody_system spin angular momentum vector - real(DP), dimension(NDIM) :: L_total = 0.0_DP !! nbody_system angular momentum vector - real(DP) :: ke_orbit_orig = 0.0_DP !! Initial orbital kinetic energy - real(DP) :: ke_spin_orig = 0.0_DP !! Initial spin kinetic energy - real(DP) :: pe_orig = 0.0_DP !! Initial potential energy - real(DP) :: be_orig = 0.0_DP !! Initial gravitational binding energy - real(DP) :: te_orig = 0.0_DP !! Initial total energy (sum of all sources of energy tracked) - real(DP) :: be_cb = 0.0_DP !! Binding energy of central body (usually orders of magnitude larger than the rest of the system, and therefore tracked seperately) - real(DP) :: E_orbit_orig = 0.0_DP !! Initial orbital energy - real(DP) :: GMtot_orig = 0.0_DP !! Initial nbody_system mass - real(DP), dimension(NDIM) :: L_total_orig = 0.0_DP !! Initial total angular momentum vector - real(DP), dimension(NDIM) :: L_orbit_orig = 0.0_DP !! Initial orbital angular momentum - real(DP), dimension(NDIM) :: L_spin_orig = 0.0_DP !! Initial spin angular momentum vector - real(DP), dimension(NDIM) :: L_escape = 0.0_DP !! Angular momentum of bodies that escaped the nbody_system (used for bookeeping) - real(DP) :: GMescape = 0.0_DP !! Mass of bodies that escaped the nbody_system (used for bookeeping) - real(DP) :: E_collisions = 0.0_DP !! Energy lost from nbody_system due to collisions - real(DP) :: E_untracked = 0.0_DP !! Energy gained from nbody_system due to escaped bodies + !! This superclass contains a minimial nbody_system of a set of test particles (tp), massive bodies (pl), and a central + !! body (cb). + class(swiftest_cb), allocatable :: cb + !! Central body data structure + class(swiftest_pl), allocatable :: pl + !! Massive body data structure + class(swiftest_tp), allocatable :: tp + !! Test particle data structure + class(swiftest_tp), allocatable :: tp_discards + !! Discarded test particle data structure + class(swiftest_pl), allocatable :: pl_discards + !! Discarded massive body particle data structure + class(swiftest_pl), allocatable :: pl_adds + !! List of added bodies in mergers or collisions + class(swiftest_tp), allocatable :: tp_adds + !! List of added bodies in mergers or collisions + class(encounter_list), allocatable :: pltp_encounter + !! List of massive body-test particle encounters in a single step + class(encounter_list), allocatable :: plpl_encounter + !! List of massive body-massive body encounters in a single step + class(collision_list_plpl), allocatable :: plpl_collision + !! List of massive body-massive body collisions in a single step + class(collision_list_pltp), allocatable :: pltp_collision + !! List of massive body-test particle collisions in a single step + class(collision_basic), allocatable :: collider + !! Collision system object + class(encounter_storage), allocatable :: encounter_history + !! Stores encounter history for later retrieval and saving to file + class(collision_storage), allocatable :: collision_history + !! Stores encounter history for later retrieval and saving to file + integer(I4B) :: maxid = -1 + !! The current maximum particle id number + real(DP) :: t = -1.0_DP + !! Integration current time + real(DP) :: GMtot = 0.0_DP + !! Total nbody_system mass - used for barycentric coordinate conversion + real(DP) :: ke_orbit = 0.0_DP + !! nbody_system orbital kinetic energy + real(DP) :: ke_spin = 0.0_DP + !! nbody_system spin kinetic energy + real(DP) :: pe = 0.0_DP + !! nbody_system potential energy + real(DP) :: be = 0.0_DP + !! nbody_system binding energy of all bodies + real(DP) :: te = 0.0_DP + !! nbody_system total energy + real(DP) :: oblpot = 0.0_DP + !! nbody_system potential energy due to oblateness of the central body + real(DP), dimension(NDIM) :: L_orbit = 0.0_DP + !! nbody_system orbital angular momentum vector + real(DP), dimension(NDIM) :: L_spin = 0.0_DP + !! nbody_system spin angular momentum vector + real(DP), dimension(NDIM) :: L_total = 0.0_DP + !! nbody_system angular momentum vector + real(DP) :: ke_orbit_orig = 0.0_DP + !! Initial orbital kinetic energy + real(DP) :: ke_spin_orig = 0.0_DP + !! Initial spin kinetic energy + real(DP) :: pe_orig = 0.0_DP + !! Initial potential energy + real(DP) :: be_orig = 0.0_DP + !! Initial gravitational binding energy + real(DP) :: te_orig = 0.0_DP + !! Initial total energy (sum of all sources of energy tracked) + real(DP) :: be_cb = 0.0_DP + !! Binding energy of central body (usually orders of magnitude larger than the rest of the system, and therefore tracked + !! seperately) + real(DP) :: E_orbit_orig = 0.0_DP + !! Initial orbital energy + real(DP) :: GMtot_orig = 0.0_DP + !! Initial nbody_system mass + real(DP), dimension(NDIM) :: L_total_orig = 0.0_DP + !! Initial total angular momentum vector + real(DP), dimension(NDIM) :: L_orbit_orig = 0.0_DP + !! Initial orbital angular momentum + real(DP), dimension(NDIM) :: L_spin_orig = 0.0_DP + !! Initial spin angular momentum vector + real(DP), dimension(NDIM) :: L_escape = 0.0_DP + !! Angular momentum of bodies that escaped the nbody_system (used for bookeeping) + real(DP) :: GMescape = 0.0_DP + !! Mass of bodies that escaped the nbody_system (used for bookeeping) + real(DP) :: E_collisions = 0.0_DP + !! Energy lost from nbody_system due to collisions + real(DP) :: E_untracked = 0.0_DP + !! Energy gained from nbody_system due to escaped bodies ! Energy, momentum, and mass errors (used in error reporting) real(DP) :: ke_orbit_error = 0.0_DP @@ -415,44 +635,73 @@ module swiftest real(DP) :: Mtot_error = 0.0_DP real(DP) :: Mescape_error = 0.0_DP - logical :: lbeg !! True if this is the beginning of a step. This is used so that test particle steps can be calculated - !! separately from massive bodies. Massive body variables are saved at half steps, and passed to - !! the test particles - logical :: lfirst_io = .true. !! Flag to indicate that this is the first time to write to a file - logical :: lfirst_peri = .true. !! Flag to indicate that this is the first pericenter passage + logical :: lbeg + !! True if this is the beginning of a step. This is used so that test particle steps can be calculated separately from + !! massive bodies. Massive body variables are saved at half steps, and passed to the test particles + logical :: lfirst_io = .true. + !! Flag to indicate that this is the first time to write to a file + logical :: lfirst_peri = .true. + !! Flag to indicate that this is the first pericenter passage contains !> Each integrator will have its own version of the step procedure(abstract_step_system), deferred :: step ! Concrete classes that are common to the basic integrator (only test particles considered for discard) - procedure :: discard => swiftest_discard_system !! Perform a discard step on the nbody_system - procedure :: compact_output => swiftest_io_compact_output !! Prints out out terminal output when display_style is set to COMPACT - procedure :: conservation_report => swiftest_io_conservation_report !! Compute energy and momentum and print out the change with time - procedure :: display_run_information => swiftest_io_display_run_information !! Displays helpful information about the run - procedure :: dump => swiftest_io_dump_system !! Dump the state of the nbody_system to a file - procedure :: get_t0_values => swiftest_io_netcdf_get_t0_values_system !! Validates the dump file to check whether the dump file initial conditions duplicate the last frame of the netcdf output. - procedure :: read_frame => swiftest_io_netcdf_read_frame_system !! Read in a frame of input data from file - procedure :: read_hdr => swiftest_io_netcdf_read_hdr_system !! Read a header for an output frame in NetCDF format - procedure :: write_hdr => swiftest_io_netcdf_write_hdr_system !! Write a header for an output frame in NetCDF format - procedure :: read_particle_info => swiftest_io_netcdf_read_particle_info_system !! Read in particle metadata from file - procedure :: read_in => swiftest_io_read_in_system !! Reads the initial conditions for an nbody system - procedure :: write_frame => swiftest_io_netcdf_write_frame_system !! Write a frame of input data from file - procedure :: obl_pot => swiftest_obl_pot_system !! Compute the contribution to the total gravitational potential due solely to the oblateness of the central body - procedure :: dealloc => swiftest_util_dealloc_system !! Deallocates all allocatables and resets all values to defaults. Acts as a base for a finalizer - procedure :: get_energy_and_momentum => swiftest_util_get_energy_and_momentum_system !! Calculates the total nbody_system energy and momentum - procedure :: get_idvals => swiftest_util_get_idvalues_system !! Returns an array of all id values in use in the nbody_system - procedure :: rescale => swiftest_util_rescale_system !! Rescales the nbody_system into a new set of units - procedure :: initialize_output_file => swiftest_io_initialize_output_file_system !! Write a frame of input data from file - procedure :: initialize => swiftest_util_setup_initialize_system !! Initialize the nbody_system from input files - procedure :: init_particle_info => swiftest_util_setup_initialize_particle_info_system !! Initialize the nbody_system from input files - ! procedure :: step_spin => tides_step_spin_system !! Steps the spins of the massive & central bodies due to tides. - procedure :: set_msys => swiftest_util_set_msys !! Sets the value of msys from the masses of nbody_system bodies. - procedure :: validate_ids => swiftest_util_valid_id_system !! Validate the numerical ids passed to the nbody_system and save the maximum value + procedure :: discard => swiftest_discard_system + !! Perform a discard step on the nbody_system + procedure :: compact_output => swiftest_io_compact_output + !! Prints out out terminal output when display_style is set to COMPACT + procedure :: conservation_report => swiftest_io_conservation_report + !! Compute energy and momentum and print out the change with time + procedure :: display_run_information => swiftest_io_display_run_information + !! Displays helpful information about the run + procedure :: dump => swiftest_io_dump_system + !! Dump the state of the nbody_system to a file + procedure :: get_t0_values => swiftest_io_netcdf_get_t0_values_system + !! Validates the dump file to check whether the dump file initial conditions duplicate the last frame of the netcdf output. + procedure :: read_frame => swiftest_io_netcdf_read_frame_system + !! Read in a frame of input data from file + procedure :: read_hdr => swiftest_io_netcdf_read_hdr_system + !! Read a header for an output frame in NetCDF format + procedure :: write_hdr => swiftest_io_netcdf_write_hdr_system + !! Write a header for an output frame in NetCDF format + procedure :: read_particle_info => swiftest_io_netcdf_read_particle_info_system + !! Read in particle metadata from file + procedure :: read_in => swiftest_io_read_in_system + !! Reads the initial conditions for an nbody system + procedure :: write_frame => swiftest_io_netcdf_write_frame_system + !! Write a frame of input data from file + procedure :: obl_pot => swiftest_obl_pot_system + !! Compute the contribution to the total gravitational potential due solely to the oblateness of the central body + procedure :: dealloc => swiftest_util_dealloc_system + !! Deallocates all allocatables and resets all values to defaults. Acts as a base for a finalizer + procedure :: get_energy_and_momentum => swiftest_util_get_energy_and_momentum_system + !! Calculates the total nbody_system energy and momentum + procedure :: get_idvals => swiftest_util_get_idvalues_system + !! Returns an array of all id values in use in the nbody_system + procedure :: rescale => swiftest_util_rescale_system + !! Rescales the nbody_system into a new set of units + procedure :: initialize_output_file => swiftest_io_initialize_output_file_system + !! Write a frame of input data from file + procedure :: initialize => swiftest_util_setup_initialize_system + !! Initialize the nbody_system from input files + procedure :: init_particle_info => swiftest_util_setup_initialize_particle_info_system + !! Initialize the nbody_system from input files + ! procedure :: step_spin => tides_step_spin_system + !! Steps the spins of the massive & central bodies due to tides. + procedure :: set_msys => swiftest_util_set_msys + !! Sets the value of msys from the masses of nbody_system bodies. + procedure :: validate_ids => swiftest_util_valid_id_system + !! Validate the numerical ids passed to the nbody_system and save the maximum value #ifdef COARRAY - procedure :: coclone => swiftest_coarray_coclone_system !! Clones the image 1 body object to all other images in the coarray structure. - procedure :: coarray_collect => swiftest_coarray_collect_system !! Collects all the test particles from other images into the image #1 test particle system - procedure :: coarray_distribute => swiftest_coarray_distribute_system !! Distributes test particles from image #1 out to all images. - procedure :: coarray_balance => swiftest_coarray_balance_system !! Checks whether or not the test particle coarrays need to be rebalanced. + procedure :: coclone => swiftest_coarray_coclone_system + !! Clones the image 1 body object to all other images in the coarray structure. + procedure :: coarray_collect => swiftest_coarray_collect_system + !! Collects all the test particles from other images into the image #1 test particle system + procedure :: coarray_distribute => swiftest_coarray_distribute_system + !! Distributes test particles from image #1 out to all images. + procedure :: coarray_balance => swiftest_coarray_balance_system + !! Checks whether or not the test particle coarrays need to be rebalanced. #endif end type swiftest_nbody_system @@ -461,436 +710,633 @@ module swiftest subroutine abstract_accel(self, nbody_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) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Current simulation time - logical, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step + class(swiftest_body), intent(inout) :: self + !! Swiftest body data structure + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + real(DP), intent(in) :: t + !! Current simulation time + logical, intent(in) :: lbeg + !! Optional argument that determines whether or not this is the beginning or end of the step end subroutine abstract_accel subroutine abstract_discard_body(self, nbody_system, param) import swiftest_body, swiftest_nbody_system, swiftest_parameters - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine abstract_discard_body subroutine abstract_kick_body(self, nbody_system, param, t, dt, lbeg) import swiftest_body, swiftest_nbody_system, swiftest_parameters, DP implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest generic body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system objec - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Current time - real(DP), intent(in) :: dt !! Stepsize - logical, intent(in) :: lbeg !! Logical flag indicating whether this is the beginning of the half step or not. + class(swiftest_body), intent(inout) :: self + !! Swiftest generic body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system objec + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + real(DP), intent(in) :: t + !! Current time + real(DP), intent(in) :: dt + !! Stepsize + logical, intent(in) :: lbeg + !! Logical flag indicating whether this is the beginning of the half step or not. end subroutine abstract_kick_body subroutine abstract_set_mu(self, cb) import swiftest_body, swiftest_cb - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine abstract_set_mu subroutine abstract_step_body(self, nbody_system, param, t, dt) import DP, swiftest_body, swiftest_nbody_system, swiftest_parameters implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest 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(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest 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 abstract_step_body subroutine abstract_step_system(self, param, t, dt) import DP, swiftest_nbody_system, swiftest_parameters implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest 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(swiftest_nbody_system), intent(inout) :: self + !! Swiftest 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 abstract_step_system end interface interface module subroutine swiftest_discard_pl(self, nbody_system, param) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameter + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameter end subroutine swiftest_discard_pl module subroutine swiftest_discard_system(self, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_discard_system module subroutine swiftest_discard_tp(self, nbody_system, param) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_discard_tp module subroutine swiftest_drift_all(mu, x, v, n, param, dt, lmask, 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) :: lmask !! 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 + 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) :: lmask + !! 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 swiftest_drift_all module subroutine swiftest_drift_body(self, nbody_system, param, dt) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest particle data structure - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - real(DP), intent(in) :: dt !! Stepsize + class(swiftest_body), intent(inout) :: self + !! Swiftest particle data structure + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters + real(DP), intent(in) :: dt + !! Stepsize end subroutine swiftest_drift_body pure elemental module subroutine swiftest_drift_one(mu, rx, ry, rz, vx, vy, vz, dt, iflag) !$omp declare simd(swiftest_drift_one) implicit none - real(DP), intent(in) :: mu !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body to drift - real(DP), intent(inout) :: rx, ry, rz, vx, vy, vz !! Position and velocity of body to drift - real(DP), intent(in) :: dt !! Step size - integer(I4B), intent(out) :: iflag !! iflag : error status flag for Danby drift (0 = OK, nonzero = ERROR) + real(DP), intent(in) :: mu + !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body to drift + real(DP), intent(inout) :: rx, ry, rz, vx, vy, vz + !! Position and velocity of body to drift + real(DP), intent(in) :: dt + !! Step size + integer(I4B), intent(out) :: iflag + !! iflag : error status flag for Danby drift (0 = OK, nonzero = ERROR) end subroutine swiftest_drift_one module subroutine swiftest_drift_cb_rotphase_update(self, param, dt) - !! Author : Kaustub Anand - !! subroutine to update the rotation phase of the central body - !! Units: radians - !! initial 0 is set at the x-axis + + !! Author : Kaustub Anand + + !! subroutine to update the rotation phase of the central body + + !! Units: radians + + !! initial 0 is set at the x-axis ! Arguments - class(swiftest_cb), intent(inout) :: self !! Swiftest central body data structure - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - real(DP), intent(in) :: dt !! Stepsize + class(swiftest_cb), intent(inout) :: self + !! Swiftest central body data structure + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters + real(DP), intent(in) :: dt + !! Stepsize end subroutine module subroutine swiftest_driver(integrator, param_file_name, display_style) implicit none - character(len=:), intent(in), allocatable :: integrator !! Symbolic code of the requested integrator - character(len=:), intent(in), allocatable :: param_file_name !! Name of the input parameters file - character(len=:), intent(in), allocatable :: display_style !! Style of the output display {"STANDARD", "COMPACT", "PROGRESS"}). Default is "STANDARD" + character(len=:), intent(in), allocatable :: integrator + !! Symbolic code of the requested integrator + character(len=:), intent(in), allocatable :: param_file_name + !! Name of the input parameters file + character(len=:), intent(in), allocatable :: display_style + !! Style of the output display {"STANDARD", "COMPACT", "PROGRESS"}). Default is "STANDARD" end subroutine swiftest_driver pure module subroutine swiftest_gr_kick_getaccb_ns_body(self, nbody_system, param) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest generic body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! Swiftest generic body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_gr_kick_getaccb_ns_body pure module subroutine swiftest_gr_kick_getacch(mu, x, lmask, n, inv_c2, agr) implicit none - real(DP), dimension(:), intent(in) :: mu !! Gravitational constant - real(DP), dimension(:,:), intent(in) :: x !! Position vectors - logical, dimension(:), intent(in) :: lmask !! Logical mask indicating which bodies to compute - integer(I4B), intent(in) :: n !! Total number of bodies - real(DP), intent(in) :: inv_c2 !! Inverse speed of light squared: 1 / c**2 - real(DP), dimension(:,:), intent(out) :: agr !! Accelerations + real(DP), dimension(:), intent(in) :: mu + !! Gravitational constant + real(DP), dimension(:,:), intent(in) :: x + !! Position vectors + logical, dimension(:), intent(in) :: lmask + !! Logical mask indicating which bodies to compute + integer(I4B), intent(in) :: n + !! Total number of bodies + real(DP), intent(in) :: inv_c2 + !! Inverse speed of light squared: 1 / c**2 + real(DP), dimension(:,:), intent(out) :: agr + !! Accelerations end subroutine swiftest_gr_kick_getacch pure elemental module subroutine swiftest_gr_p4_pos_kick(inv_c2, rx, ry, rz, vx, vy, vz, dt) implicit none - real(DP), intent(in) :: inv_c2 !! One over speed of light squared (1/c**2) - real(DP), intent(inout) :: rx, ry, rz !! Position vector - real(DP), intent(in) :: vx, vy, vz !! Velocity vector - real(DP), intent(in) :: dt !! Step size + real(DP), intent(in) :: inv_c2 + !! One over speed of light squared (1/c**2) + real(DP), intent(inout) :: rx, ry, rz + !! Position vector + real(DP), intent(in) :: vx, vy, vz + !! Velocity vector + real(DP), intent(in) :: dt + !! Step size end subroutine swiftest_gr_p4_pos_kick pure module subroutine swiftest_gr_pseudovel2vel(param, mu, rh, pv, vh) implicit none - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - real(DP), intent(in) :: mu !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body - real(DP), dimension(:), intent(in) :: rh !! Swiftestcentric position vector - real(DP), dimension(:), intent(in) :: pv !! Pseudovelocity velocity vector - see Saha & Tremain (1994), eq. (32) - real(DP), dimension(:), intent(out) :: vh !! Swiftestcentric velocity vector + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters + real(DP), intent(in) :: mu + !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body + real(DP), dimension(:), intent(in) :: rh + !! Swiftestcentric position vector + real(DP), dimension(:), intent(in) :: pv + !! Pseudovelocity velocity vector - see Saha & Tremain (1994), eq. (32) + real(DP), dimension(:), intent(out) :: vh + !! Swiftestcentric velocity vector end subroutine swiftest_gr_pseudovel2vel pure module subroutine swiftest_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 + class(swiftest_body), intent(inout) :: self + !! Swiftest particle object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_gr_pv2vh_body pure module subroutine swiftest_gr_vel2pseudovel(param, mu, rh, vh, pv) implicit none - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - real(DP), intent(in) :: mu !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body - real(DP), dimension(:), intent(in) :: rh !! Swiftestcentric position vector - real(DP), dimension(:), intent(in) :: vh !! Swiftestcentric velocity vector - real(DP), dimension(:), intent(out) :: pv !! Pseudovelocity vector - see Saha & Tremain (1994), eq. (32) + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters + real(DP), intent(in) :: mu + !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body + real(DP), dimension(:), intent(in) :: rh + !! Swiftestcentric position vector + real(DP), dimension(:), intent(in) :: vh + !! Swiftestcentric velocity vector + real(DP), dimension(:), intent(out) :: pv + !! Pseudovelocity vector - see Saha & Tremain (1994), eq. (32) end subroutine swiftest_gr_vel2pseudovel pure module subroutine swiftest_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 + class(swiftest_body), intent(inout) :: self + !! Swiftest particle object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_gr_vh2pv_body module subroutine swiftest_io_compact_output(self, param, timer) implicit none - class(swiftest_nbody_system), intent(in) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Input colleciton of user-defined parameters - class(*), intent(in) :: timer !! Object used for computing elapsed wall time + class(swiftest_nbody_system), intent(in) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Input colleciton of user-defined parameters + class(*), intent(in) :: timer + !! Object used for computing elapsed wall time end subroutine swiftest_io_compact_output module subroutine swiftest_io_conservation_report(self, param, lterminal) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Input colleciton of user-defined parameters - logical, intent(in) :: lterminal !! Indicates whether to output information to the terminal screen + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Input colleciton of user-defined parameters + logical, intent(in) :: lterminal + !! Indicates whether to output information to the terminal screen end subroutine swiftest_io_conservation_report module subroutine swiftest_io_display_run_information(self, param, integration_timer, phase) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - type(walltimer), intent(inout) :: integration_timer !! Object used for computing elapsed wall time - character(len=*), optional, intent(in) :: phase !! One of "first" or "last" + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + type(walltimer), intent(inout) :: integration_timer + !! Object used for computing elapsed wall time + character(len=*), optional, intent(in) :: phase + !! One of "first" or "last" end subroutine swiftest_io_display_run_information module subroutine swiftest_io_dump_param(self, param_file_name) implicit none - class(swiftest_parameters),intent(in) :: self !! Output collection of parameters - character(len=*), intent(in) :: param_file_name !! Parameter input file name (i.e. param.in) + class(swiftest_parameters),intent(in) :: self + !! Output collection of parameters + character(len=*), intent(in) :: param_file_name + !! Parameter input file name (i.e. param.in) end subroutine swiftest_io_dump_param module subroutine swiftest_io_dump_system(self, param, system_history) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - class(swiftest_storage), intent(inout) :: system_history !! Stores the system history between output dumps + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + class(swiftest_storage), intent(inout) :: system_history + !! Stores the system history between output dumps end subroutine swiftest_io_dump_system module subroutine swiftest_io_dump_storage(self, param) implicit none - class(swiftest_storage), intent(inout) :: self !! Swiftest simulation history storage object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_storage), intent(inout) :: self + !! Swiftest simulation history storage object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_dump_storage module subroutine swiftest_io_get_args(integrator, param_file_name, display_style, from_cli) implicit none - character(len=:), allocatable, intent(inout) :: integrator !! Symbolic code of the requested integrator - character(len=:), allocatable, intent(inout) :: param_file_name !! Name of the input parameters file - character(len=:), allocatable, intent(inout) :: display_style !! Style of the output display {"STANDARD", "COMPACT"}). Default is "STANDARD" - logical, intent(in) :: from_cli !! If true, get command-line arguments. Otherwise, use the values of the input variables + character(len=:), allocatable, intent(inout) :: integrator + !! Symbolic code of the requested integrator + character(len=:), allocatable, intent(inout) :: param_file_name + !! Name of the input parameters file + character(len=:), allocatable, intent(inout) :: display_style + !! Style of the output display {"STANDARD", "COMPACT"}). Default is "STANDARD" + logical, intent(in) :: from_cli + !! If true, get command-line arguments. Otherwise, use the values of the input variables end subroutine swiftest_io_get_args module function swiftest_io_get_token(buffer, ifirst, ilast, ierr) result(token) implicit none - character(len=*), intent(in) :: buffer !! Input string buffer - integer(I4B), intent(inout) :: ifirst !! Index of the buffer at which to start the search for a token - integer(I4B), intent(out) :: ilast !! Index of the buffer at the end of the returned token - integer(I4B), intent(out) :: ierr !! Error code - character(len=:), allocatable :: token !! Returned token string + character(len=*), intent(in) :: buffer + !! Input string buffer + integer(I4B), intent(inout) :: ifirst + !! Index of the buffer at which to start the search for a token + integer(I4B), intent(out) :: ilast + !! Index of the buffer at the end of the returned token + integer(I4B), intent(out) :: ierr + !! Error code + character(len=:), allocatable :: token + !! Returned token string end function swiftest_io_get_token module subroutine swiftest_io_log_one_message(file, message) implicit none - character(len=*), intent(in) :: file !! Name of file to log + character(len=*), intent(in) :: file + !! Name of file to log character(len=*), intent(in) :: message end subroutine swiftest_io_log_one_message module subroutine swiftest_io_log_start(param, file, header) implicit none - class(swiftest_parameters), intent(in) :: param !! Current Swiftest run configuration parameters - character(len=*), intent(in) :: file !! Name of file to log - character(len=*), intent(in) :: header !! Header to print at top of log file + class(swiftest_parameters), intent(in) :: param + !! Current Swiftest run configuration parameters + character(len=*), intent(in) :: file + !! Name of file to log + character(len=*), intent(in) :: header + !! Header to print at top of log file end subroutine swiftest_io_log_start module subroutine swiftest_io_netcdf_flush(self, param) implicit none - class(swiftest_netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_flush module subroutine swiftest_io_netcdf_get_t0_values_system(self, nc, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_get_t0_values_system module subroutine swiftest_io_netcdf_get_valid_masks(self, plmask, tpmask, plmmask, Gmtiny) implicit none - class(swiftest_netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset - logical, dimension(:), allocatable, intent(out) :: plmask !! Logical mask indicating which bodies are massive bodies - logical, dimension(:), allocatable, intent(out) :: tpmask !! Logical mask indicating which bodies are test particles - logical, dimension(:), allocatable, intent(out), optional :: plmmask !! Logical mask indicating which bodies are fully interacting massive bodies - real(DP), intent(in), optional :: Gmtiny !! The cutoff G*mass between semi-interacting and fully interacting massive bodies + class(swiftest_netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset + logical, dimension(:), allocatable, intent(out) :: plmask + !! Logical mask indicating which bodies are massive bodies + logical, dimension(:), allocatable, intent(out) :: tpmask + !! Logical mask indicating which bodies are test particles + logical, dimension(:), allocatable, intent(out), optional :: plmmask + !! Logical mask indicating which bodies are fully interacting massive bodies + real(DP), intent(in), optional :: Gmtiny + !! The cutoff G*mass between semi-interacting and fully interacting massive bodies end subroutine swiftest_io_netcdf_get_valid_masks module subroutine swiftest_io_netcdf_initialize_output(self, param) implicit none - class(swiftest_netcdf_parameters), intent(inout) :: self !! Parameters used to for writing a NetCDF dataset to file - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_netcdf_parameters), intent(inout) :: self + !! Parameters used to for writing a NetCDF dataset to file + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_initialize_output module subroutine swiftest_io_netcdf_open(self, param, readonly) implicit none - class(swiftest_netcdf_parameters), intent(inout) :: self !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - logical, optional, intent(in) :: readonly !! Logical flag indicating that this should be open read only + class(swiftest_netcdf_parameters), intent(inout) :: self + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + logical, optional, intent(in) :: readonly + !! Logical flag indicating that this should be open read only end subroutine swiftest_io_netcdf_open module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ierr) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for reading a NetCDF dataset to file - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to for reading a NetCDF dataset to file + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + integer(I4B) :: ierr + !! Error code: returns 0 if the read is successful end function swiftest_io_netcdf_read_frame_system module subroutine swiftest_io_netcdf_read_hdr_system(self, nc, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for reading a NetCDF dataset to file - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to for reading a NetCDF dataset to file + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_read_hdr_system module subroutine swiftest_io_netcdf_read_particle_info_system(self, nc, param, plmask, tpmask) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - logical, dimension(:), intent(in) :: plmask !! Logical array indicating which index values belong to massive bodies - logical, dimension(:), intent(in) :: tpmask !! Logical array indicating which index values belong to test particles + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + logical, dimension(:), intent(in) :: plmask + !! Logical array indicating which index values belong to massive bodies + logical, dimension(:), intent(in) :: tpmask + !! Logical array indicating which index values belong to test particles end subroutine swiftest_io_netcdf_read_particle_info_system module subroutine swiftest_io_netcdf_write_frame_body(self, nc, param) implicit none - class(swiftest_body), intent(in) :: self !! Swiftest base object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_body), intent(in) :: self + !! Swiftest base object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to for writing a NetCDF dataset to file + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_frame_body module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) implicit none - class(swiftest_cb), intent(inout) :: self !! Swiftest base object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_cb), intent(inout) :: self + !! Swiftest base object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to for writing a NetCDF dataset to file + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_frame_cb module subroutine swiftest_io_netcdf_write_frame_system(self, nc, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to for writing a NetCDF dataset to file + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_frame_system module subroutine swiftest_io_netcdf_write_hdr_system(self, nc, param) implicit none - class(swiftest_nbody_system), intent(in) :: self !! Swiftest nbody system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to for writing a NetCDF dataset to file - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(in) :: self + !! Swiftest nbody system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to for writing a NetCDF dataset to file + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_hdr_system module subroutine swiftest_io_netcdf_write_info_body(self, nc, param) implicit none - class(swiftest_body), intent(in) :: self !! Swiftest particle object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_body), intent(in) :: self + !! Swiftest particle object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_info_body module subroutine swiftest_io_netcdf_write_info_cb(self, nc, param) implicit none - class(swiftest_cb), intent(in) :: self !! Swiftest particle object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_cb), intent(in) :: self + !! Swiftest particle object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_netcdf_write_info_cb module subroutine swiftest_io_remove_nul_char(string) implicit none - character(len=*), intent(inout) :: string !! String to remove nul characters from + character(len=*), intent(inout) :: string + !! String to remove nul characters from end subroutine swiftest_io_remove_nul_char module subroutine swiftest_io_param_reader(self, unit, iotype, v_list, iostat, iomsg) implicit none - class(swiftest_parameters), intent(inout) :: self !! Collection of parameters - integer(I4B), intent(in) :: unit !! File unit number - character(len=*), intent(in) :: iotype !! Dummy argument passed to the input/output procedure contains the text from the char-literal-constant, prefixed with DT. - !! If you do not include a char-literal-constant, the iotype argument contains only DT. - character(len=*), intent(in) :: v_list(:) !! The first element passes the integrator code to the reader - integer(I4B), intent(out) :: iostat !! IO status code - character(len=*), intent(inout) :: iomsg !! Message to pass if iostat /= 0 + class(swiftest_parameters), intent(inout) :: self + !! Collection of parameters + integer(I4B), intent(in) :: unit + !! File unit number + character(len=*), intent(in) :: iotype + !! Dummy argument passed to the input/output procedure contains the text from the char-literal-constant, prefixed + !! with DT. If you do not include a char-literal-constant, the iotype argument contains only DT. + character(len=*), intent(in) :: v_list(:) + !! The first element passes the integrator code to the reader + integer(I4B), intent(out) :: iostat + !! IO status code + character(len=*), intent(inout) :: iomsg + !! Message to pass if iostat /= 0 end subroutine swiftest_io_param_reader module subroutine swiftest_io_param_writer(self, unit, iotype, v_list, iostat, iomsg) implicit none - class(swiftest_parameters), intent(in) :: self !! Collection of parameters - integer(I4B), intent(in) :: unit !! File unit number - character(len=*), intent(in) :: iotype !! Dummy argument passed to the input/output procedure contains the text from the char-literal-constant, prefixed with DT. - !! If you do not include a char-literal-constant, the iotype argument contains only DT. - integer(I4B), intent(in) :: v_list(:) !! Not used in this procedure - integer(I4B), intent(out) :: iostat !! IO status code - character(len=*), intent(inout) :: iomsg !! Message to pass if iostat /= 0 + class(swiftest_parameters), intent(in) :: self + !! Collection of parameters + integer(I4B), intent(in) :: unit + !! File unit number + character(len=*), intent(in) :: iotype + !! Dummy argument passed to the input/output procedure contains the text from the char-literal-constant, prefixed + !! with DT. If you do not include a char-literal-constant, the iotype argument contains only DT. + integer(I4B), intent(in) :: v_list(:) + !! Not used in this procedure + integer(I4B), intent(out) :: iostat + !! IO status code + character(len=*), intent(inout) :: iomsg + !! Message to pass if iostat /= 0 end subroutine swiftest_io_param_writer end interface interface io_param_writer_one module subroutine swiftest_io_param_writer_one_char(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - character(len=*), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + character(len=*), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_char module subroutine swiftest_io_param_writer_one_DP(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - real(DP), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + real(DP), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_DP module subroutine swiftest_io_param_writer_one_DParr(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - real(DP), dimension(:), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + real(DP), dimension(:), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_DParr module subroutine swiftest_io_param_writer_one_I4B(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - integer(I4B), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + integer(I4B), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_I4B module subroutine swiftest_io_param_writer_one_I4Barr(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - integer(I4B), dimension(:), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + integer(I4B), dimension(:), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_I4Barr module subroutine swiftest_io_param_writer_one_I8B(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - integer(I8B), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + integer(I8B), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_I8B module subroutine swiftest_io_param_writer_one_logical(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - logical, intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + logical, intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_logical #ifdef QUADPREC module subroutine swiftest_io_param_writer_one_QP(param_name, param_value, unit) implicit none - character(len=*), intent(in) :: param_name !! Name of parameter to print - real(QP), intent(in) :: param_value !! Value of parameter to print - integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to + character(len=*), intent(in) :: param_name + !! Name of parameter to print + real(QP), intent(in) :: param_value + !! Value of parameter to print + integer(I4B), intent(in) :: unit + !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_QP #endif end interface io_param_writer_one @@ -899,129 +1345,188 @@ end subroutine swiftest_io_param_writer_one_QP module subroutine swiftest_io_read_in_body(self,param) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest base object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! Swiftest base object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_read_in_body module subroutine swiftest_io_read_in_cb(self,param) implicit none - class(swiftest_cb), intent(inout) :: self !! Swiftest base object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_cb), intent(inout) :: self + !! Swiftest base object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_read_in_cb module subroutine swiftest_io_read_in_param(self, param_file_name) implicit none - class(swiftest_parameters), intent(inout) :: self !! Current run configuration parameters - character(len=*), intent(in) :: param_file_name !! Parameter input file name (i.e. param.in) + class(swiftest_parameters), intent(inout) :: self + !! Current run configuration parameters + character(len=*), intent(in) :: param_file_name + !! Parameter input file name (i.e. param.in) end subroutine swiftest_io_read_in_param module subroutine swiftest_io_read_in_system(self, nc, param) implicit none class(swiftest_nbody_system), intent(inout) :: self - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to identify a particular NetCDF dataset class(swiftest_parameters), intent(inout) :: param end subroutine swiftest_io_read_in_system module function swiftest_io_read_frame_body(self, iu, param) result(ierr) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + integer(I4B), intent(inout) :: iu + !! Unit number for the output file to write frame to + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + integer(I4B) :: ierr + !! Error code: returns 0 if the read is successful end function swiftest_io_read_frame_body module function swiftest_io_read_frame_system(self, iu, param) result(ierr) implicit none - class(swiftest_nbody_system),intent(inout) :: self !! Swiftest nbody_system object - integer(I4B), intent(inout) :: iu !! Unit number for the output file to read frame from - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + class(swiftest_nbody_system),intent(inout) :: self + !! Swiftest nbody_system object + integer(I4B), intent(inout) :: iu + !! Unit number for the output file to read frame from + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + integer(I4B) :: ierr + !! Error code: returns 0 if the read is successful end function swiftest_io_read_frame_system module subroutine swiftest_io_set_display_param(self, display_style) implicit none - class(swiftest_parameters), intent(inout) :: self !! Current run configuration parameters - character(*), intent(in) :: display_style !! Style of the output display + class(swiftest_parameters), intent(inout) :: self + !! Current run configuration parameters + character(*), intent(in) :: display_style + !! Style of the output display end subroutine swiftest_io_set_display_param module subroutine swiftest_io_toupper(string) implicit none - character(*), intent(inout) :: string !! String to make upper case + character(*), intent(inout) :: string + !! String to make upper case end subroutine swiftest_io_toupper module subroutine swiftest_io_initialize_output_file_system(self, nc, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object - class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object + class(swiftest_netcdf_parameters), intent(inout) :: nc + !! Parameters used to identify a particular NetCDF dataset + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_io_initialize_output_file_system module subroutine swiftest_kick_getacch_int_pl(self, param) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_parameters), intent(inout) :: param !! Current swiftest run configuration parameters + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_parameters), intent(inout) :: param + !! Current swiftest run configuration parameters end subroutine swiftest_kick_getacch_int_pl module subroutine swiftest_kick_getacch_int_tp(self, param, GMpl, rhp, npl) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_parameters), intent(inout) :: param !! Current swiftest run configuration parameters - real(DP), dimension(:), intent(in) :: GMpl !! Massive body masses - real(DP), dimension(:,:), intent(in) :: rhp !! Massive body position vectors - integer(I4B), intent(in) :: npl !! Number of active massive bodies + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_parameters), intent(inout) :: param + !! Current swiftest run configuration parameters + real(DP), dimension(:), intent(in) :: GMpl + !! Massive body masses + real(DP), dimension(:,:), intent(in) :: rhp + !! Massive body position vectors + integer(I4B), intent(in) :: npl + !! Number of active massive bodies end subroutine swiftest_kick_getacch_int_tp end interface interface swiftest_kick_getacch_int_all module subroutine swiftest_kick_getacch_int_all_flat_rad_pl(npl, nplpl, k_plpl, r, Gmass, radius, acc) implicit none - integer(I4B), intent(in) :: npl !! Number of massive bodies - integer(I8B), intent(in) :: nplpl !! Number of massive body interactions to compute - integer(I4B), dimension(:,:), intent(in) :: k_plpl !! Array of interaction pair indices (flattened upper triangular matrix) - real(DP), dimension(:,:), intent(in) :: r !! Position vector array - real(DP), dimension(:), intent(in) :: Gmass !! Array of massive body G*mass - real(DP), dimension(:), intent(in) :: radius !! Array of massive body radii - real(DP), dimension(:,:), intent(inout) :: acc !! Acceleration vector array + integer(I4B), intent(in) :: npl + !! Number of massive bodies + integer(I8B), intent(in) :: nplpl + !! Number of massive body interactions to compute + integer(I4B), dimension(:,:), intent(in) :: k_plpl + !! Array of interaction pair indices (flattened upper triangular matrix) + real(DP), dimension(:,:), intent(in) :: r + !! Position vector array + real(DP), dimension(:), intent(in) :: Gmass + !! Array of massive body G*mass + real(DP), dimension(:), intent(in) :: radius + !! Array of massive body radii + real(DP), dimension(:,:), intent(inout) :: acc + !! Acceleration vector array end subroutine swiftest_kick_getacch_int_all_flat_rad_pl module subroutine swiftest_kick_getacch_int_all_flat_norad_pl(npl, nplpl, k_plpl, r, Gmass, acc) implicit none - integer(I4B), intent(in) :: npl !! Number of massive bodies - integer(I8B), intent(in) :: nplpl !! Number of massive body interactions to compute - integer(I4B), dimension(:,:), intent(in) :: k_plpl !! Array of interaction pair indices (flattened upper triangular matrix) - real(DP), dimension(:,:), intent(in) :: r !! Position vector array - real(DP), dimension(:), intent(in) :: Gmass !! Array of massive body G*mass - real(DP), dimension(:,:), intent(inout) :: acc !! Acceleration vector array + integer(I4B), intent(in) :: npl + !! Number of massive bodies + integer(I8B), intent(in) :: nplpl + !! Number of massive body interactions to compute + integer(I4B), dimension(:,:), intent(in) :: k_plpl + !! Array of interaction pair indices (flattened upper triangular matrix) + real(DP), dimension(:,:), intent(in) :: r + !! Position vector array + real(DP), dimension(:), intent(in) :: Gmass + !! Array of massive body G*mass + real(DP), dimension(:,:), intent(inout) :: acc + !! Acceleration vector array end subroutine swiftest_kick_getacch_int_all_flat_norad_pl module subroutine swiftest_kick_getacch_int_all_tri_rad_pl(npl, nplm, r, Gmass, radius, acc) implicit none - integer(I4B), intent(in) :: npl !! Total number of massive bodies - integer(I4B), intent(in) :: nplm !! Number of fully interacting massive bodies - real(DP), dimension(:,:), intent(in) :: r !! Position vector array - real(DP), dimension(:), intent(in) :: Gmass !! Array of massive body G*mass - real(DP), dimension(:), intent(in) :: radius !! Array of massive body radii - real(DP), dimension(:,:), intent(inout) :: acc !! Acceleration vector array + integer(I4B), intent(in) :: npl + !! Total number of massive bodies + integer(I4B), intent(in) :: nplm + !! Number of fully interacting massive bodies + real(DP), dimension(:,:), intent(in) :: r + !! Position vector array + real(DP), dimension(:), intent(in) :: Gmass + !! Array of massive body G*mass + real(DP), dimension(:), intent(in) :: radius + !! Array of massive body radii + real(DP), dimension(:,:), intent(inout) :: acc + !! Acceleration vector array end subroutine swiftest_kick_getacch_int_all_tri_rad_pl module subroutine swiftest_kick_getacch_int_all_tri_norad_pl(npl, nplm, r, Gmass, acc) implicit none - integer(I4B), intent(in) :: npl !! Total number of massive bodies - integer(I4B), intent(in) :: nplm !! Number of fully interacting massive bodies - real(DP), dimension(:,:), intent(in) :: r !! Position vector array - real(DP), dimension(:), intent(in) :: Gmass !! Array of massive body G*mass - real(DP), dimension(:,:), intent(inout) :: acc !! Acceleration vector array + integer(I4B), intent(in) :: npl + !! Total number of massive bodies + integer(I4B), intent(in) :: nplm + !! Number of fully interacting massive bodies + real(DP), dimension(:,:), intent(in) :: r + !! Position vector array + real(DP), dimension(:), intent(in) :: Gmass + !! Array of massive body G*mass + real(DP), dimension(:,:), intent(inout) :: acc + !! Acceleration vector array end subroutine swiftest_kick_getacch_int_all_tri_norad_pl module subroutine swiftest_kick_getacch_int_all_tp(ntp, npl, rtp, rpl, GMpl, lmask, acc) implicit none - integer(I4B), intent(in) :: ntp !! Number of test particles - integer(I4B), intent(in) :: npl !! Number of massive bodies - real(DP), dimension(:,:), intent(in) :: rtp !! Test particle position vector array - real(DP), dimension(:,:), intent(in) :: rpl !! Massive body particle position vector array - real(DP), dimension(:), intent(in) :: GMpl !! Array of massive body G*mass - logical, dimension(:), intent(in) :: lmask !! Logical mask indicating which test particles should be computed - real(DP), dimension(:,:), intent(inout) :: acc !! Acceleration vector array + integer(I4B), intent(in) :: ntp + !! Number of test particles + integer(I4B), intent(in) :: npl + !! Number of massive bodies + real(DP), dimension(:,:), intent(in) :: rtp + !! Test particle position vector array + real(DP), dimension(:,:), intent(in) :: rpl + !! Massive body particle position vector array + real(DP), dimension(:), intent(in) :: GMpl + !! Array of massive body G*mass + logical, dimension(:), intent(in) :: lmask + !! Logical mask indicating which test particles should be computed + real(DP), dimension(:,:), intent(inout) :: acc + !! Acceleration vector array end subroutine swiftest_kick_getacch_int_all_tp end interface @@ -1029,66 +1534,97 @@ end subroutine swiftest_kick_getacch_int_all_tp pure module subroutine swiftest_kick_getacch_int_one_pl(rji2, xr, yr, zr, Gmi, Gmj, axi, ayi, azi, axj, ayj, azj) !$omp declare simd(swiftest_kick_getacch_int_one_pl) implicit none - real(DP), intent(in) :: rji2 !! Square of distance between the two bodies - real(DP), intent(in) :: xr, yr, zr !! Distances between the two bodies in x, y, and z directions - real(DP), intent(in) :: Gmi !! G*mass of body i - real(DP), intent(in) :: Gmj !! G*mass of body j - real(DP), intent(inout) :: axi, ayi, azi !! Acceleration vector components of body i - real(DP), intent(inout) :: axj, ayj, azj !! Acceleration vector components of body j + real(DP), intent(in) :: rji2 + !! Square of distance between the two bodies + real(DP), intent(in) :: xr, yr, zr + !! Distances between the two bodies in x, y, and z directions + real(DP), intent(in) :: Gmi + !! G*mass of body i + real(DP), intent(in) :: Gmj + !! G*mass of body j + real(DP), intent(inout) :: axi, ayi, azi + !! Acceleration vector components of body i + real(DP), intent(inout) :: axj, ayj, azj + !! Acceleration vector components of body j end subroutine swiftest_kick_getacch_int_one_pl pure module subroutine swiftest_kick_getacch_int_one_tp(rji2, xr, yr, zr, Gmpl, ax, ay, az) !$omp declare simd(swiftest_kick_getacch_int_one_tp) implicit none - real(DP), intent(in) :: rji2 !! Square of distance between the test particle and massive body - real(DP), intent(in) :: xr, yr, zr !! Distances between the two bodies in x, y, and z directions - real(DP), intent(in) :: Gmpl !! G*mass of massive body - real(DP), intent(inout) :: ax, ay, az !! Acceleration vector components of test particle + real(DP), intent(in) :: rji2 + !! Square of distance between the test particle and massive body + real(DP), intent(in) :: xr, yr, zr + !! Distances between the two bodies in x, y, and z directions + real(DP), intent(in) :: Gmpl + !! G*mass of massive body + real(DP), intent(inout) :: ax, ay, az + !! Acceleration vector components of test particle end subroutine swiftest_kick_getacch_int_one_tp module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) implicit none - integer(I4B), intent(in) :: n !! Number of bodies - real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation vector - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix !! rotation matrix - real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv !! inverse of the rotation matrix + integer(I4B), intent(in) :: n + !! Number of bodies + real(DP), dimension(NDIM), intent(in) :: rot + !! Central body rotation vector + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix + !! rotation matrix + real(DP), dimension(NDIM, NDIM), intent(inout) :: rot_matrix_inv + !! inverse of the rotation matrix end subroutine swiftest_obl_rot_matrix module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, GMpl, aoblcb) implicit none - integer(I4B), intent(in) :: n !! Number of bodies - real(DP), intent(in) :: GMcb !! Central body G*Mass - real(DP), intent(in) :: j2rp2 !! J2 * R**2 for the central body - real(DP), intent(in) :: j4rp4 !! J4 * R**4 for the central body - real(DP), dimension(:,:), intent(in) :: rh !! Heliocentric positions of bodies - logical, dimension(:), intent(in) :: lmask !! Logical mask of bodies to compute aobl - real(DP), dimension(:,:), intent(out) :: aobl !! Barycentric acceleration of bodies due to central body oblateness - real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix - real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles - real(DP), dimension(:), intent(out), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + integer(I4B), intent(in) :: n + !! Number of bodies + real(DP), intent(in) :: GMcb + !! Central body G*Mass + real(DP), intent(in) :: j2rp2 + !! J2 * R**2 for the central body + real(DP), intent(in) :: j4rp4 + !! J4 * R**4 for the central body + real(DP), dimension(:,:), intent(in) :: rh + !! Heliocentric positions of bodies + logical, dimension(:), intent(in) :: lmask + !! Logical mask of bodies to compute aobl + real(DP), dimension(:,:), intent(out) :: aobl + !! Barycentric acceleration of bodies due to central body oblateness + real(DP), dimension(NDIM), intent(in) :: rot + !! Central body rotation matrix + real(DP), dimension(:), intent(in), optional :: GMpl + !! Masses of input bodies if they are not test particles + real(DP), dimension(:), intent(out), optional :: aoblcb + !! Barycentric acceleration of central body (only needed if input bodies are massive) end subroutine swiftest_obl_acc module subroutine swiftest_obl_acc_pl(self, nbody_system) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object end subroutine swiftest_obl_acc_pl module subroutine swiftest_obl_acc_tp(self, nbody_system) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object end subroutine swiftest_obl_acc_tp module subroutine swiftest_obl_pot_system(self) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object end subroutine swiftest_obl_pot_system module subroutine swiftest_orbel_el2xv_vec(self, cb) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_orbel_el2xv_vec pure module subroutine swiftest_orbel_scget(angle, sx, cx) @@ -1101,198 +1637,288 @@ end subroutine swiftest_orbel_scget pure elemental module subroutine swiftest_orbel_xv2aeq(mu, rx, ry, rz, vx, vy, vz, a, e, q) !$omp declare simd(swiftest_orbel_xv2aeq) implicit none - real(DP), intent(in) :: mu !! Gravitational constant - real(DP), intent(in) :: rx,ry,rz !! Position vector - real(DP), intent(in) :: vx,vy,vz !! Velocity vector - real(DP), intent(out) :: a !! semimajor axis - real(DP), intent(out) :: e !! eccentricity - real(DP), intent(out) :: q !! periapsis + real(DP), intent(in) :: mu + !! Gravitational constant + real(DP), intent(in) :: rx,ry,rz + !! Position vector + real(DP), intent(in) :: vx,vy,vz + !! Velocity vector + real(DP), intent(out) :: a + !! semimajor axis + real(DP), intent(out) :: e + !! eccentricity + real(DP), intent(out) :: q + !! periapsis end subroutine swiftest_orbel_xv2aeq pure module subroutine swiftest_orbel_xv2aqt(mu, rx, ry, rz, vx, vy, vz, a, q, capm, tperi) !$omp declare simd(swiftest_orbel_xv2aqt) implicit none - real(DP), intent(in) :: mu !! Gravitational constant - real(DP), intent(in) :: rx,ry,rz !! Position vector - real(DP), intent(in) :: vx,vy,vz !! Velocity vector - real(DP), intent(out) :: a !! semimajor axis - real(DP), intent(out) :: q !! periapsis - real(DP), intent(out) :: capm !! mean anomaly - real(DP), intent(out) :: tperi !! time of pericenter passage + real(DP), intent(in) :: mu + !! Gravitational constant + real(DP), intent(in) :: rx,ry,rz + !! Position vector + real(DP), intent(in) :: vx,vy,vz + !! Velocity vector + real(DP), intent(out) :: a + !! semimajor axis + real(DP), intent(out) :: q + !! periapsis + real(DP), intent(out) :: capm + !! mean anomaly + real(DP), intent(out) :: tperi + !! time of pericenter passage end subroutine swiftest_orbel_xv2aqt - pure module subroutine swiftest_orbel_xv2el(mu, rx, ry, rz, vx, vy, vz, a, e, inc, capom, omega, capm, varpi, lam, f, cape, capf) - implicit none - real(DP), intent(in) :: mu !! Gravitational constant - real(DP), intent(in) :: rx,ry,rz !! Position vector - real(DP), intent(in) :: vx,vy,vz !! Velocity vector - real(DP), intent(out) :: a !! semimajor axis - real(DP), intent(out) :: e !! eccentricity - real(DP), intent(out) :: inc !! inclination - real(DP), intent(out) :: capom !! longitude of ascending node - real(DP), intent(out) :: omega !! argument of periapsis - real(DP), intent(out) :: capm !! mean anomaly - real(DP), intent(out) :: varpi !! longitude of periapsis - real(DP), intent(out) :: lam !! mean longitude - real(DP), intent(out) :: f !! true anomaly - real(DP), intent(out) :: cape !! eccentric anomaly (eccentric orbits) - real(DP), intent(out) :: capf !! hyperbolic anomaly (hyperbolic orbits) + pure module subroutine swiftest_orbel_xv2el(mu, rx, ry, rz, vx, vy, vz, & + a, e, inc, capom, omega, capm, varpi, lam, f, cape, capf) + implicit none + real(DP), intent(in) :: mu + !! Gravitational constant + real(DP), intent(in) :: rx,ry,rz + !! Position vector + real(DP), intent(in) :: vx,vy,vz + !! Velocity vector + real(DP), intent(out) :: a + !! semimajor axis + real(DP), intent(out) :: e + !! eccentricity + real(DP), intent(out) :: inc + !! inclination + real(DP), intent(out) :: capom + !! longitude of ascending node + real(DP), intent(out) :: omega + !! argument of periapsis + real(DP), intent(out) :: capm + !! mean anomaly + real(DP), intent(out) :: varpi + !! longitude of periapsis + real(DP), intent(out) :: lam + !! mean longitude + real(DP), intent(out) :: f + !! true anomaly + real(DP), intent(out) :: cape + !! eccentric anomaly (eccentric orbits) + real(DP), intent(out) :: capf + !! hyperbolic anomaly (hyperbolic orbits) end subroutine swiftest_orbel_xv2el module subroutine swiftest_orbel_xv2el_vec(self, cb) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_orbel_xv2el_vec module subroutine swiftest_util_setup_body(self, n, param) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - integer(I4B), intent(in) :: n !! Number of particles to allocate space for - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + integer(I4B), intent(in) :: n + !! Number of particles to allocate space for + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_util_setup_body module subroutine swiftest_util_setup_construct_system(nbody_system, param) implicit none - class(swiftest_nbody_system), allocatable, intent(inout) :: nbody_system !! Swiftest nbody_system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), allocatable, intent(inout) :: nbody_system + !! Swiftest nbody_system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_util_setup_construct_system module subroutine swiftest_util_setup_initialize_particle_info_system(self, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_util_setup_initialize_particle_info_system module subroutine swiftest_util_setup_initialize_system(self, system_history, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object - class(swiftest_storage), allocatable, intent(inout) :: system_history !! Stores the system history between output dumps - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object + class(swiftest_storage), allocatable, intent(inout) :: system_history + !! Stores the system history between output dumps + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_util_setup_initialize_system module subroutine swiftest_util_setup_pl(self, n, param) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - integer(I4B), intent(in) :: n !! Number of particles to allocate space for - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + integer(I4B), intent(in) :: n + !! Number of particles to allocate space for + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_util_setup_pl module subroutine swiftest_util_setup_tp(self, n, param) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - integer(I4B), intent(in) :: n !! Number of particles to allocate space for - class(swiftest_parameters), intent(in) :: param !! Current run configuration parametersr + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + integer(I4B), intent(in) :: n + !! Number of particles to allocate space for + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parametersr end subroutine swiftest_util_setup_tp module subroutine swiftest_user_kick_getacch_body(self, nbody_system, param, t, lbeg) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest massive body particle data structure - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody_system_object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - real(DP), intent(in) :: t !! Current time - logical, intent(in) :: lbeg !! Optional argument that determines whether or not this is the beginning or end of the step + class(swiftest_body), intent(inout) :: self + !! Swiftest massive body particle data structure + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody_system_object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + real(DP), intent(in) :: t + !! Current time + logical, intent(in) :: lbeg + !! Optional argument that determines whether or not this is the beginning or end of the step end subroutine swiftest_user_kick_getacch_body end interface interface util_append module subroutine swiftest_util_append_arr_info(arr, source, nold, lsource_mask) implicit none - type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: arr !! Destination array - type(swiftest_particle_info), dimension(:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + type(swiftest_particle_info), dimension(:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at arr(nold+1). + !! Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to end subroutine swiftest_util_append_arr_info module subroutine swiftest_util_append_arr_kin(arr, source, nold, lsource_mask) implicit none - type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: arr !! Destination array - type(swiftest_kinship), dimension(:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + type(swiftest_kinship), dimension(:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at arr(nold+1). + !! Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to end subroutine swiftest_util_append_arr_kin end interface interface module subroutine swiftest_util_append_body(self, source, lsource_mask) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_body), intent(in) :: source !! Source object to append - logical, dimension(:), intent(in) :: lsource_mask !! Logical mask indicating which elements to append to + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_body), intent(in) :: source + !! Source object to append + logical, dimension(:), intent(in) :: lsource_mask + !! Logical mask indicating which elements to append to end subroutine swiftest_util_append_body module subroutine swiftest_util_append_pl(self, source, lsource_mask) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_body), intent(in) :: source !! Source object to append - logical, dimension(:), intent(in) :: lsource_mask !! Logical mask indicating which elements to append to + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_body), intent(in) :: source + !! Source object to append + logical, dimension(:), intent(in) :: lsource_mask + !! Logical mask indicating which elements to append to end subroutine swiftest_util_append_pl module subroutine swiftest_util_append_tp(self, source, lsource_mask) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_body), intent(in) :: source !! Source object to append - logical, dimension(:), intent(in) :: lsource_mask !! Logical mask indicating which elements to append to + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_body), intent(in) :: source + !! Source object to append + logical, dimension(:), intent(in) :: lsource_mask + !! Logical mask indicating which elements to append to end subroutine swiftest_util_append_tp module subroutine swiftest_util_coord_b2h_pl(self, cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_b2h_pl module subroutine swiftest_util_coord_b2h_tp(self, cb) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_cb), intent(in) :: cb !! Swiftest central body object + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_cb), intent(in) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_b2h_tp module subroutine swiftest_util_coord_h2b_pl(self, cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_h2b_pl module subroutine swiftest_util_coord_h2b_tp(self, cb) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_cb), intent(in) :: cb !! Swiftest central body object + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_cb), intent(in) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_h2b_tp module subroutine swiftest_util_coord_vb2vh_pl(self, cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_vb2vh_pl module subroutine swiftest_util_coord_vb2vh_tp(self, vbcb) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - real(DP), dimension(:), intent(in) :: vbcb !! Barycentric velocity of the central body + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + real(DP), dimension(:), intent(in) :: vbcb + !! Barycentric velocity of the central body end subroutine swiftest_util_coord_vb2vh_tp module subroutine swiftest_util_coord_vh2vb_pl(self, cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_vh2vb_pl module subroutine swiftest_util_coord_vh2vb_tp(self, vbcb) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - real(DP), dimension(:), intent(in) :: vbcb !! Barycentric velocity of the central body + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + real(DP), dimension(:), intent(in) :: vbcb + !! Barycentric velocity of the central body end subroutine swiftest_util_coord_vh2vb_tp module subroutine swiftest_util_coord_rh2rb_pl(self, cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_rh2rb_pl module subroutine swiftest_util_coord_rh2rb_tp(self, cb) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_cb), intent(in) :: cb !! Swiftest central body object + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_cb), intent(in) :: cb + !! Swiftest central body object end subroutine swiftest_util_coord_rh2rb_tp module subroutine swiftest_util_copy_particle_info(self, source) @@ -1303,9 +1929,12 @@ end subroutine swiftest_util_copy_particle_info module subroutine swiftest_util_copy_particle_info_arr(source, dest, idx) implicit none - class(swiftest_particle_info), dimension(:), intent(in) :: source !! Source object to copy into - class(swiftest_particle_info), dimension(:), intent(inout) :: dest !! Swiftest body object with particle metadata information object - integer(I4B), dimension(:), intent(in), optional :: idx !! Optional array of indices to draw the source object + class(swiftest_particle_info), dimension(:), intent(in) :: source + !! Source object to copy into + class(swiftest_particle_info), dimension(:), intent(inout) :: dest + !! Swiftest body object with particle metadata information object + integer(I4B), dimension(:), intent(in), optional :: idx + !! Optional array of indices to draw the source object end subroutine swiftest_util_copy_particle_info_arr module subroutine swiftest_util_dealloc_body(self) @@ -1315,12 +1944,14 @@ end subroutine swiftest_util_dealloc_body module subroutine swiftest_util_dealloc_kin(self) implicit none - class(swiftest_kinship), intent(inout) :: self !! Swiftest kinship object + class(swiftest_kinship), intent(inout) :: self + !! Swiftest kinship object end subroutine swiftest_util_dealloc_kin module subroutine swiftest_util_dealloc_cb(self) implicit none - class(swiftest_cb), intent(inout) :: self !! Swiftest central body object + class(swiftest_cb), intent(inout) :: self + !! Swiftest central body object end subroutine swiftest_util_dealloc_cb module subroutine swiftest_util_dealloc_pl(self) @@ -1330,7 +1961,8 @@ end subroutine swiftest_util_dealloc_pl module subroutine swiftest_util_dealloc_storage(self) implicit none - class(swiftest_storage), intent(inout) :: self !! Swiftest storage object + class(swiftest_storage), intent(inout) :: self + !! Swiftest storage object end subroutine swiftest_util_dealloc_storage module subroutine swiftest_util_dealloc_system(self) @@ -1345,39 +1977,54 @@ end subroutine swiftest_util_dealloc_tp module subroutine swiftest_util_fill_body(self, inserts, lfill_list) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - class(swiftest_body), intent(in) :: inserts !! Swiftest body object to be inserted - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + class(swiftest_body), intent(in) :: inserts + !! Swiftest body object to be inserted + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps end subroutine swiftest_util_fill_body module subroutine swiftest_util_fill_pl(self, inserts, lfill_list) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_body), intent(in) :: inserts !! Swiftest body object to be inserted - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_body), intent(in) :: inserts + !! Swiftest body object to be inserted + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps end subroutine swiftest_util_fill_pl module subroutine swiftest_util_fill_tp(self, inserts, lfill_list) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_body), intent(in) :: inserts !! Swiftest body object to be inserted - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_body), intent(in) :: inserts + !! Swiftest body object to be inserted + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps end subroutine swiftest_util_fill_tp end interface interface util_fill module subroutine swiftest_util_fill_arr_info(keeps, inserts, lfill_list) implicit none - type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - type(swiftest_particle_info), dimension(:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + type(swiftest_particle_info), dimension(:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps end subroutine swiftest_util_fill_arr_info module subroutine swiftest_util_fill_arr_kin(keeps, inserts, lfill_list) implicit none - type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - type(swiftest_kinship), dimension(:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + type(swiftest_kinship), dimension(:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps end subroutine swiftest_util_fill_arr_kin end interface @@ -1385,43 +2032,60 @@ end subroutine swiftest_util_fill_arr_kin pure module subroutine swiftest_util_flatten_eucl_ij_to_k(n, i, j, k) !$omp declare simd(swiftest_util_flatten_eucl_ij_to_k) implicit none - integer(I4B), intent(in) :: n !! Number of bodies - integer(I4B), intent(in) :: i !! Index of the ith body - integer(I4B), intent(in) :: j !! Index of the jth body - integer(I8B), intent(out) :: k !! Index of the flattened matrix + integer(I4B), intent(in) :: n + !! Number of bodies + integer(I4B), intent(in) :: i + !! Index of the ith body + integer(I4B), intent(in) :: j + !! Index of the jth body + integer(I8B), intent(out) :: k + !! Index of the flattened matrix end subroutine swiftest_util_flatten_eucl_ij_to_k pure module subroutine swiftest_util_flatten_eucl_k_to_ij(n, k, i, j) implicit none - integer(I4B), intent(in) :: n !! Number of bodies - integer(I8B), intent(in) :: k !! Index of the flattened matrix - integer(I4B), intent(out) :: i !! Index of the ith body - integer(I4B), intent(out) :: j !! Index of the jth body + integer(I4B), intent(in) :: n + !! Number of bodies + integer(I8B), intent(in) :: k + !! Index of the flattened matrix + integer(I4B), intent(out) :: i + !! Index of the ith body + integer(I4B), intent(out) :: j + !! Index of the jth body end subroutine swiftest_util_flatten_eucl_k_to_ij module subroutine swiftest_util_flatten_eucl_plpl(self, param) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine module subroutine swiftest_util_flatten_eucl_pltp(self, pl, param) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_pl), intent(in) :: pl !! Swiftest massive body object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_pl), intent(in) :: pl + !! Swiftest massive body object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine module subroutine swiftest_util_get_energy_and_momentum_system(self, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_util_get_energy_and_momentum_system module subroutine swiftest_util_get_idvalues_system(self, idvals) implicit none - class(swiftest_nbody_system), intent(in) :: self !! Encounter snapshot object - integer(I4B), dimension(:), allocatable, intent(out) :: idvals !! Array of all id values saved in this snapshot + class(swiftest_nbody_system), intent(in) :: self + !! Encounter snapshot object + integer(I4B), dimension(:), allocatable, intent(out) :: idvals + !! Array of all id values saved in this snapshot end subroutine swiftest_util_get_idvalues_system end interface @@ -1453,78 +2117,111 @@ end subroutine swiftest_util_get_potential_energy_triangular interface module subroutine swiftest_util_get_vals_storage(self, idvals, tvals) - class(swiftest_storage), intent(in) :: self !! Swiftest storage object - integer(I4B), dimension(:), allocatable, intent(out) :: idvals !! Array of all id values in all snapshots - real(DP), dimension(:), allocatable, intent(out) :: tvals !! Array of all time values in all snapshots + class(swiftest_storage), intent(in) :: self + !! Swiftest storage object + integer(I4B), dimension(:), allocatable, intent(out) :: idvals + !! Array of all id values in all snapshots + real(DP), dimension(:), allocatable, intent(out) :: tvals + !! Array of all time values in all snapshots end subroutine swiftest_util_get_vals_storage module subroutine swiftest_util_index_array(ind_arr, n) implicit none - integer(I4B), dimension(:), allocatable, intent(inout) :: ind_arr !! Index array. Input is a pre-existing index array where n /= size(ind_arr). Output is a new index array ind_arr = [1, 2, ... n] - integer(I4B), intent(in) :: n !! The new size of the index array + integer(I4B), dimension(:), allocatable, intent(inout) :: ind_arr + !! Index array. Input is a pre-existing index array where n /= size(ind_arr). + !! Output is a new index array ind_arr = [1, 2, ... n] + integer(I4B), intent(in) :: n + !! The new size of the index array end subroutine swiftest_util_index_array module subroutine swiftest_util_index_map_storage(self) implicit none - class(swiftest_storage), intent(inout) :: self !! Swiftest storage object + class(swiftest_storage), intent(inout) :: self + !! Swiftest storage object end subroutine swiftest_util_index_map_storage module subroutine swiftest_util_make_impactors_pl(self, idx) implicit none - class(swiftest_pl), intent(inout) :: self !! Massive body object - integer(I4B), dimension(:), intent(in) :: idx !! Array holding the indices of the two bodies involved in the collision) + class(swiftest_pl), intent(inout) :: self + !! Massive body object + integer(I4B), dimension(:), intent(in) :: idx + !! Array holding the indices of the two bodies involved in the collision) end subroutine swiftest_util_make_impactors_pl module subroutine swiftest_util_peri(n,m, r, v, atp, q, isperi) implicit none - integer(I4B), intent(in) :: n !! Number of bodies - real(DP), dimension(:), intent(in) :: m !! Mass term (mu for HELIO coordinates, and Gmtot for BARY) - real(DP), dimension(:,:), intent(in) :: r !! Position vectors (rh for HELIO coordinates, rb for BARY) - real(DP), dimension(:,:), intent(in) :: v !! Position vectors (vh for HELIO coordinates, rb for BARY) - real(DP), dimension(:), intent(out) :: atp !! Semimajor axis - real(DP), dimension(:), intent(out) :: q !! Periapsis - integer(I4B), dimension(:), intent(inout) :: isperi !! Periapsis passage flag + integer(I4B), intent(in) :: n + !! Number of bodies + real(DP), dimension(:), intent(in) :: m + !! Mass term (mu for HELIO coordinates, and Gmtot for BARY) + real(DP), dimension(:,:), intent(in) :: r + !! Position vectors (rh for HELIO coordinates, rb for BARY) + real(DP), dimension(:,:), intent(in) :: v + !! Position vectors (vh for HELIO coordinates, rb for BARY) + real(DP), dimension(:), intent(out) :: atp + !! Semimajor axis + real(DP), dimension(:), intent(out) :: q + !! Periapsis + integer(I4B), dimension(:), intent(inout) :: isperi + !! Periapsis passage flag end subroutine swiftest_util_peri module subroutine swiftest_util_peri_body(self, nbody_system, param) implicit none - class(swiftest_body), intent(inout) :: self !! SyMBA massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! SyMBA massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_util_peri_body module subroutine swiftest_util_peri_tp(self, nbody_system, param) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters end subroutine swiftest_util_peri_tp module subroutine swiftest_util_rearray_pl(self, nbody_system, param) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_util_rearray_pl module subroutine swiftest_util_rearray_tp(self, nbody_system, param) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_util_rearray_tp module subroutine swiftest_util_rescale_system(self, param, mscale, dscale, tscale) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters. Returns with new values of the scale vactors and GU - real(DP), intent(in) :: mscale, dscale, tscale !! Scale factors for mass, distance, and time units, respectively. + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters. Returns with new values of the scale vactors and GU + real(DP), intent(in) :: mscale, dscale, tscale + !! Scale factors for mass, distance, and time units, respectively. end subroutine swiftest_util_rescale_system module subroutine swiftest_util_reset_kinship_pl(self, idx) implicit none - class(swiftest_pl), intent(inout) :: self !! SyMBA massive body object - integer(I4B), dimension(:), intent(in) :: idx !! Index array of bodies to reset + class(swiftest_pl), intent(inout) :: self + !! SyMBA massive body object + integer(I4B), dimension(:), intent(in) :: idx + !! Index array of bodies to reset end subroutine swiftest_util_reset_kinship_pl end interface @@ -1533,130 +2230,180 @@ end subroutine swiftest_util_reset_kinship_pl interface util_resize module subroutine swiftest_util_resize_arr_info(arr, nnew) implicit none - type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size end subroutine swiftest_util_resize_arr_info module subroutine swiftest_util_resize_arr_kin(arr, nnew) implicit none - type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size end subroutine swiftest_util_resize_arr_kin end interface interface module subroutine swiftest_util_resize_body(self, nnew) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - integer(I4B), intent(in) :: nnew !! New size neded + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + integer(I4B), intent(in) :: nnew + !! New size neded end subroutine swiftest_util_resize_body module subroutine swiftest_util_resize_pl(self, nnew) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - integer(I4B), intent(in) :: nnew !! New size neded + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + integer(I4B), intent(in) :: nnew + !! New size neded end subroutine swiftest_util_resize_pl module subroutine swiftest_util_resize_storage(storage, nold, nnew) use base, only : base_storage implicit none - class(base_storage), allocatable, intent(inout) :: storage !! Original storage object - integer(I4B), intent(in) :: nold !! Old size - integer(I4B), intent(in) :: nnew !! New size + class(base_storage), allocatable, intent(inout) :: storage + !! Original storage object + integer(I4B), intent(in) :: nold + !! Old size + integer(I4B), intent(in) :: nnew + !! New size end subroutine swiftest_util_resize_storage module subroutine swiftest_util_resize_tp(self, nnew) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - integer(I4B), intent(in) :: nnew !! New size neded + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + integer(I4B), intent(in) :: nnew + !! New size neded end subroutine swiftest_util_resize_tp module subroutine swiftest_util_set_beg_end_pl(self, rbeg, rend, vbeg) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - real(DP), dimension(:,:), intent(in), optional :: rbeg !! Position vectors at beginning of step - real(DP), dimension(:,:), intent(in), optional :: rend !! Positions vectors at end of step - real(DP), dimension(:,:), intent(in), optional :: vbeg !! vbeg is an unused variable to keep this method forward compatible with RMVS + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + real(DP), dimension(:,:), intent(in), optional :: rbeg + !! Position vectors at beginning of step + real(DP), dimension(:,:), intent(in), optional :: rend + !! Positions vectors at end of step + real(DP), dimension(:,:), intent(in), optional :: vbeg + !! vbeg is an unused variable to keep this method forward compatible with RMVS end subroutine swiftest_util_set_beg_end_pl module subroutine swiftest_util_set_ir3h(self) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object + class(swiftest_body), intent(inout) :: self + !! Swiftest body object end subroutine swiftest_util_set_ir3h module subroutine swiftest_util_set_msys(self) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody_system object + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody_system object end subroutine swiftest_util_set_msys module subroutine swiftest_util_set_mu_pl(self, cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_set_mu_pl module subroutine swiftest_util_set_mu_tp(self, cb) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_set_mu_tp module subroutine swiftest_util_set_particle_info(self, name, particle_type, status, origin_type, origin_time, collision_id, & origin_rh, origin_vh, discard_time, discard_rh, discard_vh, discard_body_id) implicit none class(swiftest_particle_info), intent(inout) :: self - character(len=*), intent(in), optional :: name !! Non-unique name - character(len=*), intent(in), optional :: particle_type !! String containing a description of the particle type (e.g. Central Body, Massive Body, Test Particle) - character(len=*), intent(in), optional :: status !! Particle status description: Active, Merged, Fragmented, etc. - character(len=*), intent(in), optional :: origin_type !! String containing a description of the origin of the particle (e.g. Initial Conditions, Supercatastrophic, Disruption, etc.) - real(DP), intent(in), optional :: origin_time !! The time of the particle's formation - integer(I4B), intent(in), optional :: collision_id !! The ID fo the collision that formed the particle - real(DP), dimension(:), intent(in), optional :: origin_rh !! The heliocentric distance vector at the time of the particle's formation - real(DP), dimension(:), intent(in), optional :: origin_vh !! The heliocentric velocity vector at the time of the particle's formation - real(DP), intent(in), optional :: discard_time !! The time of the particle's discard - real(DP), dimension(:), intent(in), optional :: discard_rh !! The heliocentric distance vector at the time of the particle's discard - real(DP), dimension(:), intent(in), optional :: discard_vh !! The heliocentric velocity vector at the time of the particle's discard - integer(I4B), intent(in), optional :: discard_body_id !! The id of the other body involved in the discard (0 if no other body involved) + character(len=*), intent(in), optional :: name + !! Non-unique name + character(len=*), intent(in), optional :: particle_type + !! String containing a description of the particle type (e.g. Central Body, Massive Body, Test Particle) + character(len=*), intent(in), optional :: status + !! Particle status description: Active, Merged, Fragmented, etc. + character(len=*), intent(in), optional :: origin_type + !! String containing a description of the origin of the particle (e.g. Initial Conditions, Disruption, etc.) + real(DP), intent(in), optional :: origin_time + !! The time of the particle's formation + integer(I4B), intent(in), optional :: collision_id + !! The ID fo the collision that formed the particle + real(DP), dimension(:), intent(in), optional :: origin_rh + !! The heliocentric distance vector at the time of the particle's formation + real(DP), dimension(:), intent(in), optional :: origin_vh + !! The heliocentric velocity vector at the time of the particle's formation + real(DP), intent(in), optional :: discard_time + !! The time of the particle's discard + real(DP), dimension(:), intent(in), optional :: discard_rh + !! The heliocentric distance vector at the time of the particle's discard + real(DP), dimension(:), intent(in), optional :: discard_vh + !! The heliocentric velocity vector at the time of the particle's discard + integer(I4B), intent(in), optional :: discard_body_id + !! The id of the other body involved in the discard (0 if no other body involved) end subroutine swiftest_util_set_particle_info module subroutine swiftest_util_set_rhill(self,cb) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_cb), intent(inout) :: cb !! Swiftest central body object + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_set_rhill module subroutine swiftest_util_set_renc_I4B(self, scale) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - integer(I4B), intent(in) :: scale !! Input scale factor (multiplier of Hill's sphere size) + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + integer(I4B), intent(in) :: scale + !! Input scale factor (multiplier of Hill's sphere size) end subroutine swiftest_util_set_renc_I4B module subroutine swiftest_util_set_renc_DP(self, scale) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - real(DP), intent(in) :: scale !! Input scale factor (multiplier of Hill's sphere size) + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + real(DP), intent(in) :: scale + !! Input scale factor (multiplier of Hill's sphere size) end subroutine swiftest_util_set_renc_DP module subroutine swiftest_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 + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + class(swiftest_cb), intent(inout) :: cb + !! Swiftest central body object end subroutine swiftest_util_set_rhill_approximate module subroutine swiftest_util_snapshot_save(storage, snapshot) use base, only : base_storage implicit none - class(base_storage), allocatable, intent(inout) :: storage !! Storage ncounter storage object - class(*), intent(in) :: snapshot !! Object to snapshot + class(base_storage), allocatable, intent(inout) :: storage + !! Storage ncounter storage object + class(*), intent(in) :: snapshot + !! Object to snapshot end subroutine swiftest_util_snapshot_save module subroutine swiftest_util_snapshot_system(self, param, nbody_system, t, arg) implicit none - class(swiftest_storage), intent(inout) :: self !! Swiftest storage object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object to store - real(DP), intent(in), optional :: t !! Time of snapshot if different from nbody_system time - character(*), intent(in), optional :: arg !! Optional argument (needed for extended storage type used in collision snapshots) + class(swiftest_storage), intent(inout) :: self + !! Swiftest storage object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object to store + real(DP), intent(in), optional :: t + !! Time of snapshot if different from nbody_system time + character(*), intent(in), optional :: arg + !! Optional argument (needed for extended storage type used in collision snapshots) end subroutine swiftest_util_snapshot_system end interface @@ -1664,16 +2411,22 @@ end subroutine swiftest_util_snapshot_system interface util_sort_rearrange module subroutine swiftest_util_sort_rearrange_arr_info(arr, ind, n) implicit none - type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange end subroutine swiftest_util_sort_rearrange_arr_info pure module subroutine swiftest_util_sort_rearrange_arr_kin(arr, ind, n) implicit none - type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange end subroutine swiftest_util_sort_rearrange_arr_kin end interface util_sort_rearrange @@ -1681,41 +2434,56 @@ end subroutine swiftest_util_sort_rearrange_arr_kin interface module subroutine swiftest_util_sort_rearrange_body(self, ind) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - integer(I4B), dimension(:), intent(in) :: ind !! Index array used to restructure the body (should contain all 1:n index values in the desired order) + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + integer(I4B), dimension(:), intent(in) :: ind + !! Index array used to restructure the body (should contain all 1:n index values in the desired order) end subroutine swiftest_util_sort_rearrange_body module subroutine swiftest_util_sort_rearrange_pl(self, ind) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - integer(I4B), dimension(:), intent(in) :: ind !! Index array used to restructure the body (should contain all 1:n index values in the desired order) + class(swiftest_pl), intent(inout) :: self + !! Swiftest massive body object + integer(I4B), dimension(:), intent(in) :: ind + !! Index array used to restructure the body (should contain all 1:n index values in the desired order) end subroutine swiftest_util_sort_rearrange_pl module subroutine swiftest_util_sort_rearrange_tp(self, ind) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - integer(I4B), dimension(:), intent(in) :: ind !! Index array used to restructure the body (should contain all 1:n index values in the desired order) + class(swiftest_tp), intent(inout) :: self + !! Swiftest test particle object + integer(I4B), dimension(:), intent(in) :: ind + !! Index array used to restructure the body (should contain all 1:n index values in the desired order) end subroutine swiftest_util_sort_rearrange_tp module subroutine swiftest_util_sort_body(self, sortby, ascending) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - character(*), intent(in) :: sortby !! Sorting attribute - logical, intent(in) :: ascending !! Logical flag indicating whether or not the sorting should be in ascending or descending order + class(swiftest_body), intent(inout) :: self + !! Swiftest body object + character(*), intent(in) :: sortby + !! Sorting attribute + logical, intent(in) :: ascending + !! Logical flag indicating whether or not the sorting should be in ascending or descending order end subroutine swiftest_util_sort_body module subroutine swiftest_util_sort_pl(self, sortby, ascending) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest body object - character(*), intent(in) :: sortby !! Sorting attribute - logical, intent(in) :: ascending !! Logical flag indicating whether or not the sorting should be in ascending or descending order + class(swiftest_pl), intent(inout) :: self + !! Swiftest body object + character(*), intent(in) :: sortby + !! Sorting attribute + logical, intent(in) :: ascending + !! Logical flag indicating whether or not the sorting should be in ascending or descending order end subroutine swiftest_util_sort_pl module subroutine swiftest_util_sort_tp(self, sortby, ascending) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest body object - character(*), intent(in) :: sortby !! Sorting attribute - logical, intent(in) :: ascending !! Logical flag indicating whether or not the sorting should be in ascending or descending order + class(swiftest_tp), intent(inout) :: self + !! Swiftest body object + character(*), intent(in) :: sortby + !! Sorting attribute + logical, intent(in) :: ascending + !! Logical flag indicating whether or not the sorting should be in ascending or descending order end subroutine swiftest_util_sort_tp end interface @@ -1723,44 +2491,64 @@ end subroutine swiftest_util_sort_tp interface util_spill module subroutine swiftest_util_spill_arr_info(keeps, discards, lspill_list, ldestructive) implicit none - type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discardss - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter the keeps array or not + type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + type(swiftest_particle_info), dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discardss + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not end subroutine swiftest_util_spill_arr_info module subroutine swiftest_util_spill_arr_kin(keeps, discards, lspill_list, ldestructive) implicit none - type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discardss - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter the keeps array or not + type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + type(swiftest_kinship), dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discardss + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not end subroutine swiftest_util_spill_arr_kin end interface interface module subroutine swiftest_util_spill_body(self, discards, lspill_list, ldestructive) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest 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 - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter the keeps array or not + class(swiftest_body), intent(inout) :: self + !! Swiftest 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 + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not end subroutine swiftest_util_spill_body module subroutine swiftest_util_spill_pl(self, discards, lspill_list, ldestructive) implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest 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 - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter the keeps array or not + class(swiftest_pl), intent(inout) :: self + !! Swiftest 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 + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not end subroutine swiftest_util_spill_pl module subroutine swiftest_util_spill_tp(self, discards, lspill_list, ldestructive) implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest 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 - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter the keeps array or not + class(swiftest_tp), intent(inout) :: self + !! Swiftest 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 + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not end subroutine swiftest_util_spill_tp end interface @@ -1768,8 +2556,10 @@ end subroutine swiftest_util_spill_tp interface module subroutine swiftest_util_valid_id_system(self, param) implicit none - class(swiftest_nbody_system), intent(inout) :: self !! Swiftest nbody system object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: self + !! Swiftest nbody system object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_util_valid_id_system module subroutine swiftest_util_version() @@ -1782,24 +2572,30 @@ end subroutine swiftest_util_version module subroutine swiftest_coarray_balance_system(nbody_system, param) !! author: David A. Minton !! - !! Checks whether or not the system needs to be rebalance. Rebalancing occurs when the image with the smallest number of test particles - !! has <90% of that of the image with the largest number of test particles. + !! Checks whether or not the system needs to be rebalance. Rebalancing occurs when the image with the smallest number of + !! test particles has <90% of that of the image with the largest number of test particles. implicit none ! Arguments - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_coarray_balance_system module subroutine swiftest_coarray_collect_system(nbody_system, param) implicit none - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_coarray_collect_system module subroutine swiftest_coarray_distribute_system(nbody_system, param) implicit none - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters end subroutine swiftest_coarray_distribute_system end interface @@ -1834,87 +2630,73 @@ module subroutine swiftest_coarray_component_collect_info_arr1D(var,dest_img) interface module subroutine swiftest_coarray_coclone_body(self) implicit none - class(swiftest_body),intent(inout),codimension[*] :: self !! Swiftest body object + class(swiftest_body),intent(inout),codimension[*] :: self + !! Swiftest body object end subroutine swiftest_coarray_coclone_body module subroutine swiftest_coarray_coclone_cb(self) implicit none - class(swiftest_cb),intent(inout),codimension[*] :: self !! Swiftest cb object + class(swiftest_cb),intent(inout),codimension[*] :: self + !! Swiftest cb object end subroutine swiftest_coarray_coclone_cb module subroutine swiftest_coarray_coclone_kin(self) implicit none - class(swiftest_kinship),intent(inout),codimension[*] :: self !! Swiftest kinship object + class(swiftest_kinship),intent(inout),codimension[*] :: self + !! Swiftest kinship object end subroutine swiftest_coarray_coclone_kin module subroutine swiftest_coarray_coclone_nc(self) implicit none - class(swiftest_netcdf_parameters),intent(inout),codimension[*] :: self !! Swiftest body object + class(swiftest_netcdf_parameters),intent(inout),codimension[*] :: self + !! Swiftest body object end subroutine swiftest_coarray_coclone_nc module subroutine swiftest_coarray_coclone_pl(self) implicit none - class(swiftest_pl),intent(inout),codimension[*] :: self !! Swiftest pl object + class(swiftest_pl),intent(inout),codimension[*] :: self + !! Swiftest pl object end subroutine swiftest_coarray_coclone_pl module subroutine swiftest_coarray_coclone_tp(self) implicit none - class(swiftest_tp),intent(inout),codimension[*] :: self !! Swiftest tp object + class(swiftest_tp),intent(inout),codimension[*] :: self + !! Swiftest tp object end subroutine swiftest_coarray_coclone_tp module subroutine swiftest_coarray_coclone_system(self) implicit none - class(swiftest_nbody_system),intent(inout),codimension[*] :: self !! Swiftest nbody system object + class(swiftest_nbody_system),intent(inout),codimension[*] :: self + !! Swiftest nbody system object end subroutine swiftest_coarray_coclone_system module subroutine swiftest_coarray_cocollect_body(self) implicit none - class(swiftest_body),intent(inout), codimension[*] :: self !! Swiftest body object + class(swiftest_body),intent(inout), codimension[*] :: self + !! Swiftest body object end subroutine swiftest_coarray_cocollect_body module subroutine swiftest_coarray_cocollect_tp(self) implicit none - class(swiftest_tp),intent(inout), codimension[*] :: self !! Swiftest tp object + class(swiftest_tp),intent(inout), codimension[*] :: self + !! Swiftest tp object end subroutine swiftest_coarray_cocollect_tp end interface #endif - interface - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) - implicit none - real(DP), intent(in) :: GMcb !! GMass of the central body - real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi_cb !! rotation phase angle of the central body - real(DP), intent(in), dimension(:) :: rh !! distance vector of body - real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector - real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle - real(DP), dimension(:), intent(inout), optional :: aoblcb!! Barycentric acceleration of central body (only for massive input bodies) - end subroutine swiftest_sph_g_acc_one - - module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) - implicit none - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - end subroutine swiftest_sph_g_acc_pl_all - - module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) - implicit none - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - end subroutine swiftest_sph_g_acc_tp_all - - end interface - contains subroutine swiftest_final_kin(self) - !! author: David A. Minton - !! - !! Finalize the swiftest kinship object - deallocates all allocatables + + !! author: David A. Minton + + !! + + !! Finalize the swiftest kinship object - deallocates all allocatables implicit none ! Argument - type(swiftest_kinship), intent(inout) :: self !! SyMBA kinship object + type(swiftest_kinship), intent(inout) :: self + !! SyMBA kinship object call self%dealloc() @@ -1923,9 +2705,12 @@ end subroutine swiftest_final_kin subroutine swiftest_final_storage(self) - !! author: David A. Minton - !! - !! Finalizer for the storage data type + + !! author: David A. Minton + + !! + + !! Finalizer for the storage data type implicit none ! Arguments type(swiftest_storage) :: self From 46433e746d20ca694707a117f26721834c845626 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 11:49:11 -0500 Subject: [PATCH 249/324] Refactored for better line limits with Ford documentation comments --- src/base/base_module.f90 | 1274 ++++++++++++++++++++++---------------- 1 file changed, 751 insertions(+), 523 deletions(-) diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index 6f0821b70..ab3c77a0d 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -8,10 +8,10 @@ ! If not, see: https://www.gnu.org/licenses. module base - !! author: The Purdue Swiftest Team - David A. Minton, Carlisle A. Wishard, Jennifer L.L. Pouplin, and Jacob R. Elliott - !! - !! Base type definitions. This allows the collision and encounter modules to be defined before the swiftest module. - !! + !! author: The Purdue Swiftest Team - David A. Minton, Carlisle A. Wishard, Jennifer L.L. Pouplin, and Jacob R. Elliott + !! + !! Base type definitions. This allows the collision and encounter modules to be defined before the swiftest module. + !! use globals #ifdef COARRAY use coarray @@ -22,109 +22,184 @@ module base !> User defined parameters that are read in from the parameters input file. !> Each paramter is initialized to a default values. type, abstract :: base_parameters - character(STRMAX) :: integrator !! Name of the nbody integrator used - character(STRMAX) :: param_file_name !! The name of the parameter file - real(DP) :: t0 = 0.0_DP !! Integration reference time - real(DP) :: tstart = -1.0_DP !! Integration start time - real(DP) :: tstop = -1.0_DP !! Integration stop time - real(DP) :: dt = -1.0_DP !! Time step - integer(I8B) :: iloop = 0_I8B !! Main loop counter - integer(I8B) :: nloops = 0_I8B !! Total number of loops to execute - integer(I8B) :: istart = 0_I8B !! Starting index for loop counter - integer(I4B) :: iout = 0 !! Output cadence counter - integer(I4B) :: idump = 0 !! Dump cadence counter - integer(I4B) :: nout = 0 !! Current output step - integer(I4B) :: istep = 0 !! Current value of istep (used for time stretching) - character(STRMAX) :: incbfile = CB_INFILE !! Name of input file for the central body - character(STRMAX) :: inplfile = PL_INFILE !! Name of input file for massive bodies - character(STRMAX) :: intpfile = TP_INFILE !! Name of input file for test particles - character(STRMAX) :: nc_in = NC_INFILE !! Name of system input file for NetCDF input - character(STRMAX) :: in_type = "NETCDF_DOUBLE" !! Data representation type of input data files - character(STRMAX) :: in_form = "XV" !! Format of input data files ("EL" or ["XV"]) - integer(I4B) :: istep_out = -1 !! Number of time steps between saved outputs - integer(I4B) :: nstep_out = -1 !! Total number of saved outputs - real(DP) :: fstep_out = 1.0_DP !! The output step time stretching factor - logical :: ltstretch = .false. !! Whether to employ time stretching or not - character(STRMAX) :: outfile = BIN_OUTFILE !! Name of output binary file - character(STRMAX) :: out_type = "NETCDF_DOUBLE" !! Binary format of output file - character(STRMAX) :: out_form = "XVEL" !! Data to write to output file - character(STRMAX) :: out_stat = 'NEW' !! Open status for output binary file - integer(I4B) :: dump_cadence = 10 !! Number of output steps between dumping simulation data to file - real(DP) :: rmin = -1.0_DP !! Minimum heliocentric radius for test particle - real(DP) :: rmax = -1.0_DP !! Maximum heliocentric radius for test particle - real(DP) :: rmaxu = -1.0_DP !! Maximum unbound heliocentric radius for test particle - real(DP) :: qmin = -1.0_DP !! Minimum pericenter distance for test particle - character(STRMAX) :: qmin_coord = "HELIO" !! Coordinate frame to use for qmin (["HELIO"] or "BARY") - real(DP) :: qmin_alo = -1.0_DP !! Minimum semimajor axis for qmin - real(DP) :: qmin_ahi = -1.0_DP !! Maximum semimajor axis for qmin - real(QP) :: MU2KG = -1.0_QP !! Converts mass units to grams - real(QP) :: TU2S = -1.0_QP !! Converts time units to seconds - real(QP) :: DU2M = -1.0_QP !! Converts distance unit to centimeters - real(DP) :: GU = -1.0_DP !! Universal gravitational constant in the system units - real(DP) :: inv_c2 = -1.0_DP !! Inverse speed of light squared in the system units - real(DP) :: GMTINY = -1.0_DP !! Smallest G*mass that is fully gravitating - real(DP) :: min_GMfrag = -1.0_DP !! Smallest G*mass that can be produced in a fragmentation event - real(DP) :: nfrag_reduction = 30.0_DP !! Reduction factor for limiting the number of collision fragments - integer(I4B), dimension(:), allocatable :: seed !! Random seeds for fragmentation modeling - logical :: lmtiny_pl = .false. !! Include semi-interacting massive bodies - character(STRMAX) :: collision_model = "MERGE" !! The Coll - character(STRMAX) :: encounter_save = "NONE" !! Indicate if and how encounter data should be saved - logical :: lenc_save_trajectory = .false. !! Indicates that when encounters are saved, the full trajectory - !! through recursion steps are saved - logical :: lenc_save_closest = .false. !! Indicates that when encounters are saved, the closest approach - !! distance between pairs of bodies is saved - character(NAMELEN):: interaction_loops = "ADAPTIVE" !! Method used to compute interaction loops. - !! Options are "TRIANGULAR", "FLAT", or "ADAPTIVE" - character(NAMELEN):: encounter_check_plpl = "ADAPTIVE" !! Method used to compute pl-pl encounter checks. - !! Options are "TRIANGULAR", "SORTSWEEP", or "ADAPTIVE" - character(NAMELEN):: encounter_check_pltp = "ADAPTIVE" !! Method used to compute pl-tp encounter checks. - !! Options are "TRIANGULAR", "SORTSWEEP", or "ADAPTIVE" - logical :: lcoarray = .false. !! Use Coarrays for test particle parallelization. + character(STRMAX) :: integrator + !! Name of the nbody integrator used + character(STRMAX) :: param_file_name + !! The name of the parameter file + real(DP) :: t0 = 0.0_DP + !! Integration reference time + real(DP) :: tstart = -1.0_DP + !! Integration start time + real(DP) :: tstop = -1.0_DP + !! Integration stop time + real(DP) :: dt = -1.0_DP + !! Time step + integer(I8B) :: iloop = 0_I8B + !! Main loop counter + integer(I8B) :: nloops = 0_I8B + !! Total number of loops to execute + integer(I8B) :: istart = 0_I8B + !! Starting index for loop counter + integer(I4B) :: iout = 0 + !! Output cadence counter + integer(I4B) :: idump = 0 + !! Dump cadence counter + integer(I4B) :: nout = 0 + !! Current output step + integer(I4B) :: istep = 0 + !! Current value of istep (used for time stretching) + character(STRMAX) :: incbfile = CB_INFILE + !! Name of input file for the central body + character(STRMAX) :: inplfile = PL_INFILE + !! Name of input file for massive bodies + character(STRMAX) :: intpfile = TP_INFILE + !! Name of input file for test particles + character(STRMAX) :: nc_in = NC_INFILE + !! Name of system input file for NetCDF input + character(STRMAX) :: in_type = "NETCDF_DOUBLE" + !! Data representation type of input data files + character(STRMAX) :: in_form = "XV" + !! Format of input data files ("EL" or ["XV"]) + integer(I4B) :: istep_out = -1 + !! Number of time steps between saved outputs + integer(I4B) :: nstep_out = -1 + !! Total number of saved outputs + real(DP) :: fstep_out = 1.0_DP + !! The output step time stretching factor + logical :: ltstretch = .false. + !! Whether to employ time stretching or not + character(STRMAX) :: outfile = BIN_OUTFILE + !! Name of output binary file + character(STRMAX) :: out_type = "NETCDF_DOUBLE" + !! Binary format of output file + character(STRMAX) :: out_form = "XVEL" + !! Data to write to output file + character(STRMAX) :: out_stat = 'NEW' + !! Open status for output binary file + integer(I4B) :: dump_cadence = 10 + !! Number of output steps between dumping simulation data to file + real(DP) :: rmin = -1.0_DP + !! Minimum heliocentric radius for test particle + real(DP) :: rmax = -1.0_DP + !! Maximum heliocentric radius for test particle + real(DP) :: rmaxu = -1.0_DP + !! Maximum unbound heliocentric radius for test particle + real(DP) :: qmin = -1.0_DP + !! Minimum pericenter distance for test particle + character(STRMAX) :: qmin_coord = "HELIO" + !! Coordinate frame to use for qmin (["HELIO"] or "BARY") + real(DP) :: qmin_alo = -1.0_DP + !! Minimum semimajor axis for qmin + real(DP) :: qmin_ahi = -1.0_DP + !! Maximum semimajor axis for qmin + real(QP) :: MU2KG = -1.0_QP + !! Converts mass units to grams + real(QP) :: TU2S = -1.0_QP + !! Converts time units to seconds + real(QP) :: DU2M = -1.0_QP + !! Converts distance unit to centimeters + real(DP) :: GU = -1.0_DP + !! Universal gravitational constant in the system units + real(DP) :: inv_c2 = -1.0_DP + !! Inverse speed of light squared in the system units + real(DP) :: GMTINY = -1.0_DP + !! Smallest G*mass that is fully gravitating + real(DP) :: min_GMfrag = -1.0_DP + !! Smallest G*mass that can be produced in a fragmentation event + real(DP) :: nfrag_reduction = 30.0_DP + !! Reduction factor for limiting the number of collision fragments + integer(I4B), dimension(:), allocatable :: seed + !! Random seeds for fragmentation modeling + logical :: lmtiny_pl = .false. + !! Include semi-interacting massive bodies + character(STRMAX) :: collision_model = "MERGE" + !! The Coll + character(STRMAX) :: encounter_save = "NONE" + !! Indicate if and how encounter data should be saved + logical :: lenc_save_trajectory = .false. + !! Indicates that when encounters are saved, the full trajectory through recursion steps are saved + logical :: lenc_save_closest = .false. + !! Indicates that when encounters are saved, the closest approach distance between pairs of bodies is saved + character(NAMELEN):: interaction_loops = "ADAPTIVE" + !! Method used to compute interaction loops. + !! Options are "TRIANGULAR", "FLAT", or "ADAPTIVE" + character(NAMELEN):: encounter_check_plpl = "ADAPTIVE" + !! Method used to compute pl-pl encounter checks. + !! Options are "TRIANGULAR", "SORTSWEEP", or "ADAPTIVE" + character(NAMELEN):: encounter_check_pltp = "ADAPTIVE" + !! Method used to compute pl-tp encounter checks. + !! Options are "TRIANGULAR", "SORTSWEEP", or "ADAPTIVE" + logical :: lcoarray = .false. + !! Use Coarrays for test particle parallelization. ! The following are not set by the user, but instead are determined by the input value of INTERACTION_LOOPS - logical :: lflatten_interactions = .false. !! Use the flattened upper triangular matrix for pl-pl interaction loops - logical :: lencounter_sas_plpl = .false. !! Use the Sort and Sweep algorithm to prune the encounter list before checking - !! for close encounters - logical :: lencounter_sas_pltp = .false. !! Use the Sort and Sweep algorithm to prune the encounter list before checking - !! for close encounters + logical :: lflatten_interactions = .false. + !! Use the flattened upper triangular matrix for pl-pl interaction loops + logical :: lencounter_sas_plpl = .false. + !! Use the Sort and Sweep algorithm to prune the encounter list before checking for close encounters + logical :: lencounter_sas_pltp = .false. + !! Use the Sort and Sweep algorithm to prune the encounter list before checking for close encounters ! Logical flags to turn on or off various features of the code - logical :: lrhill_present = .false. !! Hill radii are given as an input rather than calculated by the code (can be used to - !! inflate close encounter regions manually) - logical :: lextra_force = .false. !! User defined force function turned on - logical :: lbig_discard = .false. !! Save big bodies on every discard - logical :: lclose = .false. !! Turn on close encounters - logical :: lenergy = .false. !! Track the total energy of the system - logical :: loblatecb = .false. !! Calculate acceleration from oblate central body (automatically turns true if nonzero J2 - !! is input) - logical :: lrotation = .false. !! Include rotation states of big bodies - logical :: ltides = .false. !! Include tidal dissipation - logical :: lshgrav = .false. !! Calculate acceleration from spherical harmonics terms for the central body - !! (automatically turns true if clm array is inputted) + logical :: lrhill_present = .false. + !! Hill radii are given as an input rather than calculated by the code (can be used to inflate close encounter regions + !! manually) + logical :: lextra_force = .false. + !! User defined force function turned on + logical :: lbig_discard = .false. + !! Save big bodies on every discard + logical :: lclose = .false. + !! Turn on close encounters + logical :: lenergy = .false. + !! Track the total energy of the system + logical :: loblatecb = .false. + !! Calculate acceleration from oblate central body (automatically turns true if nonzero J2, J4, or c_lm is input) + logical :: lrotation = .false. + !! Include rotation states of big bodies + logical :: ltides = .false. + !! Include tidal dissipation ! Initial values to pass to the energy report subroutine (usually only used in the case of a restart, otherwise these will be ! updated with initial conditions values) - real(DP) :: E_orbit_orig = 0.0_DP !! Initial orbital energy - real(DP) :: GMtot_orig = 0.0_DP !! Initial system mass - real(DP), dimension(NDIM) :: L_total_orig = 0.0_DP !! Initial total angular momentum vector - real(DP), dimension(NDIM) :: L_orbit_orig = 0.0_DP !! Initial orbital angular momentum - real(DP), dimension(NDIM) :: L_spin_orig = 0.0_DP !! Initial spin angular momentum vector - real(DP), dimension(NDIM) :: L_escape = 0.0_DP !! Angular momentum of escaped bodies (used for bookeeping) - real(DP) :: GMescape = 0.0_DP !! Mass of bodies that escaped the system (used for bookeeping) - real(DP) :: E_collisions = 0.0_DP !! Energy lost from system due to collisions - real(DP) :: E_untracked = 0.0_DP !! Energy gained from system due to escaped bodies - logical :: lfirstenergy = .true. !! This is the first time computing energe - logical :: lfirstkick = .true. !! Initiate the first kick in a symplectic step - logical :: lrestart = .false. !! Indicates whether or not this is a restarted run - - character(NAMELEN) :: display_style !! Style of the output display {["STANDARD"], "COMPACT"}). - integer(I4B) :: display_unit = OUTPUT_UNIT !! File unit number for display (either to stdout or to a log file) - logical :: log_output = .false. !! Logs the output to file instead of displaying it on the terminal + real(DP) :: E_orbit_orig = 0.0_DP + !! Initial orbital energy + real(DP) :: GMtot_orig = 0.0_DP + !! Initial system mass + real(DP), dimension(NDIM) :: L_total_orig = 0.0_DP + !! Initial total angular momentum vector + real(DP), dimension(NDIM) :: L_orbit_orig = 0.0_DP + !! Initial orbital angular momentum + real(DP), dimension(NDIM) :: L_spin_orig = 0.0_DP + !! Initial spin angular momentum vector + real(DP), dimension(NDIM) :: L_escape = 0.0_DP + !! Angular momentum of escaped bodies (used for bookeeping) + real(DP) :: GMescape = 0.0_DP + !! Mass of bodies that escaped the system (used for bookeeping) + real(DP) :: E_collisions = 0.0_DP + !! Energy lost from system due to collisions + real(DP) :: E_untracked = 0.0_DP + !! Energy gained from system due to escaped bodies + logical :: lfirstenergy = .true. + !! This is the first time computing energe + logical :: lfirstkick = .true. + !! Initiate the first kick in a symplectic step + logical :: lrestart = .false. + !! Indicates whether or not this is a restarted run + + character(NAMELEN) :: display_style + !! Style of the output display {["STANDARD"], "COMPACT"}). + integer(I4B) :: display_unit = OUTPUT_UNIT + !! File unit number for display (either to stdout or to a log file) + logical :: log_output = .false. + !! Logs the output to file instead of displaying it on the terminal ! Future features not implemented or in development - logical :: lgr = .false. !! Turn on GR - logical :: lyarkovsky = .false. !! Turn on Yarkovsky effect - logical :: lyorp = .false. !! Turn on YORP effect + logical :: lgr = .false. + !! Turn on GR + logical :: lyarkovsky = .false. + !! Turn on Yarkovsky effect + logical :: lyorp = .false. + !! Turn on YORP effect contains procedure :: dealloc => base_util_dealloc_param procedure(abstract_io_dump_param), deferred :: dump @@ -140,43 +215,60 @@ module base subroutine abstract_io_dump_param(self, param_file_name) import base_parameters implicit none - class(base_parameters),intent(in) :: self !! Output collection of parameters - character(len=*), intent(in) :: param_file_name !! Parameter input file name (i.e. param.in) + class(base_parameters),intent(in) :: self + !! Output collection of parameters + character(len=*), intent(in) :: param_file_name + !! Parameter input file name (i.e. param.in) end subroutine abstract_io_dump_param subroutine abstract_io_param_reader(self, unit, iotype, v_list, iostat, iomsg) import base_parameters, I4B implicit none - class(base_parameters), intent(inout) :: self !! Collection of parameters - integer(I4B), intent(in) :: unit !! File unit number - character(len=*), intent(in) :: iotype !! Dummy argument passed to the input/output procedure contains the - !! text from the char-literal-constant, prefixed with DT. If you do - !! not include a char-literal-constant, the iotype argument contains - !! only DT. - character(len=*), intent(in) :: v_list(:) !! The first element passes the integrator code to the reader - integer(I4B), intent(out) :: iostat !! IO status code - character(len=*), intent(inout) :: iomsg !! Message to pass if iostat /= 0 + class(base_parameters), intent(inout) :: self + !! Collection of parameters + integer(I4B), intent(in) :: unit + !! File unit number + character(len=*), intent(in) :: iotype + !! Dummy argument passed to the input/output procedure contains the text from the char-literal-constant, prefixed with + !! DT. If you do not include a char-literal-constant, the iotype argument contains only DT. + character(len=*), intent(in) :: v_list(:) + !! The first element passes the integrator code to the reader + integer(I4B), intent(out) :: iostat + !! IO status code + character(len=*), intent(inout) :: iomsg + !! Message to pass if iostat /= 0 end subroutine abstract_io_param_reader subroutine abstract_io_param_writer(self, unit, iotype, v_list, iostat, iomsg) import base_parameters, I4B implicit none - class(base_parameters), intent(in) :: self !! Collection of parameters - integer(I4B), intent(in) :: unit !! File unit number - character(len=*), intent(in) :: iotype !! Dummy argument passed to the input/output procedure contains the - !! text from the char-literal-constant, prefixed with DT. If you do - !! not include a char-literal-constant, the iotype argument contains - !! only DT. - integer(I4B), intent(in) :: v_list(:) !! Not used in this procedure - integer(I4B), intent(out) :: iostat !! IO status code - character(len=*), intent(inout) :: iomsg !! Message to pass if iostat /= 0 + class(base_parameters), intent(in) :: self + !! Collection of parameters + integer(I4B), intent(in) :: unit + !! File unit number + character(len=*), intent(in) :: iotype + !! Dummy argument passed to the input/output procedure contains the + + !! text from the char-literal-constant, prefixed with DT. If you do + + !! not include a char-literal-constant, the iotype argument contains + + !! only DT. + integer(I4B), intent(in) :: v_list(:) + !! Not used in this procedure + integer(I4B), intent(out) :: iostat + !! IO status code + character(len=*), intent(inout) :: iomsg + !! Message to pass if iostat /= 0 end subroutine abstract_io_param_writer subroutine abstract_io_read_in_param(self, param_file_name) import base_parameters implicit none - class(base_parameters), intent(inout) :: self !! Current run configuration parameters - character(len=*), intent(in) :: param_file_name !! Parameter input file name (i.e. param.in) + class(base_parameters), intent(inout) :: self + !! Current run configuration parameters + character(len=*), intent(in) :: param_file_name + !! Parameter input file name (i.e. param.in) end subroutine abstract_io_read_in_param end interface @@ -184,33 +276,47 @@ end subroutine abstract_io_read_in_param type :: base_storage_frame class(*), allocatable :: item contains - procedure :: store => base_util_copy_store !! Stores a snapshot of the nbody system so that later it can be - !! retrieved for saving to file. + procedure :: store => base_util_copy_store + !! Stores a snapshot of the nbody system so that later it can be + + !! retrieved for saving to file. generic :: assignment(=) => store final :: base_final_storage_frame end type type, abstract :: base_storage - !! An class that establishes the pattern for various storage objects - integer(I4B) :: nframes !! Total number of frames that can be stored - - !! An class that establishes the pattern for various storage objects - type(base_storage_frame), dimension(:), allocatable :: frame !! Array of stored frames - integer(I4B) :: iframe = 0 !! Index of the last frame stored in the system - integer(I4B) :: nid !! Number of unique id values in all saved snapshots - integer(I4B), dimension(:), allocatable :: idvals !! The set of unique id values contained in the snapshots - integer(I4B), dimension(:), allocatable :: idmap !! The id value -> index map - integer(I4B) :: nt !! Number of unique time values in all saved snapshots - real(DP), dimension(:), allocatable :: tvals !! The set of unique time values contained in the snapshots - integer(I4B), dimension(:), allocatable :: tmap !! The t value -> index map + + !! An class that establishes the pattern for various storage objects + integer(I4B) :: nframes + !! Total number of frames that can be stored An class that establishes the pattern for various storage objects + type(base_storage_frame), dimension(:), allocatable :: frame + !! Array of stored frames + integer(I4B) :: iframe = 0 + !! Index of the last frame stored in the system + integer(I4B) :: nid + !! Number of unique id values in all saved snapshots + integer(I4B), dimension(:), allocatable :: idvals + !! The set of unique id values contained in the snapshots + integer(I4B), dimension(:), allocatable :: idmap + !! The id value -> index map + integer(I4B) :: nt + !! Number of unique time values in all saved snapshots + real(DP), dimension(:), allocatable :: tvals + !! The set of unique time values contained in the snapshots + integer(I4B), dimension(:), allocatable :: tmap + !! The t value -> index map contains - procedure :: dealloc => base_util_dealloc_storage !! Deallocates all allocatables - procedure :: reset => base_util_reset_storage !! Resets the storage object back to its original state by removing all of - !! the saved items from the storage frames - procedure :: resize => base_util_resize_storage !! Resizes storage if it is too small - procedure :: setup => base_util_setup_storage !! Sets up a storage system with a set number of frames - procedure :: save => base_util_snapshot_save !! Takes a snapshot of the current system + procedure :: dealloc => base_util_dealloc_storage + !! Deallocates all allocatables + procedure :: reset => base_util_reset_storage + !! Resets the storage object back to its original state by removing all of the saved items from the storage frames + procedure :: resize => base_util_resize_storage + !! Resizes storage if it is too small + procedure :: setup => base_util_setup_storage + !! Sets up a storage system with a set number of frames + procedure :: save => base_util_snapshot_save + !! Takes a snapshot of the current system end type base_storage @@ -230,7 +336,8 @@ end subroutine abstract_io_read_in_param subroutine abstract_util_dealloc_object(self) import base_object implicit none - class(base_object), intent(inout) :: self !! Generic Swiftest object type + class(base_object), intent(inout) :: self + !! Generic Swiftest object type end subroutine abstract_util_dealloc_object end interface @@ -307,17 +414,22 @@ end subroutine abstract_util_dealloc_object contains subroutine base_util_append_arr_char_string(arr, source, nold, lsource_mask) - !! author: David A. Minton - !! - !! Append a single array of character string type onto another. If the destination array is not allocated, or is not big - !! enough, this will allocate space for it. + + !! author: David A. Minton + !! + !! Append a single array of character string type onto another. If the destination array is not allocated, or is not big + !! enough, this will allocate space for it. implicit none ! Arguments - character(len=STRMAX), dimension(:), allocatable, intent(inout) :: arr !! Destination array - character(len=STRMAX), dimension(:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at - !! arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + character(len=STRMAX), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + character(len=STRMAX), dimension(:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at arr(nold+1). + !! Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to ! Internals integer(I4B) :: nnew, nsrc, nend_orig @@ -354,17 +466,22 @@ end subroutine base_util_append_arr_char_string subroutine base_util_append_arr_DP(arr, source, nold, lsource_mask) - !! author: David A. Minton - !! - !! Append a single array of double precision type onto another. If the destination array is not allocated, or is not big - !! enough, this will allocate space for it. + !! author: David A. Minton + !! + !! Append a single array of double precision type onto another. If the destination array is not allocated, or is not big + !! enough, this will allocate space for it. implicit none ! Arguments - real(DP), dimension(:), allocatable, intent(inout) :: arr !! Destination array - real(DP), dimension(:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at - !! arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + real(DP), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + real(DP), dimension(:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at + + !! arr(nold+1). Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to ! Internals integer(I4B) :: nnew, nsrc, nend_orig @@ -401,17 +518,21 @@ end subroutine base_util_append_arr_DP subroutine base_util_append_arr_DPvec(arr, source, nold, lsource_mask) - !! author: David A. Minton - !! - !! Append a single array of double precision vector type of size (NDIM, n) onto another. If the destination array is not - !! allocated, or is not big enough, this will allocate space for it. + !! author: David A. Minton + !! + !! Append a single array of double precision vector type of size (NDIM, n) onto another. If the destination array is not + !! allocated, or is not big enough, this will allocate space for it. implicit none ! Arguments - real(DP), dimension(:,:), allocatable, intent(inout) :: arr !! Destination array - real(DP), dimension(:,:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at - !! arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + real(DP), dimension(:,:), allocatable, intent(inout) :: arr + !! Destination array + real(DP), dimension(:,:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at arr(nold+1). + !! Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to ! Internals integer(I4B) :: nnew, nsrc, nend_orig @@ -450,17 +571,21 @@ end subroutine base_util_append_arr_DPvec subroutine base_util_append_arr_I4B(arr, source, nold, lsource_mask) - !! author: David A. Minton - !! - !! Append a single array of integer(I4B) onto another. If the destination array is not allocated, or is not big enough, - !! this will allocate space for it. + !! author: David A. Minton + !! + !! Append a single array of integer(I4B) onto another. If the destination array is not allocated, or is not big enough, + !! this will allocate space for it. implicit none ! Arguments - integer(I4B), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at - !! arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + integer(I4B), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at arr(nold+1). + !! Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to ! Internals integer(I4B) :: nnew, nsrc, nend_orig @@ -497,17 +622,21 @@ end subroutine base_util_append_arr_I4B subroutine base_util_append_arr_logical(arr, source, nold, lsource_mask) - !! author: David A. Minton - !! - !! Append a single array of logical type onto another. If the destination array is not allocated, or is not big enough, - !! this will allocate space for it. + !! author: David A. Minton + !! + !! Append a single array of logical type onto another. If the destination array is not allocated, or is not big enough, + !! this will allocate space for it. implicit none ! Arguments - logical, dimension(:), allocatable, intent(inout) :: arr !! Destination array - logical, dimension(:), allocatable, intent(in) :: source !! Array to append - integer(I4B), intent(in), optional :: nold !! Extent of original array. If passed, the source array will begin at - !! arr(nold+1). Otherwise, the size of arr will be used. - logical, dimension(:), intent(in), optional :: lsource_mask !! Logical mask indicating which elements to append to + logical, dimension(:), allocatable, intent(inout) :: arr + !! Destination array + logical, dimension(:), allocatable, intent(in) :: source + !! Array to append + integer(I4B), intent(in), optional :: nold + !! Extent of original array. If passed, the source array will begin at arr(nold+1). + !! Otherwise, the size of arr will be used. + logical, dimension(:), intent(in), optional :: lsource_mask + !! Logical mask indicating which elements to append to ! Internals integer(I4B) :: nnew, nsrc, nend_orig @@ -544,12 +673,14 @@ end subroutine base_util_append_arr_logical subroutine base_util_copy_store(self, source) - !! author: David A. Minton - !! - !! Stores a snapshot of the nbody system so that later it can be retrieved for saving to file. + !! author: David A. Minton + !! + !! Stores a snapshot of the nbody system so that later it can be retrieved for saving to file. implicit none - class(base_storage_frame), intent(inout) :: self !! Swiftest storage frame object - class(*), intent(in) :: source !! Swiftest n-body system object + class(base_storage_frame), intent(inout) :: self + !! Swiftest storage frame object + class(*), intent(in) :: source + !! Swiftest n-body system object if (allocated(self%item)) deallocate(self%item) allocate(self%item, source=source) @@ -559,12 +690,13 @@ end subroutine base_util_copy_store subroutine base_util_dealloc_param(self) - !! author: David A. Minton - !! - !! Deallocates all allocatables + !! author: David A. Minton + !! + !! Deallocates all allocatables implicit none ! Arguments - class(base_parameters),intent(inout) :: self !! Collection of parameters + class(base_parameters),intent(inout) :: self + !! Collection of parameters if (allocated(self%seed)) deallocate(self%seed) @@ -573,12 +705,13 @@ end subroutine base_util_dealloc_param subroutine base_util_dealloc_storage(self) - !! author: David A. Minton - !! - !! Resets a storage object by deallocating all items and resetting the frame counter to 0 + !! author: David A. Minton + !! + !! Resets a storage object by deallocating all items and resetting the frame counter to 0 implicit none ! Arguments - class(base_storage), intent(inout) :: self !! Swiftest storage object + class(base_storage), intent(inout) :: self + !! Swiftest storage object call self%reset() if (allocated(self%frame)) deallocate(self%frame) @@ -589,12 +722,12 @@ end subroutine base_util_dealloc_storage subroutine base_util_exit(code,unit) - !! author: David A. Minton - !! - !! Print termination message and exit program - !! - !! Adapted from David E. Kaufmann's Swifter routine: base_util_exit.f90 - !! Adapted from Hal Levison's Swift routine base_util_exit.f + !! author: David A. Minton + !! + !! Print termination message and exit program + !! + !! Adapted from David E. Kaufmann's Swifter routine: base_util_exit.f90 + !! Adapted from Hal Levison's Swift routine base_util_exit.f implicit none ! Arguments integer(I4B), intent(in) :: code @@ -602,7 +735,7 @@ subroutine base_util_exit(code,unit) ! Internals character(*), parameter :: BAR = '("---------------------------------------------------")' character(*), parameter :: SUCCESS_MSG = '(/, "Normal termination of Swiftest (version ", A, ")")' - character(*), parameter :: FAIL_MSG = '(/, "Terminating Swiftest (version ", A, ") due to error!!")' + character(*), parameter :: FAIL_MSG = '(/, "Terminating Swiftest (version ", A, ") due to error!")' character(*), parameter :: USAGE_MSG = '("Usage: swiftest_driver ' // & '[{standard}|compact|progress]")' character(*), parameter :: HELP_MSG = USAGE_MSG @@ -634,16 +767,20 @@ end subroutine base_util_exit subroutine base_util_fill_arr_char_string(keeps, inserts, lfill_list) - !! author: David A. Minton - !! - !! Performs a fill operation on a single array of type character strings - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a fill operation on a single array of type character strings. + !! This is the inverse of a spill operation implicit none ! Arguments - character(len=STRMAX), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - character(len=STRMAX), dimension(:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the - !! keeps + character(len=STRMAX), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + character(len=STRMAX), dimension(:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the + + !! keeps if (.not.allocated(keeps) .or. .not.allocated(inserts)) return @@ -655,15 +792,18 @@ end subroutine base_util_fill_arr_char_string subroutine base_util_fill_arr_DP(keeps, inserts, lfill_list) - !! author: David A. Minton - !! - !! Performs a fill operation on a single array of type DP - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a fill operation on a single array of type DP. + !! This is the inverse of a spill operation implicit none ! Arguments - real(DP), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - real(DP), dimension(:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + real(DP), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + real(DP), dimension(:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps if (.not.allocated(keeps) .or. .not.allocated(inserts)) return @@ -675,15 +815,18 @@ end subroutine base_util_fill_arr_DP subroutine base_util_fill_arr_DPvec(keeps, inserts, lfill_list) - !! author: David A. Minton - !! - !! Performs a fill operation on a single array of DP vectors with shape (NDIM, n) - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a fill operation on a single array of DP vectors with shape (NDIM, n) + !! This is the inverse of a spill operation implicit none ! Arguments - real(DP), dimension(:,:), allocatable, intent(inout) :: keeps !! Array of values to keep - real(DP), dimension(:,:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + real(DP), dimension(:,:), allocatable, intent(inout) :: keeps + !! Array of values to keep + real(DP), dimension(:,:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps ! Internals integer(I4B) :: i @@ -699,15 +842,18 @@ end subroutine base_util_fill_arr_DPvec subroutine base_util_fill_arr_I4B(keeps, inserts, lfill_list) - !! author: David A. Minton - !! - !! Performs a fill operation on a single array of type I4B - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a fill operation on a single array of type I4B + !! This is the inverse of a spill operation implicit none ! Arguments - integer(I4B), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - integer(I4B), dimension(:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + integer(I4B), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + integer(I4B), dimension(:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps if (.not.allocated(keeps) .or. .not.allocated(inserts)) return @@ -719,15 +865,18 @@ end subroutine base_util_fill_arr_I4B subroutine base_util_fill_arr_logical(keeps, inserts, lfill_list) - !! author: David A. Minton - !! - !! Performs a fill operation on a single array of logicals - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a fill operation on a single array of logicals + !! This is the inverse of a spill operation implicit none ! Arguments - logical, dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - logical, dimension(:), allocatable, intent(in) :: inserts !! Array of values to insert into keep - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + logical, dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + logical, dimension(:), allocatable, intent(in) :: inserts + !! Array of values to insert into keep + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps if (.not.allocated(keeps) .or. .not.allocated(inserts)) return @@ -738,10 +887,10 @@ subroutine base_util_fill_arr_logical(keeps, inserts, lfill_list) end subroutine base_util_fill_arr_logical subroutine base_util_reset_storage(self) - !! author: David A. Minton - !! - !! Resets the storage object back to its original state by removing all of the saved items from the storage frames, but - !! does not deallocate the frames + !! author: David A. Minton + !! + !! Resets the storage object back to its original state by removing all of the saved items from the storage frames, but + !! does not deallocate the frames implicit none ! Arguments class(base_storage), intent(inout) :: self @@ -767,16 +916,20 @@ end subroutine base_util_reset_storage subroutine base_util_resize_arr_char_string(arr, nnew) - !! author: David A. Minton - !! - !! Resizes an array component of type character string. nnew = 0 will deallocate. + !! author: David A. Minton + !! + !! Resizes an array component of type character string. nnew = 0 will deallocate. implicit none ! Arguments - character(len=STRMAX), dimension(:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + character(len=STRMAX), dimension(:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size ! Internals - character(len=STRMAX), dimension(:), allocatable :: tmp !! Temp. storage array in case the input array is already allocated - integer(I4B) :: nold !! Old size + character(len=STRMAX), dimension(:), allocatable :: tmp + !! Temp. storage array in case the input array is already allocated + integer(I4B) :: nold + !! Old size if (nnew < 0) return @@ -811,16 +964,20 @@ end subroutine base_util_resize_arr_char_string subroutine base_util_resize_arr_DP(arr, nnew) - !! author: David A. Minton - !! - !! Resizes an array component of double precision type. Passing nnew = 0 will deallocate. + !! author: David A. Minton + !! + !! Resizes an array component of double precision type. Passing nnew = 0 will deallocate. implicit none ! Arguments - real(DP), dimension(:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + real(DP), dimension(:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size ! Internals - real(DP), dimension(:), allocatable :: tmp !! Temporary storage array in case the input array is already allocated - integer(I4B) :: nold !! Old size + real(DP), dimension(:), allocatable :: tmp + !! Temporary storage array in case the input array is already allocated + integer(I4B) :: nold + !! Old size real(DP), parameter :: init_val = 0.0_DP if (nnew < 0) return @@ -856,16 +1013,20 @@ end subroutine base_util_resize_arr_DP subroutine base_util_resize_arr_DPvec(arr, nnew) - !! author: David A. Minton - !! - !! Resizes an array component of double precision vectors of size (NDIM, n). Passing nnew = 0 will deallocate. + !! author: David A. Minton + !! + !! Resizes an array component of double precision vectors of size (NDIM, n). Passing nnew = 0 will deallocate. implicit none ! Arguments - real(DP), dimension(:,:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + real(DP), dimension(:,:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size ! Internals - real(DP), dimension(:,:), allocatable :: tmp !! Temporary storage array in case the input array is already allocated - integer(I4B) :: nold !! Old size + real(DP), dimension(:,:), allocatable :: tmp + !! Temporary storage array in case the input array is already allocated + integer(I4B) :: nold + !! Old size real(DP), dimension(NDIM), parameter :: init_val = 0.0_DP integer(I4B) :: i @@ -908,16 +1069,20 @@ end subroutine base_util_resize_arr_DPvec subroutine base_util_resize_arr_I4B(arr, nnew) - !! author: David A. Minton - !! - !! Resizes an array component of integer type. Passing nnew = 0 will deallocate. + !! author: David A. Minton + !! + !! Resizes an array component of integer type. Passing nnew = 0 will deallocate. implicit none ! Arguments - integer(I4B), dimension(:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + integer(I4B), dimension(:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size ! Internals - integer(I4B), dimension(:), allocatable :: tmp !! Temporary storage array in case the input array is already allocated - integer(I4B) :: nold !! Old size + integer(I4B), dimension(:), allocatable :: tmp + !! Temporary storage array in case the input array is already allocated + integer(I4B) :: nold + !! Old size integer(I4B), parameter :: init_val = -1 if (nnew < 0) return @@ -953,16 +1118,20 @@ end subroutine base_util_resize_arr_I4B subroutine base_util_resize_arr_logical(arr, nnew) - !! author: David A. Minton - !! - !! Resizes an array component of logical type. Passing nnew = 0 will deallocate. + !! author: David A. Minton + !! + !! Resizes an array component of logical type. Passing nnew = 0 will deallocate. implicit none ! Arguments - logical, dimension(:), allocatable, intent(inout) :: arr !! Array to resize - integer(I4B), intent(in) :: nnew !! New size + logical, dimension(:), allocatable, intent(inout) :: arr + !! Array to resize + integer(I4B), intent(in) :: nnew + !! New size ! Internals - logical, dimension(:), allocatable :: tmp !! Temporary storage array in case the input array is already allocated - integer(I4B) :: nold !! Old size + logical, dimension(:), allocatable :: tmp + !! Temporary storage array in case the input array is already allocated + integer(I4B) :: nold + !! Old size logical, parameter :: init_val = .false. if (nnew < 0) return @@ -998,13 +1167,15 @@ end subroutine base_util_resize_arr_logical subroutine base_util_resize_storage(self, nnew) - !! author: David A. Minton - !! - !! Checks the current size of a Swiftest against the requested size and resizes it if it is too small. + !! author: David A. Minton + !! + !! Checks the current size of a Swiftest against the requested size and resizes it if it is too small. implicit none ! Arguments - class(base_storage), intent(inout) :: self !! Storage object - integer(I4B), intent(in) :: nnew !! New size + class(base_storage), intent(inout) :: self + !! Storage object + integer(I4B), intent(in) :: nnew + !! New size ! Internals class(base_storage_frame), dimension(:), allocatable :: tmp integer(I4B) :: i, nold, nbig @@ -1028,13 +1199,15 @@ end subroutine base_util_resize_storage subroutine base_util_setup_storage(self, n) - !! author: David A. Minton - !! - !! Checks the current size of a Swiftest against the requested size and resizes it if it is too small. + !! author: David A. Minton + !! + !! Checks the current size of a Swiftest against the requested size and resizes it if it is too small. implicit none ! Arguments - class(base_storage), intent(inout) :: self !! Storage object - integer(I4B), intent(in) :: n !! New size + class(base_storage), intent(inout) :: self + !! Storage object + integer(I4B), intent(in) :: n + !! New size if (allocated(self%frame)) deallocate(self%frame) allocate(self%frame(n)) @@ -1045,18 +1218,20 @@ end subroutine base_util_setup_storage subroutine base_util_snapshot_save(self, snapshot) - !! author: David A. Minton - !! - !! Checks the current size of the storage object against the required size and extends it by a factor of 2 more than - !! requested if it is too small. - !! Note: The reason to extend it by a factor of 2 is for performance. When there are many enounters per step, resizing - !! every time you want to add an encounter takes significant computational effort. Resizing by a factor of 2 is a tradeoff - !! between performance (fewer resize calls) and memory managment. Memory usage grows by a factor of 2 each time it fills - !! up, but no more. + !! author: David A. Minton + !! + !! Checks the current size of the storage object against the required size and extends it by a factor of 2 more than + !! requested if it is too small. + !! Note: The reason to extend it by a factor of 2 is for performance. When there are many enounters per step, resizing + !! every time you want to add an encounter takes significant computational effort. Resizing by a factor of 2 is a tradeoff + !! between performance (fewer resize calls) and memory managment. Memory usage grows by a factor of 2 each time it fills + !! up, but no more. implicit none ! Arguments - class(base_storage), intent(inout) :: self !! Storage encounter storage object - class(*), intent(in) :: snapshot !! Object to snapshot + class(base_storage), intent(inout) :: self + !! Storage encounter storage object + class(*), intent(in) :: snapshot + !! Object to snapshot ! Internals integer(I4B) :: nnew, nold @@ -1076,22 +1251,24 @@ end subroutine base_util_snapshot_save subroutine base_util_spill_arr_char_string(keeps, discards, lspill_list, ldestructive) - !! author: David A. Minton - !! - !! Performs a spill operation on a single array of type character strings - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a spill operation on a single array of type character strings + !! This is the inverse of a spill operation implicit none ! Arguments - character(len=STRMAX), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - character(len=STRMAX), dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into - !! the discards - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not - !! this operation should alter the keeps - !! array or not + character(len=STRMAX), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + character(len=STRMAX), dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discards + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not ! Internals integer(I4B) :: nspill, nkeep, nlist - character(len=STRMAX), dimension(:), allocatable :: tmp !! Array of values to keep + character(len=STRMAX), dimension(:), allocatable :: tmp + !! Array of values to keep nkeep = count(.not.lspill_list(:)) nspill = count(lspill_list(:)) @@ -1122,20 +1299,26 @@ end subroutine base_util_spill_arr_char_string subroutine base_util_spill_arr_DP(keeps, discards, lspill_list, ldestructive) - !! author: David A. Minton - !! - !! Performs a spill operation on a single array of type DP - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a spill operation on a single array of type DP + !! This is the inverse of a spill operation implicit none ! Arguments - real(DP), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - real(DP), dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discardss - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation - !! should alter the keeps array or not + real(DP), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + real(DP), dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discardss + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation + + !! should alter the keeps array or not ! Internals integer(I4B) :: nspill, nkeep, nlist - real(DP), dimension(:), allocatable :: tmp !! Array of values to keep + real(DP), dimension(:), allocatable :: tmp + !! Array of values to keep nkeep = count(.not.lspill_list(:)) nspill = count(lspill_list(:)) @@ -1166,20 +1349,24 @@ end subroutine base_util_spill_arr_DP subroutine base_util_spill_arr_DPvec(keeps, discards, lspill_list, ldestructive) - !! author: David A. Minton - !! - !! Performs a spill operation on a single array of DP vectors with shape (NDIM, n) - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a spill operation on a single array of DP vectors with shape (NDIM, n) + !! This is the inverse of a spill operation implicit none ! Arguments - real(DP), dimension(:,:), allocatable, intent(inout) :: keeps !! Array of values to keep - real(DP), dimension(:,:), allocatable, intent(inout) :: discards !! Array discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discards - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this - !! operation should alter the keeps array or not + real(DP), dimension(:,:), allocatable, intent(inout) :: keeps + !! Array of values to keep + real(DP), dimension(:,:), allocatable, intent(inout) :: discards + !! Array discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discards + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not ! Internals integer(I4B) :: i, nspill, nkeep, nlist - real(DP), dimension(:,:), allocatable :: tmp !! Array of values to keep + real(DP), dimension(:,:), allocatable :: tmp + !! Array of values to keep nkeep = count(.not.lspill_list(:)) nspill = count(lspill_list(:)) @@ -1214,20 +1401,24 @@ end subroutine base_util_spill_arr_DPvec subroutine base_util_spill_arr_I4B(keeps, discards, lspill_list, ldestructive) - !! author: David A. Minton - !! - !! Performs a spill operation on a single array of type I4B - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a spill operation on a single array of type I4B + !! This is the inverse of a spill operation implicit none ! Arguments - integer(I4B), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - integer(I4B), dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discards - logical, intent(in) :: ldestructive!! Logical flag indicating whether or not this - !! operation should alter the keeps array or not + integer(I4B), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + integer(I4B), dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discards + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter the keeps array or not ! Internals integer(I4B) :: nspill, nkeep, nlist - integer(I4B), dimension(:), allocatable :: tmp !! Array of values to keep + integer(I4B), dimension(:), allocatable :: tmp + !! Array of values to keep nkeep = count(.not.lspill_list(:)) nspill = count(lspill_list(:)) @@ -1258,20 +1449,26 @@ end subroutine base_util_spill_arr_I4B subroutine base_util_spill_arr_I8B(keeps, discards, lspill_list, ldestructive) - !! author: David A. Minton - !! - !! Performs a spill operation on a single array of type I4B - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a spill operation on a single array of type I4B + !! This is the inverse of a spill operation implicit none ! Arguments - integer(I8B), dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - integer(I8B), dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discards - logical, intent(in) :: ldestructive!! Logical flag indicating whether or not this - !! operation should alter the keeps array or not + integer(I8B), dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + integer(I8B), dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discards + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this + + !! operation should alter the keeps array or not ! Internals integer(I4B) :: nspill, nkeep, nlist - integer(I8B), dimension(:), allocatable :: tmp !! Array of values to keep + integer(I8B), dimension(:), allocatable :: tmp + !! Array of values to keep nkeep = count(.not.lspill_list(:)) nspill = count(lspill_list(:)) @@ -1302,20 +1499,26 @@ end subroutine base_util_spill_arr_I8B subroutine base_util_spill_arr_logical(keeps, discards, lspill_list, ldestructive) - !! author: David A. Minton - !! - !! Performs a spill operation on a single array of logicals - !! This is the inverse of a spill operation + !! author: David A. Minton + !! + !! Performs a spill operation on a single array of logicals + !! This is the inverse of a spill operation implicit none ! Arguments - logical, dimension(:), allocatable, intent(inout) :: keeps !! Array of values to keep - logical, dimension(:), allocatable, intent(inout) :: discards !! Array of discards - logical, dimension(:), intent(in) :: lspill_list !! Logical array of bodies to spill into the discards - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation - !! should alter the keeps array or no + logical, dimension(:), allocatable, intent(inout) :: keeps + !! Array of values to keep + logical, dimension(:), allocatable, intent(inout) :: discards + !! Array of discards + logical, dimension(:), intent(in) :: lspill_list + !! Logical array of bodies to spill into the discards + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation + + !! should alter the keeps array or no ! Internals integer(I4B) :: nspill, nkeep, nlist - logical, dimension(:), allocatable :: tmp !! Array of values to keep + logical, dimension(:), allocatable :: tmp + !! Array of values to keep nkeep = count(.not.lspill_list(:)) nspill = count(lspill_list(:)) @@ -1346,10 +1549,9 @@ end subroutine base_util_spill_arr_logical pure subroutine base_util_sort_dp(arr) - !! author: David A. Minton - !! - !! Sort input DP precision array in place into ascending numerical order using quicksort. - !! + !! author: David A. Minton + !! + !! Sort input DP precision array in place into ascending numerical order using quicksort. implicit none ! Arguments real(DP), dimension(:), intent(inout) :: arr @@ -1361,13 +1563,12 @@ end subroutine base_util_sort_dp pure subroutine base_util_sort_index_dp(arr, ind) - !! author: David A. Minton - !! - !! Sort input DP precision array by index in ascending numerical order using quick sort. - !! This algorithm works well for partially sorted arrays (which is usually the case here). - !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously - !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. - !! + !! author: David A. Minton + !! + !! Sort input DP precision array by index in ascending numerical order using quick sort. + !! This algorithm works well for partially sorted arrays (which is usually the case here). + !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously + !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. implicit none ! Arguments real(DP), dimension(:), intent(in) :: arr @@ -1390,15 +1591,15 @@ end subroutine base_util_sort_index_dp recursive pure subroutine base_util_sort_qsort_DP(arr, ind) - !! author: David A. Minton - !! - !! Sort input DP precision array by index in ascending numerical order using quicksort sort. - !! + !! author: David A. Minton + !! + !! Sort input DP precision array by index in ascending numerical order using quicksort sort. implicit none ! Arguments real(DP), dimension(:), intent(inout) :: arr integer(I4B),dimension(:),intent(out), optional :: ind - !! Internals + + !! Internals integer :: iq if (size(arr) > 1) then @@ -1418,10 +1619,10 @@ end subroutine base_util_sort_qsort_DP pure subroutine base_util_sort_partition_DP(arr, marker, ind) - !! author: David A. Minton - !! - !! Partition function for quicksort on DP type - !! + !! author: David A. Minton + !! + !! Partition function for quicksort on DP type + !! implicit none ! Arguments real(DP), intent(inout), dimension(:) :: arr @@ -1475,11 +1676,10 @@ end subroutine base_util_sort_partition_DP pure subroutine base_util_sort_i4b(arr) - !! author: David A. Minton - !! - !! Sort input integer array in place into ascending numerical order using quick sort. - !! This algorithm works well for partially sorted arrays (which is usually the case here) - !! + !! author: David A. Minton + !! + !! Sort input integer array in place into ascending numerical order using quick sort. + !! This algorithm works well for partially sorted arrays (which is usually the case here) implicit none ! Arguments integer(I4B), dimension(:), intent(inout) :: arr @@ -1491,12 +1691,11 @@ end subroutine base_util_sort_i4b pure subroutine base_util_sort_index_I4B(arr, ind) - !! author: David A. Minton - !! - !! Sort input integer array by index in ascending numerical order using quicksort. - !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously - !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. - !! + !! author: David A. Minton + !! + !! Sort input integer array by index in ascending numerical order using quicksort. + !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously + !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. implicit none ! Arguments integer(I4B), dimension(:), intent(in) :: arr @@ -1519,12 +1718,11 @@ end subroutine base_util_sort_index_I4B pure subroutine base_util_sort_index_I4B_I8Bind(arr, ind) - !! author: David A. Minton - !! - !! Sort input integer array by index in ascending numerical order using quicksort. - !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously - !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. - !! + !! author: David A. Minton + !! + !! Sort input integer array by index in ascending numerical order using quicksort. + !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously + !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. implicit none ! Arguments integer(I4B), dimension(:), intent(in) :: arr @@ -1547,12 +1745,11 @@ end subroutine base_util_sort_index_I4B_I8Bind pure subroutine base_util_sort_index_I8B_I8Bind(arr, ind) - !! author: David A. Minton - !! - !! Sort input integer array by index in ascending numerical order using quicksort. - !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously - !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. - !! + !! author: David A. Minton + !! + !! Sort input integer array by index in ascending numerical order using quicksort. + !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously + !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. implicit none ! Arguments integer(I8B), dimension(:), intent(in) :: arr @@ -1575,10 +1772,9 @@ end subroutine base_util_sort_index_I8B_I8Bind recursive pure subroutine base_util_sort_qsort_I4B(arr, ind) - !! author: David A. Minton - !! - !! Sort input I4B array by index in ascending numerical order using quicksort. - !! + !! author: David A. Minton + !! + !! Sort input I4B array by index in ascending numerical order using quicksort. implicit none ! Arguments integer(I4B), dimension(:), intent(inout) :: arr @@ -1603,10 +1799,10 @@ end subroutine base_util_sort_qsort_I4B recursive pure subroutine base_util_sort_qsort_I4B_I8Bind(arr, ind) - !! author: David A. Minton - !! - !! Sort input I4B array by index in ascending numerical order using quicksort. - !! + !! author: David A. Minton + !! + !! Sort input I4B array by index in ascending numerical order using quicksort. + !! implicit none ! Arguments integer(I4B), dimension(:), intent(inout) :: arr @@ -1631,10 +1827,9 @@ end subroutine base_util_sort_qsort_I4B_I8Bind recursive pure subroutine base_util_sort_qsort_I8B_I8Bind(arr, ind) - !! author: David A. Minton - !! - !! Sort input I8B array by index in ascending numerical order using quicksort. - !! + !! author: David A. Minton + !! + !! Sort input I8B array by index in ascending numerical order using quicksort. implicit none ! Arguments integer(I8B), dimension(:), intent(inout) :: arr @@ -1659,10 +1854,14 @@ end subroutine base_util_sort_qsort_I8B_I8Bind pure subroutine base_util_sort_partition_I4B(arr, marker, ind) - !! author: David A. Minton - !! - !! Partition function for quicksort on I4B type - !! + + !! author: David A. Minton + + !! + + !! Partition function for quicksort on I4B type + + !! implicit none ! Arguments integer(I4B), intent(inout), dimension(:) :: arr @@ -1716,10 +1915,9 @@ end subroutine base_util_sort_partition_I4B pure subroutine base_util_sort_partition_I4B_I8Bind(arr, marker, ind) - !! author: David A. Minton - !! - !! Partition function for quicksort on I4B type - !! + !! author: David A. Minton + !! + !! Partition function for quicksort on I4B type implicit none ! Arguments integer(I4B), intent(inout), dimension(:) :: arr @@ -1773,10 +1971,9 @@ end subroutine base_util_sort_partition_I4B_I8Bind pure subroutine base_util_sort_partition_I8B_I8Bind(arr, marker, ind) - !! author: David A. Minton - !! - !! Partition function for quicksort on I8B type with I8B index - !! + !! author: David A. Minton + !! + !! Partition function for quicksort on I8B type with I8B index implicit none ! Arguments integer(I8B), intent(inout), dimension(:) :: arr @@ -1830,10 +2027,10 @@ end subroutine base_util_sort_partition_I8B_I8Bind pure subroutine base_util_sort_sp(arr) - !! author: David A. Minton - !! - !! Sort input DP precision array in place into ascending numerical order using quicksort. - !! + !! author: David A. Minton + !! + !! Sort input DP precision array in place into ascending numerical order using quicksort. + !! implicit none ! Arguments real(SP), dimension(:), intent(inout) :: arr @@ -1845,12 +2042,11 @@ end subroutine base_util_sort_sp pure subroutine base_util_sort_index_sp(arr, ind) - !! author: David A. Minton - !! - !! Sort input DP precision array by index in ascending numerical order using quicksort. - !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously - !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. - !! + !! author: David A. Minton + !! + !! Sort input DP precision array by index in ascending numerical order using quicksort. + !! If ind is supplied already allocated, we assume it is an existing index array (e.g. a previously + !! sorted array). If it is not allocated, this subroutine swiftest_allocates it. implicit none ! Arguments real(SP), dimension(:), intent(in) :: arr @@ -1873,15 +2069,15 @@ end subroutine base_util_sort_index_sp recursive pure subroutine base_util_sort_qsort_SP(arr, ind) - !! author: David A. Minton - !! - !! Sort input DP precision array by index in ascending numerical order using quicksort. - !! + !! author: David A. Minton + !! + !! Sort input DP precision array by index in ascending numerical order using quicksort. implicit none ! Arguments real(SP), dimension(:), intent(inout) :: arr integer(I4B),dimension(:),intent(out), optional :: ind - !! Internals + + ! Internals integer :: iq if (size(arr) > 1) then @@ -1901,10 +2097,9 @@ end subroutine base_util_sort_qsort_SP pure subroutine base_util_sort_partition_SP(arr, marker, ind) - !! author: David A. Minton - !! - !! Partition function for quicksort on SP type - !! + !! author: David A. Minton + !! + !! Partition function for quicksort on SP type implicit none ! Arguments real(SP), intent(inout), dimension(:) :: arr @@ -1958,16 +2153,20 @@ end subroutine base_util_sort_partition_SP pure subroutine base_util_sort_rearrange_arr_char_string(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of character string in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of character string in-place from an index list. implicit none ! Arguments - character(len=STRMAX), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + character(len=STRMAX), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - character(len=STRMAX), dimension(:), allocatable :: tmp !! Temporary copy of arry used during rearrange operation + character(len=STRMAX), dimension(:), allocatable :: tmp + !! Temporary copy of arry used during rearrange operation if (.not. allocated(arr) .or. n <= 0) return allocate(tmp, mold=arr) @@ -1979,16 +2178,20 @@ end subroutine base_util_sort_rearrange_arr_char_string pure subroutine base_util_sort_rearrange_arr_DP(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of DP type in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of DP type in-place from an index list. implicit none ! Arguments - real(DP), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + real(DP), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - real(DP), dimension(:), allocatable :: tmp !! Temporary copy of array used during rearrange operation + real(DP), dimension(:), allocatable :: tmp + !! Temporary copy of array used during rearrange operation if (.not. allocated(arr) .or. n <= 0) return allocate(tmp, mold=arr) @@ -2000,16 +2203,20 @@ end subroutine base_util_sort_rearrange_arr_DP pure subroutine base_util_sort_rearrange_arr_DPvec(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of (NDIM,n) DP-type vectors in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of (NDIM,n) DP-type vectors in-place from an index list. implicit none ! Arguments - real(DP), dimension(:,:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + real(DP), dimension(:,:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - real(DP), dimension(:,:), allocatable :: tmp !! Temporary copy of array used during rearrange operation + real(DP), dimension(:,:), allocatable :: tmp + !! Temporary copy of array used during rearrange operation if (.not. allocated(arr) .or. n <= 0) return allocate(tmp, mold=arr) @@ -2021,16 +2228,20 @@ end subroutine base_util_sort_rearrange_arr_DPvec pure subroutine base_util_sort_rearrange_arr_I4B(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of integers in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of integers in-place from an index list. implicit none ! Arguments - integer(I4B), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + integer(I4B), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - integer(I4B), dimension(:), allocatable :: tmp !! Temporary copy of array used during rearrange operation + integer(I4B), dimension(:), allocatable :: tmp + !! Temporary copy of array used during rearrange operation if (.not. allocated(arr) .or. n <= 0) return allocate(tmp, mold=arr) @@ -2041,16 +2252,20 @@ pure subroutine base_util_sort_rearrange_arr_I4B(arr, ind, n) end subroutine base_util_sort_rearrange_arr_I4B pure subroutine base_util_sort_rearrange_arr_I4B_I8Bind(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of integers in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of integers in-place from an index list. implicit none ! Arguments - integer(I4B), dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I8B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I8B), intent(in) :: n !! Number of elements in arr and ind to rearrange + integer(I4B), dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I8B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I8B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - integer(I4B), dimension(:), allocatable :: tmp !! Temporary copy of array used during rearrange operation + integer(I4B), dimension(:), allocatable :: tmp + !! Temporary copy of array used during rearrange operation if (.not. allocated(arr) .or. n <= 0_I8B) return allocate(tmp, mold=arr) @@ -2062,16 +2277,20 @@ end subroutine base_util_sort_rearrange_arr_I4B_I8Bind pure subroutine base_util_sort_rearrange_arr_logical_I8Bind(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of logicals in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of logicals in-place from an index list. implicit none ! Arguments - logical, dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I8B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I8B), intent(in) :: n !! Number of elements in arr and ind to rearrange + logical, dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I8B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I8B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - logical, dimension(:), allocatable :: tmp !! Temporary copy of array used during rearrange operation + logical, dimension(:), allocatable :: tmp + !! Temporary copy of array used during rearrange operation if (.not. allocated(arr) .or. n <= 0) return allocate(tmp, mold=arr) @@ -2083,16 +2302,20 @@ end subroutine base_util_sort_rearrange_arr_logical_I8Bind pure subroutine base_util_sort_rearrange_arr_logical(arr, ind, n) - !! author: David A. Minton - !! - !! Rearrange a single array of logicals in-place from an index list. + !! author: David A. Minton + !! + !! Rearrange a single array of logicals in-place from an index list. implicit none ! Arguments - logical, dimension(:), allocatable, intent(inout) :: arr !! Destination array - integer(I4B), dimension(:), intent(in) :: ind !! Index to rearrange against - integer(I4B), intent(in) :: n !! Number of elements in arr and ind to rearrange + logical, dimension(:), allocatable, intent(inout) :: arr + !! Destination array + integer(I4B), dimension(:), intent(in) :: ind + !! Index to rearrange against + integer(I4B), intent(in) :: n + !! Number of elements in arr and ind to rearrange ! Internals - logical, dimension(:), allocatable :: tmp !! Temporary copy of array used during rearrange operation + logical, dimension(:), allocatable :: tmp + !! Temporary copy of array used during rearrange operation if (.not. allocated(arr) .or. n <= 0) return allocate(tmp, mold=arr) @@ -2104,16 +2327,18 @@ end subroutine base_util_sort_rearrange_arr_logical subroutine base_util_unique_DP(input_array, output_array, index_map) - !! author: David A. Minton - !! - !! Takes an input unsorted integer array and returns a new array of sorted, unique values (DP version) + !! author: David A. Minton + !! + !! Takes an input unsorted integer array and returns a new array of sorted, unique values (DP version) implicit none ! Arguments - real(DP), dimension(:), intent(in) :: input_array !! Unsorted input array - real(DP), dimension(:), allocatable, intent(out) :: output_array !! Sorted array of unique values - integer(I4B), dimension(:), allocatable, intent(out) :: index_map !! An array of the same size as input_array that such - !! that any for any index i, - !! output_array(index_map(i)) = input_array(i) + real(DP), dimension(:), intent(in) :: input_array + !! Unsorted input array + real(DP), dimension(:), allocatable, intent(out) :: output_array + !! Sorted array of unique values + integer(I4B), dimension(:), allocatable, intent(out) :: index_map + !! An array of the same size as input_array that such that any for any index i, + !! output_array(index_map(i)) = input_array(i) ! Internals real(DP), dimension(:), allocatable :: unique_array integer(I4B) :: n @@ -2139,16 +2364,18 @@ end subroutine base_util_unique_DP subroutine base_util_unique_I4B(input_array, output_array, index_map) - !! author: David A. Minton - !! + !! author: David A. Minton + !! !! Takes an input unsorted integer array and returns a new array of sorted, unique values (I4B version) implicit none ! Arguments - integer(I4B), dimension(:), intent(in) :: input_array !! Unsorted input array - integer(I4B), dimension(:), allocatable, intent(out) :: output_array !! Sorted array of unique values - integer(I4B), dimension(:), allocatable, intent(out) :: index_map !! An array of the same size as input_array that such - !! that any for any index i, - !! output_array(index_map(i)) = input_array(i) + integer(I4B), dimension(:), intent(in) :: input_array + !! Unsorted input array + integer(I4B), dimension(:), allocatable, intent(out) :: output_array + !! Sorted array of unique values + integer(I4B), dimension(:), allocatable, intent(out) :: index_map + !! An array of the same size as input_array that such that any for any index i, + !! output_array(index_map(i)) = input_array(i) ! Internals integer(I4B), dimension(:), allocatable :: unique_array integer(I4B) :: n, lo, hi @@ -2173,9 +2400,9 @@ end subroutine base_util_unique_I4B subroutine base_final_storage(self) - !! author: David A. Minton - !! - !! Finalizer for the storage object + !! author: David A. Minton + !! + !! Finalizer for the storage object implicit none ! Arguments class(base_storage), intent(inout) :: self @@ -2186,9 +2413,9 @@ end subroutine base_final_storage subroutine base_final_storage_frame(self) - !! author: David A. Minton - !! - !! Finalizer for the storage frame data type + !! author: David A. Minton + !! + !! Finalizer for the storage frame data type implicit none type(base_storage_frame) :: self @@ -2199,12 +2426,13 @@ end subroutine base_final_storage_frame #ifdef COARRAY subroutine base_coclone_param(self) - !! author: David A. Minton - !! - !! Broadcasts the image 1 parameter to all other images in a parameter coarray + !! author: David A. Minton + !! + !! Broadcasts the image 1 parameter to all other images in a parameter coarray implicit none ! Arguments - class(base_parameters),intent(inout),codimension[*] :: self !! Collection of parameters + class(base_parameters),intent(inout),codimension[*] :: self + !! Collection of parameters ! Internals call coclone(self%integrator) From dfa48e14e4499c059b1884216bc710cc0a30b180 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 12:21:25 -0500 Subject: [PATCH 250/324] Restructured the code so that the spherical harmonics code is its own small module. Also refactored loblatecb to lnon_spherical_cb and now select which accelration model to use based on whether cb%c_lm is allocated or not. --- src/CMakeLists.txt | 2 +- src/base/base_module.f90 | 4 +- src/helio/helio_kick.f90 | 6 +- src/rmvs/rmvs_kick.f90 | 5 +- src/rmvs/rmvs_step.f90 | 20 +-- .../shgrav_accel.f90} | 148 ++++++++---------- src/shgrav/shgrav_module.f90 | 11 ++ src/swiftest/swiftest_io.f90 | 6 +- src/swiftest/swiftest_module.f90 | 10 +- src/swiftest/swiftest_obl.f90 | 22 ++- src/swiftest/swiftest_util.f90 | 4 +- src/whm/whm_kick.f90 | 12 +- 12 files changed, 123 insertions(+), 127 deletions(-) rename src/{swiftest/swiftest_sph.f90 => shgrav/shgrav_accel.f90} (50%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bec5aa743..89eaadeee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,7 @@ SET(STRICT_MATH_FILES ${SRC}/operator/operator_unit.f90 ${SRC}/rmvs/rmvs_kick.f90 ${SRC}/rmvs/rmvs_step.f90 + ${SRC}/shgrav/shgrav_accel.f90 ${SRC}/swiftest/swiftest_drift.f90 ${SRC}/swiftest/swiftest_gr.f90 ${SRC}/swiftest/swiftest_io.f90 @@ -40,7 +41,6 @@ SET(STRICT_MATH_FILES ${SRC}/swiftest/swiftest_user.f90 ${SRC}/swiftest/swiftest_obl.f90 ${SRC}/swiftest/swiftest_orbel.f90 - ${SRC}/swiftest/swiftest_sph.f90 ${SRC}/symba/symba_drift.f90 ${SRC}/symba/symba_gr.f90 ${SRC}/symba/symba_kick.f90 diff --git a/src/base/base_module.f90 b/src/base/base_module.f90 index ab3c77a0d..705e90c5f 100644 --- a/src/base/base_module.f90 +++ b/src/base/base_module.f90 @@ -152,7 +152,7 @@ module base !! Turn on close encounters logical :: lenergy = .false. !! Track the total energy of the system - logical :: loblatecb = .false. + logical :: lnon_spherical_cb = .false. !! Calculate acceleration from oblate central body (automatically turns true if nonzero J2, J4, or c_lm is input) logical :: lrotation = .false. !! Include rotation states of big bodies @@ -2489,7 +2489,7 @@ subroutine base_coclone_param(self) call coclone(self%lbig_discard) call coclone(self%lclose) call coclone(self%lenergy) - call coclone(self%loblatecb) + call coclone(self%lnon_spherical_cb) call coclone(self%lrotation) call coclone(self%ltides) call coclone(self%E_orbit_orig) diff --git a/src/helio/helio_kick.f90 b/src/helio/helio_kick.f90 index 0552d9168..6740e0eb0 100644 --- a/src/helio/helio_kick.f90 +++ b/src/helio/helio_kick.f90 @@ -30,8 +30,8 @@ module subroutine helio_kick_getacch_pl(self, nbody_system, param, t, lbeg) associate(cb => nbody_system%cb, pl => self, npl => self%nbody) call pl%accel_int(param) - if (param%loblatecb) then - call pl%accel_obl(nbody_system) + if (param%lnon_spherical_cb) then + call pl%accel_non_spherical_cb(nbody_system) if (lbeg) then cb%aoblbeg = cb%aobl else @@ -79,7 +79,7 @@ module subroutine helio_kick_getacch_tp(self, nbody_system, param, t, lbeg) else call tp%accel_int(param, pl%Gmass(1:npl), pl%rend(:,1:npl), npl) end if - if (param%loblatecb) call tp%accel_obl(nbody_system) + if (param%lnon_spherical_cb) call tp%accel_non_spherical_cb(nbody_system) if (param%lextra_force) call tp%accel_user(nbody_system, param, t, lbeg) if (param%lgr) call tp%accel_gr(param) end associate diff --git a/src/rmvs/rmvs_kick.f90 b/src/rmvs/rmvs_kick.f90 index 3dd92ef60..b51b94737 100644 --- a/src/rmvs/rmvs_kick.f90 +++ b/src/rmvs/rmvs_kick.f90 @@ -52,8 +52,7 @@ module subroutine rmvs_kick_getacch_tp(self, nbody_system, param, t, lbeg) ! Temporarily turn off the heliocentric-dependent acceleration terms during an inner encounter using a copy of the parameter list with all of the heliocentric-specific acceleration terms turned off allocate(param_planetocen, source=param) - param_planetocen%loblatecb = .false. - param_planetocen%lshgrav = .false. + param_planetocen%lnon_spherical_cb = .false. param_planetocen%lextra_force = .false. param_planetocen%lgr = .false. @@ -91,7 +90,7 @@ module subroutine rmvs_kick_getacch_tp(self, nbody_system, param, t, lbeg) cb%Gmass = tp%cb_heliocentric%Gmass ! If the heliocentric-specifc acceleration terms are requested, compute those now - if (param%loblatecb) call tp%accel_obl(system_planetocen) + if (param%lnon_spherical_cb) call tp%accel_non_spherical_cb(system_planetocen) if (param%lextra_force) call tp%accel_user(system_planetocen, param, t, lbeg) if (param%lgr) call tp%accel_gr(param) diff --git a/src/rmvs/rmvs_step.f90 b/src/rmvs/rmvs_step.f90 index 04fadb74b..757ceb418 100644 --- a/src/rmvs/rmvs_step.f90 +++ b/src/rmvs/rmvs_step.f90 @@ -202,7 +202,7 @@ subroutine rmvs_step_out(cb, pl, tp, nbody_system, param, t, dt) call tp%step(nbody_system, param, outer_time, dto) tp%lfirst = lfirsttp else - if (param%loblatecb) then + if (param%lnon_spherical_cb) then call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rbeg, pl%lmask, pl%outer(outer_index-1)%aobl, cb%rot,& pl%Gmass, cb%aoblbeg) call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rend, pl%lmask, pl%outer(outer_index)%aobl, cb%rot, & @@ -267,14 +267,14 @@ subroutine rmvs_interp_in(cb, pl, nbody_system, param, dt, outer_index) xtmp(:, 1:npl) = pl%inner(0)%x(:, 1:npl) vtmp(:, 1:npl) = pl%inner(0)%v(:, 1:npl) - if ((param%loblatecb) .or. (param%ltides)) then + if ((param%lnon_spherical_cb) .or. (param%ltides)) then allocate(rh_original, source=pl%rh) allocate(ah_original, source=pl%ah) pl%rh(:, 1:npl) = xtmp(:, 1:npl) ! Temporarily replace heliocentric position with inner substep values to calculate the ! oblateness terms end if - if (param%loblatecb) then - call pl%accel_obl(nbody_system) + if (param%lnon_spherical_cb) then + call pl%accel_non_spherical_cb(nbody_system) pl%inner(0)%aobl(:, 1:npl) = pl%aobl(:, 1:npl) ! Save the oblateness acceleration on the planet for this substep end if ! TODO: Implement tides @@ -328,9 +328,9 @@ subroutine rmvs_interp_in(cb, pl, nbody_system, param, dt, outer_index) pl%inner(inner_index)%x(:, 1:npl) = pl%inner(inner_index)%x(:, 1:npl) + frac * xtmp(:, 1:npl) pl%inner(inner_index)%v(:, 1:npl) = pl%inner(inner_index)%v(:, 1:npl) + frac * vtmp(:, 1:npl) - if (param%loblatecb) then + if (param%lnon_spherical_cb) then pl%rh(:,1:npl) = pl%inner(inner_index)%x(:, 1:npl) - call pl%accel_obl(nbody_system) + call pl%accel_non_spherical_cb(nbody_system) pl%inner(inner_index)%aobl(:, 1:npl) = pl%aobl(:, 1:npl) end if ! TODO: Implement tides @@ -339,10 +339,10 @@ subroutine rmvs_interp_in(cb, pl, nbody_system, param, dt, outer_index) ! pl%inner(inner_index)%atide(:, 1:npl) = pl%atide(:, 1:npl) ! end if end do - if (param%loblatecb) then + if (param%lnon_spherical_cb) then ! Calculate the final value of oblateness accelerations at the final inner substep pl%rh(:, 1:npl) = pl%inner(NTPHENC)%x(:, 1:npl) - call pl%accel_obl(nbody_system) + call pl%accel_non_spherical_cb(nbody_system) pl%inner(NTPHENC)%aobl(:, 1:npl) = pl%aobl(:, 1:npl) end if ! TODO: Implement tides @@ -405,7 +405,7 @@ subroutine rmvs_step_in(cb, pl, tp, param, outer_time, dto) call plenci%set_beg_end(rbeg = plenci%inner(inner_index - 1)%x, & rend = plenci%inner(inner_index)%x) - if (param%loblatecb) then + if (param%lnon_spherical_cb) then cbenci%aoblbeg = cbenci%inner(inner_index - 1)%aobl(:, 1) cbenci%aoblend = cbenci%inner(inner_index )%aobl(:, 1) end if @@ -495,7 +495,7 @@ subroutine rmvs_make_planetocentric(param, cb, pl, tp) plenci%inner(inner_index)%x(:,1) = -cbenci%inner(inner_index)%x(:,1) plenci%inner(inner_index)%v(:,1) = -cbenci%inner(inner_index)%v(:,1) - if (param%loblatecb) then + if (param%lnon_spherical_cb) then allocate(plenci%inner(inner_index)%aobl, mold=pl%inner(inner_index)%aobl) allocate(cbenci%inner(inner_index)%aobl(NDIM,1)) cbenci%inner(inner_index)%aobl(:,1) = pl%inner(inner_index)%aobl(:, i) diff --git a/src/swiftest/swiftest_sph.f90 b/src/shgrav/shgrav_accel.f90 similarity index 50% rename from src/swiftest/swiftest_sph.f90 rename to src/shgrav/shgrav_accel.f90 index 3bdc1fceb..cd26f2567 100644 --- a/src/swiftest/swiftest_sph.f90 +++ b/src/shgrav/shgrav_accel.f90 @@ -10,41 +10,58 @@ !! Swiftest submodule to calculate higher order terms for gravitational acceleration given spherical harmonic coefficients (c_lm) -submodule (swiftest) s_swiftest_sph -use operators +submodule (shgrav) s_shgrav_accel +use swiftest use SHTOOLS contains - module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) + subroutine shgrav_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMpl, aoblcb) !! author: Kaustub P. Anand !! !! Calculate the acceleration terms for one pair of bodies given c_lm, theta, phi, r - !! - implicit none ! Arguments - real(DP), intent(in) :: GMcb !! GMass of the central body - real(DP), intent(in) :: r_0 !! radius of the central body - real(DP), intent(in) :: phi_cb !! rotation phase angle of the central body - real(DP), intent(in), dimension(:) :: rh !! distance vector of body - real(DP), intent(in), dimension(:, :, :) :: c_lm !! Spherical Harmonic coefficients - real(DP), intent(out), dimension(NDIM) :: g_sph !! acceleration vector - real(DP), intent(in), optional :: GMpl !! Mass of input body if it is not a test particle - real(DP), dimension(:), intent(inout), optional :: aoblcb!! Barycentric acceleration of central body (only for massive input bodies) + real(DP), intent(in) :: GMcb + !! GMass of the central body + real(DP), intent(in) :: r_0 + !! radius of the central body + real(DP), intent(in) :: phi_cb + !! rotation phase angle of the central body + real(DP), intent(in), dimension(:) :: rh + !! distance vector of body + real(DP), intent(in), dimension(:, :, :) :: c_lm + !! Spherical Harmonic coefficients + real(DP), intent(out), dimension(NDIM) :: g_sph + !! acceleration vector + real(DP), intent(in), optional :: GMpl + !! Mass of input body if it is not a test particle + real(DP), dimension(:), intent(inout), optional :: aoblcb + !! Barycentric acceleration of central body (only for massive input bodies) ! Internals - integer :: l, m !! SPH coefficients - integer :: l_max !! max Spherical Harmonic l order value - integer(I4B) :: N, lmindex !! Length of Legendre polynomials and index at a given l, m - real(DP) :: r_mag !! magnitude of rh - real(DP) :: phi, phi_bar !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase - real(DP) :: theta !! Inclination/Zenith angle (radians) - real(DP) :: plm, plm1 !! Associated Legendre polynomials at a given l, m - real(DP) :: ccss, cssc !! See definition in source code - real(DP) :: cos_theta, sin_theta !! cos(theta) and sin(theta) - real(DP), dimension(:), allocatable :: p !! Associated Lengendre Polynomials at a given cos(theta) - real(DP) :: fac1, fac2, r_fac !! calculation factors + integer :: l, m + !! SPH coefficients + integer :: l_max + !! max Spherical Harmonic l order value + integer(I4B) :: N, lmindex + !! Length of Legendre polynomials and index at a given l, m + real(DP) :: r_mag + !! magnitude of rh + real(DP) :: phi, phi_bar + !! Azimuthal/Phase angle (radians) wrt coordinate axes, and central body rotation phase + real(DP) :: theta + !! Inclination/Zenith angle (radians) + real(DP) :: plm, plm1 + !! Associated Legendre polynomials at a given l, m + real(DP) :: ccss, cssc + !! See definition in source code + real(DP) :: cos_theta, sin_theta + !! cos(theta) and sin(theta) + real(DP), dimension(:), allocatable :: p + !! Associated Lengendre Polynomials at a given cos(theta) + real(DP) :: fac1, fac2, r_fac + !! calculation factors g_sph(:) = 0.0_DP theta = atan2(sqrt(rh(1)**2 + rh(2)**2), rh(3)) @@ -117,70 +134,43 @@ module subroutine swiftest_sph_g_acc_one(GMcb, r_0, phi_cb, rh, c_lm, g_sph, GMp end if return - end subroutine swiftest_sph_g_acc_one + end subroutine shgrav_g_acc_one - module subroutine swiftest_sph_g_acc_pl_all(self, nbody_system) + module subroutine shgrav_acc(body, nbody_system) !! author: Kaustub P. Anand !! - !! Calculate the acceleration terms for all massive bodies given c_lm + !! Calculate the acceleration terms for bodies given c_lm values for the central body !! implicit none ! Arguments - class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object + class(swiftest_body), intent(inout) :: body + !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object ! Internals - integer(I4B) :: i = 1 - real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics + integer(I4B) :: i + real(DP), dimension(NDIM) :: g_sph + !! Gravitational terms from Spherical Harmonics - associate(pl => self, npl => self%nbody, cb => nbody_system%cb, rh => self%rh) + associate(cb => nbody_system%cb) cb%aobl(:) = 0.0_DP - - do i = 1, npl - if (pl%lmask(i)) then - ! theta = atan2(sqrt(rh(1,i)**2 + rh(2,i)**2), rh(3,i)) - ! phi = atan2(rh(2,i), rh(1,i)) ! - cb%rotphase - - call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, rh(:,i), cb%c_lm, g_sph, pl%Gmass(i), cb%aobl) - pl%ah(:, i) = pl%ah(:, i) + g_sph(:) - cb%aobl(:) - pl%aobl(:, i) = g_sph(:) - end if - end do + select type(body) + class is (swiftest_pl) + do i = 1, body%nbody + if (body%lmask(i)) then + call shgrav_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, body%rh(:,i), cb%c_lm, body%aobl, & + GMpl=body%Gmass(i), aoblcb=cb%aobl) + end if + end do + class is (swiftest_tp) + do i = 1, body%nbody + if (body%lmask(i)) then + call shgrav_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, body%rh(:,i), cb%c_lm, body%aobl) + end if + end do + end select end associate return - end subroutine swiftest_sph_g_acc_pl_all - - module subroutine swiftest_sph_g_acc_tp_all(self, nbody_system) - !! author: Kaustub P. Anand - !! - !! Calculate the acceleration terms for all test particles given c_lm - !! - implicit none - ! Arguments - class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - ! Internals - integer(I4B) :: i = 1 - real(DP), dimension(NDIM) :: g_sph !! Gravitational terms from Spherical Harmonics - real(DP), dimension(NDIM) :: aoblcb !! Temporary variable for central body oblateness acceleration - - associate(tp => self, ntp => self%nbody, cb => nbody_system%cb, rh => self%rh) - - if (nbody_system%lbeg) then - aoblcb = cb%aoblbeg - else - aoblcb = cb%aoblend - end if - - do i = 1, ntp - if (tp%lmask(i)) then - - call swiftest_sph_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, rh(:,i), cb%c_lm, g_sph) - tp%ah(:, i) = tp%ah(:, i) + g_sph(:) - aoblcb(:) - tp%aobl(:, i) = g_sph(:) - end if - end do - end associate - return - end subroutine swiftest_sph_g_acc_tp_all + end subroutine shgrav_acc -end submodule s_swiftest_sph \ No newline at end of file +end submodule s_shgrav_accel \ No newline at end of file diff --git a/src/shgrav/shgrav_module.f90 b/src/shgrav/shgrav_module.f90 index 0007bb2af..416f51d19 100644 --- a/src/shgrav/shgrav_module.f90 +++ b/src/shgrav/shgrav_module.f90 @@ -16,5 +16,16 @@ module shgrav implicit none public + interface + module subroutine shgrav_acc(body, nbody_system) + implicit none + class(swiftest_body), intent(inout) :: body + !! Swiftest body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + end subroutine shgrav_acc + + end interface + end module shgrav \ No newline at end of file diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 685954b0d..a7a341e96 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -3370,10 +3370,8 @@ module subroutine swiftest_io_read_in_system(self, nc, param) if (ierr /=0) call base_util_exit(FAILURE,param%display_unit) end if - param%lshgrav = allocated(self%cb%c_lm) - - param%loblatecb = ((self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP)) .and. (.not. param%lshgrav) - if (.not.param%loblatecb .and. .not.param%lshgrav) then + param%lnon_spherical_cb = (self%cb%j2rp2 /= 0.0_DP) .or. (self%cb%j4rp4 /= 0.0_DP) .or. allocated(self%cb%c_lm) + if (.not.param%lnon_spherical_cb) then if (allocated(self%pl%aobl)) deallocate(self%pl%aobl) if (allocated(self%tp%aobl)) deallocate(self%tp%aobl) else diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 3e0e091a5..1325cc1c4 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -36,7 +36,7 @@ module swiftest !! construct in order to "reveal" the procedures. This is done throughout the project at the beginning of many procedures (along !! with copious amounts of associate(...) statements, in order to help with code readibility) !! - !! Adapted from David E. Kaufmann's Swifter routine: module_swifter.f90 + !! Adapted from David E. Kaufmann's Swifter routine: module_swifter.f90 use globals use operators use lambda_function @@ -413,12 +413,10 @@ module swiftest !! Placeholder method for discarding massive bodies procedure :: accel_int => swiftest_kick_getacch_int_pl !! Compute direct cross (third) term heliocentric accelerations of massive bodies - procedure :: accel_obl => swiftest_obl_acc_pl + procedure :: accel_non_spherical_cb => swiftest_obl_acc_pl !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure :: setup => swiftest_util_setup_pl !! A base constructor that sets the number of bodies and allocates and initializes all arrays - !procedure :: accel_sph => shgrav_g_acc_pl_all - !! Acceleration due ot spherical harmonics terms ! procedure :: accel_tides => tides_kick_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body procedure :: append => swiftest_util_append_pl @@ -488,10 +486,8 @@ module swiftest !! Check to see if test particles should be discarded based on their positions relative to the massive bodies procedure :: accel_int => swiftest_kick_getacch_int_tp !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies - procedure :: accel_obl => swiftest_obl_acc_tp + procedure :: accel_non_spherical_cb => swiftest_obl_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body - !procedure :: accel_sph => shgrav_g_acc_tp_all - !! acceleration due to spherical harmonics procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and procedure :: append => swiftest_util_append_tp diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 8b07f7b2f..ae3f2cb32 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -9,15 +9,15 @@ submodule (swiftest) s_swiftest_obl use swiftest - use operators + use shgrav contains pure function matinv3(A) result(B) - !! Performs a direct calculation of the inverse of a 3×3 matrix. - !! - !! from https://fortranwiki.org/fortran/show/Matrix+inversion - !! + !! Performs a direct calculation of the inverse of a 3×3 matrix. + !! + !! from https://fortranwiki.org/fortran/show/Matrix+inversion + !! real(DP), intent(in) :: A(3,3) !! Matrix real(DP) :: B(3,3) !! Inverse matrix @@ -227,7 +227,11 @@ module subroutine swiftest_obl_acc_pl(self, nbody_system) associate(pl => self, cb => nbody_system%cb) npl = self%nbody - call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rh, pl%lmask, pl%aobl, cb%rot, pl%Gmass, cb%aobl) + if (allocated(cb%c_lm)) then + call shgrav_acc(self, nbody_system) + else + call swiftest_obl_acc(npl, cb%Gmass, cb%j2rp2, cb%j4rp4, pl%rh, pl%lmask, pl%aobl, cb%rot, pl%Gmass, cb%aobl) + end if #ifdef DOCONLOC do concurrent(i = 1:npl, pl%lmask(i)) shared(cb,pl) @@ -262,7 +266,11 @@ module subroutine swiftest_obl_acc_tp(self, nbody_system) associate(tp => self, cb => nbody_system%cb) ntp = self%nbody - call swiftest_obl_acc(ntp, cb%Gmass, cb%j2rp2, cb%j4rp4, tp%rh, tp%lmask, tp%aobl, cb%rot) + if (allocated(cb%c_lm)) then + call shgrav_acc(self, nbody_system) + else + call swiftest_obl_acc(ntp, cb%Gmass, cb%j2rp2, cb%j4rp4, tp%rh, tp%lmask, tp%aobl, cb%rot) + end if if (nbody_system%lbeg) then aoblcb = cb%aoblbeg else diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index bcc4a5398..469163b13 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -1281,7 +1281,7 @@ module subroutine swiftest_util_get_energy_and_momentum_system(self, param) end if ! Potential energy from the oblateness term - if (param%loblatecb) then + if (param%lnon_spherical_cb) then call nbody_system%obl_pot() nbody_system%pe = nbody_system%pe + nbody_system%oblpot end if @@ -2706,7 +2706,7 @@ module subroutine swiftest_util_setup_body(self, n, param) self%peri(:) = 0.0_DP self%atp(:) = 0.0_DP - if (param%loblatecb .or. param%lshgrav) then + if (param%lnon_spherical_cb) then allocate(self%aobl(NDIM, n)) self%aobl(:,:) = 0.0_DP end if diff --git a/src/whm/whm_kick.f90 b/src/whm/whm_kick.f90 index e0bb2e70f..0f58e9d5e 100644 --- a/src/whm/whm_kick.f90 +++ b/src/whm/whm_kick.f90 @@ -43,8 +43,8 @@ module subroutine whm_kick_getacch_pl(self, nbody_system, param, t, lbeg) call whm_kick_getacch_ah2(cb, pl) call pl%accel_int(param) - if (param%loblatecb) then - call pl%accel_obl(nbody_system) + if (param%lnon_spherical_cb) then + call pl%accel_non_spherical_cb(nbody_system) if (lbeg) then cb%aoblbeg = cb%aobl else @@ -58,12 +58,7 @@ module subroutine whm_kick_getacch_pl(self, nbody_system, param, t, lbeg) ! end if end if - if(param%lshgrav) then - call pl%accel_sph(nbody_system) - end if - if (param%lgr) call pl%accel_gr(param) - if (param%lextra_force) call pl%accel_user(nbody_system, param, t, lbeg) end associate @@ -119,8 +114,7 @@ module subroutine whm_kick_getacch_tp(self, nbody_system, param, t, lbeg) end if end if - if (param%loblatecb) call tp%accel_obl(nbody_system) - if (param%lshgrav) call tp%accel_sph(nbody_system) + if (param%lnon_spherical_cb) call tp%accel_non_spherical_cb(nbody_system) if (param%lextra_force) call tp%accel_user(nbody_system, param, t, lbeg) if (param%lgr) call tp%accel_gr(param) end associate From 74742cf9f9f887cfd62c775f2b4ef82dfdcb4307 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 12:33:21 -0500 Subject: [PATCH 251/324] Changed the netcdf IO routine to set a flag indicating whether c_lm exists or not. --- src/netcdf_io/netcdf_io_module.f90 | 2 ++ src/swiftest/swiftest_coarray.f90 | 1 + src/swiftest/swiftest_io.f90 | 13 ++++++++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index c9d0df68e..2c072186f 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -291,6 +291,8 @@ module netcdf_io !! ID for the id of the other body involved in the discard logical :: lpseudo_vel_exists = .false. !! Logical flag to indicate whether or not the pseudovelocity vectors were present in an old file. + logical :: lc_lm_exists = .false. + !! Logical flag to indicate whether or not the c_lm array was present in an old file. contains procedure :: close => netcdf_io_close !! Closes an open NetCDF file diff --git a/src/swiftest/swiftest_coarray.f90 b/src/swiftest/swiftest_coarray.f90 index c8e4da943..60912902f 100644 --- a/src/swiftest/swiftest_coarray.f90 +++ b/src/swiftest/swiftest_coarray.f90 @@ -239,6 +239,7 @@ module subroutine swiftest_coarray_coclone_nc(self) call coclone(self%discard_vh_varid) call coclone(self%discard_body_id_varname) call coclone(self%lpseudo_vel_exists) + call coclone(self%lc_lm_exists) return end subroutine swiftest_coarray_coclone_nc diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index a7a341e96..0bbd4c7cd 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -880,7 +880,7 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) nc%vh_varid), "netcdf_io_initialize_output nf90_def_var vh_varid" ) !! When GR is enabled, we need to save the pseudovelocity vectors in addition to the true heliocentric velocity vectors, - !! otherwise !! we cannnot expect bit-identical runs from restarted runs with GR enabled due to floating point errors + !! otherwise we cannnot expect bit-identical runs from restarted runs with GR enabled due to floating point errors !! during the conversion. if (param%lgr) then call netcdf_io_check( nf90_def_var(nc%id, nc%gr_pseudo_vh_varname, nc%out_type, & @@ -1008,11 +1008,10 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%j4rp4_varname, nc%out_type, nc%time_dimid, nc%j4rp4_varid), & "netcdf_io_initialize_output nf90_def_var j4rp4_varid" ) - ! status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) - ! if (status == NF90_NOERR) then - call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], & + if (nc%lc_lm_exists) then + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], & nc%c_lm_varid), "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) - ! end if + end if ! Set fill mode to NaN for all variables call netcdf_io_check( nf90_inquire(nc%id, nVariables=nvar), "netcdf_io_initialize_output nf90_inquire nVariables" ) @@ -1576,6 +1575,10 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") ! ordering of dimensions above seen to stackoverflow to prevent error 'NetCDF: Start + count exceeds dimension bound' + nc%lc_lm_exists = .true. + else + if (allocated(cb%c_lm)) deallocate(cb%c_lm) + nc%lc_lm_exists = .false. end if call self%read_particle_info(nc, param, plmask, tpmask) From 16077ede70fe8dc4c81a1c79808480e0880c967a Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 12:41:43 -0500 Subject: [PATCH 252/324] Refactored for line length limits --- src/swiftest/swiftest_module.f90 | 26 +++++++++++++------------- src/swiftest/swiftest_obl.f90 | 20 ++++++++++++-------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 1325cc1c4..0e0c40749 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -409,23 +409,23 @@ module swiftest ! These are concrete because they are the same implemenation for all integrators procedure :: make_impactors => swiftest_util_make_impactors_pl !! Make impactors out of the current kinship relationships - procedure :: discard => swiftest_discard_pl + procedure :: discard => swiftest_discard_pl !! Placeholder method for discarding massive bodies - procedure :: accel_int => swiftest_kick_getacch_int_pl + procedure :: accel_int => swiftest_kick_getacch_int_pl !! Compute direct cross (third) term heliocentric accelerations of massive bodies - procedure :: accel_non_spherical_cb => swiftest_obl_acc_pl + procedure :: accel_non_spherical_cb => swiftest_non_spherical_cb_acc_pl !! Compute the barycentric accelerations of bodies due to the oblateness of the central body - procedure :: setup => swiftest_util_setup_pl + procedure :: setup => swiftest_util_setup_pl !! A base constructor that sets the number of bodies and allocates and initializes all arrays ! procedure :: accel_tides => tides_kick_getacch_pl !! Compute the accelerations of bodies due to tidal interactions with the central body - procedure :: append => swiftest_util_append_pl + procedure :: append => swiftest_util_append_pl !! Appends elements from one structure to another - procedure :: h2b => swiftest_util_coord_h2b_pl + procedure :: h2b => swiftest_util_coord_h2b_pl !! Convert massive bodies from heliocentric to barycentric coordinates (position and velocity) - procedure :: b2h => swiftest_util_coord_b2h_pl + procedure :: b2h => swiftest_util_coord_b2h_pl !! Convert massive bodies from barycentric to heliocentric coordinates (position and velocity) - procedure :: vh2vb => swiftest_util_coord_vh2vb_pl + procedure :: vh2vb => swiftest_util_coord_vh2vb_pl !! Convert massive bodies from heliocentric to barycentric coordinates (velocity only) procedure :: vb2vh => swiftest_util_coord_vb2vh_pl !! Convert massive bodies from barycentric to heliocentric coordinates (velocity only) @@ -486,7 +486,7 @@ module swiftest !! Check to see if test particles should be discarded based on their positions relative to the massive bodies procedure :: accel_int => swiftest_kick_getacch_int_tp !! Compute direct cross (third) term heliocentric accelerations of test particles by massive bodies - procedure :: accel_non_spherical_cb => swiftest_obl_acc_tp + procedure :: accel_non_spherical_cb => swiftest_non_spherical_cb_acc_tp !! Compute the barycentric accelerations of bodies due to the oblateness of the central body procedure :: setup => swiftest_util_setup_tp !! A base constructor that sets the number of bodies and @@ -1593,21 +1593,21 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, !! Barycentric acceleration of central body (only needed if input bodies are massive) end subroutine swiftest_obl_acc - module subroutine swiftest_obl_acc_pl(self, nbody_system) + module subroutine swiftest_non_spherical_cb_acc_pl(self, nbody_system) implicit none class(swiftest_pl), intent(inout) :: self !! Swiftest massive body object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - end subroutine swiftest_obl_acc_pl + end subroutine swiftest_non_spherical_cb_acc_pl - module subroutine swiftest_obl_acc_tp(self, nbody_system) + module subroutine swiftest_non_spherical_cb_acc_tp(self, nbody_system) implicit none class(swiftest_tp), intent(inout) :: self !! Swiftest test particle object class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - end subroutine swiftest_obl_acc_tp + end subroutine swiftest_non_spherical_cb_acc_tp module subroutine swiftest_obl_pot_system(self) implicit none diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index ae3f2cb32..c2ecbb51f 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -44,7 +44,8 @@ pure function matinv3(A) result(B) module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) !! author: Kaustub P. Anand !! - !! Generate a rotation matrix and its inverse to rotate the coordinate frame to align the rotation axis along the z axis for correct spin calculation + !! Generate a rotation matrix and its inverse to rotate the coordinate frame to align the rotation axis along the z axis for + !! correct spin calculation !! implicit none @@ -95,7 +96,8 @@ module subroutine swiftest_obl_rot_matrix(n, rot, rot_matrix, rot_matrix_inv) continue end if - rot_matrix_inv(i, j) = rot_matrix_inv(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) ! Skew-symmetric matrix + Tensor product matrix + ! Skew-symmetric matrix + Tensor product matrix + rot_matrix_inv(i, j) = rot_matrix_inv(i, j) + u(i) * u(j) * (1 - cos(theta)) + S_matrix(i, j) * sin(theta) end do end do @@ -136,7 +138,8 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, real(DP), dimension(:,:), intent(out) :: aobl !! Barycentric acceleration of bodies due to central body oblateness real(DP), dimension(NDIM), intent(in) :: rot !! Central body rotation matrix real(DP), dimension(:), intent(in), optional :: GMpl !! Masses of input bodies if they are not test particles - real(DP), dimension(:), intent(out), optional :: aoblcb !! Barycentric acceleration of central body (only needed if input bodies are massive) + real(DP), dimension(:), intent(out), optional :: aoblcb + !! Barycentric acceleration of central body (only needed if input bodies are massive) ! Internals integer(I4B) :: i @@ -209,7 +212,7 @@ module subroutine swiftest_obl_acc(n, GMcb, j2rp2, j4rp4, rh, lmask, aobl, rot, end subroutine swiftest_obl_acc - module subroutine swiftest_obl_acc_pl(self, nbody_system) + module subroutine swiftest_non_spherical_cb_acc_pl(self, nbody_system) !! author: David A. Minton !! !! Compute the barycentric accelerations of massive bodies due to the oblateness of the central body @@ -244,10 +247,10 @@ module subroutine swiftest_obl_acc_pl(self, nbody_system) return - end subroutine swiftest_obl_acc_pl + end subroutine swiftest_non_spherical_cb_acc_pl - module subroutine swiftest_obl_acc_tp(self, nbody_system) + module subroutine swiftest_non_spherical_cb_acc_tp(self, nbody_system) !! author: David A. Minton !! !! Compute the barycentric accelerations of massive bodies due to the oblateness of the central body @@ -288,7 +291,7 @@ module subroutine swiftest_obl_acc_tp(self, nbody_system) end associate return - end subroutine swiftest_obl_acc_tp + end subroutine swiftest_non_spherical_cb_acc_tp module subroutine swiftest_obl_pot_system(self) @@ -328,7 +331,8 @@ end subroutine swiftest_obl_pot_system elemental function swiftest_obl_pot_one(GMcb, GMpl, j2rp2, j4rp4, zh, irh) result(oblpot) !! author: David A. Minton !! - !! Compute the contribution to the total gravitational potential due solely to the oblateness of the central body from a single massive body + !! Compute the contribution to the total gravitational potential due solely to the oblateness of the central body from a + !! single massive body !! Returned value does not include monopole term or terms higher than J4 !! !! Reference: MacMillan, W. D. 1958. The Theory of the Potential, (Dover Publications), 363. From fc80aae7d160c5815aebc9c4eda44d92b98a8a25 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 12:52:15 -0500 Subject: [PATCH 253/324] Refactored sph_harmonics.py to shgrav.py for consistency. Removed class definition and made it a collection of functions --- swiftest/__init__.py | 2 +- swiftest/shgrav.py | 150 +++++++++++++++++++++++++++++++++++ swiftest/sph_harmonics.py | 162 -------------------------------------- 3 files changed, 151 insertions(+), 163 deletions(-) create mode 100644 swiftest/shgrav.py delete mode 100644 swiftest/sph_harmonics.py diff --git a/swiftest/__init__.py b/swiftest/__init__.py index 83a324265..6227cef1f 100644 --- a/swiftest/__init__.py +++ b/swiftest/__init__.py @@ -11,4 +11,4 @@ from .constants import * from .simulation_class import Simulation -from .sph_harmonics import Sph_Harmonics \ No newline at end of file +from .shgrav import clm_from_ellipsoid, clm_from_relief \ No newline at end of file diff --git a/swiftest/shgrav.py b/swiftest/shgrav.py new file mode 100644 index 000000000..6664b3941 --- /dev/null +++ b/swiftest/shgrav.py @@ -0,0 +1,150 @@ +""" + Copyright 2024 - Minton Group at Purdue University + This file is part of Swiftest. + Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with Swiftest. + If not, see: https://www.gnu.org/licenses. +""" + +# python functions to read in and set up spherical harmonics coefficients for non-standard gravity terms +# using pySHTOOLS see: https://shtools.github.io/SHTOOLS/ +# + +from .constants import GC + +try: + import pyshtools as pysh + PYSHTOOLS_AVAILABLE = True +except ModuleNotFoundError: + PYSHTOOLS_AVAILABLE = False + print("pyshtools is not installed. Some features will be unavailable.") + +if PYSHTOOLS_AVAILABLE: + + def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radius = False, ref_radius = None): + """ + Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. + Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). + + Parameters + ---------- + mass : float + mass of the central body + density : float + density of the central body + a : float + length of the pricipal axis aligned with the x axis + b : float, optional, default = a + length of the pricipal axis aligned with the y axis + c : float, optional, default = b + length of the pricipal axis aligned with the z axis + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + lref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS + ref_radius : float, optional, default = None + Reference radius to scale the gravitational coefficients to + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + Gmass = GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + + # cap lmax to ensure fast performance without giving up accuracy + lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB + if(lmax > lmax_limit): + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # create shape grid + shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) + + # get gravity coefficients + clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization and not scaling by 4*pi to match normalisation + + # Return reference radius EQUALS the radius of the Central Body + print(f'Ensure that the Central Body radius equals the reference radius.') + + if(lref_radius == True and ref_radius is None): + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] + return clm, ref_radius + elif(lref_radius == True and ref_radius is not None): + clm_class = clm_class.change_ref(r0 = ref_radius) + clm = clm_class.to_array(normalization = '4pi') + return clm, ref_radius + else: + return clm + + def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radius = None): + """ + Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. + Uses pyshtools. + + Parameters + ---------- + mass : float + mass of the central body + density : float + density of the central body + grid : array, shape [] + DH grid of the surface relief of the body + lmax : int, optional, default = 6 + The maximum spherical harmonic degree resolvable by the grid. + lref_radius : boolean, optional, default = False + Boolean value to return the reference radius calculated by SHTOOLS + ref_radius : float, optional, default = None + Reference radius to scale the gravitational coefficients to + + Returns + ------- + clm : ndarry, shape (2, lmax+1, lmax+1) + numpy ndarray of the gravitational potential spherical harmonic coefficients. + This is a three-dimensional array formatted as coeffs[i, degree, order], + where i=0 corresponds to positive orders and i=1 to negative orders. + + """ + + Gmass = GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS + + # cap lmax to 20 to ensure fast performance + lmax_limit = 6 + if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients + lmax = lmax_limit + print(f'Setting maximum spherical harmonic degree to {lmax_limit}') + + # convert to spherical harmonics + shape_SH = pysh.SHGrid.from_array(grid) + + # get coefficients + clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization + clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization + + # Return reference radius EQUALS the radius of the Central Body + + print(f'Ensure that the Central Body radius equals the reference radius.') + + if(lref_radius == True and ref_radius is None): + ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] + return clm, ref_radius + elif(lref_radius == True and ref_radius is not None): + clm_class = clm_class.change_ref(r0 = ref_radius) + clm = clm_class.to_array(normalization = '4pi') + return clm, ref_radius + else: + return clm + +else: + def clm_from_ellipsoid(*args, **kwargs): + raise NotImplementedError("Sph_Harmonics is not available because pyshtools is not installed.") + def clm_from_relief(*args, **kwargs): + raise NotImplementedError("Sph_Harmonics is not available because pyshtools is not installed.") + \ No newline at end of file diff --git a/swiftest/sph_harmonics.py b/swiftest/sph_harmonics.py deleted file mode 100644 index 140d35e2b..000000000 --- a/swiftest/sph_harmonics.py +++ /dev/null @@ -1,162 +0,0 @@ -""" - Copyright 2023 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, Dana Singh, & Kaustub Anand - This file is part of Swiftest. - Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along with Swiftest. - If not, see: https://www.gnu.org/licenses. -""" - -# python functions to read in and set up spherical harmonics coefficients for non-standard gravity terms -# using pySHTOOLS (in python) by Mark W. -# - -import swiftest -import numpy as np -from astroquery.jplhorizons import Horizons -import astropy.units as u -from astropy.coordinates import SkyCoord -import datetime -import xarray as xr -from typing import ( - Literal, - Dict, - List, - Any -) - -try: - import pyshtools as pysh - PYSHTOOLS_AVAILABLE = True -except ModuleNotFoundError: - PYSHTOOLS_AVAILABLE = False - print("pyshtools is not installed. Some features will be unavailable.") - -if PYSHTOOLS_AVAILABLE: - - class Sph_Harmonics(object): - def clm_from_ellipsoid(mass, density, a, b = None, c = None, lmax = 6, lref_radius = False, ref_radius = None): - """ - Creates and returns the gravity coefficients for an ellipsoid with principal axes a, b, c upto a certain maximum degree lmax. - Uses pyshtools. No units necessary for a, b, & c. However, they need to be in the same units (DU). - - Parameters - ---------- - mass : float - mass of the central body - density : float - density of the central body - a : float - length of the pricipal axis aligned with the x axis - b : float, optional, default = a - length of the pricipal axis aligned with the y axis - c : float, optional, default = b - length of the pricipal axis aligned with the z axis - lmax : int, optional, default = 6 - The maximum spherical harmonic degree resolvable by the grid. - lref_radius : boolean, optional, default = False - Boolean value to return the reference radius calculated by SHTOOLS - ref_radius : float, optional, default = None - Reference radius to scale the gravitational coefficients to - - Returns - ------- - clm : ndarry, shape (2, lmax+1, lmax+1) - numpy ndarray of the gravitational potential spherical harmonic coefficients. - This is a three-dimensional array formatted as coeffs[i, degree, order], - where i=0 corresponds to positive orders and i=1 to negative orders. - - """ - Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS - - # cap lmax to ensure fast performance without giving up accuracy - lmax_limit = 6 # lmax_limit = 6 derived from Jean's Law; characteristic wavelength = the radius of the CB - if(lmax > lmax_limit): - lmax = lmax_limit - print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - - # create shape grid - shape_SH = pysh.SHGrid.from_ellipsoid(lmax = lmax, a = a, b = b, c = c) - - # get gravity coefficients - clm_class = pysh.SHGravCoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization and not scaling by 4*pi to match normalisation - - # Return reference radius EQUALS the radius of the Central Body - print(f'Ensure that the Central Body radius equals the reference radius.') - - if(lref_radius == True and ref_radius is None): - ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] - return clm, ref_radius - elif(lref_radius == True and ref_radius is not None): - clm_class = clm_class.change_ref(r0 = ref_radius) - clm = clm_class.to_array(normalization = '4pi') - return clm, ref_radius - else: - return clm - - def clm_from_relief(mass, density, grid, lmax = 6, lref_radius = False, ref_radius = None): - """ - Creates and returns the gravity coefficients for a body with a given DH grid upto a certain maximum degree lmax. - Uses pyshtools. - - Parameters - ---------- - mass : float - mass of the central body - density : float - density of the central body - grid : array, shape [] - DH grid of the surface relief of the body - lmax : int, optional, default = 6 - The maximum spherical harmonic degree resolvable by the grid. - lref_radius : boolean, optional, default = False - Boolean value to return the reference radius calculated by SHTOOLS - ref_radius : float, optional, default = None - Reference radius to scale the gravitational coefficients to - - Returns - ------- - clm : ndarry, shape (2, lmax+1, lmax+1) - numpy ndarray of the gravitational potential spherical harmonic coefficients. - This is a three-dimensional array formatted as coeffs[i, degree, order], - where i=0 corresponds to positive orders and i=1 to negative orders. - - """ - - Gmass = swiftest.constants.GC * mass # SHTOOLS uses an SI G value, and divides it before using the mass; NO NEED TO CHANGE UNITS - - # cap lmax to 20 to ensure fast performance - lmax_limit = 6 - if(lmax > lmax_limit): # FIND A BETTER WAY to judge this cut off point, i.e., relative change between coefficients - lmax = lmax_limit - print(f'Setting maximum spherical harmonic degree to {lmax_limit}') - - # convert to spherical harmonics - shape_SH = pysh.SHGrid.from_array(grid) - - # get coefficients - clm_class = pysh.SHGravcoeffs.from_shape(shape_SH, rho = density, gm = Gmass) # 4pi normalization - clm = clm_class.to_array(normalization = '4pi') # export as array with 4pi normalization - - # Return reference radius EQUALS the radius of the Central Body - - print(f'Ensure that the Central Body radius equals the reference radius.') - - if(lref_radius == True and ref_radius is None): - ref_radius = shape_SH.expand(normalization = '4pi').coeffs[0, 0, 0] - return clm, ref_radius - elif(lref_radius == True and ref_radius is not None): - clm_class = clm_class.change_ref(r0 = ref_radius) - clm = clm_class.to_array(normalization = '4pi') - return clm, ref_radius - else: - return clm - -else: - class Sph_Harmonics(object): - def clm_from_ellipsoid(*args, **kwargs): - raise NotImplementedError("Sph_Harmonics is not available because pyshtools is not installed.") - \ No newline at end of file From b00a3a332700e0998a378e627bfdd0b12d05a9e4 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 14:08:49 -0500 Subject: [PATCH 254/324] Fixed bugs that occur when number of massive bodies drops to 0 in SyMBA --- src/helio/helio_kick.f90 | 10 +-- src/swiftest/swiftest_discard.f90 | 10 +-- src/swiftest/swiftest_obl.f90 | 1 + src/swiftest/swiftest_util.f90 | 103 ++++++++++++++++------------ src/symba/symba_discard.f90 | 46 ++++++------- src/symba/symba_encounter_check.f90 | 2 +- src/symba/symba_util.f90 | 1 + 7 files changed, 97 insertions(+), 76 deletions(-) diff --git a/src/helio/helio_kick.f90 b/src/helio/helio_kick.f90 index 6740e0eb0..7b7adee40 100644 --- a/src/helio/helio_kick.f90 +++ b/src/helio/helio_kick.f90 @@ -74,10 +74,12 @@ module subroutine helio_kick_getacch_tp(self, nbody_system, param, t, lbeg) associate(tp => self, cb => nbody_system%cb, pl => nbody_system%pl, npl => nbody_system%pl%nbody) nbody_system%lbeg = lbeg - if (nbody_system%lbeg) then - call tp%accel_int(param, pl%Gmass(1:npl), pl%rbeg(:,1:npl), npl) - else - call tp%accel_int(param, pl%Gmass(1:npl), pl%rend(:,1:npl), npl) + if (npl > 0) then + if (nbody_system%lbeg) then + call tp%accel_int(param, pl%Gmass(1:npl), pl%rbeg(:,1:npl), npl) + else + call tp%accel_int(param, pl%Gmass(1:npl), pl%rend(:,1:npl), npl) + end if end if if (param%lnon_spherical_cb) call tp%accel_non_spherical_cb(nbody_system) if (param%lextra_force) call tp%accel_user(nbody_system, param, t, lbeg) diff --git a/src/swiftest/swiftest_discard.f90 b/src/swiftest/swiftest_discard.f90 index e9a19e374..19f5cee27 100644 --- a/src/swiftest/swiftest_discard.f90 +++ b/src/swiftest/swiftest_discard.f90 @@ -27,8 +27,8 @@ module subroutine swiftest_discard_system(self, param) class(swiftest_pl), allocatable :: plsub class(swiftest_tp), allocatable :: tpsub - lpl_check = allocated(self%pl_discards) - ltp_check = allocated(self%tp_discards) + lpl_check = allocated(self%pl_discards) .and. self%pl%nbody > 0 + ltp_check = allocated(self%tp_discards) .and. self%tp%nbody > 0 associate(nbody_system => self,tp => self%tp,pl => self%pl,tp_discards => self%tp_discards,pl_discards => self%pl_discards, & npl => self%pl%nbody, ntp => self%tp%nbody, t => self%t, collision_history => self%collision_history, & @@ -38,14 +38,14 @@ module subroutine swiftest_discard_system(self, param) if (lpl_check .and. pl%nbody > 0) then pl%ldiscard = pl%status(:) /= ACTIVE call pl%discard(nbody_system, param) - lpl_discards = any(pl%ldiscard(1:npl)) + if (npl > 0) lpl_discards = any(pl%ldiscard(1:npl)) end if if (ltp_check .and. tp%nbody > 0) then tp%ldiscard = tp%status(:) /= ACTIVE call tp%discard(nbody_system, param) - ltp_discards = any(tp%ldiscard(1:ntp)) - lpl_discards = any(pl%ldiscard(1:npl)) + if (ntp > 0) ltp_discards = any(tp%ldiscard(1:ntp)) + if (npl > 0) lpl_discards = any(pl%ldiscard(1:npl)) end if if (ltp_discards.or.lpl_discards) then diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index c2ecbb51f..68bd64dd0 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -313,6 +313,7 @@ module subroutine swiftest_obl_pot_system(self) associate(nbody_system => self, pl => self%pl, cb => self%cb) npl = self%pl%nbody + if (npl == 0) return if (.not. any(pl%lmask(1:npl))) return #ifdef DOCONLOC do concurrent (i = 1:npl, pl%lmask(i)) shared(cb,pl,oblpot_arr) diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 469163b13..e1bfbb17b 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -1213,32 +1213,36 @@ module subroutine swiftest_util_get_energy_and_momentum_system(self, param) nbody_system%ke_orbit = 0.0_DP nbody_system%ke_spin = 0.0_DP - kepl(:) = 0.0_DP - Lplorbit(:,:) = 0.0_DP - Lplspin(:,:) = 0.0_DP - - pl%lmask(1:npl) = pl%status(1:npl) /= INACTIVE - - nbody_system%GMtot = cb%Gmass + sum(pl%Gmass(1:npl), pl%lmask(1:npl)) + nbody_system%GMtot = cb%Gmass + if (npl > 0) then + kepl(:) = 0.0_DP + Lplorbit(:,:) = 0.0_DP + Lplspin(:,:) = 0.0_DP + pl%lmask(1:npl) = pl%status(1:npl) /= INACTIVE + nbody_system%GMtot = nbody_system%GMtot + sum(pl%Gmass(1:npl), pl%lmask(1:npl)) + end if + kecb = cb%mass * dot_product(cb%vb(:), cb%vb(:)) nbody_system%be_cb = -3*cb%Gmass * cb%mass / (5 * cb%radius) Lcborbit(:) = cb%mass * (cb%rb(:) .cross. cb%vb(:)) + if (npl > 0) then #ifdef DOCONLOC - do concurrent (i = 1:npl, pl%lmask(i)) shared(pl,Lplorbit,kepl,npl) local(h) + do concurrent (i = 1:npl, pl%lmask(i)) shared(pl,Lplorbit,kepl,npl) local(h) #else - do concurrent (i = 1:npl, pl%lmask(i)) + do concurrent (i = 1:npl, pl%lmask(i)) #endif - h(1) = pl%rb(2,i) * pl%vb(3,i) - pl%rb(3,i) * pl%vb(2,i) - h(2) = pl%rb(3,i) * pl%vb(1,i) - pl%rb(1,i) * pl%vb(3,i) - h(3) = pl%rb(1,i) * pl%vb(2,i) - pl%rb(2,i) * pl%vb(1,i) - + h(1) = pl%rb(2,i) * pl%vb(3,i) - pl%rb(3,i) * pl%vb(2,i) + h(2) = pl%rb(3,i) * pl%vb(1,i) - pl%rb(1,i) * pl%vb(3,i) + h(3) = pl%rb(1,i) * pl%vb(2,i) - pl%rb(2,i) * pl%vb(1,i) + ! Angular momentum from orbit - Lplorbit(:,i) = pl%mass(i) * h(:) + Lplorbit(:,i) = pl%mass(i) * h(:) - ! Kinetic energy from orbit - kepl(i) = pl%mass(i) * dot_product(pl%vb(:,i), pl%vb(:,i)) - end do + ! Kinetic energy from orbit + kepl(i) = pl%mass(i) * dot_product(pl%vb(:,i), pl%vb(:,i)) + end do + end if if (param%lrotation) then kespincb = cb%mass * cb%Ip(3) * cb%radius**2 * dot_product(cb%rot(:), cb%rot(:)) @@ -1246,38 +1250,48 @@ module subroutine swiftest_util_get_energy_and_momentum_system(self, param) ! For simplicity, we always assume that the rotation pole is the 3rd principal axis Lcbspin(:) = cb%Ip(3) * cb%mass * cb%radius**2 * cb%rot(:) + if (npl > 0) then #ifdef DOCONLOC - do concurrent (i = 1:npl, pl%lmask(i)) shared(pl,Lplspin,kespinpl) + do concurrent (i = 1:npl, pl%lmask(i)) shared(pl,Lplspin,kespinpl) #else - do concurrent (i = 1:npl, pl%lmask(i)) + do concurrent (i = 1:npl, pl%lmask(i)) #endif - ! Currently we assume that the rotation pole is the 3rd principal axis - ! Angular momentum from spin - Lplspin(:,i) = pl%mass(i) * pl%Ip(3,i) * pl%radius(i)**2 * pl%rot(:,i) + ! Currently we assume that the rotation pole is the 3rd principal axis + ! Angular momentum from spin + Lplspin(:,i) = pl%mass(i) * pl%Ip(3,i) * pl%radius(i)**2 * pl%rot(:,i) - ! Kinetic energy from spin - kespinpl(i) = pl%mass(i) * pl%Ip(3,i) * pl%radius(i)**2 * dot_product(pl%rot(:,i), pl%rot(:,i)) - end do + ! Kinetic energy from spin + kespinpl(i) = pl%mass(i) * pl%Ip(3,i) * pl%radius(i)**2 * dot_product(pl%rot(:,i), pl%rot(:,i)) + end do - nbody_system%ke_spin = 0.5_DP * (kespincb + sum(kespinpl(1:npl), pl%lmask(1:npl))) + nbody_system%ke_spin = 0.5_DP * (kespincb + sum(kespinpl(1:npl), pl%lmask(1:npl))) + else + nbody_system%ke_spin = 0.5_DP * kespincb + end if + if (npl > 0) then #ifdef DOCONLOC - do concurrent (j = 1:NDIM) shared(nbody_system,pl,Lplspin,Lcbspin) + do concurrent (j = 1:NDIM) shared(nbody_system,pl,Lplspin,Lcbspin) #else - do concurrent (j = 1:NDIM) + do concurrent (j = 1:NDIM) #endif - nbody_system%L_spin(j) = Lcbspin(j) + sum(Lplspin(j,1:npl), pl%lmask(1:npl)) - end do + nbody_system%L_spin(j) = Lcbspin(j) + sum(Lplspin(j,1:npl), pl%lmask(1:npl)) + end do + else + nbody_system%L_spin(:) = Lcbspin(:) + end if else nbody_system%ke_spin = 0.0_DP nbody_system%L_spin(:) = 0.0_DP end if - - if (param%lflatten_interactions) then - call swiftest_util_get_potential_energy(npl, pl%nplpl, pl%k_plpl, pl%lmask, cb%Gmass, pl%Gmass, pl%mass, pl%rb, & - nbody_system%pe) - else - call swiftest_util_get_potential_energy(npl, pl%lmask, cb%Gmass, pl%Gmass, pl%mass, pl%rb, nbody_system%pe) + + if (npl > 0) then + if (param%lflatten_interactions) then + call swiftest_util_get_potential_energy(npl, pl%nplpl, pl%k_plpl, pl%lmask, cb%Gmass, pl%Gmass, pl%mass, pl%rb, & + nbody_system%pe) + else + call swiftest_util_get_potential_energy(npl, pl%lmask, cb%Gmass, pl%Gmass, pl%mass, pl%rb, nbody_system%pe) + end if end if ! Potential energy from the oblateness term @@ -1286,16 +1300,21 @@ module subroutine swiftest_util_get_energy_and_momentum_system(self, param) nbody_system%pe = nbody_system%pe + nbody_system%oblpot end if - nbody_system%ke_orbit = 0.5_DP * (kecb + sum(kepl(1:npl), pl%lmask(1:npl))) + if (npl > 0) then + nbody_system%ke_orbit = 0.5_DP * (kecb + sum(kepl(1:npl), pl%lmask(1:npl))) #ifdef DOCONLOC - do concurrent (j = 1:NDIM) shared(nbody_system,pl,Lcborbit,Lplorbit,npl) + do concurrent (j = 1:NDIM) shared(nbody_system,pl,Lcborbit,Lplorbit,npl) #else - do concurrent (j = 1:NDIM) + do concurrent (j = 1:NDIM) #endif - nbody_system%L_orbit(j) = Lcborbit(j) + sum(Lplorbit(j,1:npl), pl%lmask(1:npl)) - end do + nbody_system%L_orbit(j) = Lcborbit(j) + sum(Lplorbit(j,1:npl), pl%lmask(1:npl)) + end do + else + nbody_system%ke_orbit = 0.5_DP * kecb + nbody_system%L_orbit(:) = Lcborbit(:) + end if - if ((param%lclose)) then + if ((param%lclose .and. (npl > 0))) then nbody_system%be = sum(-3*pl%Gmass(1:npl)*pl%mass(1:npl)/(5*pl%radius(1:npl)), pl%lmask(1:npl)) else nbody_system%be = 0.0_DP diff --git a/src/symba/symba_discard.f90 b/src/symba/symba_discard.f90 index 7c95da30a..2d22ef299 100644 --- a/src/symba/symba_discard.f90 +++ b/src/symba/symba_discard.f90 @@ -48,11 +48,13 @@ subroutine symba_discard_cb_pl(pl, nbody_system, param) write(message, *) trim(adjustl(pl%info(i)%name)) // " (" // trim(adjustl(idstr)) // ")" // & " too far from the central body at t = " // trim(adjustl(timestr)) call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & - "***********************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "***********************************************************" // & + "***********************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "***********************************************************" // & - "***********************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "***********************************************************" // & + "***********************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") call pl%info(i)%set_value(status="DISCARDED_RMAX", discard_time=nbody_system%t, discard_rh=pl%rh(:,i), & discard_vh=pl%vh(:,i)) @@ -65,11 +67,13 @@ subroutine symba_discard_cb_pl(pl, nbody_system, param) write(message, *) trim(adjustl(pl%info(i)%name)) // " (" // trim(adjustl(idstr)) // ")" // & " too close to the central body at t = " // trim(adjustl(timestr)) call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "************************************************************" // & - "************************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "************************************************************" // & + "************************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "************************************************************" // & - "************************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "************************************************************" // & + "************************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") call pl%info(i)%set_value(status="DISCARDED_RMIN", discard_time=nbody_system%t, discard_rh=pl%rh(:,i), & discard_vh=pl%vh(:,i), discard_body_id=cb%id) @@ -86,11 +90,13 @@ subroutine symba_discard_cb_pl(pl, nbody_system, param) write(message, *) trim(adjustl(pl%info(i)%name)) // " (" // trim(adjustl(idstr)) // ")" // & " is unbound and too far from barycenter at t = " // trim(adjustl(timestr)) call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "************************************************************" // & - "************************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "************************************************************" // & + "************************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, message) - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "************************************************************" // & - "************************************************************") + call swiftest_io_log_one_message(COLLISION_LOG_OUT, & + "************************************************************" // & + "************************************************************") call swiftest_io_log_one_message(COLLISION_LOG_OUT, "") call pl%info(i)%set_value(status="DISCARDED_RMAXU", discard_time=nbody_system%t, discard_rh=pl%rh(:,i), & discard_vh=pl%vh(:,i)) @@ -233,16 +239,6 @@ subroutine symba_discard_nonplpl(pl, nbody_system, param) call symba_discard_cb_pl(pl, nbody_system, param) end if if (param%qmin >= 0.0_DP) call symba_discard_peri_pl(pl, nbody_system, param) - ! if (any(pl%ldiscard(1:npl))) then - ! ldiscard(1:npl) = pl%ldiscard(1:npl) - - ! allocate(plsub, mold=pl) - ! call pl%spill(plsub, ldiscard, ldestructive=.false.) - ! nsub = plsub%nbody - ! nstart = pl_discards%nbody + 1 - ! nend = pl_discards%nbody + nsub - ! call pl_discards%append(plsub, lsource_mask=[(.true., i = 1, nsub)]) - ! end if end associate return @@ -266,7 +262,8 @@ subroutine symba_discard_nonplpl_conservation(pl, nbody_system, param) integer(I4B), dimension(:), allocatable :: discard_index_list associate(npl => pl%nbody) - discard_l_pl(1:npl) = pl%ldiscard(1:npl) .and. .not. pl%lcollision(1:npl) ! These are bodies that are discarded but not flagged as pl-pl collision + discard_l_pl(1:npl) = pl%ldiscard(1:npl) .and. .not. pl%lcollision(1:npl) ! These are bodies that are discarded but not + ! flagged as pl-pl collision ndiscard = count(discard_l_pl(:)) allocate(discard_index_list(ndiscard)) discard_index_list(:) = pack([(i, i = 1, npl)], discard_l_pl(1:npl)) @@ -341,7 +338,8 @@ end subroutine symba_discard_peri_pl module subroutine symba_discard_pl(self, nbody_system, param) !! author: David A. Minton !! - !! Call the various flavors of discards for massive bodies in SyMBA runs, including discards due to colliding with the central body or escaping the nbody_system + !! Call the various flavors of discards for massive bodies in SyMBA runs, including discards due to colliding with the central + !! body or escaping the nbody_system implicit none ! Arguments class(symba_pl), intent(inout) :: self !! SyMBA test particle object diff --git a/src/symba/symba_encounter_check.f90 b/src/symba/symba_encounter_check.f90 index 9dec2072c..768349e7e 100644 --- a/src/symba/symba_encounter_check.f90 +++ b/src/symba/symba_encounter_check.f90 @@ -256,7 +256,7 @@ module function symba_encounter_check_tp(self, param, nbody_system, dt, irec) re integer(I4B), dimension(:), allocatable :: index1, index2 lany_encounter = .false. - if (self%nbody == 0) return + if (self%nbody == 0 .or. nbody_system%pl%nbody == 0) return associate(tp => self, ntp => self%nbody, pl => nbody_system%pl, npl => nbody_system%pl%nbody, cb => nbody_system%cb) call pl%set_renc(irec) diff --git a/src/symba/symba_util.f90 b/src/symba/symba_util.f90 index 38b13978a..e54a96f5c 100644 --- a/src/symba/symba_util.f90 +++ b/src/symba/symba_util.f90 @@ -254,6 +254,7 @@ module subroutine symba_util_set_renc(self, scale) integer(I4B) :: i real(DP) :: rshell_irec + if (self%nbody == 0) return associate(pl => self, npl => self%nbody) rshell_irec = 1._DP do i = 1, scale From c914c522fdced62be6655c4829dfe6135cda85dc Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 14:09:56 -0500 Subject: [PATCH 255/324] Added spherical harmonics test case to examples --- examples/.gitignore | 1 + examples/spherical_harmonics_cb/.gitignore | 1 + .../spherical_harmonics_cb.py | 92 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 examples/spherical_harmonics_cb/.gitignore create mode 100644 examples/spherical_harmonics_cb/spherical_harmonics_cb.py diff --git a/examples/.gitignore b/examples/.gitignore index 829298555..9b6c85b05 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -8,3 +8,4 @@ !helio_gr_test !solar_impact !whm_gr_test +!spherical_harmonics_cb diff --git a/examples/spherical_harmonics_cb/.gitignore b/examples/spherical_harmonics_cb/.gitignore new file mode 100644 index 000000000..7543355dd --- /dev/null +++ b/examples/spherical_harmonics_cb/.gitignore @@ -0,0 +1 @@ +!spherical_harmonics_cb.py \ No newline at end of file diff --git a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py new file mode 100644 index 000000000..a673a3855 --- /dev/null +++ b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +""" + Copyright 2024 - The Minton Group at Purdue University + This file is part of Swiftest. + Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with Swiftest. + If not, see: https://www.gnu.org/licenses. +""" + +""" +Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the +SyMBA integrator. Using Chariklo as the example body with axes measurements taken from Leiva, et al (2017) (Jacobi +Ellipsoid model). All simulation outputs are stored in the /simdata subdirectory. + +""" + +import swiftest +import numpy as np + +seed = 123 +rng = np.random.default_rng(seed=seed) + +# set up swiftest simulation with relevant units (here they are km, days, and kg) +sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg') +sim.clean() + +# Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) +cb_mass = 6.1e18 # kg +cb_radius = 123 # km +cb_a = 157 # km +cb_b = 139 # km +cb_c = 86 # km +cb_volume = 4.0 / 3 * np.pi * cb_radius**3 # km^3 +cb_density = cb_mass / cb_volume +cb_T_rotation = 7.004 / 24.0 # converting from hours to julian days (TU) +cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/d + +# Extract the spherical harmonics coefficients (c_lm) from axes measurements +# +# The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS +# calculates the reference radius. If lref_radius = True, the function returns the reference radius used. +# We recommend setting passing and setting a reference radius. + +c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) + +# Add the central body +# The user can pass the c_lm coefficients directly to the add_body method if they do not wish to use the clm_from_ellipsoid method. +sim.add_body(name = 'Chariklo', id = 0, mass = cb_mass, rot = cb_rot, radius = cb_radius, a = 0.0, e = 0.0, inc = 0.0, capom = 0.0, omega = 0.0, capm = 0.0, c_lm = c_lm) + +# Add user-defined massive bodies +npl = 5 +density_pl = cb_density + +name_pl = ["SemiBody_01", "SemiBody_02", "SemiBody_03", "SemiBody_04", "SemiBody_05"] +a_pl = rng.uniform(150, 300, npl) +e_pl = rng.uniform(0.0, 0.2, npl) +inc_pl = rng.uniform(0.0, 10, npl) +capom_pl = rng.uniform(0.0, 360.0, npl) +omega_pl = rng.uniform(0.0, 360.0, npl) +capm_pl = rng.uniform(0.0, 360.0, npl) +R_pl = np.array([0.5, 1.0, 1.2, 0.75, 0.8]) +M_pl = 4.0 / 3 * np.pi * R_pl**3 * density_pl +Ip_pl = np.full((npl,3),0.4,) +rot_pl = np.zeros((npl,3)) +mtiny = 1.1 * np.max(M_pl) + +sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + +# Add 10 user-defined test particles. +ntp = 10 + +name_tp = ["TestParticle_01", "TestParticle_02", "TestParticle_03", "TestParticle_04", "TestParticle_05", "TestParticle_06", "TestParticle_07", "TestParticle_08", "TestParticle_09", "TestParticle_10"] +a_tp = rng.uniform(150, 300, ntp) +e_tp = rng.uniform(0.0, 0.2, ntp) +inc_tp = rng.uniform(0.0, 10, ntp) +capom_tp = rng.uniform(0.0, 360.0, ntp) +omega_tp = rng.uniform(0.0, 360.0, ntp) +capm_tp = rng.uniform(0.0, 360.0, ntp) + +sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim.set_parameter(tstart=0.0, tstop=5.0e2, dt=0.01, istep_out=100, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) + +# Display the run configuration parameters. +sim.get_parameter() +sim.save() + +# Run the simulation. Arguments may be defined here or thorugh the swiftest.Simulation() method. +sim.run() From 87fca610b23185732ede356b83b15cba0532dd45 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 14:34:49 -0500 Subject: [PATCH 256/324] Added save method to run method so that you don't have to call save before run manually --- swiftest/simulation_class.py | 1 + 1 file changed, 1 insertion(+) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index d4e3a4e0f..e4a5ca7c9 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -450,6 +450,7 @@ def run(self, # Save initial conditions if not self.restart: self.clean() + self.save() # Write out the current parameter set before executing run self.write_param(verbose=False,**kwargs) From 27937243cf1d9c926b1a81a4d8010e3edcc9aca5 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 14:35:03 -0500 Subject: [PATCH 257/324] Removed unecessary import --- examples/Basic_Simulation/output_reader.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/Basic_Simulation/output_reader.py b/examples/Basic_Simulation/output_reader.py index a46b6cefc..56f19362c 100644 --- a/examples/Basic_Simulation/output_reader.py +++ b/examples/Basic_Simulation/output_reader.py @@ -25,7 +25,6 @@ """ import swiftest -import xarray as xr import matplotlib.pyplot as plt # Read in the simulation output and store it as an Xarray dataset. From c42fdf42094cca270d7e11dfeb51dc53c4373bd4 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 14:56:55 -0500 Subject: [PATCH 258/324] Fixed indexing issue in the shgrav acceleration calculation and fixed some issues when recording discards --- .../spherical_harmonics_cb.py | 3 +-- src/shgrav/shgrav_accel.f90 | 4 ++-- src/swiftest/swiftest_discard.f90 | 21 ++++++++++++------- src/swiftest/swiftest_obl.f90 | 3 +-- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py index a673a3855..90e45252a 100644 --- a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py +++ b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py @@ -82,11 +82,10 @@ capm_tp = rng.uniform(0.0, 360.0, ntp) sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim.set_parameter(tstart=0.0, tstop=5.0e2, dt=0.01, istep_out=100, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) +sim.set_parameter(tstart=0.0, tstop=1.0, dt=0.01, istep_out=1, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) # Display the run configuration parameters. sim.get_parameter() -sim.save() # Run the simulation. Arguments may be defined here or thorugh the swiftest.Simulation() method. sim.run() diff --git a/src/shgrav/shgrav_accel.f90 b/src/shgrav/shgrav_accel.f90 index cd26f2567..4dc29bbcb 100644 --- a/src/shgrav/shgrav_accel.f90 +++ b/src/shgrav/shgrav_accel.f90 @@ -158,14 +158,14 @@ module subroutine shgrav_acc(body, nbody_system) class is (swiftest_pl) do i = 1, body%nbody if (body%lmask(i)) then - call shgrav_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, body%rh(:,i), cb%c_lm, body%aobl, & + call shgrav_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, body%rh(:,i), cb%c_lm, body%aobl(:,i), & GMpl=body%Gmass(i), aoblcb=cb%aobl) end if end do class is (swiftest_tp) do i = 1, body%nbody if (body%lmask(i)) then - call shgrav_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, body%rh(:,i), cb%c_lm, body%aobl) + call shgrav_g_acc_one(cb%Gmass, cb%radius, cb%rotphase, body%rh(:,i), cb%c_lm, body%aobl(:,i)) end if end do end select diff --git a/src/swiftest/swiftest_discard.f90 b/src/swiftest/swiftest_discard.f90 index 19f5cee27..33dd7feb0 100644 --- a/src/swiftest/swiftest_discard.f90 +++ b/src/swiftest/swiftest_discard.f90 @@ -49,8 +49,18 @@ module subroutine swiftest_discard_system(self, param) end if if (ltp_discards.or.lpl_discards) then + ! Advance the collision id number and save it + collider%maxid_collision = collider%maxid_collision + 1 + collider%collision_id = collider%maxid_collision + collider%impactors%regime = COLLRESOLVE_REGIME_MERGE + write(idstr,*) collider%collision_id + call swiftest_io_log_one_message(COLLISION_LOG_OUT, "collision_id " // trim(adjustl(idstr))) + if (ltp_discards) then allocate(ldiscard, source=tp%ldiscard(:)) + do i = 1, ntp + if (ldiscard(i)) call tp%info(i)%set_value(collision_id=collider%collision_id) + end do allocate(tpsub, mold=tp) call tp%spill(tpsub, ldiscard, ldestructive=.true.) nsub = tpsub%nbody @@ -70,6 +80,9 @@ module subroutine swiftest_discard_system(self, param) ! simply used to trigger a snapshot. if (param%lenergy) call self%conservation_report(param, lterminal=.false.) allocate(ldiscard, source=pl%ldiscard(:)) + do i = 1, npl + if (ldiscard(i)) call pl%info(i)%set_value(collision_id=collider%collision_id) + end do allocate(plsub, mold=pl) call pl%spill(plsub, ldiscard, ldestructive=.false.) nsub = plsub%nbody @@ -86,13 +99,7 @@ module subroutine swiftest_discard_system(self, param) end select call pl_discards%setup(0,param) end if - ! Advance the collision id number and save it - collider%maxid_collision = max(collider%maxid_collision, maxval(nbody_system%pl%info(:)%collision_id)) - collider%maxid_collision = collider%maxid_collision + 1 - collider%collision_id = collider%maxid_collision - collider%impactors%regime = COLLRESOLVE_REGIME_MERGE - write(idstr,*) collider%collision_id - call swiftest_io_log_one_message(COLLISION_LOG_OUT, "collision_id " // trim(adjustl(idstr))) + call collision_history%take_snapshot(param,nbody_system, t, "particle") end if diff --git a/src/swiftest/swiftest_obl.f90 b/src/swiftest/swiftest_obl.f90 index 68bd64dd0..42c03eb91 100644 --- a/src/swiftest/swiftest_obl.f90 +++ b/src/swiftest/swiftest_obl.f90 @@ -246,7 +246,6 @@ module subroutine swiftest_non_spherical_cb_acc_pl(self, nbody_system) end associate return - end subroutine swiftest_non_spherical_cb_acc_pl @@ -289,8 +288,8 @@ module subroutine swiftest_non_spherical_cb_acc_tp(self, nbody_system) end do end associate - return + return end subroutine swiftest_non_spherical_cb_acc_tp From 9ecbd60fdd880a521c11cbc26598e8f4b6c41dab Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 15:07:02 -0500 Subject: [PATCH 259/324] Updated output steps of the example --- examples/spherical_harmonics_cb/spherical_harmonics_cb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py index 90e45252a..0abc41cf1 100644 --- a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py +++ b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py @@ -82,7 +82,7 @@ capm_tp = rng.uniform(0.0, 360.0, ntp) sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim.set_parameter(tstart=0.0, tstop=1.0, dt=0.01, istep_out=1, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) +sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) # Display the run configuration parameters. sim.get_parameter() From 6deeb70af873cd32205b3f2e0e3befbdfc011b34 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 27 Feb 2024 15:36:37 -0500 Subject: [PATCH 260/324] Updated a and ecc ranges to prevent loss of particles --- examples/spherical_harmonics_cb/spherical_harmonics_cb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py index 0abc41cf1..9a3578b60 100644 --- a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py +++ b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py @@ -56,8 +56,8 @@ density_pl = cb_density name_pl = ["SemiBody_01", "SemiBody_02", "SemiBody_03", "SemiBody_04", "SemiBody_05"] -a_pl = rng.uniform(150, 300, npl) -e_pl = rng.uniform(0.0, 0.2, npl) +a_pl = rng.uniform(250, 400, npl) +e_pl = rng.uniform(0.0, 0.05, npl) inc_pl = rng.uniform(0.0, 10, npl) capom_pl = rng.uniform(0.0, 360.0, npl) omega_pl = rng.uniform(0.0, 360.0, npl) @@ -74,8 +74,8 @@ ntp = 10 name_tp = ["TestParticle_01", "TestParticle_02", "TestParticle_03", "TestParticle_04", "TestParticle_05", "TestParticle_06", "TestParticle_07", "TestParticle_08", "TestParticle_09", "TestParticle_10"] -a_tp = rng.uniform(150, 300, ntp) -e_tp = rng.uniform(0.0, 0.2, ntp) +a_tp = rng.uniform(250, 400, ntp) +e_tp = rng.uniform(0.0, 0.05, ntp) inc_tp = rng.uniform(0.0, 10, ntp) capom_tp = rng.uniform(0.0, 360.0, ntp) omega_tp = rng.uniform(0.0, 360.0, ntp) From b91616e992ae08df458fdfb0ce0c97ef2fbf988d Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 15:39:13 -0500 Subject: [PATCH 261/324] Added missing doc strings and added argment validation --- swiftest/simulation_class.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index e4a5ca7c9..2317ea87a 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2424,10 +2424,10 @@ def add_body(self, rhill: float | List[float] | npt.NDArray[np.float_] | None=None, rot: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None=None, Ip: List[float] | npt.NDArray[np.float_] | None=None, + rotphase: float | List[float] | npt.NDArray[np.float_] | None=None, J2: float | List[float] | npt.NDArray[np.float_] | None=None, J4: float | List[float] | npt.NDArray[np.float_] | None=None, c_lm: List[float] | List[npt.NDArray[np.float_]] | npt.NDArray[np.float_] | None = None, - rotphase: float | List[float] | npt.NDArray[np.float_] | None=None, align_to_central_body_rotation: bool = False, **kwargs: Any ) -> None: @@ -2473,7 +2473,13 @@ def add_body(self, Ip : (3) or (n,3) array-like of float, optional Principal axes moments of inertia vectors if these are massive bodies with rotation enabled. rotphase : float, optional - rotation phase angle of the central body in degrees + rotation phase angle in degreesif these are massive bodies with rotation enabled + J2 : float, optional + Normalized J2 values (e.g. J**2 / R**2) if this is a central body (only one of J2 or c_lm can be passed) + J4 : float, optional + Normalized J4 values (e.g. J**4 / R**4) if this is a central body (only one of J4 or c_lm can be passed) + c_lm : (2,l_max+1,l_max+1) array-like of float, optional + Spherical harmonics coefficients if this is a central body (only one of J2/J4 or c_lm can be passed) align_to_central_body_rotation : bool, default False If True, the cartesian coordinates will be aligned to the rotation pole of the central body. This is only valid for when rotation is enabled. @@ -2607,7 +2613,29 @@ def input_to_clm_array(val, n): raise ValueError("Cannot use mass and Gmass inputs simultaneously!") else: Gmass = self.GU * mass - + + is_central_body = False + if J2 is not None or J4 is not None: + is_central_body = True + if c_lm is not None: + raise ValueError("Cannot use J2/J4 and c_lm inputs simultaneously!") + if c_lm is not None: + is_central_body = True + if J2 is not None or J4 is not None: + raise ValueError("Cannot use J2/J4 and c_lm inputs simultaneously!") + + if rh is not None and vh is None: + raise ValueError("If rh is passed, vh must also be passed") + if vh is not None and rh is None: + raise ValueError("If vh is passed, rh must also be passed") + + if rh is not None: + if a is not None or e is not None or inc is not None or capom is not None or omega is not None or capm is not None: + raise ValueError("Only cartesian values or orbital elements may be passed, but not both.") + if is_central_body: + if a is not None or e is not None or inc is not None or capom is not None or omega is not None or capm is not None: + raise ValueError("Orbital elements cannot be passed for a central body.") + dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, rotphase=rotphase, time=time) From 17521dad90a4ab915d59f0b6b99b4316db139215 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 15:40:08 -0500 Subject: [PATCH 262/324] Updated the io reader to be able to read in a case with no cartesian coordinates or orbital elements (a central body only) --- swiftest/io.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/swiftest/io.py b/swiftest/io.py index 33fdb1e8f..4628fe17a 100644 --- a/swiftest/io.py +++ b/swiftest/io.py @@ -858,9 +858,15 @@ def select_active_from_frame(ds, param, framenum=-1): # Select only the active particles at this time step # Remove the inactive particles if param['OUT_FORM'] == 'XV' or param['OUT_FORM'] == 'XVEL': - iactive = iframe[count_dim].where((~np.isnan(iframe['Gmass'])) | (~np.isnan(iframe['rh'].isel(space=0))), drop=True)[count_dim] + if 'rh' in iframe: + iactive = iframe[count_dim].where((~np.isnan(iframe['Gmass'])) | (~np.isnan(iframe['rh'].isel(space=0))), drop=True)[count_dim] + else: + iactive = iframe[count_dim].where(~np.isnan(iframe['Gmass'])) else: - iactive = iframe[count_dim].where((~np.isnan(iframe['Gmass'])) | (~np.isnan(iframe['a'])), drop = True)[count_dim] + if 'a' in iframe: + iactive = iframe[count_dim].where((~np.isnan(iframe['Gmass'])) | (~np.isnan(iframe['a'])), drop = True)[count_dim] + else: + iactive = iframe[count_dim].where(~np.isnan(iframe['Gmass'])) if count_dim == "id": frame = frame.sel(id=iactive.values) elif count_dim == "name": From a17eb3e4ffc13de7722d286fc67e31671f473cf9 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 15:40:38 -0500 Subject: [PATCH 263/324] Removed unecessary arguments now that it can handle a central body input --- examples/spherical_harmonics_cb/spherical_harmonics_cb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py index 0abc41cf1..280359190 100644 --- a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py +++ b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py @@ -49,7 +49,7 @@ # Add the central body # The user can pass the c_lm coefficients directly to the add_body method if they do not wish to use the clm_from_ellipsoid method. -sim.add_body(name = 'Chariklo', id = 0, mass = cb_mass, rot = cb_rot, radius = cb_radius, a = 0.0, e = 0.0, inc = 0.0, capom = 0.0, omega = 0.0, capm = 0.0, c_lm = c_lm) +sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) # Add user-defined massive bodies npl = 5 From 9e7bae4cb1775f8d0fadcf5ea106ada29e831b61 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 27 Feb 2024 15:56:12 -0500 Subject: [PATCH 264/324] Edited comment to include normalisation of c_lm. Added J2 test codes for only tps and pl plus tp. --- examples/spherical_harmonics_cb/spherical_harmonics_cb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py index 73a683640..83df9042a 100644 --- a/examples/spherical_harmonics_cb/spherical_harmonics_cb.py +++ b/examples/spherical_harmonics_cb/spherical_harmonics_cb.py @@ -43,7 +43,7 @@ # # The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS # calculates the reference radius. If lref_radius = True, the function returns the reference radius used. -# We recommend setting passing and setting a reference radius. +# We recommend setting passing and setting a reference radius. Coefficients are geodesy (4-pi) normalised. c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) From c01f007842a37743722f4a79db1e6fa13c24e449 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:06:41 -0500 Subject: [PATCH 265/324] Fixed issues related to central body initial conditions. Now it explicitly sets rh, vh, and orbital elements if it detects a central body is being passed --- swiftest/init_cond.py | 10 ++++++++++ swiftest/simulation_class.py | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/swiftest/init_cond.py b/swiftest/init_cond.py index a8770328a..889780a03 100644 --- a/swiftest/init_cond.py +++ b/swiftest/init_cond.py @@ -363,6 +363,16 @@ def solar_system_horizons(name: str, if param['ROTATION']: Ip = Ipsun rot = rotcb + if param['IN_FORM'] == 'XV': + rh = np.array([0.0, 0.0, 0.0]) + vh = np.array([0.0, 0.0, 0.0]) + elif param['IN_FORM'] == 'EL': + a = np.nan + e = np.nan + inc = np.nan + capom = np.nan + omega = np.nan + capm = np.nan else: # Fetch solar system ephemerides from Horizons if ephemeris_id is None: ephemeris_id = name diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 2317ea87a..90e96b969 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2635,6 +2635,19 @@ def input_to_clm_array(val, n): if is_central_body: if a is not None or e is not None or inc is not None or capom is not None or omega is not None or capm is not None: raise ValueError("Orbital elements cannot be passed for a central body.") + if nbodies > 1: + raise ValueError("Only one central body may be passed.") + if rh is None: + rh = np.zeros((1,3)) + if vh is None: + vh = np.zeros((1,3)) + a = np.nan + e = np.nan + inc = np.nan + capom = np.nan + omega = np.nan + capm = np.nan + dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, rotphase=rotphase, time=time) From 2bfd4c701d2455f9b60f383de22a586f169df5b7 Mon Sep 17 00:00:00 2001 From: anand43 Date: Tue, 27 Feb 2024 16:09:50 -0500 Subject: [PATCH 266/324] Added J2 tests for 1 tp, and 1 tp+pl. Also edited a comment to include clm normalisation type --- examples/spherical_harmonics_cb/.gitignore | 4 +- .../J2_test_pl_and_tp.py | 99 +++++++++++++++++++ examples/spherical_harmonics_cb/J2_test_tp.py | 80 +++++++++++++++ 3 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 examples/spherical_harmonics_cb/J2_test_pl_and_tp.py create mode 100644 examples/spherical_harmonics_cb/J2_test_tp.py diff --git a/examples/spherical_harmonics_cb/.gitignore b/examples/spherical_harmonics_cb/.gitignore index 7543355dd..94eee0157 100644 --- a/examples/spherical_harmonics_cb/.gitignore +++ b/examples/spherical_harmonics_cb/.gitignore @@ -1 +1,3 @@ -!spherical_harmonics_cb.py \ No newline at end of file +!spherical_harmonics_cb.py +!J2_test_tp.py +!J2_test_pl_and_tp.py \ No newline at end of file diff --git a/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py b/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py new file mode 100644 index 000000000..e169bcae2 --- /dev/null +++ b/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +""" + Copyright 2024 - The Minton Group at Purdue University + This file is part of Swiftest. + Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with Swiftest. + If not, see: https://www.gnu.org/licenses. +""" + +""" +Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the +SyMBA integrator. Using Chariklo as the example body with axes measurements taken from Leiva, et al (2017) (Jacobi +Ellipsoid model). All simulation outputs are stored in the /simdata subdirectory. + +""" + +import swiftest +import numpy as np + +seed = 123 +rng = np.random.default_rng(seed=seed) + +# set up swiftest simulation with relevant units (here they are km, days, and kg) +sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg') +sim.clean() + +# Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) +cb_mass = 6.1e18 # kg +cb_radius = 123 # km +cb_a = 157 # km +cb_b = 139 # km +cb_c = 86 # km +cb_volume = 4.0 / 3 * np.pi * cb_radius**3 # km^3 +cb_density = cb_mass / cb_volume +cb_T_rotation = 7.004 / 24.0 # converting from hours to julian days (TU) +cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/d + +# Extract the spherical harmonics coefficients (c_lm) from axes measurements +# +# The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS +# calculates the reference radius. If lref_radius = True, the function returns the reference radius used. +# We recommend setting passing and setting a reference radius. Coefficients are geodesy (4-pi) normalised. + +c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) + +# extracting only the J2 terms +tmp20 = c_lm[0, 2, 0] # c_20 = -J2 +c_lm = np.zeros(np.shape(c_lm)) +c_lm[0, 2, 0] = tmp20 + +J2 = -tmp20 * np.sqrt(5) # unnormalised J2 term +j2rp2 = J2 * cb_radius**2 + +# Add the central body +# The user can pass the c_lm coefficients directly to the add_body method if they do not wish to use the clm_from_ellipsoid method. +sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) + +# Add 1 user-defined massive particle +npl = 1 +density_pl = cb_density + +name_pl = ["SemiBody_01"] +a_pl = 400.0 +e_pl = 0.03 +inc_pl = 0.0 +capom_pl = 90.0 +omega_pl = 90.0 +capm_pl = 90.0 +R_pl = 1.0 +M_pl = 4.0 / 3 * np.pi * R_pl**3 * density_pl +Ip_pl = np.full((npl,3),0.4,) +rot_pl = np.zeros((npl,3)) +mtiny = 1.1 * np.max(M_pl) + +sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + +# Add 1 user-defined test particle. +ntp = 1 + +name_tp = ["TestParticle_01"] +a_tp = 300 +e_tp = 0.05 +inc_tp = 10 +capom_tp = 0.0 +omega_tp = 0.0 +capm_tp = 0.0 + +sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) + +# Display the run configuration parameters. +sim.get_parameter() + +# Run the simulation. Arguments may be defined here or thorugh the swiftest.Simulation() method. +sim.run() diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py new file mode 100644 index 000000000..2f1a76147 --- /dev/null +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +""" + Copyright 2024 - The Minton Group at Purdue University + This file is part of Swiftest. + Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with Swiftest. + If not, see: https://www.gnu.org/licenses. +""" + +""" +Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the +SyMBA integrator. Using Chariklo as the example body with axes measurements taken from Leiva, et al (2017) (Jacobi +Ellipsoid model). All simulation outputs are stored in the /simdata subdirectory. + +""" + +import swiftest +import numpy as np + +seed = 123 +rng = np.random.default_rng(seed=seed) + +# set up swiftest simulation with relevant units (here they are km, days, and kg) +sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg') +sim.clean() + +# Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) +cb_mass = 6.1e18 # kg +cb_radius = 123 # km +cb_a = 157 # km +cb_b = 139 # km +cb_c = 86 # km +cb_volume = 4.0 / 3 * np.pi * cb_radius**3 # km^3 +cb_density = cb_mass / cb_volume +cb_T_rotation = 7.004 / 24.0 # converting from hours to julian days (TU) +cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/d + +# Extract the spherical harmonics coefficients (c_lm) from axes measurements +# +# The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS +# calculates the reference radius. If lref_radius = True, the function returns the reference radius used. +# We recommend setting passing and setting a reference radius. Coefficients are geodesy (4-pi) normalised. + +c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) + +# extracting only the J2 terms +tmp20 = c_lm[0, 2, 0] # c_20 = -J2 +c_lm = np.zeros(np.shape(c_lm)) +c_lm[0, 2, 0] = tmp20 + +J2 = -tmp20 * np.sqrt(5) # unnormalised J2 term +j2rp2 = J2 * cb_radius**2 + +# Add the central body +# The user can pass the c_lm coefficients directly to the add_body method if they do not wish to use the clm_from_ellipsoid method. +sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) + +# Add 1 user-defined test particle. +ntp = 1 + +name_tp = ["TestParticle_01"] +a_tp = 300 +e_tp = 0.05 +inc_tp = 10 +capom_tp = 0.0 +omega_tp = 0.0 +capm_tp = 0.0 + +sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) + +# Display the run configuration parameters. +sim.get_parameter() + +# Run the simulation. Arguments may be defined here or thorugh the swiftest.Simulation() method. +sim.run() From dd5b7b70d9d63bfdb668009c7191dac8eb885980 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:15:34 -0500 Subject: [PATCH 267/324] Updated docstring for accuracy --- swiftest/simulation_class.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 90e96b969..6bc6dee17 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2475,9 +2475,9 @@ def add_body(self, rotphase : float, optional rotation phase angle in degreesif these are massive bodies with rotation enabled J2 : float, optional - Normalized J2 values (e.g. J**2 / R**2) if this is a central body (only one of J2 or c_lm can be passed) + Normalized J2 values (e.g. J2*R**2, where R is the central body radius) if this is a central body (only one of J2 or c_lm can be passed) J4 : float, optional - Normalized J4 values (e.g. J**4 / R**4) if this is a central body (only one of J4 or c_lm can be passed) + Normalized J4 values (e.g. J4*R**4, where R is the central body radius) if this is a central body (only one of J4 or c_lm can be passed) c_lm : (2,l_max+1,l_max+1) array-like of float, optional Spherical harmonics coefficients if this is a central body (only one of J2/J4 or c_lm can be passed) align_to_central_body_rotation : bool, default False From c95e7f533d970ab5e677acfe6ba2f2243902d368 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:30:13 -0500 Subject: [PATCH 268/324] Altered example for J2 test case so that it can compare the c_lm vs J2 versions. Also fixed some issues with getting central body initial conditions in correctly when in EL input mode --- examples/spherical_harmonics_cb/J2_test_tp.py | 50 +++++++++++-------- swiftest/simulation_class.py | 23 +++++---- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py index 2f1a76147..afcd91cfe 100644 --- a/examples/spherical_harmonics_cb/J2_test_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -24,9 +24,9 @@ seed = 123 rng = np.random.default_rng(seed=seed) -# set up swiftest simulation with relevant units (here they are km, days, and kg) -sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg') -sim.clean() + + + # Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) cb_mass = 6.1e18 # kg @@ -39,6 +39,17 @@ cb_T_rotation = 7.004 / 24.0 # converting from hours to julian days (TU) cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/d +# Add 1 user-defined test particle. +ntp = 1 + +name_tp = ["TestParticle_01"] +a_tp = 300 +e_tp = 0.05 +inc_tp = 10 +capom_tp = 0.0 +omega_tp = 0.0 +capm_tp = 0.0 + # Extract the spherical harmonics coefficients (c_lm) from axes measurements # # The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS @@ -55,26 +66,21 @@ J2 = -tmp20 * np.sqrt(5) # unnormalised J2 term j2rp2 = J2 * cb_radius**2 -# Add the central body -# The user can pass the c_lm coefficients directly to the add_body method if they do not wish to use the clm_from_ellipsoid method. -sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) - -# Add 1 user-defined test particle. -ntp = 1 +# set up swiftest simulation with relevant units (here they are km, days, and kg) +sim_shgrav = swiftest.Simulation(simdir="shgrav",DU2M = 1e3, TU = 'd', MU = 'kg') -name_tp = ["TestParticle_01"] -a_tp = 300 -e_tp = 0.05 -inc_tp = 10 -capom_tp = 0.0 -omega_tp = 0.0 -capm_tp = 0.0 +sim_shgrav.clean() +# Use the shgrav version where you input a set of spherical harmonics coefficients +sim_shgrav.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) +sim_shgrav.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) -sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) +# Use the original "oblate" version where you pass J2 (and/or J4) +sim_obl = swiftest.Simulation(simdir="obl", DU2M = 1e3, TU='d', MU='kg') +sim_obl.clean() +sim_obl.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, J2 = j2rp2) +sim_obl.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) -# Display the run configuration parameters. -sim.get_parameter() +ds_diff = sim_shgrav.data - sim_obl.data -# Run the simulation. Arguments may be defined here or thorugh the swiftest.Simulation() method. -sim.run() diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index 6bc6dee17..abc552072 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -2637,17 +2637,18 @@ def input_to_clm_array(val, n): raise ValueError("Orbital elements cannot be passed for a central body.") if nbodies > 1: raise ValueError("Only one central body may be passed.") - if rh is None: - rh = np.zeros((1,3)) - if vh is None: - vh = np.zeros((1,3)) - a = np.nan - e = np.nan - inc = np.nan - capom = np.nan - omega = np.nan - capm = np.nan - + if self.param['IN_FORM'] == "XV": + if rh is None: + rh = np.zeros((1,3)) + if vh is None: + vh = np.zeros((1,3)) + elif self.param['IN_FORM'] == "EL": + a = np.array([np.nan]) + e = np.array([np.nan]) + inc = np.array([np.nan]) + capom = np.array([np.nan]) + omega = np.array([np.nan]) + capm = np.array([np.nan]) dsnew = init_cond.vec2xr(self.param, name=name, a=a, e=e, inc=inc, capom=capom, omega=omega, capm=capm, id=id, Gmass=Gmass, radius=radius, rhill=rhill, Ip=Ip, rh=rh, vh=vh,rot=rot, j2rp2=J2, j4rp4=J4, c_lm=c_lm, rotphase=rotphase, time=time) From 7d5209b95fda3e323475d5aa8ff9e214cdc5182a Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:38:53 -0500 Subject: [PATCH 269/324] Added a check for no massive bodies when computing nplm. Refactored to new documentation format. --- src/symba/symba_util.f90 | 163 ++++++++++++++++++++++++++------------- 1 file changed, 108 insertions(+), 55 deletions(-) diff --git a/src/symba/symba_util.f90 b/src/symba/symba_util.f90 index e54a96f5c..d98e0f57d 100644 --- a/src/symba/symba_util.f90 +++ b/src/symba/symba_util.f90 @@ -19,16 +19,19 @@ module subroutine symba_util_append_pl(self, source, lsource_mask) !! This method will automatically resize the destination body if it is too small implicit none !! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - class(swiftest_body), intent(in) :: source !! Source object to append - logical, dimension(:), intent(in) :: lsource_mask !! Logical mask indicating which elements to append to + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object + class(swiftest_body), intent(in) :: source + !! Source object to append + logical, dimension(:), intent(in) :: lsource_mask + !! Logical mask indicating which elements to append to select type(source) class is (symba_pl) call util_append(self%levelg, source%levelg, lsource_mask=lsource_mask) call util_append(self%levelm, source%levelm, lsource_mask=lsource_mask) - - call swiftest_util_append_pl(self, source, lsource_mask) ! Note: helio_pl does not have its own append method, so we skip back to the base class + ! Note: helio_pl does not have its own append method, so we skip back to the base class + call swiftest_util_append_pl(self, source, lsource_mask) class default write(*,*) "Invalid object passed to the append method. Source must be of class symba_pl or its descendents!" call base_util_exit(FAILURE) @@ -45,16 +48,19 @@ module subroutine symba_util_append_tp(self, source, lsource_mask) !! This method will automatically resize the destination body if it is too small implicit none !! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object - class(swiftest_body), intent(in) :: source !! Source object to append - logical, dimension(:), intent(in) :: lsource_mask !! Logical mask indicating which elements to append to + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object + class(swiftest_body), intent(in) :: source + !! Source object to append + logical, dimension(:), intent(in) :: lsource_mask + !! Logical mask indicating which elements to append to select type(source) class is (symba_tp) call util_append(self%levelg, source%levelg, lsource_mask=lsource_mask) call util_append(self%levelm, source%levelm, lsource_mask=lsource_mask) - - call swiftest_util_append_tp(self, source, lsource_mask) ! Note: helio_tp does not have its own append method, so we skip back to the base class + ! Note: helio_tp does not have its own append method, so we skip back to the base class + call swiftest_util_append_tp(self, source, lsource_mask) class default write(*,*) "Invalid object passed to the append method. Source must be of class symba_tp or its descendents!" call base_util_exit(FAILURE) @@ -70,7 +76,8 @@ module subroutine symba_util_dealloc_pl(self) !! Deallocates all allocatabale arrays implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object if (allocated(self%levelg)) deallocate(self%levelg) if (allocated(self%levelm)) deallocate(self%levelm) @@ -88,6 +95,7 @@ module subroutine symba_util_dealloc_system(self) implicit none ! Arguments class(symba_nbody_system), intent(inout) :: self + !! SyMBA nbody_system object self%irec = -1 call self%helio_nbody_system%dealloc() @@ -102,7 +110,8 @@ module subroutine symba_util_dealloc_tp(self) !! Deallocates all allocatabale arrays implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object if (allocated(self%levelg)) deallocate(self%levelg) if (allocated(self%levelm)) deallocate(self%levelm) @@ -150,17 +159,20 @@ module subroutine symba_util_fill_tp(self, inserts, lfill_list) !! implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object - class(swiftest_body), intent(in) :: inserts !! Inserted object - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object + class(swiftest_body), intent(in) :: inserts + !! Inserted object + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps associate(keeps => self) select type(inserts) class is (symba_tp) call util_fill(keeps%levelg, inserts%levelg, lfill_list) call util_fill(keeps%levelm, inserts%levelm, lfill_list) - - call swiftest_util_fill_tp(keeps, inserts, lfill_list) ! Note: helio_tp does not have its own fill method, so we skip back to the base class + ! Note: helio_tp does not have its own fill method, so we skip back to the base class + call swiftest_util_fill_tp(keeps, inserts, lfill_list) class default write(*,*) "Invalid object passed to the fill method. Source must be of class symba_tp or its descendents!" call base_util_exit(FAILURE) @@ -184,11 +196,18 @@ module subroutine symba_util_flatten_eucl_plpl(self, param) !! 2019. hal-0204751 implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters ! Internals integer(I8B) :: npl, nplm + if (self%nbody == 0) then + self%nplm = 0 + return + end if + associate(pl => self, nplplm => self%nplplm) npl = int(self%nbody, kind=I8B) if (param%lmtiny_pl) then @@ -198,7 +217,8 @@ module subroutine symba_util_flatten_eucl_plpl(self, param) nplm = npl end if pl%nplm = int(nplm, kind=I4B) - nplplm = nplm * npl - nplm * (nplm + 1_I8B) / 2_I8B ! number of entries in a strict lower triangle, npl x npl, minus first column including only mutually interacting bodies + ! number of entries in a strict lower triangle, npl x npl, minus first column including only mutually interacting bodies + nplplm = nplm * npl - nplm * (nplm + 1_I8B) / 2_I8B call swiftest_util_flatten_eucl_plpl(pl, param) end associate @@ -213,8 +233,10 @@ module subroutine symba_util_resize_pl(self, nnew) !! Checks the current size of a SyMBA massive body object against the requested size and resizes it if it is too small. implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - integer(I4B), intent(in) :: nnew !! New size neded + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object + integer(I4B), intent(in) :: nnew + !! New size neded call util_resize(self%levelg, nnew) call util_resize(self%levelm, nnew) @@ -230,8 +252,10 @@ module subroutine symba_util_resize_tp(self, nnew) !! Checks the current size of a test particle object against the requested size and resizes it if it is too small. implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object - integer(I4B), intent(in) :: nnew !! New size neded + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object + integer(I4B), intent(in):: nnew + !! New size neded call util_resize(self%levelg, nnew) call util_resize(self%levelm, nnew) @@ -248,8 +272,10 @@ module subroutine symba_util_set_renc(self, scale) !! implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - integer(I4B), intent(in) :: scale !! Current recursion depth + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object + integer(I4B), intent(in) :: scale + !! Current recursion depth ! Internals integer(I4B) :: i real(DP) :: rshell_irec @@ -275,9 +301,12 @@ module subroutine symba_util_setup_initialize_system(self, system_history, param !! implicit none ! Arguments - class(symba_nbody_system), intent(inout) :: self !! SyMBA nbody_system object - class(swiftest_storage), allocatable, intent(inout) :: system_history !! Stores the system history between output dumps - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + class(symba_nbody_system), intent(inout) :: self + !! SyMBA nbody_system object + class(swiftest_storage),allocatable, intent(inout) :: system_history + !! Stores the system history between output dumps + class(swiftest_parameters), intent(inout) :: param + !! Current run configuration parameters ! Call parent method associate(nbody_system => self) @@ -312,11 +341,14 @@ module subroutine symba_util_setup_pl(self, n, param) !! Equivalent in functionality to David E. Kaufmann's Swifter routine symba_util_setup.f90 implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - integer(I4B), intent(in) :: n !! Number of particles to allocate space for - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameter - - !> Call allocation method for parent class. + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object + integer(I4B), intent(in) :: n + !! Number of particles to allocate space for + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameter + + ! Call allocation method for parent class. call self%helio_pl%setup(n, param) if (n == 0) return @@ -337,9 +369,12 @@ module subroutine symba_util_setup_tp(self, n, param) !! Equivalent in functionality to David E. Kaufmann's Swifter routine whm_util_setup.f90 implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object - integer(I4B), intent(in) :: n !! Number of particles to allocate space for - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameter + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object + integer(I4B), intent(in) :: n + !! Number of particles to allocate space for + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameter !> Call allocation method for parent class. call self%helio_tp%setup(n, param) @@ -362,9 +397,12 @@ module subroutine symba_util_sort_pl(self, sortby, ascending) !! sortby is a string indicating which array component to sort. implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - character(*), intent(in) :: sortby !! Sorting attribute - logical, intent(in) :: ascending !! Logical flag indicating whether or not the sorting should be in ascending or descending order + class(symba_pl), intent(inout) :: self + !! SyMBA massive body object + character(*), intent(in) :: sortby + !! Sorting attribute + logical, intent(in) :: ascending + !! Logical flag indicating whether or not the sorting should be in ascending or descending order ! Internals integer(I4B), dimension(:), allocatable :: ind integer(I4B) :: direction @@ -403,9 +441,12 @@ module subroutine symba_util_sort_tp(self, sortby, ascending) !! sortby is a string indicating which array component to sort. implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object - character(*), intent(in) :: sortby !! Sorting attribute - logical, intent(in) :: ascending !! Logical flag indicating whether or not the sorting should be in ascending or descending order + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object + character(*), intent(in) :: sortby + !! Sorting attribute + logical, intent(in) :: ascending + !! Logical flag indicating whether or not the sorting should be in ascending or descending order ! Internals integer(I4B), dimension(:), allocatable :: ind integer(I4B) :: direction @@ -445,8 +486,10 @@ module subroutine symba_util_sort_rearrange_pl(self, ind) !! This is a helper utility used to make polymorphic sorting work on Swiftest structures. implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA massive body object - integer(I4B), dimension(:), intent(in) :: ind !! Index array used to restructure the body (should contain all 1:n index values in the desired order) + class(symba_pl), intent(inout) :: self ! + ! SyMBA massive body object + integer(I4B), dimension(:), intent(in) :: ind + !! Index array used to restructure the body (should contain all 1:n index values in the desired order) associate(pl => self, npl => self%nbody) call util_sort_rearrange(pl%levelg, ind, npl) @@ -465,8 +508,10 @@ module subroutine symba_util_sort_rearrange_tp(self, ind) !! This is a helper utility used to make polymorphic sorting work on Swiftest structures. implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA test particle object - integer(I4B), dimension(:), intent(in) :: ind !! Index array used to restructure the body (should contain all 1:n index values in the desired order) + class(symba_tp), intent(inout) :: self + !! SyMBA test particle object + integer(I4B), dimension(:), intent(in) :: ind + !! Index array used to restructure the body (should contain all 1:n index values in the desired order) associate(tp => self, ntp => self%nbody) call util_sort_rearrange(tp%nplenc, ind, ntp) @@ -487,10 +532,14 @@ module subroutine symba_util_spill_pl(self, discards, lspill_list, ldestructive) !! Adapted from David E. Kaufmann's Swifter routine whm_discard_spill.f90 implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA 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 - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter body by removing the discard list + class(symba_pl), intent(inout) :: self + !! SyMBA 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 + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter body by removing the discard list ! For each component, pack the discarded bodies into the discard object and do the inverse with the keeps !> Spill all the common components @@ -518,10 +567,14 @@ module subroutine symba_util_spill_tp(self, discards, lspill_list, ldestructive) !! Adapted from David E. Kaufmann's Swifter routine whm_discard_spill.f90 implicit none ! Arguments - class(symba_tp), intent(inout) :: self !! SyMBA 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 - logical, intent(in) :: ldestructive !! Logical flag indicating whether or not this operation should alter body by removing the discard list + class(symba_tp), intent(inout) :: self + !! SyMBA 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 + logical, intent(in) :: ldestructive + !! Logical flag indicating whether or not this operation should alter body by removing the discard list ! For each component, pack the discarded bodies into the discard object and do the inverse with the keeps !> Spill all the common components From 7f87b1d123413534dcd398e9d3cc68980917f25a Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:39:52 -0500 Subject: [PATCH 270/324] Refactor for new documentation format --- src/symba/symba_util.f90 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/symba/symba_util.f90 b/src/symba/symba_util.f90 index d98e0f57d..46a34a46c 100644 --- a/src/symba/symba_util.f90 +++ b/src/symba/symba_util.f90 @@ -130,17 +130,20 @@ module subroutine symba_util_fill_pl(self, inserts, lfill_list) !! implicit none ! Arguments - class(symba_pl), intent(inout) :: self !! SyMBA masive body object - class(swiftest_body), intent(in) :: inserts !! Inserted object - logical, dimension(:), intent(in) :: lfill_list !! Logical array of bodies to merge into the keeps + class(symba_pl), intent(inout) :: self + !! SyMBA masive body object + class(swiftest_body), intent(in) :: inserts + !! Inserted object + logical, dimension(:), intent(in) :: lfill_list + !! Logical array of bodies to merge into the keeps associate(keeps => self) select type(inserts) class is (symba_pl) call util_fill(keeps%levelg, inserts%levelg, lfill_list) call util_fill(keeps%levelm, inserts%levelm, lfill_list) - - call swiftest_util_fill_pl(keeps, inserts, lfill_list) ! Note: helio_pl does not have its own fill method, so we skip back to the base class + ! Note: helio_pl does not have its own fill method, so we skip back to the base class + call swiftest_util_fill_pl(keeps, inserts, lfill_list) class default write(*,*) "Invalid object passed to the fill method. Source must be of class symba_pl or its descendents!" call base_util_exit(FAILURE) From e6731133ad4a4f84f65ff4b3794984431c060818 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:46:08 -0500 Subject: [PATCH 271/324] Fixed problem caused by trying to compute energy errors when there are no massive bodies. Use total energy for the denominator of normalizations rather than orbital energy, which is 0 in that case. --- src/swiftest/swiftest_io.f90 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 0bbd4c7cd..c50345cd3 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -168,16 +168,19 @@ module subroutine swiftest_io_conservation_report(self, param, lterminal) end if if (.not.param%lfirstenergy) then - - nbody_system%ke_orbit_error = (ke_orbit_now - nbody_system%ke_orbit_orig) / abs(nbody_system%E_orbit_orig) - nbody_system%ke_spin_error = (ke_spin_now - nbody_system%ke_spin_orig) / abs(nbody_system%E_orbit_orig) - nbody_system%pe_error = (pe_now - nbody_system%pe_orig) / abs(nbody_system%E_orbit_orig) + nbody_system%ke_orbit_error = (ke_orbit_now - nbody_system%ke_orbit_orig) / abs(nbody_system%te_orig) + nbody_system%ke_spin_error = (ke_spin_now - nbody_system%ke_spin_orig) / abs(nbody_system%te_orig) + nbody_system%pe_error = (pe_now - nbody_system%pe_orig) / abs(nbody_system%te_orig) be_cb_orig = -(3 * cb%GM0**2 / param%GU) / (5 * cb%R0) nbody_system%be_error = (be_now - nbody_system%be_orig) / abs(nbody_system%te_orig) + (be_cb_now - be_cb_orig) & / abs(nbody_system%te_orig) - nbody_system%E_orbit_error = (E_orbit_now - nbody_system%E_orbit_orig) / abs(nbody_system%E_orbit_orig) + if (abs(nbody_system%E_orbit_orig) < 10*tiny(1.0_DP)) then + nbody_system%E_orbit_error = 0.0_DP + else + nbody_system%E_orbit_error = (E_orbit_now - nbody_system%E_orbit_orig) / abs(nbody_system%E_orbit_orig) + end if nbody_system%Ecoll_error = nbody_system%E_collisions / abs(nbody_system%te_orig) nbody_system%E_untracked_error = nbody_system%E_untracked / abs(nbody_system%te_orig) nbody_system%te_error = (nbody_system%te - nbody_system%te_orig - nbody_system%E_collisions - nbody_system%E_untracked)& From 6f7fb92f190ca717720ee6dab44e9f120d23b183 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:50:06 -0500 Subject: [PATCH 272/324] Updated example to print out difference values between the two models --- examples/spherical_harmonics_cb/J2_test_tp.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py index afcd91cfe..41f4bd313 100644 --- a/examples/spherical_harmonics_cb/J2_test_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -82,5 +82,8 @@ sim_obl.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) -ds_diff = sim_shgrav.data - sim_obl.data +diff_vars = ['a','e','inc','capom','omega','capm','rh','vh'] +ds_diff = sim_shgrav.data[diff_vars] - sim_obl.data[diff_vars] + +print(ds_diff.isel(time=-1,name=-1)) From 380d6ab226ca0267f1ac0c5b6297baf5fc06f952 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:52:17 -0500 Subject: [PATCH 273/324] Updated example to print relative errors of all quantities --- examples/spherical_harmonics_cb/J2_test_tp.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py index 41f4bd313..e4c432003 100644 --- a/examples/spherical_harmonics_cb/J2_test_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -73,17 +73,18 @@ # Use the shgrav version where you input a set of spherical harmonics coefficients sim_shgrav.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) sim_shgrav.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) +sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, integrator='whm') # Use the original "oblate" version where you pass J2 (and/or J4) sim_obl = swiftest.Simulation(simdir="obl", DU2M = 1e3, TU='d', MU='kg') sim_obl.clean() sim_obl.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, J2 = j2rp2) sim_obl.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True) +sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, integrator='whm') diff_vars = ['a','e','inc','capom','omega','capm','rh','vh'] ds_diff = sim_shgrav.data[diff_vars] - sim_obl.data[diff_vars] +ds_diff /= sim_obl.data[diff_vars] print(ds_diff.isel(time=-1,name=-1)) From 8923eb875a7a0abac383e8f8e6d2fed093a893b8 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 16:57:10 -0500 Subject: [PATCH 274/324] Dropped the step size and limited the amount of output data to the initial and final values. --- examples/spherical_harmonics_cb/J2_test_tp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py index e4c432003..4ce728461 100644 --- a/examples/spherical_harmonics_cb/J2_test_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -73,14 +73,14 @@ # Use the shgrav version where you input a set of spherical harmonics coefficients sim_shgrav.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) sim_shgrav.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, integrator='whm') +sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.001, tstep_out=10.0, dump_cadence=0, integrator='whm') # Use the original "oblate" version where you pass J2 (and/or J4) sim_obl = swiftest.Simulation(simdir="obl", DU2M = 1e3, TU='d', MU='kg') sim_obl.clean() sim_obl.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, J2 = j2rp2) sim_obl.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, integrator='whm') +sim_obl.run(tstart=0.0, tstop=10.0, dt=0.001, tstep_out=10.0, dump_cadence=0, integrator='whm') diff_vars = ['a','e','inc','capom','omega','capm','rh','vh'] ds_diff = sim_shgrav.data[diff_vars] - sim_obl.data[diff_vars] From 59ea228ec60e883fc82b5f6928c5bca98d19499d Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 17:05:21 -0500 Subject: [PATCH 275/324] Updated test case to have self-consistent values of everything --- examples/spherical_harmonics_cb/J2_test_tp.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py index 4ce728461..b4d009b84 100644 --- a/examples/spherical_harmonics_cb/J2_test_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -30,11 +30,10 @@ # Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) cb_mass = 6.1e18 # kg -cb_radius = 123 # km -cb_a = 157 # km -cb_b = 139 # km -cb_c = 86 # km -cb_volume = 4.0 / 3 * np.pi * cb_radius**3 # km^3 +cb_a = 160 # km +cb_b = 160 # km +cb_c = 90 # km +cb_volume = 4.0 / 3 * np.pi * cb_a*cb_b*cb_c**3 # km^3 cb_density = cb_mass / cb_volume cb_T_rotation = 7.004 / 24.0 # converting from hours to julian days (TU) cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/d @@ -56,7 +55,7 @@ # calculates the reference radius. If lref_radius = True, the function returns the reference radius used. # We recommend setting passing and setting a reference radius. Coefficients are geodesy (4-pi) normalised. -c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) +c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True) # extracting only the J2 terms tmp20 = c_lm[0, 2, 0] # c_20 = -J2 @@ -71,16 +70,16 @@ sim_shgrav.clean() # Use the shgrav version where you input a set of spherical harmonics coefficients -sim_shgrav.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) +sim_shgrav.add_body(name = 'OblateBody', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) sim_shgrav.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.001, tstep_out=10.0, dump_cadence=0, integrator='whm') +sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.01, tstep_out=10.0, dump_cadence=0, integrator='whm') # Use the original "oblate" version where you pass J2 (and/or J4) sim_obl = swiftest.Simulation(simdir="obl", DU2M = 1e3, TU='d', MU='kg') sim_obl.clean() -sim_obl.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, J2 = j2rp2) +sim_obl.add_body(name = 'OblateBody', mass = cb_mass, rot = cb_rot, radius = cb_radius, J2 = j2rp2) sim_obl.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim_obl.run(tstart=0.0, tstop=10.0, dt=0.001, tstep_out=10.0, dump_cadence=0, integrator='whm') +sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, tstep_out=10.0, dump_cadence=0, integrator='whm') diff_vars = ['a','e','inc','capom','omega','capm','rh','vh'] ds_diff = sim_shgrav.data[diff_vars] - sim_obl.data[diff_vars] From 20455694781b614be62d9ed3d248d0d2a1a825e5 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 17:06:32 -0500 Subject: [PATCH 276/324] Updated comments for consistency --- examples/spherical_harmonics_cb/J2_test_tp.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/spherical_harmonics_cb/J2_test_tp.py b/examples/spherical_harmonics_cb/J2_test_tp.py index b4d009b84..1c433f0d3 100644 --- a/examples/spherical_harmonics_cb/J2_test_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_tp.py @@ -12,10 +12,7 @@ """ """ -Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the -SyMBA integrator. Using Chariklo as the example body with axes measurements taken from Leiva, et al (2017) (Jacobi -Ellipsoid model). All simulation outputs are stored in the /simdata subdirectory. - +Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the WHM integrator. """ import swiftest @@ -25,10 +22,7 @@ rng = np.random.default_rng(seed=seed) - - - -# Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) +# Central Body Parameters (just an oblate sphere to test) cb_mass = 6.1e18 # kg cb_a = 160 # km cb_b = 160 # km From a711f08ef59c742ad43b35d506e10ccdb43ed34d Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 27 Feb 2024 17:15:01 -0500 Subject: [PATCH 277/324] Upated the test case that includes a massive body --- .../J2_test_pl_and_tp.py | 106 +++++++++--------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py b/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py index e169bcae2..62bd7228a 100644 --- a/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py +++ b/examples/spherical_harmonics_cb/J2_test_pl_and_tp.py @@ -12,10 +12,7 @@ """ """ -Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the -SyMBA integrator. Using Chariklo as the example body with axes measurements taken from Leiva, et al (2017) (Jacobi -Ellipsoid model). All simulation outputs are stored in the /simdata subdirectory. - +Generates and runs a set of Swiftest input files from initial conditions for the Spherical Harmonics features with the WHM integrator. """ import swiftest @@ -24,49 +21,37 @@ seed = 123 rng = np.random.default_rng(seed=seed) -# set up swiftest simulation with relevant units (here they are km, days, and kg) -sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg') -sim.clean() -# Central Body Parameters (Chariklo parameters from Leiva, et al (2017) (Jacobi Ellipsoid model)) +# Central Body Parameters (just an oblate sphere to test) cb_mass = 6.1e18 # kg -cb_radius = 123 # km -cb_a = 157 # km -cb_b = 139 # km -cb_c = 86 # km -cb_volume = 4.0 / 3 * np.pi * cb_radius**3 # km^3 +cb_a = 160 # km +cb_b = 160 # km +cb_c = 90 # km +cb_volume = 4.0 / 3 * np.pi * cb_a*cb_b*cb_c**3 # km^3 cb_density = cb_mass / cb_volume cb_T_rotation = 7.004 / 24.0 # converting from hours to julian days (TU) cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/d -# Extract the spherical harmonics coefficients (c_lm) from axes measurements -# -# The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS -# calculates the reference radius. If lref_radius = True, the function returns the reference radius used. -# We recommend setting passing and setting a reference radius. Coefficients are geodesy (4-pi) normalised. - -c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) - -# extracting only the J2 terms -tmp20 = c_lm[0, 2, 0] # c_20 = -J2 -c_lm = np.zeros(np.shape(c_lm)) -c_lm[0, 2, 0] = tmp20 +# Add 1 user-defined test particle. +ntp = 1 -J2 = -tmp20 * np.sqrt(5) # unnormalised J2 term -j2rp2 = J2 * cb_radius**2 +name_tp = ["TestParticle_01"] +a_tp = 400 +e_tp = 0.05 +inc_tp = 10 +capom_tp = 0.0 +omega_tp = 0.0 +capm_tp = 0.0 -# Add the central body -# The user can pass the c_lm coefficients directly to the add_body method if they do not wish to use the clm_from_ellipsoid method. -sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) # Add 1 user-defined massive particle npl = 1 density_pl = cb_density -name_pl = ["SemiBody_01"] -a_pl = 400.0 +name_pl = ["MassiveBody_01"] +a_pl = 300.0 e_pl = 0.03 -inc_pl = 0.0 +inc_pl = 0.001 capom_pl = 90.0 omega_pl = 90.0 capm_pl = 90.0 @@ -74,26 +59,47 @@ M_pl = 4.0 / 3 * np.pi * R_pl**3 * density_pl Ip_pl = np.full((npl,3),0.4,) rot_pl = np.zeros((npl,3)) -mtiny = 1.1 * np.max(M_pl) +mtiny = 0.1 * np.max(M_pl) -sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) -# Add 1 user-defined test particle. -ntp = 1 +# Extract the spherical harmonics coefficients (c_lm) from axes measurements +# +# The user can pass an optional reference radius at which the coefficients are calculated. If not provided, SHTOOLS +# calculates the reference radius. If lref_radius = True, the function returns the reference radius used. +# We recommend setting passing and setting a reference radius. Coefficients are geodesy (4-pi) normalised. -name_tp = ["TestParticle_01"] -a_tp = 300 -e_tp = 0.05 -inc_tp = 10 -capom_tp = 0.0 -omega_tp = 0.0 -capm_tp = 0.0 +c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True) -sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) -sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) +# extracting only the J2 terms +tmp20 = c_lm[0, 2, 0] # c_20 = -J2 +c_lm = np.zeros(np.shape(c_lm)) +c_lm[0, 2, 0] = tmp20 -# Display the run configuration parameters. -sim.get_parameter() +J2 = -tmp20 * np.sqrt(5) # unnormalised J2 term +j2rp2 = J2 * cb_radius**2 + +# set up swiftest simulation with relevant units (here they are km, days, and kg) +sim_shgrav = swiftest.Simulation(simdir="shgrav",DU2M = 1e3, TU = 'd', MU = 'kg') + +sim_shgrav.clean() +# Use the shgrav version where you input a set of spherical harmonics coefficients +sim_shgrav.add_body(name = 'OblateBody', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) +sim_shgrav.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim_shgrav.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) +sim_shgrav.run(tstart=0.0, tstop=10.0, dt=0.01, tstep_out=10.0, dump_cadence=0, mtiny=mtiny, integrator='symba') + +# Use the original "oblate" version where you pass J2 (and/or J4) +sim_obl = swiftest.Simulation(simdir="obl", DU2M = 1e3, TU='d', MU='kg') +sim_obl.clean() +sim_obl.add_body(name = 'OblateBody', mass = cb_mass, rot = cb_rot, radius = cb_radius, J2 = j2rp2) +sim_obl.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) +sim_obl.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) +sim_obl.run(tstart=0.0, tstop=10.0, dt=0.01, tstep_out=10.0, dump_cadence=0, mtiny=mtiny, integrator='symba') + +diff_vars = ['a','e','inc','capom','omega','capm','rh','vh'] +ds_diff = sim_shgrav.data[diff_vars] - sim_obl.data[diff_vars] +ds_diff /= sim_obl.data[diff_vars] + +print(ds_diff.isel(time=-1,name=-2)) +print(ds_diff.isel(time=-1,name=-1)) -# Run the simulation. Arguments may be defined here or thorugh the swiftest.Simulation() method. -sim.run() From adfb7c5ec1a3a34b1e6e4f7c1e1a0ac62101df3a Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 28 Feb 2024 14:19:19 -0500 Subject: [PATCH 278/324] Make sure to save the first frame on a non-restart run. --- swiftest/simulation_class.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/swiftest/simulation_class.py b/swiftest/simulation_class.py index abc552072..a7c2d0438 100644 --- a/swiftest/simulation_class.py +++ b/swiftest/simulation_class.py @@ -448,9 +448,11 @@ def run(self, return # Save initial conditions - if not self.restart: + if self.restart: + self.save(framenum=-1) + else: self.clean() - self.save() + self.save(framenum=0) # Write out the current parameter set before executing run self.write_param(verbose=False,**kwargs) @@ -2952,7 +2954,7 @@ def read_output_file(self, param_tmp['BIN_OUT'] = self.simdir / self.param['NC_IN'] self.init_cond = io.swiftest2xr(param_tmp, verbose=False, dask=dask) else: - self.init_cond = self.data.isel(time=0) + self.init_cond = self.data.isel(time=[0]).copy(deep=True) if self.read_encounters: self.read_encounter_file(dask=dask) @@ -3124,7 +3126,7 @@ def save(self, if not self.simdir.exists(): self.simdir.mkdir(parents=True, exist_ok=True) - self.init_cond = self.data.copy(deep=True) + self.init_cond = self.data.isel(time=[framenum]).copy(deep=True) if codename == "Swiftest": infile_name = Path(self.simdir) / param['NC_IN'] From 345b21f48de16ffc32b3e2cf9bf5ed66d13f4be9 Mon Sep 17 00:00:00 2001 From: anand43 Date: Wed, 28 Feb 2024 16:16:26 -0500 Subject: [PATCH 279/324] Testing git permissions --- docs/getting-started-guide/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index d6b7e1ebd..c177bd9d3 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -2,7 +2,7 @@ Getting Started ################ -TBD +TBD - Test .. toctree:: :maxdepth: 2 From 91e2f3e419e76448a578df237d3757b6052bbf45 Mon Sep 17 00:00:00 2001 From: Kaustub Anand Date: Wed, 28 Feb 2024 17:28:52 -0500 Subject: [PATCH 280/324] testing git permissions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c82417c58..52d61e123 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Swiftest User Manual ### The Purdue University Swiftest Team #### Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh - +TEST --- Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is an extension of the [Swifter](https://www.boulder.swri.edu/swifter/) software package, detailed in Duncan, Levison, and Lee (1998), that incorporates modern programming techniques and performance improvements. Swiftest contains the following numerical integrators: From 6240dc3cc619f5ddd8a8db91abf6810a7e943d16 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 10:59:23 -0500 Subject: [PATCH 281/324] Added readme to getting started guide - TESTING --- docs/getting-started-guide/index.rst | 636 ++++++++++++++++++++++++++- 1 file changed, 635 insertions(+), 1 deletion(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index d6b7e1ebd..27cf3ebff 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -2,7 +2,641 @@ Getting Started ################ -TBD +# Swiftest User Manual +### The Purdue University Swiftest Team +#### Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh + +--- + +Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is an extension of the [Swifter](https://www.boulder.swri.edu/swifter/) software package, detailed in Duncan, Levison, and Lee (1998), that incorporates modern programming techniques and performance improvements. Swiftest contains the following numerical integrators: + +- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. See [Wisdom & Holman (1991)](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract). +- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of WHM that is capable of handling close encounters between test particles and massive bodies. See [Levison & Duncan (1994)](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub). +- **Democratic Heliocentric (HELIO)** - A symplectic integrator that uses the democratic heliocentric coordinate frame. See [Duncan, Levison, & Lee (1998)](https://iopscience.iop.org/article/10.1086/300541). +- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO that is capable of handling close encounters between massive bodies. See [Duncan, Levison, & Lee (1998)](https://iopscience.iop.org/article/10.1086/300541). + +Swiftest also includes the collisional fragmentation algorithm **Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to resolve collisions between massive bodies by determining the collisional regime, derived from the work of [Leinhardt & Stewart (2012)](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79), and generating the appropriate mass distribution of fragments. Swiftest fully incorporates collisional fragments into the gravitational system, evolving these new bodies along with pre-existing bodies, including their growth and any future fragmentation events in which they are involved. + +--- + +#### Installation + +For most users, installing swiftest can be done via pip using the command: + +``` +pip install swiftest +``` + +This will install the `swiftest` Python package, which can be incorporated into Python projects using `import swiftest`. It also will install a standalone executable called `swiftest_driver`, which can execute simulations from the command line, provided that initial conditions and configuration files are available in the path. + +**Building the `swiftest` Python package and standalone `swiftest_driver` executable** + +Swiftest is designed to be downloaded, compiled, and run on a Linux or MacOS based system. Windows support is currently being developed. + +It is possible to download, compile, and run Swiftest on a machine with at least 400 MB of free disk space and 8 GB of RAM. To take full advantage of the parallelization and performance updates included in Swiftest, it is highly recommended that Swiftest be installed on a high-performance computing cluster. For reference, Swiftest is maintained on the Purdue University [Bell Community Cluster](https://www.rcac.purdue.edu/compute/bell). + +Swiftest is written in Modern Fortran and must be compiled using an appropriate compiler. We recommend the Intel Fortran Compiler Classic (ifort) version 19.0 or higher. For details on installing ifort, see the [Intel installation documentation](https://www.intel.com/content/www/us/en/developer/tools/oneapi/fortran-compiler.html#gs.6xhjgy). The GCC/GNU Fortran Compiler (gfortran) version 9 or higher is also compatible. For details on installing gfortran, see the [GNU Fortran documentation](https://gcc.gnu.org/wiki/GFortran). + +Swiftest output files are stored in the NetCDF file format. This takes the place of the flat binary output file included in Swifter (and its predecessor [Swift](https://www.boulder.swri.edu/~hal/swift.html)). The NetCDF output format is compatible with Python, Java, and other languages that can be used to process and analyze simulation data. Details on installing NetCDF and the NetCDF Fortran Library can be found on the [Unidata website](https://docs.unidata.ucar.edu/netcdf-fortran/current/). NetCDF is built on HDF5 and it is necessary to install HDF and HDF5 as well. Details on installing HDF and HDF5 can be found on the [HDF Group website](https://www.hdfgroup.org/solutions/hdf5). + +Parallelization in Swiftest is done with OpenMP. Version 3.1.4 or higher is necessary to make use of parallelization in Swiftest. If Swiftest is only to be run in serial, this package is not necessary. See the [OpenMP website](https://www.openmp.org/resources/openmp-compilers-tools/) for more details and installation instructions. + +*Example of a module configuration that is necessary for compiling and running Swiftest:* +``` +1. intel/19.0.5.281 +2. openmpi/3.1.4 +3. netcdf/4.7.4 +4. netcdf-fortran/4.5.3 +5. hdf/4.2.15 +6. hdf5/1.10.6 +``` + +**Downloading Swiftest** + +The easiest way to get Swiftest on your machine is to clone the GitHub repository. To do so, open a terminal window and type the following: + +``` +$ git clone https://github.com/carlislewishard/swiftest.git +``` + +If your cloned version is not already set to the master branch: + +``` +$ git checkout master +``` + +To pull down any updates to Swiftest: + +``` +$ git pull +``` + +You now have a Swiftest repository on your personal machine that you may compile, edit, and run as you see fit. + +**Compiling the Swiftest driver program** + +***Compiling `swiftest_driver` using Docker*** + +By far the simplest, most reliable way of compiling the driver program is via a Docker container. The Swiftest project contains a Dockerfile that may be used to generate an executable without needing to provide any external dependencies, other than the Docker engine itself (see [here](https://docs.docker.com/get-docker/) for instructions on obtaining Docker). Once Docker is installed and the Docker engine is running, execute: +``` +$ docker build --target=export_driver \ + --output=bin \ + --build-arg MACHINE_CODE_VALUE="Host" \ + [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ + [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] +``` + +The Docker build will download and compile all of the library dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries and the Swiftest driver using Intel compilers. Once completed, the Swiftest executable, called ```swiftest_driver```, should now be created in the ```bin/``` directory. + +> Note: The Dockerfile is designed to build an executable that is compatible with a broad range of CPU architectures by specifying the SSE2 instruction as a target for SIMD instructions using the `-x` compiler option. When compiling on the same CPU archictecture you plan to execute the driver program, for the highest possible SIMD performance, use `--build-arg MACHINE_CODE_VALUE="Host" to override the default `MACHINE_CODE_VALUE="SSE2"`. For additional options see [here](https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-1/x-qx.html). + +The optional Docker argument `EXTRA_CMAKE_OPTIONS` is provided to pass any additional CMake arguments (see below). + +***Compiling `swiftest_driver` using CMake*** +Several build scripts are available in the `buildscripts` folder for building Swiftest and its dependencies on a Linux or Mac system. These are used when generating the official Swiftest Python wheels using cibuildwheel. To build the complete project, run `buildscripts\build_all.sh` from the command line. + +***Compiling `swiftest_driver` using CMake*** + +The Swiftest driver program is written in modern Fortran and must be compiled before it can be run. After compilation, an executable, called the `swiftest_driver``, will have been created in the ```bin/``` directory. + +Swiftest is compiled through [CMake](https://cmake.org/). Compiling with CMake has a number of benefits that provide a streamlined experience for the Swiftest user and developer. At compilation, CMake will automatically select the set of flags that are compatible with the local compiler. CMake also allows a Swiftest developer to re-compile only the files that have been edited, instead of requiring the developer to re-compile the entire Swiftest program. Please visit the CMake website for more information on how to install CMake. + +As mentioned in the **System Requirements** section, Swiftest requires the NetCDF and NetCDF Fortran libraries to be installed prior to compilation. If the libraries are installed in the standard library location on your machine, CMake should be able to find the libraries without specifying the path. However, if CMake struggles to find the NetCDF libraries, there are two ways to set the path to these libraries. + +1. Create an environment variable called ```NETCDF_FORTRAN_HOME``` that contains the path to the location where the libraries are installed +2. Set the path at the build step using ```-CMAKE_PREFIX_PATH=/path/to/netcdf/``` + +CMake allows the user to specify a set of compiler flags to use during compilation. We define five sets of compiler flags: release, testing, profile, math, and debug. To view and/or edit the flags included in each set, see ```swiftest/cmake/Modules/SetFortranFlags.cmake```. + +As a general rule, the release flags are fully optimized and best used when running Swiftest with the goal of generating results. This is the default set of flags. When making changes to the Swiftest source code, it is best to compile Swiftest using the debug set of flags. You may also define your own set of compiler flags. + +Navigate to the topmost directory in your Swiftest repository. It is best practice to create a ```build``` directory in your topmost directory from which you will compile Swiftest. This way, temporary CMake files will not clutter up the ```swiftest/src/``` sub-directories. The commands to build the source code into a ```build``` directory and compile Swiftest are: + +``` +$ cmake -B build -S . +$ cmake --build build +``` +The [CMake Fortran template](https://github.com/SethMMorton/cmake_fortran_template) comes with a script that can be used to clean out any build artifacts and start from scratch: + +``` +$ cmake -P distclean.cmake +``` + +The Swiftest CMake configuration comes with several customization options: + +| Option | CMake command | +| --------------------------------|------------------------------------------------------------| +| Build type | \-DCMAKE_BUILD_TYPE=[**RELEASE**\|DEBUG\|TESTING\|PROFILE] | +| Enable/Disable OpenMP support | \-DUSE_OPENMP=[**ON**\|OFF] | +| Enable/Disable SIMD directives | \-DUSE_SIMD=[**ON**\|OFF] | +| Enable/Disable Coarray support (experimental) | \-DUSE_COARRAY=[ON\|**OFF**] | +| Set Fortran compiler path | \-DCMAKE_Fortran_COMPILER=/path/to/fortran/compiler | +| Set path to make program | \-DCMAKE_MAKE_PROGRAM=/path/to/make | +| Enable/Disable shared libraries (Intel only) | \-DBUILD_SHARED_LIBS=[**ON\|OFF] | +| Add additional include path | \-DCMAKE_Fortran_FLAGS="-I/path/to/libraries | +| Install prefix | \-DCMAKE_INSTALL_PREFIX=["/path/to/install"\|**"/usr/local"**] | + + +To see a list of all possible options available to CMake: +``` +$ cmake -B build -S . -LA +``` + +The Swiftest executable, called `swiftest_driver`, should now be created in the `bin/` directory. + + +**Download the `swiftest_driver` as a Docker or Singularity container.** + +The Swiftest driver is available as a Docker container on DockerHub in two versions: Intel and GNU. The Intel version was compiled for the x86_64 CPU using the Intel classic Fortran compiler. The GNU version was compliled for the x86_64 CPU using gfortran. The Intel version is faster than the GNU version (though not as fast as a native compile to the target CPU that you wish to run it on due to vectorization optimizations that Swiftest takes advantage of), however it is much larger: The Intel version is ~2.7GB while the GNU version is ~300MB. The Singularity container pulls from the same DockerHub container. + +To facilitate installation of the container, we provide a set of shell scripts to help automate the process of installing container versions of the executable. To install the default Intel version of the docker container from within the `swiftest\` project directory + +``` +$ cd docker +$ . ./install.sh +``` + +To install the GNU version: + +``` +$ cd docker +$ . ./install.sh gnu +``` + +The Singularity versions are installed the same way, just replace `cd docker` with `cd singularity` above. + +Whether installing either the Docker or Singularity containers, the install script will copy an executable shell script `swiftest_driver` into `swiftest/bin/`. Not that when installing the Singularity container, the install script will set an environment variable called `SWIFTEST_SIF` that must point to the aboslute path of the container file called `swiftest_driver.sif`. To use the driver script in a future shell, rather than running the install script again, we suggest adding the environment variable definition to your shell startup script (e.g. add `export SWIFTEST_SIF="/path/to/swiftest/singularity/swiftest.sif"` to your `.zshrc`) + + +**Swiftest Python Package** + +Included with Swiftest, in the ```/swiftest/python/swiftest/``` directory, is a Python package designed to facilitate seamless data processing and analysis. The Python package, also called Swiftest, can be used to generate input files, run Swiftest simulations, and process output files in the NetCDF file format. + +To begin, Swiftest can be added to an existing conda environment, or a new conda environment may be created, so long as the required packages are installed. To create and activate a new conda environment with the prerequisite packages, open a terminal and navigate to the ```/swiftest/python/swiftest/``` directory. Type the following: + +``` +$ conda create --name EnvName pip scipy numpy matplotlib pandas xarray jupyter astropy -y +$ conda activate EnvName +``` + +Next, we will install further required packages. Using the ```-e``` flag imports all packages in ```/swiftest/python/swiftest/requirements.txt```, including Swiftest. If the Swiftest Python package is updated in the future, using the ```-e``` flag should ensure that the user does not have to reinstall the package to use the updated version. + +``` +$ pip install --user -e . +``` + +The Swiftest Python package should now be installed in the conda environment and is ready to use. If you would like to take the further step to add Swiftest to a Jupyter Notebook kernel, type the following: + +``` +$ ipython kernel install --user --name EnvName --display-name "Swiftest Kernel" +``` + +--- + +#### Usage + +Swiftest is built to make running a Swiftest simulation a streamlined and user-friendly experience, even for a new user. As a result, Swiftest is highly flexible and a simulation can be created, run, and processed in a number of different ways. The first choice the user must make is if they would prefer ASCII input files or NetCDF input files. We recommend NetCDF input files, however we include documentation for ASCII input files for completeness. + +**Brief Outline** + +To create and run a Swiftest simulation using the Swiftest Python package, follow the general script below. For more details on the input files and user options, continue reading this section. + +``` +import swiftest # Import the Swiftest Python package +sim = swiftest.Simulation(simdir = "directory_name", **kwargs) # Initialize a Swiftest simulation and define a directory/path in which to store simulation data +sim.add_solar_system_body(**kwargs) # Add any desired named Solar System bodies, including the Sun +sim.add_body(**kwargs) # Add any desired user defined bodies +sim.get_parameter(**kwargs) # View the default simulation parameters +sim.set_parameter(**kwargs) # Set any desired simulation parameters +sim.write_param(**kwargs) # Write simulation parameters to the param.in +sim.save(**kwargs) # Save the simulation initial conditions to init_cond.nc +sim.run(**kwargs) # Run the simulation (leave off if running from the executable) +``` + +To read in a set of Swiftest output files using the Swiftest Python package, follow the general script below. For more details on the output files and user options, continue reading this section. + +``` +import swiftest # Import the Swiftest Python package +sim = swiftest.Simulation(simdir = "directory_name", read_data=True) # Initialize a Swiftest simulation +sim.data # Body data over time +sim.init_cond # The initial conditions for the simulation +sim.encounters # Encounter data for all close encountering pairs +sim.collisions # Collision data for all colliders and collisional fragments +``` + +**NetCDF Input Files (Recommended)** + +Swiftest accepts a single NetCDF input file. This file can be created using the Swiftest Python Package through a few simple steps. + +To begin, simply create a new Python script in the directory you would like to store your simulation. Open the new script and import the Swiftest Python package. + +``` +import swiftest +``` + +Next, we initialize the Swiftest simulation object. Various parameters can be provided to the simulation via key word arguments at this stage. + +``` +sim = swiftest.Simulation(simdir = "directory_name", **kwargs) +``` + +The argument ```simdir``` is the name of the subdirectory in which to store all simulation data. This does not have to exist at the time the simulation object is initialized. + +The key word arguments available to the user, along with the default values for these arguments, are described in [simulation_kwargs](README_tables/simulation_kwargs.md). + +After creating the simulation and defining all desired parameters as keyword arguments, it is time to add bodies to the simulation. The Swiftest Python package interfaces with the [NASA JPL Horizons database](https://ssd.jpl.nasa.gov/horizons/), allowing a user to easily import the initial conditions of known solar system bodies using the ```add_solar_system_body``` method. + +``` +sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto"]) +``` + +User defined bodies can also be added to a Swiftest simulation through the Python package. Massive bodies and test particles can both be added using the ```add_body``` method. + +``` +sim.add_body(**kwargs) +``` + +The key word arguments available to the user for the ```add_body``` method are described in [add_body_kwargs](README_tables/add_body_kwargs.md). + +Once all desired bodies have been added to the Swiftest simulation, the simulation parameters can be accessed and changed using the ```get_parameter``` and ```set_parameter``` methods. The key word arguments available to the user for the ```get_parameter``` and ```set_parameter``` are the same as those described in [simulation_kwargs](README_tables/simulation_kwargs.md). + +After all desired parameters have been set, the parameters can be saved to the **param.in** using the ```write_param``` method. The key word arguments available to the user for the ```write_param``` method are described in [write_param_kwargs](README_tables/write_param_kwargs.md). + +The state of the system can be saved to the initial conditions NetCDF file, **init_cond.nc**, using the ```save``` method. The key word arguments available to the user for the ```save``` method are described in [save_kwargs](README_tables/save_kwargs.md). + +Finally, a simulation can be run from the same script in which it is created (or a separate Python script) using the ```run``` method. This is optional as the simulation can also be run from an executable. More details on running a Swiftest simulation can be found in the section **Running a Swiftest Simulation**. The key word arguments available to the user for the ```run``` method are the same as those described in [simulation_kwargs](README_tables/simulation_kwargs.md). + +**ASCII Input Files** +Swiftest accepts 4 ASCII input files. All four ASCII input files are necessary if using the ASCII input format, however the structure of each input file varies slightly depending on the features and capabilities of the integrator selected. The four ASCII input files are not necessary if using NetCDF input files. The four input files are as follows: + +- **param.in** - The parameter input file. +- **cb.in** - The central body input file. +- **pl.in** - The massive body input file. +- **tp.in** - The test particle input file. + +The parameter options used in the parameter input file are as described in [simulation_kwargs](README_tables/simulation_kwargs.md). + +The **cb.in** includes all central body initial conditions. The structure of the **cb.in** is as follows: + +``` +0 ! ID number +1.0 ! Gravitational mass (G*mass) in mass units (ex. 39.47841760435743 for Sun in M_sun/AU/year) +1.0 ! Central body radius is distance units (ex. 0.004650467260962157 for Sun in AU) +0.0 ! J2 term, optional, set to 0.0 for a spherical body +0.0 ! J4 term, optional, set to 0.0 for a spherical body +0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only +0.0 0.0 0.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only +``` + +The **pl.in** includes all massive body initial conditions. The structure of the **pl.in** is as follows: + +``` +2 ! Total number of massive bodies +1, 0.0, 0.0 ! ID number, Gravitational mass (G*mass) in mass units, Hill Radius in distance units if RHILL_PRESENT is set to YES, leave off if not using +0.0 ! Radius is distance units if CHK_CLOSE is set to YES, leave off if not using +1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination +1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly +0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only +1.0 1.0 1.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only +2, 0.0, 0.0 +0.0 +1.0 1.0 1.0 +1.0 1.0 1.0 +0.4 0.4 0.4 +1.0 1.0 1.0 +``` + +The **tp.in** includes all test particle initial conditions. In the event that no test particles are desired, the **tp.in** must still be included, however it can simply contain a single ```0```. The structure of the **tp.in** is as follows: + +``` +2 ! Total number of test particles +3 ! ID number +1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination +1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly +4 +1.0 1.0 1.0 +1.0 1.0 1.0 +``` + +Note that the ID numbers of the test particles are a continuation of the ID numbers of the massive bodies. No two bodies in the system can have the same ID number. + +**Running a Swiftest Simulation** + +The input files necessary to successfully run Swiftest should now be generated in the simulation directory. The user is now faced with a second choice: to run a Swiftest simulation from a Python environment or to run it directly from an executable. Either option is possible with NetCDF format input files, however ASCII input files must be run directly from an executable. + +**Running via Python** + +To run a Swiftest simulation from the same script in which the initial conditions are created, simply add the following line after you have finished defining parameters and adding bodies to the simulation: + +``` +sim.run() +``` + +To run a previously created set of initial conditions, first read the old parameter file into Python, and then run it. Note that Swiftest will look in the ```/simdata``` subdirectory for the initial conditions by default. You may set a new path to the initial conditions using the ```param_file``` keyword argument. See the documentation detailing the key word arguments available to the user in [simulation_kwargs](README_tables/simulation_kwargs.md). + +``` +sim = swiftest.Simulation(simdir = "directory_name", read_param=True) +sim.run() +``` + +**Running via an Executable** + +To run a Swiftest simulation through an executable, create a symbolic link to the Swiftest driver from your current directory. + +``` +$ ln -s ~/PATH/TO/swiftest/bin/swiftest_driver . +``` + +To run Swiftest, simply type the following command into the terminal: + +``` +$ ./swiftest_driver INTEGRATOR param.in +``` + +Where ```INTEGRATOR``` is your integrator of choice, either ```whm```, ```rmvs```, ```helio```, or ```symba```. + +**Outputs** + +The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. The standard output files are as follows: +- **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ```ISTEP_OUT``` timesteps and written every ```DUMP_CADENCE```. This file can be analyzed using the Swiftest Python package (```sim.data```). +- **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ```FRAGMENTATION``` is ```YES```, Swiftest SyMBA only. +- **swiftest.log** - A log containing a brief update on the status of the run. Only generated if Swiftest is run through the Python package or through a shell script. If Swiftest is run through an executable, these updates are output directly to the terminal. +- **collisions.nc** - The details of each collision that occurs in a simulation are recorded in a NetCDF file. Only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True```. This file can be analyzed using the Swiftest Python package (```sim.collisions```). +- **encounters.nc** - The details of each close encounter that occurs in a simulation are recorded in a NetCDF file. Only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True```. This file can be analyzed using the Swiftest Python package (```sim.encounters```). +- **init_cond.nc** - The initial conditions used to run the simulation. This file can be analyzed using the Swiftest Python package (```sim.init_cond```). +- **encounter_check_plpl_timer.log** - The log containing the encounter check timer for each massive body/massive body encounter, only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True``` and ```ENCOUNTER_CHECK```/```encounter_check_loops``` is ```ADAPTIVE```. +- **encounter_check_pltp_time.log** - The log containing the encounter check timer for each massive body/test particle encounter, only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True``` and ```ENCOUNTER_CHECK```/```encounter_check_loops``` is ```ADAPTIVE```. +- **interaction_timer.log** - The log containing the interaction loop timer for each interacting pair of bodies, only if ```INTERACTION_LOOPS``` is ```ADAPTIVE```. + +To read in a Swiftest output file, simply create a new Python script in the simulation directory. + +``` +import swiftest +sim = swiftest.Simulation(simdir = "directory_name", read_data=True) +``` + +All Swiftest data is now stored in the Xarray datasets ```sim.data```, ```sim.collisions```, and ```sim.encounters``` and is easily processed, manipulated, and analyzed. + +Regardless of whether the status outputs are recorded in the **swiftest.log** or in the terminal, the output format is the same. Below is an example of a single status output: + +`````` +Time = 1.00000E+03; fraction done = 0.001; Number of active plm, pl, tp = 57, 108, 50 + DL/L0 = 6.83763E-12; DEcollisions/|E0| = 0.00000E+00; D(Eorbit+Ecollisions)/|E0| = 2.65579E-03; DM/M0 = 0.00000E+00 +Integration steps: Total wall time: 2.99848E+02; Interval wall time: 9.36192E+01;Interval wall time/step: 4.68956E-04 +`````` + +The first line includes the simulation time, the fraction of the simulation that is complete relative to ```tstop```, the number of fully-interactive massive bodies (```plm```) (SyMBA only), the total number of massive bodies (```pl```) including fully-interactive and semi-interactive bodies, and the number of test particles (```tp```) remaining in the system at that time. The second line includes the angular momentum error, the change in energy as a result of collisions only, the total change in energy, and the change in mass up to this point in the simulation (error analysis included only if ```ENERGY```/```compute_conservation_values``` is set to ```YES```/```True```). The third line contains the total wall time elapsed since the start of the simulation, the wall time elapsed since the start of the last step, and the average wall time per step since the start of the simulation. + +**Restarting a Simulation From t $\neq$ 0** + +Just like Swiftest allows the user to run a simulation through an executable or through Python, Swiftest also allows the user to restart a simulation from t $\neq$ 0 in the same two manners. This can be useful in the case of an accidental termination of a simulation, such as through a power outage or computer failure. In many cases, it is also necessary to run a simulation to a new end point, past the original ```TSTOP```. + +**Restarting via Python** + +To restart a Swiftest simulation via the Swiftest Python package, follow the outline below: + +``` +import swiftest +sim = swiftest.Simulation(simdir = "directory_name", read_data=True) +sim.set_parameter(tstop=VAL) # Set a new stop time if desired +sim.write_param() # Write simulation parameters to the param.in +sim.run() +``` + +Note that Swiftest will look in the ```/simdata``` subdirectory for the initial conditions by default. You may set a new path to the initial conditions using the ```param_file``` keyword argument. + +**Restarting via an Executable** + +Every ```DUMP_CADENCE``` X ```ISTEP_OUT``` timesteps, Swiftest writes all simulation information from memory to the output files. At the same time, Swiftest also writes all simulation information to a new parameter file, titled **param.XXXXXXXXXXXXXXXXXX.in**. To restart a run from a previous parameter file, simply follow the instructions detailed in the **Running via an Executable** section, replacing ```param.in``` with the name of the parameter file from which you wish to restart. + +--- + +#### Updates to Swifter Included in Swiftest + +**Collisional Fragmentation via Fraggle** + +To activate the Fraggle algorithm, set ```FRAGMENTATION```/```fragmentation``` to ```YES```/```True```, depending on the mode in which Swiftest is being run. When resolving a close encounter that results in a collision, Fraggle determines the regime of the collision as well as the mass, number, position, velocity, and rotation of all resulting bodies. This is distinct from Swiftest SyMBA's predecessor, Swifter SyMBA, which assumes that all collisions result in perfect mergers. + +Fraggle distinguishes the following collisional regimes: (1) perfect merging, which includes the cratering, partial accretion, and graze-and-merge regimes of Leinhardt & Stewart 2012, (2) disruption, which includes the partial erosion regime of Leinhardt & Stewart 2012, (3) super-catastrophic disruption, and (4) hit-and-run events which can be either ‘pure’ or ‘disruptive’. + +For every collision throughout the course of a simulation, Fraggle writes a brief description of the collision to the **fraggle.log** output file. An example of a collision, stored in the **fraggle.log** output file, is as follows: + +``` +Fraggle logfile + + ********************************************************************************************************************** + Collision between massive bodies detected at time t = 2.063709800335315E-006 + ********************************************************************************************************************** + + -------------------------------------------------------------------- + Fraggle collisional regime determination results + -------------------------------------------------------------------- + True number of colliders : 2 + Index list of true colliders : 1 2 + Regime: Disruption + Energy loss : 2.298848838233116E-022 + -------------------------------------------------------------------- + Disruption between Target (1) and Projectile (2) + Fraggle generating 28 fragments. + Fraggle try 1 + Fraggle fragment generation succeeded after 1 tries + Generating 28 fragments +``` + +The details of the collision are stored in the simulation object (```sim.collisions```) which can be accessed using the Swiftest Python package. + +**General Relativity** + +From its observation in the mid-1800s to the development of the theory of general relativity by Albert Einstein in 1915, the precession of Mercury's perihelion puzzled scientists and observers. Mercury's orbit precesses by approximately $42.980 \pm 0.001$ arcseconds / century more than is expected from Newtonian mechanics. This deviation can be explained by the curvature of spacetime due to the mass of the Sun. Mercury's close proximity to the Sun enhances the effects of general relativity, providing a good test case to highlight the functionality of general relativity in Swiftest. + +In this test case, we track the orbit of Mercury for 1000 years as it orbits around the Sun in the presence of the seven other massive planets. The precession rate of the longitude of periapsis of Mercury, as calculated by Swiftest SyMBA, differs by only $\sim 0.0286 \%$ from the precession rate calculated from the NASA JPL Horizons database. + +|![SyMBA General Relativity](README_figs/symba_gr.png "SyMBA General Relativity")| +|:--:| +|**Figure 1** - The longitude of periapsis of Mercury over 1000 years, as calculated by Swifter SyMBA (dotted green), Swiftest SyMBA with general relativity turned off (long dashed yellow), and Swiftest SyMBA with general relativity turned on (short dashed blue). These results are compared to the periapsis of Mercury as calculated from the NASA JPL Horizons database (solid red). Swiftest SyMBA with general relativity turned off is in good agreement with Swifter SyMBA ($\sim 0.00053 \%$ difference), while Swiftest SyMBA with general relativity turned on is in good agreement with the NASA JPL Horizons database ($\sim 0.0286 \%$ difference).| + +**Adaptive Interaction Calculations and Encounter Checking** + +In Swifter SyMBA, gravitational interactions between bodies are calculated on a pair-by-pair basis by solving an upper triangular matrix. In practice, this is done through a double loop. While effective, solving a triangular matrix is computationally costly and it is considered best practice to avoid nested loops wherever possible. Swiftest SyMBA offers an alternative to this method, allowing the user to choose between calculating the gravitational interactions between bodies through a traditional triangular matrix or through a flattened Euclidean distance matrix. + +A Euclidean distance matrix is a two-dimensional array that stores the distance between each pairing of points in a set of elements. For more details on the algorithm implemented in Swiftest to flatten the Euclidean distance matrix, please see [Angeletti, Bonny, & Koko 2019](https://hal.archives-ouvertes.fr/hal-02047514). + +Along with allowing the user to choose whether the gravitational interactions are calculated through an upper triangular matrix or a flattened Euclidean distance matrix, Swiftest SyMBA allows the user to let the program determine the speedier solution. Through adaptive interaction calculations, Swiftest SyMBA periodically tracks the time it takes to complete an interaction calculation using both the triangular and flat methods. Whichever method proves to be quicker is implemented until the next time both methods are tested. Swiftest SyMBA periodically checks the performance of each method, possibly switching between the two methods multiple times over the course of a simulation. By selecting adaptive interaction calculations, the user allows Swiftest SyMBA to optimize its own performance and adapt to changes in the number of particle pairings as the simulation progresses. + +An example of the adaptive interaction calculations, stored in the **interaction_timer.log** output file, is as follows: + +``` +Interaction loop timer logfile ! The file header +Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which calculation method is fastest +symba_kick_getacch_int_pl: loop timer turned on at t = 0.000000000000000E+000 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun +symba_kick_getacch_int_pl: stage 1 ! Begins timing the first method +FLAT 95 7353 1.291989664082687E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) +symba_kick_getacch_int_pl: stage 2 ! Begins timing the second method +TRIANGULAR 100 7353 1.359989120087039E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) +symba_kick_getacch_int_pl: the fastest loop method tested is FLAT ! The subroutine in which the timing is being conducted and which interaction calculation method is determined to be fastest +``` + +In addition to calculating the gravitational interactions between pairings of bodies, Swifter SyMBA also uses an upper triangular matrix to check if pairings of bodies are in a close encounter state. While similar to interaction calculations, encounter checking can be further simplified to exclude pairs of bodies which, based on their physical distance, are unlikely to be in an encounter state. To address this, Swiftest SyMBA offers an alternative to solving an upper triangular matrix through the sort and sweep method. + +The sort and sweep method of collision detection (see [Ericson 2005](https://www.sciencedirect.com/book/9781558607323/real-time-collision-detection) for more details), also known as the sweep and prune method, is a way of limiting the number of pairs of bodies that need to be checked for a collision in each time step. At the start of a new time step, the position of each body is calculated and the critical radius of each body is determined. The critical radius is based on the radius of a body's Hill sphere. The distance from a body's center to the extent of its critical radius defines the encounter sphere of the body. The position of the center of mass of the body and the extent of its encounter sphere are used to define the bounding box used in the sort and sweep algorithm. Based on the defined bounding box, the positions of the lower and upper bounds of all of the bodies in the simulation are compiled into sorted lists. Because each body is unlikely to move significantly between time steps, updating these sorted lists each time step is relatively straightforward. Only when the bounding boxes of two bodies overlap in all axes are the bodies flagged as an encountering pair. + +The sort and sweep algorithm is computationally efficient because it limits the number of potential encountering pairs that must be checked for encounters. For example, by calculating the bounding boxes of two bodies on opposite sides of the solar system, the algorithm then sorts the upper and lower bounds of these two bounding boxes into opposite ends of a sorted list. Through this sorting, the algorithm recognizes that these two bodies are unlikely to encounter one another in the following time step and is able to quickly exclude them from more extensive encounter checking, saving time and computational resources. +In the same way that the user can allow Swiftest SyMBA to adapt when calculating the gravitational interactions between bodies, the user can also allow Swiftest SyMBA to determine the faster method of encounter checking. Just as Swiftest SyMBA periodically tests the interaction calculation methods, it also periodically tests the encounter checking methods. The quicker of the two methods is selected and implemented, allowing Swiftest SyMBA to adapt to changes in the distribution of bodies in the system as the simulation progresses. + +An example of the adaptive encounter checking, stored in the **encounter_check_plpl_timer.log** output file, is as follows: + +``` +Encounter check loop timer logfile ! The file header +Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which checking method is fastest +encounter_check_all_plpl: loop timer turned on at t = 5.000000000000000E-003 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun +encounter_check_all_plpl: stage 1 ! Begins timing the first method +SORTSWEEP 196 7353 2.665578675370597E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) +encounter_check_all_plpl: stage 2 ! Begins timing the second method +TRIANGULAR 164 7353 2.230382156942744E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) +encounter_check_all_plpl: the fastest loop method tested is TRIANGULAR ! The subroutine in which the timing is being conducted and which encounter checking method is determined to be fastest +``` + +Together, adaptive interaction calculations and encounter checking are idea for lengthy simulations with a large number of particles. The flexibility of Swiftest SyMBA ensures that the parameters of the integration are optimized for each individual simulation, even as the simulation evolves. + +**NetCDF Compatibility** + +The NetCDF (Network Common Data Form) file format is a cross-platform method of creating, accessing, and sharing data. Due to its self-describing nature, NetCDF is ideal for archiving multidimensional scientific data. NetCDF files are also appendable, allowing for data to be added to a file after creation, making the NetCDF file format well suited for handling simulation output. NetCDF is maintained by the University Corporation for Atmospheric Research (UCAR) and is a standard file format across much of the atmospheric modeling community. + +In Swifter SyMBA, simulation outputs were stored in a flat binary file. These binary files could only be easily accessed through [SwiftVis](https://cs.trinity.edu/~mlewis/SwiftVis/), a data analysis and visualization software package designed to process Swifter data. In accordance with modern data management practices and industry standards, Swiftest incorporates a NetCDF output file format for all simulation types. NetCDF is compatible with many of today's most widely-used programming languages including Fortran, Python, Java, C++, and more. By writing simulation data to a NetCDF output file, Swiftest provides the user with the flexibility to analyze and visualize data in any language they choose. The NetCDF file format is also adaptable such that any future additions to Swiftest can be seamlessly incorporated into the output file. + +**Object-Oriented Programming** + +The 2003 version of Fortran introduced object-oriented programming, with Fortran 2008 providing further updates. Swiftest is written in modern Fortran and takes advantage of many of the object-oriented programming features included in Fortran 2003. In doing so, Swiftest is a complete restructure of its predecessor, Swifter. The reusability and simplification of code in Swiftest through object-oriented programming is a modern and flexible approach that allows for future enhancements and additions to the Swiftest package. + +**Parallelization** + +Parallelization using OpenMP is still under development in Swiftest. For preliminary results, see **Figure 2**. + +--- + +#### Examples + +All examples are included in the ```/swiftest/examples/``` directory. Simply run the script(s) included in the directory as you would normally run a Python script. See the **README.txt** included in each example directory for more details. + +**Basic_Simulation** + +This example walks through how to set up a standard solar system simulation. It can be found in the ```/swiftest/examples/Basic_Simulation``` directory. It is intended to be run using the SyMBA integrator. It contains three classes of bodies: +- Fully-Interacting Massive Bodies - Gravitationally affect and are affected by other massive bodies. +- Semi-Interacting Massive Bodies - Gravitationally affect and are affected by fully-interacting massive bodies, do not gravitationally affect and are not affected by other semi-interacting massive bodies. +- Test Particles - Gravitationally affected by fully-interacting massive bodies only. + +To generate the initial conditions, run the Python script titled **basic_simulation.py**. This script also runs Swiftest SyMBA, generating output. To process the output file, run the script titled **output_reader.py**. + +**Chambers2013** + +This example acts as a comparison to the work of [Chambers 2013](https://www.sciencedirect.com/science/article/pii/S0019103513000754?via%3Dihub). It can be found in the ```/swiftest/examples/Chambers2013``` directory. It is intended to be run using the SyMBA integrator and highlights how to run Swiftest using and executable, as opposed to through a Python script. To generate the initial conditions, run **init_cond.py**. To run Swiftest with these intial conditions, type: + +``` +./swiftest_driver symba param.in +``` + +To process the output file, run the script titled **scattermovie.py**. + +**Fragmentation** + +This example highlights the functionality of the Fraggle algorithm. It can be found in the ```/swiftest/examples/Fragmentation``` directory. It is intended to be run using the SyMBA integrator. It contains 9 pre-built collisional test cases: + +- A Head-On Disruptive Collision +- An Off-Axis Disruptive Collision +- A Head-On Super-Catastrophic Disruptive Collision +- An Off-Axis Super-Catastrophic Disruptive Collision +- A Disruptive Hit and Run Collision +- A Pure Hit and Run Collision +- A Merger +- A Merger Crossing the Spin Barrier +- All of the Above + +To generate, run, and create a movie depicting the collision, run the Python script titled **Fragmentation_Movie.py**. Please note that this example requires a large amount of memory. For reference, this example was created and run using 4 nodes, each with 256 GB of memory. This amount of computational memory is necessary to generate a smooth movie. In this example, the trajectories of all bodies involved in the collision are saved at every point in the simulation. This is extremely expensive and should only be used to study a particular collisional event in detail. + +**helio_gr_test** + +This example demonstrates the functionality of general relativity in Swiftest HELIO. It can be found in the ```/swiftest/examples/helio_gr_test``` directory. It is intended to be run using the HELIO integrator. Because the SyMBA integrator is built upon the HELIO integrator, GR is also available in SyMBA. + +**Multibody_Fragmentation** + +This example highlights the functionality of the Fraggle algorithm. It can be found in the ```/swiftest/examples/Mulitbody_Fragmentation``` directory. It is intended to be run using the SyMBA integrator. To generate a set of initial conditions, run the initial conditions using Swiftest, and generate a movie depicting the collisional result, run the Python script titled **Multibody_Movie.py**. + +**solar_impact** + +This example demonstrates the conservation of angular momentum, energy, and mass during a collision between a massive body and the Sun, or central body. It can be found in the ```/swiftest/examples/solar_impact``` directory. It is intended to be run using the SyMBA integrator. + +**Swifter_Swiftest** + +This set of examples acts as a comparison between Swiftest and its predecessor, Swifter. Two unique simulations are included in this example, one with 8 massive bodies and 0 test particles, and one with 108 massive bodies and 50 test particles. These simulations can be found in the ```/swiftest/examples/Swifter_Swiftest/8pl_0tp``` and the ```/swiftest/examples/Swifter_Swiftest/108pl_50tp``` directories, respectively. They are intended to be run using the SyMBA integrator. For details on how to run a simulation using Swifter, please see the [Swifter website](https://www.boulder.swri.edu/swifter/). + +**whm_gr_test** + +This example demonstrates the functionality of general relativity in Swiftest WHM. It can be found in the ```/swiftest/examples/whm_gr_test``` directory. It is intended to be run using the WHM integrator. Because the SyMBA integrator is built upon the HELIO integrator, which is in turn built upon the WHM integrator, GR is also available in SyMBA. + +--- + +#### Simulation Parameter FAQs and Recommendations + +**How do I know what timestep to use for my simulation (**```dt```**)?** + +A good rule is to set ```dt``` equal to one tenth the orbit of the inner-most body in your simulation. For example, if Mercury is your inner-most body, ```dt``` should be set to one tenth Mercury's orbit. Mercury's orbit is ~0.24 years (~88 days) so a timestep of 0.024 years should be sufficiently small to accurately model the orbit of Mercury. You can always go smaller to increase resolution. + +**How often should I output (**```ISTEP_OUT``` or ```TSTEP_OUT```, **and** ```DUMP_CADENCE```**)?** + +Depending on your simulation, you may want to write to the output file more or less frequently. Writing takes a considerable amount of computational time, so it is important to set a output cadence that is manageable. Conversely, storing data in memory may not be reasonable for all simulation configurations or hardware, so writing more frequently may be necessary. There is no hard and fast rule for how often you should output, however it is dependent on your total simulation length (```tmax```) and your timestep (```dt```). Think of ```ISTEP_OUT``` as the number of timesteps between writing to memory (or, alternatively with ```TSTEP_OUT```, the length of time between writing to memory), and ```DUMP_CADENCE``` as the number of write to memory operations between writing to file. + +For example, an appropriate output cadence for a run with a timestep of 0.005 years and a total simulation length of 100 My might be ```ISTEP_OUT = 2e5``` (```TSTEP_OUT = 1e3```) and ```DUMP_CADENCE = 10```. This means that data will be stores to memory every 2e5 timesteps and written to file every 2e6 timesteps. Based on our value of ```dt```, this is every 1,000 years and every 10,000 years, respectively. Our total simulation length tells us that we will write to file 10,000 times over the course of the simulation. For longer simulations, the output cadence may be less frequent to save computational space. For shorter simulations, the output cadence may be more frequent to increase resolution. + +**What mass threshold should I set to differentiate fully-interactive and semi-interactive bodies (**```GMTINY``` **or** ```MTINY```**)?** + +Semi-interacting bodies are useful because the integrator is not required to calculate gravitational interactions between pairs of semi-interacting particles. This can result in significant performance improvements, especially for systems that require hundreds or thousands of massive bodies. If your system only has a few tens of massive bodies, semi-interacting bodies may not be necessary. If you would like to differentiate between these two classes of bodies, simply set the mass threshold to be some value between the mass of the smallest fully-interacting body and the mass of the largest semi-interacting body that you choose. Semi-interacting bodies can collide with each other and grow to become fully interacting bodies once they pass the mass threshold. + +**What should minimum fragment mass should I use (**```MIN_GMFRAG``` **or** ```MIN_MFRAG```**)?** + +This mass threshold is necessary to ensure that Swiftest SyMBA does not generate huge amounts of very small fragments, grinding the model to a halt. While this value is largely empirical and dependent on each specific set of initial conditions, a good place to start is to set the minimum fragment mass threshold to be one tenth the size of the smallest body in your simulation. You can also adjust ```FRAG_REDUCTION``` to keep the number of fragments within a reasonable range. + +**What are the limits of Swiftest SyMBA?** + +While Swiftest SyMBA is a powerful tool for modeling gravitational interactions between massive bodies, it does have its limits. Swiftest SyMBA is best used for systems containing tens to hundreds of fully-interacting massive bodies. It is also best used for timescales on the order of a few hundred million years or less. While it is possible to model systems on a billion year timescale, the computational power required may be beyond what is available to the average user. In these cases, it is recommended that the user consider modeling with test particles instead of massive bodies. For systems that contain mainly test particles, with few to no close encounters between massive bodies, Swiftest RMVS is likely a more appropriate tool. + +To get a sense of the scope of your desired simulation, it is recommended that you run your initial conditions and parameters for a just few steps. Make sure that you set ```ISTEP_OUT``` and ```DUMP_CADENCE``` to output only once the simulation is complete, not between steps. Because writing to the output files and memory takes a significant amount of computational time compared to integrating the step, we want to avoid counting writing time in our diagnostic information. The terminal output contains information about the total wall time and the wall time per integration step. To get a sense of how long your run will take to complete your desired ```tmax```, simply scale up the wall time per integration step to the number of steps necessary for ```tmax``` to be reached. Remember that writing to the output files will take a considerable amount of time. Adjust your initial conditions and parameters accordingly. + +--- + +#### References + +- Angeletti, M., Bonny, J. -M., and Koko, J. (2019). Parallel Euclidean distance matrix computation on big datasets. **HAL**. [HAL Id: hal-02047514](https://hal.archives-ouvertes.fr/hal-02047514) +- Duncan, M. J., Levison, H. F., and Lee, M. H. (1998). A Multiple Time Step Symplectic Algorithm for Integrating Close Encounters. **The Astronomical Journal**, 116, 2067. [doi: 10.1086/300541](https://iopscience.iop.org/article/10.1086/300541) +- Chambers, J. E. (2013). Late-Stage Planetary Accretion Including Hit-and-Run Collisions and Fragmentation. **Icarus**, 224. [doi: 10.1016/j.icarus.2013.02.015](https://www.sciencedirect.com/science/article/pii/S0019103513000754?via%3Dihub) +- Ericson, C. (2005) Real-Time Collision Detection. **Elsevier Inc.** [ISBN: 978-1-55860-732-3](https://www.sciencedirect.com/book/9781558607323/real-time-collision-detection) +- Leinhardt, Z. M. and Stewart, S. T. (2012). Collisions between Gravity-dominated Bodies. I. Outcome Regimes and Scaling Laws. **The Astrophysical Journal**, 745, 79. [doi:10.1088/0004-637X/745/1/79](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79) +- Levison, H. F. and Duncan, M. J. (1994). The Long-Term Behavior of Short-Period Comets. **Icarus**, 108, 18. [doi: 10.1006/icar.1994.1039](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub) +- Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body problem. **The Astronomical Journal**, 102. [doi: 0.1086/115978](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract) +- Wishard et al. (2023) - In preparation + +--- + +#### Community Guidelines + +**Contributing to Swiftest** +Swiftest is open source and can be freely accessed through our [GitHub page](https://github.itap.purdue.edu/MintonGroup/swiftest). If you wish to make a change and have that change incorporated into the published version of Swiftest, please issue a pull request. If you wish to edit Swiftest for your own personal use, no pull request is necessary. + +**Reporting an Issue** +If you stumble upon a bug or issue with the functionality of Swiftest, we want to hear about it! If you have a fix for this bug, please issue a pull request. If you do not have a fix for the bug and would like to report it, please contact the Purdue Swiftest Team via email (cwishard@purdue.edu). + +**User Support** +For help using Swiftest, please contact the Purdue Swiftest Team via email (cwishard@purdue.edu). + +--- + +#### Licensing Agreement + +Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with Swiftest. If not, see . + .. toctree:: :maxdepth: 2 From 0667643f5b5113017bc40ce0cf57873c8035d773 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 11:05:45 -0500 Subject: [PATCH 282/324] Testing pandoc for .md to .rst conversion --- docs/getting-started-guide/index.rst | 1590 ++++++++++++++++++-------- 1 file changed, 1098 insertions(+), 492 deletions(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 27cf3ebff..c6122fa5c 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -1,641 +1,1247 @@ ################ Getting Started ################ - -# Swiftest User Manual -### The Purdue University Swiftest Team -#### Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh - ---- - -Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is an extension of the [Swifter](https://www.boulder.swri.edu/swifter/) software package, detailed in Duncan, Levison, and Lee (1998), that incorporates modern programming techniques and performance improvements. Swiftest contains the following numerical integrators: - -- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. See [Wisdom & Holman (1991)](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract). -- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of WHM that is capable of handling close encounters between test particles and massive bodies. See [Levison & Duncan (1994)](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub). -- **Democratic Heliocentric (HELIO)** - A symplectic integrator that uses the democratic heliocentric coordinate frame. See [Duncan, Levison, & Lee (1998)](https://iopscience.iop.org/article/10.1086/300541). -- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO that is capable of handling close encounters between massive bodies. See [Duncan, Levison, & Lee (1998)](https://iopscience.iop.org/article/10.1086/300541). - -Swiftest also includes the collisional fragmentation algorithm **Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to resolve collisions between massive bodies by determining the collisional regime, derived from the work of [Leinhardt & Stewart (2012)](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79), and generating the appropriate mass distribution of fragments. Swiftest fully incorporates collisional fragments into the gravitational system, evolving these new bodies along with pre-existing bodies, including their growth and any future fragmentation events in which they are involved. - ---- - -#### Installation - -For most users, installing swiftest can be done via pip using the command: - -``` -pip install swiftest -``` - -This will install the `swiftest` Python package, which can be incorporated into Python projects using `import swiftest`. It also will install a standalone executable called `swiftest_driver`, which can execute simulations from the command line, provided that initial conditions and configuration files are available in the path. - -**Building the `swiftest` Python package and standalone `swiftest_driver` executable** - -Swiftest is designed to be downloaded, compiled, and run on a Linux or MacOS based system. Windows support is currently being developed. - -It is possible to download, compile, and run Swiftest on a machine with at least 400 MB of free disk space and 8 GB of RAM. To take full advantage of the parallelization and performance updates included in Swiftest, it is highly recommended that Swiftest be installed on a high-performance computing cluster. For reference, Swiftest is maintained on the Purdue University [Bell Community Cluster](https://www.rcac.purdue.edu/compute/bell). - -Swiftest is written in Modern Fortran and must be compiled using an appropriate compiler. We recommend the Intel Fortran Compiler Classic (ifort) version 19.0 or higher. For details on installing ifort, see the [Intel installation documentation](https://www.intel.com/content/www/us/en/developer/tools/oneapi/fortran-compiler.html#gs.6xhjgy). The GCC/GNU Fortran Compiler (gfortran) version 9 or higher is also compatible. For details on installing gfortran, see the [GNU Fortran documentation](https://gcc.gnu.org/wiki/GFortran). - -Swiftest output files are stored in the NetCDF file format. This takes the place of the flat binary output file included in Swifter (and its predecessor [Swift](https://www.boulder.swri.edu/~hal/swift.html)). The NetCDF output format is compatible with Python, Java, and other languages that can be used to process and analyze simulation data. Details on installing NetCDF and the NetCDF Fortran Library can be found on the [Unidata website](https://docs.unidata.ucar.edu/netcdf-fortran/current/). NetCDF is built on HDF5 and it is necessary to install HDF and HDF5 as well. Details on installing HDF and HDF5 can be found on the [HDF Group website](https://www.hdfgroup.org/solutions/hdf5). - -Parallelization in Swiftest is done with OpenMP. Version 3.1.4 or higher is necessary to make use of parallelization in Swiftest. If Swiftest is only to be run in serial, this package is not necessary. See the [OpenMP website](https://www.openmp.org/resources/openmp-compilers-tools/) for more details and installation instructions. - -*Example of a module configuration that is necessary for compiling and running Swiftest:* -``` -1. intel/19.0.5.281 -2. openmpi/3.1.4 -3. netcdf/4.7.4 -4. netcdf-fortran/4.5.3 -5. hdf/4.2.15 -6. hdf5/1.10.6 -``` +Swiftest User Manual +==================== + +The Purdue University Swiftest Team +----------------------------------- + +Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +-------------- + +Swiftest is a software packaged designed to model the dynamical +evolution of gravitational systems. Swiftest is an extension of the +`Swifter `__ software package, +detailed in Duncan, Levison, and Lee (1998), that incorporates modern +programming techniques and performance improvements. Swiftest contains +the following numerical integrators: + +- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. + See `Wisdom & Holman + (1991) `__. +- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of + WHM that is capable of handling close encounters between test + particles and massive bodies. See `Levison & Duncan + (1994) `__. +- **Democratic Heliocentric (HELIO)** - A symplectic integrator that + uses the democratic heliocentric coordinate frame. See `Duncan, + Levison, & Lee + (1998) `__. +- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO + that is capable of handling close encounters between massive bodies. + See `Duncan, Levison, & Lee + (1998) `__. + +Swiftest also includes the collisional fragmentation algorithm +**Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to +resolve collisions between massive bodies by determining the collisional +regime, derived from the work of `Leinhardt & Stewart +(2012) `__, +and generating the appropriate mass distribution of fragments. Swiftest +fully incorporates collisional fragments into the gravitational system, +evolving these new bodies along with pre-existing bodies, including +their growth and any future fragmentation events in which they are +involved. + +-------------- + +Installation +~~~~~~~~~~~~ + +For most users, installing swiftest can be done via pip using the +command: + +:: + + pip install swiftest + +This will install the ``swiftest`` Python package, which can be +incorporated into Python projects using ``import swiftest``. It also +will install a standalone executable called ``swiftest_driver``, which +can execute simulations from the command line, provided that initial +conditions and configuration files are available in the path. + +**Building the ``swiftest`` Python package and standalone +``swiftest_driver`` executable** + +Swiftest is designed to be downloaded, compiled, and run on a Linux or +MacOS based system. Windows support is currently being developed. + +It is possible to download, compile, and run Swiftest on a machine with +at least 400 MB of free disk space and 8 GB of RAM. To take full +advantage of the parallelization and performance updates included in +Swiftest, it is highly recommended that Swiftest be installed on a +high-performance computing cluster. For reference, Swiftest is +maintained on the Purdue University `Bell Community +Cluster `__. + +Swiftest is written in Modern Fortran and must be compiled using an +appropriate compiler. We recommend the Intel Fortran Compiler Classic +(ifort) version 19.0 or higher. For details on installing ifort, see the +`Intel installation +documentation `__. +The GCC/GNU Fortran Compiler (gfortran) version 9 or higher is also +compatible. For details on installing gfortran, see the `GNU Fortran +documentation `__. + +Swiftest output files are stored in the NetCDF file format. This takes +the place of the flat binary output file included in Swifter (and its +predecessor `Swift `__). +The NetCDF output format is compatible with Python, Java, and other +languages that can be used to process and analyze simulation data. +Details on installing NetCDF and the NetCDF Fortran Library can be found +on the `Unidata +website `__. +NetCDF is built on HDF5 and it is necessary to install HDF and HDF5 as +well. Details on installing HDF and HDF5 can be found on the `HDF Group +website `__. + +Parallelization in Swiftest is done with OpenMP. Version 3.1.4 or higher +is necessary to make use of parallelization in Swiftest. If Swiftest is +only to be run in serial, this package is not necessary. See the `OpenMP +website `__ +for more details and installation instructions. + +*Example of a module configuration that is necessary for compiling and +running Swiftest:* + +:: + + 1. intel/19.0.5.281 + 2. openmpi/3.1.4 + 3. netcdf/4.7.4 + 4. netcdf-fortran/4.5.3 + 5. hdf/4.2.15 + 6. hdf5/1.10.6 **Downloading Swiftest** -The easiest way to get Swiftest on your machine is to clone the GitHub repository. To do so, open a terminal window and type the following: - -``` -$ git clone https://github.com/carlislewishard/swiftest.git -``` - -If your cloned version is not already set to the master branch: - -``` -$ git checkout master -``` - -To pull down any updates to Swiftest: - -``` -$ git pull -``` - -You now have a Swiftest repository on your personal machine that you may compile, edit, and run as you see fit. - -**Compiling the Swiftest driver program** - -***Compiling `swiftest_driver` using Docker*** - -By far the simplest, most reliable way of compiling the driver program is via a Docker container. The Swiftest project contains a Dockerfile that may be used to generate an executable without needing to provide any external dependencies, other than the Docker engine itself (see [here](https://docs.docker.com/get-docker/) for instructions on obtaining Docker). Once Docker is installed and the Docker engine is running, execute: -``` -$ docker build --target=export_driver \ - --output=bin \ - --build-arg MACHINE_CODE_VALUE="Host" \ - [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ - [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] -``` - -The Docker build will download and compile all of the library dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries and the Swiftest driver using Intel compilers. Once completed, the Swiftest executable, called ```swiftest_driver```, should now be created in the ```bin/``` directory. - -> Note: The Dockerfile is designed to build an executable that is compatible with a broad range of CPU architectures by specifying the SSE2 instruction as a target for SIMD instructions using the `-x` compiler option. When compiling on the same CPU archictecture you plan to execute the driver program, for the highest possible SIMD performance, use `--build-arg MACHINE_CODE_VALUE="Host" to override the default `MACHINE_CODE_VALUE="SSE2"`. For additional options see [here](https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-1/x-qx.html). +The easiest way to get Swiftest on your machine is to clone the GitHub +repository. To do so, open a terminal window and type the following: -The optional Docker argument `EXTRA_CMAKE_OPTIONS` is provided to pass any additional CMake arguments (see below). +:: -***Compiling `swiftest_driver` using CMake*** -Several build scripts are available in the `buildscripts` folder for building Swiftest and its dependencies on a Linux or Mac system. These are used when generating the official Swiftest Python wheels using cibuildwheel. To build the complete project, run `buildscripts\build_all.sh` from the command line. + $ git clone https://github.com/carlislewishard/swiftest.git -***Compiling `swiftest_driver` using CMake*** - -The Swiftest driver program is written in modern Fortran and must be compiled before it can be run. After compilation, an executable, called the `swiftest_driver``, will have been created in the ```bin/``` directory. - -Swiftest is compiled through [CMake](https://cmake.org/). Compiling with CMake has a number of benefits that provide a streamlined experience for the Swiftest user and developer. At compilation, CMake will automatically select the set of flags that are compatible with the local compiler. CMake also allows a Swiftest developer to re-compile only the files that have been edited, instead of requiring the developer to re-compile the entire Swiftest program. Please visit the CMake website for more information on how to install CMake. +If your cloned version is not already set to the master branch: -As mentioned in the **System Requirements** section, Swiftest requires the NetCDF and NetCDF Fortran libraries to be installed prior to compilation. If the libraries are installed in the standard library location on your machine, CMake should be able to find the libraries without specifying the path. However, if CMake struggles to find the NetCDF libraries, there are two ways to set the path to these libraries. +:: -1. Create an environment variable called ```NETCDF_FORTRAN_HOME``` that contains the path to the location where the libraries are installed -2. Set the path at the build step using ```-CMAKE_PREFIX_PATH=/path/to/netcdf/``` + $ git checkout master -CMake allows the user to specify a set of compiler flags to use during compilation. We define five sets of compiler flags: release, testing, profile, math, and debug. To view and/or edit the flags included in each set, see ```swiftest/cmake/Modules/SetFortranFlags.cmake```. +To pull down any updates to Swiftest: -As a general rule, the release flags are fully optimized and best used when running Swiftest with the goal of generating results. This is the default set of flags. When making changes to the Swiftest source code, it is best to compile Swiftest using the debug set of flags. You may also define your own set of compiler flags. +:: -Navigate to the topmost directory in your Swiftest repository. It is best practice to create a ```build``` directory in your topmost directory from which you will compile Swiftest. This way, temporary CMake files will not clutter up the ```swiftest/src/``` sub-directories. The commands to build the source code into a ```build``` directory and compile Swiftest are: + $ git pull -``` -$ cmake -B build -S . -$ cmake --build build -``` -The [CMake Fortran template](https://github.com/SethMMorton/cmake_fortran_template) comes with a script that can be used to clean out any build artifacts and start from scratch: +You now have a Swiftest repository on your personal machine that you may +compile, edit, and run as you see fit. -``` -$ cmake -P distclean.cmake -``` +**Compiling the Swiftest driver program** -The Swiftest CMake configuration comes with several customization options: +**Compiling ``swiftest_driver`` using Docker** + +By far the simplest, most reliable way of compiling the driver program +is via a Docker container. The Swiftest project contains a Dockerfile +that may be used to generate an executable without needing to provide +any external dependencies, other than the Docker engine itself (see +`here `__ for instructions on +obtaining Docker). Once Docker is installed and the Docker engine is +running, execute: + +:: + + $ docker build --target=export_driver \ + --output=bin \ + --build-arg MACHINE_CODE_VALUE="Host" \ + [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ + [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] + +The Docker build will download and compile all of the library +dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries +and the Swiftest driver using Intel compilers. Once completed, the +Swiftest executable, called ``swiftest_driver``, should now be created +in the ``bin/`` directory. + + Note: The Dockerfile is designed to build an executable that is + compatible with a broad range of CPU architectures by specifying the + SSE2 instruction as a target for SIMD instructions using the ``-x`` + compiler option. When compiling on the same CPU archictecture you + plan to execute the driver program, for the highest possible SIMD + performance, use + ``--build-arg MACHINE_CODE_VALUE="Host" to override the default``\ MACHINE_CODE_VALUE=“SSE2”\`. + For additional options see + `here `__. + +The optional Docker argument ``EXTRA_CMAKE_OPTIONS`` is provided to pass +any additional CMake arguments (see below). + +**Compiling ``swiftest_driver`` using CMake** Several build scripts are +available in the ``buildscripts`` folder for building Swiftest and its +dependencies on a Linux or Mac system. These are used when generating +the official Swiftest Python wheels using cibuildwheel. To build the +complete project, run ``buildscripts\build_all.sh`` from the command +line. + +**Compiling ``swiftest_driver`` using CMake** + +The Swiftest driver program is written in modern Fortran and must be +compiled before it can be run. After compilation, an executable, called +the \`swiftest_driver`\`, will have been created in the ``bin/`` +directory. + +Swiftest is compiled through `CMake `__. Compiling +with CMake has a number of benefits that provide a streamlined +experience for the Swiftest user and developer. At compilation, CMake +will automatically select the set of flags that are compatible with the +local compiler. CMake also allows a Swiftest developer to re-compile +only the files that have been edited, instead of requiring the developer +to re-compile the entire Swiftest program. Please visit the CMake +website for more information on how to install CMake. + +As mentioned in the **System Requirements** section, Swiftest requires +the NetCDF and NetCDF Fortran libraries to be installed prior to +compilation. If the libraries are installed in the standard library +location on your machine, CMake should be able to find the libraries +without specifying the path. However, if CMake struggles to find the +NetCDF libraries, there are two ways to set the path to these libraries. + +1. Create an environment variable called ``NETCDF_FORTRAN_HOME`` that + contains the path to the location where the libraries are installed +2. Set the path at the build step using + ``-CMAKE_PREFIX_PATH=/path/to/netcdf/`` + +CMake allows the user to specify a set of compiler flags to use during +compilation. We define five sets of compiler flags: release, testing, +profile, math, and debug. To view and/or edit the flags included in each +set, see ``swiftest/cmake/Modules/SetFortranFlags.cmake``. + +As a general rule, the release flags are fully optimized and best used +when running Swiftest with the goal of generating results. This is the +default set of flags. When making changes to the Swiftest source code, +it is best to compile Swiftest using the debug set of flags. You may +also define your own set of compiler flags. + +Navigate to the topmost directory in your Swiftest repository. It is +best practice to create a ``build`` directory in your topmost directory +from which you will compile Swiftest. This way, temporary CMake files +will not clutter up the ``swiftest/src/`` sub-directories. The commands +to build the source code into a ``build`` directory and compile Swiftest +are: + +:: + + $ cmake -B build -S . + $ cmake --build build + +The `CMake Fortran +template `__ +comes with a script that can be used to clean out any build artifacts +and start from scratch: + +:: + + $ cmake -P distclean.cmake + +The Swiftest CMake configuration comes with several customization +options: + ++------------------------+---------------------------------------------+ +| Option | CMake command | ++========================+=============================================+ +| Build type | -DCMAKE_BUILD_ | +| | TYPE=[**RELEASE**\ \|DEBUG|TESTING|PROFILE] | ++------------------------+---------------------------------------------+ +| Enable/Disable OpenMP | -DUSE_OPENMP=[**ON**\ \|OFF] | +| support | | ++------------------------+---------------------------------------------+ +| Enable/Disable SIMD | -DUSE_SIMD=[**ON**\ \|OFF] | +| directives | | ++------------------------+---------------------------------------------+ +| Enable/Disable Coarray | -DUSE_COARRAY=[ON\|\ **OFF**] | +| support (experimental) | | ++------------------------+---------------------------------------------+ +| Set Fortran compiler | -DCMAKE | +| path | _Fortran_COMPILER=/path/to/fortran/compiler | ++------------------------+---------------------------------------------+ +| Set path to make | -DCMAKE_MAKE_PROGRAM=/path/to/make | +| program | | ++------------------------+---------------------------------------------+ +| Enable/Disable shared | -DBUILD_SHARED_LIBS=[\**ON|OFF] | +| libraries (Intel only) | | ++------------------------+---------------------------------------------+ +| Add additional include | -DCMAKE_Fortran_FLAGS=“-I/path/to/libraries | +| path | | ++------------------------+---------------------------------------------+ +| Install prefix | -DCMAKE_INSTALL_PREF | +| | IX=[“/path/to/install”\|\ **“/usr/local”**] | ++------------------------+---------------------------------------------+ -| Option | CMake command | -| --------------------------------|------------------------------------------------------------| -| Build type | \-DCMAKE_BUILD_TYPE=[**RELEASE**\|DEBUG\|TESTING\|PROFILE] | -| Enable/Disable OpenMP support | \-DUSE_OPENMP=[**ON**\|OFF] | -| Enable/Disable SIMD directives | \-DUSE_SIMD=[**ON**\|OFF] | -| Enable/Disable Coarray support (experimental) | \-DUSE_COARRAY=[ON\|**OFF**] | -| Set Fortran compiler path | \-DCMAKE_Fortran_COMPILER=/path/to/fortran/compiler | -| Set path to make program | \-DCMAKE_MAKE_PROGRAM=/path/to/make | -| Enable/Disable shared libraries (Intel only) | \-DBUILD_SHARED_LIBS=[**ON\|OFF] | -| Add additional include path | \-DCMAKE_Fortran_FLAGS="-I/path/to/libraries | -| Install prefix | \-DCMAKE_INSTALL_PREFIX=["/path/to/install"\|**"/usr/local"**] | +To see a list of all possible options available to CMake: +:: -To see a list of all possible options available to CMake: -``` -$ cmake -B build -S . -LA -``` + $ cmake -B build -S . -LA -The Swiftest executable, called `swiftest_driver`, should now be created in the `bin/` directory. +The Swiftest executable, called ``swiftest_driver``, should now be +created in the ``bin/`` directory. +**Download the ``swiftest_driver`` as a Docker or Singularity +container.** -**Download the `swiftest_driver` as a Docker or Singularity container.** +The Swiftest driver is available as a Docker container on DockerHub in +two versions: Intel and GNU. The Intel version was compiled for the +x86_64 CPU using the Intel classic Fortran compiler. The GNU version was +compliled for the x86_64 CPU using gfortran. The Intel version is faster +than the GNU version (though not as fast as a native compile to the +target CPU that you wish to run it on due to vectorization optimizations +that Swiftest takes advantage of), however it is much larger: The Intel +version is ~2.7GB while the GNU version is ~300MB. The Singularity +container pulls from the same DockerHub container. -The Swiftest driver is available as a Docker container on DockerHub in two versions: Intel and GNU. The Intel version was compiled for the x86_64 CPU using the Intel classic Fortran compiler. The GNU version was compliled for the x86_64 CPU using gfortran. The Intel version is faster than the GNU version (though not as fast as a native compile to the target CPU that you wish to run it on due to vectorization optimizations that Swiftest takes advantage of), however it is much larger: The Intel version is ~2.7GB while the GNU version is ~300MB. The Singularity container pulls from the same DockerHub container. +To facilitate installation of the container, we provide a set of shell +scripts to help automate the process of installing container versions of +the executable. To install the default Intel version of the docker +container from within the ``swiftest\`` project directory -To facilitate installation of the container, we provide a set of shell scripts to help automate the process of installing container versions of the executable. To install the default Intel version of the docker container from within the `swiftest\` project directory +:: -``` -$ cd docker -$ . ./install.sh -``` + $ cd docker + $ . ./install.sh To install the GNU version: -``` -$ cd docker -$ . ./install.sh gnu -``` +:: -The Singularity versions are installed the same way, just replace `cd docker` with `cd singularity` above. + $ cd docker + $ . ./install.sh gnu -Whether installing either the Docker or Singularity containers, the install script will copy an executable shell script `swiftest_driver` into `swiftest/bin/`. Not that when installing the Singularity container, the install script will set an environment variable called `SWIFTEST_SIF` that must point to the aboslute path of the container file called `swiftest_driver.sif`. To use the driver script in a future shell, rather than running the install script again, we suggest adding the environment variable definition to your shell startup script (e.g. add `export SWIFTEST_SIF="/path/to/swiftest/singularity/swiftest.sif"` to your `.zshrc`) +The Singularity versions are installed the same way, just replace +``cd docker`` with ``cd singularity`` above. +Whether installing either the Docker or Singularity containers, the +install script will copy an executable shell script ``swiftest_driver`` +into ``swiftest/bin/``. Not that when installing the Singularity +container, the install script will set an environment variable called +``SWIFTEST_SIF`` that must point to the aboslute path of the container +file called ``swiftest_driver.sif``. To use the driver script in a +future shell, rather than running the install script again, we suggest +adding the environment variable definition to your shell startup script +(e.g. add +``export SWIFTEST_SIF="/path/to/swiftest/singularity/swiftest.sif"`` to +your ``.zshrc``) **Swiftest Python Package** -Included with Swiftest, in the ```/swiftest/python/swiftest/``` directory, is a Python package designed to facilitate seamless data processing and analysis. The Python package, also called Swiftest, can be used to generate input files, run Swiftest simulations, and process output files in the NetCDF file format. +Included with Swiftest, in the ``/swiftest/python/swiftest/`` directory, +is a Python package designed to facilitate seamless data processing and +analysis. The Python package, also called Swiftest, can be used to +generate input files, run Swiftest simulations, and process output files +in the NetCDF file format. -To begin, Swiftest can be added to an existing conda environment, or a new conda environment may be created, so long as the required packages are installed. To create and activate a new conda environment with the prerequisite packages, open a terminal and navigate to the ```/swiftest/python/swiftest/``` directory. Type the following: +To begin, Swiftest can be added to an existing conda environment, or a +new conda environment may be created, so long as the required packages +are installed. To create and activate a new conda environment with the +prerequisite packages, open a terminal and navigate to the +``/swiftest/python/swiftest/`` directory. Type the following: -``` -$ conda create --name EnvName pip scipy numpy matplotlib pandas xarray jupyter astropy -y -$ conda activate EnvName -``` +:: -Next, we will install further required packages. Using the ```-e``` flag imports all packages in ```/swiftest/python/swiftest/requirements.txt```, including Swiftest. If the Swiftest Python package is updated in the future, using the ```-e``` flag should ensure that the user does not have to reinstall the package to use the updated version. + $ conda create --name EnvName pip scipy numpy matplotlib pandas xarray jupyter astropy -y + $ conda activate EnvName -``` -$ pip install --user -e . -``` +Next, we will install further required packages. Using the ``-e`` flag +imports all packages in ``/swiftest/python/swiftest/requirements.txt``, +including Swiftest. If the Swiftest Python package is updated in the +future, using the ``-e`` flag should ensure that the user does not have +to reinstall the package to use the updated version. -The Swiftest Python package should now be installed in the conda environment and is ready to use. If you would like to take the further step to add Swiftest to a Jupyter Notebook kernel, type the following: +:: -``` -$ ipython kernel install --user --name EnvName --display-name "Swiftest Kernel" -``` + $ pip install --user -e . ---- +The Swiftest Python package should now be installed in the conda +environment and is ready to use. If you would like to take the further +step to add Swiftest to a Jupyter Notebook kernel, type the following: -#### Usage +:: -Swiftest is built to make running a Swiftest simulation a streamlined and user-friendly experience, even for a new user. As a result, Swiftest is highly flexible and a simulation can be created, run, and processed in a number of different ways. The first choice the user must make is if they would prefer ASCII input files or NetCDF input files. We recommend NetCDF input files, however we include documentation for ASCII input files for completeness. + $ ipython kernel install --user --name EnvName --display-name "Swiftest Kernel" -**Brief Outline** - -To create and run a Swiftest simulation using the Swiftest Python package, follow the general script below. For more details on the input files and user options, continue reading this section. - -``` -import swiftest # Import the Swiftest Python package -sim = swiftest.Simulation(simdir = "directory_name", **kwargs) # Initialize a Swiftest simulation and define a directory/path in which to store simulation data -sim.add_solar_system_body(**kwargs) # Add any desired named Solar System bodies, including the Sun -sim.add_body(**kwargs) # Add any desired user defined bodies -sim.get_parameter(**kwargs) # View the default simulation parameters -sim.set_parameter(**kwargs) # Set any desired simulation parameters -sim.write_param(**kwargs) # Write simulation parameters to the param.in -sim.save(**kwargs) # Save the simulation initial conditions to init_cond.nc -sim.run(**kwargs) # Run the simulation (leave off if running from the executable) -``` - -To read in a set of Swiftest output files using the Swiftest Python package, follow the general script below. For more details on the output files and user options, continue reading this section. - -``` -import swiftest # Import the Swiftest Python package -sim = swiftest.Simulation(simdir = "directory_name", read_data=True) # Initialize a Swiftest simulation -sim.data # Body data over time -sim.init_cond # The initial conditions for the simulation -sim.encounters # Encounter data for all close encountering pairs -sim.collisions # Collision data for all colliders and collisional fragments -``` +-------------- -**NetCDF Input Files (Recommended)** +Usage +~~~~~ -Swiftest accepts a single NetCDF input file. This file can be created using the Swiftest Python Package through a few simple steps. +Swiftest is built to make running a Swiftest simulation a streamlined +and user-friendly experience, even for a new user. As a result, Swiftest +is highly flexible and a simulation can be created, run, and processed +in a number of different ways. The first choice the user must make is if +they would prefer ASCII input files or NetCDF input files. We recommend +NetCDF input files, however we include documentation for ASCII input +files for completeness. -To begin, simply create a new Python script in the directory you would like to store your simulation. Open the new script and import the Swiftest Python package. - -``` -import swiftest -``` - -Next, we initialize the Swiftest simulation object. Various parameters can be provided to the simulation via key word arguments at this stage. - -``` -sim = swiftest.Simulation(simdir = "directory_name", **kwargs) -``` - -The argument ```simdir``` is the name of the subdirectory in which to store all simulation data. This does not have to exist at the time the simulation object is initialized. - -The key word arguments available to the user, along with the default values for these arguments, are described in [simulation_kwargs](README_tables/simulation_kwargs.md). - -After creating the simulation and defining all desired parameters as keyword arguments, it is time to add bodies to the simulation. The Swiftest Python package interfaces with the [NASA JPL Horizons database](https://ssd.jpl.nasa.gov/horizons/), allowing a user to easily import the initial conditions of known solar system bodies using the ```add_solar_system_body``` method. - -``` -sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto"]) -``` +**Brief Outline** -User defined bodies can also be added to a Swiftest simulation through the Python package. Massive bodies and test particles can both be added using the ```add_body``` method. +To create and run a Swiftest simulation using the Swiftest Python +package, follow the general script below. For more details on the input +files and user options, continue reading this section. -``` -sim.add_body(**kwargs) -``` +:: -The key word arguments available to the user for the ```add_body``` method are described in [add_body_kwargs](README_tables/add_body_kwargs.md). + import swiftest # Import the Swiftest Python package + sim = swiftest.Simulation(simdir = "directory_name", **kwargs) # Initialize a Swiftest simulation and define a directory/path in which to store simulation data + sim.add_solar_system_body(**kwargs) # Add any desired named Solar System bodies, including the Sun + sim.add_body(**kwargs) # Add any desired user defined bodies + sim.get_parameter(**kwargs) # View the default simulation parameters + sim.set_parameter(**kwargs) # Set any desired simulation parameters + sim.write_param(**kwargs) # Write simulation parameters to the param.in + sim.save(**kwargs) # Save the simulation initial conditions to init_cond.nc + sim.run(**kwargs) # Run the simulation (leave off if running from the executable) -Once all desired bodies have been added to the Swiftest simulation, the simulation parameters can be accessed and changed using the ```get_parameter``` and ```set_parameter``` methods. The key word arguments available to the user for the ```get_parameter``` and ```set_parameter``` are the same as those described in [simulation_kwargs](README_tables/simulation_kwargs.md). +To read in a set of Swiftest output files using the Swiftest Python +package, follow the general script below. For more details on the output +files and user options, continue reading this section. -After all desired parameters have been set, the parameters can be saved to the **param.in** using the ```write_param``` method. The key word arguments available to the user for the ```write_param``` method are described in [write_param_kwargs](README_tables/write_param_kwargs.md). +:: -The state of the system can be saved to the initial conditions NetCDF file, **init_cond.nc**, using the ```save``` method. The key word arguments available to the user for the ```save``` method are described in [save_kwargs](README_tables/save_kwargs.md). + import swiftest # Import the Swiftest Python package + sim = swiftest.Simulation(simdir = "directory_name", read_data=True) # Initialize a Swiftest simulation + sim.data # Body data over time + sim.init_cond # The initial conditions for the simulation + sim.encounters # Encounter data for all close encountering pairs + sim.collisions # Collision data for all colliders and collisional fragments -Finally, a simulation can be run from the same script in which it is created (or a separate Python script) using the ```run``` method. This is optional as the simulation can also be run from an executable. More details on running a Swiftest simulation can be found in the section **Running a Swiftest Simulation**. The key word arguments available to the user for the ```run``` method are the same as those described in [simulation_kwargs](README_tables/simulation_kwargs.md). +**NetCDF Input Files (Recommended)** -**ASCII Input Files** -Swiftest accepts 4 ASCII input files. All four ASCII input files are necessary if using the ASCII input format, however the structure of each input file varies slightly depending on the features and capabilities of the integrator selected. The four ASCII input files are not necessary if using NetCDF input files. The four input files are as follows: +Swiftest accepts a single NetCDF input file. This file can be created +using the Swiftest Python Package through a few simple steps. -- **param.in** - The parameter input file. -- **cb.in** - The central body input file. -- **pl.in** - The massive body input file. -- **tp.in** - The test particle input file. +To begin, simply create a new Python script in the directory you would +like to store your simulation. Open the new script and import the +Swiftest Python package. -The parameter options used in the parameter input file are as described in [simulation_kwargs](README_tables/simulation_kwargs.md). +:: -The **cb.in** includes all central body initial conditions. The structure of the **cb.in** is as follows: + import swiftest -``` -0 ! ID number -1.0 ! Gravitational mass (G*mass) in mass units (ex. 39.47841760435743 for Sun in M_sun/AU/year) -1.0 ! Central body radius is distance units (ex. 0.004650467260962157 for Sun in AU) -0.0 ! J2 term, optional, set to 0.0 for a spherical body -0.0 ! J4 term, optional, set to 0.0 for a spherical body -0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only -0.0 0.0 0.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only -``` +Next, we initialize the Swiftest simulation object. Various parameters +can be provided to the simulation via key word arguments at this stage. -The **pl.in** includes all massive body initial conditions. The structure of the **pl.in** is as follows: +:: -``` -2 ! Total number of massive bodies -1, 0.0, 0.0 ! ID number, Gravitational mass (G*mass) in mass units, Hill Radius in distance units if RHILL_PRESENT is set to YES, leave off if not using -0.0 ! Radius is distance units if CHK_CLOSE is set to YES, leave off if not using -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly -0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only -1.0 1.0 1.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only -2, 0.0, 0.0 -0.0 -1.0 1.0 1.0 -1.0 1.0 1.0 -0.4 0.4 0.4 -1.0 1.0 1.0 -``` + sim = swiftest.Simulation(simdir = "directory_name", **kwargs) -The **tp.in** includes all test particle initial conditions. In the event that no test particles are desired, the **tp.in** must still be included, however it can simply contain a single ```0```. The structure of the **tp.in** is as follows: +The argument ``simdir`` is the name of the subdirectory in which to +store all simulation data. This does not have to exist at the time the +simulation object is initialized. -``` -2 ! Total number of test particles -3 ! ID number -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly -4 -1.0 1.0 1.0 -1.0 1.0 1.0 -``` +The key word arguments available to the user, along with the default +values for these arguments, are described in +`simulation_kwargs `__. -Note that the ID numbers of the test particles are a continuation of the ID numbers of the massive bodies. No two bodies in the system can have the same ID number. +After creating the simulation and defining all desired parameters as +keyword arguments, it is time to add bodies to the simulation. The +Swiftest Python package interfaces with the `NASA JPL Horizons +database `__, allowing a user to +easily import the initial conditions of known solar system bodies using +the ``add_solar_system_body`` method. + +:: + + sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto"]) + +User defined bodies can also be added to a Swiftest simulation through +the Python package. Massive bodies and test particles can both be added +using the ``add_body`` method. + +:: + + sim.add_body(**kwargs) + +The key word arguments available to the user for the ``add_body`` method +are described in `add_body_kwargs `__. + +Once all desired bodies have been added to the Swiftest simulation, the +simulation parameters can be accessed and changed using the +``get_parameter`` and ``set_parameter`` methods. The key word arguments +available to the user for the ``get_parameter`` and ``set_parameter`` +are the same as those described in +`simulation_kwargs `__. + +After all desired parameters have been set, the parameters can be saved +to the **param.in** using the ``write_param`` method. The key word +arguments available to the user for the ``write_param`` method are +described in +`write_param_kwargs `__. + +The state of the system can be saved to the initial conditions NetCDF +file, **init_cond.nc**, using the ``save`` method. The key word +arguments available to the user for the ``save`` method are described in +`save_kwargs `__. + +Finally, a simulation can be run from the same script in which it is +created (or a separate Python script) using the ``run`` method. This is +optional as the simulation can also be run from an executable. More +details on running a Swiftest simulation can be found in the section +**Running a Swiftest Simulation**. The key word arguments available to +the user for the ``run`` method are the same as those described in +`simulation_kwargs `__. + +**ASCII Input Files** Swiftest accepts 4 ASCII input files. All four +ASCII input files are necessary if using the ASCII input format, however +the structure of each input file varies slightly depending on the +features and capabilities of the integrator selected. The four ASCII +input files are not necessary if using NetCDF input files. The four +input files are as follows: + +- **param.in** - The parameter input file. +- **cb.in** - The central body input file. +- **pl.in** - The massive body input file. +- **tp.in** - The test particle input file. + +The parameter options used in the parameter input file are as described +in `simulation_kwargs `__. + +The **cb.in** includes all central body initial conditions. The +structure of the **cb.in** is as follows: + +:: + + 0 ! ID number + 1.0 ! Gravitational mass (G*mass) in mass units (ex. 39.47841760435743 for Sun in M_sun/AU/year) + 1.0 ! Central body radius is distance units (ex. 0.004650467260962157 for Sun in AU) + 0.0 ! J2 term, optional, set to 0.0 for a spherical body + 0.0 ! J4 term, optional, set to 0.0 for a spherical body + 0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only + 0.0 0.0 0.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only + +The **pl.in** includes all massive body initial conditions. The +structure of the **pl.in** is as follows: + +:: + + 2 ! Total number of massive bodies + 1, 0.0, 0.0 ! ID number, Gravitational mass (G*mass) in mass units, Hill Radius in distance units if RHILL_PRESENT is set to YES, leave off if not using + 0.0 ! Radius is distance units if CHK_CLOSE is set to YES, leave off if not using + 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination + 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly + 0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only + 1.0 1.0 1.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only + 2, 0.0, 0.0 + 0.0 + 1.0 1.0 1.0 + 1.0 1.0 1.0 + 0.4 0.4 0.4 + 1.0 1.0 1.0 + +The **tp.in** includes all test particle initial conditions. In the +event that no test particles are desired, the **tp.in** must still be +included, however it can simply contain a single ``0``. The structure of +the **tp.in** is as follows: + +:: + + 2 ! Total number of test particles + 3 ! ID number + 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination + 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly + 4 + 1.0 1.0 1.0 + 1.0 1.0 1.0 + +Note that the ID numbers of the test particles are a continuation of the +ID numbers of the massive bodies. No two bodies in the system can have +the same ID number. **Running a Swiftest Simulation** -The input files necessary to successfully run Swiftest should now be generated in the simulation directory. The user is now faced with a second choice: to run a Swiftest simulation from a Python environment or to run it directly from an executable. Either option is possible with NetCDF format input files, however ASCII input files must be run directly from an executable. +The input files necessary to successfully run Swiftest should now be +generated in the simulation directory. The user is now faced with a +second choice: to run a Swiftest simulation from a Python environment or +to run it directly from an executable. Either option is possible with +NetCDF format input files, however ASCII input files must be run +directly from an executable. **Running via Python** -To run a Swiftest simulation from the same script in which the initial conditions are created, simply add the following line after you have finished defining parameters and adding bodies to the simulation: - -``` -sim.run() -``` - -To run a previously created set of initial conditions, first read the old parameter file into Python, and then run it. Note that Swiftest will look in the ```/simdata``` subdirectory for the initial conditions by default. You may set a new path to the initial conditions using the ```param_file``` keyword argument. See the documentation detailing the key word arguments available to the user in [simulation_kwargs](README_tables/simulation_kwargs.md). - -``` -sim = swiftest.Simulation(simdir = "directory_name", read_param=True) -sim.run() -``` - -**Running via an Executable** +To run a Swiftest simulation from the same script in which the initial +conditions are created, simply add the following line after you have +finished defining parameters and adding bodies to the simulation: -To run a Swiftest simulation through an executable, create a symbolic link to the Swiftest driver from your current directory. +:: -``` -$ ln -s ~/PATH/TO/swiftest/bin/swiftest_driver . -``` + sim.run() -To run Swiftest, simply type the following command into the terminal: +To run a previously created set of initial conditions, first read the +old parameter file into Python, and then run it. Note that Swiftest will +look in the ``/simdata`` subdirectory for the initial conditions by +default. You may set a new path to the initial conditions using the +``param_file`` keyword argument. See the documentation detailing the key +word arguments available to the user in +`simulation_kwargs `__. -``` -$ ./swiftest_driver INTEGRATOR param.in -``` +:: -Where ```INTEGRATOR``` is your integrator of choice, either ```whm```, ```rmvs```, ```helio```, or ```symba```. + sim = swiftest.Simulation(simdir = "directory_name", read_param=True) + sim.run() -**Outputs** +**Running via an Executable** -The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. The standard output files are as follows: -- **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ```ISTEP_OUT``` timesteps and written every ```DUMP_CADENCE```. This file can be analyzed using the Swiftest Python package (```sim.data```). -- **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ```FRAGMENTATION``` is ```YES```, Swiftest SyMBA only. -- **swiftest.log** - A log containing a brief update on the status of the run. Only generated if Swiftest is run through the Python package or through a shell script. If Swiftest is run through an executable, these updates are output directly to the terminal. -- **collisions.nc** - The details of each collision that occurs in a simulation are recorded in a NetCDF file. Only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True```. This file can be analyzed using the Swiftest Python package (```sim.collisions```). -- **encounters.nc** - The details of each close encounter that occurs in a simulation are recorded in a NetCDF file. Only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True```. This file can be analyzed using the Swiftest Python package (```sim.encounters```). -- **init_cond.nc** - The initial conditions used to run the simulation. This file can be analyzed using the Swiftest Python package (```sim.init_cond```). -- **encounter_check_plpl_timer.log** - The log containing the encounter check timer for each massive body/massive body encounter, only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True``` and ```ENCOUNTER_CHECK```/```encounter_check_loops``` is ```ADAPTIVE```. -- **encounter_check_pltp_time.log** - The log containing the encounter check timer for each massive body/test particle encounter, only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True``` and ```ENCOUNTER_CHECK```/```encounter_check_loops``` is ```ADAPTIVE```. -- **interaction_timer.log** - The log containing the interaction loop timer for each interacting pair of bodies, only if ```INTERACTION_LOOPS``` is ```ADAPTIVE```. +To run a Swiftest simulation through an executable, create a symbolic +link to the Swiftest driver from your current directory. -To read in a Swiftest output file, simply create a new Python script in the simulation directory. +:: -``` -import swiftest -sim = swiftest.Simulation(simdir = "directory_name", read_data=True) -``` + $ ln -s ~/PATH/TO/swiftest/bin/swiftest_driver . -All Swiftest data is now stored in the Xarray datasets ```sim.data```, ```sim.collisions```, and ```sim.encounters``` and is easily processed, manipulated, and analyzed. +To run Swiftest, simply type the following command into the terminal: -Regardless of whether the status outputs are recorded in the **swiftest.log** or in the terminal, the output format is the same. Below is an example of a single status output: +:: -`````` -Time = 1.00000E+03; fraction done = 0.001; Number of active plm, pl, tp = 57, 108, 50 - DL/L0 = 6.83763E-12; DEcollisions/|E0| = 0.00000E+00; D(Eorbit+Ecollisions)/|E0| = 2.65579E-03; DM/M0 = 0.00000E+00 -Integration steps: Total wall time: 2.99848E+02; Interval wall time: 9.36192E+01;Interval wall time/step: 4.68956E-04 -`````` + $ ./swiftest_driver INTEGRATOR param.in -The first line includes the simulation time, the fraction of the simulation that is complete relative to ```tstop```, the number of fully-interactive massive bodies (```plm```) (SyMBA only), the total number of massive bodies (```pl```) including fully-interactive and semi-interactive bodies, and the number of test particles (```tp```) remaining in the system at that time. The second line includes the angular momentum error, the change in energy as a result of collisions only, the total change in energy, and the change in mass up to this point in the simulation (error analysis included only if ```ENERGY```/```compute_conservation_values``` is set to ```YES```/```True```). The third line contains the total wall time elapsed since the start of the simulation, the wall time elapsed since the start of the last step, and the average wall time per step since the start of the simulation. +Where ``INTEGRATOR`` is your integrator of choice, either ``whm``, +``rmvs``, ``helio``, or ``symba``. -**Restarting a Simulation From t $\neq$ 0** +**Outputs** -Just like Swiftest allows the user to run a simulation through an executable or through Python, Swiftest also allows the user to restart a simulation from t $\neq$ 0 in the same two manners. This can be useful in the case of an accidental termination of a simulation, such as through a power outage or computer failure. In many cases, it is also necessary to run a simulation to a new end point, past the original ```TSTOP```. +The number and type of output files generated by Swiftest depends on the +input parameters selected and the method through which Swiftest was run. +The standard output files are as follows: - **data.nc** - Always +generated, the output file containing the information for every body in +the system, recorded every ``ISTEP_OUT`` timesteps and written every +``DUMP_CADENCE``. This file can be analyzed using the Swiftest Python +package (``sim.data``). - **collisions.log** - The log containing the +record of each fragmentation event, including the collisional regime, +and the number of the fragments created, only if ``FRAGMENTATION`` is +``YES``, Swiftest SyMBA only. - **swiftest.log** - A log containing a +brief update on the status of the run. Only generated if Swiftest is run +through the Python package or through a shell script. If Swiftest is run +through an executable, these updates are output directly to the +terminal. - **collisions.nc** - The details of each collision that +occurs in a simulation are recorded in a NetCDF file. Only if +``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file +can be analyzed using the Swiftest Python package (``sim.collisions``). +- **encounters.nc** - The details of each close encounter that occurs in +a simulation are recorded in a NetCDF file. Only if +``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file +can be analyzed using the Swiftest Python package (``sim.encounters``). +- **init_cond.nc** - The initial conditions used to run the simulation. +This file can be analyzed using the Swiftest Python package +(``sim.init_cond``). - **encounter_check_plpl_timer.log** - The log +containing the encounter check timer for each massive body/massive body +encounter, only if ``CHK_CLOSE``/``close_encounter_check`` is +``YES``/``True`` and ``ENCOUNTER_CHECK``/``encounter_check_loops`` is +``ADAPTIVE``. - **encounter_check_pltp_time.log** - The log containing +the encounter check timer for each massive body/test particle encounter, +only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True`` and +``ENCOUNTER_CHECK``/``encounter_check_loops`` is ``ADAPTIVE``. - +**interaction_timer.log** - The log containing the interaction loop +timer for each interacting pair of bodies, only if ``INTERACTION_LOOPS`` +is ``ADAPTIVE``. + +To read in a Swiftest output file, simply create a new Python script in +the simulation directory. + +:: + + import swiftest + sim = swiftest.Simulation(simdir = "directory_name", read_data=True) + +All Swiftest data is now stored in the Xarray datasets ``sim.data``, +``sim.collisions``, and ``sim.encounters`` and is easily processed, +manipulated, and analyzed. + +Regardless of whether the status outputs are recorded in the +**swiftest.log** or in the terminal, the output format is the same. +Below is an example of a single status output: + +:: + + Time = 1.00000E+03; fraction done = 0.001; Number of active plm, pl, tp = 57, 108, 50 + DL/L0 = 6.83763E-12; DEcollisions/|E0| = 0.00000E+00; D(Eorbit+Ecollisions)/|E0| = 2.65579E-03; DM/M0 = 0.00000E+00 + Integration steps: Total wall time: 2.99848E+02; Interval wall time: 9.36192E+01;Interval wall time/step: 4.68956E-04 + +The first line includes the simulation time, the fraction of the +simulation that is complete relative to ``tstop``, the number of +fully-interactive massive bodies (``plm``) (SyMBA only), the total +number of massive bodies (``pl``) including fully-interactive and +semi-interactive bodies, and the number of test particles (``tp``) +remaining in the system at that time. The second line includes the +angular momentum error, the change in energy as a result of collisions +only, the total change in energy, and the change in mass up to this +point in the simulation (error analysis included only if +``ENERGY``/``compute_conservation_values`` is set to ``YES``/``True``). +The third line contains the total wall time elapsed since the start of +the simulation, the wall time elapsed since the start of the last step, +and the average wall time per step since the start of the simulation. + +**Restarting a Simulation From t :math:`\neq` 0** + +Just like Swiftest allows the user to run a simulation through an +executable or through Python, Swiftest also allows the user to restart a +simulation from t :math:`\neq` 0 in the same two manners. This can be +useful in the case of an accidental termination of a simulation, such as +through a power outage or computer failure. In many cases, it is also +necessary to run a simulation to a new end point, past the original +``TSTOP``. **Restarting via Python** -To restart a Swiftest simulation via the Swiftest Python package, follow the outline below: +To restart a Swiftest simulation via the Swiftest Python package, follow +the outline below: + +:: -``` -import swiftest -sim = swiftest.Simulation(simdir = "directory_name", read_data=True) -sim.set_parameter(tstop=VAL) # Set a new stop time if desired -sim.write_param() # Write simulation parameters to the param.in -sim.run() -``` + import swiftest + sim = swiftest.Simulation(simdir = "directory_name", read_data=True) + sim.set_parameter(tstop=VAL) # Set a new stop time if desired + sim.write_param() # Write simulation parameters to the param.in + sim.run() -Note that Swiftest will look in the ```/simdata``` subdirectory for the initial conditions by default. You may set a new path to the initial conditions using the ```param_file``` keyword argument. +Note that Swiftest will look in the ``/simdata`` subdirectory for the +initial conditions by default. You may set a new path to the initial +conditions using the ``param_file`` keyword argument. **Restarting via an Executable** -Every ```DUMP_CADENCE``` X ```ISTEP_OUT``` timesteps, Swiftest writes all simulation information from memory to the output files. At the same time, Swiftest also writes all simulation information to a new parameter file, titled **param.XXXXXXXXXXXXXXXXXX.in**. To restart a run from a previous parameter file, simply follow the instructions detailed in the **Running via an Executable** section, replacing ```param.in``` with the name of the parameter file from which you wish to restart. +Every ``DUMP_CADENCE`` X ``ISTEP_OUT`` timesteps, Swiftest writes all +simulation information from memory to the output files. At the same +time, Swiftest also writes all simulation information to a new parameter +file, titled **param.XXXXXXXXXXXXXXXXXX.in**. To restart a run from a +previous parameter file, simply follow the instructions detailed in the +**Running via an Executable** section, replacing ``param.in`` with the +name of the parameter file from which you wish to restart. ---- +-------------- -#### Updates to Swifter Included in Swiftest +Updates to Swifter Included in Swiftest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Collisional Fragmentation via Fraggle** -To activate the Fraggle algorithm, set ```FRAGMENTATION```/```fragmentation``` to ```YES```/```True```, depending on the mode in which Swiftest is being run. When resolving a close encounter that results in a collision, Fraggle determines the regime of the collision as well as the mass, number, position, velocity, and rotation of all resulting bodies. This is distinct from Swiftest SyMBA's predecessor, Swifter SyMBA, which assumes that all collisions result in perfect mergers. - -Fraggle distinguishes the following collisional regimes: (1) perfect merging, which includes the cratering, partial accretion, and graze-and-merge regimes of Leinhardt & Stewart 2012, (2) disruption, which includes the partial erosion regime of Leinhardt & Stewart 2012, (3) super-catastrophic disruption, and (4) hit-and-run events which can be either ‘pure’ or ‘disruptive’. - -For every collision throughout the course of a simulation, Fraggle writes a brief description of the collision to the **fraggle.log** output file. An example of a collision, stored in the **fraggle.log** output file, is as follows: - -``` -Fraggle logfile - - ********************************************************************************************************************** - Collision between massive bodies detected at time t = 2.063709800335315E-006 - ********************************************************************************************************************** - - -------------------------------------------------------------------- - Fraggle collisional regime determination results - -------------------------------------------------------------------- - True number of colliders : 2 - Index list of true colliders : 1 2 - Regime: Disruption - Energy loss : 2.298848838233116E-022 - -------------------------------------------------------------------- - Disruption between Target (1) and Projectile (2) - Fraggle generating 28 fragments. - Fraggle try 1 - Fraggle fragment generation succeeded after 1 tries - Generating 28 fragments -``` - -The details of the collision are stored in the simulation object (```sim.collisions```) which can be accessed using the Swiftest Python package. +To activate the Fraggle algorithm, set +``FRAGMENTATION``/``fragmentation`` to ``YES``/``True``, depending on +the mode in which Swiftest is being run. When resolving a close +encounter that results in a collision, Fraggle determines the regime of +the collision as well as the mass, number, position, velocity, and +rotation of all resulting bodies. This is distinct from Swiftest SyMBA’s +predecessor, Swifter SyMBA, which assumes that all collisions result in +perfect mergers. + +Fraggle distinguishes the following collisional regimes: (1) perfect +merging, which includes the cratering, partial accretion, and +graze-and-merge regimes of Leinhardt & Stewart 2012, (2) disruption, +which includes the partial erosion regime of Leinhardt & Stewart 2012, +(3) super-catastrophic disruption, and (4) hit-and-run events which can +be either ‘pure’ or ‘disruptive’. + +For every collision throughout the course of a simulation, Fraggle +writes a brief description of the collision to the **fraggle.log** +output file. An example of a collision, stored in the **fraggle.log** +output file, is as follows: + +:: + + Fraggle logfile + + ********************************************************************************************************************** + Collision between massive bodies detected at time t = 2.063709800335315E-006 + ********************************************************************************************************************** + + -------------------------------------------------------------------- + Fraggle collisional regime determination results + -------------------------------------------------------------------- + True number of colliders : 2 + Index list of true colliders : 1 2 + Regime: Disruption + Energy loss : 2.298848838233116E-022 + -------------------------------------------------------------------- + Disruption between Target (1) and Projectile (2) + Fraggle generating 28 fragments. + Fraggle try 1 + Fraggle fragment generation succeeded after 1 tries + Generating 28 fragments + +The details of the collision are stored in the simulation object +(``sim.collisions``) which can be accessed using the Swiftest Python +package. **General Relativity** -From its observation in the mid-1800s to the development of the theory of general relativity by Albert Einstein in 1915, the precession of Mercury's perihelion puzzled scientists and observers. Mercury's orbit precesses by approximately $42.980 \pm 0.001$ arcseconds / century more than is expected from Newtonian mechanics. This deviation can be explained by the curvature of spacetime due to the mass of the Sun. Mercury's close proximity to the Sun enhances the effects of general relativity, providing a good test case to highlight the functionality of general relativity in Swiftest. - -In this test case, we track the orbit of Mercury for 1000 years as it orbits around the Sun in the presence of the seven other massive planets. The precession rate of the longitude of periapsis of Mercury, as calculated by Swiftest SyMBA, differs by only $\sim 0.0286 \%$ from the precession rate calculated from the NASA JPL Horizons database. - -|![SyMBA General Relativity](README_figs/symba_gr.png "SyMBA General Relativity")| -|:--:| -|**Figure 1** - The longitude of periapsis of Mercury over 1000 years, as calculated by Swifter SyMBA (dotted green), Swiftest SyMBA with general relativity turned off (long dashed yellow), and Swiftest SyMBA with general relativity turned on (short dashed blue). These results are compared to the periapsis of Mercury as calculated from the NASA JPL Horizons database (solid red). Swiftest SyMBA with general relativity turned off is in good agreement with Swifter SyMBA ($\sim 0.00053 \%$ difference), while Swiftest SyMBA with general relativity turned on is in good agreement with the NASA JPL Horizons database ($\sim 0.0286 \%$ difference).| +From its observation in the mid-1800s to the development of the theory +of general relativity by Albert Einstein in 1915, the precession of +Mercury’s perihelion puzzled scientists and observers. Mercury’s orbit +precesses by approximately :math:`42.980 \pm 0.001` arcseconds / century +more than is expected from Newtonian mechanics. This deviation can be +explained by the curvature of spacetime due to the mass of the Sun. +Mercury’s close proximity to the Sun enhances the effects of general +relativity, providing a good test case to highlight the functionality of +general relativity in Swiftest. + +In this test case, we track the orbit of Mercury for 1000 years as it +orbits around the Sun in the presence of the seven other massive +planets. The precession rate of the longitude of periapsis of Mercury, +as calculated by Swiftest SyMBA, differs by only :math:`\sim 0.0286 \%` +from the precession rate calculated from the NASA JPL Horizons database. + ++-----------------------------------------------------------------------+ +| |SyMBA General Relativity| | ++=======================================================================+ +| **Figure 1** - The longitude of periapsis of Mercury over 1000 years, | +| as calculated by Swifter SyMBA (dotted green), Swiftest SyMBA with | +| general relativity turned off (long dashed yellow), and Swiftest | +| SyMBA with general relativity turned on (short dashed blue). These | +| results are compared to the periapsis of Mercury as calculated from | +| the NASA JPL Horizons database (solid red). Swiftest SyMBA with | +| general relativity turned off is in good agreement with Swifter SyMBA | +| (:math:`\sim 0.00053 \%` difference), while Swiftest SyMBA with | +| general relativity turned on is in good agreement with the NASA JPL | +| Horizons database (:math:`\sim 0.0286 \%` difference). | ++-----------------------------------------------------------------------+ **Adaptive Interaction Calculations and Encounter Checking** -In Swifter SyMBA, gravitational interactions between bodies are calculated on a pair-by-pair basis by solving an upper triangular matrix. In practice, this is done through a double loop. While effective, solving a triangular matrix is computationally costly and it is considered best practice to avoid nested loops wherever possible. Swiftest SyMBA offers an alternative to this method, allowing the user to choose between calculating the gravitational interactions between bodies through a traditional triangular matrix or through a flattened Euclidean distance matrix. - -A Euclidean distance matrix is a two-dimensional array that stores the distance between each pairing of points in a set of elements. For more details on the algorithm implemented in Swiftest to flatten the Euclidean distance matrix, please see [Angeletti, Bonny, & Koko 2019](https://hal.archives-ouvertes.fr/hal-02047514). - -Along with allowing the user to choose whether the gravitational interactions are calculated through an upper triangular matrix or a flattened Euclidean distance matrix, Swiftest SyMBA allows the user to let the program determine the speedier solution. Through adaptive interaction calculations, Swiftest SyMBA periodically tracks the time it takes to complete an interaction calculation using both the triangular and flat methods. Whichever method proves to be quicker is implemented until the next time both methods are tested. Swiftest SyMBA periodically checks the performance of each method, possibly switching between the two methods multiple times over the course of a simulation. By selecting adaptive interaction calculations, the user allows Swiftest SyMBA to optimize its own performance and adapt to changes in the number of particle pairings as the simulation progresses. - -An example of the adaptive interaction calculations, stored in the **interaction_timer.log** output file, is as follows: - -``` -Interaction loop timer logfile ! The file header -Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which calculation method is fastest -symba_kick_getacch_int_pl: loop timer turned on at t = 0.000000000000000E+000 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun -symba_kick_getacch_int_pl: stage 1 ! Begins timing the first method -FLAT 95 7353 1.291989664082687E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) -symba_kick_getacch_int_pl: stage 2 ! Begins timing the second method -TRIANGULAR 100 7353 1.359989120087039E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) -symba_kick_getacch_int_pl: the fastest loop method tested is FLAT ! The subroutine in which the timing is being conducted and which interaction calculation method is determined to be fastest -``` - -In addition to calculating the gravitational interactions between pairings of bodies, Swifter SyMBA also uses an upper triangular matrix to check if pairings of bodies are in a close encounter state. While similar to interaction calculations, encounter checking can be further simplified to exclude pairs of bodies which, based on their physical distance, are unlikely to be in an encounter state. To address this, Swiftest SyMBA offers an alternative to solving an upper triangular matrix through the sort and sweep method. - -The sort and sweep method of collision detection (see [Ericson 2005](https://www.sciencedirect.com/book/9781558607323/real-time-collision-detection) for more details), also known as the sweep and prune method, is a way of limiting the number of pairs of bodies that need to be checked for a collision in each time step. At the start of a new time step, the position of each body is calculated and the critical radius of each body is determined. The critical radius is based on the radius of a body's Hill sphere. The distance from a body's center to the extent of its critical radius defines the encounter sphere of the body. The position of the center of mass of the body and the extent of its encounter sphere are used to define the bounding box used in the sort and sweep algorithm. Based on the defined bounding box, the positions of the lower and upper bounds of all of the bodies in the simulation are compiled into sorted lists. Because each body is unlikely to move significantly between time steps, updating these sorted lists each time step is relatively straightforward. Only when the bounding boxes of two bodies overlap in all axes are the bodies flagged as an encountering pair. - -The sort and sweep algorithm is computationally efficient because it limits the number of potential encountering pairs that must be checked for encounters. For example, by calculating the bounding boxes of two bodies on opposite sides of the solar system, the algorithm then sorts the upper and lower bounds of these two bounding boxes into opposite ends of a sorted list. Through this sorting, the algorithm recognizes that these two bodies are unlikely to encounter one another in the following time step and is able to quickly exclude them from more extensive encounter checking, saving time and computational resources. -In the same way that the user can allow Swiftest SyMBA to adapt when calculating the gravitational interactions between bodies, the user can also allow Swiftest SyMBA to determine the faster method of encounter checking. Just as Swiftest SyMBA periodically tests the interaction calculation methods, it also periodically tests the encounter checking methods. The quicker of the two methods is selected and implemented, allowing Swiftest SyMBA to adapt to changes in the distribution of bodies in the system as the simulation progresses. - -An example of the adaptive encounter checking, stored in the **encounter_check_plpl_timer.log** output file, is as follows: - -``` -Encounter check loop timer logfile ! The file header -Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which checking method is fastest -encounter_check_all_plpl: loop timer turned on at t = 5.000000000000000E-003 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun -encounter_check_all_plpl: stage 1 ! Begins timing the first method -SORTSWEEP 196 7353 2.665578675370597E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) -encounter_check_all_plpl: stage 2 ! Begins timing the second method -TRIANGULAR 164 7353 2.230382156942744E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) -encounter_check_all_plpl: the fastest loop method tested is TRIANGULAR ! The subroutine in which the timing is being conducted and which encounter checking method is determined to be fastest -``` - -Together, adaptive interaction calculations and encounter checking are idea for lengthy simulations with a large number of particles. The flexibility of Swiftest SyMBA ensures that the parameters of the integration are optimized for each individual simulation, even as the simulation evolves. +In Swifter SyMBA, gravitational interactions between bodies are +calculated on a pair-by-pair basis by solving an upper triangular +matrix. In practice, this is done through a double loop. While +effective, solving a triangular matrix is computationally costly and it +is considered best practice to avoid nested loops wherever possible. +Swiftest SyMBA offers an alternative to this method, allowing the user +to choose between calculating the gravitational interactions between +bodies through a traditional triangular matrix or through a flattened +Euclidean distance matrix. + +A Euclidean distance matrix is a two-dimensional array that stores the +distance between each pairing of points in a set of elements. For more +details on the algorithm implemented in Swiftest to flatten the +Euclidean distance matrix, please see `Angeletti, Bonny, & Koko +2019 `__. + +Along with allowing the user to choose whether the gravitational +interactions are calculated through an upper triangular matrix or a +flattened Euclidean distance matrix, Swiftest SyMBA allows the user to +let the program determine the speedier solution. Through adaptive +interaction calculations, Swiftest SyMBA periodically tracks the time it +takes to complete an interaction calculation using both the triangular +and flat methods. Whichever method proves to be quicker is implemented +until the next time both methods are tested. Swiftest SyMBA periodically +checks the performance of each method, possibly switching between the +two methods multiple times over the course of a simulation. By selecting +adaptive interaction calculations, the user allows Swiftest SyMBA to +optimize its own performance and adapt to changes in the number of +particle pairings as the simulation progresses. + +An example of the adaptive interaction calculations, stored in the +**interaction_timer.log** output file, is as follows: + +:: + + Interaction loop timer logfile ! The file header + Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which calculation method is fastest + symba_kick_getacch_int_pl: loop timer turned on at t = 0.000000000000000E+000 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun + symba_kick_getacch_int_pl: stage 1 ! Begins timing the first method + FLAT 95 7353 1.291989664082687E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) + symba_kick_getacch_int_pl: stage 2 ! Begins timing the second method + TRIANGULAR 100 7353 1.359989120087039E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) + symba_kick_getacch_int_pl: the fastest loop method tested is FLAT ! The subroutine in which the timing is being conducted and which interaction calculation method is determined to be fastest + +In addition to calculating the gravitational interactions between +pairings of bodies, Swifter SyMBA also uses an upper triangular matrix +to check if pairings of bodies are in a close encounter state. While +similar to interaction calculations, encounter checking can be further +simplified to exclude pairs of bodies which, based on their physical +distance, are unlikely to be in an encounter state. To address this, +Swiftest SyMBA offers an alternative to solving an upper triangular +matrix through the sort and sweep method. + +The sort and sweep method of collision detection (see `Ericson +2005 `__ +for more details), also known as the sweep and prune method, is a way of +limiting the number of pairs of bodies that need to be checked for a +collision in each time step. At the start of a new time step, the +position of each body is calculated and the critical radius of each body +is determined. The critical radius is based on the radius of a body’s +Hill sphere. The distance from a body’s center to the extent of its +critical radius defines the encounter sphere of the body. The position +of the center of mass of the body and the extent of its encounter sphere +are used to define the bounding box used in the sort and sweep +algorithm. Based on the defined bounding box, the positions of the lower +and upper bounds of all of the bodies in the simulation are compiled +into sorted lists. Because each body is unlikely to move significantly +between time steps, updating these sorted lists each time step is +relatively straightforward. Only when the bounding boxes of two bodies +overlap in all axes are the bodies flagged as an encountering pair. + +| The sort and sweep algorithm is computationally efficient because it + limits the number of potential encountering pairs that must be checked + for encounters. For example, by calculating the bounding boxes of two + bodies on opposite sides of the solar system, the algorithm then sorts + the upper and lower bounds of these two bounding boxes into opposite + ends of a sorted list. Through this sorting, the algorithm recognizes + that these two bodies are unlikely to encounter one another in the + following time step and is able to quickly exclude them from more + extensive encounter checking, saving time and computational resources. +| In the same way that the user can allow Swiftest SyMBA to adapt when + calculating the gravitational interactions between bodies, the user + can also allow Swiftest SyMBA to determine the faster method of + encounter checking. Just as Swiftest SyMBA periodically tests the + interaction calculation methods, it also periodically tests the + encounter checking methods. The quicker of the two methods is selected + and implemented, allowing Swiftest SyMBA to adapt to changes in the + distribution of bodies in the system as the simulation progresses. + +An example of the adaptive encounter checking, stored in the +**encounter_check_plpl_timer.log** output file, is as follows: + +:: + + Encounter check loop timer logfile ! The file header + Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which checking method is fastest + encounter_check_all_plpl: loop timer turned on at t = 5.000000000000000E-003 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun + encounter_check_all_plpl: stage 1 ! Begins timing the first method + SORTSWEEP 196 7353 2.665578675370597E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) + encounter_check_all_plpl: stage 2 ! Begins timing the second method + TRIANGULAR 164 7353 2.230382156942744E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) + encounter_check_all_plpl: the fastest loop method tested is TRIANGULAR ! The subroutine in which the timing is being conducted and which encounter checking method is determined to be fastest + +Together, adaptive interaction calculations and encounter checking are +idea for lengthy simulations with a large number of particles. The +flexibility of Swiftest SyMBA ensures that the parameters of the +integration are optimized for each individual simulation, even as the +simulation evolves. **NetCDF Compatibility** -The NetCDF (Network Common Data Form) file format is a cross-platform method of creating, accessing, and sharing data. Due to its self-describing nature, NetCDF is ideal for archiving multidimensional scientific data. NetCDF files are also appendable, allowing for data to be added to a file after creation, making the NetCDF file format well suited for handling simulation output. NetCDF is maintained by the University Corporation for Atmospheric Research (UCAR) and is a standard file format across much of the atmospheric modeling community. +The NetCDF (Network Common Data Form) file format is a cross-platform +method of creating, accessing, and sharing data. Due to its +self-describing nature, NetCDF is ideal for archiving multidimensional +scientific data. NetCDF files are also appendable, allowing for data to +be added to a file after creation, making the NetCDF file format well +suited for handling simulation output. NetCDF is maintained by the +University Corporation for Atmospheric Research (UCAR) and is a standard +file format across much of the atmospheric modeling community. + +In Swifter SyMBA, simulation outputs were stored in a flat binary file. +These binary files could only be easily accessed through +`SwiftVis `__, a data analysis +and visualization software package designed to process Swifter data. In +accordance with modern data management practices and industry standards, +Swiftest incorporates a NetCDF output file format for all simulation +types. NetCDF is compatible with many of today’s most widely-used +programming languages including Fortran, Python, Java, C++, and more. By +writing simulation data to a NetCDF output file, Swiftest provides the +user with the flexibility to analyze and visualize data in any language +they choose. The NetCDF file format is also adaptable such that any +future additions to Swiftest can be seamlessly incorporated into the +output file. -In Swifter SyMBA, simulation outputs were stored in a flat binary file. These binary files could only be easily accessed through [SwiftVis](https://cs.trinity.edu/~mlewis/SwiftVis/), a data analysis and visualization software package designed to process Swifter data. In accordance with modern data management practices and industry standards, Swiftest incorporates a NetCDF output file format for all simulation types. NetCDF is compatible with many of today's most widely-used programming languages including Fortran, Python, Java, C++, and more. By writing simulation data to a NetCDF output file, Swiftest provides the user with the flexibility to analyze and visualize data in any language they choose. The NetCDF file format is also adaptable such that any future additions to Swiftest can be seamlessly incorporated into the output file. - **Object-Oriented Programming** -The 2003 version of Fortran introduced object-oriented programming, with Fortran 2008 providing further updates. Swiftest is written in modern Fortran and takes advantage of many of the object-oriented programming features included in Fortran 2003. In doing so, Swiftest is a complete restructure of its predecessor, Swifter. The reusability and simplification of code in Swiftest through object-oriented programming is a modern and flexible approach that allows for future enhancements and additions to the Swiftest package. +The 2003 version of Fortran introduced object-oriented programming, with +Fortran 2008 providing further updates. Swiftest is written in modern +Fortran and takes advantage of many of the object-oriented programming +features included in Fortran 2003. In doing so, Swiftest is a complete +restructure of its predecessor, Swifter. The reusability and +simplification of code in Swiftest through object-oriented programming +is a modern and flexible approach that allows for future enhancements +and additions to the Swiftest package. **Parallelization** -Parallelization using OpenMP is still under development in Swiftest. For preliminary results, see **Figure 2**. +Parallelization using OpenMP is still under development in Swiftest. For +preliminary results, see **Figure 2**. ---- +-------------- -#### Examples +Examples +~~~~~~~~ -All examples are included in the ```/swiftest/examples/``` directory. Simply run the script(s) included in the directory as you would normally run a Python script. See the **README.txt** included in each example directory for more details. +All examples are included in the ``/swiftest/examples/`` directory. +Simply run the script(s) included in the directory as you would normally +run a Python script. See the **README.txt** included in each example +directory for more details. **Basic_Simulation** -This example walks through how to set up a standard solar system simulation. It can be found in the ```/swiftest/examples/Basic_Simulation``` directory. It is intended to be run using the SyMBA integrator. It contains three classes of bodies: -- Fully-Interacting Massive Bodies - Gravitationally affect and are affected by other massive bodies. -- Semi-Interacting Massive Bodies - Gravitationally affect and are affected by fully-interacting massive bodies, do not gravitationally affect and are not affected by other semi-interacting massive bodies. -- Test Particles - Gravitationally affected by fully-interacting massive bodies only. - -To generate the initial conditions, run the Python script titled **basic_simulation.py**. This script also runs Swiftest SyMBA, generating output. To process the output file, run the script titled **output_reader.py**. +This example walks through how to set up a standard solar system +simulation. It can be found in the +``/swiftest/examples/Basic_Simulation`` directory. It is intended to be +run using the SyMBA integrator. It contains three classes of bodies: - +Fully-Interacting Massive Bodies - Gravitationally affect and are +affected by other massive bodies. - Semi-Interacting Massive Bodies - +Gravitationally affect and are affected by fully-interacting massive +bodies, do not gravitationally affect and are not affected by other +semi-interacting massive bodies. - Test Particles - Gravitationally +affected by fully-interacting massive bodies only. + +To generate the initial conditions, run the Python script titled +**basic_simulation.py**. This script also runs Swiftest SyMBA, +generating output. To process the output file, run the script titled +**output_reader.py**. **Chambers2013** -This example acts as a comparison to the work of [Chambers 2013](https://www.sciencedirect.com/science/article/pii/S0019103513000754?via%3Dihub). It can be found in the ```/swiftest/examples/Chambers2013``` directory. It is intended to be run using the SyMBA integrator and highlights how to run Swiftest using and executable, as opposed to through a Python script. To generate the initial conditions, run **init_cond.py**. To run Swiftest with these intial conditions, type: - -``` -./swiftest_driver symba param.in -``` +This example acts as a comparison to the work of `Chambers +2013 `__. +It can be found in the ``/swiftest/examples/Chambers2013`` directory. It +is intended to be run using the SyMBA integrator and highlights how to +run Swiftest using and executable, as opposed to through a Python +script. To generate the initial conditions, run **init_cond.py**. To run +Swiftest with these intial conditions, type: -To process the output file, run the script titled **scattermovie.py**. +:: -**Fragmentation** + ./swiftest_driver symba param.in -This example highlights the functionality of the Fraggle algorithm. It can be found in the ```/swiftest/examples/Fragmentation``` directory. It is intended to be run using the SyMBA integrator. It contains 9 pre-built collisional test cases: +To process the output file, run the script titled **scattermovie.py**. -- A Head-On Disruptive Collision -- An Off-Axis Disruptive Collision -- A Head-On Super-Catastrophic Disruptive Collision -- An Off-Axis Super-Catastrophic Disruptive Collision -- A Disruptive Hit and Run Collision -- A Pure Hit and Run Collision -- A Merger -- A Merger Crossing the Spin Barrier -- All of the Above +**Fragmentation** -To generate, run, and create a movie depicting the collision, run the Python script titled **Fragmentation_Movie.py**. Please note that this example requires a large amount of memory. For reference, this example was created and run using 4 nodes, each with 256 GB of memory. This amount of computational memory is necessary to generate a smooth movie. In this example, the trajectories of all bodies involved in the collision are saved at every point in the simulation. This is extremely expensive and should only be used to study a particular collisional event in detail. +This example highlights the functionality of the Fraggle algorithm. It +can be found in the ``/swiftest/examples/Fragmentation`` directory. It +is intended to be run using the SyMBA integrator. It contains 9 +pre-built collisional test cases: + +- A Head-On Disruptive Collision +- An Off-Axis Disruptive Collision +- A Head-On Super-Catastrophic Disruptive Collision +- An Off-Axis Super-Catastrophic Disruptive Collision +- A Disruptive Hit and Run Collision +- A Pure Hit and Run Collision +- A Merger +- A Merger Crossing the Spin Barrier +- All of the Above + +To generate, run, and create a movie depicting the collision, run the +Python script titled **Fragmentation_Movie.py**. Please note that this +example requires a large amount of memory. For reference, this example +was created and run using 4 nodes, each with 256 GB of memory. This +amount of computational memory is necessary to generate a smooth movie. +In this example, the trajectories of all bodies involved in the +collision are saved at every point in the simulation. This is extremely +expensive and should only be used to study a particular collisional +event in detail. **helio_gr_test** -This example demonstrates the functionality of general relativity in Swiftest HELIO. It can be found in the ```/swiftest/examples/helio_gr_test``` directory. It is intended to be run using the HELIO integrator. Because the SyMBA integrator is built upon the HELIO integrator, GR is also available in SyMBA. +This example demonstrates the functionality of general relativity in +Swiftest HELIO. It can be found in the +``/swiftest/examples/helio_gr_test`` directory. It is intended to be run +using the HELIO integrator. Because the SyMBA integrator is built upon +the HELIO integrator, GR is also available in SyMBA. **Multibody_Fragmentation** -This example highlights the functionality of the Fraggle algorithm. It can be found in the ```/swiftest/examples/Mulitbody_Fragmentation``` directory. It is intended to be run using the SyMBA integrator. To generate a set of initial conditions, run the initial conditions using Swiftest, and generate a movie depicting the collisional result, run the Python script titled **Multibody_Movie.py**. +This example highlights the functionality of the Fraggle algorithm. It +can be found in the ``/swiftest/examples/Mulitbody_Fragmentation`` +directory. It is intended to be run using the SyMBA integrator. To +generate a set of initial conditions, run the initial conditions using +Swiftest, and generate a movie depicting the collisional result, run the +Python script titled **Multibody_Movie.py**. **solar_impact** -This example demonstrates the conservation of angular momentum, energy, and mass during a collision between a massive body and the Sun, or central body. It can be found in the ```/swiftest/examples/solar_impact``` directory. It is intended to be run using the SyMBA integrator. +This example demonstrates the conservation of angular momentum, energy, +and mass during a collision between a massive body and the Sun, or +central body. It can be found in the ``/swiftest/examples/solar_impact`` +directory. It is intended to be run using the SyMBA integrator. **Swifter_Swiftest** -This set of examples acts as a comparison between Swiftest and its predecessor, Swifter. Two unique simulations are included in this example, one with 8 massive bodies and 0 test particles, and one with 108 massive bodies and 50 test particles. These simulations can be found in the ```/swiftest/examples/Swifter_Swiftest/8pl_0tp``` and the ```/swiftest/examples/Swifter_Swiftest/108pl_50tp``` directories, respectively. They are intended to be run using the SyMBA integrator. For details on how to run a simulation using Swifter, please see the [Swifter website](https://www.boulder.swri.edu/swifter/). +This set of examples acts as a comparison between Swiftest and its +predecessor, Swifter. Two unique simulations are included in this +example, one with 8 massive bodies and 0 test particles, and one with +108 massive bodies and 50 test particles. These simulations can be found +in the ``/swiftest/examples/Swifter_Swiftest/8pl_0tp`` and the +``/swiftest/examples/Swifter_Swiftest/108pl_50tp`` directories, +respectively. They are intended to be run using the SyMBA integrator. +For details on how to run a simulation using Swifter, please see the +`Swifter website `__. **whm_gr_test** -This example demonstrates the functionality of general relativity in Swiftest WHM. It can be found in the ```/swiftest/examples/whm_gr_test``` directory. It is intended to be run using the WHM integrator. Because the SyMBA integrator is built upon the HELIO integrator, which is in turn built upon the WHM integrator, GR is also available in SyMBA. - ---- - -#### Simulation Parameter FAQs and Recommendations - -**How do I know what timestep to use for my simulation (**```dt```**)?** - -A good rule is to set ```dt``` equal to one tenth the orbit of the inner-most body in your simulation. For example, if Mercury is your inner-most body, ```dt``` should be set to one tenth Mercury's orbit. Mercury's orbit is ~0.24 years (~88 days) so a timestep of 0.024 years should be sufficiently small to accurately model the orbit of Mercury. You can always go smaller to increase resolution. - -**How often should I output (**```ISTEP_OUT``` or ```TSTEP_OUT```, **and** ```DUMP_CADENCE```**)?** - -Depending on your simulation, you may want to write to the output file more or less frequently. Writing takes a considerable amount of computational time, so it is important to set a output cadence that is manageable. Conversely, storing data in memory may not be reasonable for all simulation configurations or hardware, so writing more frequently may be necessary. There is no hard and fast rule for how often you should output, however it is dependent on your total simulation length (```tmax```) and your timestep (```dt```). Think of ```ISTEP_OUT``` as the number of timesteps between writing to memory (or, alternatively with ```TSTEP_OUT```, the length of time between writing to memory), and ```DUMP_CADENCE``` as the number of write to memory operations between writing to file. - -For example, an appropriate output cadence for a run with a timestep of 0.005 years and a total simulation length of 100 My might be ```ISTEP_OUT = 2e5``` (```TSTEP_OUT = 1e3```) and ```DUMP_CADENCE = 10```. This means that data will be stores to memory every 2e5 timesteps and written to file every 2e6 timesteps. Based on our value of ```dt```, this is every 1,000 years and every 10,000 years, respectively. Our total simulation length tells us that we will write to file 10,000 times over the course of the simulation. For longer simulations, the output cadence may be less frequent to save computational space. For shorter simulations, the output cadence may be more frequent to increase resolution. - -**What mass threshold should I set to differentiate fully-interactive and semi-interactive bodies (**```GMTINY``` **or** ```MTINY```**)?** - -Semi-interacting bodies are useful because the integrator is not required to calculate gravitational interactions between pairs of semi-interacting particles. This can result in significant performance improvements, especially for systems that require hundreds or thousands of massive bodies. If your system only has a few tens of massive bodies, semi-interacting bodies may not be necessary. If you would like to differentiate between these two classes of bodies, simply set the mass threshold to be some value between the mass of the smallest fully-interacting body and the mass of the largest semi-interacting body that you choose. Semi-interacting bodies can collide with each other and grow to become fully interacting bodies once they pass the mass threshold. - -**What should minimum fragment mass should I use (**```MIN_GMFRAG``` **or** ```MIN_MFRAG```**)?** - -This mass threshold is necessary to ensure that Swiftest SyMBA does not generate huge amounts of very small fragments, grinding the model to a halt. While this value is largely empirical and dependent on each specific set of initial conditions, a good place to start is to set the minimum fragment mass threshold to be one tenth the size of the smallest body in your simulation. You can also adjust ```FRAG_REDUCTION``` to keep the number of fragments within a reasonable range. +This example demonstrates the functionality of general relativity in +Swiftest WHM. It can be found in the ``/swiftest/examples/whm_gr_test`` +directory. It is intended to be run using the WHM integrator. Because +the SyMBA integrator is built upon the HELIO integrator, which is in +turn built upon the WHM integrator, GR is also available in SyMBA. + +-------------- + +Simulation Parameter FAQs and Recommendations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**How do I know what timestep to use for my simulation +(**\ ``dt``\ **)?** + +A good rule is to set ``dt`` equal to one tenth the orbit of the +inner-most body in your simulation. For example, if Mercury is your +inner-most body, ``dt`` should be set to one tenth Mercury’s orbit. +Mercury’s orbit is ~0.24 years (~88 days) so a timestep of 0.024 years +should be sufficiently small to accurately model the orbit of Mercury. +You can always go smaller to increase resolution. + +**How often should I output (**\ ``ISTEP_OUT`` or ``TSTEP_OUT``, **and** +``DUMP_CADENCE``\ **)?** + +Depending on your simulation, you may want to write to the output file +more or less frequently. Writing takes a considerable amount of +computational time, so it is important to set a output cadence that is +manageable. Conversely, storing data in memory may not be reasonable for +all simulation configurations or hardware, so writing more frequently +may be necessary. There is no hard and fast rule for how often you +should output, however it is dependent on your total simulation length +(``tmax``) and your timestep (``dt``). Think of ``ISTEP_OUT`` as the +number of timesteps between writing to memory (or, alternatively with +``TSTEP_OUT``, the length of time between writing to memory), and +``DUMP_CADENCE`` as the number of write to memory operations between +writing to file. + +For example, an appropriate output cadence for a run with a timestep of +0.005 years and a total simulation length of 100 My might be +``ISTEP_OUT = 2e5`` (``TSTEP_OUT = 1e3``) and ``DUMP_CADENCE = 10``. +This means that data will be stores to memory every 2e5 timesteps and +written to file every 2e6 timesteps. Based on our value of ``dt``, this +is every 1,000 years and every 10,000 years, respectively. Our total +simulation length tells us that we will write to file 10,000 times over +the course of the simulation. For longer simulations, the output cadence +may be less frequent to save computational space. For shorter +simulations, the output cadence may be more frequent to increase +resolution. + +**What mass threshold should I set to differentiate fully-interactive +and semi-interactive bodies (**\ ``GMTINY`` **or** ``MTINY``\ **)?** + +Semi-interacting bodies are useful because the integrator is not +required to calculate gravitational interactions between pairs of +semi-interacting particles. This can result in significant performance +improvements, especially for systems that require hundreds or thousands +of massive bodies. If your system only has a few tens of massive bodies, +semi-interacting bodies may not be necessary. If you would like to +differentiate between these two classes of bodies, simply set the mass +threshold to be some value between the mass of the smallest +fully-interacting body and the mass of the largest semi-interacting body +that you choose. Semi-interacting bodies can collide with each other and +grow to become fully interacting bodies once they pass the mass +threshold. + +**What should minimum fragment mass should I use (**\ ``MIN_GMFRAG`` +**or** ``MIN_MFRAG``\ **)?** + +This mass threshold is necessary to ensure that Swiftest SyMBA does not +generate huge amounts of very small fragments, grinding the model to a +halt. While this value is largely empirical and dependent on each +specific set of initial conditions, a good place to start is to set the +minimum fragment mass threshold to be one tenth the size of the smallest +body in your simulation. You can also adjust ``FRAG_REDUCTION`` to keep +the number of fragments within a reasonable range. **What are the limits of Swiftest SyMBA?** -While Swiftest SyMBA is a powerful tool for modeling gravitational interactions between massive bodies, it does have its limits. Swiftest SyMBA is best used for systems containing tens to hundreds of fully-interacting massive bodies. It is also best used for timescales on the order of a few hundred million years or less. While it is possible to model systems on a billion year timescale, the computational power required may be beyond what is available to the average user. In these cases, it is recommended that the user consider modeling with test particles instead of massive bodies. For systems that contain mainly test particles, with few to no close encounters between massive bodies, Swiftest RMVS is likely a more appropriate tool. - -To get a sense of the scope of your desired simulation, it is recommended that you run your initial conditions and parameters for a just few steps. Make sure that you set ```ISTEP_OUT``` and ```DUMP_CADENCE``` to output only once the simulation is complete, not between steps. Because writing to the output files and memory takes a significant amount of computational time compared to integrating the step, we want to avoid counting writing time in our diagnostic information. The terminal output contains information about the total wall time and the wall time per integration step. To get a sense of how long your run will take to complete your desired ```tmax```, simply scale up the wall time per integration step to the number of steps necessary for ```tmax``` to be reached. Remember that writing to the output files will take a considerable amount of time. Adjust your initial conditions and parameters accordingly. - ---- - -#### References - -- Angeletti, M., Bonny, J. -M., and Koko, J. (2019). Parallel Euclidean distance matrix computation on big datasets. **HAL**. [HAL Id: hal-02047514](https://hal.archives-ouvertes.fr/hal-02047514) -- Duncan, M. J., Levison, H. F., and Lee, M. H. (1998). A Multiple Time Step Symplectic Algorithm for Integrating Close Encounters. **The Astronomical Journal**, 116, 2067. [doi: 10.1086/300541](https://iopscience.iop.org/article/10.1086/300541) -- Chambers, J. E. (2013). Late-Stage Planetary Accretion Including Hit-and-Run Collisions and Fragmentation. **Icarus**, 224. [doi: 10.1016/j.icarus.2013.02.015](https://www.sciencedirect.com/science/article/pii/S0019103513000754?via%3Dihub) -- Ericson, C. (2005) Real-Time Collision Detection. **Elsevier Inc.** [ISBN: 978-1-55860-732-3](https://www.sciencedirect.com/book/9781558607323/real-time-collision-detection) -- Leinhardt, Z. M. and Stewart, S. T. (2012). Collisions between Gravity-dominated Bodies. I. Outcome Regimes and Scaling Laws. **The Astrophysical Journal**, 745, 79. [doi:10.1088/0004-637X/745/1/79](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79) -- Levison, H. F. and Duncan, M. J. (1994). The Long-Term Behavior of Short-Period Comets. **Icarus**, 108, 18. [doi: 10.1006/icar.1994.1039](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub) -- Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body problem. **The Astronomical Journal**, 102. [doi: 0.1086/115978](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract) -- Wishard et al. (2023) - In preparation - ---- - -#### Community Guidelines - -**Contributing to Swiftest** -Swiftest is open source and can be freely accessed through our [GitHub page](https://github.itap.purdue.edu/MintonGroup/swiftest). If you wish to make a change and have that change incorporated into the published version of Swiftest, please issue a pull request. If you wish to edit Swiftest for your own personal use, no pull request is necessary. - -**Reporting an Issue** -If you stumble upon a bug or issue with the functionality of Swiftest, we want to hear about it! If you have a fix for this bug, please issue a pull request. If you do not have a fix for the bug and would like to report it, please contact the Purdue Swiftest Team via email (cwishard@purdue.edu). - -**User Support** -For help using Swiftest, please contact the Purdue Swiftest Team via email (cwishard@purdue.edu). - ---- - -#### Licensing Agreement - -Swiftest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - -Swiftest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with Swiftest. If not, see . +While Swiftest SyMBA is a powerful tool for modeling gravitational +interactions between massive bodies, it does have its limits. Swiftest +SyMBA is best used for systems containing tens to hundreds of +fully-interacting massive bodies. It is also best used for timescales on +the order of a few hundred million years or less. While it is possible +to model systems on a billion year timescale, the computational power +required may be beyond what is available to the average user. In these +cases, it is recommended that the user consider modeling with test +particles instead of massive bodies. For systems that contain mainly +test particles, with few to no close encounters between massive bodies, +Swiftest RMVS is likely a more appropriate tool. + +To get a sense of the scope of your desired simulation, it is +recommended that you run your initial conditions and parameters for a +just few steps. Make sure that you set ``ISTEP_OUT`` and +``DUMP_CADENCE`` to output only once the simulation is complete, not +between steps. Because writing to the output files and memory takes a +significant amount of computational time compared to integrating the +step, we want to avoid counting writing time in our diagnostic +information. The terminal output contains information about the total +wall time and the wall time per integration step. To get a sense of how +long your run will take to complete your desired ``tmax``, simply scale +up the wall time per integration step to the number of steps necessary +for ``tmax`` to be reached. Remember that writing to the output files +will take a considerable amount of time. Adjust your initial conditions +and parameters accordingly. + +-------------- + +References +~~~~~~~~~~ + +- Angeletti, M., Bonny, J. -M., and Koko, J. (2019). Parallel Euclidean + distance matrix computation on big datasets. **HAL**. `HAL Id: + hal-02047514 `__ +- Duncan, M. J., Levison, H. F., and Lee, M. H. (1998). A Multiple Time + Step Symplectic Algorithm for Integrating Close Encounters. **The + Astronomical Journal**, 116, 2067. `doi: + 10.1086/300541 `__ +- Chambers, J. E. (2013). Late-Stage Planetary Accretion Including + Hit-and-Run Collisions and Fragmentation. **Icarus**, 224. `doi: + 10.1016/j.icarus.2013.02.015 `__ +- Ericson, C. (2005) Real-Time Collision Detection. **Elsevier Inc.** + `ISBN: + 978-1-55860-732-3 `__ +- Leinhardt, Z. M. and Stewart, S. T. (2012). Collisions between + Gravity-dominated Bodies. I. Outcome Regimes and Scaling Laws. **The + Astrophysical Journal**, 745, 79. + `doi:10.1088/0004-637X/745/1/79 `__ +- Levison, H. F. and Duncan, M. J. (1994). The Long-Term Behavior of + Short-Period Comets. **Icarus**, 108, 18. `doi: + 10.1006/icar.1994.1039 `__ +- Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body + problem. **The Astronomical Journal**, 102. `doi: + 0.1086/115978 `__ +- Wishard et al. (2023) - In preparation + +-------------- + +Community Guidelines +~~~~~~~~~~~~~~~~~~~~ + +**Contributing to Swiftest** Swiftest is open source and can be freely +accessed through our `GitHub +page `__. If you +wish to make a change and have that change incorporated into the +published version of Swiftest, please issue a pull request. If you wish +to edit Swiftest for your own personal use, no pull request is +necessary. + +**Reporting an Issue** If you stumble upon a bug or issue with the +functionality of Swiftest, we want to hear about it! If you have a fix +for this bug, please issue a pull request. If you do not have a fix for +the bug and would like to report it, please contact the Purdue Swiftest +Team via email (cwishard@purdue.edu). + +**User Support** For help using Swiftest, please contact the Purdue +Swiftest Team via email (cwishard@purdue.edu). + +-------------- + +Licensing Agreement +~~~~~~~~~~~~~~~~~~~ + +Swiftest is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Swiftest is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along +with Swiftest. If not, see https://www.gnu.org/licenses/. + +.. |SyMBA General Relativity| image:: README_figs/symba_gr.png .. toctree:: From 7f4114d0c0be78a1e4a20664359d0609eaa9dfe8 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 11:48:31 -0500 Subject: [PATCH 283/324] Updated README.md to include published DOI for Swiftest --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d414b765..55c9a3920 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,7 @@ Where ```INTEGRATOR``` is your integrator of choice, either ```whm```, ```rmvs`` **Outputs** The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. The standard output files are as follows: + - **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ```ISTEP_OUT``` timesteps and written every ```DUMP_CADENCE```. This file can be analyzed using the Swiftest Python package (```sim.data```). - **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ```FRAGMENTATION``` is ```YES```, Swiftest SyMBA only. - **swiftest.log** - A log containing a brief update on the status of the run. Only generated if Swiftest is run through the Python package or through a shell script. If Swiftest is run through an executable, these updates are output directly to the terminal. @@ -608,7 +609,8 @@ To get a sense of the scope of your desired simulation, it is recommended that y - Leinhardt, Z. M. and Stewart, S. T. (2012). Collisions between Gravity-dominated Bodies. I. Outcome Regimes and Scaling Laws. **The Astrophysical Journal**, 745, 79. [doi:10.1088/0004-637X/745/1/79](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79) - Levison, H. F. and Duncan, M. J. (1994). The Long-Term Behavior of Short-Period Comets. **Icarus**, 108, 18. [doi: 10.1006/icar.1994.1039](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub) - Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body problem. **The Astronomical Journal**, 102. [doi: 0.1086/115978](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract) -- Wishard et al. (2023) - In preparation +- Wishard et al. (2023) - - Swiftest: An *N*-body Integrator for Gravitational Systems. **Journal of Open Source Software**, 8(90), 5409, + [https://doi.org/10.21105/joss.05409](https://doi.org/10.21105/joss.05409) --- From e8f2ac0352e9532b9f7f3ed4b6b9bcafc264b7e0 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 11:51:31 -0500 Subject: [PATCH 284/324] Added readme.md to Getting Started Guide --- docs/getting-started-guide/index.rst | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index c6122fa5c..e08e3d255 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -12,6 +12,7 @@ Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh -------------- + Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is an extension of the `Swifter `__ software package, @@ -64,8 +65,8 @@ will install a standalone executable called ``swiftest_driver``, which can execute simulations from the command line, provided that initial conditions and configuration files are available in the path. -**Building the ``swiftest`` Python package and standalone -``swiftest_driver`` executable** +**Building the** ``swiftest`` **Python package and standalone** +``swiftest_driver`` **executable** Swiftest is designed to be downloaded, compiled, and run on a Linux or MacOS based system. Windows support is currently being developed. @@ -143,7 +144,7 @@ compile, edit, and run as you see fit. **Compiling the Swiftest driver program** -**Compiling ``swiftest_driver`` using Docker** +**Compiling** ``swiftest_driver`` **using Docker** By far the simplest, most reliable way of compiling the driver program is via a Docker container. The Swiftest project contains a Dockerfile @@ -180,14 +181,14 @@ in the ``bin/`` directory. The optional Docker argument ``EXTRA_CMAKE_OPTIONS`` is provided to pass any additional CMake arguments (see below). -**Compiling ``swiftest_driver`` using CMake** Several build scripts are +**Compiling** ``swiftest_driver`` **using CMake** Several build scripts are available in the ``buildscripts`` folder for building Swiftest and its dependencies on a Linux or Mac system. These are used when generating the official Swiftest Python wheels using cibuildwheel. To build the complete project, run ``buildscripts\build_all.sh`` from the command line. -**Compiling ``swiftest_driver`` using CMake** +**Compiling** ``swiftest_driver`` **using CMake** The Swiftest driver program is written in modern Fortran and must be compiled before it can be run. After compilation, an executable, called @@ -612,11 +613,13 @@ Where ``INTEGRATOR`` is your integrator of choice, either ``whm``, The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. -The standard output files are as follows: - **data.nc** - Always +The standard output files are as follows: +- **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ``ISTEP_OUT`` timesteps and written every ``DUMP_CADENCE``. This file can be analyzed using the Swiftest Python -package (``sim.data``). - **collisions.log** - The log containing the +package (``sim.data``). +- **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ``FRAGMENTATION`` is ``YES``, Swiftest SyMBA only. - **swiftest.log** - A log containing a @@ -750,7 +753,7 @@ output file, is as follows: Fraggle logfile - ********************************************************************************************************************** + *********************************************************************************************************************** Collision between massive bodies detected at time t = 2.063709800335315E-006 ********************************************************************************************************************** @@ -1199,7 +1202,9 @@ References - Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body problem. **The Astronomical Journal**, 102. `doi: 0.1086/115978 `__ -- Wishard et al. (2023) - In preparation +- Wishard et al. (2023) - Swiftest: An *N*-body Integrator for + Gravitational Systems. **Journal of Open Source Software**, 8(90), 5409, + `https://doi.org/10.21105/joss.05409 `__ -------------- From bc4b0f6cf2917c40f82c22e56ccd47c04fbc1e45 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 11:55:03 -0500 Subject: [PATCH 285/324] fixed some formatting issues --- docs/getting-started-guide/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index e08e3d255..9ca882c19 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -192,7 +192,7 @@ line. The Swiftest driver program is written in modern Fortran and must be compiled before it can be run. After compilation, an executable, called -the \`swiftest_driver`\`, will have been created in the ``bin/`` +the ``swiftest_driver``, will have been created in the ``bin/`` directory. Swiftest is compiled through `CMake `__. Compiling @@ -291,7 +291,7 @@ To see a list of all possible options available to CMake: The Swiftest executable, called ``swiftest_driver``, should now be created in the ``bin/`` directory. -**Download the ``swiftest_driver`` as a Docker or Singularity +**Download the** ``swiftest_driver`` **as a Docker or Singularity container.** The Swiftest driver is available as a Docker container on DockerHub in From a6f6457bd6a47e9dfeb899cbc7c2d1df4b624e04 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 12:43:56 -0500 Subject: [PATCH 286/324] Added a blank line to show bullet point list better --- docs/getting-started-guide/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 9ca882c19..04fdb55f2 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -614,6 +614,7 @@ Where ``INTEGRATOR`` is your integrator of choice, either ``whm``, The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. The standard output files are as follows: + - **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ``ISTEP_OUT`` timesteps and written every From 6bf942f76ea329a65a03b163fcd6d8b357ccd1b0 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 12:51:15 -0500 Subject: [PATCH 287/324] Added a blank line to show bullet point list better. Again --- docs/getting-started-guide/index.rst | 42 ++++++---------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 04fdb55f2..ffd227144 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -615,39 +615,15 @@ The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. The standard output files are as follows: -- **data.nc** - Always -generated, the output file containing the information for every body in -the system, recorded every ``ISTEP_OUT`` timesteps and written every -``DUMP_CADENCE``. This file can be analyzed using the Swiftest Python -package (``sim.data``). -- **collisions.log** - The log containing the -record of each fragmentation event, including the collisional regime, -and the number of the fragments created, only if ``FRAGMENTATION`` is -``YES``, Swiftest SyMBA only. - **swiftest.log** - A log containing a -brief update on the status of the run. Only generated if Swiftest is run -through the Python package or through a shell script. If Swiftest is run -through an executable, these updates are output directly to the -terminal. - **collisions.nc** - The details of each collision that -occurs in a simulation are recorded in a NetCDF file. Only if -``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file -can be analyzed using the Swiftest Python package (``sim.collisions``). -- **encounters.nc** - The details of each close encounter that occurs in -a simulation are recorded in a NetCDF file. Only if -``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file -can be analyzed using the Swiftest Python package (``sim.encounters``). -- **init_cond.nc** - The initial conditions used to run the simulation. -This file can be analyzed using the Swiftest Python package -(``sim.init_cond``). - **encounter_check_plpl_timer.log** - The log -containing the encounter check timer for each massive body/massive body -encounter, only if ``CHK_CLOSE``/``close_encounter_check`` is -``YES``/``True`` and ``ENCOUNTER_CHECK``/``encounter_check_loops`` is -``ADAPTIVE``. - **encounter_check_pltp_time.log** - The log containing -the encounter check timer for each massive body/test particle encounter, -only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True`` and -``ENCOUNTER_CHECK``/``encounter_check_loops`` is ``ADAPTIVE``. - -**interaction_timer.log** - The log containing the interaction loop -timer for each interacting pair of bodies, only if ``INTERACTION_LOOPS`` -is ``ADAPTIVE``. +- **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ``ISTEP_OUT`` timesteps and written every ``DUMP_CADENCE``. This file can be analyzed using the Swiftest Python package (``sim.data``). +- **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ``FRAGMENTATION`` is ``YES``, Swiftest SyMBA only. +- **swiftest.log** - A log containing a brief update on the status of the run. Only generated if Swiftest is run through the Python package or through a shell script. If Swiftest is run through an executable, these updates are output directly to the terminal. +- **collisions.nc** - The details of each collision that occurs in a simulation are recorded in a NetCDF file. Only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file can be analyzed using the Swiftest Python package (``sim.collisions``). +- **encounters.nc** - The details of each close encounter that occurs in a simulation are recorded in a NetCDF file. Only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file can be analyzed using the Swiftest Python package (``sim.encounters``). +- **init_cond.nc** - The initial conditions used to run the simulation. This file can be analyzed using the Swiftest Python package (``sim.init_cond``). +- **encounter_check_plpl_timer.log** - The log containing the encounter check timer for each massive body/massive body encounter, only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True`` and ``ENCOUNTER_CHECK``/``encounter_check_loops`` is ``ADAPTIVE``. +- **encounter_check_pltp_time.log** - The log containing the encounter check timer for each massive body/test particle encounter, only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True`` and ``ENCOUNTER_CHECK``/``encounter_check_loops`` is ``ADAPTIVE``. +- **interaction_timer.log** - The log containing the interaction loop timer for each interacting pair of bodies, only if ``INTERACTION_LOOPS`` is ``ADAPTIVE``. To read in a Swiftest output file, simply create a new Python script in the simulation directory. From 6d4df798ceffdf5a635991029f79546ee05550a6 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 12:53:24 -0500 Subject: [PATCH 288/324] fixed math symbol issue --- docs/getting-started-guide/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index ffd227144..8210b5497 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -661,7 +661,7 @@ The third line contains the total wall time elapsed since the start of the simulation, the wall time elapsed since the start of the last step, and the average wall time per step since the start of the simulation. -**Restarting a Simulation From t :math:`\neq` 0** +**Restarting a Simulation From t** :math:`\neq` **0** Just like Swiftest allows the user to run a simulation through an executable or through Python, Swiftest also allows the user to restart a From 4c62739574e482c6c66172ff2744d8fe57f17145 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 14:23:08 -0500 Subject: [PATCH 289/324] Restructured documentation page and fixed errors with the rendering of the CMake build options --- .gitignore | 1 - README.md | 621 +-------------------- {README_figs => docs/_static}/symba_gr.png | Bin docs/getting-started-guide/index.rst | 103 +--- docs/index.rst | 24 +- 5 files changed, 54 insertions(+), 695 deletions(-) rename {README_figs => docs/_static}/symba_gr.png (100%) diff --git a/.gitignore b/.gitignore index a250469db..6d2a03086 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,6 @@ docs/generated/ docs/generated/**/* docs/**/*.DS_Store docs/**/*.swp -docs/ !docs/_static/**/*.png !docs/_static/**/*.svg **/*.ai diff --git a/README.md b/README.md index 55c9a3920..c74663a26 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,10 @@ -# Swiftest User Manual -### The Purdue University Swiftest Team -#### Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh - ---- - -Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is an extension of the [Swifter](https://www.boulder.swri.edu/swifter/) software package, detailed in Duncan, Levison, and Lee (1998), that incorporates modern programming techniques and performance improvements. Swiftest contains the following numerical integrators: - -- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. See [Wisdom & Holman (1991)](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract). -- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of WHM that is capable of handling close encounters between test particles and massive bodies. See [Levison & Duncan (1994)](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub). -- **Democratic Heliocentric (HELIO)** - A symplectic integrator that uses the democratic heliocentric coordinate frame. See [Duncan, Levison, & Lee (1998)](https://iopscience.iop.org/article/10.1086/300541). -- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO that is capable of handling close encounters between massive bodies. See [Duncan, Levison, & Lee (1998)](https://iopscience.iop.org/article/10.1086/300541). - -Swiftest also includes the collisional fragmentation algorithm **Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to resolve collisions between massive bodies by determining the collisional regime, derived from the work of [Leinhardt & Stewart (2012)](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79), and generating the appropriate mass distribution of fragments. Swiftest fully incorporates collisional fragments into the gravitational system, evolving these new bodies along with pre-existing bodies, including their growth and any future fragmentation events in which they are involved. +# Swiftest --- +Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is a re-write of the +`Swifter `__ software package +Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is a re-write of the [Swifter](https://www.boulder.swri.edu/swifter/) software package that incorporates modern programming techniques and performance +improvements. #### Installation @@ -25,607 +16,9 @@ pip install swiftest This will install the `swiftest` Python package, which can be incorporated into Python projects using `import swiftest`. It also will install a standalone executable called `swiftest_driver`, which can execute simulations from the command line, provided that initial conditions and configuration files are available in the path. -**Building the `swiftest` Python package and standalone `swiftest_driver` executable** - -Swiftest is designed to be downloaded, compiled, and run on a Linux or MacOS based system. Windows support is currently being developed. - -It is possible to download, compile, and run Swiftest on a machine with at least 400 MB of free disk space and 8 GB of RAM. To take full advantage of the parallelization and performance updates included in Swiftest, it is highly recommended that Swiftest be installed on a high-performance computing cluster. For reference, Swiftest is maintained on the Purdue University [Bell Community Cluster](https://www.rcac.purdue.edu/compute/bell). - -Swiftest is written in Modern Fortran and must be compiled using an appropriate compiler. We recommend the Intel Fortran Compiler Classic (ifort) version 19.0 or higher. For details on installing ifort, see the [Intel installation documentation](https://www.intel.com/content/www/us/en/developer/tools/oneapi/fortran-compiler.html#gs.6xhjgy). The GCC/GNU Fortran Compiler (gfortran) version 9 or higher is also compatible. For details on installing gfortran, see the [GNU Fortran documentation](https://gcc.gnu.org/wiki/GFortran). - -Swiftest output files are stored in the NetCDF file format. This takes the place of the flat binary output file included in Swifter (and its predecessor [Swift](https://www.boulder.swri.edu/~hal/swift.html)). The NetCDF output format is compatible with Python, Java, and other languages that can be used to process and analyze simulation data. Details on installing NetCDF and the NetCDF Fortran Library can be found on the [Unidata website](https://docs.unidata.ucar.edu/netcdf-fortran/current/). NetCDF is built on HDF5 and it is necessary to install HDF and HDF5 as well. Details on installing HDF and HDF5 can be found on the [HDF Group website](https://www.hdfgroup.org/solutions/hdf5). - -Parallelization in Swiftest is done with OpenMP. Version 3.1.4 or higher is necessary to make use of parallelization in Swiftest. If Swiftest is only to be run in serial, this package is not necessary. See the [OpenMP website](https://www.openmp.org/resources/openmp-compilers-tools/) for more details and installation instructions. - -*Example of a module configuration that is necessary for compiling and running Swiftest:* -``` -1. intel/19.0.5.281 -2. openmpi/3.1.4 -3. netcdf/4.7.4 -4. netcdf-fortran/4.5.3 -5. hdf/4.2.15 -6. hdf5/1.10.6 -``` - -**Downloading Swiftest** - -The easiest way to get Swiftest on your machine is to clone the GitHub repository. To do so, open a terminal window and type the following: - -``` -$ git clone https://github.com/carlislewishard/swiftest.git -``` - -If your cloned version is not already set to the master branch: - -``` -$ git checkout master -``` - -To pull down any updates to Swiftest: - -``` -$ git pull -``` - -You now have a Swiftest repository on your personal machine that you may compile, edit, and run as you see fit. - -**Compiling the Swiftest driver program** - -***Compiling `swiftest_driver` using Docker*** - -By far the simplest, most reliable way of compiling the driver program is via a Docker container. The Swiftest project contains a Dockerfile that may be used to generate an executable without needing to provide any external dependencies, other than the Docker engine itself (see [here](https://docs.docker.com/get-docker/) for instructions on obtaining Docker). Once Docker is installed and the Docker engine is running, execute: -``` -$ docker build --target=export_driver \ - --output=bin \ - --build-arg MACHINE_CODE_VALUE="Host" \ - [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ - [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] -``` - -The Docker build will download and compile all of the library dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries and the Swiftest driver using Intel compilers. Once completed, the Swiftest executable, called ```swiftest_driver```, should now be created in the ```bin/``` directory. - -> Note: The Dockerfile is designed to build an executable that is compatible with a broad range of CPU architectures by specifying the SSE2 instruction as a target for SIMD instructions using the `-x` compiler option. When compiling on the same CPU archictecture you plan to execute the driver program, for the highest possible SIMD performance, use `--build-arg MACHINE_CODE_VALUE="Host" to override the default `MACHINE_CODE_VALUE="SSE2"`. For additional options see [here](https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-1/x-qx.html). - -The optional Docker argument `EXTRA_CMAKE_OPTIONS` is provided to pass any additional CMake arguments (see below). - -***Compiling `swiftest_driver` using CMake*** -Several build scripts are available in the `buildscripts` folder for building Swiftest and its dependencies on a Linux or Mac system. These are used when generating the official Swiftest Python wheels using cibuildwheel. To build the complete project, run `buildscripts\build_all.sh` from the command line. - -***Compiling `swiftest_driver` using CMake*** - -The Swiftest driver program is written in modern Fortran and must be compiled before it can be run. After compilation, an executable, called the `swiftest_driver``, will have been created in the ```bin/``` directory. - -Swiftest is compiled through [CMake](https://cmake.org/). Compiling with CMake has a number of benefits that provide a streamlined experience for the Swiftest user and developer. At compilation, CMake will automatically select the set of flags that are compatible with the local compiler. CMake also allows a Swiftest developer to re-compile only the files that have been edited, instead of requiring the developer to re-compile the entire Swiftest program. Please visit the CMake website for more information on how to install CMake. - -As mentioned in the **System Requirements** section, Swiftest requires the NetCDF and NetCDF Fortran libraries to be installed prior to compilation. If the libraries are installed in the standard library location on your machine, CMake should be able to find the libraries without specifying the path. However, if CMake struggles to find the NetCDF libraries, there are two ways to set the path to these libraries. - -1. Create an environment variable called ```NETCDF_FORTRAN_HOME``` that contains the path to the location where the libraries are installed -2. Set the path at the build step using ```-CMAKE_PREFIX_PATH=/path/to/netcdf/``` - -CMake allows the user to specify a set of compiler flags to use during compilation. We define five sets of compiler flags: release, testing, profile, math, and debug. To view and/or edit the flags included in each set, see ```swiftest/cmake/Modules/SetFortranFlags.cmake```. - -As a general rule, the release flags are fully optimized and best used when running Swiftest with the goal of generating results. This is the default set of flags. When making changes to the Swiftest source code, it is best to compile Swiftest using the debug set of flags. You may also define your own set of compiler flags. - -Navigate to the topmost directory in your Swiftest repository. It is best practice to create a ```build``` directory in your topmost directory from which you will compile Swiftest. This way, temporary CMake files will not clutter up the ```swiftest/src/``` sub-directories. The commands to build the source code into a ```build``` directory and compile Swiftest are: - -``` -$ cmake -B build -S . -$ cmake --build build -``` -The [CMake Fortran template](https://github.com/SethMMorton/cmake_fortran_template) comes with a script that can be used to clean out any build artifacts and start from scratch: - -``` -$ cmake -P distclean.cmake -``` - -The Swiftest CMake configuration comes with several customization options: - -| Option | CMake command | -| --------------------------------|------------------------------------------------------------| -| Build type | \-DCMAKE_BUILD_TYPE=[**RELEASE**\|DEBUG\|TESTING\|PROFILE] | -| Enable/Disable OpenMP support | \-DUSE_OPENMP=[**ON**\|OFF] | -| Enable/Disable SIMD directives | \-DUSE_SIMD=[**ON**\|OFF] | -| Enable/Disable Coarray support (experimental) | \-DUSE_COARRAY=[ON\|**OFF**] | -| Set Fortran compiler path | \-DCMAKE_Fortran_COMPILER=/path/to/fortran/compiler | -| Set path to make program | \-DCMAKE_MAKE_PROGRAM=/path/to/make | -| Enable/Disable shared libraries (Intel only) | \-DBUILD_SHARED_LIBS=[**ON\|OFF] | -| Add additional include path | \-DCMAKE_Fortran_FLAGS="-I/path/to/libraries | -| Install prefix | \-DCMAKE_INSTALL_PREFIX=["/path/to/install"\|**"/usr/local"**] | - - -To see a list of all possible options available to CMake: -``` -$ cmake -B build -S . -LA -``` - -The Swiftest executable, called `swiftest_driver`, should now be created in the `bin/` directory. - - -**Download the `swiftest_driver` as a Docker or Singularity container.** - -The Swiftest driver is available as a Docker container on DockerHub in two versions: Intel and GNU. The Intel version was compiled for the x86_64 CPU using the Intel classic Fortran compiler. The GNU version was compliled for the x86_64 CPU using gfortran. The Intel version is faster than the GNU version (though not as fast as a native compile to the target CPU that you wish to run it on due to vectorization optimizations that Swiftest takes advantage of), however it is much larger: The Intel version is ~2.7GB while the GNU version is ~300MB. The Singularity container pulls from the same DockerHub container. - -To facilitate installation of the container, we provide a set of shell scripts to help automate the process of installing container versions of the executable. To install the default Intel version of the docker container from within the `swiftest\` project directory - -``` -$ cd docker -$ . ./install.sh -``` - -To install the GNU version: - -``` -$ cd docker -$ . ./install.sh gnu -``` - -The Singularity versions are installed the same way, just replace `cd docker` with `cd singularity` above. +#### Documentation -Whether installing either the Docker or Singularity containers, the install script will copy an executable shell script `swiftest_driver` into `swiftest/bin/`. Not that when installing the Singularity container, the install script will set an environment variable called `SWIFTEST_SIF` that must point to the aboslute path of the container file called `swiftest_driver.sif`. To use the driver script in a future shell, rather than running the install script again, we suggest adding the environment variable definition to your shell startup script (e.g. add `export SWIFTEST_SIF="/path/to/swiftest/singularity/swiftest.sif"` to your `.zshrc`) - - -**Swiftest Python Package** - -Included with Swiftest, in the ```/swiftest/python/swiftest/``` directory, is a Python package designed to facilitate seamless data processing and analysis. The Python package, also called Swiftest, can be used to generate input files, run Swiftest simulations, and process output files in the NetCDF file format. - -To begin, Swiftest can be added to an existing conda environment, or a new conda environment may be created, so long as the required packages are installed. To create and activate a new conda environment with the prerequisite packages, open a terminal and navigate to the ```/swiftest/python/swiftest/``` directory. Type the following: - -``` -$ conda create --name EnvName pip scipy numpy matplotlib pandas xarray jupyter astropy -y -$ conda activate EnvName -``` - -Next, we will install further required packages. Using the ```-e``` flag imports all packages in ```/swiftest/python/swiftest/requirements.txt```, including Swiftest. If the Swiftest Python package is updated in the future, using the ```-e``` flag should ensure that the user does not have to reinstall the package to use the updated version. - -``` -$ pip install --user -e . -``` - -The Swiftest Python package should now be installed in the conda environment and is ready to use. If you would like to take the further step to add Swiftest to a Jupyter Notebook kernel, type the following: - -``` -$ ipython kernel install --user --name EnvName --display-name "Swiftest Kernel" -``` - ---- - -#### Usage - -Swiftest is built to make running a Swiftest simulation a streamlined and user-friendly experience, even for a new user. As a result, Swiftest is highly flexible and a simulation can be created, run, and processed in a number of different ways. The first choice the user must make is if they would prefer ASCII input files or NetCDF input files. We recommend NetCDF input files, however we include documentation for ASCII input files for completeness. - -**Brief Outline** - -To create and run a Swiftest simulation using the Swiftest Python package, follow the general script below. For more details on the input files and user options, continue reading this section. - -``` -import swiftest # Import the Swiftest Python package -sim = swiftest.Simulation(simdir = "directory_name", **kwargs) # Initialize a Swiftest simulation and define a directory/path in which to store simulation data -sim.add_solar_system_body(**kwargs) # Add any desired named Solar System bodies, including the Sun -sim.add_body(**kwargs) # Add any desired user defined bodies -sim.get_parameter(**kwargs) # View the default simulation parameters -sim.set_parameter(**kwargs) # Set any desired simulation parameters -sim.write_param(**kwargs) # Write simulation parameters to the param.in -sim.save(**kwargs) # Save the simulation initial conditions to init_cond.nc -sim.run(**kwargs) # Run the simulation (leave off if running from the executable) -``` - -To read in a set of Swiftest output files using the Swiftest Python package, follow the general script below. For more details on the output files and user options, continue reading this section. - -``` -import swiftest # Import the Swiftest Python package -sim = swiftest.Simulation(simdir = "directory_name", read_data=True) # Initialize a Swiftest simulation -sim.data # Body data over time -sim.init_cond # The initial conditions for the simulation -sim.encounters # Encounter data for all close encountering pairs -sim.collisions # Collision data for all colliders and collisional fragments -``` - -**NetCDF Input Files (Recommended)** - -Swiftest accepts a single NetCDF input file. This file can be created using the Swiftest Python Package through a few simple steps. - -To begin, simply create a new Python script in the directory you would like to store your simulation. Open the new script and import the Swiftest Python package. - -``` -import swiftest -``` - -Next, we initialize the Swiftest simulation object. Various parameters can be provided to the simulation via key word arguments at this stage. - -``` -sim = swiftest.Simulation(simdir = "directory_name", **kwargs) -``` - -The argument ```simdir``` is the name of the subdirectory in which to store all simulation data. This does not have to exist at the time the simulation object is initialized. - -The key word arguments available to the user, along with the default values for these arguments, are described in [simulation_kwargs](README_tables/simulation_kwargs.md). - -After creating the simulation and defining all desired parameters as keyword arguments, it is time to add bodies to the simulation. The Swiftest Python package interfaces with the [NASA JPL Horizons database](https://ssd.jpl.nasa.gov/horizons/), allowing a user to easily import the initial conditions of known solar system bodies using the ```add_solar_system_body``` method. - -``` -sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto"]) -``` - -User defined bodies can also be added to a Swiftest simulation through the Python package. Massive bodies and test particles can both be added using the ```add_body``` method. - -``` -sim.add_body(**kwargs) -``` - -The key word arguments available to the user for the ```add_body``` method are described in [add_body_kwargs](README_tables/add_body_kwargs.md). - -Once all desired bodies have been added to the Swiftest simulation, the simulation parameters can be accessed and changed using the ```get_parameter``` and ```set_parameter``` methods. The key word arguments available to the user for the ```get_parameter``` and ```set_parameter``` are the same as those described in [simulation_kwargs](README_tables/simulation_kwargs.md). - -After all desired parameters have been set, the parameters can be saved to the **param.in** using the ```write_param``` method. The key word arguments available to the user for the ```write_param``` method are described in [write_param_kwargs](README_tables/write_param_kwargs.md). - -The state of the system can be saved to the initial conditions NetCDF file, **init_cond.nc**, using the ```save``` method. The key word arguments available to the user for the ```save``` method are described in [save_kwargs](README_tables/save_kwargs.md). - -Finally, a simulation can be run from the same script in which it is created (or a separate Python script) using the ```run``` method. This is optional as the simulation can also be run from an executable. More details on running a Swiftest simulation can be found in the section **Running a Swiftest Simulation**. The key word arguments available to the user for the ```run``` method are the same as those described in [simulation_kwargs](README_tables/simulation_kwargs.md). - -**ASCII Input Files** -Swiftest accepts 4 ASCII input files. All four ASCII input files are necessary if using the ASCII input format, however the structure of each input file varies slightly depending on the features and capabilities of the integrator selected. The four ASCII input files are not necessary if using NetCDF input files. The four input files are as follows: - -- **param.in** - The parameter input file. -- **cb.in** - The central body input file. -- **pl.in** - The massive body input file. -- **tp.in** - The test particle input file. - -The parameter options used in the parameter input file are as described in [simulation_kwargs](README_tables/simulation_kwargs.md). - -The **cb.in** includes all central body initial conditions. The structure of the **cb.in** is as follows: - -``` -0 ! ID number -1.0 ! Gravitational mass (G*mass) in mass units (ex. 39.47841760435743 for Sun in M_sun/AU/year) -1.0 ! Central body radius is distance units (ex. 0.004650467260962157 for Sun in AU) -0.0 ! J2 term, optional, set to 0.0 for a spherical body -0.0 ! J4 term, optional, set to 0.0 for a spherical body -0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only -0.0 0.0 0.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only -``` - -The **pl.in** includes all massive body initial conditions. The structure of the **pl.in** is as follows: - -``` -2 ! Total number of massive bodies -1, 0.0, 0.0 ! ID number, Gravitational mass (G*mass) in mass units, Hill Radius in distance units if RHILL_PRESENT is set to YES, leave off if not using -0.0 ! Radius is distance units if CHK_CLOSE is set to YES, leave off if not using -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly -0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only -1.0 1.0 1.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only -2, 0.0, 0.0 -0.0 -1.0 1.0 1.0 -1.0 1.0 1.0 -0.4 0.4 0.4 -1.0 1.0 1.0 -``` - -The **tp.in** includes all test particle initial conditions. In the event that no test particles are desired, the **tp.in** must still be included, however it can simply contain a single ```0```. The structure of the **tp.in** is as follows: - -``` -2 ! Total number of test particles -3 ! ID number -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination -1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly -4 -1.0 1.0 1.0 -1.0 1.0 1.0 -``` - -Note that the ID numbers of the test particles are a continuation of the ID numbers of the massive bodies. No two bodies in the system can have the same ID number. - -**Running a Swiftest Simulation** - -The input files necessary to successfully run Swiftest should now be generated in the simulation directory. The user is now faced with a second choice: to run a Swiftest simulation from a Python environment or to run it directly from an executable. Either option is possible with NetCDF format input files, however ASCII input files must be run directly from an executable. - -**Running via Python** - -To run a Swiftest simulation from the same script in which the initial conditions are created, simply add the following line after you have finished defining parameters and adding bodies to the simulation: - -``` -sim.run() -``` - -To run a previously created set of initial conditions, first read the old parameter file into Python, and then run it. Note that Swiftest will look in the ```/simdata``` subdirectory for the initial conditions by default. You may set a new path to the initial conditions using the ```param_file``` keyword argument. See the documentation detailing the key word arguments available to the user in [simulation_kwargs](README_tables/simulation_kwargs.md). - -``` -sim = swiftest.Simulation(simdir = "directory_name", read_param=True) -sim.run() -``` - -**Running via an Executable** - -To run a Swiftest simulation through an executable, create a symbolic link to the Swiftest driver from your current directory. - -``` -$ ln -s ~/PATH/TO/swiftest/bin/swiftest_driver . -``` - -To run Swiftest, simply type the following command into the terminal: - -``` -$ ./swiftest_driver INTEGRATOR param.in -``` - -Where ```INTEGRATOR``` is your integrator of choice, either ```whm```, ```rmvs```, ```helio```, or ```symba```. - -**Outputs** - -The number and type of output files generated by Swiftest depends on the input parameters selected and the method through which Swiftest was run. The standard output files are as follows: - -- **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ```ISTEP_OUT``` timesteps and written every ```DUMP_CADENCE```. This file can be analyzed using the Swiftest Python package (```sim.data```). -- **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ```FRAGMENTATION``` is ```YES```, Swiftest SyMBA only. -- **swiftest.log** - A log containing a brief update on the status of the run. Only generated if Swiftest is run through the Python package or through a shell script. If Swiftest is run through an executable, these updates are output directly to the terminal. -- **collisions.nc** - The details of each collision that occurs in a simulation are recorded in a NetCDF file. Only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True```. This file can be analyzed using the Swiftest Python package (```sim.collisions```). -- **encounters.nc** - The details of each close encounter that occurs in a simulation are recorded in a NetCDF file. Only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True```. This file can be analyzed using the Swiftest Python package (```sim.encounters```). -- **init_cond.nc** - The initial conditions used to run the simulation. This file can be analyzed using the Swiftest Python package (```sim.init_cond```). -- **encounter_check_plpl_timer.log** - The log containing the encounter check timer for each massive body/massive body encounter, only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True``` and ```ENCOUNTER_CHECK```/```encounter_check_loops``` is ```ADAPTIVE```. -- **encounter_check_pltp_time.log** - The log containing the encounter check timer for each massive body/test particle encounter, only if ```CHK_CLOSE```/```close_encounter_check``` is ```YES```/```True``` and ```ENCOUNTER_CHECK```/```encounter_check_loops``` is ```ADAPTIVE```. -- **interaction_timer.log** - The log containing the interaction loop timer for each interacting pair of bodies, only if ```INTERACTION_LOOPS``` is ```ADAPTIVE```. - -To read in a Swiftest output file, simply create a new Python script in the simulation directory. - -``` -import swiftest -sim = swiftest.Simulation(simdir = "directory_name", read_data=True) -``` - -All Swiftest data is now stored in the Xarray datasets ```sim.data```, ```sim.collisions```, and ```sim.encounters``` and is easily processed, manipulated, and analyzed. - -Regardless of whether the status outputs are recorded in the **swiftest.log** or in the terminal, the output format is the same. Below is an example of a single status output: - -`````` -Time = 1.00000E+03; fraction done = 0.001; Number of active plm, pl, tp = 57, 108, 50 - DL/L0 = 6.83763E-12; DEcollisions/|E0| = 0.00000E+00; D(Eorbit+Ecollisions)/|E0| = 2.65579E-03; DM/M0 = 0.00000E+00 -Integration steps: Total wall time: 2.99848E+02; Interval wall time: 9.36192E+01;Interval wall time/step: 4.68956E-04 -`````` - -The first line includes the simulation time, the fraction of the simulation that is complete relative to ```tstop```, the number of fully-interactive massive bodies (```plm```) (SyMBA only), the total number of massive bodies (```pl```) including fully-interactive and semi-interactive bodies, and the number of test particles (```tp```) remaining in the system at that time. The second line includes the angular momentum error, the change in energy as a result of collisions only, the total change in energy, and the change in mass up to this point in the simulation (error analysis included only if ```ENERGY```/```compute_conservation_values``` is set to ```YES```/```True```). The third line contains the total wall time elapsed since the start of the simulation, the wall time elapsed since the start of the last step, and the average wall time per step since the start of the simulation. - -**Restarting a Simulation From t $\neq$ 0** - -Just like Swiftest allows the user to run a simulation through an executable or through Python, Swiftest also allows the user to restart a simulation from t $\neq$ 0 in the same two manners. This can be useful in the case of an accidental termination of a simulation, such as through a power outage or computer failure. In many cases, it is also necessary to run a simulation to a new end point, past the original ```TSTOP```. - -**Restarting via Python** - -To restart a Swiftest simulation via the Swiftest Python package, follow the outline below: - -``` -import swiftest -sim = swiftest.Simulation(simdir = "directory_name", read_data=True) -sim.set_parameter(tstop=VAL) # Set a new stop time if desired -sim.write_param() # Write simulation parameters to the param.in -sim.run() -``` - -Note that Swiftest will look in the ```/simdata``` subdirectory for the initial conditions by default. You may set a new path to the initial conditions using the ```param_file``` keyword argument. - -**Restarting via an Executable** - -Every ```DUMP_CADENCE``` X ```ISTEP_OUT``` timesteps, Swiftest writes all simulation information from memory to the output files. At the same time, Swiftest also writes all simulation information to a new parameter file, titled **param.XXXXXXXXXXXXXXXXXX.in**. To restart a run from a previous parameter file, simply follow the instructions detailed in the **Running via an Executable** section, replacing ```param.in``` with the name of the parameter file from which you wish to restart. - ---- - -#### Updates to Swifter Included in Swiftest - -**Collisional Fragmentation via Fraggle** - -To activate the Fraggle algorithm, set ```FRAGMENTATION```/```fragmentation``` to ```YES```/```True```, depending on the mode in which Swiftest is being run. When resolving a close encounter that results in a collision, Fraggle determines the regime of the collision as well as the mass, number, position, velocity, and rotation of all resulting bodies. This is distinct from Swiftest SyMBA's predecessor, Swifter SyMBA, which assumes that all collisions result in perfect mergers. - -Fraggle distinguishes the following collisional regimes: (1) perfect merging, which includes the cratering, partial accretion, and graze-and-merge regimes of Leinhardt & Stewart 2012, (2) disruption, which includes the partial erosion regime of Leinhardt & Stewart 2012, (3) super-catastrophic disruption, and (4) hit-and-run events which can be either ‘pure’ or ‘disruptive’. - -For every collision throughout the course of a simulation, Fraggle writes a brief description of the collision to the **fraggle.log** output file. An example of a collision, stored in the **fraggle.log** output file, is as follows: - -``` -Fraggle logfile - - ********************************************************************************************************************** - Collision between massive bodies detected at time t = 2.063709800335315E-006 - ********************************************************************************************************************** - - -------------------------------------------------------------------- - Fraggle collisional regime determination results - -------------------------------------------------------------------- - True number of colliders : 2 - Index list of true colliders : 1 2 - Regime: Disruption - Energy loss : 2.298848838233116E-022 - -------------------------------------------------------------------- - Disruption between Target (1) and Projectile (2) - Fraggle generating 28 fragments. - Fraggle try 1 - Fraggle fragment generation succeeded after 1 tries - Generating 28 fragments -``` - -The details of the collision are stored in the simulation object (```sim.collisions```) which can be accessed using the Swiftest Python package. - -**General Relativity** - -From its observation in the mid-1800s to the development of the theory of general relativity by Albert Einstein in 1915, the precession of Mercury's perihelion puzzled scientists and observers. Mercury's orbit precesses by approximately $42.980 \pm 0.001$ arcseconds / century more than is expected from Newtonian mechanics. This deviation can be explained by the curvature of spacetime due to the mass of the Sun. Mercury's close proximity to the Sun enhances the effects of general relativity, providing a good test case to highlight the functionality of general relativity in Swiftest. - -In this test case, we track the orbit of Mercury for 1000 years as it orbits around the Sun in the presence of the seven other massive planets. The precession rate of the longitude of periapsis of Mercury, as calculated by Swiftest SyMBA, differs by only $\sim 0.0286 \%$ from the precession rate calculated from the NASA JPL Horizons database. - -|![SyMBA General Relativity](README_figs/symba_gr.png "SyMBA General Relativity")| -|:--:| -|**Figure 1** - The longitude of periapsis of Mercury over 1000 years, as calculated by Swifter SyMBA (dotted green), Swiftest SyMBA with general relativity turned off (long dashed yellow), and Swiftest SyMBA with general relativity turned on (short dashed blue). These results are compared to the periapsis of Mercury as calculated from the NASA JPL Horizons database (solid red). Swiftest SyMBA with general relativity turned off is in good agreement with Swifter SyMBA ($\sim 0.00053 \%$ difference), while Swiftest SyMBA with general relativity turned on is in good agreement with the NASA JPL Horizons database ($\sim 0.0286 \%$ difference).| - -**Adaptive Interaction Calculations and Encounter Checking** - -In Swifter SyMBA, gravitational interactions between bodies are calculated on a pair-by-pair basis by solving an upper triangular matrix. In practice, this is done through a double loop. While effective, solving a triangular matrix is computationally costly and it is considered best practice to avoid nested loops wherever possible. Swiftest SyMBA offers an alternative to this method, allowing the user to choose between calculating the gravitational interactions between bodies through a traditional triangular matrix or through a flattened Euclidean distance matrix. - -A Euclidean distance matrix is a two-dimensional array that stores the distance between each pairing of points in a set of elements. For more details on the algorithm implemented in Swiftest to flatten the Euclidean distance matrix, please see [Angeletti, Bonny, & Koko 2019](https://hal.archives-ouvertes.fr/hal-02047514). - -Along with allowing the user to choose whether the gravitational interactions are calculated through an upper triangular matrix or a flattened Euclidean distance matrix, Swiftest SyMBA allows the user to let the program determine the speedier solution. Through adaptive interaction calculations, Swiftest SyMBA periodically tracks the time it takes to complete an interaction calculation using both the triangular and flat methods. Whichever method proves to be quicker is implemented until the next time both methods are tested. Swiftest SyMBA periodically checks the performance of each method, possibly switching between the two methods multiple times over the course of a simulation. By selecting adaptive interaction calculations, the user allows Swiftest SyMBA to optimize its own performance and adapt to changes in the number of particle pairings as the simulation progresses. - -An example of the adaptive interaction calculations, stored in the **interaction_timer.log** output file, is as follows: - -``` -Interaction loop timer logfile ! The file header -Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which calculation method is fastest -symba_kick_getacch_int_pl: loop timer turned on at t = 0.000000000000000E+000 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun -symba_kick_getacch_int_pl: stage 1 ! Begins timing the first method -FLAT 95 7353 1.291989664082687E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) -symba_kick_getacch_int_pl: stage 2 ! Begins timing the second method -TRIANGULAR 100 7353 1.359989120087039E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) -symba_kick_getacch_int_pl: the fastest loop method tested is FLAT ! The subroutine in which the timing is being conducted and which interaction calculation method is determined to be fastest -``` - -In addition to calculating the gravitational interactions between pairings of bodies, Swifter SyMBA also uses an upper triangular matrix to check if pairings of bodies are in a close encounter state. While similar to interaction calculations, encounter checking can be further simplified to exclude pairs of bodies which, based on their physical distance, are unlikely to be in an encounter state. To address this, Swiftest SyMBA offers an alternative to solving an upper triangular matrix through the sort and sweep method. - -The sort and sweep method of collision detection (see [Ericson 2005](https://www.sciencedirect.com/book/9781558607323/real-time-collision-detection) for more details), also known as the sweep and prune method, is a way of limiting the number of pairs of bodies that need to be checked for a collision in each time step. At the start of a new time step, the position of each body is calculated and the critical radius of each body is determined. The critical radius is based on the radius of a body's Hill sphere. The distance from a body's center to the extent of its critical radius defines the encounter sphere of the body. The position of the center of mass of the body and the extent of its encounter sphere are used to define the bounding box used in the sort and sweep algorithm. Based on the defined bounding box, the positions of the lower and upper bounds of all of the bodies in the simulation are compiled into sorted lists. Because each body is unlikely to move significantly between time steps, updating these sorted lists each time step is relatively straightforward. Only when the bounding boxes of two bodies overlap in all axes are the bodies flagged as an encountering pair. - -The sort and sweep algorithm is computationally efficient because it limits the number of potential encountering pairs that must be checked for encounters. For example, by calculating the bounding boxes of two bodies on opposite sides of the solar system, the algorithm then sorts the upper and lower bounds of these two bounding boxes into opposite ends of a sorted list. Through this sorting, the algorithm recognizes that these two bodies are unlikely to encounter one another in the following time step and is able to quickly exclude them from more extensive encounter checking, saving time and computational resources. -In the same way that the user can allow Swiftest SyMBA to adapt when calculating the gravitational interactions between bodies, the user can also allow Swiftest SyMBA to determine the faster method of encounter checking. Just as Swiftest SyMBA periodically tests the interaction calculation methods, it also periodically tests the encounter checking methods. The quicker of the two methods is selected and implemented, allowing Swiftest SyMBA to adapt to changes in the distribution of bodies in the system as the simulation progresses. - -An example of the adaptive encounter checking, stored in the **encounter_check_plpl_timer.log** output file, is as follows: - -``` -Encounter check loop timer logfile ! The file header -Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which checking method is fastest -encounter_check_all_plpl: loop timer turned on at t = 5.000000000000000E-003 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun -encounter_check_all_plpl: stage 1 ! Begins timing the first method -SORTSWEEP 196 7353 2.665578675370597E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) -encounter_check_all_plpl: stage 2 ! Begins timing the second method -TRIANGULAR 164 7353 2.230382156942744E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) -encounter_check_all_plpl: the fastest loop method tested is TRIANGULAR ! The subroutine in which the timing is being conducted and which encounter checking method is determined to be fastest -``` - -Together, adaptive interaction calculations and encounter checking are idea for lengthy simulations with a large number of particles. The flexibility of Swiftest SyMBA ensures that the parameters of the integration are optimized for each individual simulation, even as the simulation evolves. - -**NetCDF Compatibility** - -The NetCDF (Network Common Data Form) file format is a cross-platform method of creating, accessing, and sharing data. Due to its self-describing nature, NetCDF is ideal for archiving multidimensional scientific data. NetCDF files are also appendable, allowing for data to be added to a file after creation, making the NetCDF file format well suited for handling simulation output. NetCDF is maintained by the University Corporation for Atmospheric Research (UCAR) and is a standard file format across much of the atmospheric modeling community. - -In Swifter SyMBA, simulation outputs were stored in a flat binary file. These binary files could only be easily accessed through [SwiftVis](https://cs.trinity.edu/~mlewis/SwiftVis/), a data analysis and visualization software package designed to process Swifter data. In accordance with modern data management practices and industry standards, Swiftest incorporates a NetCDF output file format for all simulation types. NetCDF is compatible with many of today's most widely-used programming languages including Fortran, Python, Java, C++, and more. By writing simulation data to a NetCDF output file, Swiftest provides the user with the flexibility to analyze and visualize data in any language they choose. The NetCDF file format is also adaptable such that any future additions to Swiftest can be seamlessly incorporated into the output file. - -**Object-Oriented Programming** - -The 2003 version of Fortran introduced object-oriented programming, with Fortran 2008 providing further updates. Swiftest is written in modern Fortran and takes advantage of many of the object-oriented programming features included in Fortran 2003. In doing so, Swiftest is a complete restructure of its predecessor, Swifter. The reusability and simplification of code in Swiftest through object-oriented programming is a modern and flexible approach that allows for future enhancements and additions to the Swiftest package. - -**Parallelization** - -Parallelization using OpenMP is still under development in Swiftest. For preliminary results, see **Figure 2**. - ---- - -#### Examples - -All examples are included in the ```/swiftest/examples/``` directory. Simply run the script(s) included in the directory as you would normally run a Python script. See the **README.txt** included in each example directory for more details. - -**Basic_Simulation** - -This example walks through how to set up a standard solar system simulation. It can be found in the ```/swiftest/examples/Basic_Simulation``` directory. It is intended to be run using the SyMBA integrator. It contains three classes of bodies: -- Fully-Interacting Massive Bodies - Gravitationally affect and are affected by other massive bodies. -- Semi-Interacting Massive Bodies - Gravitationally affect and are affected by fully-interacting massive bodies, do not gravitationally affect and are not affected by other semi-interacting massive bodies. -- Test Particles - Gravitationally affected by fully-interacting massive bodies only. - -To generate the initial conditions, run the Python script titled **basic_simulation.py**. This script also runs Swiftest SyMBA, generating output. To process the output file, run the script titled **output_reader.py**. - -**Chambers2013** - -This example acts as a comparison to the work of [Chambers 2013](https://www.sciencedirect.com/science/article/pii/S0019103513000754?via%3Dihub). It can be found in the ```/swiftest/examples/Chambers2013``` directory. It is intended to be run using the SyMBA integrator and highlights how to run Swiftest using and executable, as opposed to through a Python script. To generate the initial conditions, run **init_cond.py**. To run Swiftest with these intial conditions, type: - -``` -./swiftest_driver symba param.in -``` - -To process the output file, run the script titled **scattermovie.py**. - -**Fragmentation** - -This example highlights the functionality of the Fraggle algorithm. It can be found in the ```/swiftest/examples/Fragmentation``` directory. It is intended to be run using the SyMBA integrator. It contains 9 pre-built collisional test cases: - -- A Head-On Disruptive Collision -- An Off-Axis Disruptive Collision -- A Head-On Super-Catastrophic Disruptive Collision -- An Off-Axis Super-Catastrophic Disruptive Collision -- A Disruptive Hit and Run Collision -- A Pure Hit and Run Collision -- A Merger -- A Merger Crossing the Spin Barrier -- All of the Above - -To generate, run, and create a movie depicting the collision, run the Python script titled **Fragmentation_Movie.py**. Please note that this example requires a large amount of memory. For reference, this example was created and run using 4 nodes, each with 256 GB of memory. This amount of computational memory is necessary to generate a smooth movie. In this example, the trajectories of all bodies involved in the collision are saved at every point in the simulation. This is extremely expensive and should only be used to study a particular collisional event in detail. - -**helio_gr_test** - -This example demonstrates the functionality of general relativity in Swiftest HELIO. It can be found in the ```/swiftest/examples/helio_gr_test``` directory. It is intended to be run using the HELIO integrator. Because the SyMBA integrator is built upon the HELIO integrator, GR is also available in SyMBA. - -**Multibody_Fragmentation** - -This example highlights the functionality of the Fraggle algorithm. It can be found in the ```/swiftest/examples/Mulitbody_Fragmentation``` directory. It is intended to be run using the SyMBA integrator. To generate a set of initial conditions, run the initial conditions using Swiftest, and generate a movie depicting the collisional result, run the Python script titled **Multibody_Movie.py**. - -**solar_impact** - -This example demonstrates the conservation of angular momentum, energy, and mass during a collision between a massive body and the Sun, or central body. It can be found in the ```/swiftest/examples/solar_impact``` directory. It is intended to be run using the SyMBA integrator. - -**Swifter_Swiftest** - -This set of examples acts as a comparison between Swiftest and its predecessor, Swifter. Two unique simulations are included in this example, one with 8 massive bodies and 0 test particles, and one with 108 massive bodies and 50 test particles. These simulations can be found in the ```/swiftest/examples/Swifter_Swiftest/8pl_0tp``` and the ```/swiftest/examples/Swifter_Swiftest/108pl_50tp``` directories, respectively. They are intended to be run using the SyMBA integrator. For details on how to run a simulation using Swifter, please see the [Swifter website](https://www.boulder.swri.edu/swifter/). - -**whm_gr_test** - -This example demonstrates the functionality of general relativity in Swiftest WHM. It can be found in the ```/swiftest/examples/whm_gr_test``` directory. It is intended to be run using the WHM integrator. Because the SyMBA integrator is built upon the HELIO integrator, which is in turn built upon the WHM integrator, GR is also available in SyMBA. - ---- - -#### Simulation Parameter FAQs and Recommendations - -**How do I know what timestep to use for my simulation (**```dt```**)?** - -A good rule is to set ```dt``` equal to one tenth the orbit of the inner-most body in your simulation. For example, if Mercury is your inner-most body, ```dt``` should be set to one tenth Mercury's orbit. Mercury's orbit is ~0.24 years (~88 days) so a timestep of 0.024 years should be sufficiently small to accurately model the orbit of Mercury. You can always go smaller to increase resolution. - -**How often should I output (**```ISTEP_OUT``` or ```TSTEP_OUT```, **and** ```DUMP_CADENCE```**)?** - -Depending on your simulation, you may want to write to the output file more or less frequently. Writing takes a considerable amount of computational time, so it is important to set a output cadence that is manageable. Conversely, storing data in memory may not be reasonable for all simulation configurations or hardware, so writing more frequently may be necessary. There is no hard and fast rule for how often you should output, however it is dependent on your total simulation length (```tmax```) and your timestep (```dt```). Think of ```ISTEP_OUT``` as the number of timesteps between writing to memory (or, alternatively with ```TSTEP_OUT```, the length of time between writing to memory), and ```DUMP_CADENCE``` as the number of write to memory operations between writing to file. - -For example, an appropriate output cadence for a run with a timestep of 0.005 years and a total simulation length of 100 My might be ```ISTEP_OUT = 2e5``` (```TSTEP_OUT = 1e3```) and ```DUMP_CADENCE = 10```. This means that data will be stores to memory every 2e5 timesteps and written to file every 2e6 timesteps. Based on our value of ```dt```, this is every 1,000 years and every 10,000 years, respectively. Our total simulation length tells us that we will write to file 10,000 times over the course of the simulation. For longer simulations, the output cadence may be less frequent to save computational space. For shorter simulations, the output cadence may be more frequent to increase resolution. - -**What mass threshold should I set to differentiate fully-interactive and semi-interactive bodies (**```GMTINY``` **or** ```MTINY```**)?** - -Semi-interacting bodies are useful because the integrator is not required to calculate gravitational interactions between pairs of semi-interacting particles. This can result in significant performance improvements, especially for systems that require hundreds or thousands of massive bodies. If your system only has a few tens of massive bodies, semi-interacting bodies may not be necessary. If you would like to differentiate between these two classes of bodies, simply set the mass threshold to be some value between the mass of the smallest fully-interacting body and the mass of the largest semi-interacting body that you choose. Semi-interacting bodies can collide with each other and grow to become fully interacting bodies once they pass the mass threshold. - -**What should minimum fragment mass should I use (**```MIN_GMFRAG``` **or** ```MIN_MFRAG```**)?** - -This mass threshold is necessary to ensure that Swiftest SyMBA does not generate huge amounts of very small fragments, grinding the model to a halt. While this value is largely empirical and dependent on each specific set of initial conditions, a good place to start is to set the minimum fragment mass threshold to be one tenth the size of the smallest body in your simulation. You can also adjust ```FRAG_REDUCTION``` to keep the number of fragments within a reasonable range. - -**What are the limits of Swiftest SyMBA?** - -While Swiftest SyMBA is a powerful tool for modeling gravitational interactions between massive bodies, it does have its limits. Swiftest SyMBA is best used for systems containing tens to hundreds of fully-interacting massive bodies. It is also best used for timescales on the order of a few hundred million years or less. While it is possible to model systems on a billion year timescale, the computational power required may be beyond what is available to the average user. In these cases, it is recommended that the user consider modeling with test particles instead of massive bodies. For systems that contain mainly test particles, with few to no close encounters between massive bodies, Swiftest RMVS is likely a more appropriate tool. - -To get a sense of the scope of your desired simulation, it is recommended that you run your initial conditions and parameters for a just few steps. Make sure that you set ```ISTEP_OUT``` and ```DUMP_CADENCE``` to output only once the simulation is complete, not between steps. Because writing to the output files and memory takes a significant amount of computational time compared to integrating the step, we want to avoid counting writing time in our diagnostic information. The terminal output contains information about the total wall time and the wall time per integration step. To get a sense of how long your run will take to complete your desired ```tmax```, simply scale up the wall time per integration step to the number of steps necessary for ```tmax``` to be reached. Remember that writing to the output files will take a considerable amount of time. Adjust your initial conditions and parameters accordingly. - ---- - -#### References - -- Angeletti, M., Bonny, J. -M., and Koko, J. (2019). Parallel Euclidean distance matrix computation on big datasets. **HAL**. [HAL Id: hal-02047514](https://hal.archives-ouvertes.fr/hal-02047514) -- Duncan, M. J., Levison, H. F., and Lee, M. H. (1998). A Multiple Time Step Symplectic Algorithm for Integrating Close Encounters. **The Astronomical Journal**, 116, 2067. [doi: 10.1086/300541](https://iopscience.iop.org/article/10.1086/300541) -- Chambers, J. E. (2013). Late-Stage Planetary Accretion Including Hit-and-Run Collisions and Fragmentation. **Icarus**, 224. [doi: 10.1016/j.icarus.2013.02.015](https://www.sciencedirect.com/science/article/pii/S0019103513000754?via%3Dihub) -- Ericson, C. (2005) Real-Time Collision Detection. **Elsevier Inc.** [ISBN: 978-1-55860-732-3](https://www.sciencedirect.com/book/9781558607323/real-time-collision-detection) -- Leinhardt, Z. M. and Stewart, S. T. (2012). Collisions between Gravity-dominated Bodies. I. Outcome Regimes and Scaling Laws. **The Astrophysical Journal**, 745, 79. [doi:10.1088/0004-637X/745/1/79](https://iopscience.iop.org/article/10.1088/0004-637X/745/1/79) -- Levison, H. F. and Duncan, M. J. (1994). The Long-Term Behavior of Short-Period Comets. **Icarus**, 108, 18. [doi: 10.1006/icar.1994.1039](https://www.sciencedirect.com/science/article/pii/S0019103584710396?via%3Dihub) -- Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body problem. **The Astronomical Journal**, 102. [doi: 0.1086/115978](https://ui.adsabs.harvard.edu/abs/1991AJ....102.1528W/abstract) -- Wishard et al. (2023) - - Swiftest: An *N*-body Integrator for Gravitational Systems. **Journal of Open Source Software**, 8(90), 5409, - [https://doi.org/10.21105/joss.05409](https://doi.org/10.21105/joss.05409) - ---- - -#### Community Guidelines - -**Contributing to Swiftest** -Swiftest is open source and can be freely accessed through our [GitHub page](https://github.itap.purdue.edu/MintonGroup/swiftest). If you wish to make a change and have that change incorporated into the published version of Swiftest, please issue a pull request. If you wish to edit Swiftest for your own personal use, no pull request is necessary. - -**Reporting an Issue** -If you stumble upon a bug or issue with the functionality of Swiftest, we want to hear about it! If you have a fix for this bug, please issue a pull request. If you do not have a fix for the bug and would like to report it, please contact the Purdue Swiftest Team via email (cwishard@purdue.edu). - -**User Support** -For help using Swiftest, please contact the Purdue Swiftest Team via email (cwishard@purdue.edu). - ---- +Please see the [Swiftest documentation](https://swiftest.readthedocs.io/en/latest/) page for more details, including advanced installation instructions, user guides, API documentation, and examples. #### Licensing Agreement diff --git a/README_figs/symba_gr.png b/docs/_static/symba_gr.png similarity index 100% rename from README_figs/symba_gr.png rename to docs/_static/symba_gr.png diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 8210b5497..344ca0136 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -1,53 +1,8 @@ +.. currentmodule:: swiftest + ################ Getting Started ################ -Swiftest User Manual -==================== - -The Purdue University Swiftest Team ------------------------------------ - -Carlisle Wishard, David Minton, Jennifer Pouplin, Jake Elliott, & Dana Singh -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - --------------- - - -Swiftest is a software packaged designed to model the dynamical -evolution of gravitational systems. Swiftest is an extension of the -`Swifter `__ software package, -detailed in Duncan, Levison, and Lee (1998), that incorporates modern -programming techniques and performance improvements. Swiftest contains -the following numerical integrators: - -- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. - See `Wisdom & Holman - (1991) `__. -- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of - WHM that is capable of handling close encounters between test - particles and massive bodies. See `Levison & Duncan - (1994) `__. -- **Democratic Heliocentric (HELIO)** - A symplectic integrator that - uses the democratic heliocentric coordinate frame. See `Duncan, - Levison, & Lee - (1998) `__. -- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO - that is capable of handling close encounters between massive bodies. - See `Duncan, Levison, & Lee - (1998) `__. - -Swiftest also includes the collisional fragmentation algorithm -**Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to -resolve collisions between massive bodies by determining the collisional -regime, derived from the work of `Leinhardt & Stewart -(2012) `__, -and generating the appropriate mass distribution of fragments. Swiftest -fully incorporates collisional fragments into the gravitational system, -evolving these new bodies along with pre-existing bodies, including -their growth and any future fragmentation events in which they are -involved. - --------------- Installation ~~~~~~~~~~~~ @@ -251,36 +206,28 @@ and start from scratch: The Swiftest CMake configuration comes with several customization options: -+------------------------+---------------------------------------------+ -| Option | CMake command | -+========================+=============================================+ -| Build type | -DCMAKE_BUILD_ | -| | TYPE=[**RELEASE**\ \|DEBUG|TESTING|PROFILE] | -+------------------------+---------------------------------------------+ -| Enable/Disable OpenMP | -DUSE_OPENMP=[**ON**\ \|OFF] | -| support | | -+------------------------+---------------------------------------------+ -| Enable/Disable SIMD | -DUSE_SIMD=[**ON**\ \|OFF] | -| directives | | -+------------------------+---------------------------------------------+ -| Enable/Disable Coarray | -DUSE_COARRAY=[ON\|\ **OFF**] | -| support (experimental) | | -+------------------------+---------------------------------------------+ -| Set Fortran compiler | -DCMAKE | -| path | _Fortran_COMPILER=/path/to/fortran/compiler | -+------------------------+---------------------------------------------+ -| Set path to make | -DCMAKE_MAKE_PROGRAM=/path/to/make | -| program | | -+------------------------+---------------------------------------------+ -| Enable/Disable shared | -DBUILD_SHARED_LIBS=[\**ON|OFF] | -| libraries (Intel only) | | -+------------------------+---------------------------------------------+ -| Add additional include | -DCMAKE_Fortran_FLAGS=“-I/path/to/libraries | -| path | | -+------------------------+---------------------------------------------+ -| Install prefix | -DCMAKE_INSTALL_PREF | -| | IX=[“/path/to/install”\|\ **“/usr/local”**] | -+------------------------+---------------------------------------------+ ++----------------------------------------------+-------------------------------------------------------------------+ +| Option | CMake command | ++==============================================+===================================================================+ +| Build type | ``-DCMAKE_BUILD_TYPE=[**RELEASE**\|DEBUG\|TESTING\|PROFILE]`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Enable/Disable OpenMP support | ``-DUSE_OPENMP=[**ON**\|OFF]`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Enable/Disable SIMD directives | ``-DUSE_SIMD=[**ON**\|OFF]`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Enable/Disable Coarray support (experimental)| ``-DUSE_COARRAY=[ON\|**OFF**]`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Set Fortran compiler path | ``-DCMAKE_Fortran_COMPILER=/path/to/fortran/compiler`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Set path to make program | ``-DCMAKE_MAKE_PROGRAM=/path/to/make`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Enable/Disable shared libraries (Intel only) | ``-DBUILD_SHARED_LIBS=[**ON**\|OFF]`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Add additional include path | ``-DCMAKE_Fortran_FLAGS="-I/path/to/libraries"`` | ++----------------------------------------------+-------------------------------------------------------------------+ +| Install prefix | ``-DCMAKE_INSTALL_PREFIX=["/path/to/install"\|**"/usr/local"**]`` | ++----------------------------------------------+-------------------------------------------------------------------+ + To see a list of all possible options available to CMake: @@ -1223,7 +1170,7 @@ more details. You should have received a copy of the GNU General Public License along with Swiftest. If not, see https://www.gnu.org/licenses/. -.. |SyMBA General Relativity| image:: README_figs/symba_gr.png +.. |SyMBA General Relativity| image:: ../_static/symba_gr.png .. toctree:: diff --git a/docs/index.rst b/docs/index.rst index a84d13b53..ed9cb22ac 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,8 +1,28 @@ .. module:: swiftest Swiftest -==================== -Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is an upgrade over the `Swifter `_ software package. +======== + +Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is a re-write of the +`Swifter `__ software package that incorporates modern programming techniques and performance +improvements. +Swiftest contains the following numerical integrators: + +- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. + See `Wisdom & Holman (1991) `__. +- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of WHM that is capable of handling close encounters between test + particles and massive bodies. See `Levison & Duncan (1994) `__. +- **Democratic Heliocentric (HELIO)** - A symplectic integrator that uses the democratic heliocentric coordinate frame. See +- `Duncan, Levison, & Lee (1998) `__. +- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO that is capable of handling close encounters between massive bodies. + See `Duncan, Levison, & Lee (1998) `__. + +Swiftest also includes the collisional fragmentation algorithm **Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to +resolve collisions between massive bodies by determining the collisional regime, derived from the work of `Leinhardt & Stewart +(2012) `__, and generating the appropriate mass distribution of fragments. Swiftest +fully incorporates collisional fragments into the gravitational system, evolving these new bodies along with pre-existing bodies, including +their growth and any future fragmentation events in which they are involved. + **Useful links**: `Home `__ | From 0f2002535f02ef565fd26ee0a2cc599b4504e72e Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 14:58:58 -0500 Subject: [PATCH 290/324] Added sub directories to the user guide --- .gitignore | 6 +++--- docs/user-guide/basic-simulation/index.rst | 10 ++++++++++ docs/user-guide/index.rst | 6 ++++-- docs/user-guide/spherical-harmonics/index.rst | 10 ++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 docs/user-guide/basic-simulation/index.rst create mode 100644 docs/user-guide/spherical-harmonics/index.rst diff --git a/.gitignore b/.gitignore index 67541a087..a2e8f50fc 100644 --- a/.gitignore +++ b/.gitignore @@ -45,13 +45,13 @@ _dependencies !.readthedocs.yaml !docs/ !docs/**/* -docs/_build/ +!docs/_build/ docs/_build/**/* docs/generated/ docs/generated/**/* docs/**/*.DS_Store docs/**/*.swp -docs/ +!docs/ !docs/_static/**/*.png !docs/_static/**/*.svg **/*.ai @@ -77,4 +77,4 @@ actions-runner* env/** venv/** -sandbox/** \ No newline at end of file +sandbox/** diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst new file mode 100644 index 000000000..178f9bfb6 --- /dev/null +++ b/docs/user-guide/basic-simulation/index.rst @@ -0,0 +1,10 @@ +################# +Basic Simulation +################# + +Here, we will walk you through the basic features of Swiftest. +This is based on ``Basic_Simulation`` in ``swiftest/examples``. + +.. toctree:: + :maxdepth: 2 + :hidden: \ No newline at end of file diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index b63a21e90..6b79531cf 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -2,9 +2,11 @@ User Guide ########### -TBD - +In this user guide, you will find detailed descriptions and examples that describe the many capabilities of Swiftest and how to use them. .. toctree:: :maxdepth: 2 :hidden: + + Basic Simulation + Spherical Harmonics \ No newline at end of file diff --git a/docs/user-guide/spherical-harmonics/index.rst b/docs/user-guide/spherical-harmonics/index.rst new file mode 100644 index 000000000..456312d26 --- /dev/null +++ b/docs/user-guide/spherical-harmonics/index.rst @@ -0,0 +1,10 @@ +################# +Spherical Harmonics +################# + +Here, we show how to use Swiftest's Spherical Harmonics capabilities. +This is based on ``spherical_harmonics_cb`` in ``swiftest/examples``. + +.. toctree:: + :maxdepth: 2 + :hidden: \ No newline at end of file From 4fb2ed9318fd0cf7bcda0c28156c52e1c2a9cf93 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 15:21:01 -0500 Subject: [PATCH 291/324] Fixed sectioning length --- docs/user-guide/spherical-harmonics/index.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/user-guide/spherical-harmonics/index.rst b/docs/user-guide/spherical-harmonics/index.rst index 456312d26..06380bd4a 100644 --- a/docs/user-guide/spherical-harmonics/index.rst +++ b/docs/user-guide/spherical-harmonics/index.rst @@ -1,10 +1,12 @@ -################# +################### Spherical Harmonics -################# +################### Here, we show how to use Swiftest's Spherical Harmonics capabilities. -This is based on ``spherical_harmonics_cb`` in ``swiftest/examples``. +This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. -.. toctree:: - :maxdepth: 2 - :hidden: \ No newline at end of file + + +.. .. toctree:: +.. :maxdepth: 2 +.. :hidden: \ No newline at end of file From f7b4f4bc1ccd29577d601ed446f4176c3fd368ba Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 16:23:32 -0500 Subject: [PATCH 292/324] Basic Simulation User Guide written through add_body --- docs/user-guide/basic-simulation/index.rst | 128 ++++++++++++++++++++- docs/user-guide/index.rst | 4 + 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 178f9bfb6..62b332786 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -2,9 +2,127 @@ Basic Simulation ################# -Here, we will walk you through the basic features of Swiftest. -This is based on ``Basic_Simulation`` in ``swiftest/examples``. +Here, we will walk you through the basic features of Swiftest and using them in Python. +This is based on ``/Basic_Simulation`` in ``swiftest/examples``. -.. toctree:: - :maxdepth: 2 - :hidden: \ No newline at end of file +Start with importing Swiftest and other packages we will use in this tutorial. :: + + import swiftest + import numpy as np + +Initial Simulation Setup +=========================== + +Create a Swiftest Simulation object and clean the simulation directory of any previous Swiftest objects, if any. +Outputs are stored in the ``/simdata`` directory by default. :: + + sim = swiftest.Simulation() + sim.clean() + +An optional argument can be passed to specify the simulation directory :: + + simdir = '/path/to/simdir' + sim = swiftest.Simulation(simdir=simdir) + sim.clean() + +Now that we have a simulation object set up (with default parameters), we can add bodies to the simulation. +The biggest body in the simulation is taken as the central body. + +Solar System Bodies +========================= + +We can add solar system bodies to the simulation using the ``add_solar_system_body`` method. +This method uses JPL Horizons to extract the parameters. :: + + # Add the modern planets and the Sun using the JPL Horizons Database. + sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) + +We can add other small bodies too. :: + + # Add in some main belt asteroids + sim.add_solar_system_body(name=["Ceres","Vesta","Pallas","Hygiea"],id_type="smallbody") + + # Add in some big KBOs + sim.add_solar_system_body(name=["Pluto","Eris","Haumea","Quaoar"]) + + # Add in some Centaurs + sim.add_solar_system_body(name=["Chiron","Chariklo"]) + +User Defined Bodies +========================= + +For completeness, let's also add some bodies with user defined parameters using ``sim.add_body()``. +We will randomize the initial conditions and therefore import the ``numpy.random`` module.:: + + from numpy.random import default_rng + rng = default_rng(seed=123) + +Starting with massive bodies: :: + + npl = 5 # number of massive bodies + density_pl = 3000.0 / (sim.param['MU2KG'] / sim.param['DU2M'] ** 3) + name_pl = ["SemiBody_01", "SemiBody_02", "SemiBody_03", "SemiBody_04", "SemiBody_05"] + + M_pl = np.array([6e20, 8e20, 1e21, 3e21, 5e21]) * sim.KG2MU # mass in simulation units + R_pl = np.full(npl, (3 * M_pl/ (4 * np.pi * density_pl)) ** (1.0 / 3.0)) # radius + Ip_pl = np.full((npl,3),0.4,) # moment of inertia + rot_pl = np.zeros((npl,3)) # initial rotation vector in degrees/TU + mtiny = 1.1 * np.max(M_pl) # threshold mass for semi-interacting bodies in SyMBA. + +Depending on the simulation parameters, we can add bodies with Orbital Elements or Cartesian Coordinates. + +Orbital Elements +------------------- + +Initialize orbital elements and then add the bodies. :: + + a_pl = rng.uniform(0.3, 1.5, npl) # semi-major axis + e_pl = rng.uniform(0.0, 0.2, npl) # eccentricity + inc_pl = rng.uniform(0.0, 10, npl) # inclination (degrees) + capom_pl = rng.uniform(0.0, 360.0, npl) # longitude of the ascending node + omega_pl = rng.uniform(0.0, 360.0, npl) # argument of periapsis + capm_pl = rng.uniform(0.0, 360.0, npl) # mean anomaly + + sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + +Cartesian Coordinates +---------------------- + +The process is similar for adding bodies with Cartesian coordinates. Start by defining the position and velocity vectors. +Here we define the orbital velocities and scale them by a random value. :: + + # position vectors + rh_pl = rng.uniform(-5, 5, (npl,3)) + rh_pl_mag = np.linalg.norm(rh_pl, axis=1) # magnitudes of the position vector + + # General velocity vectors + + # define the magnitudes + velocity_scale = rng.uniform(0.5, 1.5, npl) # scale the orbital velocity + vh_pl_mag = velocity_scale * np.sqrt(sim.GU * M_pl / rh_pl_mag) # magnitude of the velocity vector + + # initialize the vectors using the position vectors + vx = rh_pl.T[0] * vh_pl_mag / rh_pl_mag + vy = rh_pl.T[1] * vh_pl_mag / rh_pl_mag + vz = rh_pl.T[2] * vh_pl_mag / rh_pl_mag + + # rotate the velocity vectors to the XY plane for orbital motion + vh_pl = np.array([vx, vy, vz]).T + vh_pl = np.cross(vh_pl, np.array([0,0,1])) # velocity vectors + + sim.add_body(name=name_pl, rh=rh_pl, vh=vh_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + + + +Customising Simulation Parameters +================================== + +The user can also specify simulation parameters when creating the Swiftest object as defined in <>, but we will come back to this later. + + + + + +.. .. toctree:: +.. :maxdepth: 2 +.. :hidden: diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index 6b79531cf..cc1e39360 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -4,6 +4,10 @@ User Guide In this user guide, you will find detailed descriptions and examples that describe the many capabilities of Swiftest and how to use them. +Basic Simulation + +Spherical Harmonics + .. toctree:: :maxdepth: 2 :hidden: From a56dd5de91b6d0de070983d8bb14a2dbb31929f5 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 16:50:57 -0500 Subject: [PATCH 293/324] Major updates to the getting started guide and started process of cleaning up Docker scripts to work with the newest version of the code --- Dockerfile.GNU-Linux | 67 +- Dockerfile.Intel | 47 +- docs/getting-started-guide/index.rst | 1162 +++----------------------- pyproject.toml | 2 +- 4 files changed, 158 insertions(+), 1120 deletions(-) diff --git a/Dockerfile.GNU-Linux b/Dockerfile.GNU-Linux index 1e8a87a0d..409cd489c 100644 --- a/Dockerfile.GNU-Linux +++ b/Dockerfile.GNU-Linux @@ -13,9 +13,8 @@ # dynamically. # This build target compiles all dependencies and the swiftest driver itself -FROM continuumio/miniconda3:23.5.2-0 as build-deps +FROM ubuntu:focal-20240123 as build-deps SHELL ["/bin/bash", "--login", "-c"] -ENV PATH="/opt/conda/bin:${PATH}" WORKDIR /swiftest ENV INSTALL_DIR=/usr/local @@ -29,50 +28,14 @@ ENV LD_LIBRARY_PATH="${INSTALL_DIR}/lib" ENV LDFLAGS="-L${INSTALL_DIR}/lib" ENV CPPFLAGS="-I${INSTALL_DIR}/include" -COPY ./buildscripts/swiftest-build-env.yml ./ -COPY ./buildscripts/fetch_dependencies.sh ./ -RUN ./fetch_dependencies.sh -d ./ +COPY ./buildscripts/ ./buildscripts/ +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + m4 && \ + rm -rf /var/lib/apt/lists/* && \ + buildscripts/build_dependencies.sh -p ${INSTALL_DIR} -# Get the HDF5, NetCDF-C, and NetCDF-Fortran libraries -RUN conda update --all -y && \ - conda install conda-libmamba-solver -y && \ - conda config --set solver libmamba && \ - conda env create --file swiftest-build-env.yml --name swiftest-build-env && \ - conda init bash && \ - echo "conda activate swiftest-build-env" >> ~/.bashrc - -RUN cd zlib-* && \ - ./configure \ - --prefix=${INSTALL_DIR} \ - --static && \ - make && make install && \ - cd ../hdf5-* && \ - ./configure \ - --prefix=${INSTALL_DIR} \ - --disable-shared \ - --enable-build-mode=production \ - --disable-fortran \ - --disable-java \ - --disable-cxx \ - --with-zlib=${INSTALL_DIR} && \ - make && make install && \ - cd ../netcdf-c-* && \ - ./configure \ - --prefix=${INSTALL_DIR} \ - --disable-shared \ - --disable-dap \ - --disable-libxml2 \ - --disable-byterange && \ - make && make install && \ - cd ../netcdf-fortran-* && \ - export CFLAGS="-fPIC" && \ - export FCFLAGS="${CFLAGS}" && \ - export FFLAGS=${CFLAGS} && \ - export LIBS=$(${INSTALL_DIR}/bin/nc-config --libs --static) && \ - ./configure --disable-shared --prefix=${NFDIR} && \ - make && make install - -FROM continuumio/miniconda3:23.5.2-0 as build-swiftest +FROM ubuntu:focal-20240123 as build-swiftest SHELL ["/bin/bash", "--login", "-c"] ENV SHELL="/bin/bash" WORKDIR /swiftest @@ -80,18 +43,14 @@ WORKDIR /swiftest # Copy build artifacts over to the swiftest package builder stage ENV INSTALL_DIR=/usr/local COPY --from=build-deps ${INSTALL_DIR}/ ${INSTALL_DIR}/ -COPY --from=build-deps /opt/conda/envs/ /opt/conda/envs/ -COPY --from=build-deps /root/.bashrc /root/ # Compile the Swiftest project COPY ./cmake/ ./cmake/ +COPY ./pyproject.toml ./ COPY ./src/ ./src/ COPY ./swiftest/ ./swiftest/ +COPY ./tests/ ./tests/ COPY ./CMakeLists.txt ./ -COPY ./setup.py ./ -COPY ./environment.yml ./ -COPY ./pyproject.toml ./ -COPY ./requirements.txt ./ COPY ./version.txt ./ # Generate the build environment in conda @@ -107,4 +66,8 @@ RUN export NFCFG="${INSTALL_DIR}/bin/nf-config" && \ #Export the generated wheel file to the host machine FROM scratch as export-wheel -COPY --from=build-swiftest /swiftest/dist/ ./ \ No newline at end of file +COPY --from=build-swiftest /swiftest/dist/ ./ + +FROM scratch as export-driver +COPY --from=build-swiftest /swiftest/build/bin/swiftest_driver ./ +COPY --from=build-swiftest /swiftest/build/bin/libswiftest.so ./ \ No newline at end of file diff --git a/Dockerfile.Intel b/Dockerfile.Intel index f66509d8d..9c322e103 100644 --- a/Dockerfile.Intel +++ b/Dockerfile.Intel @@ -34,44 +34,12 @@ ENV LD_LIBRARY_PATH="${INSTALL_DIR}/lib" ENV LDFLAGS="-L${INSTALL_DIR}/lib" ENV CPPFLAGS="-I${INSTALL_DIR}/include" -COPY ./buildscripts/fetch_dependencies.sh ./ +COPY ./buildscripts/ ./buildscripts/ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ m4 && \ rm -rf /var/lib/apt/lists/* && \ - ./fetch_dependencies.sh -d ./ - -# Get the HDF5, NetCDF-C, and NetCDF-Fortran libraries -RUN cd zlib-* && \ - ./configure \ - --prefix=${INSTALL_DIR} \ - --static && \ - make && make install && \ - cd ../hdf5-* && \ - ./configure \ - --prefix=${INSTALL_DIR} \ - --disable-shared \ - --enable-build-mode=production \ - --disable-fortran \ - --disable-java \ - --disable-cxx \ - --with-zlib=${INSTALL_DIR} && \ - make && make install && \ - cd ../netcdf-c-* && \ - ./configure \ - --prefix=${INSTALL_DIR} \ - --disable-shared \ - --disable-dap \ - --disable-libxml2 \ - --disable-byterange && \ - make && make install -RUN cd netcdf-fortran-* && \ - export CFLAGS="-fPIC" && \ - export FCFLAGS="${CFLAGS} -standard-semantics" && \ - export FFLAGS=${CFLAGS} && \ - export LIBS=$(${INSTALL_DIR}/bin/nc-config --libs --static) && \ - ./configure --disable-shared --prefix=${NFDIR} && \ - make && make install + buildscripts/build_dependencies.sh -p ${INSTALL_DIR} FROM intel/oneapi-hpckit:2023.1.0-devel-ubuntu20.04 as build-swiftest ENV SCRIPT_DIR="buildscripts" @@ -98,18 +66,15 @@ ENV LD_LIBRARY_PATH="${INSTALL_DIR}/lib:${LD_LIBRARY_PATH}" COPY --from=build-deps ${INSTALL_DIR}/ ${INSTALL_DIR}/ # Compile the Swiftest project -COPY ./requirements.txt ./ -COPY ./environment.yml ./ COPY ./cmake/ ./cmake/ COPY ./pyproject.toml ./ -COPY ./setup.py ./ COPY ./src/ ./src/ COPY ./swiftest/ ./swiftest/ +COPY ./tests/ ./tests/ COPY ./CMakeLists.txt ./ COPY ./version.txt ./ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install python3-pip python3.8-venv -y -# Generate the build environment in conda ENV PIP_ROOT_USER_ACTION=ignore ENV LDFLAGS="-L${INSTALL_DIR}/lib" ENV CFLAGS="-fPIC" @@ -123,4 +88,8 @@ RUN export NFCFG="${INSTALL_DIR}/bin/nf-config" && \ #Export the generated wheel file to the host machine FROM scratch as export-wheel -COPY --from=build-swiftest /swiftest/dist/ ./ \ No newline at end of file +COPY --from=build-swiftest /swiftest/dist/ ./ + +FROM scratch as export-driver +COPY --from=build-swiftest /swiftest/build/bin/swiftest_driver ./ +COPY --from=build-swiftest /swiftest/build/bin/libswiftest.so ./ \ No newline at end of file diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 344ca0136..514b5ffdb 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -1,16 +1,14 @@ .. currentmodule:: swiftest -################ +=============== Getting Started -################ +=============== Installation -~~~~~~~~~~~~ +------------ For most users, installing swiftest can be done via pip using the -command: - -:: +command:: pip install swiftest @@ -20,28 +18,20 @@ will install a standalone executable called ``swiftest_driver``, which can execute simulations from the command line, provided that initial conditions and configuration files are available in the path. -**Building the** ``swiftest`` **Python package and standalone** -``swiftest_driver`` **executable** -Swiftest is designed to be downloaded, compiled, and run on a Linux or -MacOS based system. Windows support is currently being developed. +Building Swiftest from source +----------------------------- -It is possible to download, compile, and run Swiftest on a machine with -at least 400 MB of free disk space and 8 GB of RAM. To take full -advantage of the parallelization and performance updates included in -Swiftest, it is highly recommended that Swiftest be installed on a -high-performance computing cluster. For reference, Swiftest is -maintained on the Purdue University `Bell Community -Cluster `__. +If you wish to build Swiftest from source, which in some cases can lead to some performance improvements over the pre-built wheels, +you can do so by following the instructions below. This will require a Fortran compiler, CMake, and the NetCDF and HDF5 libraries to +be installed on your system. The instructions below are for building Swiftest on a Linux or MacOS system. Windows support is +currently being explored. -Swiftest is written in Modern Fortran and must be compiled using an -appropriate compiler. We recommend the Intel Fortran Compiler Classic -(ifort) version 19.0 or higher. For details on installing ifort, see the -`Intel installation -documentation `__. -The GCC/GNU Fortran Compiler (gfortran) version 9 or higher is also -compatible. For details on installing gfortran, see the `GNU Fortran -documentation `__. +You can obtain the latest version of Swiftest from the GitHub `repository `__ , or from +from a `releases `__ as a tarball. + +Required Dependencies +--------------------- Swiftest output files are stored in the NetCDF file format. This takes the place of the flat binary output file included in Swifter (and its @@ -61,96 +51,64 @@ only to be run in serial, this package is not necessary. See the `OpenMP website `__ for more details and installation instructions. -*Example of a module configuration that is necessary for compiling and -running Swiftest:* - -:: - - 1. intel/19.0.5.281 - 2. openmpi/3.1.4 - 3. netcdf/4.7.4 - 4. netcdf-fortran/4.5.3 - 5. hdf/4.2.15 - 6. hdf5/1.10.6 - -**Downloading Swiftest** - -The easiest way to get Swiftest on your machine is to clone the GitHub -repository. To do so, open a terminal window and type the following: - -:: +Central body gravity is modeled using the `SHTOOLS library `. +It is necessary to build and install SHTOOLS before building Swiftest. Optionally the ``pySHTOOLS`` package may also be installed +in order to use the tools to compute spherical harmonics cofficients for the central body when generating initial conditions, but is not required. - $ git clone https://github.com/carlislewishard/swiftest.git +Swiftest is written in Modern Fortran and must be compiled using an +appropriate compiler. We recommend the Intel Fortran Compiler Classic +(ifort) version 19.0 or higher. For details on installing ifort, see the +`Intel installation +documentation `__. +The GCC/GNU Fortran Compiler (gfortran) version 9 or higher is also +compatible. For details on installing gfortran, see the `GNU Fortran +documentation `__. +As of the time of writing, the ifx compiler is not supported. -If your cloned version is not already set to the master branch: -:: +Installing Dependencies using the Buildscripts +---------------------------------------------- - $ git checkout master +The Swiftest project contains a set of build scripts that can be used to help build the dependencies required to build Swiftest. +These scripts are used to build the official Swiftest Python wheels using cibuildwheel. In addition, we have also included a pair of +scripts that will set environment variables for Linux or MacOS. -To pull down any updates to Swiftest: +For Linux, ensure that at least ``libxml2-devel`` and ``libcurl-devel`` are installed. +Building the dependencies can be done by running the following command from the command line:: -:: + $ . buildscripts/set_environment_linux.sh + $ buildscripts/build_dependencies.sh - $ git pull +For Mac Builds, the dependencies are built in a similar way. Ensure that the Xcode command line tools are installed as well as the Homebrew package manager. +Building the dependencies can be done by running the following command from the command line:: -You now have a Swiftest repository on your personal machine that you may -compile, edit, and run as you see fit. + $ brew install coreutils + $ . buildscripts/set_environment_mac.sh + $ buildscripts/build_dependencies.sh -m ${MACOSX_DEPLOYMENT_TARGET} -**Compiling the Swiftest driver program** -**Compiling** ``swiftest_driver`` **using Docker** +Note that the above scripts will use gfortran to build the dependencies. If you wish to use the Intel Fortran Compiler, you will need to modify the build scripts to use the Intel Fortran Compiler. -By far the simplest, most reliable way of compiling the driver program -is via a Docker container. The Swiftest project contains a Dockerfile -that may be used to generate an executable without needing to provide -any external dependencies, other than the Docker engine itself (see -`here `__ for instructions on -obtaining Docker). Once Docker is installed and the Docker engine is -running, execute: -:: +Building the Swiftest Python Package and Executable +--------------------------------------------------- - $ docker build --target=export_driver \ - --output=bin \ - --build-arg MACHINE_CODE_VALUE="Host" \ - [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ - [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] +Once dependencies are installed, you can install the Swiftest Python package and the Swiftest executable by running the following command from the command line:: -The Docker build will download and compile all of the library -dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries -and the Swiftest driver using Intel compilers. Once completed, the -Swiftest executable, called ``swiftest_driver``, should now be created -in the ``bin/`` directory. + $ pip install . - Note: The Dockerfile is designed to build an executable that is - compatible with a broad range of CPU architectures by specifying the - SSE2 instruction as a target for SIMD instructions using the ``-x`` - compiler option. When compiling on the same CPU archictecture you - plan to execute the driver program, for the highest possible SIMD - performance, use - ``--build-arg MACHINE_CODE_VALUE="Host" to override the default``\ MACHINE_CODE_VALUE=“SSE2”\`. - For additional options see - `here `__. +Or, alternatively, if you wish to install an editable version:: -The optional Docker argument ``EXTRA_CMAKE_OPTIONS`` is provided to pass -any additional CMake arguments (see below). + $ pip install --no-build-isolation -ve . -**Compiling** ``swiftest_driver`` **using CMake** Several build scripts are -available in the ``buildscripts`` folder for building Swiftest and its -dependencies on a Linux or Mac system. These are used when generating -the official Swiftest Python wheels using cibuildwheel. To build the -complete project, run ``buildscripts\build_all.sh`` from the command -line. -**Compiling** ``swiftest_driver`` **using CMake** +Building the exectuable using CMake +----------------------------------- -The Swiftest driver program is written in modern Fortran and must be -compiled before it can be run. After compilation, an executable, called -the ``swiftest_driver``, will have been created in the ``bin/`` -directory. +Although Swiftest is designed to be run from Python, it is also possible to run Swiftest simulations from the command line using the ``swiftest_driver`` executable, provided it has +an initial conditions file and a configuration parameter file, which are typically generated using the Python package. -Swiftest is compiled through `CMake `__. Compiling +The ``swiftest_driver`` is compiled through `CMake `__. Compiling with CMake has a number of benefits that provide a streamlined experience for the Swiftest user and developer. At compilation, CMake will automatically select the set of flags that are compatible with the @@ -191,55 +149,95 @@ are: :: - $ cmake -B build -S . - $ cmake --build build + $ cmake -B build -S . -G Ninja + $ cmake --build build -j8 + +You may omit the ``-G Ninja`` flag if you do not have the Ninja build system installed. The ``-j8`` flag is used to specify the number of threads to use during compilation. -The `CMake Fortran -template `__ -comes with a script that can be used to clean out any build artifacts -and start from scratch: +The `CMake Fortran template `__ +comes with a script that can be used to clean out any build artifacts and start from scratch: :: $ cmake -P distclean.cmake -The Swiftest CMake configuration comes with several customization -options: - -+----------------------------------------------+-------------------------------------------------------------------+ -| Option | CMake command | -+==============================================+===================================================================+ -| Build type | ``-DCMAKE_BUILD_TYPE=[**RELEASE**\|DEBUG\|TESTING\|PROFILE]`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Enable/Disable OpenMP support | ``-DUSE_OPENMP=[**ON**\|OFF]`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Enable/Disable SIMD directives | ``-DUSE_SIMD=[**ON**\|OFF]`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Enable/Disable Coarray support (experimental)| ``-DUSE_COARRAY=[ON\|**OFF**]`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Set Fortran compiler path | ``-DCMAKE_Fortran_COMPILER=/path/to/fortran/compiler`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Set path to make program | ``-DCMAKE_MAKE_PROGRAM=/path/to/make`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Enable/Disable shared libraries (Intel only) | ``-DBUILD_SHARED_LIBS=[**ON**\|OFF]`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Add additional include path | ``-DCMAKE_Fortran_FLAGS="-I/path/to/libraries"`` | -+----------------------------------------------+-------------------------------------------------------------------+ -| Install prefix | ``-DCMAKE_INSTALL_PREFIX=["/path/to/install"\|**"/usr/local"**]`` | -+----------------------------------------------+-------------------------------------------------------------------+ - - -To see a list of all possible options available to CMake: - -:: +The Swiftest CMake configuration comes with several customization options: + +.. _gs-cmake-options-table: + ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Option | CMake command | Default value | ++==============================================+=======================================================+===============+ +| Build type | -DCMAKE_BUILD_TYPE=[RELEASE\|DEBUG\|TESTING\|PROFILE] | RELEASE | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Enable/Disable OpenMP support | -DUSE_OPENMP=[ON\|OFF] | ON | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Enable/Disable SIMD directives | -DUSE_SIMD=[ON\|OFF] | ON | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Enable/Disable Coarray support (experimental)| -DUSE_COARRAY=[ON\|OFF] | OFF | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Set Fortran compiler path | -DCMAKE_Fortran_COMPILER=/path/to/fortran/compiler | ${FC} | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Set path to make program | -DCMAKE_MAKE_PROGRAM=/path/to/make | ${PATH} | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Enable/Disable shared libraries (Intel only) | -DBUILD_SHARED_LIBS=[ON\|OFF] | ON | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Add additional include path | -DCMAKE_Fortran_FLAGS="-I/path/to/libraries" | None | ++----------------------------------------------+-------------------------------------------------------+---------------+ +| Install prefix | -DCMAKE_INSTALL_PREFIX=["/path/to/install"\|] | /usr/local | ++----------------------------------------------+-------------------------------------------------------+---------------+ + + +To see a list of all possible options available to CMake:: $ cmake -B build -S . -LA -The Swiftest executable, called ``swiftest_driver``, should now be -created in the ``bin/`` directory. +The Swiftest executable, called ``swiftest_driver`` as well as the shared library, either ``libswiftest.so`` or ``libswiftest.dylib``, +depending on your platform, should now be created in the ``build/bin/`` directory. You can also install the it into your system by running:: + + $ cmake --install build + +You may need to run the above command as root or with sudo if you are installing into a system directory. + + +Building the exectuable using Docker +------------------------------------ + +The Swiftest project contains a Dockerfile +that may be used to generate an executable without needing to provide +any external dependencies, other than the Docker engine itself (see +`here `__ for instructions on +obtaining Docker). Once Docker is installed and the Docker engine is +running, execute:: + + $ docker build --target=export-driver \ + --output=./bin \ + --build-arg MACHINE_CODE_VALUE="Host" \ + [ -f Dockerfile.GNU-Linux | -f Dockerfile.Intel ] \ + [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ + [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] . -**Download the** ``swiftest_driver`` **as a Docker or Singularity -container.** +The Docker build will download and compile all of the library +dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries +and the Swiftest driver using Intel compilers. Once completed, the +Swiftest executable, called ``swiftest_driver``, should now be created +in the ``bin/`` directory. + + Note: The Dockerfile is designed to build an executable that is + compatible with a broad range of CPU architectures by specifying the + SSE2 instruction as a target for SIMD instructions using the ``-x`` + compiler option. When compiling on the same CPU archictecture you + plan to execute the driver program, for the highest possible SIMD + performance, use + ``--build-arg MACHINE_CODE_VALUE="Host"`` to override the default ``MACHINE_CODE_VALUE=“SSE2”``. + For additional options see + `here `__. + +The optional Docker argument ``EXTRA_CMAKE_OPTIONS`` is provided to pass any additional CMake arguments (see `supported CMake options `_) + + +Download the executable as a Docker or Singularity container. +------------------------------------------------------------- The Swiftest driver is available as a Docker container on DockerHub in two versions: Intel and GNU. The Intel version was compiled for the @@ -254,16 +252,12 @@ container pulls from the same DockerHub container. To facilitate installation of the container, we provide a set of shell scripts to help automate the process of installing container versions of the executable. To install the default Intel version of the docker -container from within the ``swiftest\`` project directory - -:: +container from within the ``swiftest\`` project directory:: $ cd docker $ . ./install.sh -To install the GNU version: - -:: +To install the GNU version:: $ cd docker $ . ./install.sh gnu @@ -283,894 +277,6 @@ adding the environment variable definition to your shell startup script ``export SWIFTEST_SIF="/path/to/swiftest/singularity/swiftest.sif"`` to your ``.zshrc``) -**Swiftest Python Package** - -Included with Swiftest, in the ``/swiftest/python/swiftest/`` directory, -is a Python package designed to facilitate seamless data processing and -analysis. The Python package, also called Swiftest, can be used to -generate input files, run Swiftest simulations, and process output files -in the NetCDF file format. - -To begin, Swiftest can be added to an existing conda environment, or a -new conda environment may be created, so long as the required packages -are installed. To create and activate a new conda environment with the -prerequisite packages, open a terminal and navigate to the -``/swiftest/python/swiftest/`` directory. Type the following: - -:: - - $ conda create --name EnvName pip scipy numpy matplotlib pandas xarray jupyter astropy -y - $ conda activate EnvName - -Next, we will install further required packages. Using the ``-e`` flag -imports all packages in ``/swiftest/python/swiftest/requirements.txt``, -including Swiftest. If the Swiftest Python package is updated in the -future, using the ``-e`` flag should ensure that the user does not have -to reinstall the package to use the updated version. - -:: - - $ pip install --user -e . - -The Swiftest Python package should now be installed in the conda -environment and is ready to use. If you would like to take the further -step to add Swiftest to a Jupyter Notebook kernel, type the following: - -:: - - $ ipython kernel install --user --name EnvName --display-name "Swiftest Kernel" - --------------- - -Usage -~~~~~ - -Swiftest is built to make running a Swiftest simulation a streamlined -and user-friendly experience, even for a new user. As a result, Swiftest -is highly flexible and a simulation can be created, run, and processed -in a number of different ways. The first choice the user must make is if -they would prefer ASCII input files or NetCDF input files. We recommend -NetCDF input files, however we include documentation for ASCII input -files for completeness. - -**Brief Outline** - -To create and run a Swiftest simulation using the Swiftest Python -package, follow the general script below. For more details on the input -files and user options, continue reading this section. - -:: - - import swiftest # Import the Swiftest Python package - sim = swiftest.Simulation(simdir = "directory_name", **kwargs) # Initialize a Swiftest simulation and define a directory/path in which to store simulation data - sim.add_solar_system_body(**kwargs) # Add any desired named Solar System bodies, including the Sun - sim.add_body(**kwargs) # Add any desired user defined bodies - sim.get_parameter(**kwargs) # View the default simulation parameters - sim.set_parameter(**kwargs) # Set any desired simulation parameters - sim.write_param(**kwargs) # Write simulation parameters to the param.in - sim.save(**kwargs) # Save the simulation initial conditions to init_cond.nc - sim.run(**kwargs) # Run the simulation (leave off if running from the executable) - -To read in a set of Swiftest output files using the Swiftest Python -package, follow the general script below. For more details on the output -files and user options, continue reading this section. - -:: - - import swiftest # Import the Swiftest Python package - sim = swiftest.Simulation(simdir = "directory_name", read_data=True) # Initialize a Swiftest simulation - sim.data # Body data over time - sim.init_cond # The initial conditions for the simulation - sim.encounters # Encounter data for all close encountering pairs - sim.collisions # Collision data for all colliders and collisional fragments - -**NetCDF Input Files (Recommended)** - -Swiftest accepts a single NetCDF input file. This file can be created -using the Swiftest Python Package through a few simple steps. - -To begin, simply create a new Python script in the directory you would -like to store your simulation. Open the new script and import the -Swiftest Python package. - -:: - - import swiftest - -Next, we initialize the Swiftest simulation object. Various parameters -can be provided to the simulation via key word arguments at this stage. - -:: - - sim = swiftest.Simulation(simdir = "directory_name", **kwargs) - -The argument ``simdir`` is the name of the subdirectory in which to -store all simulation data. This does not have to exist at the time the -simulation object is initialized. - -The key word arguments available to the user, along with the default -values for these arguments, are described in -`simulation_kwargs `__. - -After creating the simulation and defining all desired parameters as -keyword arguments, it is time to add bodies to the simulation. The -Swiftest Python package interfaces with the `NASA JPL Horizons -database `__, allowing a user to -easily import the initial conditions of known solar system bodies using -the ``add_solar_system_body`` method. - -:: - - sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto"]) - -User defined bodies can also be added to a Swiftest simulation through -the Python package. Massive bodies and test particles can both be added -using the ``add_body`` method. - -:: - - sim.add_body(**kwargs) - -The key word arguments available to the user for the ``add_body`` method -are described in `add_body_kwargs `__. - -Once all desired bodies have been added to the Swiftest simulation, the -simulation parameters can be accessed and changed using the -``get_parameter`` and ``set_parameter`` methods. The key word arguments -available to the user for the ``get_parameter`` and ``set_parameter`` -are the same as those described in -`simulation_kwargs `__. - -After all desired parameters have been set, the parameters can be saved -to the **param.in** using the ``write_param`` method. The key word -arguments available to the user for the ``write_param`` method are -described in -`write_param_kwargs `__. - -The state of the system can be saved to the initial conditions NetCDF -file, **init_cond.nc**, using the ``save`` method. The key word -arguments available to the user for the ``save`` method are described in -`save_kwargs `__. - -Finally, a simulation can be run from the same script in which it is -created (or a separate Python script) using the ``run`` method. This is -optional as the simulation can also be run from an executable. More -details on running a Swiftest simulation can be found in the section -**Running a Swiftest Simulation**. The key word arguments available to -the user for the ``run`` method are the same as those described in -`simulation_kwargs `__. - -**ASCII Input Files** Swiftest accepts 4 ASCII input files. All four -ASCII input files are necessary if using the ASCII input format, however -the structure of each input file varies slightly depending on the -features and capabilities of the integrator selected. The four ASCII -input files are not necessary if using NetCDF input files. The four -input files are as follows: - -- **param.in** - The parameter input file. -- **cb.in** - The central body input file. -- **pl.in** - The massive body input file. -- **tp.in** - The test particle input file. - -The parameter options used in the parameter input file are as described -in `simulation_kwargs `__. - -The **cb.in** includes all central body initial conditions. The -structure of the **cb.in** is as follows: - -:: - - 0 ! ID number - 1.0 ! Gravitational mass (G*mass) in mass units (ex. 39.47841760435743 for Sun in M_sun/AU/year) - 1.0 ! Central body radius is distance units (ex. 0.004650467260962157 for Sun in AU) - 0.0 ! J2 term, optional, set to 0.0 for a spherical body - 0.0 ! J4 term, optional, set to 0.0 for a spherical body - 0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only - 0.0 0.0 0.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only - -The **pl.in** includes all massive body initial conditions. The -structure of the **pl.in** is as follows: - -:: - - 2 ! Total number of massive bodies - 1, 0.0, 0.0 ! ID number, Gravitational mass (G*mass) in mass units, Hill Radius in distance units if RHILL_PRESENT is set to YES, leave off if not using - 0.0 ! Radius is distance units if CHK_CLOSE is set to YES, leave off if not using - 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination - 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly - 0.4 0.4 0.4 ! Principal moments of inertia, optional, leave off if not using, SyMBA only - 1.0 1.0 1.0 ! Rotational vectors in radians per second, optional, leave off if not using, SyMBA only - 2, 0.0, 0.0 - 0.0 - 1.0 1.0 1.0 - 1.0 1.0 1.0 - 0.4 0.4 0.4 - 1.0 1.0 1.0 - -The **tp.in** includes all test particle initial conditions. In the -event that no test particles are desired, the **tp.in** must still be -included, however it can simply contain a single ``0``. The structure of -the **tp.in** is as follows: - -:: - - 2 ! Total number of test particles - 3 ! ID number - 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric position vector, if it is set to EL then this is the semi-major axis, the eccentricity, and the inclination - 1.0 1.0 1.0 ! If IN_FORM is set to XV then this is the heliocentric velocity vector, if it is set to EL then this is the longitude of the ascending node, the argument of pericenter, and the mean anomaly - 4 - 1.0 1.0 1.0 - 1.0 1.0 1.0 - -Note that the ID numbers of the test particles are a continuation of the -ID numbers of the massive bodies. No two bodies in the system can have -the same ID number. - -**Running a Swiftest Simulation** - -The input files necessary to successfully run Swiftest should now be -generated in the simulation directory. The user is now faced with a -second choice: to run a Swiftest simulation from a Python environment or -to run it directly from an executable. Either option is possible with -NetCDF format input files, however ASCII input files must be run -directly from an executable. - -**Running via Python** - -To run a Swiftest simulation from the same script in which the initial -conditions are created, simply add the following line after you have -finished defining parameters and adding bodies to the simulation: - -:: - - sim.run() - -To run a previously created set of initial conditions, first read the -old parameter file into Python, and then run it. Note that Swiftest will -look in the ``/simdata`` subdirectory for the initial conditions by -default. You may set a new path to the initial conditions using the -``param_file`` keyword argument. See the documentation detailing the key -word arguments available to the user in -`simulation_kwargs `__. - -:: - - sim = swiftest.Simulation(simdir = "directory_name", read_param=True) - sim.run() - -**Running via an Executable** - -To run a Swiftest simulation through an executable, create a symbolic -link to the Swiftest driver from your current directory. - -:: - - $ ln -s ~/PATH/TO/swiftest/bin/swiftest_driver . - -To run Swiftest, simply type the following command into the terminal: - -:: - - $ ./swiftest_driver INTEGRATOR param.in - -Where ``INTEGRATOR`` is your integrator of choice, either ``whm``, -``rmvs``, ``helio``, or ``symba``. - -**Outputs** - -The number and type of output files generated by Swiftest depends on the -input parameters selected and the method through which Swiftest was run. -The standard output files are as follows: - -- **data.nc** - Always generated, the output file containing the information for every body in the system, recorded every ``ISTEP_OUT`` timesteps and written every ``DUMP_CADENCE``. This file can be analyzed using the Swiftest Python package (``sim.data``). -- **collisions.log** - The log containing the record of each fragmentation event, including the collisional regime, and the number of the fragments created, only if ``FRAGMENTATION`` is ``YES``, Swiftest SyMBA only. -- **swiftest.log** - A log containing a brief update on the status of the run. Only generated if Swiftest is run through the Python package or through a shell script. If Swiftest is run through an executable, these updates are output directly to the terminal. -- **collisions.nc** - The details of each collision that occurs in a simulation are recorded in a NetCDF file. Only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file can be analyzed using the Swiftest Python package (``sim.collisions``). -- **encounters.nc** - The details of each close encounter that occurs in a simulation are recorded in a NetCDF file. Only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True``. This file can be analyzed using the Swiftest Python package (``sim.encounters``). -- **init_cond.nc** - The initial conditions used to run the simulation. This file can be analyzed using the Swiftest Python package (``sim.init_cond``). -- **encounter_check_plpl_timer.log** - The log containing the encounter check timer for each massive body/massive body encounter, only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True`` and ``ENCOUNTER_CHECK``/``encounter_check_loops`` is ``ADAPTIVE``. -- **encounter_check_pltp_time.log** - The log containing the encounter check timer for each massive body/test particle encounter, only if ``CHK_CLOSE``/``close_encounter_check`` is ``YES``/``True`` and ``ENCOUNTER_CHECK``/``encounter_check_loops`` is ``ADAPTIVE``. -- **interaction_timer.log** - The log containing the interaction loop timer for each interacting pair of bodies, only if ``INTERACTION_LOOPS`` is ``ADAPTIVE``. - -To read in a Swiftest output file, simply create a new Python script in -the simulation directory. - -:: - - import swiftest - sim = swiftest.Simulation(simdir = "directory_name", read_data=True) - -All Swiftest data is now stored in the Xarray datasets ``sim.data``, -``sim.collisions``, and ``sim.encounters`` and is easily processed, -manipulated, and analyzed. - -Regardless of whether the status outputs are recorded in the -**swiftest.log** or in the terminal, the output format is the same. -Below is an example of a single status output: - -:: - - Time = 1.00000E+03; fraction done = 0.001; Number of active plm, pl, tp = 57, 108, 50 - DL/L0 = 6.83763E-12; DEcollisions/|E0| = 0.00000E+00; D(Eorbit+Ecollisions)/|E0| = 2.65579E-03; DM/M0 = 0.00000E+00 - Integration steps: Total wall time: 2.99848E+02; Interval wall time: 9.36192E+01;Interval wall time/step: 4.68956E-04 - -The first line includes the simulation time, the fraction of the -simulation that is complete relative to ``tstop``, the number of -fully-interactive massive bodies (``plm``) (SyMBA only), the total -number of massive bodies (``pl``) including fully-interactive and -semi-interactive bodies, and the number of test particles (``tp``) -remaining in the system at that time. The second line includes the -angular momentum error, the change in energy as a result of collisions -only, the total change in energy, and the change in mass up to this -point in the simulation (error analysis included only if -``ENERGY``/``compute_conservation_values`` is set to ``YES``/``True``). -The third line contains the total wall time elapsed since the start of -the simulation, the wall time elapsed since the start of the last step, -and the average wall time per step since the start of the simulation. - -**Restarting a Simulation From t** :math:`\neq` **0** - -Just like Swiftest allows the user to run a simulation through an -executable or through Python, Swiftest also allows the user to restart a -simulation from t :math:`\neq` 0 in the same two manners. This can be -useful in the case of an accidental termination of a simulation, such as -through a power outage or computer failure. In many cases, it is also -necessary to run a simulation to a new end point, past the original -``TSTOP``. - -**Restarting via Python** - -To restart a Swiftest simulation via the Swiftest Python package, follow -the outline below: - -:: - - import swiftest - sim = swiftest.Simulation(simdir = "directory_name", read_data=True) - sim.set_parameter(tstop=VAL) # Set a new stop time if desired - sim.write_param() # Write simulation parameters to the param.in - sim.run() - -Note that Swiftest will look in the ``/simdata`` subdirectory for the -initial conditions by default. You may set a new path to the initial -conditions using the ``param_file`` keyword argument. - -**Restarting via an Executable** - -Every ``DUMP_CADENCE`` X ``ISTEP_OUT`` timesteps, Swiftest writes all -simulation information from memory to the output files. At the same -time, Swiftest also writes all simulation information to a new parameter -file, titled **param.XXXXXXXXXXXXXXXXXX.in**. To restart a run from a -previous parameter file, simply follow the instructions detailed in the -**Running via an Executable** section, replacing ``param.in`` with the -name of the parameter file from which you wish to restart. - --------------- - -Updates to Swifter Included in Swiftest -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**Collisional Fragmentation via Fraggle** - -To activate the Fraggle algorithm, set -``FRAGMENTATION``/``fragmentation`` to ``YES``/``True``, depending on -the mode in which Swiftest is being run. When resolving a close -encounter that results in a collision, Fraggle determines the regime of -the collision as well as the mass, number, position, velocity, and -rotation of all resulting bodies. This is distinct from Swiftest SyMBA’s -predecessor, Swifter SyMBA, which assumes that all collisions result in -perfect mergers. - -Fraggle distinguishes the following collisional regimes: (1) perfect -merging, which includes the cratering, partial accretion, and -graze-and-merge regimes of Leinhardt & Stewart 2012, (2) disruption, -which includes the partial erosion regime of Leinhardt & Stewart 2012, -(3) super-catastrophic disruption, and (4) hit-and-run events which can -be either ‘pure’ or ‘disruptive’. - -For every collision throughout the course of a simulation, Fraggle -writes a brief description of the collision to the **fraggle.log** -output file. An example of a collision, stored in the **fraggle.log** -output file, is as follows: - -:: - - Fraggle logfile - - *********************************************************************************************************************** - Collision between massive bodies detected at time t = 2.063709800335315E-006 - ********************************************************************************************************************** - - -------------------------------------------------------------------- - Fraggle collisional regime determination results - -------------------------------------------------------------------- - True number of colliders : 2 - Index list of true colliders : 1 2 - Regime: Disruption - Energy loss : 2.298848838233116E-022 - -------------------------------------------------------------------- - Disruption between Target (1) and Projectile (2) - Fraggle generating 28 fragments. - Fraggle try 1 - Fraggle fragment generation succeeded after 1 tries - Generating 28 fragments - -The details of the collision are stored in the simulation object -(``sim.collisions``) which can be accessed using the Swiftest Python -package. - -**General Relativity** - -From its observation in the mid-1800s to the development of the theory -of general relativity by Albert Einstein in 1915, the precession of -Mercury’s perihelion puzzled scientists and observers. Mercury’s orbit -precesses by approximately :math:`42.980 \pm 0.001` arcseconds / century -more than is expected from Newtonian mechanics. This deviation can be -explained by the curvature of spacetime due to the mass of the Sun. -Mercury’s close proximity to the Sun enhances the effects of general -relativity, providing a good test case to highlight the functionality of -general relativity in Swiftest. - -In this test case, we track the orbit of Mercury for 1000 years as it -orbits around the Sun in the presence of the seven other massive -planets. The precession rate of the longitude of periapsis of Mercury, -as calculated by Swiftest SyMBA, differs by only :math:`\sim 0.0286 \%` -from the precession rate calculated from the NASA JPL Horizons database. - -+-----------------------------------------------------------------------+ -| |SyMBA General Relativity| | -+=======================================================================+ -| **Figure 1** - The longitude of periapsis of Mercury over 1000 years, | -| as calculated by Swifter SyMBA (dotted green), Swiftest SyMBA with | -| general relativity turned off (long dashed yellow), and Swiftest | -| SyMBA with general relativity turned on (short dashed blue). These | -| results are compared to the periapsis of Mercury as calculated from | -| the NASA JPL Horizons database (solid red). Swiftest SyMBA with | -| general relativity turned off is in good agreement with Swifter SyMBA | -| (:math:`\sim 0.00053 \%` difference), while Swiftest SyMBA with | -| general relativity turned on is in good agreement with the NASA JPL | -| Horizons database (:math:`\sim 0.0286 \%` difference). | -+-----------------------------------------------------------------------+ - -**Adaptive Interaction Calculations and Encounter Checking** - -In Swifter SyMBA, gravitational interactions between bodies are -calculated on a pair-by-pair basis by solving an upper triangular -matrix. In practice, this is done through a double loop. While -effective, solving a triangular matrix is computationally costly and it -is considered best practice to avoid nested loops wherever possible. -Swiftest SyMBA offers an alternative to this method, allowing the user -to choose between calculating the gravitational interactions between -bodies through a traditional triangular matrix or through a flattened -Euclidean distance matrix. - -A Euclidean distance matrix is a two-dimensional array that stores the -distance between each pairing of points in a set of elements. For more -details on the algorithm implemented in Swiftest to flatten the -Euclidean distance matrix, please see `Angeletti, Bonny, & Koko -2019 `__. - -Along with allowing the user to choose whether the gravitational -interactions are calculated through an upper triangular matrix or a -flattened Euclidean distance matrix, Swiftest SyMBA allows the user to -let the program determine the speedier solution. Through adaptive -interaction calculations, Swiftest SyMBA periodically tracks the time it -takes to complete an interaction calculation using both the triangular -and flat methods. Whichever method proves to be quicker is implemented -until the next time both methods are tested. Swiftest SyMBA periodically -checks the performance of each method, possibly switching between the -two methods multiple times over the course of a simulation. By selecting -adaptive interaction calculations, the user allows Swiftest SyMBA to -optimize its own performance and adapt to changes in the number of -particle pairings as the simulation progresses. - -An example of the adaptive interaction calculations, stored in the -**interaction_timer.log** output file, is as follows: - -:: - - Interaction loop timer logfile ! The file header - Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which calculation method is fastest - symba_kick_getacch_int_pl: loop timer turned on at t = 0.000000000000000E+000 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun - symba_kick_getacch_int_pl: stage 1 ! Begins timing the first method - FLAT 95 7353 1.291989664082687E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) - symba_kick_getacch_int_pl: stage 2 ! Begins timing the second method - TRIANGULAR 100 7353 1.359989120087039E-002 ! The calculation method type, the time (in seconds) to calculate all interactions, the number of massive body / massive body interactions, and the time per interaction (time / number of interactions) - symba_kick_getacch_int_pl: the fastest loop method tested is FLAT ! The subroutine in which the timing is being conducted and which interaction calculation method is determined to be fastest - -In addition to calculating the gravitational interactions between -pairings of bodies, Swifter SyMBA also uses an upper triangular matrix -to check if pairings of bodies are in a close encounter state. While -similar to interaction calculations, encounter checking can be further -simplified to exclude pairs of bodies which, based on their physical -distance, are unlikely to be in an encounter state. To address this, -Swiftest SyMBA offers an alternative to solving an upper triangular -matrix through the sort and sweep method. - -The sort and sweep method of collision detection (see `Ericson -2005 `__ -for more details), also known as the sweep and prune method, is a way of -limiting the number of pairs of bodies that need to be checked for a -collision in each time step. At the start of a new time step, the -position of each body is calculated and the critical radius of each body -is determined. The critical radius is based on the radius of a body’s -Hill sphere. The distance from a body’s center to the extent of its -critical radius defines the encounter sphere of the body. The position -of the center of mass of the body and the extent of its encounter sphere -are used to define the bounding box used in the sort and sweep -algorithm. Based on the defined bounding box, the positions of the lower -and upper bounds of all of the bodies in the simulation are compiled -into sorted lists. Because each body is unlikely to move significantly -between time steps, updating these sorted lists each time step is -relatively straightforward. Only when the bounding boxes of two bodies -overlap in all axes are the bodies flagged as an encountering pair. - -| The sort and sweep algorithm is computationally efficient because it - limits the number of potential encountering pairs that must be checked - for encounters. For example, by calculating the bounding boxes of two - bodies on opposite sides of the solar system, the algorithm then sorts - the upper and lower bounds of these two bounding boxes into opposite - ends of a sorted list. Through this sorting, the algorithm recognizes - that these two bodies are unlikely to encounter one another in the - following time step and is able to quickly exclude them from more - extensive encounter checking, saving time and computational resources. -| In the same way that the user can allow Swiftest SyMBA to adapt when - calculating the gravitational interactions between bodies, the user - can also allow Swiftest SyMBA to determine the faster method of - encounter checking. Just as Swiftest SyMBA periodically tests the - interaction calculation methods, it also periodically tests the - encounter checking methods. The quicker of the two methods is selected - and implemented, allowing Swiftest SyMBA to adapt to changes in the - distribution of bodies in the system as the simulation progresses. - -An example of the adaptive encounter checking, stored in the -**encounter_check_plpl_timer.log** output file, is as follows: - -:: - - Encounter check loop timer logfile ! The file header - Diagnostic values: loop style, time count, nplpl, metric ! The diagnostic values used to determine which checking method is fastest - encounter_check_all_plpl: loop timer turned on at t = 5.000000000000000E-003 ! The subroutine in which the timing is being conducted and the time (in simulation time) at which the timer is begun - encounter_check_all_plpl: stage 1 ! Begins timing the first method - SORTSWEEP 196 7353 2.665578675370597E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) - encounter_check_all_plpl: stage 2 ! Begins timing the second method - TRIANGULAR 164 7353 2.230382156942744E-002 ! The checking method type, the time (in seconds) to check all possible encounters, the number of possible massive body / massive body encounters, and the time per encounter (time / number of possible encounters) - encounter_check_all_plpl: the fastest loop method tested is TRIANGULAR ! The subroutine in which the timing is being conducted and which encounter checking method is determined to be fastest - -Together, adaptive interaction calculations and encounter checking are -idea for lengthy simulations with a large number of particles. The -flexibility of Swiftest SyMBA ensures that the parameters of the -integration are optimized for each individual simulation, even as the -simulation evolves. - -**NetCDF Compatibility** - -The NetCDF (Network Common Data Form) file format is a cross-platform -method of creating, accessing, and sharing data. Due to its -self-describing nature, NetCDF is ideal for archiving multidimensional -scientific data. NetCDF files are also appendable, allowing for data to -be added to a file after creation, making the NetCDF file format well -suited for handling simulation output. NetCDF is maintained by the -University Corporation for Atmospheric Research (UCAR) and is a standard -file format across much of the atmospheric modeling community. - -In Swifter SyMBA, simulation outputs were stored in a flat binary file. -These binary files could only be easily accessed through -`SwiftVis `__, a data analysis -and visualization software package designed to process Swifter data. In -accordance with modern data management practices and industry standards, -Swiftest incorporates a NetCDF output file format for all simulation -types. NetCDF is compatible with many of today’s most widely-used -programming languages including Fortran, Python, Java, C++, and more. By -writing simulation data to a NetCDF output file, Swiftest provides the -user with the flexibility to analyze and visualize data in any language -they choose. The NetCDF file format is also adaptable such that any -future additions to Swiftest can be seamlessly incorporated into the -output file. - -**Object-Oriented Programming** - -The 2003 version of Fortran introduced object-oriented programming, with -Fortran 2008 providing further updates. Swiftest is written in modern -Fortran and takes advantage of many of the object-oriented programming -features included in Fortran 2003. In doing so, Swiftest is a complete -restructure of its predecessor, Swifter. The reusability and -simplification of code in Swiftest through object-oriented programming -is a modern and flexible approach that allows for future enhancements -and additions to the Swiftest package. - -**Parallelization** - -Parallelization using OpenMP is still under development in Swiftest. For -preliminary results, see **Figure 2**. - --------------- - -Examples -~~~~~~~~ - -All examples are included in the ``/swiftest/examples/`` directory. -Simply run the script(s) included in the directory as you would normally -run a Python script. See the **README.txt** included in each example -directory for more details. - -**Basic_Simulation** - -This example walks through how to set up a standard solar system -simulation. It can be found in the -``/swiftest/examples/Basic_Simulation`` directory. It is intended to be -run using the SyMBA integrator. It contains three classes of bodies: - -Fully-Interacting Massive Bodies - Gravitationally affect and are -affected by other massive bodies. - Semi-Interacting Massive Bodies - -Gravitationally affect and are affected by fully-interacting massive -bodies, do not gravitationally affect and are not affected by other -semi-interacting massive bodies. - Test Particles - Gravitationally -affected by fully-interacting massive bodies only. - -To generate the initial conditions, run the Python script titled -**basic_simulation.py**. This script also runs Swiftest SyMBA, -generating output. To process the output file, run the script titled -**output_reader.py**. - -**Chambers2013** - -This example acts as a comparison to the work of `Chambers -2013 `__. -It can be found in the ``/swiftest/examples/Chambers2013`` directory. It -is intended to be run using the SyMBA integrator and highlights how to -run Swiftest using and executable, as opposed to through a Python -script. To generate the initial conditions, run **init_cond.py**. To run -Swiftest with these intial conditions, type: - -:: - - ./swiftest_driver symba param.in - -To process the output file, run the script titled **scattermovie.py**. - -**Fragmentation** - -This example highlights the functionality of the Fraggle algorithm. It -can be found in the ``/swiftest/examples/Fragmentation`` directory. It -is intended to be run using the SyMBA integrator. It contains 9 -pre-built collisional test cases: - -- A Head-On Disruptive Collision -- An Off-Axis Disruptive Collision -- A Head-On Super-Catastrophic Disruptive Collision -- An Off-Axis Super-Catastrophic Disruptive Collision -- A Disruptive Hit and Run Collision -- A Pure Hit and Run Collision -- A Merger -- A Merger Crossing the Spin Barrier -- All of the Above - -To generate, run, and create a movie depicting the collision, run the -Python script titled **Fragmentation_Movie.py**. Please note that this -example requires a large amount of memory. For reference, this example -was created and run using 4 nodes, each with 256 GB of memory. This -amount of computational memory is necessary to generate a smooth movie. -In this example, the trajectories of all bodies involved in the -collision are saved at every point in the simulation. This is extremely -expensive and should only be used to study a particular collisional -event in detail. - -**helio_gr_test** - -This example demonstrates the functionality of general relativity in -Swiftest HELIO. It can be found in the -``/swiftest/examples/helio_gr_test`` directory. It is intended to be run -using the HELIO integrator. Because the SyMBA integrator is built upon -the HELIO integrator, GR is also available in SyMBA. - -**Multibody_Fragmentation** - -This example highlights the functionality of the Fraggle algorithm. It -can be found in the ``/swiftest/examples/Mulitbody_Fragmentation`` -directory. It is intended to be run using the SyMBA integrator. To -generate a set of initial conditions, run the initial conditions using -Swiftest, and generate a movie depicting the collisional result, run the -Python script titled **Multibody_Movie.py**. - -**solar_impact** - -This example demonstrates the conservation of angular momentum, energy, -and mass during a collision between a massive body and the Sun, or -central body. It can be found in the ``/swiftest/examples/solar_impact`` -directory. It is intended to be run using the SyMBA integrator. - -**Swifter_Swiftest** - -This set of examples acts as a comparison between Swiftest and its -predecessor, Swifter. Two unique simulations are included in this -example, one with 8 massive bodies and 0 test particles, and one with -108 massive bodies and 50 test particles. These simulations can be found -in the ``/swiftest/examples/Swifter_Swiftest/8pl_0tp`` and the -``/swiftest/examples/Swifter_Swiftest/108pl_50tp`` directories, -respectively. They are intended to be run using the SyMBA integrator. -For details on how to run a simulation using Swifter, please see the -`Swifter website `__. - -**whm_gr_test** - -This example demonstrates the functionality of general relativity in -Swiftest WHM. It can be found in the ``/swiftest/examples/whm_gr_test`` -directory. It is intended to be run using the WHM integrator. Because -the SyMBA integrator is built upon the HELIO integrator, which is in -turn built upon the WHM integrator, GR is also available in SyMBA. - --------------- - -Simulation Parameter FAQs and Recommendations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**How do I know what timestep to use for my simulation -(**\ ``dt``\ **)?** - -A good rule is to set ``dt`` equal to one tenth the orbit of the -inner-most body in your simulation. For example, if Mercury is your -inner-most body, ``dt`` should be set to one tenth Mercury’s orbit. -Mercury’s orbit is ~0.24 years (~88 days) so a timestep of 0.024 years -should be sufficiently small to accurately model the orbit of Mercury. -You can always go smaller to increase resolution. - -**How often should I output (**\ ``ISTEP_OUT`` or ``TSTEP_OUT``, **and** -``DUMP_CADENCE``\ **)?** - -Depending on your simulation, you may want to write to the output file -more or less frequently. Writing takes a considerable amount of -computational time, so it is important to set a output cadence that is -manageable. Conversely, storing data in memory may not be reasonable for -all simulation configurations or hardware, so writing more frequently -may be necessary. There is no hard and fast rule for how often you -should output, however it is dependent on your total simulation length -(``tmax``) and your timestep (``dt``). Think of ``ISTEP_OUT`` as the -number of timesteps between writing to memory (or, alternatively with -``TSTEP_OUT``, the length of time between writing to memory), and -``DUMP_CADENCE`` as the number of write to memory operations between -writing to file. - -For example, an appropriate output cadence for a run with a timestep of -0.005 years and a total simulation length of 100 My might be -``ISTEP_OUT = 2e5`` (``TSTEP_OUT = 1e3``) and ``DUMP_CADENCE = 10``. -This means that data will be stores to memory every 2e5 timesteps and -written to file every 2e6 timesteps. Based on our value of ``dt``, this -is every 1,000 years and every 10,000 years, respectively. Our total -simulation length tells us that we will write to file 10,000 times over -the course of the simulation. For longer simulations, the output cadence -may be less frequent to save computational space. For shorter -simulations, the output cadence may be more frequent to increase -resolution. - -**What mass threshold should I set to differentiate fully-interactive -and semi-interactive bodies (**\ ``GMTINY`` **or** ``MTINY``\ **)?** - -Semi-interacting bodies are useful because the integrator is not -required to calculate gravitational interactions between pairs of -semi-interacting particles. This can result in significant performance -improvements, especially for systems that require hundreds or thousands -of massive bodies. If your system only has a few tens of massive bodies, -semi-interacting bodies may not be necessary. If you would like to -differentiate between these two classes of bodies, simply set the mass -threshold to be some value between the mass of the smallest -fully-interacting body and the mass of the largest semi-interacting body -that you choose. Semi-interacting bodies can collide with each other and -grow to become fully interacting bodies once they pass the mass -threshold. - -**What should minimum fragment mass should I use (**\ ``MIN_GMFRAG`` -**or** ``MIN_MFRAG``\ **)?** - -This mass threshold is necessary to ensure that Swiftest SyMBA does not -generate huge amounts of very small fragments, grinding the model to a -halt. While this value is largely empirical and dependent on each -specific set of initial conditions, a good place to start is to set the -minimum fragment mass threshold to be one tenth the size of the smallest -body in your simulation. You can also adjust ``FRAG_REDUCTION`` to keep -the number of fragments within a reasonable range. - -**What are the limits of Swiftest SyMBA?** - -While Swiftest SyMBA is a powerful tool for modeling gravitational -interactions between massive bodies, it does have its limits. Swiftest -SyMBA is best used for systems containing tens to hundreds of -fully-interacting massive bodies. It is also best used for timescales on -the order of a few hundred million years or less. While it is possible -to model systems on a billion year timescale, the computational power -required may be beyond what is available to the average user. In these -cases, it is recommended that the user consider modeling with test -particles instead of massive bodies. For systems that contain mainly -test particles, with few to no close encounters between massive bodies, -Swiftest RMVS is likely a more appropriate tool. - -To get a sense of the scope of your desired simulation, it is -recommended that you run your initial conditions and parameters for a -just few steps. Make sure that you set ``ISTEP_OUT`` and -``DUMP_CADENCE`` to output only once the simulation is complete, not -between steps. Because writing to the output files and memory takes a -significant amount of computational time compared to integrating the -step, we want to avoid counting writing time in our diagnostic -information. The terminal output contains information about the total -wall time and the wall time per integration step. To get a sense of how -long your run will take to complete your desired ``tmax``, simply scale -up the wall time per integration step to the number of steps necessary -for ``tmax`` to be reached. Remember that writing to the output files -will take a considerable amount of time. Adjust your initial conditions -and parameters accordingly. - --------------- - -References -~~~~~~~~~~ - -- Angeletti, M., Bonny, J. -M., and Koko, J. (2019). Parallel Euclidean - distance matrix computation on big datasets. **HAL**. `HAL Id: - hal-02047514 `__ -- Duncan, M. J., Levison, H. F., and Lee, M. H. (1998). A Multiple Time - Step Symplectic Algorithm for Integrating Close Encounters. **The - Astronomical Journal**, 116, 2067. `doi: - 10.1086/300541 `__ -- Chambers, J. E. (2013). Late-Stage Planetary Accretion Including - Hit-and-Run Collisions and Fragmentation. **Icarus**, 224. `doi: - 10.1016/j.icarus.2013.02.015 `__ -- Ericson, C. (2005) Real-Time Collision Detection. **Elsevier Inc.** - `ISBN: - 978-1-55860-732-3 `__ -- Leinhardt, Z. M. and Stewart, S. T. (2012). Collisions between - Gravity-dominated Bodies. I. Outcome Regimes and Scaling Laws. **The - Astrophysical Journal**, 745, 79. - `doi:10.1088/0004-637X/745/1/79 `__ -- Levison, H. F. and Duncan, M. J. (1994). The Long-Term Behavior of - Short-Period Comets. **Icarus**, 108, 18. `doi: - 10.1006/icar.1994.1039 `__ -- Wisdom, J. and Holman, M. (1991). Symplectic maps for the N-body - problem. **The Astronomical Journal**, 102. `doi: - 0.1086/115978 `__ -- Wishard et al. (2023) - Swiftest: An *N*-body Integrator for - Gravitational Systems. **Journal of Open Source Software**, 8(90), 5409, - `https://doi.org/10.21105/joss.05409 `__ - --------------- - -Community Guidelines -~~~~~~~~~~~~~~~~~~~~ - -**Contributing to Swiftest** Swiftest is open source and can be freely -accessed through our `GitHub -page `__. If you -wish to make a change and have that change incorporated into the -published version of Swiftest, please issue a pull request. If you wish -to edit Swiftest for your own personal use, no pull request is -necessary. - -**Reporting an Issue** If you stumble upon a bug or issue with the -functionality of Swiftest, we want to hear about it! If you have a fix -for this bug, please issue a pull request. If you do not have a fix for -the bug and would like to report it, please contact the Purdue Swiftest -Team via email (cwishard@purdue.edu). - -**User Support** For help using Swiftest, please contact the Purdue -Swiftest Team via email (cwishard@purdue.edu). - --------------- - -Licensing Agreement -~~~~~~~~~~~~~~~~~~~ - -Swiftest is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation, either version 3 of the License, or (at your -option) any later version. - -Swiftest is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along -with Swiftest. If not, see https://www.gnu.org/licenses/. - -.. |SyMBA General Relativity| image:: ../_static/symba_gr.png .. toctree:: diff --git a/pyproject.toml b/pyproject.toml index 1ada4eedf..417acd3cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,7 +136,7 @@ CMAKE_INSTALL_LIBDIR="lib" [tool.cibuildwheel.linux] skip = "cp312-* pp* -manylinux_i686* *-musllinux*" before-all = [ - "yum install doxygen libxml2-devel libcurl-devel -y", + "yum install libxml2-devel libcurl-devel -y", "buildscripts/build_dependencies.sh -p /usr/local" ] From 8d5f513bced332337979cca97ac1b48588576db9 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 17:14:27 -0500 Subject: [PATCH 294/324] Added a detailed simulation setup and a basic --- docs/user-guide/basic-simulation/index.rst | 98 ++--------- .../detailed-simulation-setup/index.rst | 165 ++++++++++++++++++ docs/user-guide/index.rst | 3 + 3 files changed, 181 insertions(+), 85 deletions(-) create mode 100644 docs/user-guide/detailed-simulation-setup/index.rst diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 62b332786..5d2945f33 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -13,17 +13,10 @@ Start with importing Swiftest and other packages we will use in this tutorial. : Initial Simulation Setup =========================== -Create a Swiftest Simulation object and clean the simulation directory of any previous Swiftest objects, if any. +Create a Swiftest Simulation object. Outputs are stored in the ``/simdata`` directory by default. :: sim = swiftest.Simulation() - sim.clean() - -An optional argument can be passed to specify the simulation directory :: - - simdir = '/path/to/simdir' - sim = swiftest.Simulation(simdir=simdir) - sim.clean() Now that we have a simulation object set up (with default parameters), we can add bodies to the simulation. The biggest body in the simulation is taken as the central body. @@ -37,91 +30,26 @@ This method uses JPL Horizons to extract the parameters. :: # Add the modern planets and the Sun using the JPL Horizons Database. sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) -We can add other small bodies too. :: +Add other small bodies too: :: # Add in some main belt asteroids sim.add_solar_system_body(name=["Ceres","Vesta","Pallas","Hygiea"],id_type="smallbody") - # Add in some big KBOs - sim.add_solar_system_body(name=["Pluto","Eris","Haumea","Quaoar"]) - - # Add in some Centaurs - sim.add_solar_system_body(name=["Chiron","Chariklo"]) - -User Defined Bodies -========================= - -For completeness, let's also add some bodies with user defined parameters using ``sim.add_body()``. -We will randomize the initial conditions and therefore import the ``numpy.random`` module.:: - - from numpy.random import default_rng - rng = default_rng(seed=123) - -Starting with massive bodies: :: - - npl = 5 # number of massive bodies - density_pl = 3000.0 / (sim.param['MU2KG'] / sim.param['DU2M'] ** 3) - name_pl = ["SemiBody_01", "SemiBody_02", "SemiBody_03", "SemiBody_04", "SemiBody_05"] - - M_pl = np.array([6e20, 8e20, 1e21, 3e21, 5e21]) * sim.KG2MU # mass in simulation units - R_pl = np.full(npl, (3 * M_pl/ (4 * np.pi * density_pl)) ** (1.0 / 3.0)) # radius - Ip_pl = np.full((npl,3),0.4,) # moment of inertia - rot_pl = np.zeros((npl,3)) # initial rotation vector in degrees/TU - mtiny = 1.1 * np.max(M_pl) # threshold mass for semi-interacting bodies in SyMBA. - -Depending on the simulation parameters, we can add bodies with Orbital Elements or Cartesian Coordinates. - -Orbital Elements -------------------- - -Initialize orbital elements and then add the bodies. :: - - a_pl = rng.uniform(0.3, 1.5, npl) # semi-major axis - e_pl = rng.uniform(0.0, 0.2, npl) # eccentricity - inc_pl = rng.uniform(0.0, 10, npl) # inclination (degrees) - capom_pl = rng.uniform(0.0, 360.0, npl) # longitude of the ascending node - omega_pl = rng.uniform(0.0, 360.0, npl) # argument of periapsis - capm_pl = rng.uniform(0.0, 360.0, npl) # mean anomaly - - sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) - -Cartesian Coordinates ----------------------- - -The process is similar for adding bodies with Cartesian coordinates. Start by defining the position and velocity vectors. -Here we define the orbital velocities and scale them by a random value. :: - - # position vectors - rh_pl = rng.uniform(-5, 5, (npl,3)) - rh_pl_mag = np.linalg.norm(rh_pl, axis=1) # magnitudes of the position vector - - # General velocity vectors - - # define the magnitudes - velocity_scale = rng.uniform(0.5, 1.5, npl) # scale the orbital velocity - vh_pl_mag = velocity_scale * np.sqrt(sim.GU * M_pl / rh_pl_mag) # magnitude of the velocity vector - - # initialize the vectors using the position vectors - vx = rh_pl.T[0] * vh_pl_mag / rh_pl_mag - vy = rh_pl.T[1] * vh_pl_mag / rh_pl_mag - vz = rh_pl.T[2] * vh_pl_mag / rh_pl_mag - - # rotate the velocity vectors to the XY plane for orbital motion - vh_pl = np.array([vx, vy, vz]).T - vh_pl = np.cross(vh_pl, np.array([0,0,1])) # velocity vectors - - sim.add_body(name=name_pl, rh=rh_pl, vh=vh_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) - - - -Customising Simulation Parameters -================================== - -The user can also specify simulation parameters when creating the Swiftest object as defined in <>, but we will come back to this later. + # Add in some big KBOs and Centaurs + sim.add_solar_system_body(name=["Pluto","Eris","Haumea","Quaoar", "Chiron","Chariklo"]) +Running the Simulation +======================== +We now set up the simulation parameters. Here we have a simulation starting from :math: `0.0 y` and running for :math: `1 My = 1e6 years` +with time steps of :math: `0.01 years`. :: + sim.set_parameter(tstart=0.0, tstop=1.0e6, dt=0.01) + +Once everything is set up, we can save the simulation object and then run it: :: + sim.save() + sim.run() .. .. toctree:: .. :maxdepth: 2 diff --git a/docs/user-guide/detailed-simulation-setup/index.rst b/docs/user-guide/detailed-simulation-setup/index.rst new file mode 100644 index 000000000..cde59a13b --- /dev/null +++ b/docs/user-guide/detailed-simulation-setup/index.rst @@ -0,0 +1,165 @@ +################# +Basic Simulation +################# + +Here, we will walk you through the basic features of Swiftest and using them in Python. +This is based on ``/Basic_Simulation`` in ``swiftest/examples``. + +Start with importing Swiftest and other packages we will use in this tutorial. :: + + import swiftest + import numpy as np + +Initial Simulation Setup +=========================== + +Create a Swiftest Simulation object and clean the simulation directory of any previous Swiftest objects, if any. +Outputs are stored in the ``/simdata`` directory by default. :: + + sim = swiftest.Simulation() + sim.clean() + +An optional argument can be passed to specify the simulation directory :: + + simdir = '/path/to/simdir' + sim = swiftest.Simulation(simdir=simdir) + sim.clean() + +Now that we have a simulation object set up (with default parameters), we can add bodies to the simulation. +The biggest body in the simulation is taken as the central body. + +Solar System Bodies +========================= + +We can add solar system bodies to the simulation using the ``add_solar_system_body`` method. +This method uses JPL Horizons to extract the parameters. :: + + # Add the modern planets and the Sun using the JPL Horizons Database. + sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) + +We can add other small bodies too. :: + + # Add in some main belt asteroids + sim.add_solar_system_body(name=["Ceres","Vesta","Pallas","Hygiea"],id_type="smallbody") + + # Add in some big KBOs + sim.add_solar_system_body(name=["Pluto","Eris","Haumea","Quaoar"]) + + # Add in some Centaurs + sim.add_solar_system_body(name=["Chiron","Chariklo"]) + +User Defined Bodies +========================= + +For completeness, let's also add some bodies with user defined parameters using ``sim.add_body()``. +We will randomize the initial conditions and therefore import the ``numpy.random`` module.:: + + from numpy.random import default_rng + rng = default_rng(seed=123) + +Starting with **massive bodies:** :: + + npl = 5 # number of massive bodies + density_pl = 3000.0 / (sim.param['MU2KG'] / sim.param['DU2M'] ** 3) + name_pl = ["SemiBody_01", "SemiBody_02", "SemiBody_03", "SemiBody_04", "SemiBody_05"] + + M_pl = np.array([6e20, 8e20, 1e21, 3e21, 5e21]) * sim.KG2MU # mass in simulation units + R_pl = np.full(npl, (3 * M_pl/ (4 * np.pi * density_pl)) ** (1.0 / 3.0)) # radius + Ip_pl = np.full((npl,3),0.4,) # moment of inertia + rot_pl = np.zeros((npl,3)) # initial rotation vector in degrees/TU + mtiny = 1.1 * np.max(M_pl) # threshold mass for semi-interacting bodies in SyMBA. + +Depending on the simulation parameters, we can add bodies with Orbital Elements or Cartesian Coordinates. + +Orbital Elements +------------------- + +Initialize orbital elements and then add the bodies. :: + + a_pl = rng.uniform(0.3, 1.5, npl) # semi-major axis + e_pl = rng.uniform(0.0, 0.2, npl) # eccentricity + inc_pl = rng.uniform(0.0, 10, npl) # inclination (degrees) + capom_pl = rng.uniform(0.0, 360.0, npl) # longitude of the ascending node + omega_pl = rng.uniform(0.0, 360.0, npl) # argument of periapsis + capm_pl = rng.uniform(0.0, 360.0, npl) # mean anomaly + + sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + +Cartesian Coordinates +---------------------- + +The process is similar for adding bodies with Cartesian coordinates. However, the parameter `init_cond_format` must be set to `XV` before adding the bodies. +The process of setting parameters is explained in the next section. +Start by defining the position and velocity vectors. Here we define the orbital velocities and scale them by a random value. :: + + # position vectors + rh_pl = rng.uniform(-5, 5, (npl,3)) + rh_pl_mag = np.linalg.norm(rh_pl, axis=1) # magnitudes of the position vector + + # General velocity vectors + + # define the magnitudes + velocity_scale = rng.uniform(0.5, 1.5, npl) # scale the orbital velocity + vh_pl_mag = velocity_scale * np.sqrt(sim.GU * M_pl / rh_pl_mag) # magnitude of the velocity vector + + # initialize the vectors using the position vectors + vx = rh_pl.T[0] * vh_pl_mag / rh_pl_mag + vy = rh_pl.T[1] * vh_pl_mag / rh_pl_mag + vz = rh_pl.T[2] * vh_pl_mag / rh_pl_mag + + # rotate the velocity vectors to the XY plane for orbital motion + vh_pl = np.array([vx, vy, vz]).T + vh_pl = np.cross(vh_pl, np.array([0,0,1])) # velocity vectors + + sim.add_body(name=name_pl, rh=rh_pl, vh=vh_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + +The process is similar for **test particles**. The only difference is to exclude ``mass`` and ``radius``. +Here is an example with orbital elements: :: + + # Add 10 user-defined test particles. + ntp = 10 + + name_tp = ["TestParticle_01", "TestParticle_02", "TestParticle_03", "TestParticle_04", "TestParticle_05", "TestParticle_06", "TestParticle_07", "TestParticle_08", "TestParticle_09", "TestParticle_10"] + a_tp = rng.uniform(0.3, 1.5, ntp) + e_tp = rng.uniform(0.0, 0.2, ntp) + inc_tp = rng.uniform(0.0, 10, ntp) + capom_tp = rng.uniform(0.0, 360.0, ntp) + omega_tp = rng.uniform(0.0, 360.0, ntp) + capm_tp = rng.uniform(0.0, 360.0, ntp) + + sim.add_body(name=name_tp, a=a_tp, e=e_tp, inc=inc_tp, capom=capom_tp, omega=omega_tp, capm=capm_tp) + + +Customising Simulation Parameters +================================== + +Now that we have added the bodies, we can set the simulation parameters. ``tstop`` and ``dt`` need to be set before running the simulation. +This can be done in multiple ways: + +- When creating the initial Swiftest simulation object :: + + sim = swiftest.Simulation(simdir = simdir, integrator = 'symba', init_cond_format = 'EL', tstart=0.0, tstop=1.0e6, dt=0.01, + istep_out=100, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) + +- ``sim.set_parameter()``: Set individual parameters in the simulation. The user can set one or multiple at a time. :: + + sim.set_parameter(tstart=0.0, tstop=1.0e6, dt=0.01, istep_out=100, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) + sim.set_parameter(rmin = 0.05) + +We now set up the simulation parameters. Here we have a simulation starting from :math: `0.0 y` and running for :math: `1 My = 1e6 years` +with time steps of :math: `0.01 years`. The timestep should be less than or equal to :math: `\frac{1}{10}` of the orbital period of the innermost body. + +The user can then write the parameters to the `param.in` file by using ``sim.write_param()``. +To see the parameters of the simulation, use ``sim.get_parameter()``. + +Running the Simulation +======================== + +Once everything is set up, we can save the simulation object and then run it: :: + + sim.save() + sim.run() + +.. .. toctree:: +.. :maxdepth: 2 +.. :hidden: diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index cc1e39360..012ad150a 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -6,6 +6,8 @@ In this user guide, you will find detailed descriptions and examples that descri Basic Simulation +Detailed Simulation Setup + Spherical Harmonics .. toctree:: @@ -13,4 +15,5 @@ Spherical Harmonics :hidden: Basic Simulation + Detailed Simulation Setup Spherical Harmonics \ No newline at end of file From 7df24033ccd2aae9af2a2525a8685dc27447944e Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 17:15:17 -0500 Subject: [PATCH 295/324] Fixed typos --- docs/user-guide/basic-simulation/index.rst | 3 +-- docs/user-guide/detailed-simulation-setup/index.rst | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 5d2945f33..6c7a6238b 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -8,7 +8,6 @@ This is based on ``/Basic_Simulation`` in ``swiftest/examples``. Start with importing Swiftest and other packages we will use in this tutorial. :: import swiftest - import numpy as np Initial Simulation Setup =========================== @@ -43,7 +42,7 @@ Running the Simulation We now set up the simulation parameters. Here we have a simulation starting from :math: `0.0 y` and running for :math: `1 My = 1e6 years` with time steps of :math: `0.01 years`. :: - + sim.set_parameter(tstart=0.0, tstop=1.0e6, dt=0.01) Once everything is set up, we can save the simulation object and then run it: :: diff --git a/docs/user-guide/detailed-simulation-setup/index.rst b/docs/user-guide/detailed-simulation-setup/index.rst index cde59a13b..7e3438df4 100644 --- a/docs/user-guide/detailed-simulation-setup/index.rst +++ b/docs/user-guide/detailed-simulation-setup/index.rst @@ -1,5 +1,5 @@ ################# -Basic Simulation +Detailed Simulation ################# Here, we will walk you through the basic features of Swiftest and using them in Python. From 403c5be0492218ba9eef1008a4b2583cdaf9ba46 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 17:16:06 -0500 Subject: [PATCH 296/324] Title line sectioning too short --- docs/user-guide/detailed-simulation-setup/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user-guide/detailed-simulation-setup/index.rst b/docs/user-guide/detailed-simulation-setup/index.rst index 7e3438df4..16226894e 100644 --- a/docs/user-guide/detailed-simulation-setup/index.rst +++ b/docs/user-guide/detailed-simulation-setup/index.rst @@ -1,6 +1,6 @@ -################# +##################### Detailed Simulation -################# +##################### Here, we will walk you through the basic features of Swiftest and using them in Python. This is based on ``/Basic_Simulation`` in ``swiftest/examples``. From 6eeb6c893f370b4a7b0fc53494ec411c74d625f1 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 17:19:07 -0500 Subject: [PATCH 297/324] Fixed formatting for latex math --- docs/user-guide/basic-simulation/index.rst | 6 +++--- docs/user-guide/detailed-simulation-setup/index.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 6c7a6238b..940c62138 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -5,7 +5,7 @@ Basic Simulation Here, we will walk you through the basic features of Swiftest and using them in Python. This is based on ``/Basic_Simulation`` in ``swiftest/examples``. -Start with importing Swiftest and other packages we will use in this tutorial. :: +Start with importing Swiftest. :: import swiftest @@ -40,8 +40,8 @@ Add other small bodies too: :: Running the Simulation ======================== -We now set up the simulation parameters. Here we have a simulation starting from :math: `0.0 y` and running for :math: `1 My = 1e6 years` -with time steps of :math: `0.01 years`. :: +We now set up the simulation parameters. Here we have a simulation starting from `0.0 y` and running for `1 My = 1e6 years` +with time steps of `0.01 years`. :: sim.set_parameter(tstart=0.0, tstop=1.0e6, dt=0.01) diff --git a/docs/user-guide/detailed-simulation-setup/index.rst b/docs/user-guide/detailed-simulation-setup/index.rst index 16226894e..d5212ffbd 100644 --- a/docs/user-guide/detailed-simulation-setup/index.rst +++ b/docs/user-guide/detailed-simulation-setup/index.rst @@ -146,8 +146,8 @@ This can be done in multiple ways: sim.set_parameter(tstart=0.0, tstop=1.0e6, dt=0.01, istep_out=100, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) sim.set_parameter(rmin = 0.05) -We now set up the simulation parameters. Here we have a simulation starting from :math: `0.0 y` and running for :math: `1 My = 1e6 years` -with time steps of :math: `0.01 years`. The timestep should be less than or equal to :math: `\frac{1}{10}` of the orbital period of the innermost body. +We now set up the simulation parameters. Here we have a simulation starting from `0.0 y` and running for `1 My = 1e6 years` +with time steps of `0.01 years`. The timestep should be less than or equal to 1/10 of the orbital period of the innermost body. The user can then write the parameters to the `param.in` file by using ``sim.write_param()``. To see the parameters of the simulation, use ``sim.get_parameter()``. From d29693cfd667c1bf1f345db75ed03f1a3f560210 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 17:22:04 -0500 Subject: [PATCH 298/324] Edited User guide. Testing --- docs/user-guide/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index 012ad150a..a50fdb8d5 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -4,11 +4,11 @@ User Guide In this user guide, you will find detailed descriptions and examples that describe the many capabilities of Swiftest and how to use them. -Basic Simulation +- Setting up a Basic Simulation -Detailed Simulation Setup +- A more Detailed Simulation Setup -Spherical Harmonics +- Understanding the Spherical Harmonics capabilities .. toctree:: :maxdepth: 2 From 93fdf979c4b0cd1ed48c3a2212c50d416cd6d3a4 Mon Sep 17 00:00:00 2001 From: anand43 Date: Thu, 29 Feb 2024 17:29:42 -0500 Subject: [PATCH 299/324] Added doc links to the user guide --- docs/user-guide/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index a50fdb8d5..f3a941582 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -4,11 +4,11 @@ User Guide In this user guide, you will find detailed descriptions and examples that describe the many capabilities of Swiftest and how to use them. -- Setting up a Basic Simulation +- Setting up a :doc:`Basic Simulation ` -- A more Detailed Simulation Setup +- A more in-depth :doc:`Detailed Simulation Setup ` -- Understanding the Spherical Harmonics capabilities +- Understanding the :doc:`Spherical Harmonics capabilities ` .. toctree:: :maxdepth: 2 From 257464b30003f846d3008d82dabbe413a91afa13 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:03:47 -0500 Subject: [PATCH 300/324] Fixed some mismatches in the api documentation --- docs/api.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index 0e757b398..604bc0553 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -69,6 +69,7 @@ Adding Bodies to a Simulation Simulation.add_body Simulation.add_solar_system_body + Simulation.set_central_body File Input and Output @@ -82,8 +83,8 @@ File Input and Output Simulation.read_encounter_file Simulation.read_collision_file Simulation.follow + Simulation.initial_conditions_from_data Simulation.save - Simulation.initial_conditions_from_bin Simulation.convert Simulation.clean From b86e29702d2b210cdc0569bad060b320ebabbf22 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:09:19 -0500 Subject: [PATCH 301/324] Removed the Docker instructions until they can be cleaned up --- docs/getting-started-guide/index.rst | 74 +--------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 514b5ffdb..790e0d231 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -203,79 +203,7 @@ You may need to run the above command as root or with sudo if you are installing Building the exectuable using Docker ------------------------------------ -The Swiftest project contains a Dockerfile -that may be used to generate an executable without needing to provide -any external dependencies, other than the Docker engine itself (see -`here `__ for instructions on -obtaining Docker). Once Docker is installed and the Docker engine is -running, execute:: - - $ docker build --target=export-driver \ - --output=./bin \ - --build-arg MACHINE_CODE_VALUE="Host" \ - [ -f Dockerfile.GNU-Linux | -f Dockerfile.Intel ] \ - [ --build-arg BUILD_TYPE="*RELEASE*|DEBUG|TESTING|PROFILE" ] \ - [ --build-arg EXTRA_CMAKE_OPTIONS="-D" ] . - -The Docker build will download and compile all of the library -dependencies (HDF5, NetCDF-C, and NetCDF-Fortran) as static libraries -and the Swiftest driver using Intel compilers. Once completed, the -Swiftest executable, called ``swiftest_driver``, should now be created -in the ``bin/`` directory. - - Note: The Dockerfile is designed to build an executable that is - compatible with a broad range of CPU architectures by specifying the - SSE2 instruction as a target for SIMD instructions using the ``-x`` - compiler option. When compiling on the same CPU archictecture you - plan to execute the driver program, for the highest possible SIMD - performance, use - ``--build-arg MACHINE_CODE_VALUE="Host"`` to override the default ``MACHINE_CODE_VALUE=“SSE2”``. - For additional options see - `here `__. - -The optional Docker argument ``EXTRA_CMAKE_OPTIONS`` is provided to pass any additional CMake arguments (see `supported CMake options `_) - - -Download the executable as a Docker or Singularity container. -------------------------------------------------------------- - -The Swiftest driver is available as a Docker container on DockerHub in -two versions: Intel and GNU. The Intel version was compiled for the -x86_64 CPU using the Intel classic Fortran compiler. The GNU version was -compliled for the x86_64 CPU using gfortran. The Intel version is faster -than the GNU version (though not as fast as a native compile to the -target CPU that you wish to run it on due to vectorization optimizations -that Swiftest takes advantage of), however it is much larger: The Intel -version is ~2.7GB while the GNU version is ~300MB. The Singularity -container pulls from the same DockerHub container. - -To facilitate installation of the container, we provide a set of shell -scripts to help automate the process of installing container versions of -the executable. To install the default Intel version of the docker -container from within the ``swiftest\`` project directory:: - - $ cd docker - $ . ./install.sh - -To install the GNU version:: - - $ cd docker - $ . ./install.sh gnu - -The Singularity versions are installed the same way, just replace -``cd docker`` with ``cd singularity`` above. - -Whether installing either the Docker or Singularity containers, the -install script will copy an executable shell script ``swiftest_driver`` -into ``swiftest/bin/``. Not that when installing the Singularity -container, the install script will set an environment variable called -``SWIFTEST_SIF`` that must point to the aboslute path of the container -file called ``swiftest_driver.sif``. To use the driver script in a -future shell, rather than running the install script again, we suggest -adding the environment variable definition to your shell startup script -(e.g. add -``export SWIFTEST_SIF="/path/to/swiftest/singularity/swiftest.sif"`` to -your ``.zshrc``) +TBD From 6451ada41e7575a06711e14fb6fe1423997a0769 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:11:58 -0500 Subject: [PATCH 302/324] Got rid of flag that was causing the warning when building the docs --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 803b51e0e..9e41b7474 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -68,7 +68,7 @@ html: .PHONY: rtdhtml rtdhtml: - $(SPHINXBUILD) -T -j auto -E -W --keep-going -b html -d $(BUILDDIR)/doctrees -D language=en . $(BUILDDIR)/html + $(SPHINXBUILD) -T -E -W --keep-going -b html -d $(BUILDDIR)/doctrees -D language=en . $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." From 7d5a216a379928e9e2303a17b0cb137fbb2273bd Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:12:27 -0500 Subject: [PATCH 303/324] Incremented the version number --- pyproject.toml | 2 +- src/globals/globals_module.f90 | 2 +- version.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0e754dc6b..aca1f0c2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "swiftest" -version = "2024.2.0" +version = "2024.3.0" authors=[ {name = 'David A. Minton', email='daminton@purdue.edu'}, {name = 'Carlisle Wishard'}, diff --git a/src/globals/globals_module.f90 b/src/globals/globals_module.f90 index c17d6a2eb..0507b0bcb 100644 --- a/src/globals/globals_module.f90 +++ b/src/globals/globals_module.f90 @@ -48,7 +48,7 @@ module globals integer(I4B), parameter :: UPPERCASE_OFFSET = iachar('A') - iachar('a') !! ASCII character set parameter for lower to upper !! conversion - offset between upper and lower - character(*), parameter :: VERSION = "2024.2.0" !! Swiftest version + character(*), parameter :: VERSION = "2024.3.0" !! Swiftest version !> Symbolic name for integrator types character(*), parameter :: UNKNOWN_INTEGRATOR = "UKNOWN INTEGRATOR" diff --git a/version.txt b/version.txt index 032892e0c..b6503254e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2024.2.0 \ No newline at end of file +2024.3.0 \ No newline at end of file From aee556c7927dfb06bdb6753f8198426ffff8beb3 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:19:25 -0500 Subject: [PATCH 304/324] Rearranged some of the documentation pages --- docs/getting-started-guide/index.rst | 23 +++++++++++++++++++++++ docs/index.rst | 21 ++------------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/docs/getting-started-guide/index.rst b/docs/getting-started-guide/index.rst index 790e0d231..66fca89e4 100644 --- a/docs/getting-started-guide/index.rst +++ b/docs/getting-started-guide/index.rst @@ -4,6 +4,29 @@ Getting Started =============== +Swiftest is a re-write of the `Swifter `__ software package that incorporates modern programming techniques and performance +improvements. Swiftest contains the following numerical integrators: + +- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. + See `Wisdom & Holman (1991) `__. +- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of WHM that is capable of handling close encounters between test + particles and massive bodies. See `Levison & Duncan (1994) `__. +- **Democratic Heliocentric (HELIO)** - A symplectic integrator that uses the democratic heliocentric coordinate frame. See +- `Duncan, Levison, & Lee (1998) `__. +- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO that is capable of handling close encounters between massive bodies. + See `Duncan, Levison, & Lee (1998) `__. + +Swiftest also includes the collisional fragmentation algorithm *Fraggle*, which can be used to model collisional fragmentation when using the SyMBA integrator. +Fraggle is designed to resolve collisions between massive bodies by determining the collisional regime, derived from the work of `Leinhardt & Stewart +(2012) `__, and generating the appropriate mass distribution of fragments. Swiftest +fully incorporates collisional fragments into the gravitational system, evolving these new bodies along with pre-existing bodies, including +their growth and any future fragmentation events in which they are involved. + +Swiftest is written in Modern Fortran and is designed to be run from Python. The Python package provides a set of tools for generating +initial conditions, running simulations, and processing output data. Swiftest can also be run from the command line using the ``swiftest_driver`` executable, +provided that initial conditions and configuration files are available in the path. + + Installation ------------ diff --git a/docs/index.rst b/docs/index.rst index ed9cb22ac..a7e43d04d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,25 +3,8 @@ Swiftest ======== -Swiftest is a software packaged designed to model the dynamical evolution of gravitational systems. Swiftest is a re-write of the -`Swifter `__ software package that incorporates modern programming techniques and performance -improvements. -Swiftest contains the following numerical integrators: - -- **Wisdom-Holman Mapping (WHM)** - A symplectic n-body mapping method. - See `Wisdom & Holman (1991) `__. -- **Regularized Mixed Variable Symplectic (RMVS)** - An extension of WHM that is capable of handling close encounters between test - particles and massive bodies. See `Levison & Duncan (1994) `__. -- **Democratic Heliocentric (HELIO)** - A symplectic integrator that uses the democratic heliocentric coordinate frame. See -- `Duncan, Levison, & Lee (1998) `__. -- **Symplectic Massive Body Algorithm (SyMBA)** - An extension of HELIO that is capable of handling close encounters between massive bodies. - See `Duncan, Levison, & Lee (1998) `__. - -Swiftest also includes the collisional fragmentation algorithm **Fraggle**, an addition to the SyMBA integrator. Fraggle is designed to -resolve collisions between massive bodies by determining the collisional regime, derived from the work of `Leinhardt & Stewart -(2012) `__, and generating the appropriate mass distribution of fragments. Swiftest -fully incorporates collisional fragments into the gravitational system, evolving these new bodies along with pre-existing bodies, including -their growth and any future fragmentation events in which they are involved. +Swiftest is a software packaged designed to model the long-term dynamical dynamics of n-body systems with a dominant central body, +like the solar system. **Useful links**: From dce3582f53e38fd0babfd35634c7dd325c5ae30f Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:25:28 -0500 Subject: [PATCH 305/324] Turned a method name into a link to the API page of the method. --- docs/user-guide/basic-simulation/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 940c62138..f5e888c91 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -13,7 +13,7 @@ Initial Simulation Setup =========================== Create a Swiftest Simulation object. -Outputs are stored in the ``/simdata`` directory by default. :: +Outputs are stored in the ``./simdata`` directory by default. :: sim = swiftest.Simulation() @@ -23,7 +23,7 @@ The biggest body in the simulation is taken as the central body. Solar System Bodies ========================= -We can add solar system bodies to the simulation using the ``add_solar_system_body`` method. +We can add solar system bodies to the simulation using the :func:`add_solar_system_body ` method. This method uses JPL Horizons to extract the parameters. :: # Add the modern planets and the Sun using the JPL Horizons Database. From 8dda11f3d1049be23145ab616f9ab780658df4a3 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 29 Feb 2024 19:45:41 -0500 Subject: [PATCH 306/324] Cleaned up the basic simulation example page a bit --- docs/user-guide/basic-simulation/index.rst | 38 ++++++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index f5e888c91..0d37f808d 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -12,13 +12,14 @@ Start with importing Swiftest. :: Initial Simulation Setup =========================== -Create a Swiftest Simulation object. +Create a Swiftest :class:`Simulation ` object. Outputs are stored in the ``./simdata`` directory by default. :: sim = swiftest.Simulation() Now that we have a simulation object set up (with default parameters), we can add bodies to the simulation. -The biggest body in the simulation is taken as the central body. +The biggest body in the simulation is taken as the central body. Swiftest sets a Simulation object up with a set of default parameters, +including a default unit system of AU, y, and solar masses. Solar System Bodies ========================= @@ -40,16 +41,39 @@ Add other small bodies too: :: Running the Simulation ======================== -We now set up the simulation parameters. Here we have a simulation starting from `0.0 y` and running for `1 My = 1e6 years` -with time steps of `0.01 years`. :: +We now can some simulation parameters using the :func:`set_parameter ` method. +Here we have a simulation that runs for 1 My a step size of 0.01 y. We will also save the system every 1000 y and wait until the end of the simulation to write the simulation data to file using the ``dump_cadence=0`` argument :: - sim.set_parameter(tstart=0.0, tstop=1.0e6, dt=0.01) + sim.set_parameter(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) -Once everything is set up, we can save the simulation object and then run it: :: +Once everything is set up, we call the :func:`run ` method to integrate the system forward in time:: - sim.save() sim.run() +Swiftest is relatively flexible with arguments. You can pass the parameters in when initializing the simulation object, or even later when running. +So the following are all equivalent:: + + sim = swiftest.Simulation(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) + sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) + sim.run() + + sim = swiftest.Simulation() + sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) + sim.set_parameter(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) + sim.run() + + sim = swiftest.Simulation() + sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) + sim.run(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) + + +Analayzing Simulation Output +============================= + +Once a simulation has been run, its output data is stored in the ``./simdata`` directory. The main data is stored in a file with a +default name of ``data.nc``, which is a netCDF file. It is read in and stored as an `Xarray Dataset `__ object in the ``sim.data`` attribute. + + .. .. toctree:: .. :maxdepth: 2 .. :hidden: From 66f1d2d9cdc414672d544c66897149d9fe009a86 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 07:54:09 -0500 Subject: [PATCH 307/324] Revised the basic simulation user guide with more detail. --- docs/user-guide/basic-simulation/index.rst | 88 ++++++++++++++++++---- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 0d37f808d..4863764e8 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -3,7 +3,6 @@ Basic Simulation ################# Here, we will walk you through the basic features of Swiftest and using them in Python. -This is based on ``/Basic_Simulation`` in ``swiftest/examples``. Start with importing Swiftest. :: @@ -18,31 +17,78 @@ Outputs are stored in the ``./simdata`` directory by default. :: sim = swiftest.Simulation() Now that we have a simulation object set up (with default parameters), we can add bodies to the simulation. -The biggest body in the simulation is taken as the central body. Swiftest sets a Simulation object up with a set of default parameters, -including a default unit system of AU, y, and solar masses. +The biggest body in the simulation is taken as the central body. Solar System Bodies ========================= -We can add solar system bodies to the simulation using the :func:`add_solar_system_body ` method. -This method uses JPL Horizons to extract the parameters. :: +We can add solar system bodies to the simulation using the :func:`add_solar_system_body ` +method. This method uses JPL Horizons to extract the parameters. :: # Add the modern planets and the Sun using the JPL Horizons Database. sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) -Add other small bodies too: :: - - # Add in some main belt asteroids - sim.add_solar_system_body(name=["Ceres","Vesta","Pallas","Hygiea"],id_type="smallbody") - - # Add in some big KBOs and Centaurs - sim.add_solar_system_body(name=["Pluto","Eris","Haumea","Quaoar", "Chiron","Chariklo"]) Running the Simulation ======================== -We now can some simulation parameters using the :func:`set_parameter ` method. -Here we have a simulation that runs for 1 My a step size of 0.01 y. We will also save the system every 1000 y and wait until the end of the simulation to write the simulation data to file using the ``dump_cadence=0`` argument :: +Before we run the simulation, we need to set some parameters to control the total length and step size of an integration. Swiftest +sets a Simulation object up with a set of default parameters, including a default unit system of AU, y, and solar masses. However, +you are required to set the ``tstop`` and ``dt`` parameters before running the simulation. These control the total time of the +simulation and the time step size, respectively. + +.. note:: + The symplectic integrators used in Swiftest are not adaptive, so the time step size is fixed throughout the simulation. + Typically you want to choose a step size that is no more than 1/20th of the shortest orbital period in the system. So for the + solar system, a step size of 0.01 y is a good choice in order to accurately model Mercury's orbit. + +Another important consideration is the number of steps you wish to save and how often the output is saved to file (the output +cadence). By default, Swiftest will save every output step to disk. However, Swiftest is designed to simulate systems for long +periods of time, so it is often not practical to save every single time step to disk. There are three ways to control how many +steps are saved to file: ``tstep_out``, ``istep_out``, and ``nstep_out``. + +- ``istep_out``: This is the integer number of time steps between output saves to file, which can be used to control the output + cadence. For example, if you set ``istep_out=1000``, then the simulation will save the system every 1000 time steps. This is + useful if you want to save the system every N time steps, regardless of the time interval between steps. + +- ``tstep_out``: This is the approximate time interval between output steps. This is the most intuitive way to control the output + cadence. It is the time interval between each output step in the simulation. For example, if you set ``tstep_out=1e3``, then the + simulation will save the system every 1000 y. Internally, Swiftest uses the integer value ``istep_out`` to control the output + cadence, which is computed as:: + + istep_out = floor(tstep_out/dt) + + Only one of either ``tstep_out`` or ``istep_out`` should be set. + +- ``nstep_out``: The total number of times that outputs are written to file. Passing this allows for a geometric progression of + output steps, given by the following formula:: + + TSTART, f**0 * TSTEP_OUT, f**1 * TSTEP_OUT, f**2 * TSTEP_OUT, ..., f**(nstep_out-1) * TSTEP_OUT + + where ``f`` is a factor that can stretch (or shrink) the time between outputs. Setting:: + + nstep_out = int((tstart - tstop) / (tstep_out)) + + is equivalent to the standard linear output (i.e. ``f==1``) and is the same as not passing anything for this argument. + +Simulation data is stored in NetCDF format, which is a self-describing binary file format that is widely used in the scientific +community. However, writing to disk is a slow process, so writing to disk can be a bottleneck in the simulation. To mitigate this, +Swiftest has a ``dump_cadence`` parameter that controls how often the simulation data is written to disk. The integer value passed +to ``dump_cadence`` controls the number of output steps (as determined ``istep_out``) between when the saved data is dumped to a +file. The default value is 10, which means that Swiftest will store 10 outputs in memory before dumping them to file. +Setting ``dump_cadence`` to 0 is a a special case that tells Swiftest to store *all* output in memory until the end of the +simulation. This is useful for short simulations, but can be memory intensive for long simulations. + +The choice of what values to set for ``tstep_out`` (or ``istep_out``), ``nstep_out``, and ``dump_cadence`` depends on the particular +simulation. Higher values of ``dump_cadence`` are typically useful for simulations with small numbers of bodies and small values +of ```tstep_out`` where frequent writing to disk can severely impact performance. For simulations with large numbers of bodies and +larger values of ``tstep_out``, it is often better to set ``dump_cadence`` to a smaller value and write the data to disk more often +so that the memory usage does not become too large. The default value of ``dump_cadence`` of 10 is a good compromise for most use +caes. + +We can set these simulation parameters using the :func:`set_parameter ` method. +Here we have a simulation that runs for 1 My a step size of 0.01 y. We will also save the system every 1000 y and wait until the end +of the simulation to write the simulation data to file using the ``dump_cadence=0`` argument:: sim.set_parameter(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) @@ -66,12 +112,24 @@ So the following are all equivalent:: sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) sim.run(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) +.. note:: + Swiftest uses OpenMP parallelization to help speed up the integration, however the parallelization is most effective when there + are large numbers of bodies in the simulation. For small numbers of bodies, the overhead of parallelization can actually slow + the simulation down. The number of threads used by Swiftest can be controlled using the ``OMP_NUM_THREADS`` environment + variable. For example, to use 4 threads, you can set the environment variable using the following command in a Unix-like shell:: + + export OMP_NUM_THREADS=4 + + For our example simulation, which only includes the solar system, it is best to run the simulation with a single thread. We plan + to build in an adaptive thread control in the future, but for now, you must time your simulations and set the number of threads + manually. Analayzing Simulation Output ============================= Once a simulation has been run, its output data is stored in the ``./simdata`` directory. The main data is stored in a file with a -default name of ``data.nc``, which is a netCDF file. It is read in and stored as an `Xarray Dataset `__ object in the ``sim.data`` attribute. +default name of ``data.nc``, which is a netCDF file. It is read in and stored as an +`Xarray Dataset `__ object in the ``sim.data`` attribute. .. .. toctree:: From 764c061079cefc3f66943764b00667dda11f663c Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 09:11:34 -0500 Subject: [PATCH 308/324] Fixed typo --- docs/user-guide/basic-simulation/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 4863764e8..5958406e7 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -132,6 +132,6 @@ default name of ``data.nc``, which is a netCDF file. It is read in and stored as `Xarray Dataset `__ object in the ``sim.data`` attribute. -.. .. toctree:: +.. toctree:: .. :maxdepth: 2 .. :hidden: From af759238d18328f9559a08e33a04bd12ba88555b Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 10:43:32 -0500 Subject: [PATCH 309/324] Changed spherical to gravitational harmonics --- docs/user-guide/gravitational-harmonics/index.rst | 12 ++++++++++++ docs/user-guide/index.rst | 2 +- docs/user-guide/spherical-harmonics/index.rst | 12 ------------ 3 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 docs/user-guide/gravitational-harmonics/index.rst delete mode 100644 docs/user-guide/spherical-harmonics/index.rst diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst new file mode 100644 index 000000000..98d0a8d7c --- /dev/null +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -0,0 +1,12 @@ +######################### +Gravitational Harmonics +########################## + +Here, we show how to use Swiftest's Gravitational Harmonics capabilities. +This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. + + + +.. .. toctree:: +.. :maxdepth: 2 +.. :hidden: \ No newline at end of file diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index f3a941582..de0a3b858 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -16,4 +16,4 @@ In this user guide, you will find detailed descriptions and examples that descri Basic Simulation Detailed Simulation Setup - Spherical Harmonics \ No newline at end of file + Gravitational Harmonics \ No newline at end of file diff --git a/docs/user-guide/spherical-harmonics/index.rst b/docs/user-guide/spherical-harmonics/index.rst deleted file mode 100644 index 06380bd4a..000000000 --- a/docs/user-guide/spherical-harmonics/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -################### -Spherical Harmonics -################### - -Here, we show how to use Swiftest's Spherical Harmonics capabilities. -This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. - - - -.. .. toctree:: -.. :maxdepth: 2 -.. :hidden: \ No newline at end of file From 4176815439150e4e7c894036d0f97f10103a6f3a Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 10:48:12 -0500 Subject: [PATCH 310/324] Fixed linking issues --- docs/user-guide/gravitational-harmonics/index.rst | 2 +- docs/user-guide/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index 98d0a8d7c..0e9f188cd 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -1,4 +1,4 @@ -######################### +########################## Gravitational Harmonics ########################## diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst index de0a3b858..faa81fdc3 100644 --- a/docs/user-guide/index.rst +++ b/docs/user-guide/index.rst @@ -8,7 +8,7 @@ In this user guide, you will find detailed descriptions and examples that descri - A more in-depth :doc:`Detailed Simulation Setup ` -- Understanding the :doc:`Spherical Harmonics capabilities ` +- Understanding the :doc:`Gravitational Harmonics capabilities ` .. toctree:: :maxdepth: 2 From 196029564bdc48ba6276cdc362de3c433eaa0da8 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 11:02:39 -0500 Subject: [PATCH 311/324] Added intro to grav harmonics --- docs/user-guide/gravitational-harmonics/index.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index 0e9f188cd..dc4fe4b1c 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -3,6 +3,15 @@ Gravitational Harmonics ########################## Here, we show how to use Swiftest's Gravitational Harmonics capabilities. +Swiftest uses `SHTOOLS ` to compute the gravitational harmonics coefficients for a given body and calculate it's associated acceleration kick. +The coefficients can be computed in a number of ways: +- Using the axes measurements of the body ( :func: `clm_from_ellipsoid `) +- Using a surface relief grid ( :func: `clm_from_relief `). + + * This function is still in development and may not work as expected. + +- Manually entering the coefficients when adding the central body ( :func: `add_body `) + This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. From d320174377033ae07761e038432707251a3a3454 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 11:04:32 -0500 Subject: [PATCH 312/324] Fixed linking issues --- docs/user-guide/gravitational-harmonics/index.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index dc4fe4b1c..5cffea631 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -3,14 +3,16 @@ Gravitational Harmonics ########################## Here, we show how to use Swiftest's Gravitational Harmonics capabilities. -Swiftest uses `SHTOOLS ` to compute the gravitational harmonics coefficients for a given body and calculate it's associated acceleration kick. +Swiftest uses `SHTOOLS `__ to compute the gravitational harmonics coefficients for a given body and calculate it's associated acceleration kick. The coefficients can be computed in a number of ways: -- Using the axes measurements of the body ( :func: `clm_from_ellipsoid `) -- Using a surface relief grid ( :func: `clm_from_relief `). + +- Using the axes measurements of the body ( :func:`clm_from_ellipsoid `) + +- Using a surface relief grid ( :func:`clm_from_relief `). * This function is still in development and may not work as expected. -- Manually entering the coefficients when adding the central body ( :func: `add_body `) +- Manually entering the coefficients when adding the central body ( :func:`add_body `) This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. From ff5338cc6823d25db9a24d92fd0d392d11c48f71 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 11:17:25 -0500 Subject: [PATCH 313/324] testing math functions and adjusted bulleted lists --- .../gravitational-harmonics/index.rst | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index 5cffea631..790339207 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -2,21 +2,37 @@ Gravitational Harmonics ########################## -Here, we show how to use Swiftest's Gravitational Harmonics capabilities. -Swiftest uses `SHTOOLS `__ to compute the gravitational harmonics coefficients for a given body and calculate it's associated acceleration kick. +Here, we show how to use Swiftest's Gravitational Harmonics capabilities. This is based on ``/spherical_harmonics_cb`` +in ``swiftest/examples``. Swiftest uses `SHTOOLS `__ to compute the gravitational +harmonics coefficients for a given body and calculate it's associated acceleration kick. The additional acceleration +kick is based on the gravitaional potential described `here `__. + +..math:: + + U(r) = \frac{GM}{r} \sum_{l=0}^{\infty} \sum_{m=-l}^{l} \left( \frac{R_0}{r} \right)^l C_{lm} Y_{lm} (\theta, \phi) \label{grav_pot} + +* Gravitational potential:math:`U` at a point:math:`\Vec{r}`;:math:`\theta` is the polar angle;:math:`\phi` is the azimuthal angle;:math:`R_0` is the central body +radius;:math:`G` is the gravitational constant;:math:`Y_{lm}` is the spherical harmonic function at degree:math:`l` and order:math:`m`;:math:`C_{lm}` is the corresponding coefficient. + + +Gravitational Harmonics coefficients +===================================== + +Swiftest adopts the :math:`4\pi` or geodesy normalization for the gravitational harmonics coefficients. The coefficients can be computed in a number of ways: - Using the axes measurements of the body ( :func:`clm_from_ellipsoid `) - Using a surface relief grid ( :func:`clm_from_relief `). - * This function is still in development and may not work as expected. + - This function is still in development and may not work as expected. - Manually entering the coefficients when adding the central body ( :func:`add_body `) -This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. +Computing coefficients from axes measurements +=============================================== .. .. toctree:: .. :maxdepth: 2 From 8448c4badae86badcd4a9bdbbfe6d1efabb98f31 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 11:20:41 -0500 Subject: [PATCH 314/324] Testing math and rearranging --- docs/user-guide/gravitational-harmonics/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index 790339207..754707750 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -7,18 +7,18 @@ in ``swiftest/examples``. Swiftest uses `SHTOOLS `__. -..math:: +.. math:: U(r) = \frac{GM}{r} \sum_{l=0}^{\infty} \sum_{m=-l}^{l} \left( \frac{R_0}{r} \right)^l C_{lm} Y_{lm} (\theta, \phi) \label{grav_pot} -* Gravitational potential:math:`U` at a point:math:`\Vec{r}`;:math:`\theta` is the polar angle;:math:`\phi` is the azimuthal angle;:math:`R_0` is the central body -radius;:math:`G` is the gravitational constant;:math:`Y_{lm}` is the spherical harmonic function at degree:math:`l` and order:math:`m`;:math:`C_{lm}` is the corresponding coefficient. +Gravitational potential :math:`U` at a point :math:`\Vec{r}`; :math:`\theta` is the polar angle; :math:`\phi` is the azimuthal angle; +:math:`R_0` is the central body radius; :math:`G` is the gravitational constant; :math:`Y_{lm}` is the spherical harmonic function at degree :math:`l` and order :math:`m`; :math:`C_{lm}` is the corresponding coefficient. Gravitational Harmonics coefficients ===================================== -Swiftest adopts the :math:`4\pi` or geodesy normalization for the gravitational harmonics coefficients. +Swiftest adopts the :math:`4\pi` or geodesy normalization for the gravitational harmonics coefficients. The coefficients can be computed in a number of ways: - Using the axes measurements of the body ( :func:`clm_from_ellipsoid `) From a79319aa9a5034b7e00bec52f7561357879fb607 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 11:44:15 -0500 Subject: [PATCH 315/324] Rearranged file io to better manage how and when gravitational harmonics dimensions, coordinates, and variables are defined and stored --- src/netcdf_io/netcdf_io_module.f90 | 46 +++++---- src/swiftest/swiftest_io.f90 | 156 +++++++++++++++-------------- 2 files changed, 110 insertions(+), 92 deletions(-) diff --git a/src/netcdf_io/netcdf_io_module.f90 b/src/netcdf_io/netcdf_io_module.f90 index 2c072186f..34196dc50 100644 --- a/src/netcdf_io/netcdf_io_module.f90 +++ b/src/netcdf_io/netcdf_io_module.f90 @@ -64,25 +64,6 @@ module netcdf_io !! ID for the space variable character(len=1), dimension(3) :: space_coords = ["x","y","z"] !! The space dimension coordinate labels - character(NAMELEN) :: sign_dimname = "sign" - !! name of the sign dimension for c_lm - integer(I4B) :: sign_dimid - !! ID for sign dimension - integer(I4B) :: sign_varid - !! ID for sign variable - character(NAMELEN) :: l_dimname = "l" - !! name of l dimension for c_lm - integer(I4B) :: l_dimid - !! ID for the l dimension for c_lm - integer(I4B) :: l_varid - !! ID for the l variable - character(NAMELEN) :: m_dimname = "m" - !! name of m dimension for c_lm - integer(I4B) :: m_dimid - !! ID for the m dimension for c_lm - integer(I4B) :: m_varid - !! ID for the m variable - ! Non-dimension ids and variable names character(NAMELEN) :: id_varname = "id" @@ -291,8 +272,35 @@ module netcdf_io !! ID for the id of the other body involved in the discard logical :: lpseudo_vel_exists = .false. !! Logical flag to indicate whether or not the pseudovelocity vectors were present in an old file. + + ! Gravitational harmonics ids and variable names logical :: lc_lm_exists = .false. !! Logical flag to indicate whether or not the c_lm array was present in an old file. + character(NAMELEN) :: sign_dimname = "sign" + !! name of the sign dimension for c_lm + integer(I4B) :: sign_dimid + !! ID for sign dimension + integer(I4B) :: sign_varid + !! ID for sign variable + integer(I4B), dimension(2) :: sign_coords = [-1,1] + !! The sign dimension coordinate labels + character(NAMELEN) :: l_dimname = "l" + !! name of l dimension for c_lm + integer(I4B) :: l_dimid + !! ID for the l dimension for c_lm + integer(I4B) :: l_varid + !! ID for the l variable + character(NAMELEN) :: m_dimname = "m" + !! name of m dimension for c_lm + integer(I4B) :: m_dimid + !! ID for the m dimension for c_lm + integer(I4B) :: m_varid + !! ID for the m variable + integer(I4B) :: m_dim_max + !! Maximum value of the m dimension + integer(I4B) :: l_dim_max + !! Maximum value of the l dimension + contains procedure :: close => netcdf_io_close !! Closes an open NetCDF file diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index c50345cd3..8209f2a34 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -686,7 +686,7 @@ module subroutine swiftest_io_netcdf_get_t0_values_system(self, nc, param) class(swiftest_netcdf_parameters), intent(inout) :: nc !! Parameters used to identify a particular NetCDF dataset class(swiftest_parameters), intent(inout) :: param ! Internals - integer(I4B) :: itmax, idmax, tslot + integer(I4B) :: itmax, idmax, tslot, status real(DP), dimension(:), allocatable :: vals logical, dimension(:), allocatable :: plmask, tpmask real(DP), dimension(1) :: rtemp @@ -754,6 +754,23 @@ module subroutine swiftest_io_netcdf_get_t0_values_system(self, nc, param) cb%L0(:) = Ip0(3) * mass0 * cb%R0**2 * rot0(:) L(:) = cb%Ip(3) * cb%mass * cb%radius**2 * cb%rot(:) cb%dL(:) = L(:) - cb%L0 + + status = nf90_inq_varid(nc%id, nc%j2rp2_varname, nc%j2rp2_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_get_var(nc%id, nc%j2rp2_varid, cb%j2rp2, start=[tslot]), & + "netcdf_io_get_t0_values_system nf90_getvar j2rp2_varid" ) + else + cb%j2rp2 = 0.0_DP + end if + + status = nf90_inq_varid(nc%id, nc%j4rp4_varname, nc%j4rp4_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_get_var(nc%id, nc%j4rp4_varid, cb%j4rp4, start=[tslot]), & + "netcdf_io_get_t0_values_system nf90_getvar j4rp4_varid" ) + else + cb%j4rp4 = 0.0_DP + end if + end if ! Retrieve the current bookkeeping variables @@ -767,15 +784,6 @@ module subroutine swiftest_io_netcdf_get_t0_values_system(self, nc, param) call netcdf_io_check( nf90_get_var(nc%id, nc%E_untracked_varid, self%E_untracked, start=[tslot]), & "netcdf_io_get_t0_values_system E_untracked_varid" ) - ! ! SH gravity variable dimensions - - ! call netcdf_io_check( nf90_get_var(nc%id, nc%sign_dimname, nc%sign_dimid), & - ! "swiftest_io_netcdf_open nf90_inq_dimid sign_dimid") - ! call netcdf_io_check( nf90_inq_dimid(nc%id, nc%l_dimname, nc%l_dimid), & - ! "swiftest_io_netcdf_open nf90_inq_dimid l_dimid") - ! call netcdf_io_check( nf90_inq_dimid(nc%id, nc%m_dimname, nc%m_dimid), & - ! "swiftest_io_netcdf_open nf90_inq_dimid m_dimid") - end if deallocate(vals) @@ -803,7 +811,7 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) integer(I4B), parameter :: NO_FILL = 0 logical :: fileExists character(len=STRMAX) :: errmsg - integer(I4B) :: ndims + integer(I4B) :: i, ndims associate(nc => self) @@ -839,13 +847,7 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) "netcdf_io_initialize_output nf90_def_dim name_dimid" ) ! dimension to store particle id numbers call netcdf_io_check( nf90_def_dim(nc%id, nc%str_dimname, NAMELEN, nc%str_dimid), & "netcdf_io_initialize_output nf90_def_dim str_dimid" ) ! Dimension for string variables - - call netcdf_io_check( nf90_def_dim(nc%id, nc%sign_dimname, NF90_UNLIMITED, nc%sign_dimid), & - "swiftest_io_netcdf_open nf90_def_dim sign_dimid") - call netcdf_io_check( nf90_def_dim(nc%id, nc%l_dimname, NF90_UNLIMITED, nc%l_dimid), & - "swiftest_io_netcdf_open nf90_def_dim l_dimid") - call netcdf_io_check( nf90_def_dim(nc%id, nc%m_dimname, NF90_UNLIMITED, nc%m_dimid), & - "swiftest_io_netcdf_open nf90_def_dim m_dimid") + ! Dimension coordinates call netcdf_io_check( nf90_def_var(nc%id, nc%time_dimname, nc%out_type, nc%time_dimid, nc%time_varid), & @@ -855,13 +857,6 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_def_var(nc%id, nc%name_dimname, NF90_CHAR, [nc%str_dimid, nc%name_dimid], nc%name_varid), & "netcdf_io_initialize_output nf90_def_var name_varid" ) - call netcdf_io_check( nf90_def_var(nc%id, nc%sign_dimname, nc%out_type, nc%sign_dimid, nc%sign_varid), & - "swiftest_io_netcdf_open nf90_def_var sign_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%l_dimname, nc%out_type, nc%l_dimid, nc%l_varid), & - "swiftest_io_netcdf_open nf90_def_var l_varid") - call netcdf_io_check( nf90_def_var(nc%id, nc%m_dimname, nc%out_type, nc%m_dimid, nc%m_varid), & - "swiftest_io_netcdf_open nf90_def_var m_varid") - ! Variables call netcdf_io_check( nf90_def_var(nc%id, nc%id_varname, NF90_INT, nc%name_dimid, nc%id_varid), & "netcdf_io_initialize_output nf90_def_var id_varid" ) @@ -962,13 +957,37 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) if (param%lrotation) then call netcdf_io_check( nf90_def_var(nc%id, nc%Ip_varname, nc%out_type, [nc%space_dimid, nc%name_dimid, nc%time_dimid], & - nc%Ip_varid), & - "netcdf_io_initialize_output nf90_def_var Ip_varid" ) + nc%Ip_varid), "netcdf_io_initialize_output nf90_def_var Ip_varid" ) call netcdf_io_check( nf90_def_var(nc%id, nc%rot_varname, nc%out_type, [nc%space_dimid, nc%name_dimid, nc%time_dimid], & - nc%rot_varid), & - "netcdf_io_initialize_output nf90_def_var rot_varid" ) + nc%rot_varid), "netcdf_io_initialize_output nf90_def_var rot_varid" ) call netcdf_io_check( nf90_def_var(nc%id, nc%rotphase_varname, nc%out_type, nc%time_dimid, nc%rotphase_varid), & "netcdf_io_initialize_output nf90_def_var rotphase_varid" ) + + + if (nc%lc_lm_exists) then + call netcdf_io_check( nf90_def_dim(nc%id, nc%sign_dimname, NF90_UNLIMITED, nc%sign_dimid), & + "swiftest_io_netcdf_open nf90_def_dim sign_dimid") + call netcdf_io_check( nf90_def_dim(nc%id, nc%l_dimname, NF90_UNLIMITED, nc%l_dimid), & + "swiftest_io_netcdf_open nf90_def_dim l_dimid") + call netcdf_io_check( nf90_def_dim(nc%id, nc%m_dimname, NF90_UNLIMITED, nc%m_dimid), & + "swiftest_io_netcdf_open nf90_def_dim m_dimid") + + call netcdf_io_check( nf90_def_var(nc%id, nc%sign_dimname, nc%out_type, nc%sign_dimid, nc%sign_varid), & + "swiftest_io_netcdf_open nf90_def_var sign_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%l_dimname, nc%out_type, nc%l_dimid, nc%l_varid), & + "swiftest_io_netcdf_open nf90_def_var l_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%m_dimname, nc%out_type, nc%m_dimid, nc%m_varid), & + "swiftest_io_netcdf_open nf90_def_var m_varid") + call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], & + nc%c_lm_varid), "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) + + else + call netcdf_io_check( nf90_def_var(nc%id, nc%j2rp2_varname, nc%out_type, nc%time_dimid, nc%j2rp2_varid), & + "netcdf_io_initialize_output nf90_def_var j2rp2_varid" ) + call netcdf_io_check( nf90_def_var(nc%id, nc%j4rp4_varname, nc%out_type, nc%time_dimid, nc%j4rp4_varid), & + "netcdf_io_initialize_output nf90_def_var j4rp4_varid" ) + end if + end if ! if (param%ltides) then @@ -1006,16 +1025,6 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) "netcdf_io_initialize_output nf90_def_var GMescape_varid" ) end if - call netcdf_io_check( nf90_def_var(nc%id, nc%j2rp2_varname, nc%out_type, nc%time_dimid, nc%j2rp2_varid), & - "netcdf_io_initialize_output nf90_def_var j2rp2_varid" ) - call netcdf_io_check( nf90_def_var(nc%id, nc%j4rp4_varname, nc%out_type, nc%time_dimid, nc%j4rp4_varid), & - "netcdf_io_initialize_output nf90_def_var j4rp4_varid" ) - - if (nc%lc_lm_exists) then - call netcdf_io_check( nf90_def_var(nc%id, nc%c_lm_varname, nc%out_type, [nc%m_dimid, nc%l_dimid, nc%sign_dimid], & - nc%c_lm_varid), "netcdf_io_initialize_output nf90_def_var c_lm_varid" ) - end if - ! Set fill mode to NaN for all variables call netcdf_io_check( nf90_inquire(nc%id, nVariables=nvar), "netcdf_io_initialize_output nf90_inquire nVariables" ) do varid = 1, nvar @@ -1062,6 +1071,17 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) call netcdf_io_check( nf90_put_var(nc%id, nc%space_varid, nc%space_coords, start=[1], count=[NDIM]), & "netcdf_io_initialize_output nf90_put_var space" ) + if (param%lrotation .and. nc%lc_lm_exists) then + + ! Populate coordinate values for l and m and export to hdf file + call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, [(i, i=0, nc%l_dim_max-1)]), & + "netcdf_io_write_frame_cb nf90_put_var l_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, [(i, i=0, nc%m_dim_max-1)]), & + "netcdf_io_write_frame_cb nf90_put_var m_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1,-1]), & + "netcdf_io_write_frame_cb nf90_put_var sign_varid") + end if + end associate return @@ -1354,7 +1374,6 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier integer(I4B) :: ierr !! Error code: returns 0 if the read is successful ! Internals integer(I4B) :: i, idmax, npl_check, ntp_check, str_max, status, npl, ntp - integer(I4B) :: l_dim_max, m_dim_max ! dimensions for c_lm array real(DP), dimension(:), allocatable :: rtemp real(DP), dimension(:,:), allocatable :: vectemp integer(I4B), dimension(:), allocatable :: itemp @@ -1569,16 +1588,20 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = l_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = m_dim_max), "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = nc%l_dim_max),& + "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = nc%m_dim_max), & + "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") - if(.not. allocated(cb%c_lm)) then - allocate(cb%c_lm(m_dim_max, l_dim_max, 2)) - end if - call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [m_dim_max, l_dim_max, 2]), "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + if(.not. allocated(cb%c_lm)) allocate(cb%c_lm(nc%m_dim_max, nc%l_dim_max, 2)) + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & + "netcdf_io_read_frame_system nf90_getvar c_lm_varid") - ! ordering of dimensions above seen to stackoverflow to prevent error 'NetCDF: Start + count exceeds dimension bound' nc%lc_lm_exists = .true. + if (abs(cb%j2rp2) > tiny(1.0_DP) .or. (abs(cb%j4rp4) > tiny(1.0_DP))) then + write(*,*) "Error reading in NetCDF file: cannot use both c_lm and j2rp2/j4rp4" + call base_util_exit(FAILURE,param%display_unit) + end if else if (allocated(cb%c_lm)) deallocate(cb%c_lm) nc%lc_lm_exists = .false. @@ -2097,7 +2120,6 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters ! Internals integer(I4B) :: idslot, old_mode, tmp, i - integer(I4B) :: l_dim_max, m_dim_max integer(I4B), dimension(:), allocatable :: lm_coords integer(I4B) :: status @@ -2119,10 +2141,7 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cb nf90_put_var cb mass_varid" ) if (param%lclose) call netcdf_io_check( nf90_put_var(nc%id, nc%radius_varid, self%radius, start=[idslot, tslot]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb radius_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%j2rp2_varid, self%j2rp2, start=[tslot]), & - "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j2rp2_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%j4rp4_varid, self%j4rp4, start=[tslot]), & - "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j4rp4_varid" ) + if (param%lrotation) then call netcdf_io_check( nf90_put_var(nc%id, nc%Ip_varid, self%Ip(:), start=[1, idslot, tslot], count=[NDIM,1,1]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb Ip_varid" ) @@ -2130,30 +2149,21 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) count=[NDIM,1,1]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rot_varid" ) - ! Following the template of j2rp2 call netcdf_io_check( nf90_put_var(nc%id, nc%rotphase_varid, self%rotphase * RAD2DEG, start = [tslot]), & "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") - end if - - if (allocated(self%c_lm)) then - status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) - if (status == NF90_NOERR) then - m_dim_max = size(self%c_lm, 1) - l_dim_max = size(self%c_lm, 2) - - ! Populate coordinate values for l and m and export to hdf file - allocate(lm_coords(l_dim_max)) - do i = 0, l_dim_max - 1 - lm_coords(i + 1) = i - end do - - call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var l_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, lm_coords), "netcdf_io_write_frame_cb nf90_put_var m_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1,-1]), "netcdf_io_write_frame_cb nf90_put_var sign_varid") + + if (nc%lc_lm_exists) then + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then - ! Write dimension-coordinates to file - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [m_dim_max, l_dim_max, 2]), & - "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & + "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") + else + call netcdf_io_check( nf90_put_var(nc%id, nc%j2rp2_varid, self%j2rp2, start=[tslot]), & + "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j2rp2_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%j4rp4_varid, self%j4rp4, start=[tslot]), & + "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j4rp4_varid" ) + end if end if end if From c414bad8eac8b7fc40ca26144d27a898879287e0 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 11:54:06 -0500 Subject: [PATCH 316/324] Added a safety check to ensure that l_dim_max and m_dim_max are the same --- src/swiftest/swiftest_io.f90 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 8209f2a34..4d1bcc185 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1592,16 +1592,22 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = nc%m_dim_max), & "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") - + + if (nc%l_dim_max /= nc%m_dim_max) then + write(*,*) "Error reading in NetCDF file: c_lm requires l_dim_max = m_dim_max" + call base_util_exit(FAILURE,param%display_unit) + end if + if(.not. allocated(cb%c_lm)) allocate(cb%c_lm(nc%m_dim_max, nc%l_dim_max, 2)) call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & "netcdf_io_read_frame_system nf90_getvar c_lm_varid") - nc%lc_lm_exists = .true. if (abs(cb%j2rp2) > tiny(1.0_DP) .or. (abs(cb%j4rp4) > tiny(1.0_DP))) then write(*,*) "Error reading in NetCDF file: cannot use both c_lm and j2rp2/j4rp4" call base_util_exit(FAILURE,param%display_unit) end if + + nc%lc_lm_exists = .true. else if (allocated(cb%c_lm)) deallocate(cb%c_lm) nc%lc_lm_exists = .false. From b5daf158740be863dc2c07da48b5f67df6f41e50 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 12:08:26 -0500 Subject: [PATCH 317/324] Fixed problem that was preventing j2 and j4 values from being saved. Also added some clarifying comments and restructured to only read in j2,j4, or c_lm values when rotation is turned on --- src/swiftest/swiftest_io.f90 | 106 ++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 4d1bcc185..4a020816b 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1546,8 +1546,8 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier ! Set initial central body angular momentum for bookkeeping cb%L0(:) = cb%Ip(3) * cb%mass * cb%R0**2 * cb%rot(:) - - ! rotphase may not be input by the user + + ! Check if rotphase is input by user. If not, set to 0 status = nf90_inq_varid(nc%id, nc%rotphase_varname, nc%rotphase_varid) if (status == NF90_NOERR) then call netcdf_io_check( nf90_get_var(nc%id, nc%rotphase_varid, cb%rotphase, start=[tslot]), & @@ -1556,6 +1556,53 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier else cb%rotphase = 0.0_DP end if + + ! Check if the J2 and J4 terms are input by user. If not, set them to 0 + status = nf90_inq_varid(nc%id, nc%j2rp2_varname, nc%j2rp2_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_get_var(nc%id, nc%j2rp2_varid, cb%j2rp2, start=[tslot]), & + "netcdf_io_read_frame_system nf90_getvar j2rp2_varid" ) + else + cb%j2rp2 = 0.0_DP + end if + + status = nf90_inq_varid(nc%id, nc%j4rp4_varname, nc%j4rp4_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_get_var(nc%id, nc%j4rp4_varid, cb%j4rp4, start=[tslot]), & + "netcdf_io_read_frame_system nf90_getvar j4rp4_varid" ) + else + cb%j4rp4 = 0.0_DP + end if + + ! Check if gravitational harmonics coefficients, c_lm, are set by the user. Also ensure that + ! c_lm and j2rp2/j4rp4 are not both set. + status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) + if (status == NF90_NOERR) then + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = nc%l_dim_max),& + "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) + call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = nc%m_dim_max), & + "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") + + if (nc%l_dim_max /= nc%m_dim_max) then + write(*,*) "Error reading in NetCDF file: c_lm requires l_dim_max = m_dim_max" + call base_util_exit(FAILURE,param%display_unit) + end if + + if(.not. allocated(cb%c_lm)) allocate(cb%c_lm(nc%m_dim_max, nc%l_dim_max, 2)) + call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & + "netcdf_io_read_frame_system nf90_getvar c_lm_varid") + + if (abs(cb%j2rp2) > tiny(1.0_DP) .or. (abs(cb%j4rp4) > tiny(1.0_DP))) then + write(*,*) "Error reading in NetCDF file: cannot use both c_lm and j2rp2/j4rp4" + call base_util_exit(FAILURE,param%display_unit) + end if + + nc%lc_lm_exists = .true. + else + if (allocated(cb%c_lm)) deallocate(cb%c_lm) + nc%lc_lm_exists = .false. + end if + end if ! if (param%ltides) then @@ -1570,48 +1617,9 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier ! if (npl > 0) pl%Q(:) = pack(rtemp, plmask) ! end if - status = nf90_inq_varid(nc%id, nc%j2rp2_varname, nc%j2rp2_varid) - if (status == NF90_NOERR) then - call netcdf_io_check( nf90_get_var(nc%id, nc%j2rp2_varid, cb%j2rp2, start=[tslot]), & - "netcdf_io_read_frame_system nf90_getvar j2rp2_varid" ) - else - cb%j2rp2 = 0.0_DP - end if - status = nf90_inq_varid(nc%id, nc%j4rp4_varname, nc%j4rp4_varid) - if (status == NF90_NOERR) then - call netcdf_io_check( nf90_get_var(nc%id, nc%j4rp4_varid, cb%j4rp4, start=[tslot]), & - "netcdf_io_read_frame_system nf90_getvar j4rp4_varid" ) - else - cb%j4rp4 = 0.0_DP - end if - status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) - if (status == NF90_NOERR) then - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%l_dimid, len = nc%l_dim_max),& - "netcdf_io_read_frame_system nf90_inquire_dimension l_dimid" ) - call netcdf_io_check( nf90_inquire_dimension(nc%id, nc%m_dimid, len = nc%m_dim_max), & - "netcdf_io_read_frame_system nf90_inquire_dimension m_dimid") - - if (nc%l_dim_max /= nc%m_dim_max) then - write(*,*) "Error reading in NetCDF file: c_lm requires l_dim_max = m_dim_max" - call base_util_exit(FAILURE,param%display_unit) - end if - if(.not. allocated(cb%c_lm)) allocate(cb%c_lm(nc%m_dim_max, nc%l_dim_max, 2)) - call netcdf_io_check( nf90_get_var(nc%id, nc%c_lm_varid, cb%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & - "netcdf_io_read_frame_system nf90_getvar c_lm_varid") - - if (abs(cb%j2rp2) > tiny(1.0_DP) .or. (abs(cb%j4rp4) > tiny(1.0_DP))) then - write(*,*) "Error reading in NetCDF file: cannot use both c_lm and j2rp2/j4rp4" - call base_util_exit(FAILURE,param%display_unit) - end if - - nc%lc_lm_exists = .true. - else - if (allocated(cb%c_lm)) deallocate(cb%c_lm) - nc%lc_lm_exists = .false. - end if call self%read_particle_info(nc, param, plmask, tpmask) @@ -2159,17 +2167,13 @@ module subroutine swiftest_io_netcdf_write_frame_cb(self, nc, param) "swiftest_io_netcdf_write_frame_cb nf90_put_var cb rotphase") if (nc%lc_lm_exists) then - status = nf90_inq_varid(nc%id, nc%c_lm_varname, nc%c_lm_varid) - if (status == NF90_NOERR) then - - call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & + call netcdf_io_check( nf90_put_var(nc%id, nc%c_lm_varid, self%c_lm, count = [nc%m_dim_max, nc%l_dim_max, 2]), & "netcdf_io_write_frame_cb nf90_put_var c_lm_varid") - else - call netcdf_io_check( nf90_put_var(nc%id, nc%j2rp2_varid, self%j2rp2, start=[tslot]), & - "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j2rp2_varid" ) - call netcdf_io_check( nf90_put_var(nc%id, nc%j4rp4_varid, self%j4rp4, start=[tslot]), & - "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j4rp4_varid" ) - end if + else + call netcdf_io_check( nf90_put_var(nc%id, nc%j2rp2_varid, self%j2rp2, start=[tslot]), & + "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j2rp2_varid" ) + call netcdf_io_check( nf90_put_var(nc%id, nc%j4rp4_varid, self%j4rp4, start=[tslot]), & + "swiftest_io_netcdf_write_frame_cb nf90_put_var cb j4rp4_varid" ) end if end if From ab017e73fddc005df3a76cf6616060a925ebbc81 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 12:17:30 -0500 Subject: [PATCH 318/324] Fixed some minor issues with the dimension coordinate definitions --- src/swiftest/swiftest_io.f90 | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 4a020816b..0dabd4f99 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -1072,14 +1072,13 @@ module subroutine swiftest_io_netcdf_initialize_output(self, param) "netcdf_io_initialize_output nf90_put_var space" ) if (param%lrotation .and. nc%lc_lm_exists) then - - ! Populate coordinate values for l and m and export to hdf file - call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, [(i, i=0, nc%l_dim_max-1)]), & - "netcdf_io_write_frame_cb nf90_put_var l_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, [(i, i=0, nc%m_dim_max-1)]), & - "netcdf_io_write_frame_cb nf90_put_var m_varid") - call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, [1,-1]), & - "netcdf_io_write_frame_cb nf90_put_var sign_varid") + ! Populate coordinate values for l, m, and sign + call netcdf_io_check( nf90_put_var(nc%id, nc%l_varid, [(i, i=0, nc%l_dim_max-1)], start=[1], count=[nc%l_dim_max]), & + "netcdf_io_netcdf_initialize_output nf90_put_var l_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%m_varid, [(i, i=0, nc%m_dim_max-1)], start=[1], count=[nc%m_dim_max]), & + "netcdf_io_netcdf_initialize_output nf90_put_var m_varid") + call netcdf_io_check( nf90_put_var(nc%id, nc%sign_varid, nc%sign_coords, start=[1], count=[2] ), & + "netcdf_io_netcdf_initialize_output nf90_put_var sign_varid") end if end associate @@ -1617,10 +1616,6 @@ module function swiftest_io_netcdf_read_frame_system(self, nc, param) result(ier ! if (npl > 0) pl%Q(:) = pack(rtemp, plmask) ! end if - - - - call self%read_particle_info(nc, param, plmask, tpmask) if (param%in_form == "EL") then From 849e2a7100492c77182152216900e2742b792653 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 12:18:58 -0500 Subject: [PATCH 319/324] Refactoring for new documentation system and to enforce line limits --- src/swiftest/swiftest_gr.f90 | 78 ++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/swiftest/swiftest_gr.f90 b/src/swiftest/swiftest_gr.f90 index a24ff2507..8de7e3dc8 100644 --- a/src/swiftest/swiftest_gr.f90 +++ b/src/swiftest/swiftest_gr.f90 @@ -23,9 +23,12 @@ pure module subroutine swiftest_gr_kick_getaccb_ns_body(self, nbody_system, para !! Adapted from David A. Minton's Swifter routine routine gr_kick_getaccb_ns.f90 implicit none ! Arguments - class(swiftest_body), intent(inout) :: self !! Swiftest generic body object - class(swiftest_nbody_system), intent(inout) :: nbody_system !! Swiftest nbody system object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! Swiftest generic body object + class(swiftest_nbody_system), intent(inout) :: nbody_system + !! Swiftest nbody system object + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters ! Internals real(DP) :: rmag, rdotv, vmag2 integer(I4B) :: i @@ -62,12 +65,18 @@ pure module subroutine swiftest_gr_kick_getacch(mu, x, lmask, n, inv_c2, agr) !! Adapted from David A. Minton's Swifter routine routine gr_whm_kick_getacch.f90 implicit none ! Arguments - real(DP), dimension(:), intent(in) :: mu !! Gravitational constant - real(DP), dimension(:,:), intent(in) :: x !! Position vectors - logical, dimension(:), intent(in) :: lmask !! Logical mask indicating which bodies to compute - integer(I4B), intent(in) :: n !! Total number of bodies - real(DP), intent(in) :: inv_c2 !! Inverse speed of light squared: 1 / c**2 - real(DP), dimension(:,:), intent(out) :: agr !! Accelerations + real(DP), dimension(:), intent(in) :: mu + !! Gravitational constant + real(DP), dimension(:,:), intent(in) :: x + !! Position vectors + logical, dimension(:), intent(in) :: lmask + !! Logical mask indicating which bodies to compute + integer(I4B), intent(in) :: n + !! Total number of bodies + real(DP), intent(in) :: inv_c2 + !! Inverse speed of light squared: 1 / c**2 + real(DP), dimension(:,:), intent(out) :: agr + !! Accelerations ! Internals integer(I4B) :: i real(DP) :: beta, rjmag4 @@ -100,10 +109,14 @@ pure elemental module subroutine swiftest_gr_p4_pos_kick(inv_c2, rx, ry, rz, vx, !! Adapted from David A. Minton's Swifter routine gr_whm_p4.f90 implicit none ! Arguments - real(DP), intent(in) :: inv_c2 !! One over speed of light squared (1/c**2) - real(DP), intent(inout) :: rx, ry, rz !! Position vector - real(DP), intent(in) :: vx, vy, vz !! Velocity vector - real(DP), intent(in) :: dt !! Step size + real(DP), intent(in) :: inv_c2 + !! One over speed of light squared (1/c**2) + real(DP), intent(inout) :: rx, ry, rz + !! Position vector + real(DP), intent(in) :: vx, vy, vz + !! Velocity vector + real(DP), intent(in) :: dt + !! Step size ! Internals real(DP) :: drx, dry, drz real(DP) :: vmag2 @@ -133,11 +146,16 @@ pure module subroutine swiftest_gr_pseudovel2vel(param, mu, rh, pv, vh) !! Adapted from David A. Minton's Swifter routine gr_pseudovel2vel.f90 implicit none ! Arguments - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - real(DP), intent(in) :: mu !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body - real(DP), dimension(:), intent(in) :: rh !! Heliocentric position vector - real(DP), dimension(:), intent(in) :: pv !! Pseudovelocity velocity vector - see Saha & Tremain (1994), eq. (32) - real(DP), dimension(:), intent(out) :: vh !! Heliocentric velocity vector + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters + real(DP), intent(in) :: mu + !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body + real(DP), dimension(:), intent(in) :: rh + !! Heliocentric position vector + real(DP), dimension(:), intent(in) :: pv + !! Pseudovelocity velocity vector - see Saha & Tremain (1994), eq. (32) + real(DP), dimension(:), intent(out) :: vh + !! Heliocentric velocity vector ! Internals real(DP) :: vmag2, rmag, grterm @@ -191,11 +209,16 @@ pure module subroutine swiftest_gr_vel2pseudovel(param, mu, rh, vh, pv) !! Adapted from David A. Minton's Swifter routine gr_vel2pseudovel.f90 implicit none ! Arguments - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters - real(DP), intent(in) :: mu !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body - real(DP), dimension(:), intent(in) :: rh !! Heliocentric position vector - real(DP), dimension(:), intent(in) :: vh !! Heliocentric velocity vector - real(DP), dimension(:), intent(out) :: pv !! Pseudovelocity vector - see Saha & Tremain (1994), eq. (32) + class(swiftest_parameters), intent(in) :: param + !! Current run configuration parameters + real(DP), intent(in) :: mu + !! G * (Mcb + m), G = gravitational constant, Mcb = mass of central body, m = mass of body + real(DP), dimension(:), intent(in) :: rh + !! Heliocentric position vector + real(DP), dimension(:), intent(in) :: vh + !! Heliocentric velocity vector + real(DP), dimension(:), intent(out) :: pv + !! Pseudovelocity vector - see Saha & Tremain (1994), eq. (32) ! Internals real(DP) :: v2, G, pv2, rterm, det real(DP), dimension(NDIM,NDIM) :: J,Jinv @@ -264,11 +287,14 @@ pure module subroutine swiftest_gr_vh2pv_body(self, param) !! Wrapper function that converts from heliocentric velocity to pseudovelocity for Swiftest bodies implicit none ! Arguments - class(swiftest_body), intent(inout) :: self !! Swiftest particle object - class(swiftest_parameters), intent(in) :: param !! Current run configuration parameters + class(swiftest_body), intent(inout) :: self + !! Swiftest particle object + 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 + real(DP), dimension(:,:), allocatable :: pv + !! Temporary holder of pseudovelocity for in-place conversion associate(n => self%nbody) if (n == 0) return From d7393edc75d6845912911f8f1602251ee75d0d2f Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 12:35:35 -0500 Subject: [PATCH 320/324] Added example data output --- docs/user-guide/basic-simulation/index.rst | 65 ++++++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 5958406e7..7b8d34463 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -79,6 +79,12 @@ file. The default value is 10, which means that Swiftest will store 10 outputs i Setting ``dump_cadence`` to 0 is a a special case that tells Swiftest to store *all* output in memory until the end of the simulation. This is useful for short simulations, but can be memory intensive for long simulations. +.. note:: + Changing the value of ``dump_cadence`` does not change the amount of data that is output by the end of the simulation. It only + changes how often the data is written to disk. Changing the value of ``tstep_out`` (or ``istep_out``) *does* change the amount of + data that is output by the end of the simulation. Intermediate steps between output steps are not saved to disk, and cannot be + recovered after the simulation has finished. + The choice of what values to set for ``tstep_out`` (or ``istep_out``), ``nstep_out``, and ``dump_cadence`` depends on the particular simulation. Higher values of ``dump_cadence`` are typically useful for simulations with small numbers of bodies and small values of ```tstep_out`` where frequent writing to disk can severely impact performance. For simulations with large numbers of bodies and @@ -87,10 +93,10 @@ so that the memory usage does not become too large. The default value of ``dump_ caes. We can set these simulation parameters using the :func:`set_parameter ` method. -Here we have a simulation that runs for 1 My a step size of 0.01 y. We will also save the system every 1000 y and wait until the end +Here we have a simulation that runs for 100,000 y a step size of 0.01 y. We will also save the system every 1000 y and wait until the end of the simulation to write the simulation data to file using the ``dump_cadence=0`` argument:: - sim.set_parameter(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) + sim.set_parameter(tstop=1.0e5, tstep_out=1e3, dt=0.01, dump_cadence=0) Once everything is set up, we call the :func:`run ` method to integrate the system forward in time:: @@ -99,7 +105,7 @@ Once everything is set up, we call the :func:`run ` met Swiftest is relatively flexible with arguments. You can pass the parameters in when initializing the simulation object, or even later when running. So the following are all equivalent:: - sim = swiftest.Simulation(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) + sim = swiftest.Simulation(tstop=1.0e5, tstep_out=1e3, dt=0.01, dump_cadence=0) sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) sim.run() @@ -110,7 +116,7 @@ So the following are all equivalent:: sim = swiftest.Simulation() sim.add_solar_system_body(["Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"]) - sim.run(tstop=1.0e6, tstep_out=1e3, dt=0.01, dump_cadence=0) + sim.run(tstop=1.0e5, tstep_out=1e3, dt=0.01, dump_cadence=0) .. note:: Swiftest uses OpenMP parallelization to help speed up the integration, however the parallelization is most effective when there @@ -131,6 +137,57 @@ Once a simulation has been run, its output data is stored in the ``./simdata`` d default name of ``data.nc``, which is a netCDF file. It is read in and stored as an `Xarray Dataset `__ object in the ``sim.data`` attribute. +Here is an example of what the dataset looks like after the above simulation has been run:: + + In [8]: sim.data + Out[8]: + Size: 229kB + + Dimensions: (time: 101, space: 3, name: 9) + Coordinates: + * time (time) float64 808B 0.0 1e+03 2e+03 ... 9.9e+04 1e+05 + * space (space) Date: Fri, 1 Mar 2024 13:01:54 -0500 Subject: [PATCH 321/324] fixed typo with vector --- docs/user-guide/gravitational-harmonics/index.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index 754707750..ac926de91 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -11,10 +11,9 @@ kick is based on the gravitaional potential described `here `) - Using a surface relief grid ( :func:`clm_from_relief `). - - - This function is still in development and may not work as expected. + - Note: This function is still in development and may not work as expected. - Manually entering the coefficients when adding the central body ( :func:`add_body `) From 5870bfdf9005f3b1447716b9c4ecda543bc91e7d Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 13:30:38 -0500 Subject: [PATCH 322/324] Adding coefficients computation --- .../gravitational-harmonics/index.rst | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index ac926de91..285b26869 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -4,34 +4,84 @@ Gravitational Harmonics Here, we show how to use Swiftest's Gravitational Harmonics capabilities. This is based on ``/spherical_harmonics_cb`` in ``swiftest/examples``. Swiftest uses `SHTOOLS `__ to compute the gravitational -harmonics coefficients for a given body and calculate it's associated acceleration kick. The additional acceleration -kick is based on the gravitaional potential described `here `__. +harmonics coefficients for a given body and calculate it's associated acceleration kick. The conventions and formulae used +to calculate the additional kick are described `here `__. The gravitational +potential is given by the following equation: .. math:: U(r) = \frac{GM}{r} \sum_{l=0}^{\infty} \sum_{m=-l}^{l} \left( \frac{R_0}{r} \right)^l C_{lm} Y_{lm} (\theta, \phi) \label{grav_pot} Gravitational potential :math:`U` at a point :math:`\vec{r}`; :math:`\theta` is the polar angle; :math:`\phi` is the azimuthal angle; -:math:`R_0` is the central body radius; :math:`G` is the gravitational constant; :math:`Y_{lm}` is the spherical harmonic function at degree :math:`l` and order :math:`m`; :math:`C_{lm}` is the corresponding coefficient. +:math:`R_0` is the central body radius; :math:`G` is the gravitational constant; :math:`Y_{lm}` is the spherical harmonic function at +degree :math:`l` and order :math:`m`; :math:`C_{lm}` is the corresponding coefficient. Gravitational Harmonics coefficients ===================================== -Swiftest adopts the :math:`4\pi` or geodesy normalization for the gravitational harmonics coefficients. +Swiftest adopts the :math:`4\pi` or geodesy normalization for the gravitational harmonics coefficients described +in `Weiczorek et al. (2015) `__. + The coefficients can be computed in a number of ways: -- Using the axes measurements of the body ( :func:`clm_from_ellipsoid `) - -- Using a surface relief grid ( :func:`clm_from_relief `). +- Using the axes measurements of the body. (:func:`clm_from_ellipsoid `) +- Using a surface relief grid (:func:`clm_from_relief `). - Note: This function is still in development and may not work as expected. - -- Manually entering the coefficients when adding the central body ( :func:`add_body `) - +- Manually entering the coefficients when adding the central body. (:func:`add_body `) +.. - Ensure to correctly normalize the coefficients if manually entering them. Computing coefficients from axes measurements =============================================== +Given the axes measurements of a body, the gravitational harmonics coefficients can be computed in a straightforward +manner. Let's start with setting up the simulation object with units of `km`, `days`, and `kg`. :: + + import swiftest + + sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg', integrator = 'symba') + sim.clean() + +Define the central body parameters. Here we use Chariklo as an example body and refer to Jacobi Ellipsoid model from +`Leiva et al. (2017) `__ for the axes measurements. :: + + cb_mass = 6.1e18 + cb_radius = 123 + cb_a = 157 + cb_b = 139 + cb_c = 86 + cb_volume = 4.0 / 3 * np.pi * cb_radius**3 + cb_density = cb_mass / cb_volume + cb_T_rotation = 7.004 # hours + cb_T_rotation/= 24.0 # converting to julian days (TU) + cb_rot = [[0, 0, 360.0 / cb_T_rotation]] # degrees/TU + +Once the central body parameters are defined, we can compute the gravitational harmonics coefficients (:math:`C_{lm}`). +The output coefficients are already correctly normalized. :: + + c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True) + +Add the central body to the simulation. :: + + sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) + +Set the parameters for the simulation and run. :: + + sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) + + # Run the simulation + sim.run() + +Setting a reference radius for the coefficients +================================================== + +The coefficients can be computed with respect to a reference radius. This is useful when the user wants to explicitly set the reference radius. :: + + c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True, ref_radius = cb_radius) + + + + .. .. toctree:: .. :maxdepth: 2 .. :hidden: \ No newline at end of file From 3cc5ef602f65b80a73e16de59f4b61a1f7322f31 Mon Sep 17 00:00:00 2001 From: anand43 Date: Fri, 1 Mar 2024 13:43:54 -0500 Subject: [PATCH 323/324] Added more content to grav harmonics --- .../gravitational-harmonics/index.rst | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/user-guide/gravitational-harmonics/index.rst b/docs/user-guide/gravitational-harmonics/index.rst index 285b26869..f4452666c 100644 --- a/docs/user-guide/gravitational-harmonics/index.rst +++ b/docs/user-guide/gravitational-harmonics/index.rst @@ -20,31 +20,34 @@ Gravitational Harmonics coefficients ===================================== Swiftest adopts the :math:`4\pi` or geodesy normalization for the gravitational harmonics coefficients described -in `Weiczorek et al. (2015) `__. +in `Weiczorek et al. (2015) `__. The coefficients can be computed in a number of ways: - Using the axes measurements of the body. (:func:`clm_from_ellipsoid `) -- Using a surface relief grid (:func:`clm_from_relief `). - - Note: This function is still in development and may not work as expected. -- Manually entering the coefficients when adding the central body. (:func:`add_body `) -.. - Ensure to correctly normalize the coefficients if manually entering them. +- Using a surface relief grid (:func:`clm_from_relief `). *Note: This function is still in development and may not work as expected.* -Computing coefficients from axes measurements -=============================================== +- Manually entering the coefficients when adding the central body. (:func:`add_body `) -Given the axes measurements of a body, the gravitational harmonics coefficients can be computed in a straightforward -manner. Let's start with setting up the simulation object with units of `km`, `days`, and `kg`. :: +Set up a Simulation +==================== + +Let's start with setting up the simulation object with units of `km`, `days`, and `kg`. :: import swiftest sim = swiftest.Simulation(DU2M = 1e3, TU = 'd', MU = 'kg', integrator = 'symba') sim.clean() -Define the central body parameters. Here we use Chariklo as an example body and refer to Jacobi Ellipsoid model from +Computing coefficients from axes measurements +=============================================== + +Given the axes measurements of a body, the gravitational harmonics coefficients can be computed in a straightforward +manner. Here we use Chariklo as an example body and refer to Jacobi Ellipsoid model from `Leiva et al. (2017) `__ for the axes measurements. :: + # Define the central body parameters. cb_mass = 6.1e18 cb_radius = 123 cb_a = 157 @@ -61,10 +64,36 @@ The output coefficients are already correctly normalized. :: c_lm, cb_radius = swiftest.clm_from_ellipsoid(mass = cb_mass, density = cb_density, a = cb_a, b = cb_b, c = cb_c, lmax = 6, lref_radius = True) -Add the central body to the simulation. :: +Add the central body to the simulation along with the coefficients. :: sim.add_body(name = 'Chariklo', mass = cb_mass, rot = cb_rot, radius = cb_radius, c_lm = c_lm) +Now the user can set up the rest of the simulation as they prefer. + +Final Steps for Running the Simulation +======================================= + +Add other bodies to the simulation. :: + + # Add user-defined massive bodies + npl = 5 + density_pl = cb_density + + name_pl = ["SemiBody_01", "SemiBody_02", "SemiBody_03", "SemiBody_04", "SemiBody_05"] + a_pl = rng.uniform(250, 400, npl) + e_pl = rng.uniform(0.0, 0.05, npl) + inc_pl = rng.uniform(0.0, 10, npl) + capom_pl = rng.uniform(0.0, 360.0, npl) + omega_pl = rng.uniform(0.0, 360.0, npl) + capm_pl = rng.uniform(0.0, 360.0, npl) + R_pl = np.array([0.5, 1.0, 1.2, 0.75, 0.8]) + M_pl = 4.0 / 3 * np.pi * R_pl**3 * density_pl + Ip_pl = np.full((npl,3),0.4,) + rot_pl = np.zeros((npl,3)) + mtiny = 1.1 * np.max(M_pl) + + sim.add_body(name=name_pl, a=a_pl, e=e_pl, inc=inc_pl, capom=capom_pl, omega=omega_pl, capm=capm_pl, mass=M_pl, radius=R_pl, Ip=Ip_pl, rot=rot_pl) + Set the parameters for the simulation and run. :: sim.set_parameter(tstart=0.0, tstop=10.0, dt=0.01, istep_out=10, dump_cadence=0, compute_conservation_values=True, mtiny=mtiny) From e05168e7d55766a5d3cd22455b91e232e05c3a8e Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 1 Mar 2024 13:57:06 -0500 Subject: [PATCH 324/324] Added an example of a plot to the basic example --- docs/_static/basic_simulation_a_vs_t_plot.png | Bin 0 -> 29037 bytes docs/user-guide/basic-simulation/index.rst | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 docs/_static/basic_simulation_a_vs_t_plot.png diff --git a/docs/_static/basic_simulation_a_vs_t_plot.png b/docs/_static/basic_simulation_a_vs_t_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..6fec4c451da8a11f2cc6e3f82253fcfaf871b0ff GIT binary patch literal 29037 zcmd43XH->Nw=K9qa*l#z1Qk(&0)pfml^hhwDj-Od43d*X1rZg=N)!+!=O`i~B1v+V zBvFwJZ%od2U%T(!ud42=`ctQI&S}ctd#yd^m}B(OdmrnOrn(X-5d#qhgCSK>me@Hcv{@;dOpt1b#RTyz{PUEIx`?_#c-yExu=aJhfag3ax&^MiX1_5!>j zyaE^5tX*6jABght+5OKK@H#kK@wNTDfj)%LQTgTr42Iks{fm_&m3Sm(lfj zwLI$SquaM5wbqsVu=CnkZ??xcO$-EB7vF!H!iy;3E!8hjHO|e@E;TfA;>fV*Cekek zEamQx=r7vU$t8+-`+n87=~?haPJ#Ac9Xkh?W?r%r-+aM;P-9x8IaFx}45yz=`$k>DcKwHC`+VNhgV&nRt(b%>gYvy%0(c zMYF^G9eNQ*Gn!2MtJR}1#?@}@^dz$Bn$o$tvbnlVHl?S<#H#zqwF%iZwX^~r?)^0% zuY0)WRr~477x^NS+HaXkL4Ok+{>Ml$Dq@&gDVeNNpmTj;xWXz($a$#ib z6a=4&%=p7uB)rTf8Ui$P4a@Q&7IX~^nrEHc`HBW2|NL=*O)n8G)Z{{MFzV zxWtg>vVg#BVxNs&pWB*;IM>CC!JI0}*RIL?`1mAA*3ED2726G8f%R=%aLFhuJE@*c zovumX>FFsl_v%4f&w`;|HU&2PWkNy%EF9eQeOG3T=B-Rlk!RusbN7`-z6+*C#OqS>_-T~ngfQ03@baoSPFcV z*fJtv7Nuc`&g$E&8ns7n!F>B*)pey$%fuumno-ySz64xUSzTRmYh`qHn*03uT)n*) zU2}2}@w(i!f()d+Hm;Ge>7ud(Od^gLd@?5g=1Koi`!M)#&w{+7A|ATPpM{=mz2WyU z9kWeOIF!uz=^wv*Ih6N6!}z{ZEKBR|=2G$PHZraRRS3(DqN?fI(z#Eth?-n9>+OsM z`ono%fsJfFlC0PP{`*IoTsX<<_?g{5vJT`3u3P{tj9dd#qc)H^A=_|4mYNbm;wS@B_Z(hf0MGM-irX zH!i*#UJj3pT>8@Ygc;V)w*PHo471qFnh)1hR2qL2-|nvWJL*|^OiN39quieP@5<=# zOu2oYF83WvON$17EP8%3=}bByh@T*Qa*LzGgCF&NQor21gD$VHuYdaVsUb}!=v%e> zs-?R=I}RC(csT6^{fV{7=IhS{UR+K%JAVhSq zyD4Uuq^GB6KK(KJN0qB>=F-hJI1Ex!tj(dMwwH?^RFD4nU`6h>GV-Jc zG(;_JZ5(IL;KED9?7lOQ;1%EPIC;^uuBLqxr|I0xgRfWd=Tf}w0yhpPD~9Q6Aj+*ZHAcP~Z?w}5icIE*%lVw0onK0Hd5E+88mXja6t;gF zpPBXg%^UOm?e+PdY>f|lVWakKL#4LG=FOquc7zz!H&i!o-lV^BpMDp1`M&nUUq3Eg zyj6Cs&gs6YkB_)w6ny~Pt!2DAI}W7DcMju{zecO+lwz2kblDMwVCUxM&i5BEdi|LX zkbJl+cr$TesrB#jaIx=!7v$h8jJIN0BpkaH=#u|teVqG^_TompuSAUrpJFUaG<@53 zIxCepI1=#l@_N(0uau3g?W9|El5vV*L1?#iuzI%GvL_cki3PfU_g|Ko3r1)!kBgKMc`bjpNZrO9gktK)Zu#Ujdx~PEZ)B^ zLG7B}|J~Kr!B-#ECAmieORoS&xv*wKwdT)vH3;M&*>wM|x#rAR$q4uHhje{?eV;lz zTVGv$!0)^70Xe$2zrShLS;#Z`yG`l0rOnR5?5??Z2iXFB+a$?AQ}^cQ2?>1@6?R>l zVtMV?Z^O-)cueAs`26lv*3f8+Iwi37O^zIkfR+CI`SZ^OtjJa>rejX_4cu(+?9Nnj zf`}qupE2N~X*xXEbDH@?S!o2zXI5%RNfbgsf=5Y$r=_clliG!kfdFZO(>0r1Ul$QU z)923N;|0mo3FH?PB+TjL>dueXOKogyJbwI`E%h-GF);`4 z7ua_R@4vyV7L9Oa4)qPp#8_-?CXJVlwRZvwlmpLRelV-ok!jFFI(WU1e7<$D|- z9~2xM9R5R9RdsDTR!WicnPI_6ICU)(jX|@2`M9~8(8VGvv~ycfv5Pd_$A%ZQ#W2f3 z+J<}*8W$HA9{EsK78~}To12@#M_A6#kO9RI)(JfMR}>I9kXs@h>JLsrp}_c8REW&{ z{MmHpa-+3ileJ(*Ru*2qenDJ$2%J!Lbuw*j?ZKxOb;3$U92;=~I7Ho0x3lAcoEWybG|)l#sQpgUe0OFy zqyPjw)Fcnd|s-)gla0zLOxe&KQ``H6al&q}dW~LI!&o%7fi%9OT$)PL$D7i=NBFc(nyu07j@x!|KS58r;Mw+p7-Bhs5)tBX?5QjK^42b zU1oKx7B>ErmVxosKBO_IGk7~QaqtmvQlVHewYIiW(&;9shCl%_@6FMIOhWpMjsWK! zfS|V~wYw$mHm6RVLg?=sU-A zbXU7jcjlRsAbUeV6}v4PURAMGb#{I~azS6Xg)JD6nY4leE=m)yM4$1!p}NJz$Injs z@6usvO=2MfSwQebf21V}fog5Czt&8i9j#WN&mk;KhfWqO#?8adHc4d%x)N6*ORqKEozCEXmj(|AT^z-&!sBYrT+Q%u-Wi}(1Z&H zSAHDzeE&YN>BYhOwY|L^tvLYA%a}p)Ks|F;#by9?-A%^9;c?p z*3{IT_4a(Feonu@Fa$nSp~Q8Rzaba!`6cHW<(Zio>2yst$OEfenUF7UmECWI95U%5 z%4n?r5a8Lzow-!<{Jx?2J;_vZ^jnA$j-fC2uiOS8$Hl|bnl2YMv*23Wj1~)$EG!nR zl&fp$tCr=_YT=CJQbW5S7A`)XX1Lc=oKk$C&}&rS+i={U|G_shZ=Uo0-# zR31R-L`Vq|FzUU;#27`B$z%yUYE3-3=3F4uubtJ2m(zeoZ6!CyFEd9!f7VrEGjwh- zzbKRf8_L(y_>ZRhQ*`vg_Dm^Wi{~pwSHfEsj}BLl_#gbdc7ME%8MD@i&pJ`Jw}Rjq zKkNxqt!qhFNLOoqlf|$~k;S*;u;cL7ZCk)0%}h(fK(413up}w7AB`v}5%jFA-=F2X zbmtSrmseM*ZAuvc5_g+dOS7>R%`K#a2-AWYq!Rl-z1tu z=;iC1|C#R=ar;FNo%8GlU~e(hY8BP(=5_B{cD@Wbm+JGr@lTApJ=)9V;qs2@C|5qn zwXn!#)<3>1yLGs;YMhZT~-fb~F` zdUkU-B?rIr%%_tQ#2mp5un@B3;QDnxX3)1u_ zI&C<)BO^v6r!LE@4;eNsxL9m1_QAI?4!W(H-NO!`3h=i0axn`5&di;v*RMIJP6=b? zA+&jG)?|TWDB~)uI=GJ--{RX!Eg>ffw%*Rp&bHUeXXocvRM5kDN6>hd^CB!5)EPPW zzPC2_0WX|7+#5f#fW#SHmkKEC((R9*~ zb5|Ga9Av5W!@bpMsBh8A)~Oy-g!^#qXWsLeiL4}hSpdUho^#AKTVvj+Br1$~7t923Fm>8>*sgr?(-V&EjSfD>g4JuABQBimIDqxF3=Jc`f7gEc^r>`#{_U1< zN*;9^1|9dcvRSMOQB;iv3Kcv(uOh$(D+440ee}mG1A|%s_)r7X)Fg}Ab`=#BD8YA< zsuY(1rz*$w7M|#bZUX=$s-&9IqnbwEtQGm*KZ;j`Zw^fX$`SEcW8=PXp}X9{^bd5j zozT#kl@FT>GTb`Qy!S9b8UybQ($0ncBi^*&VfbHNs6yyHoGP+FpA7Hwe;8j?f+`Nt z1x2^7umT`OUVeUhpG|ttLRz2A@E^_9+{Mt3!yi`r&!_{!2f3ysb8OuWV#iiJ={`vwiE0~{c9in0M9!#~x&uix|DozDpi6T49P zXqVi|1^`{a)MRrQLP#Dvvx&2F_f^%@IIhS;_xQnm8(5akbMLI5a1vU6I0ZjfuU=)= zcNnd3_68_>?KyvX(CNh+kS3v4fBO1$<(=rT_a)q>J(q*@-k8_A+`|b!Fq6DKNuB-d z>#%(*#B>z)TPYIWWm0K6&pRz=W@k&QSxOB@&D*lnvu&M zO?Bgw!dQLjrS{iOpsWPcm-xmfjvIA8R}1S8y_DmEPYGC>LCW6-!ms$@p4&CpE4(1A z0b_S#!RE8TrbJoh5I4@?{LTehFI2mio!6C(|oAp z9_d*1@2_I)DpXnO$zDHCh^Zl__Vgk)V48P#+Nml=?LA+%O*ihX)-;0}xrQMaSF{)nf(-e<=d)*PxXQF9o1n0|gMxzxTtkZ)HX{7i$8f=&c_3;dLae+R=o;dsw_ zU2zyAQHj%pHXL)K#^VxHBFVj90wnbO(uD@l83Qt~FkY!Y@{M8^E2B2dy{oHr>oVNf zIV#zPWpc&4gI=Xnah#=Ib>l~eTQ^FqDbcQD8g4n%h5*xZsw0svu|s@!KJ!ME%X!5A zzIw%kn)~h1Ro^fuI8ltk>bzSMLF7{qPx5YVSK#`VUtc{E9`iWix6@(DZ~28DQmGlh z(SnGsS?6@XEq+IP<4^u6mFVjqhwGngDJ%?j0OoL~%Wn!uCELwi_hS)&CVu3Q4Nv?~ zPxo2v@7zcH)`otMY9~V(5on^JrIm@}+=sxt@&3-ES0m88BGP30@2~^Hj~HpVAN@k3 zM<|X?S9&hyW+UPU3j>F24buK}pMh!Xb>UGQ4C-PbFZJYYLl!@I@rHj*jkxC!icW>d zlkM%Dz}=7~c7%-Y{}e7TIf`kT0k%IU5?a5OnfCZ~xSSk8KzsZ-j!T!ceEp!f0j=!( zUAt}Ww*rYVRs*nuvwo{XrNkyhbaY0JGSyQ()`Af1jx8m*I@wd*O02Cfg=`&xOPeYv zA8T^({mlq9#f>Ll0!69TweR@}KX!Usa(Jo>?CW+cucb;dWBC0J_rtdqStbr3h`ND! z4&N#S2Y3r#$yicQZq&64Xc1qq>eV)&gb?l|jjv8_UWrK? zW2HXl_R5mu8q4Paa zKH^O5wY3rrFzw4rA!0=T0(uFnd@xrg^79e(xh9L^i5FHWjXD|Qz)=AT~;oP>MhjXl*8!8o8ewEAf{exN{c2eJ7yfICyxjAAXlEHH_XG z_ha?jZe~U7DdJht1qH$oo}2}>p9v5I2zF}oZjv~OH+ z(r+V0iRMhAvD+zVT7i?F3SR(t#Okw#WnVda@~vSh5s*3|CPhks`ysYj;B;2rx3oNK z*_9HFQVY~%39mm5OGWj(|B?2f&+;6C77r3H)FKQfjEuPnLKX#CW_LJr2U8HW^I!B< zbC1GXtb6 z?q|?E{tU#*A2aS)A9^xB{0fW2iY``AfC6S&v(`k6O6J*X&oOM`oUXG822)UT8(asB z!=Qd*FhGK@eZEj+Hd5hq1C%rX%9x4oYJ9E9?qh@)kNNblwZ!^;T*$UcK-U}6G{d=b z>eDkY|CT0$@&EPfSN~hP#O4&x5;M3K2Z~rxBU(P@MT~I-jSTSu6+1tZ5V3(4;B35# z@AX$Al)&|egoHRVL#O=gh)0DAh!ZV+{r)L>v>W2TzX-q?6-)uZ4K!-$v_3!4j|Z@& z#VU3LTWRvPg9VO&+svS2doJZCc@lVQKtEG~#JtkL1~a>l1bDAhW;cq%7H)ew*|@fN z17$};goUAraFkL!Fz2fuXVp4HL=#}!b!gP5VWSmgWUzjIO^&Qyt*h2s>ek~&`sWW$ z6&@Cbh%%I2D*)!NLnkn~Tt5EMu6z_vB@Pu(boy((x9lH`0$B8!jCd5aA zdf)@8p+HsiKV=pOgH}lSF_2jlpT4+s8xIcs1)7s5EkG(Sm>rFKEJ++RI;A6NY0U@tdZ3iKm;dwWmzEo^#CZhFnuGm|N` z;i!RlZxzD3`6YVP9v_34mj!enoSiQt+F;nex?nKXiI0oRzt!T2DZr>?1_4US?!nhN zIRtT>Lc7y1iZePmg=Gmw0D+>i0=RK@A<@X0aO~lhvCrOe`ExOM-u@!f*xy}JQW@@9 zbuR?0n(WIvilB*pm8-`F*fIWN3SR;zVf@+aHtw}>>z-{mo+lqIzSDgONuv!ogktB} z&*2LLMh~L*S5arqD#-+_Uki$s3q>{WWh6i)fX<_5`V7EDW%!&X`0A&#N;kbulHjqc zXe$M~>Mv4B2*WK3OCJ2u@!1-6pC7CB{%{ugX^ zAXGyyXiWi3J0MWUxny?`ru9?Y*QZ+F85V3qON}UDV4L?3x9Z!59qOZx_UELWHNI`k zcFcMrm6DM9Y=ap;8y_EezCn>>PyWcgjG+g>e~h}1N5@JX(xZij+;DF$7kED)MGQ9| ztjf#(saGPva&KTxxVxmcOSXJfi;KnsQrqJfFCIakI|AYD0i0E_StE93RL86=obE%o z0S3kKtR2@^=Sqi*6AI4Smb=L`WE#+VFei5`QR=-1g=9CApMm2?-(DslE&-<)4mY ztRIiXB|ZsDqmhy|ums`Ac+j$rm~udLCom~K8!Cv**xOn?PR+FL1~hOICYwSq{_E3i zO4m#QGeeg^1Zn}0uam4t+xURXpFDdO3TqC)Skiy+evE7j#CG!SreMMi*JAb2?6CU1 z6)^-K#N1bcfd*!y0Ffe~XCb)T8V5-gBrM_;tsVKMW%h!v-@c7%zwS-Q{_>$|(ZFO%u=Erz&hswyeXA}0Egdw#fXb$vI`5;h$EZs z8ir`RMzePU%}a5|xx*F9q{zVcZ%GXF=HS?XH>?fRAJXb%U2BA33a>v{cHqeq5D=g? zeYi=B=t3ZXZd`o!m7um`fr=Fu0O79b)@-8bX&xS)DIsVPfZ@X7tNlau^UI4MI94@# zE7e?FT-I92<)dzlK%++@9D4pdA>yph6)6m`J?fFzc7FEYKj0SVq>*kSaA;J3^#D2X zNkRf{vO3+eV-D`iVaw%8-w$)h-D5$7Ofjb;&L0CDt}Il4z<_g%=l@TBnQ?!yHy5aK zs5-W5W2lBhopN356=3~w^It{b@slS3XVjiG04>@B_k<*3Xah5iUH1+S|AxBjA6uGw zagp5vp`hbapY@F9t)^^ zUxF-@Keq>*SS&O*lfVu@egSgs7(qbySsB%{(DHC=Gz_#aaKKEhx3RX-8W;t1CJD=> zZ&!9rrH8RJjZ{7;hCTu^&WP{c^4gBiHuU(wRTV#&Q-=fRR%C0?f|?|YILGQ@tNC|1 z7pqr4l0GI0)$ej|CKWb=eRf{$K(PXAB+n^qVC<^bA`VFEEW(oTA)u9h?y>svJOHw) z_Te71P!)@L`G^!pU7cJ0wAiiV&09Q8MNNIlbK_18kb@MmW*al@NRi`u0JsR1-5Vb) zkvvO56oLtkPuy+qgiqr5S&am>FsXekQ@;ZtL{}QQ_UWOHY_3R`<`|Sb=UmvFuXd8_ zeKx8uJnka^LK7JVfRJy{RyK(FfI4abYk-8V#6=@(Z_n!^X)1p;vzvZ>3t(~tG$T_` zWZDKy{i31c0H%iy625!V?d3dlezdN|apqo^lk2{6?>pyJtrsFr7A@YO68|W*r8Dtf z7JB7A=85qKVWq5M<-g*ae}eYw8(nUs?(B?jwt_ z-VzC35UTjVk!!WIwwix`t+EX)&iBSA?xbj^t$S$R zxDgJ*@w`hFIP!SD{R2!)r=Y0)7Z2b6O?&ch-G5q9=efB9IaPktcs?kRdqi~1^=Msz zX3WTUXO>yt6wVK{rNBcGV-O$*cGT6?HH;_o!Zf)R75L=nAx{JJAS*H;2r%O(NXWCz zCjW(C=yT3s|8d5s&-oJdD#=jbJb(XGxW))#GiV=Y5PU}LhZ=7s4)npmFm40rp50m^ zR|6xFIplSW|Ms>Av{2B|f42McUzwc&oq_4!KsfwMPTq#{HB@77r8=Nq3yEonYl3)k z)7t=wS9!fSnN7iaoy7GYw__)P3TZ~(5QqqTL}Q>00`wW~4ESezJ~P%4H3?ufLq-u~ z3;cheY6_=8VroG}_}8!dHwyaIjf-L$&_SKQ=mKK%G~jhyjQGKy9$*?z9qta)TQmmZ zQqBUO3F;Sy?dsK=>gpiZnRqRnL4XRW%osM{aF9F0wy5^xlM(UFUY&~hjL5GIhOQ+4 za0|K&xb}XYBMZcC-`|VfGM3doTJ84{wfTo9A&onk+65qaKl~mLUJeglbsyi4MI5I} zvZP?|DHJ*BPM8vBRw?o`xN)>fFn0@FgSi+4zY@= zs;r92qy2IytLEnBLC#1%hF%PgX08OUD^Lm;WUcDKBcaCt426p-k;t@S9|w~0Cume+ zTO;Xie|~yCJT|uNcB};6oA>7Ay+DzMBd!?$ga<&jV*63i8fdwq`v(ED!L}ps4pJpR z{s1E%i^l}k{(7vRJhV#BFWsJS6nSUU#|Lxm<|T(7cMea1-`=UdjrcO?(Wc&a z@CJeVrAI?*)VixPUPJN`B*%%bVyp6Cp+FcGNWHY~-D=mRP|)J2{D34_2dRVwC8T417|JVafdJ^SSfV57NA#{pjubxx(ndkD=?_Zu;g-Ql)*i&HkXaK2; zJ-7kf4Qrn`Vke;I#=)T4pbYLm@73Bcv6YHUnPgz%0Kps%Pdd7+s6u@#?d}vFkAmw? zLmg`?0=~sMj9Q?oS3np#F3b!cBlpFN@&HGX`dS$UtZaqTG;C>}Vtf+hcX9B)TAeim zDB*@!@?k+!npCc<7hGP9KckX87IYy9W=t;u+QG$uj4A*0x{At^aj`yV0L{yXX9oaq ziwZjeGFjBFy4KYR&Y5D@C4Jy3-Zy$@`<{P7kwqKg&Wy z!490&0DI<*Vhdad1lO!)=vgv8Nb82ZS*cp$MT*;Ym*3%u4}%xCzTLQZa(?qasR2mi z2SpvY9MYghf2a_=FVj(*NJsl`!7&E)3E-l0g4X4;>D1QdfGJqEQzxw-LF&0r(KnNI zhV^bdCn3W4Z*P7Ol}ghm5Ivws!8~0TRgMTH7vGERZz|0t8Iu+3T{ug>5uessc7=;^ z19y_oRd!oeT3I?6hk{CTUhkWWu#C3SVT$r6#$fMTxJF4G6dO2ZpVUH~Zd|6pa}A;o zkqUm?K^`L0mzI*X-C?xGk`u~3h_QS2MyAG&)_G@gNIxKLl=$HhPEK_a!$U4{&B@UE zCejdf!VnYJjW?mM?R{{BG?zoXy>V;y^3qDI)4SAc1Xt3Ui5=3Jo9F^xYh$zWU3#2 zmMotXnGCSL_6uMsMM66;eO$C87`Il<5&Dlo@3=rGV9vEyU0atzCKQGP#^1Xv=n9bA^}2n>V?Kga z88Pu{jRyBmSgsLRp_94aER|R;G_eMIyVKTq=cn=Kq^(#6W+mkg{s65(@3hYCwbJz(iIrl|#s5UiACg`f+h1)TGvI%LnB|QFXWq+9q0!)c8 zJo~}$;wDz?K=880$nWYLH2P=So)>l1{b^7VQf+ zD_~veyi1_##qcFFyr+SmlW>vqgpZQ#gqYC@zuXTCL0ac!dPYgETQUjeDti3YYpkt3 zUGrcdTf2c@gfi6pJRF;vFs3!ys}o}S#5m0fYKvC&o;$ z2Fi$VVyb;jYOdo?f4f5;nk9X=huwNBbV+i?f7O~tHU&dLL(xbfuPLp4K5fA=@N6^5 z_0Us`x*Rq5%Z_%UWDs!97cpt7-<$abPleXp!C^M3a8L2KGB|@hyP}vRYc6`qJq|06 zQ-Td=Wcb3Q*!Q)hJX$9Pdc1Qo@#cZ$pRiT~Y;Zm^6bX-r_=~n;uE&bx^ju$q{egoU zEc_!aC(DW{s#ynv1;N+ooyNd!mDcE{bF)Bh7kl61^m49eT z3zXy|{Ahk&(_Mfa&aJztkoaESgoJh28h*1%iVX8%y%wo!1m$AM+7;b13=>i-!L~X# zMHULyJ6!X7qWH-)0@$TaX{xTRJX&k*Sx8JQDzQn2Qy$e5oOoMP&Ri3V9cyca zdTphE$dq8QDC;`DobP3qhtrc%hK#)K?-&RKi{&n0-Y5|3)sTJmU=Gw{@rY!S&N27A z-X%is_k<`!pK#!rvxi%%^*bN78q<6#7tNM?>F=%6!+WID^_sk4QLw~<&p8iUzrV;& zc0JVB4BMww-NQ|c8If(p5D{p2NX5CR=JYhR2Xbq%)~#97Y($4`NejU-6BNPgJ!MHB#wnAS zMBw*`dZl32arN!frD$u5Oa`L(s6J&ht4ar5p-pnV+F8(iDRmj0ff zrhX-OS}(cg(*@4$*uE=XU%0>6(1*Qg;J=6~6GonroZz^cBmZuQ@g}eO3D*o3)yOMM z)mo%)R7fdl)|j0eygyME+X+g1;U`fGVCN$wN+vp-Ru>U|)>xZM0`JHA5d8A@^-o|q z^U9pO^BxntO3~y>;77pj!0+QTV0_3K%s1~vOH;Mx%j&#C>4NLuaDJIxWn;I)Gn^Ak zmTiXgN|lsaUc5?-;-kl6{*T4Jr5W8+xN2FuO;Tr4N7B~OLE%trvDP5t@k=AtO#bjH z zOEI|{GsWSkWD=Aol`XXVauHpcqkBG5QaZLu*1X<1c~)a4&Jb(VA7_4daN@%I=F(Ex zuirJ^@Y^O1l#yTKQlNJN_`?k26t{qdt2>Q^fO}oz?0+c7=m-U5?|Kn z#5j0Yh(3r;WelEN)IFg~=vA?$DMm5v+EAsF<@*sOkoGcu>LNlkqiD@BA%JVmm0>9!o3GM-W^ zvDHY(j+w!YFu=gD^xNE7+3g@mETrT9LUh$QIXcnbEN@}n;0%1c9BjiVWuR<>t9u>~C%=Z$ zuJK}Zn{g?w7NCDAk`(S9}C{W#K~$_ z1Ge%bX(O-3*N%NQXE+P6<78z&F^4Ow9r;XQ|KM<515|Lci3)ipPneEMj8vyDn1_D;zUJ*2OhJ&c)^Kayzx)#!q=1(zXHgyK zX})OnNtR$crnjN8jAn&7LG$Ciw9cp?NXR8GoM7WA#@JvR0bB&COJU#T-BwGUGenN>z|<0CjhAH!B(Ee^4BvWa8i zsCzWY>Cf8Zd^U!f4e2+X^*O zOg)AZL;#qE#FM{fR1znz2DXq*b2dOWI}n0jmvC37EQ}78eR4<>kCFrPXYIM7Y#?K$v6=;4Imbd2t<6%H zpD(OAEAwt~=I`4LjH-f%pJ=5WjTbGp9!tfQ#KzL%Yw9jEc(i|ls30w^DiIJOXiYcJ zWco`!ZHQ6*-NVK;Tmgze$VkRgj4ls-CGi4KHU2KhRk7CiOylN(uZlU&g` zaj9|oZ8>Ra>4coHD;IdDeo!@1h*ztpxf!2FK>b^O+EOa!z#qr@!P|{*H$TlPrF}o) z7s8m%z#3S3xaRqJA&h{~x+*EHvjn1_Bt)IoJ~Dpq!>eAdGqB`lOfN~`#>FN1h{##w zyZ*3zQ?&`+m%&-|jmcio&eoOIa-b&=8BCfcET;>c43_!M-CV0Olp1C|W1d~bsT3Z5 zC%f>RdK_m?iJ@{F&DhrHx!7!J0-^$LAAx+m&&x(&Oa%7Gr}`IT6tkyEEs@5d#`#IU zqPi%cBBsHk_ipfh#jp1r{BwhIW}5SBqr&4;Q>La2PD~Q(E!5A2Y)=9u{N2wl*wo~* zg1R!*<+ye2M&gQv-6Y4HZGNxKE+Bn;{6XX}>wGEn{OEK3jrCC?T?0My-nAzlJJIz` zb6e9d^ZkN6{T`mODHR#um6JUnpdpQ)rdKlnwpkL zT1wVn>lz`Awui`TQscH_d4d4VXjT9ka;c{%PVYx)KnHR~ps?`+#WHka>_Y1oz z@S2-%Fnjn6Nc7N)Ooo=Zi$DFCN}aF6_tZBQzi8yo64@;`+mYXY>(lKg`Qq`hu|OF{ zG*&A}mjm;3-CvW0$-!NPW=laVU8(u4{>txg2aR8WK>$&DZLEGwFg1XMIi7RLQuLD; zu_?6xSL1V0S8i}2JO;H0Jl}}J-Pzdz|CI-Dck954PY>A^w$=))v<3v>J9Y{UASYzS za@p`{3+i+6HD$k&k`qQ;UN~@N%@d@$yc}oO(`VN0?{^pOms${flS{mDbUH*G*Dh9n zESc+dj~lL9T<-+d=+WIcPMK2!yJBCS_2w^(d8SU?&zmd0VB6WLsiqRgDK$WM0jw&B z?EyWM)NgNi9O>iW!XiVW%O%jBF%4j_oY?@15-C9Ih~*|edC?zcP+;tbQ)MG@ysRI+ zf;Fd*nw2$nhj>m7<}Hu>51)&BUakX93$HzzQzg4P>XlQ?d&E_1-z%+{TlQ138!R}s zBml*Z*vofd8Sw$zrN`mU+&XyIm_ajc1(rJu7_r;`7<>tEu#pHTn#|8I?DzY!&-NN# z4;~p4!JCaa93ikAgS*0Z>-|@pe`rFmAgzDXG=K?P(Eaje{h1_oTcaT?d;O%u26 z&Lho75EN3dpzMS32JQ<80~V)x|HuDlivEAvi>~gPJZeGeZ9@W^&!283P44DRv1IjQO92S* zzd|Mq_wrmU!72W{iKiiSbtdy8LIcj~IidlVWbXQE&W5d3&wTc95&3b<53a9*(5E z#R)VG-T;htsE}=cT1Eyo_=7N@7EOlFSguVpZq$PV0fV`F_b!jBJ(^inPd?VM&^ZjD zGYLob9A^n*($s&%5)~>MhP%2Z1X>r7R$UiualMb{ymjL z%{pFxp>brX?Ep5x)<$o(em=(#p8qR?^E457U4+TI4I5yPK)D2sNF(zY@_N7xmRJgP z(f_0FfMr7p9W~OdBCyB7kfWV*9UR7A;HZq1+~q=J6@OO8S%DxfF!6;s3*-W)dIcdM z%#{d3M&Rko$qH?YAo6TzulhH zm#_F>T$GTI5Ix%fITeuPQ33Wm!`gk2{xe~841@@AGA0rKo!@iQM+fys=ju&C`$AU) z3%-cUJVo8%t}Towmv>0IH=}Lg`V7NO>tIMigJKmBHBK;oX$C$H)}~E|UTHERV;9=}8cuUs$!sjb<*< z&I1DFj-zaNeq+hEfr@#2Rj+t76cxSJ9qEOWcMhDG1&zC zEW7DlIDVY${$EJq|5i-T;7Wob3g85aG2NvDkTjqIF;`twiCb$wm+E4jY#f~@A+QQ_ z;V`Zd+BFyX{1DW|_r@|{XgnzDUU2!>L^2r^btSP^9}JVc?2(%V4mt?L7EpjYahM|squ;oX4uwuYoLZlqWc_i^Kg^{x3CHTQU#w5>!CA{5qpB;c433C}GHY}iT!f~IjS}JUo*cu4}JFZeqJ-GU>fg=!RDg?)T zeqTqUz;MoN9-z+E=I0TR3>xY3ZSuyqp(HB4Acf?jI({tH}HQ(OCVJ@Pb^ z1z&@tJ!=dJ7!3l0d+`z8YAv`gD?qd0zx|N}h6c@`3?iG-TCCsx36@wTUSY34)<_ap zOqG1-28ue34FBLsC_93VAH!Z&>&1Pvk^R*G2kvGBX!)_n1!c`g!b7WX$uW$ zorYP__Kp7}lv#@-NAqLO+&(!uV+2bsfwvaPivX1K#3g8m&>XR~OYm!WhDc|>XO)K0 zKRJHq;1F+C{rV6{@mw@<(`ssJ&7k2iez7VwOfvRWvej|^4MO&3a()T0q@p$l4ZyI2 zp#iFaOc<_v`VCOlfg(SB6j%Jyr@=7GsB~=@3_ca(?HOO-lyZyRHj$9)6-*{0g;9zn5 zJb(^k9YoRFFocH;xW{wVP`@_z0M~5)OmfhKIkmhzZp<;11Rap@XuC}cJq-f|Flk(J zPbHiRGzNi;5$I6Eh)6I@c}}8v14snDG5yxHWP4OnFyb_6D(I32zB(8@qXyrq?R$_o z6^x9GS|X7=_Zw=j5(zCSOhI1If7<}S_;`olfdj}n50;bDKdWI39odgzd~zBkQt$_% z=-4>`3$4ZA`@8Vq6lq^yNq@)eRs=wx9i@PAYBDtK1Oq~4+$K;FV1NXfLlM62hRxeY z;2GRbFlaZ_O;vF2QJD{YJvEGCO=M1F=e>O^Uv58&9mA>GSKw{mE4M-0qL!1R=q@So@zUP0>Jk_rWdVi3#U`#(@)O7wQD^FbF!m! zUn`9Yxs+si^vVl{em|g%ezYintiH?&$B$I{T<>~^pI-D}Zy?7G9_UnQ#C7395Io{& zvnW25?D$Dgr(C5{0rn z1<$W?n|xgu`){9l_1}6z*Z--z=RaD9e{22u|I;te>3`X z1OWg6*x_%$BsAR?3nQCi8PpeH^OI>aUZVM=|EOwz4j_lIAj>0a=+M{)R3PM=(bUm- z5Xy0^#D{RdB(9%{Q*(q2D7c$Kfel0H&8WiwPaG9y4UFjM!9c6ETP*0IEdr;w(RI#L z{Spuc+dmqAhZA*CqsOKcjhw@PP2Y?Uq;s+`jwuBQoFlQS`_4LshC~>!Mm&0+5*K&6 ze&9K{8K7qGBs_W2o$CZhN^9Wz-S{NYI8KFqo?vVKg8%H9c5w@b&*=@3-+Ynu6Q+#; z;7>r{xA$~>{><>_XKyx)p7z;@Nk}4N!%MhYJWwfs#E^9ys1ytaj6d-7Br~XcS}}$9 zB+H3oBAi9IKWpk}ky*LYUMs`-QFWIs{TAMzpCXlS$Cm;=R59>+)7J3P?Xw8`u#o%M z3qR#PbMgGWcUiC5c`p$Xy`h46{8y!pPnp9qYe-fM@#U4J39#5@F_`#1JT+DBx4HMe z&Husp`*(#cPM^u)zKXZEt}Pvx)^C&k-8#L0A+4LyETX*ej+%eJ89Wn=Lbl;OVSSo3(tIRv7SmMI}n`P6&FPD8b`^pFfrYy@ts(lIdm? zu*kZsd;yuiL^$7IpUo%z=)oA(?=e3;m8QwX@t3Z?i&*LAsb8~i-X$`JWtZXo4CcI{ z(>y$89UaE0LV&lw*4y7?Jnf&Ig$D~fB1BffJb7eGs>u0w{!vR*%DdOE;Yn{W0@lK^khwR++~<%H|iNjH&+yyE6%g8HX6q*PT_Z0X+QH*~(w*wLHB zQlT{%n2owo#(CaMUD;pg3~Zckj^InjYb@mIG_0+UZY!DbiIJ76Z~d-HnobjFld%<) zwdMb`L`||i$;B6+NV~RYUUsIz#aZIom0K;ortZJ0fAu-)8#LZ43LQ2N>o*H*e}>WV z@krIm?IXYqTJs!P^Ojii7Ka6FFxEMtVYiKoc{a1QZm*(}5KCL%#!;SM-5=mTKwRGy z=|2$ZKTe)0#Ik;G)J$!aEV-R?wO%M;Hiwrdq_&3UG-sM-$QE6QHes|n`2!28DXRE% zA$p9oq=qhwL{tPv*hHaI1BKPq%C2Fvh}f`x>p)m)?akk_A9Zd;Lg>Fs4B7IoTzP$` z<;+;)%fZ;j;%BI#rE^x=1DjHI$r(dIJmsl z+uJbb)HvrBHrzcO@YR|ql|$#dnfkS-v9wmM2|g@D9<}gg2|@zFIlvi$?WEF9`5WUu zFe_eJ&!n*YNOeb?Qc{UNO}MSmEIMqA>0GP`&Iv5oi$+*)$EhD$%0vntqttQmiNW1A zL9)3~^yzC=Mmf1$a@X(TGSSYiiP%ymJ|($jDBP0$reldWSftV+WVn6lZAjZ}@W4Xw zz-+K#ww#ZR=v2>lbMZV~7Y(#u6#>m@?a?i9%AD;+TgF5k)1H z@?N*|toK>(`%LRy?_bYa$3LgN*}wg}@9%y8?(4cfU+4LSeMi2}ti;tbtvEmxVh`4n z=zQn*O_teHb!~FH@rNpNF<`3OTYjXbbZA9Qu z0OuALrQSPyBAj}8?Es&MMXU@k$W%URuq(N}U2LBTlJ;hN+m`KFHzHlXXZVrE8G+-$HvDQ-0_EBZ??Fa?XE{tr%KQ8h{lN?iHRNbxI0*I%V9=Q z)lt!iCibpQ)2!U(b5vq$%3-Y;X<;ML%6Hz&{lpY3;zZY7nvt%|%jfv;ohHRj?VCfM z;gOuk#!9-TfJ_Wk?B0Y|AOXK%*T$OF51S@AkO`)eCySXb$D*6?Pm@P)a`tlVTKABR z>?SrWl$}%Futlf%UszB3l6rnP^vimgZ`WVg#grTkdJ>-WY&E81&-g{d%;v{-Wy&Wc zl+#-eq__T7*t&h-W7@YfBJXT6S;h5G?GrLM$HmqQbK;?8&4Nxo#ElsSeK^}HCTIRJFAsJ?j8vN{)Z^-wCqq? zeh4i+#Gp_Wvou*)X|?ZJQak{O< z7_sLb>+p^bzSSS9YWA+QNMyFKbxxlwGRm(x-6E1py-9V*&mSm|UzS+YXC0W^JZY(} z@!L^%Q4DBO)lv2_UM>qARS$e&7ue^-Cgl3r!XVid8@_F@=|oDNFQTL1508}6mE{JZnE8NmUva>NQcmq zlIpC}S~d7t;)>Y*YK1{P35wcTxxDBNGKZFba$DcoaB5cvt<48aI+$BJ>1Mif zH*%zCZ6?NPS;Y)x@$0k&g+09 z_(uo;7`b}pUAIqb6t+LwxRo7CnnR(^bfIycQBH2be&Ys7eA}0bD zEkD-x>ayf_Gb~?xq`fTKxwHo@nriv&A_ZliMGvdYNMfWi+8A?-eR6Yq#icFe%dP#2 zn+0`V$oGRLU&n!%ct&zw(FMCC37Ye( z@y|_4+r*T4+mdsF)6-ad3^!pv!goPAX~^yMWB+@c*nrL0zkO9_nqGpHwh2+jqMEZ;e^tCmL}l%0w%l6O<^dy+DCSyl+`gH2Mx2;#7;|q(tWhgO_=-cZ#TA8XV--Pw% zHWn}}kXWnTJ3LAz{oOad(AQ_o)L_+g*NE-TxaIe7EdK7dAf>IBgkoc#zE1y1XXd4F zY|${D^qiHjJMmFAKcC97T!(Gt1P{xURM@Yaf%sCMnKMj?Vb*)l0oMC^tnKA#U^NQ0aU#jzQ2Hq`KRZ>+EUcSt2mVzjOO4GG>JM@j-v_-?Ak(PUA>S(mq{JNS00G z1?15@OkNkK=H@@s2kdcgNqdEeh&{#)}L+@#b#0>#Y!T@Hz*Wdou7+w8W|rn z^CG^tebc?=d!q3Ylc|ICiiw0j+WbBza7Ep;Fsw-H)iE!Xwb^{IT1KbPP+lO4ULKxY zG!xR%)ZO`bdl%imAbZD7cbkch*80+?R(5ac6$SMAC#m$8ZNDBp&vTu7f3IR%pWAkI zgVxFZu!QO1$Xn;ve%Fbuqiz4L9wAlyl9|`v;`HyalRK7$XLVFJpJTIIkhPbJs((f+ zoBli|=T$vfcr2p)aBn&Lp5g(Y?)yLA2#z`CRqL2`nB>a1_U4uOoR=F(_MuB~?^R1q zKCD!}TyOC?e~Qx%b>;l>-&&WIru>n0;AqlNu92!_QtFi1 z`Av>WavP^4Ff!9z#xt&OJbSjtE|hn2wjmN>O&qwD*4XWLZF!jB;&gcPpu+DLPVd*| zf1kaOzACb*=gs5uKW%HBK3n}o=WSo^HSJ*k>$!IhzD|98q@H84Rcmi#!anWiO-&sI zszYIwjt8opUu*qgc(-QaWp|JKb$S7#rA!4|(=ET&lJX4J?W3+%0y-5Bq)d(lo#n6Z zJ;E{7+jdF2Q0>Q+YfRhHk_=yeFa55?JlD~hYv$j(xuR#S$m7XA>v!3v-s!xlyYAdM zk!`c?$I<(5EgrVMd-Hky9|==^J$_U2COW%yuYE~8`EqUKPWn}cB}A5F$Cw;BkEGQhcui>(pfYqPOg(lr2>Ui9Zu1ABX5N0lY`>l5*G;?A%a+(m70Wj&X z<|;H{E;R9FOvmp`yOp8Iu9@;|^0O6St)K=(cngzLmV;hz-;6@;dq_ZLI0lEHIz(g) z$a*gHw^??fs(6*TQR0>ad7n?hx2or8Mn*>45Sb+o1IRi-pf{*0NRgwMG`gpIiFHGa zUFd$i$M&lD-W}vXsExKHi~grojz8m&|2o5)7Vb^4&0o9dw;{f$`gQT+n6`!Q%C#r= zI=8osq)xP*kQh#sI<}oe0$B^~$=~Baiv>d}O zVEdJ^WH@JNXa$Q(N_JTya?~uc1n$SF=3GzdWhw*1)R{0Gw+mko&bZZj?D3nd$iAMR zf);)A?xi(A6NJ;vR`!PbhW7DHNm!c;HQ`3`O;BQ}Q(pu8I)DuPGlR*oVMB-IXCHjl)jid`ao_+yDFV^FHcFG~nMDg?d}%@opdTJz&& z4?MWv&Zp(lRX@dU^>FyuU;m~1Yn#eODRZIB0kua+`3Prurby*;5&fE|n?QIhAp&ut z35vjm_A8$p1iY2@NajhBwDJm{vRz%gD&v^P#JNVExsgL8xDpbNB{CYZN8oXsqpXr& zeZs)}6h0y6>yZbwt^oEC^eUWP!n%`yOp8BQa3|8Q@caKpO{|3UE5D$*fa}cpSURS; zK>xIxAOlHy3`eG$B!2)i^EA&mpF1TRxT^IL2mNiVt&=b6;WBa}##8~9=nFcQRSa`e;FIM)#g!N%PG z$OIvTvdZ)XkUZj>`pd+fKtSEVpon$d#H;i-w2j1GbG%i>h)nSrP_Lk#2Et0<2gQtmcWU51zo9WqhR`tchHpINlz1nit@TFwynaXfd8!oT=OP2y`hUjz#gV=*3dffx3}C* zd3otp*9*x-(lmqPhpQ!l%KdX?L7PYH$ZZO|bg$le5<(v+#i4egZ8jKD1IZpQ2&4jd z5;DesY!phnL}h?@r0nA(4}$@up6JaA-YRi3KGj6iyL{ye6DUTo~r@^N4Md24<=}Ekme9!#q z1i8r9_uj#o4vPS>5kj~?vbKgWw6gjW0&kd@0j&mHHNhECL95_IEU*ZWfgwn%&1{95 zS7hDNfQ`G{dH>v99Fvtm{4WOQAT$S{_eMoz${#yPN5H0Y$f>(r`>03L9xxxYad=Yo zywtvxXn3{7HjTC5#XfO7!cn=-@b z<&ck;?FS=BnTZ!C6lN&m%=7=Y2^aUZQ;}5xCC1khB&#ElHCKr-is@8Qy zE|8WiYstO+3Tc|Kfr&AbG(~~N+;?V}_3OEEuR4MNf}fR#bcdkaM%N6&{vsJ|O1X#a zI7U1%o$<(s4>2zj(n$_OodQ;-%%RunXXtJP+TWFUDGhxu^Zx-CTDIRM`)St)OaynX zNY$YE`FTd0iP4>6Vh2I{3bGLt5>ktk^O6IU}7=K*{@phVfGo?A~i0F>$0l$-fwXb~g= zLmAJG?CI))f`au$JTPm=@QVz&@~Q;cFDIx#0{I1mmFHeZg0y0p)`^jBgHb0B)L=3} z<{_X151X{3PTJ)GiZxkMuvex8fLcYMTg)58Yw=Np6Hk~`yd+C837wyThu)b~k^~bT(#C!wu?vhU! zo{Yv;Lqo%5H~x^;($)?^6B}6gN^F3-?mJ!uPBDj#j=7Gp@wx^7MbqkP;)lb;Vd0Tx z5rvKvznXXvpoB8SYpiptFx=W*`I+<&IQ}po%${(xa4E}9ou3vaPQDKS3UMtNqyZ2i zHFth^>tYzRPKwjmi&yPkrFVA0Iz!=}6Hj4_y=Kw^JR^!d0@CXx&tcMR+~Z&rmo`Cz zwF!=?1ab3lc(KZVJ8Xpl3#i)mu2(?&f{o?Q!-h`>2YniP&8#YS?H5nv0wDo65Y8K+ zMAN(8V({OoT!rBz9Vu|}kBC7Z$ZxmmyluJp!K`iliVa5tz!0)T;hA-WF|!g`{5xkq zo&>J3BvPRsWtGP-{t;+V&43P2dQug_8%F|_InJsZptla}yDv5u<(It$)Od!p9`RFL zAjmZzAD^JXyjF+y;X3}{`LF2%psZwJ`;-k=cw45B_uA5$~2n`9%H#p#!-2fiz zY$Mtz*^rh1q$B}P^90=R+OiId?(sTy)EjZ)U<(H@FdU)$2hGt0l6{0!Bl5$-EtP}+ zWr6+(gqb$IqKa8*WnskF}CWjA` zvg|fh))9_x^CGyn;n+U-b1rBl?K@8_S=pG6R^zX3&ekQ1EV$J?wSc!RrZHHV7tR@7 z;uVB!{R9Rla>;xXZg+dFV3vD)vSd}Y#ZIyeVYf9HwhNo9AxxhQCreD>1$V34AuGT#J;5m$%`-lRrj=i=grVhEd7&3J25d~7pkmc%jJJSlEZ5iu{973q-&od zWpL{U1#}w1MtGaLfoIV6w30u0Lwi)yo3~*vhX$rGm>7fHd$H6IDk$0yFk&M` zp6lUSYc|#AliyCzh5BFc%ZXo#Sbed9SwX=)R10zkm9psG>}mkR1Cx@t2@SFmd>i83 z!)|{7@tP&H5GYh+dqN2yAY5TIfQb>%B!q85Mx8YYHtc;ybF zep1jjXv;$Y=PrU|VTlTC>mqP*{1Smg*#fYzO-PzT+QT4+vV=1u#VP=E55g^WJ}Pa) zpMBtrKZS^P+U_Vgds6lwC0N^!NQAr?VKPEs0K$bh<}wYq^l$kq1M^6l>3OZTh DoV?&% literal 0 HcmV?d00001 diff --git a/docs/user-guide/basic-simulation/index.rst b/docs/user-guide/basic-simulation/index.rst index 7b8d34463..32bd6ffaa 100644 --- a/docs/user-guide/basic-simulation/index.rst +++ b/docs/user-guide/basic-simulation/index.rst @@ -139,8 +139,8 @@ default name of ``data.nc``, which is a netCDF file. It is read in and stored as Here is an example of what the dataset looks like after the above simulation has been run:: - In [8]: sim.data - Out[8]: + In [5]: sim.data + Out[5]: Size: 229kB Dimensions: (time: 101, space: 3, name: 9) @@ -188,7 +188,18 @@ Here is an example of what the dataset looks like after the above simulation has j4rp4 (time) float64 808B -2.247e-18 -2.247e-18 ... -2.247e-18 +As you can see, even in this very simple example, the dataset contains a large amount of information about the simulated system. +For details about the definitions of *variables*, *dimensions*, and *coordinates*, see the +`Terminology `__. section of the Xarray documentation. Xarray +Datasets are very powerful and flexible, and can be used to analyze and visualize the simulation data in a variety of ways. +Here is an example where we can generate a simple plot of the semimajor axis vs. time history of all the planets in the system:: + + sim.data['a'].where(sim.data.particle_type != 'Central Body', drop=True).plot(x='time',hue='name') + +.. image:: ../../_static/basic_simulation_a_vs_t_plot.png + +This is just a simple example of what you can do with the simulation data. Xarray has a large number of built-in plotting and +data processing functions. For more information, see the `Xarray documentation `__. -.. toctree:: .. :maxdepth: 2 .. :hidden: