B
    à‹dÐ[  ã               @   sT   d Z ddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 G dd„ de
ƒZdS )	z
Class for NRSur7dq4Remnant model for the mass, spin and kick of the final BH of
generically precessing binary black holes.

Vijay Varma, 2019.
é    Né   )Úpn_spin_evolution_wrapper)Úquaternion_utils)ÚNRFitsc               @   sB   e Zd ZdZdd„ Zdd„ Zdd„ Zddd„Zdd„ Zdd„ Z	dS )ÚNRSur7dq4Remnanta/  
    Class for NRSur7dq4Remnant model for the mass, spin and kick of the final BH
    of generically precessing binary black holes.

    Paper: arxiv:1905.09300

    Parameter ranges for usage: 

        q = [1, 6.01] 

        $\chi_{A}, \chi_{B}$ = [-1, 1]

    Training parameter ranges: 

        q = [1, 4.01] 

        $\chi_{A}, \chi_{B}$ = [-0.81, 0.81]

    But extrapolates reasonably to the above mass ratios and spins. However,
    if a guarantee of accuracy is required, this model should be used within
    the training parameter range.
    c             C   s¬   || }|| }|| }	|| }
|| }t  |
¡}t jt |g¡jt |g¡jddjd }t jt |g¡jt |	g¡jddjd }t  ||¡}t  ||¡}|||||fS )aK   Computes PN spins and dynamics at a given idx.

        Inputs:
            chiA:       Dimless spin evolution of BhA in inertial frame.
            chiB:       Dimless spin evolution of BhB in inertial frame.
            omega:      Orbital frequency evolution (this is total-mass times
                        the angular orbital frequency).
            lNhat:      Orbital angular momentum direction evolution.
            phi:        Orbital phase evolution.
            idx:        Index for output.

        Outputs (all are time series):
            chiA_at_idx_coorb:  Spin of BhA at idx, in coorbital frame.
            chiB_at_idx_coorb:  Spin of BhB at idx, in coorbital frame.
            quat_copr_at_idx:   Coprecessing frame quaternion at idx.
            phi_at_idx:         Orbital phase in the coprecessing frame at idx.
            omega_at_idx        Orbital frequency at idx (this is total-mass
                                times the angular orbital frequency).

        The inertial frame is assumed to be aligned to the coorbital frame at
        the first index.
        r   )Zinverser   )r   Zalign_vec_quatÚtransform_time_dependent_vectorÚnpÚarrayÚTÚrotate_in_plane)ÚselfZchiAZchiBÚomegaZlNhatÚphiÚidxZomega_at_idxZchiA_at_idxZchiB_at_idxZlNhat_at_idxZ
phi_at_idxZquat_copr_at_idxZchiA_at_idx_coprZchiB_at_idx_coprZchiA_at_idx_coorbZchiB_at_idx_coorb© r   úr/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/lalsimulation/nrfits/NRSur7dq4Remnant.pyÚ!_get_coorbital_frame_spins_at_idx&   s$    
z2NRSur7dq4Remnant._get_coorbital_frame_spins_at_idxc             C   sî   t  d¡}t ¡ }	|r$t |	dd¡ t  ||d |d |d |d |d |d ||d |d |d |d ||	|¡\}
}}}}}}}}}}}|
j}
|j}t |j|j|j|jg¡}t |j|j|jg¡j	}t |j|j|jg¡j	}|
||||fS )aM   A wrapper for NRSur7dq4 dynamics.

        Inputs:
            q:          Mass ratio, mA/mB >= 1.
            chiA0:      Dimless spin of BhA in the coorbital frame at omega_ref.
            chiB0:      Dimless spin of BhB in the coorbital frame at omega_ref.
            init_quat:  Coprecessing frame quaternion at omega_ref.
            init_orbphase:
                        Orbital phase in the coprecessing frame at omega_ref.
            omega_ref:  Orbital frequency in the coprecessing frame at the
                        reference epoch where the input spins are given. Note:
                        This is total-mass times the angular orbital frequency.
            unlimited_extrapolation:
                        If True, allows unlimited extrapolation to regions well
                        outside the surrogate's training region. Else, raises
                        an error.

        Outputs:
            t_dyn:      Time values at which the dynamics are returned. These
                        are nonuniform and sparse.
            copr_quat:  Time series of coprecessing frame quaternions.
            orbphase:   Orbital phase time series in the coprecessing frame.
            chiA_copr:  Time series of spin of BhA in the coprecessing frame.
            chiB_copr:  Time series of spin of BhB in the coprecessing frame.
        Z	NRSur7dq4Úunlimited_extrapolationr   r   é   é   )
ÚlalsimZ#SimInspiralGetApproximantFromStringÚlalÚ
CreateDictÚDictInsertUINT4ValueZPrecessingNRSurDynamicsÚdatar   r	   r
   )r   ÚqÚchiA0ÚchiB0Z	init_quatZinit_orbphaseÚ	omega_refr   Z	approxTagÚ	LALParamsZt_dynZquat0Zquat1Zquat2Zquat3ZorbphaseZchiAxZchiAyZchiAzZchiBxZchiByZchiBzZ	copr_quatZ	chiA_coprZ	chiB_coprr   r   r   Ú_get_surrogate_dynamics]   s    
$"z(NRSur7dq4Remnant._get_surrogate_dynamicsc          	   C   sÖ   t  ||||¡\}}	}
}}t t || ¡¡}|  |
||||	|¡\}}}}}|  |||||||¡\}}}}}t ||¡}|t t || ¡¡ }t t || ¡¡}|  |
||||	|¡\}}}}}||||||
||fS )aÎ   Gets PN spins and frame dynamics at a time close to the start
            of the surrogate waveform model.

        Inputs:
            q:          Mass ratio, mA/mB >= 1.
            chiA0:      Initial dimless spin of BhA in the LAL inertial frame.
            chiB0:      Initial dimless spin of BhB in the LAL inertial frame.
            omega0:     Initial orbital frequency. The spins are specified at
                        this frequency. Note: This is total-mass times the
                        angular orbital frequency.
            omega_switch_IG:
                        Initial guess for the orbital frequency at which to
                        switch from PN to surrogate dynamics. We use PN to
                        evolve the spins until the surrogate becomes valid. The
                        surrogate is in time domain, so it is not
                        straightforward to determine the frequency at which it
                        is valid. So, we evolve with PN until omega_switch_IG.
                        However, this is chosen to be overly conservative such
                        that this initial guess works for all q<=6 cases.
                        Ideally, we would like to use as much as possible of
                        the surrogate spin evolution. So, using the PN spins at
                        omega_switch_IG, the surrogate dynamics are evolved
                        both backwards and forwards in time. This lets us get
                        surrogate orbital frequency at t_sur_switch, as well as
                        the corresponding PN spins at this time.
            t_sur_switch:
                        The time at which the PN spins are returned so that
                        surrogate dynamics can be regenerated starting as early
                        as possible.
            unlimited_extrapolation:
                        If True, Allow unlimited extrapolation to regions well
                        outside the surrogate's training region. Else, raises
                        an error.

        Outputs:
            PN spin and frame dynamics at t_sur_switch, as well as the spins
            and orbital frequency evolution.

            chiA_PN_at_idx_coorb:
                        PN spin of BhA at t_sur_switch, in the coorbital frame.
            chiB_PN_at_idx_coorb:
                        PN spin of BhB at t_sur_switch, in the coorbital frame.
            quat_PN_copr_at_idx:
                        PN coprecessing frame quaternions at t_sur_switch.
            phi_PN_at_idx:
                        PN orbital phase at t_sur_switch.
            omega_PN_at_idx:
                        PN orbital frequency at t_sur_switch.
            chiA_PN:    PN Spin evolution of BhA in the inertial frame.
            chiB_PN:    PN Spin evolution of BhB in the inertial frame.
            omega_PN:   PN orbital frequency evolution. Note: This is total-mass
                        times the angular orbital frequency.
        )r   Úspin_evolutionr   ÚargminÚabsr   r    Zgradient)r   r   r   r   Úomega0Úomega_switch_IGÚt_sur_switchr   Úomega_PNZphi_PNÚchiA_PNÚchiB_PNZlNhat_PNr   ZchiA_PN_at_idx_coorbZchiB_PN_at_idx_coorbZquat_PN_copr_at_idxZphi_PN_at_idxZomega_PN_at_idxÚ	dyn_timesÚquat_surÚorbphase_surÚchiA_copr_surÚchiB_copr_surZ	omega_surÚomega_init_surr   r   r   Ú _get_pn_spins_at_surrogate_start   s    ;z1NRSur7dq4Remnant._get_pn_spins_at_surrogate_startç¸…ëQ¸ž?é`ðÿÿFc	          
   C   s  ||k r0|   |||||||¡\}	}
}}}}}}n,||ddddgd|dddf\}	}
}}}}}}|  ||	|
||||¡\}}}}}d}t t || ¡¡}|j| }|| }t || |¡}t || |¡}|rt ||j¡j}t ||j¡j}|||||||||dœ	}nd}|||||fS )a§   Uses PN and surrogate spin evolution to evolve spins of the
        component BHs from an initial orbital frequency = omega0 until t=-100 M
        from the peak of the waveform.

        Inputs:
            q:          Mass ratio, mA/mB >= 1.
            chiA0:      Initial dimless spin of BhA in the inertial frame.
            chiB0:      Initial dimless spin of BhB in the inertial frame. Note
                        that the LAL inertial frame coincides with the
                        coorbital frame used in the surrogate models.
            omega0:     Initial orbital frequency in the coprecessing frame.
                        The spins are specified at this frequency. Note: This
                        is total-mass times the angular orbital frequency.
            omega_switch_IG:
                        Initial guess for orbital frequency used to determine
                        if PN spin evolution is required, and where to switch
                        from PN spin evolution to the surrogate.
                If omega0 >= omega_switch_IG:
                        PN evolution is not required and the surrogate dynamics
                        are used to evolve the spin until t=-100M. Default
                        value for omega_switch_IG is 0.03 which is expected to
                        be large enough for q<=6.  NOTE: If you get errors
                        about omega0 being too small for the surrogate, try
                        increasing omega_switch_IG.
                If omega0 < omega_switch_IG:
                        Use PN to evolve the spins until the surrogate becomes
                        valid. The surrogate is in time domain, so it is not
                        straightforward to determine the frequency at which it
                        is valid. So, we evolve with PN until omega_switch_IG.
                        However, this is chosen to be overly conservative such
                        that this initial guess works for all q<=6 cases.
                        Ideally, we would like to use as much as possible of
                        the surrogate spin evolution. So, using the PN spins at
                        omega_switch_IG, the surrogate dynamics are evolved
                        both backwards and forwards in time.  Then the PN spins
                        at omega = omega_sur[t_sur_switch] are used to
                        reevaluate the surrogate dynamics. This way,
                        omega_switch_IG is only used as an initial guess for
                        where to switch to the surrogate, and we switch to the
                        surrogate as early as possible.
            t_sur_switch:
                        The time at which we switch to the surrogate evolution.
                        This should be slightly larger than the surrogate start
                        time of -4300M. Since we use the PN spins at
                        omega_sur[t_sur_switch] to reevaluate the surrogate
                        dynamics, it is possible that for the given PN spins at
                        omega_sur[t_sur_switch], the surrogate is not long
                        enough. Default: -4000.
            return_spin_evolution:
                        Also return the spin evolution and dynamics as a
                        dictionary.
            unlimited_extrapolation:
                        If True, Allow unlimited extrapolation to regions well
                        outside the surrogate's training region. Else, raises
                        an error.
        Outputs:
            chiA_coorb_fitnode:
                        Spin of BhA in the coorbital frame at t=-100M.
            chiB_coorb_fitnode:
                        Spin of BhB in the coorbital frame at t=-100M.
            quat_fitnode:
                        Coprecessing frame quaternions at t=-100M.
            orbphase_fitnode:
                        Orbital phase in the coprecessing frame at t=-100M.
            spin_evolution:
                        Dictionary containing the PN and surrogate spin
                        evolution (in the inertial frame) and dynamics.
                        Default: None, unless return_spin_evolution=True.
        r   r   Niœÿÿÿ)	Zt_surÚchiA_surÚchiB_surr,   r+   r'   r(   r)   r/   )	r0   r    r   r"   r#   r
   r   r   r   )r   r   r   r   r$   r%   r&   Zreturn_spin_evolutionr   ZchiA0_nrsur_coorbZchiB0_nrsur_coorbZquat0_nrsur_coprZ
phi0_nrsurr/   r(   r)   r'   r*   r+   r,   r-   r.   Zfitnode_timeZnodeIdxÚquat_fitnodeÚorbphase_fitnodeÚchiA_coorb_fitnodeÚchiB_coorb_fitnoder3   r4   r!   r   r   r   Ú_evolve_spinsí   sB    M

,

zNRSur7dq4Remnant._evolve_spinsc             C   s€   |d }|| }|| }	|dkr2|}
|}d}d}n<|t j |	 tj tjd  }| j|||||d\}
}}}}||
|||g}|S )aÜ  
        If f_ref = -1, assumes the reference epoch is at t=-100M and
            just returns the input spins, which are expected to be in
            the coorbital frame at t=-100M.
        Else, takes the spins at f_ref and evolves them using a combination of
        PN and NRSur7dq4 until t=-100M. The returned spins are in the coorbital
        frame at t=-100M.

        See eval_fits.eval_nrfit() for the definitions of the arguments of
        this function.
        r   éÿÿÿÿNr   )r   )r   Úpir   ZG_SIZC_SIr9   )r   Úm1Úm2ÚchiA_vecÚchiB_vecZf_refÚextra_params_dictr   r   ÚMr7   r8   r5   r6   r   r!   Ú
fit_paramsr   r   r   Ú_get_fit_paramsu  s    z NRSur7dq4Remnant._get_fit_paramsc             C   s  |\}}}}}t  ¡ }	|d r,t  |	dd¡ |dkrnt ||d |d |d |d |d |d d|	¡	jd }
n |dkr¬t ||d |d |d |d |d |d d|	¡	j}
nJ|d	krêt ||d |d |d |d |d |d d
|	¡	j}
ntd| ƒ‚|dk	rt |
||¡}
t	 
|
¡S )a\   Evaluates a particular fit for NRSur7dq4Remnant using the fit_params
        returned by _get_fit_params().

        fit_type can be one of "FinalMass", "FinalSpin" or "RecoilKick".

        Passing extra_params_dict = {"unlimited_extrapolation": True}, will
        ignore any extrapolation errors. USE AT YOUR OWN RISK!! Default: False.
        r   r   Z	FinalMassr   r   ÚmfZ	FinalSpinZchifZ
RecoilKickZvfzVInvalid fit_type=%s. This model only allows 'FinalMass', 'FinalSpin' and 'RecoilKick'.N)r   r   r   r   r   r   Ú
ValueErrorr   Z"transform_vector_coorb_to_inertialr   Z
atleast_1d)r   rB   Zfit_typer@   r   r>   r?   r5   r6   r   Úvalr   r   r   Ú	_eval_fit£  s2    



zNRSur7dq4Remnant._eval_fitN)r1   r2   FF)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r    r0   r9   rC   rG   r   r   r   r   r      s   70`  
 .r   )rK   Únumpyr   Zlalsimulationr   r   Ú r   r   Znrfitsr   r   r   r   r   r   Ú<module>   s   