| """Tests for analysis/code/applications.py (the no-plotting analysis module). |
| |
| Builds a tiny synthetic applications.hdf5 + spreadsheet so the correction math can be checked |
| in CI without the multi-hundred-megabyte release files. |
| """ |
| import os |
| import sys |
|
|
| import numpy as np |
| import pandas as pd |
| import h5py |
| import pytest |
|
|
| HERE = os.path.dirname(os.path.abspath(__file__)) |
| sys.path.insert(0, os.path.join(HERE, "..", "..", "data", "applications")) |
| sys.path.insert(0, HERE) |
| import paths |
|
|
| from applications_reader import Applications, SHELL_SIZES, SOLVENTS |
| import applications as A |
|
|
| SCALE = 1e4 |
| MISS = np.int32(-2147483648) |
|
|
|
|
| def test_distribution_shift_by_solvent_table_averages_per_solvent(): |
| """distribution_shift_by_solvent_table averages the three coefficient-choice RMSEs per solvent, |
| and surfaces the water column as the biggest extrapolation gap (the S15 story).""" |
| remapped = A.FORMULA_REMAP["stationary_plus_qcd + openMM"] |
| per_solute = {"H": pd.DataFrame([ |
| {"formula": remapped, "solvent": "chloroform", "solute": "a", "rmse": 0.10}, |
| {"formula": remapped, "solvent": "chloroform", "solute": "b", "rmse": 0.20}, |
| {"formula": remapped, "solvent": "TIP4P", "solute": "a", "rmse": 0.30}, |
| {"formula": remapped, "solvent": "TIP4P", "solute": "b", "rmse": 0.50}, |
| ])} |
| per_solvent = {"H": pd.DataFrame([ |
| {"formula": remapped, "solvent": "chloroform", "rmse": 0.16}, |
| {"formula": remapped, "solvent": "TIP4P", "rmse": 0.45}, |
| ])} |
| bootstrap = pd.DataFrame([ |
| {"nucleus": "H", "formula": remapped, "solvent": "chloroform", "solute": "a", "seed": 0, "Bootstrap_RMSE": 0.14}, |
| {"nucleus": "H", "formula": remapped, "solvent": "chloroform", "solute": "b", "seed": 0, "Bootstrap_RMSE": 0.18}, |
| {"nucleus": "H", "formula": remapped, "solvent": "TIP4P", "solute": "a", "seed": 0, "Bootstrap_RMSE": 0.60}, |
| {"nucleus": "H", "formula": remapped, "solvent": "TIP4P", "solute": "b", "seed": 0, "Bootstrap_RMSE": 0.80}, |
| ]) |
| table = A.distribution_shift_by_solvent_table(per_solute, per_solvent, bootstrap, "H", |
| "stationary_plus_qcd + openMM") |
| assert list(table.index) == ["TIP4P", "chloroform"] |
| assert list(table.columns) == ["Extrapolated from delta22", "Scaled to Test Set", "Scaled to Solute"] |
| assert table.loc["chloroform", "Scaled to Solute"] == pytest.approx(0.15) |
| assert table.loc["chloroform", "Scaled to Test Set"] == pytest.approx(0.16) |
| assert table.loc["chloroform", "Extrapolated from delta22"] == pytest.approx(0.16) |
| assert table.loc["TIP4P", "Scaled to Solute"] == pytest.approx(0.40) |
| assert table.loc["TIP4P", "Extrapolated from delta22"] == pytest.approx(0.70) |
| chl_gap = table.loc["chloroform", "Extrapolated from delta22"] - table.loc["chloroform", "Scaled to Solute"] |
| water_gap = table.loc["TIP4P", "Extrapolated from delta22"] - table.loc["TIP4P", "Scaled to Solute"] |
| assert water_gap > chl_gap |
|
|
|
|
| def _enc(a): |
| a = np.asarray(a, dtype=np.float64) |
| nan = np.isnan(a) |
| out = np.round(np.where(nan, 0.0, a) * SCALE).astype(np.int32) |
| out[nan] = MISS |
| return out |
|
|
|
|
| @pytest.fixture |
| def loader(tmp_path): |
| """One solute (vomicine), 3 atoms, one H site over atoms 1+2, one C site over atom 3. |
| magnet_x is set so the solvated-minus-isolated correction is a known constant per shell.""" |
| h5 = tmp_path / "applications.hdf5" |
| xlsx = tmp_path / "exp.xlsx" |
| with h5py.File(h5, "w") as f: |
| sg = f.create_group("solvents") |
| for sv in SOLVENTS: |
| sg.create_group(sv).create_dataset("atomic_numbers", data=np.array([6], np.int32)) |
| g = f.create_group("vomicine") |
| g.create_dataset("atomic_numbers", data=np.array([1, 1, 6], np.int32)) |
| mx = g.create_group("magnet_x") |
| for sv in SOLVENTS: |
| svg = mx.create_group(sv) |
| for k, shell in enumerate(SHELL_SIZES): |
| arr = np.zeros((4, 3, 2), dtype=np.float64) |
| arr[:, :, 0] = 10.0 |
| arr[:, :, 1] = 10.0 + 0.1 * (k + 1) |
| svg.create_dataset(f"shell_{shell}", data=_enc(arr)) |
| svg.create_dataset("stationary", data=_enc(np.full(3, 10.0))) |
| mz = g.create_group("magnet_zero") |
| mz.create_dataset("stationary", data=_enc(np.array([100.0, 101.0, 50.0]))) |
| mz.create_dataset("pcm_correction", data=_enc(np.array([-1.0, -1.0, -2.0]))) |
| q = g.create_group("qcd") |
| q.create_dataset("stationary", data=_enc(np.zeros((3, 4)))) |
| q.create_dataset("trajectories", data=_enc(np.zeros((2, 3, 3, 4)))) |
| cm = f.create_group("composite_model") |
| cmc = cm.create_group("pcm_conversion_factors") |
| |
| rows = "solvent,pcm_conversion_factor\n" + "".join( |
| f"{s},1.0\n" for s in ["chloroform", "benzene", "methanol", "water"]) |
| cmc.create_dataset("H", data=rows) |
| cmc.create_dataset("C", data=rows) |
| with pd.ExcelWriter(xlsx) as w: |
| pd.DataFrame({ |
| "site": ["H", "1 C"], "nucleus": ["H", "C"], |
| "atom_numbers": ["1,2", "3"], |
| "chloroform": [1.0, 2.0], "benzene": [1.0, 2.0], |
| "methanol": [1.0, 2.0], "water": [1.0, 2.0], |
| }).to_excel(w, sheet_name="vomicine", index=False) |
| return Applications(h5, xlsx) |
|
|
|
|
| def test_shell_convergence_values(loader): |
| df = A.shell_convergence_corrections(loader, "vomicine", "H") |
| |
| assert df.index.get_level_values("solvent").nunique() == len(SOLVENTS) |
| assert df.index.get_level_values("site").unique().tolist() == ["01 H"] |
| |
| row = df.xs("chloroform", level="solvent").iloc[0] |
| for k, shell in enumerate(SHELL_SIZES): |
| assert row[f"shell_{shell}"] == pytest.approx(0.1 * (k + 1), abs=5e-5) |
|
|
|
|
| def test_only_requested_nucleus(loader): |
| df = A.shell_convergence_corrections(loader, "vomicine", "H") |
| |
| sites = df.index.get_level_values("site").unique().tolist() |
| assert all("C" not in s for s in sites) |
|
|
|
|
| def test_site_atom_indices(): |
| assert A.site_atom_indices("1,2") == [0, 1] |
| assert A.site_atom_indices("21") == [20] |
|
|
|
|
| def test_fit_recovers_known_line(): |
| |
| df = pd.DataFrame({"stationary": [1.0, 2.0, 3.0, 4.0], "experimental": [7.0, 9.0, 11.0, 13.0]}) |
| rmse, params = A.fit(df, "stationary") |
| assert rmse < 1e-9 |
| assert params["Intercept"] == pytest.approx(5.0, abs=1e-6) |
| assert params["stationary"] == pytest.approx(2.0, abs=1e-6) |
|
|
|
|
| def test_fit_ignores_rows_with_no_experimental_value(): |
| |
| |
| df = pd.DataFrame({ |
| "stationary": [1.0, 2.0, 3.0, 4.0], |
| "experimental": [7.0, 9.0, 11.0, np.nan], |
| }) |
| rmse, params = A.fit(df, "stationary") |
| assert rmse < 1e-9 |
| assert params["stationary"] == pytest.approx(2.0, abs=1e-6) |
|
|
|
|
| def test_fit_matches_statsmodels(): |
| |
| |
| rng = np.random.default_rng(7) |
| n = 60 |
| df = pd.DataFrame({ |
| "stationary": rng.normal(100, 20, n), "pcm": rng.normal(0, 2, n), |
| "qcd": rng.normal(0, 1, n), "openMM": rng.normal(0, 2, n), |
| }) |
| df["experimental"] = (2.0 * df["stationary"] + 0.5 * df["pcm"] - 0.3 * df["qcd"] |
| + 1.0 + rng.normal(0, 1, n)) |
| df.loc[[3, 17, 42], "experimental"] = np.nan |
| df.loc[[8, 25], "pcm"] = np.nan |
| for formula in ["stationary", "stationary + pcm", "stationary + pcm + qcd", |
| "stationary + pcm + qcd + openMM"]: |
| rmse, params = A.fit(df, formula) |
| s_rmse, s_params = A._fit_statsmodels(df, formula) |
| assert rmse == pytest.approx(s_rmse, abs=1e-8), formula |
| for name in s_params.index: |
| assert params[name] == pytest.approx(s_params[name], abs=1e-6), f"{formula}:{name}" |
|
|
|
|
| def test_build_query_df_nn(loader): |
| q = A.build_query_df_nn(loader) |
| expected = {"solute", "nucleus", "site", "solvent", "experimental", "stationary", "pcm", |
| "openMM", "openMM_vib", "qcd", "stationary_plus_pcm", "stationary_plus_qcd", |
| "stationary_plus_op_vib"} |
| assert expected.issubset(q.columns) |
| |
| |
| h = q[(q["nucleus"] == "H") & (q["solvent"] == "chloroform")].iloc[0] |
| assert h["stationary"] == pytest.approx(100.5, abs=1e-3) |
| assert h["stationary_plus_pcm"] == pytest.approx(99.5, abs=1e-3) |
| assert h["qcd"] == pytest.approx(0.0, abs=1e-3) |
|
|
|
|
| def test_apply_bootstrap_nan_handling(): |
| |
| coeffs = pd.DataFrame([{"solvent": "chloroform", "formula": "pcm2", "seed": 0, |
| "Intercept": 5.0, "stationary": 2.0, "openMM": np.nan}]) |
| data = pd.DataFrame([ |
| {"solute": "m", "nucleus": "H", "site": "a", "solvent": "chloroform", |
| "experimental": 7.0, "stationary": 1.0, "openMM": 9.0}, |
| {"solute": "m", "nucleus": "H", "site": "b", "solvent": "chloroform", |
| "experimental": np.nan, "stationary": np.nan, "openMM": 9.0}, |
| ]) |
| out = A.apply_bootstrap_params_to_full_dataset(data, coeffs, nucleus="H").set_index("site") |
| assert out.loc["a", "predicted"] == pytest.approx(7.0) |
| assert np.isnan(out.loc["b", "predicted"]) |
|
|
|
|
| def test_apply_bootstrap_and_solute_rmse(): |
| |
| coeffs = pd.DataFrame({"solvent": ["chloroform"], "formula": ["pcm2"], "seed": [0], |
| "Intercept": [5.0], "stationary": [2.0]}) |
| data = pd.DataFrame({ |
| "solute": ["m", "m"], "nucleus": ["H", "H"], "site": ["01 H", "02 H"], |
| "solvent": ["chloroform", "chloroform"], "experimental": [7.0, 9.0], "stationary": [1.0, 2.0], |
| }) |
| preds = A.apply_bootstrap_params_to_full_dataset(data, coeffs, nucleus="H") |
| assert np.allclose(preds["predicted"], preds["experimental"]) |
| rmses = A.compute_solute_rmses(preds) |
| assert rmses["Bootstrap_RMSE"].iloc[0] == pytest.approx(0.0, abs=1e-9) |
|
|
|
|
| |
|
|
| def _rmse_comparison_fixture(): |
| """Two test-set solutes ("m", "n"), one solvent, formula "stationary + openMM". Each solute has |
| only 2 points against 3 free parameters, so a per-solute-only fit is always exact (RMSE 0) -- |
| that part needs no special data. The 4 points are deliberately NOT co-planar in (stationary, |
| openMM, experimental) space (verified: an earlier version of this fixture picked co-planar |
| points by accident, which made the pooled "Scaled to Test Set" fit ALSO exact and silently |
| hid the "formula" column bug this fixture now catches -- see the FORMULA_REMAP note below), so |
| the pooled fit has nonzero RMSE and "Scaled to Test Set" != "Scaled to Solute". The bootstrap |
| coefficients are also chosen far from both fits, so all three columns differ.""" |
| query_df_nn = pd.DataFrame([ |
| {"solute": "m", "nucleus": "H", "site": "01", "solvent": "chloroform", "experimental": 10.0, "stationary": 5.0, "openMM": 1.0}, |
| {"solute": "m", "nucleus": "H", "site": "02", "solvent": "chloroform", "experimental": 12.0, "stationary": 6.0, "openMM": 1.0}, |
| {"solute": "n", "nucleus": "H", "site": "01", "solvent": "chloroform", "experimental": 20.0, "stationary": 5.0, "openMM": 2.0}, |
| {"solute": "n", "nucleus": "H", "site": "02", "solvent": "chloroform", "experimental": 23.0, "stationary": 7.0, "openMM": 2.0}, |
| ]) |
| formula = "stationary + openMM" |
| per_solute = {"H": A.fit_formulas_per_solvent_and_solute(query_df_nn, [formula], ["chloroform"], |
| ["m", "n"], A.FORMULA_REMAP)} |
| all_solute = {"H": A.fit_formulas_per_solvent(query_df_nn, [formula], ["chloroform"], A.FORMULA_REMAP)} |
| |
| |
| |
| |
| |
| remapped = A.FORMULA_REMAP[formula] |
| coeffs = pd.DataFrame({"solvent": ["chloroform"], "formula": [remapped], "seed": [0], |
| "Intercept": [0.0], "stationary": [1.0], "openMM": [1.0]}) |
| preds = A.apply_bootstrap_params_to_full_dataset(query_df_nn, coeffs, nucleus="H") |
| bootstrap_rmses = A.compute_solute_rmses(preds) |
| return query_df_nn, per_solute, all_solute, bootstrap_rmses, formula |
|
|
|
|
| def test_scaled_to_test_set_per_solute_rmse_applies_one_pooled_fit_per_solute(): |
| query_df_nn, _, all_solute, _, formula = _rmse_comparison_fixture() |
| out = A.scaled_to_test_set_per_solute_rmse(query_df_nn, all_solute, "H", "chloroform", formula) |
| assert set(out["solute"]) == {"m", "n"} |
| |
| assert out["Bootstrap_RMSE"].notna().all() |
|
|
|
|
| def test_fitting_rmse_comparison_table_has_all_three_columns_and_solutes(): |
| query_df_nn, per_solute, all_solute, bootstrap_rmses, formula = _rmse_comparison_fixture() |
| table = A.fitting_rmse_comparison_table(query_df_nn, per_solute, all_solute, bootstrap_rmses, |
| "H", "chloroform", formula) |
| assert set(table.columns) == {"Scaled to Solute", "Scaled to Test Set", "Extrapolated from delta22"} |
| assert set(table.index) == {"m", "n"} |
| assert table.notna().all().all() |
| |
| assert table["Scaled to Solute"].max() < 1e-8 |
| |
| |
| assert table["Scaled to Test Set"].max() > 1e-3 |
| |
| assert (table["Extrapolated from delta22"] - table["Scaled to Solute"]).abs().min() > 0.1 |
|
|
|
|
| @pytest.mark.skipif( |
| not os.path.exists(paths.dataset_file("applications", file=__file__)), |
| reason="real applications.hdf5 not present") |
| def test_fitting_rmse_comparison_table_reproduces_published_chloroform_values(): |
| """Every published "Fitting RMSE Comparisons (chloroform, H)" value (SI Figure S15), read |
| directly off the SI, reproduced from the released data. Cross-checks the delta-22-bootstrap |
| ("Extrapolated") column at a slightly looser tolerance since it averages over random seeds.""" |
| real_data_dir = os.path.join(HERE, "..", "..", "data", "applications") |
| loader = Applications(paths.dataset_file("applications", file=__file__), |
| os.path.join(real_data_dir, "applications_experimental.xlsx")) |
| query_df_nn = A.build_query_df_nn(loader) |
| seed = A.build_bootstrap_seed_coeffs(loader) |
| per_solute = A.per_solute_fits(query_df_nn) |
| all_solute = A.per_solvent_fits(query_df_nn) |
| preds_h = A.apply_bootstrap_params_to_full_dataset(query_df_nn, seed["H"], nucleus="H") |
| bootstrap_rmses_h = A.compute_solute_rmses(preds_h) |
| table = A.fitting_rmse_comparison_table(query_df_nn, per_solute, all_solute, bootstrap_rmses_h, |
| "H", "chloroform", "stationary_plus_qcd + openMM") |
| |
| published = { |
| ("isomer_1E", "Scaled to Solute"): 0.138, ("isomer_1E", "Scaled to Test Set"): 0.138, |
| ("vomicine", "Scaled to Solute"): 0.173, ("vomicine", "Scaled to Test Set"): 0.183, |
| ("prednisone", "Scaled to Solute"): 0.130, ("prednisone", "Scaled to Test Set"): 0.153, |
| ("flavone", "Scaled to Solute"): 0.021, ("flavone", "Scaled to Test Set"): 0.062, |
| } |
| for (solute, col), expected in published.items(): |
| assert table.loc[solute, col] == pytest.approx(expected, abs=3e-3), f"{solute}/{col}" |
| published_extrapolated = {"isomer_1E": 0.146, "vomicine": 0.180, "prednisone": 0.166, "flavone": 0.060} |
| for solute, expected in published_extrapolated.items(): |
| assert table.loc[solute, "Extrapolated from delta22"] == pytest.approx(expected, abs=0.02), solute |
|
|
|
|
| @pytest.mark.skipif( |
| not os.path.exists(paths.dataset_file("applications", file=__file__)), |
| reason="real applications.hdf5 not present") |
| def test_distribution_shift_by_solvent_table_flags_water_on_real_data(): |
| """The per-solvent distribution-shift check on real data: for protons, TIP4P (water) must show |
| the largest 'Extrapolated from delta22' minus 'Scaled to Solute' gap -- the exact claim the |
| function's docstring and SI Figure S15's narrative make (the peptide dominates the water column). |
| Also spot-checks two published per-solvent RMSE values.""" |
| real_data_dir = os.path.join(HERE, "..", "..", "data", "applications") |
| loader = Applications(paths.dataset_file("applications", file=__file__), |
| os.path.join(real_data_dir, "applications_experimental.xlsx")) |
| query_df_nn = A.build_query_df_nn(loader) |
| seed = A.build_bootstrap_seed_coeffs(loader) |
| per_solute = A.per_solute_fits(query_df_nn) |
| all_solute = A.per_solvent_fits(query_df_nn) |
| bootstrap_h = A.compute_solute_rmses( |
| A.apply_bootstrap_params_to_full_dataset(query_df_nn, seed["H"], nucleus="H")) |
| table = A.distribution_shift_by_solvent_table(per_solute, all_solute, bootstrap_h, "H", |
| "stationary_plus_qcd + openMM") |
| gap = table["Extrapolated from delta22"] - table["Scaled to Solute"] |
| assert gap.idxmax() == "TIP4P", f"expected water to have the largest extrapolation gap, got {gap.idxmax()}" |
| assert table.loc["TIP4P", "Extrapolated from delta22"] == pytest.approx(0.336, abs=0.01) |
| assert table.loc["chloroform", "Scaled to Solute"] == pytest.approx(0.107, abs=0.01) |
|
|
|
|
| |
|
|
| def _feature_space_fixture(): |
| """A test-set solute ("m") and a delta-22 solute, both nucleus H, in chloroform and benzene |
| (TIP4P/methanol deliberately absent from "m" to check the solvent filter drops rows cleanly). |
| stationary_plus_qcd/openMM are chosen so delta-22's chloroform plane is exact-fittable |
| (3 points, 3 free parameters -> zero residual).""" |
| query_df_nn = pd.DataFrame([ |
| {"solute": "m", "nucleus": "H", "solvent": "chloroform", "stationary_plus_qcd": 10.0, "openMM": 1.0, "experimental": 12.0}, |
| {"solute": "m", "nucleus": "H", "solvent": "benzene", "stationary_plus_qcd": 11.0, "openMM": 2.0, "experimental": 15.0}, |
| {"solute": "m", "nucleus": "C", "solvent": "chloroform", "stationary_plus_op_vib": 100.0, "openMM": 3.0, "experimental": 120.0}, |
| ]) |
| delta22_query_df_nn = pd.DataFrame([ |
| {"solute": "delta22", "nucleus": "H", "solvent": "chloroform", "stationary_plus_qcd": 12.0, "openMM": 0.0, "experimental": 12.0}, |
| {"solute": "delta22", "nucleus": "H", "solvent": "chloroform", "stationary_plus_qcd": 14.0, "openMM": 1.0, "experimental": 15.0}, |
| {"solute": "delta22", "nucleus": "H", "solvent": "chloroform", "stationary_plus_qcd": 16.0, "openMM": 2.0, "experimental": 18.0}, |
| {"solute": "delta22", "nucleus": "H", "solvent": "benzene", "stationary_plus_qcd": 9.0, "openMM": 1.5, "experimental": 13.0}, |
| ]) |
| return query_df_nn, delta22_query_df_nn |
|
|
|
|
| def test_feature_space_coverage_table_combines_and_centers_both_datasets(): |
| query_df_nn, delta22_query_df_nn = _feature_space_fixture() |
| out = A.feature_space_coverage_table(query_df_nn, delta22_query_df_nn, "H", solvents=("chloroform", "benzene")) |
| assert set(out["dataset"]) == {"Test Set", "Delta22"} |
| assert set(out["solvent"]) == {"chloroform", "benzene"} |
| |
| assert out["x"].mean() == pytest.approx(0.0, abs=1e-9) |
| assert out["y"].mean() == pytest.approx(0.0, abs=1e-9) |
|
|
|
|
| def test_feature_space_coverage_table_drops_solvents_test_set_lacks(): |
| query_df_nn, delta22_query_df_nn = _feature_space_fixture() |
| out = A.feature_space_coverage_table(query_df_nn, delta22_query_df_nn, "H", |
| solvents=("chloroform", "benzene", "methanol", "TIP4P")) |
| |
| assert set(out["solvent"]) == {"chloroform", "benzene"} |
|
|
|
|
| def test_delta22_plane_residuals_table_delta22_residuals_are_near_zero(): |
| |
| |
| |
| query_df_nn, delta22_query_df_nn = _feature_space_fixture() |
| out = A.delta22_plane_residuals_table(query_df_nn, delta22_query_df_nn, "H", solvents=("chloroform",)) |
| d22 = out[out["dataset"] == "Delta22"] |
| assert len(d22) == 3 |
| assert np.allclose(d22["residual"], 0.0, atol=1e-6) |
| |
| test_row = out[out["dataset"] == "Test Set"] |
| assert len(test_row) == 1 |
|
|
|
|
| def test_delta22_plane_residuals_table_skips_solvents_with_too_few_delta22_points(): |
| |
| query_df_nn, delta22_query_df_nn = _feature_space_fixture() |
| out = A.delta22_plane_residuals_table(query_df_nn, delta22_query_df_nn, "H", solvents=("chloroform", "benzene")) |
| assert set(out["solvent"]) == {"chloroform"} |
|
|
|
|
| @pytest.mark.skipif( |
| not os.path.exists(paths.dataset_file("applications", file=__file__)), |
| reason="real applications.hdf5 not present") |
| def test_feature_space_and_residuals_tables_sane_on_real_data(): |
| """Not an exact-number reproduction (these are scatter plots, not summary statistics) -- |
| structural sanity checks: delta-22's own residuals against its own fitted plane average to |
| (near) zero every solvent, and the known H/TIP4P data-scarcity caveat from the SI text ("the |
| available experimental data for water in the test set is limited to one solute") shows up as a |
| small test-set count for that one solvent.""" |
| real_data_dir = os.path.join(HERE, "..", "..", "data", "applications") |
| delta22_dir = os.path.join(HERE, "..", "..", "data", "delta22") |
| sys.path.insert(0, delta22_dir) |
| import delta22 as D |
| loader = Applications(paths.dataset_file("applications", file=__file__), |
| os.path.join(real_data_dir, "applications_experimental.xlsx")) |
| query_df_nn = A.build_query_df_nn(loader) |
| delta22_query_df_nn = D.add_composite_columns(D.load_query_df_nn( |
| paths.dataset_file("delta22", file=__file__), os.path.join(delta22_dir, "delta22_experimental.xlsx"), |
| verbose=False)) |
| for nucleus in ["H", "C"]: |
| residuals = A.delta22_plane_residuals_table(query_df_nn, delta22_query_df_nn, nucleus) |
| d22_means = residuals[residuals["dataset"] == "Delta22"].groupby("solvent")["residual"].mean() |
| assert (d22_means.abs() < 1e-6).all() |
| test_counts = residuals[residuals["dataset"] == "Test Set"].groupby("solvent").size() |
| assert test_counts["chloroform"] > 50 |
| |
| |
| |
| assert 0 < test_counts.get("TIP4P", 0) < test_counts["chloroform"] / 5 |
|
|