Exemplo n.º 1
0
  def testNormalTriad(self):
    """
    Check the correct working of the normalTriad() function.
    """
    phi=array([0.0,pi/2,pi,3*pi/2,0.0,0.0])
    theta=array([0.0,0.0,0.0,0.0,pi/2,-pi/2])
    pExpected=array([[0,-1,0,1,0,0], [1,0,-1,0,1,1], [0,0,0,0,0,0]])
    qExpected=array([[0,0,0,0,-1,1], [0,0,0,0,0,0], [1,1,1,1,0,0]])
    rExpected=array([[1,0,-1,0,0,0], [0,1,0,-1,0,0], [0,0,0,0,1,-1]])
    p, q, r = normalTriad(phi,theta)
    assert_array_almost_equal(pExpected, p, decimal=15)
    assert_array_almost_equal(qExpected, q, decimal=15)
    assert_array_almost_equal(rExpected, r, decimal=15)

    phiRandom = 2.0*pi*rand(10)
    thetaRandom = -pi/2.0+pi*rand(10)
    z=array([0,0,1])
    for phi in phiRandom:
      for theta in thetaRandom:
        p, q, r = normalTriad(phi,theta)
        rExpected=array([cos(phi)*cos(theta), sin(phi)*cos(theta), sin(theta)])
        pExpected=cross(z,rExpected)
        pExpected=pExpected/sqrt(dot(pExpected,pExpected))
        qExpected=cross(rExpected,pExpected)
        assert_array_almost_equal(pExpected, p, decimal=8)
        assert_array_almost_equal(qExpected, q, decimal=8)
        assert_array_almost_equal(rExpected, r, decimal=8)
Exemplo n.º 2
0
  def testNormalTriad(self):
    """
    Check the correct working of the normalTriad() function.
    """
    phi=array([0.0,pi/2,pi,3*pi/2,0.0,0.0])
    theta=array([0.0,0.0,0.0,0.0,pi/2,-pi/2])
    pExpected=array([[0,-1,0,1,0,0], [1,0,-1,0,1,1], [0,0,0,0,0,0]])
    qExpected=array([[0,0,0,0,-1,1], [0,0,0,0,0,0], [1,1,1,1,0,0]])
    rExpected=array([[1,0,-1,0,0,0], [0,1,0,-1,0,0], [0,0,0,0,1,-1]])
    p, q, r = normalTriad(phi,theta)
    assert_array_almost_equal(pExpected, p, decimal=15)
    assert_array_almost_equal(qExpected, q, decimal=15)
    assert_array_almost_equal(rExpected, r, decimal=15)

    phiRandom = 2.0*pi*rand(10)
    thetaRandom = -pi/2.0+pi*rand(10)
    z=array([0,0,1])
    for phi in phiRandom:
      for theta in thetaRandom:
        p, q, r = normalTriad(phi,theta)
        rExpected=array([cos(phi)*cos(theta), sin(phi)*cos(theta), sin(theta)])
        pExpected=cross(z,rExpected)
        pExpected=pExpected/sqrt(dot(pExpected,pExpected))
        qExpected=cross(rExpected,pExpected)
        assert_array_almost_equal(pExpected, p, decimal=8)
        assert_array_almost_equal(qExpected, q, decimal=8)
        assert_array_almost_equal(rExpected, r, decimal=8)
Exemplo n.º 3
0
    def propagate_astrometry(self, phi, theta, parallax, muphistar, mutheta, vrad, t0, t1):
        """
        Propagate the position of a source from the reference epoch t0 to the new epoch t1.

        Parameters
        ----------

        phi : float
            Longitude at reference epoch (radians).
        theta : float
            Latitude at reference epoch (radians).
        parallax : float
            Parallax at the reference epoch (mas).
        muphistar : float
            Proper motion in longitude (including cos(latitude) term) at reference epoch (mas/yr).
        mutheta : float
            Proper motion in latitude at reference epoch (mas/yr).
        vrad : float
            Radial velocity at reference epoch (km/s).
        t0 : float
            Reference epoch (Julian years).
        t1 : float
            New epoch (Julian years).

        Returns
        -------

        Astrometric parameters, including the "radial proper motion" (NOT the radial velocity), at the new epoch.
        phi1, theta1, parallax1, muphistar1, mutheta1, mur1 = epoch_prop_pos(..., t0, t1)
        """

        t = t1-t0
        p0, q0, r0 = normalTriad(phi, theta)

        # Convert input data to units of radians and Julian year. Use ICRS coordinate names internally to
        # avoid errors in translating the formulae to code.
        pmra0 = muphistar*self.mastorad
        pmdec0 = mutheta*self.mastorad
        plx0 = parallax*self.mastorad
        pmr0 = vrad*parallax/auKmYearPerSec*self.mastorad
        pmtot0sqr = (muphistar**2 + mutheta**2) * self.mastorad**2

        # Proper motion vector
        pmvec0 = pmra0*p0+pmdec0*q0

        f = (1 + 2*pmr0*t + (pmtot0sqr+pmr0**2)*t**2)**(-0.5)
        u = (r0*(1+pmr0*t) + pmvec0*t)*f

        _, phi1, theta1 = cartesianToSpherical(u[0], u[1], u[2])
        parallax1 = parallax*f
        pmr1 = (pmr0+(pmtot0sqr + pmr0**2)*t)*f**2
        pmvec1 = (pmvec0*(1+pmr0*t) - r0*pmr0**2*t)*f**3
        p1, q1, r1 = normalTriad(phi1, theta1)
        muphistar1 = sum(p1*pmvec1/self.mastorad, axis=0)
        mutheta1 = sum(q1*pmvec1/self.mastorad, axis =0)
        murad1 = pmr1/self.mastorad

        return phi1, theta1, parallax1, muphistar1, mutheta1, murad1
Exemplo n.º 4
0
def radial_velocity_distribution(PDFs, ra, dec, plx, mura, mudec, C, x = np.arange(-500., 500., 0.0025), v_r_err = 0.):

    p_vr_M = []
    p_vr_C = []
    p_vr_C_temp = []

    ICRS_to_galactic = coords.CoordinateTransformation(coords.Transformations.ICRS2GAL)
    l, b = ICRS_to_galactic.transformSkyCoordinates(ra, dec)
    pml, pmb = ICRS_to_galactic.transformProperMotions(ra, dec, mura,mudec)
    C_gal = ICRS_to_galactic.transformCovarianceMatrix(ra, dec, C)
    jacobian = array([[-pml * k/plx**2., k/plx, 0.   ],
                     [-pmb * k/plx**2., 0.   , k/plx]])
    cov_v_tan = jacobian.dot(C_gal[2:5,2:5]).dot(jacobian.T)
    v_t_gal = array([pml*k/plx, pmb*k/plx])
    p_gal, q_gal, r_gal = normalTriad(l, b)
    coordtrans = np.vstack((p_gal, q_gal, r_gal))
    for N in PDFs:
        mean_v_rad_M = r_gal.dot(N.mean)
        sig_v_rad_M  = np.sqrt(r_gal.dot(N.cov).dot(r_gal) + v_r_err**2.)
        newPDF_M = univariate(mean = mean_v_rad_M, sigma = sig_v_rad_M)
        newPDF_M.amp = N.amp
        p_vr_M.append(newPDF_M)

        mean_v_l = p_gal.dot(N.mean)
        mean_v_b = q_gal.dot(N.mean)
        mean_v_tan = array([mean_v_l, mean_v_b])
        cov_pqr_gal = coordtrans.dot(N.cov).dot(coordtrans.T)
        cov_pqr_gal[:2,:2] += cov_v_tan
        cov_pqr_gal[2,2]   += v_r_err**2.
        A = cov_pqr_gal[:2,:2]
        B = cov_pqr_gal[2, 2]
        C = cov_pqr_gal[2,:2]
        A_inv = np.linalg.inv(A)
        mean_v_rad_C = mean_v_rad_M + C.dot(A_inv.dot(v_t_gal - mean_v_tan))
        sig_v_rad_C = np.sqrt(B - C.dot(A_inv).dot(C.T))
        newPDF_C = norm(loc=mean_v_rad_C, scale=sig_v_rad_C)
        newPDF_C.A = A
        newPDF_C.mean_v_tan = mean_v_tan
        prob_v_tan_gal = N.amp * m_n.pdf(v_t_gal, mean = mean_v_tan, cov = A)
        newPDF_C.prob_v_tan_gal = prob_v_tan_gal
        p_vr_C_temp.append(newPDF_C)

    prob_v_tan_gal = np.sum(N_C.prob_v_tan_gal for N_C in p_vr_C_temp)

    for N, N_C in zip(PDFs, p_vr_C_temp):
        N_C.q = N.amp * m_n.pdf(v_t_gal, mean = N_C.mean_v_tan, cov = N_C.A) / prob_v_tan_gal
        p_vr_C.append(N_C)

    p_m = array([N_M.amp * N_M.pdf(x) for N_M in p_vr_M])
    p_c = array([N_C.q * N_C.pdf(x) for N_C in p_vr_C])
    p_m = p_m.sum(axis=0)
    p_c = p_c.sum(axis=0)

    y = np.vstack((x, p_c, p_m))

    return y
Exemplo n.º 5
0
def _like3(init_par, alpha, delta, plx_obs, mualpha_obs, mudelta_obs, sigma_obs, ccoef, i):
	"""
	Estimate the likelihood function for every set of observation.
	Then, estimate the function U(init_par) that needs to be minimized 
	to find the best fit to the parameters.

	Parameters:
	------------
	init_par - Set of initial values for: 1) i-th parallax [mas];
				       2) The cluster centroid velocity  [vx_0, vy_0, vz_0] [km/s];
				       3) The cluster velocity dispersion, sigma_v [km/s];
	alpha, delta -  position of i-th star [rad];
	plx_obs, mualpha_obs, mudelta_obs -  observed values for parallaxes and proper motions [mas, mas/yr] of i-th star;
	vrad_obs -  radial velocities [km/s] of i-th star;

	sigma_obs - 3-dim array of observed errors for parallax and proper motion [mas, mas/yr] of i-th star;
	sigma_vrad -  error on radial velocities [km/s] of i-th star;

	ccoef - 3-dim array of correlation coefficients from the HIP catalogue of i-th star. 
	
	Returns:
	-----------
	g - values of g_i(theta) for the i-th star, see eq. 19 in Lindegren+2000;
	U(init_par) - The function in Eq. (18) of Lindegren+2000, for the i-th star.	
	"""

	plx_mod, v, sigma_v =  init_par[i], init_par[-4:-1], init_par[-1]  
	p, q, r = normalTriad(alpha, delta)
	mualpha_mod = np.dot(np.transpose(p),v)*plx_mod/_A
	mudelta_mod = np.dot(np.transpose(q),v)*plx_mod/_A
  	
	sigma_plx, sigma_mualpha, sigma_mudelta = sigma_obs
	r_plx_muRa, r_plx_muDec, r_muRa_muDec = ccoef[0], ccoef[1], ccoef[2] 
	
	C = np.zeros((3,3),dtype=np.float64)
	C[0,0],C[1,1],C[2,2] = sigma_plx**2.,sigma_mualpha**2., sigma_mudelta**2.
	C[0,1], C[0,2] = r_plx_muRa*sigma_plx*sigma_mualpha, r_plx_muDec*sigma_plx*sigma_mudelta
	C[1,0], C[1,2] = r_plx_muRa*sigma_plx*sigma_mualpha, r_muRa_muDec*sigma_mualpha*sigma_mudelta
	C[2,0], C[2,1] = r_plx_muDec*sigma_plx*sigma_mudelta, r_muRa_muDec*sigma_mualpha*sigma_mudelta

	E = np.zeros((3,3),dtype=np.float64)
	E[1,1],E[2,2] = (sigma_v**2.)*(plx_mod/_A)**2., (sigma_v**2.)*(plx_mod/_A)**2.
	
	D = np.add(E,C)
	detD =  det(D) 
	invD =  inv(D)
		
	a_c = np.array([plx_obs - plx_mod, mualpha_obs - mualpha_mod, mudelta_obs-mudelta_mod])
	g_func = row_matrix_col(a_c, a_c, invD)
	
	
	return  detD, g_func
Exemplo n.º 6
0
    def _getJacobian(self, phi, theta):
        """
        Calculates the Jacobian for the transformation of the position errors and proper motion errors
        between coordinate systems. This Jacobian is also the rotation matrix for the transformation of
        proper motions. See section 1.5.3 of the Hipparcos Explanatory Volume 1 (equation 1.5.20). This
        matrix has the following form:

            |  c  s |
        J = |       |
            | -s  c |

        Parameters
        ----------

        phi       - The longitude-like angle of the position of the source (radians).
        theta     - The latitude-like angle of the position of the source (radians).

        Returns
        -------

        c, s - The Jacobian matrix elements c and s corresponding to (phi, theta) and the currently
               desired coordinate system transformation.
        """

        p, q, r = normalTriad(phi, theta)

        # zRot = z-axis of new coordinate system expressed in terms of old system
        zRot = self.rotationMatrix[2, :]

        if (p.ndim == 2):
            zRotAll = tile(zRot, p.shape[1]).reshape(p.shape[1], 3)
            pRot = cross(zRotAll, r.T)
            normPRot = norm(pRot, axis=1)
            for i in range(pRot.shape[0]):
                pRot[i] = pRot[i] / normPRot[i]
            c = zeros(pRot.shape[0])
            s = zeros(pRot.shape[0])
            for i in range(pRot.shape[0]):
                c[i] = dot(pRot[i], p.T[i])
                s[i] = dot(pRot[i], q.T[i])
            return c, s
        else:
            pRot = cross(zRot, r.T)
            pRot = pRot / norm(pRot)
            return dot(pRot, p), dot(pRot, q)
Exemplo n.º 7
0
    def _getJacobian(self, phi, theta):
        """
        Calculates the Jacobian for the transformation of the position errors and proper motion errors
        between coordinate systems. This Jacobian is also the rotation matrix for the transformation of
        proper motions. See section 1.5.3 of the Hipparcos Explanatory Volume 1 (equation 1.5.20). This
        matrix has the following form:

            |  c  s |
        J = |       |
            | -s  c |

        Parameters
        ----------

        phi       - The longitude-like angle of the position of the source (radians).
        theta     - The latitude-like angle of the position of the source (radians).

        Returns
        -------

        c, s - The Jacobian matrix elements c and s corresponding to (phi, theta) and the currently
               desired coordinate system transformation.
        """

        p, q, r = normalTriad(phi, theta)

        # zRot = z-axis of new coordinate system expressed in terms of old system
        zRot = self.rotationMatrix[2,:]

        if (p.ndim == 2):
            zRotAll = tile(zRot, p.shape[1]).reshape(p.shape[1],3)
            pRot = cross(zRotAll, r.T)
            normPRot = norm(pRot,axis=1)
            for i in range(pRot.shape[0]):
                pRot[i] = pRot[i]/normPRot[i]
            c = zeros(pRot.shape[0])
            s = zeros(pRot.shape[0])
            for i in range(pRot.shape[0]):
                c[i] = dot(pRot[i], p.T[i])
                s[i] = dot(pRot[i], q.T[i])
            return c, s
        else:
            pRot = cross(zRot, r.T)
            pRot = pRot/norm(pRot)
            return dot(pRot,p), dot(pRot,q)
Exemplo n.º 8
0
    def _getJacobian(self, phi, theta):
        """
    Calculates the Jacobian for the transformation of the position errors and proper motion errors
    between coordinate systems. This Jacobian is also the rotation matrix for the transformation of
    proper motions. See section 1.5.3 of the Hipparcos Explanatory Volume 1 (equation 1.5.20).

    Parameters
    ----------

    phi       - The longitude-like angle of the position of the source (radians).
    theta     - The latitude-like angle of the position of the source (radians).

    Returns
    -------

    jacobian - The Jacobian matrix corresponding to (phi, theta) and the currently desired coordinate
               system transformation.
    """

        p, q, r = normalTriad(phi, theta)

        # zRot = z-axis of new coordinate system expressed in terms of old system
        zRot = self.rotationMatrix[2, :]
        zRotAll = zRot
        if (p.ndim == 2):
            for i in range(p.shape[1] - 1):
                zRotAll = vstack((zRotAll, zRot))
        pRot = cross(zRotAll, transpose(r))
        if (p.ndim == 2):
            normPRot = sqrt(diag(dot(pRot, transpose(pRot))))
            for i in range(pRot.shape[0]):
                pRot[i, :] = pRot[i, :] / normPRot[i]
        else:
            pRot = pRot / norm(pRot)

        if (p.ndim == 2):
            return diag(dot(pRot, p)), diag(dot(pRot, q))
        else:
            return dot(pRot, p), dot(pRot, q)
Exemplo n.º 9
0
def _like(init_par, alpha, delta, obs, sigma_obs, ccoef, N):
    """
	Estimate the likelihood function for every set of observations.
	Then, estimate the function U(init_par) that needs to be minimized 
	to find the best fit to the parameters.

	Parameters:
	------------
	init_par - Set of initial values for: 1) All the parallaxes [mas];
				       2) The cluster centroid velocity  [vx_0, vy_0, vz_0] [km/s];
				       3) The cluster velocity dispersion, sigma_v [km/s];
	alpha, delta - Array of cluster member positions [rad];
	obs - Matrix  of observed values for parallaxes and proper motions [mas, mas/yr];
	sigma_obs - 3-dim array of observed errors for parallaxes and proper motions [mas, mas/yr];
	ccoef - 3-dim array of correlation coefficients. 
	N - the number of stars;

	Returns:
	-----------
	g - An array of values with the values of g_i(theta) for each star in the group, see eq. 19 in Lindegren+2000;
	U(init_par) - The function in Eq. (18) of Lindegren+2000, i.e. the function that needs to be minimized.
	"""

    plx_mod, v, sigma_v = init_par[:-4], init_par[-4:-1], init_par[-1]
    plx_obs, mualpha_obs, mudelta_obs = obs[:, 0], obs[:, 1], obs[:, 2]

    p, q, r = normalTriad(alpha, delta)
    mualpha_mod = np.dot(np.transpose(p), v) * plx_mod / _A
    mudelta_mod = np.dot(np.transpose(q), v) * plx_mod / _A

    sigma_plx, sigma_mualpha, sigma_mudelta = np.transpose(sigma_obs)

    C = np.zeros((3, 3, N), dtype=np.float64)
    C[0, 0, :], C[1, 1, :], C[
        2, 2, :] = sigma_plx**2., sigma_mualpha**2., sigma_mudelta**2.

    r_plx_muRa, r_plx_muDec, r_muRa_muDec = np.zeros(N), np.zeros(N), np.zeros(
        N)
    r_plx_muRa[:], r_plx_muDec[:], r_muRa_muDec[:] = ccoef[:,
                                                           0], ccoef[:,
                                                                     1], ccoef[:,
                                                                               2]
    C[0, 1, :], C[
        0,
        2, :] = r_plx_muRa * sigma_plx * sigma_mualpha, r_plx_muDec * sigma_plx * sigma_mudelta
    C[1, 0, :], C[
        1,
        2, :] = r_plx_muRa * sigma_plx * sigma_mualpha, r_muRa_muDec * sigma_mualpha * sigma_mudelta
    C[2, 0, :], C[
        2,
        1, :] = r_plx_muDec * sigma_plx * sigma_mudelta, r_muRa_muDec * sigma_mualpha * sigma_mudelta

    E = np.zeros((3, 3, N), dtype=np.float64)
    E[1, 1, :], E[2, 2, :] = (sigma_v**2.) * (plx_mod / _A)**2., (
        sigma_v**2.) * (plx_mod / _A)**2.
    D, invD, detD = np.zeros((3, 3, N), dtype=np.float64), np.zeros(
        (3, 3, N), dtype=np.float64), np.ones(N)
    D = np.add(E, C)

    for i in range(N):
        det, invmat = matrix_det_inv(D[:, :, i])
        #print(det, invmat)
        detD[i] = det
        invD[:, :, i] = invmat

    a_c = np.ones((3, N))
    a_c = [
        plx_obs - plx_mod, mualpha_obs - mualpha_mod, mudelta_obs - mudelta_mod
    ]

    g_func = row_matrix_col(a_c, a_c, invD)

    like = np.ones(N)
    like = ((2 * np.pi)**(-1.5) * detD**(-0.5)) * np.exp(-0.5 * g_func)

    return np.array(np.sum(np.log(detD)) + np.sum(g_func)), g_func
Exemplo n.º 10
0
def stella_Nmatrix_4d(init_par, alpha, delta, plx_obs, mualpha_obs,
                      mudelta_obs, vrad_obs, sigma_obs, sigma_vrad, ccoef, N,
                      i):
    """
	Estimate covariance matrix of the likelihood function.

	Parameters:
	------------
	init_par - Set of initial values for: 1) All the parallaxes [mas];
				     	      2) The cluster centroid velocity  [vx_0, vy_0, vz_0] [km/s];
				       	      3) The cluster velocity dispersion [km/s];
	alpha, delta - Cluster member positions [rad];
	plx_obs, mualpha_obs, mudelta_obs - observed values for parallaxes and proper motions [mas, mas/yr];
	sigma_obs - observed errors for parallaxes and proper motions [mas, mas/yr];
	ccoef - 3-dim array of correlation coefficients from the HIP catalogue;
	N - number of stars;
	Returns:
	-----------
	Cov - N+4 x N+4 matrix, corresponding to the covariance of the parameters of the likelihood function.
	"""

    parallax, v, sigma_v = init_par[i], init_par[-4:-1], init_par[-1]

    p, q, r = normalTriad(alpha, delta)
    mualpha_mod = np.dot(np.transpose(p), v) * parallax / _A
    mudelta_mod = np.dot(np.transpose(q), v) * parallax / _A
    vrad_mod = np.dot(np.transpose(r), v)

    plx_mod, mualpha_mod, mudelta_mod = parallax, mualpha_mod, mudelta_mod
    sigma_plx, sigma_mualpha, sigma_mudelta = np.transpose(sigma_obs)

    C = np.zeros((4, 4), dtype=np.float64)
    C[0, 0], C[1,
               1], C[2,
                     2] = sigma_plx**2., sigma_mualpha**2., sigma_mudelta**2.
    C[3, 3] = sigma_vrad**2.
    corr_coefficient_plx_mualpha, corr_coefficient_plx_mudelta, corr_coefficient_mualpha_mudelta = ccoef[
        0], ccoef[1], ccoef[2]

    C[0, 1], C[
        0,
        2] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta
    C[1, 0], C[
        1,
        2] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    C[2, 0], C[
        2,
        1] = corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    E = np.zeros((4, 4), dtype=np.float64)
    E[1, 1], E[2, 2], E[3, 3] = (sigma_v**2.) * (parallax / _A)**2., (
        sigma_v**2.) * (parallax / _A)**2., sigma_v**2.
    D, invD = np.zeros((4, 4), dtype=np.float64), np.zeros((4, 4),
                                                           dtype=np.float64)
    D = np.add(E, C)

    invD = np.linalg.inv(D)

    cprime_pi, cprime_vx, cprime_vy, cprime_vz, = np.ones(4), np.ones(
        4), np.ones(4), np.ones(4)

    cprime_pi[0] = 1.
    cprime_pi[1] = np.dot(np.transpose(p), v) / _A
    cprime_pi[2] = np.dot(np.transpose(q), v) / _A
    cprime_pi[3] = 0

    cprime_vx[0] = 0.
    cprime_vx[1] = -np.sin(alpha) * plx_mod / _A
    cprime_vx[2] = -np.sin(delta) * np.cos(alpha) * plx_mod / _A
    cprime_vx[3] = np.cos(delta) * np.cos(alpha)

    cprime_vy[0] = 0.
    cprime_vy[1] = np.cos(alpha) * plx_mod / _A
    cprime_vy[2] = -np.sin(delta) * np.sin(alpha) * plx_mod / _A
    cprime_vy[3] = np.cos(delta) * np.sin(alpha)

    cprime_vz[0] = 0.
    cprime_vz[1] = 0.
    cprime_vz[2] = np.cos(delta) * plx_mod / _A
    cprime_vz[3] = np.sin(delta)

    dD_dpi, dD_dsigmav, dD_dpi2, dD_dsigmav2, dD_dpisigmav = np.zeros(
        (4, 4)), np.zeros((4, 4)), np.zeros((4, 4)), np.zeros(
            (4, 4)), np.zeros((4, 4))

    dD_dpi[1, 1] = 2. * plx_mod * ((sigma_v / _A)**2.)
    dD_dpi[2, 2] = 2. * plx_mod * ((sigma_v / _A)**2.)

    dD_dsigmav[1, 1] = 2. * sigma_v * ((plx_mod / _A)**2.)
    dD_dsigmav[2, 2] = 2. * sigma_v * ((plx_mod / _A)**2.)
    dD_dsigmav[3, 3] = 2. * sigma_v

    dD_dpi2[1, 1] = 2. * ((sigma_v / _A)**2.)
    dD_dpi2[2, 2] = 2. * ((sigma_v / _A)**2.)

    dD_dsigmav2[1, 1] = 2. * ((plx_mod / _A)**2.)
    dD_dsigmav2[2, 2] = 2. * ((plx_mod / _A)**2.)
    dD_dsigmav2[3, 3] = 2.

    dD_dpisigmav[1, 1] = 4. * plx_mod * sigma_v / ((_A)**2.)
    dD_dpisigmav[2, 2] = 4. * plx_mod * sigma_v / ((_A)**2.)

    ### See formula A.7
    hess = np.zeros((N + 4, N + 4))

    hess_pi2, hess_vx2, hess_vy2, hess_vz2, hess_sigmav2 = 0, 0, 0, 0, 0
    hess_pi_vx, hess_pi_vy, hess_pi_vz, hess_pi_sigmav = 0, 0, 0, 0
    hess_vx_vy, hess_vx_vz, hess_vy_vz = 0, 0, 0

    hess_vx2 += np.dot(np.dot(invD, cprime_vx), cprime_vx)
    hess_vy2 += np.dot(np.dot(invD, cprime_vy), cprime_vy)
    hess_vz2 += np.dot(np.dot(invD, cprime_vz), cprime_vz)
    hess_pi2 += np.dot(np.dot(invD, cprime_pi), cprime_pi)
    hess_pi_vx += np.dot(np.dot(invD, cprime_pi), cprime_vx)
    hess_pi_vy += np.dot(np.dot(invD, cprime_pi), cprime_vy)
    hess_pi_vz += np.dot(np.dot(invD, cprime_pi), cprime_vz)
    hess_vx_vy += np.dot(np.dot(invD, cprime_vx), cprime_vy)
    hess_vx_vz += np.dot(np.dot(invD, cprime_vx), cprime_vz)
    hess_vy_vz += np.dot(np.dot(invD, cprime_vy), cprime_vz)

    hess_pi2 += 0.5 * np.trace(
        -np.dot(np.dot(invD, dD_dpi), np.dot(invD, dD_dpi)) +
        np.dot(invD, dD_dpi2))
    hess_pi2 += 0.5 * np.tensordot(
        D, 2 * np.dot(np.dot(np.dot(invD, dD_dpi), np.dot(invD, dD_dpi)), invD)
        - np.dot(np.dot(invD, dD_dpi2), invD))

    hess_sigmav2 += 0.5 * np.trace(
        -np.dot(np.dot(invD, dD_dsigmav), np.dot(invD, dD_dsigmav)) +
        np.dot(invD, dD_dsigmav2))
    hess_sigmav2 += 0.5 * np.tensordot(
        D,
        2 * np.dot(np.dot(np.dot(invD, dD_dsigmav), np.dot(invD, dD_dsigmav)),
                   invD) - np.dot(np.dot(invD, dD_dsigmav2), invD))

    hess_pi_sigmav += 0.5 * np.trace(
        -np.dot(np.dot(invD, dD_dpi), np.dot(invD, dD_dsigmav)) +
        np.dot(invD, dD_dpisigmav))
    hess_pi_sigmav += 0.5 * np.tensordot(
        D, 2 * np.dot(np.dot(np.dot(invD, dD_dpi), np.dot(invD, dD_dsigmav)),
                      invD) - np.dot(np.dot(invD, dD_dpisigmav), invD))

    hess[i, i] = hess_pi2
    hess[i, -1] = hess_pi_sigmav
    hess[i, -2] = hess_pi_vz
    hess[i, -3] = hess_pi_vy
    hess[i, -4] = hess_pi_vx
    hess[-1, i] = hess[i, -1]
    hess[-2, i] = hess[i, -2]
    hess[-3, i] = hess[i, -3]
    hess[-4, i] = hess[i, -4]

    hess[-1, -1], hess[-2, -2], hess[-3, -3], hess[
        -4, -4] = hess_sigmav2, hess_vz2, hess_vy2, hess_vx2
    hess[-2, -3], hess[-3, -4], hess[-2,
                                     -4] = hess_vy_vz, hess_vx_vy, hess_vx_vz
    hess[-3, -2], hess[-4, -3], hess[-4, -2] = hess[-2, -3], hess[-3,
                                                                  -4], hess[-2,
                                                                            -4]

    return hess  ### N = -E(H) for L
Exemplo n.º 11
0
def stella_grad_3d(init_par, alpha, delta, plx_obs, mualpha_obs, mudelta_obs,
                   vrad_obs, sigma_obs, sigma_vrad, ccoef, N, i):
    """
	Estimate the jacobian matrix of the likelihood function.

	Parameters:
	------------
	init_par - Set of initial values for: 1) All the parallaxes [mas];
				     	      2) The cluster centroid velocity  [vx_0, vy_0, vz_0] [km/s];
				       	      3) The cluster velocity dispersion [km/s];
	alpha, delta - Cluster member positions [rad];
	plx_obs, mualpha_obs, mudelta_obs - observed values for parallaxes and proper motions [mas, mas/yr];
	sigma_obs - observed errors for parallaxes and proper motions [mas, mas/yr];
	ccoef - 3-dim array of correlation coefficients from the HIP catalogue;
	N - number of stars;
	"""

    parallax, v, sigma_v = init_par[i], init_par[-4:-1], init_par[-1]

    p, q, r = normalTriad(alpha, delta)
    mualpha_mod = np.dot(np.transpose(p), v) * parallax / _A
    mudelta_mod = np.dot(np.transpose(q), v) * parallax / _A

    plx_mod, mualpha_mod, mudelta_mod = parallax, mualpha_mod, mudelta_mod
    sigma_plx, sigma_mualpha, sigma_mudelta = np.transpose(sigma_obs)

    C = np.zeros((3, 3), dtype=np.float64)
    C[0, 0], C[1,
               1], C[2,
                     2] = sigma_plx**2., sigma_mualpha**2., sigma_mudelta**2.

    corr_coefficient_plx_mualpha, corr_coefficient_plx_mudelta, corr_coefficient_mualpha_mudelta = ccoef[
        0], ccoef[1], ccoef[2]

    C[0, 1], C[
        0,
        2] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta
    C[1, 0], C[
        1,
        2] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    C[2, 0], C[
        2,
        1] = corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    E = np.zeros((3, 3), dtype=np.float64)
    E[1,
      1], E[2,
            2] = (sigma_v**2.) * (parallax /
                                  _A)**2., (sigma_v**2.) * (parallax / _A)**2.

    D, invD = np.zeros((3, 3), dtype=np.float64), np.zeros((3, 3),
                                                           dtype=np.float64)
    D = np.add(E, C)

    invD = np.linalg.inv(D)

    a_c = np.array([
        plx_obs - plx_mod, mualpha_obs - mualpha_mod, mudelta_obs - mudelta_mod
    ])

    cprime_pi, cprime_vx, cprime_vy, cprime_vz, = np.ones(3), np.ones(
        3), np.ones(3), np.ones(3)

    cprime_pi[0] = 1.
    cprime_pi[1] = np.dot(np.transpose(p), v) / _A
    cprime_pi[2] = np.dot(np.transpose(q), v) / _A

    cprime_vx[0] = 0.
    cprime_vx[1] = -np.sin(alpha) * plx_mod / _A
    cprime_vx[2] = -np.sin(delta) * np.cos(alpha) * plx_mod / _A

    cprime_vy[0] = 0.
    cprime_vy[1] = np.cos(alpha) * plx_mod / _A
    cprime_vy[2] = -np.sin(delta) * np.sin(alpha) * plx_mod / _A

    cprime_vz[0] = 0.
    cprime_vz[1] = 0.
    cprime_vz[2] = np.cos(delta) * plx_mod / _A

    dD_dpi, dD_dsigmav = np.zeros((3, 3)), np.zeros((3, 3))

    dD_dpi[1, 1] = 2. * plx_mod * ((sigma_v / _A)**2.)
    dD_dpi[2, 2] = 2. * plx_mod * ((sigma_v / _A)**2.)

    dD_dsigmav[1, 1] = 2. * sigma_v * ((plx_mod / _A)**2.)
    dD_dsigmav[2, 2] = 2. * sigma_v * ((plx_mod / _A)**2.)

    ### See formula A.3
    f = np.zeros(N + 4)

    f_pi = 0
    f_vx, f_vy, f_vz, f_sigmav = 0, 0, 0, 0

    f_vx += np.dot(np.dot(invD, cprime_vx), a_c)
    f_vy += np.dot(np.dot(invD, cprime_vy), a_c)
    f_vz += np.dot(np.dot(invD, cprime_vz), a_c)
    f_pi += np.dot(np.dot(invD, cprime_pi), a_c)

    f_pi -= 0.5 * np.trace(np.dot(invD, dD_dpi))
    f_pi += 0.5 * np.dot(np.dot(np.dot(np.dot(invD, dD_dpi), invD), a_c), a_c)

    f_sigmav -= 0.5 * np.trace(np.dot(invD, dD_dsigmav))
    f_sigmav += 0.5 * np.dot(
        np.dot(np.dot(np.dot(invD, dD_dsigmav), invD), a_c), a_c)

    f[i] = f_pi

    f[-4], f[-3], f[-2], f[-1] = f_vx, f_vy, f_vz, f_sigmav

    ### f is Grad L(theta), see Eq. 17
    return -2 * f  ### Grad U(theta), see Eq. 18
Exemplo n.º 12
0
def Nmatrix(init_par, alpha, delta, obs, sigma_obs, ccoef, N):
    """
	Estimate covariance matrix of the likelihood function.

	Parameters:
	------------
	init_par - Set of initial values for: 1) All the parallaxes [mas];
				     	      2) The cluster centroid velocity  [vx_0, vy_0, vz_0] [km/s];
				       	      3) The cluster velocity dispersion [km/s];
	alpha, delta - Cluster member positions [rad];
	obs - observed values for parallaxes and proper motions [mas, mas/yr];
	sigma_obs - observed errors for parallaxes and proper motions [mas, mas/yr];
	ccoef - 3-dim array of correlation coefficients from the HIP catalogue;
	N - number of stars;
	Returns:
	-----------
	Cov - N+4 x N+4 matrix, corresponding to the covariance of the parameters of the likelihood function.
	"""
    parallax, v, sigma_v = init_par[:-4], init_par[-4:-1], init_par[-1]
    plx_obs, mualpha_obs, mudelta_obs = obs[:, 0], obs[:, 1], obs[:, 2]

    p, q, r = normalTriad(alpha, delta)
    mualpha_mod = np.dot(np.transpose(p), v) * parallax / _A
    mudelta_mod = np.dot(np.transpose(q), v) * parallax / _A

    plx_mod, mualpha_mod, mudelta_mod = parallax, mualpha_mod, mudelta_mod
    sigma_plx, sigma_mualpha, sigma_mudelta = np.transpose(sigma_obs)
    a, like, expo, detD = np.ones(N), np.ones(N), np.ones(N), np.ones(N)
    C = np.zeros((3, 3, N), dtype=np.float64)
    C[0, 0, :], C[1, 1, :], C[
        2, 2, :] = sigma_plx**2., sigma_mualpha**2., sigma_mudelta**2.
    corr_coefficient_plx_mualpha, corr_coefficient_plx_mudelta, corr_coefficient_mualpha_mudelta = np.zeros(
        N), np.zeros(N), np.zeros(N)
    corr_coefficient_plx_mualpha[:], corr_coefficient_plx_mudelta[:], corr_coefficient_mualpha_mudelta[:] = ccoef[:,
                                                                                                                  0], ccoef[:,
                                                                                                                            1], ccoef[:,
                                                                                                                                      2]

    C[0, 1, :], C[
        0,
        2, :] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta
    C[1, 0, :], C[
        1,
        2, :] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    C[2, 0, :], C[
        2,
        1, :] = corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    E = np.zeros((3, 3, N), dtype=np.float64)
    E[1, 1, :], E[2, 2, :] = (sigma_v**2.) * (parallax / _A)**2., (
        sigma_v**2.) * (parallax / _A)**2.
    D, invD = np.zeros((3, 3, N), dtype=np.float64), np.zeros((3, 3, N),
                                                              dtype=np.float64)
    D = np.add(E, C)
    for i in range(N):
        detD[i] = matrix_det(D[:, :, i])
        invD[:, :, i] = matrix_inv(D[:, :, i])

    a_c = np.ones((3, N))
    a_c = [
        plx_obs - plx_mod, mualpha_obs - mualpha_mod, mudelta_obs - mudelta_mod
    ]




    cprime_pi, cprime_vx, cprime_vy, cprime_vz,  = np.ones((3,N)), np.ones((3,N)), \
          np.ones((3,N)), np.ones((3,N)),
    cprime_pi[0, :] = 1.
    cprime_pi[1, :] = np.dot(np.transpose(p), v) / _A
    cprime_pi[2, :] = np.dot(np.transpose(q), v) / _A

    cprime_vx[0, :] = 0.
    cprime_vx[1, :] = -np.sin(alpha) * plx_mod / _A
    cprime_vx[2, :] = -np.sin(delta) * np.cos(alpha) * plx_mod / _A

    cprime_vy[0, :] = 0.
    cprime_vy[1, :] = np.cos(alpha) * plx_mod / _A
    cprime_vy[2, :] = -np.sin(delta) * np.sin(alpha) * plx_mod / _A

    cprime_vz[0, :] = 0.
    cprime_vz[1, :] = 0.
    cprime_vz[2, :] = np.cos(delta) * plx_mod / _A

    dlnd_dpi, dlnd_dsigmav = np.zeros(N), np.zeros(N)
    de_dpi, de_dsigmav = np.zeros(N), np.zeros(N)

    ### See formula A.5
    de_dpi[:] = ((sigma_v / _A)**2.) * 2. * plx_mod[:]
    de_dsigmav[:] = ((plx_mod[:] / _A)**2.) * 2. * sigma_v

    dlnd_dpi[:] = (invD[1, 1, :] + invD[2, 2, :]) * de_dpi[:]
    dlnd_dsigmav[:] = (invD[1, 1, :] + invD[2, 2, :]) * de_dsigmav[:]

    ### See formula A.7
    hess = np.zeros((N + 4, N + 4))

    hess_diag_pi, hess_diag_pi_1, hess_diag_pi_2 = np.zeros(N), np.zeros(
        N), np.zeros(N)
    hess_diag_pi_1[:] = invD[0, 0, :]*cprime_pi[0, :]*cprime_pi[0, :] + invD[0, 1, :]*cprime_pi[0, :]*cprime_pi[1, :] + invD[0, 2, :]*cprime_pi[0, :]*cprime_pi[2, :] + \
          invD[1, 0, :]*cprime_pi[1, :]*cprime_pi[0, :] + invD[1, 1, :]*cprime_pi[1, :]*cprime_pi[1, :] + invD[1, 2, :]*cprime_pi[1, :]*cprime_pi[2, :] + \
           invD[2, 0, :]*cprime_pi[2, :]*cprime_pi[0, :] + invD[2, 1, :]*cprime_pi[2, :]*cprime_pi[1, :] + invD[2, 2, :]*cprime_pi[2, :]*cprime_pi[2, :]

    #hess_diag_pi_2[:] = np.sum(0.5*(invD[1, 1, :]**2. + 2.*invD[1, 2, :]**2. + invD[2, 2, :]**2.)*de_dpi[:]*de_dpi[:]) ### Check if it's with or without sum: without!
    # So correct formula is below.
    hess_diag_pi_2[:] = (
        0.5 *
        (invD[1, 1, :]**2. + 2. * invD[1, 2, :]**2. + invD[2, 2, :]**2.) *
        de_dpi[:] * de_dpi[:])
    hess_diag_pi[:] = hess_diag_pi_1[:] + hess_diag_pi_2[:]

    hess_diag_vx, hess_diag_vy, hess_diag_vz, hess_diag_sigmav = np.zeros(
        N), np.zeros(N), np.zeros(N), np.zeros(N)
    hess_pi_vx, hess_pi_vy, hess_pi_vz, hess_pi_sigmav = np.zeros(N), np.zeros(
        N), np.zeros(N), np.zeros(N)
    hess_diag_vxi, hess_diag_vyi, hess_diag_vzi = np.zeros(N), np.zeros(
        N), np.zeros(N)

    hess_diag_vxi[:] = invD[0, 0, :]*cprime_vx[0, :]*cprime_vx[0, :] + invD[0, 1, :]*cprime_vx[0, :]*cprime_vx[1, :] + invD[0, 2, :]*cprime_vx[0, :]*cprime_vx[2, :] + \
         invD[1, 0, :]*cprime_vx[1, :]*cprime_vx[0, :] + invD[1, 1, :]*cprime_vx[1, :]*cprime_vx[1, :] + invD[1, 2, :]*cprime_vx[1, :]*cprime_vx[2, :] + \
         invD[2, 0, :]*cprime_vx[2, :]*cprime_vx[0, :] + invD[2, 1, :]*cprime_vx[2, :]*cprime_vx[1, :] + invD[2, 2, :]*cprime_vx[2, :]*cprime_vx[2, :]

    hess_diag_vyi[:] = invD[0, 0, :]*cprime_vy[0, :]*cprime_vy[0, :] + invD[0, 1, :]*cprime_vy[0, :]*cprime_vy[1, :] + invD[0, 2, :]*cprime_vy[0, :]*cprime_vy[2, :] +\
         invD[1, 0, :]*cprime_vy[1, :]*cprime_vy[0, :] + invD[1, 1, :]*cprime_vy[1, :]*cprime_vy[1, :] + invD[1, 2, :]*cprime_vy[1, :]*cprime_vy[2, :] +\
         invD[2, 0, :]*cprime_vy[2, :]*cprime_vy[0, :] + invD[2, 1, :]*cprime_vy[2, :]*cprime_vy[1, :] + invD[2, 2, :]*cprime_vy[2, :]*cprime_vy[2, :]


    hess_diag_vzi[:] = invD[0, 0, :]*cprime_vz[0, :]*cprime_vz[0, :] + invD[0, 1, :]*cprime_vz[0, :]*cprime_vz[1, :] + invD[0, 2, :]*cprime_vz[0, :]*cprime_vz[2, :] +\
         invD[1, 0, :]*cprime_vz[1, :]*cprime_vz[0, :] + invD[1, 1, :]*cprime_vz[1, :]*cprime_vz[1, :] + invD[1, 2, :]*cprime_vz[1, :]*cprime_vz[2, :] +\
         invD[2, 0, :]*cprime_vz[2, :]*cprime_vz[0, :] + invD[2, 1, :]*cprime_vz[2, :]*cprime_vz[1, :] + invD[2, 2, :]*cprime_vz[2, :]*cprime_vz[2, :]


    hess_pi_vx[:] = invD[0, 0, :]*cprime_pi[0,:]*cprime_vx[0, :] + invD[0, 1, :]*cprime_pi[0,:]*cprime_vx[1, :] + invD[0, 2, :]*cprime_pi[0,:]*cprime_vx[2, :] +\
      invD[1, 0, :]*cprime_pi[1,:]*cprime_vx[0, :] + invD[1, 1, :]*cprime_pi[1,:]*cprime_vx[1, :] + invD[1, 2, :]*cprime_pi[1,:]*cprime_vx[2, :] +\
      invD[2, 0, :]*cprime_pi[2,:]*cprime_vx[0, :] + invD[2, 1, :]*cprime_pi[2,:]*cprime_vx[1, :] + invD[2, 2, :]*cprime_pi[2,:]*cprime_vx[2, :]

    hess_pi_vy[:] = invD[0, 0, :]*cprime_pi[0,:]*cprime_vy[0, :] + invD[0, 1, :]*cprime_pi[0,:]*cprime_vy[1, :] + invD[0, 2, :]*cprime_pi[0,:]*cprime_vy[2, :] +\
      invD[1, 0, :]*cprime_pi[1,:]*cprime_vy[0, :] + invD[1, 1, :]*cprime_pi[1,:]*cprime_vy[1, :] + invD[1, 2, :]*cprime_pi[1,:]*cprime_vy[2, :] +\
      invD[2, 0, :]*cprime_pi[2,:]*cprime_vy[0, :] + invD[2, 1, :]*cprime_pi[2,:]*cprime_vy[1, :] + invD[2, 2, :]*cprime_pi[2,:]*cprime_vy[2, :]

    hess_pi_vz[:] = invD[0, 0, :]*cprime_pi[0,:]*cprime_vz[0, :] + invD[0, 1, :]*cprime_pi[0,:]*cprime_vz[1, :] + invD[0, 2, :]*cprime_pi[0,:]*cprime_vz[2, :] +\
      invD[1, 0, :]*cprime_pi[1,:]*cprime_vz[0, :] + invD[1, 1, :]*cprime_pi[1,:]*cprime_vz[1, :] + invD[1, 2, :]*cprime_pi[1,:]*cprime_vz[2, :] +\
      invD[2, 0, :]*cprime_pi[2,:]*cprime_vz[0, :] + invD[2, 1, :]*cprime_pi[2,:]*cprime_vz[1, :] + invD[2, 2, :]*cprime_pi[2,:]*cprime_vz[2, :]

    hess_diag_vx = np.sum(hess_diag_vxi)
    hess_diag_vy = np.sum(hess_diag_vyi)
    hess_diag_vz = np.sum(hess_diag_vzi)

    hess_diag_sigmav = np.sum(
        0.5 *
        (invD[1, 1, :]**2. + 2. * invD[1, 2, :]**2. + invD[2, 2, :]**2.) *
        de_dsigmav[:] * de_dsigmav[:])
    hess_pi_sigmav[:] = 0.5 * (invD[1, 1, :]**2. + 2. * invD[1, 2, :]**2. +
                               invD[2, 2, :]**2.) * de_dpi[:] * de_dsigmav[:]

    hess_diag = np.concatenate(
        (hess_diag_pi,
         np.array([hess_diag_vx, hess_diag_vy, hess_diag_vz,
                   hess_diag_sigmav])))

    for i in range(N + 4):
        hess[i, i] = hess_diag[i]

    for j in range(N):
        hess[j, -4] = hess_pi_vx[j]
        hess[j, -3] = hess_pi_vy[j]
        hess[j, -2] = hess_pi_vz[j]
        hess[j, -1] = hess_pi_sigmav[j]
        hess[-4, j] = hess_pi_vx[j]
        hess[-3, j] = hess_pi_vy[j]
        hess[-2, j] = hess_pi_vz[j]
        hess[-1, j] = hess_pi_sigmav[j]

    part_12, part_13, part_23 = np.zeros(N), np.zeros(N), np.zeros(N)
    for ia in range(3):
        for ib in range(3):
            part_12[:] += invD[ia, ib, :] * cprime_vx[ia, :] * cprime_vy[ib, :]
            part_13[:] += invD[ia, ib, :] * cprime_vx[ia, :] * cprime_vz[ib, :]
            part_23[:] += invD[ia, ib, :] * cprime_vy[ia, :] * cprime_vz[ib, :]

    hess[-4, -3] = np.sum(part_12)
    hess[-3, -4] = hess[-4, -3]

    hess[-4, -2] = np.sum(part_13)
    hess[-2, -4] = hess[-4, -2]

    hess[-3, -2] = np.sum(part_23)
    hess[-2, -3] = hess[-3, -2]

    #### I am returning here the matrix Njk, which is defined as -E(H),
    #### where H is the hessian of the likelihood: therefore to obtain the real hessian, one
    #### should multiply this by '-1' (see function below.)
    return hess  ### See eq. 18
Exemplo n.º 13
0
def gradient(init_par, alpha, delta, obs, sigma_obs, ccoef, N):
    """
	Estimate gradient of the likelihood function.

	Parameters:
	------------
	init_par - Set of initial values for: 1) All the parallaxes [mas];
				       2) The cluster centroid velocity  [vx_0, vy_0, vz_0] [km/s];
				       3) The cluster velocity dispersion, sigma_v [km/s];
	alpha, delta - Cluster member positions [rad];
	obs - observed values for parallaxes and proper motions [mas, mas/yr];
	sigma_obs - observed errors for parallaxes and proper motions [mas, mas/yr];
	ccoef - 3-dim array of correlation coefficients from the HIP catalogue;
	N - number of stars;
	Returns:
	-----------
	f - An array with n+4 elements corresponding to the gradient of the likelihood 
		   with respect to the n+4 variables.
	"""

    ## Initial parameters

    parallax, v, sigma_v = init_par[:-4], init_par[-4:-1], init_par[-1]
    plx_obs, mualpha_obs, mudelta_obs = obs[:, 0], obs[:, 1], obs[:, 2]

    ### Define normal triad and proper motions
    p, q, r = normalTriad(alpha, delta)
    mualpha_mod = np.dot(np.transpose(p), v) * parallax / _A
    mudelta_mod = np.dot(np.transpose(q), v) * parallax / _A

    plx_mod, mualpha_mod, mudelta_mod = parallax, mualpha_mod, mudelta_mod
    sigma_plx, sigma_mualpha, sigma_mudelta = np.transpose(sigma_obs)
    a, like, expo, detD = np.ones(N), np.ones(N), np.ones(N), np.ones(N)

    ### Eq. 8 in Lindegren+2000 (Covariance Matrix)
    C = np.zeros((3, 3, N), dtype=np.float64)
    C[0, 0, :], C[1, 1, :], C[
        2, 2, :] = sigma_plx**2., sigma_mualpha**2., sigma_mudelta**2.
    corr_coefficient_plx_mualpha, corr_coefficient_plx_mudelta, corr_coefficient_mualpha_mudelta = np.zeros(
        N), np.zeros(N), np.zeros(N)
    corr_coefficient_plx_mualpha[:], corr_coefficient_plx_mudelta[:], corr_coefficient_mualpha_mudelta[:] = ccoef[:,
                                                                                                                  0], ccoef[:,
                                                                                                                            1], ccoef[:,
                                                                                                                                      2]

    C[0, 1, :], C[
        0,
        2, :] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta
    C[1, 0, :], C[
        1,
        2, :] = corr_coefficient_plx_mualpha * sigma_plx * sigma_mualpha, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta
    C[2, 0, :], C[
        2,
        1, :] = corr_coefficient_plx_mudelta * sigma_plx * sigma_mudelta, corr_coefficient_mualpha_mudelta * sigma_mualpha * sigma_mudelta

    ### Eq. 16 in Lindegren+2000 (Definition of D matrix)
    E = np.zeros((3, 3, N), dtype=np.float64)
    E[1, 1, :], E[2, 2, :] = (sigma_v * parallax[:] /
                              _A)**2., (sigma_v * parallax[:] / _A)**2.
    D, invD = np.zeros((3, 3, N), dtype=np.float64), np.zeros((3, 3, N),
                                                              dtype=np.float64)
    D = np.add(E, C)
    for i in range(N):
        detD[i] = matrix_det(D[:, :, i])
        invD[:, :, i] = matrix_inv(D[:, :, i])

    a_c = np.ones((3, N))
    a_c = [
        plx_obs - plx_mod, mualpha_obs - mualpha_mod, mudelta_obs - mudelta_mod
    ]

    ### First derivatives in Eq. A3
    cprime_pi, cprime_vx, cprime_vy, cprime_vz,  = np.ones((3,N)), np.ones((3,N)), \
          np.ones((3,N)), np.ones((3,N)),
    cprime_pi[0, :] = 1.
    cprime_pi[1, :] = np.dot(np.transpose(p), v) / _A
    cprime_pi[2, :] = np.dot(np.transpose(q), v) / _A

    cprime_vx[0, :] = 0.
    cprime_vx[1, :] = -np.sin(alpha) * plx_mod / _A
    cprime_vx[2, :] = -np.sin(delta) * np.cos(alpha) * plx_mod / _A

    cprime_vy[0, :] = 0.
    cprime_vy[1, :] = np.cos(alpha) * plx_mod / _A
    cprime_vy[2, :] = -np.sin(delta) * np.sin(alpha) * plx_mod / _A

    cprime_vz[0, :] = 0.
    cprime_vz[1, :] = 0.
    cprime_vz[2, :] = np.cos(delta) * plx_mod / _A

    dlnd_dpi, dlnd_dsigmav = np.zeros(N), np.zeros(N)
    de_dpi, de_dsigmav = np.zeros(N), np.zeros(N)

    ### See Eq. A5
    de_dpi[:] = ((sigma_v / _A)**2.) * 2. * plx_mod[:]
    de_dsigmav[:] = ((plx_mod[:] / _A)**2.) * 2. * sigma_v

    dlnd_dpi[:] = (invD[1, 1, :] + invD[2, 2, :]) * de_dpi[:]
    dlnd_dsigmav[:] = (invD[1, 1, :] + invD[2, 2, :]) * de_dsigmav[:]

    ### See Eq. A6
    dG_dpi, dG_dsigmav = np.zeros((3, 3, N)), np.zeros((3, 3, N))

    dG_dpi[0,0,:], dG_dpi[0,1,:], dG_dpi[0,2,:] = (-invD[0,1,:]*invD[1, 0, :] - invD[0, 2, :]*invD[2,0,:])*de_dpi[:], \
               (-invD[0,1,:]*invD[1, 1, :] - invD[0,2,:]*invD[2, 1, :])*de_dpi[:], \
               (-invD[0,1,:]*invD[1,2,:] - invD[0,2,:]*invD[2,2,:])*de_dpi[:]
    dG_dpi[1,0,:], dG_dpi[1,1,:], dG_dpi[1,2,:] = (-invD[1,1,:]*invD[1, 0, :] - invD[1, 2, :]*invD[2,0,:])*de_dpi[:], \
               (-invD[1,1,:]*invD[1, 1, :] - invD[1,2,:]*invD[2, 1, :])*de_dpi[:], \
               (-invD[1,1,:]*invD[1,2,:] - invD[1,2,:]*invD[2,2,:])*de_dpi[:]
    dG_dpi[2,0,:], dG_dpi[2,1,:], dG_dpi[2,2,:] = (-invD[2,1,:]*invD[1, 0, :] - invD[2, 2, :]*invD[2,0,:])*de_dpi[:], \
               (-invD[2,1,:]*invD[1, 1, :] - invD[2,2,:]*invD[2, 1, :])*de_dpi[:], \
               (-invD[2,1,:]*invD[1,2,:] - invD[2,2,:]*invD[2,2,:])*de_dpi[:]


    dG_dsigmav[0,0,:], dG_dsigmav[0,1,:], dG_dsigmav[0,2,:] = (-invD[0,1,:]*invD[1, 0, :] - invD[0, 2, :]*invD[2,0,:])*de_dsigmav[:], \
             (-invD[0,1,:]*invD[1, 1, :] - invD[0,2,:]*invD[2, 1, :])*de_dsigmav[:], \
             (-invD[0,1,:]*invD[1,2,:] - invD[0,2,:]*invD[2,2,:])*de_dsigmav[:]
    dG_dsigmav[1,0,:], dG_dsigmav[1,1,:], dG_dsigmav[1,2,:] = (-invD[1,1,:]*invD[1, 0, :] - invD[1, 2, :]*invD[2,0,:])*de_dsigmav[:], \
             (-invD[1,1,:]*invD[1, 1, :] - invD[1,2,:]*invD[2, 1, :])*de_dsigmav[:], \
             (-invD[1,1,:]*invD[1,2,:] - invD[1,2,:]*invD[2,2,:])*de_dsigmav[:]
    dG_dsigmav[2,0,:], dG_dsigmav[2,1,:], dG_dsigmav[2,2,:] = (-invD[2,1,:]*invD[1, 0, :] - invD[2, 2, :]*invD[2,0,:])*de_dsigmav[:], \
             (-invD[2,1,:]*invD[1, 1, :] - invD[2,2,:]*invD[2, 1, :])*de_dsigmav[:], \
             (-invD[2,1,:]*invD[1,2,:] - invD[2,2,:]*invD[2,2,:])*de_dsigmav[:]

    f_dpi = np.zeros((N), dtype=np.float64)

    for i in range(N):
        f_dpi_1, f_dpi_3 = 0., 0.0
        for ia in range(3):
            for ib in range(3):
                f_dpi_1 += invD[ia, ib, i] * cprime_pi[ia, i] * a_c[ib][i]
                f_dpi_3 += (-0.5) * (dG_dpi[ia, ib, i] * a_c[ia][i] *
                                     a_c[ib][i])

        f_dpi_2 = (-0.5) * dlnd_dpi[i]
        f_dpi[i] = f_dpi_1 + f_dpi_2 + f_dpi_3

    f_vx, f_vy, f_vz, f_sigmav = np.zeros(N), np.zeros(N), np.zeros(
        N), np.zeros(N)

    f_vx = np.sum(invD[0,0,:]*cprime_vx[0,:]*a_c[0][:] + invD[0,1,:]*cprime_vx[0,:]*a_c[1][:] + invD[0,2,:]*cprime_vx[0,:]*a_c[2][:] + \
        invD[1,0,:]*cprime_vx[1,:]*a_c[0][:] + invD[1,1,:]*cprime_vx[1,:]*a_c[1][:] + invD[1,2,:]*cprime_vx[1,:]*a_c[2][:] + \
        invD[2,0,:]*cprime_vx[2,:]*a_c[0][:] + invD[2,1,:]*cprime_vx[2,:]*a_c[1][:] + invD[2,2,:]*cprime_vx[2,:]*a_c[2][:])

    f_vy = np.sum(invD[0,0,:]*cprime_vy[0,:]*a_c[0][:] + invD[0,1,:]*cprime_vy[0,:]*a_c[1][:] + invD[0,2,:]*cprime_vy[0,:]*a_c[2][:] + \
        invD[1,0,:]*cprime_vy[1,:]*a_c[0][:] + invD[1,1,:]*cprime_vy[1,:]*a_c[1][:] + invD[1,2,:]*cprime_vy[1][:]*a_c[2][:] + \
        invD[2,0,:]*cprime_vy[2,:]*a_c[0][:] + invD[2,1,:]*cprime_vy[2,:]*a_c[1][:] + invD[2,2,:]*cprime_vy[2,:]*a_c[2][:])

    f_vz = np.sum(invD[0,0,:]*cprime_vz[0,:]*a_c[0][:] + invD[0,1,:]*cprime_vz[0,:]*a_c[1][:] + invD[0,2,:]*cprime_vz[0,:]*a_c[2][:] + \
        invD[1,0,:]*cprime_vz[1,:]*a_c[0][:] + invD[1,1,:]*cprime_vz[1,:]*a_c[1][:] + invD[1,2,:]*cprime_vz[1,:]*a_c[2][:] + \
        invD[2,0,:]*cprime_vz[2,:]*a_c[0][:] + invD[2,1,:]*cprime_vz[2,:]*a_c[1][:] + invD[2,2,:]*cprime_vz[2,:]*a_c[2][:])

    f_sigmav = np.sum(-0.5*(dG_dsigmav[0,0,:]*a_c[0][:]*a_c[0][:] + dG_dsigmav[0,1,:]*a_c[1][:]*a_c[0][:]+ dG_dsigmav[0,2,:]*a_c[2][:]*a_c[0][:] + \
         dG_dsigmav[1,0,i]*a_c[1][:]*a_c[0][:] + dG_dsigmav[1,1,:]*a_c[1][:]*a_c[1][:]+ dG_dsigmav[1,2,:]*a_c[1][:]*a_c[2][:] +
         dG_dsigmav[2,0,i]*a_c[2][:]*a_c[0][:] + dG_dsigmav[2,1,:]*a_c[2][:]*a_c[1][:]+ dG_dsigmav[2,2,:]*a_c[2][:]*a_c[2][:]))

    f_sigmav = f_sigmav - 0.5 * np.sum(dlnd_dsigmav)
    f = np.concatenate(
        (f_dpi, np.array([f_vx, f_vy, f_vz,
                          f_sigmav])))  ### Grad L(theta), see Eq. 17
    return -2. * f  ### Grad U(theta), see Eq. 18
Exemplo n.º 14
0
    def propagate_astrometry_and_covariance_matrix(self, a0, c0, t0, t1):
        """
        Propagate the covariance matrix of the astrometric parameters and radial proper motion of a
        source from epoch t0 to epoch t1.

        Code based on the Hipparcos Fortran implementation by Lennart Lindegren.

        Parameters
        ----------

        a0 : array_like
            6-element vector: (phi, theta, parallax, muphistar, mutheta, vrad) in units of (radians,
            radians, mas, mas/yr, mas/yr, km/s). Shape of a should be (6,) or (6,N), with N the number of
            sources for which the astrometric parameters are provided.

        c0 : array_like
            Covariance matrix stored in a 6x6 element array. This can be constructed from the columns
            listed in the Gaia catalogue. The units are [mas^2, mas^2/yr, mas^2/yr^2] for the various
            elements. Note that the elements in the 6th row and column should be:
            c[6,i]=c[i,6]=c[i,3]*vrad/auKmYearPerSec for i=1,..,5 and
            c[6,6]=c[3,3]*(vrad^2+vrad_error^2)/auKmYearPerSec^2+(parallax*vrad_error/auKmYearPerSec)^2

            Shape of c0 should be (6,6) or (N,6,6).

        t0 : float
            Reference epoch (Julian years).

        t1 : float
            New epoch (Julian years).

        Returns
        -------

        Astrometric parameters, including the "radial proper motion" (NOT the radial velocity), and
        covariance matrix at the new epoch as a 2D matrix with the new variances on the diagional and the
        covariance in the off-diagonal elements.
        """

        zero, one, two, three = 0, 1, 2, 3
        tau = t1-t0

        # Calculate the normal triad [p0 q0 r0] at t0
        p0, q0, r0 = normalTriad(a0[0], a0[1])

        # Convert to internal units (radians, Julian year)
        par0 = a0[2]*self.mastorad
        pma0 = a0[3]*self.mastorad
        pmd0 = a0[4]*self.mastorad
        pmr0 = a0[5]*a0[2]/auKmYearPerSec*self.mastorad

        # Proper motion vector
        pmvec0 = pma0*p0+pmd0*q0

        # Auxiliary quantities
        tau2 = tau*tau
        pm02 = pma0**2 + pmd0**2
        w = one + pmr0*tau
        f2 = one/(one + two*pmr0*tau + (pm02+pmr0**2)*tau2)
        f = sqrt(f2)
        f3 = f2*f
        f4 = f2*f2

        # Position vector and parallax at t1
        u = (r0*w + pmvec0*tau)*f
        _, ra, dec = cartesianToSpherical(u[0], u[1], u[2])
        par = par0*f

        # Proper motion vector and radial proper motion at t1
        pmvec = (pmvec0*(one+pmr0*tau) - r0*pmr0**2*tau)*f3
        pmr = (pmr0+(pm02 + pmr0**2)*tau)*f2

        # Normal triad at t1
        p, q, r = normalTriad(ra, dec)

        # Convert parameters at t1 to external units (mas, Julian year)
        pma = sum(p*pmvec, axis=0)
        pmd = sum(q*pmvec, axis =0)

        a = zeros_like(a0)
        a[0] = ra
        a[1] = dec
        a[2] = par/self.mastorad
        a[3] = pma/self.mastorad
        a[4] = pmd/self.mastorad
        a[5] = pmr/self.mastorad

        # Auxiliary quantities for the partial derivatives

        pmz = pmvec0*f - three*pmvec*w
        pp0 = sum(p*p0, axis=0)
        pq0 = sum(p*q0, axis=0)
        pr0 = sum(p*r0, axis=0)
        qp0 = sum(q*p0, axis=0)
        qq0 = sum(q*q0, axis=0)
        qr0 = sum(q*r0, axis=0)
        ppmz = sum(p*pmz, axis=0)
        qpmz = sum(q*pmz, axis=0)

        J = zeros_like(c0)
        if (c0.ndim==2):
            J = J[newaxis,:,:]

        # Partial derivatives
        J[:,0,0] = pp0*w*f - pr0*pma0*tau*f
        J[:,0,1] = pq0*w*f - pr0*pmd0*tau*f
        J[:,0,2] = zero
        J[:,0,3] = pp0*tau*f
        J[:,0,4] = pq0*tau*f
        J[:,0,5] = -pma*tau2

        J[:,1,0] = qp0*w*f - qr0*pma0*tau*f
        J[:,1,1] = qq0*w*f - qr0*pmd0*tau*f
        J[:,1,2] = zero
        J[:,1,3] = qp0*tau*f
        J[:,1,4] = qq0*tau*f
        J[:,1,5] = -pmd*tau2

        J[:,2,0] = zero
        J[:,2,1] = zero
        J[:,2,2] = f
        J[:,2,3] = -par*pma0*tau2*f2
        J[:,2,4] = -par*pmd0*tau2*f2
        J[:,2,5] = -par*w*tau*f2

        J[:,3,0] = -pp0*pm02*tau*f3 - pr0*pma0*w*f3
        J[:,3,1] = -pq0*pm02*tau*f3 - pr0*pmd0*w*f3
        J[:,3,2] = zero
        J[:,3,3] = pp0*w*f3 - two*pr0*pma0*tau*f3 - three*pma*pma0*tau2*f2
        J[:,3,4] = pq0*w*f3 - two*pr0*pmd0*tau*f3 - three*pma*pmd0*tau2*f2
        J[:,3,5] = ppmz*tau*f2

        J[:,4,0] = -qp0*pm02*tau*f3 - qr0*pma0*w*f3
        J[:,4,1] = -qq0*pm02*tau*f3 - qr0*pmd0*w*f3
        J[:,4,2] = zero
        J[:,4,3] = qp0*w*f3 - two*qr0*pma0*tau*f3 - three*pmd*pma0*tau2*f2
        J[:,4,4] = qq0*w*f3 - two*qr0*pmd0*tau*f3 - three*pmd*pmd0*tau2*f2
        J[:,4,5] = qpmz*tau*f2

        J[:,5,0] = zero
        J[:,5,1] = zero
        J[:,5,2] = zero
        J[:,5,3] = two*pma0*w*tau*f4
        J[:,5,4] = two*pmd0*w*tau*f4
        J[:,5,5] = (w**2 - pm02*tau2)*f4

        JT = zeros_like(J)
        for i in range(J.shape[0]):
            JT[i] = J[i].T

        if (c0.ndim==2):
            c = matmul(J,matmul(c0[newaxis,:,:],JT))
        else:
            c = matmul(J,matmul(c0,JT))

        return a, squeeze(c)