            self.residue_type = self.get_res_type(struct_object_list[0])

        self.superimpose_all(struct_object_list)
        self.log.info('Classifying %s residues', self.residue_type.upper())

        if self.residue_type.upper() in ('ALA', 'GLY'):
            self.rotamer_classes = [struct_object_list, []]
            self.rotamer_classes[0][0].id = self.rotamer_classes[0][0].id + '_representative'
        else:
            self.interpolator = generate_molprobity_interpolator(self.residue_type)
            rotamers = self.create_rotamers(self.residue_type)
            self.rotamers = rotamers
            self.rotamer_classes = self.find_rotamers(struct_object_list, rotamers)

            #filter same name rotamers
            rotamers_tmp = []
            classes_tmp = []
            names = []

            for i, rotamer in enumerate(rotamers):
                name = rotamer['name']
                if rotamers_tmp is [] or name not in names:
                    rotamers_tmp.append(rotamer)
                    names.append(name)
                    classes_tmp.append(self.rotamer_classes[i])
                else:
                    index = names.index(name)
                    classes_tmp[index] = classes_tmp[index] + self.rotamer_classes[i]
            classes_tmp.append(self.rotamer_classes[-1])
            self.rotamer_classes = classes_tmp
            self.rotamers = rotamers_tmp

            for class_ in self.rotamer_classes:
                if len(class_) > 200:
                    repr_index = self.find_repr_model_fast(class_, rotamers)
                else:
                    repr_index = self.find_repr_model(class_)
                if repr_index is not None:
                    class_[repr_index].id = class_[repr_index].id + '_representative'

        self.save_rotamers(self.rotamer_classes)
        text = func.report_elapsed(start)
        self.log.info(text)

    @staticmethod
    def load_rotamer_lib(rotamer_lib_path=None):
        """
        Reads the rotamer library in json format
        :param rotamer_lib_path: json file
        :return: file content
        """
        if rotamer_lib_path is not None:
            try:
                with open(rotamer_lib_path) as j:
                    data = json.load(j)
                    return data
            except:
                pass
        data = p_lib.ROTAMER_BOUNDS
        return data

    def setup_log(self, warning_level):
        """
        Setup process_log
        :param warning_level:
        :return:
        """
        class_log = func.setup_logger('process_log', self.log_path, warning_level=warning_level)
        return class_log

    def setup_model_read_error_out(self):
        if self.log_path is not None:
            err_out_file = os.path.splitext(self.log_path)[0] + '.err'
        else:
            err_out_file = os.path.join(self.corrupted_files_dir, 'corrupted_files.err')
        return err_out_file

    def create_model_list(self):
        """
        Reads all.cif,.pdb and.ent files in a directory and creates a list of structure objects
        """
        if self.residue_type is not None:
            r_type = self.residue_type
            type_defined = True
        else:
            type_defined = False
            r_type = None

        files = os.listdir(self.in_dir)
        cif_names = [i for i in files if (i.endswith('.cif') or i.endswith('.pdb') or i.endswith('.ent'))
                     and not i.startswith('.')]

        str_object_list = []
        for element in cif_names:
            try:
                structure = bio_utils.load_structure(os.path.join(self.in_dir, element))
            except:
                # If the residue file could not be read for some reason it will move it
                self.log.info('Failed to process %s file\nMoving it and related files to %s\nCheck %s for details',
                              element, self.corrupted_files_dir, self.model_err_out_path)
                exc_type, exc_value, exc_traceback = sys.exc_info()
                traceback.print_tb(exc_traceback, file=self.model_err_out)
                # os.replace(os.path.join(self.in_dir, element), os.path.join(self.corrupted_files_dir, element))
                prefix = element.split('_')[0]
                related_files = [i for i in files if i.startswith(prefix)]
                if related_files:
                    for file in related_files:
                        shutil.move(os.path.join(self.in_dir, file), os.path.join(self.corrupted_files_dir, file))
            else:
                tt = self.get_res_type(structure)
                if tt is not None:
                    if r_type is None:
                        r_type = tt
                    if tt == r_type:
                        str_object_list.append(structure)
                    elif not type_defined:
                        raise Exception('There are multiple residue types in the input and no '
                                        '"residue_type" parameter specified. '
                                        '\nPlease restart with defined "residue_type" parameter')

        if not str_object_list:
            raise Exception('There are no atomic residue files in the specified directory: {}'.format(self.in_dir))
        return str_object_list

    @staticmethod
    def set_rotamers_data_structure():
        """
        A dictionary to define the rotameric angles for standard amino acids.
        :return: dictionary
        """
        residue_rotamers = nomenclature.ROTAMER_DATA
        for key in residue_rotamers.keys():
            residue_rotamers[key]['id'] = None
            residue_rotamers[key]['name'] = None
        return residue_rotamers

    def create_rotamers(self, residue_3let):
        """
        Creates a list of dictionaries with relevant rotameric parameters for the specified residue type
        :param residue_3let: residue code (3 letter)
        :return: list of dictionaries
        """
        residue_3let = residue_3let.lower()
        rotamers = []

        residue_lib_data = self.rotamer_lib[residue_3let]
        for rotamer in residue_lib_data:
            rot_data_structure = copy.deepcopy(self.rotamers_data_structure[residue_3let])
            for key in rot_data_structure.keys():
                if key.startswith('chi_'):
                    rot_data_structure[key]['angle_val'] = rotamer[key]
                    nr = key.split('_')[-1]
                    try:
                        value = int(rotamer['chi-width_' + nr])
                    except TypeError:
                        value = self.default_width

                    if not self.use_minimal_width:
                        rot_data_structure[key]['angle_width'] = value
                    else:
                        rot_data_structure[key]['angle_width'] = max([value, self.default_width])
                else:
                    rot_data_structure[key] = rotamer[key]
            rotamers.append(rot_data_structure)

        return rotamers

    @staticmethod
    def get_res_type(model):
        """
        Reads the 3 letter residue code from a residue  BIO.PDB object
        :param model:
        :return: 3 letter residue code
        """
        residues = [residue for residue in model.get_residues()]
        if len(residues) == 1:
            return residues[0].get_resname().lower()
        else:
            return None

    @staticmethod
    def _get_dihedral_angle(residue, atom_names):
        if len(atom_names) <