Repository: openforcefield/openff-toolkit

Issue:
Bug: ElectrostaticsHandler's scale14 is not wired up correctly
**Describe the bug**
It's not clear that the [`ElectrostaticsHandler`'s `scale14` attribute](https://github.com/openforcefield/openforcefield/blob/master/openforcefield/typing/engines/smirnoff/parameters.py#L2409) plugs into anything. We should make sure that it reaches the System's `Exceptions` list. The code will probably look similar to that of [`vdWHandler`](https://github.com/openforcefield/openforcefield/blob/master/openforcefield/typing/engines/smirnoff/parameters.py#L2392-L2393)


Discussion:

Patch:
diff --git a/docs/releasehistory.rst b/docs/releasehistory.rst
index 0a5961b1..02c1bc7a 100644
--- a/docs/releasehistory.rst
+++ b/docs/releasehistory.rst
@@ -10,6 +10,13 @@ Releases follow the ``major.minor.micro`` scheme recommended by `PEP440 <https:/
 0.9.1 - Current development
 ---------------------------
 
+Behavior changed
+""""""""
+- `PR #802 <https://github.com/openforcefield/openforcefield/pull/802>`_: Fixes
+  `Issue #408 <https://github.com/openforcefield/openforcefield/issues/408>`_. The 1-4 scaling
+  factor for electrostatic interactions is now properly set by the value specified in the force
+  field. Previously it fell back to a default value of 0.83333. The toolkit may now produce
+  slightly different energies as a result of this change.
 
 0.9.0 - Namespace Migration
 ---------------------------
diff --git a/openff/toolkit/data/reference_energies/README.md b/openff/toolkit/data/reference_energies/README.md
index 40fba24f..ea76a2a7 100644
--- a/openff/toolkit/data/reference_energies/README.md
+++ b/openff/toolkit/data/reference_energies/README.md
@@ -1,2 +1,3 @@
 ## Manifest
 - `reference_0.8.0.json` - generated by `python /path/to/file.py` with conda environment reference_0.8.0.json.txt
+- `reference_after_802.json` - generated by `openff/toolkit/tests/test_energies.py` with conda environment reference_after_802.txt, corresponds to commit 02dba85c51dcff3ee3426d2a407811ac9bac1749 in PR #802, between 0.9.0 and 0.9.1
diff --git a/openff/toolkit/data/reference_energies/reference_after_802.json b/openff/toolkit/data/reference_energies/reference_after_802.json
new file mode 100644
index 00000000..a5e1b507
--- /dev/null
+++ b/openff/toolkit/data/reference_energies/reference_after_802.json
@@ -0,0 +1,1 @@
+{"ethanol.sdf_constrained": -10.218466677044418, "ethanol.sdf_unconstrained": -10.198561552956757, "methane_multiconformer.sdf_constrained": 2.0119485713874554, "methane_multiconformer.sdf_unconstrained": 2.0175533558944263, "CID20742535_anion.sdf_constrained": 276.1593524884936, "CID20742535_anion.sdf_unconstrained": 276.22885133679705}
\ No newline at end of file
diff --git a/openff/toolkit/data/reference_energies/reference_after_802.json.txt b/openff/toolkit/data/reference_energies/reference_after_802.json.txt
new file mode 100644
index 00000000..803e016a
--- /dev/null
+++ b/openff/toolkit/data/reference_energies/reference_after_802.json.txt
@@ -0,0 +1,291 @@
+# packages in environment at /Users/mwt/miniconda3/envs/openff-dev:
+#
+# Name                    Version                   Build  Channel
+abseil-cpp                20200923.3           h046ec9c_0    conda-forge
+amberlite                 16.0                     pypi_0    pypi
+ambertools                20.15                    pypi_0    pypi
+anyio                     2.0.2            py37hf985489_4    conda-forge
+apipkg                    1.5                        py_0    conda-forge
+appdirs                   1.4.4              pyh9f0ad1d_0    conda-forge
+appnope                   0.1.2            py37hf985489_1    conda-forge
+argon2-cffi               20.1.0           py37hf967b71_2    conda-forge
+arpack                    3.7.0                h918f95b_2    conda-forge
+arrow                     0.17.0           py37hf985489_1    conda-forge
+arrow-cpp                 3.0.0           py37hd5a70a8_1_cpu    conda-forge
+astor                     0.8.1              pyh9f0ad1d_0    conda-forge
+astunparse                1.6.3              pyhd8ed1ab_0    conda-forge
+async_generator           1.10                       py_0    conda-forge
+attrs                     20.3.0             pyhd3deb0d_0    conda-forge
+aws-c-cal                 0.4.5                ha1a74bd_4    conda-forge
+aws-c-common              0.4.65               h35c211d_0    conda-forge
+aws-c-event-stream        0.2.6                h142b3dd_1    conda-forge
+aws-c-io                  0.8.0                h3654196_0    conda-forge
+aws-checksums             0.1.10               h3654196_2    conda-forge
+aws-sdk-cpp               1.8.130              h0bc5ae4_1    conda-forge
+babel                     2.9.0              pyhd3deb0d_0    conda-forge
+backcall                  0.2.0              pyh9f0ad1d_0    conda-forge
+backports                 1.0                        py_2    conda-forge
+backports.functools_lru_cache 1.6.1                      py_0    conda-forge
+binaryornot               0.4.4                      py_1    conda-forge
+black                     20.8b1                     py_1    conda-forge
+bleach                    3.2.3              pyh44b312d_0    conda-forge
+blosc                     1.21.0               h046ec9c_0    conda-forge
+boost                     1.74.0           py37h9bf10a3_3    conda-forge
+boost-cpp                 1.74.0               h43a636a_2    conda-forge
+brotli                    1.0.9                h046ec9c_4    conda-forge
+brotlipy                  0.7.0           py37hf967b71_1001    conda-forge
+bson                      0.5.9                      py_0    conda-forge
+bzip2                     1.0.8                hc929b4f_4    conda-forge
+c-ares                    1.17.1               hc929b4f_0    conda-forge
+ca-certificates           2021.1.19            hecd8cb5_0    defaults
+cached-property           1.5.2                      py_0    defaults
+cairo                     1.16.0            h4ec454a_1007    conda-forge
+certifi                   2020.12.5        py37hecd8cb5_0    defaults
+cffi                      1.14.4           py37hc5b2277_1    conda-forge
+cfgv                      3.2.0                      py_0    conda-forge
+chardet                   4.0.0            py37hf985489_1    conda-forge
+click                     7.1.2              pyh9f0ad1d_0    conda-forge
+codecov                   2.1.11             pyhd3deb0d_0    conda-forge
+conda                     4.9.2            py37hf985489_0    conda-forge
+conda-package-handling    1.7.2            py37h395d20d_0    conda-forge
+conda-tree                0.1.0                      py_0    conda-forge
+cookiecutter              1.7.2              pyh9f0ad1d_0    conda-forge
+coverage                  5.4              py37hf967b71_0    conda-forge
+cryptography              3.3.1            py37haf76d9e_1    conda-forge
+curl                      7.71.1               hb0a8c7a_1    defaults
+cycler                    0.10.0                     py_2    conda-forge
+cython                    0.29.21          py37h54c7649_2    conda-forge
+dataclasses               0.7                      py37_0    conda-forge
+decopatch                 1.4.8              pyhd8ed1ab_0    conda-forge
+decorator                 4.4.2                      py_0    conda-forge
+defusedxml                0.6.0                      py_0    conda-forge
+distlib                   0.3.1              pyh9f0ad1d_0    conda-forge
+editdistance              0.5.3            py37h54c7649_3    conda-forge
+entrypoints               0.3             py37hc8dfbb8_1002    conda-forge
+execnet                   1.8.0              pyh44b312d_0    conda-forge
+fftw                      3.3.9           nompi_hc41c0bf_100    conda-forge
+filelock                  3.0.12             pyh9f0ad1d_0    conda-forge
+flake8                    3.8.4                      py_0    conda-forge
+fontconfig                2.13.1            hd23ceaa_1004    conda-forge
+freetype                  2.10.4               h4cff582_1    conda-forge
+gettext                   0.19.8.1          h7937167_1005    conda-forge
+gflags                    2.2.2             hb1e8313_1004    conda-forge
+glog                      0.4.0                hb7f4fc5_3    conda-forge
+grpc-cpp                  1.35.0               h330f241_0    conda-forge
+h5py                      3.1.0           nompi_py37hcd7841c_100    conda-forge
+hdf4                      4.2.13            h71d84a9_1004    conda-forge
+hdf5                      1.10.6          nompi_hc5d9132_1114    conda-forge
+icu                       68.1                 h74dc148_0    conda-forge
+identify                  1.5.13             pyh44b312d_0    conda-forge
+idna                      2.10               pyh9f0ad1d_0    conda-forge
+importlib-metadata        3.4.0            py37hf985489_0    conda-forge
+importlib_metadata        3.4.0                hd8ed1ab_0    conda-forge
+importlib_resources       5.1.0            py37hf985489_0    conda-forge
+iniconfig                 1.1.1              pyh9f0ad1d_0    conda-forge
+ipdb                      0.13.4             pyhd3deb0d_0    conda-forge
+ipykernel                 5.4.2            py37he01cfaa_0    conda-forge
+ipython                   7.19.0           py37he01cfaa_2    conda-forge
+ipython_genutils          0.2.0                      py_1    conda-forge
+ipywidgets                7.6.3              pyhd3deb0d_0    conda-forge
+isort                     5.7.0              pyhd8ed1ab_0    conda-forge
+jedi                      0.17.2           py37hf985489_1    conda-forge
+jinja2                    2.11.3             pyh44b312d_0    conda-forge
+jinja2-time               0.2.0                      py_2    conda-forge
+jpeg                      9d                   hbcb3906_0    conda-forge
+json5                     0.9.5              pyh9f0ad1d_0    conda-forge
+jsonschema                3.2.0            py37hc8dfbb8_1    conda-forge
+jupyter_client            6.1.11             pyhd8ed1ab_1    conda-forge
+jupyter_core              4.7.1            py37hf985489_0    conda-forge
+jupyter_server            1.2.3            py37hf985489_1    conda-forge
+jupyterlab                3.0.6              pyhd8ed1ab_0    conda-forge
+jupyterlab_pygments       0.1.2              pyh9f0ad1d_0    conda-forge
+jupyterlab_server         2.1.3              pyhd8ed1ab_0    conda-forge
+jupyterlab_widgets        1.0.0              pyhd8ed1ab_1    conda-forge
+kiwisolver                1.3.1            py37h70f7d40_1    conda-forge
+krb5                      1.18.2               h75d18d8_0    defaults
+lcms2                     2.11                 hdc706ca_1    conda-forge
+libarchive                3.5.1                h0a5793d_1    conda-forge
+libblas                   3.9.0                7_openblas    conda-forge
+libcblas                  3.9.0                7_openblas    conda-forge
+libcurl                   7.71.1               h8a08a2b_1    defaults
+libcxx                    11.0.1               habf9029_0    conda-forge
+libedit                   3.1.20191231         hed1e85f_2    conda-forge
+libev                     4.33                 haf1e3a3_1    conda-forge
+libevent                  2.1.10               hddc9c9b_3    conda-forge
+libffi                    3.3                  h046ec9c_2    conda-forge
+libgfortran               5.0.0           9_3_0_h6c81a4c_17    conda-forge
+libgfortran4              7.5.0               h1a10cd1_15    conda-forge
+libgfortran5              9.3.0               h6c81a4c_17    conda-forge
+libglib                   2.66.4               ha480d04_2    conda-forge
+libiconv                  1.16                 haf1e3a3_0    conda-forge
+liblapack                 3.9.0                7_openblas    conda-forge
+libnetcdf                 4.7.4           nompi_h9d8a93f_107    conda-forge
+libnghttp2                1.41.0               h7580e61_2    conda-forge
+libopenblas               0.3.12          openmp_h54245bb_1    conda-forge
+libpng                    1.6.37               hb0a8c7a_2    conda-forge
+libprotobuf               3.14.0               hfd3ada9_0    conda-forge
+libsodium                 1.0.18               hbcb3906_1    conda-forge
+libsolv                   0.7.17               hfd3ada9_0    conda-forge
+libssh2                   1.9.0                h39bdce6_5    conda-forge
+libthrift                 0.13.0               h8459986_6    conda-forge
+libtiff                   4.2.0                h355d032_0    conda-forge
+libutf8proc               2.6.1                h35c211d_0    conda-forge
+libwebp-base              1.2.0                hbcf498f_0    conda-forge
+libxcb                    1.13              h35c211d_1003    conda-forge
+libxml2                   2.9.10               h802ca4f_3    conda-forge
+libxslt                   1.1.33               h5739fc3_2    conda-forge
+llvm-openmp               11.0.1               h7c73e74_0    conda-forge
+lxml                      4.6.2            py37he94f95d_1    conda-forge
+lz4-c                     1.9.3                h046ec9c_0    conda-forge
+lzo                       2.10              haf1e3a3_1000    conda-forge
+makefun                   1.9.5              pyhd8ed1ab_0    conda-forge
+mamba                     0.7.10           py37h85ac496_0    conda-forge
+markupsafe                1.1.1            py37hf967b71_3    conda-forge
+matplotlib-base           3.3.4            py37haa7e288_0    conda-forge
+mccabe                    0.6.1                      py_1    conda-forge
+mdtraj                    1.9.5            py37h22c4154_0    conda-forge
+mistune                   0.8.4           py37hf967b71_1003    conda-forge
+mmpbsa-py                 16.0                     pypi_0    pypi
+mock                      4.0.3            py37hf985489_1    conda-forge
+more-itertools            8.6.0              pyhd8ed1ab_0    conda-forge
+msgpack-python            1.0.2            py37h70f7d40_1    conda-forge
+mypy                      0.800              pyhd8ed1ab_0    conda-forge
+mypy_extensions           0.4.3            py37hf985489_3    conda-forge
+nbclassic                 0.2.6              pyhd8ed1ab_0    conda-forge
+nbclient                  0.5.1                      py_0    conda-forge
+nbconvert                 6.0.7            py37hf985489_3    conda-forge
+nbformat                  5.1.2              pyhd8ed1ab_1    conda-forge
+nbval                     0.9.6              pyh9f0ad1d_0    conda-forge
+ncurses                   6.2                  h2e338ed_4    conda-forge
+nest-asyncio              1.4.3              pyhd8ed1ab_0    conda-forge
+netcdf-fortran            4.5.3           nompi_h282ae0b_101    conda-forge
+networkx                  2.5                        py_0    conda-forge
+nglview                   2.7.7              pyh5ca1d4c_1    conda-forge
+nodeenv                   1.5.0              pyh9f0ad1d_0    conda-forge
+notebook                  6.2.0            py37hf985489_0    conda-forge
+numexpr                   2.7.2            py37h010c265_0    conda-forge
+numpy                     1.20.0           py37ha9839cc_0    conda-forge
+olefile                   0.46               pyh9f0ad1d_1    conda-forge
+openeye-toolkits          2020.2.0                 py37_0    openeye
+openff-forcefields        1.3.0              pyh44b312d_0    conda-forge
+openff-toolkit            0.9.0                     dev_0    <develop>
+openff-units              0.0.0+4.ge9bf622.dirty           dev_0    <develop>
+openmm                    7.5.0           py37h19dfff4_5_apple    conda-forge
+openssl                   1.1.1i               h9ed2024_0    defaults
+orc                       1.6.7                h675e114_0    conda-forge
+packaging                 20.9               pyhd3eb1b0_0    defaults
+packmol-memgen            1.1.0rc0                 pypi_0    pypi
+pandas                    1.2.1            py37h010c265_0    conda-forge
+pandoc                    2.11.4               h35c211d_0    conda-forge
+pandocfilters             1.4.3            py37hecd8cb5_1    defaults
+parmed                    at20RC5+54.g5702a232fe.dirty          pypi_0    pypi
+parquet-cpp               1.5.1                         1    conda-forge
+parso                     0.7.1              pyh9f0ad1d_0    conda-forge
+pathspec                  0.8.1              pyhd3deb0d_0    conda-forge
+pcre                      8.44                 hb1e8313_0    conda-forge
+pdb4amber                 1.7.dev0                 pypi_0    pypi
+perl                      5.32.0               hbcb3906_0    conda-forge
+pexpect                   4.8.0            py37hc8dfbb8_1    conda-forge
+pickleshare               0.7.5           py37hc8dfbb8_1002    conda-forge
+pillow                    8.1.0            py37h40a97b9_1    conda-forge
+pint                      0.16.1                     py_0    conda-forge
+pip                       21.0.1             pyhd8ed1ab_0    conda-forge
+pixman                    0.40.0               hbcb3906_0    conda-forge
+plotly                    4.14.3             pyh44b312d_0    conda-forge
+pluggy                    0.13.1           py37hf985489_4    conda-forge
+poyo                      0.5.0                      py_0    conda-forge
+pre-commit                2.10.0           py37hf985489_0    conda-forge
+prometheus_client         0.9.0              pyhd3deb0d_0    conda-forge
+prompt-toolkit            3.0.14             pyha770c72_0    conda-forge
+psutil                    5.8.0            py37hf967b71_1    conda-forge
+pthread-stubs             0.4               hc929b4f_1001    conda-forge
+ptyprocess                0.7.0              pyhd3deb0d_0    conda-forge
+py                        1.10.0             pyhd3deb0d_0    conda-forge
+py-cpuinfo                7.0.0              pyh9f0ad1d_0    conda-forge
+pyarrow                   3.0.0           py37hc6b1ce4_1_cpu    conda-forge
+pycairo                   1.20.0           py37ha7df449_1    conda-forge
+pycodestyle               2.6.0              pyh9f0ad1d_0    conda-forge
+pycosat                   0.6.3           py37hf967b71_1006    conda-forge
+pycparser                 2.20               pyh9f0ad1d_2    conda-forge
+pydantic                  1.7.3            py37he6e4e01_0    conda-forge
+pyflakes                  2.2.0              pyh9f0ad1d_0    conda-forge
+pygments                  2.7.4              pyhd8ed1ab_0    conda-forge
+pyopenssl                 20.0.1             pyhd8ed1ab_0    conda-forge
+pyparsing                 2.4.7              pyh9f0ad1d_0    conda-forge
+pyrsistent                0.17.3           py37hf967b71_2    conda-forge
+pysocks                   1.7.1            py37hf985489_3    conda-forge
+pytables                  3.6.1            py37he95298d_3    conda-forge
+pytest                    6.2.2            py37hf985489_0    conda-forge
+pytest-cases              3.2.0              pyhd8ed1ab_0    conda-forge
+pytest-cov                2.11.1             pyh44b312d_0    conda-forge
+pytest-forked             1.3.0                      py_0    defaults
+pytest-lazy-fixture       0.6.3                      py_0    conda-forge
+pytest-xdist              2.2.0              pyhd8ed1ab_0    conda-forge
+python                    3.7.9           h6c3b2c9_0_cpython    conda-forge
+python-dateutil           2.8.1                      py_0    conda-forge
+python-slugify            4.0.1              pyh9f0ad1d_0    conda-forge
+python_abi                3.7                     1_cp37m    conda-forge
+pytraj                    2.0.5                    pypi_0    pypi
+pytz                      2021.1             pyhd8ed1ab_0    conda-forge
+pyyaml                    5.4.1            py37hf967b71_0    conda-forge
+pyzmq                     22.0.1           py37hf4687c3_0    conda-forge
+qcelemental               0.17.0+17.g7fb730e           dev_0    <develop>
+qcengine                  0.17.0                     py_0    conda-forge
+qcportal                  0.14.0                     py_1    conda-forge
+rdkit                     2020.09.4        py37hdb0908f_0    conda-forge
+re2                       2020.11.01           h2e338ed_0    conda-forge
+readline                  8.1                  h9ed2024_0    defaults
+regex                     2020.11.13       py37hf967b71_1    conda-forge
+reportlab                 3.5.60           py37h603b006_0    conda-forge
+reproc                    14.2.1               hbcb3906_0    conda-forge
+reproc-cpp                14.2.1               h2e338ed_0    conda-forge
+requests                  2.25.1             pyhd3deb0d_0    conda-forge
+retrying                  1.3.3                      py_2    conda-forge
+ruamel_yaml               0.15.87          py37haf1e3a3_1    defaults
+sander                    16.0                     pypi_0    pypi
+scipy                     1.6.0            py37h6bb7d36_0    conda-forge
+send2trash                1.5.0                      py_0    conda-forge
+setuptools                52.0.0           py37hecd8cb5_0    defaults
+six                       1.15.0             pyh9f0ad1d_0    conda-forge
+smirnoff99frosst          1.1.0              pyh44b312d_0    conda-forge
+snappy                    1.1.8                hb1e8313_3    conda-forge
+sniffio                   1.2.0            py37hf985489_1    conda-forge
+sqlalchemy                1.3.22           py37hf967b71_1    conda-forge
+sqlite                    3.34.0               h17101e1_0    conda-forge
+terminado                 0.9.2            py37hf985489_0    conda-forge
+testpath                  0.4.4                      py_0    conda-forge
+text-unidecode            1.3                        py_0    conda-forge
+tinydb                    4.3.0              pyhd3deb0d_0    conda-forge
+tk                        8.6.10               hb0a8c7a_1    conda-forge
+toml                      0.10.2             pyhd8ed1ab_0    conda-forge
+tornado                   6.1              py37hf967b71_1    conda-forge
+tqdm                      4.56.0             pyhd8ed1ab_0    conda-forge
+traitlets                 5.0.5                      py_0    conda-forge
+typed-ast                 1.4.2            py37hf967b71_0    conda-forge
+typing_extensions         3.7.4.3                    py_0    conda-forge
+tzdata                    2021a                he74cb21_0    conda-forge
+unidecode                 1.1.2              pyhd8ed1ab_0    conda-forge
+urllib3                   1.26.3             pyhd8ed1ab_0    conda-forge
+virtualenv                20.4.2           py37hf985489_0    conda-forge
+wcwidth                   0.2.5              pyh9f0ad1d_2    conda-forge
+webencodings              0.5.1                      py_1    conda-forge
+wheel                     0.36.2             pyhd3deb0d_0    conda-forge
+whichcraft                0.6.1                      py_0    conda-forge
+widgetsnbextension        3.5.1            py37hf985489_4    conda-forge
+xmltodict                 0.12.0                     py_0    conda-forge
+xorg-kbproto              1.0.7             h35c211d_1002    conda-forge
+xorg-libice               1.0.10               h01d97ff_0    conda-forge
+xorg-libsm                1.2.3             h1de35cc_1000    conda-forge
+xorg-libx11               1.6.12               haf1e3a3_0    conda-forge
+xorg-libxau               1.0.9                h35c211d_0    conda-forge
+xorg-libxdmcp             1.1.3                h35c211d_0    conda-forge
+xorg-libxext              1.3.4                h01d97ff_0    conda-forge
+xorg-libxt                1.2.1                h35c211d_0    conda-forge
+xorg-xextproto            7.3.0             h35c211d_1002    conda-forge
+xorg-xproto               7.0.31            h35c211d_1007    conda-forge
+xz                        5.2.5                haf1e3a3_1    conda-forge
+yaml                      0.2.5                haf1e3a3_0    conda-forge
+zeromq                    4.3.3                h74dc148_3    conda-forge
+zipp                      3.4.0                      py_0    conda-forge
+zlib                      1.2.11            h7795811_1010    conda-forge
+zstd                      1.4.8                hf387650_1    conda-forge
diff --git a/openff/toolkit/typing/engines/smirnoff/forcefield.py b/openff/toolkit/typing/engines/smirnoff/forcefield.py
index 00a0478d..416a58d2 100644
--- a/openff/toolkit/typing/engines/smirnoff/forcefield.py
+++ b/openff/toolkit/typing/engines/smirnoff/forcefield.py
@@ -1328,6 +1328,42 @@ class ForceField:
         for parameter_handler in parameter_handlers:
             parameter_handler.postprocess_system(system, topology, **kwargs)
 
+        # Handle 1-4 scaling interactions here, instead of in handlers, since OpenMM
+        # does things slightly differently than other engines may
+        electrostatics_14 = self.get_parameter_handler(tagname="Electrostatics").scale14
+        vdw_14 = self.get_parameter_handler(tagname="vdW").scale14
+
+        # Create exceptions based on bonds.
+        # QUESTION: Will we want to do this for *all* cases, or would we ever want flexibility here?
+        bond_particle_indices = []
+
+        for topology_molecule in topology.topology_molecules:
+
+            top_mol_particle_start_index = topology_molecule.atom_start_topology_index
+
+            for topology_bond in topology_molecule.bonds:
+                top_index_1 = topology_molecule._ref_to_top_index[
+                    topology_bond.bond.atom1_index
+                ]
+                top_index_2 = topology_molecule._ref_to_top_index[
+                    topology_bond.bond.atom2_index
+                ]
+
+                top_index_1 += top_mol_particle_start_index
+                top_index_2 += top_mol_particle_start_index
+
+                bond_particle_indices.append((top_index_1, top_index_2))
+
+        # TODO: Can we generalize this to allow for `CustomNonbondedForce` implementations too?
+        forces = [system.getForce(i) for i in range(system.getNumForces())]
+        nonbonded_force = [f for f in forces if type(f) == openmm.NonbondedForce][0]
+
+        nonbonded_force.createExceptionsFromBonds(
+            bond_particle_indices,
+            electrostatics_14,
+            vdw_14,
+        )
+
         if return_topology:
             return (system, topology)
         else:
diff --git a/openff/toolkit/typing/engines/smirnoff/parameters.py b/openff/toolkit/typing/engines/smirnoff/parameters.py
index 8cfb0771..42d360b9 100644
--- a/openff/toolkit/typing/engines/smirnoff/parameters.py
+++ b/openff/toolkit/typing/engines/smirnoff/parameters.py
@@ -3656,44 +3656,6 @@ class vdWHandler(_NonbondedHandler):
             assigned_terms=atom_matches, valence_terms=list(topology.topology_atoms)
         )
 
-    # TODO: Can we express separate constraints for postprocessing and normal processing?
-    def postprocess_system(self, system, topology, **kwargs):
-        # Create exceptions based on bonds.
-        # TODO: This postprocessing must occur after the ChargeIncrementModelHandler
-        # QUESTION: Will we want to do this for *all* cases, or would we ever want flexibility here?
-        bond_particle_indices = []
-
-        for topology_molecule in topology.topology_molecules:
-
-            top_mol_particle_start_index = topology_molecule.atom_start_topology_index
-
-            for topology_bond in topology_molecule.bonds:
-
-                top_index_1 = topology_molecule._ref_to_top_index[
-                    topology_bond.bond.atom1_index
-                ]
-                top_index_2 = topology_molecule._ref_to_top_index[
-                    topology_bond.bond.atom2_index
-                ]
-
-                top_index_1 += top_mol_particle_start_index
-                top_index_2 += top_mol_particle_start_index
-
-                bond_particle_indices.append((top_index_1, top_index_2))
-
-        for force in system.getForces():
-            # TODO: Should we just store which `Force` object we are adding to and use that instead,
-            # to prevent interference with other kinds of forces in the future?
-            # TODO: Can we generalize this to allow for `CustomNonbondedForce` implementations too?
-            if isinstance(force, openmm.NonbondedForce):
-                # nonbonded.createExceptionsFromBonds(bond_particle_indices, self.coulomb14scale, self.lj14scale)
-
-                # TODO: Don't mess with electrostatic scaling here. Have a separate electrostatics handler.
-                force.createExceptionsFromBonds(
-                    bond_particle_indices, 0.83333, self.scale14
-                )
-                # force.createExceptionsFromBonds(bond_particle_indices, self.coulomb14scale, self._scale14)
-
 
 class ElectrostaticsHandler(_NonbondedHandler):
     """Handles SMIRNOFF ``<Electrostatics>`` tags.


Test patch:
diff --git a/openff/toolkit/tests/test_energies.py b/openff/toolkit/tests/test_energies.py
index ca4030ee..de0f1537 100644
--- a/openff/toolkit/tests/test_energies.py
+++ b/openff/toolkit/tests/test_energies.py
@@ -23,7 +23,9 @@ def test_reference(constrained, mol):
     """Minimal regression test comparing molecule energies to energies computed
     by version 0.8.0 of the toolkit"""
     # TODO: Also test periodic vs. vacuum
-    with open(get_data_file_path("reference_energies/reference_0.8.0.json"), "r") as fi:
+    with open(
+        get_data_file_path("reference_energies/reference_after_802.json"), "r"
+    ) as fi:
         reference = json.loads(fi.read())
 
     name = mol + "_"
diff --git a/openff/toolkit/tests/test_forcefield.py b/openff/toolkit/tests/test_forcefield.py
index c6a6b390..5cde8666 100644
--- a/openff/toolkit/tests/test_forcefield.py
+++ b/openff/toolkit/tests/test_forcefield.py
@@ -26,6 +26,7 @@ from numpy.testing import assert_almost_equal
 from simtk import openmm, unit
 
 from openff.toolkit.tests.utils import (
+    get_14_scaling_factors,
     requires_openeye,
     requires_openeye_mol2,
     requires_rdkit,
@@ -4201,6 +4202,76 @@ class TestForceFieldParameterAssignment:
             allow_nonintegral_charges=False,
         )
 
+    def test_modified_14_factors(self):
+        """Test that the 1-4 scaling factors for electrostatics and vdW handlers matche,
+        to a tight precision, the values specified in the force field."""
+        top = Molecule.from_smiles("CCCC").to_topology()
+        default_14 = ForceField("test_forcefields/test_forcefield.offxml")
+        e_mod_14 = ForceField("test_forcefields/test_forcefield.offxml")
+        vdw_mod_14 = ForceField("test_forcefields/test_forcefield.offxml")
+
+        e_mod_14["Electrostatics"].scale14 = 0.66
+        assert e_mod_14["Electrostatics"].scale14 == 0.66
+
+        vdw_mod_14["vdW"].scale14 = 0.777
+        assert vdw_mod_14["vdW"].scale14 == 0.777
+
+        default_omm_sys = default_14.create_openmm_system(top)
+        e_mod_omm_sys = e_mod_14.create_openmm_system(top)
+        vdw_mod_omm_sys = vdw_mod_14.create_openmm_system(top)
+
+        for omm_sys, expected_vdw_14, expected_coul_14 in [
+            [default_omm_sys, 0.5, 0.833333],
+            [e_mod_omm_sys, 0.5, 0.66],
+            [vdw_mod_omm_sys, 0.777, 0.833333],
+        ]:
+            found_coul_14, found_vdw_14 = get_14_scaling_factors(omm_sys)
+
+            np.testing.assert_almost_equal(
+                actual=found_vdw_14,
+                desired=expected_vdw_14,
+                decimal=10,
+                err_msg="vdW 1-4 scaling factors do not match",
+            )
+
+            np.testing.assert_almost_equal(
+                actual=found_coul_14,
+                desired=expected_coul_14,
+                decimal=10,
+                err_msg="Electrostatics 1-4 scaling factors do not match",
+            )
+
+    def test_14_missing_nonbonded_handler(self):
+        """Test that something sane happens with 1-4 scaling factors if a
+        ForceField is missing a vdWHandler and/or ElectrostaticsHandler"""
+        top = Molecule.from_smiles("CCCC").to_topology()
+
+        ff_no_vdw = ForceField("test_forcefields/test_forcefield.offxml")
+        ff_no_electrostatics = ForceField("test_forcefields/test_forcefield.offxml")
+        ff_no_nonbonded = ForceField("test_forcefields/test_forcefield.offxml")
+
+        ff_no_vdw.deregister_parameter_handler("vdW")
+        ff_no_nonbonded.deregister_parameter_handler("vdW")
+
+        ff_no_electrostatics.deregister_parameter_handler("Electrostatics")
+        ff_no_nonbonded.deregister_parameter_handler("Electrostatics")
+
+        sys_no_vdw = ff_no_vdw.create_openmm_system(top)
+        sys_no_electrostatics = ff_no_electrostatics.create_openmm_system(top)
+        sys_no_nonbonded = ff_no_nonbonded.create_openmm_system(top)
+
+        np.testing.assert_almost_equal(
+            actual=get_14_scaling_factors(sys_no_vdw)[0],
+            desired=ff_no_vdw["Electrostatics"].scale14,
+            decimal=8,
+        )
+
+        np.testing.assert_almost_equal(
+            actual=get_14_scaling_factors(sys_no_electrostatics)[1],
+            desired=ff_no_electrostatics["vdW"].scale14,
+            decimal=8,
+        )
+
     @requires_openeye
     def test_overwrite_bond_orders(self):
         """Test that previously-defined bond orders in the topology are overwritten"""
diff --git a/openff/toolkit/tests/utils.py b/openff/toolkit/tests/utils.py
index 9ea95c0a..173ea4ed 100644
--- a/openff/toolkit/tests/utils.py
+++ b/openff/toolkit/tests/utils.py
@@ -21,6 +21,7 @@ import itertools
 import os
 import pprint
 import textwrap
+from typing import List, Tuple
 
 import numpy as np
 import pytest
@@ -1788,3 +1789,29 @@ def evaluate_molecules_off(molecules, forcefield, minimize=False):
     )
 
     return xyz, ene
+
+
+def get_14_scaling_factors(omm_sys: openmm.System) -> Tuple[List, List]:
+    """Find the 1-4 scaling factors as they are applied to an OpenMM System"""
+    nonbond_force = [
+        f for f in omm_sys.getForces() if type(f) == openmm.NonbondedForce
+    ][0]
+
+    vdw_14 = list()
+    coul_14 = list()
+
+    for exception_idx in range(nonbond_force.getNumExceptions()):
+        i, j, q, sig, eps = nonbond_force.getExceptionParameters(exception_idx)
+
+        # Trust that q == 0 covers the cases of 1-2, 1-3, and truly being 0
+        if q / unit.elementary_charge ** 2 != 0:
+            q_i = nonbond_force.getParticleParameters(i)[0]
+            q_j = nonbond_force.getParticleParameters(j)[0]
+            coul_14.append(q / (q_i * q_j))
+
+        if eps / unit.kilojoule_per_mole != 0:
+            eps_i = nonbond_force.getParticleParameters(i)[2]
+            eps_j = nonbond_force.getParticleParameters(j)[2]
+            vdw_14.append(eps / (eps_i * eps_j) ** 0.5)
+
+    return coul_14, vdw_14