GWForge.fisher.derivatives ========================== .. py:module:: GWForge.fisher.derivatives .. autoapi-nested-parse:: First and second derivatives of the detector response. Most of the work is deciding which derivatives have to be numerical. A bilby source model returns :math:`\tilde h_+` and :math:`\tilde h_\times` from the intrinsic parameters plus ``theta_jn``, ``phase`` and ``luminosity_distance``, and has **no** dependence on ``ra``, ``dec``, ``psi`` or ``geocent_time`` -- so those four, plus ``luminosity_distance``, are exact. See :mod:`GWForge.fisher.antenna_derivatives` for the geometry and :mod:`GWForge.fisher.stepsize` for how the numerical steps are chosen. Everything else is differenced with fourth-order five-point stencils, which give the first and second derivative from the same five evaluations. Note ``phase`` is *not* analytic for a higher-mode waveform: each :math:`(\ell, m)` carries :math:`e^{-i m \phi_c}` and the mode decomposition is not exposed. Mixed second derivatives between a numerical and an analytic parameter are taken by differencing the *exact analytic* derivative along the numerical stencil. That matters when ``earth_rotation`` is on, because the masses then reach the response through :math:`\tau(f)` as well as through the waveform. Classes ------- .. autoapisummary:: GWForge.fisher.derivatives.WaveformDerivatives Functions --------- .. autoapisummary:: GWForge.fisher.derivatives.analytic_derivatives Module Contents --------------- .. py:function:: analytic_derivatives(interferometer, polarizations, parameters, earth_rotation=True, finite_size=True, order=1) Exact response and derivatives for the five closed-form parameters. Writing :math:`h = P\,S` with :math:`P = F_+\tilde h_+ + F_\times\tilde h_\times` and :math:`S = e^{-2\pi i f\tau}`, .. math:: \partial_a h = \big(\partial_a P - 2\pi i f\,\partial_a\tau\,P\big) S, and the second derivative follows from one more product rule. ``ra``, ``dec``, ``psi`` and ``geocent_time`` enter through :class:`AntennaDerivatives`; ``luminosity_distance`` is handled separately because :math:`h \propto 1/d_L` makes every one of its derivatives a rescaling of a derivative we already have. :param interferometer: :type interferometer: bilby.gw.detector.Interferometer :param polarizations: ``{'plus': ..., 'cross': ...}`` on the interferometer's frequency grid. :type polarizations: dict :param parameters: Source parameters. :type parameters: dict :param earth_rotation: Response options; must match those used elsewhere. :type earth_rotation: bool :param finite_size: Response options; must match those used elsewhere. :type finite_size: bool :param order: ``2`` also returns second derivatives. :type order: int :returns: ``(response, first, second)``. ``first`` maps a parameter name to a full-length complex array; ``second`` maps a sorted name pair to one. Both are zero outside the interferometer's frequency mask. :rtype: tuple .. py:class:: WaveformDerivatives(interferometers, waveform_generator, parameters, fisher_parameters=None, earth_rotation=True, finite_size=True, step_sizes=None, order=1, calibrate=True, target_change=TARGET_FRACTIONAL_CHANGE, estimate_noise=True) First and second derivatives of the detector response for one source. Combines the exact closed-form derivatives of :func:`analytic_derivatives` with fourth-order finite differences for the parameters the waveform actually depends on. The waveform is evaluated once per stencil point and cached, because the polarizations do not depend on which detector is looking; detectors are then projected one at a time by :meth:`derivatives`. That ordering matters for memory: a second-derivative array is ``n_parameters**2`` frequency series, so holding one for every detector at once reaches gigabytes at a high sampling frequency, while the cached polarizations are only ``2`` series per stencil point. For eleven parameters this is ``4 * n_numerical + 1`` waveform evaluations at ``order = 1``, plus four per numerical pair at ``order = 2``. :ivar names: Parameter names, in the order used by the Fisher matrix. :vartype names: list of str :ivar analytic, numerical: The split of ``names`` by differentiation method. :vartype analytic, numerical: list of str :ivar steps: Finite-difference step actually used for each numerical parameter. :vartype steps: dict :ivar waveform_evaluations: How many times the waveform generator was called. :vartype waveform_evaluations: int .. py:attribute:: interferometers .. py:attribute:: waveform_generator .. py:attribute:: parameters .. py:attribute:: names :value: ['chirp_mass', 'symmetric_mass_ratio', 'luminosity_distance', 'ra', 'dec', 'theta_jn', 'psi',... .. py:attribute:: earth_rotation :value: True .. py:attribute:: finite_size :value: True .. py:attribute:: order :value: 1 .. py:attribute:: estimate_noise :value: True .. py:attribute:: index .. py:attribute:: analytic .. py:attribute:: numerical .. py:attribute:: steps .. py:attribute:: noise_ratios .. py:attribute:: waveform_evaluations :value: 0 .. py:method:: derivatives(interferometer) Response and derivative arrays for one detector. :param interferometer: Must belong to the network this object was built with. :type interferometer: bilby.gw.detector.Interferometer :returns: ``(response, first, second)`` where ``first`` has shape ``(n_parameters, n_frequencies)`` and ``second`` has shape ``(n_parameters, n_parameters, n_frequencies)`` -- or is ``None`` when ``order < 2``. :rtype: tuple