예제 #1
0
 def azimuth(self, t, deg=True, std=False, syst=False):
     "Return the azimuth with respect to the positive x-axis."
     x, y, z = self._construct_n(t)
     azimuth = (atan2(z, x) + 2. * pi) % (2. * pi)
     if deg:
         azimuth = degrees(azimuth)
     return self._return_result(azimuth, std, syst)
예제 #2
0
 def azimuth(self, t, deg=True, std=False, syst=False):
     "Return the azimuth with respect to the positive x-axis."
     x, y, z = self._construct_n(t)
     azimuth = (atan2(z, x) + 2.*pi) % (2.*pi)
     if deg:
         azimuth = degrees(azimuth)
     return self._return_result(azimuth, std, syst)
예제 #3
0
    def get_source_apparent_pos(self, epoch, enlargeFactor=1.0):

        lensPos = self._lens.getRaDec(epoch)
        sourcePos = self._source.getRaDec(epoch)

        shift_mag = self.get_unresolved_centroid_shift_at_epoch(epoch)
        shift_angle = np.atan2(
            (sourcePos[0] - lensPos[0]) * np.cos(numpy.deg2rad(lensPos[1])),
            sourcePos[1] - lensPos[1])

        appSourceRa = sourcePos[0] + (
            (enlargeFactor * shift_mag * np.cos(shift_angle)) / (3600 * 1000))
        appSourceDec = sourcePos[1] + (
            (enlargeFactor * shift_mag * np.sin(shift_angle)) / (36000 * 1000))

        return numpy.array([appSourceRa, appSourceDec])
예제 #4
0
def cartesian_to_angular(x, y, z):
    """Converts from cartesian to angular coordinates
	"""

    norm = np.sqrt(x**2 + y**2 + z**2)

    x = x / norm
    y = y / norm
    z = z / norm

    dec = np.asin(z)
    ra = np.atan2(y, x)

    ra = ra * rad2deg
    dec = dec * rad2deg

    return numpy.array([ra, dec])
예제 #5
0
def get_angular_sep(ra1, dec1, ra2, dec2):

    ra1 = ra1 * deg2rad
    ra2 = ra2 * deg2rad

    dec1 = dec1 * deg2rad
    dec2 = dec2 * deg2rad

    top = np.sqrt((np.cos(dec2) * np.sin(ra2 - ra1))**(2) +
                  (np.cos(dec1) * np.sin(dec2) -
                   np.sin(dec1) * np.cos(dec2) * np.cos(ra2 - ra1))**(2))

    bottom = (np.sin(dec1) * np.sin(dec2)) + (np.cos(dec1) * np.cos(dec2) *
                                              np.cos(ra2 - ra1))

    dist = np.atan2(top, bottom)

    return (dist / deg2rad) * 3600.0 * 1000.0
예제 #6
0
def test_against_uncertainties_package():
    try:
        from uncertainties import ufloat
        from uncertainties import umath
        from math import sqrt as math_sqrt
    except ImportError:
        return
    X, varX = 0.5, 0.04
    Y, varY = 3, 0.09
    N = 3
    ux = ufloat(X, math_sqrt(varX))
    uy = ufloat(Y, math_sqrt(varY))

    def _compare(result, u):
        Z, varZ = result
        assert abs(Z-u.n)/u.n < 1e-13 and (varZ-u.s**2)/u.s**2 < 1e-13, \
            "expected (%g,%g) got (%g,%g)"%(u.n,u.s**2,Z,varZ)

    def _check_pow(u):
        _compare(pow(X, varX, N), u)

    def _check_unary(op, u):
        _compare(op(X, varX), u)

    def _check_binary(op, u):
        _compare(op(X, varX, Y, varY), u)

    _check_pow(ux**N)
    _check_binary(add, ux+uy)
    _check_binary(sub, ux-uy)
    _check_binary(mul, ux*uy)
    _check_binary(div, ux/uy)
    _check_binary(pow2, ux**uy)

    _check_unary(exp, umath.exp(ux))
    _check_unary(log, umath.log(ux))
    _check_unary(sin, umath.sin(ux))
    _check_unary(cos, umath.cos(ux))
    _check_unary(tan, umath.tan(ux))
    _check_unary(arcsin, umath.asin(ux))
    _check_unary(arccos, umath.acos(ux))
    _check_unary(arctan, umath.atan(ux))
    _check_binary(arctan2, umath.atan2(ux, uy))
예제 #7
0
def test_against_uncertainties_package():
    try:
        from uncertainties import ufloat
        from uncertainties import umath
        from math import sqrt as math_sqrt
    except ImportError:
        return
    X, varX = 0.5, 0.04
    Y, varY = 3, 0.09
    N = 3
    ux = ufloat(X, math_sqrt(varX))
    uy = ufloat(Y, math_sqrt(varY))

    def _compare(result, u):
        Z, varZ = result
        assert abs(Z-u.n)/u.n < 1e-13 and (varZ-u.s**2)/u.s**2 < 1e-13, \
            "expected (%g,%g) got (%g,%g)"%(u.n, u.s**2, Z, varZ)

    def _check_pow(u):
        _compare(pow(X, varX, N), u)

    def _check_unary(op, u):
        _compare(op(X, varX), u)

    def _check_binary(op, u):
        _compare(op(X, varX, Y, varY), u)

    _check_pow(ux**N)
    _check_binary(add, ux + uy)
    _check_binary(sub, ux - uy)
    _check_binary(mul, ux * uy)
    _check_binary(div, ux / uy)
    _check_binary(pow2, ux**uy)

    _check_unary(exp, umath.exp(ux))
    _check_unary(log, umath.log(ux))
    _check_unary(sin, umath.sin(ux))
    _check_unary(cos, umath.cos(ux))
    _check_unary(tan, umath.tan(ux))
    _check_unary(arcsin, umath.asin(ux))
    _check_unary(arccos, umath.acos(ux))
    _check_unary(arctan, umath.atan(ux))
    _check_binary(arctan2, umath.atan2(ux, uy))
예제 #8
0
    def u_get_zenith_azimuth(self, u_dir_x, u_dir_y, u_dir_z, with_flip=True):
        """Get zeniths and azimuths [in radians] from direction vector.

        Parameters
        ----------
        u_dir_x : unumpy.array
            The x-component of the direction vector with uncertainty.
        u_dir_y : unumpy.array
            The y-component of the direction vector with uncertainty.
        u_dir_z : unumpy.array
            The z-component of the direction vector with uncertainty.
        with_flip : bool, optional
            If True, then the direction vectors show in the opposite direction
            than the zenith/azimuth pairs. This is common within IceCube
            software, since the direction vector shows along the particle
            direction, whereas the zenith/azimuth shows to the source position.

        Returns
        -------
        unumpy.array, unumpy.array
            The zenith and azimuth angles with uncertainties.
        """
        # normalize
        if not self.is_normalized(u_dir_x.nominal_value, u_dir_y.nominal_value,
                                  u_dir_z.nominal_value):
            u_dir_x, u_dir_y, u_dir_z = \
                self.u_normalize_dir(u_dir_x, u_dir_y, u_dir_z)

        if with_flip:
            u_dir_x *= -1
            u_dir_y *= -1
            u_dir_z *= -1

        if np.abs(u_dir_z.nominal_value) > 1.:
            raise ValueError('Z-component |{!r}| > 1!'.format(
                u_dir_z.nominal_value))
        zenith = umath.acos(u_dir_z)
        azimuth = (umath.atan2(u_dir_y, u_dir_x) + 2 * np.pi) % (2 * np.pi)

        return zenith, azimuth
예제 #9
0
def get_angular_sep(ra1, dec1, ra2, dec2):
    """
	implements the vincinerty distance formular in the case
	of a sphere.
	"""

    ra1 = ra1 * deg2rad
    ra2 = ra2 * deg2rad

    dec1 = dec1 * deg2rad
    dec2 = dec2 * deg2rad

    top = np.sqrt((np.cos(dec2) * np.sin(ra2 - ra1))**(2) +
                  (np.cos(dec1) * np.sin(dec2) -
                   np.sin(dec1) * np.cos(dec2) * np.cos(ra2 - ra1))**(2))

    bottom = (np.sin(dec1) * np.sin(dec2)) + (np.cos(dec1) * np.cos(dec2) *
                                              np.cos(ra2 - ra1))

    dist = np.atan2(top, bottom)

    return (dist / deg2rad) * 3600.0 * 1000.0
예제 #10
0
    def get_summary(self, nodmx=False):
        """Return a human-readable summary of the Fitter results.
        
        Parameters
        ----------
        nodmx : bool
            Set to True to suppress printing DMX parameters in summary
        """

        # Need to check that fit has been done first!
        if not hasattr(self, "covariance_matrix"):
            log.warning(
                "fit_toas() has not been run, so pre-fit and post-fit will be the same!"
            )

        from uncertainties import ufloat
        import uncertainties.umath as um

        # First, print fit quality metrics
        s = "Fitted model using {} method with {} free parameters to {} TOAs\n".format(
            self.method, len(self.get_fitparams()), self.toas.ntoas)
        s += "Prefit residuals Wrms = {}, Postfit residuals Wrms = {}\n".format(
            self.resids_init.rms_weighted(), self.resids.rms_weighted())
        s += "Chisq = {:.3f} for {} d.o.f. for reduced Chisq of {:.3f}\n".format(
            self.resids.chi2, self.resids.dof, self.resids.chi2_reduced)
        s += "\n"

        # Next, print the model parameters
        s += "{:<14s} {:^20s} {:^28s} {}\n".format("PAR", "Prefit", "Postfit",
                                                   "Units")
        s += "{:<14s} {:>20s} {:>28s} {}\n".format("=" * 14, "=" * 20,
                                                   "=" * 28, "=" * 5)
        for pn in list(self.get_allparams().keys()):
            if nodmx and pn.startswith("DMX"):
                continue
            prefitpar = getattr(self.model_init, pn)
            par = getattr(self.model, pn)
            if par.value is not None:
                if isinstance(par, strParameter):
                    s += "{:14s} {:>20s} {:28s} {}\n".format(
                        pn, prefitpar.value, "", par.units)
                elif isinstance(par, AngleParameter):
                    # Add special handling here to put uncertainty into arcsec
                    if par.frozen:
                        s += "{:14s} {:>20s} {:>28s} {} \n".format(
                            pn, str(prefitpar.quantity), "", par.units)
                    else:
                        if par.units == u.hourangle:
                            uncertainty_unit = pint.hourangle_second
                        else:
                            uncertainty_unit = u.arcsec
                        s += "{:14s} {:>20s}  {:>16s} +/- {:.2g} \n".format(
                            pn,
                            str(prefitpar.quantity),
                            str(par.quantity),
                            par.uncertainty.to(uncertainty_unit),
                        )

                else:
                    # Assume a numerical parameter
                    if par.frozen:
                        s += "{:14s} {:20g} {:28s} {} \n".format(
                            pn, prefitpar.value, "", par.units)
                    else:
                        # s += "{:14s} {:20g} {:20g} {:20.2g} {} \n".format(
                        #     pn,
                        #     prefitpar.value,
                        #     par.value,
                        #     par.uncertainty.value,
                        #     par.units,
                        # )
                        s += "{:14s} {:20g} {:28SP} {} \n".format(
                            pn,
                            prefitpar.value,
                            ufloat(par.value, par.uncertainty.value),
                            par.units,
                        )
        # Now print some useful derived parameters
        s += "\nDerived Parameters:\n"
        if hasattr(self.model, "F0"):
            F0 = self.model.F0.quantity
            if not self.model.F0.frozen:
                p, perr = pint.utils.pferrs(F0, self.model.F0.uncertainty)
                s += "Period = {} +/- {}\n".format(p.to(u.s), perr.to(u.s))
            else:
                s += "Period = {}\n".format((1.0 / F0).to(u.s))
        if hasattr(self.model, "F1"):
            F1 = self.model.F1.quantity
            if not any([self.model.F1.frozen, self.model.F0.frozen]):
                p, perr, pd, pderr = pint.utils.pferrs(
                    F0, self.model.F0.uncertainty, F1,
                    self.model.F1.uncertainty)
                s += "Pdot = {} +/- {}\n".format(
                    pd.to(u.dimensionless_unscaled),
                    pderr.to(u.dimensionless_unscaled))
                brakingindex = 3
                s += "Characteristic age = {:.4g} (braking index = {})\n".format(
                    pint.utils.pulsar_age(F0, F1, n=brakingindex),
                    brakingindex)
                s += "Surface magnetic field = {:.3g}\n".format(
                    pint.utils.pulsar_B(F0, F1))
                s += "Magnetic field at light cylinder = {:.4g}\n".format(
                    pint.utils.pulsar_B_lightcyl(F0, F1))
                I_NS = I = 1.0e45 * u.g * u.cm**2
                s += "Spindown Edot = {:.4g} (I={})\n".format(
                    pint.utils.pulsar_edot(F0, F1, I=I_NS), I_NS)

        if hasattr(self.model, "PX"):
            if not self.model.PX.frozen:
                s += "\n"
                px = ufloat(
                    self.model.PX.quantity.to(u.arcsec).value,
                    self.model.PX.uncertainty.to(u.arcsec).value,
                )
                s += "Parallax distance = {:.3uP} pc\n".format(1.0 / px)

        # Now binary system derived parameters
        binary = None
        for x in self.model.components:
            if x.startswith("Binary"):
                binary = x
        if binary is not None:
            s += "\n"
            s += "Binary model {}\n".format(binary)

            if binary.startswith("BinaryELL1"):
                if not any([
                        self.model.EPS1.frozen,
                        self.model.EPS2.frozen,
                        self.model.TASC.frozen,
                        self.model.PB.frozen,
                ]):
                    eps1 = ufloat(
                        self.model.EPS1.quantity.value,
                        self.model.EPS1.uncertainty.value,
                    )
                    eps2 = ufloat(
                        self.model.EPS2.quantity.value,
                        self.model.EPS2.uncertainty.value,
                    )
                    tasc = ufloat(
                        # This is a time in MJD
                        self.model.TASC.quantity.mjd,
                        self.model.TASC.uncertainty.to(u.d).value,
                    )
                    pb = ufloat(
                        self.model.PB.quantity.to(u.d).value,
                        self.model.PB.uncertainty.to(u.d).value,
                    )
                    s += "Conversion from ELL1 parameters:\n"
                    ecc = um.sqrt(eps1**2 + eps2**2)
                    s += "ECC = {:P}\n".format(ecc)
                    om = um.atan2(eps1, eps2) * 180.0 / np.pi
                    if om < 0.0:
                        om += 360.0
                    s += "OM  = {:P}\n".format(om)
                    t0 = tasc + pb * om / 360.0
                    s += "T0  = {:SP}\n".format(t0)

                    s += pint.utils.ELL1_check(
                        self.model.A1.quantity,
                        ecc.nominal_value,
                        self.resids.rms_weighted(),
                        self.toas.ntoas,
                        outstring=True,
                    )
                    s += "\n"

                # Masses and inclination
                if not any([self.model.PB.frozen, self.model.A1.frozen]):
                    pbs = ufloat(
                        self.model.PB.quantity.to(u.s).value,
                        self.model.PB.uncertainty.to(u.s).value,
                    )
                    a1 = ufloat(
                        self.model.A1.quantity.to(pint.ls).value,
                        self.model.A1.uncertainty.to(pint.ls).value,
                    )
                    fm = 4.0 * np.pi**2 * a1**3 / (4.925490947e-6 * pbs**2)
                    s += "Mass function = {:SP} Msun\n".format(fm)
                    mcmed = pint.utils.companion_mass(
                        self.model.PB.quantity,
                        self.model.A1.quantity,
                        inc=60.0 * u.deg,
                        mpsr=1.4 * u.solMass,
                    )
                    mcmin = pint.utils.companion_mass(
                        self.model.PB.quantity,
                        self.model.A1.quantity,
                        inc=90.0 * u.deg,
                        mpsr=1.4 * u.solMass,
                    )
                    s += "Companion mass min, median (assuming Mpsr = 1.4 Msun) = {:.4f}, {:.4f} Msun\n".format(
                        mcmin, mcmed)

                if hasattr(self.model, "SINI"):
                    if not self.model.SINI.frozen:
                        si = ufloat(
                            self.model.SINI.quantity.value,
                            self.model.SINI.uncertainty.value,
                        )
                        s += "From SINI in model:\n"
                        s += "    cos(i) = {:SP}\n".format(um.sqrt(1 - si**2))
                        s += "    i = {:SP} deg\n".format(
                            um.asin(si) * 180.0 / np.pi)

                    psrmass = pint.utils.pulsar_mass(
                        self.model.PB.quantity,
                        self.model.A1.quantity,
                        self.model.M2.quantity,
                        np.arcsin(self.model.SINI.quantity),
                    )
                    s += "Pulsar mass (Shapiro Delay) = {}".format(psrmass)

        return s
예제 #11
0
def candid_grid(input_data,
                step=10,
                rmin=20,
                rmax=400,
                diam=0,
                obs=['cp', 'v2'],
                extra_error_cp=0,
                err_scale=1,
                extra_error_v2=0,
                instruments=None,
                doNotFit=[
                    'diam*',
                ],
                ncore=1,
                verbose=False):
    """ This function is an user friendly interface between the users of amical
    pipeline and the CANDID analysis package (https://github.com/amerand/CANDID).

    Parameters:
    -----------
    `input_data` {str or list}:
        oifits file names or list of oifits files,\n
    `step` {int}:
        step used to compute the binary grid positions,\n
    `rmin`, `rmax` {float}:
        Bounds of the grid [mas],\n
    `diam` {float}:
        Stellar diameter of the primary star [mas] (default=0),\n
    `obs` {list}:
        List of observables to be fitted (default: ['cp', 'v2']),\n
    `doNotFit` {list}:
        Parameters not fitted (default: ['diam*']),\n
    `verbose` {boolean}:
        print some informations {default: False}.

    Outputs:
    --------
    `res` {dict}:
        Dictionnary of the results ('best'), uncertainties ('uncer'),
        reduced chi2 ('chi2') and sigma detection ('nsigma').
    """

    cprint(' | --- Start CANDID fitting --- :', 'green')
    o = candid.Open(input_data,
                    extra_error=extra_error_cp,
                    err_scale=err_scale,
                    extra_error_v2=extra_error_v2,
                    instruments=instruments)

    o.observables = obs

    o.fitMap(rmax=rmax,
             rmin=rmin,
             ncore=ncore,
             fig=0,
             step=step,
             addParam={"diam*": diam},
             doNotFit=doNotFit,
             verbose=verbose)

    fit = o.bestFit["best"]
    e_fit = o.bestFit["uncer"]
    chi2 = o.bestFit['chi2']
    nsigma = o.bestFit['nsigma']

    f = fit["f"] / 100.0
    e_f = e_fit["f"] / 100.0
    if (e_f < 0) or (e_fit["x"] < 0) or (e_fit["y"] < 0):
        print('Warning: error dm is negative.')
        e_f = abs(e_f)
        e_fit["x"] = 0
        e_fit["y"] = 0

    f_u = ufloat(f, e_f)
    x, y = fit["x"], fit["y"]
    x_u = ufloat(x, e_fit["x"])
    y_u = ufloat(y, e_fit["y"])

    dm = -2.5 * umath.log10(f_u)
    s = (x_u**2 + y_u**2)**0.5
    posang = ((umath.atan2(x_u, y_u) * 180 / np.pi))
    if posang.nominal_value < 0:
        posang = 360 + posang

    cr = 1 / f_u
    cprint("\nResults binary fit (χ2 = %2.1f, nσ = %2.1f):" % (chi2, nsigma),
           "cyan")
    cprint("-------------------", "cyan")

    print("Sep = %2.1f +/- %2.1f mas" % (s.nominal_value, s.std_dev))
    print("Theta = %2.1f +/- %2.1f deg" %
          (posang.nominal_value, posang.std_dev))
    print("CR = %2.1f +/- %2.1f" % (cr.nominal_value, cr.std_dev))
    print("dm = %2.2f +/- %2.2f" % (dm.nominal_value, dm.std_dev))
    res = {
        'best': {
            'model': 'binary_res',
            'dm': dm.nominal_value,
            'theta': posang.nominal_value,
            'sep': s.nominal_value,
            'diam': fit["diam*"],
            'x0': 0,
            'y0': 0
        },
        'uncer': {
            'dm': dm.std_dev,
            'theta': posang.std_dev,
            'sep': s.std_dev
        },
        'chi2': chi2,
        'nsigma': nsigma,
        'comp': o.bestFit["best"]
    }

    return res
예제 #12
0
def candid_grid(
    input_data: Union[str, List[str]],
    step: int = 10,
    rmin: float = 20,
    rmax: float = 400,
    diam: float = 0,
    obs: Optional[List[str]] = None,
    extra_error_cp: float = 0,
    err_scale: float = 1,
    extra_error_v2: float = 0,
    instruments=None,
    doNotFit=None,
    ncore: int = 1,
    save: bool = False,
    outputfile: Optional[str] = None,
    verbose: bool = False,
):
    """This function is an user friendly interface between the users of amical
    pipeline and the CANDID analysis package (https://github.com/amerand/CANDID).

    Parameters:
    -----------
    `input_data`:
        oifits file names or list of oifits files,\n
    `step`:
        step used to compute the binary grid positions,\n
    `rmin`, `rmax`:
        Bounds of the grid [mas],\n
    `diam`:
        Stellar diameter of the primary star [mas] (default=0),\n
    `obs`:
        List of observables to be fitted (default: ['cp', 'v2']),\n
    `doNotFit`:
        Parameters not fitted (default: ['diam*']),\n
    `verbose`:
        print some informations {default: False}.

    Outputs:
    --------
    `res` {dict}:
        Dictionnary of the results ('best'), uncertainties ('uncer'),
        reduced chi2 ('chi2') and sigma detection ('nsigma').
    """
    if obs is None:
        obs = ["cp", "v2"]
    if doNotFit is None:
        doNotFit = ["diam*"]

    cprint(" | --- Start CANDID fitting --- :", "green")
    o = candid.Open(
        input_data,
        extra_error=extra_error_cp,
        err_scale=err_scale,
        extra_error_v2=extra_error_v2,
        instruments=instruments,
    )

    o.observables = obs

    o.fitMap(
        rmax=rmax,
        rmin=rmin,
        ncore=ncore,
        fig=0,
        step=step,
        addParam={"diam*": diam},
        doNotFit=doNotFit,
        verbose=verbose,
    )

    if save:
        if isinstance(input_data, list):
            first_input = input_data[0]
        else:
            first_input = input_data
        filename = os.path.basename(first_input) + "_detection_map_candid.pdf"
        if outputfile is not None:
            filename = outputfile
        plt.savefig(filename, dpi=300)

    fit = o.bestFit["best"]
    e_fit = o.bestFit["uncer"]
    chi2 = o.bestFit["chi2"]
    nsigma = o.bestFit["nsigma"]

    f = fit["f"] / 100.0
    e_f = e_fit["f"] / 100.0
    if (e_f < 0) or (e_fit["x"] < 0) or (e_fit["y"] < 0):
        print("Warning: error dm is negative.")
        e_f = abs(e_f)
        e_fit["x"] = 0
        e_fit["y"] = 0

    f_u = ufloat(f, e_f)
    x, y = fit["x"], fit["y"]
    x_u = ufloat(x, e_fit["x"])
    y_u = ufloat(y, e_fit["y"])

    dm = -2.5 * umath.log10(f_u)
    s = (x_u ** 2 + y_u ** 2) ** 0.5
    posang = umath.atan2(x_u, y_u) * 180 / np.pi
    if posang.nominal_value < 0:
        posang = 360 + posang

    cr = 1 / f_u
    cprint(f"\nResults binary fit (χ2 = {chi2:2.1f}, nσ = {nsigma:2.1f}):", "cyan")
    cprint("-------------------", "cyan")

    print(f"Sep = {s.nominal_value:2.1f} +/- {s.std_dev:2.1f} mas")
    print(f"Theta = {posang.nominal_value:2.1f} +/- {posang.std_dev:2.1f} deg")
    print(f"CR = {cr.nominal_value:2.1f} +/- {cr.std_dev:2.1f}")
    print(f"dm = {dm.nominal_value:2.2f} +/- {dm.std_dev:2.2f}")
    res = {
        "best": {
            "model": "binary_res",
            "dm": dm.nominal_value,
            "theta": posang.nominal_value,
            "sep": s.nominal_value,
            "diam": fit["diam*"],
            "x0": 0,
            "y0": 0,
        },
        "uncer": {"dm": dm.std_dev, "theta": posang.std_dev, "sep": s.std_dev},
        "chi2": chi2,
        "nsigma": nsigma,
        "comp": o.bestFit["best"],
    }

    return res