Ejemplo n.º 1
0
class ScoreFunction:
    """ 
    The ScoreFucntion object must initialize by having object ScoreTable read in as Dictionary.
    > 130909: should I move pose storage out of the class? 

    """

    def __init__(self, score_table, wts, null_frag_score, pose={}):
        """
        1. Score methods:
            function call operations
            > Given a pose, return the total_score
            > Given a frag_idx, return the score relatively to the rest of the residues in the pose (update the pose?)

        2. Evaluation method:
            return stats for evaluation/debug purposes
            > Per-residue stats: decomposite scores for each residue level
            > Summarize score: overall results for a pose

        """

        assert isScoreTable(score_table)
        assert isWeights(wts)

        self._score_table = score_table
        self._wts = wts
        self._null_frag_score = null_frag_score

        # Private Member
        self.__pose = FragIdxPose()  # selected_frags_dict

    def __call__(self, input):
        """ 
        Two operations:
        1. scorefxn( pose ):  #
            ** noteworthy: the pose object here is Pose
            > assign Residue object for each position, and 
            > return a total score of it
        2. scorefxn( frag_idx ): 
            > return frag score for the frag_idx to a pose

        """
        assert isPose(input) or isFragIdx(input)

        if isPose(input):  # a residual pose
            """ 1. update the residue of the verbose_pose to be composed of Residue objects
                2. return a total score """

            residual_pose = input
            self.update_pose(residual_pose)  # the frag_idx in the input has been update to self.__pose

            # use the new ScoreTable to rescore it residual_pose
            output_pose = Pose()
            for frag_idx in self.__pose:
                output_pose.update_residue(self.score_evaluator(frag_idx, True))

            return output_pose

        elif isFragIdx(input):
            """ return a residue score """
            return self.score_evaluator(input)

    def residualize_pose(self):
        """ Pose() has methods to evaluate the state """
        residual_pose = Pose()

        for frag_idx in self.__pose:
            residual_pose.update_residue(self.score_evaluator(frag_idx, True))

        return residual_pose

    def get_density_score_dict(self):
        return self._score_table.get_density_score_dict()

    def get_candidate_frags(self, pos):
        """ return candidate fragid objects from a position as a list """
        return self._score_table.get_candidate_frags(pos)

    def clone(self):
        """ would it work? don't know yet """
        return copy.deepcopy(self)

    def update_score_table(self, new_score_table):
        assert isScoreTable(new_score_table)
        self._score_table = new_score_table

    def update_pose(self, pose):
        """ simply assign the coming pose to the in-object pose """
        assert isFragIdxPose(pose) or isPose(pose)

        if isFragIdxPose(pose):
            self.__pose = pose

        elif isPose(pose):
            for residue in pose:
                pos = residue._frag_id._pos
                # print pos, residue._score
                frag_idx = self._score_table.frag_to_index(residue._frag_id())
                self.__pose.update_residue(pos, frag_idx)

    def set_weights(self, new_wts):
        """ This is in particular useful when you want to interactive use this class to rescore by changing the weights """
        assert isWeights(new_wts)
        self._wts = new_wts

    def set_null_frag_score(self, new_null_frag_score):
        """ This is being used whenever low acceptance rate of MonteCarlo object - lower the null_frag_score """
        assert new_null_frag_score
        self._null_frag_score = new_null_frag_score

    #### the main method to score ####
    def score_evaluator(self, candidate_frag_idx, verbose=False):
        """ 
        Given a candidate_frag_idx, return a frag_score of the fragment to the selected ones,
        1. null_frag - return null_frag_score
        2. frag - return frag_score
        """
        assert isFragIdxPose(
            self.__pose
        )  # is a Pose instance, and has been initialized; this is because when instance ScoreFunction class, you don't have to give it a Pose class

        # skip null fragment: this is for when calculating total_score
        if isNullFrag(candidate_frag_idx):
            if verbose:
                candidate_frag_id = FragID(self._score_table.index_to_frag(candidate_frag_idx))  # make FragID object
                return Residue(candidate_frag_id, self._null_frag_score)
            else:
                return self._null_frag_score

        density_score, all_overlap_score, all_closab_score, all_clash_score = (0.0,) * 4

        # one-body score:
        try:
            density_score = self._score_table.density_score_lookup(candidate_frag_idx)
            density_score *= self._wts._density_score_wt
            rmsd = self._score_table.rmsd_lookup(candidate_frag_idx)

        except KeyError:
            stderr.write("Error: %s does not have density score\n" % candidate_frag_idx)
            exit()

        # two-body score: the candidate_frag to the rest selected ones
        """ for each candidate placement, calculate frag_score against all selected frags """

        for selected_frag_idx in self.__pose:  # pose as an iterator of positions

            if selected_frag_idx == candidate_frag_idx:
                continue  # no two-body score to itself
            if isNullFrag(selected_frag_idx):
                continue  # you don't need to compare to null fragment

            # overlap using table to do a fast lookup
            if self._score_table.overlapping_check_table_lookup(candidate_frag_idx, selected_frag_idx):
                # The reason why you don't need to look up clash score for overlapping fragments is because it has been considered while calculating overlap_score
                try:
                    overlap_score = self._score_table.overlap_score_lookup(candidate_frag_idx, selected_frag_idx)
                    overlap_score *= self._wts._overlap_score_wt
                    all_overlap_score += overlap_score

                except KeyError:
                    stderr.write(
                        "WARNING: %s %s don't have overlap score\n"
                        % (
                            self._score_table.index_to_frag(candidate_frag_idx),
                            self._score_table.index_to_frag(selected_frag_id),
                        )
                    )
                    continue
            else:
                try:
                    closab_score = self._score_table.closab_score_lookup(candidate_frag_idx, selected_frag_idx)
                    closab_score *= self._wts._closab_score_wt
                    all_closab_score += closab_score

                    clash_score = self._score_table.clash_score_lookup(candidate_frag_idx, selected_frag_idx)
                    clash_score *= self._wts._clash_score_wt
                    all_clash_score += clash_score

                except KeyError:
                    stderr.write(
                        "WARNING: %s %s don't have nonoverlap score\n"
                        % (
                            self._score_table.index_to_frag(candidate_frag_idx),
                            self._score_table.index_to_frag(selected_frag_id),
                        )
                    )
                    continue

        #### end of calculating "the candidate_frag" to the selected ones ####
        frag_score = density_score + all_overlap_score + all_closab_score + all_clash_score

        if verbose:
            """ This is to be used at the very end of stage of simulation to dump residual decomposed scores; 
                preferably will only be called in scorefxn.show_state() """
            candidate_frag_id = FragID(self._score_table.index_to_frag(candidate_frag_idx))  # make FragID object
            residue = Residue(
                candidate_frag_id, frag_score, density_score, all_overlap_score, all_closab_score, all_clash_score, rmsd
            )  # missing Boltzmann
            return residue
        else:
            return frag_score