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
309 stars 90 forks source link

Error attempting to load Sage forcefield #1699

Closed spencercguo closed 1 year ago

spencercguo commented 1 year ago

Describe the bug When I try to load an OpenFF forcefield using the toolkit and Smirnoff, I get a strange error regarding a "missing unary operator".

To Reproduce

from openff.toolkit import ForceField                                                                                                                                                                          
forcefield = ForceField('openff-2.1.0.offxml')

Output

---------------------------------------------------------------------------                                                                                                                                            
DefinitionSyntaxError                     Traceback (most recent call last)                                                                                                                                            
Input In [6], in <cell line: 2>()                                                                                                                                                                                      
      1 from openff.toolkit import ForceField                                                                                                                                                                          
----> 2 forcefield = ForceField('openff-2.1.0.offxml')                                                                                                                                                                 

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/typing/engines/smirnoff/forcefield.py:307, in ForceField.__init__(self, aromaticity_model, parameter_handler_classes, para
meter_io_handler_classes, disable_version_check, allow_cosmetic_attributes, load_plugins, *sources)                                                                                                                    
    304 self._register_parameter_io_handler_classes(parameter_io_handler_classes)                                                                                                                                      
    306 # Parse all sources containing SMIRNOFF parameter definitions                                                                                                                                                  
--> 307 self.parse_sources(sources, allow_cosmetic_attributes=allow_cosmetic_attributes)                                                                                                                               

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/typing/engines/smirnoff/forcefield.py:768, in ForceField.parse_sources(self, sources, allow_cosmetic_attributes)          
    766 for source in sources:                                                                                                                                                                                         
    767     smirnoff_data = self.parse_smirnoff_from_source(source)                                                                                                                                                    
--> 768     self._load_smirnoff_data(                                                                                                                                                                                  
    769         smirnoff_data, allow_cosmetic_attributes=allow_cosmetic_attributes                                                                                                                                     
    770     )                                                                                                                                                                                                          

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/typing/engines/smirnoff/forcefield.py:876, in ForceField._load_smirnoff_data(self, smirnoff_data, allow_cosmetic_attribute
s)                                                                                                                                                                                                                     
    873     self._add_date(smirnoff_data["SMIRNOFF"]["Date"])                                                                                                                                                          
    875 # Go through the whole SMIRNOFF data structure, trying to convert all strings to Quantity                                                                                                                      
--> 876 smirnoff_data = convert_all_strings_to_quantity(smirnoff_data)                                                                                                                                                 
    878 # Go through the subsections, delegating each to the proper ParameterHandler                                                                                                                                   
    879                                                                                                                                                                                                                
    880 # Define keys which are expected from the spec, but are not parameter sections                                                                                                                                 
    881 l1_spec_keys = ["Author", "Date", "version", "aromaticity_model"]                                                                                                                                              

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:233, in convert_all_strings_to_quantity(smirnoff_data)                                                     
    231 if isinstance(smirnoff_data, dict):                                                                                                                                                                            
    232     for key, value in smirnoff_data.items():                                                                                                                                                                   
--> 233         smirnoff_data[key] = convert_all_strings_to_quantity(value)                                                                                                                                            
    234     obj_to_return = smirnoff_data                                                                                                                                                                              
    236 elif isinstance(smirnoff_data, list):                                                                                                                                                                          

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:233, in convert_all_strings_to_quantity(smirnoff_data)                                                     
    231 if isinstance(smirnoff_data, dict):                                                                                                                                                                            
    232     for key, value in smirnoff_data.items():                                                                                                                                                                   
--> 233         smirnoff_data[key] = convert_all_strings_to_quantity(value)                                                                                                                                            
    234     obj_to_return = smirnoff_data                                                                                                                                                                              
    236 elif isinstance(smirnoff_data, list):                                                                                                                                                                          

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:233, in convert_all_strings_to_quantity(smirnoff_data)                                                     
    231 if isinstance(smirnoff_data, dict):                                                                         
    232     for key, value in smirnoff_data.items():                                                                                                                                                         [50/47471]
--> 233         smirnoff_data[key] = convert_all_strings_to_quantity(value)                                                                                                                                            
    234     obj_to_return = smirnoff_data                                                                                                                                                                              
    236 elif isinstance(smirnoff_data, list):                                                                                                                                                                          

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:233, in convert_all_strings_to_quantity(smirnoff_data)                                                     
    231 if isinstance(smirnoff_data, dict):                                                                                                                                                                            
    232     for key, value in smirnoff_data.items():
--> 233         smirnoff_data[key] = convert_all_strings_to_quantity(value)
    234     obj_to_return = smirnoff_data
    236 elif isinstance(smirnoff_data, list):

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:238, in convert_all_strings_to_quantity(smirnoff_data)
    236 elif isinstance(smirnoff_data, list):
    237     for index, item in enumerate(smirnoff_data):
--> 238         smirnoff_data[index] = convert_all_strings_to_quantity(item)
    239     obj_to_return = smirnoff_data
    241 elif isinstance(smirnoff_data, int) or isinstance(smirnoff_data, float):

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:233, in convert_all_strings_to_quantity(smirnoff_data)
    231 if isinstance(smirnoff_data, dict):
    232     for key, value in smirnoff_data.items():
--> 233         smirnoff_data[key] = convert_all_strings_to_quantity(value)
    234     obj_to_return = smirnoff_data
    236 elif isinstance(smirnoff_data, list):

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:246, in convert_all_strings_to_quantity(smirnoff_data)
    244 else:
    245     try:
--> 246         obj_to_return = object_to_quantity(smirnoff_data)
    247     except (AttributeError, TypeError, SyntaxError):
    248         obj_to_return = smirnoff_data

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/functools.py:888, in singledispatch.<locals>.wrapper(*args, **kw)
    884 if not args:
    885     raise TypeError(f'{funcname} requires at least '
    886                     '1 positional argument')
--> 888 return dispatch(args[0].__class__)(*args, **kw)

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:318, in _(obj)
    315 import pint
    317 try:
--> 318     return string_to_quantity(obj)
    319 except pint.errors.UndefinedUnitError:
    320     raise ValueError

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/openff/toolkit/utils/utils.py:200, in string_to_quantity(quantity_string)
    197 from pint import UndefinedUnitError
    199 try:
--> 200     quantity = unit.Quantity(quantity_string)
    201 except (TokenError, UndefinedUnitError):
    202     return quantity_string

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/pint/facets/plain/quantity.py:209, in PlainQuantity.__new__(cls, value, units)
    207 if units is None and isinstance(value, str):
    208     ureg = SharedRegistryObject.__new__(cls)._REGISTRY
--> 209     inst = ureg.parse_expression(value)
    210     return cls.__new__(cls, inst)
    212 if units is None and isinstance(value, cls):

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/pint/facets/plain/registry.py:1255, in PlainRegistry.parse_expression(self, input_string, case_sensitive, use_decimal, **values)
   1252 input_string = string_preprocessor(input_string)
   1253 gen = tokenizer(input_string)
-> 1255 return build_eval_tree(gen).evaluate(
   1256     lambda x: self._eval_token(x, case_sensitive=case_sensitive, **values)
   1257 )

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/pint/pint_eval.py:114, in EvalTreeNode.evaluate(self, define_op, bin_op, un_op)
    112     if op_text not in bin_op:
    113         raise DefinitionSyntaxError('missing binary operator "%s"' % op_text)
--> 114     left = self.left.evaluate(define_op, bin_op, un_op)
    115     return bin_op[op_text](left, self.right.evaluate(define_op, bin_op, un_op))
    116 elif self.operator:
    117     # unary operator

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/pint/pint_eval.py:114, in EvalTreeNode.evaluate(self, define_op, bin_op, un_op)
    112     if op_text not in bin_op:
    113         raise DefinitionSyntaxError('missing binary operator "%s"' % op_text)
--> 114     left = self.left.evaluate(define_op, bin_op, un_op)
    115     return bin_op[op_text](left, self.right.evaluate(define_op, bin_op, un_op))
    116 elif self.operator:
    117     # unary operator

    [... skipping similar frames: EvalTreeNode.evaluate at line 114 (4 times)]

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/pint/pint_eval.py:114, in EvalTreeNode.evaluate(self, define_op, bin_op, un_op)
    112     if op_text not in bin_op:
    113         raise DefinitionSyntaxError('missing binary operator "%s"' % op_text)
--> 114     left = self.left.evaluate(define_op, bin_op, un_op)
    115     return bin_op[op_text](left, self.right.evaluate(define_op, bin_op, un_op))
    116 elif self.operator:
    117     # unary operator

File /beagle3/dinner/scguo/miniconda3/envs/openmm/lib/python3.9/site-packages/pint/pint_eval.py:120, in EvalTreeNode.evaluate(self, define_op, bin_op, un_op)
    118     op_text = self.operator[1]
    119     if op_text not in un_op:
--> 120         raise DefinitionSyntaxError('missing unary operator "%s"' % op_text)
    121     return un_op[op_text](self.left.evaluate(define_op, bin_op, un_op))
    122 else:
    123     # single value

DefinitionSyntaxError: missing unary operator "*"

Computing environment (please complete the following information): OS: Linux Python version: 3.9.15 These are the versions of OpenFF tools I have installed Conda environment: running conda list | grep openff yields

openff-amber-ff-ports     0.0.3              pyh6c4a22f_0    conda-forge
openff-forcefields        2023.08.0          pyh1a96a4e_0    conda-forge
openff-interchange        0.2.3              pyhd8ed1ab_1    conda-forge
openff-interchange-base   0.2.3              pyhd8ed1ab_1    conda-forge
openff-toolkit            0.11.2             pyhd8ed1ab_1    conda-forge
openff-toolkit-base       0.11.2             pyhd8ed1ab_1    conda-forge
openff-units              0.2.0              pyh1a96a4e_0    conda-forge
openff-utilities          0.1.8              pyh1a96a4e_0    conda-forge
mattwthompson commented 1 year ago

How did you create the environment and install the toolkit? I can't reproduce this in a fresh environment (mamba create -n tmp openff-toolkit -c conda-forge). The quickest solution is probably to create a new environment.

spencercguo commented 1 year ago

The environment I installed was with OpenMM 7.7 so perhaps that might have been the issue. I was able to install openff-toolkit and load the Forcefield correctly with a fresh mamba installation.

mattwthompson commented 1 year ago

Great!

The issue was probably Pint - the toolkit should work with OpenMM 7.7 - but as long as fresh environment works, I'm not eager to dig deeper into it.