openforcefield / openff-toolkit

The Open Forcefield Toolkit provides implementations of the SMIRNOFF format, parameterization engine, and other tools. Documentation available at http://open-forcefield-toolkit.readthedocs.io
http://openforcefield.org
MIT License
316 stars 92 forks source link

Niche openeye edge case causing errors in OpenEye generate_conformers #1615

Closed hmacdope closed 1 year ago

hmacdope commented 1 year ago

Describe the bug

If you try and manipulate the OpenEye logging stream inside a function and then call OEOmega with HydrogenSampling=True you will get a segfault. This can be an issue if you are using the OpenEyeToolkitWrapper.generate_conformers method after manipulating Ostreams

I sent a report to OpenEye so will likely hear back soon.

To Reproduce

from openeye import oechem
from openeye import oeomega

from openff.toolkit.topology import Molecule
from openff.toolkit.utils.openeye_wrapper import  OpenEyeToolkitWrapper

def set_out():
    errfs = oechem.oeofstream("openeye_log.txt")
    if not errfs:
        oechem.OEThrow.Fatal("Unable to create %s" % fname)
    oechem.OEThrow.SetOutputStream(errfs)
    oechem.OEThrow.SetLevel(oechem.OEErrorLevel_Debug)
    oechem.OEThrow.Info("Hello, world!")

def do_omega():
    mol = Molecule.from_smiles("c1ccccc1[C@H](C)Cl")
    tk = OpenEyeToolkitWrapper()
    tk.generate_conformers(mol)

if __name__ == "__main__":
    set_out()
    # setting output in function causes segfault when calling oeomega
    # 99 % sure its when trying to write the line  "Warning: Cannot perform Hydrogen sampling with GPU-Omega: GPU-Omega disabled"
    do_omega()

Output

GDB stack trace shown below

Screenshot from 2023-05-23 10-44-22

Computing environment (please complete the following information):

Additional context

apayne97 commented 1 year ago

Do you still get this error when you just directly use Omega instead of trying to use it through the openff toolkit?

hmacdope commented 1 year ago

I havn't tested, my contact with openeye indicated that one must return the output stream from the function on linux to have it work.

apayne97 commented 1 year ago

OH is it different on linux vs mac?

hmacdope commented 1 year ago

The comment I got back from the openeye people was that basically you need to keep the output stream in scope.

Do this instead.

def set_out():
    errfs = oechem.oeofstream("openeye_log.txt")
    if not errfs:
        oechem.OEThrow.Fatal("Unable to create %s" % fname)
    oechem.OEThrow.SetOutputStream(errfs)
    oechem.OEThrow.SetLevel(oechem.OEErrorLevel_Debug)
    oechem.OEThrow.Info("Hello, world!")
    return errfs

def do_omega(errfs):
    mol = Molecule.from_smiles("c1ccccc1[C@H](C)Cl")
    tk = OpenEyeToolkitWrapper()
    tk.generate_conformers(mol)

if __name__ == "__main__":
    errfs = set_out()
    do_omega(errfs)

But is a bit clunky.

apayne97 commented 1 year ago

can we just close the stream when we're done with a certain part? i.e. open and close within the run_docking_oe function, etc

hmacdope commented 1 year ago

Yeah seems like it should be possible!

hmacdope commented 1 year ago

Following up @apayne97 if you use:

erfs.flush()
erfs.close()

OR

keep the log buffer in scope by returning it.

everything seems to work OK.

I will close here for now. Anyone feel free to reopen if this re-occurs for some reason.