Uses the features database to create a mapping from Rosetta-numbered residues to PDB ATOM residues.
            Next, the object's rosetta_sequences (a dict of Sequences) element is created.
            Finally, a SequenceMap object is created mapping the Rosetta Sequences to the ATOM Sequences.

            The extra_command_flags parameter expects a string e.g. "-ignore_zero_occupancy false".

            If cache_dir is passed then the file <self.pdb_id>.

def construct_pdb_to_rosetta_residue_map(self, rosetta_scripts_path, rosetta_database_path = None, extra_command_flags = None, cache_dir = None):
        ''' Uses the features database to create a mapping from Rosetta-numbered residues to PDB ATOM residues.
            Next, the object's rosetta_sequences (a dict of Sequences) element is created.
            Finally, a SequenceMap object is created mapping the Rosetta Sequences to the ATOM Sequences.

            The extra_command_flags parameter expects a string e.g. "-ignore_zero_occupancy false".

            If cache_dir is passed then the file <self.pdb_id>.
        '''

        ## Create a mapping from Rosetta-numbered residues to PDB ATOM residues

        import json

        # Apply any PDB-specific hacks
        specific_flag_hacks = None
        if self.pdb_id and HACKS_pdb_specific_hacks.get(self.pdb_id):
            specific_flag_hacks = HACKS_pdb_specific_hacks[self.pdb_id]

        skeletal_chains = sorted([k for k in self.chain_types.keys() if self.chain_types[k] == 'Protein skeleton'])
        if skeletal_chains:
            raise PDBMissingMainchainAtomsException('The PDB to Rosetta residue map could not be created as chains %s only have CA atoms present.' % ", ".join(skeletal_chains))

        # Get the residue mapping using the features database
        mapping = None
        cached_json_mapping_filepath = None
        if cache_dir:
            cached_json_mapping_filepath = os.path.join(cache_dir, '{0}.rosetta2pdb.rawmap.json'.format(self.pdb_id)) # note: the resmap.json file created by self.get_atom_sequence_to_rosetta_json_map is more involved - rawmap is simply what is returned by get_pdb_contents_to_pose_residue_map
        if self.pdb_id and cache_dir and os.path.exists(cached_json_mapping_filepath):
            # Read cached file
            try:
                mapping = json.loads(read_file(cached_json_mapping_filepath))
            except: pass
        if mapping == None:
            pdb_file_contents = "\n".join(self.structure_lines)
            success, mapping = get_pdb_contents_to_pose_residue_map(pdb_file_contents, rosetta_scripts_path, rosetta_database_path = rosetta_database_path, pdb_id = self.pdb_id, extra_flags = ((specific_flag_hacks or '') + ' ' + (extra_command_flags or '')).strip())
            if not success:
                raise colortext.Exception("An error occurred mapping the PDB ATOM residue IDs to the Rosetta numbering.\n%s" % "\n".join(mapping))
            if self.pdb_id and cache_dir:
                write_file(cached_json_mapping_filepath, json.dumps(mapping, indent = 4, sort_keys = True))

        ## Create Sequences for the Rosetta residues (self.rosetta_sequences)

        # Initialize maps
        rosetta_residues = {}
        rosetta_sequences = {}
        for chain_id in self.atom_chain_order:
            chain_type = self.chain_types[chain_id]
            rosetta_residues[chain_id] = {}
            rosetta_sequences[chain_id] = Sequence(chain_type)

        # Create a map rosetta_residues, Chain -> Rosetta residue ID -> Rosetta residue information
        rosetta_pdb_mappings = {}
        for chain_id in self.atom_chain_order:
            rosetta_pdb_mappings[chain_id] = {}
        for k, v in mapping.iteritems():
            rosetta_residues[k[0]][v['pose_residue_id']] = v
            rosetta_pdb_mappings[k[0]][v['pose_residue_id']] = k

        # Create rosetta_sequences map Chain -> Sequence(Residue)
        for chain_id, v in sorted(rosetta_residues.iteritems()):
            chain_type = self.chain_types[chain_id]
            for rosetta_id, residue_info in sorted(v.iteritems()):
                short_residue_type = None

                residue_type = None
                if chain_type == 'Protein':
                    residue_type = residue_info['name3'].strip()
                    short_residue_type = residue_type_3to1_map.get(residue_type, 'X') # some HETATMs can be passed here e.g. MG so we can not map those cases
                else:
                    residue_type = residue_info['res_type'].strip()
                    if chain_type == 'DNA':
                        if residue_type.find('UpperDNA') != -1 or residue_type.find('LowerDNA') != -1:
                            residue_type = residue_type[:3]
                        short_residue_type = dna_nucleotides_3to1_map.get(residue_type) # Commenting this out since Rosetta does not seem to handle these "or non_canonical_dna.get(residue_type)"
                    else:
                        assert(chain_type == 'RNA')
                        if residue_type.find('UpperRNA') != -1 or residue_type.find('LowerRNA') != -1 or (len(residue_type) > 3 and residue_type[3] == ':'):
                            residue_type = residue_type[:3]
                        short_residue_type = rna_nucleotides_3to1_map.get(residue_type)

                if short_residue_type == None:
                    raise colortext.Exception('Could not determine the one-letter code of the residue: chain {0}, chain_type "{1}", residue "{2}", residue type "{3}".'.format(chain_id, chain_type, rosetta_id, residue_type))

                rosetta_sequences[chain_id].add(Residue(chain_id, rosetta_id, short_residue_type, chain_type))


        ## Create SequenceMap objects to map the Rosetta Sequences to the ATOM Sequences
        rosetta_to_atom_sequence_maps = {}
        for chain_id, rosetta_pdb_mapping in rosetta_pdb_mappings.iteritems():
            rosetta_to_atom_sequence_maps[chain_id] = SequenceMap.from_dict(rosetta_pdb_mapping)

        self.rosetta_to_atom_sequence_maps = rosetta_to_atom_sequence_maps
        self.rosetta_sequences = rosetta_sequences