Creates the ATOM Sequences.

def _get_ATOM_sequences(self):
        '''Creates the ATOM Sequences.'''

        # Get a list of all residues with ATOM or HETATM records
        atom_sequences = {}
        structural_residue_IDs_set = set() # use a set for a quicker lookup
        ignore_HETATMs = True # todo: fix this if we need to deal with HETATMs

        residue_lines_by_chain = []
        structural_residue_IDs_set = []

        present_chain_ids = {}
        for l in self.structure_lines:
            if len(l) > 21 and l[:3] != 'TER':
                present_chain_ids[l[21]] = present_chain_ids.get(l[21], set())
                present_chain_ids[l[21]].add(l[:6])

        model_index = 0
        residue_lines_by_chain.append([])
        structural_residue_IDs_set.append(set())
        full_code_map = {}
        hetatm_map = {}
        full_atom_map = {}
        for l in self.structure_lines:
            chain_id = None
            if l.startswith("TER   "):
                model_index += 1
                residue_lines_by_chain.append([])
                structural_residue_IDs_set.append(set())
            else:
                residue_id = l[21:27]
                if residue_id not in structural_residue_IDs_set[model_index]:
                    residue_lines_by_chain[model_index].append(l)
                    structural_residue_IDs_set[model_index].add(residue_id)
                if l.startswith('ATOM'):
                    chain_id = l[21]
                    # Only use ATOM records to build the code map as chains can have ligands HETATMs
                    full_code_map[chain_id] = full_code_map.get(chain_id, set())
                    full_code_map[chain_id].add(l[17:20].strip())

                    # Only use ATOM records to build the atom map as CA-only chains can have ligands described in full as HETATMs
                    full_atom_map[chain_id] = full_atom_map.get(chain_id, set())
                    full_atom_map[chain_id].add(l[12:16].strip())
                elif l.startswith('HETATM'):
                    chain_id = l[21]
                    hetatm_map[chain_id] = hetatm_map.get(chain_id, set())
                    hetatm_map[chain_id].add(l[17:20].strip())

        # Get the residues used by the residue lines. These can be used to determine the chain type if the header is missing.
        for chain_id in self.atom_chain_order:
            if full_code_map.get(chain_id):
                # The chains may contain other molecules e.g. MG or HOH so before we decide their type based on residue types alone,
                # we subtract out those non-canonicals
                canonical_molecules = full_code_map[chain_id].intersection(dna_nucleotides.union(rna_nucleotides).union(residue_types_3))

                determined_chain_type = None
                if canonical_molecules.union(dna_nucleotides) == dna_nucleotides:
                    determined_chain_type = 'DNA'
                elif canonical_molecules.union(rna_nucleotides) == rna_nucleotides:
                    determined_chain_type = 'RNA'
                elif len(full_code_map[chain_id]) == 1 and 'UNK' in full_code_map[chain_id]:
                    determined_chain_type = 'Unknown'
                elif canonical_molecules:
                    if len(full_atom_map[chain_id]) == 1 and 'CA' in full_atom_map[chain_id]:
                        determined_chain_type = 'Protein skeleton'
                    else:
                        determined_chain_type = 'Protein'
                else:
                    determined_chain_type = PDB._determine_heterogen_chain_type(canonical_molecules)

                if self.chain_types.get(chain_id):
                    assert(self.chain_types[chain_id] == determined_chain_type)
                else:
                    self.chain_types[chain_id] = determined_chain_type

        line_types_by_chain = []
        chain_ids = []
        for model_index in range(len(residue_lines_by_chain)):
            line_types = set()
            if residue_lines_by_chain[model_index]:
                if missing_chain_ids.get(self.pdb_id):
                    chain_ids.append(missing_chain_ids[self.pdb_id])
                else:
                    chain_ids.append(residue_lines_by_chain[model_index][0][21])
            for l in residue_lines_by_chain[model_index]:
                line_types.add(l[0:6])
            if line_types == set(['ATOM']):
                line_types_by_chain.append('ATOM')
            elif line_types == set(['HETATM']):
                line_types_by_chain.append('HETATM')
            else:
                line_types_by_chain.append('Mixed')

        for x in range(0, len(residue_lines_by_chain)):
            residue_lines = residue_lines_by_chain[x]
            line_types = line_types_by_chain[x]
            if ignore_HETATMs and line_types == 'HETATM':
                continue

            for y in range(len(residue_lines)):
                l = residue_lines[y]
                residue_type = l[17:20].strip()
                if l.startswith("HETATM"):
                    if self.modified_residue_mapping_3.get(residue_type):
                        residue_type = self.modified_residue_mapping_3[residue_type]
                    elif y == (len(residue_lines) - 1):
                        # last residue in the chain
                        if residue_type == 'NH2':
                            residue_type = 'UNK' # fixes a few cases e.g. 1MBG, 1K9Q, 1KA6
                        elif ignore_HETATMs:
                            continue

                    elif ignore_HETATMs:
                        continue

                residue_id = l[21:27]
                chain_id = l[21]
                if missing_chain_ids.get(self.pdb_id):
                    chain_id = missing_chain_ids[self.pdb_id]

                if chain_id in self.chain_types:
                    # This means the pdb had SEQRES and we constructed atom_sequences
                    chain_type = self.chain_types[chain_id]
                else:
                    # Otherwise assume this is protein
                    chain_type = 'Protein'

                atom_sequences[chain_id] = atom_sequences.get(chain_id, Sequence(chain_type))

                residue_type = self.modified_residue_mapping_3.get(residue_type, residue_type)

                short_residue_type = None
                if residue_type == 'UNK':
                    short_residue_type = 'X'
                elif chain_type == 'Unknown':
                    assert(False) # we should not reach here - Unknown chains should only contain UNK records
                elif chain_type == 'Protein' or chain_type == 'Protein skeleton':
                    short_residue_type = residue_type_3to1_map.get(residue_type) or protonated_residue_type_3to1_map.get(residue_type) or non_canonical_amino_acids.get(residue_type)
                elif chain_type == 'DNA':
                    short_residue_type = dna_nucleotides_2to1_map.get(residue_type) or non_canonical_dna.get(residue_type)
                elif chain_type == 'RNA':
                    short_residue_type = non_canonical_rna.get(residue_type) or residue_type

                if not short_residue_type:
                    if l.startswith("ATOM") and l[12:16] == ' OH2' and l[17:20] == 'TIP':
                        continue
                    elif not self.strict:
                        short_residue_type = 'X'
                    else:
                        raise NonCanonicalResidueException("Unrecognized residue type %s in PDB file '%s', residue ID '%s'." % (residue_type, str(self.pdb_id), str(residue_id)))

                #structural_residue_IDs.append((residue_id, short_residue_type))
                # KAB - way to allow for multiresidue noncanonical AA's
                if len(short_residue_type) == 1:
                    atom_sequences[chain_id].add(PDBResidue(residue_id[0], residue_id[1:], short_residue_type, chain_type))
                else:
                    for char in short_residue_type:
                        atom_sequences[chain_id].add(PDBResidue(residue_id[0], residue_id[1:], char, chain_type))

        # Assign 'Ligand' or 'Heterogen' to all HETATM-only chains
        for chain_id in present_chain_ids.keys():
            if chain_id not in self.chain_types:
                assert('ATOM  ' not in present_chain_ids[chain_id])
                self.chain_types[chain_id] = PDB._determine_heterogen_chain_type(hetatm_map.get(chain_id, set()))
        self.atom_sequences = atom_sequences