Skip to content

Commit f77af4a

Browse files
authored
Merge pull request #17 from cclib/dev/calculation_methods
Dev/calculation methods
2 parents 4f4fa4c + 64977bf commit f77af4a

File tree

9 files changed

+5855
-0
lines changed

9 files changed

+5855
-0
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ makedocs(;
1616
pages=[
1717
"Home" => "index.md",
1818
"How to parse files" => "io.md",
19+
"Additional Analyses" => "calculation.md",
1920
"AtomsBase Integration" => "atombase.md"
2021
],
2122
)

docs/src/calculation.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Additional Analyses
2+
3+
Cclib also allows to further analyse calculation ouputs.
4+
5+
# C squared population analysis (CSPA)
6+
**CSPA** can be used to determine and interpret the electron density of a molecule. The contribution of the a-th atomic orbital to the i-th molecular orbital can be written in terms of the molecular orbital coefficients:
7+
$$\Phi_{ai} = \frac{c^2_{ai}}{\sum_k c^2_{ki}}$$
8+
```Julia
9+
# Example calculation files can be found in the test folder of the main branch.
10+
julia> using Cclib
11+
julia> aoresults, fragresults, fragcharges = cspa("./Trp_polar.fchk")
12+
```
13+
14+
* ``aoresults``: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1, 46, 1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
15+
* ``fragresults``: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1, 24, 5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
16+
* ``fragcharges``: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
17+
18+
# Mulliken population analysis (MPA)
19+
MPA can be used to determine and interpret the electron density of a molecule. The contribution of the a-th atomic orbital to the i-th molecular orbital in this method is written in terms of the molecular orbital coefficients, c, and the overlap matrix, S:
20+
$$\Phi_{ai} = \sum_b c_{ai} c_{bi} S_{ab}$$
21+
```Julia
22+
julia> using Cclib
23+
julia> aoresults, fragresults, fragcharges = mpa("./Trp_polar.fchk")
24+
```
25+
26+
* ``aoresults``: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1, 46, 1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
27+
* ``fragresults``: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1, 24, 5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
28+
* ``fragcharges``: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
29+
30+
# Löwdin Population Analysis
31+
```Julia
32+
julia> using Cclib
33+
julia> aoresults, fragresults, fragcharges = lpa("./Trp_polar.fchk")
34+
```
35+
36+
* ``aoresults``: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1, 46, 1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
37+
* ``fragresults``: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1, 24, 5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
38+
* ``fragcharges``: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
39+
40+
# Bickelhaupt Population Analysis
41+
The Bickelhaupt class available from cclib.method performs Bickelhaupt population analysis that has been proposed in *Organometallics* 1996, 15, 13, 2923–2931. [doi:10.1021/om950966x](https://pubs.acs.org/doi/abs/10.1021/om950966x)
42+
43+
The contribution of the a-th atomic orbital to the i-th molecular orbital in this method is written in terms of the molecular orbital coefficients, c, and the overlap matrix, S:
44+
45+
$$\Phi_{ai,\alpha} = \sum_b w_{ab,\alpha} c_{ai,\alpha} c_{bi,\alpha} S_{ab}$$
46+
47+
where the weights $w_{ab}$ that are applied on the Mulliken atomic orbital contributions are defined as following when the coefficients of the molecular orbitals are substituted into equation 11 in the original article.
48+
49+
$$w_{ab,\alpha} = 2 \frac{\sum_k c_{ak,\alpha}^2}{\sum_i c_{ai,\alpha}^2 + \sum_j c_{bj,\alpha}^2}$$
50+
51+
In case of unrestricted calculations, $\alpha$ charges and $\beta$ charges are each determined to obtain total charge. In restricted calculations, $\alpha$ subscript can be ignored since the coefficients are equivalent for both spin orbitals.
52+
53+
The weights are introduced to replace the somewhat arbitrary partitioning of off-diagonal charges in the Mulliken population analysis, which divides the off-diagonal charges identically to both atoms. Bickelhaupt population analysis instead divides the off-diagonal elements based on the relative magnitude of diagonal elements.
54+
```Julia
55+
julia> using Cclib
56+
julia> aoresults, fragresults, fragcharges = bpa("./Trp_polar.fchk")
57+
```
58+
* ``aoresults``: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1, 46, 1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
59+
* ``fragresults``: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1, 24, 5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
60+
* ``fragcharges``: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
61+
62+
# Density Matrix calculation
63+
Calculates the electron density matrix
64+
```Julia
65+
julia> using Cclib
66+
julia> result = density("./Trp_polar.fchk")
67+
```
68+
Returns an array with three axes. The first axis is for the spin contributions, the second and the third axes for the density matrix, which follows standard definition.
69+
# Mayer’s Bond Orders (MBO)
70+
Calculates Mayer's bond orders
71+
```Julia
72+
julia> using Cclib
73+
julia> result = mbo("./Trp_polar.fchk")
74+
```
75+
Returns an array with three axes. The first axis is for contributions of each spin to the MBO, while the second and the third correspond to the indices of the atoms.
76+
# Charge Decomposition Analysis
77+
The Charge Decomposition Analysis (CDA) as developed by Gernot Frenking et al. is used to study the donor-acceptor interactions of a molecule in terms of two user-specified fragments.
78+
```Julia
79+
julia> using Cclib
80+
julia> donations, bdonations, repulsions = cda("BH3CO-sp.log", "BH3.log", "CO.log")
81+
```
82+
Returns donations, bdonations (back donations), and repulsions attributes.
83+
These attributes are simply lists of 1-dimensional arrays corresponding to the restricted or alpha/beta molecular orbitals of the entire molecule.
84+
85+
<!-- # Bader’s QTAIM -->

src/Cclib.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ using UnitfulAtomic
77
using Logging
88

99
include("config.jl")
10+
include("calculation_methods.jl")
1011
include("functions.jl")
1112
include("ab_integration.jl")
1213

src/calculation_methods.jl

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#
2+
# Calculation methods for qchem outputs
3+
#
4+
export cspa
5+
export mpa
6+
export density
7+
export lpa
8+
export bpa
9+
export density
10+
export mbo
11+
export cda
12+
export bader
13+
14+
# dimensions of some outputs are NxMxK, however python return dimension N as a list, not an array
15+
function expand(x)
16+
N = length(x)
17+
x = pyconvert(Array{Float64}, x[0])
18+
return reshape(x, (N, size(x)...))
19+
end
20+
21+
"""
22+
cspa(file::String)
23+
24+
C-Squared Population Analysis (CSPA)
25+
# Arguments
26+
- `file::String`: Cclib-supported output file
27+
# Returns
28+
Tuple with 3 elements:
29+
- `aoresults`: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1][46][1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
30+
- `fragresults`: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1][24][5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
31+
- `fragcharges`: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
32+
"""
33+
function cspa(file::String)
34+
#TODO: implement the optional args from docs
35+
data = cclib[].io.ccread(file)
36+
mol = cclib[].method.CSPA(data)
37+
mol.calculate()
38+
aoresults = mol.__dict__["aoresults"] |> expand
39+
fragresults = mol.__dict__["fragresults"] |> expand
40+
fragcharges = pyconvert(Array{Float64}, mol.__dict__["fragcharges"])
41+
return aoresults, fragresults, fragcharges
42+
end
43+
44+
"""
45+
mpa(file::String)
46+
47+
Mulliken Population Analysis
48+
# Arguments
49+
- `file::String`: Cclib-supported output file
50+
# Returns
51+
Tuple with 3 elements:
52+
- `aoresults`: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1][46][1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
53+
- `fragresults`: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1][24][5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
54+
- `fragcharges`: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
55+
"""
56+
function mpa(file::String)
57+
data = cclib[].io.ccread(file)
58+
mol = cclib[].method.MPA(data)
59+
mol.calculate()
60+
aoresults = mol.__dict__["aoresults"] |> expand
61+
fragresults = mol.__dict__["fragresults"] |> expand
62+
fragcharges = pyconvert(Array{Float64}, mol.__dict__["fragcharges"])
63+
return aoresults, fragresults, fragcharges
64+
end
65+
66+
"""
67+
lpa(file::String)
68+
69+
Lowdin Population Analysis
70+
# Arguments
71+
- `file::String`: Cclib-supported output file
72+
# Returns
73+
Tuple with 3 elements:
74+
- `aoresults`: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1][46][1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
75+
- `fragresults`: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1][24][5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
76+
- `fragcharges`: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
77+
"""
78+
function lpa(file::String)
79+
data = cclib[].io.ccread(file)
80+
mol = cclib[].method.LPA(data)
81+
mol.calculate()
82+
aoresults = mol.__dict__["aoresults"] |> expand
83+
fragresults = mol.__dict__["fragresults"] |> expand
84+
fragcharges = pyconvert(Array{Float64}, mol.__dict__["fragcharges"])
85+
return aoresults, fragresults, fragcharges
86+
end
87+
88+
"""
89+
bpa(file::String)
90+
91+
Bickelhaupt Population Analysis
92+
# Arguments
93+
- `file::String`: Cclib-supported output file
94+
# Returns
95+
Tuple with 3 elements:
96+
- `aoresults`: a three dimensional array with spin, molecular orbital, and atomic orbitals as the axes, so that ``aoresults[1][46][1]`` gives the contribution of the 1st atomic orbital to the 46th alpha/restricted molecular orbital,
97+
- `fragresults`: a three dimensional array with spin, molecular orbital, and atoms as the axes, so that ``fragresults[1][24][5]`` gives the contribution of the 5th fragment orbitals to the 24th beta molecular orbital)
98+
- `fragcharges`: a vector with the number of (partial) electrons in each fragment, so that ``fragcharges[3]`` gives the number of electrons in the 3rd fragment.
99+
"""
100+
function bpa(file::String)
101+
data = cclib[].io.ccread(file)
102+
mol = cclib[].method.Bickelhaupt(data)
103+
mol.calculate()
104+
aoresults = mol.__dict__["aoresults"] |> expand
105+
fragresults = mol.__dict__["fragresults"] |> expand
106+
fragcharges = pyconvert(Array{Float64}, mol.__dict__["fragcharges"])
107+
return aoresults, fragresults, fragcharges
108+
end
109+
110+
"""
111+
density(file::String)
112+
113+
Density matrix calculation
114+
# Arguments
115+
- `file::String`: Cclib-supported output file
116+
# Returns
117+
- An array with three axes. The first axis is for the spin contributions,
118+
the second and the third axes for the density matrix, which follows standard definition.
119+
"""
120+
function density(file::String)
121+
data = cclib[].io.ccread(file)
122+
mol = cclib[].method.Density(data)
123+
mol.calculate()
124+
return pyconvert(Array{Float64}, mol.__dict__["density"])
125+
end
126+
127+
"""
128+
mbo(file::String)
129+
130+
Calculate Mayer's bond orders
131+
# Arguments
132+
- `file::String`: Cclib-supported output file
133+
# Returns
134+
- An array with three axes. The first axis is for contributions of each spin to the MBO,
135+
while the second and third correspond to the indices of the atoms.
136+
"""
137+
function mbo(file::String)
138+
data = cclib[].io.ccread(file)
139+
mol = cclib[].method.MBO(data)
140+
mol.calculate()
141+
return pyconvert(Array{Float64}, mol.__dict__["fragresults"])
142+
end
143+
144+
"""
145+
cda(file::String)
146+
147+
Charge decomposition analysis
148+
# Arguments
149+
- `mol::String`: Cclib-supported output file
150+
- `frag1::String`: Cclib-supported output file
151+
- `frag2::String`: Cclib-supported output file
152+
# Returns
153+
- Tuple (donations, backdonations, repulsions)
154+
donations, bdonations (back donations), and repulsions attributes.
155+
These attributes are simply lists of 1-dimensional arrays corresponding to the restricted or alpha/beta molecular orbitals of the entire molecule.
156+
"""
157+
function cda(mol::String, frag1::String, frag2::String)
158+
mol = cclib[].io.ccread(mol)
159+
frag1 = cclib[].io.ccread(frag1)
160+
frag2 = cclib[].io.ccread(frag2)
161+
mol = cclib[].method.CDA(mol)
162+
mol.calculate([frag1, frag2])
163+
donations = mol.__dict__["donations"] |> expand
164+
bdonations = mol.__dict__["bdonations"] |> expand
165+
repulsions = mol.__dict__["repulsions"] |> expand
166+
return donations, bdonations, repulsions
167+
end
168+
169+
# TODO: this requires PyQuante which doens't seem to work
170+
# when trying to install it into a conda env
171+
# """
172+
# bader(file::string)
173+
174+
# bader's qtaim charges calculation
175+
# # arguments
176+
# - `file::string`: cclib-supported output file
177+
# # returns
178+
# tuple (donations, backdonations, repulsions)
179+
# """
180+
# function bader(file::String, vol::Vector{Vector{Float64}})
181+
# data = cclib[].io.ccread(file)
182+
# vol = pytuple(pytuple(i) for i in vol)
183+
# vol = cclib[].method.volume(vol...)
184+
# mol = cclib[].method.bader(data, vol)
185+
# mol.calculate()
186+
# return mol
187+
# # aoresults = mol.__dict__["aoresults"] |> expand
188+
# # fragresults = mol.__dict__["fragresults"] |> expand
189+
# # fragcharges = pyconvert(array{float64}, mol.__dict__["fragcharges"])
190+
# # return aoresults, fragresults, fragcharges
191+
# end

0 commit comments

Comments
 (0)