MolSSI / QCEngine

Quantum chemistry program executor and IO standardizer (QCSchema).
https://molssi.github.io/QCEngine/
BSD 3-Clause "New" or "Revised" License
162 stars 78 forks source link

openmm and pint 0.22 incompatible #416

Open loriab opened 11 months ago

loriab commented 11 months ago

Describe the bug

To Reproduce

3 test cases fail when pint=0.22. I noticed when solving the devtools/conda-envs/openmm.yaml w/o a python specified, so got py311. An error trace below.

qcengine/tests/test_procedures.py::test_geometric_generic[openmm-model5-bench5] FAILED                                                                                                                  [ 61%]
qcengine/tests/test_procedures.py::test_geometric_generic[openmm-model6-bench6] FAILED                                                                                                                  [ 65%]
qcengine/tests/test_procedures.py::test_geometric_generic[openmm-model7-bench7] FAILED                                                                                                                  [ 69%]
qcengine/tests/test_procedures.py::test_geometric_generic[qcore-model8-bench8] SKIPPED (Not detecting module qcore. Install package if necessary to enable tests.)                                      [ 73%]
qcengine/tests/test_procedures.py::test_nwchem_relax[0] SKIPPED (Not detecting module nwchem. Install package if necessary to enable tests.)                                                            [ 76%]
qcengine/tests/test_procedures.py::test_nwchem_relax[1] SKIPPED (Not detecting module nwchem. Install package if necessary to enable tests.)                                                            [ 80%]
qcengine/tests/test_procedures.py::test_nwchem_restart SKIPPED (Not detecting module nwchem. Install package if necessary to enable tests.)                                                             [ 84%]
qcengine/tests/test_procedures.py::test_torsiondrive_generic FAILED                                                                                                                                     [ 88%]
qcengine/tests/test_procedures.py::test_optimization_mrchem[geometric] SKIPPED (Not detecting module mrchem. Install package if necessary to enable tests.)                                             [ 92%]
qcengine/tests/test_procedures.py::test_optimization_mrchem[optking] SKIPPED (Not detecting module mrchem. Install package if necessary to enable tests.)                                               [ 96%]
qcengine/tests/test_procedures.py::test_optimization_mrchem[berny] SKIPPED (Not detecting module mrchem. Install package if necessary to enable tests.)                                                 [100%]

================================================================================================== FAILURES ===================================================================================================
________________________________________________________________________________ test_geometric_generic[openmm-model5-bench5] _________________________________________________________________________________

input_data = {'initial_molecule': Molecule(name='H2O', formula='H2O', hash='d91fd62'), 'input_specification': {'driver': 'gradient'...'basis': 'smirnoff', 'method': 'openff-1.0.0'}}, 'keywords': {'coordsys': 'tric', 'maxiter': 100, 'program': 'openmm'}}
program = 'openmm', model = {'basis': 'smirnoff', 'method': 'openff-1.0.0'}, bench = [1.8344994291796748, 3.010099477501204, 110.25177977849998]

    @using("geometric")
    @pytest.mark.parametrize(
        "program, model, bench",
        [
            pytest.param(
                "rdkit", {"method": "UFF"}, [1.87130923886072, 2.959448636243545, 104.5099642579023], marks=using("rdkit")
            ),
            pytest.param(
                "rdkit",
                {"method": "mmff94"},
                [1.8310842343589573, 2.884612338953529, 103.93822919865106],
                marks=using("rdkit"),
            ),
            pytest.param(
                "rdkit",
                {"method": "MMFF94s"},
                [1.8310842343589573, 2.884612338953529, 103.93822919865106],
                marks=using("rdkit"),
            ),
            pytest.param(
                "torchani",
                {"method": "ANI1x"},
                [1.82581873750194, 2.866376526793269, 103.4332610730292],
                marks=using("torchani"),
            ),
            pytest.param(
                "mopac",
                {"method": "PM6"},
                [1.793052302291527, 2.893333237502448, 107.57254391453196],
                marks=using("mopac"),
            ),
            pytest.param(
                "openmm",
                {"method": "openff-1.0.0", "basis": "smirnoff"},
                [1.8344994291796748, 3.010099477501204, 110.25177977849998],
                marks=using("openmm"),
            ),
            pytest.param(
                "openmm",
                {"method": "openff_unconstrained-1.0.0", "basis": "smirnoff"},
                [1.8344994291195869, 3.0100994772976124, 110.25259556886984],
                marks=using("openmm"),
            ),
            pytest.param(
                "openmm",
                {"method": "smirnoff99Frosst-1.1.0", "basis": "smirnoff"},
                [1.814137087600702, 3.025566213038376, 112.9999999990053],
                marks=using("openmm"),
            ),
            pytest.param(
                "qcore",
                {"method": "GFN1"},
                [1.8104763949897031, 2.9132449420655213, 107.13403040879244],
                marks=using("qcore"),
            ),
        ],
    )
    def test_geometric_generic(input_data, program, model, bench):

        input_data["initial_molecule"] = qcng.get_molecule("water")
        input_data["input_specification"]["model"] = model
        input_data["keywords"]["program"] = program
        input_data["input_specification"]["extras"] = {"_secret_tags": {"mysecret_tag": "data1"}}

>       ret = qcng.compute_procedure(input_data, "geometric", raise_error=True)

qcengine/tests/test_procedures.py:251: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
qcengine/compute.py:181: in compute_procedure
    return handle_output_metadata(output_data, metadata, raise_error=raise_error, return_dict=return_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

output_data = {'energies': [None], 'error': {'error_message': 'geomeTRIC run_json error:\nTraceback (most recent call last):\n  File...7012782744263]]) has attribute \'to_openmm\'\n\n', 'error_type': 'unknown'}, 'extras': {}, 'final_molecule': None, ...}
metadata = {'retries': 0, 'stderr': None, 'stdout': None, 'success': True, ...}, raise_error = True, return_dict = False

    def handle_output_metadata(
        output_data: Union[Dict[str, Any], "AtomicResult", "OptimizationResult", "FailedOperation"],
        metadata: Dict[str, Any],
        raise_error: bool = False,
        return_dict: bool = True,
    ) -> Union[Dict[str, Any], "AtomicResult", "OptimizationResult", "FailedOperation"]:
        """
        Fuses general metadata and output together.

        Parameters:
            output_data: The original output object to be fused with metadata
            metadata: Metadata produced by the compute_wrapper context manager
            raise_error: Raise an exception if errors exist (True) or return FailedOperation (False)
            return_dict: Return dictionary or object representation of data

        Returns
        -------
        result : AtomicResult, OptimizationResult, FailedOperation, or dict representation of any one.
            Output type depends on return_dict or a dict if an error was generated in model construction
        """

        if isinstance(output_data, dict):
            output_fusion = output_data  # Error handling
        else:
            output_fusion = output_data.dict()

        # Do not override if computer generates
        output_fusion["stdout"] = output_fusion.get("stdout", None) or metadata["stdout"]
        output_fusion["stderr"] = output_fusion.get("stderr", None) or metadata["stderr"]

        if metadata["success"] is not True:
            output_fusion["success"] = False
            output_fusion["error"] = {"error_type": metadata["error_type"], "error_message": metadata["error_message"]}

        # Raise an error if one exists and a user requested a raise
        if raise_error and (output_fusion["success"] is not True):
            msg = "stdout:\n{}".format(output_fusion["stdout"])
            msg += "\nstderr:\n{}".format(output_fusion["stderr"])
            LOGGER.info(msg)
>           raise ValueError(output_fusion["error"]["error_message"])
E           ValueError: geomeTRIC run_json error:
E           Traceback (most recent call last):
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/geometric/run_json.py", line 258, in geometric_run_json
E               geometric.optimize.Optimize(coords, M, IC, engine, dirname, params)
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/geometric/optimize.py", line 779, in Optimize
E               return optimizer.optimizeGeometry()
E                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/geometric/optimize.py", line 692, in optimizeGeometry
E               self.calcEnergyForce()
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/geometric/optimize.py", line 283, in calcEnergyForce
E               spcalc = self.engine.calc(self.X, self.dirname, read_data=(self.Iteration==0))
E                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/geometric/engine.py", line 1470, in calc
E               return self.calc_new(coords, dirname)
E                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/geometric/engine.py", line 1461, in calc_new
E               raise QCEngineAPIEngineError("QCEngineAPI computation did not execute correctly. Message: " + ret["error"]["error_message"])
E           geometric.errors.QCEngineAPIEngineError: QCEngineAPI computation did not execute correctly. Message: QCEngine Execution Error:
E           Traceback (most recent call last):
E             File "/psi/gits/QCEngine/qcengine/programs/openmm.py", line 301, in compute
E               context.setPositions(off_mol.conformers[0])
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/openmm/openmm.py", line 3479, in setPositions
E               return _openmm.Context_setPositions(self, positions)
E                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: in method Context_setPositions, argument 2 could not be converted to type std::vector< Vec3,std::allocator< Vec3 > > const &
E           
E           During handling of the above exception, another exception occurred:
E           
E           Traceback (most recent call last):
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/pint/facets/numpy/quantity.py", line 229, in __getattr__
E               return getattr(self._magnitude, item)
E                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AttributeError: 'numpy.ndarray' object has no attribute 'to_openmm'
E           
E           During handling of the above exception, another exception occurred:
E           
E           Traceback (most recent call last):
E             File "/psi/gits/QCEngine/qcengine/util.py", line 117, in compute_wrapper
E               yield metadata
E             File "/psi/gits/QCEngine/qcengine/compute.py", line 108, in compute
E               output_data = executor.compute(input_data, config)
E                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E             File "/psi/gits/QCEngine/qcengine/programs/openmm.py", line 303, in compute
E               context.setPositions(off_mol.conformers[0].to_openmm())
E                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E             File "/psi/toolchainconda/envs/openmm/lib/python3.11/site-packages/pint/facets/numpy/quantity.py", line 231, in __getattr__
E               raise AttributeError(
E           AttributeError: Neither Quantity object nor its magnitude ([[ 0.                  0.                 -0.068516245955287 ]
E            [ 0.                 -0.790689888799627   0.5437012782744263]
E            [ 0.                  0.790689888799627   0.5437012782744263]]) has attribute 'to_openmm'

qcengine/util.py:186: ValueError

Not sure who to ping. Maybe @dotsdl