docs: def prune_structure_according_to_loop_definitions(self, loops_segments, search_radius, expected_min_loop_length = None, expected_max_loop_length = None, generate_pymol_session = True, check_sequence = False, keep_Ca_buttress_atoms = True):
          '''Removes the loop residues identified by the residues in loops_segments and all sidechains with heavy atoms
             within 10A of any heavy atom of the loop.
             If keep_Ca_buttress_atoms is set then the N and Ca backbone atoms of the first loop residue are kept and the
               Ca and C backbone atoms of the last loop residue are kept. This is a useful option to use for Rosetta as
               discarding those atoms can negatively affect some of the loop modeling protocols.
          '''
  
          # Extract the list of Residues defined in the loops definitions
          loop_residues = []
          loop_N_terminii = []
          loop_C_terminii = []
          parsed_sequences = []
          for loop in loops_segments:
  
              # Identify the Residues corresponding to the loops file definition
              start_id = loop.StartResidueID
              end_id = loop.EndResidueID
              chain_id = loop.Chain
              start_residue, end_residue = None, None
  
              try:
                  start_residue = self.residues[chain_id][loop.StartResidueID]
                  end_residue = self.residues[chain_id][loop.EndResidueID]
              except Exception, e:
                  raise Exception('Could not find the start or end residue in the chain.')
  
              if start_residue in loop_residues or end_residue in loop_residues:
                  raise Exception('Error: The loops segments overlap.')
  
              # We assume that the loops file identifies a range in document order
              loop_residue_ids = []
              loop_start = False
              for l in self.indexed_lines:
                  if l[0] == 'ATOM' or l[0] == 'HETATM':
                      atom_residue = l[3].residue
                      if not loop_start:
                          if atom_residue == start_residue:
                              loop_start = True
                              if atom_residue not in loop_residues:
                                  if atom_residue.residue_id not in loop_residue_ids:
                                      loop_residue_ids.append(atom_residue.residue_id)
                                  loop_residues.append(atom_residue)
                      else:
                          if atom_residue not in loop_residues:
                              if atom_residue.residue_id not in loop_residue_ids:
                                  loop_residue_ids.append(atom_residue.residue_id)
                              loop_residues.append(atom_residue)
                          if atom_residue == end_residue:
                              break
  
              parsed_sequence = ''.join([loop_residue.get_amino_acid_code() for loop_residue in loop_residues])
              if check_sequence:
                  if not parsed_sequence == loop.Sequence:
                      raise Exception('Expected to find sequence {0} but found sequence {1}.'.format(loop.Sequence, parsed_sequence))
              parsed_sequences.append((parsed_sequence, ';'.join([chain_id + lrid.strip() for lrid in loop_residue_ids])))
  
              # These parameters currently only makes sense for a single loop
              if expected_min_loop_length != None and ((expected_min_loop_length > len(loop_residues)) or (expected_min_loop_length > len(loop_residue_ids))):
                  raise Exception('Expected to identify at least {0} residues but {1} were identified.'.format(expected_min_loop_length, len(loop_residues)))
              if expected_max_loop_length != None and ((expected_max_loop_length < len(loop_residues)) or (expected_max_loop_length < len(loop_residue_ids))):
                  raise Exception('Expected to identify at most {0} residues but {1} were identified.'.format(expected_max_loop_length, len(loop_residues)))
  
              # Keep track of the loop terminii
              loop_N_terminii.append(start_residue)
              loop_C_terminii.append(end_residue)
  
          # Determine the sidechain atoms to be removed
          sidechain_atom_serial_numbers = self.find_sidechain_atoms_within_radius_of_residue_objects(loop_residues, search_radius)
  
          # Determine the loop residue atoms to be removed
          loop_residues_ids = set()
          loop_atom_serial_numbers = set()
          atoms_serial_numbers_to_keep_in_cutting = set()
          for loop_residue in loop_residues:
              for aatom in loop_residue.get('ATOM'):
                  if keep_Ca_buttress_atoms:
                      # Keep the N and CA atoms of the N-terminus side and the CA and C atoms of the C-terminus side
                      if (loop_residue in loop_N_terminii) and (aatom.name == 'N' or aatom.name == 'CA'):
                          atoms_serial_numbers_to_keep_in_cutting.add(aatom.serial_number)
                          continue
                      elif (loop_residue in loop_C_terminii) and (aatom.name == 'CA' or aatom.name == 'C'):
                          atoms_serial_numbers_to_keep_in_cutting.add(aatom.serial_number)
                          continue
                  loop_atom_serial_numbers.add(aatom.serial_number)
          assert(len(sidechain_atom_serial_numbers.intersection(loop_atom_serial_numbers)) == 0)
  
          # Create a FASTA file with the loops' sequences
          FASTA = []
          FASTA_line_length = self.FASTA_line_length
          for x in range(len(parsed_sequences)):
              parsed_sequence = parsed_sequences[x][0]
              FASTA.append('>loop_{0}|Residues {1}'.format(x + 1, parsed_sequences[x][1].strip()))
              for idx in range(0, len(parsed_sequence), FASTA_line_length):
                  FASTA.append(parsed_sequence[idx:idx + FASTA_line_length])
          FASTA_file = '\n'.join(FASTA)
  
          bonsai_pdb_content, cutting_pdb_content, PSE_file, PSE_script = self.prune(loop_atom_serial_numbers, sidechain_atom_serial_numbers, atoms_serial_numbers_to_keep_in_cutting = atoms_serial_numbers_to_keep_in_cutting, generate_pymol_session = generate_pymol_session)
          return bonsai_pdb_content, cutting_pdb_content, PSE_file, PSE_script, FASTA_file