code: def calculateScore(m):
      if _fscores is None:
          readFragmentScores()
  
      # fragment score
      # <- 2 is the *radius* of the circular fingerprint
      fp = rdMolDescriptors.GetMorganFingerprint(m, 2)
      fps = fp.GetNonzeroElements()
      score1 = 0.0
      nf = 0
      for bitId, v in iteritems(fps):
          nf += v
          sfp = bitId
          score1 += _fscores.get(sfp, -4) * v
      score1 /= nf
  
      # features score
      nAtoms = m.GetNumAtoms()
      nChiralCenters = len(
          Chem.FindMolChiralCenters(m, includeUnassigned=True)
      )
      ri = m.GetRingInfo()
      nBridgeheads, nSpiro = numBridgeheadsAndSpiro(m, ri)
      nMacrocycles = 0
      for x in ri.AtomRings():
          if len(x) > 8:
              nMacrocycles += 1
  
      sizePenalty = nAtoms**1.005 - nAtoms
      stereoPenalty = math.log10(nChiralCenters + 1)
      spiroPenalty = math.log10(nSpiro + 1)
      bridgePenalty = math.log10(nBridgeheads + 1)
      macrocyclePenalty = 0.0
      # ---------------------------------------
      # This differs from the paper, which defines:
      #  macrocyclePenalty = math.log10(nMacrocycles+1)
      # This form generates better results when 2 or more macrocycles are present
      if nMacrocycles > 0:
          macrocyclePenalty = math.log10(2)
  
      score2 = (
          0.0
          - sizePenalty
          - stereoPenalty
          - spiroPenalty
          - bridgePenalty
          - macrocyclePenalty
      )
  
      # correction for the fingerprint density
      # not in the original publication, added in version 1.1
      # to make highly symmetrical molecules easier to synthetise
      score3 = 0.0
      if nAtoms > len(fps):
          score3 = math.log(float(nAtoms) / len(fps)) * 0.5
  
      sascore = score1 + score2 + score3
  
      # need to transform "raw" value into scale between 1 and 10
      min = -4.0
      max = 2.5
      sascore = 11.0 - (sascore - min + 1) / (max - min) * 9.0
      # smooth the 10-end
      if sascore > 8.0:
          sascore = 8.0 + math.log(sascore + 1.0 - 9.0)
      if sascore > 10.0:
          sascore = 10.0
      elif sascore < 1.0:
          sascore = 1.0
  
      return sascore
  
file_path: DIG/dig/ggraph/method/JTVAE/fast_jtnn/sascorer.py
imports: from __future__ import print_function
  from rdkit import Chem
  from rdkit.Chem import rdMolDescriptors
  from rdkit.six.moves import cPickle
  from rdkit.six import iteritems
  import math
  from collections import defaultdict
  import os.path
label_desc: Use image node_id 3 for calling a global function with example usage: calculateScore(m) and returns: sascore