| 1 | From 6bd910b83c180687a9cd53ba39f84c539f91c7c6 Mon Sep 17 00:00:00 2001
|
| 2 | From: David Wright <[email protected]>
|
| 3 | Date: Fri, 31 Oct 2025 19:18:01 -0700
|
| 4 | Subject: [PATCH 1/2] fix: Cython>=3.0 and Python 3.13 compatibility
|
| 5 |
|
| 6 | ---
|
| 7 | holodeck/cyutils.pxd | 4 ++--
|
| 8 | holodeck/cyutils.pyx | 32 ++++++++++++++++----------------
|
| 9 | holodeck/sams/sam_cyutils.pyx | 16 ++++++++--------
|
| 10 | pyproject.toml | 4 ++--
|
| 11 | requirements.txt | 4 ++--
|
| 12 | 5 files changed, 30 insertions(+), 30 deletions(-)
|
| 13 |
|
| 14 | diff --git a/holodeck/cyutils.pxd b/holodeck/cyutils.pxd
|
| 15 | index 9b12bf09..ede11a17 100644
|
| 16 | |
| 17 | |
| 18 | @@ -1,5 +1,5 @@
|
| 19 | """Header file for cython `cyutils.py`
|
| 20 | """
|
| 21 |
|
| 22 | -cdef double _interp_between_vals(double xnew, double xl, double xr, double yl, double yr)
|
| 23 | -cdef double interp_at_index(int idx, double xnew, double[:] xold, double[:] yold)
|
| 24 | \ No newline at end of file
|
| 25 | +cdef double _interp_between_vals(double xnew, double xl, double xr, double yl, double yr) noexcept
|
| 26 | +cdef double interp_at_index(int idx, double xnew, double[:] xold, double[:] yold) noexcept
|
| 27 | \ No newline at end of file
|
| 28 | diff --git a/holodeck/cyutils.pyx b/holodeck/cyutils.pyx
|
| 29 | index fcdb4d3b..599b496b 100644
|
| 30 | |
| 31 | |
| 32 | @@ -51,7 +51,7 @@ cdef double GW_SRC_CONST = 8.0 * pow(MY_NWTG, 5.0/3.0) * pow(M_PI, 2.0/3.0) / sq
|
| 33 | # ==== Utility Functions ====
|
| 34 |
|
| 35 |
|
| 36 | -cdef double bessel_recursive(int nn, double ne, double jn_m1, double jn_m2):
|
| 37 | +cdef double bessel_recursive(int nn, double ne, double jn_m1, double jn_m2) noexcept:
|
| 38 | """Recursive relation for calculating bessel functions
|
| 39 |
|
| 40 | J_n(x) = 2 * [(n-1) / x] * J_n-1(x) - J_n-2(x)
|
| 41 | @@ -76,7 +76,7 @@ cdef double bessel_recursive(int nn, double ne, double jn_m1, double jn_m2):
|
| 42 | return jn
|
| 43 |
|
| 44 |
|
| 45 | -cdef double _gw_ecc_func(double eccen):
|
| 46 | +cdef double _gw_ecc_func(double eccen) noexcept:
|
| 47 | """Calculate the GW Hardening rate eccentricitiy dependence F(e).
|
| 48 |
|
| 49 | See [Peters1964]_ Eq. 5.6, or [EN2007]_ Eq. 2.3
|
| 50 | @@ -99,7 +99,7 @@ cdef double _gw_ecc_func(double eccen):
|
| 51 |
|
| 52 | @cython.boundscheck(False)
|
| 53 | @cython.wraparound(False)
|
| 54 | -cdef void my_trapz_grid_weight(int index, int size, double[:] grid, double *rv):
|
| 55 | +cdef void my_trapz_grid_weight(int index, int size, double[:] grid, double *rv) noexcept:
|
| 56 | """Determine the trapezoid-rule weight and bin-width for the given grid point.
|
| 57 |
|
| 58 | Parameters
|
| 59 | @@ -142,7 +142,7 @@ cdef void my_trapz_grid_weight(int index, int size, double[:] grid, double *rv):
|
| 60 | return
|
| 61 |
|
| 62 |
|
| 63 | -cdef double gw_freq_dist_func__scalar_scalar(int nn, double ee):
|
| 64 | +cdef double gw_freq_dist_func__scalar_scalar(int nn, double ee) noexcept:
|
| 65 | """Calculate the GW frequency distribution function at the given harmonic and eccentricity, g(n,e).
|
| 66 |
|
| 67 | See [EN2007]_ Eq. 2.4
|
| 68 | @@ -198,7 +198,7 @@ cdef double gw_freq_dist_func__scalar_scalar(int nn, double ee):
|
| 69 | @cython.wraparound(False)
|
| 70 | @cython.nonecheck(False)
|
| 71 | @cython.cdivision(True)
|
| 72 | -cdef void unravel(int idx, int[] shape, int *ii_out, int *jj_out):
|
| 73 | +cdef void unravel(int idx, int[] shape, int *ii_out, int *jj_out) noexcept:
|
| 74 | """Convert from a 1D/flattened index into a 2D pair of (unraveled) indices.
|
| 75 |
|
| 76 | NOTE: row-major / c-style ordering is assumed. This is the numpy default.
|
| 77 | @@ -290,7 +290,7 @@ cdef int sort_compare(const void *a, const void *b) noexcept nogil:
|
| 78 | return 0
|
| 79 |
|
| 80 |
|
| 81 | -cdef void argsort(double *values, int size, int **indices):
|
| 82 | +cdef void argsort(double *values, int size, int **indices) noexcept:
|
| 83 | """Find the indices that sort the given 1D array of double values.
|
| 84 |
|
| 85 | This is done using an array of `sorter` struct instances which store both index and value.
|
| 86 | @@ -323,7 +323,7 @@ cdef void argsort(double *values, int size, int **indices):
|
| 87 | @cython.wraparound(False)
|
| 88 | @cython.nonecheck(False)
|
| 89 | @cython.cdivision(True)
|
| 90 | -cdef double _interp_between_vals(double xnew, double xl, double xr, double yl, double yr):
|
| 91 | +cdef double _interp_between_vals(double xnew, double xl, double xr, double yl, double yr) noexcept:
|
| 92 | cdef double ynew = yl + (yr - yl) * (xnew - xl) / (xr - xl)
|
| 93 | return ynew
|
| 94 |
|
| 95 | @@ -332,7 +332,7 @@ cdef double _interp_between_vals(double xnew, double xl, double xr, double yl, d
|
| 96 | @cython.wraparound(False)
|
| 97 | @cython.nonecheck(False)
|
| 98 | @cython.cdivision(True)
|
| 99 | -cdef double interp_at_index(int idx, double xnew, double[:] xold, double[:] yold):
|
| 100 | +cdef double interp_at_index(int idx, double xnew, double[:] xold, double[:] yold) noexcept:
|
| 101 | """Perform linear interpolation at the given index in a pair of arrays.
|
| 102 |
|
| 103 | Parameters
|
| 104 | @@ -852,7 +852,7 @@ cdef double[:, :, :] _sam_calc_gwb_single_eccen_discrete(
|
| 105 |
|
| 106 |
|
| 107 | def sam_poisson_gwb(dist, hc2, nreals, normal_threshold=1e10):
|
| 108 | - return _sam_poisson_gwb(np.array(dist.shape), dist, hc2, nreals, long(normal_threshold))
|
| 109 | + return _sam_poisson_gwb(np.array(dist.shape), dist, hc2, nreals, int(normal_threshold))
|
| 110 |
|
| 111 |
|
| 112 | @cython.boundscheck(False)
|
| 113 | @@ -934,7 +934,7 @@ def ss_bg_hc(number, h2fdf, nreals, normal_threshold=1e10):
|
| 114 | @cython.cdivision(True)
|
| 115 | cdef void _ss_bg_hc(long[:] shape, double[:,:,:,:] h2fdf, double[:,:,:,:] number,
|
| 116 | long nreals, long thresh,
|
| 117 | - double[:,:] hc2ss, double[:,:] hc2bg, long[:,:,:] ssidx):
|
| 118 | + double[:,:] hc2ss, double[:,:] hc2bg, long[:,:,:] ssidx) noexcept:
|
| 119 | """
|
| 120 | Calculates the characteristic strain from loud single sources and a background of all other sources.
|
| 121 |
|
| 122 | @@ -1069,7 +1069,7 @@ cdef void _ss_bg_hc_and_par(long[:] shape, double[:,:,:,:] h2fdf, double[:,:,:,:
|
| 123 | long nreals, long thresh,
|
| 124 | double[:] mt, double[:] mr, double[:] rz,
|
| 125 | double[:,:] hc2ss, double[:,:] hc2bg, long[:,:,:] ssidx,
|
| 126 | - double[:,:,:] bgpar, double[:,:,:] sspar):
|
| 127 | + double[:,:,:] bgpar, double[:,:,:] sspar) noexcept:
|
| 128 | """
|
| 129 | Calculates the characteristic strain from loud single sources and a background of all other sources.
|
| 130 |
|
| 131 | @@ -1204,7 +1204,7 @@ def sort_h2fdf(h2fdf):
|
| 132 |
|
| 133 | return
|
| 134 |
|
| 135 | -cdef (int *) _sort_h2fdf(double[:] flat_h2fdf, long size):
|
| 136 | +cdef (int *) _sort_h2fdf(double[:] flat_h2fdf, long size) except NULL:
|
| 137 |
|
| 138 | cdef (double *)array = <double *>malloc(size * sizeof(double))
|
| 139 | cdef (int *)indices = <int *>malloc(size * sizeof(int))
|
| 140 | @@ -1266,7 +1266,7 @@ def loudest_hc_from_sorted(number, h2fdf, nreals, nloudest, msort, qsort, zsort,
|
| 141 | cdef void _loudest_hc_from_sorted(long[:] shape, double[:,:,:,:] h2fdf, double[:,:,:,:] number,
|
| 142 | long nreals, long nloudest, long thresh,
|
| 143 | long[:] msort, long[:] qsort, long[:] zsort,
|
| 144 | - double[:,:,:] hc2ss, double[:,:] hc2bg):
|
| 145 | + double[:,:,:] hc2ss, double[:,:] hc2bg) noexcept:
|
| 146 | """
|
| 147 | Calculates the characteristic strain from loud single sources and a background of all other sources.
|
| 148 |
|
| 149 | @@ -1410,7 +1410,7 @@ cdef void _loudest_hc_and_par_from_sorted(long[:] shape, double[:,:,:,:] h2fdf,
|
| 150 | long nreals, long nloudest, long thresh,
|
| 151 | double[:] mt, double[:] mr, double[:] rz,
|
| 152 | long[:] msort, long[:] qsort, long[:] zsort,
|
| 153 | - double[:,:,:] hc2ss, double[:,:] hc2bg, double[:,:,:] lspar, double[:,:,:] bgpar, long[:,:,:,:] ssidx):
|
| 154 | + double[:,:,:] hc2ss, double[:,:] hc2bg, double[:,:,:] lspar, double[:,:,:] bgpar, long[:,:,:,:] ssidx) noexcept:
|
| 155 | """
|
| 156 | Calculates the characteristic strain from loud single sources and a background of all other sources.
|
| 157 |
|
| 158 | @@ -1617,7 +1617,7 @@ cdef void _loudest_hc_and_par_from_sorted_redz(long[:] shape, double[:,:,:,:] h2
|
| 159 | double[:] mt, double[:] mr, double[:] rz,
|
| 160 | double[:,:,:,:] redz_final, double[:,:,:,:] dcom_final, double[:,:,:,:] sepa, double[:,:,:,:] angs,
|
| 161 | long[:] msort, long[:] qsort, long[:] zsort,
|
| 162 | - double[:,:,:] hc2ss, double[:,:] hc2bg, double[:,:,:,:] sspar, double[:,:,:] bgpar):
|
| 163 | + double[:,:,:] hc2ss, double[:,:] hc2bg, double[:,:,:,:] sspar, double[:,:,:] bgpar) noexcept:
|
| 164 | """
|
| 165 | Calculates the characteristic strain from loud single sources and a background of all other sources.
|
| 166 |
|
| 167 | @@ -2046,7 +2046,7 @@ def Sh_rest(hc_ss, hc_bg, freqs, nexcl):
|
| 168 | cdef void _Sh_rest(
|
| 169 | double[:,:,:] hc_ss, double[:,:,] hc_bg, double[:] freqs, long nexcl,
|
| 170 | long nreals, long nfreqs, long nloudest,
|
| 171 | - double[:,:,:] Sh_rest):
|
| 172 | + double[:,:,:] Sh_rest) noexcept:
|
| 173 | """
|
| 174 | Calculate the noise from all the single sources except the source in question
|
| 175 | and the next N_excl loudest sources.
|
| 176 | diff --git a/holodeck/sams/sam_cyutils.pyx b/holodeck/sams/sam_cyutils.pyx
|
| 177 | index ed411270..1a36a9ea 100644
|
| 178 | |
| 179 | |
| 180 | @@ -50,20 +50,20 @@ cpdef double hard_gw(double mtot, double mrat, double sepa):
|
| 181 |
|
| 182 |
|
| 183 | @cython.cdivision(True)
|
| 184 | -cdef double kepler_freq_from_sepa(double mtot, double sepa):
|
| 185 | +cdef double kepler_freq_from_sepa(double mtot, double sepa) noexcept:
|
| 186 | cdef double freq = KEPLER_CONST_FREQ * sqrt(mtot) / pow(sepa, 1.5)
|
| 187 | return freq
|
| 188 |
|
| 189 |
|
| 190 | @cython.cdivision(True)
|
| 191 | -cdef double kepler_sepa_from_freq(double mtot, double freq):
|
| 192 | +cdef double kepler_sepa_from_freq(double mtot, double freq) noexcept:
|
| 193 | cdef double sepa = KEPLER_CONST_SEPA * pow(mtot, 1.0/3.0) / pow(freq, 2.0/3.0)
|
| 194 | return sepa
|
| 195 |
|
| 196 |
|
| 197 | @cython.boundscheck(False)
|
| 198 | @cython.wraparound(False)
|
| 199 | -cdef int while_while_increasing(int start, int size, double val, double[:] edges):
|
| 200 | +cdef int while_while_increasing(int start, int size, double val, double[:] edges) noexcept:
|
| 201 | """Step through an INCREASING array of `edges`, first forward, then backward, to find edges bounding `val`.
|
| 202 |
|
| 203 | Use this function when `start` is already a close guess, and we just need to update a bit.
|
| 204 | @@ -86,7 +86,7 @@ cdef int while_while_increasing(int start, int size, double val, double[:] edges
|
| 205 |
|
| 206 | @cython.boundscheck(False)
|
| 207 | @cython.wraparound(False)
|
| 208 | -cdef int while_while_decreasing(int start, int size, double val, double[:] edges):
|
| 209 | +cdef int while_while_decreasing(int start, int size, double val, double[:] edges) noexcept:
|
| 210 | """Step through a DECREASING array of `edges`, first forward, then backward, to find edges bounding `val`.
|
| 211 |
|
| 212 | Use this function when `start` is already a close guess, and we just need to update a bit.
|
| 213 | @@ -175,7 +175,7 @@ cdef void _integrate_differential_number_3dx1d(
|
| 214 | double[:, :, :, :] dnum,
|
| 215 | # output
|
| 216 | double[:, :, :, :] numb
|
| 217 | -):
|
| 218 | +) noexcept:
|
| 219 | """Integrate the differential number of binaries over each grid bin into total numbers of binaries.
|
| 220 |
|
| 221 | Trapezoid used over first 3 dims (mtot, mrat, redz), and Riemann over 4th (freq).
|
| 222 | @@ -238,7 +238,7 @@ cdef void _integrate_differential_number_3dx1d(
|
| 223 |
|
| 224 |
|
| 225 | @cython.cdivision(True)
|
| 226 | -cdef double _hard_func_2pwl(double norm, double xx, double gamma_inner, double gamma_outer):
|
| 227 | +cdef double _hard_func_2pwl(double norm, double xx, double gamma_inner, double gamma_outer) noexcept:
|
| 228 | cdef double dadt = - norm * pow(1.0 + xx, -gamma_outer+gamma_inner) / pow(xx, gamma_inner-1)
|
| 229 | return dadt
|
| 230 |
|
| 231 | @@ -247,7 +247,7 @@ cdef double _hard_func_2pwl(double norm, double xx, double gamma_inner, double g
|
| 232 | cdef double _hard_func_2pwl_gw(
|
| 233 | double mtot, double mrat, double sepa,
|
| 234 | double norm, double rchar, double gamma_inner, double gamma_outer
|
| 235 | -):
|
| 236 | +) noexcept:
|
| 237 | cdef double dadt = _hard_func_2pwl(norm, sepa/rchar, gamma_inner, gamma_outer)
|
| 238 | dadt += hard_gw(mtot, mrat, sepa)
|
| 239 | return dadt
|
| 240 | @@ -327,7 +327,7 @@ cdef void _get_hardening_norm_2pwl(
|
| 241 | lifetime_2pwl_params args,
|
| 242 | # output
|
| 243 | double[:] norm_log10,
|
| 244 | -):
|
| 245 | +) noexcept:
|
| 246 |
|
| 247 | cdef double XTOL = 1e-3
|
| 248 | cdef double RTOL = 1e-5
|
| 249 | diff --git a/pyproject.toml b/pyproject.toml
|
| 250 | index ce2b0a69..9158a019 100644
|
| 251 | |
| 252 | |
| 253 | @@ -1,6 +1,6 @@
|
| 254 | [build-system]
|
| 255 | # cython/numpy/scipy are required to build cython extensions. The build steps are specified in `setup.py`
|
| 256 | -requires = ["setuptools >= 40.6.0", "wheel", "Cython<3.0.0", "numpy", "scipy"]
|
| 257 | +requires = ["setuptools >= 40.6.0", "wheel", "Cython>=3.0.0", "numpy>=1.26", "scipy"]
|
| 258 | build-backend = "setuptools.build_meta"
|
| 259 |
|
| 260 | [tool.mypy]
|
| 261 | @@ -40,4 +40,4 @@ select = [
|
| 262 | ]
|
| 263 |
|
| 264 | [tool.ruff.mccabe]
|
| 265 | -max-complexity = 15
|
| 266 | \ No newline at end of file
|
| 267 | +max-complexity = 15
|
| 268 | diff --git a/requirements.txt b/requirements.txt
|
| 269 | index 0ab402e5..171d10fc 100644
|
| 270 | |
| 271 | |
| 272 | @@ -4,12 +4,12 @@ h5py
|
| 273 | ipywidgets # required for tqdm to work (at the moment, looks like a bug)
|
| 274 | kalepy
|
| 275 | matplotlib
|
| 276 | -numpy
|
| 277 | +numpy>=1.26
|
| 278 | scipy
|
| 279 | # pydoe
|
| 280 | psutil
|
| 281 | tqdm
|
| 282 | -cython<3.0.0
|
| 283 | +cython>=3.0.0
|
| 284 | # schwimmbad # used in the `gps` submodule
|
| 285 | # emcee # used in the `gps` submodule
|
| 286 | # george # used in the `gps` submodule
|
| 287 |
|
| 288 | From 303a564aa5443ca766463fc5eee0eb5549fd0076 Mon Sep 17 00:00:00 2001
|
| 289 | From: David Wright <[email protected]>
|
| 290 | Date: Wed, 19 Nov 2025 14:19:42 -0800
|
| 291 | Subject: [PATCH 2/2] ci: update CI/CD to include Python 3.13
|
| 292 |
|
| 293 | ---
|
| 294 | .github/workflows/publish_to_pypi.yaml | 4 ++--
|
| 295 | .github/workflows/unit-tests-ci.yaml | 2 +-
|
| 296 | tox.ini | 1 +
|
| 297 | 3 files changed, 4 insertions(+), 3 deletions(-)
|
| 298 |
|
| 299 | diff --git a/.github/workflows/publish_to_pypi.yaml b/.github/workflows/publish_to_pypi.yaml
|
| 300 | index 04e74904..e1fcc13d 100644
|
| 301 | |
| 302 | |
| 303 | @@ -21,8 +21,8 @@ jobs:
|
| 304 | - name: Build wheels
|
| 305 | uses: pypa/[email protected]
|
| 306 | env:
|
| 307 | - # Skip CPython 3.6, 3.7, 3.8, 3.12, PyPy, 32-bit, and musl
|
| 308 | - CIBW_SKIP: "cp36-* cp37-* cp38-* cp312-* pp* *i686 *musllinux*"
|
| 309 | + # Skip CPython 3.6, 3.7, 3.8, 3.12, 3.13, PyPy, 32-bit, and musl
|
| 310 | + CIBW_SKIP: "cp36-* cp37-* cp38-* cp312-* cp313-* pp* *i686 *musllinux*"
|
| 311 |
|
| 312 | - uses: actions/upload-artifact@v3
|
| 313 | with:
|
| 314 | diff --git a/.github/workflows/unit-tests-ci.yaml b/.github/workflows/unit-tests-ci.yaml
|
| 315 | index 79aa4057..39793f49 100644
|
| 316 | |
| 317 | |
| 318 | @@ -17,7 +17,7 @@ jobs:
|
| 319 | strategy:
|
| 320 | matrix:
|
| 321 | os: [ubuntu-latest, macOS-latest]
|
| 322 | - python-version: ['3.9', '3.10', '3.11', '3.12']
|
| 323 | + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
|
| 324 | # mpi: [ 'mpich', 'openmpi', 'intelmpi']
|
| 325 | # mpi: ['openmpi']
|
| 326 |
|
| 327 | diff --git a/tox.ini b/tox.ini
|
| 328 | index 741c5327..a1ee38f3 100644
|
| 329 | |
| 330 | |
| 331 | @@ -24,6 +24,7 @@ envlist =
|
| 332 | py310
|
| 333 | py311
|
| 334 | py312
|
| 335 | + py313
|
| 336 |
|
| 337 | [testenv]
|
| 338 | allowlist_externals =
|