code: def calculate_acd(acd_structure, fpf):
      
  
      # initialize variables
      fw_dict = defaultdict(int) # a count of the number of molecules that share a given framework
  
      # loop over the molecules in acd_structure and count up the molecules consistent with each unique framework
      for mol in acd_structure:
          fw_smiles = mol[4]
          fw_dict[fw_smiles] += 1
  
      fw_count = [x[1] for x in fw_dict.items()] # a list of the molecule count consistent with each unique framework
      fw_count.sort(reverse=True)                # always sort from high to low s.t.: 1 >= ACD >= 0.5
  
      n_actives = len(acd_structure) # number of active molecules above the fpf threshold
      n_active_fw = len(fw_count)    # number of unique active frameworks above the fpf threshold
      # determine the acd
      acd = (1. / n_actives) * (1. / n_active_fw) * sum(np.cumsum(fw_count))
  
      return (fpf, acd)
docs: Determine the area under the cumulative distribution function of the active framework count, or ACD, of those
      actives ranked better than the specified False Postive Fraction.
      :param acd_structure: list [(id, best_score, best_query, status, fw smiles), ..., ]. All of the molecules in the
      list are actives.
      :param fpf: float the False Positive fraction above which the ACD is calculated
      :return: (fpf, ACD)