Skip to content

Commit f5e74e7

Browse files
authored
Merge pull request #40 from theochem/rho_components_derivs
Radial derivatives for orbital components of rho
2 parents 968ebf1 + 3837506 commit f5e74e7

File tree

6 files changed

+1271
-4
lines changed

6 files changed

+1271
-4
lines changed

.github/workflows/pytest.yaml

+11-1
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,21 @@ jobs:
3838
run: |
3939
pip install -v .
4040
41-
- name: Run pytest
41+
- name: Run pytest default tests
4242
uses: pavelzw/pytest-action@v2
4343
with:
4444
verbose: true
4545
emoji: true
4646
job-summary: true
4747
click-to-expand: true
4848
report-title: 'Test Report'
49+
50+
- name: Run pytest Dev Tests
51+
uses: pavelzw/pytest-action@v2
52+
with:
53+
verbose: true
54+
emoji: true
55+
job-summary: true
56+
click-to-expand: true
57+
report-title: 'Dev Test Report'
58+
pytest-args: '-m dev'

atomdb/datasets/gaussian/__init__.py

+202-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
from gbasis.wrappers import from_iodata
2323

2424
from gbasis.evals.density import evaluate_density as eval_dens
25-
from gbasis.evals.density import evaluate_deriv_density as eval_d_dens
25+
from gbasis.evals.density import evaluate_density_gradient
26+
from gbasis.evals.density import evaluate_density_hessian
2627
from gbasis.evals.density import evaluate_posdef_kinetic_energy_density as eval_pd_ked
27-
from gbasis.evals.density import evaluate_basis
2828
from gbasis.evals.eval_deriv import evaluate_deriv_basis
29+
from gbasis.evals.eval import evaluate_basis
2930

3031
from grid.onedgrid import UniformInteger
3132
from grid.rtransform import ExpRTransform
@@ -61,6 +62,31 @@
6162

6263

6364
def _load_fchk(n_atom, element, n_elec, multi, basis_name, data_path):
65+
r"""Load Gaussian fchk file and return the iodata object
66+
67+
This function finds the fchk file in the data directory corresponding to the given parameters,
68+
loads it and returns the iodata object.
69+
70+
Parameters
71+
----------
72+
n_atom : int
73+
Atomic number
74+
element : str
75+
Chemical symbol of the species
76+
n_elec : int
77+
Number of electrons
78+
multi : int
79+
Multiplicity
80+
basis_name : str
81+
Basis set name
82+
data_path : str
83+
Path to the data directory
84+
85+
Returns
86+
-------
87+
iodata : iodata.IOData
88+
Iodata object containing the data from the fchk file
89+
"""
6490
bname = basis_name.lower().replace("-", "").replace("*", "p").replace("+", "d")
6591
prefix = f"atom_{str(n_atom).zfill(3)}_{element}"
6692
tag = f"N{str(n_elec).zfill(2)}_M{multi}"
@@ -96,6 +122,178 @@ def eval_orbs_density(one_density_matrix, orb_eval):
96122
return density
97123

98124

125+
def eval_orbs_radial_d_density(one_density_matrix, basis, points, transform=None):
126+
"""Compute the radial derivative of the density orbital components.
127+
128+
For a set of points, compute the radial derivative of the density component for each orbital
129+
given the basis set and the basis transformation matrix.
130+
131+
Parameters
132+
----------
133+
one_density_matrix : np.ndarray(K_orb, K_orb)
134+
One-electron density matrix in terms of the given basis set.
135+
basis : gbasis.basis.Basis
136+
Basis set used to evaluate the radial derivative of the density
137+
points : np.ndarray(N, 3)
138+
Cartesian coordinates of the points in space (in atomic units) where the derivatives
139+
are evaluated.
140+
Rows correspond to the points and columns correspond to the :math:`x, y, \text{and} z`
141+
components.
142+
143+
Returns
144+
-------
145+
radial_orb_d_dens : np.ndarray(K, N)
146+
Radial derivative of the density at the set of points for each orbital component.
147+
"""
148+
# compute the basis values for the points output shape (K, N)
149+
basis_val = evaluate_basis(basis, points, transform=transform)
150+
151+
# compute unitary vectors for the directions of the points
152+
unitvect_pts = points / np.linalg.norm(points, axis=1)[:, None]
153+
154+
# array to store the radial derivative of the density (orbital components)
155+
output = np.zeros_like(basis_val)
156+
157+
# orders for the cartesian directions
158+
orders_one = np.array(([1, 0, 0], [0, 1, 0], [0, 0, 1]))
159+
160+
# for each cartesian direction
161+
for ind, orders in enumerate(orders_one):
162+
# compute the derivative of each orbital for the cartesian direction
163+
deriv_comp = evaluate_deriv_basis(basis, points, orders, transform)
164+
# compute matrix product of 1RDM and d|phi_i|^2/dx(or y or z) for each point
165+
density = 2 * one_density_matrix @ basis_val * deriv_comp
166+
# project derivative components to the radial component
167+
density *= unitvect_pts[:, ind]
168+
169+
output += density
170+
return output
171+
172+
173+
def eval_orbs_radial_dd_density(one_density_matrix, basis, points, transform=None):
174+
"""Compute the radial second derivative of the density orbital components.
175+
176+
For a set of points, compute the radial second derivative of the density component for each
177+
orbital given the basis set and the basis transformation matrix.
178+
179+
Parameters
180+
----------
181+
one_density_matrix : np.ndarray(K_orb, K_orb)
182+
One-electron density matrix in terms of the given basis set.
183+
basis : gbasis.basis.Basis
184+
Basis set used to evaluate the radial derivative of the density
185+
points : np.ndarray(N, 3)
186+
Cartesian coordinates of the points in space (in atomic units) where the derivatives
187+
are evaluated.
188+
Rows correspond to the points and columns correspond to the :math:`x, y, \text{and} z`
189+
components.
190+
191+
Returns
192+
-------
193+
radial_dd_orb_dens : np.ndarray(K, N)
194+
Radial second derivative of the density at the set of points for each orbital component.
195+
"""
196+
# compute unitary vectors for the directions of the points
197+
unitvect_pts = points / np.linalg.norm(points, axis=1)[:, None]
198+
199+
# compute the basis values for the points output shape (K, N)
200+
orb_val = evaluate_basis(basis, points, transform=transform)
201+
202+
# compute first order derivatives of the basis for the points
203+
orb_d_x = evaluate_deriv_basis(basis, points, np.array([1, 0, 0]), transform)
204+
orb_d_y = evaluate_deriv_basis(basis, points, np.array([0, 1, 0]), transform)
205+
orb_d_z = evaluate_deriv_basis(basis, points, np.array([0, 0, 1]), transform)
206+
207+
# assemble the gradient of basis functions for the points
208+
orb_1d = np.array([orb_d_x, orb_d_y, orb_d_z])
209+
210+
# array to store the radial second derivative of the orbital components of density, shape (K, N)
211+
output = np.zeros((one_density_matrix.shape[0], points.shape[0]))
212+
213+
# for each distinct element of the Hessian
214+
for i in range(3):
215+
for j in range(i + 1):
216+
# cartesian orders for the hessian element [i, j]
217+
hess_order = np.array([0, 0, 0])
218+
hess_order[i] += 1
219+
hess_order[j] += 1
220+
221+
# derivative of the basis for the points with order hess_order
222+
orb_dd_ij = evaluate_deriv_basis(basis, points, hess_order, transform)
223+
224+
# compute hessian of orbital contributions to the density
225+
# 2 * (dphi/di * 1RDM @ dphi/dj + phi * 1RDM @ Hij)
226+
dd_rho_orb_ij = 2 * (
227+
np.einsum("il,ij,jl -> jl", orb_dd_ij, one_density_matrix, orb_val)
228+
+ np.einsum("il,ij,jl -> jl", orb_1d[i], one_density_matrix, orb_1d[j])
229+
)
230+
231+
# project the hessian of the orbital contributions to the density to the radial component
232+
increment = np.einsum(
233+
"i,ji,i -> ji", unitvect_pts[:, i], dd_rho_orb_ij, unitvect_pts[:, j]
234+
)
235+
# add the contribution to the output
236+
output += increment
237+
# if element not in the diagonal, add the symmetric contribution
238+
if i != j:
239+
output += increment
240+
return output
241+
242+
243+
def eval_radial_d_density(one_density_matrix, basis, points):
244+
"""Compute the radial derivative of the density.
245+
246+
For a set of points, compute the radial derivative of the density
247+
given the one-electron density matrix and the basis set.
248+
249+
Parameters
250+
----------
251+
one_density_matrix : np.ndarray(K_orb, K_orb)
252+
One-electron density matrix (1DM) from K orbitals
253+
basis : gbasis.basis.Basis
254+
Basis set used to evaluate the radial derivative of the density
255+
points : np.ndarray(N, 3)
256+
Set of points where the radial derivative of the density is evaluated
257+
258+
Returns
259+
-------
260+
radial_d_density : np.ndarray(N)
261+
Radial derivative of the density at the set of points
262+
"""
263+
rho_grad = evaluate_density_gradient(one_density_matrix, basis, points)
264+
# compute unitary vectors for the directions of the points
265+
unitvect_pts = points / np.linalg.norm(points, axis=1)[:, None]
266+
# compute the radial derivative of the density
267+
return np.einsum("ij,ij->i", unitvect_pts, rho_grad)
268+
269+
270+
def eval_radial_dd_density(one_density_matrix, basis, points):
271+
"""Compute the radial derivative of the density.
272+
273+
For a set of points, compute the radial derivative of the density
274+
given the one-electron density matrix and the basis set.
275+
276+
Parameters
277+
----------
278+
one_density_matrix : np.ndarray(K_orb, K_orb)
279+
One-electron density matrix (1DM) from K orbitals
280+
basis : gbasis.basis.Basis
281+
Basis set used to evaluate the radial derivative of the density
282+
points : np.ndarray(N, 3)
283+
Set of points where the radial derivative of the density is evaluated
284+
285+
Returns
286+
-------
287+
radial_dd_density : np.ndarray(N)
288+
Radial derivative of the density at the set of points
289+
"""
290+
rho_hess = evaluate_density_hessian(one_density_matrix, basis, points)
291+
# compute unitary vectors for the directions of the points
292+
unitvect_pts = points / np.linalg.norm(points, axis=1)[:, None]
293+
# compute the radial second derivative of the density
294+
return np.einsum("ij,ijk,ik->i", unitvect_pts, rho_hess, unitvect_pts)
295+
296+
99297
def eval_orb_ked(one_density_matrix, basis, points, transform=None, coord_type="spherical"):
100298
"Adapted from Gbasis"
101299
orbt_ked = 0
@@ -157,6 +355,8 @@ def run(elem, charge, mult, nexc, dataset, datapath):
157355
orb_dens_dn = eval_orbs_density(dm1_dn, orb_eval)
158356
dens_tot = eval_dens(dm1_tot, obasis, atgrid.points, coord_type=coord_types, transform=None)
159357

358+
# compute radial derivatives of the density
359+
160360
# Compute kinetic energy density
161361
orb_ked_up = eval_orb_ked(dm1_up, obasis, atgrid.points, transform=None, coord_type=coord_types)
162362
orb_ked_dn = eval_orb_ked(dm1_dn, obasis, atgrid.points, transform=None, coord_type=coord_types)

0 commit comments

Comments
 (0)