B
    d3o                 @   s  d Z ddl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 ddlmZmZmZ ddlmZ ddlmZmZ dd	lmZmZmZ d
d Zdd Zi ZdddZdd Zdejkreejd d G dd de Z!dd Z"G dd de Z#dddZ$dS )zdThis module provides utilities for calculating detector responses and timing
between observatories.
    N)
TimeSeries)InterpolatingConfigParser)Time)	constantscoordinatesunits)rotation_matrix)sdaymeter)cossinpic             C   s   t | dddddj}|S )Ngpsutc)r   r   )formatscalelocationZmean)r   Zsidereal_timerad)gps_timegmst r   [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/pycbc/detector.pygmst_accurate.   s    r   c                 sJ   t j dd   D }  fdd| D } fdd| D }tt||S )ae  Return list of detectors known in the currently sourced lalsuite.
    This function will query lalsuite about which detectors are known to
    lalsuite. Detectors are identified by a two character string e.g. 'K1',
    but also by a longer, and clearer name, e.g. KAGRA. This function returns
    both. As LAL doesn't really expose this functionality we have to make some
    assumptions about how this information is stored in LAL. Therefore while
    we hope this function will work correctly, it's possible it will need
    updating in the future. Better if lal would expose this information
    properly.
    c             S   s   g | ]}d |kr|qS )ZDETECTOR_PREFIXr   ).0jr   r   r   
<listcomp>@   s    z+get_available_detectors.<locals>.<listcomp>c                s   g | ]} | qS r   r   )r   k)ldr   r   r   A   s    c                s   g | ]} | d d qS )PREFIXNAME)replace)r   r   )r   r   r   r   B   s    )lal__dict__keyslistzip)Zknown_lal_namesZknown_prefixesZknown_namesr   )r   r   get_available_detectors4   s
    r&   c             C   sJ  |dkr|t jd  }td| td|  }}t | |dg||dgdddgg}td| td|  }}t | |dg||dgdddgg}	|	| d }
t|tj d}tt jd | tj d}t ||}t |
|}
t |j	|
}
t
jj|tj |tj |tj d}t |jj|jj|jjg}||
|||d	d	d
t| < dS )a   Add a new detector on the earth

    Parameters
    ----------

    name: str
        two-letter name to identify the detector
    longitude: float
        Longitude in radians using geodetic coordinates of the detector
    latitude: float
        Latitude in radians using geodetic coordinates of the detector
    yangle: float
        Azimuthal angle of the y-arm (angle drawn from pointing north)
    xangle: float
        Azimuthal angle of the x-arm (angle drawn from point north). If not set
        we assume a right angle detector following the right-hand rule.
    height: float
        The height in meters of the detector above the standard
        reference ellipsoidal earth
    Ng       @   r   g      @zy)heightg        )r   responseyanglexangler*   	xaltitude	yaltitude)npr   r   r   arrayr   r   r   matmulTr   EarthLocationZfrom_geodeticr
   xvaluer)   r(   _custom_ground_detectors)name	longitudelatituder,   r-   r*   abZxrespZyresprespZrm1Zrm2Zrmlocr   r   r   add_detector_on_earthG   s2    $$
r?   c       
         s   dt ddgfi}t| }|d}x|D ]}t|d| y| d \}}W n& tk
r|   td|	 Y nX x D ]}t
 |  |< qW y fdd	|D }W n0 tk
r }	 ztd
|W dd}	~	X Y nX || f|  q(W dS )z Add custom detectors from a configuration file

    Parameters
    ----------
    config_files: str or list of strs
        The config file(s) which specify new detectors
    Zearth_normalr9   r:   detectorzdetector-{}methodz(Missing or unkown method, options are {}c                s   g | ]}  |qS r   )pop)r   arg)kwdsr   r   r      s    z(load_detector_config.<locals>.<listcomp>z2missing required detector argument {} are requiredN)r?   r   Zget_subsectionsdictitemsr   rB   KeyError
ValueErrorr#   floatupper)
config_filesmethodsconfZdetsdetrA   	arg_namesr   argser   )rD   r   load_detector_config   s&    


rR   ZPYCBC_DETECTOR_CONFIG:c               @   s~   e Zd ZdZd ddZdd Zdd Zd	d
 Zdd Zd!ddZ	dd Z
dd Zdd Zd"ddZdd Zdd Zdd ZdS )#Detectorz"A gravitational wave detector
      VAc             C   s   t || _|dd t D krNtjd}|| j| _| jj| _| jj	| _	n:|t
krzt
| | _| jd | _| jd | _	ntd|tj| j	d | j	d | j	d	 td
}|jj| _|jj| _|| _d| _d| _dS )a   Create class representing a gravitational-wave detector
        Parameters
        ----------
        detector_name: str
            The two-character detector string, i.e. H1, L1, V1, K1, I1
        reference_time: float
            Default is time of GW150914. In this case, the earth's rotation
        will be estimated from a reference time. If 'None', we will
        calculate the time for each gps time requested explicitly
        using a slower but higher precision method.
        c             S   s   g | ]\}}|qS r   r   )r   pfxr8   r   r   r   r      s    z%Detector.__init__.<locals>.<listcomp>lalsimulationr+   r   zUnkown detector {}r      r'   )unitN)strr8   r&   pycbcZlibutilsZimport_optionalZDetectorPrefixToLALDetector_lalr+   r   r7   inforH   r   r   r4   r
   Zlatr   r:   Zlonr9   reference_timer	   gmst_reference)selfZdetector_namer^   Zlalsimr>   r   r   r   __init__   s(    




zDetector.__init__c             C   s2   | j d k	r&ttjj| _t| j | _ntdd S )Nz<Can't get accurate sidereal time without GPS reference time!)r^   rI   r	   sir   r   r_   RuntimeError)r`   r   r   r   set_gmst_reference   s    
zDetector.set_gmst_referencec             C   s   t | dr| jS ddl}| }| j|_| j|_| jd |_	| jd |_
| jd |_| jd |_| jd |_d	|_| }||||j}|| _|S dS )
z( Return lal data type detector instance r\   r   Nr*   r-   r,   r/   r.   g     @@)hasattrr\   r!   Z
FrDetectorr9   ZvertexLongitudeRadiansr:   ZvertexLatitudeRadiansr]   ZvertexElevationZxArmAzimuthRadiansZyArmAzimuthRadiansZxArmAltitudeRadiansZyArmMidpointrT   ZCreateDetectorZLALDETECTORTYPE_IFODIFF)r`   r!   dr5   rr   r   r   r!      s     
zDetector.lalc             C   sV   | j d krt|S | jd kr$|   || j  | j dtj  }| j| dtj  }|S )Ng       @)r^   r   r_   rd   r	   r0   r   )r`   r   Zdphaser   r   r   r   gmst_estimate   s    

zDetector.gmst_estimatec             C   s&   | j |j  }t||d tjj S )a   Return the light travel time from this detector
        Parameters
        ----------
        det: Detector
            The other detector to determine the light travel time to.
        Returns
        -------
        time: float
            The light travel time in seconds
        g      ?)r   rI   dotr   cr6   )r`   rN   rf   r   r   r   light_travel_time_to_detector   s    z&Detector.light_travel_time_to_detectortensorc       "      C   s  t |tjrt|}| || }t|}t|}t|}	t|}
t|}t|}| | || |
  }| | || |
  }||	 }tj|||gt	d}| j
|}|| || |
  }|| || |
  }||	 }tj|||gt	d}| j
|}|dkr8|	 | }|	| }|
 }tj|||gt	d}| j
|}|dkrt|dr|| ||  jddtj}|| ||  jddtj}n(|| ||   }|| ||   }||fS |dkrHt|dr|| ||  jddtj}|| ||  jddtj}n(|| ||   }|| ||   }||fS |dkrt|dr|| ||  jddtj} || jdd}!n || ||   } ||  }!| |!fS dS )	aM  Return the detector response.

        Parameters
        ----------
        right_ascension: float or numpy.ndarray
            The right ascension of the source
        declination: float or numpy.ndarray
            The declination of the source
        polarization: float or numpy.ndarray
            The polarization angle of the source
        polarization_type: string flag: Tensor, Vector or Scalar
            The gravitational wave polarizations. Default: 'Tensor'

        Returns
        -------
        fplus(default) or fx or fb : float or numpy.ndarray
            The plus or vector-x or breathing polarization factor for this sky location / orientation
        fcross(default) or fy or fl : float or numpy.ndarray
            The cross or vector-y or longitudnal polarization factor for this sky location / orientation
        )dtyperl   shaper   )ZaxisZvectorZscalarN)
isinstancer!   ZLIGOTimeGPSrI   rh   r   r   r0   r1   objectr+   ri   re   sumastypefloat64)"r`   right_ascensiondeclinationpolarizationt_gpsZpolarization_typeZghaZcosghaZsinghaZcosdecZsindecZcospsiZsinpsiZx0x1Zx2r5   dxZy0y1y2r)   ZdyZz0Zz1Zz2r(   ZdzZfplusZfcrossZfxfyZfbflr   r   r   antenna_pattern  s\    


 "
 "
 zDetector.antenna_patternc             C   s   |  tdddg|||S )z4Return the time delay from the earth center
        r   )time_delay_from_locationr0   r1   )r`   rt   ru   rw   r   r   r   time_delay_from_earth_centerT  s    z%Detector.time_delay_from_earth_centerc             C   sp   |  || }t|}|t| }|t|  }t|}	tj|||	gtd}
|| j }||
tj	t
jj S )a  Return the time delay from the given location to detector for
        a signal with the given sky location
        In other words return `t1 - t2` where `t1` is the
        arrival time in this detector and `t2` is the arrival time in the
        other location.

        Parameters
        ----------
        other_location : numpy.ndarray of coordinates
            A detector instance.
        right_ascension : float
            The right ascension (in rad) of the signal.
        declination : float
            The declination (in rad) of the signal.
        t_gps : float
            The GPS time (in s) of the signal.

        Returns
        -------
        float
            The arrival time difference between the detectors.
        )rm   )rh   r   r   r0   r1   rp   r   ri   rr   rs   r   rj   r6   )r`   other_locationrt   ru   rw   Zra_anglecosde0e1e2ehatry   r   r   r   r   \  s    
z!Detector.time_delay_from_locationc             C   s   |  |j|||S )a:  Return the time delay from the given to detector for a signal with
        the given sky location; i.e. return `t1 - t2` where `t1` is the
        arrival time in this detector and `t2` is the arrival time in the
        other detector. Note that this would return the same value as
        `time_delay_from_earth_center` if `other_detector` was geocentric.
        Parameters
        ----------
        other_detector : detector.Detector
            A detector instance.
        right_ascension : float
            The right ascension (in rad) of the signal.
        declination : float
            The declination (in rad) of the signal.
        t_gps : float
            The GPS time (in s) of the signal.
        Returns
        -------
        float
            The arrival time difference between the detectors.
        )r   r   )r`   Zother_detectorrt   ru   rw   r   r   r   time_delay_from_detector  s    z!Detector.time_delay_from_detectorr!   Nc          	   C   s   |dkr^ddl }||tj |tj ||||  }	t|	jj|	j|	j	tjdd}
n|dkr|dk	rv|}nt
|jt
|j d }|dkr|}n.|d	krt|trt|tstd
|j }| ||||\}}| |||}|| ||  }
t
|
j| |
_ntd||
S )a  Return the strain of a waveform as measured by the detector.
        Apply the time shift for the given detector relative to the assumed
        geocentric frame and apply the antenna patterns to the plus and cross
        polarizations.

        Parameters
        ----------
        hp: pycbc.types.TimeSeries
            Plus polarization of the GW
        hc: pycbc.types.TimeSeries
            Cross polarization of the GW
        ra: float
            Right ascension of source location
        dec: float
            Declination of source location
        polarization: float
            Polarization angle of the source
        method: {'lal', 'constant', 'vary_polarization'}
            The method to use for projecting the polarizations into the
            detector frame. Default is 'lal'.
        reference_time: float, Optional
            The time to use as, a reference for some methods of projection.
            Used by 'constant' and 'vary_polarization' methods. Uses average
            time if not provided.
        r!   r   NF)Zdelta_tepochrm   copy)constantvary_polarizationg       @r   r   zCWaveform polarizations must be given as time series for this methodzUnkown projection method {})rW   Z SimDetectorStrainREAL8TimeSeriesrr   r0   rs   r!   r   dataZdeltaTr   rI   end_time
start_timero   	TypeErrorZsample_timesnumpyr~   r   rH   r   )r`   hpZhcradecrv   rA   r^   rW   Zh_laltsZrtimetimefpfcdtr   r   r   project_wave  s2    



zDetector.project_wavec             C   s(   | j | |dtj   }| j}||fS )a  Return the optimal orientation in right ascension and declination
           for a given GPS time.

        Parameters
        ----------
        t_gps: float
            Time in gps seconds

        Returns
        -------
        ra: float
            Right ascension that is optimally oriented for the detector
        dec: float
            Declination that is optimally oriented for the detector
        g       @)r9   rh   r0   r   r:   )r`   rw   r   r   r   r   r   optimal_orientation  s    zDetector.optimal_orientationc             C   s   | j }tj|d |d |d tjdddd}d|_t|j	j
tj   }tt|j	t|jt|jg| }|S )z Transforms GCRS frame to ICRS frame

        Returns
        ----------
        loc: numpy.ndarray shape (3,1) units: AU
             ICRS coordinates in cartesian system
        r   rX   r'   gcrs	cartesian)r5   r)   r(   rY   framerepresentation_typeicrs)r   r   SkyCoordr   mtransform_tor   r0   float32r5   rY   AU	decompose	to_stringr1   r)   r(   )r`   r>   convr   r   r   get_icrs_pos  s    zDetector.get_icrs_posc             C   sR   |  ||||\}}t|}	dd|	|	   }
||
 d ||	 d  d }|| S )a   Distance scaled to account for amplitude factors

        The effective distance of the source. This scales the distance so that
        the amplitude is equal to a source which is optimally oriented with
        respect to the detector. For fixed detector-frame intrinsic parameters
        this is a measure of the expected signal strength.

        Parameters
        ----------
        distance: float
            Source luminosity distance in megaparsecs
        ra: float
            The right ascension in radians
        dec: float
            The declination in radians
        pol: float
            Polarization angle of the gravitational wave in radians
        time: float
            GPS time in seconds
        inclination:
            The inclination of the binary's orbital plane

        Returns
        -------
        eff_dist: float
            The effective distance of the source
        g      ?g      ?g       @)r~   r0   r   )r`   Zdistancer   r   Zpolr   Zinclinationr   r   Zicipr   r   r   r   effective_distance  s
    
zDetector.effective_distance)rU   )rl   )r!   N)__name__
__module____qualname____doc__ra   rd   r!   rh   rk   r~   r   r   r   r   r   r   r   r   r   r   r   rT      s   
%

P# 
LrT   c             C   s   t jd | }ddt|t|   td|   td|  t|td|   td|   }ddt|t|   td|   td|  t|td|   td|   }||fS )uE  Return the antenna pattern factors F+ and Fx as a function of sky
    location and polarization angle for a hypothetical interferometer located
    at the north pole. Angles are in radians. Declinations of ±π/2 correspond
    to the normal to the detector plane (i.e. overhead and underneath) while
    the point with zero right ascension and declination is the direction
    of one of the interferometer arms.
    Parameters
    ----------
    right_ascension: float
    declination: float
    polarization: float
    Returns
    -------
    f_plus: float
    f_cros: float
    g       @g      g      ?g      ?)r0   r   r   r   )rt   ru   rv   thetaZf_plusZf_crossr   r   r   overhead_antenna_pattern/  s    ."."r   c               @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )LISAzFor LISA detector
    c             C   s   d S )Nr   )r`   r   r   r   ra   T  s    zLISA.__init__c             C   s4  t |dddj}ttdd}d\}}dtj | d | }|d d t d | }d	\}}|d| td
  }	|t| ||	 t|t| t| dt|d  t|    }
|t| ||	 t|t| t| dt|d  t|    }td
 | |	 t||  }t|
||g| _	| j	S )aW  Return the position of LISA detector for a given reference time
        Parameters
        ----------
        ref_time : numpy.ScalarType

        Returns
        -------
        location : numpy.ndarray of shape (3,3)
               Returns the position of all 3 sattelites with each row
               correspoding to a single axis.
        r   r   )valr   r   rX      )r   r   g       @g      @)g      ?g5Þ?   r'   )
r   Zjyearr0   r1   ranger   sqrtr   r   r   )r`   Zref_timenkappaZ_lambda_alphaZbeta_nr;   LrQ   r5   r)   r(   r   r   r   get_posW  s    DD zLISA.get_posc             C   s   |}t j|d |d |d tjdddd}d|_t|jj	tj
   }tt|jt|jt|jg| }|S )ac   Transforms ICRS frame to GCRS frame

        Parameters
        ----------
        loc : numpy.ndarray shape (3,1) units: AU
              Cartesian Coordinates of the location
              in ICRS frame

        Returns
        ----------
        loc : numpy.ndarray shape (3,1) units: meters
              GCRS coordinates in cartesian system
        r   rX   r'   r   r   )r5   r)   r(   rY   r   r   r   )r   r   r   r   r   r   r0   r   r5   rY   r   r   r   r1   r)   r(   )r`   r   r>   r   r   r   r   get_gcrs_posr  s    zLISA.get_gcrs_posc             C   sV   | j | }t|}|t| }|t|  }t|}	t|||	g}
||
tjj S )a   Return the time delay from the LISA detector to detector for
        a signal with the given sky location. In other words return
        `t1 - t2` where `t1` is the arrival time in this detector and
        `t2` is the arrival time in the other location. Units(AU)

        Parameters
        ----------
        other_location : numpy.ndarray of coordinates in ICRS frame
            A detector instance.
        right_ascension : float
            The right ascension (in rad) of the signal.
        declination : float
            The declination (in rad) of the signal.
        t_gps : float
            The GPS time (in s) of the signal.

        Returns
        -------
        numpy.ndarray
            The arrival time difference between the detectors.
        )	r   r   r   r0   r1   ri   r   rj   r6   )r`   r   rt   ru   rw   ry   r   r   r   r   r   r   r   r   r     s    
zLISA.time_delay_from_locationc             C   s   t || }| ||||S )a  Return the time delay from the LISA detector for a signal with
        the given sky location in ICRS frame; i.e. return `t1 - t2` where
        `t1` is the arrival time in this detector and `t2` is the arrival
        time in the other detector.

        Parameters
        ----------
        other_detector : detector.Detector
            A detector instance.
        right_ascension : float
            The right ascension (in rad) of the signal.
        declination : float
            The declination (in rad) of the signal.
        t_gps : float
            The GPS time (in s) of the signal.

        Returns
        -------
        numpy.ndarray
            The arrival time difference between the detectors.
        )rT   r   r   )r`   rN   rt   ru   rw   r>   r   r   r   r     s    zLISA.time_delay_from_detectorc          	   C   s^   t |ddd}tjd|ddd}d|_| tt|j	t|j
t|jg|||S )	zBReturn the time delay from the earth center in ICRS frame
        r   r   )r   r   r   earthN)r   r   r   )r   r   get_bodyr   r   r   r0   r1   r   r5   r)   r(   )r`   rt   ru   rw   r   r   r   r   r     s    z!LISA.time_delay_from_earth_centerN)
r   r   r   r   ra   r   r   r   r   r   r   r   r   r   r   Q  s   r   , c             C   s   | r| t| S dS )zPretty-print a list (or set) of detectors: return a string listing
    the given detectors alphabetically and separated by the given string
    (comma by default).
    zno detectors)joinsorted)Zifos	separatorr   r   r   ppdets  s    r   )r   Nr   )r   )%r   osr   r0   r!   Zpycbc.libutilsr[   Zpycbc.typesr   Zpycbc.types.configr   Zastropy.timer   Zastropyr   r   r   Z$astropy.coordinates.matrix_utilitiesr   Zastropy.units.sir	   r
   r   r   r   r   r&   r7   r?   rR   environsplitrp   rT   r   r   r   r   r   r   r   <module>   s2   
8
   "