- I have made MMFF atom typing more robust since I realized that
  incorrect typing might arise when hydrogens were not added after
  generating 3D coordinates from SMILES strings; now all 761 test molecules
  are correctly typed no matter whether hydrogens are explicit or implicit

- MMFF test suite: I have cut down to the bare essential the
  MMFF94/MMFF94s reference log files, but their size could be reduced only
  by about 30%. It could have been reduced more converting multiple spaces
  into a tab, but the MMFF94 file (the larger one) would still be around
  11 MB, and human readability would be greatly impaired. Hence I decided
  to keep the spaces and gzip the reference logs, which reduces their
  combined size to ~ 3.5 MB, which I think is fine; the test program checks
  if the gunzipped files already exist, otherwise it gunzips them upfront.
  While cutting, I also sorted the molecules in the same order as in the
  SDF/SMILES files, so that it runs about 10 times faster than before.
  Now the test runs on MMFF94 only (MMFF94s only concerns different OOP
  parameters, there are no algorithmic differences, so as long as one does
  not alter the original parameters it can be safely skipped), computing
  every 4th molecule, and it runs in 12 seconds on my laptop. Running
  all molecules takes ~ 50 seconds, but I think it is rather overkill,
  and I would keep it as it is.

- I have added a test suite for MMFF ForceFieldHelpers (like the one
  already existing for UFF); I have also complemented the Python wrapper
  test suite for ForceFieldHelpers with a few tests for MMFF.

- I have written Python wrappers for the MMFF-related functionality;
  while doing that I realized that many of the wrapper code relocations
  that I made in my previous pull request were not necessary/appropriate,
  so I reverted them. The only difference from the UFF Python API is that,
  just like for the C++ API, in addition to the PyForceField object there
  is a PyMMFFMolProperties object which is created before constructing the
  force field itself; the PyMMFFMolProperties is necessary to set (e.g.,
  dielectric constant, dielectric model) or get (e.g., atom type, formal
  and partial charge) some MMFF properties which are not present in UFF,
  while preserving binary compatibility of the libraries. Probably you
  remember that we discussed about setting atom type and charge properties
  with SetProp besides populating the MMFFMolProperties object, in order
  to allow easy access to Python users. However, I think that the solution
  I adopted is preferrable since it is more consistent with the C++ API,
  it enables faster access to properties and it allows tailoring the MMFF
  environment (i.e., choosing MMFF94/MMFF94s, setting the verbosity level,
  including/excluding terms from the MMFF equation, setting dielectric
  constant/model) just as from C++.

  The MMFF-related Python functions I implemented are:

  * MMFFOptimizeMolecule(mol, mmffVariant = "MMFF94", maxIters = 200,
      nonBondedThresh = 100.0, confId = -1, ignoreInterfragInteractions
      = true)

    uses MMFF to optimize a molecule's structure (just like
    UFFOptimizeMolecule)

  * SanitizeMMFFMol(mol)

    sanitizes a molecule according to MMFF requirements

  * SetupMMFFForceField(mol, mmffVariant = "MMFF94", mmffVerbosity = 0)

    returns a PyMMFFMolProperties object for a molecule; the
    PyMMFFMolProperties object is required by MMFFGetMoleculeForceField()
    and can be used to get/set MMFF properties

  * MMFFGetMoleculeForceField(mol, pyMMFFMolProperties,
      nonBondedThresh = 100.0, confId = -1, ignoreInterfragInteractions
      = true)

    returns a MMFF force field for a molecule (just like
    UFFGetMoleculeForceField)

  * MMFFHasAllMoleculeParams(mol)

    checks if MMFF parameters are available for all of a molecule's atoms
    (just like UFFHasAllMoleculeParams)

  There are also a few methods connected to the PyMMFFMolProperties class
  which mirror those available from C++ for the MMFFMolProperties class:

  * GetMMFFAtomType(idx)

    Retrieves MMFF atom type for atom with index idx

  * GetMMFFFormalCharge(idx)

    Retrieves MMFF formal charge for atom with index idx

  * GetMMFFPartialCharge(idx)

    Retrieves MMFF partial charge for atom with index idx

  * SetMMFFDielectricModel(dielModel = 1)

    sets the DielModel MMFF property (1: constant; 2: distance-dependent;
    defaults to constant)

  * SetMMFFDielectricConstant(dielConst = 1.0)

    Sets the DielConst MMFF property (defaults to 1.0)

  * SetMMFFBondTerm(state = True)

    Sets the bond term to be included in the MMFF equation (defaults
    to True)

  * SetMMFFAngleTerm(state = True)

    Sets the angle term to be included in the MMFF equation (defaults
    to True)

  * SetMMFFStretchBendTerm(state = True)

    Sets the stretch-bend term to be included in the MMFF equation (defaults
    to True)

  * SetMMFFOopTerm(state = True)

    Sets the out-of-plane bend term to be included in the MMFF equation
    (defaults to True)

  * SetMMFFTorsionTerm(state = True)

    Sets the torsional term to be included in the MMFF equation (defaults
    to True)

  * SetMMFFVdWTerm(state = True)

    Sets the Van der Waals term to be included in the MMFF equation
    (defaults to True)

  * SetMMFFEleTerm(state = True)

    Sets the electrostatic term to be included in the MMFF equation
    (defaults to True)

  * SetMMFFVariant(mmffVariant = "MMFF94")

    Sets the MMFF variant to be used ("MMFF94" or "MMFF94s"; defaults to
    "MMFF94")

  * SetMMFFVerbosity(verbosity = 0)

    Sets the MMFF verbosity (0: none; 1: low; 2: high; defaults to 0)

  Hence, most users will do something like this to optimize a molecule
  structure obtained from a SMILES string:

  from rdkit import Chem
  from rdkit.Chem import AllChem

  m = Chem.MolFromSmiles("O=C(C)c1cccnc1", False)
  AllChem.SanitizeMMFFMol(m)
  m2 = Chem.AddHs(m)
  AllChem.EmbedMolecule(m2)
  # Opt
  AllChem.MMFFOptimizeMolecule(m2)
  print >>file('structure_min.sdf','w'), Chem.MolToMolBlock(m2)

  Those willing to play a bit more with MMFF properties may do the
  following:

  from rdkit import Chem
  from rdkit.Chem import AllChem

  m = Chem.MolFromSmiles("O=C(C)c1cccnc1", False)
  AllChem.SanitizeMMFFMol(m)
  m2 = Chem.AddHs(m)
  AllChem.EmbedMolecule(m2)
  pyMP = AllChem.SetupMMFFForceField(m2)
  pyMP.SetMMFFVariant("MMFF94s")
  pyMP.SetMMFFDielectricModel(2)
  pyFF = AllChem.MMFFGetMoleculeForceField(m2, pyMP)
  pyFF.Minimize()
  print >>file('structure_min.sdf','w'), Chem.MolToMolBlock(m2)
  print 'Energy = {0:12.4f}'.format(pyFF.CalcEnergy())
  i = 0
  for i in range(0, m2.GetNumAtoms()):
    print '{0:4d} {1:4d} {2:8.4f} {3:8.4f}'.format(i + 1,
      int(pyMP.GetMMFFAtomType(i)),
      float(pyMP.GetMMFFFormalCharge(i)),
      float(pyMP.GetMMFFPartialCharge(i)))

- OOP backport to UFF. I added the inversion term to the UFF
  implementation following the original UFF paper by Rappe'. I have already
  modified the figures in a couple of test files to reflect the new energy
  values.

- 2-bit neighbor matrix and graph-based angle enumeration now reflect
  the MMFF implementation.
Merge pull request #99 from ptosco/ptosco-MMFF

MMFF & UFF update