def _find_next_pass(self, start_date):
        def elevation(delta_seconds):
            return self._elevation_at(start_date +
                                      dt.timedelta(seconds=delta_seconds))

        start_elevation = self._elevation_at(start_date)
        period_s = orbital_period(self.predictor.mean_motion) * 60

        # Find date for maximum elevation within the next orbital period
        # NOTE: This is the most expensive operation
        res_tca = minimize_scalar(
            lambda t: -elevation(t),
            bounds=(0, period_s),
            method=minimize_scalar_bounded_alt,
            options=dict(xatol=self.tolerance_s),
        )
        t_tca = res_tca.x
        tca = start_date + dt.timedelta(seconds=t_tca)
        max_elevation = -res_tca.fun
        if max_elevation < self.max_elevation_gt:
            return False, None, tca, start_date + dt.timedelta(
                seconds=period_s), max_elevation

        # Find AOS
        try:
            if self.aos_at < start_elevation:
                # AOS is past the start date
                t_left = -period_s / 2
            else:
                t_left = 0
            t_aos = root_scalar(
                lambda t: elevation(t) - self.aos_at,
                bracket=(t_left, t_tca),
                xtol=self.tolerance_s,
            ).root
        except ValueError as e:
            raise PropagationError(
                "Could not find AOS of pass with TCA {}".format(tca)) from e

        # Ensure location is visible at AOS by adding atol
        aos = start_date + dt.timedelta(seconds=t_aos + self.tolerance_s)

        # LOS must be between TCA and half the next period
        try:
            t_los = root_scalar(
                lambda t: elevation(t) - self.aos_at,
                bracket=(t_tca, t_tca + period_s / 2),
                xtol=self.tolerance_s,
            ).root
        except ValueError as e:
            raise PropagationError(
                "Could not find LOS of pass with AOS {} and TCA {}".format(
                    aos, tca)) from e
        else:
            los = start_date + dt.timedelta(seconds=t_los)

        return True, aos, tca, los, max_elevation
 def _find_nearest_ascending(self, descending_date):
     for candidate in self._sample_points(descending_date):
         if self.is_ascending(candidate):
             return candidate
     else:
         logger.error('Could not find an ascending pass over %s start date: %s - TLE: %s',
                      self.location, descending_date, self.propagator.tle)
         raise PropagationError('Can not find an ascending phase')