Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cbd abdot #101

Open
wants to merge 82 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
ef11e8d
local changes
mssiwek Jun 21, 2023
5536e99
Merge branch 'dev' of https://github.com/nanograv/holodeck into cbd_a…
mssiwek Jun 21, 2023
f0f1376
Merge branch 'dev' of https://github.com/nanograv/holodeck into cbd_a…
mssiwek Jul 5, 2023
075b742
notebooks
mssiwek Jul 12, 2023
1f2983a
Merge branch 'dev' of https://github.com/nanograv/holodeck into cbd_a…
mssiwek Jul 12, 2023
ec911fb
Eddington limited accretion
mssiwek Jul 12, 2023
f998954
add separation and eccentricity to sample_universe
mssiwek Jul 12, 2023
e371e15
interpolating eccentricity in sample_universe
mssiwek Jul 17, 2023
649a452
Merge branch 'dev' of https://github.com/nanograv/holodeck into cbd_a…
mssiwek Jul 17, 2023
f666fa1
fixed bug in utils.trapz()
mssiwek Jul 20, 2023
fcbb53f
notebook changes?
mssiwek Jul 20, 2023
71c61e9
Merge branch 'dev' of https://github.com/nanograv/holodeck into cbd_a…
mssiwek Jul 20, 2023
d980e73
documentation in samples
mssiwek Aug 7, 2023
a910f28
merge conflict
mssiwek Aug 7, 2023
b7ff13b
Merge branch 'cbd_abdot' of https://github.com/nanograv/holodeck into…
mssiwek Aug 7, 2023
e9938ee
merge conflict with dev
mssiwek Aug 7, 2023
6377966
add evol_mass switch in accretion, and add dadt,dedt in sample_universe
mssiwek Sep 1, 2023
f0522ac
Merge branch 'dev' of https://github.com/nanograv/holodeck into cbd_a…
mssiwek Sep 1, 2023
f890878
notebook to check effect of cbd on gwb
mssiwek Sep 1, 2023
0997bdf
Comment out old warning - dont think its still relevant
lzkelley Sep 1, 2023
97fb6ac
Add LZK version of notebook for messing around with stuff
lzkelley Sep 1, 2023
4c10550
Cleanup '_gws_harmonics_at_evo_fobs' method, store 'harms' (hc^2 harm…
lzkelley Sep 4, 2023
e78182f
fixed bug due to mass being updated AFTER calculating dadt for timestep
mssiwek Sep 22, 2023
f142b54
switch to include dfdt_mdot
mssiwek Sep 22, 2023
1b2becc
switch to include dfdt_mdot in utils.py
mssiwek Sep 22, 2023
335fa7f
fixed DF attenuation
mssiwek Sep 22, 2023
99fea98
merge conflict resolved
mssiwek Sep 22, 2023
40a8129
Add a flag to CBD_Torques to turn on/off positive da/dt values (i.e. …
lzkelley Sep 25, 2023
b872486
Add (stern) warning when using attenuate=False in dynamical friction
lzkelley Sep 25, 2023
71a43e3
Complete re-write of Evolution class integration method.
lzkelley Sep 26, 2023
3283e3c
BUG: fix cython issue with new cython version
lzkelley Sep 26, 2023
961c11e
Store all hardening rates, dont go past ISCO, cleanup
lzkelley Sep 26, 2023
45644d9
Add new cython module for performing interpolation of new discrete po…
lzkelley Sep 27, 2023
3b1c1a7
Debugging and development tweaks
lzkelley Sep 27, 2023
f84dacc
dfdt with accretion
mssiwek Sep 27, 2023
753aebf
Add formal tests for discrete_cyutils.interp_at_fobs --- currently wo…
lzkelley Sep 28, 2023
1cde72f
Restore the old version of 'Evolution' and add 'New_Evolution' along …
lzkelley Sep 28, 2023
b85185e
notebooks
mssiwek Sep 28, 2023
e595e63
merge conflict in notebook resolved
mssiwek Sep 28, 2023
bdfb798
no need to set mdot=0 at >1.e5pc separations
mssiwek Sep 28, 2023
91b6ccb
initialize self.mdot=0 whether or not we use accretion, otherwise stu…
mssiwek Sep 28, 2023
6fd92e2
Cleanup
lzkelley Sep 28, 2023
6030e58
INCOMPLETE: implement GW calculation in New_Evolution
lzkelley Sep 28, 2023
54c1356
Continue implementing GWB calculation in New_Evolution.
lzkelley Sep 29, 2023
3b5093c
make accretion.py compatible with both new and old evo
mssiwek Sep 29, 2023
e397a60
evolution compatible with old/new evo, fixed mass switching issue in …
mssiwek Sep 29, 2023
ca30430
hardening compatible with new/old evo
mssiwek Sep 29, 2023
cfd4ad1
m1m2 order for both evo classes, output change in velocity_orbital
mssiwek Sep 29, 2023
b7f1eba
new tests and changes in notebooks
mssiwek Sep 29, 2023
9a0d022
GW calculation with New_Evolution seems to be working
lzkelley Sep 29, 2023
327028f
Merge remote-tracking branch 'origin/cbd_abdot' into manual-merge
lzkelley Sep 30, 2023
6bd2cfc
Implement dfdt_mdot into New_Evolution
lzkelley Sep 30, 2023
479eb61
changes in notebook
mssiwek Oct 2, 2023
c687df2
Merge branch 'dev_discrete-time-based-evo' of https://github.com/nano…
mssiwek Oct 2, 2023
c68d862
add ebeq function and move interpolation and pkl loading to init
mssiwek Oct 5, 2023
4130229
cfl condition for eccentricity evolution, add nsteps and cfl as param…
mssiwek Oct 5, 2023
28053d2
move interp and pkl.load to init
mssiwek Oct 5, 2023
2862cc8
BUG: no 'bool' in cython, cast to int before passing
lzkelley Oct 5, 2023
f4737c5
Merge branch 'cbd_abdot' into dev_discrete-time-based-evo
lzkelley Oct 5, 2023
ada4712
commenting out eccen cfl
mssiwek Oct 5, 2023
b5c8107
Merge branch 'cbd_abdot' of https://github.com/nanograv/holodeck into…
mssiwek Oct 5, 2023
d6bedcd
Interpolate mdot in New_Evolution
lzkelley Oct 6, 2023
30be4b0
Merge branch 'cbd_abdot' of https://github.com/nanograv/holodeck into…
mssiwek Oct 6, 2023
0410222
BUG: fix shape issue with mdot GWB calculation; update speed-test-cbd…
lzkelley Oct 6, 2023
2617303
Merge branch 'cbd_abdot' of https://github.com/nanograv/holodeck into…
mssiwek Oct 6, 2023
744e214
BUG
lzkelley Oct 6, 2023
4e61d92
DF stops at 10pc
mssiwek Oct 6, 2023
0241c8f
pre-calculating tables for df
mssiwek Oct 6, 2023
1b1b064
Merge branch 'cbd_abdot' of https://github.com/nanograv/holodeck into…
mssiwek Oct 6, 2023
32f1329
revert to previous interpolation due to bug in pre-calculated values
mssiwek Oct 6, 2023
31a8435
interpolate pre-calculated tables for DF
mssiwek Oct 11, 2023
f093682
removed a printf
mssiwek Oct 11, 2023
0c8b73b
added sample_universe calculation
mssiwek Oct 11, 2023
f0ffd7e
skip df hardening for sub-parsec binaries
mssiwek Oct 11, 2023
e46aa10
replace np.digitize with data_fobs[interp_idx]
mssiwek Oct 11, 2023
a696637
debug dfdt_mdot
mssiwek Oct 11, 2023
b1c0bbb
absolute value of dfdt when softening happens
mssiwek Jan 19, 2024
7f746d8
DOCS: minor notes and cleanup
lzkelley Jan 23, 2024
8b1f2a1
take absolute dlnf values for floars or arr
mssiwek Feb 19, 2024
b26b848
merge conflict
mssiwek Feb 19, 2024
96b4d69
merge
mssiwek Feb 19, 2024
ab1906a
step is now a required argument
mssiwek Feb 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 105 additions & 72 deletions holodeck/accretion.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import os
import numpy as np
from scipy.interpolate import RectBivariateSpline
from holodeck import _PATH_DATA
from holodeck import _PATH_DATA, utils
from holodeck.constants import SPLC, EDDT


Expand All @@ -37,7 +37,7 @@ class Accretion:
"""

def __init__(self, accmod='Basic', f_edd=0.01, mdot_ext=None, eccen=0.0,
subpc=True, **kwargs):
subpc=True, edd_lim=None, evol_mass=True, **kwargs):
""" Initializes the Accretion class.

Parameters
Expand All @@ -51,6 +51,7 @@ def __init__(self, accmod='Basic', f_edd=0.01, mdot_ext=None, eccen=0.0,
eccen : float, optional
Eccentricity value.
subpc : boolean, optional
edd_lim : None, or numerical value. This limits the accretion to a factor edd_lim the Eddington limit.

Other Parameters
----------------
Expand All @@ -62,6 +63,32 @@ def __init__(self, accmod='Basic', f_edd=0.01, mdot_ext=None, eccen=0.0,
self.mdot_ext = mdot_ext
self.eccen = eccen
self.subpc = subpc
self.edd_lim = edd_lim
self.evol_mass = evol_mass

""" PRE-CALCULATE PREFERENTIAL ACCRETION FUNCTION """
if self.accmod == 'Siwek22':
""" interpolate to get lambda at [q,e] """
def lambda_qe_interp_2d(fp="data/preferential_accretion/siwek+22/", es=[0.0,0.2,0.4,0.6,0.8]):
all_lambdas = []
for e in es:
fname = 'preferential_accretion/siwek+22/lambda_e=%.2f.txt' % e
fname = os.path.join(_PATH_DATA, fname)
lambda_e = np.loadtxt(fname)
qs = lambda_e[:, 0]
lambdas = lambda_e[:, 1]
all_lambdas.append(lambdas)
# True values of q, e
x = qs
y = es
# Populate the true values of q, e in a meshgrid
X, Y = np.meshgrid(x, y)
Z = all_lambdas

return(RectBivariateSpline(np.array(x), np.array(y),
np.array(Z).T, kx=1, ky=1))

self.swk_acc = lambda_qe_interp_2d()

def mdot_eddington(self, mass, eps=0.1):
"""Calculate the total accretion rate based on masses and a fraction of the Eddington limit.
Expand Down Expand Up @@ -92,34 +119,43 @@ def mdot_eddington(self, mass, eps=0.1):
>>> print(acc.mdot_eddington(mass))

"""
from holodeck.constants import SPLC, EDDT

# medd = (4.*np.pi*NWTG*MPRT)/(eps*SPLC*SIGMA_T) * self.mtot
medd = self.f_edd * (EDDT/(eps * SPLC**2)) * mass
return(medd)

def mdot_total(self, evol, step):
def mdot_total(self, evol, bin, step):
from holodeck.constants import PC

if self.mdot_ext is not None:
""" accretion rates have been supplied externally """
mdot = self.mdot_ext[:,step-1]
raise NotImplementedError("THIS HASNT BEEN UPDATED TO NEW TIME-BASED INTEGRATION!")
mdot = self.mdot_ext[:, step-1]

else:
""" Get accretion rates as a fraction (f_edd in self._acc) of the
Eddington limit from current BH masses """
total_bh_masses = np.sum(evol.mass[:, step-1, :], axis=1)
if bin == None:
total_bh_masses = np.sum(evol.mass[:, step, :], axis=-1)
else:
total_bh_masses = np.sum(evol.mass[step, :])
mdot = self.mdot_eddington(total_bh_masses)

""" Calculate individual accretion rates """
if self.subpc:
""" Indices where separation is less than or equal to a parsec """
ind_sepa = evol.sepa[:, step] <= PC
else:
""" Indices where separation is less than or equal to 100 kilo-parsec """
ind_sepa = evol.sepa[:, step] <= 10**5 * PC
if bin == None:
#we are using old evol method, i.e. calculating mdot for all binaries at a given step
mdot[evol.sepa[:, step]>PC] = 0.0
else:
#new evol method, iterating over individual binaries, so mdot is just a float
if evol.sepa[step] > PC:
mdot = 0.0

""" Set total accretion rates to 0 when separation is larger than 1pc or 10kpc,
depending on subpc switch applied to accretion instance """
mdot[~ind_sepa] = 0
return(mdot)
return mdot

def pref_acc(self, mdot, evol, step):
def pref_acc(self, mdot, evol, bin, step):
"""
Contains a variety of accretion models to choose from to calculate primary vs secondary
accretion rates.
Expand Down Expand Up @@ -156,104 +192,101 @@ def pref_acc(self, mdot, evol, step):
accessed.

"""
m1 = evol.mass[:, step - 1, 0]
m2 = evol.mass[:, step - 1, 1]

if bin == None:
m1, m2 = utils.m1m2_ordered(evol.mass[:,step].T[0], evol.mass[:,step].T[1])
else:
m1, m2 = utils.m1m2_ordered(*evol.mass[step])


if self.accmod == 'Siwek22':
# Calculate the mass ratio
q_b = m2 / m1
# secondary and primary may swap indices
# need to account for that and reverse the mass ratio
inds_rev = q_b > 1
q_b[inds_rev] = 1./q_b[inds_rev]
"""if evol has an eccentricity distribution,
we use it, if not, we set each eccentricity to
the value specified in __init__ """
if evol.eccen is not None:
e_b = evol.eccen[:, step-1]
if bin == None:
e_b = evol.eccen[:, step] if (evol.eccen is not None) else None
else:
e_b = self.eccen
""" Now interpolate to get lambda at [q,e] """
def lambda_qe_interp_2d(fp="data/preferential_accretion/siwek+22/", es=[0.0,0.2,0.4,0.6,0.8]):
all_lambdas = []
for e in es:
fname = 'preferential_accretion/siwek+22/lambda_e=%.2f.txt' % e
fname = os.path.join(_PATH_DATA, fname)
lambda_e = np.loadtxt(fname)
qs = lambda_e[:, 0]
lambdas = lambda_e[:, 1]
all_lambdas.append(lambdas)
# True values of q, e
x = qs
y = es
# Populate the true values of q, e in a meshgrid
X, Y = np.meshgrid(x, y)
Z = all_lambdas
e_b = evol.eccen[step] if (evol.eccen is not None) else None

return(RectBivariateSpline(np.array(x), np.array(y),
np.array(Z).T, kx=1, ky=1))

lamb_interp = lambda_qe_interp_2d()
lamb_interp = self.swk_acc
# Need to use RectBivariateSpline.ev to evaluate the interpolation
# at points, allowing q_b and e_b to be in non-ascending order
q_b = m2 / m1
lamb_qe = lamb_interp.ev(q_b, e_b)
mdot_1 = 1./(np.array(lamb_qe) + 1.) * mdot
mdot_2 = np.array(lamb_qe)/(np.array(lamb_qe) + 1.) * mdot

# After calculating the primary and secondary accretion rates,
# they need to be placed at the correct index into `mdot_arr`, to
# account for primary/secondary being at 0-th OR 1-st index
mdot_arr = np.zeros(np.shape(evol.mass[:, step-1, :]))
inds_m1_primary = m1 >= m2 # where first mass is actually primary
inds_m2_primary = m2 >= m1 # where second mass is actually primary
mdot_arr[:, 0][inds_m1_primary] = mdot_1[inds_m1_primary]
mdot_arr[:, 0][~inds_m1_primary] = mdot_2[~inds_m1_primary]
mdot_arr[:, 1][inds_m2_primary] = mdot_1[inds_m2_primary]
mdot_arr[:, 1][~inds_m2_primary] = mdot_2[~inds_m2_primary]
# `mdot_arr` is then passed to `_take_next_step()` in evolution.py
return(mdot_arr)

if self.accmod == 'Basic':
mdot_1 = mdot_2 = 0.5 * mdot
mdot_arr = np.array([mdot_1, mdot_2]).T
return(mdot_arr)

if self.accmod == 'Proportional':
""" Get primary and secondary masses """
m1 = self.m1
m2 = self.m2
# Calculate ratio of accretion rates so that mass ratio stays
# constant through accretion
mdot_ratio = m2/(m1 + m2)
mdot_2 = mdot_ratio * mdot
mdot_1 = (1. - mdot_ratio) * mdot
mdot_arr = np.array([mdot_1, mdot_2]).T
return(mdot_arr)

if self.accmod == 'Primary':
mdot_ratio = 0.
mdot_2 = mdot_ratio * mdot
mdot_1 = (1. - mdot_ratio) * mdot
mdot_arr = np.array([mdot_1, mdot_2]).T
return(mdot_arr)

if self.accmod == 'Secondary':
mdot_ratio = 1.
mdot_2 = mdot_ratio * mdot
mdot_1 = (1. - mdot_ratio) * mdot
mdot_arr = np.array([mdot_1, mdot_2]).T
return(mdot_arr)

if self.accmod == 'Duffell':
# Taken from Paul's paper: http://arxiv.org/abs/1911.05506
def f(q): return 1./(0.1 + 0.9 * q)
q = m2/m1
mdot_1 = mdot/(1. + f(q))
mdot_2 = f(q) * mdot_1
mdot_arr = np.array([mdot_1, mdot_2]).T
return(mdot_arr)

# Catch any weirdness if no model is selected.
if self.edd_lim is not None:
#need to limit the accretion rate to edd_lim times the Eddington limit
medd_1 = self.edd_lim * (self.mdot_eddington(m1)/self.f_edd)
mdot_1 = np.minimum(np.array(medd_1), np.array(mdot_1))
medd_2 = self.edd_lim * (self.mdot_eddington(m2)/self.f_edd)
mdot_2 = np.minimum(np.array(medd_2), np.array(mdot_2))

# After calculating the primary and secondary accretion rates,
# they need to be placed at the correct index into `mdot_arr`, to
# account for primary/secondary being at 0-th OR 1-st index
if bin == None:
inds_m1_primary = evol.mass[:,step].T[0] >= evol.mass[:,step].T[1]
mdot_arr = np.zeros(np.shape(evol.mass[:, step-1, :]))
mdot_arr[:, 0][inds_m1_primary] = mdot_1[inds_m1_primary]
mdot_arr[:, 0][~inds_m1_primary] = mdot_2[~inds_m1_primary]
inds_m2_primary = evol.mass[:,step-1].T[1] >= evol.mass[:,step-1].T[0]
mdot_arr[:, 1][inds_m2_primary] = mdot_1[inds_m2_primary]
mdot_arr[:, 1][~inds_m2_primary] = mdot_2[~inds_m2_primary]
else:
if evol.mass[step, 0] >= evol.mass[step, 1]:
mdot_arr = [mdot_1, mdot_2]
else:
mdot_arr = [mdot_2, mdot_1]

# Catch any case where no model is selected.
if self.accmod is None:
raise TypeError("'None' value provided for accretion model." +
"An accretion model is required.")

return np.asarray(mdot_arr)

def ebeq(self, qb):
import pickle as pkl
fp_ebeq_pkl = 'cbd_torques/siwek+23/eb_eq_arr.pkl'
fp_ebeq_pkl = os.path.join(_PATH_DATA, fp_ebeq_pkl)
fp_ebeq = open(fp_ebeq_pkl, 'rb')
ebeq_dict = pkl.load(fp_ebeq)

all_qb = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

all_ebeq = []

for q in all_qb:
all_ebeq.append(ebeq_dict['q=%.2f_sum_grav_acc' %q])

return(np.interp(qb, all_qb, all_ebeq))

5 changes: 4 additions & 1 deletion holodeck/cyutils.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
"""

cdef double _interp_between_vals(double xnew, double xl, double xr, double yl, double yr)
cdef double interp_at_index(int idx, double xnew, double[:] xold, double[:] yold)
cdef double interp_at_index(int idx, double xnew, double[:] xold, double[:] yold)
cdef double gw_freq_dist_func__scalar_scalar(int nn, double ee)


3 changes: 2 additions & 1 deletion holodeck/discrete/evolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,8 @@ def _init_step_zero(self):
setattr(self, f"_dedt_{ii}", np.zeros_like(self.dadt))

# ---- Initialize hardening rate at first step
dadt_init, dedt_init = self._hardening_rate(step=0)
step0 = 0
dadt_init, dedt_init = self._hardening_rate(step0)

self.dadt[:, 0] = dadt_init
if (pop.eccen is not None):
Expand Down
13 changes: 12 additions & 1 deletion holodeck/discrete/population.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ class Pop_Illustris(_Population_Discrete):

"""

def __init__(self, fname=None, **kwargs):
def __init__(self, select=None, fname=None, **kwargs):
"""Initialize a binary population using data in the given filename.

Parameters
Expand All @@ -314,6 +314,8 @@ def __init__(self, fname=None, **kwargs):
Additional keyword-arguments passed to `super().__init__`.

"""
self._select = select

if fname is None:
fname = _DEF_ILLUSTRIS_FNAME
fname = os.path.join(_PATH_DATA, fname)
Expand Down Expand Up @@ -347,6 +349,15 @@ def _init(self):
# Get the stellar mass, and take that as bulge mass
self.mbulge = data['SubhaloMassInRadType'][:, st_idx, :] #: Stellar mass / stellar-bulge mass [grams]
self.vdisp = data['SubhaloVelDisp'] #: Velocity dispersion of galaxy [?cm/s?]

if self._select is not None:
print(f"\n=====\nWARNING SELECTING ONLY {self._select} BINARIES FROM DATA\n=====\n")
names = ['sepa', 'mass', 'scafa', 'mbulge', 'vdisp']
for nam in names:
vals = getattr(self, nam)
vals = vals[:self._select]
setattr(self, nam, vals)

return


Expand Down
Loading
Loading