//  [python]
def check_partial_trajectory(self, fit_gmm=True, fit_slope=True,
                                 determine_model=True):
        w_non_zero = ((self.c >= 0.1 * np.max(self.c)) &
                      (self.u >= 0.1 * np.max(self.u)) &
                      (self.s >= 0.1 * np.max(self.s)))
        u_non_zero = self.u[w_non_zero]
        s_non_zero = self.s[w_non_zero]
        if len(u_non_zero) < 10:
            self.low_quality = True
            return

        # GMM
        w_low = ((np.percentile(s_non_zero, 30) <= s_non_zero) &
                 (s_non_zero <= np.percentile(s_non_zero, 40)))
        if np.sum(w_low) < 10:
            fit_gmm = False
            self.partial = True
        if self.local_std is None:
            logg.warn('local standard deviation not provided. '
                      'Skipping GMM..', v=2)
        if self.embed_coord is None:
            logg.warn('Warning: embedded coordinates not provided. '
                      'Skipping GMM..')
        if (fit_gmm and self.local_std is not None and self.embed_coord
                is not None):

            pdist = pairwise_distances(
                self.embed_coord[w_non_zero, :][w_low, :])
            dists = (np.ravel(pdist[np.triu_indices_from(pdist, k=1)])
                     .reshape(-1, 1))
            model = mixture.GaussianMixture(n_components=2, covariance_type='tied',
                                    random_state=2021).fit(dists)
            mean_diff = np.abs(model.means_[1][0] - model.means_[0][0])
            criterion1 = mean_diff > self.local_std / self.tm
            logg.update(f'GMM: difference between means = {mean_diff}, '
                        f'threshold = {self.local_std / self.tm}.', v=2)
            criterion2 = np.all(model.weights_[1] > 0.2 / self.tm)
            logg.update('GMM: weight of the second Gaussian ='
                        f' {model.weights_[1]}.', v=2)
            if criterion1 and criterion2:
                self.partial = False
            else:
                self.partial = True
            logg.update(f'GMM decides {"" if self.partial else "not "}'
                        'partial.', v=2)

        # steady-state slope
        wu = self.u >= np.percentile(u_non_zero, 95)
        ws = self.s >= np.percentile(s_non_zero, 95)
        ss_u = self.u[wu | ws]
        ss_s = self.s[wu | ws]
        if np.all(ss_u == 0) or np.all(ss_s == 0):
            self.low_quality = True
            return
        gamma = np.dot(ss_u, ss_s) / np.dot(ss_s, ss_s)
        self.steady_state_func = lambda x: gamma*x

        # thickness of phase portrait
        u_norm = u_non_zero / np.max(self.u)
        s_norm = s_non_zero / np.max(self.s)
        exp = np.hstack((np.reshape(u_norm, (-1, 1)),
                         np.reshape(s_norm, (-1, 1))))
        U, S, Vh = np.linalg.svd(exp)
        self.thickness = S[1]

        # slope-based direction decision
        with np.errstate(divide='ignore', invalid='ignore'):
            slope = self.u / self.s
        non_nan = ~np.isnan(slope)
        slope = slope[non_nan]
        on = slope >= gamma
        off = slope < gamma
        if len(ss_u) < 10 or len(u_non_zero) < 10:
            fit_slope = False
            self.direction = 'complete'
        if fit_slope:
            slope_ = u_non_zero / s_non_zero
            on_ = slope_ >= gamma
            off_ = slope_ < gamma
            on_dist = np.sum((u_non_zero[on_] - gamma * s_non_zero[on_])**2)
            off_dist = np.sum((gamma * s_non_zero[off_] - u_non_zero[off_])**2)
            logg.update(f'Slope: SSE on induction phase = {on_dist},'
                        f' SSE on repression phase = {off_dist}.', v=2)
            if self.thickness < 1.5 / np.sqrt(self.tm):
                narrow = True
            else:
                narrow = False
            logg.update(f'Thickness of trajectory = {self.thickness}. '
                        f'Trajectory is {"narrow" if narrow else "normal"}.',
                        v=2)
            if on_dist > 10 * self.tm**2 * off_dist:
                self.direction = 'on'
                self.partial = True
            elif off_dist > 10 * self.tm**2 * on_dist:
                self.direction = 'off'
                self.partial = True
            else:
                if self.partial is True:
                    if on_dist > 3 * self.tm * off_dist:
                        self.direction = 'on'
                    elif off_dist > 3 * self.tm * on_dist:
                        self.direction = 'off'
                    else:
                        if narrow:
                            self.direction = 'on'
                        else:
                            self.direction = 'complete'
                            self.partial = False
                else:
                    if narrow:
                        self.direction = ('off'
                                          if off_dist > 2 * self.tm * on_dist
                                          else 'on')
                        self.partial = True
                    else:
                        self.direction = 'complete'

        # model pre-determination
        if self.direction == 'on':
            self.model_ = 1
        elif self.direction == 'off':
            self.model_ = 2
        else:
            c_high = self.c >= np.mean(self.c) + 2 * np.std(self.c)
            c_high = c_high[non_nan]
            if np.sum(c_high) < 10:
                c_high = self.c >= np.mean(self.c) + np.std(self.c)
                c_high = c_high[non_nan]
            if np.sum(c_high) < 10:
                c_high = self.c >= np.percentile(self.c, 90)
                c_high = c_high[non_nan]
            if np.sum(self.c[non_nan][c_high] == 0) > 0.5*np.sum(c_high):
                self.low_quality = True
                return
            c_high_on = np.sum(c_high & on)
            c_high_off = np.sum(c_high & off)
            if c_high_on > c_high_off:
                self.model_ = 1
            else:
                self.model_ = 2
        if determine_model:
            self.model = self.model_

        if not self.known_pars:
            if fit_gmm or fit_slope:
                logg.update(f'predicted partial trajectory: {self.partial}',
                            v=1)
                logg.update('predicted trajectory direction:'
                            f'{self.direction}', v=1)
            if determine_model:
                logg.update(f'predicted model: {self.model}', v=1)