Manybody calculations#
Manybody calculations aim to compute interaction energies and to extrapolate total system energies and properties by computing the energies/properties on collections of fragments that compose a larger system.
For more details about manybody calculations in general, see blah.
Manybody computations in QCArchive are implemented as a service and computed using the QCManyBody package. The individual calculations themselves can be run from any of the QM packages available in QCArchive.
See also the QCManybody article
Note
The “initial molecules” for the manybody calculations must contain more than one fragment. It’s these fragments that are used to construct the clusters for the manybody calculations.
Manybody Record#
The ManybodyRecord
object contains all the fields of the
base record class, but also contains manybody-specific fields:
initial_molecule
- The initial (fragmented molecule) that the manybody calculation was run onspecification
- The level of theory and other options for running the calculation (see below)clusters
- List ofManybodyCluster
objects that represent the individual (child) calculations (that is, the calculations run on all the monomers, dimers, etc).
The ManybodyCluster
objects contain:
molecule_id
andmolecule
- the actual molecule this child calculation used. This molecule is a subset of the fragments of the input molecule.fragments
- Indices of the fragments this molecule/calculation representsbasis
- The fragment basis used in this molecule. The molecule may contain ghost atoms for some centers to deal with basis-set superposition error, and the ghosted fragments represent additions to the basis. For example,fragments=[4]
andbasis=[4,8]
means the calculation is run on fragment 4, but includes basis sets from both fragments 4 and 8. Note that this is fragments, not atom indices.mc_level
- Label of the model chemistry (ie, ‘psi4/b3lyp/6-31g*’). This is automatically generated by QCArchive.singlepoint_id
andsinglepoint_record
- The singlepoint record of the calculation.
The full calculated results of the manybody calculation itself are stored in the properties field of the record.
Manybody Specification#
The specification for a manybody record is a ManybodySpecification
.
The fields of that are:
program
- Program to run the manybody calculation itself. Only value available right now isqcmanybody
levels
- Dictionary of the different singlpoint specifications for different levels of the expansion (see below)bsse_correction
- Correction for the basis set superposition error. This is a list that can contain multiple values, enabling calculating with different levels of correction simulataneously. Values are:nocp
for no correctioncp
for counterpoise correctionvmfc
for Valiron-Mayer Function Counterpoise
keywords
- Additional keywords for running the calculation. Currently, one keyword is supported:return_total_data - Computes/Returns the total energy/gradient, etc, of the system. If false, only the interaction energy is returned. Default is false.
protocols
- Additional keywords controlling the return of information. This is reserved for future use.
The levels
parameter is a dictionary of levels of expansion to a specification describing
how that level should be computed. The keys are integers representing the level (1 = monomers, 2 = dimers, etc)
and the value is a singlepoint specification/qc specification. A string
“supersystem” key can be used for the supersystem calculation.
Compute the interaction energy of dimers using one level of theory
from qcportal.manybody import ManybodySpecification
ManybodySpecification(
program="qcmanybody",
bsse_correction=["nocp"],
levels={
1: QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
),
2: QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
),
},
)
Interaction energy as above, but adding CP correction
from qcportal.manybody import ManybodySpecification
ManybodySpecification(
program="qcmanybody",
bsse_correction=["nocp", "cp"],
levels={
1: QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
),
2: QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
),
},
)
Include total energy for a 4-fragment system
from qcportal.manybody import ManybodySpecification
ManybodySpecification(
program="qcmanybody",
bsse_correction=["cp"],
levels={
1: QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
),
2: QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
),
},
keywords={'return_total_data': True}
)
Using different levels of theory
from qcportal.manybody import ManybodySpecification
ManybodySpecification(
program="qcmanybody",
bsse_correction=["nocp", "cp"],
levels={
1: QCSpecification(
program="psi4",
driver="energy",
method="ccsd",
basis="cc-pvqz",
),
2: QCSpecification(
program="psi4",
driver="energy",
method="ccsd",
basis="cc-pvtz",
),
3: QCSpecification(
program="psi4",
driver="energy",
method="ccsd",
basis="cc-pvdz",
),
}
)
Submitting Records#
Manybody records can be submitted using a client via the add_manybodys()
method.
This method takes the following information:
initial_molecules
- A single molecule or list of molecules to computeprogram
- Alwaysqcmanybody
levels
,bsse_correction
,keywords
- Same as in the specification above
See Submitting computations for more information about other fields.
Manybody Dataset#
Manybody datasets are collections of manybody records.
Entries
contain the initial (fragmented)
molecule.
The dataset specifications
contain a manybody specification (see above)
Client Examples#
When creating the levels
member of the specification or to be passed into the
add_manybodys()
client function, it is often
easiest to define the specification separately and use the resulting object
as values in the levels
dictionary.
Obtain a single record by ID
r = client.get_manybodys(123)
Obtain multiple records by ID
r_lst = client.get_manybodys([123, 456])
Obtain multiple records by ID, ignoring missing records
r_lst = client.get_manybodys([123, 456, 789], missing_ok=True)
Include all data for a record during initial fetch
r_lst = client.get_manybodys([123, 456], include=['**'])
Query manybody records by program, method, basis
# NOTE - we are querying by the program actually used in the singlepoint calculations here
# not the overarching manybody program
r_iter = client.query_manybodys(qc_program='psi4', qc_method='b3lyp', qc_basis='def2-svp')
for r in r_iter:
print(r.id)
Query manybody records by program and when the record was created, include all data
# NOTE - we are querying by the program actually used in the singlepoint calculations here
# not the overarching manybody program
r_iter = client.query_manybodys(program='psi4',
created_after='2024-03-21 12:34:56',
include=['**'])
limit=50)
for r in r_iter:
print(r.id)
Create some fragmented molecules
water_dimer = Molecule(symbols=['O', 'H', 'H', 'O', 'H', 'H'],
geometry=[2.81211079, 0.1255717, 0.0,
3.48216662, -1.5543998, 0.0,
1.00578203, -0.1092573, 0.0,
-2.68215279, -0.12325075, 0.0,
-3.27523823, 0.81341093, 1.43347254,
-3.27523823, 0.81341093, -1.43347254],
fragments=[[0, 1, 2], [3, 4, 5]],
)
water_stacked = Molecule(symbols=['O', 'H', 'H', 'O', 'H', 'H', 'O', 'H', 'H', 'O', 'H', 'H'],
geometry=[2.81211079, 0.1255717, 0.0,
3.48216662, -1.5543998, 0.0,
1.00578203, -0.1092573, 0.0,
2.81211079, 0.1255717, 4.0,
3.48216662, -1.5543998, 4.0,
1.00578203, -0.1092573, 4.0,
2.81211079, 0.1255717, 8.0,
3.48216662, -1.5543998, 8.0,
1.00578203, -0.1092573, 8.0,
2.81211079, 0.1255717, 12.0,
3.48216662, -1.5543998, 12.0,
1.00578203, -0.1092573, 12.0
],
fragments=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]],
)
Add a manybody record - compute the interaction energy of a dimer, no BSSE correction
qc_spec = QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
)
meta, ids = client.add_manybodys([water_dimer],
program='qcmanybody',
levels={
1: qc_spec,
2: qc_spec,
},
bsse_correction=['nocp'],
keywords={}
)
Add a manybody record - compute the interaction energy of a dimer, CP-corrected
qc_spec = QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="6-31G*",
)
meta, ids = client.add_manybodys([water_dimer],
program='qcmanybody',
levels={
1: qc_spec,
2: qc_spec,
},
bsse_correction=['cp'],
keywords={}
)
Add a manybody record - using different levels of theory
qc_spec_1 = QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="def2-tzvp",
)
qc_spec_2 = QCSpecification(
program="psi4",
driver="energy",
method="b3lyp",
basis="def2-svp",
)
meta, ids = client.add_manybodys([water_dimer],
program='qcmanybody',
levels={
1: qc_spec_1,
2: qc_spec_2,
},
bsse_correction=['nocp'],
keywords={}
)
Dataset Examples#
Create a manybody dataset with default options
ds = client.add_dataset(
"manybody",
"Dataset Name",
"An example of a manybody dataset"
)
Add a single entry to a manybody dataset
water_dimer = Molecule(symbols=['O', 'H', 'H', 'O', 'H', 'H'],
geometry=[2.81211079, 0.1255717, 0.0,
3.48216662, -1.5543998, 0.0,
1.00578203, -0.1092573, 0.0,
-2.68215279, -0.12325075, 0.0,
-3.27523823, 0.81341093, 1.43347254,
-3.27523823, 0.81341093, -1.43347254],
fragments=[[0, 1, 2], [3, 4, 5]],
)
ds.add_entry("water_dimer", water_dimer)
Add many entries to a manybody dataset
from qcportal.manybody import ManybodyDatasetEntry
# Construct a list of entries to add somehow
ent_1 = ManybodyDatasetEntry(name="water_dimer", initial_molecule=water_dimer)
ent_2 = ManybodyDatasetEntry(name="water_stacked", initial_molecule=water_stacked)
new_entries = [ent_1, ent_2]
# Efficiently add all entries in a single call
ds.add_entries(new_entries)
Add a specification to a manybody dataset
from qcportal.manybody import ManybodySpecification
spec = ManybodySpecification(
program="qcmanybody",
bsse_correction=["nocp", "cp"],
levels={
1: QCSpecification(
program="psi4",
driver="energy",
method="ccsd",
basis="cc-pvqz",
),
2: QCSpecification(
program="psi4",
driver="energy",
method="ccsd",
basis="cc-pvtz",
),
3: QCSpecification(
program="psi4",
driver="energy",
method="ccsd",
basis="cc-pvdz",
),
}
)
ds.add_specification("psi4/ccsd/multi", spec)
Manybody QCPortal API#
PortalClient methods