diff --git a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml index 24e66cd999b7380f11a201b35ea2f929c5ae7a93..b7009a7d3b06087d875c10aa1861a8456dd3f4e0 100644 --- a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml @@ -30,6 +30,9 @@ Snapshots: delta_time: 1.01 # Time difference between consecutive outputs (in internal units) compression: 1 +Scheduler: + links_per_tasks: 500 + # Parameters governing the conserved quantities statistics Statistics: scale_factor_first: 0.92 # Scale-factor of the first stat dump (cosmological run) diff --git a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml index 7d47d39481e2f2794e83660ac0868d624e6b38ad..5a753cdf0da41dd4ec102eff351a83658c4761ee 100644 --- a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml @@ -22,7 +22,10 @@ Cosmology: Omega_m: 0.307 # Matter density parameter Omega_lambda: 0.693 # Dark-energy density parameter Omega_b: 0.0455 # Baryon density parameter - + +Scheduler: + links_per_tasks: 500 + # Parameters governing the time integration TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). diff --git a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml index caaebdb7c4876b0f70459a817f3ab4758d833216..cfe76f51efb0920ffdb092d6af7db0104db0ee85 100644 --- a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml +++ b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml @@ -25,6 +25,7 @@ Cosmology: Scheduler: max_top_level_cells: 8 + links_per_tasks: 500 # Parameters governing the time integration TimeIntegration: diff --git a/examples/SubgridTests/BlackHoleSwallowing/check_masses.py b/examples/SubgridTests/BlackHoleSwallowing/check_masses.py new file mode 100644 index 0000000000000000000000000000000000000000..c7f1d7b2c1f90efa285c13c75f0e5243f36e49ea --- /dev/null +++ b/examples/SubgridTests/BlackHoleSwallowing/check_masses.py @@ -0,0 +1,70 @@ +import h5py as h5 +import numpy as np + + +f = h5.File("bh_swallowing_serial_0001.hdf5", "r") +f_mpi = h5.File("bh_swallowing_mpi_0001.hdf5", "r") +f_ics = h5.File("bh_swallowing.hdf5", "r") + +m = np.array(f["/PartType5/Masses"])#[:] +m_mpi = np.array(f_mpi["/PartType5/Masses"])#[:] +m_ics = np.array(f_ics["/PartType5/Masses"])#[:] + +ids = np.array(f["/PartType5/ParticleIDs"])#[:] +ids_mpi = np.array(f_mpi["/PartType5/ParticleIDs"])#[:] +ids_ics = np.array(f_ics["/PartType5/ParticleIDs"])#[:] + +rank = np.argsort(ids) +rank_mpi = np.argsort(ids_mpi) +rank_ics = np.argsort(ids_ics) + +m = m[rank] +m_mpi = m_mpi[rank_mpi] +m_ics = m_ics[rank_ics] + +ids = ids[rank] +ids_mpi = ids_mpi[rank_mpi] +ids_ics = ids_ics[rank_ics] + + +# Check +#print ids - ids_mpi +#print ids - ids_ics + +count_wrong = 0 + +print "ID -- ICs mass -- serial mass -- MPI mass" +for i in range(np.size(ids)): + print "%14d %5f %5f %5f"%(ids[i], m_ics[i], m[i], m_mpi[i]), + + if m[i] > m_ics[i] * 1.1: + print "#", + else: + print " ", + + if m[i] != m_mpi[i]: + count_wrong += 1 + print " <---" + else: + print "" + +print "Found", count_wrong, "wrong BH masses." + + +ids_gas_mpi = f_mpi["/PartType0/ParticleIDs"][:] +ids_removed_mpi = np.loadtxt("list_mpi.txt") + +for i in range(np.size(ids_removed_mpi)): + result = np.where(ids_gas_mpi == ids_removed_mpi) + print result + + +ids_gas = f["/PartType0/ParticleIDs"][:] +ids_removed = np.loadtxt("list.txt") + +for i in range(np.size(ids_removed)): + result = np.where(ids_gas == ids_removed) + print result + +#rho_gas = f["/PartType0/Density"][:] +#print np.mean(rho_gas), np.std(rho_gas) diff --git a/examples/SubgridTests/BlackHoleSwallowing/getGlass.sh b/examples/SubgridTests/BlackHoleSwallowing/getGlass.sh new file mode 100755 index 0000000000000000000000000000000000000000..ffd92e88deae6e91237059adac2a6c2067caee46 --- /dev/null +++ b/examples/SubgridTests/BlackHoleSwallowing/getGlass.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassCube_32.hdf5 diff --git a/examples/SubgridTests/BlackHoleSwallowing/makeIC.py b/examples/SubgridTests/BlackHoleSwallowing/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..5490924003ad3b86b042cc3b62c12f97ec60f8d4 --- /dev/null +++ b/examples/SubgridTests/BlackHoleSwallowing/makeIC.py @@ -0,0 +1,154 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program 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 Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +from numpy import * + +# Some constants +solar_mass_cgs = 1.988480e33 +kpc_in_cm = 3.085678e21 +mp_cgs = 1.67e-24 +boltzmann_k_cgs = 1.38e-16 + +# Parameters +gamma = 5./3. # Gas adiabatic index +rho_cgs = mp_cgs # Background density +u0_cgs = 1.2e12 # Desired initial internal energy (1.2e12 ~ 10^4K) +P_cgs = rho_cgs*u0_cgs*(gamma - 1.) # Background pressure +fileName = "bh_swallowing.hdf5" + +# Units +unit_l_cgs = 3.085678e24 # kpc +unit_m_cgs = 1.988480e43 # 10^10 Msun +unit_v_cgs = 1e5 # km / s +unit_A_cgs = 1. +unit_T_cgs = 1. +unit_t_cgs = unit_l_cgs / unit_v_cgs + +boxsize_cgs = 10. * kpc_in_cm +vol_cgs = boxsize_cgs**3 + +#--------------------------------------------------- +glass = h5py.File("glassCube_32.hdf5", "r") + +# Read particle positions and h from the glass +pos = glass["/PartType0/Coordinates"][:,:] +eps = 1e-6 +pos = (pos - pos.min()) / (pos.max() - pos.min() + eps) * boxsize_cgs / unit_l_cgs +h = glass["/PartType0/SmoothingLength"][:] * boxsize_cgs / unit_l_cgs + +numPart = size(h) + +# Generate extra arrays +v = zeros((numPart, 3)) +ids = linspace(1, numPart, numPart) +m_cgs = zeros(numPart) +u_cgs = zeros(numPart) +m = zeros(numPart) +u = zeros(numPart) + +m_cgs[:] = rho_cgs * vol_cgs / numPart +u_cgs[:] = P_cgs / (rho_cgs * (gamma - 1)) + +# BHs +bh_pos = zeros((2, 3)) +bh_pos[0,:] = 0.5 * boxsize_cgs / unit_l_cgs + +#diff = [4.812127e-03, 4.908179e-03, -4.878537e-03] - bh_pos[0,:] + +#print diff + +bh_pos[1,:] = 0.5 * boxsize_cgs / unit_l_cgs + diff + +print bh_pos + +# BHs don't move +bh_v = zeros((2, 3)) +bh_v[:,:] = 0. + +# increase mass to keep it at center +bh_m_cgs = ones(2) * m_cgs[0] +bh_ids = linspace(numPart + 1, numPart + 2, 2, dtype='L') +bh_h = ones(2) * [h.max()] + +print bh_ids + +#-------------------------------------------------- + +# Check quantities are correct for debugging +print("boxsize kpc " + str(boxsize_cgs/kpc_in_cm)) +print("density cm^-3 " + str(rho_cgs/mp_cgs)) +print("initial temperature K " + str(u_cgs[0] / boltzmann_k_cgs*((gamma - 1)*rho_cgs))) + +# Convert to internal units +bh_m = bh_m_cgs/unit_m_cgs +m[:] = m_cgs/unit_m_cgs +u[:] = u_cgs*unit_v_cgs**-2 +boxsize = boxsize_cgs/unit_l_cgs + + +#-------------------------------------------------- + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = [boxsize]*3 +grp.attrs["NumPart_Total"] = [numPart, 0, 0, 0, 0, 2] +#grp.attrs["NumPart_Total"] = [numPart, 0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [numPart, 0, 0, 0, 0, 2] +#grp.attrs["NumPart_ThisFile"] = [numPart, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = 0 +grp.attrs["Dimension"] = 3 + +#Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = 0 + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = unit_l_cgs +grp.attrs["Unit mass in cgs (U_M)"] = unit_m_cgs +grp.attrs["Unit time in cgs (U_t)"] = unit_t_cgs +grp.attrs["Unit current in cgs (U_I)"] = unit_A_cgs +grp.attrs["Unit temperature in cgs (U_T)"] = unit_T_cgs + +#Particle group +grp = file.create_group("/PartType0") +grp.create_dataset('Coordinates', data=pos, dtype='d') +grp.create_dataset('Velocities', data=v, dtype='f') +grp.create_dataset('Masses', data=m, dtype='f') +grp.create_dataset('SmoothingLength', data=h, dtype='f') +grp.create_dataset('InternalEnergy', data=u, dtype='f') +grp.create_dataset('ParticleIDs', data=ids, dtype='L') + +# stellar group +grp = file.create_group("/PartType5") +grp.create_dataset("Coordinates", (2,3),data=bh_pos, dtype="d") +grp.create_dataset('Velocities', (2,3),data=bh_v, dtype='f') +grp.create_dataset('Masses', (2,1),data=bh_m, dtype='f') +grp.create_dataset('SmoothingLength', (2,1),data=bh_h, dtype='f') +grp.create_dataset('ParticleIDs', (2,1),data=bh_ids[::-1], dtype='L') + +file.close() diff --git a/examples/SubgridTests/BlackHoleSwallowing/swallowing.yml b/examples/SubgridTests/BlackHoleSwallowing/swallowing.yml new file mode 100644 index 0000000000000000000000000000000000000000..e0637308e9cc9631e7cd042920163a98bf7e0bf0 --- /dev/null +++ b/examples/SubgridTests/BlackHoleSwallowing/swallowing.yml @@ -0,0 +1,92 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e24 # Mpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1. # Amperes + UnitTemp_in_cgs: 1. # Kelvin + +# Cosmological parameters +Cosmology: + h: 0.6777 # Reduced Hubble constant + a_begin: 0.5 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.307 # Matter density parameter + Omega_lambda: 0.693 # Dark-energy density parameter + Omega_b: 0.0455 # Baryon density parameter + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0 # The starting time of the simulation (in internal units). + time_end: 1.3e-2 # The end time of the simulation (in internal units). + dt_min: 1e-10 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-5 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: bh_swallowing_serial # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 3.e-5 # Time difference between consecutive outputs without cosmology (internal units) + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + time_first: 0. + delta_time: 1.e-5 # non cosmology time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 10. # Kelvin + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./bh_swallowing.hdf5 # The file to read + periodic: 1 + +Scheduler: + max_top_level_cells: 8 + tasks_per_cell: 500 + +# Parameters for the EAGLE "equation of state" +EAGLEEntropyFloor: + Jeans_density_threshold_H_p_cm3: 0.1 # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Jeans_over_density_threshold: 10. # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in. + Jeans_temperature_norm_K: 8000 # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin. + Jeans_gamma_effective: 1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor + Cool_density_threshold_H_p_cm3: 1e-5 # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in. + Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. + Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor + +# Metallicites read in for the gas and star +EAGLEChemistry: + init_abundance_metal: 0.01 + init_abundance_Hydrogen: 0.752 + init_abundance_Helium: 0.248 + init_abundance_Carbon: 0.0 + init_abundance_Nitrogen: 0.0 + init_abundance_Oxygen: 0.0 + init_abundance_Neon: 0.0 + init_abundance_Magnesium: 0.0 + init_abundance_Silicon: 0.0 + init_abundance_Iron: 0.0 + +# Standard EAGLE cooling options +EAGLECooling: + dir_name: ./coolingtables/ # Location of the Wiersma+08 cooling tables + H_reion_z: 11.5 # Redshift of Hydrogen re-ionization + H_reion_eV_p_H: 2.0 + He_reion_z_centre: 3.5 # Redshift of the centre of the Helium re-ionization Gaussian + He_reion_z_sigma: 0.5 # Spread in redshift of the Helium re-ionization Gaussian + He_reion_eV_p_H: 2.0 # Energy inject by Helium re-ionization in electron-volt per Hydrogen atom + +# EAGLE AGN model +EAGLEAGN: + subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. + max_eddington_fraction: 1. # Maximal allowed accretion rate in units of the Eddington rate. + radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. + coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. + AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. + AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. diff --git a/examples/SubgridTests/BlackHoleSwallowing/swallowing_mpi.yml b/examples/SubgridTests/BlackHoleSwallowing/swallowing_mpi.yml new file mode 100644 index 0000000000000000000000000000000000000000..8db524c9caa7f0941e34d6a44976076abc7f2dba --- /dev/null +++ b/examples/SubgridTests/BlackHoleSwallowing/swallowing_mpi.yml @@ -0,0 +1,92 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e24 # Mpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1. # Amperes + UnitTemp_in_cgs: 1. # Kelvin + +# Cosmological parameters +Cosmology: + h: 0.6777 # Reduced Hubble constant + a_begin: 0.5 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.307 # Matter density parameter + Omega_lambda: 0.693 # Dark-energy density parameter + Omega_b: 0.0455 # Baryon density parameter + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0 # The starting time of the simulation (in internal units). + time_end: 1.3e-2 # The end time of the simulation (in internal units). + dt_min: 1e-10 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-5 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: bh_swallowing_mpi # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 3.e-5 # Time difference between consecutive outputs without cosmology (internal units) + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + time_first: 0. + delta_time: 1.e-5 # non cosmology time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 10. # Kelvin + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./bh_swallowing.hdf5 # The file to read + periodic: 1 + +Scheduler: + max_top_level_cells: 8 + tasks_per_cell: 500 + +# Parameters for the EAGLE "equation of state" +EAGLEEntropyFloor: + Jeans_density_threshold_H_p_cm3: 0.1 # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Jeans_over_density_threshold: 10. # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in. + Jeans_temperature_norm_K: 8000 # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin. + Jeans_gamma_effective: 1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor + Cool_density_threshold_H_p_cm3: 1e-5 # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in. + Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. + Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor + +# Metallicites read in for the gas and star +EAGLEChemistry: + init_abundance_metal: 0.01 + init_abundance_Hydrogen: 0.752 + init_abundance_Helium: 0.248 + init_abundance_Carbon: 0.0 + init_abundance_Nitrogen: 0.0 + init_abundance_Oxygen: 0.0 + init_abundance_Neon: 0.0 + init_abundance_Magnesium: 0.0 + init_abundance_Silicon: 0.0 + init_abundance_Iron: 0.0 + +# Standard EAGLE cooling options +EAGLECooling: + dir_name: ./coolingtables/ # Location of the Wiersma+08 cooling tables + H_reion_z: 11.5 # Redshift of Hydrogen re-ionization + H_reion_eV_p_H: 2.0 + He_reion_z_centre: 3.5 # Redshift of the centre of the Helium re-ionization Gaussian + He_reion_z_sigma: 0.5 # Spread in redshift of the Helium re-ionization Gaussian + He_reion_eV_p_H: 2.0 # Energy inject by Helium re-ionization in electron-volt per Hydrogen atom + +# EAGLE AGN model +EAGLEAGN: + subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. + max_eddington_fraction: 1. # Maximal allowed accretion rate in units of the Eddington rate. + radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. + coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. + AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. + AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. diff --git a/src/Makefile.am b/src/Makefile.am index 7ae03c4d677f4d60ac580c3e9a8c7ec1f8305398..7556089b828cb901f0ba2b1e576cf4793e3e1e8e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,7 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ star_formation_struct.h star_formation.h star_formation_iact.h \ star_formation_logger.h star_formation_logger_struct.h \ velociraptor_struct.h velociraptor_io.h random.h memuse.h black_holes.h black_holes_io.h \ - black_holes_properties.h feedback.h feedback_struct.h feedback_properties.h + black_holes_properties.h black_holes_struct.h feedback.h feedback_struct.h feedback_properties.h # source files for EAGLE cooling EAGLE_COOLING_SOURCES = @@ -218,6 +218,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h black_holes/Default/black_holes.h black_holes/Default/black_holes_io.h \ black_holes/Default/black_holes_part.h black_holes/Default/black_holes_iact.h \ black_holes/Default/black_holes_properties.h \ + black_holes/Default/black_holes_struct.h \ black_holes/EAGLE/black_holes.h black_holes/EAGLE/black_holes_io.h \ black_holes/EAGLE/black_holes_part.h black_holes/EAGLE/black_holes_iact.h \ black_holes/EAGLE/black_holes_properties.h diff --git a/src/black_holes/Default/black_holes.h b/src/black_holes/Default/black_holes.h index fa7ece225dbed571b5bfb4f695f1fb50e4a59422..ebc5a36841e07fe96d81319914f065516ef43517 100644 --- a/src/black_holes/Default/black_holes.h +++ b/src/black_holes/Default/black_holes.h @@ -23,6 +23,7 @@ /* Local includes */ #include "black_holes_properties.h" +#include "black_holes_struct.h" #include "dimension.h" #include "kernel_hydro.h" #include "minmax.h" @@ -139,6 +140,58 @@ black_holes_bpart_has_no_neighbours(struct bpart* restrict bp, bp->density.wcount_dh = 0.f; } +/** + * @brief Update the properties of a black hole particles by swallowing + * a gas particle. + * + * @param bp The #bpart to update. + * @param p The #part that is swallowed. + * @param xp The #xpart that is swallowed. + * @param cosmo The current cosmological model. + */ +__attribute__((always_inline)) INLINE static void black_holes_swallow_part( + struct bpart* bp, const struct part* p, const struct xpart* xp, + const struct cosmology* cosmo) { + + /* Nothing to do here: No swallowing in the default model */ +} + +/** + * @brief Update a given #part's BH data field to mark the particle has + * not yet been swallowed. + * + * @param p_data The #part's #black_holes_part_data structure. + */ +__attribute__((always_inline)) INLINE static void +black_holes_mark_as_not_swallowed(struct black_holes_part_data* p_data) { + + /* Nothing to do here: No swallowing in the default model */ +} + +/** + * @brief Update a given #part's BH data field to mark the particle has + * having been been swallowed. + * + * @param p_data The #part's #black_holes_part_data structure. + */ +__attribute__((always_inline)) INLINE static void black_holes_mark_as_swallowed( + struct black_holes_part_data* p_data) { + + /* Nothing to do here: No swallowing in the default model */ +} + +/** + * @brief Return the ID of the BH that should swallow this #part. + * + * @param p_data The #part's #black_holes_part_data structure. + */ +__attribute__((always_inline)) INLINE static long long +black_holes_get_swallow_id(struct black_holes_part_data* p_data) { + + /* Return a non-existing ID */ + return -1; +} + /** * @brief Compute the accretion rate of the black hole and all the quantites * required for the feedback loop. diff --git a/src/black_holes/Default/black_holes_iact.h b/src/black_holes/Default/black_holes_iact.h index 4aeb27b4e13a614036962a564d99a80c6990ebec..37e3facc4a14a8eaa1b87e1c60dfeae22dfecf44 100644 --- a/src/black_holes/Default/black_holes_iact.h +++ b/src/black_holes/Default/black_holes_iact.h @@ -63,6 +63,28 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_bh_density( #endif } +/** + * @brief Swallowing interaction between two particles (non-symmetric). + * + * Function used to flag the gas particles that will be swallowed + * by the black hole particle. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param bi First particle (black hole). + * @param pj Second particle (gas) + * @param xpj The extended data of the second particle. + * @param cosmo The cosmological model. + * @param ti_current Current integer time value (for random numbers). + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_bh_swallow( + const float r2, const float *dx, const float hi, const float hj, + struct bpart *restrict bi, struct part *restrict pj, + struct xpart *restrict xpj, const struct cosmology *cosmo, + const integertime_t ti_current) {} + /** * @brief Feedback interaction between two particles (non-symmetric). * diff --git a/src/black_holes/Default/black_holes_part.h b/src/black_holes/Default/black_holes_part.h index 360eb45d9e2ccb14e8ff55b6d286e7bb91ef89cc..db8c9b18cb8bac72cd7b3b239930aa2306e5171d 100644 --- a/src/black_holes/Default/black_holes_part.h +++ b/src/black_holes/Default/black_holes_part.h @@ -19,8 +19,7 @@ #ifndef SWIFT_DEFAULT_BLACK_HOLE_PART_H #define SWIFT_DEFAULT_BLACK_HOLE_PART_H -/* Some standard headers. */ -#include <stdlib.h> +#include "chemistry_struct.h" /** * @brief Particle fields for the black hole particles. @@ -63,6 +62,10 @@ struct bpart { } density; + /*! Chemistry information (e.g. metal content at birth, swallowed metal + * content, etc.) */ + struct chemistry_bpart_data chemistry_data; + #ifdef SWIFT_DEBUG_CHECKS /* Time of the last drift */ diff --git a/src/black_holes/Default/black_holes_struct.h b/src/black_holes/Default/black_holes_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..3fdb0ee882b075d40a8725fa52b221d48dcbd722 --- /dev/null +++ b/src/black_holes/Default/black_holes_struct.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Matthieu Schaller (schaller@strw.leidenuniv.nl) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_BLACK_HOLES_STRUCT_DEFAULT_H +#define SWIFT_BLACK_HOLES_STRUCT_DEFAULT_H + +/** + * @brief Black holes-related fields carried by each *gas* particle. + */ +struct black_holes_part_data {}; + +#endif /* SWIFT_BLACK_HOLES_STRUCT_DEFAULT_H */ diff --git a/src/black_holes/EAGLE/black_holes.h b/src/black_holes/EAGLE/black_holes.h index 6e9be26bc6dea438df80e15054ebe5303ecf5b63..ccb97e015b50046e10b4966548bf59d55d73c526 100644 --- a/src/black_holes/EAGLE/black_holes.h +++ b/src/black_holes/EAGLE/black_holes.h @@ -21,6 +21,7 @@ /* Local includes */ #include "black_holes_properties.h" +#include "black_holes_struct.h" #include "cosmology.h" #include "dimension.h" #include "kernel_hydro.h" @@ -101,7 +102,7 @@ __attribute__((always_inline)) INLINE static void black_holes_predict_extra( * @param bp The particle. */ __attribute__((always_inline)) INLINE static void -black_holes_reset_predicted_values(struct bpart* restrict bp) {} +black_holes_reset_predicted_values(struct bpart* bp) {} /** * @brief Kick the additional variables @@ -153,7 +154,7 @@ __attribute__((always_inline)) INLINE static void black_holes_end_density( * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void -black_holes_bpart_has_no_neighbours(struct bpart* restrict bp, +black_holes_bpart_has_no_neighbours(struct bpart* bp, const struct cosmology* cosmo) { /* Some smoothing length multiples. */ @@ -166,6 +167,99 @@ black_holes_bpart_has_no_neighbours(struct bpart* restrict bp, bp->density.wcount_dh = 0.f; } +/** + * @brief Update the properties of a black hole particles by swallowing + * a gas particle. + * + * @param bp The #bpart to update. + * @param p The #part that is swallowed. + * @param xp The #xpart that is swallowed. + * @param cosmo The current cosmological model. + */ +__attribute__((always_inline)) INLINE static void black_holes_swallow_part( + struct bpart* bp, const struct part* p, const struct xpart* xp, + const struct cosmology* cosmo) { + + /* Get the current dynamical masses */ + const float gas_mass = hydro_get_mass(p); + const float BH_mass = bp->mass; + + /* Increase the dynamical mass of the BH. */ + bp->mass += gas_mass; + bp->gpart->mass += gas_mass; + + /* Update the BH momentum */ + const float BH_mom[3] = {BH_mass * bp->v[0] + gas_mass * p->v[0], + BH_mass * bp->v[1] + gas_mass * p->v[1], + BH_mass * bp->v[2] + gas_mass * p->v[2]}; + + bp->v[0] = BH_mom[0] / bp->mass; + bp->v[1] = BH_mom[1] / bp->mass; + bp->v[2] = BH_mom[2] / bp->mass; + bp->gpart->v_full[0] = bp->v[0]; + bp->gpart->v_full[1] = bp->v[1]; + bp->gpart->v_full[2] = bp->v[2]; + + /* Update the BH metal masses */ + struct chemistry_bpart_data* bp_chem = &bp->chemistry_data; + const struct chemistry_part_data* p_chem = &p->chemistry_data; + + bp_chem->metal_mass_total += p_chem->metal_mass_fraction_total * gas_mass; + for (int i = 0; i < chemistry_element_count; ++i) { + bp_chem->metal_mass[i] += p_chem->metal_mass_fraction[i] * gas_mass; + } + bp_chem->mass_from_SNIa += p_chem->mass_from_SNIa; + bp_chem->mass_from_SNII += p_chem->mass_from_SNII; + bp_chem->mass_from_AGB += p_chem->mass_from_AGB; + bp_chem->metal_mass_from_SNIa += + p_chem->metal_mass_fraction_from_SNIa * gas_mass; + bp_chem->metal_mass_from_SNII += + p_chem->metal_mass_fraction_from_SNII * gas_mass; + bp_chem->metal_mass_from_AGB += + p_chem->metal_mass_fraction_from_AGB * gas_mass; + bp_chem->iron_mass_from_SNIa += + p_chem->iron_mass_fraction_from_SNIa * gas_mass; + + /* This BH lost a neighbour */ + bp->num_ngbs--; + bp->ngb_mass -= gas_mass; +} + +/** + * @brief Update a given #part's BH data field to mark the particle has + * not yet been swallowed. + * + * @param p_data The #part's #black_holes_part_data structure. + */ +__attribute__((always_inline)) INLINE static void +black_holes_mark_as_not_swallowed(struct black_holes_part_data* p_data) { + + p_data->swallow_id = -1; +} + +/** + * @brief Update a given #part's BH data field to mark the particle has + * having been been swallowed. + * + * @param p_data The #part's #black_holes_part_data structure. + */ +__attribute__((always_inline)) INLINE static void black_holes_mark_as_swallowed( + struct black_holes_part_data* p_data) { + + p_data->swallow_id = -2; +} + +/** + * @brief Return the ID of the BH that should swallow this #part. + * + * @param p_data The #part's #black_holes_part_data structure. + */ +__attribute__((always_inline)) INLINE static long long +black_holes_get_swallow_id(struct black_holes_part_data* p_data) { + + return p_data->swallow_id; +} + /** * @brief Compute the accretion rate of the black hole and all the quantites * required for the feedback loop. @@ -181,6 +275,8 @@ __attribute__((always_inline)) INLINE static void black_holes_prepare_feedback( const struct phys_const* constants, const struct cosmology* cosmo, const double dt) { + if (dt == 0.) return; + /* Gather some physical constants (all in internal units) */ const double G = constants->const_newton_G; const double c = constants->const_speed_light_c; @@ -245,7 +341,9 @@ __attribute__((always_inline)) INLINE static void black_holes_prepare_feedback( bp->total_accreted_mass += mass_rate * dt; bp->energy_reservoir += luminosity * epsilon_f * dt; - /* Energy required to have a feedback event */ + /* Energy required to have a feedback event + * Note that we have subtracted the particles we swallowed from the ngb_mass + * and num_ngbs accumulators. */ const double mean_ngb_mass = bp->ngb_mass / ((double)bp->num_ngbs); const double E_feedback_event = num_ngbs_to_heat * delta_u * mean_ngb_mass; @@ -327,7 +425,8 @@ INLINE static void black_holes_create_from_gas( const struct part* p) { /* All the non-basic properties of the black hole have been zeroed - in the FOF code. We just update the rest. */ + * in the FOF code. We update them here. + * (i.e. position, velocity, mass, time-step have been set) */ /* Birth time */ bp->formation_scale_factor = cosmo->a; @@ -335,6 +434,31 @@ INLINE static void black_holes_create_from_gas( /* Initial seed mass */ bp->subgrid_mass = props->subgrid_seed_mass; + /* We haven't accreted anything yet */ + bp->total_accreted_mass = 0.f; + + /* Initial metal masses */ + const float gas_mass = hydro_get_mass(p); + + struct chemistry_bpart_data* bp_chem = &bp->chemistry_data; + const struct chemistry_part_data* p_chem = &p->chemistry_data; + + bp_chem->metal_mass_total = p_chem->metal_mass_fraction_total * gas_mass; + for (int i = 0; i < chemistry_element_count; ++i) { + bp_chem->metal_mass[i] = p_chem->metal_mass_fraction[i] * gas_mass; + } + bp_chem->mass_from_SNIa = p_chem->mass_from_SNIa; + bp_chem->mass_from_SNII = p_chem->mass_from_SNII; + bp_chem->mass_from_AGB = p_chem->mass_from_AGB; + bp_chem->metal_mass_from_SNIa = + p_chem->metal_mass_fraction_from_SNIa * gas_mass; + bp_chem->metal_mass_from_SNII = + p_chem->metal_mass_fraction_from_SNII * gas_mass; + bp_chem->metal_mass_from_AGB = + p_chem->metal_mass_fraction_from_AGB * gas_mass; + bp_chem->iron_mass_from_SNIa = + p_chem->iron_mass_fraction_from_SNIa * gas_mass; + /* First initialisation */ black_holes_init_bpart(bp); } diff --git a/src/black_holes/EAGLE/black_holes_iact.h b/src/black_holes/EAGLE/black_holes_iact.h index 0db85b3924fee6b4a8d0dcc3263c1746788219cc..27723f00c92e0eafd011cf29bdd017215c0a776c 100644 --- a/src/black_holes/EAGLE/black_holes_iact.h +++ b/src/black_holes/EAGLE/black_holes_iact.h @@ -22,6 +22,7 @@ /* Local includes */ #include "hydro.h" #include "random.h" +#include "space.h" /** * @brief Density interaction between two particles (non-symmetric). @@ -93,6 +94,71 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_bh_density( #endif } +/** + * @brief Swallowing interaction between two particles (non-symmetric). + * + * Function used to flag the gas particles that will be swallowed + * by the black hole particle. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param bi First particle (black hole). + * @param pj Second particle (gas) + * @param xpj The extended data of the second particle. + * @param cosmo The cosmological model. + * @param ti_current Current integer time value (for random numbers). + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_bh_swallow( + const float r2, const float *dx, const float hi, const float hj, + struct bpart *restrict bi, struct part *restrict pj, + struct xpart *restrict xpj, const struct cosmology *cosmo, + const integertime_t ti_current) { + + float wi; + + /* Get r and 1/r. */ + const float r_inv = 1.0f / sqrtf(r2); + const float r = r2 * r_inv; + + /* Compute the kernel function */ + const float hi_inv = 1.0f / hi; + const float ui = r * hi_inv; + kernel_eval(ui, &wi); + + /* Is the BH hungry? */ + if (bi->subgrid_mass > bi->mass) { + + /* Probability to swallow this particle */ + const float prob = (bi->subgrid_mass - bi->mass) * wi / bi->rho_gas; + + /* Draw a random number (Note mixing both IDs) */ + const float rand = random_unit_interval(bi->id + pj->id, ti_current, + random_number_BH_swallow); + + /* Are we lucky? */ + if (rand < prob) { + + /* This particle is swallowed by the BH with the largest ID of all the + * candidates wanting to swallow it */ + if (pj->black_holes_data.swallow_id < bi->id) { + + message("BH %lld wants to swallow gas particle %lld", bi->id, pj->id); + + pj->black_holes_data.swallow_id = bi->id; + + } else { + + message( + "BH %lld wants to swallow gas particle %lld BUT CANNOT (old " + "swallow id=%lld)", + bi->id, pj->id, pj->black_holes_data.swallow_id); + } + } + } +} + /** * @brief Feedback interaction between two particles (non-symmetric). * @@ -137,6 +203,11 @@ runner_iact_nonsym_bh_feedback(const float r2, const float *dx, const float hi, /* Impose maximal viscosity */ hydro_set_viscosity_alpha_max_feedback(pj); + + /* message( */ + /* "We did some AGN heating! id %llu BH id %llu probability " */ + /* " %.5e random_num %.5e du %.5e du/ini %.5e", */ + /* pj->id, bi->id, prob, rand, delta_u, delta_u / u_init); */ } } diff --git a/src/black_holes/EAGLE/black_holes_part.h b/src/black_holes/EAGLE/black_holes_part.h index b6d15dfa06be1c4572845d1b9656b053439f70d1..45be4461ceea1beefaa84ce4705280b4a9b45491 100644 --- a/src/black_holes/EAGLE/black_holes_part.h +++ b/src/black_holes/EAGLE/black_holes_part.h @@ -19,6 +19,8 @@ #ifndef SWIFT_EAGLE_BLACK_HOLE_PART_H #define SWIFT_EAGLE_BLACK_HOLE_PART_H +#include "chemistry_struct.h" + /** * @brief Particle fields for the black hole particles. * @@ -73,7 +75,8 @@ struct bpart { /*! Subgrid mass of the black hole */ float subgrid_mass; - /*! Total accreted mass of the black hole */ + /*! Total accreted mass of the black hole (including accreted mass onto BHs + * that were merged) */ float total_accreted_mass; /*! Energy reservoir for feedback */ @@ -108,6 +111,10 @@ struct bpart { } to_distribute; + /*! Chemistry information (e.g. metal content at birth, swallowed metal + * content, etc.) */ + struct chemistry_bpart_data chemistry_data; + #ifdef SWIFT_DEBUG_CHECKS /* Time of the last drift */ diff --git a/src/black_holes/EAGLE/black_holes_struct.h b/src/black_holes/EAGLE/black_holes_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..cf0e9c3975c1a1d9bda0065a5072465ae886297f --- /dev/null +++ b/src/black_holes/EAGLE/black_holes_struct.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Matthieu Schaller (schaller@strw.leidenuniv.nl) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_BLACK_HOLES_STRUCT_EAGLE_H +#define SWIFT_BLACK_HOLES_STRUCT_EAGLE_H + +/** + * @brief Black holes-related fields carried by each *gas* particle. + */ +struct black_holes_part_data { + + /*! ID of the black-hole that will swallow this #part. */ + long long swallow_id; +}; + +#endif /* SWIFT_BLACK_HOLES_STRUCT_EAGLE_H */ diff --git a/src/black_holes_struct.h b/src/black_holes_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..5535caf23eb9d6eaed3774faa96e75f6f9f73625 --- /dev/null +++ b/src/black_holes_struct.h @@ -0,0 +1,39 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Matthieu Schaller (schaller@strw.leidenuniv.nl) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_BLACK_HOLES_STRUCT_H +#define SWIFT_BLACK_HOLES_STRUCT_H + +/** + * @file src/feedback_struct.h + * @brief Branches between the different feedback functions. + */ + +/* Config parameters. */ +#include "../config.h" + +/* Import the right black holes definition */ +#if defined(BLACK_HOLES_NONE) +#include "./black_holes/Default/black_holes_struct.h" +#elif defined(BLACK_HOLES_EAGLE) +#include "./black_holes/EAGLE/black_holes_struct.h" +#else +#error "Invalid choice of black holes function." +#endif + +#endif /* SWIFT_BLACK_HOLES_STRUCT_H */ diff --git a/src/cell.c b/src/cell.c index fca6a04ea746d6d5c995318c7433c8ff2ccb98d2..115a0e253e187758b448909558c02809dbd32f9f 100644 --- a/src/cell.c +++ b/src/cell.c @@ -590,6 +590,28 @@ int cell_pack_tags(const struct cell *c, int *tags) { #endif } +void cell_pack_part_swallow(const struct cell *c, + struct black_holes_part_data *data) { + + const size_t count = c->hydro.count; + const struct part *parts = c->hydro.parts; + + for (size_t i = 0; i < count; ++i) { + data[i] = parts[i].black_holes_data; + } +} + +void cell_unpack_part_swallow(struct cell *c, + const struct black_holes_part_data *data) { + + const size_t count = c->hydro.count; + struct part *parts = c->hydro.parts; + + for (size_t i = 0; i < count; ++i) { + parts[i].black_holes_data = data[i]; + } +} + /** * @brief Unpack the data of a given cell and its sub-cells. * @@ -1382,6 +1404,67 @@ int cell_slocktree(struct cell *c) { } } +/** + * @brief Lock a cell for access to its array of #bpart and hold its parents. + * + * @param c The #cell. + * @return 0 on success, 1 on failure + */ +int cell_blocktree(struct cell *c) { + TIMER_TIC + + /* First of all, try to lock this cell. */ + if (c->black_holes.hold || lock_trylock(&c->black_holes.lock) != 0) { + TIMER_TOC(timer_locktree); + return 1; + } + + /* Did somebody hold this cell in the meantime? */ + if (c->black_holes.hold) { + /* Unlock this cell. */ + if (lock_unlock(&c->black_holes.lock) != 0) error("Failed to unlock cell."); + + /* Admit defeat. */ + TIMER_TOC(timer_locktree); + return 1; + } + + /* Climb up the tree and lock/hold/unlock. */ + struct cell *finger; + for (finger = c->parent; finger != NULL; finger = finger->parent) { + /* Lock this cell. */ + if (lock_trylock(&finger->black_holes.lock) != 0) break; + + /* Increment the hold. */ + atomic_inc(&finger->black_holes.hold); + + /* Unlock the cell. */ + if (lock_unlock(&finger->black_holes.lock) != 0) + error("Failed to unlock cell."); + } + + /* If we reached the top of the tree, we're done. */ + if (finger == NULL) { + TIMER_TOC(timer_locktree); + return 0; + } + + /* Otherwise, we hit a snag. */ + else { + /* Undo the holds up to finger. */ + for (struct cell *finger2 = c->parent; finger2 != finger; + finger2 = finger2->parent) + atomic_dec(&finger2->black_holes.hold); + + /* Unlock this cell. */ + if (lock_unlock(&c->black_holes.lock) != 0) error("Failed to unlock cell."); + + /* Admit defeat. */ + TIMER_TOC(timer_locktree); + return 1; + } +} + /** * @brief Unlock a cell's parents for access to #part array. * @@ -1454,6 +1537,24 @@ void cell_sunlocktree(struct cell *c) { TIMER_TOC(timer_locktree); } +/** + * @brief Unlock a cell's parents for access to #bpart array. + * + * @param c The #cell. + */ +void cell_bunlocktree(struct cell *c) { + TIMER_TIC + + /* First of all, try to unlock this cell. */ + if (lock_unlock(&c->black_holes.lock) != 0) error("Failed to unlock cell."); + + /* Climb up the tree and unhold the parents. */ + for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) + atomic_dec(&finger->black_holes.hold); + + TIMER_TOC(timer_locktree); +} + /** * @brief Sort the parts into eight bins along the given pivots. * @@ -1886,6 +1987,8 @@ void cell_clean_links(struct cell *c, void *data) { c->stars.density = NULL; c->stars.feedback = NULL; c->black_holes.density = NULL; + c->black_holes.swallow = NULL; + c->black_holes.do_swallow = NULL; c->black_holes.feedback = NULL; } @@ -2903,20 +3006,16 @@ void cell_activate_subcell_black_holes_tasks(struct cell *ci, struct cell *cj, } /* Otherwise, activate the drifts. */ - else { - if (cell_is_active_black_holes(ci, e)) { - - /* Activate the drifts if the cells are local. */ - if (ci->nodeID == engine_rank) cell_activate_drift_bpart(ci, s); - if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s); - } + else if (cell_is_active_black_holes(ci, e) || + cell_is_active_black_holes(cj, e)) { - if (cell_is_active_black_holes(cj, e)) { + /* Activate the drifts if the cells are local. */ + if (ci->nodeID == engine_rank) cell_activate_drift_bpart(ci, s); + if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s); - /* Activate the drifts if the cells are local. */ - if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); - if (cj->nodeID == engine_rank) cell_activate_drift_bpart(cj, s); - } + /* Activate the drifts if the cells are local. */ + if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); + if (cj->nodeID == engine_rank) cell_activate_drift_bpart(cj, s); } } /* Otherwise, pair interation */ } @@ -3727,6 +3826,7 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s, * @return 1 If the space needs rebuilding. 0 otherwise. */ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) { + struct engine *e = s->space->e; const int nodeID = e->nodeID; int rebuild = 0; @@ -3750,39 +3850,35 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) { const int cj_nodeID = nodeID; #endif - /* Activate the drifts */ - if (t->type == task_type_self && ci_active) { - cell_activate_drift_part(ci, s); - cell_activate_drift_bpart(ci, s); - } - /* Only activate tasks that involve a local active cell. */ if ((ci_active || cj_active) && (ci_nodeID == nodeID || cj_nodeID == nodeID)) { + scheduler_activate(s, t); - if (t->type == task_type_pair) { - /* Do ci */ - if (ci_active) { + /* Activate the drifts */ + if (t->type == task_type_self) { + cell_activate_drift_part(ci, s); + cell_activate_drift_bpart(ci, s); + } - /* Activate the drift tasks. */ - if (ci_nodeID == nodeID) cell_activate_drift_bpart(ci, s); - if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); - } + /* Activate the drifts */ + else if (t->type == task_type_pair) { - /* Do cj */ - if (cj_active) { + /* Activate the drift tasks. */ + if (ci_nodeID == nodeID) cell_activate_drift_bpart(ci, s); + if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); - /* Activate the drift tasks. */ - if (cj_nodeID == nodeID) cell_activate_drift_bpart(cj, s); - if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); - } + if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); + if (cj_nodeID == nodeID) cell_activate_drift_bpart(cj, s); } + /* Store current values of dx_max and h_max. */ else if (t->type == task_type_sub_self) { cell_activate_subcell_black_holes_tasks(ci, NULL, s); } + /* Store current values of dx_max and h_max. */ else if (t->type == task_type_sub_pair) { cell_activate_subcell_black_holes_tasks(ci, cj, s); } @@ -3790,76 +3886,99 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) { /* Only interested in pair interactions as of here. */ if (t->type == task_type_pair || t->type == task_type_sub_pair) { + /* Check whether there was too much particle motion, i.e. the cell neighbour conditions were violated. */ if (cell_need_rebuild_for_black_holes_pair(ci, cj)) rebuild = 1; if (cell_need_rebuild_for_black_holes_pair(cj, ci)) rebuild = 1; + scheduler_activate(s, ci->hydro.super->black_holes.swallow_ghost[0]); + scheduler_activate(s, cj->hydro.super->black_holes.swallow_ghost[0]); + #ifdef WITH_MPI /* Activate the send/recv tasks. */ if (ci_nodeID != nodeID) { - if (cj_active) { - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_xv); - /* If the local cell is active, more stuff will be needed. */ - scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart, - ci_nodeID); - cell_activate_drift_bpart(cj, s); + /* Receive the foreign parts to compute BH accretion rates and do the + * swallowing */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_rho); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_part_swallow); - /* If the local cell is active, send its ti_end values. */ - scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart, - ci_nodeID); - } + /* Send the local BHs to tag the particles to swallow and to do feedback + */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart_rho, + ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart_feedback, + ci_nodeID); - if (ci_active) { - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart); + /* Drift before you send */ + cell_activate_drift_bpart(cj, s); - /* If the foreign cell is active, we want its ti_end values. */ - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart); + /* Send the new BH time-steps */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart, + ci_nodeID); - /* Is the foreign cell active and will need stuff from us? */ - scheduler_activate_send(s, cj->mpi.send, task_subtype_xv, ci_nodeID); + /* Receive the foreign BHs to tag particles to swallow and for feedback + */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_rho); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_feedback); - /* Drift the cell which will be sent; note that not all sent - particles will be drifted, only those that are needed. */ - cell_activate_drift_part(cj, s); - } - - } else if (cj_nodeID != nodeID) { - /* If the local cell is active, receive data from the foreign cell. */ - if (ci_active) { - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_xv); + /* Receive the foreign BH time-steps */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart); - /* If the local cell is active, more stuff will be needed. */ - scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart, - cj_nodeID); - cell_activate_drift_bpart(ci, s); + /* Send the local part information */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_part_swallow, + ci_nodeID); - /* If the local cell is active, send its ti_end values. */ - scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart, - cj_nodeID); - } - - if (cj_active) { - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart); + /* Drift the cell which will be sent; note that not all sent + particles will be drifted, only those that are needed. */ + cell_activate_drift_part(cj, s); - /* If the foreign cell is active, we want its ti_end values. */ - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart); - - /* Is the foreign cell active and will need stuff from us? */ - scheduler_activate_send(s, ci->mpi.send, task_subtype_xv, cj_nodeID); + } else if (cj_nodeID != nodeID) { - /* Drift the cell which will be sent; note that not all sent - particles will be drifted, only those that are needed. */ - cell_activate_drift_part(ci, s); - } + /* Receive the foreign parts to compute BH accretion rates and do the + * swallowing */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_rho); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_part_swallow); + + /* Send the local BHs to tag the particles to swallow and to do feedback + */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart_rho, + cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart_feedback, + cj_nodeID); + + /* Drift before you send */ + cell_activate_drift_bpart(ci, s); + + /* Send the new BH time-steps */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart, + cj_nodeID); + + /* Receive the foreign BHs to tag particles to swallow and for feedback + */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_rho); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_feedback); + + /* Receive the foreign BH time-steps */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart); + + /* Send the local part information */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_part_swallow, + cj_nodeID); + + /* Drift the cell which will be sent; note that not all sent + particles will be drifted, only those that are needed. */ + cell_activate_drift_part(ci, s); } #endif } } - /* Un-skip the feedback tasks involved with this cell. */ - for (struct link *l = c->black_holes.feedback; l != NULL; l = l->next) { + /* Un-skip the swallow tasks involved with this cell. */ + for (struct link *l = c->black_holes.swallow; l != NULL; l = l->next) { struct task *t = l->t; struct cell *ci = t->ci; struct cell *cj = t->cj; @@ -3873,36 +3992,80 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) { const int cj_nodeID = nodeID; #endif - if (t->type == task_type_self && ci_active) { + /* Only activate tasks that involve a local active cell. */ + if ((ci_active || cj_active) && + (ci_nodeID == nodeID || cj_nodeID == nodeID)) { + scheduler_activate(s, t); } + } + + /* Un-skip the swallow tasks involved with this cell. */ + for (struct link *l = c->black_holes.do_swallow; l != NULL; l = l->next) { + struct task *t = l->t; + struct cell *ci = t->ci; + struct cell *cj = t->cj; + const int ci_active = cell_is_active_black_holes(ci, e); + const int cj_active = (cj != NULL) ? cell_is_active_black_holes(cj, e) : 0; +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif + + /* Only activate tasks that involve a local active cell. */ + if ((ci_active || cj_active) && + (ci_nodeID == nodeID || cj_nodeID == nodeID)) { - else if (t->type == task_type_sub_self && ci_active) { scheduler_activate(s, t); } + } - else if (t->type == task_type_pair || t->type == task_type_sub_pair) { - /* We only want to activate the task if the cell is active and is - going to update some gas on the *local* node */ - if ((ci_nodeID == nodeID && cj_nodeID == nodeID) && - (ci_active || cj_active)) { - scheduler_activate(s, t); + /* Un-skip the feedback tasks involved with this cell. */ + for (struct link *l = c->black_holes.feedback; l != NULL; l = l->next) { + struct task *t = l->t; + struct cell *ci = t->ci; + struct cell *cj = t->cj; + const int ci_active = cell_is_active_black_holes(ci, e); + const int cj_active = (cj != NULL) ? cell_is_active_black_holes(cj, e) : 0; +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif - } else if ((ci_nodeID == nodeID && cj_nodeID != nodeID) && (cj_active)) { - scheduler_activate(s, t); + /* Only activate tasks that involve a local active cell. */ + if ((ci_active || cj_active) && + (ci_nodeID == nodeID || cj_nodeID == nodeID)) { - } else if ((ci_nodeID != nodeID && cj_nodeID == nodeID) && (ci_active)) { - scheduler_activate(s, t); - } + scheduler_activate(s, t); } - - /* Nothing more to do here, all drifts activated above */ } /* Unskip all the other task types. */ if (c->nodeID == nodeID && cell_is_active_black_holes(c, e)) { - if (c->black_holes.ghost != NULL) - scheduler_activate(s, c->black_holes.ghost); + + /* for (struct link *l = c->black_holes.swallow; l != NULL; l = l->next) + */ + /* scheduler_activate(s, l->t); */ + /* for (struct link *l = c->black_holes.do_swallow; l != NULL; l = + * l->next) + */ + /* scheduler_activate(s, l->t); */ + /* for (struct link *l = c->black_holes.feedback; l != NULL; l = l->next) + */ + /* scheduler_activate(s, l->t); */ + + if (c->black_holes.density_ghost != NULL) + scheduler_activate(s, c->black_holes.density_ghost); + if (c->black_holes.swallow_ghost[0] != NULL) + scheduler_activate(s, c->black_holes.swallow_ghost[0]); + if (c->black_holes.swallow_ghost[1] != NULL) + scheduler_activate(s, c->black_holes.swallow_ghost[1]); if (c->black_holes.black_holes_in != NULL) scheduler_activate(s, c->black_holes.black_holes_in); if (c->black_holes.black_holes_out != NULL) @@ -3920,7 +4083,8 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) { * @brief Set the super-cell pointers for all cells in a hierarchy. * * @param c The top-level #cell to play with. - * @param super Pointer to the deepest cell with tasks in this part of the tree. + * @param super Pointer to the deepest cell with tasks in this part of the + * tree. * @param with_hydro Are we running with hydrodynamics on? * @param with_grav Are we running with gravity on? */ @@ -3945,8 +4109,8 @@ void cell_set_super(struct cell *c, struct cell *super, const int with_hydro, * @brief Set the super-cell pointers for all cells in a hierarchy. * * @param c The top-level #cell to play with. - * @param super_hydro Pointer to the deepest cell with tasks in this part of the - * tree. + * @param super_hydro Pointer to the deepest cell with tasks in this part of + * the tree. */ void cell_set_super_hydro(struct cell *c, struct cell *super_hydro) { /* Are we in a cell with some kind of self/pair task ? */ @@ -4177,8 +4341,14 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { hydro_remove_part(p, xp); /* Remove the particle entirely */ + struct gpart *gp = p->gpart; cell_remove_part(e, c, p, xp); + /* and it's gravity friend */ + if (gp != NULL) { + cell_remove_gpart(e, c, gp); + } + continue; } } @@ -4197,9 +4367,12 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { xp->x_diff_sort[2] * xp->x_diff_sort[2]; dx2_max_sort = max(dx2_max_sort, dx2_sort); - /* Maximal smoothing length */ + /* Update the maximal smoothing length in the cell */ cell_h_max = max(cell_h_max, p->h); + /* Mark the particle has not being swallowed */ + black_holes_mark_as_not_swallowed(&p->black_holes_data); + /* Get ready for a density calculation */ if (part_is_active(p, e)) { hydro_init_part(p, &e->s->hs); @@ -4754,7 +4927,8 @@ void cell_clear_stars_sort_flags(struct cell *c, const int clear_unused_flags) { cell_clear_flag(c, cell_flag_do_stars_sub_sort); } - /* Indicate that the cell is not sorted and cancel the pointer sorting arrays. + /* Indicate that the cell is not sorted and cancel the pointer sorting + * arrays. */ c->stars.sorted = 0; cell_free_stars_sorts(c); @@ -4788,7 +4962,8 @@ void cell_clear_hydro_sort_flags(struct cell *c, const int clear_unused_flags) { cell_clear_flag(c, cell_flag_do_hydro_sub_sort); } - /* Indicate that the cell is not sorted and cancel the pointer sorting arrays. + /* Indicate that the cell is not sorted and cancel the pointer sorting + * arrays. */ c->hydro.sorted = 0; cell_free_hydro_sorts(c); @@ -4938,9 +5113,9 @@ void cell_recursively_shift_sparts(struct cell *c, * @param e The #engine. * @param c The leaf-cell in which to add the #spart. * - * @return A pointer to the newly added #spart. The spart has a been zeroed and - * given a position within the cell as well as set to the minimal active time - * bin. + * @return A pointer to the newly added #spart. The spart has a been zeroed + * and given a position within the cell as well as set to the minimal active + * time bin. */ struct spart *cell_add_spart(struct engine *e, struct cell *const c) { /* Perform some basic consitency checks */ @@ -5020,7 +5195,8 @@ struct spart *cell_add_spart(struct engine *e, struct cell *const c) { * current cell*/ cell_recursively_shift_sparts(top, progeny, /* main_branch=*/1); - /* Make sure the gravity will be recomputed for this particle in the next step + /* Make sure the gravity will be recomputed for this particle in the next + * step */ struct cell *top2 = c; while (top2->parent != NULL) { @@ -5060,7 +5236,8 @@ struct spart *cell_add_spart(struct engine *e, struct cell *const c) { /** * @brief "Remove" a gas particle from the calculation. * - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. @@ -5085,12 +5262,17 @@ void cell_remove_part(const struct engine *e, struct cell *c, struct part *p, /* Un-link the part */ p->gpart = NULL; + + /* Update the space-wide counters */ + const size_t one = 1; + atomic_add(&e->s->nr_inhibited_parts, one); } /** * @brief "Remove" a gravity particle from the calculation. * - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. @@ -5104,12 +5286,17 @@ void cell_remove_gpart(const struct engine *e, struct cell *c, /* Mark the particle as inhibited */ gp->time_bin = time_bin_inhibited; + + /* Update the space-wide counters */ + const size_t one = 1; + atomic_add(&e->s->nr_inhibited_gparts, one); } /** * @brief "Remove" a star particle from the calculation. * - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. @@ -5131,12 +5318,17 @@ void cell_remove_spart(const struct engine *e, struct cell *c, /* Un-link the spart */ sp->gpart = NULL; + + /* Update the space-wide counters */ + const size_t one = 1; + atomic_add(&e->s->nr_inhibited_sparts, one); } /** * @brief "Remove" a black hole particle from the calculation. * - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. @@ -5159,6 +5351,10 @@ void cell_remove_bpart(const struct engine *e, struct cell *c, /* Un-link the bpart */ bp->gpart = NULL; + + /* Update the space-wide counters */ + const size_t one = 1; + atomic_add(&e->s->nr_inhibited_bparts, one); } /** @@ -5168,7 +5364,8 @@ void cell_remove_bpart(const struct engine *e, struct cell *c, * Note that the #part is not destroyed. The pointer is still valid * after this call and the properties of the #part are not altered * apart from the time-bin and #gpart pointer. - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. @@ -5204,6 +5401,9 @@ struct gpart *cell_convert_part_to_gpart(const struct engine *e, struct cell *c, gp->ti_kick = p->ti_kick; #endif + /* Update the space-wide counters */ + atomic_inc(&e->s->nr_inhibited_parts); + return gp; } @@ -5214,7 +5414,8 @@ struct gpart *cell_convert_part_to_gpart(const struct engine *e, struct cell *c, * Note that the #spart is not destroyed. The pointer is still valid * after this call and the properties of the #spart are not altered * apart from the time-bin and #gpart pointer. - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. @@ -5249,6 +5450,9 @@ struct gpart *cell_convert_spart_to_gpart(const struct engine *e, gp->ti_kick = sp->ti_kick; #endif + /* Update the space-wide counters */ + atomic_inc(&e->s->nr_inhibited_sparts); + return gp; } @@ -5259,7 +5463,8 @@ struct gpart *cell_convert_spart_to_gpart(const struct engine *e, * Note that the #part is not destroyed. The pointer is still valid * after this call and the properties of the #part are not altered * apart from the time-bin and #gpart pointer. - * The particle is inhibited and will officially be removed at the next rebuild. + * The particle is inhibited and will officially be removed at the next + * rebuild. * * @param e The #engine. * @param c The #cell from which to remove the #part. @@ -5325,8 +5530,8 @@ struct spart *cell_convert_part_to_spart(struct engine *e, struct cell *c, } /** - * @brief Re-arrange the #part in a top-level cell such that all the extra ones - * for on-the-fly creation are located at the end of the array. + * @brief Re-arrange the #part in a top-level cell such that all the extra + * ones for on-the-fly creation are located at the end of the array. * * @param c The #cell to sort. * @param parts_offset The offset between the first #part in the array and the @@ -5377,12 +5582,13 @@ void cell_reorder_extra_parts(struct cell *c, const ptrdiff_t parts_offset) { } /** - * @brief Re-arrange the #spart in a top-level cell such that all the extra ones - * for on-the-fly creation are located at the end of the array. + * @brief Re-arrange the #spart in a top-level cell such that all the extra + * ones for on-the-fly creation are located at the end of the array. * * @param c The #cell to sort. - * @param sparts_offset The offset between the first #spart in the array and the - * first #spart in the global array in the space structure (for re-linking). + * @param sparts_offset The offset between the first #spart in the array and + * the first #spart in the global array in the space structure (for + * re-linking). */ void cell_reorder_extra_sparts(struct cell *c, const ptrdiff_t sparts_offset) { struct spart *sparts = c->stars.parts; @@ -5432,8 +5638,8 @@ void cell_reorder_extra_sparts(struct cell *c, const ptrdiff_t sparts_offset) { } /** - * @brief Re-arrange the #gpart in a top-level cell such that all the extra ones - * for on-the-fly creation are located at the end of the array. + * @brief Re-arrange the #gpart in a top-level cell such that all the extra + * ones for on-the-fly creation are located at the end of the array. * * @param c The #cell to sort. * @param parts The global array of #part (for re-linking). diff --git a/src/cell.h b/src/cell.h index 7500522f1737cacd43aa2cf4d0cb52eb53bec68b..6fcc0afb79dc3b76c70acdcbde87c6d2264aba27 100644 --- a/src/cell.h +++ b/src/cell.h @@ -420,9 +420,6 @@ struct cell { /*! Number of #part updated in this cell. */ int updated; - /*! Number of #part inhibited in this cell. */ - int inhibited; - /*! Is the #part data of this cell being used in a sub-cell? */ int hold; @@ -521,9 +518,6 @@ struct cell { /*! Number of #gpart updated in this cell. */ int updated; - /*! Number of #gpart inhibited in this cell. */ - int inhibited; - /*! Is the #gpart data of this cell being used in a sub-cell? */ int phold; @@ -624,9 +618,6 @@ struct cell { /*! Number of #spart updated in this cell. */ int updated; - /*! Number of #spart inhibited in this cell. */ - int inhibited; - /*! Is the #spart data of this cell being used in a sub-cell? */ int hold; @@ -657,12 +648,22 @@ struct cell { struct task *black_holes_out; /*! The star ghost task itself */ - struct task *ghost; + struct task *density_ghost; - /*! Linked list of the tasks computing this cell's star density. */ + /*! The star ghost task itself */ + struct task *swallow_ghost[2]; + + /*! Linked list of the tasks computing this cell's BH density. */ struct link *density; - /*! Linked list of the tasks computing this cell's star feedback. */ + /*! Linked list of the tasks computing this cell's BH swallowing and + * merging. */ + struct link *swallow; + + /*! Linked list of the tasks processing the particles to swallow */ + struct link *do_swallow; + + /*! Linked list of the tasks computing this cell's BH feedback. */ struct link *feedback; /*! Max smoothing length in this cell. */ @@ -703,9 +704,6 @@ struct cell { /*! Number of #bpart updated in this cell. */ int updated; - /*! Number of #bpart inhibited in this cell. */ - int inhibited; - /*! Is the #bpart data of this cell being used in a sub-cell? */ int hold; @@ -808,9 +806,15 @@ int cell_mlocktree(struct cell *c); void cell_munlocktree(struct cell *c); int cell_slocktree(struct cell *c); void cell_sunlocktree(struct cell *c); +int cell_blocktree(struct cell *c); +void cell_bunlocktree(struct cell *c); int cell_pack(struct cell *c, struct pcell *pc, const int with_gravity); int cell_unpack(struct pcell *pc, struct cell *c, struct space *s, const int with_gravity); +void cell_pack_part_swallow(const struct cell *c, + struct black_holes_part_data *data); +void cell_unpack_part_swallow(struct cell *c, + const struct black_holes_part_data *data); int cell_pack_tags(const struct cell *c, int *tags); int cell_unpack_tags(const int *tags, struct cell *c); int cell_pack_end_step_hydro(struct cell *c, struct pcell_step_hydro *pcell); diff --git a/src/chemistry/EAGLE/chemistry_io.h b/src/chemistry/EAGLE/chemistry_io.h index 62de85d47329a588d658cc61db72510337988638..023791133d6fee78497f27ad741bcfcd1eeec5ce 100644 --- a/src/chemistry/EAGLE/chemistry_io.h +++ b/src/chemistry/EAGLE/chemistry_io.h @@ -166,6 +166,50 @@ INLINE static int chemistry_write_sparticles(const struct spart* sparts, return 12; } +/** + * @brief Specifies which black hole particle fields to write to a dataset + * + * @param bparts The black hole particle array. + * @param list The list of i/o properties to write. + * + * @return Returns the number of fields to write. + */ +INLINE static int chemistry_write_bparticles(const struct bpart* bparts, + struct io_props* list) { + + /* List what we want to write */ + list[0] = + io_make_output_field("ElementMass", FLOAT, chemistry_element_count, + UNIT_CONV_MASS, bparts, chemistry_data.metal_mass); + + list[1] = io_make_output_field("MetalMass", FLOAT, chemistry_element_count, + UNIT_CONV_MASS, bparts, + chemistry_data.metal_mass_total); + + list[2] = io_make_output_field("MassFromSNIa", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.mass_from_SNIa); + + list[3] = io_make_output_field("MassFromSNII", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.mass_from_SNII); + + list[4] = io_make_output_field("MassFromAGB", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.mass_from_AGB); + + list[5] = io_make_output_field("MetalMassFromSNIa", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.metal_mass_from_SNIa); + + list[6] = io_make_output_field("MetalMassFromSNII", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.metal_mass_from_SNII); + + list[7] = io_make_output_field("MetalMassFromAGB", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.metal_mass_from_AGB); + + list[8] = io_make_output_field("IronMassFromSNIa", FLOAT, 1, UNIT_CONV_MASS, + bparts, chemistry_data.iron_mass_from_SNIa); + + return 9; +} + #ifdef HAVE_HDF5 /** diff --git a/src/chemistry/EAGLE/chemistry_struct.h b/src/chemistry/EAGLE/chemistry_struct.h index f5e47347f8b6a910640624ddfc0b5968242eedf6..32d5faaac08886684ebe78ea3696f7aaacab48ea 100644 --- a/src/chemistry/EAGLE/chemistry_struct.h +++ b/src/chemistry/EAGLE/chemistry_struct.h @@ -89,4 +89,37 @@ struct chemistry_part_data { float smoothed_iron_mass_fraction_from_SNIa; }; +/** + * @brief Chemical abundances traced by the #bpart in the EAGLE model. + */ +struct chemistry_bpart_data { + + /*! Mass in a given element */ + float metal_mass[chemistry_element_count]; + + /*! Mass in *all* metals */ + float metal_mass_total; + + /*! Mass coming from SNIa */ + float mass_from_SNIa; + + /*! Mass coming from AGB */ + float mass_from_AGB; + + /*! Mass coming from SNII */ + float mass_from_SNII; + + /*! Metal mass coming from SNIa */ + float metal_mass_from_SNIa; + + /*! Metal mass coming from AGB */ + float metal_mass_from_AGB; + + /*! Metal mass coming from SNII */ + float metal_mass_from_SNII; + + /*! Iron mass coming from SNIa */ + float iron_mass_from_SNIa; +}; + #endif /* SWIFT_CHEMISTRY_STRUCT_EAGLE_H */ diff --git a/src/chemistry/GEAR/chemistry_io.h b/src/chemistry/GEAR/chemistry_io.h index b29f7db65d3ab7dce4b0dcafed06c97a9e621bfe..7d21be4d138f40b626c29a9711166496f34b75d3 100644 --- a/src/chemistry/GEAR/chemistry_io.h +++ b/src/chemistry/GEAR/chemistry_io.h @@ -113,6 +113,21 @@ INLINE static int chemistry_write_sparticles(const struct spart* sparts, return 3; } +/** + * @brief Specifies which black hole particle fields to write to a dataset + * + * @param bparts The black hole particle array. + * @param list The list of i/o properties to write. + * + * @return Returns the number of fields to write. + */ +INLINE static int chemistry_write_bparticles(const struct bpart* bparts, + struct io_props* list) { + + /* No fields to write here */ + return 0; +} + #ifdef HAVE_HDF5 /** diff --git a/src/chemistry/GEAR/chemistry_struct.h b/src/chemistry/GEAR/chemistry_struct.h index c3443126cf0ac72c76774d9000fe218378cc6663..105b72d7fd731356a6f1135ce41b03bb2f898acf 100644 --- a/src/chemistry/GEAR/chemistry_struct.h +++ b/src/chemistry/GEAR/chemistry_struct.h @@ -58,4 +58,9 @@ struct chemistry_part_data { float Z; }; +/** + * @brief Chemical abundances traced by the #bpart in the GEAR model. + */ +struct chemistry_bpart_data {}; + #endif /* SWIFT_CHEMISTRY_STRUCT_GEAR_H */ diff --git a/src/chemistry/none/chemistry_io.h b/src/chemistry/none/chemistry_io.h index c6e5b7b769cec667fee8c3fc674f3b4aa35929c1..698d92c7ca7479400d331bd6adf8d695782a3094 100644 --- a/src/chemistry/none/chemistry_io.h +++ b/src/chemistry/none/chemistry_io.h @@ -72,6 +72,23 @@ INLINE static int chemistry_write_sparticles(const struct spart* sparts, return 0; } +/** + * @brief Specifies which bparticle fields to write to a dataset + * + * @param bparts The bparticle array. + * @param list The list of i/o properties to write. + * + * @return Returns the number of fields to write. + */ +INLINE static int chemistry_write_bparticles(const struct bpart* bparts, + struct io_props* list) { + + /* update list according to hydro_io */ + + /* Return the number of fields to write */ + return 0; +} + #ifdef HAVE_HDF5 /** diff --git a/src/chemistry/none/chemistry_struct.h b/src/chemistry/none/chemistry_struct.h index a80699d66cccd2e290555006d45216ff53d9c99c..3b065bcdf6cbf2fec6f9cb213180e36267fa6a8f 100644 --- a/src/chemistry/none/chemistry_struct.h +++ b/src/chemistry/none/chemistry_struct.h @@ -43,4 +43,11 @@ struct chemistry_global_data {}; */ struct chemistry_part_data {}; +/** + * @brief Chemistry properties carried by the #bpart. + * + * Nothing here. + */ +struct chemistry_bpart_data {}; + #endif /* SWIFT_CHEMISTRY_STRUCT_NONE_H */ diff --git a/src/common_io.c b/src/common_io.c index 537f06e53837619d5f5011628aa649fce90164cb..140dfc14593aa8964845e3bb73cbf01c2176e534 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -387,6 +387,59 @@ void io_write_engine_policy(hid_t h_file, const struct engine* e) { H5Gclose(h_grp); } +static long long cell_count_non_inhibited_gas(const struct cell* c) { + const int total_count = c->hydro.count; + struct part* parts = c->hydro.parts; + long long count = 0; + for (int i = 0; i < total_count; ++i) { + if (!(parts[i].time_bin != time_bin_inhibited) && + !(parts[i].time_bin != time_bin_not_created)) { + ++count; + } + } + return count; +} + +static long long cell_count_non_inhibited_dark_matter(const struct cell* c) { + const int total_count = c->grav.count; + struct gpart* gparts = c->grav.parts; + long long count = 0; + for (int i = 0; i < total_count; ++i) { + if (!(gparts[i].time_bin != time_bin_inhibited) && + !(gparts[i].time_bin != time_bin_not_created) && + (gparts[i].type == swift_type_dark_matter)) { + ++count; + } + } + return count; +} + +static long long cell_count_non_inhibited_stars(const struct cell* c) { + const int total_count = c->stars.count; + struct spart* sparts = c->stars.parts; + long long count = 0; + for (int i = 0; i < total_count; ++i) { + if (!(sparts[i].time_bin != time_bin_inhibited) && + !(sparts[i].time_bin != time_bin_not_created)) { + ++count; + } + } + return count; +} + +static long long cell_count_non_inhibited_black_holes(const struct cell* c) { + const int total_count = c->black_holes.count; + struct bpart* bparts = c->black_holes.parts; + long long count = 0; + for (int i = 0; i < total_count; ++i) { + if (!(bparts[i].time_bin != time_bin_inhibited) && + !(bparts[i].time_bin != time_bin_not_created)) { + ++count; + } + } + return count; +} + void io_write_cell_offsets(hid_t h_grp, const int cdim[3], const struct cell* cells_top, const int nr_cells, const double width[3], const int nodeID, @@ -438,15 +491,10 @@ void io_write_cell_offsets(hid_t h_grp, const int cdim[3], centres[i * 3 + 2] = cells_top[i].loc[2] + cell_width[2] * 0.5; /* Count real particles that will be written */ - count_part[i] = cells_top[i].hydro.count - cells_top[i].hydro.inhibited; - count_gpart[i] = cells_top[i].grav.count - cells_top[i].grav.inhibited; - count_spart[i] = cells_top[i].stars.count - cells_top[i].stars.inhibited; - count_bpart[i] = cells_top[i].stars.count - cells_top[i].stars.inhibited; - - /* Only count DM gpart (gpart without friends) */ - count_gpart[i] -= count_part[i]; - count_gpart[i] -= count_spart[i]; - count_gpart[i] -= count_bpart[i]; + count_part[i] = cell_count_non_inhibited_gas(&cells_top[i]); + count_gpart[i] = cell_count_non_inhibited_dark_matter(&cells_top[i]); + count_spart[i] = cell_count_non_inhibited_stars(&cells_top[i]); + count_bpart[i] = cell_count_non_inhibited_black_holes(&cells_top[i]); /* Offsets including the global offset of all particles on this MPI rank */ @@ -454,7 +502,8 @@ void io_write_cell_offsets(hid_t h_grp, const int cdim[3], offset_gpart[i] = local_offset_gpart + global_offsets[swift_type_dark_matter]; offset_spart[i] = local_offset_spart + global_offsets[swift_type_stars]; - offset_bpart[i] = local_offset_bpart + global_offsets[swift_type_stars]; + offset_bpart[i] = + local_offset_bpart + global_offsets[swift_type_black_hole]; local_offset_part += count_part[i]; local_offset_gpart += count_gpart[i]; diff --git a/src/engine.c b/src/engine.c index c7ee60aa5756360344e47fc8dae768137b009eca..a42ead2d878f102dadaa925510f41296e48dde69 100644 --- a/src/engine.c +++ b/src/engine.c @@ -2715,7 +2715,7 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c, #endif /* Counters for the different quantities. */ - size_t updated = 0, inhibited = 0; + size_t updated = 0; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; @@ -2739,7 +2739,6 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c, ti_hydro_beg_max = max(ti_hydro_beg_max, cp->hydro.ti_beg_max); updated += cp->hydro.updated; - inhibited += cp->hydro.inhibited; /* Check if the cell is inactive and in that case reorder the SFH */ if (!cell_is_starting_hydro(cp, e)) { @@ -2759,7 +2758,7 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c, c->hydro.ti_end_max = ti_hydro_end_max; c->hydro.ti_beg_max = ti_hydro_beg_max; c->hydro.updated = updated; - c->hydro.inhibited = inhibited; + // c->hydro.inhibited = inhibited; /* Store the star formation history in the parent cell */ star_formation_logger_add(&c->stars.sfh, &sfh_updated); @@ -2790,7 +2789,7 @@ void engine_collect_end_of_step_recurse_grav(struct cell *c, #endif /* Counters for the different quantities. */ - size_t updated = 0, inhibited = 0; + size_t updated = 0; integertime_t ti_grav_end_min = max_nr_timesteps, ti_grav_end_max = 0, ti_grav_beg_max = 0; @@ -2808,7 +2807,6 @@ void engine_collect_end_of_step_recurse_grav(struct cell *c, ti_grav_beg_max = max(ti_grav_beg_max, cp->grav.ti_beg_max); updated += cp->grav.updated; - inhibited += cp->grav.inhibited; /* Collected, so clear for next time. */ cp->grav.updated = 0; @@ -2820,7 +2818,6 @@ void engine_collect_end_of_step_recurse_grav(struct cell *c, c->grav.ti_end_max = ti_grav_end_max; c->grav.ti_beg_max = ti_grav_beg_max; c->grav.updated = updated; - c->grav.inhibited = inhibited; } /** @@ -2847,7 +2844,7 @@ void engine_collect_end_of_step_recurse_stars(struct cell *c, #endif /* Counters for the different quantities. */ - size_t updated = 0, inhibited = 0; + size_t updated = 0; integertime_t ti_stars_end_min = max_nr_timesteps, ti_stars_end_max = 0, ti_stars_beg_max = 0; @@ -2865,7 +2862,6 @@ void engine_collect_end_of_step_recurse_stars(struct cell *c, ti_stars_beg_max = max(ti_stars_beg_max, cp->stars.ti_beg_max); updated += cp->stars.updated; - inhibited += cp->stars.inhibited; /* Collected, so clear for next time. */ cp->stars.updated = 0; @@ -2877,7 +2873,6 @@ void engine_collect_end_of_step_recurse_stars(struct cell *c, c->stars.ti_end_max = ti_stars_end_max; c->stars.ti_beg_max = ti_stars_beg_max; c->stars.updated = updated; - c->stars.inhibited = inhibited; } /** @@ -2904,7 +2899,7 @@ void engine_collect_end_of_step_recurse_black_holes(struct cell *c, #endif /* Counters for the different quantities. */ - size_t updated = 0, inhibited = 0; + size_t updated = 0; integertime_t ti_black_holes_end_min = max_nr_timesteps, ti_black_holes_end_max = 0, ti_black_holes_beg_max = 0; @@ -2925,7 +2920,6 @@ void engine_collect_end_of_step_recurse_black_holes(struct cell *c, max(ti_black_holes_beg_max, cp->black_holes.ti_beg_max); updated += cp->black_holes.updated; - inhibited += cp->black_holes.inhibited; /* Collected, so clear for next time. */ cp->black_holes.updated = 0; @@ -2937,7 +2931,6 @@ void engine_collect_end_of_step_recurse_black_holes(struct cell *c, c->black_holes.ti_end_max = ti_black_holes_end_max; c->black_holes.ti_beg_max = ti_black_holes_beg_max; c->black_holes.updated = updated; - c->black_holes.inhibited = inhibited; } /** @@ -2968,7 +2961,6 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, /* Local collectible */ size_t updated = 0, g_updated = 0, s_updated = 0, b_updated = 0; - size_t inhibited = 0, g_inhibited = 0, s_inhibited = 0, b_inhibited = 0; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; integertime_t ti_gravity_end_min = max_nr_timesteps, ti_gravity_end_max = 0, @@ -3033,11 +3025,6 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, s_updated += c->stars.updated; b_updated += c->black_holes.updated; - inhibited += c->hydro.inhibited; - g_inhibited += c->grav.inhibited; - s_inhibited += c->stars.inhibited; - b_inhibited += c->black_holes.inhibited; - /* Check if the cell is inactive and in that case reorder the SFH */ if (!cell_is_starting_hydro(c, e)) { star_formation_logger_log_inactive_cell(&c->stars.sfh); @@ -3063,11 +3050,6 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, data->s_updated += s_updated; data->b_updated += b_updated; - data->inhibited += inhibited; - data->g_inhibited += g_inhibited; - data->s_inhibited += s_inhibited; - data->b_inhibited += b_inhibited; - /* Add the SFH information from this engine to the global data */ star_formation_logger_add(sfh_top, &sfh_updated); @@ -3124,8 +3106,6 @@ void engine_collect_end_of_step(struct engine *e, int apply) { struct space *s = e->s; struct end_of_step_data data; data.updated = 0, data.g_updated = 0, data.s_updated = 0, data.b_updated = 0; - data.inhibited = 0, data.g_inhibited = 0, data.s_inhibited = 0, - data.b_inhibited = 0; data.ti_hydro_end_min = max_nr_timesteps, data.ti_hydro_end_max = 0, data.ti_hydro_beg_max = 0; data.ti_gravity_end_min = max_nr_timesteps, data.ti_gravity_end_max = 0, @@ -3144,11 +3124,12 @@ void engine_collect_end_of_step(struct engine *e, int apply) { s->local_cells_with_tasks_top, s->nr_local_cells_with_tasks, sizeof(int), 0, &data); - /* Store the local number of inhibited particles */ - s->nr_inhibited_parts = data.inhibited; - s->nr_inhibited_gparts = data.g_inhibited; - s->nr_inhibited_sparts = data.s_inhibited; - s->nr_inhibited_bparts = data.b_inhibited; + /* Get the number of inhibited particles from the space-wide counters + * since these have been updated atomically during the time-steps. */ + data.inhibited = s->nr_inhibited_parts; + data.g_inhibited = s->nr_inhibited_gparts; + data.s_inhibited = s->nr_inhibited_sparts; + data.b_inhibited = s->nr_inhibited_bparts; /* Store these in the temporary collection group. */ collectgroup1_init( @@ -3184,11 +3165,12 @@ void engine_collect_end_of_step(struct engine *e, int apply) { error("Failed to get same ti_gravity_end_min, is %lld, should be %lld", in_i[1], e->collect_group1.ti_gravity_end_min); - long long in_ll[3], out_ll[3]; + long long in_ll[4], out_ll[4]; out_ll[0] = data.updated; out_ll[1] = data.g_updated; out_ll[2] = data.s_updated; - if (MPI_Allreduce(out_ll, in_ll, 3, MPI_LONG_LONG_INT, MPI_SUM, + out_ll[3] = data.b_updated; + if (MPI_Allreduce(out_ll, in_ll, 4, MPI_LONG_LONG_INT, MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS) error("Failed to aggregate particle counts."); if (in_ll[0] != (long long)e->collect_group1.updated) @@ -3200,11 +3182,15 @@ void engine_collect_end_of_step(struct engine *e, int apply) { if (in_ll[2] != (long long)e->collect_group1.s_updated) error("Failed to get same s_updated, is %lld, should be %lld", in_ll[2], e->collect_group1.s_updated); + if (in_ll[3] != (long long)e->collect_group1.b_updated) + error("Failed to get same b_updated, is %lld, should be %lld", in_ll[3], + e->collect_group1.b_updated); out_ll[0] = data.inhibited; out_ll[1] = data.g_inhibited; out_ll[2] = data.s_inhibited; - if (MPI_Allreduce(out_ll, in_ll, 3, MPI_LONG_LONG_INT, MPI_SUM, + out_ll[3] = data.b_inhibited; + if (MPI_Allreduce(out_ll, in_ll, 4, MPI_LONG_LONG_INT, MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS) error("Failed to aggregate particle counts."); if (in_ll[0] != (long long)e->collect_group1.inhibited) @@ -3216,6 +3202,9 @@ void engine_collect_end_of_step(struct engine *e, int apply) { if (in_ll[2] != (long long)e->collect_group1.s_inhibited) error("Failed to get same s_inhibited, is %lld, should be %lld", in_ll[2], e->collect_group1.s_inhibited); + if (in_ll[3] != (long long)e->collect_group1.b_inhibited) + error("Failed to get same b_inhibited, is %lld, should be %lld", in_ll[3], + e->collect_group1.b_inhibited); int buff = 0; if (MPI_Allreduce(&e->forcerebuild, &buff, 1, MPI_INT, MPI_MAX, @@ -3336,9 +3325,17 @@ void engine_skip_force_and_kick(struct engine *e) { t->type == task_type_stars_in || t->type == task_type_stars_out || t->type == task_type_star_formation || t->type == task_type_extra_ghost || + t->type == task_type_bh_swallow_ghost1 || + t->type == task_type_bh_swallow_ghost2 || t->subtype == task_subtype_gradient || t->subtype == task_subtype_stars_feedback || t->subtype == task_subtype_bh_feedback || + t->subtype == task_subtype_bh_swallow || + t->subtype == task_subtype_do_swallow || + t->subtype == task_subtype_bpart_rho || + t->subtype == task_subtype_part_swallow || + t->subtype == task_subtype_bpart_swallow || + t->subtype == task_subtype_bpart_feedback || t->subtype == task_subtype_tend_part || t->subtype == task_subtype_tend_gpart || t->subtype == task_subtype_tend_spart || @@ -3571,6 +3568,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, #ifdef SWIFT_DEBUG_CHECKS /* Make sure all woken-up particles have been processed */ space_check_limiter(e->s); + space_check_swallow(e->s); #endif /* Recover the (integer) end of the next time-step */ @@ -3859,6 +3857,7 @@ void engine_step(struct engine *e) { /* Make sure all woken-up particles have been processed */ space_check_limiter(e->s); space_check_sort_flags(e->s); + space_check_swallow(e->s); #endif /* Collect information about the next time-step */ diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c index 150ec107f999cc390c34f54d3b5835919cc83cf8..af119c9370d83eace384690b9b58aaa95e49867e 100644 --- a/src/engine_maketasks.c +++ b/src/engine_maketasks.c @@ -318,11 +318,18 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci, * @param e The #engine. * @param ci The sending #cell. * @param cj Dummy cell containing the nodeID of the receiving node. + * @param t_rho The density comm. task, if it has already been created. + * @param t_swallow The BH swallow comm. task, if it has already been created. + * @param t_gas_swallow The gas swallow comm. task, if it has already been + * created. * @param t_feedback The send_feed #task, if it has already been created. * @param t_ti The recv_ti_end #task, if it has already been created. */ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci, - struct cell *cj, struct task *t_feedback, + struct cell *cj, struct task *t_rho, + struct task *t_swallow, + struct task *t_gas_swallow, + struct task *t_feedback, struct task *t_ti) { #ifdef WITH_MPI @@ -340,31 +347,60 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci, /* If so, attach send tasks. */ if (l != NULL) { - if (t_feedback == NULL) { + if (t_rho == NULL) { /* Make sure this cell is tagged. */ cell_ensure_tagged(ci); /* Create the tasks and their dependencies? */ - t_feedback = scheduler_addtask(s, task_type_send, task_subtype_bpart, - ci->mpi.tag, 0, ci, cj); + t_rho = scheduler_addtask(s, task_type_send, task_subtype_bpart_rho, + ci->mpi.tag, 0, ci, cj); + + /* t_swallow = */ + /* scheduler_addtask(s, task_type_send, task_subtype_bpart_swallow, */ + /* ci->mpi.tag, 0, ci, cj); */ + + t_gas_swallow = scheduler_addtask( + s, task_type_send, task_subtype_part_swallow, ci->mpi.tag, 0, ci, cj); + + t_feedback = + scheduler_addtask(s, task_type_send, task_subtype_bpart_feedback, + ci->mpi.tag, 0, ci, cj); t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend_bpart, ci->mpi.tag, 0, ci, cj); - /* The send_black_holes task should unlock the super_cell's kick task. */ + /* The send_black_holes task should unlock the super_cell's BH exit point + * task. */ scheduler_addunlock(s, t_feedback, ci->hydro.super->black_holes.black_holes_out); + scheduler_addunlock(s, ci->hydro.super->black_holes.swallow_ghost[1], + t_feedback); + /* Ghost before you send */ - scheduler_addunlock(s, ci->hydro.super->black_holes.ghost, t_feedback); + scheduler_addunlock(s, ci->hydro.super->black_holes.density_ghost, t_rho); + scheduler_addunlock(s, t_rho, + ci->hydro.super->black_holes.swallow_ghost[0]); /* Drift before you send */ - scheduler_addunlock(s, ci->hydro.super->black_holes.drift, t_feedback); + /* scheduler_addunlock(s, ci->hydro.super->black_holes.swallow_ghost[0], + */ + /* t_swallow); */ + /* scheduler_addunlock(s, t_swallow, */ + /* ci->hydro.super->black_holes.swallow_ghost[1]); */ + + scheduler_addunlock(s, ci->hydro.super->black_holes.swallow_ghost[0], + t_gas_swallow); + scheduler_addunlock(s, t_gas_swallow, + ci->hydro.super->black_holes.swallow_ghost[1]); scheduler_addunlock(s, ci->super->timestep, t_ti); } + engine_addlink(e, &ci->mpi.send, t_rho); + // engine_addlink(e, &ci->mpi.send, t_swallow); + engine_addlink(e, &ci->mpi.send, t_gas_swallow); engine_addlink(e, &ci->mpi.send, t_feedback); engine_addlink(e, &ci->mpi.send, t_ti); } @@ -373,7 +409,8 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci, if (ci->split) for (int k = 0; k < 8; k++) if (ci->progeny[k] != NULL) - engine_addtasks_send_black_holes(e, ci->progeny[k], cj, t_feedback, + engine_addtasks_send_black_holes(e, ci->progeny[k], cj, t_rho, + t_swallow, t_gas_swallow, t_feedback, t_ti); #else @@ -460,10 +497,10 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, scheduler_addunlock(s, t_rho, l->t); } - /* Make sure the part have been sent before the BHs compute their densities. - */ + /* Make sure the part have been received before the BHs compute their + * accretion rates (depends on particles' rho). */ for (struct link *l = c->black_holes.density; l != NULL; l = l->next) { - scheduler_addunlock(s, t_xv, l->t); + scheduler_addunlock(s, t_rho, l->t); } } @@ -571,10 +608,17 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c, * * @param e The #engine. * @param c The foreign #cell. + * @param t_rho The density comm. task, if it has already been created. + * @param t_swallow The BH swallow comm. task, if it has already been created. + * @param t_gas_swallow The gas swallow comm. task, if it has already been + * created. * @param t_feedback The recv_feed #task, if it has already been created. * @param t_ti The recv_ti_end #task, if it has already been created. */ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c, + struct task *t_rho, + struct task *t_swallow, + struct task *t_gas_swallow, struct task *t_feedback, struct task *t_ti) { @@ -582,7 +626,7 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c, struct scheduler *s = &e->sched; /* Have we reached a level where there are any black_holes tasks ? */ - if (t_feedback == NULL && c->black_holes.density != NULL) { + if (t_rho == NULL && c->black_holes.density != NULL) { #ifdef SWIFT_DEBUG_CHECKS /* Make sure this cell has a valid tag. */ @@ -590,14 +634,27 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c, #endif // SWIFT_DEBUG_CHECKS /* Create the tasks. */ - t_feedback = scheduler_addtask(s, task_type_recv, task_subtype_bpart, - c->mpi.tag, 0, c, NULL); + t_rho = scheduler_addtask(s, task_type_recv, task_subtype_bpart_rho, + c->mpi.tag, 0, c, NULL); + + /* t_swallow = scheduler_addtask(s, task_type_recv, + * task_subtype_bpart_swallow, */ + /* c->mpi.tag, 0, c, NULL); */ + + t_gas_swallow = scheduler_addtask( + s, task_type_recv, task_subtype_part_swallow, c->mpi.tag, 0, c, NULL); + + t_feedback = scheduler_addtask( + s, task_type_recv, task_subtype_bpart_feedback, c->mpi.tag, 0, c, NULL); t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_bpart, c->mpi.tag, 0, c, NULL); } - if (t_feedback != NULL) { + if (t_rho != NULL) { + engine_addlink(e, &c->mpi.recv, t_rho); + // engine_addlink(e, &c->mpi.recv, t_swallow); + engine_addlink(e, &c->mpi.recv, t_gas_swallow); engine_addlink(e, &c->mpi.recv, t_feedback); engine_addlink(e, &c->mpi.recv, t_ti); @@ -606,9 +663,23 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c, #endif for (struct link *l = c->black_holes.density; l != NULL; l = l->next) { - scheduler_addunlock(s, l->t, t_feedback); + scheduler_addunlock(s, l->t, t_rho); } + for (struct link *l = c->hydro.force; l != NULL; l = l->next) { + scheduler_addunlock(s, l->t, t_gas_swallow); + } + + for (struct link *l = c->black_holes.swallow; l != NULL; l = l->next) { + scheduler_addunlock(s, t_rho, l->t); + // scheduler_addunlock(s, l->t, t_swallow); + scheduler_addunlock(s, l->t, t_gas_swallow); + } + for (struct link *l = c->black_holes.do_swallow; l != NULL; l = l->next) { + // scheduler_addunlock(s, t_swallow, l->t); + scheduler_addunlock(s, t_gas_swallow, l->t); + scheduler_addunlock(s, l->t, t_feedback); + } for (struct link *l = c->black_holes.feedback; l != NULL; l = l->next) { scheduler_addunlock(s, t_feedback, l->t); scheduler_addunlock(s, l->t, t_ti); @@ -619,7 +690,8 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c, if (c->split) for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) - engine_addtasks_recv_black_holes(e, c->progeny[k], t_feedback, t_ti); + engine_addtasks_recv_black_holes(e, c->progeny[k], t_rho, t_swallow, + t_gas_swallow, t_feedback, t_ti); #else error("SWIFT was not compiled with MPI support."); @@ -925,6 +997,12 @@ void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c) { task_subtype_none, 0, 0, c, NULL); } + if (with_black_holes) { + c->black_holes.swallow_ghost[0] = + scheduler_addtask(s, task_type_bh_swallow_ghost1, task_subtype_none, + 0, /* implicit =*/1, c, NULL); + } + /* Local tasks only... */ if (c->nodeID == e->nodeID) { @@ -1012,8 +1090,11 @@ void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c) { scheduler_addtask(s, task_type_bh_out, task_subtype_none, 0, /* implicit = */ 1, c, NULL); - c->black_holes.ghost = scheduler_addtask( - s, task_type_bh_ghost, task_subtype_none, 0, 0, c, NULL); + c->black_holes.density_ghost = scheduler_addtask( + s, task_type_bh_density_ghost, task_subtype_none, 0, 0, c, NULL); + + c->black_holes.swallow_ghost[1] = scheduler_addtask( + s, task_type_bh_swallow_ghost2, task_subtype_none, 0, 0, c, NULL); scheduler_addunlock(s, c->super->kick2, c->black_holes.black_holes_in); scheduler_addunlock(s, c->black_holes.black_holes_out, @@ -1636,6 +1717,8 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, struct task *t_star_density = NULL; struct task *t_star_feedback = NULL; struct task *t_bh_density = NULL; + struct task *t_bh_swallow = NULL; + struct task *t_do_swallow = NULL; struct task *t_bh_feedback = NULL; for (int ind = 0; ind < num_elements; ind++) { @@ -1660,6 +1743,8 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* Self-interaction? */ else if (t_type == task_type_self && t_subtype == task_subtype_density) { + const int bcount_i = ci->black_holes.count; + /* Make the self-density tasks depend on the drift only. */ scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t); @@ -1684,9 +1769,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, } /* The black hole feedback tasks */ - if (with_black_holes) { + if (with_black_holes && bcount_i > 0) { t_bh_density = scheduler_addtask( sched, task_type_self, task_subtype_bh_density, flags, 0, ci, NULL); + t_bh_swallow = scheduler_addtask( + sched, task_type_self, task_subtype_bh_swallow, flags, 0, ci, NULL); + t_do_swallow = scheduler_addtask( + sched, task_type_self, task_subtype_do_swallow, flags, 0, ci, NULL); t_bh_feedback = scheduler_addtask(sched, task_type_self, task_subtype_bh_feedback, flags, 0, ci, NULL); @@ -1701,8 +1790,10 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, engine_addlink(e, &ci->stars.density, t_star_density); engine_addlink(e, &ci->stars.feedback, t_star_feedback); } - if (with_black_holes) { + if (with_black_holes && bcount_i > 0) { engine_addlink(e, &ci->black_holes.density, t_bh_density); + engine_addlink(e, &ci->black_holes.swallow, t_bh_swallow); + engine_addlink(e, &ci->black_holes.do_swallow, t_do_swallow); engine_addlink(e, &ci->black_holes.feedback, t_bh_feedback); } @@ -1745,7 +1836,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->stars.stars_out); } - if (with_black_holes) { + if (with_black_holes && bcount_i > 0) { scheduler_addunlock(sched, ci->hydro.super->black_holes.drift, t_bh_density); @@ -1753,8 +1844,20 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock(sched, ci->hydro.super->black_holes.black_holes_in, t_bh_density); scheduler_addunlock(sched, t_bh_density, - ci->hydro.super->black_holes.ghost); - scheduler_addunlock(sched, ci->hydro.super->black_holes.ghost, + ci->hydro.super->black_holes.density_ghost); + + scheduler_addunlock(sched, ci->hydro.super->black_holes.density_ghost, + t_bh_swallow); + scheduler_addunlock(sched, t_bh_swallow, + ci->hydro.super->black_holes.swallow_ghost[0]); + + scheduler_addunlock( + sched, ci->hydro.super->black_holes.swallow_ghost[0], t_do_swallow); + scheduler_addunlock(sched, t_do_swallow, + ci->hydro.super->black_holes.swallow_ghost[1]); + + scheduler_addunlock(sched, + ci->hydro.super->black_holes.swallow_ghost[1], t_bh_feedback); scheduler_addunlock(sched, t_bh_feedback, ci->hydro.super->black_holes.black_holes_out); @@ -1770,6 +1873,9 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* Otherwise, pair interaction? */ else if (t_type == task_type_pair && t_subtype == task_subtype_density) { + const int bcount_i = ci->black_holes.count; + const int bcount_j = cj->black_holes.count; + /* Make all density tasks depend on the drift */ if (ci->nodeID == nodeID) { scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t); @@ -1805,9 +1911,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, } /* The black hole feedback tasks */ - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { t_bh_density = scheduler_addtask( sched, task_type_pair, task_subtype_bh_density, flags, 0, ci, cj); + t_bh_swallow = scheduler_addtask( + sched, task_type_pair, task_subtype_bh_swallow, flags, 0, ci, cj); + t_do_swallow = scheduler_addtask( + sched, task_type_pair, task_subtype_do_swallow, flags, 0, ci, cj); t_bh_feedback = scheduler_addtask( sched, task_type_pair, task_subtype_bh_feedback, flags, 0, ci, cj); } @@ -1824,9 +1934,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, engine_addlink(e, &ci->stars.feedback, t_star_feedback); engine_addlink(e, &cj->stars.feedback, t_star_feedback); } - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { engine_addlink(e, &ci->black_holes.density, t_bh_density); engine_addlink(e, &cj->black_holes.density, t_bh_density); + engine_addlink(e, &ci->black_holes.swallow, t_bh_swallow); + engine_addlink(e, &cj->black_holes.swallow, t_bh_swallow); + engine_addlink(e, &ci->black_holes.do_swallow, t_do_swallow); + engine_addlink(e, &cj->black_holes.do_swallow, t_do_swallow); engine_addlink(e, &ci->black_holes.feedback, t_bh_feedback); engine_addlink(e, &cj->black_holes.feedback, t_bh_feedback); } @@ -1898,7 +2012,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->stars.stars_out); } - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { scheduler_addunlock(sched, ci->hydro.super->black_holes.drift, t_bh_density); @@ -1907,8 +2021,21 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock( sched, ci->hydro.super->black_holes.black_holes_in, t_bh_density); scheduler_addunlock(sched, t_bh_density, - ci->hydro.super->black_holes.ghost); - scheduler_addunlock(sched, ci->hydro.super->black_holes.ghost, + ci->hydro.super->black_holes.density_ghost); + + scheduler_addunlock(sched, ci->hydro.super->black_holes.density_ghost, + t_bh_swallow); + scheduler_addunlock(sched, t_bh_swallow, + ci->hydro.super->black_holes.swallow_ghost[0]); + + scheduler_addunlock(sched, + ci->hydro.super->black_holes.swallow_ghost[0], + t_do_swallow); + scheduler_addunlock(sched, t_do_swallow, + ci->hydro.super->black_holes.swallow_ghost[1]); + + scheduler_addunlock(sched, + ci->hydro.super->black_holes.swallow_ghost[1], t_bh_feedback); scheduler_addunlock(sched, t_bh_feedback, ci->hydro.super->black_holes.black_holes_out); @@ -1924,6 +2051,11 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock(sched, ci->hydro.super->stars.sorts, t_star_feedback); } + + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { + scheduler_addunlock(sched, t_bh_swallow, + ci->hydro.super->black_holes.swallow_ghost[0]); + } } if (cj->nodeID == nodeID) { @@ -1950,7 +2082,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, cj->hydro.super->stars.stars_out); } - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { scheduler_addunlock(sched, cj->hydro.super->black_holes.drift, t_bh_density); @@ -1960,8 +2092,22 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, cj->hydro.super->black_holes.black_holes_in, t_bh_density); scheduler_addunlock(sched, t_bh_density, - cj->hydro.super->black_holes.ghost); - scheduler_addunlock(sched, cj->hydro.super->black_holes.ghost, + cj->hydro.super->black_holes.density_ghost); + + scheduler_addunlock(sched, + cj->hydro.super->black_holes.density_ghost, + t_bh_swallow); + scheduler_addunlock(sched, t_bh_swallow, + cj->hydro.super->black_holes.swallow_ghost[0]); + + scheduler_addunlock(sched, + cj->hydro.super->black_holes.swallow_ghost[0], + t_do_swallow); + scheduler_addunlock(sched, t_do_swallow, + cj->hydro.super->black_holes.swallow_ghost[1]); + + scheduler_addunlock(sched, + cj->hydro.super->black_holes.swallow_ghost[1], t_bh_feedback); scheduler_addunlock(sched, t_bh_feedback, cj->hydro.super->black_holes.black_holes_out); @@ -1978,6 +2124,12 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock(sched, cj->hydro.super->stars.sorts, t_star_feedback); } + + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { + + scheduler_addunlock(sched, t_bh_swallow, + cj->hydro.super->black_holes.swallow_ghost[0]); + } } } @@ -1985,6 +2137,8 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, else if (t_type == task_type_sub_self && t_subtype == task_subtype_density) { + const int bcount_i = ci->black_holes.count; + /* Make all density tasks depend on the drift and sorts. */ scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t); scheduler_addunlock(sched, ci->hydro.super->hydro.sorts, t); @@ -2010,10 +2164,18 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, } /* The black hole feedback tasks */ - if (with_black_holes) { + if (with_black_holes && bcount_i > 0) { t_bh_density = scheduler_addtask(sched, task_type_sub_self, task_subtype_bh_density, flags, 0, ci, NULL); + t_bh_swallow = + scheduler_addtask(sched, task_type_sub_self, + task_subtype_bh_swallow, flags, 0, ci, NULL); + + t_do_swallow = + scheduler_addtask(sched, task_type_sub_self, + task_subtype_do_swallow, flags, 0, ci, NULL); + t_bh_feedback = scheduler_addtask(sched, task_type_sub_self, task_subtype_bh_feedback, flags, 0, ci, NULL); @@ -2028,8 +2190,10 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, engine_addlink(e, &ci->stars.density, t_star_density); engine_addlink(e, &ci->stars.feedback, t_star_feedback); } - if (with_black_holes) { + if (with_black_holes && bcount_i > 0) { engine_addlink(e, &ci->black_holes.density, t_bh_density); + engine_addlink(e, &ci->black_holes.swallow, t_bh_swallow); + engine_addlink(e, &ci->black_holes.do_swallow, t_do_swallow); engine_addlink(e, &ci->black_holes.feedback, t_bh_feedback); } @@ -2078,7 +2242,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->stars.stars_out); } - if (with_black_holes) { + if (with_black_holes && bcount_i > 0) { scheduler_addunlock(sched, ci->hydro.super->black_holes.drift, t_bh_density); @@ -2086,8 +2250,20 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock(sched, ci->hydro.super->black_holes.black_holes_in, t_bh_density); scheduler_addunlock(sched, t_bh_density, - ci->hydro.super->black_holes.ghost); - scheduler_addunlock(sched, ci->hydro.super->black_holes.ghost, + ci->hydro.super->black_holes.density_ghost); + + scheduler_addunlock(sched, ci->hydro.super->black_holes.density_ghost, + t_bh_swallow); + scheduler_addunlock(sched, t_bh_swallow, + ci->hydro.super->black_holes.swallow_ghost[0]); + + scheduler_addunlock( + sched, ci->hydro.super->black_holes.swallow_ghost[0], t_do_swallow); + scheduler_addunlock(sched, t_do_swallow, + ci->hydro.super->black_holes.swallow_ghost[1]); + + scheduler_addunlock(sched, + ci->hydro.super->black_holes.swallow_ghost[1], t_bh_feedback); scheduler_addunlock(sched, t_bh_feedback, ci->hydro.super->black_holes.black_holes_out); @@ -2105,6 +2281,9 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, else if (t_type == task_type_sub_pair && t_subtype == task_subtype_density) { + const int bcount_i = ci->black_holes.count; + const int bcount_j = cj->black_holes.count; + /* Make all density tasks depend on the drift */ if (ci->nodeID == nodeID) { scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t); @@ -2140,10 +2319,16 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, } /* The black hole feedback tasks */ - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { t_bh_density = scheduler_addtask(sched, task_type_sub_pair, task_subtype_bh_density, flags, 0, ci, cj); + t_bh_swallow = + scheduler_addtask(sched, task_type_sub_pair, + task_subtype_bh_swallow, flags, 0, ci, cj); + t_do_swallow = + scheduler_addtask(sched, task_type_sub_pair, + task_subtype_do_swallow, flags, 0, ci, cj); t_bh_feedback = scheduler_addtask(sched, task_type_sub_pair, task_subtype_bh_feedback, flags, 0, ci, cj); @@ -2161,9 +2346,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, engine_addlink(e, &ci->stars.feedback, t_star_feedback); engine_addlink(e, &cj->stars.feedback, t_star_feedback); } - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { engine_addlink(e, &ci->black_holes.density, t_bh_density); engine_addlink(e, &cj->black_holes.density, t_bh_density); + engine_addlink(e, &ci->black_holes.swallow, t_bh_swallow); + engine_addlink(e, &cj->black_holes.swallow, t_bh_swallow); + engine_addlink(e, &ci->black_holes.do_swallow, t_do_swallow); + engine_addlink(e, &cj->black_holes.do_swallow, t_do_swallow); engine_addlink(e, &ci->black_holes.feedback, t_bh_feedback); engine_addlink(e, &cj->black_holes.feedback, t_bh_feedback); } @@ -2234,7 +2423,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->stars.stars_out); } - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { scheduler_addunlock(sched, ci->hydro.super->black_holes.drift, t_bh_density); @@ -2243,8 +2432,21 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock( sched, ci->hydro.super->black_holes.black_holes_in, t_bh_density); scheduler_addunlock(sched, t_bh_density, - ci->hydro.super->black_holes.ghost); - scheduler_addunlock(sched, ci->hydro.super->black_holes.ghost, + ci->hydro.super->black_holes.density_ghost); + + scheduler_addunlock(sched, ci->hydro.super->black_holes.density_ghost, + t_bh_swallow); + scheduler_addunlock(sched, t_bh_swallow, + ci->hydro.super->black_holes.swallow_ghost[0]); + + scheduler_addunlock(sched, + ci->hydro.super->black_holes.swallow_ghost[0], + t_do_swallow); + scheduler_addunlock(sched, t_do_swallow, + ci->hydro.super->black_holes.swallow_ghost[1]); + + scheduler_addunlock(sched, + ci->hydro.super->black_holes.swallow_ghost[1], t_bh_feedback); scheduler_addunlock(sched, t_bh_feedback, ci->hydro.super->black_holes.black_holes_out); @@ -2262,6 +2464,11 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock(sched, ci->hydro.super->stars.sorts, t_star_feedback); } + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { + + scheduler_addunlock(sched, t_bh_swallow, + ci->hydro.super->black_holes.swallow_ghost[0]); + } } if (cj->nodeID == nodeID) { @@ -2288,7 +2495,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, cj->hydro.super->stars.stars_out); } - if (with_black_holes) { + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { scheduler_addunlock(sched, cj->hydro.super->black_holes.drift, t_bh_density); @@ -2298,8 +2505,22 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, cj->hydro.super->black_holes.black_holes_in, t_bh_density); scheduler_addunlock(sched, t_bh_density, - cj->hydro.super->black_holes.ghost); - scheduler_addunlock(sched, cj->hydro.super->black_holes.ghost, + cj->hydro.super->black_holes.density_ghost); + + scheduler_addunlock(sched, + cj->hydro.super->black_holes.density_ghost, + t_bh_swallow); + scheduler_addunlock(sched, t_bh_swallow, + cj->hydro.super->black_holes.swallow_ghost[0]); + + scheduler_addunlock(sched, + cj->hydro.super->black_holes.swallow_ghost[0], + t_do_swallow); + scheduler_addunlock(sched, t_do_swallow, + cj->hydro.super->black_holes.swallow_ghost[1]); + + scheduler_addunlock(sched, + cj->hydro.super->black_holes.swallow_ghost[1], t_bh_feedback); scheduler_addunlock(sched, t_bh_feedback, cj->hydro.super->black_holes.black_holes_out); @@ -2316,6 +2537,11 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, scheduler_addunlock(sched, cj->hydro.super->stars.sorts, t_star_feedback); } + + if (with_black_holes && (bcount_i > 0 || bcount_j > 0)) { + scheduler_addunlock(sched, t_bh_swallow, + cj->hydro.super->black_holes.swallow_ghost[0]); + } } } } @@ -2489,7 +2715,10 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements, * connection. */ if ((e->policy & engine_policy_black_holes) && (type & proxy_cell_type_hydro)) - engine_addtasks_send_black_holes(e, ci, cj, /*t_feedback=*/NULL, + engine_addtasks_send_black_holes(e, ci, cj, /*t_rho=*/NULL, + /*t_swallow=*/NULL, + /*t_gas_swallow=*/NULL, + /*t_feedback=*/NULL, /*t_ti=*/NULL); /* Add the send tasks for the cells in the proxy that have a gravity @@ -2528,7 +2757,11 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements, * connection. */ if ((e->policy & engine_policy_black_holes) && (type & proxy_cell_type_hydro)) - engine_addtasks_recv_black_holes(e, ci, NULL, NULL); + engine_addtasks_recv_black_holes(e, ci, /*t_rho=*/NULL, + /*t_swallow=*/NULL, + /*t_gas_swallow=*/NULL, + /*t_feedback=*/NULL, + /*t_ti=*/NULL); /* Add the recv tasks for the cells in the proxy that have a gravity * connection. */ diff --git a/src/engine_marktasks.c b/src/engine_marktasks.c index b8d96edbbd8e5385f0d02dfc98116bd267920370..73cb820d6b221940b22e2b7ef37ad613f51d8ff8 100644 --- a/src/engine_marktasks.c +++ b/src/engine_marktasks.c @@ -194,6 +194,30 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } } + else if (t_type == task_type_self && + t_subtype == task_subtype_bh_swallow) { + if (ci_active_black_holes) { + scheduler_activate(s, t); + } + } + + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_bh_swallow) { + if (ci_active_black_holes) scheduler_activate(s, t); + } + + else if (t_type == task_type_self && + t_subtype == task_subtype_do_swallow) { + if (ci_active_black_holes) { + scheduler_activate(s, t); + } + } + + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_do_swallow) { + if (ci_active_black_holes) scheduler_activate(s, t); + } + else if (t_type == task_type_self && t_subtype == task_subtype_bh_feedback) { if (ci_active_black_holes) { @@ -378,30 +402,22 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } /* Black_Holes density */ - else if ((t_subtype == task_subtype_bh_density) && + else if ((t_subtype == task_subtype_bh_density || + t_subtype == task_subtype_bh_swallow || + t_subtype == task_subtype_do_swallow || + t_subtype == task_subtype_bh_feedback) && (ci_active_black_holes || cj_active_black_holes) && (ci_nodeID == nodeID || cj_nodeID == nodeID)) { scheduler_activate(s, t); /* Set the correct sorting flags */ - if (t_type == task_type_pair) { - - /* Do ci */ - if (ci_active_black_holes) { - - /* Activate the drift tasks. */ - if (ci_nodeID == nodeID) cell_activate_drift_bpart(ci, s); - if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); - } - - /* Do cj */ - if (cj_active_black_holes) { + if (t_type == task_type_pair && t_subtype == task_subtype_bh_density) { + if (ci_nodeID == nodeID) cell_activate_drift_bpart(ci, s); + if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); - /* Activate the drift tasks. */ - if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); - if (cj_nodeID == nodeID) cell_activate_drift_bpart(cj, s); - } + if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); + if (cj_nodeID == nodeID) cell_activate_drift_bpart(cj, s); } /* Store current values of dx_max and h_max. */ @@ -411,28 +427,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } } - /* Black_Holes feedback */ - else if (t_subtype == task_subtype_bh_feedback) { - - /* We only want to activate the task if the cell is active and is - going to update some gas on the *local* node */ - if ((ci_nodeID == nodeID && cj_nodeID == nodeID) && - (ci_active_black_holes || cj_active_black_holes)) { - - scheduler_activate(s, t); - - } else if ((ci_nodeID == nodeID && cj_nodeID != nodeID) && - (cj_active_black_holes)) { - - scheduler_activate(s, t); - - } else if ((ci_nodeID != nodeID && cj_nodeID == nodeID) && - (ci_active_black_holes)) { - - scheduler_activate(s, t); - } - } - /* Gravity */ else if ((t_subtype == task_subtype_grav) && ((ci_active_gravity && ci_nodeID == nodeID) || @@ -669,68 +663,86 @@ void engine_marktasks_mapper(void *map_data, int num_elements, if (cell_need_rebuild_for_black_holes_pair(ci, cj)) *rebuild_space = 1; if (cell_need_rebuild_for_black_holes_pair(cj, ci)) *rebuild_space = 1; + scheduler_activate(s, ci->hydro.super->black_holes.swallow_ghost[0]); + scheduler_activate(s, cj->hydro.super->black_holes.swallow_ghost[0]); + #ifdef WITH_MPI /* Activate the send/recv tasks. */ if (ci_nodeID != nodeID) { - if (cj_active_black_holes) { - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_xv); + /* Receive the foreign parts to compute BH accretion rates and do the + * swallowing */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_rho); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_part_swallow); - /* If the local cell is active, more stuff will be needed. */ - scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart, - ci_nodeID); - cell_activate_drift_bpart(cj, s); + /* Send the local BHs to tag the particles to swallow and to do + * feedback */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart_rho, + ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart_feedback, + ci_nodeID); - /* If the local cell is active, send its ti_end values. */ - scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart, - ci_nodeID); - } + /* Drift before you send */ + cell_activate_drift_bpart(cj, s); - if (ci_active_black_holes) { - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart); + /* Send the new BH time-steps */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart, + ci_nodeID); - /* If the foreign cell is active, we want its ti_end values. */ - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart); + /* Receive the foreign BHs to tag particles to swallow and for + * feedback */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_rho); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_feedback); - /* Is the foreign cell active and will need stuff from us? */ - scheduler_activate_send(s, cj->mpi.send, task_subtype_xv, - ci_nodeID); + /* Receive the foreign BH time-steps */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart); - /* Drift the cell which will be sent; note that not all sent - particles will be drifted, only those that are needed. */ - cell_activate_drift_part(cj, s); - } + /* Send the local part information */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_part_swallow, + ci_nodeID); + + /* Drift the cell which will be sent; note that not all sent + particles will be drifted, only those that are needed. */ + cell_activate_drift_part(cj, s); } else if (cj_nodeID != nodeID) { - /* If the local cell is active, receive data from the foreign cell. */ - if (ci_active_black_holes) { - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_xv); + /* Receive the foreign parts to compute BH accretion rates and do the + * swallowing */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_rho); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_part_swallow); - /* If the local cell is active, more stuff will be needed. */ - scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart, - cj_nodeID); - cell_activate_drift_bpart(ci, s); + /* Send the local BHs to tag the particles to swallow and to do + * feedback */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart_rho, + cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart_feedback, + cj_nodeID); - /* If the local cell is active, send its ti_end values. */ - scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart, - cj_nodeID); - } + /* Drift before you send */ + cell_activate_drift_bpart(ci, s); - if (cj_active_black_holes) { - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart); + /* Send the new BH time-steps */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart, + cj_nodeID); - /* If the foreign cell is active, we want its ti_end values. */ - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart); + /* Receive the foreign BHs to tag particles to swallow and for + * feedback */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_rho); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_feedback); - /* Is the foreign cell active and will need stuff from us? */ - scheduler_activate_send(s, ci->mpi.send, task_subtype_xv, - cj_nodeID); + /* Receive the foreign BH time-steps */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart); - /* Drift the cell which will be sent; note that not all sent - particles will be drifted, only those that are needed. */ - cell_activate_drift_part(ci, s); - } + /* Send the local part information */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_part_swallow, + cj_nodeID); + + /* Drift the cell which will be sent; note that not all sent + particles will be drifted, only those that are needed. */ + cell_activate_drift_part(ci, s); } #endif } @@ -878,7 +890,9 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } /* Black hole ghost tasks ? */ - else if (t_type == task_type_bh_ghost) { + else if (t_type == task_type_bh_density_ghost || + t_type == task_type_bh_swallow_ghost1 || + t_type == task_type_bh_swallow_ghost2) { if (cell_is_active_black_holes(t->ci, e)) scheduler_activate(s, t); } diff --git a/src/hashmap.h b/src/hashmap.h index 40bb309e552266942afdacd79b5cb8268132a74f..a4b89ebaf9434ce6f753ba124c0c59969b807b56 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -127,10 +127,11 @@ void hashmap_init(hashmap_t *m); * capacity, since it will grow if too many collisions occur. As a rule * of thumb, allocate twice as many elements as you think you will need. * - * @param size New table size. If zero, the current size will be increase - * by a fixed rate. + * @param m The hasmmap to grow. + * @param new_size New table size. If zero, the current size will be increase + * by a fixed rate. */ -void hashmap_grow(hashmap_t *m, size_t size); +void hashmap_grow(hashmap_t *m, size_t new_size); /** * @brief Add a key/value pair to the hashmap, overwriting whatever was diff --git a/src/hydro/AnarchyDU/hydro_part.h b/src/hydro/AnarchyDU/hydro_part.h index 98bb058af9881fd050e6b9f2101766870ed26a46..c30f778b80d91d576052082c6e849fa9d1a4f38e 100644 --- a/src/hydro/AnarchyDU/hydro_part.h +++ b/src/hydro/AnarchyDU/hydro_part.h @@ -27,6 +27,7 @@ * Price 2008 thermal diffusion (particle definition) */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -190,6 +191,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Time-step length */ timebin_t time_bin; diff --git a/src/hydro/AnarchyPU/hydro_part.h b/src/hydro/AnarchyPU/hydro_part.h index 3c59f2d7c1b8610eeef816c674038dcab5554130..2ba76967ac074df68e6beddd51713ae0505430f6 100644 --- a/src/hydro/AnarchyPU/hydro_part.h +++ b/src/hydro/AnarchyPU/hydro_part.h @@ -19,6 +19,7 @@ ******************************************************************************/ #ifndef SWIFT_ANARCHY_PU_HYDRO_PART_H #define SWIFT_ANARCHY_PU_HYDRO_PART_H + /** * @file AnarchyPU/hydro_part.h * @brief P-U conservative implementation of SPH, @@ -28,6 +29,7 @@ * See AnarchyPU/hydro.h for references. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -194,6 +196,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Time-step length */ timebin_t time_bin; diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h index e5c8aab4e88dc4f2a6ffe38ea8931e8f7849e5de..a3fa2545aa58d54e02c54af02103d047a5c8cf17 100644 --- a/src/hydro/Default/hydro_part.h +++ b/src/hydro/Default/hydro_part.h @@ -27,6 +27,7 @@ * Price 2017 (PHANTOM) diffusion) (particle definition) */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -190,6 +191,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Time-step length */ timebin_t time_bin; diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h index 3001700395b8584981c0087c8ff402a953461213..7a8844d560561dae80c676a0b5bb72b34416d080 100644 --- a/src/hydro/Gadget2/hydro_part.h +++ b/src/hydro/Gadget2/hydro_part.h @@ -31,6 +31,7 @@ * Gadget-2 tree-code neighbours search. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "logger.h" @@ -151,6 +152,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /* Time-step length */ timebin_t time_bin; diff --git a/src/hydro/GizmoMFM/hydro_part.h b/src/hydro/GizmoMFM/hydro_part.h index 8097b1b2560f24f78636bbb855700054524fe0bb..2ca752dac714d5fca02e2552601c18174f98a8ab 100644 --- a/src/hydro/GizmoMFM/hydro_part.h +++ b/src/hydro/GizmoMFM/hydro_part.h @@ -19,6 +19,7 @@ #ifndef SWIFT_GIZMO_MFM_HYDRO_PART_H #define SWIFT_GIZMO_MFM_HYDRO_PART_H +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -192,6 +193,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /* Time-step length */ timebin_t time_bin; diff --git a/src/hydro/GizmoMFV/hydro_part.h b/src/hydro/GizmoMFV/hydro_part.h index af83dbd92590a30aa401e1cc5626554633058b1f..db43c03cba3c23a4d4d8ab81cc62ebc5951299f3 100644 --- a/src/hydro/GizmoMFV/hydro_part.h +++ b/src/hydro/GizmoMFV/hydro_part.h @@ -19,6 +19,7 @@ #ifndef SWIFT_GIZMO_MFV_HYDRO_PART_H #define SWIFT_GIZMO_MFV_HYDRO_PART_H +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -203,6 +204,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /* Time-step length */ timebin_t time_bin; diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h index 7697f36ca723875a8b77705eefcf2e2af4605583..0e61b95cc164690b178806c9906a195cb86a01ac 100644 --- a/src/hydro/Minimal/hydro_part.h +++ b/src/hydro/Minimal/hydro_part.h @@ -32,6 +32,7 @@ * Physics, 2012, Volume 231, Issue 3, pp. 759-794. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -170,9 +171,12 @@ struct part { } force; }; - /* Chemistry information */ + /*! Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Time-step length */ timebin_t time_bin; diff --git a/src/hydro/Planetary/hydro_part.h b/src/hydro/Planetary/hydro_part.h index b2725ca1fceddb196a6b2be42b768eb3f88f1101..db0396f7af06335e1e17b1255941781db1300a78 100644 --- a/src/hydro/Planetary/hydro_part.h +++ b/src/hydro/Planetary/hydro_part.h @@ -33,6 +33,7 @@ * Physics, 2012, Volume 231, Issue 3, pp. 759-794. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "equation_of_state.h" // For enum material_id @@ -175,6 +176,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Material identifier flag */ enum eos_planetary_material_id mat_id; diff --git a/src/hydro/PressureEnergy/hydro_part.h b/src/hydro/PressureEnergy/hydro_part.h index 20c326da443e4acd1c3bdc0ebd01cce81bb6bad7..ded83d70176409332b669517ed203fdf95ecfd5e 100644 --- a/src/hydro/PressureEnergy/hydro_part.h +++ b/src/hydro/PressureEnergy/hydro_part.h @@ -31,6 +31,7 @@ * See PressureEnergy/hydro.h for references. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -173,6 +174,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Time-step length */ timebin_t time_bin; diff --git a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h index 5a520f522a85ac87376d7db8cc78f58c66e3550b..644b30234ad40d0571249726f96358453e06956a 100644 --- a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h +++ b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h @@ -32,6 +32,7 @@ * See PressureEnergy/hydro.h for references. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -177,6 +178,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /*! Time-step length */ timebin_t time_bin; diff --git a/src/hydro/PressureEntropy/hydro_part.h b/src/hydro/PressureEntropy/hydro_part.h index 6cf5a88a167c529ad81737f1e206ba475f6bbc0e..cf7204ba1e157ce69f523414ab0321f61d110a94 100644 --- a/src/hydro/PressureEntropy/hydro_part.h +++ b/src/hydro/PressureEntropy/hydro_part.h @@ -30,6 +30,7 @@ * Volume 428, Issue 4, pp. 2840-2856 with a simple Balsara viscosity term. */ +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "star_formation_struct.h" @@ -153,6 +154,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /* Time-step length */ timebin_t time_bin; diff --git a/src/hydro/Shadowswift/hydro_part.h b/src/hydro/Shadowswift/hydro_part.h index d229b5c9d63ecfa855397f74f8a52a4117cefc03..4d8c44a3637b6ca67ba00d3c6f654692504207f6 100644 --- a/src/hydro/Shadowswift/hydro_part.h +++ b/src/hydro/Shadowswift/hydro_part.h @@ -18,7 +18,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#ifndef SWIFT_SHADOWSWIFT_HYDRO_PART_H +#define SWIFT_SHADOWSWIFT_HYDRO_PART_H +#include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" #include "tracers_struct.h" @@ -180,6 +183,9 @@ struct part { /* Chemistry information */ struct chemistry_part_data chemistry_data; + /*! Black holes information (e.g. swallowing ID) */ + struct black_holes_part_data black_holes_data; + /* Time-step length */ timebin_t time_bin; @@ -200,3 +206,5 @@ struct part { struct voronoi_cell cell; } SWIFT_STRUCT_ALIGN; + +#endif /* SWIFT_SHADOWSWIFT_HYDRO_PART_H */ diff --git a/src/parallel_io.c b/src/parallel_io.c index 7ba28d6f506338ea4e9a34343203bae4e794637d..db1fbe2426a3e858dd429aa495641a4e0d4ed631 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -1232,6 +1232,7 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], case swift_type_black_hole: black_holes_write_particles(bparts, list, &num_fields); + num_fields += chemistry_write_bparticles(bparts, list + num_fields); if (with_stf) { num_fields += velociraptor_write_bparts(bparts, list + num_fields); } @@ -1552,11 +1553,11 @@ void write_output_parallel(struct engine* e, const char* baseName, if (swift_memalign("parts_written", (void**)&parts_written, part_align, Ngas_written * sizeof(struct part)) != 0) - error("Error while allocating temporart memory for parts"); + error("Error while allocating temporary memory for parts"); if (swift_memalign("xparts_written", (void**)&xparts_written, xpart_align, Ngas_written * sizeof(struct xpart)) != 0) - error("Error while allocating temporart memory for xparts"); + error("Error while allocating temporary memory for xparts"); /* Collect the particles we want to write */ io_collect_parts_to_write(parts, xparts, parts_written, @@ -1602,7 +1603,7 @@ void write_output_parallel(struct engine* e, const char* baseName, if (swift_memalign("gparts_written", (void**)&gparts_written, gpart_align, Ndm_written * sizeof(struct gpart)) != 0) - error("Error while allocating temporart memory for gparts"); + error("Error while allocating temporary memory for gparts"); if (with_stf) { if (swift_memalign( @@ -1610,7 +1611,7 @@ void write_output_parallel(struct engine* e, const char* baseName, gpart_align, Ndm_written * sizeof(struct velociraptor_gpart_data)) != 0) error( - "Error while allocating temporart memory for gparts STF " + "Error while allocating temporary memory for gparts STF " "data"); } @@ -1651,7 +1652,7 @@ void write_output_parallel(struct engine* e, const char* baseName, if (swift_memalign("sparts_written", (void**)&sparts_written, spart_align, Nstars_written * sizeof(struct spart)) != 0) - error("Error while allocating temporart memory for sparts"); + error("Error while allocating temporary memory for sparts"); /* Collect the particles we want to write */ io_collect_sparts_to_write(sparts, sparts_written, Nstars, @@ -1675,6 +1676,8 @@ void write_output_parallel(struct engine* e, const char* baseName, /* No inhibted particles: easy case */ Nparticles = Nblackholes; black_holes_write_particles(bparts, list, &num_fields); + num_fields += chemistry_write_bparticles(bparts, list + num_fields); + if (with_stf) { num_fields += velociraptor_write_bparts(bparts, list + num_fields); } @@ -1687,7 +1690,7 @@ void write_output_parallel(struct engine* e, const char* baseName, if (swift_memalign("bparts_written", (void**)&bparts_written, bpart_align, Nblackholes_written * sizeof(struct bpart)) != 0) - error("Error while allocating temporart memory for bparts"); + error("Error while allocating temporary memory for bparts"); /* Collect the particles we want to write */ io_collect_bparts_to_write(bparts, bparts_written, Nblackholes, @@ -1695,6 +1698,8 @@ void write_output_parallel(struct engine* e, const char* baseName, /* Select the fields to write */ black_holes_write_particles(bparts_written, list, &num_fields); + num_fields += chemistry_write_bparticles(bparts, list + num_fields); + if (with_stf) { num_fields += velociraptor_write_bparts(bparts_written, list + num_fields); diff --git a/src/runner.c b/src/runner.c index 49302fe08c572ce4f372d882c6a0c2c944c14412..622bd337170ed9939be168ec63d125bf67b9bf69 100644 --- a/src/runner.c +++ b/src/runner.c @@ -75,11 +75,13 @@ #include "timestep_limiter.h" #include "tracers.h" +/* Unique identifier of loop types */ #define TASK_LOOP_DENSITY 0 #define TASK_LOOP_GRADIENT 1 #define TASK_LOOP_FORCE 2 #define TASK_LOOP_LIMITER 3 #define TASK_LOOP_FEEDBACK 4 +#define TASK_LOOP_SWALLOW 5 /* Import the density loop functions. */ #define FUNCTION density @@ -135,6 +137,13 @@ #undef FUNCTION_TASK_LOOP #undef FUNCTION +/* Import the black hole feedback loop functions. */ +#define FUNCTION swallow +#define FUNCTION_TASK_LOOP TASK_LOOP_SWALLOW +#include "runner_doiact_black_holes.h" +#undef FUNCTION_TASK_LOOP +#undef FUNCTION + /* Import the black hole feedback loop functions. */ #define FUNCTION feedback #define FUNCTION_TASK_LOOP TASK_LOOP_FEEDBACK @@ -559,11 +568,11 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { * @param c The cell. * @param timer Are we timing this ? */ -void runner_do_black_holes_ghost(struct runner *r, struct cell *c, int timer) { +void runner_do_black_holes_density_ghost(struct runner *r, struct cell *c, + int timer) { struct bpart *restrict bparts = c->black_holes.parts; const struct engine *e = r->e; - const int with_cosmology = e->policy & engine_policy_cosmology; const struct cosmology *cosmo = e->cosmology; const float black_holes_h_max = e->hydro_properties->h_max; const float black_holes_h_min = e->hydro_properties->h_min; @@ -586,7 +595,7 @@ void runner_do_black_holes_ghost(struct runner *r, struct cell *c, int timer) { if (c->split) { for (int k = 0; k < 8; k++) { if (c->progeny[k] != NULL) { - runner_do_black_holes_ghost(r, c->progeny[k], 0); + runner_do_black_holes_density_ghost(r, c->progeny[k], 0); /* Update h_max */ h_max = max(h_max, c->progeny[k]->black_holes.h_max); @@ -682,25 +691,6 @@ void runner_do_black_holes_ghost(struct runner *r, struct cell *c, int timer) { if (((bp->h >= black_holes_h_max) && (f < 0.f)) || ((bp->h <= black_holes_h_min) && (f > 0.f))) { - /* Get particle time-step */ - double dt; - if (with_cosmology) { - const integertime_t ti_step = get_integer_timestep(bp->time_bin); - const integertime_t ti_begin = - get_integer_time_begin(e->ti_current - 1, bp->time_bin); - - dt = cosmology_get_delta_time(e->cosmology, ti_begin, - ti_begin + ti_step); - } else { - dt = get_timestep(bp->time_bin, e->time_base); - } - - /* Compute variables required for the feedback loop */ - black_holes_prepare_feedback(bp, e->black_holes_properties, - e->physical_constants, e->cosmology, - dt); - - /* Reset quantities computed by the feedback loop */ black_holes_reset_feedback(bp); /* Ok, we are done with this particle */ @@ -791,28 +781,10 @@ void runner_do_black_holes_ghost(struct runner *r, struct cell *c, int timer) { /* We now have a particle whose smoothing length has converged */ + black_holes_reset_feedback(bp); + /* Check if h_max has increased */ h_max = max(h_max, bp->h); - - /* Get particle time-step */ - double dt; - if (with_cosmology) { - const integertime_t ti_step = get_integer_timestep(bp->time_bin); - const integertime_t ti_begin = - get_integer_time_begin(e->ti_current - 1, bp->time_bin); - - dt = cosmology_get_delta_time(e->cosmology, ti_begin, - ti_begin + ti_step); - } else { - dt = get_timestep(bp->time_bin, e->time_base); - } - - /* Compute variables required for the feedback loop */ - black_holes_prepare_feedback(bp, e->black_holes_properties, - e->physical_constants, e->cosmology, dt); - - /* Reset quantities computed by the feedback loop */ - black_holes_reset_feedback(bp); } /* We now need to treat the particles whose smoothing length had not @@ -888,7 +860,7 @@ void runner_do_black_holes_ghost(struct runner *r, struct cell *c, int timer) { /* The ghost may not always be at the top level. * Therefore we need to update h_max between the super- and top-levels */ - if (c->black_holes.ghost) { + if (c->black_holes.density_ghost) { for (struct cell *tmp = c->parent; tmp != NULL; tmp = tmp->parent) { atomic_max_d(&tmp->black_holes.h_max, h_max); } @@ -897,6 +869,65 @@ void runner_do_black_holes_ghost(struct runner *r, struct cell *c, int timer) { if (timer) TIMER_TOC(timer_do_black_holes_ghost); } +/** + * @brief Intermediate task after the BHs have done their swallowing step. + * This is used to update the BH quantities if necessary. + * + * @param r The runner thread. + * @param c The cell. + * @param timer Are we timing this ? + */ +void runner_do_black_holes_swallow_ghost(struct runner *r, struct cell *c, + int timer) { + + struct bpart *restrict bparts = c->black_holes.parts; + const int count = c->black_holes.count; + const struct engine *e = r->e; + const int with_cosmology = e->policy & engine_policy_cosmology; + + TIMER_TIC; + + /* Anything to do here? */ + if (!cell_is_active_hydro(c, e)) return; + + /* Recurse? */ + if (c->split) { + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + runner_do_black_holes_swallow_ghost(r, c->progeny[k], 0); + } else { + + /* Loop over the parts in this cell. */ + for (int i = 0; i < count; i++) { + + /* Get a direct pointer on the part. */ + struct bpart *bp = &bparts[i]; + + if (bpart_is_active(bp, e)) { + + /* Get particle time-step */ + double dt; + if (with_cosmology) { + const integertime_t ti_step = get_integer_timestep(bp->time_bin); + const integertime_t ti_begin = + get_integer_time_begin(e->ti_current - 1, bp->time_bin); + + dt = cosmology_get_delta_time(e->cosmology, ti_begin, + ti_begin + ti_step); + } else { + dt = get_timestep(bp->time_bin, e->time_base); + } + + /* Compute variables required for the feedback loop */ + black_holes_prepare_feedback(bp, e->black_holes_properties, + e->physical_constants, e->cosmology, dt); + } + } + } + + if (timer) TIMER_TOC(timer_do_black_holes_ghost); +} + /** * @brief Calculate gravity acceleration from external potential * @@ -3323,11 +3354,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { s_updated += cp->stars.updated; b_updated += cp->black_holes.updated; - inhibited += cp->hydro.inhibited; - g_inhibited += cp->grav.inhibited; - s_inhibited += cp->stars.inhibited; - b_inhibited += cp->black_holes.inhibited; - ti_hydro_end_min = min(cp->hydro.ti_end_min, ti_hydro_end_min); ti_hydro_end_max = max(cp->hydro.ti_end_max, ti_hydro_end_max); ti_hydro_beg_max = max(cp->hydro.ti_beg_max, ti_hydro_beg_max); @@ -3356,11 +3382,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { c->stars.updated = s_updated; c->black_holes.updated = b_updated; - c->hydro.inhibited = inhibited; - c->grav.inhibited = g_inhibited; - c->stars.inhibited = s_inhibited; - c->black_holes.inhibited = b_inhibited; - c->hydro.ti_end_min = ti_hydro_end_min; c->hydro.ti_end_max = ti_hydro_end_max; c->hydro.ti_beg_max = ti_hydro_beg_max; @@ -3655,7 +3676,8 @@ void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer) { #endif #ifdef SWIFT_DEBUG_CHECKS - if (e->policy & engine_policy_self_gravity) { + if ((e->policy & engine_policy_self_gravity) && + !(e->policy & engine_policy_black_holes)) { /* Let's add a self interaction to simplify the count */ gp->num_interacted++; @@ -3692,6 +3714,212 @@ void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer) { if (timer) TIMER_TOC(timer_end_grav_force); } +/** + * @brief Process all the gas particles in a cell that have been flagged for + * swallowing by a black hole. + * + * This is done by recursing down to the leaf-level and skipping the sub-cells + * that have not been drifted as they would not have any particles with + * swallowing flag. We then loop over the particles with a flag and look into + * the space-wide list of black holes for the particle with the corresponding + * ID. If found, the BH swallows the gas particle and the gas particle is + * removed. If the cell is local, we may be looking for a foreign BH, in which + * case, we do not update the BH (that will be done on its node) but just remove + * the gas particle. + * + * @param r The thread #runner. + * @param c The #cell. + * @param timer Are we timing this? + */ +void runner_do_swallow(struct runner *r, struct cell *c, int timer) { + + struct engine *e = r->e; + struct space *s = e->s; + struct bpart *bparts = s->bparts; + const size_t nr_bpart = s->nr_bparts; +#ifdef WITH_MPI + struct bpart *bparts_foreign = s->bparts_foreign; + const size_t nr_bparts_foreign = s->nr_bparts_foreign; +#endif + + struct part *parts = c->hydro.parts; + struct xpart *xparts = c->hydro.xparts; + + /* Early abort? + * (We only want cells for which we drifted the gas as these are + * the only ones that could have gas particles that have been flagged + * for swallowing) */ + if (c->hydro.count == 0 || c->hydro.ti_old_part != e->ti_current) { + return; + } + + /* Loop over the progeny ? */ + if (c->split) { + for (int k = 0; k < 8; k++) { + if (c->progeny[k] != NULL) { + struct cell *restrict cp = c->progeny[k]; + + runner_do_swallow(r, cp, 0); + } + } + } else { + + /* Loop over all the gas particles in the cell + * Note that the cell (and hence the parts) may be local or foreign. */ + const size_t nr_parts = c->hydro.count; + for (size_t k = 0; k < nr_parts; k++) { + + /* Get a handle on the part. */ + struct part *const p = &parts[k]; + struct xpart *const xp = &xparts[k]; + + /* Ignore inhibited particles (they have already been removed!) */ + if (part_is_inhibited(p, e)) continue; + + /* Get the ID of the black holes that will swallow this part */ + const long long swallow_id = + black_holes_get_swallow_id(&p->black_holes_data); + + /* Has this particle been flagged for swallowing? */ + if (swallow_id >= 0) { + +#ifdef SWIFT_DEBUG_CHECKS + if (p->ti_drift != e->ti_current) + error("Trying to swallow an un-drifted particle."); +#endif + + /* ID of the BH swallowing this particle */ + const long long BH_id = swallow_id; + + /* Have we found this particle's BH already? */ + int found = 0; + + /* Let's look for the hungry black hole in the local list */ + for (size_t i = 0; i < nr_bpart; ++i) { + + /* Get a handle on the bpart. */ + struct bpart *bp = &bparts[i]; + + if (bp->id == BH_id) { + + /* Lock the space as we are going to work directly on the bpart list + */ + lock_lock(&s->lock); + + /* Swallow the gas particle (i.e. update the BH properties) */ + black_holes_swallow_part(bp, p, xp, e->cosmology); + + /* Release the space as we are done updating the bpart */ + if (lock_unlock(&s->lock) != 0) + error("Failed to unlock the space."); + + message("BH %lld swallowing particle %lld", bp->id, p->id); + + /* If the gas particle is local, remove it */ + if (c->nodeID == e->nodeID) { + + message("BH %lld removing particle %lld", bp->id, p->id); + + /* Finally, remove the gas particle from the system */ + struct gpart *gp = p->gpart; + cell_remove_part(e, c, p, xp); + cell_remove_gpart(e, c, gp); + } + + /* In any case, prevent the particle from being re-swallowed */ + black_holes_mark_as_swallowed(&p->black_holes_data); + + found = 1; + break; + } + + } /* Loop over local BHs */ + +#ifdef WITH_MPI + + /* We could also be in the case of a local gas particle being + * swallowed by a foreign BH. In this case, we won't update the + * BH but just remove the particle from the local list. */ + if (c->nodeID == e->nodeID && !found) { + + /* Let's look for the foreign hungry black hole */ + for (size_t i = 0; i < nr_bparts_foreign; ++i) { + + /* Get a handle on the bpart. */ + struct bpart *bp = &bparts_foreign[i]; + + if (bp->id == BH_id) { + + message("BH %lld removing particle %lld (foreign BH case)", + bp->id, p->id); + + /* Finally, remove the gas particle from the system */ + struct gpart *gp = p->gpart; + cell_remove_part(e, c, p, xp); + cell_remove_gpart(e, c, gp); + + found = 1; + break; + } + } /* Loop over foreign BHs */ + } /* Is the cell local? */ +#endif + + /* If we have a local particle, we must have found the BH in one + * of our list of black holes. */ + if (c->nodeID == e->nodeID && !found) { + error("Gas particle %lld could not find BH %lld to be swallowed", + p->id, swallow_id); + } + } /* Part was flagged for swallowing */ + } /* Loop over the parts */ + } /* Cell is not split */ +} + +/** + * @brief Processing of gas particles to swallow - self task case. + * + * @param r The thread #runner. + * @param c The #cell. + * @param timer Are we timing this? + */ +void runner_do_swallow_self(struct runner *r, struct cell *c, int timer) { + +#ifdef SWIFT_DEBUG_CHECKS + if (c->nodeID != r->e->nodeID) error("Running self task on foreign node"); + if (!cell_is_active_black_holes(c, r->e)) + error("Running self task on inactive cell"); +#endif + + runner_do_swallow(r, c, timer); +} + +/** + * @brief Processing of gas particles to swallow - pair task case. + * + * @param r The thread #runner. + * @param ci First #cell. + * @param cj Second #cell. + * @param timer Are we timing this? + */ +void runner_do_swallow_pair(struct runner *r, struct cell *ci, struct cell *cj, + int timer) { + + const struct engine *e = r->e; + +#ifdef SWIFT_DEBUG_CHECKS + if (ci->nodeID != e->nodeID && cj->nodeID != e->nodeID) + error("Running pair task on foreign node"); + if (!cell_is_active_black_holes(ci, e) && !cell_is_active_black_holes(cj, e)) + error("Running pair task with two inactive cells"); +#endif + + /* Run the swallowing loop only in the cell that is the neighbour of the + * active BH */ + if (cell_is_active_black_holes(cj, e)) runner_do_swallow(r, ci, timer); + if (cell_is_active_black_holes(ci, e)) runner_do_swallow(r, cj, timer); +} + /** * @brief Construct the cell properties from the received #part. * @@ -4080,9 +4308,11 @@ void *runner_main(void *data) { } #endif -/* Check that we haven't scheduled an inactive task */ #ifdef SWIFT_DEBUG_CHECKS + /* Check that we haven't scheduled an inactive task */ t->ti_run = e->ti_current; + /* Store the task that will be running (for debugging only) */ + r->t = t; #endif /* Different types of tasks... */ @@ -4108,6 +4338,10 @@ void *runner_main(void *data) { runner_doself_branch_stars_feedback(r, ci); else if (t->subtype == task_subtype_bh_density) runner_doself_branch_bh_density(r, ci); + else if (t->subtype == task_subtype_bh_swallow) + runner_doself_branch_bh_swallow(r, ci); + else if (t->subtype == task_subtype_do_swallow) + runner_do_swallow_self(r, ci, 1); else if (t->subtype == task_subtype_bh_feedback) runner_doself_branch_bh_feedback(r, ci); else @@ -4133,7 +4367,11 @@ void *runner_main(void *data) { runner_dopair_branch_stars_feedback(r, ci, cj); else if (t->subtype == task_subtype_bh_density) runner_dopair_branch_bh_density(r, ci, cj); - else if (t->subtype == task_subtype_bh_feedback) + else if (t->subtype == task_subtype_bh_swallow) + runner_dopair_branch_bh_swallow(r, ci, cj); + else if (t->subtype == task_subtype_do_swallow) { + runner_do_swallow_pair(r, ci, cj, 1); + } else if (t->subtype == task_subtype_bh_feedback) runner_dopair_branch_bh_feedback(r, ci, cj); else error("Unknown/invalid task subtype (%d).", t->subtype); @@ -4156,6 +4394,10 @@ void *runner_main(void *data) { runner_dosub_self_stars_feedback(r, ci, 1); else if (t->subtype == task_subtype_bh_density) runner_dosub_self_bh_density(r, ci, 1); + else if (t->subtype == task_subtype_bh_swallow) + runner_dosub_self_bh_swallow(r, ci, 1); + else if (t->subtype == task_subtype_do_swallow) + runner_do_swallow_self(r, ci, 1); else if (t->subtype == task_subtype_bh_feedback) runner_dosub_self_bh_feedback(r, ci, 1); else @@ -4179,7 +4421,11 @@ void *runner_main(void *data) { runner_dosub_pair_stars_feedback(r, ci, cj, 1); else if (t->subtype == task_subtype_bh_density) runner_dosub_pair_bh_density(r, ci, cj, 1); - else if (t->subtype == task_subtype_bh_feedback) + else if (t->subtype == task_subtype_bh_swallow) + runner_dosub_pair_bh_swallow(r, ci, cj, 1); + else if (t->subtype == task_subtype_do_swallow) { + runner_do_swallow_pair(r, ci, cj, 1); + } else if (t->subtype == task_subtype_bh_feedback) runner_dosub_pair_bh_feedback(r, ci, cj, 1); else error("Unknown/invalid task subtype (%d).", t->subtype); @@ -4215,8 +4461,11 @@ void *runner_main(void *data) { case task_type_stars_ghost: runner_do_stars_ghost(r, ci, 1); break; - case task_type_bh_ghost: - runner_do_black_holes_ghost(r, ci, 1); + case task_type_bh_density_ghost: + runner_do_black_holes_density_ghost(r, ci, 1); + break; + case task_type_bh_swallow_ghost2: + runner_do_black_holes_swallow_ghost(r, ci, 1); break; case task_type_drift_part: runner_do_drift_part(r, ci, 1); @@ -4263,6 +4512,8 @@ void *runner_main(void *data) { free(t->buff); } else if (t->subtype == task_subtype_sf_counts) { free(t->buff); + } else if (t->subtype == task_subtype_part_swallow) { + free(t->buff); } break; case task_type_recv: @@ -4289,14 +4540,22 @@ void *runner_main(void *data) { runner_do_recv_part(r, ci, 0, 1); } else if (t->subtype == task_subtype_gradient) { runner_do_recv_part(r, ci, 0, 1); + } else if (t->subtype == task_subtype_part_swallow) { + cell_unpack_part_swallow(ci, + (struct black_holes_part_data *)t->buff); + free(t->buff); } else if (t->subtype == task_subtype_limiter) { runner_do_recv_part(r, ci, 0, 1); } else if (t->subtype == task_subtype_gpart) { runner_do_recv_gpart(r, ci, 1); } else if (t->subtype == task_subtype_spart) { runner_do_recv_spart(r, ci, 1, 1); - } else if (t->subtype == task_subtype_bpart) { + } else if (t->subtype == task_subtype_bpart_rho) { runner_do_recv_bpart(r, ci, 1, 1); + } else if (t->subtype == task_subtype_bpart_swallow) { + runner_do_recv_bpart(r, ci, 0, 1); + } else if (t->subtype == task_subtype_bpart_feedback) { + runner_do_recv_bpart(r, ci, 0, 1); } else if (t->subtype == task_subtype_multipole) { cell_unpack_multipoles(ci, (struct gravity_tensors *)t->buff); free(t->buff); @@ -4343,6 +4602,9 @@ void *runner_main(void *data) { cj->tasks_executed[t->type]++; cj->subtasks_executed[t->subtype]++; } + + /* This runner is not doing a task anymore */ + r->t = NULL; #endif /* We're done with this task, see if we get a next one. */ diff --git a/src/runner.h b/src/runner.h index c7b923ed262965e9dd7566dd093084c6f0948079..1dc62ad6f5dc1c92851cf841a4ab55836d084bac 100644 --- a/src/runner.h +++ b/src/runner.h @@ -29,6 +29,7 @@ /* Includes. */ #include "cache.h" #include "gravity_cache.h" +#include "task.h" struct cell; struct engine; @@ -64,6 +65,11 @@ struct runner { /*! The particle cache of cell cj. */ struct cache cj_cache; #endif + +#ifdef SWIFT_DEBUG_CHECKS + /*! Pointer to the task this runner is currently performing */ + const struct task *t; +#endif }; /* Function prototypes. */ diff --git a/src/runner_doiact.h b/src/runner_doiact.h index a69489ed29c4cbf51fa25243944206efe4b00188..6caa287cf726f85778ef5abdc184acaf759e8b0e 100644 --- a/src/runner_doiact.h +++ b/src/runner_doiact.h @@ -1424,6 +1424,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Recover pj */ struct part *pj = &parts_j[sort_active_j[pjd].i]; + + /* Skip inhibited particles. + * Note we are looping over active particles but in the case where + * the cell thinks all the particles are active (because of the + * ti_end_max), particles may have nevertheless been inhibted by BH + * swallowing in the mean time. */ + if (part_is_inhibited(pj, e)) continue; + const float hj = pj->h; /* Get the position of pj in the right frame */ @@ -1465,6 +1473,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); + if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif @@ -1533,6 +1542,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); + if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif @@ -1594,6 +1604,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Recover pi */ struct part *pi = &parts_i[sort_active_i[pid].i]; + + /* Skip inhibited particles. + * Note we are looping over active particles but in the case where + * the cell thinks all the particles are active (because of the + * ti_end_max), particles may have nevertheless been inhibted by BH + * swallowing in the mean time. */ + if (part_is_inhibited(pi, e)) continue; + const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; diff --git a/src/runner_doiact_black_holes.h b/src/runner_doiact_black_holes.h index efd2d02b3aca3c530b4e1af13e38328368c99f7c..eeb5c3d60bdd11148c0537e0391ab64d1212a98a 100644 --- a/src/runner_doiact_black_holes.h +++ b/src/runner_doiact_black_holes.h @@ -172,7 +172,7 @@ void DO_NONSYM_PAIR1_BH_NAIVE(struct runner *r, struct cell *restrict ci, #ifdef SWIFT_DEBUG_CHECKS #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) if (ci->nodeID != engine_rank) error("Should be run on a different node"); -#else +#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) if (cj->nodeID != engine_rank) error("Should be run on a different node"); #endif #endif @@ -254,11 +254,16 @@ void DOPAIR1_BH_NAIVE(struct runner *r, struct cell *restrict ci, #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) const int do_ci_bh = ci->nodeID == r->e->nodeID; const int do_cj_bh = cj->nodeID == r->e->nodeID; -#else +#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) /* here we are updating the hydro -> switch ci, cj */ const int do_ci_bh = cj->nodeID == r->e->nodeID; const int do_cj_bh = ci->nodeID == r->e->nodeID; +#else + /* The swallow task is executed on both sides */ + const int do_ci_bh = 1; + const int do_cj_bh = 1; #endif + if (do_ci_bh && ci->black_holes.count != 0 && cj->hydro.count != 0) DO_NONSYM_PAIR1_BH_NAIVE(r, ci, cj); if (do_cj_bh && cj->black_holes.count != 0 && ci->hydro.count != 0) @@ -608,11 +613,16 @@ void DOPAIR1_BRANCH_BH(struct runner *r, struct cell *ci, struct cell *cj) { #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) const int do_ci_bh = ci->nodeID == e->nodeID; const int do_cj_bh = cj->nodeID == e->nodeID; -#else +#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) /* here we are updating the hydro -> switch ci, cj */ const int do_ci_bh = cj->nodeID == e->nodeID; const int do_cj_bh = ci->nodeID == e->nodeID; +#else + /* The swallow task is executed on both sides */ + const int do_ci_bh = 1; + const int do_cj_bh = 1; #endif + const int do_ci = (ci->black_holes.count != 0 && cj->hydro.count != 0 && ci_active && do_ci_bh); const int do_cj = (cj->black_holes.count != 0 && ci->hydro.count != 0 && @@ -682,11 +692,15 @@ void DOSUB_PAIR1_BH(struct runner *r, struct cell *ci, struct cell *cj, #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) const int do_ci_bh = ci->nodeID == e->nodeID; const int do_cj_bh = cj->nodeID == e->nodeID; -#else +#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) /* here we are updating the hydro -> switch ci, cj */ const int do_ci_bh = cj->nodeID == e->nodeID; const int do_cj_bh = ci->nodeID == e->nodeID; +#else + const int do_ci_bh = 1; + const int do_cj_bh = 1; #endif + const int do_ci = ci->black_holes.count != 0 && cj->hydro.count != 0 && cell_is_active_black_holes(ci, e) && do_ci_bh; const int do_cj = cj->black_holes.count != 0 && ci->hydro.count != 0 && diff --git a/src/scheduler.c b/src/scheduler.c index 6367fe2cb57734b6d73e3737c992958d3a1d3ed0..367fbe599a14e86fd592569c9e2b1de8a45154e0 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1408,7 +1408,7 @@ void scheduler_reweight(struct scheduler *s, int verbose) { case task_type_stars_ghost: if (t->ci == t->ci->hydro.super) cost = wscale * scount_i; break; - case task_type_bh_ghost: + case task_type_bh_density_ghost: if (t->ci == t->ci->hydro.super) cost = wscale * bcount_i; break; case task_type_drift_part: @@ -1672,6 +1672,14 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { t->ci->mpi.pcell_size * sizeof(struct pcell_step_black_holes), MPI_BYTE, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); + } else if (t->subtype == task_subtype_part_swallow) { + t->buff = (struct black_holes_part_data *)malloc( + sizeof(struct black_holes_part_data) * t->ci->hydro.count); + err = MPI_Irecv( + t->buff, + t->ci->hydro.count * sizeof(struct black_holes_part_data), + MPI_BYTE, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], + &t->req); } else if (t->subtype == task_subtype_xv || t->subtype == task_subtype_rho || t->subtype == task_subtype_gradient) { @@ -1686,7 +1694,9 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { err = MPI_Irecv(t->ci->stars.parts, t->ci->stars.count, spart_mpi_type, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); - } else if (t->subtype == task_subtype_bpart) { + } else if (t->subtype == task_subtype_bpart_rho || + t->subtype == task_subtype_bpart_swallow || + t->subtype == task_subtype_bpart_feedback) { err = MPI_Irecv(t->ci->black_holes.parts, t->ci->black_holes.count, bpart_mpi_type, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); @@ -1791,6 +1801,27 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { MPI_BYTE, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } + } else if (t->subtype == task_subtype_part_swallow) { + t->buff = (struct black_holes_part_data *)malloc( + sizeof(struct black_holes_part_data) * t->ci->hydro.count); + cell_pack_part_swallow(t->ci, + (struct black_holes_part_data *)t->buff); + + if (t->ci->hydro.count * sizeof(struct black_holes_part_data) > + s->mpi_message_limit) { + err = MPI_Isend( + t->buff, + t->ci->hydro.count * sizeof(struct black_holes_part_data), + MPI_BYTE, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], + &t->req); + } else { + err = MPI_Issend( + t->buff, + t->ci->hydro.count * sizeof(struct black_holes_part_data), + MPI_BYTE, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], + &t->req); + } + } else if (t->subtype == task_subtype_xv || t->subtype == task_subtype_rho || t->subtype == task_subtype_gradient) { @@ -1821,7 +1852,9 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { err = MPI_Issend(t->ci->stars.parts, t->ci->stars.count, spart_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); - } else if (t->subtype == task_subtype_bpart) { + } else if (t->subtype == task_subtype_bpart_rho || + t->subtype == task_subtype_bpart_swallow || + t->subtype == task_subtype_bpart_feedback) { if ((t->ci->black_holes.count * sizeof(struct bpart)) > s->mpi_message_limit) err = MPI_Isend(t->ci->black_holes.parts, t->ci->black_holes.count, diff --git a/src/serial_io.c b/src/serial_io.c index e16a3351d75e176bf71d6dc1c791a37574de96f9..c05c69e1e86b737e1e7f06b995f89f6bb548901a 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -1241,7 +1241,7 @@ void write_output_serial(struct engine* e, const char* baseName, if (swift_memalign("gparts_written", (void**)&gparts_written, gpart_align, Ndm_written * sizeof(struct gpart)) != 0) - error("Error while allocating temporart memory for gparts"); + error("Error while allocating temporary memory for gparts"); if (with_stf) { if (swift_memalign( @@ -1250,7 +1250,7 @@ void write_output_serial(struct engine* e, const char* baseName, Ndm_written * sizeof(struct velociraptor_gpart_data)) != 0) error( - "Error while allocating temporart memory for gparts STF " + "Error while allocating temporary memory for gparts STF " "data"); } @@ -1291,7 +1291,7 @@ void write_output_serial(struct engine* e, const char* baseName, if (swift_memalign("sparts_written", (void**)&sparts_written, spart_align, Nstars_written * sizeof(struct spart)) != 0) - error("Error while allocating temporart memory for sparts"); + error("Error while allocating temporary memory for sparts"); /* Collect the particles we want to write */ io_collect_sparts_to_write(sparts, sparts_written, Nstars, @@ -1316,6 +1316,9 @@ void write_output_serial(struct engine* e, const char* baseName, /* No inhibted particles: easy case */ Nparticles = Nblackholes; black_holes_write_particles(bparts, list, &num_fields); + num_fields += + chemistry_write_bparticles(bparts, list + num_fields); + if (with_stf) { num_fields += velociraptor_write_bparts(bparts, list + num_fields); @@ -1329,7 +1332,7 @@ void write_output_serial(struct engine* e, const char* baseName, if (swift_memalign( "bparts_written", (void**)&bparts_written, bpart_align, Nblackholes_written * sizeof(struct bpart)) != 0) - error("Error while allocating temporart memory for bparts"); + error("Error while allocating temporary memory for bparts"); /* Collect the particles we want to write */ io_collect_bparts_to_write(bparts, bparts_written, Nblackholes, @@ -1337,6 +1340,9 @@ void write_output_serial(struct engine* e, const char* baseName, /* Select the fields to write */ black_holes_write_particles(bparts_written, list, &num_fields); + num_fields += + chemistry_write_bparticles(bparts, list + num_fields); + if (with_stf) { num_fields += velociraptor_write_bparts(bparts_written, list + num_fields); diff --git a/src/single_io.c b/src/single_io.c index afce1e1e6ebb6a8101ccfa109efd8df9e10fbd33..7a7856d29ce35435f750f2f71d66e0269d114261 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -989,11 +989,11 @@ void write_output_single(struct engine* e, const char* baseName, if (swift_memalign("parts_written", (void**)&parts_written, part_align, Ngas_written * sizeof(struct part)) != 0) - error("Error while allocating temporart memory for parts"); + error("Error while allocating temporary memory for parts"); if (swift_memalign("xparts_written", (void**)&xparts_written, xpart_align, Ngas_written * sizeof(struct xpart)) != 0) - error("Error while allocating temporart memory for xparts"); + error("Error while allocating temporary memory for xparts"); /* Collect the particles we want to write */ io_collect_parts_to_write(parts, xparts, parts_written, @@ -1039,7 +1039,7 @@ void write_output_single(struct engine* e, const char* baseName, if (swift_memalign("gparts_written", (void**)&gparts_written, gpart_align, Ndm_written * sizeof(struct gpart)) != 0) - error("Error while allocating temporart memory for gparts"); + error("Error while allocating temporary memory for gparts"); if (with_stf) { if (swift_memalign( @@ -1047,7 +1047,7 @@ void write_output_single(struct engine* e, const char* baseName, gpart_align, Ndm_written * sizeof(struct velociraptor_gpart_data)) != 0) error( - "Error while allocating temporart memory for gparts STF " + "Error while allocating temporary memory for gparts STF " "data"); } @@ -1086,7 +1086,7 @@ void write_output_single(struct engine* e, const char* baseName, if (swift_memalign("sparts_written", (void**)&sparts_written, spart_align, Nstars_written * sizeof(struct spart)) != 0) - error("Error while allocating temporart memory for sparts"); + error("Error while allocating temporary memory for sparts"); /* Collect the particles we want to write */ io_collect_sparts_to_write(sparts, sparts_written, Nstars, @@ -1111,6 +1111,8 @@ void write_output_single(struct engine* e, const char* baseName, /* No inhibted particles: easy case */ N = Nblackholes; black_holes_write_particles(bparts, list, &num_fields); + num_fields += chemistry_write_bparticles(bparts, list + num_fields); + if (with_stf) { num_fields += velociraptor_write_bparts(bparts, list + num_fields); } @@ -1123,7 +1125,7 @@ void write_output_single(struct engine* e, const char* baseName, if (swift_memalign("bparts_written", (void**)&bparts_written, bpart_align, Nblackholes_written * sizeof(struct bpart)) != 0) - error("Error while allocating temporart memory for bparts"); + error("Error while allocating temporary memory for bparts"); /* Collect the particles we want to write */ io_collect_bparts_to_write(bparts, bparts_written, Nblackholes, @@ -1131,6 +1133,8 @@ void write_output_single(struct engine* e, const char* baseName, /* Select the fields to write */ black_holes_write_particles(bparts_written, list, &num_fields); + num_fields += + chemistry_write_bparticles(bparts_written, list + num_fields); if (with_stf) { num_fields += velociraptor_write_bparts(bparts_written, list + num_fields); diff --git a/src/space.c b/src/space.c index 3ff86f439d20e0e63d2ab61314e5599aedb75dfc..488672eb0b704d70506372c7152f0b554d09de4b 100644 --- a/src/space.c +++ b/src/space.c @@ -213,19 +213,15 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, c->hydro.count = 0; c->hydro.count_total = 0; c->hydro.updated = 0; - c->hydro.inhibited = 0; c->grav.count = 0; c->grav.count_total = 0; c->grav.updated = 0; - c->grav.inhibited = 0; c->stars.count = 0; c->stars.count_total = 0; c->stars.updated = 0; - c->stars.inhibited = 0; c->black_holes.count = 0; c->black_holes.count_total = 0; c->black_holes.updated = 0; - c->black_holes.inhibited = 0; c->grav.init = NULL; c->grav.init_out = NULL; c->hydro.extra_ghost = NULL; @@ -235,8 +231,12 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, c->stars.ghost = NULL; c->stars.density = NULL; c->stars.feedback = NULL; - c->black_holes.ghost = NULL; + c->black_holes.density_ghost = NULL; + c->black_holes.swallow_ghost[0] = NULL; + c->black_holes.swallow_ghost[1] = NULL; c->black_holes.density = NULL; + c->black_holes.swallow = NULL; + c->black_holes.do_swallow = NULL; c->black_holes.feedback = NULL; c->kick1 = NULL; c->kick2 = NULL; @@ -4080,6 +4080,9 @@ void space_first_init_parts_mapper(void *restrict map_data, int count, tracers_first_init_xpart(&p[k], &xp[k], us, phys_const, cosmo, hydro_props, cool_func); + /* And the black hole markers */ + black_holes_mark_as_not_swallowed(&p[k].black_holes_data); + #ifdef SWIFT_DEBUG_CHECKS /* Check part->gpart->part linkeage. */ if (p[k].gpart && p[k].gpart->id_or_neg_offset != -(k + delta)) @@ -5209,6 +5212,49 @@ void space_check_limiter(struct space *s) { #endif } +/** + * @brief #threadpool mapper function for the swallow debugging check + */ +void space_check_swallow_mapper(void *map_data, int nr_parts, + void *extra_data) { +#ifdef SWIFT_DEBUG_CHECKS + /* Unpack the data */ + struct part *restrict parts = (struct part *)map_data; + + /* Verify that all particles have been swallowed or are untouched */ + for (int k = 0; k < nr_parts; k++) { + + if (parts[k].time_bin == time_bin_inhibited) continue; + + const long long swallow_id = + black_holes_get_swallow_id(&parts[k].black_holes_data); + + if (swallow_id != -1) + error("Particle has not been swallowed! id=%lld", parts[k].id); + } +#else + error("Calling debugging code without debugging flag activated."); +#endif +} + +/** + * @brief Checks that all particles have their swallow flag in a "no swallow" + * state. + * + * Should only be used for debugging purposes. + * + * @param s The #space to check. + */ +void space_check_swallow(struct space *s) { +#ifdef SWIFT_DEBUG_CHECKS + + threadpool_map(&s->e->threadpool, space_check_swallow_mapper, s->parts, + s->nr_parts, sizeof(struct part), 1000, NULL); +#else + error("Calling debugging code without debugging flag activated."); +#endif +} + void space_check_sort_flags_mapper(void *map_data, int nr_cells, void *extra_data) { diff --git a/src/space.h b/src/space.h index 88f38209e7d8d82b021cd518dfa9806e4ec844eb..21d36b7e880c3b8943e03bfbbc16bfefe6fff0d1 100644 --- a/src/space.h +++ b/src/space.h @@ -354,6 +354,7 @@ void space_check_top_multipoles_drift_point(struct space *s, integertime_t ti_drift); void space_check_timesteps(struct space *s); void space_check_limiter(struct space *s); +void space_check_swallow(struct space *s); void space_check_sort_flags(struct space *s); void space_replicate(struct space *s, int replicate, int verbose); void space_generate_gas(struct space *s, const struct cosmology *cosmo, diff --git a/src/task.c b/src/task.c index 77731ae02f8c84597565717319241997a77fadf7..9d7167e0b82cf8459676f5216aabb1c0f6ce7fb8 100644 --- a/src/task.c +++ b/src/task.c @@ -91,18 +91,21 @@ const char *taskID_names[task_type_count] = {"none", "stars_sort", "bh_in", "bh_out", - "bh_ghost", + "bh_density_ghost", + "bh_swallow_ghost1", + "bh_swallow_ghost2", "fof_self", "fof_pair"}; /* Sub-task type names. */ const char *subtaskID_names[task_subtype_count] = { - "none", "density", "gradient", "force", - "limiter", "grav", "external_grav", "tend_part", - "tend_gpart", "tend_spart", "tend_bpart", "xv", - "rho", "gpart", "multipole", "spart", - "stars_density", "stars_feedback", "sf_count", "bpart", - "bh_density", "bh_feedback"}; + "none", "density", "gradient", "force", + "limiter", "grav", "external_grav", "tend_part", + "tend_gpart", "tend_spart", "tend_bpart", "xv", + "rho", "part_swallow", "gpart", "multipole", + "spart", "stars_density", "stars_feedback", "sf_count", + "bpart_rho", "bpart_swallow", "bpart_feedback", "bh_density", + "bh_swallow", "do_swallow", "bh_feedback"}; #ifdef WITH_MPI /* MPI communicators for the subtypes. */ @@ -137,6 +140,7 @@ MPI_Comm subtaskMPI_comms[task_subtype_count]; TASK_CELL_OVERLAP(part, hydro.parts, hydro.count); TASK_CELL_OVERLAP(gpart, grav.parts, grav.count); TASK_CELL_OVERLAP(spart, stars.parts, stars.count); +TASK_CELL_OVERLAP(bpart, black_holes.parts, black_holes.count); /** * @brief Returns the #task_actions for a given task. @@ -172,7 +176,8 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( break; case task_type_drift_bpart: - case task_type_bh_ghost: + case task_type_bh_density_ghost: + case task_type_bh_swallow_ghost2: return task_action_bpart; break; @@ -196,6 +201,8 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_subtype_bh_density: case task_subtype_bh_feedback: + case task_subtype_bh_swallow: + case task_subtype_do_swallow: return task_action_all; break; @@ -289,11 +296,15 @@ float task_overlap(const struct task *restrict ta, (ta_act == task_action_gpart || ta_act == task_action_all); const int ta_spart = (ta_act == task_action_spart || ta_act == task_action_all); + const int ta_bpart = + (ta_act == task_action_bpart || ta_act == task_action_all); const int tb_part = (tb_act == task_action_part || tb_act == task_action_all); const int tb_gpart = (tb_act == task_action_gpart || tb_act == task_action_all); const int tb_spart = (tb_act == task_action_spart || tb_act == task_action_all); + const int tb_bpart = + (tb_act == task_action_bpart || tb_act == task_action_all); /* In the case where both tasks act on parts */ if (ta_part && tb_part) { @@ -358,6 +369,27 @@ float task_overlap(const struct task *restrict ta, return ((float)size_intersect) / (size_union - size_intersect); } + /* In the case where both tasks act on bparts */ + else if (ta_bpart && tb_bpart) { + + /* Compute the union of the cell data. */ + size_t size_union = 0; + if (ta->ci != NULL) size_union += ta->ci->black_holes.count; + if (ta->cj != NULL) size_union += ta->cj->black_holes.count; + if (tb->ci != NULL) size_union += tb->ci->black_holes.count; + if (tb->cj != NULL) size_union += tb->cj->black_holes.count; + + if (size_union == 0) return 0.f; + + /* Compute the intersection of the cell data. */ + const size_t size_intersect = task_cell_overlap_bpart(ta->ci, tb->ci) + + task_cell_overlap_bpart(ta->ci, tb->cj) + + task_cell_overlap_bpart(ta->cj, tb->ci) + + task_cell_overlap_bpart(ta->cj, tb->cj); + + return ((float)size_intersect) / (size_union - size_intersect); + } + /* Else, no overlap */ return 0.f; } @@ -411,6 +443,12 @@ void task_unlock(struct task *t) { (subtype == task_subtype_stars_feedback)) { cell_sunlocktree(ci); cell_unlocktree(ci); + } else if ((subtype == task_subtype_bh_density) || + (subtype == task_subtype_bh_feedback) || + (subtype == task_subtype_bh_swallow) || + (subtype == task_subtype_do_swallow)) { + cell_bunlocktree(ci); + cell_unlocktree(ci); } else { cell_unlocktree(ci); } @@ -429,6 +467,14 @@ void task_unlock(struct task *t) { cell_sunlocktree(cj); cell_unlocktree(ci); cell_unlocktree(cj); + } else if ((subtype == task_subtype_bh_density) || + (subtype == task_subtype_bh_feedback) || + (subtype == task_subtype_bh_swallow) || + (subtype == task_subtype_do_swallow)) { + cell_bunlocktree(ci); + cell_bunlocktree(cj); + cell_unlocktree(ci); + cell_unlocktree(cj); } else { cell_unlocktree(ci); cell_unlocktree(cj); @@ -550,6 +596,17 @@ int task_lock(struct task *t) { cell_sunlocktree(ci); return 0; } + } else if ((subtype == task_subtype_bh_density) || + (subtype == task_subtype_bh_feedback) || + (subtype == task_subtype_bh_swallow) || + (subtype == task_subtype_do_swallow)) { + if (ci->black_holes.hold) return 0; + if (ci->hydro.hold) return 0; + if (cell_blocktree(ci) != 0) return 0; + if (cell_locktree(ci) != 0) { + cell_bunlocktree(ci); + return 0; + } } else { /* subtype == hydro */ if (ci->hydro.hold) return 0; if (cell_locktree(ci) != 0) return 0; @@ -596,6 +653,29 @@ int task_lock(struct task *t) { cell_unlocktree(ci); return 0; } + } else if ((subtype == task_subtype_bh_density) || + (subtype == task_subtype_bh_feedback) || + (subtype == task_subtype_bh_swallow) || + (subtype == task_subtype_do_swallow)) { + /* Lock the BHs and the gas particles in both cells */ + if (ci->black_holes.hold || cj->black_holes.hold) return 0; + if (ci->hydro.hold || cj->hydro.hold) return 0; + if (cell_blocktree(ci) != 0) return 0; + if (cell_blocktree(cj) != 0) { + cell_bunlocktree(ci); + return 0; + } + if (cell_locktree(ci) != 0) { + cell_bunlocktree(ci); + cell_bunlocktree(cj); + return 0; + } + if (cell_locktree(cj) != 0) { + cell_bunlocktree(ci); + cell_bunlocktree(cj); + cell_unlocktree(ci); + return 0; + } } else { /* subtype == hydro */ /* Lock the parts in both cells */ if (ci->hydro.hold || cj->hydro.hold) return 0; @@ -716,6 +796,12 @@ void task_get_group_name(int type, int subtype, char *cluster) { case task_subtype_bh_density: strcpy(cluster, "BHDensity"); break; + case task_subtype_bh_swallow: + strcpy(cluster, "BHSwallow"); + break; + case task_subtype_do_swallow: + strcpy(cluster, "DoSwallow"); + break; case task_subtype_bh_feedback: strcpy(cluster, "BHFeedback"); break; diff --git a/src/task.h b/src/task.h index eef0aca5fb075725fb1da51ccaf4033a3608e078..995f39357f810e068b3fe4e4304bfab8f9734080 100644 --- a/src/task.h +++ b/src/task.h @@ -86,7 +86,9 @@ enum task_types { task_type_stars_sort, task_type_bh_in, /* Implicit */ task_type_bh_out, /* Implicit */ - task_type_bh_ghost, + task_type_bh_density_ghost, + task_type_bh_swallow_ghost1, + task_type_bh_swallow_ghost2, task_type_fof_self, task_type_fof_pair, task_type_count @@ -109,14 +111,19 @@ enum task_subtypes { task_subtype_tend_bpart, task_subtype_xv, task_subtype_rho, + task_subtype_part_swallow, task_subtype_gpart, task_subtype_multipole, task_subtype_spart, task_subtype_stars_density, task_subtype_stars_feedback, task_subtype_sf_counts, - task_subtype_bpart, + task_subtype_bpart_rho, + task_subtype_bpart_swallow, + task_subtype_bpart_feedback, task_subtype_bh_density, + task_subtype_bh_swallow, + task_subtype_do_swallow, task_subtype_bh_feedback, task_subtype_count } __attribute__((packed)); diff --git a/tools/plot_task_dependencies.py b/tools/plot_task_dependencies.py index b835b04261cf54b361f347f88bbb27f230a6be16..dbb39144fc1497d405c368ce3b59063ee8c97983 100644 --- a/tools/plot_task_dependencies.py +++ b/tools/plot_task_dependencies.py @@ -146,7 +146,7 @@ def taskIsBlackHoles(name): name: str Task name """ - if "bh" in name or "bpart" in name: + if "bh" in name or "bpart" in name or "swallow" in name: return True return False @@ -181,13 +181,13 @@ def taskIsHydro(name): return True if "density" in name and "stars" not in name and "bh" not in name: return True - if "rho" in name: + if "rho" in name and "bpart" not in name: return True if "gradient" in name: return True if "force" in name: return True - if "xv" in name: + if "xv" in name and "bpart" not in name: return True task_name = [ diff --git a/tools/task_plots/analyse_tasks.py b/tools/task_plots/analyse_tasks.py index aad447148dd35af434003c0f14f773179b320b03..6dcba21841db61748beb06203441016101619b8f 100755 --- a/tools/task_plots/analyse_tasks.py +++ b/tools/task_plots/analyse_tasks.py @@ -134,6 +134,8 @@ SUBTYPES = [ "sf_counts" "bpart", "bh_density", + "bh_swallow", + "do_swallow", "bh_feedback", "count", ] diff --git a/tools/task_plots/plot_tasks.py b/tools/task_plots/plot_tasks.py index 070ae2f3c509d6ae8fef8bad9ffec6c316060a7c..e7621b321434ddb97df4b2bb1f31ff9609d71c5e 100755 --- a/tools/task_plots/plot_tasks.py +++ b/tools/task_plots/plot_tasks.py @@ -219,6 +219,8 @@ SUBTYPES = [ "sf_counts", "bpart", "bh_density", + "bh_swallow", + "do_swallow", "bh_feedback", "count", ] @@ -275,6 +277,14 @@ FULLTYPES = [ "pair/bh_density", "sub_self/bh_density", "sub_pair/bh_density", + "self/bh_swallow", + "pair/bh_swallow", + "sub_self/bh_swallow", + "sub_pair/bh_swallow", + "self/do_swallow", + "pair/do_swallow", + "sub_self/do_swallow", + "sub_pair/do_swallow", "self/bh_feedback", "pair/bh_feedback", "sub_self/bh_feedback",