Source code for jhuki.twochargedpunctures

#!/usr/bin/env python3

# Copyright (C) 2021-2022 Gabriele Bozzola
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, see <https://www.gnu.org/licenses/>.

"""The :py:mod:`~.twochargedpunctures` module extends :py:mod:`~.twopunctures`
 for the case of charged black holes. The interface is nearly identical.
"""

from functools import lru_cache
from math import sqrt

from jhuki.externals.nrpypn import compute_quasicircular_momenta
from jhuki.twopunctures import TwoPunctures


[docs]def prepare_quasicircular_inspiral( mass_ratio, coordinate_distance, total_bare_mass=1, chi_plus=(0, 0, 0), chi_minus=(0, 0, 0), lambda_plus=0, lambda_minus=0, **kwargs, ): """Return a :py:class:`~.TwoChargedPunctures` that describes a quasi-circular inspiral. We always assume that the plus puncture is the most massive one. We compute the momenta starting from the uncharged case and scaling by sqrt(1 - lambda1 * lambda2). This is essentially 0 PN. It works well for low charge, but not that much for higher charge. :param mass_ratio: Mass ratio of the binary. :type mass_ratio: float :param lambda_plus: Charge-to-mass-ratio of the black hole on the positive side of the x (or z) axis. :type lambda_plus: float :param lambda_minus: Charge-to-mass-ratio of the black hole on the negative side of the x (or z) axis. :type lambda_minus: float :param coordinate_distance: Initial coordinate separation. :type coordinate_distance: float :param total_bare_mass: Rescale masses and momenta so that the total bare mass of the system is this. :type total_bare_mass: float :param chi_plus: Dimensionless spin of the black hole on the positive side of the x (or z) axis along the three directions. :type chi_plus: tuple/list with three numbers :param chi_minus: Dimensionless spin of the black hole on the negative side of the x (or z) axis along the three directions. :type chi_minus: tuple/list with three numbers Unknown arguments are passed to :py:class:`~.TwoPunctures`. :returns: A :py:class:`~.TwoPunctures` for a quasi-circular inspiral. :rtype: :py:class:`~.TwoPunctures` """ if mass_ratio < 1: mass_ratio = 1 / mass_ratio Pt, Pr = compute_quasicircular_momenta( mass_ratio, coordinate_distance, chi_plus, chi_minus ) mass_plus = mass_ratio / (1 + mass_ratio) * total_bare_mass mass_minus = 1 / (1 + mass_ratio) * total_bare_mass factor = sqrt(1 - lambda_plus * lambda_minus) Pt, Pr = Pt * total_bare_mass * factor, Pr * total_bare_mass * factor momenta_plus = (-Pr, Pt, 0) momenta_minus = (Pr, -Pt, 0) return TwoChargedPunctures( mass_plus, mass_minus, coordinate_distance, momenta_plus=momenta_plus, momenta_minus=momenta_minus, chi_plus=chi_plus, chi_minus=chi_minus, charge_plus=lambda_plus * mass_plus, charge_minus=lambda_minus * mass_minus, give_bare_mass=False, **kwargs, )
[docs]class TwoChargedPunctures(TwoPunctures): """The :py:class:`~.TwoChargedPunctures` extends :py:class:`~.TwoPunctures` for the case charged black holes (to use with the ``TwoChargedPunctures`` thorn). As :py:class:`~.TwoPunctures`, this class is immutable. :ivar charge_plus: Charge of the black hole on the positive side of the x (or z) axis. :vartype charge_plus: float :ivar charge_minus: Charge of the black hole on the negative side of the x (or z) axis. :vartype charge_minus: float """ def __init__( self, mass_plus, mass_minus, coordinate_distance, momenta_plus=None, momenta_minus=None, chi_plus=None, chi_minus=None, charge_plus=0, charge_minus=0, swap_xz=False, give_bare_mass=False, ): """Constructor. :param mass_plus: Mass of the black hole on the positive side of the x (or z) axis. :type mass_plus: float :param mass_minus: Mass of the black hole on the negative side of the x (or z) axis. :type mass_minus: float :param charge_plus: Charge of the black hole on the positive side of the x (or z) axis. :type charge_plus: float :param charge_minus: Charge of the black hole on the negative side of the x (or z) axis. :type charge_minus: float :param coordinate_separation: Initial coordinate separation. :type coordinate_separation: float :param par_b: Half of the initial separation. :type par_b: float :param momenta_plus: Array with the linear momenta along the three directions for the black hole on the positive side of the x (or z) axis. If ``swap_xz`` is True, these are the values after swapping. For example ``(0, 0, 0.5)`` is a vector along the z axis. (This is the opposite of what happens in ``TwoPunctures``, where you have to define the values before swapping) :type momenta_plus: list/tuple :param momenta_minus: Array with the linear momenta along the three directions for the black hole on the positive side of the x (or z) axis. If ``swap_xz`` is True, these are the values after swapping. For example ``(0, 0, 0.5)`` is a vector along the z axis. (This is the opposite of what happens in ``TwoPunctures``, where you have to define the values before swapping) :type momenta_minus: list/tuple :param chi_plus: Array with the dimensionless_spin along the three directions for the black hole on the positive side of the x (or z) axis. If ``swap_xz`` is True, these are the values after swapping. For example ``(0, 0, 0.5)`` is a vector along the z axis. (This is the opposite of what happens in ``TwoPunctures``, where you have to define the values before swapping) :type chi_plus: list/tuple :param chi_minus: Array with the dimensionless spin along the three directions for the black hole on the positive side of the x (or z) axis. If ``swap_xz`` is True, these are the values after swapping. For example ``(0, 0, 0.5)`` is a vector along the z axis. (This is the opposite of what happens in ``TwoPunctures``, where you have to define the values before swapping) :type chi_minus: list/tuple :param swap_xz: If True, activate the ``swap_xz`` parameter in TwoPunctures. :type swap_xz: bool :param give_bare_mass: If True, set this parameter to True in the parfile. :type give_bare_mass: bool """ super().__init__( mass_plus, mass_minus, coordinate_distance, momenta_plus=momenta_plus, momenta_minus=momenta_minus, chi_plus=chi_plus, chi_minus=chi_minus, swap_xz=swap_xz, give_bare_mass=give_bare_mass, initial_alpha="psi^n", ) self.charge_plus = charge_plus self.charge_minus = charge_minus @property @lru_cache(1) def parfile_code(self): """Return the code you would put in your parfile.""" uncharged_parfile = ( super() .parfile_code.replace("TwoPunctures", "TwoChargedPunctures") .replace("twopunctures", "twochargedpunctures") ) charged_parfile = ( f"{uncharged_parfile}\n" f"TwoChargedPunctures::par_q_plus = {self.charge_plus}\n" f"TwoChargedPunctures::par_q_minus = {self.charge_minus}" ) return charged_parfile