Gridoptimization calculations#
Grid optimizations perform a multi-dimensional scan over internal coordinates (distance, angle, dihedral). At each grid point, a constrained geometry optimization is performed to minimize the energy while holding selected coordinates fixed. This produces a grid of optimized structures and their final energies.
Gridoptimization Records#
Gridoptimization records contain all the fields of a base record, and additionally include:
initial_molecule- The molecule used as the starting geometry for the scanstarting_molecule- The molecule actually used to start the scan (after optional preoptimization)starting_grid- The grid indices where the scan started (if relative steps were used)optimizations- A mapping from grid keys to each constrainedOptimizationRecordspecification- The scan/optimization setup (see below)
The optimizations can be accessed via the optimizations
property, which returns a dictionary mapping grid keys to optimization records. Grid keys are tuples of integers
(one per scan dimension) that index the steps defined in your scan. A special key "preoptimization" is used
for the optional initial unconstrained optimization.
The convenience property final_energies
returns a dictionary mapping grid keys (tuples) to the final energy from each optimization.
Note
The mapping keys are represented as strings when serialized;
use serialize_key() and
deserialize_key() for conversions if needed.
Gridoptimization Specification#
The specification for a grid optimization is a
GridoptimizationSpecification. The key fields are:
program- The gridoptimization driver program ("gridoptimization")optimization_specification- How each constrained optimization should be run; see Optimization Specificationkeywords- The scan definition and related options (see below)
The keywords are provided via GridoptimizationKeywords and include:
scans- A list ofScanDimensionobjects describing each scan dimension:type- One ofScanTypeEnum(distance,angle,dihedral)indices- Atom indices. This is zero-indexed, so the first atom of the molecule has index 0. There are 2 indices for distance, 3 for angle, 4 for dihedral.steps- A strictly monotonic list of values; units are Bohr for distances and degrees for angles/dihedralsstep_type-StepTypeEnum(absoluteorrelative)
preoptimization- IfTrue, perform an unconstrained optimization before scanning. This is especially useful withrelativestep types so that relative steps are taken from a relaxed starting geometry.
Note: The constrained optimizations at each grid point use the specification supplied by the
OptimizationSpecification, including the level of theory
and programs. See Optimization Specification.
Absolute vs. Relative step_type#
Each ScanDimension declares how its steps should be
interpreted via the step_type field:
absolute– The values instepsare the absolute target values for the corresponding internal coordinate. For example, a dihedral scan withsteps=[-180, -165, ..., 180]constrains that dihedral to those exact angles at each grid point. Likewise, a bond-distance scan withsteps=[2.5, 2.6, 2.7](in Bohr) constrains the distance to those exact values.relative– The values instepsare offsets relative to the value measured on the starting molecule for the scan. At submission time the server constructs the constraints by adding the offset to the measured value on the starting geometry. Concretely, for a given grid indexithe constraint value used issteps[i] + measure(starting_molecule, indices).
Starting molecule and starting grid#
If
preoptimizationisTrue, the starting molecule is the final geometry from an initial unconstrained optimization of the input structure. IfpreoptimizationisFalse, the starting molecule is simply the initial molecule you submitted.The
starting_gridstored on the record is the index tuple of the first constrained optimization that is launched: it is chosen as the grid point whose target value is closest to the starting molecule. Forabsolutedimensions this means picking the step closest tomeasure(starting_molecule, indices); forrelativedimensions this means picking the step closest to0(no change).
Practical tips#
Use
relativesteps when you want to explore around the current structure without having to compute absolute values ahead of time (for example,[-0.2, 0.0, 0.2]Bohr around the current bond length, or[-10, 0, 10]degrees around a torsion).Use
absolutesteps when you want the grid aligned to specific absolute values (for example, a canonical[-180, -165, ..., 180]dihedral scan).preoptimization=Trueis often helpful withrelativescans so the offsets are applied from a relaxed geometry.
Examples of building specifications#
Single-dimension dihedral scan with preoptimization
from qcportal.gridoptimization import GridoptimizationSpecification, GridoptimizationKeywords, ScanDimension
from qcportal.optimization import OptimizationSpecification
from qcportal.singlepoint import QCSpecification
go_spec = GridoptimizationSpecification(
program="gridoptimization",
optimization_specification=OptimizationSpecification(
program="geometric",
qc_specification=QCSpecification(program="psi4", method="b3lyp", basis="def2-svp", driver="deferred"),
),
keywords=GridoptimizationKeywords(
scans=[
ScanDimension(type="dihedral", indices=[0, 1, 2, 3], step_type="absolute", steps=list(range(-180, 181, 15)))
],
preoptimization=True,
),
)
Two-dimensional scan combining a bond stretch and angle bend
from qcportal.gridoptimization import GridoptimizationSpecification, GridoptimizationKeywords, ScanDimension
from qcportal.optimization import OptimizationSpecification
from qcportal.singlepoint import QCSpecification
go_spec = GridoptimizationSpecification(
program="gridoptimization",
optimization_specification=OptimizationSpecification(
program="geometric",
qc_specification=QCSpecification(program="psi4", method="wb97x-d", basis="def2-tzvp", driver="deferred"),
),
keywords=GridoptimizationKeywords(
scans=[
ScanDimension(type="distance", indices=[0, 1], step_type="relative", steps=[-0.2, 0.0, 0.2]),
ScanDimension(type="angle", indices=[1, 2, 3], step_type="absolute", steps=[90.0, 110.0, 130.0]),
],
preoptimization=True,
),
)
Relative dihedral offsets around the starting torsion (with preoptimization)
from qcportal.gridoptimization import GridoptimizationSpecification, GridoptimizationKeywords, ScanDimension
from qcportal.optimization import OptimizationSpecification
from qcportal.singlepoint import QCSpecification
go_spec = GridoptimizationSpecification(
program="gridoptimization",
optimization_specification=OptimizationSpecification(
program="geometric",
qc_specification=QCSpecification(program="psi4", method="b3lyp", basis="def2-svp", driver="deferred"),
),
keywords=GridoptimizationKeywords(
scans=[
# Offsets in degrees relative to the starting torsion value
ScanDimension(type="dihedral", indices=[0, 1, 2, 3], step_type="relative", steps=[-30.0, 0.0, 30.0])
],
preoptimization=True,
),
)
Relative bond-length scan without preoptimization
from qcportal.gridoptimization import GridoptimizationSpecification, GridoptimizationKeywords, ScanDimension
from qcportal.optimization import OptimizationSpecification
from qcportal.singlepoint import QCSpecification
go_spec = GridoptimizationSpecification(
program="gridoptimization",
optimization_specification=OptimizationSpecification(
program="geometric",
qc_specification=QCSpecification(program="psi4", method="wb97x-d", basis="def2-tzvp", driver="deferred"),
),
keywords=GridoptimizationKeywords(
scans=[
# Offsets in Bohr relative to the starting bond length
ScanDimension(type="distance", indices=[0, 1], step_type="relative", steps=[-0.2, 0.0, 0.2])
],
preoptimization=False,
),
)
Submitting Records#
Gridoptimization records can be submitted using a client via the add_gridoptimizations() method.
This method takes the following key information:
initial_molecules- A single molecule or list of molecules to scanprogram- The gridoptimization program (use"gridoptimization")optimization_specification- The optimization setup for each grid point (see Gridoptimization Specification)keywords- The grid scan definition and options
See Submitting computations for more information about other common fields such as compute tag and priority.
Client Examples#
Obtain a single gridoptimization record by ID
r = client.get_gridoptimizations(123)
Obtain multiple gridoptimization records by ID
r_lst = client.get_gridoptimizations([123, 456])
Include molecules and child optimizations during initial fetch
r = client.get_gridoptimizations(123, include=["**"]) # include all data
Query gridoptimizations by QC method/basis and include optimizations
r_iter = client.query_gridoptimizations(qc_method='b3lyp', qc_basis='def2-svp', include=['optimizations'])
for r in r_iter:
print(r.id, len(r.optimizations))
Submit gridoptimizations
from qcportal.gridoptimization import GridoptimizationSpecification, GridoptimizationKeywords, ScanDimension
from qcportal.optimization import OptimizationSpecification
from qcportal.singlepoint import QCSpecification
spec = GridoptimizationSpecification(
program='gridoptimization',
optimization_specification=OptimizationSpecification(
program='geometric',
qc_specification=QCSpecification(program='psi4', method='b3lyp', basis='def2-svp', driver='deferred'),
),
keywords=GridoptimizationKeywords(
scans=[ScanDimension(type='dihedral', indices=[0,1,2,3], step_type='absolute', steps=list(range(-180,181,15)))],
preoptimization=True,
),
)
meta, ids = client.add_gridoptimizations([mol1, mol2], program='gridoptimization', optimization_specification=spec.optimization_specification, keywords=spec.keywords)
Gridoptimization Datasets#
Gridoptimization datasets are collections of gridoptimization records.
Entries contain a single initial molecule
and optional metadata. The dataset specifications
wrap a GridoptimizationSpecification.
See Datasets for general dataset operations and advanced usage.
Dataset Examples#
Create a gridoptimization dataset
ds = client.add_dataset("gridoptimization", "Grid Scan Dataset", "A demonstration grid scan dataset")
Add entries to a gridoptimization dataset
from qcportal.gridoptimization import GridoptimizationDatasetEntry
from qcportal.molecules import Molecule
entries = []
for name, geom in [("butane", butane_geom), ("ethane", ethane_geom)]:
mol = Molecule.from_data(geom) if isinstance(geom, str) else Molecule(**geom)
entries.append(GridoptimizationDatasetEntry(name=name, initial_molecule=mol))
ds.add_entries(entries)
Add a specification to a gridoptimization dataset
from qcportal.gridoptimization import GridoptimizationSpecification, GridoptimizationKeywords, ScanDimension
from qcportal.optimization import OptimizationSpecification
from qcportal.singlepoint import QCSpecification
go_spec = GridoptimizationSpecification(
program="gridoptimization",
optimization_specification=OptimizationSpecification(
program="geometric",
qc_specification=QCSpecification(program="psi4", method="b3lyp", basis="def2-svp", driver="deferred"),
),
keywords=GridoptimizationKeywords(
scans=[ScanDimension(type="dihedral", indices=[0, 1, 2, 3], step_type="absolute", steps=list(range(-180, 181, 60)))],
preoptimization=True,
),
)
ds.add_specification("go-geometric/psi4-b3lyp-def2-svp", go_spec)
Gridoptimization QCPortal API#
PortalClient methods