示例#1
0
    def _magnitude_to_sat_flux(self, magnitude):
        """
        translates magnitude in reference frame (OGLE I-band in most cases)
        to satellite flux scale
        """
        if self._sat_blending_flux != 0.:
            warnings.warn(
                "self._sat_blending_flux is not 0. - not sure if this works")

        flux = Utils.get_flux_from_mag(magnitude)
        (fs, fb) = self.event.model.get_ref_fluxes()
        magnification = (flux - fb) / fs[0]
        flux_sat = self._magnification_to_sat_flux(magnification)
        return flux_sat
示例#2
0
    def chi2_gradient(self, parameters, fit_blending=None):
        """
        Calculate chi^2 gradient (also called Jacobian), i.e.,
        :math:`d chi^2/d parameter`.

        Parameters :
            parameters: *str* or *list*, required
                Parameters with respect to which gradient is calculated.
                Currently accepted parameters are: ``t_0``, ``u_0``, ``t_eff``,
                ``t_E``, ``pi_E_N``, and ``pi_E_E``. The parameters for
                which you request gradient must be defined in py:attr:`~model`.

            fit_blending: *boolean*, optional
                Are we fitting for blending flux? If not then blending flux is
                fixed to 0.  Default is the same as
                :py:func:`MulensModel.fit.Fit.fit_fluxes()`.

        Returns :
            gradient: *float* or *np.ndarray*
                chi^2 gradient
        """
        if not isinstance(parameters, list):
            parameters = [parameters]
        implemented = {'t_0', 't_E', 'u_0', 't_eff', 'pi_E_N', 'pi_E_E'}
        if len(set(parameters) - implemented) > 0:
            raise NotImplementedError((
                "chi^2 gradient is implemented only for {:}\nCannot work " +
                "with {:}").format(implemented, parameters))
        gradient = {param: 0 for param in parameters}

        if self.model.n_sources != 1:
            raise NotImplementedError("Sorry, chi2 for binary sources is " +
                                      "not implemented yet")
        if self.model.n_lenses != 1:
            raise NotImplementedError(
                'Event.chi2_gradient() works only ' +
                'single lens models currently')
        as_dict = self.model.parameters.as_dict()
        if 'rho' in as_dict or 't_star' in as_dict:
            raise NotImplementedError(
                'Event.chi2_gradient() is not working ' +
                'for finite source models yet')

        # Define a Fit given the model and perform linear fit for fs and fb
        self._update_data_in_model()
        self.fit = Fit(
            data=self.datasets, magnification=self.model.data_magnification)
        # For binary source cases, the above line would need to be replaced,
        # so that it uses self.model.fit.
        if fit_blending is not None:
            self.fit.fit_fluxes(fit_blending=fit_blending)
        else:
            self.fit.fit_fluxes()

        for (i, dataset) in enumerate(self.datasets):
            (data, err_data) = dataset.data_and_err_in_chi2_fmt()
            factor = data - self.fit.get_chi2_format(data=dataset)
            factor *= -2. / err_data**2
            if dataset.chi2_fmt == 'mag':
                factor *= -2.5 / (log(10.) * Utils.get_flux_from_mag(data))
            factor *= self.fit.flux_of_sources(dataset)[0]

            kwargs = {}
            if dataset.ephemerides_file is not None:
                kwargs['satellite_skycoord'] = dataset.satellite_skycoord
            trajectory = Trajectory(
                    dataset.time, self.model.parameters,
                    self.model.get_parallax(), self.coords, **kwargs)
            u_2 = trajectory.x**2 + trajectory.y**2
            u_ = np.sqrt(u_2)
            d_A_d_u = -8. / (u_2 * (u_2 + 4) * np.sqrt(u_2 + 4))
            factor *= d_A_d_u

            factor_d_x_d_u = (factor * trajectory.x / u_)[dataset.good]
            sum_d_x_d_u = np.sum(factor_d_x_d_u)
            factor_d_y_d_u = (factor * trajectory.y / u_)[dataset.good]
            sum_d_y_d_u = np.sum(factor_d_y_d_u)
            dt = dataset.time[dataset.good] - as_dict['t_0']

            # Exactly 2 out of (u_0, t_E, t_eff) must be defined and
            # gradient depends on which ones are defined.
            if 't_eff' not in as_dict:
                t_E = as_dict['t_E'].to(u.day).value
                if 't_0' in parameters:
                    gradient['t_0'] += -sum_d_x_d_u / t_E
                if 'u_0' in parameters:
                    gradient['u_0'] += sum_d_y_d_u
                if 't_E' in parameters:
                    gradient['t_E'] += np.sum(factor_d_x_d_u * -dt / t_E**2)
            elif 't_E' not in as_dict:
                t_eff = as_dict['t_eff'].to(u.day).value
                if 't_0' in parameters:
                    gradient['t_0'] += -sum_d_x_d_u * as_dict['u_0'] / t_eff
                if 'u_0' in parameters:
                    gradient['u_0'] += sum_d_y_d_u + np.sum(
                            factor_d_x_d_u * dt / t_eff)
                if 't_eff' in parameters:
                    gradient['t_eff'] += np.sum(
                            factor_d_x_d_u * -dt *
                            as_dict['u_0'] / t_eff**2)
            elif 'u_0' not in as_dict:
                t_E = as_dict['t_E'].to(u.day).value
                t_eff = as_dict['t_eff'].to(u.day).value
                if 't_0' in parameters:
                    gradient['t_0'] += -sum_d_x_d_u / t_E
                if 't_E' in parameters:
                    gradient['t_E'] += (
                            np.sum(factor_d_x_d_u * dt) -
                            sum_d_y_d_u * t_eff) / t_E**2
                if 't_eff' in parameters:
                    gradient['t_eff'] += sum_d_y_d_u / t_E
            else:
                raise KeyError(
                    'Something is wrong with ModelParameters in ' +
                    'Event.chi2_gradient():\n', as_dict)

            # Below we deal with parallax only.
            if 'pi_E_N' in parameters or 'pi_E_E' in parameters:
                parallax = {
                    'earth_orbital': False,
                    'satellite': False,
                    'topocentric': False}
                trajectory_no_piE = Trajectory(
                    dataset.time, self.model.parameters, parallax, self.coords,
                    **kwargs)
                dx = (trajectory.x - trajectory_no_piE.x)[dataset.good]
                dy = (trajectory.y - trajectory_no_piE.y)[dataset.good]
                delta_E = dx * as_dict['pi_E_E'] + dy * as_dict['pi_E_N']
                delta_N = dx * as_dict['pi_E_N'] - dy * as_dict['pi_E_E']
                det = as_dict['pi_E_N']**2 + as_dict['pi_E_E']**2

                if 'pi_E_N' in parameters:
                    gradient['pi_E_N'] += np.sum(
                        factor_d_x_d_u * delta_N + factor_d_y_d_u * delta_E)
                    gradient['pi_E_N'] /= det
                if 'pi_E_E' in parameters:
                    gradient['pi_E_E'] += np.sum(
                        factor_d_x_d_u * delta_E - factor_d_y_d_u * delta_N)
                    gradient['pi_E_E'] /= det

        if len(parameters) == 1:
            out = gradient[parameters[0]]
        else:
            out = np.array([gradient[p] for p in parameters])
        return out