15 Commits

Author SHA1 Message Date
Greg Landrum
f4012abbcd Small cleanups of the MMFF94 code (#8593)
* progress, passes tests, needs more optimization

* passes tests

* minor

* cleanup
set diagonal elements of matrix

* replace numeric consts with enum

---------

Co-authored-by: ptosco <paolo.tosco@novartis.com>
2025-06-24 08:07:51 +02:00
Kevin Boyd
af6347963f Condense MMFF Contribs into single contrib per type. (#8175)
* Condense MMFF electrostatics and contrib instances.

Previously, a separate contrib had been added for each common term.
Each of these required a separate allocation, and a separate dynamic dispatch
on call. This change moves to an SOA style, making data access contiguous and
drastically reducing the number of calls.

* Make suggested copyright fixes and svn artifact removals
2025-01-29 06:18:09 +01:00
Greg Landrum
69b143edd0 Swap from RDUNUSED_PARAM to unnamed parameters (#4433)
* cleanup

* more cleanup
2021-08-24 17:19:46 -04:00
Brian Kelley
473db39c4f Fix/mmff threadsafety issues (#2518)
* Force thread safe initialization of default MMFF parameters

* Add a test that currently crashes for multithreaded initialization

* Don't optimize the same mol at the same time

* Remove extra copying

* Fix dereference

* Make all Collection Classes const compatible, remove old singletons

* Remove pre-thread intialization of MMFF params
2019-07-12 06:45:47 +02:00
Brian Kelley
373a89021e Change boost int types to std types (#2233) 2019-01-22 17:45:03 +01:00
Brian Kelley
7488840ac4 Fix/urange check (#1506)
* Fixes atom documentation

* Fixes #1461

This is a complicated one.  Basically URANGE_CHECK when
used on unsigned integers has a problem when the size of
the range it’s checking is 0.  The standard operations is
to check

URANGE(num, size-1)

Which (for unsigned integers) obviously rolls over.

This fixes all usage cases to be

URANGE(num+1, size)

And fixes the bugs found.  (addBond and the mmff tests)

* Fixes #1461 - Updates URANGE_CHECK to be 0<=x<hi
2017-09-11 21:17:33 +02:00
Greg Landrum
e08e0d16d8 first pass, using google style 2015-11-14 14:58:11 +01:00
Brian Kelley
fb84c9f0b7 Switches to URANGE_CHECK when appropriate 2015-10-18 21:14:02 -04:00
Brian Kelley
5f59333a56 Silences unused parameters 2015-10-18 14:02:29 -04:00
Greg Landrum
6c373ef11f - added C++ and Python helpers to retrieve force-field parameters
(i.e., equilibrium distances/angles and force constants) from
  UFF and MMFF in response to two requests recently appeared
  on the RDKit-discuss mailing list:
  http://sourceforge.net/p/rdkit/mailman/message/32953737/
  http://sourceforge.net/p/rdkit/mailman/message/32880156/
- did some clean up on the MMFF code
- NB there are two ABI changes:
  1) StretchBendContrib(ForceField *owner,
       const unsigned int idx1, const unsigned int idx2, const unsigned int idx3,
       const MMFFStbn *mmffStbnParams, const MMFFAngle *mmffAngleParams,
       const MMFFBond *mmffBondParams1, const MMFFBond *mmffBondParams2);
     previously was:
     StretchBendContrib(ForceField *owner,
       const unsigned int idx1, const unsigned int idx2, const unsigned int idx3,
       const std::pair<bool, const MMFFStbn *> mmffStbnParams,
       const MMFFAngle *mmffAngleParams, const MMFFBond *mmffBondParams1,
       const MMFFBond *mmffBondParams2);
  2) std::pair<double, double> calcStbnForceConstants(const MMFFStbn *mmffStbnParams);
     previously was:
     std::pair<double, double> calcStbnForceConstants
       (const std::pair<bool, const MMFFStbn *> mmffStbnParams);
  The two changes are NOT mandatory - however, both the StretchBendContrib constructor
  and calcStbnForceConstants(), though public, are basically "internal" method that
  most likely no-one has ever invoked. Given that the current API is MUCH better
  and cleaner, I would really advise for the new version.
2014-11-17 05:51:20 +01:00
ptosco
ba4a48ce05 - fixed a bug in Code/ForceField/MMFF/testMMFFForceField.cpp
- fixed a bug in Code/GraphMol/ForceFieldHelpers/MMFF/AtomTyper.cpp
  which caused misassignment of atom types in CYGUAN01 upon shuffling
  the order of atoms in the validation SDF files
- added checks for acos and asin function parameters to be within
  a (-1, 1) range
2014-06-01 16:23:03 +01:00
ptosco
5b70cdbdc1 - added relative DistanceConstraints (i.e., +/- with respect
to the current value) (C++/Python)
- added absolute/relative AngleConstraints (C++/Python)
- added absolute/relative TorsionConstraints (C++/Python)
- added PositionConstraints (C++/Python)
- exposed fixedPoints from Python
- added relevant C++/Python tests
- removed a number of redundant "this->" in member functions
- moved some getGrad() code into Utils::calcAngleBendGrad and
  Utils::calcTorsionGrad to avoid repeating the same code
  for constraints
2013-12-02 19:58:29 +01:00
Greg Landrum
a92b7bd3c4 fix a clang compiler warning 2013-11-06 04:50:24 +01:00
ptosco
b1acab59b0 - 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.
2013-09-16 12:08:02 +02:00
ptosco
3f4297fa44 Created a new MMFF branch. I moved some files/folders from
Code/ForceField and Code/GraphMol/ForceFieldHelpers to the
respective UFF subfolders since from now on UFF will not be
the only available force field anymore. I updated the
relevant CMakeLists.txt files accordingly.

Paolo
2013-08-18 09:11:29 +02:00