|
22 | 22 | from gbasis.wrappers import from_iodata
|
23 | 23 |
|
24 | 24 | 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 |
26 | 27 | from gbasis.evals.density import evaluate_posdef_kinetic_energy_density as eval_pd_ked
|
27 |
| -from gbasis.evals.density import evaluate_basis |
28 | 28 | from gbasis.evals.eval_deriv import evaluate_deriv_basis
|
| 29 | +from gbasis.evals.eval import evaluate_basis |
29 | 30 |
|
30 | 31 | from grid.onedgrid import UniformInteger
|
31 | 32 | from grid.rtransform import ExpRTransform
|
|
61 | 62 |
|
62 | 63 |
|
63 | 64 | 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 | + """ |
64 | 90 | bname = basis_name.lower().replace("-", "").replace("*", "p").replace("+", "d")
|
65 | 91 | prefix = f"atom_{str(n_atom).zfill(3)}_{element}"
|
66 | 92 | tag = f"N{str(n_elec).zfill(2)}_M{multi}"
|
@@ -96,6 +122,178 @@ def eval_orbs_density(one_density_matrix, orb_eval):
|
96 | 122 | return density
|
97 | 123 |
|
98 | 124 |
|
| 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 | + |
99 | 297 | def eval_orb_ked(one_density_matrix, basis, points, transform=None, coord_type="spherical"):
|
100 | 298 | "Adapted from Gbasis"
|
101 | 299 | orbt_ked = 0
|
@@ -157,6 +355,8 @@ def run(elem, charge, mult, nexc, dataset, datapath):
|
157 | 355 | orb_dens_dn = eval_orbs_density(dm1_dn, orb_eval)
|
158 | 356 | dens_tot = eval_dens(dm1_tot, obasis, atgrid.points, coord_type=coord_types, transform=None)
|
159 | 357 |
|
| 358 | + # compute radial derivatives of the density |
| 359 | + |
160 | 360 | # Compute kinetic energy density
|
161 | 361 | orb_ked_up = eval_orb_ked(dm1_up, obasis, atgrid.points, transform=None, coord_type=coord_types)
|
162 | 362 | orb_ked_dn = eval_orb_ked(dm1_dn, obasis, atgrid.points, transform=None, coord_type=coord_types)
|
|
0 commit comments