diff --git a/qcengine/programs/tests/test_mrchem.py b/qcengine/programs/tests/test_mrchem.py index e1caba7b..421b745d 100644 --- a/qcengine/programs/tests/test_mrchem.py +++ b/qcengine/programs/tests/test_mrchem.py @@ -18,8 +18,9 @@ def h2o(schema_versions): @pytest.fixture -def fh(): - return qcel.models.Molecule( +def fh(schema_versions): + models, _ = schema_versions + return models.Molecule( geometry=[[0.000000000000, 0.000000000000, -1.642850273986], [0.000000000000, 0.000000000000, 0.087149726014]], symbols=["H", "F"], fix_com=True, @@ -105,13 +106,15 @@ def test_dipole(h2o, schema_versions, request): @using("mrchem") -def test_gradient(fh): +def test_gradient(fh, schema_versions, request): + models, _ = schema_versions + mr_kws = { "world_prec": 1.0e-3, "world_size": 6, } - inp = qcel.models.AtomicInput( + inp = models.AtomicInput( molecule=fh, driver="gradient", model={ @@ -120,7 +123,9 @@ def test_gradient(fh): keywords=mr_kws, ) + inp = checkver_and_convert(inp, request.node.name, "pre") res = qcng.compute(inp, "mrchem", raise_error=True, return_dict=True) + res = checkver_and_convert(res, request.node.name, "post") # Make sure the calculation completed successfully assert compare_values( diff --git a/qcengine/programs/tests/test_sdftd3.py b/qcengine/programs/tests/test_sdftd3.py index e2a21142..24477355 100644 --- a/qcengine/programs/tests/test_sdftd3.py +++ b/qcengine/programs/tests/test_sdftd3.py @@ -10,23 +10,26 @@ import qcelemental as qcel import qcengine as qcng -from qcengine.testing import using +from qcengine.testing import checkver_and_convert, schema_versions, using @using("s-dftd3") -def test_dftd3_task_b97m_m01(): +def test_dftd3_task_b97m_m01(schema_versions, request): + models, _ = schema_versions thr = 1.0e-8 return_result = -0.05879001214961249 - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-01"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-01", return_dict=True)), model={"method": "b97m"}, driver="energy", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "s-dftd3") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") print(atomic_result.return_result) assert atomic_result.success @@ -45,28 +48,32 @@ def test_dftd3_task_b97m_m01(): ], ids=["d3bj", "d3zero", "d3mbj", "d3mzero", "d3op"], ) -def test_dftd3_task_pbe_m02(inp): +def test_dftd3_task_pbe_m02(inp, schema_versions, request): + models, _ = schema_versions # return to 1.0e-8 after https://github.com/MolSSI/QCEngine/issues/370 thr = 1.0e-7 return_result = inp["return_result"] - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-02"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-02", return_dict=True)), model={"method": "pbe"}, keywords={"level_hint": inp["level_hint"]}, driver="energy", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "s-dftd3") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(atomic_result.return_result, abs=thr) == return_result @using("s-dftd3") -def test_dftd3_task_tpss_m02(): +def test_dftd3_task_tpss_m02(schema_versions, request): + models, _ = schema_versions thr = 1.0e-8 @@ -91,8 +98,8 @@ def test_dftd3_task_tpss_m02(): ] ) - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-02"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-02", return_dict=True)), model={"method": ""}, keywords={ "level_hint": "d3mbj", @@ -105,14 +112,17 @@ def test_dftd3_task_tpss_m02(): driver="gradient", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "s-dftd3") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(atomic_result.return_result, abs=thr) == return_result @using("s-dftd3") -def test_dftd3_task_r2scan_m03(): +def test_dftd3_task_r2scan_m03(schema_versions, request): + models, _ = schema_versions thr = 1.0e-8 @@ -137,14 +147,16 @@ def test_dftd3_task_r2scan_m03(): ] ) - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-03"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-03", return_dict=True)), keywords={"level_hint": "d3bj"}, driver="gradient", model={"method": "r2scan"}, ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "s-dftd3") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(return_result, abs=thr) == atomic_result.return_result @@ -152,19 +164,22 @@ def test_dftd3_task_r2scan_m03(): @using("s-dftd3") -def test_dftd3_task_unknown_method(): +def test_dftd3_task_unknown_method(schema_versions, request): + models, models_out = schema_versions - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("water"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("water", return_dict=True)), keywords={"level_hint": "d3zero"}, model={"method": "non-existent-method"}, driver="energy", ) - error = qcel.models.ComputeError( + error = models_out.ComputeError( error_type="input error", error_message="No entry for 'non-existent-method' present" ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "s-dftd3") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post", vercheck=False, cast_dict_as="FailedOperation") print(atomic_result.error) assert not atomic_result.success @@ -172,9 +187,10 @@ def test_dftd3_task_unknown_method(): @using("s-dftd3") -def test_dftd3_task_cold_fusion(): +def test_dftd3_task_cold_fusion(schema_versions, request): + models, models_out = schema_versions - atomic_input = qcel.models.AtomicInput( + atomic_input = models.AtomicInput( molecule={ "symbols": ["Li", "Li", "Li", "Li"], "geometry": [ @@ -189,12 +205,14 @@ def test_dftd3_task_cold_fusion(): model={"method": "pbe"}, driver="energy", ) - error = qcel.models.ComputeError( + error = models_out.ComputeError( error_type="input error", error_message="Too close interatomic distances found", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "s-dftd3") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post", vercheck=False) print(atomic_result.error) assert not atomic_result.success diff --git a/qcengine/programs/tests/test_xtb.py b/qcengine/programs/tests/test_xtb.py index 7dbad30f..98bb07ee 100644 --- a/qcengine/programs/tests/test_xtb.py +++ b/qcengine/programs/tests/test_xtb.py @@ -254,7 +254,8 @@ def test_xtb_task_gfn2xtb_m01(schema_versions, request): @using("xtb") -def test_xtb_task_gfn2xtb_m02(): +def test_xtb_task_gfn2xtb_m02(schema_versions, request): + models, _ = schema_versions thr = 1.0e-8 @@ -279,8 +280,8 @@ def test_xtb_task_gfn2xtb_m02(): ] ) - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-02"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-02", return_dict=True)), model={"method": "GFN2-xTB"}, driver="gradient", keywords={ @@ -289,14 +290,17 @@ def test_xtb_task_gfn2xtb_m02(): }, ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(atomic_result.return_result, abs=thr) == return_result @using("xtb") -def test_xtb_task_gfn2xtb_m03(): +def test_xtb_task_gfn2xtb_m03(schema_versions, request): + models, _ = schema_versions thr = 1.0e-8 @@ -321,8 +325,8 @@ def test_xtb_task_gfn2xtb_m03(): ] ) - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-03"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-03",return_dict=True)), model={"method": "GFN2-xTB"}, driver="gradient", keywords={ @@ -330,14 +334,17 @@ def test_xtb_task_gfn2xtb_m03(): }, ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(atomic_result.return_result, abs=thr) == return_result @using("xtb") -def test_xtb_task_gfn2xtb_m04(): +def test_xtb_task_gfn2xtb_m04(schema_versions, request): + models, _ = schema_versions thr = 1.0e-6 @@ -365,13 +372,15 @@ def test_xtb_task_gfn2xtb_m04(): ), } - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-04"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-04", return_dict=True)), model={"method": "GFN2-xTB"}, driver="properties", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(atomic_result.return_result["dipole"], abs=thr) == return_result["dipole"] @@ -380,19 +389,22 @@ def test_xtb_task_gfn2xtb_m04(): @using("xtb") -def test_xtb_task_gfn2xtb_m05(): +def test_xtb_task_gfn2xtb_m05(schema_versions, request): + models, _ = schema_versions thr = 1.0e-8 return_result = -27.73598761779656 - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("mindless-05"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("mindless-05", return_dict=True)), model={"method": "GFN2-xTB"}, driver="energy", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post") assert atomic_result.success assert pytest.approx(atomic_result.return_result, abs=thr) == return_result @@ -400,43 +412,50 @@ def test_xtb_task_gfn2xtb_m05(): @using("xtb") -def test_xtb_task_unknown_method(): +def test_xtb_task_unknown_method(schema_versions, request): + models, models_out = schema_versions - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("water"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("water", return_dict=True)), model={"method": "GFN-xTB"}, driver="energy", ) - error = qcel.models.ComputeError(error_type="input_error", error_message="Invalid method GFN-xTB provided in model") + error = models_out.ComputeError(error_type="input_error", error_message="Invalid method GFN-xTB provided in model") + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post", vercheck=False) assert not atomic_result.success assert atomic_result.error == error @using("xtb") -def test_xtb_task_unsupported_driver(): +def test_xtb_task_unsupported_driver(schema_versions, request): + models, models_out = schema_versions - atomic_input = qcel.models.AtomicInput( - molecule=qcng.get_molecule("water"), + atomic_input = models.AtomicInput( + molecule=models.Molecule(**qcng.get_molecule("water", return_dict=True)), model={"method": "GFN2-xTB"}, driver="hessian", ) - error = qcel.models.ComputeError( + error = models_out.ComputeError( error_type="input_error", error_message="Calculation succeeded but invalid driver request provided" ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post", vercheck=False) assert not atomic_result.success assert atomic_result.error == error @using("xtb") -def test_xtb_task_cold_fusion(): +def test_xtb_task_cold_fusion(schema_versions, request): + models, models_out = schema_versions - atomic_input = qcel.models.AtomicInput( + atomic_input = models.AtomicInput( molecule={ "symbols": ["Li", "Li", "Li", "Li"], "geometry": [ @@ -450,12 +469,14 @@ def test_xtb_task_cold_fusion(): model={"method": "GFN2-xTB"}, driver="energy", ) - error = qcel.models.ComputeError( + error = models_out.ComputeError( error_type="runtime_error", error_message="Setup of molecular structure failed:\n-1- xtb_api_newMolecule: Could not generate molecular structure", ) + atomic_input = checkver_and_convert(atomic_input, request.node.name, "pre") atomic_result = qcng.compute(atomic_input, "xtb") + atomic_result = checkver_and_convert(atomic_result, request.node.name, "post", vercheck=False) assert not atomic_result.success assert atomic_result.error == error diff --git a/qcengine/testing.py b/qcengine/testing.py index 03035fa1..6fcfb277 100644 --- a/qcengine/testing.py +++ b/qcengine/testing.py @@ -227,7 +227,7 @@ def schema_versions(request): return qcel.models, qcel.models -def checkver_and_convert(mdl, tnm, prepost): +def checkver_and_convert(mdl, tnm, prepost, vercheck: bool = True, cast_dict_as=None): import json import pydantic @@ -237,14 +237,16 @@ def check_model_v1(m): assert isinstance( m, qcel.models.v1.basemodels.ProtoModel ), f"type({m.__class__.__name__}) = {type(m)} ⊄ v1.ProtoModel" - assert m.schema_version == 1, f"{m.__class__.__name__}.schema_version = {m.schema_version} != 1" + if vercheck: + assert m.schema_version == 1, f"{m.__class__.__name__}.schema_version = {m.schema_version} != 1" def check_model_v2(m): assert isinstance(m, pydantic.BaseModel), f"type({m.__class__.__name__}) = {type(m)} ⊄ BaseModel" assert isinstance( m, qcel.models.v2.basemodels.ProtoModel ), f"type({m.__class__.__name__}) = {type(m)} ⊄ v2.ProtoModel" - assert m.schema_version == 2, f"{m.__class__.__name__}.schema_version = {m.schema_version} != 2" + if vercheck: + assert m.schema_version == 2, f"{m.__class__.__name__}.schema_version = {m.schema_version} != 2" if prepost == "pre": dict_in = isinstance(mdl, dict) @@ -265,11 +267,17 @@ def check_model_v2(m): dict_in = isinstance(mdl, dict) if "as_v1" in tnm or "to_v1" in tnm or "None" in tnm: if dict_in: - mdl = qcel.models.v1.AtomicResult(**mdl) + if cast_dict_as: + mdl = getattr(qcel.models.v1, cast_dict_as)(**mdl) + else: + mdl = qcel.models.v1.AtomicResult(**mdl) check_model_v1(mdl) elif "as_v2" in tnm or "to_v2" in tnm: if dict_in: - mdl = qcel.models.v2.AtomicResult(**mdl) + if cast_dict_as: + mdl = getattr(qcel.models.v2, cast_dict_as)(**mdl) + else: + mdl = qcel.models.v2.AtomicResult(**mdl) mdl = mdl.convert_v(2) check_model_v2(mdl)