docs: def assign_type(mol, force_recalc=False):
      """ PATTY [Bush et al. J. Inf. Comput. Sci 33 (1993) 756-762]
      TODO: not yet implemented
  
      1:cation 2:anion 3:donor 4:acceptor
      5:polar 6:hydrophobe 7:others
      """
      if "PATTY" in mol.descriptors and not force_recalc:
          return
      mol.require("Phys_charge")
      for i, atom in mol.atoms_iter():
          # default is 7 (others)
          nbrcnt = mol.neighbor_count(i)
          if atom.charge > 0 or atom.charge_phys > 0 or \
                  atom.charge_conj > 0 and not atom.n_oxide:
              atom.type = 1  # cation
          elif atom.charge < 0 or atom.charge_phys < 0 or \
                  atom.charge_conj < 0 and not atom.n_oxide:
              atom.type = 2  # anion
          elif atom.symbol == "N":
              if nbrcnt in (1, 2):
                  if atom.pi == 2:
                      atom.type = 3  # donor
                  elif atom.pi == 1:
                      atom.type = 4  # acceptor
          elif atom.symbol == "O":
              if nbrcnt == 1 and not atom.pi:
                  atom.type = 5  # polar
              else:
                  atom.type = 4  # acceptor
          elif atom.symbol in ("C", "Si", "S", "Se", "P", "As"):
              ewg = False
              for n, bond in mol.neighbors(i).items():
                  natom = mol.atom(n)
                  if natom.symbol in ("N", "O", "S") and atom.pi \
                          and not (natom.pi == 2 and mol.neighbor_count(n) == 3):
                      # the sp2 adjacent to neg (but not conj tert amine) is 7
                      ewg = True
                      break
              if not ewg:
                  atom.type = 6  # hydrophobes
          elif atom.symbol in ("F", "Cl", "Br", "I") and nbrcnt == 1:
              atom.type = 6  # typical halogens are hydrophobic
      mol.descriptors.add("PATTY")