<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def chem_shifts_by_residue(self, amino_acids=None, atoms=None, amino_acids_and_atoms=None, nmrstar_version="3"):
 """Organize chemical shifts by amino acid residue. :param list amino_acids: List of amino acids three-letter codes. :param list atoms: List of BMRB atom type codes. :param dict amino_acids_and_atoms: Amino acid and its atoms key-value pairs. :param str nmrstar_version: Version of NMR-STAR format to use for look up chemical shifts loop. :return: List of OrderedDict per each chain :rtype: :py:class:`list` of :py:class:`collections.OrderedDict` """

        if (amino_acids_and_atoms and amino_acids) or (amino_acids_and_atoms and atoms):
            raise ValueError('"amino_acids_and_atoms" parameter cannot be used simultaneously with '
                             '"amino_acids" and "atoms" parameters, one or another must be provided.')

        chemshifts_loop = NMRSTAR_CONSTANTS[nmrstar_version]["chemshifts_loop"]
        aminoacid_seq_id = NMRSTAR_CONSTANTS[nmrstar_version]["aminoacid_seq_id"]
        aminoacid_code = NMRSTAR_CONSTANTS[nmrstar_version]["aminoacid_code"]
        atom_code = NMRSTAR_CONSTANTS[nmrstar_version]["atom_code"]
        chemshift_value = NMRSTAR_CONSTANTS[nmrstar_version]["chemshift_value"]

        chains = []
        for saveframe in self:
            if saveframe == u"data" or saveframe.startswith(u"comment"):
                continue
            else:
                for ind in self[saveframe].keys():
                    if ind.startswith(u"loop_"):
                        if list(self[saveframe][ind][0]) == chemshifts_loop:
                            chem_shifts_dict = OrderedDict()
                            for entry in self[saveframe][ind][1]:
                                residue_id = entry[aminoacid_seq_id]
                                chem_shifts_dict.setdefault(residue_id, OrderedDict())
                                chem_shifts_dict[residue_id][u"AA3Code"] = entry[aminoacid_code]
                                chem_shifts_dict[residue_id][u"Seq_ID"] = residue_id
                                chem_shifts_dict[residue_id][entry[atom_code]] = entry[chemshift_value]
                            chains.append(chem_shifts_dict)

        if amino_acids_and_atoms:
            for chem_shifts_dict in chains:
                for aa_dict in list(chem_shifts_dict.values()):
                    if aa_dict[u"AA3Code"].upper() not in list(amino_acids_and_atoms.keys()):
                        chem_shifts_dict.pop(aa_dict[u"Seq_ID"])
                    else:
                        for resonance in list(aa_dict.keys()):
                            if resonance in (u"AA3Code", u"Seq_ID") or resonance.upper() in amino_acids_and_atoms[aa_dict[u"AA3Code"]]:
                                continue
                            else:
                                aa_dict.pop(resonance)
        else:
            if amino_acids:
                for chem_shifts_dict in chains:
                    for aa_dict in list(chem_shifts_dict.values()):
                        if aa_dict[u"AA3Code"].upper() not in amino_acids:
                            chem_shifts_dict.pop(aa_dict[u"Seq_ID"])

            if atoms:
                for chem_shifts_dict in chains:
                    for aa_dict in chem_shifts_dict.values():
                        for resonance in list(aa_dict.keys()):
                            if resonance in (u"AA3Code", u"Seq_ID") or resonance.upper() in atoms:
                                continue
                            else:
                                aa_dict.pop(resonance)
        return chains