Generated by Cython 0.29.35

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

Raw output: sam_cython.c

+001: """
  __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 002: 
 003: $ python setup.py build_ext -i
 004: 
 005: $ python setup.py develop
 006: 
 007: """
 008: 
 009: import cython
+010: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 10, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 10, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 011: cimport numpy as np
+012: np.import_array()
  __pyx_t_2 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 12, __pyx_L1_error)
 013: 
 014: from scipy.optimize.cython_optimize cimport brentq
 015: 
 016: from libc.stdio cimport printf, fflush, stdout
 017: from libc.stdlib cimport malloc, free
 018: # make sure to use c-native math functions instead of python/numpy
 019: from libc.math cimport pow, sqrt, M_PI, NAN, log10, sin, cos
 020: 
+021: import holodeck as holo
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_holodeck, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_holo, __pyx_t_1) < 0) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 022: from holodeck.cyutils cimport interp_at_index, _interp_between_vals
 023: 
 024: 
 025: # ---- Define Parameters
 026: 
 027: 
 028: # ---- Define Constants
 029: 
+030: cdef double MY_NWTG = 6.6742999e-08
  __pyx_v_8holodeck_10sam_cython_MY_NWTG = 6.6742999e-08;
+031: cdef double MY_SPLC = 29979245800.0
  __pyx_v_8holodeck_10sam_cython_MY_SPLC = 29979245800.0;
+032: cdef double MY_MPC = 3.08567758e+24
  __pyx_v_8holodeck_10sam_cython_MY_MPC = 3.08567758e+24;
+033: cdef double MY_MSOL = 1.988409870698051e+33
  __pyx_v_8holodeck_10sam_cython_MY_MSOL = 1.988409870698051e+33;
+034: cdef double MY_YR = 31557600.0
  __pyx_v_8holodeck_10sam_cython_MY_YR = 31557600.0;
+035: cdef double MY_SCHW = 1.4852320538237328e-28     #: Schwarzschild Constant  2*G/c^2  [cm]
  __pyx_v_8holodeck_10sam_cython_MY_SCHW = 1.4852320538237328e-28;
+036: cdef double GW_DADT_SEP_CONST = - 64.0 * pow(MY_NWTG, 3) / 5.0 / pow(MY_SPLC, 5)
  __pyx_t_3 = ((-64.0 * pow(__pyx_v_8holodeck_10sam_cython_MY_NWTG, 3.0)) / 5.0);
  __pyx_t_4 = pow(__pyx_v_8holodeck_10sam_cython_MY_SPLC, 5.0);
  if (unlikely(__pyx_t_4 == 0)) {
    PyErr_SetString(PyExc_ZeroDivisionError, "float division");
    __PYX_ERR(0, 36, __pyx_L1_error)
  }
  __pyx_v_8holodeck_10sam_cython_GW_DADT_SEP_CONST = (__pyx_t_3 / __pyx_t_4);
 037: 
+038: cdef double MY_PC = MY_MPC / 1.0e6
  __pyx_v_8holodeck_10sam_cython_MY_PC = (__pyx_v_8holodeck_10sam_cython_MY_MPC / 1.0e6);
+039: cdef double MY_GYR = MY_YR * 1.0e9
  __pyx_v_8holodeck_10sam_cython_MY_GYR = (__pyx_v_8holodeck_10sam_cython_MY_YR * 1.0e9);
+040: cdef double KEPLER_CONST_FREQ = (1.0 / (2.0*M_PI)) * sqrt(MY_NWTG)
  __pyx_t_4 = (2.0 * M_PI);
  if (unlikely(__pyx_t_4 == 0)) {
    PyErr_SetString(PyExc_ZeroDivisionError, "float division");
    __PYX_ERR(0, 40, __pyx_L1_error)
  }
  __pyx_v_8holodeck_10sam_cython_KEPLER_CONST_FREQ = ((1.0 / __pyx_t_4) * sqrt(__pyx_v_8holodeck_10sam_cython_MY_NWTG));
+041: cdef double KEPLER_CONST_SEPA = pow(MY_NWTG, 1.0/3.0) / pow(2.0*M_PI, 2.0/3.0)
  __pyx_t_4 = pow(__pyx_v_8holodeck_10sam_cython_MY_NWTG, (1.0 / 3.0));
  __pyx_t_3 = pow((2.0 * M_PI), (2.0 / 3.0));
  if (unlikely(__pyx_t_3 == 0)) {
    PyErr_SetString(PyExc_ZeroDivisionError, "float division");
    __PYX_ERR(0, 41, __pyx_L1_error)
  }
  __pyx_v_8holodeck_10sam_cython_KEPLER_CONST_SEPA = (__pyx_t_4 / __pyx_t_3);
+042: cdef double FOUR_PI_SPLC_OVER_MPC = 4 * M_PI * MY_SPLC / MY_MPC
  __pyx_t_3 = ((4.0 * M_PI) * __pyx_v_8holodeck_10sam_cython_MY_SPLC);
  if (unlikely(__pyx_v_8holodeck_10sam_cython_MY_MPC == 0)) {
    PyErr_SetString(PyExc_ZeroDivisionError, "float division");
    __PYX_ERR(0, 42, __pyx_L1_error)
  }
  __pyx_v_8holodeck_10sam_cython_FOUR_PI_SPLC_OVER_MPC = (__pyx_t_3 / __pyx_v_8holodeck_10sam_cython_MY_MPC);
 043: 
 044: 
 045: @cython.cdivision(True)
+046: cpdef double hard_gw(double mtot, double mrat, double sepa):
static PyObject *__pyx_pw_8holodeck_10sam_cython_1hard_gw(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static double __pyx_f_8holodeck_10sam_cython_hard_gw(double __pyx_v_mtot, double __pyx_v_mrat, double __pyx_v_sepa, CYTHON_UNUSED int __pyx_skip_dispatch) {
  double __pyx_v_dadt;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("hard_gw", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_1hard_gw(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyObject *__pyx_pw_8holodeck_10sam_cython_1hard_gw(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  double __pyx_v_mtot;
  double __pyx_v_mrat;
  double __pyx_v_sepa;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("hard_gw (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_mtot,&__pyx_n_s_mrat,&__pyx_n_s_sepa,0};
    PyObject* values[3] = {0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mtot)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mrat)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_gw", 1, 3, 3, 1); __PYX_ERR(0, 46, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sepa)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_gw", 1, 3, 3, 2); __PYX_ERR(0, 46, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "hard_gw") < 0)) __PYX_ERR(0, 46, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
    }
    __pyx_v_mtot = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_mtot == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error)
    __pyx_v_mrat = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_mrat == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error)
    __pyx_v_sepa = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_sepa == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error)
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("hard_gw", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 46, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.hard_gw", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_hard_gw(__pyx_self, __pyx_v_mtot, __pyx_v_mrat, __pyx_v_sepa);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_hard_gw(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_mtot, double __pyx_v_mrat, double __pyx_v_sepa) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("hard_gw", 0);
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = PyFloat_FromDouble(__pyx_f_8holodeck_10sam_cython_hard_gw(__pyx_v_mtot, __pyx_v_mrat, __pyx_v_sepa, 0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 46, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("holodeck.sam_cython.hard_gw", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 047: # cdef double hard_gw(double mtot, double mrat, double sepa):
+048:     cdef double dadt = GW_DADT_SEP_CONST * pow(mtot, 3) * mrat / pow(sepa, 3) / pow(1 + mrat, 2)
  __pyx_v_dadt = ((((__pyx_v_8holodeck_10sam_cython_GW_DADT_SEP_CONST * pow(__pyx_v_mtot, 3.0)) * __pyx_v_mrat) / pow(__pyx_v_sepa, 3.0)) / pow((1.0 + __pyx_v_mrat), 2.0));
+049:     return dadt
  __pyx_r = __pyx_v_dadt;
  goto __pyx_L0;
 050: 
 051: 
 052: @cython.cdivision(True)
+053: cdef double kepler_freq_from_sepa(double mtot, double sepa):
static double __pyx_f_8holodeck_10sam_cython_kepler_freq_from_sepa(double __pyx_v_mtot, double __pyx_v_sepa) {
  double __pyx_v_freq;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("kepler_freq_from_sepa", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+054:     cdef double freq = KEPLER_CONST_FREQ * sqrt(mtot) / pow(sepa, 1.5)
  __pyx_v_freq = ((__pyx_v_8holodeck_10sam_cython_KEPLER_CONST_FREQ * sqrt(__pyx_v_mtot)) / pow(__pyx_v_sepa, 1.5));
+055:     return freq
  __pyx_r = __pyx_v_freq;
  goto __pyx_L0;
 056: 
 057: 
 058: @cython.cdivision(True)
+059: cdef double kepler_sepa_from_freq(double mtot, double freq):
static double __pyx_f_8holodeck_10sam_cython_kepler_sepa_from_freq(double __pyx_v_mtot, double __pyx_v_freq) {
  double __pyx_v_sepa;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("kepler_sepa_from_freq", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+060:     cdef double sepa = KEPLER_CONST_SEPA * pow(mtot, 1.0/3.0) / pow(freq, 2.0/3.0)
  __pyx_v_sepa = ((__pyx_v_8holodeck_10sam_cython_KEPLER_CONST_SEPA * pow(__pyx_v_mtot, (1.0 / 3.0))) / pow(__pyx_v_freq, (2.0 / 3.0)));
+061:     return sepa
  __pyx_r = __pyx_v_sepa;
  goto __pyx_L0;
 062: 
 063: 
 064: @cython.boundscheck(False)
 065: @cython.wraparound(False)
+066: cdef int while_while_increasing(int start, int size, double val, double[:] edges):
static int __pyx_f_8holodeck_10sam_cython_while_while_increasing(int __pyx_v_start, int __pyx_v_size, double __pyx_v_val, __Pyx_memviewslice __pyx_v_edges) {
  int __pyx_v_index;
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("while_while_increasing", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 067:     """Step through an INCREASING array of `edges`, first forward, then backward, to find edges bounding `val`.
 068: 
 069:     Use this function when `start` is already a close guess, and we just need to update a bit.
 070: 
 071:     """
 072: 
+073:     cdef int index = start    #: index corresponding to the LEFT side of the edges bounding `val`
  __pyx_v_index = __pyx_v_start;
 074: 
 075:     # `index < size-2` so that the result is always within the edges array
 076:     # `edges[index+1] < val` to get the RIGHT-edge to be MORE than `val`
+077:     while (index < size - 2) and (edges[index+1] < val):
  while (1) {
    __pyx_t_2 = ((__pyx_v_index < (__pyx_v_size - 2)) != 0);
    if (__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L5_bool_binop_done;
    }
    __pyx_t_3 = (__pyx_v_index + 1);
    __pyx_t_2 = (((*((double *) ( /* dim=0 */ (__pyx_v_edges.data + __pyx_t_3 * __pyx_v_edges.strides[0]) ))) < __pyx_v_val) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L5_bool_binop_done:;
    if (!__pyx_t_1) break;
+078:         index += 1
    __pyx_v_index = (__pyx_v_index + 1);
  }
 079: 
 080:     # `edges[index] > val` to get the LEFT-edge to be LESS than `val`
+081:     while (index > 0) and (edges[index] > val):
  while (1) {
    __pyx_t_2 = ((__pyx_v_index > 0) != 0);
    if (__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L9_bool_binop_done;
    }
    __pyx_t_3 = __pyx_v_index;
    __pyx_t_2 = (((*((double *) ( /* dim=0 */ (__pyx_v_edges.data + __pyx_t_3 * __pyx_v_edges.strides[0]) ))) > __pyx_v_val) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L9_bool_binop_done:;
    if (!__pyx_t_1) break;
+082:         index -= 1
    __pyx_v_index = (__pyx_v_index - 1);
  }
 083: 
+084:     return index
  __pyx_r = __pyx_v_index;
  goto __pyx_L0;
 085: 
 086: 
 087: @cython.boundscheck(False)
 088: @cython.wraparound(False)
+089: cdef int while_while_decreasing(int start, int size, double val, double[:] edges):
static int __pyx_f_8holodeck_10sam_cython_while_while_decreasing(int __pyx_v_start, int __pyx_v_size, double __pyx_v_val, __Pyx_memviewslice __pyx_v_edges) {
  int __pyx_v_index;
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("while_while_decreasing", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 090:     """Step through a DECREASING array of `edges`, first forward, then backward, to find edges bounding `val`.
 091: 
 092:     Use this function when `start` is already a close guess, and we just need to update a bit.
 093: 
 094:     """
 095: 
+096:     cdef int index = start    #: index corresponding to the LEFT side of the edges bounding `val`
  __pyx_v_index = __pyx_v_start;
 097: 
 098:     # `index < size-1` so that the result is always within the edges array
 099:     # `edges[index+1] > val` to get the RIGHT-edge to be LESS than `val`
+100:     while (index < size - 1) and (edges[index+1] > val):
  while (1) {
    __pyx_t_2 = ((__pyx_v_index < (__pyx_v_size - 1)) != 0);
    if (__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L5_bool_binop_done;
    }
    __pyx_t_3 = (__pyx_v_index + 1);
    __pyx_t_2 = (((*((double *) ( /* dim=0 */ (__pyx_v_edges.data + __pyx_t_3 * __pyx_v_edges.strides[0]) ))) > __pyx_v_val) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L5_bool_binop_done:;
    if (!__pyx_t_1) break;
+101:         index += 1
    __pyx_v_index = (__pyx_v_index + 1);
  }
 102: 
 103:     # `edges[index-1] < val` to get the LEFT-edge to be MORE than `val`
+104:     while (index > 0) and (edges[index-1] < val):
  while (1) {
    __pyx_t_2 = ((__pyx_v_index > 0) != 0);
    if (__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L9_bool_binop_done;
    }
    __pyx_t_3 = (__pyx_v_index - 1);
    __pyx_t_2 = (((*((double *) ( /* dim=0 */ (__pyx_v_edges.data + __pyx_t_3 * __pyx_v_edges.strides[0]) ))) < __pyx_v_val) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L9_bool_binop_done:;
    if (!__pyx_t_1) break;
+105:         index -= 1
    __pyx_v_index = (__pyx_v_index - 1);
  }
 106: 
+107:     return index
  __pyx_r = __pyx_v_index;
  goto __pyx_L0;
 108: 
 109: 
 110: # ==================================================================================================
 111: # ====    Integrate Bins from differential-parameter-volume to total numbers   ====
 112: # ==================================================================================================
 113: 
 114: 
+115: def integrate_differential_number_3dx1d(edges, dnum):
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_3integrate_differential_number_3dx1d(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_8holodeck_10sam_cython_2integrate_differential_number_3dx1d[] = "Integrate the differential number of binaries over each grid bin into total numbers of binaries.\n\n    Trapezoid used over first 3 dims (mtot, mrat, redz), and Riemann over 4th (freq).\n    (Riemann seemed empirically to be more accurate for freq, but this should be revisited.)\n    mtot is integrated over `log10(mtot)` and frequency is integrated over `ln(f)`.\n\n    Note on array shapes:\n    input  `dnum` is shaped (M, Q, Z, F)\n    input  `edges` must be (4,) of array_like of lengths:  M, Q, Z, F+1\n    output `numb` is shaped (M-1, Q-1, Z-1, F)\n\n    Arguments\n    ---------\n    edges : (4,) array_like  w/ lengths M, Q, Z, F+1\n        Grid edges of `mtot`, `mrat`, `redz`, and `freq`\n        NOTE: `mtot` should be passed as regular `mtot`, NOT log10(mtot)\n              `freq` should be passed as regular `freq`, NOT    ln(freq)\n    dnum : (M, Q, Z, F)\n        Differential number of binaries, dN/[dlog10M dq qz dlnf] where 'N' is in units of dimensionless number.\n\n    Returns\n    -------\n    numb : (M-1, Q-1, Z-1, F)\n\n    ";
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_3integrate_differential_number_3dx1d = {"integrate_differential_number_3dx1d", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_3integrate_differential_number_3dx1d, METH_VARARGS|METH_KEYWORDS, __pyx_doc_8holodeck_10sam_cython_2integrate_differential_number_3dx1d};
static PyObject *__pyx_pw_8holodeck_10sam_cython_3integrate_differential_number_3dx1d(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_edges = 0;
  PyObject *__pyx_v_dnum = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_differential_number_3dx1d (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_edges,&__pyx_n_s_dnum,0};
    PyObject* values[2] = {0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_edges)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dnum)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_differential_number_3dx1d", 1, 2, 2, 1); __PYX_ERR(0, 115, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "integrate_differential_number_3dx1d") < 0)) __PYX_ERR(0, 115, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
    }
    __pyx_v_edges = values[0];
    __pyx_v_dnum = values[1];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("integrate_differential_number_3dx1d", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 115, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.integrate_differential_number_3dx1d", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_2integrate_differential_number_3dx1d(__pyx_self, __pyx_v_edges, __pyx_v_dnum);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_2integrate_differential_number_3dx1d(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_edges, PyObject *__pyx_v_dnum) {
  PyObject *__pyx_v_shape = NULL;
  PyObject *__pyx_v_new_shape = NULL;
  PyArrayObject *__pyx_v_numb = 0;
  PyObject *__pyx_v_ee = NULL;
  PyObject *__pyx_7genexpr__pyx_v_ee = NULL;
  PyObject *__pyx_8genexpr1__pyx_v_sh = NULL;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_numb;
  __Pyx_Buffer __pyx_pybuffer_numb;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_differential_number_3dx1d", 0);
  __pyx_pybuffer_numb.pybuffer.buf = NULL;
  __pyx_pybuffer_numb.refcount = 0;
  __pyx_pybuffernd_numb.data = NULL;
  __pyx_pybuffernd_numb.rcbuffer = &__pyx_pybuffer_numb;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_XDECREF(__pyx_t_10);
  __Pyx_XDECREF(__pyx_t_11);
  __Pyx_XDECREF(__pyx_t_12);
  __Pyx_XDECREF(__pyx_t_13);
  __Pyx_XDECREF(__pyx_t_14);
  __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_20, 1);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_numb.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("holodeck.sam_cython.integrate_differential_number_3dx1d", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_numb.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF(__pyx_v_shape);
  __Pyx_XDECREF(__pyx_v_new_shape);
  __Pyx_XDECREF((PyObject *)__pyx_v_numb);
  __Pyx_XDECREF(__pyx_v_ee);
  __Pyx_XDECREF(__pyx_7genexpr__pyx_v_ee);
  __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_sh);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__23 = PyTuple_Pack(8, __pyx_n_s_edges, __pyx_n_s_dnum, __pyx_n_s_shape, __pyx_n_s_new_shape, __pyx_n_s_numb, __pyx_n_s_ee, __pyx_n_s_ee, __pyx_n_s_sh); if (unlikely(!__pyx_tuple__23)) __PYX_ERR(0, 115, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__23);
  __Pyx_GIVEREF(__pyx_tuple__23);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_3integrate_differential_number_3dx1d, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 115, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_integrate_differential_number_3d, __pyx_t_1) < 0) __PYX_ERR(0, 115, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__24 = (PyObject*)__Pyx_PyCode_New(2, 0, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__23, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_integrate_differential_number_3d, 115, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__24)) __PYX_ERR(0, 115, __pyx_L1_error)
 116:     """Integrate the differential number of binaries over each grid bin into total numbers of binaries.
 117: 
 118:     Trapezoid used over first 3 dims (mtot, mrat, redz), and Riemann over 4th (freq).
 119:     (Riemann seemed empirically to be more accurate for freq, but this should be revisited.)
 120:     mtot is integrated over `log10(mtot)` and frequency is integrated over `ln(f)`.
 121: 
 122:     Note on array shapes:
 123:     input  `dnum` is shaped (M, Q, Z, F)
 124:     input  `edges` must be (4,) of array_like of lengths:  M, Q, Z, F+1
 125:     output `numb` is shaped (M-1, Q-1, Z-1, F)
 126: 
 127:     Arguments
 128:     ---------
 129:     edges : (4,) array_like  w/ lengths M, Q, Z, F+1
 130:         Grid edges of `mtot`, `mrat`, `redz`, and `freq`
 131:         NOTE: `mtot` should be passed as regular `mtot`, NOT log10(mtot)
 132:               `freq` should be passed as regular `freq`, NOT    ln(freq)
 133:     dnum : (M, Q, Z, F)
 134:         Differential number of binaries, dN/[dlog10M dq qz dlnf] where 'N' is in units of dimensionless number.
 135: 
 136:     Returns
 137:     -------
 138:     numb : (M-1, Q-1, Z-1, F)
 139: 
 140:     """
 141: 
 142:     # each edge should have the same length as the corresponding dimension of `dnum`
+143:     shape = [len(ee) for ee in edges]
  { /* enter inner scope */
    __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 143, __pyx_L5_error)
    __Pyx_GOTREF(__pyx_t_1);
    if (likely(PyList_CheckExact(__pyx_v_edges)) || PyTuple_CheckExact(__pyx_v_edges)) {
      __pyx_t_2 = __pyx_v_edges; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0;
      __pyx_t_4 = NULL;
    } else {
      __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_edges); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 143, __pyx_L5_error)
      __Pyx_GOTREF(__pyx_t_2);
      __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L5_error)
    }
    for (;;) {
      if (likely(!__pyx_t_4)) {
        if (likely(PyList_CheckExact(__pyx_t_2))) {
          if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_5 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 143, __pyx_L5_error)
          #else
          __pyx_t_5 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 143, __pyx_L5_error)
          __Pyx_GOTREF(__pyx_t_5);
          #endif
        } else {
          if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 143, __pyx_L5_error)
          #else
          __pyx_t_5 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 143, __pyx_L5_error)
          __Pyx_GOTREF(__pyx_t_5);
          #endif
        }
      } else {
        __pyx_t_5 = __pyx_t_4(__pyx_t_2);
        if (unlikely(!__pyx_t_5)) {
          PyObject* exc_type = PyErr_Occurred();
          if (exc_type) {
            if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
            else __PYX_ERR(0, 143, __pyx_L5_error)
          }
          break;
        }
        __Pyx_GOTREF(__pyx_t_5);
      }
      __Pyx_XDECREF_SET(__pyx_7genexpr__pyx_v_ee, __pyx_t_5);
      __pyx_t_5 = 0;
      __pyx_t_6 = PyObject_Length(__pyx_7genexpr__pyx_v_ee); if (unlikely(__pyx_t_6 == ((Py_ssize_t)-1))) __PYX_ERR(0, 143, __pyx_L5_error)
      __pyx_t_5 = PyInt_FromSsize_t(__pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 143, __pyx_L5_error)
      __Pyx_GOTREF(__pyx_t_5);
      if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(0, 143, __pyx_L5_error)
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    }
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_XDECREF(__pyx_7genexpr__pyx_v_ee); __pyx_7genexpr__pyx_v_ee = 0;
    goto __pyx_L8_exit_scope;
    __pyx_L5_error:;
    __Pyx_XDECREF(__pyx_7genexpr__pyx_v_ee); __pyx_7genexpr__pyx_v_ee = 0;
    goto __pyx_L1_error;
    __pyx_L8_exit_scope:;
  } /* exit inner scope */
  __pyx_v_shape = ((PyObject*)__pyx_t_1);
  __pyx_t_1 = 0;
 144:     # except the last edge (freq), where `dnum` should be 1-shorter
+145:     shape[-1] -= 1
  __pyx_t_3 = -1L;
  __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_shape, __pyx_t_3, Py_ssize_t, 1, PyInt_FromSsize_t, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 145, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyInt_SubtractObjC(__pyx_t_1, __pyx_int_1, 1, 1, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 145, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (unlikely(__Pyx_SetItemInt(__pyx_v_shape, __pyx_t_3, __pyx_t_2, Py_ssize_t, 1, PyInt_FromSsize_t, 1, 1, 1) < 0)) __PYX_ERR(0, 145, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+146:     assert np.shape(dnum) == tuple(shape)
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 146, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 146, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_5);
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __pyx_t_1 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
      __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_5);
      if (likely(__pyx_t_1)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
        __Pyx_INCREF(__pyx_t_1);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_5, function);
      }
    }
    __pyx_t_2 = (__pyx_t_1) ? __Pyx_PyObject_Call2Args(__pyx_t_5, __pyx_t_1, __pyx_v_dnum) : __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_dnum);
    __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 146, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __pyx_t_5 = PyList_AsTuple(__pyx_v_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 146, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_5);
    __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 146, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 146, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    if (unlikely(!__pyx_t_7)) {
      PyErr_SetNone(PyExc_AssertionError);
      __PYX_ERR(0, 146, __pyx_L1_error)
    }
  }
  #endif
 147:     # the number will be shaped as one-less the size of each dimension of `dnum`
+148:     new_shape = [sh-1 for sh in dnum.shape]
  { /* enter inner scope */
    __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 148, __pyx_L11_error)
    __Pyx_GOTREF(__pyx_t_1);
    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_dnum, __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 148, __pyx_L11_error)
    __Pyx_GOTREF(__pyx_t_5);
    if (likely(PyList_CheckExact(__pyx_t_5)) || PyTuple_CheckExact(__pyx_t_5)) {
      __pyx_t_2 = __pyx_t_5; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0;
      __pyx_t_4 = NULL;
    } else {
      __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 148, __pyx_L11_error)
      __Pyx_GOTREF(__pyx_t_2);
      __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 148, __pyx_L11_error)
    }
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    for (;;) {
      if (likely(!__pyx_t_4)) {
        if (likely(PyList_CheckExact(__pyx_t_2))) {
          if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_5 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 148, __pyx_L11_error)
          #else
          __pyx_t_5 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 148, __pyx_L11_error)
          __Pyx_GOTREF(__pyx_t_5);
          #endif
        } else {
          if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 148, __pyx_L11_error)
          #else
          __pyx_t_5 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 148, __pyx_L11_error)
          __Pyx_GOTREF(__pyx_t_5);
          #endif
        }
      } else {
        __pyx_t_5 = __pyx_t_4(__pyx_t_2);
        if (unlikely(!__pyx_t_5)) {
          PyObject* exc_type = PyErr_Occurred();
          if (exc_type) {
            if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
            else __PYX_ERR(0, 148, __pyx_L11_error)
          }
          break;
        }
        __Pyx_GOTREF(__pyx_t_5);
      }
      __Pyx_XDECREF_SET(__pyx_8genexpr1__pyx_v_sh, __pyx_t_5);
      __pyx_t_5 = 0;
      __pyx_t_5 = __Pyx_PyInt_SubtractObjC(__pyx_8genexpr1__pyx_v_sh, __pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 148, __pyx_L11_error)
      __Pyx_GOTREF(__pyx_t_5);
      if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(0, 148, __pyx_L11_error)
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    }
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_sh); __pyx_8genexpr1__pyx_v_sh = 0;
    goto __pyx_L14_exit_scope;
    __pyx_L11_error:;
    __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_sh); __pyx_8genexpr1__pyx_v_sh = 0;
    goto __pyx_L1_error;
    __pyx_L14_exit_scope:;
  } /* exit inner scope */
  __pyx_v_new_shape = ((PyObject*)__pyx_t_1);
  __pyx_t_1 = 0;
 149:     # except for the last dimension (freq) which is the same shape
+150:     new_shape[-1] = dnum.shape[-1]
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_dnum, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 150, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, -1L, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 150, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (unlikely(__Pyx_SetItemInt(__pyx_v_new_shape, -1L, __pyx_t_2, long, 1, __Pyx_PyInt_From_long, 1, 1, 1) < 0)) __PYX_ERR(0, 150, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 151: 
 152:     # prepare output array
+153:     cdef np.ndarray[np.double_t, ndim=4] numb = np.zeros(new_shape)
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 153, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_zeros); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 153, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
    __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_5);
    if (likely(__pyx_t_1)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
      __Pyx_INCREF(__pyx_t_1);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_5, function);
    }
  }
  __pyx_t_2 = (__pyx_t_1) ? __Pyx_PyObject_Call2Args(__pyx_t_5, __pyx_t_1, __pyx_v_new_shape) : __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_new_shape);
  __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 153, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 153, __pyx_L1_error)
  __pyx_t_8 = ((PyArrayObject *)__pyx_t_2);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_numb.rcbuffer->pybuffer, (PyObject*)__pyx_t_8, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 4, 0, __pyx_stack) == -1)) {
      __pyx_v_numb = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_numb.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 153, __pyx_L1_error)
    } else {__pyx_pybuffernd_numb.diminfo[0].strides = __pyx_pybuffernd_numb.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_numb.diminfo[0].shape = __pyx_pybuffernd_numb.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_numb.diminfo[1].strides = __pyx_pybuffernd_numb.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_numb.diminfo[1].shape = __pyx_pybuffernd_numb.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_numb.diminfo[2].strides = __pyx_pybuffernd_numb.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_numb.diminfo[2].shape = __pyx_pybuffernd_numb.rcbuffer->pybuffer.shape[2]; __pyx_pybuffernd_numb.diminfo[3].strides = __pyx_pybuffernd_numb.rcbuffer->pybuffer.strides[3]; __pyx_pybuffernd_numb.diminfo[3].shape = __pyx_pybuffernd_numb.rcbuffer->pybuffer.shape[3];
    }
  }
  __pyx_t_8 = 0;
  __pyx_v_numb = ((PyArrayObject *)__pyx_t_2);
  __pyx_t_2 = 0;
 154:     # Convert from  mtot => log10(mtot)  and  freq ==> ln(freq)
+155:     ee = [np.log10(edges[0]), edges[1], edges[2], np.diff(np.log(edges[3]))]
  __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_log10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_edges, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_9 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) {
    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_1);
    if (likely(__pyx_t_9)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
      __Pyx_INCREF(__pyx_t_9);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_1, function);
    }
  }
  __pyx_t_2 = (__pyx_t_9) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_9, __pyx_t_5) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5);
  __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_edges, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_edges, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_n_s_np); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_10);
  __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_diff); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
  __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_n_s_np); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_12);
  __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_n_s_log); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_13);
  __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
  __pyx_t_12 = __Pyx_GetItemInt(__pyx_v_edges, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_12);
  __pyx_t_14 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_13))) {
    __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_13);
    if (likely(__pyx_t_14)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13);
      __Pyx_INCREF(__pyx_t_14);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_13, function);
    }
  }
  __pyx_t_10 = (__pyx_t_14) ? __Pyx_PyObject_Call2Args(__pyx_t_13, __pyx_t_14, __pyx_t_12) : __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_t_12);
  __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0;
  __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
  if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_10);
  __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
  __pyx_t_13 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_11))) {
    __pyx_t_13 = PyMethod_GET_SELF(__pyx_t_11);
    if (likely(__pyx_t_13)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
      __Pyx_INCREF(__pyx_t_13);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_11, function);
    }
  }
  __pyx_t_9 = (__pyx_t_13) ? __Pyx_PyObject_Call2Args(__pyx_t_11, __pyx_t_13, __pyx_t_10) : __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_10);
  __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0;
  __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
  if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_9);
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  __pyx_t_11 = PyList_New(4); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 155, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __Pyx_GIVEREF(__pyx_t_2);
  PyList_SET_ITEM(__pyx_t_11, 0, __pyx_t_2);
  __Pyx_GIVEREF(__pyx_t_1);
  PyList_SET_ITEM(__pyx_t_11, 1, __pyx_t_1);
  __Pyx_GIVEREF(__pyx_t_5);
  PyList_SET_ITEM(__pyx_t_11, 2, __pyx_t_5);
  __Pyx_GIVEREF(__pyx_t_9);
  PyList_SET_ITEM(__pyx_t_11, 3, __pyx_t_9);
  __pyx_t_2 = 0;
  __pyx_t_1 = 0;
  __pyx_t_5 = 0;
  __pyx_t_9 = 0;
  __pyx_v_ee = ((PyObject*)__pyx_t_11);
  __pyx_t_11 = 0;
 156:     # integrate
+157:     _integrate_differential_number_3dx1d(ee[0], ee[1], ee[2], ee[3], dnum, numb)
  __pyx_t_11 = __Pyx_GetItemInt_List(__pyx_v_ee, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __pyx_t_15 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_11, PyBUF_WRITABLE); if (unlikely(!__pyx_t_15.memview)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  __pyx_t_11 = __Pyx_GetItemInt_List(__pyx_v_ee, 1, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __pyx_t_16 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_11, PyBUF_WRITABLE); if (unlikely(!__pyx_t_16.memview)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  __pyx_t_11 = __Pyx_GetItemInt_List(__pyx_v_ee, 2, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __pyx_t_17 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_11, PyBUF_WRITABLE); if (unlikely(!__pyx_t_17.memview)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  __pyx_t_11 = __Pyx_GetItemInt_List(__pyx_v_ee, 3, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __pyx_t_18 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_11, PyBUF_WRITABLE); if (unlikely(!__pyx_t_18.memview)) __PYX_ERR(0, 157, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  __pyx_t_19 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(__pyx_v_dnum, PyBUF_WRITABLE); if (unlikely(!__pyx_t_19.memview)) __PYX_ERR(0, 157, __pyx_L1_error)
  __pyx_t_20 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(((PyObject *)__pyx_v_numb), PyBUF_WRITABLE); if (unlikely(!__pyx_t_20.memview)) __PYX_ERR(0, 157, __pyx_L1_error)
  __pyx_f_8holodeck_10sam_cython__integrate_differential_number_3dx1d(__pyx_t_15, __pyx_t_16, __pyx_t_17, __pyx_t_18, __pyx_t_19, __pyx_t_20);
  __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
  __pyx_t_15.memview = NULL;
  __pyx_t_15.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
  __pyx_t_16.memview = NULL;
  __pyx_t_16.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
  __pyx_t_17.memview = NULL;
  __pyx_t_17.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
  __pyx_t_18.memview = NULL;
  __pyx_t_18.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
  __pyx_t_19.memview = NULL;
  __pyx_t_19.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_20, 1);
  __pyx_t_20.memview = NULL;
  __pyx_t_20.data = NULL;
 158: 
+159:     return numb
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(((PyObject *)__pyx_v_numb));
  __pyx_r = ((PyObject *)__pyx_v_numb);
  goto __pyx_L0;
 160: 
 161: 
 162: @cython.boundscheck(False)
 163: @cython.wraparound(False)
 164: @cython.nonecheck(False)
 165: @cython.cdivision(True)
+166: cdef void _integrate_differential_number_3dx1d(
static void __pyx_f_8holodeck_10sam_cython__integrate_differential_number_3dx1d(__Pyx_memviewslice __pyx_v_log10_mtot, __Pyx_memviewslice __pyx_v_mrat, __Pyx_memviewslice __pyx_v_redz, __Pyx_memviewslice __pyx_v_dln_freq, __Pyx_memviewslice __pyx_v_dnum, __Pyx_memviewslice __pyx_v_numb) {
  int __pyx_v_n_mtot;
  int __pyx_v_n_mrat;
  int __pyx_v_n_redz;
  int __pyx_v_n_freq;
  int __pyx_v_mm;
  int __pyx_v_qq;
  int __pyx_v_zz;
  int __pyx_v_ff;
  int __pyx_v_ii;
  int __pyx_v_jj;
  int __pyx_v_kk;
  double __pyx_v_dm;
  double __pyx_v_dmdq;
  double __pyx_v_dmdqdz;
  PyObject *__pyx_v_temp = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_integrate_differential_number_3dx1d", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_22);
  __Pyx_WriteUnraisable("holodeck.sam_cython._integrate_differential_number_3dx1d", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0);
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_temp);
  __Pyx_RefNannyFinishContext();
}
 167:     double[:] log10_mtot,
 168:     double[:] mrat,
 169:     double[:] redz,
 170:     double[:] dln_freq,    # actually ln(freq)
 171:     double[:, :, :, :] dnum,
 172:     # output
 173:     double[:, :, :, :] numb
 174: ):
 175:     """Integrate the differential number of binaries over each grid bin into total numbers of binaries.
 176: 
 177:     Trapezoid used over first 3 dims (mtot, mrat, redz), and Riemann over 4th (freq).
 178:     See docstrings in `integrate_differential_number_3dx1d`
 179: 
 180:     """
 181: 
+182:     cdef int n_mtot = log10_mtot.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_log10_mtot, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 182, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 182, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 182, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_mtot = __pyx_t_3;
+183:     cdef int n_mrat = mrat.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_mrat, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 183, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 183, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_mrat = __pyx_t_3;
+184:     cdef int n_redz = redz.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_redz, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 184, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 184, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 184, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_redz = __pyx_t_3;
+185:     cdef int n_freq = dln_freq.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_dln_freq, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 185, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 185, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 185, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_freq = __pyx_t_3;
 186: 
 187:     cdef int mm, qq, zz, ff, ii, jj, kk
 188:     cdef double dm, dmdq, dmdqdz
 189: 
+190:     for mm in range(n_mtot-1):                              # iterate over output-shape of mass-grid
  __pyx_t_4 = (__pyx_v_n_mtot - 1);
  __pyx_t_5 = __pyx_t_4;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_5; __pyx_t_3+=1) {
    __pyx_v_mm = __pyx_t_3;
+191:         dm = log10_mtot[mm+1] - log10_mtot[mm]              # get the bin-length
    __pyx_t_6 = (__pyx_v_mm + 1);
    __pyx_t_7 = __pyx_v_mm;
    __pyx_v_dm = ((*((double *) ( /* dim=0 */ (__pyx_v_log10_mtot.data + __pyx_t_6 * __pyx_v_log10_mtot.strides[0]) ))) - (*((double *) ( /* dim=0 */ (__pyx_v_log10_mtot.data + __pyx_t_7 * __pyx_v_log10_mtot.strides[0]) ))));
 192: 
+193:         for qq in range(n_mrat-1):                          # iterate over output-shape of mass-ratio-grid
    __pyx_t_8 = (__pyx_v_n_mrat - 1);
    __pyx_t_9 = __pyx_t_8;
    for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) {
      __pyx_v_qq = __pyx_t_10;
+194:             dmdq = dm * (mrat[qq+1] - mrat[qq])             # get the bin-area
      __pyx_t_7 = (__pyx_v_qq + 1);
      __pyx_t_6 = __pyx_v_qq;
      __pyx_v_dmdq = (__pyx_v_dm * ((*((double *) ( /* dim=0 */ (__pyx_v_mrat.data + __pyx_t_7 * __pyx_v_mrat.strides[0]) ))) - (*((double *) ( /* dim=0 */ (__pyx_v_mrat.data + __pyx_t_6 * __pyx_v_mrat.strides[0]) )))));
 195: 
+196:             for zz in range(n_redz-1):                      # iterate over output-shape of redsz-grid
      __pyx_t_11 = (__pyx_v_n_redz - 1);
      __pyx_t_12 = __pyx_t_11;
      for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_12; __pyx_t_13+=1) {
        __pyx_v_zz = __pyx_t_13;
+197:                 dmdqdz = dmdq * (redz[zz+1] - redz[zz])     # get the bin-volume
        __pyx_t_6 = (__pyx_v_zz + 1);
        __pyx_t_7 = __pyx_v_zz;
        __pyx_v_dmdqdz = (__pyx_v_dmdq * ((*((double *) ( /* dim=0 */ (__pyx_v_redz.data + __pyx_t_6 * __pyx_v_redz.strides[0]) ))) - (*((double *) ( /* dim=0 */ (__pyx_v_redz.data + __pyx_t_7 * __pyx_v_redz.strides[0]) )))));
 198: 
 199:                 # iterate over output-shape of frequency
 200:                 # note that this is a Riemann sum, so input and output dimensions are the same size
+201:                 for ff in range(n_freq):
        __pyx_t_14 = __pyx_v_n_freq;
        __pyx_t_15 = __pyx_t_14;
        for (__pyx_t_16 = 0; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) {
          __pyx_v_ff = __pyx_t_16;
+202:                     temp = 0.0
          __Pyx_INCREF(__pyx_float_0_0);
          __Pyx_XDECREF_SET(__pyx_v_temp, __pyx_float_0_0);
 203: 
 204:                     # iterate over each vertex of this cube, averaging the contributions
+205:                     for ii in range(2):                     # mass vertices
          for (__pyx_t_17 = 0; __pyx_t_17 < 2; __pyx_t_17+=1) {
            __pyx_v_ii = __pyx_t_17;
+206:                         for jj in range(2):                 # mass-ratio vertices
            for (__pyx_t_18 = 0; __pyx_t_18 < 2; __pyx_t_18+=1) {
              __pyx_v_jj = __pyx_t_18;
+207:                             for kk in range(2):             # redshift vertices
              for (__pyx_t_19 = 0; __pyx_t_19 < 2; __pyx_t_19+=1) {
                __pyx_v_kk = __pyx_t_19;
+208:                                 temp += dnum[mm+ii, qq+jj, zz+kk, ff]
                __pyx_t_7 = (__pyx_v_mm + __pyx_v_ii);
                __pyx_t_6 = (__pyx_v_qq + __pyx_v_jj);
                __pyx_t_20 = (__pyx_v_zz + __pyx_v_kk);
                __pyx_t_21 = __pyx_v_ff;
                __pyx_t_1 = PyFloat_FromDouble((*((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_dnum.data + __pyx_t_7 * __pyx_v_dnum.strides[0]) ) + __pyx_t_6 * __pyx_v_dnum.strides[1]) ) + __pyx_t_20 * __pyx_v_dnum.strides[2]) ) + __pyx_t_21 * __pyx_v_dnum.strides[3]) )))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 208, __pyx_L1_error)
                __Pyx_GOTREF(__pyx_t_1);
                __pyx_t_2 = PyNumber_InPlaceAdd(__pyx_v_temp, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 208, __pyx_L1_error)
                __Pyx_GOTREF(__pyx_t_2);
                __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
                __Pyx_DECREF_SET(__pyx_v_temp, __pyx_t_2);
                __pyx_t_2 = 0;
              }
            }
          }
 209: 
+210:                     numb[mm, qq, zz, ff] = temp * dmdqdz * dln_freq[ff] / 8.0
          __pyx_t_2 = PyFloat_FromDouble(__pyx_v_dmdqdz); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 210, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_2);
          __pyx_t_1 = PyNumber_Multiply(__pyx_v_temp, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 210, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_1);
          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
          __pyx_t_21 = __pyx_v_ff;
          __pyx_t_2 = PyFloat_FromDouble((*((double *) ( /* dim=0 */ (__pyx_v_dln_freq.data + __pyx_t_21 * __pyx_v_dln_freq.strides[0]) )))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 210, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_2);
          __pyx_t_22 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_22)) __PYX_ERR(0, 210, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_22);
          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
          __pyx_t_2 = __Pyx_PyFloat_TrueDivideObjC(__pyx_t_22, __pyx_float_8_0, 8.0, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 210, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_2);
          __Pyx_DECREF(__pyx_t_22); __pyx_t_22 = 0;
          __pyx_t_23 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_23 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 210, __pyx_L1_error)
          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
          __pyx_t_21 = __pyx_v_mm;
          __pyx_t_20 = __pyx_v_qq;
          __pyx_t_6 = __pyx_v_zz;
          __pyx_t_7 = __pyx_v_ff;
          *((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_numb.data + __pyx_t_21 * __pyx_v_numb.strides[0]) ) + __pyx_t_20 * __pyx_v_numb.strides[1]) ) + __pyx_t_6 * __pyx_v_numb.strides[2]) ) + __pyx_t_7 * __pyx_v_numb.strides[3]) )) = __pyx_t_23;
        }
      }
    }
  }
 211: 
+212:     return
  goto __pyx_L0;
 213: 
 214: 
 215: # ==================================================================================================
 216: # ====    Fixed_Time_2pwl_SAM - Hardening Model    ====
 217: # ==================================================================================================
 218: 
 219: 
 220: # @cython.cdivision(True)
 221: # cpdef double _hard_func_2pwl(double norm, double xx, double gamma_inner, double gamma_outer):
 222: #     cdef double dadt = - norm * pow(1.0 + xx, -gamma_outer+gamma_inner) / pow(xx, gamma_inner-1)
 223: #     return dadt
 224: 
 225: 
 226: # @cython.cdivision(True)
 227: # cpdef double hard_func_2pwl_gw(
 228: #     double mtot, double mrat, double sepa,
 229: #     double norm, double rchar, double gamma_inner, double gamma_outer
 230: # ):
 231: #     cdef double dadt = _hard_func_2pwl(norm, sepa/rchar, gamma_inner, gamma_outer)
 232: #     dadt += hard_gw(mtot, mrat, sepa)
 233: #     return dadt
 234: 
 235: 
 236: @cython.cdivision(True)
+237: cdef double _hard_func_2pwl(double norm, double xx, double gamma_inner, double gamma_outer):
static double __pyx_f_8holodeck_10sam_cython__hard_func_2pwl(double __pyx_v_norm, double __pyx_v_xx, double __pyx_v_gamma_inner, double __pyx_v_gamma_outer) {
  double __pyx_v_dadt;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_hard_func_2pwl", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+238:     cdef double dadt = - norm * pow(1.0 + xx, -gamma_outer+gamma_inner) / pow(xx, gamma_inner-1)
  __pyx_v_dadt = (((-__pyx_v_norm) * pow((1.0 + __pyx_v_xx), ((-__pyx_v_gamma_outer) + __pyx_v_gamma_inner))) / pow(__pyx_v_xx, (__pyx_v_gamma_inner - 1.0)));
+239:     return dadt
  __pyx_r = __pyx_v_dadt;
  goto __pyx_L0;
 240: 
 241: 
 242: @cython.cdivision(True)
+243: cdef double _hard_func_2pwl_gw(
static double __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw(double __pyx_v_mtot, double __pyx_v_mrat, double __pyx_v_sepa, double __pyx_v_norm, double __pyx_v_rchar, double __pyx_v_gamma_inner, double __pyx_v_gamma_outer) {
  double __pyx_v_dadt;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_hard_func_2pwl_gw", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 244:     double mtot, double mrat, double sepa,
 245:     double norm, double rchar, double gamma_inner, double gamma_outer
 246: ):
+247:     cdef double dadt = _hard_func_2pwl(norm, sepa/rchar, gamma_inner, gamma_outer)
  __pyx_v_dadt = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl(__pyx_v_norm, (__pyx_v_sepa / __pyx_v_rchar), __pyx_v_gamma_inner, __pyx_v_gamma_outer);
+248:     dadt += hard_gw(mtot, mrat, sepa)
  __pyx_v_dadt = (__pyx_v_dadt + __pyx_f_8holodeck_10sam_cython_hard_gw(__pyx_v_mtot, __pyx_v_mrat, __pyx_v_sepa, 0));
+249:     return dadt
  __pyx_r = __pyx_v_dadt;
  goto __pyx_L0;
 250: 
 251: 
 252: @cython.cdivision(True)
+253: cdef double[:] _hard_func_2pwl_gw_1darray(
static __Pyx_memviewslice __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw_1darray(__Pyx_memviewslice __pyx_v_mtot, __Pyx_memviewslice __pyx_v_mrat, __Pyx_memviewslice __pyx_v_sepa, __Pyx_memviewslice __pyx_v_norm, __Pyx_memviewslice __pyx_v_rchar, __Pyx_memviewslice __pyx_v_gamma_inner, __Pyx_memviewslice __pyx_v_gamma_outer) {
  int __pyx_v_ii;
  int __pyx_v_size;
  PyArrayObject *__pyx_v_dadt = 0;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_dadt;
  __Pyx_Buffer __pyx_pybuffer_dadt;
  __Pyx_memviewslice __pyx_r = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_hard_func_2pwl_gw_1darray", 0);
  __pyx_pybuffer_dadt.pybuffer.buf = NULL;
  __pyx_pybuffer_dadt.refcount = 0;
  __pyx_pybuffernd_dadt.data = NULL;
  __pyx_pybuffernd_dadt.rcbuffer = &__pyx_pybuffer_dadt;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_dadt.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __pyx_r.data = NULL;
  __pyx_r.memview = NULL;
  __Pyx_AddTraceback("holodeck.sam_cython._hard_func_2pwl_gw_1darray", __pyx_clineno, __pyx_lineno, __pyx_filename);
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_dadt.rcbuffer->pybuffer);
  if (unlikely(!__pyx_r.memview)) {
    PyErr_SetString(PyExc_TypeError, "Memoryview return value is not initialized");
  }
  __pyx_L2:;
  __Pyx_XDECREF((PyObject *)__pyx_v_dadt);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 254:     double[:] mtot, double[:] mrat, double[:] sepa,
 255:     double[:] norm, double[:] rchar, double[:] gamma_inner, double[:] gamma_outer
 256: ):
 257:     cdef int ii
+258:     cdef int size = mtot.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_mtot, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 258, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 258, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 258, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_size = __pyx_t_3;
+259:     cdef np.ndarray[np.double_t, ndim=1] dadt = np.zeros(size)
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 259, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_zeros); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 259, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 259, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
    __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4);
    if (likely(__pyx_t_5)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
      __Pyx_INCREF(__pyx_t_5);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_4, function);
    }
  }
  __pyx_t_2 = (__pyx_t_5) ? __Pyx_PyObject_Call2Args(__pyx_t_4, __pyx_t_5, __pyx_t_1) : __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_1);
  __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 259, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 259, __pyx_L1_error)
  __pyx_t_6 = ((PyArrayObject *)__pyx_t_2);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_dadt.rcbuffer->pybuffer, (PyObject*)__pyx_t_6, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES| PyBUF_WRITABLE, 1, 0, __pyx_stack) == -1)) {
      __pyx_v_dadt = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_dadt.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 259, __pyx_L1_error)
    } else {__pyx_pybuffernd_dadt.diminfo[0].strides = __pyx_pybuffernd_dadt.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_dadt.diminfo[0].shape = __pyx_pybuffernd_dadt.rcbuffer->pybuffer.shape[0];
    }
  }
  __pyx_t_6 = 0;
  __pyx_v_dadt = ((PyArrayObject *)__pyx_t_2);
  __pyx_t_2 = 0;
+260:     for ii in range(size):
  __pyx_t_3 = __pyx_v_size;
  __pyx_t_7 = __pyx_t_3;
  for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
    __pyx_v_ii = __pyx_t_8;
+261:         dadt[ii] = _hard_func_2pwl(norm[ii], sepa[ii]/rchar[ii], gamma_inner[ii], gamma_outer[ii])
    __pyx_t_9 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_9 < 0) {
      __pyx_t_9 += __pyx_v_norm.shape[0];
      if (unlikely(__pyx_t_9 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_9 >= __pyx_v_norm.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 261, __pyx_L1_error)
    }
    __pyx_t_11 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_11 < 0) {
      __pyx_t_11 += __pyx_v_sepa.shape[0];
      if (unlikely(__pyx_t_11 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_11 >= __pyx_v_sepa.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 261, __pyx_L1_error)
    }
    __pyx_t_12 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_12 < 0) {
      __pyx_t_12 += __pyx_v_rchar.shape[0];
      if (unlikely(__pyx_t_12 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_12 >= __pyx_v_rchar.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 261, __pyx_L1_error)
    }
    __pyx_t_13 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_13 < 0) {
      __pyx_t_13 += __pyx_v_gamma_inner.shape[0];
      if (unlikely(__pyx_t_13 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_13 >= __pyx_v_gamma_inner.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 261, __pyx_L1_error)
    }
    __pyx_t_14 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_14 < 0) {
      __pyx_t_14 += __pyx_v_gamma_outer.shape[0];
      if (unlikely(__pyx_t_14 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_14 >= __pyx_v_gamma_outer.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 261, __pyx_L1_error)
    }
    __pyx_t_15 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_15 < 0) {
      __pyx_t_15 += __pyx_pybuffernd_dadt.diminfo[0].shape;
      if (unlikely(__pyx_t_15 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_15 >= __pyx_pybuffernd_dadt.diminfo[0].shape)) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 261, __pyx_L1_error)
    }
    *__Pyx_BufPtrStrided1d(__pyx_t_5numpy_double_t *, __pyx_pybuffernd_dadt.rcbuffer->pybuffer.buf, __pyx_t_15, __pyx_pybuffernd_dadt.diminfo[0].strides) = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl((*((double *) ( /* dim=0 */ (__pyx_v_norm.data + __pyx_t_9 * __pyx_v_norm.strides[0]) ))), ((*((double *) ( /* dim=0 */ (__pyx_v_sepa.data + __pyx_t_11 * __pyx_v_sepa.strides[0]) ))) / (*((double *) ( /* dim=0 */ (__pyx_v_rchar.data + __pyx_t_12 * __pyx_v_rchar.strides[0]) )))), (*((double *) ( /* dim=0 */ (__pyx_v_gamma_inner.data + __pyx_t_13 * __pyx_v_gamma_inner.strides[0]) ))), (*((double *) ( /* dim=0 */ (__pyx_v_gamma_outer.data + __pyx_t_14 * __pyx_v_gamma_outer.strides[0]) ))));
+262:         dadt[ii] += hard_gw(mtot[ii], mrat[ii], sepa[ii])
    __pyx_t_14 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_14 < 0) {
      __pyx_t_14 += __pyx_v_mtot.shape[0];
      if (unlikely(__pyx_t_14 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_14 >= __pyx_v_mtot.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 262, __pyx_L1_error)
    }
    __pyx_t_13 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_13 < 0) {
      __pyx_t_13 += __pyx_v_mrat.shape[0];
      if (unlikely(__pyx_t_13 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_13 >= __pyx_v_mrat.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 262, __pyx_L1_error)
    }
    __pyx_t_12 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_12 < 0) {
      __pyx_t_12 += __pyx_v_sepa.shape[0];
      if (unlikely(__pyx_t_12 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_12 >= __pyx_v_sepa.shape[0])) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 262, __pyx_L1_error)
    }
    __pyx_t_11 = __pyx_v_ii;
    __pyx_t_10 = -1;
    if (__pyx_t_11 < 0) {
      __pyx_t_11 += __pyx_pybuffernd_dadt.diminfo[0].shape;
      if (unlikely(__pyx_t_11 < 0)) __pyx_t_10 = 0;
    } else if (unlikely(__pyx_t_11 >= __pyx_pybuffernd_dadt.diminfo[0].shape)) __pyx_t_10 = 0;
    if (unlikely(__pyx_t_10 != -1)) {
      __Pyx_RaiseBufferIndexError(__pyx_t_10);
      __PYX_ERR(0, 262, __pyx_L1_error)
    }
    *__Pyx_BufPtrStrided1d(__pyx_t_5numpy_double_t *, __pyx_pybuffernd_dadt.rcbuffer->pybuffer.buf, __pyx_t_11, __pyx_pybuffernd_dadt.diminfo[0].strides) += __pyx_f_8holodeck_10sam_cython_hard_gw((*((double *) ( /* dim=0 */ (__pyx_v_mtot.data + __pyx_t_14 * __pyx_v_mtot.strides[0]) ))), (*((double *) ( /* dim=0 */ (__pyx_v_mrat.data + __pyx_t_13 * __pyx_v_mrat.strides[0]) ))), (*((double *) ( /* dim=0 */ (__pyx_v_sepa.data + __pyx_t_12 * __pyx_v_sepa.strides[0]) ))), 0);
  }
 263: 
+264:     return dadt
  __pyx_t_16 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(((PyObject *)__pyx_v_dadt), PyBUF_WRITABLE); if (unlikely(!__pyx_t_16.memview)) __PYX_ERR(0, 264, __pyx_L1_error)
  __pyx_r = __pyx_t_16;
  __pyx_t_16.memview = NULL;
  __pyx_t_16.data = NULL;
  goto __pyx_L0;
 265: 
 266: 
+267: def hard_func_2pwl_gw(
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_5hard_func_2pwl_gw(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_8holodeck_10sam_cython_4hard_func_2pwl_gw[] = "\n\n    NOTE: this function will be somewhat slow, because of the explicit broadcasting!\n\n    ";
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_5hard_func_2pwl_gw = {"hard_func_2pwl_gw", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_5hard_func_2pwl_gw, METH_VARARGS|METH_KEYWORDS, __pyx_doc_8holodeck_10sam_cython_4hard_func_2pwl_gw};
static PyObject *__pyx_pw_8holodeck_10sam_cython_5hard_func_2pwl_gw(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_mtot = 0;
  PyObject *__pyx_v_mrat = 0;
  PyObject *__pyx_v_sepa = 0;
  PyObject *__pyx_v_norm = 0;
  PyObject *__pyx_v_rchar = 0;
  PyObject *__pyx_v_gamma_inner = 0;
  PyObject *__pyx_v_gamma_outer = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("hard_func_2pwl_gw (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_mtot,&__pyx_n_s_mrat,&__pyx_n_s_sepa,&__pyx_n_s_norm,&__pyx_n_s_rchar,&__pyx_n_s_gamma_inner,&__pyx_n_s_gamma_outer,0};
    PyObject* values[7] = {0,0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
        CYTHON_FALLTHROUGH;
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mtot)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mrat)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, 1); __PYX_ERR(0, 267, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sepa)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, 2); __PYX_ERR(0, 267, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_norm)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, 3); __PYX_ERR(0, 267, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rchar)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, 4); __PYX_ERR(0, 267, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_inner)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, 5); __PYX_ERR(0, 267, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  6:
        if (likely((values[6] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_outer)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, 6); __PYX_ERR(0, 267, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "hard_func_2pwl_gw") < 0)) __PYX_ERR(0, 267, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 7) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
      values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
    }
    __pyx_v_mtot = values[0];
    __pyx_v_mrat = values[1];
    __pyx_v_sepa = values[2];
    __pyx_v_norm = values[3];
    __pyx_v_rchar = values[4];
    __pyx_v_gamma_inner = values[5];
    __pyx_v_gamma_outer = values[6];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("hard_func_2pwl_gw", 1, 7, 7, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 267, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.hard_func_2pwl_gw", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_4hard_func_2pwl_gw(__pyx_self, __pyx_v_mtot, __pyx_v_mrat, __pyx_v_sepa, __pyx_v_norm, __pyx_v_rchar, __pyx_v_gamma_inner, __pyx_v_gamma_outer);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_4hard_func_2pwl_gw(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_mtot, PyObject *__pyx_v_mrat, PyObject *__pyx_v_sepa, PyObject *__pyx_v_norm, PyObject *__pyx_v_rchar, PyObject *__pyx_v_gamma_inner, PyObject *__pyx_v_gamma_outer) {
  PyObject *__pyx_v_args = NULL;
  PyObject *__pyx_v_shape = NULL;
  PyObject *__pyx_v_dadt = NULL;
  PyObject *__pyx_8genexpr2__pyx_v_aa = NULL;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("hard_func_2pwl_gw", 0);
  __Pyx_INCREF(__pyx_v_mtot);
  __Pyx_INCREF(__pyx_v_mrat);
  __Pyx_INCREF(__pyx_v_sepa);
  __Pyx_INCREF(__pyx_v_norm);
  __Pyx_INCREF(__pyx_v_rchar);
  __Pyx_INCREF(__pyx_v_gamma_inner);
  __Pyx_INCREF(__pyx_v_gamma_outer);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_XDECREF(__pyx_t_10);
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_12, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_13, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_14, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
  __Pyx_AddTraceback("holodeck.sam_cython.hard_func_2pwl_gw", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_args);
  __Pyx_XDECREF(__pyx_v_shape);
  __Pyx_XDECREF(__pyx_v_dadt);
  __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_aa);
  __Pyx_XDECREF(__pyx_v_mtot);
  __Pyx_XDECREF(__pyx_v_mrat);
  __Pyx_XDECREF(__pyx_v_sepa);
  __Pyx_XDECREF(__pyx_v_norm);
  __Pyx_XDECREF(__pyx_v_rchar);
  __Pyx_XDECREF(__pyx_v_gamma_inner);
  __Pyx_XDECREF(__pyx_v_gamma_outer);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__25 = PyTuple_Pack(11, __pyx_n_s_mtot, __pyx_n_s_mrat, __pyx_n_s_sepa, __pyx_n_s_norm, __pyx_n_s_rchar, __pyx_n_s_gamma_inner, __pyx_n_s_gamma_outer, __pyx_n_s_args, __pyx_n_s_shape, __pyx_n_s_dadt, __pyx_n_s_aa); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(0, 267, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__25);
  __Pyx_GIVEREF(__pyx_tuple__25);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_5hard_func_2pwl_gw, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 267, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_hard_func_2pwl_gw, __pyx_t_1) < 0) __PYX_ERR(0, 267, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(7, 0, 11, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__25, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_hard_func_2pwl_gw, 267, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(0, 267, __pyx_L1_error)
 268:     mtot, mrat, sepa,
 269:     norm, rchar, gamma_inner, gamma_outer
 270: ):
 271:     """
 272: 
 273:     NOTE: this function will be somewhat slow, because of the explicit broadcasting!
 274: 
 275:     """
+276:     args = mtot, mrat, sepa, norm, rchar, gamma_inner, gamma_outer
  __pyx_t_1 = PyTuple_New(7); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 276, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_INCREF(__pyx_v_mtot);
  __Pyx_GIVEREF(__pyx_v_mtot);
  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_mtot);
  __Pyx_INCREF(__pyx_v_mrat);
  __Pyx_GIVEREF(__pyx_v_mrat);
  PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_mrat);
  __Pyx_INCREF(__pyx_v_sepa);
  __Pyx_GIVEREF(__pyx_v_sepa);
  PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_sepa);
  __Pyx_INCREF(__pyx_v_norm);
  __Pyx_GIVEREF(__pyx_v_norm);
  PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_v_norm);
  __Pyx_INCREF(__pyx_v_rchar);
  __Pyx_GIVEREF(__pyx_v_rchar);
  PyTuple_SET_ITEM(__pyx_t_1, 4, __pyx_v_rchar);
  __Pyx_INCREF(__pyx_v_gamma_inner);
  __Pyx_GIVEREF(__pyx_v_gamma_inner);
  PyTuple_SET_ITEM(__pyx_t_1, 5, __pyx_v_gamma_inner);
  __Pyx_INCREF(__pyx_v_gamma_outer);
  __Pyx_GIVEREF(__pyx_v_gamma_outer);
  PyTuple_SET_ITEM(__pyx_t_1, 6, __pyx_v_gamma_outer);
  __pyx_v_args = __pyx_t_1;
  __pyx_t_1 = 0;
+277:     args = np.broadcast_arrays(*args)
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 277, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_broadcast_arrays); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 277, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PySequence_Tuple(__pyx_v_args); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 277, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 277, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF_SET(__pyx_v_args, __pyx_t_3);
  __pyx_t_3 = 0;
+278:     shape = args[0].shape
  __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_args, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 278, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 278, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_v_shape = __pyx_t_1;
  __pyx_t_1 = 0;
+279:     mtot, mrat, sepa, norm, rchar, gamma_inner, gamma_outer = [aa.flatten() for aa in args]
  { /* enter inner scope */
    __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 279, __pyx_L5_error)
    __Pyx_GOTREF(__pyx_t_1);
    if (likely(PyList_CheckExact(__pyx_v_args)) || PyTuple_CheckExact(__pyx_v_args)) {
      __pyx_t_3 = __pyx_v_args; __Pyx_INCREF(__pyx_t_3); __pyx_t_4 = 0;
      __pyx_t_5 = NULL;
    } else {
      __pyx_t_4 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_v_args); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 279, __pyx_L5_error)
      __Pyx_GOTREF(__pyx_t_3);
      __pyx_t_5 = Py_TYPE(__pyx_t_3)->tp_iternext; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 279, __pyx_L5_error)
    }
    for (;;) {
      if (likely(!__pyx_t_5)) {
        if (likely(PyList_CheckExact(__pyx_t_3))) {
          if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_3)) break;
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 279, __pyx_L5_error)
          #else
          __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 279, __pyx_L5_error)
          __Pyx_GOTREF(__pyx_t_2);
          #endif
        } else {
          if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 279, __pyx_L5_error)
          #else
          __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 279, __pyx_L5_error)
          __Pyx_GOTREF(__pyx_t_2);
          #endif
        }
      } else {
        __pyx_t_2 = __pyx_t_5(__pyx_t_3);
        if (unlikely(!__pyx_t_2)) {
          PyObject* exc_type = PyErr_Occurred();
          if (exc_type) {
            if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
            else __PYX_ERR(0, 279, __pyx_L5_error)
          }
          break;
        }
        __Pyx_GOTREF(__pyx_t_2);
      }
      __Pyx_XDECREF_SET(__pyx_8genexpr2__pyx_v_aa, __pyx_t_2);
      __pyx_t_2 = 0;
      __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_8genexpr2__pyx_v_aa, __pyx_n_s_flatten); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 279, __pyx_L5_error)
      __Pyx_GOTREF(__pyx_t_6);
      __pyx_t_7 = NULL;
      if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) {
        __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6);
        if (likely(__pyx_t_7)) {
          PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
          __Pyx_INCREF(__pyx_t_7);
          __Pyx_INCREF(function);
          __Pyx_DECREF_SET(__pyx_t_6, function);
        }
      }
      __pyx_t_2 = (__pyx_t_7) ? __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_7) : __Pyx_PyObject_CallNoArg(__pyx_t_6);
      __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
      if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 279, __pyx_L5_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
      if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_2))) __PYX_ERR(0, 279, __pyx_L5_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    }
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_aa); __pyx_8genexpr2__pyx_v_aa = 0;
    goto __pyx_L8_exit_scope;
    __pyx_L5_error:;
    __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_aa); __pyx_8genexpr2__pyx_v_aa = 0;
    goto __pyx_L1_error;
    __pyx_L8_exit_scope:;
  } /* exit inner scope */
  if (1) {
    PyObject* sequence = __pyx_t_1;
    Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
    if (unlikely(size != 7)) {
      if (size > 7) __Pyx_RaiseTooManyValuesError(7);
      else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
      __PYX_ERR(0, 279, __pyx_L1_error)
    }
    #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
    __pyx_t_3 = PyList_GET_ITEM(sequence, 0); 
    __pyx_t_2 = PyList_GET_ITEM(sequence, 1); 
    __pyx_t_6 = PyList_GET_ITEM(sequence, 2); 
    __pyx_t_7 = PyList_GET_ITEM(sequence, 3); 
    __pyx_t_8 = PyList_GET_ITEM(sequence, 4); 
    __pyx_t_9 = PyList_GET_ITEM(sequence, 5); 
    __pyx_t_10 = PyList_GET_ITEM(sequence, 6); 
    __Pyx_INCREF(__pyx_t_3);
    __Pyx_INCREF(__pyx_t_2);
    __Pyx_INCREF(__pyx_t_6);
    __Pyx_INCREF(__pyx_t_7);
    __Pyx_INCREF(__pyx_t_8);
    __Pyx_INCREF(__pyx_t_9);
    __Pyx_INCREF(__pyx_t_10);
    #else
    {
      Py_ssize_t i;
      PyObject** temps[7] = {&__pyx_t_3,&__pyx_t_2,&__pyx_t_6,&__pyx_t_7,&__pyx_t_8,&__pyx_t_9,&__pyx_t_10};
      for (i=0; i < 7; i++) {
        PyObject* item = PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 279, __pyx_L1_error)
        __Pyx_GOTREF(item);
        *(temps[i]) = item;
      }
    }
    #endif
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  }
  __Pyx_DECREF_SET(__pyx_v_mtot, __pyx_t_3);
  __pyx_t_3 = 0;
  __Pyx_DECREF_SET(__pyx_v_mrat, __pyx_t_2);
  __pyx_t_2 = 0;
  __Pyx_DECREF_SET(__pyx_v_sepa, __pyx_t_6);
  __pyx_t_6 = 0;
  __Pyx_DECREF_SET(__pyx_v_norm, __pyx_t_7);
  __pyx_t_7 = 0;
  __Pyx_DECREF_SET(__pyx_v_rchar, __pyx_t_8);
  __pyx_t_8 = 0;
  __Pyx_DECREF_SET(__pyx_v_gamma_inner, __pyx_t_9);
  __pyx_t_9 = 0;
  __Pyx_DECREF_SET(__pyx_v_gamma_outer, __pyx_t_10);
  __pyx_t_10 = 0;
+280:     dadt = _hard_func_2pwl_gw_1darray(mtot, mrat, sepa, norm, rchar, gamma_inner, gamma_outer)
  __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_mtot, PyBUF_WRITABLE); if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_12 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_mrat, PyBUF_WRITABLE); if (unlikely(!__pyx_t_12.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_13 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_sepa, PyBUF_WRITABLE); if (unlikely(!__pyx_t_13.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_14 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_norm, PyBUF_WRITABLE); if (unlikely(!__pyx_t_14.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_15 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_rchar, PyBUF_WRITABLE); if (unlikely(!__pyx_t_15.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_16 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_gamma_inner, PyBUF_WRITABLE); if (unlikely(!__pyx_t_16.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_17 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_gamma_outer, PyBUF_WRITABLE); if (unlikely(!__pyx_t_17.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __pyx_t_18 = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw_1darray(__pyx_t_11, __pyx_t_12, __pyx_t_13, __pyx_t_14, __pyx_t_15, __pyx_t_16, __pyx_t_17); if (unlikely(!__pyx_t_18.memview)) __PYX_ERR(0, 280, __pyx_L1_error)
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __pyx_t_11.memview = NULL;
  __pyx_t_11.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_12, 1);
  __pyx_t_12.memview = NULL;
  __pyx_t_12.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_13, 1);
  __pyx_t_13.memview = NULL;
  __pyx_t_13.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_14, 1);
  __pyx_t_14.memview = NULL;
  __pyx_t_14.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
  __pyx_t_15.memview = NULL;
  __pyx_t_15.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
  __pyx_t_16.memview = NULL;
  __pyx_t_16.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
  __pyx_t_17.memview = NULL;
  __pyx_t_17.data = NULL;
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_t_18, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 280, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
  __pyx_t_18.memview = NULL;
  __pyx_t_18.data = NULL;
  __pyx_v_dadt = __pyx_t_1;
  __pyx_t_1 = 0;
+281:     dadt = np.array(dadt).reshape(shape)
  __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 281, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_9);
  __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_array); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 281, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_8);
  __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
  __pyx_t_9 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) {
    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8);
    if (likely(__pyx_t_9)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8);
      __Pyx_INCREF(__pyx_t_9);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_8, function);
    }
  }
  __pyx_t_10 = (__pyx_t_9) ? __Pyx_PyObject_Call2Args(__pyx_t_8, __pyx_t_9, __pyx_v_dadt) : __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_v_dadt);
  __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
  if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 281, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_10);
  __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
  __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_reshape); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 281, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_8);
  __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
  __pyx_t_10 = NULL;
  if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) {
    __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_8);
    if (likely(__pyx_t_10)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8);
      __Pyx_INCREF(__pyx_t_10);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_8, function);
    }
  }
  __pyx_t_1 = (__pyx_t_10) ? __Pyx_PyObject_Call2Args(__pyx_t_8, __pyx_t_10, __pyx_v_shape) : __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_v_shape);
  __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
  if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 281, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
  __Pyx_DECREF_SET(__pyx_v_dadt, __pyx_t_1);
  __pyx_t_1 = 0;
+282:     return dadt
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(__pyx_v_dadt);
  __pyx_r = __pyx_v_dadt;
  goto __pyx_L0;
 283: 
 284: 
+285: def find_2pwl_hardening_norm(time, mtot, mrat, sepa_init, rchar, gamma_inner, gamma_outer, nsteps):
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_7find_2pwl_hardening_norm(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_7find_2pwl_hardening_norm = {"find_2pwl_hardening_norm", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_7find_2pwl_hardening_norm, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_8holodeck_10sam_cython_7find_2pwl_hardening_norm(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_time = 0;
  PyObject *__pyx_v_mtot = 0;
  PyObject *__pyx_v_mrat = 0;
  PyObject *__pyx_v_sepa_init = 0;
  PyObject *__pyx_v_rchar = 0;
  PyObject *__pyx_v_gamma_inner = 0;
  PyObject *__pyx_v_gamma_outer = 0;
  PyObject *__pyx_v_nsteps = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("find_2pwl_hardening_norm (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_time,&__pyx_n_s_mtot,&__pyx_n_s_mrat,&__pyx_n_s_sepa_init,&__pyx_n_s_rchar,&__pyx_n_s_gamma_inner,&__pyx_n_s_gamma_outer,&__pyx_n_s_nsteps,0};
    PyObject* values[8] = {0,0,0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
        CYTHON_FALLTHROUGH;
        case  7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
        CYTHON_FALLTHROUGH;
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_time)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mtot)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 1); __PYX_ERR(0, 285, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mrat)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 2); __PYX_ERR(0, 285, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sepa_init)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 3); __PYX_ERR(0, 285, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rchar)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 4); __PYX_ERR(0, 285, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_inner)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 5); __PYX_ERR(0, 285, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  6:
        if (likely((values[6] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_outer)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 6); __PYX_ERR(0, 285, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  7:
        if (likely((values[7] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nsteps)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, 7); __PYX_ERR(0, 285, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "find_2pwl_hardening_norm") < 0)) __PYX_ERR(0, 285, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 8) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
      values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
      values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
    }
    __pyx_v_time = values[0];
    __pyx_v_mtot = values[1];
    __pyx_v_mrat = values[2];
    __pyx_v_sepa_init = values[3];
    __pyx_v_rchar = values[4];
    __pyx_v_gamma_inner = values[5];
    __pyx_v_gamma_outer = values[6];
    __pyx_v_nsteps = values[7];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("find_2pwl_hardening_norm", 1, 8, 8, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 285, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.find_2pwl_hardening_norm", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_6find_2pwl_hardening_norm(__pyx_self, __pyx_v_time, __pyx_v_mtot, __pyx_v_mrat, __pyx_v_sepa_init, __pyx_v_rchar, __pyx_v_gamma_inner, __pyx_v_gamma_outer, __pyx_v_nsteps);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_6find_2pwl_hardening_norm(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_time, PyObject *__pyx_v_mtot, PyObject *__pyx_v_mrat, PyObject *__pyx_v_sepa_init, PyObject *__pyx_v_rchar, PyObject *__pyx_v_gamma_inner, PyObject *__pyx_v_gamma_outer, PyObject *__pyx_v_nsteps) {
  PyArrayObject *__pyx_v_norm_log10 = 0;
  __pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params __pyx_v_args;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_norm_log10;
  __Pyx_Buffer __pyx_pybuffer_norm_log10;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("find_2pwl_hardening_norm", 0);
  __pyx_pybuffer_norm_log10.pybuffer.buf = NULL;
  __pyx_pybuffer_norm_log10.refcount = 0;
  __pyx_pybuffernd_norm_log10.data = NULL;
  __pyx_pybuffernd_norm_log10.rcbuffer = &__pyx_pybuffer_norm_log10;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_5);
  __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_10, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_norm_log10.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("holodeck.sam_cython.find_2pwl_hardening_norm", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_norm_log10.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF((PyObject *)__pyx_v_norm_log10);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__27 = PyTuple_Pack(10, __pyx_n_s_time, __pyx_n_s_mtot, __pyx_n_s_mrat, __pyx_n_s_sepa_init, __pyx_n_s_rchar, __pyx_n_s_gamma_inner, __pyx_n_s_gamma_outer, __pyx_n_s_nsteps, __pyx_n_s_norm_log10, __pyx_n_s_args); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(0, 285, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__27);
  __Pyx_GIVEREF(__pyx_tuple__27);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_7find_2pwl_hardening_norm, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 285, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_find_2pwl_hardening_norm, __pyx_t_1) < 0) __PYX_ERR(0, 285, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(8, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_find_2pwl_hardening_norm, 285, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(0, 285, __pyx_L1_error)
+286:     assert np.ndim(time) == 0
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 286, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_ndim); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 286, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
      __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
      if (likely(__pyx_t_2)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
        __Pyx_INCREF(__pyx_t_2);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_3, function);
      }
    }
    __pyx_t_1 = (__pyx_t_2) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_2, __pyx_v_time) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_time);
    __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 286, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyInt_EqObjC(__pyx_t_1, __pyx_int_0, 0, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 286, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 286, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    if (unlikely(!__pyx_t_4)) {
      PyErr_SetNone(PyExc_AssertionError);
      __PYX_ERR(0, 286, __pyx_L1_error)
    }
  }
  #endif
+287:     assert np.ndim(mtot) == 1
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 287, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 287, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __pyx_t_1 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
      __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_2);
      if (likely(__pyx_t_1)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
        __Pyx_INCREF(__pyx_t_1);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_2, function);
      }
    }
    __pyx_t_3 = (__pyx_t_1) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_1, __pyx_v_mtot) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_mtot);
    __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
    if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = __Pyx_PyInt_EqObjC(__pyx_t_3, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 287, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 287, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    if (unlikely(!__pyx_t_4)) {
      PyErr_SetNone(PyExc_AssertionError);
      __PYX_ERR(0, 287, __pyx_L1_error)
    }
  }
  #endif
+288:     assert np.shape(mtot) == np.shape(mrat)
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) {
      __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1);
      if (likely(__pyx_t_3)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
        __Pyx_INCREF(__pyx_t_3);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_1, function);
      }
    }
    __pyx_t_2 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_3, __pyx_v_mtot) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v_mtot);
    __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
    if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_5);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
      __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5);
      if (likely(__pyx_t_3)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
        __Pyx_INCREF(__pyx_t_3);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_5, function);
      }
    }
    __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_5, __pyx_t_3, __pyx_v_mrat) : __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_mrat);
    __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __pyx_t_5 = PyObject_RichCompare(__pyx_t_2, __pyx_t_1, Py_EQ); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 288, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    if (unlikely(!__pyx_t_4)) {
      PyErr_SetNone(PyExc_AssertionError);
      __PYX_ERR(0, 288, __pyx_L1_error)
    }
  }
  #endif
 289: 
+290:     cdef np.ndarray[np.double_t, ndim=1] norm_log10 = np.zeros(mtot.size)
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 290, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_zeros); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 290, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_mtot, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 290, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
    __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
    if (likely(__pyx_t_3)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
      __Pyx_INCREF(__pyx_t_3);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_2, function);
    }
  }
  __pyx_t_5 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_3, __pyx_t_1) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_1);
  __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 290, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  if (!(likely(((__pyx_t_5) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_5, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 290, __pyx_L1_error)
  __pyx_t_6 = ((PyArrayObject *)__pyx_t_5);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_norm_log10.rcbuffer->pybuffer, (PyObject*)__pyx_t_6, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) {
      __pyx_v_norm_log10 = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_norm_log10.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 290, __pyx_L1_error)
    } else {__pyx_pybuffernd_norm_log10.diminfo[0].strides = __pyx_pybuffernd_norm_log10.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_norm_log10.diminfo[0].shape = __pyx_pybuffernd_norm_log10.rcbuffer->pybuffer.shape[0];
    }
  }
  __pyx_t_6 = 0;
  __pyx_v_norm_log10 = ((PyArrayObject *)__pyx_t_5);
  __pyx_t_5 = 0;
 291: 
 292:     cdef lifetime_2pwl_params args
+293:     args.target_time = time
  __pyx_t_7 = __pyx_PyFloat_AsDouble(__pyx_v_time); if (unlikely((__pyx_t_7 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 293, __pyx_L1_error)
  __pyx_v_args.target_time = __pyx_t_7;
+294:     args.sepa_init = sepa_init
  __pyx_t_7 = __pyx_PyFloat_AsDouble(__pyx_v_sepa_init); if (unlikely((__pyx_t_7 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 294, __pyx_L1_error)
  __pyx_v_args.sepa_init = __pyx_t_7;
+295:     args.rchar = rchar
  __pyx_t_7 = __pyx_PyFloat_AsDouble(__pyx_v_rchar); if (unlikely((__pyx_t_7 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 295, __pyx_L1_error)
  __pyx_v_args.rchar = __pyx_t_7;
+296:     args.gamma_inner = gamma_inner
  __pyx_t_7 = __pyx_PyFloat_AsDouble(__pyx_v_gamma_inner); if (unlikely((__pyx_t_7 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L1_error)
  __pyx_v_args.gamma_inner = __pyx_t_7;
+297:     args.gamma_outer = gamma_outer
  __pyx_t_7 = __pyx_PyFloat_AsDouble(__pyx_v_gamma_outer); if (unlikely((__pyx_t_7 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 297, __pyx_L1_error)
  __pyx_v_args.gamma_outer = __pyx_t_7;
+298:     args.nsteps = nsteps
  __pyx_t_8 = __Pyx_PyInt_As_int(__pyx_v_nsteps); if (unlikely((__pyx_t_8 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 298, __pyx_L1_error)
  __pyx_v_args.nsteps = __pyx_t_8;
 299: 
+300:     _get_hardening_norm_2pwl(mtot, mrat, args, norm_log10)
  __pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_mtot, PyBUF_WRITABLE); if (unlikely(!__pyx_t_9.memview)) __PYX_ERR(0, 300, __pyx_L1_error)
  __pyx_t_10 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_mrat, PyBUF_WRITABLE); if (unlikely(!__pyx_t_10.memview)) __PYX_ERR(0, 300, __pyx_L1_error)
  __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(((PyObject *)__pyx_v_norm_log10), PyBUF_WRITABLE); if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 300, __pyx_L1_error)
  __pyx_f_8holodeck_10sam_cython__get_hardening_norm_2pwl(__pyx_t_9, __pyx_t_10, __pyx_v_args, __pyx_t_11);
  __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
  __pyx_t_9.memview = NULL;
  __pyx_t_9.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_10, 1);
  __pyx_t_10.memview = NULL;
  __pyx_t_10.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __pyx_t_11.memview = NULL;
  __pyx_t_11.data = NULL;
 301: 
+302:     return norm_log10
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(((PyObject *)__pyx_v_norm_log10));
  __pyx_r = ((PyObject *)__pyx_v_norm_log10);
  goto __pyx_L0;
 303: 
 304: 
+305: ctypedef struct lifetime_2pwl_params:
struct __pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params {
  double target_time;
  double mt;
  double mr;
  double sepa_init;
  double rchar;
  double gamma_inner;
  double gamma_outer;
  int nsteps;
};
 306:     double target_time
 307:     double mt
 308:     double mr
 309:     double sepa_init
 310:     double rchar
 311:     double gamma_inner
 312:     double gamma_outer
 313:     int nsteps
 314: 
 315: 
 316: @cython.boundscheck(False)
 317: @cython.wraparound(False)
 318: @cython.nonecheck(False)
 319: @cython.cdivision(True)
+320: cdef void _get_hardening_norm_2pwl(
static void __pyx_f_8holodeck_10sam_cython__get_hardening_norm_2pwl(__Pyx_memviewslice __pyx_v_mtot, __Pyx_memviewslice __pyx_v_mrat, __pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params __pyx_v_args, __Pyx_memviewslice __pyx_v_norm_log10) {
  double __pyx_v_XTOL;
  double __pyx_v_RTOL;
  int __pyx_v_MITR;
  double __pyx_v_NORM_LOG10_LO;
  double __pyx_v_NORM_LOG10_HI;
  int __pyx_v_num;
  int __pyx_v_ii;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_get_hardening_norm_2pwl", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_WriteUnraisable("holodeck.sam_cython._get_hardening_norm_2pwl", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0);
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
}
 321:     double[:] mtot,
 322:     double[:] mrat,
 323:     lifetime_2pwl_params args,
 324:     # output
 325:     double[:] norm_log10,
 326: ):
 327: 
+328:     cdef double XTOL = 1e-3
  __pyx_v_XTOL = 1e-3;
+329:     cdef double RTOL = 1e-5
  __pyx_v_RTOL = 1e-5;
+330:     cdef int MITR = 100    # note: the function doesn't return an error on failure, it still returns last try
  __pyx_v_MITR = 0x64;
+331:     cdef double NORM_LOG10_LO = -20.0
  __pyx_v_NORM_LOG10_LO = -20.0;
+332:     cdef double NORM_LOG10_HI = +20.0
  __pyx_v_NORM_LOG10_HI = 20.0;
 333: 
+334:     cdef int num = mtot.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_mtot, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 334, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 334, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 334, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_num = __pyx_t_3;
+335:     assert mtot.size == mrat.size
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_mtot, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 335, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 335, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_mrat, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 335, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 335, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_4);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = PyObject_RichCompare(__pyx_t_1, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 335, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 335, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    if (unlikely(!__pyx_t_5)) {
      PyErr_SetNone(PyExc_AssertionError);
      __PYX_ERR(0, 335, __pyx_L1_error)
    }
  }
  #endif
 336:     cdef double time
 337: 
 338:     cdef int ii
+339:     for ii in range(num):
  __pyx_t_3 = __pyx_v_num;
  __pyx_t_6 = __pyx_t_3;
  for (__pyx_t_7 = 0; __pyx_t_7 < __pyx_t_6; __pyx_t_7+=1) {
    __pyx_v_ii = __pyx_t_7;
+340:         args.mt = mtot[ii]
    __pyx_t_8 = __pyx_v_ii;
    __pyx_v_args.mt = (*((double *) ( /* dim=0 */ (__pyx_v_mtot.data + __pyx_t_8 * __pyx_v_mtot.strides[0]) )));
+341:         args.mr = mrat[ii]
    __pyx_t_8 = __pyx_v_ii;
    __pyx_v_args.mr = (*((double *) ( /* dim=0 */ (__pyx_v_mrat.data + __pyx_t_8 * __pyx_v_mrat.strides[0]) )));
+342:         norm_log10[ii] = brentq(
    __pyx_t_8 = __pyx_v_ii;
    *((double *) ( /* dim=0 */ (__pyx_v_norm_log10.data + __pyx_t_8 * __pyx_v_norm_log10.strides[0]) )) = __pyx_f_5scipy_8optimize_15cython_optimize_6_zeros_brentq(__pyx_f_8holodeck_10sam_cython_get_binary_lifetime_2pwl, __pyx_v_NORM_LOG10_LO, __pyx_v_NORM_LOG10_HI, ((__pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params *)(&__pyx_v_args)), __pyx_v_XTOL, __pyx_v_RTOL, __pyx_v_MITR, NULL);
  }
 343:             get_binary_lifetime_2pwl, NORM_LOG10_LO, NORM_LOG10_HI,
 344:             <lifetime_2pwl_params *> &args, XTOL, RTOL, MITR, NULL
 345:         )
 346:         # time = get_binary_lifetime_2pwl(norm_log10[ii], <lifetime_2pwl_params *> &args)
 347:         # total_time[ii] = time + args.target_time
 348: 
+349:     return
  goto __pyx_L0;
 350: 
 351: 
 352: @cython.boundscheck(False)
 353: @cython.wraparound(False)
 354: @cython.nonecheck(False)
 355: @cython.cdivision(True)
+356: cdef double get_binary_lifetime_2pwl(double norm_log10, void *args):
static double __pyx_f_8holodeck_10sam_cython_get_binary_lifetime_2pwl(double __pyx_v_norm_log10, void *__pyx_v_args) {
  __pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params *__pyx_v_pars;
  double __pyx_v_risco_log10;
  double __pyx_v_sepa_log10;
  double __pyx_v_norm;
  double __pyx_v_dx;
  double __pyx_v_time;
  CYTHON_UNUSED int __pyx_v_ii;
  double __pyx_v_sepa_right;
  double __pyx_v_dadt_right;
  double __pyx_v_dt;
  double __pyx_v_sepa_left;
  double __pyx_v_dadt_left;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_binary_lifetime_2pwl", 0);
/* … */
  /* function exit code */
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
+357:     cdef lifetime_2pwl_params *pars = <lifetime_2pwl_params *> args
  __pyx_v_pars = ((__pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params *)__pyx_v_args);
 358: 
+359:     cdef double risco_log10 = log10(3.0 * MY_SCHW * pars.mt)
  __pyx_v_risco_log10 = log10(((3.0 * __pyx_v_8holodeck_10sam_cython_MY_SCHW) * __pyx_v_pars->mt));
+360:     cdef double sepa_log10 = log10(pars.sepa_init)
  __pyx_v_sepa_log10 = log10(__pyx_v_pars->sepa_init);
+361:     cdef double norm = pow(10.0, norm_log10)
  __pyx_v_norm = pow(10.0, __pyx_v_norm_log10);
 362: 
 363:     # step-size, in log10-space, to go from sepa_init to ISCO
+364:     cdef double dx = (sepa_log10 - risco_log10) / pars.nsteps
  __pyx_v_dx = ((__pyx_v_sepa_log10 - __pyx_v_risco_log10) / ((double)__pyx_v_pars->nsteps));
+365:     cdef double time = 0.0
  __pyx_v_time = 0.0;
 366: 
 367:     cdef int ii
 368:     cdef double sepa_right, dadt_right, dt
 369: 
+370:     cdef double sepa_left = pow(10.0, sepa_log10)
  __pyx_v_sepa_left = pow(10.0, __pyx_v_sepa_log10);
+371:     cdef double dadt_left = _hard_func_2pwl_gw(
  __pyx_v_dadt_left = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw(__pyx_v_pars->mt, __pyx_v_pars->mr, __pyx_v_sepa_left, __pyx_v_norm, __pyx_v_pars->rchar, __pyx_v_pars->gamma_inner, __pyx_v_pars->gamma_outer);
 372:         pars.mt, pars.mr, sepa_left,
 373:         norm, pars.rchar, pars.gamma_inner, pars.gamma_outer
 374:     )
 375: 
+376:     for ii in range(pars.nsteps):
  __pyx_t_1 = __pyx_v_pars->nsteps;
  __pyx_t_2 = __pyx_t_1;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
    __pyx_v_ii = __pyx_t_3;
+377:         sepa_log10 -= dx
    __pyx_v_sepa_log10 = (__pyx_v_sepa_log10 - __pyx_v_dx);
+378:         sepa_right = pow(10.0, sepa_log10)
    __pyx_v_sepa_right = pow(10.0, __pyx_v_sepa_log10);
 379: 
 380:         # Get total hardening rate at k+1 edge
+381:         dadt_right = _hard_func_2pwl_gw(
    __pyx_v_dadt_right = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw(__pyx_v_pars->mt, __pyx_v_pars->mr, __pyx_v_sepa_right, __pyx_v_norm, __pyx_v_pars->rchar, __pyx_v_pars->gamma_inner, __pyx_v_pars->gamma_outer);
 382:             pars.mt, pars.mr, sepa_right,
 383:             norm, pars.rchar, pars.gamma_inner, pars.gamma_outer
 384:         )
 385: 
 386:         # Find time to move from left to right
+387:         dt = 2.0 * (sepa_right - sepa_left) / (dadt_left + dadt_right)
    __pyx_v_dt = ((2.0 * (__pyx_v_sepa_right - __pyx_v_sepa_left)) / (__pyx_v_dadt_left + __pyx_v_dadt_right));
+388:         time += dt
    __pyx_v_time = (__pyx_v_time + __pyx_v_dt);
 389: 
+390:         sepa_left = sepa_right
    __pyx_v_sepa_left = __pyx_v_sepa_right;
+391:         dadt_left = dadt_right
    __pyx_v_dadt_left = __pyx_v_dadt_right;
  }
 392: 
+393:     time = time - pars.target_time
  __pyx_v_time = (__pyx_v_time - __pyx_v_pars->target_time);
+394:     return time
  __pyx_r = __pyx_v_time;
  goto __pyx_L0;
 395: 
 396: 
+397: def integrate_binary_evolution_2pwl(norm_log10, mtot, mrat, sepa_init, rchar, gamma_inner, gamma_outer, nsteps):
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_9integrate_binary_evolution_2pwl(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_9integrate_binary_evolution_2pwl = {"integrate_binary_evolution_2pwl", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_9integrate_binary_evolution_2pwl, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_8holodeck_10sam_cython_9integrate_binary_evolution_2pwl(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_norm_log10 = 0;
  PyObject *__pyx_v_mtot = 0;
  PyObject *__pyx_v_mrat = 0;
  PyObject *__pyx_v_sepa_init = 0;
  PyObject *__pyx_v_rchar = 0;
  PyObject *__pyx_v_gamma_inner = 0;
  PyObject *__pyx_v_gamma_outer = 0;
  PyObject *__pyx_v_nsteps = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_binary_evolution_2pwl (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_norm_log10,&__pyx_n_s_mtot,&__pyx_n_s_mrat,&__pyx_n_s_sepa_init,&__pyx_n_s_rchar,&__pyx_n_s_gamma_inner,&__pyx_n_s_gamma_outer,&__pyx_n_s_nsteps,0};
    PyObject* values[8] = {0,0,0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
        CYTHON_FALLTHROUGH;
        case  7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
        CYTHON_FALLTHROUGH;
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_norm_log10)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mtot)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 1); __PYX_ERR(0, 397, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mrat)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 2); __PYX_ERR(0, 397, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sepa_init)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 3); __PYX_ERR(0, 397, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rchar)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 4); __PYX_ERR(0, 397, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_inner)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 5); __PYX_ERR(0, 397, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  6:
        if (likely((values[6] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_outer)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 6); __PYX_ERR(0, 397, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  7:
        if (likely((values[7] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nsteps)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, 7); __PYX_ERR(0, 397, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "integrate_binary_evolution_2pwl") < 0)) __PYX_ERR(0, 397, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 8) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
      values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
      values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
    }
    __pyx_v_norm_log10 = values[0];
    __pyx_v_mtot = values[1];
    __pyx_v_mrat = values[2];
    __pyx_v_sepa_init = values[3];
    __pyx_v_rchar = values[4];
    __pyx_v_gamma_inner = values[5];
    __pyx_v_gamma_outer = values[6];
    __pyx_v_nsteps = values[7];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("integrate_binary_evolution_2pwl", 1, 8, 8, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 397, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.integrate_binary_evolution_2pwl", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_8integrate_binary_evolution_2pwl(__pyx_self, __pyx_v_norm_log10, __pyx_v_mtot, __pyx_v_mrat, __pyx_v_sepa_init, __pyx_v_rchar, __pyx_v_gamma_inner, __pyx_v_gamma_outer, __pyx_v_nsteps);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_8integrate_binary_evolution_2pwl(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_norm_log10, PyObject *__pyx_v_mtot, PyObject *__pyx_v_mrat, PyObject *__pyx_v_sepa_init, PyObject *__pyx_v_rchar, PyObject *__pyx_v_gamma_inner, PyObject *__pyx_v_gamma_outer, PyObject *__pyx_v_nsteps) {
  __pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params __pyx_v_args;
  double __pyx_v_time;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("integrate_binary_evolution_2pwl", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_AddTraceback("holodeck.sam_cython.integrate_binary_evolution_2pwl", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__29 = PyTuple_Pack(10, __pyx_n_s_norm_log10, __pyx_n_s_mtot, __pyx_n_s_mrat, __pyx_n_s_sepa_init, __pyx_n_s_rchar, __pyx_n_s_gamma_inner, __pyx_n_s_gamma_outer, __pyx_n_s_nsteps, __pyx_n_s_args, __pyx_n_s_time); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(0, 397, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__29);
  __Pyx_GIVEREF(__pyx_tuple__29);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_9integrate_binary_evolution_2pwl, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 397, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_integrate_binary_evolution_2pwl, __pyx_t_1) < 0) __PYX_ERR(0, 397, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__30 = (PyObject*)__Pyx_PyCode_New(8, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__29, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_integrate_binary_evolution_2pwl, 397, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__30)) __PYX_ERR(0, 397, __pyx_L1_error)
 398:     cdef lifetime_2pwl_params args
+399:     args.mt = mtot
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_mtot); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 399, __pyx_L1_error)
  __pyx_v_args.mt = __pyx_t_1;
+400:     args.mr = mrat
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_mrat); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 400, __pyx_L1_error)
  __pyx_v_args.mr = __pyx_t_1;
+401:     args.target_time = 0.0
  __pyx_v_args.target_time = 0.0;
+402:     args.sepa_init = sepa_init
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_sepa_init); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 402, __pyx_L1_error)
  __pyx_v_args.sepa_init = __pyx_t_1;
+403:     args.rchar = rchar
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_rchar); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 403, __pyx_L1_error)
  __pyx_v_args.rchar = __pyx_t_1;
+404:     args.gamma_inner = gamma_inner
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_gamma_inner); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 404, __pyx_L1_error)
  __pyx_v_args.gamma_inner = __pyx_t_1;
+405:     args.gamma_outer = gamma_outer
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_gamma_outer); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 405, __pyx_L1_error)
  __pyx_v_args.gamma_outer = __pyx_t_1;
+406:     args.nsteps = nsteps
  __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_v_nsteps); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 406, __pyx_L1_error)
  __pyx_v_args.nsteps = __pyx_t_2;
 407: 
+408:     time = get_binary_lifetime_2pwl(norm_log10, <lifetime_2pwl_params *> &args)
  __pyx_t_1 = __pyx_PyFloat_AsDouble(__pyx_v_norm_log10); if (unlikely((__pyx_t_1 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 408, __pyx_L1_error)
  __pyx_v_time = __pyx_f_8holodeck_10sam_cython_get_binary_lifetime_2pwl(__pyx_t_1, ((__pyx_t_8holodeck_10sam_cython_lifetime_2pwl_params *)(&__pyx_v_args)));
+409:     return time
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_time); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 409, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_r = __pyx_t_3;
  __pyx_t_3 = 0;
  goto __pyx_L0;
 410: 
 411: 
 412: # ==================================================================================================
 413: # ====    Dynamic Binary Number - calculate number of binaries at each frequency    ====
 414: # ==================================================================================================
 415: 
 416: 
+417: def dynamic_binary_number_at_fobs(fobs_orb, sam, hard, cosmo):
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_11dynamic_binary_number_at_fobs(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_11dynamic_binary_number_at_fobs = {"dynamic_binary_number_at_fobs", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_11dynamic_binary_number_at_fobs, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_8holodeck_10sam_cython_11dynamic_binary_number_at_fobs(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_fobs_orb = 0;
  PyObject *__pyx_v_sam = 0;
  PyObject *__pyx_v_hard = 0;
  PyObject *__pyx_v_cosmo = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("dynamic_binary_number_at_fobs (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_fobs_orb,&__pyx_n_s_sam,&__pyx_n_s_hard,&__pyx_n_s_cosmo,0};
    PyObject* values[4] = {0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_fobs_orb)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sam)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("dynamic_binary_number_at_fobs", 1, 4, 4, 1); __PYX_ERR(0, 417, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_hard)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("dynamic_binary_number_at_fobs", 1, 4, 4, 2); __PYX_ERR(0, 417, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_cosmo)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("dynamic_binary_number_at_fobs", 1, 4, 4, 3); __PYX_ERR(0, 417, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "dynamic_binary_number_at_fobs") < 0)) __PYX_ERR(0, 417, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 4) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
    }
    __pyx_v_fobs_orb = values[0];
    __pyx_v_sam = values[1];
    __pyx_v_hard = values[2];
    __pyx_v_cosmo = values[3];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("dynamic_binary_number_at_fobs", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 417, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.dynamic_binary_number_at_fobs", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_10dynamic_binary_number_at_fobs(__pyx_self, __pyx_v_fobs_orb, __pyx_v_sam, __pyx_v_hard, __pyx_v_cosmo);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_10dynamic_binary_number_at_fobs(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fobs_orb, PyObject *__pyx_v_sam, PyObject *__pyx_v_hard, PyObject *__pyx_v_cosmo) {
  PyObject *__pyx_v_dens = NULL;
  PyObject *__pyx_v_shape = NULL;
  PyArrayObject *__pyx_v_diff_num = 0;
  PyArrayObject *__pyx_v_redz_final = 0;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_diff_num;
  __Pyx_Buffer __pyx_pybuffer_diff_num;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_redz_final;
  __Pyx_Buffer __pyx_pybuffer_redz_final;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("dynamic_binary_number_at_fobs", 0);
  __pyx_pybuffer_diff_num.pybuffer.buf = NULL;
  __pyx_pybuffer_diff_num.refcount = 0;
  __pyx_pybuffernd_diff_num.data = NULL;
  __pyx_pybuffernd_diff_num.rcbuffer = &__pyx_pybuffer_diff_num;
  __pyx_pybuffer_redz_final.pybuffer.buf = NULL;
  __pyx_pybuffer_redz_final.refcount = 0;
  __pyx_pybuffernd_redz_final.data = NULL;
  __pyx_pybuffernd_redz_final.rcbuffer = &__pyx_pybuffer_redz_final;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __PYX_XDEC_MEMVIEW(&__pyx_t_8, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_20, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_21, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_22, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_23, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_24, 1);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_diff_num.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_redz_final.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("holodeck.sam_cython.dynamic_binary_number_at_fobs", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_diff_num.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_redz_final.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF(__pyx_v_dens);
  __Pyx_XDECREF(__pyx_v_shape);
  __Pyx_XDECREF((PyObject *)__pyx_v_diff_num);
  __Pyx_XDECREF((PyObject *)__pyx_v_redz_final);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__31 = PyTuple_Pack(8, __pyx_n_s_fobs_orb, __pyx_n_s_sam, __pyx_n_s_hard, __pyx_n_s_cosmo, __pyx_n_s_dens, __pyx_n_s_shape, __pyx_n_s_diff_num, __pyx_n_s_redz_final); if (unlikely(!__pyx_tuple__31)) __PYX_ERR(0, 417, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__31);
  __Pyx_GIVEREF(__pyx_tuple__31);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_11dynamic_binary_number_at_fobs, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 417, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_dynamic_binary_number_at_fobs, __pyx_t_1) < 0) __PYX_ERR(0, 417, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__32 = (PyObject*)__Pyx_PyCode_New(4, 0, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__31, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_dynamic_binary_number_at_fobs, 417, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__32)) __PYX_ERR(0, 417, __pyx_L1_error)
 418: 
+419:     dens = sam.static_binary_density
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_static_binary_density); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 419, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_v_dens = __pyx_t_1;
  __pyx_t_1 = 0;
 420: 
+421:     shape = sam.shape + (fobs_orb.size,)
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 421, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_fobs_orb, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 421, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 421, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_GIVEREF(__pyx_t_2);
  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
  __pyx_t_2 = 0;
  __pyx_t_2 = PyNumber_Add(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 421, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_v_shape = __pyx_t_2;
  __pyx_t_2 = 0;
+422:     cdef np.ndarray[np.double_t, ndim=4] diff_num = np.zeros(shape)
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 422, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_zeros); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 422, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) {
    __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1);
    if (likely(__pyx_t_3)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
      __Pyx_INCREF(__pyx_t_3);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_1, function);
    }
  }
  __pyx_t_2 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_3, __pyx_v_shape) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v_shape);
  __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 422, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 422, __pyx_L1_error)
  __pyx_t_4 = ((PyArrayObject *)__pyx_t_2);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_diff_num.rcbuffer->pybuffer, (PyObject*)__pyx_t_4, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 4, 0, __pyx_stack) == -1)) {
      __pyx_v_diff_num = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 422, __pyx_L1_error)
    } else {__pyx_pybuffernd_diff_num.diminfo[0].strides = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_diff_num.diminfo[0].shape = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_diff_num.diminfo[1].strides = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_diff_num.diminfo[1].shape = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_diff_num.diminfo[2].strides = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_diff_num.diminfo[2].shape = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.shape[2]; __pyx_pybuffernd_diff_num.diminfo[3].strides = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.strides[3]; __pyx_pybuffernd_diff_num.diminfo[3].shape = __pyx_pybuffernd_diff_num.rcbuffer->pybuffer.shape[3];
    }
  }
  __pyx_t_4 = 0;
  __pyx_v_diff_num = ((PyArrayObject *)__pyx_t_2);
  __pyx_t_2 = 0;
+423:     cdef np.ndarray[np.double_t, ndim=4] redz_final = -1.0 * np.ones(shape)
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 423, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ones); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 423, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_1)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_1);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  __pyx_t_2 = (__pyx_t_1) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_1, __pyx_v_shape) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_shape);
  __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 423, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = PyNumber_Multiply(__pyx_float_neg_1_0, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 423, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 423, __pyx_L1_error)
  __pyx_t_5 = ((PyArrayObject *)__pyx_t_3);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_redz_final.rcbuffer->pybuffer, (PyObject*)__pyx_t_5, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 4, 0, __pyx_stack) == -1)) {
      __pyx_v_redz_final = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 423, __pyx_L1_error)
    } else {__pyx_pybuffernd_redz_final.diminfo[0].strides = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_redz_final.diminfo[0].shape = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_redz_final.diminfo[1].strides = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_redz_final.diminfo[1].shape = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_redz_final.diminfo[2].strides = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_redz_final.diminfo[2].shape = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.shape[2]; __pyx_pybuffernd_redz_final.diminfo[3].strides = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.strides[3]; __pyx_pybuffernd_redz_final.diminfo[3].shape = __pyx_pybuffernd_redz_final.rcbuffer->pybuffer.shape[3];
    }
  }
  __pyx_t_5 = 0;
  __pyx_v_redz_final = ((PyArrayObject *)__pyx_t_3);
  __pyx_t_3 = 0;
 424: 
 425:     # ---- Fixed_Time_2pwl_SAM
 426: 
+427:     if isinstance(hard, holo.hardening.Fixed_Time_2PL_SAM):
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_holo); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 427, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_hardening); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 427, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_Fixed_Time_2PL_SAM); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 427, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_6 = PyObject_IsInstance(__pyx_v_hard, __pyx_t_3); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 427, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_7 = (__pyx_t_6 != 0);
  if (__pyx_t_7) {
/* … */
    goto __pyx_L3;
  }
 428: 
+429:         _dynamic_binary_number_at_fobs_2pwl(
    __pyx_t_25 = __pyx_f_8holodeck_10sam_cython__dynamic_binary_number_at_fobs_2pwl(__pyx_t_8, __pyx_t_9, __pyx_t_10, __pyx_t_11, __pyx_t_12, __pyx_t_13, __pyx_t_14, __pyx_t_15, __pyx_t_16, __pyx_t_17, __pyx_t_18, __pyx_t_19, __pyx_t_20, __pyx_t_21, __pyx_t_22, __pyx_t_23, __pyx_t_24); if (unlikely(__pyx_t_25 == ((int)-1))) __PYX_ERR(0, 429, __pyx_L1_error)
    __PYX_XDEC_MEMVIEW(&__pyx_t_8, 1);
    __pyx_t_8.memview = NULL;
    __pyx_t_8.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
    __pyx_t_11.memview = NULL;
    __pyx_t_11.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
    __pyx_t_15.memview = NULL;
    __pyx_t_15.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
    __pyx_t_16.memview = NULL;
    __pyx_t_16.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
    __pyx_t_17.memview = NULL;
    __pyx_t_17.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
    __pyx_t_18.memview = NULL;
    __pyx_t_18.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
    __pyx_t_19.memview = NULL;
    __pyx_t_19.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_20, 1);
    __pyx_t_20.memview = NULL;
    __pyx_t_20.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_21, 1);
    __pyx_t_21.memview = NULL;
    __pyx_t_21.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_22, 1);
    __pyx_t_22.memview = NULL;
    __pyx_t_22.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_23, 1);
    __pyx_t_23.memview = NULL;
    __pyx_t_23.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_24, 1);
    __pyx_t_24.memview = NULL;
    __pyx_t_24.data = NULL;
+430:             fobs_orb, hard._sepa_init, hard._num_steps,
    __pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_fobs_orb, PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 430, __pyx_L1_error)
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_hard, __pyx_n_s_sepa_init_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 430, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_9 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_9 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 430, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_hard, __pyx_n_s_num_steps); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 430, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_10 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_10 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 430, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+431:             hard._norm, hard._rchar, hard._gamma_inner, hard._gamma_outer,
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_hard, __pyx_n_s_norm_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_hard, __pyx_n_s_rchar_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_12 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_12 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_hard, __pyx_n_s_gamma_inner_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_13 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_13 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_hard, __pyx_n_s_gamma_outer_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_14 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_14 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 431, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+432:             dens, sam.mtot, sam.mrat, sam.redz, sam._gmt_time,
    __pyx_t_15 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_v_dens, PyBUF_WRITABLE); if (unlikely(!__pyx_t_15.memview)) __PYX_ERR(0, 432, __pyx_L1_error)
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_mtot); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_16 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_16.memview)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_mrat); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_17 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_17.memview)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_redz); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_18 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_18.memview)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_gmt_time); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_19 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_19.memview)) __PYX_ERR(0, 432, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+433:             cosmo._grid_z, cosmo._grid_dcom, cosmo._grid_age,
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cosmo, __pyx_n_s_grid_z); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 433, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_20 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_20.memview)) __PYX_ERR(0, 433, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cosmo, __pyx_n_s_grid_dcom); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 433, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_21 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_21.memview)) __PYX_ERR(0, 433, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cosmo, __pyx_n_s_grid_age); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 433, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_22 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_22.memview)) __PYX_ERR(0, 433, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 434:             # output:
+435:             redz_final, diff_num
    __pyx_t_23 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(((PyObject *)__pyx_v_redz_final), PyBUF_WRITABLE); if (unlikely(!__pyx_t_23.memview)) __PYX_ERR(0, 435, __pyx_L1_error)
    __pyx_t_24 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(((PyObject *)__pyx_v_diff_num), PyBUF_WRITABLE); if (unlikely(!__pyx_t_24.memview)) __PYX_ERR(0, 435, __pyx_L1_error)
 436:         )
 437: 
 438:     # ---- Hard_GW
 439: 
+440:     elif isinstance(hard, holo.hardening.Hard_GW) or issubclass(hard, holo.hardening.Hard_GW):
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_holo); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_hardening); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_Hard_GW); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_6 = PyObject_IsInstance(__pyx_v_hard, __pyx_t_3); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_26 = (__pyx_t_6 != 0);
  if (!__pyx_t_26) {
  } else {
    __pyx_t_7 = __pyx_t_26;
    goto __pyx_L4_bool_binop_done;
  }
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_holo); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_hardening); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_Hard_GW); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_26 = PyObject_IsSubclass(__pyx_v_hard, __pyx_t_3); if (unlikely(__pyx_t_26 == ((int)-1))) __PYX_ERR(0, 440, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_6 = (__pyx_t_26 != 0);
  __pyx_t_7 = __pyx_t_6;
  __pyx_L4_bool_binop_done:;
  if (likely(__pyx_t_7)) {
/* … */
    goto __pyx_L3;
  }
+441:         _dynamic_binary_number_at_fobs_gw(
    __pyx_t_25 = __pyx_f_8holodeck_10sam_cython__dynamic_binary_number_at_fobs_gw(__pyx_t_22, __pyx_t_19, __pyx_t_21, __pyx_t_20, __pyx_t_18, __pyx_t_15, __pyx_t_17, __pyx_t_16, __pyx_t_24, __pyx_t_23); if (unlikely(__pyx_t_25 == ((int)-1))) __PYX_ERR(0, 441, __pyx_L1_error)
    __PYX_XDEC_MEMVIEW(&__pyx_t_22, 1);
    __pyx_t_22.memview = NULL;
    __pyx_t_22.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
    __pyx_t_19.memview = NULL;
    __pyx_t_19.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_21, 1);
    __pyx_t_21.memview = NULL;
    __pyx_t_21.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_20, 1);
    __pyx_t_20.memview = NULL;
    __pyx_t_20.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_18, 1);
    __pyx_t_18.memview = NULL;
    __pyx_t_18.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_15, 1);
    __pyx_t_15.memview = NULL;
    __pyx_t_15.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_17, 1);
    __pyx_t_17.memview = NULL;
    __pyx_t_17.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_16, 1);
    __pyx_t_16.memview = NULL;
    __pyx_t_16.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_24, 1);
    __pyx_t_24.memview = NULL;
    __pyx_t_24.data = NULL;
    __PYX_XDEC_MEMVIEW(&__pyx_t_23, 1);
    __pyx_t_23.memview = NULL;
    __pyx_t_23.data = NULL;
+442:             fobs_orb,
    __pyx_t_22 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_fobs_orb, PyBUF_WRITABLE); if (unlikely(!__pyx_t_22.memview)) __PYX_ERR(0, 442, __pyx_L1_error)
+443:             dens, sam.mtot, sam.mrat, sam.redz, sam._redz_prime,
    __pyx_t_19 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_v_dens, PyBUF_WRITABLE); if (unlikely(!__pyx_t_19.memview)) __PYX_ERR(0, 443, __pyx_L1_error)
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_mtot); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_21 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_21.memview)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_mrat); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_20 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_20.memview)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_redz); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_18 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_18.memview)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_sam, __pyx_n_s_redz_prime); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_15 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_15.memview)) __PYX_ERR(0, 443, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+444:             cosmo._grid_z, cosmo._grid_dcom,
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cosmo, __pyx_n_s_grid_z); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 444, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_17 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_17.memview)) __PYX_ERR(0, 444, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cosmo, __pyx_n_s_grid_dcom); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 444, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_16 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_3, PyBUF_WRITABLE); if (unlikely(!__pyx_t_16.memview)) __PYX_ERR(0, 444, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 445:             # output:
+446:             redz_final, diff_num
    __pyx_t_24 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(((PyObject *)__pyx_v_redz_final), PyBUF_WRITABLE); if (unlikely(!__pyx_t_24.memview)) __PYX_ERR(0, 446, __pyx_L1_error)
    __pyx_t_23 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(((PyObject *)__pyx_v_diff_num), PyBUF_WRITABLE); if (unlikely(!__pyx_t_23.memview)) __PYX_ERR(0, 446, __pyx_L1_error)
 447:         )
 448: 
 449:     # ---- OTHER
 450: 
 451:     else:
+452:         raise ValueError(f"Unexpected `hard` value {hard}!")
  /*else*/ {
    __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 452, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_27 = 0;
    __pyx_t_28 = 127;
    __Pyx_INCREF(__pyx_kp_u_Unexpected_hard_value);
    __pyx_t_27 += 24;
    __Pyx_GIVEREF(__pyx_kp_u_Unexpected_hard_value);
    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_kp_u_Unexpected_hard_value);
    __pyx_t_2 = __Pyx_PyObject_FormatSimple(__pyx_v_hard, __pyx_empty_unicode); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 452, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_28 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_2) > __pyx_t_28) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_2) : __pyx_t_28;
    __pyx_t_27 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_2);
    __Pyx_GIVEREF(__pyx_t_2);
    PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
    __pyx_t_2 = 0;
    __Pyx_INCREF(__pyx_kp_u_);
    __pyx_t_27 += 1;
    __Pyx_GIVEREF(__pyx_kp_u_);
    PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_kp_u_);
    __pyx_t_2 = __Pyx_PyUnicode_Join(__pyx_t_3, 3, __pyx_t_27, __pyx_t_28); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 452, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 452, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __PYX_ERR(0, 452, __pyx_L1_error)
  }
  __pyx_L3:;
 453: 
+454:     return redz_final, diff_num
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 454, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_INCREF(((PyObject *)__pyx_v_redz_final));
  __Pyx_GIVEREF(((PyObject *)__pyx_v_redz_final));
  PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_redz_final));
  __Pyx_INCREF(((PyObject *)__pyx_v_diff_num));
  __Pyx_GIVEREF(((PyObject *)__pyx_v_diff_num));
  PyTuple_SET_ITEM(__pyx_t_3, 1, ((PyObject *)__pyx_v_diff_num));
  __pyx_r = __pyx_t_3;
  __pyx_t_3 = 0;
  goto __pyx_L0;
 455: 
 456: @cython.boundscheck(False)
 457: @cython.wraparound(False)
 458: @cython.nonecheck(False)
 459: @cython.cdivision(True)
+460: cdef int _dynamic_binary_number_at_fobs_2pwl(
static int __pyx_f_8holodeck_10sam_cython__dynamic_binary_number_at_fobs_2pwl(__Pyx_memviewslice __pyx_v_target_fobs_orb, double __pyx_v_sepa_init, int __pyx_v_num_steps, __Pyx_memviewslice __pyx_v_hard_norm, double __pyx_v_hard_rchar, double __pyx_v_hard_gamma_inner, double __pyx_v_hard_gamma_outer, __Pyx_memviewslice __pyx_v_dens, __Pyx_memviewslice __pyx_v_mtot, __Pyx_memviewslice __pyx_v_mrat, __Pyx_memviewslice __pyx_v_redz, __Pyx_memviewslice __pyx_v_gmt_time, __Pyx_memviewslice __pyx_v_redz_interp_grid, __Pyx_memviewslice __pyx_v_dcom_interp_grid, __Pyx_memviewslice __pyx_v_tage_interp_grid, __Pyx_memviewslice __pyx_v_redz_final, __Pyx_memviewslice __pyx_v_diff_num) {
  int __pyx_v_n_mtot;
  int __pyx_v_n_mrat;
  int __pyx_v_n_redz;
  int __pyx_v_n_freq;
  int __pyx_v_n_interp;
  double __pyx_v_age_universe;
  double __pyx_v_sepa_init_log10;
  int __pyx_v_ii;
  int __pyx_v_jj;
  int __pyx_v_kk;
  int __pyx_v_ff;
  CYTHON_UNUSED int __pyx_v_step;
  int __pyx_v_interp_left_idx;
  int __pyx_v_interp_right_idx;
  int __pyx_v_new_interp_idx;
  double __pyx_v_mt;
  double __pyx_v_mr;
  double __pyx_v_norm;
  double __pyx_v_risco;
  double __pyx_v_dx;
  double __pyx_v_new_redz;
  double __pyx_v_gmt;
  double __pyx_v_ftarget;
  double __pyx_v_target_frst_orb;
  double __pyx_v_sepa_log10;
  double __pyx_v_sepa;
  double __pyx_v_sepa_left;
  double __pyx_v_sepa_right;
  double __pyx_v_dadt_left;
  double __pyx_v_dadt_right;
  double __pyx_v_time_evo;
  double __pyx_v_redz_left;
  double __pyx_v_redz_right;
  double __pyx_v_time_left;
  double __pyx_v_time_right;
  double __pyx_v_new_time;
  double __pyx_v_frst_orb_left;
  double __pyx_v_fobs_orb_left;
  double __pyx_v_frst_orb_right;
  double __pyx_v_fobs_orb_right;
  double *__pyx_v_redz_age;
  int __pyx_v_rev;
  double __pyx_v_dt;
  double __pyx_v_dcom;
  double __pyx_v_dadt;
  double __pyx_v_tres;
  double __pyx_v_cosmo_fact;
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_dynamic_binary_number_at_fobs_2pwl", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_AddTraceback("holodeck.sam_cython._dynamic_binary_number_at_fobs_2pwl", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = -1;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 461:     double[:] target_fobs_orb,
 462:     double sepa_init,
 463:     int num_steps,
 464: 
 465:     double[:, :] hard_norm,
 466:     double hard_rchar,
 467:     double hard_gamma_inner,
 468:     double hard_gamma_outer,
 469: 
 470:     double[:, :, :] dens,
 471:     double[:] mtot,
 472:     double[:] mrat,
 473:     double[:] redz,
 474:     double[:, :, :] gmt_time,
 475: 
 476:     double[:] redz_interp_grid,
 477:     double[:] dcom_interp_grid,
 478:     double[:] tage_interp_grid,
 479: 
 480:     # output
 481:     double[:, :, :, :] redz_final,
 482:     double[:, :, :, :] diff_num,
 483: ) except -1:
 484:     """Convert from binary volume-density (all separations) to binary number at particular frequencies.
 485:     """
 486: 
+487:     cdef int n_mtot = mtot.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_mtot, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 487, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 487, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 487, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_mtot = __pyx_t_3;
+488:     cdef int n_mrat = mrat.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_mrat, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 488, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 488, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 488, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_mrat = __pyx_t_3;
+489:     cdef int n_redz = redz.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_redz, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 489, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 489, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 489, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_redz = __pyx_t_3;
+490:     cdef int n_freq = target_fobs_orb.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_target_fobs_orb, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 490, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 490, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 490, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_freq = __pyx_t_3;
+491:     cdef int n_interp = redz_interp_grid.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_redz_interp_grid, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 491, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 491, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 491, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_interp = __pyx_t_3;
+492:     cdef double age_universe = tage_interp_grid[n_interp - 1]
  __pyx_t_4 = (__pyx_v_n_interp - 1);
  __pyx_v_age_universe = (*((double *) ( /* dim=0 */ (__pyx_v_tage_interp_grid.data + __pyx_t_4 * __pyx_v_tage_interp_grid.strides[0]) )));
+493:     cdef double sepa_init_log10 = log10(sepa_init)
  __pyx_v_sepa_init_log10 = log10(__pyx_v_sepa_init);
 494: 
 495:     cdef int ii, jj, kk, ff, step, interp_left_idx, interp_right_idx, new_interp_idx
 496:     cdef double mt, mr, norm, risco, dx, new_redz, gmt, ftarget, target_frst_orb
 497:     cdef double sepa_log10, sepa, sepa_left, sepa_right, dadt_left, dadt_right
 498:     cdef double time_evo, redz_left, redz_right, time_left, time_right, new_time
 499:     cdef double frst_orb_left, fobs_orb_left, frst_orb_right, fobs_orb_right
 500: 
 501:     # ---- Calculate ages corresponding to SAM `redz` grid
 502: 
+503:     cdef double *redz_age = <double *>malloc(n_redz * sizeof(double))     # (Z,) age of the universe in [sec]
  __pyx_v_redz_age = ((double *)malloc((__pyx_v_n_redz * (sizeof(double)))));
+504:     ii = 0
  __pyx_v_ii = 0;
 505:     cdef int rev
+506:     for kk in range(n_redz):
  __pyx_t_3 = __pyx_v_n_redz;
  __pyx_t_5 = __pyx_t_3;
  for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) {
    __pyx_v_kk = __pyx_t_6;
 507:         # iterate in reverse order to match with `redz_interp_grid` which is decreasing
+508:         rev = n_redz - 1 - kk
    __pyx_v_rev = ((__pyx_v_n_redz - 1) - __pyx_v_kk);
 509:         # get to the right index of the interpolation-grid
+510:         while (redz_interp_grid[ii+1] > redz[rev]) and (ii < n_interp - 1):
    while (1) {
      __pyx_t_4 = (__pyx_v_ii + 1);
      __pyx_t_8 = __pyx_v_rev;
      __pyx_t_9 = (((*((double *) ( /* dim=0 */ (__pyx_v_redz_interp_grid.data + __pyx_t_4 * __pyx_v_redz_interp_grid.strides[0]) ))) > (*((double *) ( /* dim=0 */ (__pyx_v_redz.data + __pyx_t_8 * __pyx_v_redz.strides[0]) )))) != 0);
      if (__pyx_t_9) {
      } else {
        __pyx_t_7 = __pyx_t_9;
        goto __pyx_L7_bool_binop_done;
      }
      __pyx_t_9 = ((__pyx_v_ii < (__pyx_v_n_interp - 1)) != 0);
      __pyx_t_7 = __pyx_t_9;
      __pyx_L7_bool_binop_done:;
      if (!__pyx_t_7) break;
+511:             ii += 1
      __pyx_v_ii = (__pyx_v_ii + 1);
    }
 512: 
 513:         # interpolate
+514:         redz_age[rev] = interp_at_index(ii, redz[rev], redz_interp_grid, tage_interp_grid)
    __pyx_t_8 = __pyx_v_rev;
    (__pyx_v_redz_age[__pyx_v_rev]) = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_ii, (*((double *) ( /* dim=0 */ (__pyx_v_redz.data + __pyx_t_8 * __pyx_v_redz.strides[0]) ))), __pyx_v_redz_interp_grid, __pyx_v_tage_interp_grid);
  }
 515: 
 516:     # ---- calculate dynamic binary numbers for all SAM grid bins
 517: 
+518:     for ii in range(n_mtot):
  __pyx_t_3 = __pyx_v_n_mtot;
  __pyx_t_5 = __pyx_t_3;
  for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) {
    __pyx_v_ii = __pyx_t_6;
+519:         mt = mtot[ii]
    __pyx_t_8 = __pyx_v_ii;
    __pyx_v_mt = (*((double *) ( /* dim=0 */ (__pyx_v_mtot.data + __pyx_t_8 * __pyx_v_mtot.strides[0]) )));
 520: 
 521:         # Determine separation step-size, in log10-space, to integrate from sepa_init to ISCO
+522:         risco = 3.0 * MY_SCHW * mt     # ISCO is 3x combined schwarzschild radius
    __pyx_v_risco = ((3.0 * __pyx_v_8holodeck_10sam_cython_MY_SCHW) * __pyx_v_mt);
+523:         dx = (sepa_init_log10 - log10(risco)) / num_steps
    __pyx_v_dx = ((__pyx_v_sepa_init_log10 - log10(__pyx_v_risco)) / ((double)__pyx_v_num_steps));
 524: 
+525:         for jj in range(n_mrat):
    __pyx_t_10 = __pyx_v_n_mrat;
    __pyx_t_11 = __pyx_t_10;
    for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) {
      __pyx_v_jj = __pyx_t_12;
+526:             mr = mrat[jj]
      __pyx_t_8 = __pyx_v_jj;
      __pyx_v_mr = (*((double *) ( /* dim=0 */ (__pyx_v_mrat.data + __pyx_t_8 * __pyx_v_mrat.strides[0]) )));
 527: 
 528:             # Binary evolution is determined by M and q only
 529:             # so integration is started for each of these bins
+530:             sepa_log10 = sepa_init_log10                # set initial separation to initial value
      __pyx_v_sepa_log10 = __pyx_v_sepa_init_log10;
+531:             norm = hard_norm[ii, jj]                    # get hardening-rate normalization for this bin
      __pyx_t_8 = __pyx_v_ii;
      __pyx_t_4 = __pyx_v_jj;
      __pyx_v_norm = (*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_hard_norm.data + __pyx_t_8 * __pyx_v_hard_norm.strides[0]) ) + __pyx_t_4 * __pyx_v_hard_norm.strides[1]) )));
 532: 
 533:             # Get total hardening rate at left-most edge
+534:             sepa_left = pow(10.0, sepa_log10)
      __pyx_v_sepa_left = pow(10.0, __pyx_v_sepa_log10);
+535:             dadt_left = _hard_func_2pwl_gw(
      __pyx_v_dadt_left = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw(__pyx_v_mt, __pyx_v_mr, __pyx_v_sepa_left, __pyx_v_norm, __pyx_v_hard_rchar, __pyx_v_hard_gamma_inner, __pyx_v_hard_gamma_outer);
 536:                 mt, mr, sepa_left,
 537:                 norm, hard_rchar, hard_gamma_inner, hard_gamma_outer
 538:             )
 539: 
 540:             # get rest-frame orbital frequency of binary at left edge
+541:             frst_orb_left = kepler_freq_from_sepa(mt, sepa_left)
      __pyx_v_frst_orb_left = __pyx_f_8holodeck_10sam_cython_kepler_freq_from_sepa(__pyx_v_mt, __pyx_v_sepa_left);
 542: 
 543:             # ---- Integrate of `num_steps` discrete intervals in binary separation from large to small
 544: 
+545:             time_evo = 0.0                  # track total binary evolution time
      __pyx_v_time_evo = 0.0;
+546:             interp_left_idx = 0                 # interpolation index, will be updated in each step
      __pyx_v_interp_left_idx = 0;
+547:             for step in range(num_steps):
      __pyx_t_13 = __pyx_v_num_steps;
      __pyx_t_14 = __pyx_t_13;
      for (__pyx_t_15 = 0; __pyx_t_15 < __pyx_t_14; __pyx_t_15+=1) {
        __pyx_v_step = __pyx_t_15;
 548:                 # Increment the current separation
+549:                 sepa_log10 -= dx
        __pyx_v_sepa_log10 = (__pyx_v_sepa_log10 - __pyx_v_dx);
+550:                 sepa_right = pow(10.0, sepa_log10)
        __pyx_v_sepa_right = pow(10.0, __pyx_v_sepa_log10);
+551:                 frst_orb_right = kepler_freq_from_sepa(mt, sepa_right)
        __pyx_v_frst_orb_right = __pyx_f_8holodeck_10sam_cython_kepler_freq_from_sepa(__pyx_v_mt, __pyx_v_sepa_right);
 552: 
 553:                 # Get total hardening rate at the right-edge of this step (left-edge already obtained)
+554:                 dadt_right = _hard_func_2pwl_gw(
        __pyx_v_dadt_right = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw(__pyx_v_mt, __pyx_v_mr, __pyx_v_sepa_right, __pyx_v_norm, __pyx_v_hard_rchar, __pyx_v_hard_gamma_inner, __pyx_v_hard_gamma_outer);
 555:                     mt, mr, sepa_right,
 556:                     norm, hard_rchar, hard_gamma_inner, hard_gamma_outer
 557:                 )
 558: 
 559:                 # Find time to move from left- to right- edges:  dt = da / (da/dt)
+560:                 dt = 2.0 * (sepa_right - sepa_left) / (dadt_left + dadt_right)
        __pyx_v_dt = ((2.0 * (__pyx_v_sepa_right - __pyx_v_sepa_left)) / (__pyx_v_dadt_left + __pyx_v_dadt_right));
+561:                 time_evo += dt
        __pyx_v_time_evo = (__pyx_v_time_evo + __pyx_v_dt);
 562: 
 563:                 # ---- Iterate over starting redshift bins
 564: 
+565:                 for kk in range(n_redz-1, -1, -1):
        for (__pyx_t_16 = (__pyx_v_n_redz - 1); __pyx_t_16 > -1; __pyx_t_16-=1) {
          __pyx_v_kk = __pyx_t_16;
 566:                     # get the total time from each starting redshift, plus GMT time, plus evolution time to this step
+567:                     gmt = gmt_time[ii, jj, kk]
          __pyx_t_4 = __pyx_v_ii;
          __pyx_t_8 = __pyx_v_jj;
          __pyx_t_17 = __pyx_v_kk;
          __pyx_v_gmt = (*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_gmt_time.data + __pyx_t_4 * __pyx_v_gmt_time.strides[0]) ) + __pyx_t_8 * __pyx_v_gmt_time.strides[1]) ) + __pyx_t_17 * __pyx_v_gmt_time.strides[2]) )));
+568:                     time_right = time_evo + gmt + redz_age[kk]
          __pyx_v_time_right = ((__pyx_v_time_evo + __pyx_v_gmt) + (__pyx_v_redz_age[__pyx_v_kk]));
 569:                     # also get the evolution-time to the left edge
+570:                     time_left = time_right - dt
          __pyx_v_time_left = (__pyx_v_time_right - __pyx_v_dt);
 571: 
 572:                     # if we pass the age of the universe, this binary has stalled, no further redshifts will work
 573:                     # NOTE: if `gmt_time` decreases faster than redshift bins increase the universe age,
 574:                     #       then systems in later `redz` bins may no longer stall, so we still need to calculate them
 575:                     #       i.e. we can NOT use a `break` statement here
+576:                     if time_left > age_universe:
          __pyx_t_7 = ((__pyx_v_time_left > __pyx_v_age_universe) != 0);
          if (__pyx_t_7) {
/* … */
          }
+577:                         continue
            goto __pyx_L15_continue;
 578: 
 579:                     # find the redshift bins corresponding to left- and right- side of step
 580:                     # left edge
+581:                     interp_left_idx = while_while_increasing(interp_left_idx, n_interp, time_left, tage_interp_grid)
          __pyx_v_interp_left_idx = __pyx_f_8holodeck_10sam_cython_while_while_increasing(__pyx_v_interp_left_idx, __pyx_v_n_interp, __pyx_v_time_left, __pyx_v_tage_interp_grid);
 582: 
+583:                     redz_left = interp_at_index(interp_left_idx, time_left, tage_interp_grid, redz_interp_grid)
          __pyx_v_redz_left = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_interp_left_idx, __pyx_v_time_left, __pyx_v_tage_interp_grid, __pyx_v_redz_interp_grid);
 584: 
 585:                     # double check that left-edge is within age of Universe (should rarely if ever be a problem
 586:                     # but possible due to rounding/interpolation errors
+587:                     if redz_left < 0.0:
          __pyx_t_7 = ((__pyx_v_redz_left < 0.0) != 0);
          if (__pyx_t_7) {
/* … */
          }
+588:                         continue
            goto __pyx_L15_continue;
 589: 
 590:                     # find right-edge starting from left edge, i.e. `interp_left_idx` (`interp_left_idx` is not a typo!)
+591:                     interp_right_idx = while_while_increasing(interp_left_idx, n_interp, time_right, tage_interp_grid)
          __pyx_v_interp_right_idx = __pyx_f_8holodeck_10sam_cython_while_while_increasing(__pyx_v_interp_left_idx, __pyx_v_n_interp, __pyx_v_time_right, __pyx_v_tage_interp_grid);
 592:                     # NOTE: because `time_right` can be larger than age of universe, it can exceed `tage_interp_grid`
 593:                     #       in this case `interp_right_idx=n_interp-2`, and the `interp_at_index` function can still
 594:                     #       be used to extrapolate to further out values, which will likely be negative
 595: 
+596:                     redz_right = interp_at_index(interp_right_idx, time_right, tage_interp_grid, redz_interp_grid)
          __pyx_v_redz_right = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_interp_right_idx, __pyx_v_time_right, __pyx_v_tage_interp_grid, __pyx_v_redz_interp_grid);
 597:                     # NOTE: at this point `redz_right` could be negative, even though `redz_left` is definitely not
+598:                     if redz_right < 0.0:
          __pyx_t_7 = ((__pyx_v_redz_right < 0.0) != 0);
          if (__pyx_t_7) {
/* … */
          }
+599:                         redz_right = 0.0
            __pyx_v_redz_right = 0.0;
 600: 
 601:                     # convert to frequencies
+602:                     fobs_orb_left = frst_orb_left / (1.0 + redz_left)
          __pyx_v_fobs_orb_left = (__pyx_v_frst_orb_left / (1.0 + __pyx_v_redz_left));
+603:                     fobs_orb_right = frst_orb_right / (1.0 + redz_right)
          __pyx_v_fobs_orb_right = (__pyx_v_frst_orb_right / (1.0 + __pyx_v_redz_right));
 604: 
 605:                     # ---- Iterate over all target frequencies
 606: 
 607:                     # NOTE: there should be a more efficient way to do this.
 608:                     #       Tried a different implementation in `_dynamic_binary_number_at_fobs_1`, but not working
 609:                     #       some of the frequency bins seem to be getting skipped in that version.
 610: 
+611:                     for ff in range(n_freq):
          __pyx_t_18 = __pyx_v_n_freq;
          __pyx_t_19 = __pyx_t_18;
          for (__pyx_t_20 = 0; __pyx_t_20 < __pyx_t_19; __pyx_t_20+=1) {
            __pyx_v_ff = __pyx_t_20;
+612:                         ftarget = target_fobs_orb[ff]
            __pyx_t_17 = __pyx_v_ff;
            __pyx_v_ftarget = (*((double *) ( /* dim=0 */ (__pyx_v_target_fobs_orb.data + __pyx_t_17 * __pyx_v_target_fobs_orb.strides[0]) )));
 613: 
 614:                         # If the integration-step does NOT bracket the target frequency, continue to next frequency
+615:                         if (ftarget < fobs_orb_left) or (fobs_orb_right < ftarget):
            __pyx_t_9 = ((__pyx_v_ftarget < __pyx_v_fobs_orb_left) != 0);
            if (!__pyx_t_9) {
            } else {
              __pyx_t_7 = __pyx_t_9;
              goto __pyx_L23_bool_binop_done;
            }
            __pyx_t_9 = ((__pyx_v_fobs_orb_right < __pyx_v_ftarget) != 0);
            __pyx_t_7 = __pyx_t_9;
            __pyx_L23_bool_binop_done:;
            if (__pyx_t_7) {
/* … */
            }
+616:                             continue
              goto __pyx_L20_continue;
 617: 
 618:                         # ------------------------------------------------------
 619:                         # ---- TARGET FOUND ----
 620: 
 621:                         # At this point in the code, this target frequency is inbetween the left- and right- edges
 622:                         # of the integration step, so we can interpolate the evolution to exactly this frequency,
 623:                         # and perform the actual dynamic_binary_number calculation
 624: 
+625:                         new_time = _interp_between_vals(ftarget, fobs_orb_left, fobs_orb_right, time_left, time_right)
            __pyx_v_new_time = __pyx_f_8holodeck_7cyutils__interp_between_vals(__pyx_v_ftarget, __pyx_v_fobs_orb_left, __pyx_v_fobs_orb_right, __pyx_v_time_left, __pyx_v_time_right);
 626: 
 627:                         # `time_right` can be after age of Universe, make sure interpolated value is not
 628:                         #    if it is, then all higher-frequencies will also, so break out of target-frequency loop
+629:                         if new_time > tage_interp_grid[n_interp - 1]:
            __pyx_t_17 = (__pyx_v_n_interp - 1);
            __pyx_t_7 = ((__pyx_v_new_time > (*((double *) ( /* dim=0 */ (__pyx_v_tage_interp_grid.data + __pyx_t_17 * __pyx_v_tage_interp_grid.strides[0]) )))) != 0);
            if (__pyx_t_7) {
/* … */
            }
+630:                             break
              goto __pyx_L21_break;
 631: 
 632:                         # find index in interpolation grid for this exact time
+633:                         new_interp_idx = interp_left_idx      # start from left-step edge
            __pyx_v_new_interp_idx = __pyx_v_interp_left_idx;
+634:                         new_interp_idx = while_while_increasing(new_interp_idx, n_interp, new_time, tage_interp_grid)
            __pyx_v_new_interp_idx = __pyx_f_8holodeck_10sam_cython_while_while_increasing(__pyx_v_new_interp_idx, __pyx_v_n_interp, __pyx_v_new_time, __pyx_v_tage_interp_grid);
 635: 
 636:                         # get redshift
+637:                         new_redz = interp_at_index(new_interp_idx, new_time, tage_interp_grid, redz_interp_grid)
            __pyx_v_new_redz = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_new_interp_idx, __pyx_v_new_time, __pyx_v_tage_interp_grid, __pyx_v_redz_interp_grid);
 638:                         # get comoving distance
+639:                         dcom = interp_at_index(new_interp_idx, new_time, tage_interp_grid, dcom_interp_grid)
            __pyx_v_dcom = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_new_interp_idx, __pyx_v_new_time, __pyx_v_tage_interp_grid, __pyx_v_dcom_interp_grid);
 640: 
 641:                         # Store redshift
+642:                         redz_final[ii, jj, kk, ff] = new_redz
            __pyx_t_17 = __pyx_v_ii;
            __pyx_t_8 = __pyx_v_jj;
            __pyx_t_4 = __pyx_v_kk;
            __pyx_t_21 = __pyx_v_ff;
            *((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_redz_final.data + __pyx_t_17 * __pyx_v_redz_final.strides[0]) ) + __pyx_t_8 * __pyx_v_redz_final.strides[1]) ) + __pyx_t_4 * __pyx_v_redz_final.strides[2]) ) + __pyx_t_21 * __pyx_v_redz_final.strides[3]) )) = __pyx_v_new_redz;
 643: 
 644:                         # find rest-frame orbital frequency and binary separation
+645:                         target_frst_orb = ftarget * (1.0 + new_redz)
            __pyx_v_target_frst_orb = (__pyx_v_ftarget * (1.0 + __pyx_v_new_redz));
+646:                         sepa = kepler_sepa_from_freq(mt, target_frst_orb)
            __pyx_v_sepa = __pyx_f_8holodeck_10sam_cython_kepler_sepa_from_freq(__pyx_v_mt, __pyx_v_target_frst_orb);
 647: 
 648:                         # calculate total hardening rate at this exact separation
+649:                         dadt = _hard_func_2pwl_gw(
            __pyx_v_dadt = __pyx_f_8holodeck_10sam_cython__hard_func_2pwl_gw(__pyx_v_mt, __pyx_v_mr, __pyx_v_sepa, __pyx_v_norm, __pyx_v_hard_rchar, __pyx_v_hard_gamma_inner, __pyx_v_hard_gamma_outer);
 650:                             mt, mr, sepa,
 651:                             norm, hard_rchar, hard_gamma_inner, hard_gamma_outer
 652:                         )
 653: 
 654:                         # calculate residence/hardening time = f/[df/dt] = -(2/3) a/[da/dt]
+655:                         tres = - (2.0/3.0) * sepa / dadt
            __pyx_v_tres = (((-(2.0 / 3.0)) * __pyx_v_sepa) / __pyx_v_dadt);
 656: 
 657:                         # calculate number of binaries
+658:                         cosmo_fact = FOUR_PI_SPLC_OVER_MPC * (1.0 + new_redz) * pow(dcom / MY_MPC, 2)
            __pyx_v_cosmo_fact = ((__pyx_v_8holodeck_10sam_cython_FOUR_PI_SPLC_OVER_MPC * (1.0 + __pyx_v_new_redz)) * pow((__pyx_v_dcom / __pyx_v_8holodeck_10sam_cython_MY_MPC), 2.0));
+659:                         diff_num[ii, jj, kk, ff] = dens[ii, jj, kk] * tres * cosmo_fact
            __pyx_t_21 = __pyx_v_ii;
            __pyx_t_4 = __pyx_v_jj;
            __pyx_t_8 = __pyx_v_kk;
            __pyx_t_17 = __pyx_v_ii;
            __pyx_t_22 = __pyx_v_jj;
            __pyx_t_23 = __pyx_v_kk;
            __pyx_t_24 = __pyx_v_ff;
            *((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_diff_num.data + __pyx_t_17 * __pyx_v_diff_num.strides[0]) ) + __pyx_t_22 * __pyx_v_diff_num.strides[1]) ) + __pyx_t_23 * __pyx_v_diff_num.strides[2]) ) + __pyx_t_24 * __pyx_v_diff_num.strides[3]) )) = (((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_dens.data + __pyx_t_21 * __pyx_v_dens.strides[0]) ) + __pyx_t_4 * __pyx_v_dens.strides[1]) ) + __pyx_t_8 * __pyx_v_dens.strides[2]) ))) * __pyx_v_tres) * __pyx_v_cosmo_fact);
            __pyx_L20_continue:;
          }
          __pyx_L21_break:;
          __pyx_L15_continue:;
        }
 660: 
 661:                         # ----------------------
 662:                         # ------------------------------------------------------
 663: 
 664:                 # update new left edge
+665:                 dadt_left = dadt_right
        __pyx_v_dadt_left = __pyx_v_dadt_right;
+666:                 sepa_left = sepa_right
        __pyx_v_sepa_left = __pyx_v_sepa_right;
+667:                 frst_orb_left = frst_orb_right
        __pyx_v_frst_orb_left = __pyx_v_frst_orb_right;
      }
    }
  }
 668:                 # note that we _cannot_ do this for redz or freqs because the redshift _bin_ is changing
 669: 
+670:     free(redz_age)
  free(__pyx_v_redz_age);
 671: 
+672:     return 0
  __pyx_r = 0;
  goto __pyx_L0;
 673: 
 674: 
 675: @cython.boundscheck(False)
 676: @cython.wraparound(False)
 677: @cython.nonecheck(False)
 678: @cython.cdivision(True)
+679: cdef int _dynamic_binary_number_at_fobs_gw(
static int __pyx_f_8holodeck_10sam_cython__dynamic_binary_number_at_fobs_gw(__Pyx_memviewslice __pyx_v_target_fobs_orb, __Pyx_memviewslice __pyx_v_dens, __Pyx_memviewslice __pyx_v_mtot, __Pyx_memviewslice __pyx_v_mrat, __Pyx_memviewslice __pyx_v_redz, __Pyx_memviewslice __pyx_v_redz_prime, __Pyx_memviewslice __pyx_v_redz_interp_grid, __Pyx_memviewslice __pyx_v_dcom_interp_grid, __Pyx_memviewslice __pyx_v_redz_final, __Pyx_memviewslice __pyx_v_diff_num) {
  int __pyx_v_n_mtot;
  int __pyx_v_n_mrat;
  int __pyx_v_n_redz;
  int __pyx_v_n_freq;
  int __pyx_v_n_interp;
  int __pyx_v_ii;
  int __pyx_v_jj;
  int __pyx_v_kk;
  int __pyx_v_ff;
  int __pyx_v_interp_idx;
  int __pyx_v__kk;
  double __pyx_v_mt;
  double __pyx_v_mr;
  double __pyx_v_ftarget;
  double __pyx_v_target_frst_orb;
  double __pyx_v_sepa;
  double __pyx_v_rad_isco;
  double __pyx_v_frst_orb_isco;
  double __pyx_v_rzp;
  double __pyx_v_dcom;
  double __pyx_v_dadt;
  double __pyx_v_tres;
  double __pyx_v_cosmo_fact;
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_dynamic_binary_number_at_fobs_gw", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_AddTraceback("holodeck.sam_cython._dynamic_binary_number_at_fobs_gw", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = -1;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 680:     double[:] target_fobs_orb,
 681: 
 682:     double[:, :, :] dens,
 683:     double[:] mtot,
 684:     double[:] mrat,
 685:     double[:] redz,
 686:     double[:, :, :] redz_prime,
 687: 
 688:     double[:] redz_interp_grid,
 689:     double[:] dcom_interp_grid,
 690: 
 691:     # output
 692:     double[:, :, :, :] redz_final,
 693:     double[:, :, :, :] diff_num,
 694: ) except -1:
 695:     """Convert from binary volume-density (all separations) to binary number at particular frequencies.
 696:     """
 697: 
+698:     cdef int n_mtot = mtot.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_mtot, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 698, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 698, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_mtot = __pyx_t_3;
+699:     cdef int n_mrat = mrat.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_mrat, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 699, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 699, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 699, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_mrat = __pyx_t_3;
+700:     cdef int n_redz = redz.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_redz, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 700, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 700, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 700, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_redz = __pyx_t_3;
+701:     cdef int n_freq = target_fobs_orb.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_target_fobs_orb, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 701, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 701, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 701, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_freq = __pyx_t_3;
+702:     cdef int n_interp = redz_interp_grid.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_redz_interp_grid, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 702, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 702, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 702, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_interp = __pyx_t_3;
 703: 
 704:     cdef int ii, jj, kk, ff, interp_idx, _kk
 705:     cdef double mt, mr, ftarget, target_frst_orb, sepa, rad_isco, frst_orb_isco, rzp
 706: 
 707: 
 708:     # ---- calculate dynamic binary numbers for all SAM grid bins
 709: 
+710:     for ii in range(n_mtot):
  __pyx_t_3 = __pyx_v_n_mtot;
  __pyx_t_4 = __pyx_t_3;
  for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) {
    __pyx_v_ii = __pyx_t_5;
+711:         mt = mtot[ii]
    __pyx_t_6 = __pyx_v_ii;
    __pyx_v_mt = (*((double *) ( /* dim=0 */ (__pyx_v_mtot.data + __pyx_t_6 * __pyx_v_mtot.strides[0]) )));
+712:         rad_isco = 3.0 * MY_SCHW * mt
    __pyx_v_rad_isco = ((3.0 * __pyx_v_8holodeck_10sam_cython_MY_SCHW) * __pyx_v_mt);
+713:         frst_orb_isco = kepler_freq_from_sepa(mt, rad_isco)
    __pyx_v_frst_orb_isco = __pyx_f_8holodeck_10sam_cython_kepler_freq_from_sepa(__pyx_v_mt, __pyx_v_rad_isco);
 714: 
+715:         for jj in range(n_mrat):
    __pyx_t_7 = __pyx_v_n_mrat;
    __pyx_t_8 = __pyx_t_7;
    for (__pyx_t_9 = 0; __pyx_t_9 < __pyx_t_8; __pyx_t_9+=1) {
      __pyx_v_jj = __pyx_t_9;
+716:             mr = mrat[jj]
      __pyx_t_6 = __pyx_v_jj;
      __pyx_v_mr = (*((double *) ( /* dim=0 */ (__pyx_v_mrat.data + __pyx_t_6 * __pyx_v_mrat.strides[0]) )));
 717: 
+718:             interp_idx = 0
      __pyx_v_interp_idx = 0;
+719:             for _kk in range(n_redz):
      __pyx_t_10 = __pyx_v_n_redz;
      __pyx_t_11 = __pyx_t_10;
      for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) {
        __pyx_v__kk = __pyx_t_12;
+720:                 kk = n_redz - 1 - _kk
        __pyx_v_kk = ((__pyx_v_n_redz - 1) - __pyx_v__kk);
 721: 
 722:                 # redz_prime is -1 for systems past age of Universe
+723:                 rzp = <double>redz_prime[ii, jj, kk]
        __pyx_t_6 = __pyx_v_ii;
        __pyx_t_13 = __pyx_v_jj;
        __pyx_t_14 = __pyx_v_kk;
        __pyx_v_rzp = ((double)(*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_redz_prime.data + __pyx_t_6 * __pyx_v_redz_prime.strides[0]) ) + __pyx_t_13 * __pyx_v_redz_prime.strides[1]) ) + __pyx_t_14 * __pyx_v_redz_prime.strides[2]) ))));
+724:                 if rzp <= 0.0:
        __pyx_t_15 = ((__pyx_v_rzp <= 0.0) != 0);
        if (__pyx_t_15) {
/* … */
        }
+725:                     continue
          goto __pyx_L7_continue;
 726: 
+727:                 for ff in range(n_freq):
        __pyx_t_16 = __pyx_v_n_freq;
        __pyx_t_17 = __pyx_t_16;
        for (__pyx_t_18 = 0; __pyx_t_18 < __pyx_t_17; __pyx_t_18+=1) {
          __pyx_v_ff = __pyx_t_18;
+728:                     redz_final[ii, jj, kk, ff] = rzp
          __pyx_t_14 = __pyx_v_ii;
          __pyx_t_13 = __pyx_v_jj;
          __pyx_t_6 = __pyx_v_kk;
          __pyx_t_19 = __pyx_v_ff;
          *((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_redz_final.data + __pyx_t_14 * __pyx_v_redz_final.strides[0]) ) + __pyx_t_13 * __pyx_v_redz_final.strides[1]) ) + __pyx_t_6 * __pyx_v_redz_final.strides[2]) ) + __pyx_t_19 * __pyx_v_redz_final.strides[3]) )) = __pyx_v_rzp;
 729: 
+730:                     ftarget = target_fobs_orb[ff]
          __pyx_t_19 = __pyx_v_ff;
          __pyx_v_ftarget = (*((double *) ( /* dim=0 */ (__pyx_v_target_fobs_orb.data + __pyx_t_19 * __pyx_v_target_fobs_orb.strides[0]) )));
 731:                     # find rest-frame orbital frequency and binary separation
+732:                     target_frst_orb = ftarget * (1.0 + rzp)
          __pyx_v_target_frst_orb = (__pyx_v_ftarget * (1.0 + __pyx_v_rzp));
 733:                     # if target frequency is above ISCO freq, then all future ones will be also, so: break
+734:                     if target_frst_orb > frst_orb_isco:
          __pyx_t_15 = ((__pyx_v_target_frst_orb > __pyx_v_frst_orb_isco) != 0);
          if (__pyx_t_15) {
/* … */
          }
+735:                         break
            goto __pyx_L11_break;
 736: 
 737:                     # get comoving distance
+738:                     interp_idx = while_while_decreasing(interp_idx, n_interp, rzp, redz_interp_grid)
          __pyx_v_interp_idx = __pyx_f_8holodeck_10sam_cython_while_while_decreasing(__pyx_v_interp_idx, __pyx_v_n_interp, __pyx_v_rzp, __pyx_v_redz_interp_grid);
+739:                     dcom = interp_at_index(interp_idx, rzp, redz_interp_grid, dcom_interp_grid)
          __pyx_v_dcom = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_interp_idx, __pyx_v_rzp, __pyx_v_redz_interp_grid, __pyx_v_dcom_interp_grid);
 740: 
 741:                     # calculate total hardening rate at this exact separation
+742:                     sepa = kepler_sepa_from_freq(mt, target_frst_orb)
          __pyx_v_sepa = __pyx_f_8holodeck_10sam_cython_kepler_sepa_from_freq(__pyx_v_mt, __pyx_v_target_frst_orb);
+743:                     dadt = hard_gw(mt, mr, sepa)
          __pyx_v_dadt = __pyx_f_8holodeck_10sam_cython_hard_gw(__pyx_v_mt, __pyx_v_mr, __pyx_v_sepa, 0);
 744: 
 745:                     # calculate residence/hardening time = f/[df/dt] = -(2/3) a/[da/dt]
+746:                     tres = - (2.0/3.0) * sepa / dadt
          __pyx_v_tres = (((-(2.0 / 3.0)) * __pyx_v_sepa) / __pyx_v_dadt);
 747: 
 748:                     # calculate number of binaries
+749:                     cosmo_fact = FOUR_PI_SPLC_OVER_MPC * (1.0 + rzp) * pow(dcom / MY_MPC, 2)
          __pyx_v_cosmo_fact = ((__pyx_v_8holodeck_10sam_cython_FOUR_PI_SPLC_OVER_MPC * (1.0 + __pyx_v_rzp)) * pow((__pyx_v_dcom / __pyx_v_8holodeck_10sam_cython_MY_MPC), 2.0));
+750:                     diff_num[ii, jj, kk, ff] = dens[ii, jj, kk] * tres * cosmo_fact
          __pyx_t_19 = __pyx_v_ii;
          __pyx_t_6 = __pyx_v_jj;
          __pyx_t_13 = __pyx_v_kk;
          __pyx_t_14 = __pyx_v_ii;
          __pyx_t_20 = __pyx_v_jj;
          __pyx_t_21 = __pyx_v_kk;
          __pyx_t_22 = __pyx_v_ff;
          *((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_diff_num.data + __pyx_t_14 * __pyx_v_diff_num.strides[0]) ) + __pyx_t_20 * __pyx_v_diff_num.strides[1]) ) + __pyx_t_21 * __pyx_v_diff_num.strides[2]) ) + __pyx_t_22 * __pyx_v_diff_num.strides[3]) )) = (((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_dens.data + __pyx_t_19 * __pyx_v_dens.strides[0]) ) + __pyx_t_6 * __pyx_v_dens.strides[1]) ) + __pyx_t_13 * __pyx_v_dens.strides[2]) ))) * __pyx_v_tres) * __pyx_v_cosmo_fact);
        }
        __pyx_L11_break:;
        __pyx_L7_continue:;
      }
    }
  }
 751: 
+752:     return 0
  __pyx_r = 0;
  goto __pyx_L0;
 753: 
 754: 
 755: 
 756: # ==================================================================================================
 757: # ====    DetStats Functions    ====
 758: # ==================================================================================================
 759: 
 760: 
+761: def gamma_of_rho_interp(rho, rsort, rho_interp_grid, gamma_interp_grid):
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_13gamma_of_rho_interp(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_8holodeck_10sam_cython_12gamma_of_rho_interp[] = "\n    rho : 1Darray of scalars\n        SNR of single sources, in flat array\n    rsort : 1Darray\n        order of flat rho values smallest to largest\n    rho_interp_grid : 1Darray\n        rho values corresponding to each gamma\n    gamma_interp_grid : 1Darray\n        gamma values corresponding to each rho\n\n    ";
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_13gamma_of_rho_interp = {"gamma_of_rho_interp", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_13gamma_of_rho_interp, METH_VARARGS|METH_KEYWORDS, __pyx_doc_8holodeck_10sam_cython_12gamma_of_rho_interp};
static PyObject *__pyx_pw_8holodeck_10sam_cython_13gamma_of_rho_interp(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_rho = 0;
  PyObject *__pyx_v_rsort = 0;
  PyObject *__pyx_v_rho_interp_grid = 0;
  PyObject *__pyx_v_gamma_interp_grid = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("gamma_of_rho_interp (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_rho,&__pyx_n_s_rsort,&__pyx_n_s_rho_interp_grid,&__pyx_n_s_gamma_interp_grid,0};
    PyObject* values[4] = {0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rho)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rsort)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("gamma_of_rho_interp", 1, 4, 4, 1); __PYX_ERR(0, 761, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rho_interp_grid)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("gamma_of_rho_interp", 1, 4, 4, 2); __PYX_ERR(0, 761, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_gamma_interp_grid)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("gamma_of_rho_interp", 1, 4, 4, 3); __PYX_ERR(0, 761, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "gamma_of_rho_interp") < 0)) __PYX_ERR(0, 761, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 4) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
    }
    __pyx_v_rho = values[0];
    __pyx_v_rsort = values[1];
    __pyx_v_rho_interp_grid = values[2];
    __pyx_v_gamma_interp_grid = values[3];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("gamma_of_rho_interp", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 761, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.gamma_of_rho_interp", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_12gamma_of_rho_interp(__pyx_self, __pyx_v_rho, __pyx_v_rsort, __pyx_v_rho_interp_grid, __pyx_v_gamma_interp_grid);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_12gamma_of_rho_interp(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_rho, PyObject *__pyx_v_rsort, PyObject *__pyx_v_rho_interp_grid, PyObject *__pyx_v_gamma_interp_grid) {
  PyArrayObject *__pyx_v_gamma = 0;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_gamma;
  __Pyx_Buffer __pyx_pybuffer_gamma;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("gamma_of_rho_interp", 0);
  __pyx_pybuffer_gamma.pybuffer.buf = NULL;
  __pyx_pybuffer_gamma.refcount = 0;
  __pyx_pybuffernd_gamma.data = NULL;
  __pyx_pybuffernd_gamma.rcbuffer = &__pyx_pybuffer_gamma;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_7, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_8, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_10, 1);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_gamma.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("holodeck.sam_cython.gamma_of_rho_interp", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_gamma.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF((PyObject *)__pyx_v_gamma);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__33 = PyTuple_Pack(5, __pyx_n_s_rho, __pyx_n_s_rsort, __pyx_n_s_rho_interp_grid, __pyx_n_s_gamma_interp_grid, __pyx_n_s_gamma); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(0, 761, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__33);
  __Pyx_GIVEREF(__pyx_tuple__33);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_13gamma_of_rho_interp, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 761, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_gamma_of_rho_interp, __pyx_t_1) < 0) __PYX_ERR(0, 761, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__34 = (PyObject*)__Pyx_PyCode_New(4, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__33, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_gamma_of_rho_interp, 761, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__34)) __PYX_ERR(0, 761, __pyx_L1_error)
 762:     """
 763:     rho : 1Darray of scalars
 764:         SNR of single sources, in flat array
 765:     rsort : 1Darray
 766:         order of flat rho values smallest to largest
 767:     rho_interp_grid : 1Darray
 768:         rho values corresponding to each gamma
 769:     gamma_interp_grid : 1Darray
 770:         gamma values corresponding to each rho
 771: 
 772:     """
 773:     # pass in the interp grid
+774:     cdef np.ndarray[np.double_t, ndim=1] gamma = np.zeros(rho.shape)
  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 774, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 774, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_rho, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 774, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_4 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  __pyx_t_1 = (__pyx_t_4) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_4, __pyx_t_2) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2);
  __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 774, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 774, __pyx_L1_error)
  __pyx_t_5 = ((PyArrayObject *)__pyx_t_1);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_gamma.rcbuffer->pybuffer, (PyObject*)__pyx_t_5, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) {
      __pyx_v_gamma = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_gamma.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 774, __pyx_L1_error)
    } else {__pyx_pybuffernd_gamma.diminfo[0].strides = __pyx_pybuffernd_gamma.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_gamma.diminfo[0].shape = __pyx_pybuffernd_gamma.rcbuffer->pybuffer.shape[0];
    }
  }
  __pyx_t_5 = 0;
  __pyx_v_gamma = ((PyArrayObject *)__pyx_t_1);
  __pyx_t_1 = 0;
 775: 
+776:     _gamma_of_rho_interp(rho, rsort, rho_interp_grid, gamma_interp_grid, gamma)
  __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_rho, PyBUF_WRITABLE); if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 776, __pyx_L1_error)
  __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_ds_long(__pyx_v_rsort, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 776, __pyx_L1_error)
  __pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_rho_interp_grid, PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 776, __pyx_L1_error)
  __pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_gamma_interp_grid, PyBUF_WRITABLE); if (unlikely(!__pyx_t_9.memview)) __PYX_ERR(0, 776, __pyx_L1_error)
  __pyx_t_10 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(((PyObject *)__pyx_v_gamma), PyBUF_WRITABLE); if (unlikely(!__pyx_t_10.memview)) __PYX_ERR(0, 776, __pyx_L1_error)
  (void)(__pyx_f_8holodeck_10sam_cython__gamma_of_rho_interp(__pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9, __pyx_t_10));
  __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
  __pyx_t_6.memview = NULL;
  __pyx_t_6.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_7, 1);
  __pyx_t_7.memview = NULL;
  __pyx_t_7.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_8, 1);
  __pyx_t_8.memview = NULL;
  __pyx_t_8.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
  __pyx_t_9.memview = NULL;
  __pyx_t_9.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_10, 1);
  __pyx_t_10.memview = NULL;
  __pyx_t_10.data = NULL;
 777: 
+778:     return gamma
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(((PyObject *)__pyx_v_gamma));
  __pyx_r = ((PyObject *)__pyx_v_gamma);
  goto __pyx_L0;
 779: 
 780: @cython.boundscheck(False)
 781: @cython.wraparound(False)
 782: @cython.nonecheck(False)
 783: @cython.cdivision(True)
+784: cdef int _gamma_of_rho_interp(
static int __pyx_f_8holodeck_10sam_cython__gamma_of_rho_interp(__Pyx_memviewslice __pyx_v_rho, __Pyx_memviewslice __pyx_v_rsort, __Pyx_memviewslice __pyx_v_rho_interp_grid, __Pyx_memviewslice __pyx_v_gamma_interp_grid, __Pyx_memviewslice __pyx_v_gamma) {
  int __pyx_v_n_rho;
  int __pyx_v_n_interp;
  int __pyx_v_ii;
  int __pyx_v_kk;
  int __pyx_v_rr;
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_gamma_of_rho_interp", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_WriteUnraisable("holodeck.sam_cython._gamma_of_rho_interp", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 785:     double[:] rho, long[:] rsort,
 786:     double[:] rho_interp_grid, double[:] gamma_interp_grid,
 787:     # output
 788:     double[:] gamma
 789:     ):
 790:     """ Find gamma of rho by interpolation over rho and gamma grids.
 791:     """
 792: 
+793:     cdef int n_rho = rho.size
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_rho, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 793, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 793, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 793, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_n_rho = __pyx_t_3;
+794:     cdef int n_interp = rho_interp_grid.size
  __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_rho_interp_grid, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 794, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 794, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 794, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_n_interp = __pyx_t_3;
 795:     cdef int ii, kk, rr
+796:     ii = 0 # get rho in order using rho[rsort[ii]]
  __pyx_v_ii = 0;
 797: 
+798:     for kk in range(n_rho):
  __pyx_t_3 = __pyx_v_n_rho;
  __pyx_t_4 = __pyx_t_3;
  for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) {
    __pyx_v_kk = __pyx_t_5;
+799:         rr = rsort[kk] # index of next largest rho, equiv to rev in redz calculation
    __pyx_t_6 = __pyx_v_kk;
    __pyx_v_rr = (*((long *) ( /* dim=0 */ (__pyx_v_rsort.data + __pyx_t_6 * __pyx_v_rsort.strides[0]) )));
 800:         # print('kk =',kk,' rr =', rr, 'rho[rr] =', rho[rr])
 801:         # get to the right index of the interpolation-grid
+802:         while (rho_interp_grid[ii+1] < rho[rr]) and (ii < n_interp -2):
    while (1) {
      __pyx_t_6 = (__pyx_v_ii + 1);
      __pyx_t_8 = __pyx_v_rr;
      __pyx_t_9 = (((*((double *) ( /* dim=0 */ (__pyx_v_rho_interp_grid.data + __pyx_t_6 * __pyx_v_rho_interp_grid.strides[0]) ))) < (*((double *) ( /* dim=0 */ (__pyx_v_rho.data + __pyx_t_8 * __pyx_v_rho.strides[0]) )))) != 0);
      if (__pyx_t_9) {
      } else {
        __pyx_t_7 = __pyx_t_9;
        goto __pyx_L7_bool_binop_done;
      }
      __pyx_t_9 = ((__pyx_v_ii < (__pyx_v_n_interp - 2)) != 0);
      __pyx_t_7 = __pyx_t_9;
      __pyx_L7_bool_binop_done:;
      if (!__pyx_t_7) break;
+803:             ii += 1
      __pyx_v_ii = (__pyx_v_ii + 1);
    }
 804:         # print('ii =',ii, ' rho_interp[ii] =', rho_interp_grid[ii], ' rho_interp[ii+1] =', rho_interp_grid[ii+1])
 805:         # interpolate
+806:         gamma[rr] = interp_at_index(ii, rho[rr], rho_interp_grid, gamma_interp_grid)
    __pyx_t_8 = __pyx_v_rr;
    __pyx_t_6 = __pyx_v_rr;
    *((double *) ( /* dim=0 */ (__pyx_v_gamma.data + __pyx_t_6 * __pyx_v_gamma.strides[0]) )) = __pyx_f_8holodeck_7cyutils_interp_at_index(__pyx_v_ii, (*((double *) ( /* dim=0 */ (__pyx_v_rho.data + __pyx_t_8 * __pyx_v_rho.strides[0]) ))), __pyx_v_rho_interp_grid, __pyx_v_gamma_interp_grid);
  }
 807:         # print('rho =', rho[rr], ' gamma =', gamma[rr], '\n')\
 808: 
+809:     return 0
  __pyx_r = 0;
  goto __pyx_L0;
 810: 
 811: 
+812: def snr_ss(amp, F_iplus, F_icross, iotas, dur, Phi_0, S_i, freqs):
/* Python wrapper */
static PyObject *__pyx_pw_8holodeck_10sam_cython_15snr_ss(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_8holodeck_10sam_cython_14snr_ss[] = " Calculate single source SNR\n\n\n    Parameters\n    ----------\n    amp : (F,R,L) NDarray\n        Dimensionless strain amplitude of loudest single sources\n    F_iplus : (P,F,S,L) NDarray\n        Antenna pattern function for each pulsar.\n    F_icross : (P,F,S,L) NDarray\n        Antenna pattern function for each pulsar.\n    iotas : (F,S,L) NDarray\n        Inclination, used to calculate:\n        a_pol = 1 + np.cos(iotas) **2\n        b_pol = -2 * np.cos(iotas)\n    dur : scalar\n        Duration of observations.\n    Phi_0 : (F,S,L) NDarray\n        Initial GW phase\n    S_i : (P,F,R,L) NDarray\n        Total noise of each pulsar wrt detection of each single source, in s^3\n    freqs : (F,) 1Darray\n        Observed frequency bin centers.\n\n    Returns\n    -------\n    snr_ss : (F,R,S,L) NDarray\n        SNR from the whole PTA for each single source with\n        each realized sky position (S) and realized strain (R)\n\n    ";
static PyMethodDef __pyx_mdef_8holodeck_10sam_cython_15snr_ss = {"snr_ss", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8holodeck_10sam_cython_15snr_ss, METH_VARARGS|METH_KEYWORDS, __pyx_doc_8holodeck_10sam_cython_14snr_ss};
static PyObject *__pyx_pw_8holodeck_10sam_cython_15snr_ss(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_amp = 0;
  PyObject *__pyx_v_F_iplus = 0;
  PyObject *__pyx_v_F_icross = 0;
  PyObject *__pyx_v_iotas = 0;
  PyObject *__pyx_v_dur = 0;
  PyObject *__pyx_v_Phi_0 = 0;
  PyObject *__pyx_v_S_i = 0;
  PyObject *__pyx_v_freqs = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("snr_ss (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_amp,&__pyx_n_s_F_iplus,&__pyx_n_s_F_icross,&__pyx_n_s_iotas,&__pyx_n_s_dur,&__pyx_n_s_Phi_0,&__pyx_n_s_S_i,&__pyx_n_s_freqs,0};
    PyObject* values[8] = {0,0,0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
        CYTHON_FALLTHROUGH;
        case  7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
        CYTHON_FALLTHROUGH;
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_amp)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_F_iplus)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 1); __PYX_ERR(0, 812, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_F_icross)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 2); __PYX_ERR(0, 812, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_iotas)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 3); __PYX_ERR(0, 812, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dur)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 4); __PYX_ERR(0, 812, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_Phi_0)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 5); __PYX_ERR(0, 812, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  6:
        if (likely((values[6] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_S_i)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 6); __PYX_ERR(0, 812, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  7:
        if (likely((values[7] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_freqs)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, 7); __PYX_ERR(0, 812, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "snr_ss") < 0)) __PYX_ERR(0, 812, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 8) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
      values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
      values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
    }
    __pyx_v_amp = values[0];
    __pyx_v_F_iplus = values[1];
    __pyx_v_F_icross = values[2];
    __pyx_v_iotas = values[3];
    __pyx_v_dur = values[4];
    __pyx_v_Phi_0 = values[5];
    __pyx_v_S_i = values[6];
    __pyx_v_freqs = values[7];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("snr_ss", 1, 8, 8, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 812, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("holodeck.sam_cython.snr_ss", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_8holodeck_10sam_cython_14snr_ss(__pyx_self, __pyx_v_amp, __pyx_v_F_iplus, __pyx_v_F_icross, __pyx_v_iotas, __pyx_v_dur, __pyx_v_Phi_0, __pyx_v_S_i, __pyx_v_freqs);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_8holodeck_10sam_cython_14snr_ss(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_amp, PyObject *__pyx_v_F_iplus, PyObject *__pyx_v_F_icross, PyObject *__pyx_v_iotas, PyObject *__pyx_v_dur, PyObject *__pyx_v_Phi_0, PyObject *__pyx_v_S_i, PyObject *__pyx_v_freqs) {
  PyObject *__pyx_v_nfreqs = NULL;
  PyObject *__pyx_v_nreals = NULL;
  PyObject *__pyx_v_nloudest = NULL;
  PyObject *__pyx_v_npsrs = NULL;
  PyObject *__pyx_v_nskies = NULL;
  PyArrayObject *__pyx_v_snr_ss = 0;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_snr_ss;
  __Pyx_Buffer __pyx_pybuffer_snr_ss;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("snr_ss", 0);
  __pyx_pybuffer_snr_ss.pybuffer.buf = NULL;
  __pyx_pybuffer_snr_ss.refcount = 0;
  __pyx_pybuffernd_snr_ss.data = NULL;
  __pyx_pybuffernd_snr_ss.rcbuffer = &__pyx_pybuffer_snr_ss;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_7, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_8, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_12, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_13, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_snr_ss.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("holodeck.sam_cython.snr_ss", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_snr_ss.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF(__pyx_v_nfreqs);
  __Pyx_XDECREF(__pyx_v_nreals);
  __Pyx_XDECREF(__pyx_v_nloudest);
  __Pyx_XDECREF(__pyx_v_npsrs);
  __Pyx_XDECREF(__pyx_v_nskies);
  __Pyx_XDECREF((PyObject *)__pyx_v_snr_ss);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__35 = PyTuple_Pack(14, __pyx_n_s_amp, __pyx_n_s_F_iplus, __pyx_n_s_F_icross, __pyx_n_s_iotas, __pyx_n_s_dur, __pyx_n_s_Phi_0, __pyx_n_s_S_i, __pyx_n_s_freqs, __pyx_n_s_nfreqs, __pyx_n_s_nreals, __pyx_n_s_nloudest, __pyx_n_s_npsrs, __pyx_n_s_nskies, __pyx_n_s_snr_ss); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(0, 812, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__35);
  __Pyx_GIVEREF(__pyx_tuple__35);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8holodeck_10sam_cython_15snr_ss, NULL, __pyx_n_s_holodeck_sam_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 812, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_snr_ss, __pyx_t_1) < 0) __PYX_ERR(0, 812, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__36 = (PyObject*)__Pyx_PyCode_New(8, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__35, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_holodeck_sam_cython_pyx, __pyx_n_s_snr_ss, 812, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__36)) __PYX_ERR(0, 812, __pyx_L1_error)
 813:     """ Calculate single source SNR
 814: 
 815: 
 816:     Parameters
 817:     ----------
 818:     amp : (F,R,L) NDarray
 819:         Dimensionless strain amplitude of loudest single sources
 820:     F_iplus : (P,F,S,L) NDarray
 821:         Antenna pattern function for each pulsar.
 822:     F_icross : (P,F,S,L) NDarray
 823:         Antenna pattern function for each pulsar.
 824:     iotas : (F,S,L) NDarray
 825:         Inclination, used to calculate:
 826:         a_pol = 1 + np.cos(iotas) **2
 827:         b_pol = -2 * np.cos(iotas)
 828:     dur : scalar
 829:         Duration of observations.
 830:     Phi_0 : (F,S,L) NDarray
 831:         Initial GW phase
 832:     S_i : (P,F,R,L) NDarray
 833:         Total noise of each pulsar wrt detection of each single source, in s^3
 834:     freqs : (F,) 1Darray
 835:         Observed frequency bin centers.
 836: 
 837:     Returns
 838:     -------
 839:     snr_ss : (F,R,S,L) NDarray
 840:         SNR from the whole PTA for each single source with
 841:         each realized sky position (S) and realized strain (R)
 842: 
 843:     """
+844:     nfreqs, nreals, nloudest = amp.shape[0], amp.shape[1], amp.shape[2]
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_amp, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 844, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 844, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_amp, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 844, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 844, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_amp, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 844, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_1, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 844, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_nfreqs = __pyx_t_2;
  __pyx_t_2 = 0;
  __pyx_v_nreals = __pyx_t_3;
  __pyx_t_3 = 0;
  __pyx_v_nloudest = __pyx_t_4;
  __pyx_t_4 = 0;
+845:     npsrs, nskies = F_iplus.shape[0], F_iplus.shape[2]
  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_F_iplus, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 845, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 845, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_F_iplus, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 845, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_4, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 845, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_v_npsrs = __pyx_t_3;
  __pyx_t_3 = 0;
  __pyx_v_nskies = __pyx_t_2;
  __pyx_t_2 = 0;
+846:     cdef np.ndarray[np.double_t, ndim=4] snr_ss = np.zeros((nfreqs, nreals, nskies, nloudest))
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 846, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_zeros); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 846, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = PyTuple_New(4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 846, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_INCREF(__pyx_v_nfreqs);
  __Pyx_GIVEREF(__pyx_v_nfreqs);
  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_nfreqs);
  __Pyx_INCREF(__pyx_v_nreals);
  __Pyx_GIVEREF(__pyx_v_nreals);
  PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_nreals);
  __Pyx_INCREF(__pyx_v_nskies);
  __Pyx_GIVEREF(__pyx_v_nskies);
  PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_nskies);
  __Pyx_INCREF(__pyx_v_nloudest);
  __Pyx_GIVEREF(__pyx_v_nloudest);
  PyTuple_SET_ITEM(__pyx_t_3, 3, __pyx_v_nloudest);
  __pyx_t_1 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
    __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_4);
    if (likely(__pyx_t_1)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
      __Pyx_INCREF(__pyx_t_1);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_4, function);
    }
  }
  __pyx_t_2 = (__pyx_t_1) ? __Pyx_PyObject_Call2Args(__pyx_t_4, __pyx_t_1, __pyx_t_3) : __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_3);
  __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 846, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 846, __pyx_L1_error)
  __pyx_t_5 = ((PyArrayObject *)__pyx_t_2);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_snr_ss.rcbuffer->pybuffer, (PyObject*)__pyx_t_5, &__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 4, 0, __pyx_stack) == -1)) {
      __pyx_v_snr_ss = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 846, __pyx_L1_error)
    } else {__pyx_pybuffernd_snr_ss.diminfo[0].strides = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_snr_ss.diminfo[0].shape = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_snr_ss.diminfo[1].strides = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_snr_ss.diminfo[1].shape = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_snr_ss.diminfo[2].strides = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_snr_ss.diminfo[2].shape = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.shape[2]; __pyx_pybuffernd_snr_ss.diminfo[3].strides = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.strides[3]; __pyx_pybuffernd_snr_ss.diminfo[3].shape = __pyx_pybuffernd_snr_ss.rcbuffer->pybuffer.shape[3];
    }
  }
  __pyx_t_5 = 0;
  __pyx_v_snr_ss = ((PyArrayObject *)__pyx_t_2);
  __pyx_t_2 = 0;
+847:     _snr_ss(
  (void)(__pyx_f_8holodeck_10sam_cython__snr_ss(__pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9, __pyx_t_10, __pyx_t_11, __pyx_t_12, __pyx_t_13, __pyx_t_14, __pyx_t_15, __pyx_t_16, __pyx_t_17, __pyx_t_18, __pyx_t_19));
  __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1);
  __pyx_t_6.memview = NULL;
  __pyx_t_6.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_7, 1);
  __pyx_t_7.memview = NULL;
  __pyx_t_7.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_8, 1);
  __pyx_t_8.memview = NULL;
  __pyx_t_8.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
  __pyx_t_9.memview = NULL;
  __pyx_t_9.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __pyx_t_11.memview = NULL;
  __pyx_t_11.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_12, 1);
  __pyx_t_12.memview = NULL;
  __pyx_t_12.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_13, 1);
  __pyx_t_13.memview = NULL;
  __pyx_t_13.data = NULL;
  __PYX_XDEC_MEMVIEW(&__pyx_t_19, 1);
  __pyx_t_19.memview = NULL;
  __pyx_t_19.data = NULL;
+848:         amp, F_iplus, F_icross, iotas, dur, Phi_0, S_i, freqs,
  __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_v_amp, PyBUF_WRITABLE); if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(__pyx_v_F_iplus, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(__pyx_v_F_icross, PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_v_iotas, PyBUF_WRITABLE); if (unlikely(!__pyx_t_9.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_10 = __pyx_PyFloat_AsDouble(__pyx_v_dur); if (unlikely((__pyx_t_10 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_double(__pyx_v_Phi_0, PyBUF_WRITABLE); if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_12 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(__pyx_v_S_i, PyBUF_WRITABLE); if (unlikely(!__pyx_t_12.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
  __pyx_t_13 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_freqs, PyBUF_WRITABLE); if (unlikely(!__pyx_t_13.memview)) __PYX_ERR(0, 848, __pyx_L1_error)
+849:         npsrs, nfreqs, nreals, nskies, nloudest,
  __pyx_t_14 = __Pyx_PyInt_As_long(__pyx_v_npsrs); if (unlikely((__pyx_t_14 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 849, __pyx_L1_error)
  __pyx_t_15 = __Pyx_PyInt_As_long(__pyx_v_nfreqs); if (unlikely((__pyx_t_15 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 849, __pyx_L1_error)
  __pyx_t_16 = __Pyx_PyInt_As_long(__pyx_v_nreals); if (unlikely((__pyx_t_16 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 849, __pyx_L1_error)
  __pyx_t_17 = __Pyx_PyInt_As_long(__pyx_v_nskies); if (unlikely((__pyx_t_17 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 849, __pyx_L1_error)
  __pyx_t_18 = __Pyx_PyInt_As_long(__pyx_v_nloudest); if (unlikely((__pyx_t_18 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 849, __pyx_L1_error)
+850:         snr_ss)
  __pyx_t_19 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_double(((PyObject *)__pyx_v_snr_ss), PyBUF_WRITABLE); if (unlikely(!__pyx_t_19.memview)) __PYX_ERR(0, 850, __pyx_L1_error)
+851:     return snr_ss
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(((PyObject *)__pyx_v_snr_ss));
  __pyx_r = ((PyObject *)__pyx_v_snr_ss);
  goto __pyx_L0;
 852: 
 853: @cython.boundscheck(False)
 854: @cython.wraparound(False)
 855: @cython.nonecheck(False)
 856: @cython.cdivision(True)
+857: cdef int _snr_ss(
static int __pyx_f_8holodeck_10sam_cython__snr_ss(__Pyx_memviewslice __pyx_v_amp, __Pyx_memviewslice __pyx_v_F_iplus, __Pyx_memviewslice __pyx_v_F_icross, __Pyx_memviewslice __pyx_v_iotas, double __pyx_v_dur, __Pyx_memviewslice __pyx_v_Phi_0, __Pyx_memviewslice __pyx_v_S_i, __Pyx_memviewslice __pyx_v_freqs, long __pyx_v_npsrs, long __pyx_v_nfreqs, long __pyx_v_nreals, long __pyx_v_nskies, long __pyx_v_nloudest, __Pyx_memviewslice __pyx_v_snr_ss) {
  int __pyx_v_pp;
  int __pyx_v_ff;
  int __pyx_v_rr;
  int __pyx_v_ss;
  int __pyx_v_ll;
  float __pyx_v_a_pol;
  float __pyx_v_b_pol;
  float __pyx_v_Phi_T;
  float __pyx_v_pta_snr_sq;
  float __pyx_v_coef;
  float __pyx_v_term1;
  float __pyx_v_term2;
  float __pyx_v_term3;
  int __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("_snr_ss", 0);
/* … */
  /* function exit code */
  __pyx_r = 0;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 858:     double[:,:,:] amp,
 859:     double[:,:,:,:] F_iplus,
 860:     double[:,:,:,:] F_icross,
 861:     double[:,:,:] iotas,
 862:     double dur,
 863:     double[:,:,:] Phi_0,
 864:     double[:,:,:,:] S_i,
 865:     double[:] freqs,
 866:     long npsrs, long nfreqs, long nreals, long nskies, long nloudest,
 867:     # output
 868:     double[:,:,:,:] snr_ss
 869:     ):
 870:     """
 871: 
 872:     Parameters
 873:     ----------
 874:     amp : (F,R,L) NDarray
 875:         Dimensionless strain amplitude of loudest single sources
 876:     F_iplus : (P,F,S,L) NDarray
 877:         Antenna pattern function for each pulsar.
 878:     F_icross : (P,F,S,L) NDarray
 879:         Antenna pattern function for each pulsar.
 880:     iotas : (F,S,L) NDarray
 881:         Inclination, used to calculate:
 882:         a_pol = 1 + np.cos(iotas) **2
 883:         b_pol = -2 * np.cos(iotas)
 884:     dur : scalar
 885:         Duration of observations.
 886:     Phi_0 : (F,S,L) NDarray
 887:         Initial GW phase
 888:     S_i : (P,F,R,L) NDarray
 889:         Total noise of each pulsar wrt detection of each single source, in s^3
 890:     freqs : (F,) 1Darray
 891:         Observed frequency bin centers.
 892:     snr_ss : (F,R,S,L) NDarray
 893:         Pointer to single source SNR array, to be calculated.
 894: 
 895:     NOTE: This may be improved by moving some of the math outside the function.
 896:     I.e., passing in sin/cos of NDarrays to be used.
 897:     """
 898: 
 899:     cdef int pp, ff, rr, ss, ll
 900:     cdef float a_pol, b_pol, Phi_T, pta_snr_sq, coef, term1, term2, term3
 901:     # print('npsrs %d, nfreqs %d, nreals %d, nskies %d, nloudest %d' % (npsrs, nfreqs, nreals, nskies, nloudest))
 902: 
+903:     for ff in range(nfreqs):
  __pyx_t_1 = __pyx_v_nfreqs;
  __pyx_t_2 = __pyx_t_1;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
    __pyx_v_ff = __pyx_t_3;
+904:         for ss in range(nskies):
    __pyx_t_4 = __pyx_v_nskies;
    __pyx_t_5 = __pyx_t_4;
    for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) {
      __pyx_v_ss = __pyx_t_6;
+905:             for ll in range(nloudest):
      __pyx_t_7 = __pyx_v_nloudest;
      __pyx_t_8 = __pyx_t_7;
      for (__pyx_t_9 = 0; __pyx_t_9 < __pyx_t_8; __pyx_t_9+=1) {
        __pyx_v_ll = __pyx_t_9;
+906:                 a_pol = 1 + pow(cos(iotas[ff,ss,ll]), 2.0)
        __pyx_t_10 = __pyx_v_ff;
        __pyx_t_11 = __pyx_v_ss;
        __pyx_t_12 = __pyx_v_ll;
        __pyx_v_a_pol = (1.0 + pow(cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_iotas.data + __pyx_t_10 * __pyx_v_iotas.strides[0]) ) + __pyx_t_11 * __pyx_v_iotas.strides[1]) ) + __pyx_t_12 * __pyx_v_iotas.strides[2]) )))), 2.0));
+907:                 b_pol = -2 * cos(iotas[ff,ss,ll])
        __pyx_t_12 = __pyx_v_ff;
        __pyx_t_11 = __pyx_v_ss;
        __pyx_t_10 = __pyx_v_ll;
        __pyx_v_b_pol = (-2.0 * cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_iotas.data + __pyx_t_12 * __pyx_v_iotas.strides[0]) ) + __pyx_t_11 * __pyx_v_iotas.strides[1]) ) + __pyx_t_10 * __pyx_v_iotas.strides[2]) )))));
+908:                 Phi_T = 2 * M_PI * freqs[ff] * dur + Phi_0[ff,ss,ll]
        __pyx_t_10 = __pyx_v_ff;
        __pyx_t_11 = __pyx_v_ff;
        __pyx_t_12 = __pyx_v_ss;
        __pyx_t_13 = __pyx_v_ll;
        __pyx_v_Phi_T = ((((2.0 * M_PI) * (*((double *) ( /* dim=0 */ (__pyx_v_freqs.data + __pyx_t_10 * __pyx_v_freqs.strides[0]) )))) * __pyx_v_dur) + (*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_11 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_12 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_13 * __pyx_v_Phi_0.strides[2]) ))));
+909:                 for rr in range(nreals):
        __pyx_t_14 = __pyx_v_nreals;
        __pyx_t_15 = __pyx_t_14;
        for (__pyx_t_16 = 0; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) {
          __pyx_v_rr = __pyx_t_16;
+910:                     pta_snr_sq = 0
          __pyx_v_pta_snr_sq = 0.0;
+911:                     for pp in range(npsrs):
          __pyx_t_17 = __pyx_v_npsrs;
          __pyx_t_18 = __pyx_t_17;
          for (__pyx_t_19 = 0; __pyx_t_19 < __pyx_t_18; __pyx_t_19+=1) {
            __pyx_v_pp = __pyx_t_19;
 912:                         # calculate coefficient depending on
 913:                         # function of amp, S_i, and freqs
+914:                         coef = pow(amp[ff,rr,ll], 2.0) / (S_i[pp,ff,rr,ll] * 8 * pow(M_PI * freqs[ff], 3.0))
            __pyx_t_13 = __pyx_v_ff;
            __pyx_t_12 = __pyx_v_rr;
            __pyx_t_11 = __pyx_v_ll;
            __pyx_t_10 = __pyx_v_pp;
            __pyx_t_20 = __pyx_v_ff;
            __pyx_t_21 = __pyx_v_rr;
            __pyx_t_22 = __pyx_v_ll;
            __pyx_t_23 = __pyx_v_ff;
            __pyx_v_coef = (pow((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_amp.data + __pyx_t_13 * __pyx_v_amp.strides[0]) ) + __pyx_t_12 * __pyx_v_amp.strides[1]) ) + __pyx_t_11 * __pyx_v_amp.strides[2]) ))), 2.0) / (((*((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_S_i.data + __pyx_t_10 * __pyx_v_S_i.strides[0]) ) + __pyx_t_20 * __pyx_v_S_i.strides[1]) ) + __pyx_t_21 * __pyx_v_S_i.strides[2]) ) + __pyx_t_22 * __pyx_v_S_i.strides[3]) ))) * 8.0) * pow((M_PI * (*((double *) ( /* dim=0 */ (__pyx_v_freqs.data + __pyx_t_23 * __pyx_v_freqs.strides[0]) )))), 3.0)));
 915: 
 916:                         # calculate terms that depend on p, f, s, and l
 917:                         # functions of F_iplus, F_icross, a_pol, b_pol, Phi_0, and Phi_T
 918:                         term1 = (
+919:                             pow(a_pol * F_iplus[pp,ff,ss,ll], 2.0)
            __pyx_t_23 = __pyx_v_pp;
            __pyx_t_22 = __pyx_v_ff;
            __pyx_t_21 = __pyx_v_ss;
            __pyx_t_20 = __pyx_v_ll;
+920:                             * (Phi_T * (1.0 + 2.0 * pow(sin(Phi_0[ff,ss,ll]), 2.0))
            __pyx_t_10 = __pyx_v_ff;
            __pyx_t_11 = __pyx_v_ss;
            __pyx_t_12 = __pyx_v_ll;
/* … */
            __pyx_v_term1 = (pow((__pyx_v_a_pol * (*((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_F_iplus.data + __pyx_t_23 * __pyx_v_F_iplus.strides[0]) ) + __pyx_t_22 * __pyx_v_F_iplus.strides[1]) ) + __pyx_t_21 * __pyx_v_F_iplus.strides[2]) ) + __pyx_t_20 * __pyx_v_F_iplus.strides[3]) )))), 2.0) * (((__pyx_v_Phi_T * (1.0 + (2.0 * pow(sin((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_10 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_11 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_12 * __pyx_v_Phi_0.strides[2]) )))), 2.0)))) + (cos(__pyx_v_Phi_T) * ((-1.0 * sin(__pyx_v_Phi_T)) + (4.0 * cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_13 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_24 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_25 * __pyx_v_Phi_0.strides[2]) )))))))) - (4.0 * sin((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_26 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_27 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_28 * __pyx_v_Phi_0.strides[2]) )))))));
+921:                                 + cos(Phi_T) * (-1.0 * sin(Phi_T) + 4.0 * cos(Phi_0[ff,ss,ll]))
            __pyx_t_13 = __pyx_v_ff;
            __pyx_t_24 = __pyx_v_ss;
            __pyx_t_25 = __pyx_v_ll;
+922:                                 - 4.0 * sin(Phi_0[ff,ss,ll])
            __pyx_t_26 = __pyx_v_ff;
            __pyx_t_27 = __pyx_v_ss;
            __pyx_t_28 = __pyx_v_ll;
 923:                                 )
 924:                         )
 925:                         term2 = (
+926:                             pow(b_pol * F_icross[pp,ff,ss,ll], 2.0)
            __pyx_t_28 = __pyx_v_pp;
            __pyx_t_27 = __pyx_v_ff;
            __pyx_t_26 = __pyx_v_ss;
            __pyx_t_25 = __pyx_v_ll;
+927:                             * (Phi_T * (1.0 + 2.0 * pow(cos(Phi_0[ff,ss,ll]), 2.0))
            __pyx_t_24 = __pyx_v_ff;
            __pyx_t_13 = __pyx_v_ss;
            __pyx_t_12 = __pyx_v_ll;
/* … */
            __pyx_v_term2 = (pow((__pyx_v_b_pol * (*((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_F_icross.data + __pyx_t_28 * __pyx_v_F_icross.strides[0]) ) + __pyx_t_27 * __pyx_v_F_icross.strides[1]) ) + __pyx_t_26 * __pyx_v_F_icross.strides[2]) ) + __pyx_t_25 * __pyx_v_F_icross.strides[3]) )))), 2.0) * (((__pyx_v_Phi_T * (1.0 + (2.0 * pow(cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_24 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_13 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_12 * __pyx_v_Phi_0.strides[2]) )))), 2.0)))) + (sin(__pyx_v_Phi_T) * cos(__pyx_v_Phi_T))) - (4.0 * cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_11 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_10 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_20 * __pyx_v_Phi_0.strides[2]) )))))));
+928:                                 + sin(Phi_T) * cos(Phi_T) - 4.0 * cos(Phi_0[ff,ss,ll])
            __pyx_t_11 = __pyx_v_ff;
            __pyx_t_10 = __pyx_v_ss;
            __pyx_t_20 = __pyx_v_ll;
 929:                                 )
 930:                         )
 931:                         term3 = (
+932:                             -2.0 * a_pol * b_pol * F_iplus[pp,ff,ss,ll] * F_icross[pp,ff,ss,ll]
            __pyx_t_20 = __pyx_v_pp;
            __pyx_t_10 = __pyx_v_ff;
            __pyx_t_11 = __pyx_v_ss;
            __pyx_t_12 = __pyx_v_ll;
            __pyx_t_13 = __pyx_v_pp;
            __pyx_t_24 = __pyx_v_ff;
            __pyx_t_25 = __pyx_v_ss;
            __pyx_t_26 = __pyx_v_ll;
+933:                             * (2.0 * Phi_T * sin(Phi_T) *cos(Phi_0[ff,ss,ll])
            __pyx_t_27 = __pyx_v_ff;
            __pyx_t_28 = __pyx_v_ss;
            __pyx_t_21 = __pyx_v_ll;
/* … */
            __pyx_v_term3 = (((((-2.0 * __pyx_v_a_pol) * __pyx_v_b_pol) * (*((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_F_iplus.data + __pyx_t_20 * __pyx_v_F_iplus.strides[0]) ) + __pyx_t_10 * __pyx_v_F_iplus.strides[1]) ) + __pyx_t_11 * __pyx_v_F_iplus.strides[2]) ) + __pyx_t_12 * __pyx_v_F_iplus.strides[3]) )))) * (*((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_F_icross.data + __pyx_t_13 * __pyx_v_F_icross.strides[0]) ) + __pyx_t_24 * __pyx_v_F_icross.strides[1]) ) + __pyx_t_25 * __pyx_v_F_icross.strides[2]) ) + __pyx_t_26 * __pyx_v_F_icross.strides[3]) )))) * ((((2.0 * __pyx_v_Phi_T) * sin(__pyx_v_Phi_T)) * cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_27 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_28 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_21 * __pyx_v_Phi_0.strides[2]) ))))) + (sin(__pyx_v_Phi_T) * (((sin(__pyx_v_Phi_T) - (2.0 * sin((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_22 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_23 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_29 * __pyx_v_Phi_0.strides[2]) )))))) + ((2.0 * cos(__pyx_v_Phi_T)) * cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_30 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_31 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_32 * __pyx_v_Phi_0.strides[2]) )))))) - (2.0 * cos((*((double *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_Phi_0.data + __pyx_t_33 * __pyx_v_Phi_0.strides[0]) ) + __pyx_t_34 * __pyx_v_Phi_0.strides[1]) ) + __pyx_t_35 * __pyx_v_Phi_0.strides[2]) )))))))));
+934:                                 + sin(Phi_T) * (sin(Phi_T) - 2.0 * sin(Phi_0[ff,ss,ll])
            __pyx_t_22 = __pyx_v_ff;
            __pyx_t_23 = __pyx_v_ss;
            __pyx_t_29 = __pyx_v_ll;
+935:                                                 + 2.0 * cos(Phi_T) * cos(Phi_0[ff,ss,ll])
            __pyx_t_30 = __pyx_v_ff;
            __pyx_t_31 = __pyx_v_ss;
            __pyx_t_32 = __pyx_v_ll;
+936:                                                 - 2.0 * cos(Phi_0[ff,ss,ll])
            __pyx_t_33 = __pyx_v_ff;
            __pyx_t_34 = __pyx_v_ss;
            __pyx_t_35 = __pyx_v_ll;
 937:                                                 )
 938:                             )
 939:                         )
+940:                         pta_snr_sq += coef*(term1 + term2 + term3) # sum snr^2 of all pulsars for a single source
            __pyx_v_pta_snr_sq = (__pyx_v_pta_snr_sq + (__pyx_v_coef * ((__pyx_v_term1 + __pyx_v_term2) + __pyx_v_term3)));
          }
 941: 
 942:                     # set snr for a single source, using sum from all pulsars
+943:                     snr_ss[ff,rr,ss,ll] = sqrt(pta_snr_sq)
          __pyx_t_35 = __pyx_v_ff;
          __pyx_t_34 = __pyx_v_rr;
          __pyx_t_33 = __pyx_v_ss;
          __pyx_t_32 = __pyx_v_ll;
          *((double *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_snr_ss.data + __pyx_t_35 * __pyx_v_snr_ss.strides[0]) ) + __pyx_t_34 * __pyx_v_snr_ss.strides[1]) ) + __pyx_t_33 * __pyx_v_snr_ss.strides[2]) ) + __pyx_t_32 * __pyx_v_snr_ss.strides[3]) )) = sqrt(__pyx_v_pta_snr_sq);
        }
      }
    }
  }
 944: 
 945: