Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# flake8: noqa 

2import numpy as np 

3from numpy import linalg 

4from ase import units 

5 

6# Three variables extracted from what used to be endless repetitions below. 

7Ax = np.array([[1, 0, 0, -1, 0, 0, 0, 0, 0], 

8 [0, 1, 0, 0, -1, 0, 0, 0, 0], 

9 [0, 0, 1, 0, 0, -1, 0, 0, 0], 

10 [0, 0, 0, -1, 0, 0, 1, 0, 0], 

11 [0, 0, 0, 0, -1, 0, 0, 1, 0], 

12 [0, 0, 0, 0, 0, -1, 0, 0, 1]]) 

13Bx = np.array([[1, 0, 0, -1, 0, 0], 

14 [0, 1, 0, 0, -1, 0], 

15 [0, 0, 1, 0, 0, -1]]) 

16Mx = Bx 

17 

18 

19 

20class Morse: 

21 def __init__(self, atomi, atomj, D, alpha, r0): 

22 self.atomi = atomi 

23 self.atomj = atomj 

24 self.D = D 

25 self.alpha = alpha 

26 self.r0 = r0 

27 self.r = None 

28 

29class Bond: 

30 def __init__(self, atomi, atomj, k, b0, 

31 alpha=None, rref=None): 

32 self.atomi = atomi 

33 self.atomj = atomj 

34 self.k = k 

35 self.b0 = b0 

36 self.alpha = alpha 

37 self.rref = rref 

38 self.b = None 

39 

40class Angle: 

41 def __init__(self, atomi, atomj, atomk, k, a0, cos=False, 

42 alpha=None, rref=None): 

43 self.atomi = atomi 

44 self.atomj = atomj 

45 self.atomk = atomk 

46 self.k = k 

47 self.a0 = a0 

48 self.cos = cos 

49 self.alpha = alpha 

50 self.rref = rref 

51 self.a = None 

52 

53class Dihedral: 

54 def __init__(self, atomi, atomj, atomk, atoml, k, d0=None, n=None, 

55 alpha=None, rref=None): 

56 self.atomi = atomi 

57 self.atomj = atomj 

58 self.atomk = atomk 

59 self.atoml = atoml 

60 self.k = k 

61 self.d0 = d0 

62 self.n = n 

63 self.alpha = alpha 

64 self.rref = rref 

65 self.d = None 

66 

67class VdW: 

68 def __init__(self, atomi, atomj, epsilonij=None, sigmaij=None, rminij=None, 

69 Aij=None, Bij=None, epsiloni=None, epsilonj=None, 

70 sigmai=None, sigmaj=None, rmini=None, rminj=None, scale=1.0): 

71 self.atomi = atomi 

72 self.atomj = atomj 

73 if epsilonij is not None: 

74 if sigmaij is not None: 

75 self.Aij = scale * 4.0 * epsilonij * sigmaij**12 

76 self.Bij = scale * 4.0 * epsilonij * sigmaij**6 * scale 

77 elif rminij is not None: 

78 self.Aij = scale * epsilonij * rminij**12 

79 self.Bij = scale * 2.0 * epsilonij * rminij**6 

80 else: 

81 raise NotImplementedError("not implemented combination" 

82 "of vdW parameters.") 

83 elif Aij is not None and Bij is not None: 

84 self.Aij = scale * Aij 

85 self.Bij = scale * Bij 

86 elif epsiloni is not None and epsilonj is not None: 

87 if sigmai is not None and sigmaj is not None: 

88 self.Aij = ( scale * 4.0 * np.sqrt(epsiloni * epsilonj) 

89 * ((sigmai + sigmaj) / 2.0)**12 ) 

90 self.Bij = ( scale * 2.0 * np.sqrt(epsiloni * epsilonj) 

91 * ((sigmai + sigmaj) / 2.0)**6 ) 

92 elif rmini is not None and rminj is not None: 

93 self.Aij = ( scale * np.sqrt(epsiloni * epsilonj) 

94 * ((rmini + rminj) / 2.0)**12 ) 

95 self.Bij = ( scale * 2.0 * np.sqrt(epsiloni * epsilonj) 

96 * ((rmini + rminj) / 2.0)**6 ) 

97 else: 

98 raise NotImplementedError("not implemented combination" 

99 "of vdW parameters.") 

100 self.r = None 

101 

102class Coulomb: 

103 def __init__(self, atomi, atomj, chargeij=None, 

104 chargei=None, chargej=None, scale=1.0): 

105 self.atomi = atomi 

106 self.atomj = atomj 

107 if chargeij is not None: 

108 self.chargeij = ( scale * chargeij * 8.9875517873681764e9 

109 * units.m * units.J / units.C / units.C ) 

110 elif chargei is not None and chargej is not None: 

111 self.chargeij = ( scale * chargei * chargej * 8.9875517873681764e9 

112 * units.m * units.J / units.C / units.C ) 

113 else: 

114 raise NotImplementedError("not implemented combination" 

115 "of Coulomb parameters.") 

116 self.r = None 

117 

118def get_morse_potential_eta(atoms, morse): 

119 i = morse.atomi 

120 j = morse.atomj 

121 

122 rij = rel_pos_pbc(atoms, i, j) 

123 dij = linalg.norm(rij) 

124 

125 if dij > morse.r0: 

126 exp = np.exp(-morse.alpha*(dij-morse.r0)) 

127 eta = 1.0 - (1.0 - exp)**2 

128 else: 

129 eta = 1.0 

130 

131 return eta 

132 

133def get_morse_potential_value(atoms, morse): 

134 i = morse.atomi 

135 j = morse.atomj 

136 

137 rij = rel_pos_pbc(atoms, i, j) 

138 dij = linalg.norm(rij) 

139 

140 exp = np.exp(-morse.alpha*(dij-morse.r0)) 

141 

142 v = morse.D*(1.0-exp)**2 

143 

144 morse.r = dij 

145 

146 return i, j, v 

147 

148def get_morse_potential_gradient(atoms, morse): 

149 i = morse.atomi 

150 j = morse.atomj 

151 

152 rij = rel_pos_pbc(atoms, i, j) 

153 dij = linalg.norm(rij) 

154 eij = rij/dij 

155 

156 exp = np.exp(-morse.alpha*(dij-morse.r0)) 

157 

158 gr = 2.0*morse.D*morse.alpha*exp*(1.0-exp)*eij 

159 

160 gx = np.dot(Mx.T, gr) 

161 

162 morse.r = dij 

163 

164 return i, j, gx 

165 

166def get_morse_potential_hessian(atoms, morse, spectral=False): 

167 i = morse.atomi 

168 j = morse.atomj 

169 

170 rij = rel_pos_pbc(atoms, i, j) 

171 dij = linalg.norm(rij) 

172 eij = rij/dij 

173 

174 Pij = np.tensordot(eij,eij,axes=0) 

175 Qij = np.eye(3)-Pij 

176 

177 exp = np.exp(-morse.alpha*(dij-morse.r0)) 

178 

179 Hr = ( 2.0*morse.D*morse.alpha*exp*(morse.alpha*(2.0*exp-1.0)*Pij 

180 + (1.0-exp)/dij*Qij) ) 

181 

182 Hx = np.dot(Mx.T, np.dot(Hr, Mx)) 

183 

184 if spectral: 

185 eigvals, eigvecs = linalg.eigh(Hx) 

186 D = np.diag(np.abs(eigvals)) 

187 U = eigvecs 

188 Hx = np.dot(U,np.dot(D,np.transpose(U))) 

189 

190 morse.r = dij 

191 

192 return i, j, Hx 

193 

194def get_morse_potential_reduced_hessian(atoms, morse): 

195 i = morse.atomi 

196 j = morse.atomj 

197 

198 rij = rel_pos_pbc(atoms, i, j) 

199 dij = linalg.norm(rij) 

200 eij = rij/dij 

201 

202 Pij = np.tensordot(eij,eij,axes=0) 

203 

204 exp = np.exp(-morse.alpha*(dij-morse.r0)) 

205 

206 Hr = np.abs(2.0*morse.D*morse.alpha**2*exp*(2.0*exp-1.0))*Pij 

207 

208 Hx = np.dot(Mx.T, np.dot(Hr, Mx)) 

209 

210 morse.r = dij 

211 

212 return i, j, Hx 

213 

214def get_bond_potential_value(atoms, bond): 

215 i = bond.atomi 

216 j = bond.atomj 

217 

218 rij = rel_pos_pbc(atoms, i, j) 

219 dij = linalg.norm(rij) 

220 

221 v = 0.5*bond.k*(dij-bond.b0)**2 

222 

223 bond.b = dij 

224 

225 return i, j, v 

226 

227def get_bond_potential_gradient(atoms, bond): 

228 i = bond.atomi 

229 j = bond.atomj 

230 

231 rij = rel_pos_pbc(atoms, i, j) 

232 dij = linalg.norm(rij) 

233 eij = rij/dij 

234 

235 gr = bond.k*(dij-bond.b0)*eij 

236 

237 gx = np.dot(Bx.T, gr) 

238 

239 bond.b = dij 

240 

241 return i, j, gx 

242 

243def get_bond_potential_hessian(atoms, bond, morses=None, spectral=False): 

244 i = bond.atomi 

245 j = bond.atomj 

246 

247 rij = rel_pos_pbc(atoms, i, j) 

248 dij = linalg.norm(rij) 

249 eij = rij/dij 

250 

251 Pij = np.tensordot(eij,eij,axes=0) 

252 Qij = np.eye(3)-Pij 

253 

254 Hr = bond.k*Pij+bond.k*(dij-bond.b0)/dij*Qij 

255 

256 if bond.alpha is not None: 

257 Hr *= np.exp(bond.alpha[0]*(bond.rref[0]**2-dij**2)) 

258 

259 if morses is not None: 

260 for m in range(len(morses)): 

261 if ( morses[m].atomi == i or 

262 morses[m].atomi == j ): 

263 Hr *= get_morse_potential_eta(atoms, morses[m]) 

264 elif ( morses[m].atomj == i or 

265 morses[m].atomj == j ): 

266 Hr *= get_morse_potential_eta(atoms, morses[m]) 

267 

268 Hx = np.dot(Bx.T, np.dot(Hr, Bx)) 

269 

270 if spectral: 

271 eigvals, eigvecs = linalg.eigh(Hx) 

272 D = np.diag(np.abs(eigvals)) 

273 U = eigvecs 

274 Hx = np.dot(U,np.dot(D,np.transpose(U))) 

275 

276 bond.b = dij 

277 

278 return i, j, Hx 

279 

280def get_bond_potential_reduced_hessian(atoms, bond, morses=None): 

281 i = bond.atomi 

282 j = bond.atomj 

283 

284 rij = rel_pos_pbc(atoms, i, j) 

285 dij = linalg.norm(rij) 

286 eij = rij/dij 

287 

288 Pij = np.tensordot(eij,eij,axes=0) 

289 

290 Hr = bond.k*Pij 

291 

292 if bond.alpha is not None: 

293 Hr *= np.exp(bond.alpha[0]*(bond.rref[0]**2-dij**2)) 

294 

295 if morses is not None: 

296 for m in range(len(morses)): 

297 if ( morses[m].atomi == i or 

298 morses[m].atomi == j ): 

299 Hr *= get_morse_potential_eta(atoms, morses[m]) 

300 elif ( morses[m].atomj == i or 

301 morses[m].atomj == j ): 

302 Hr *= get_morse_potential_eta(atoms, morses[m]) 

303 

304 Hx = np.dot(Bx.T, np.dot(Hr, Bx)) 

305 

306 bond.b = dij 

307 

308 return i, j, Hx 

309 

310def get_bond_potential_reduced_hessian_test(atoms, bond): 

311 

312 i, j, v = get_bond_potential_value(atoms, bond) 

313 i, j, gx = get_bond_potential_gradient(atoms, bond) 

314 

315 Hx = np.tensordot(gx,gx,axes=0)/v/2.0 

316 

317 return i, j, Hx 

318 

319def get_angle_potential_value(atoms, angle): 

320 

321 i = angle.atomi 

322 j = angle.atomj 

323 k = angle.atomk 

324 

325 rij = rel_pos_pbc(atoms, i, j) 

326 dij = linalg.norm(rij) 

327 eij = rij/dij 

328 rkj = rel_pos_pbc(atoms, k, j) 

329 dkj = linalg.norm(rkj) 

330 ekj = rkj/dkj 

331 eijekj = np.dot(eij, ekj) 

332 if np.abs(eijekj) > 1.0: 

333 eijekj = np.sign(eijekj) 

334 

335 a = np.arccos(eijekj) 

336 

337 if angle.cos: 

338 da = np.cos(a)-np.cos(angle.a0) 

339 else: 

340 da = a-angle.a0 

341 da = da - np.around(da / np.pi) * np.pi 

342 

343 v = 0.5*angle.k*da**2 

344 

345 angle.a = a 

346 

347 return i, j, k, v 

348 

349def get_angle_potential_gradient(atoms, angle): 

350 i = angle.atomi 

351 j = angle.atomj 

352 k = angle.atomk 

353 

354 rij = rel_pos_pbc(atoms, i, j) 

355 dij = linalg.norm(rij) 

356 eij = rij/dij 

357 rkj = rel_pos_pbc(atoms, k, j) 

358 dkj = linalg.norm(rkj) 

359 ekj = rkj/dkj 

360 eijekj = np.dot(eij, ekj) 

361 if np.abs(eijekj) > 1.0: 

362 eijekj = np.sign(eijekj) 

363 

364 a = np.arccos(eijekj) 

365 if angle.cos: 

366 da = np.cos(a)-np.cos(angle.a0) 

367 else: 

368 da = a-angle.a0 

369 da = da - np.around(da / np.pi) * np.pi 

370 sina = np.sin(a) 

371 

372 Pij = np.tensordot(eij,eij,axes=0) 

373 Qij = np.eye(3)-Pij 

374 Pkj = np.tensordot(ekj,ekj,axes=0) 

375 Qkj = np.eye(3)-Pkj 

376 

377 gr = np.zeros(6) 

378 if angle.cos: 

379 gr[0:3] = angle.k*da/dij*np.dot(Qij,ekj) 

380 gr[3:6] = angle.k*da/dkj*np.dot(Qkj,eij) 

381 elif np.abs(sina) > 0.001: 

382 gr[0:3] = -angle.k*da/sina/dij*np.dot(Qij,ekj) 

383 gr[3:6] = -angle.k*da/sina/dkj*np.dot(Qkj,eij) 

384 

385 gx = np.dot(Ax.T, gr) 

386 

387 angle.a = a 

388 

389 return i, j, k, gx 

390 

391def get_angle_potential_hessian(atoms, angle, morses=None, spectral=False): 

392 i = angle.atomi 

393 j = angle.atomj 

394 k = angle.atomk 

395 

396 rij = rel_pos_pbc(atoms, i, j) 

397 dij = linalg.norm(rij) 

398 dij2 = dij*dij 

399 eij = rij/dij 

400 rkj = rel_pos_pbc(atoms, k, j) 

401 dkj = linalg.norm(rkj) 

402 dkj2 = dkj*dkj 

403 ekj = rkj/dkj 

404 dijdkj = dij*dkj 

405 eijekj = np.dot(eij, ekj) 

406 if np.abs(eijekj) > 1.0: 

407 eijekj = np.sign(eijekj) 

408 

409 a = np.arccos(eijekj) 

410 if angle.cos: 

411 da = np.cos(a)-np.cos(angle.a0) 

412 cosa0 = np.cos(angle.a0) 

413 else: 

414 da = a-angle.a0 

415 da = da - np.around(da / np.pi) * np.pi 

416 sina = np.sin(a) 

417 cosa = np.cos(a) 

418 ctga = cosa/sina 

419 

420 Pij = np.tensordot(eij,eij,axes=0) 

421 Qij = np.eye(3)-Pij 

422 Pkj = np.tensordot(ekj,ekj,axes=0) 

423 Qkj = np.eye(3)-Pkj 

424 Pik = np.tensordot(eij,ekj,axes=0) 

425 Pki = np.tensordot(ekj,eij,axes=0) 

426 P = np.eye(3)*eijekj 

427 

428 QijPkjQij = np.dot(Qij, np.dot(Pkj, Qij)) 

429 QijPkiQkj = np.dot(Qij, np.dot(Pki, Qkj)) 

430 QkjPijQkj = np.dot(Qkj, np.dot(Pij, Qkj)) 

431 

432 Hr = np.zeros((6,6)) 

433 if angle.cos and np.abs(sina) > 0.001: 

434 factor = 1.0-2.0*cosa*cosa+cosa*cosa0 

435 Hr[0:3,0:3] = ( angle.k*(factor*QijPkjQij/sina 

436 - sina*da*(-ctga*QijPkjQij/sina+np.dot(Qij, Pki) 

437 -np.dot(Pij, Pki)*2.0+(Pik+P)))/sina/dij2 ) 

438 Hr[0:3,3:6] = ( angle.k*(factor*QijPkiQkj/sina 

439 - sina*da*(-ctga*QijPkiQkj/sina 

440 -np.dot(Qij, Qkj)))/sina/dijdkj ) 

441 Hr[3:6,0:3] = Hr[0:3,3:6].T 

442 Hr[3:6,3:6] = ( angle.k*(factor*QkjPijQkj/sina 

443 - sina*da*(-ctga*QkjPijQkj/sina 

444 +np.dot(Qkj, Pik)-np.dot(Pkj, Pik) 

445 *2.0+(Pki+P)))/sina/dkj2 ) 

446 elif np.abs(sina) > 0.001: 

447 Hr[0:3,0:3] = ( angle.k*(QijPkjQij/sina 

448 + da*(-ctga*QijPkjQij/sina+np.dot(Qij, Pki) 

449 -np.dot(Pij, Pki)*2.0+(Pik+P)))/sina/dij2 ) 

450 Hr[0:3,3:6] = ( angle.k*(QijPkiQkj/sina 

451 + da*(-ctga*QijPkiQkj/sina 

452 -np.dot(Qij, Qkj)))/sina/dijdkj ) 

453 Hr[3:6,0:3] = Hr[0:3,3:6].T 

454 Hr[3:6,3:6] = ( angle.k*(QkjPijQkj/sina 

455 + da*(-ctga*QkjPijQkj/sina 

456 +np.dot(Qkj, Pik)-np.dot(Pkj, Pik) 

457 *2.0+(Pki+P)))/sina/dkj2 ) 

458 

459 if angle.alpha is not None: 

460 Hr *= ( np.exp(angle.alpha[0]*(angle.rref[0]**2-dij**2)) 

461 *np.exp(angle.alpha[1]*(angle.rref[1]**2-dkj**2)) ) 

462 

463 if morses is not None: 

464 for m in range(len(morses)): 

465 if ( morses[m].atomi == i or 

466 morses[m].atomi == j or 

467 morses[m].atomi == k ): 

468 Hr *= get_morse_potential_eta(atoms, morses[m]) 

469 elif ( morses[m].atomj == i or 

470 morses[m].atomj == j or 

471 morses[m].atomj == k ): 

472 Hr *= get_morse_potential_eta(atoms, morses[m]) 

473 

474 Hx = np.dot(Ax.T, np.dot(Hr, Ax)) 

475 

476 if spectral: 

477 eigvals, eigvecs = linalg.eigh(Hx) 

478 D = np.diag(np.abs(eigvals)) 

479 U = eigvecs 

480 Hx = np.dot(U,np.dot(D,np.transpose(U))) 

481 

482 angle.a = a 

483 

484 return i, j, k, Hx 

485 

486def get_angle_potential_reduced_hessian(atoms, angle, morses=None): 

487 i = angle.atomi 

488 j = angle.atomj 

489 k = angle.atomk 

490 

491 rij = rel_pos_pbc(atoms, i, j) 

492 dij = linalg.norm(rij) 

493 dij2 = dij*dij 

494 eij = rij/dij 

495 rkj = rel_pos_pbc(atoms, k, j) 

496 dkj = linalg.norm(rkj) 

497 dkj2 = dkj*dkj 

498 ekj = rkj/dkj 

499 dijdkj = dij*dkj 

500 eijekj = np.dot(eij, ekj) 

501 if np.abs(eijekj) > 1.0: 

502 eijekj = np.sign(eijekj) 

503 

504 a = np.arccos(eijekj) 

505 sina = np.sin(a) 

506 sina2 = sina*sina 

507 

508 Pij = np.tensordot(eij,eij,axes=0) 

509 Qij = np.eye(3)-Pij 

510 Pkj = np.tensordot(ekj,ekj,axes=0) 

511 Qkj = np.eye(3)-Pkj 

512 Pki = np.tensordot(ekj,eij,axes=0) 

513 

514 Hr = np.zeros((6,6)) 

515 if np.abs(sina) > 0.001: 

516 Hr[0:3,0:3] = np.dot(Qij, np.dot(Pkj, Qij))/dij2 

517 Hr[0:3,3:6] = np.dot(Qij, np.dot(Pki, Qkj))/dijdkj 

518 Hr[3:6,0:3] = Hr[0:3,3:6].T 

519 Hr[3:6,3:6] = np.dot(Qkj, np.dot(Pij, Qkj))/dkj2 

520 

521 if angle.cos and np.abs(sina) > 0.001: 

522 cosa = np.cos(a) 

523 cosa0 = np.cos(angle.a0) 

524 factor = np.abs(1.0-2.0*cosa*cosa+cosa*cosa0) 

525 Hr = Hr*factor*angle.k/sina2 

526 elif np.abs(sina) > 0.001: 

527 Hr = Hr*angle.k/sina2 

528 

529 if angle.alpha is not None: 

530 Hr *= ( np.exp(angle.alpha[0]*(angle.rref[0]**2-dij**2)) 

531 *np.exp(angle.alpha[1]*(angle.rref[1]**2-dkj**2)) ) 

532 

533 if morses is not None: 

534 for m in range(len(morses)): 

535 if ( morses[m].atomi == i or 

536 morses[m].atomi == j or 

537 morses[m].atomi == k ): 

538 Hr *= get_morse_potential_eta(atoms, morses[m]) 

539 elif ( morses[m].atomj == i or 

540 morses[m].atomj == j or 

541 morses[m].atomj == k ): 

542 Hr *= get_morse_potential_eta(atoms, morses[m]) 

543 

544 Hx=np.dot(Ax.T, np.dot(Hr, Ax)) 

545 

546 angle.a = a 

547 

548 return i, j, k, Hx 

549 

550def get_angle_potential_reduced_hessian_test(atoms, angle): 

551 i, j, k, v = get_angle_potential_value(atoms, angle) 

552 i, j, k, gx = get_angle_potential_gradient(atoms, angle) 

553 

554 Hx = np.tensordot(gx,gx,axes=0)/v/2.0 

555 

556 return i, j, k, Hx 

557 

558def get_dihedral_potential_value(atoms, dihedral): 

559 i = dihedral.atomi 

560 j = dihedral.atomj 

561 k = dihedral.atomk 

562 l = dihedral.atoml 

563 

564 rij = rel_pos_pbc(atoms, i, j) 

565 rkj = rel_pos_pbc(atoms, k, j) 

566 rkl = rel_pos_pbc(atoms, k, l) 

567 

568 rmj = np.cross(rij, rkj) 

569 dmj = linalg.norm(rmj) 

570 emj = rmj/dmj 

571 rnk = np.cross(rkj, rkl) 

572 dnk = linalg.norm(rnk) 

573 enk = rnk/dnk 

574 emjenk = np.dot(emj, enk) 

575 if np.abs(emjenk) > 1.0: 

576 emjenk = np.sign(emjenk) 

577 

578 d = np.sign(np.dot(rkj, np.cross(rmj, rnk)))*np.arccos(emjenk) 

579 

580 if dihedral.d0 is None: 

581 v = 0.5*dihedral.k*(1.0 - np.cos(2.0 * d)) 

582 else: 

583 dd = d-dihedral.d0 

584 dd = dd - np.around(dd / np.pi / 2.0) * np.pi * 2.0 

585 if dihedral.n is None: 

586 v = 0.5*dihedral.k*dd**2 

587 else: 

588 v = dihedral.k*(1.0 + np.cos(dihedral.n*d - dihedral.d0)) 

589 

590 dihedral.d = d 

591 

592 return i, j, k, l, v 

593 

594def get_dihedral_potential_gradient(atoms, dihedral): 

595 i = dihedral.atomi 

596 j = dihedral.atomj 

597 k = dihedral.atomk 

598 l = dihedral.atoml 

599 

600 rij = rel_pos_pbc(atoms, i, j) 

601 rkj = rel_pos_pbc(atoms, k, j) 

602 dkj = linalg.norm(rkj) 

603 dkj2 = dkj*dkj 

604 rkl = rel_pos_pbc(atoms, k, l) 

605 

606 rijrkj = np.dot(rij, rkj) 

607 rkjrkl = np.dot(rkj, rkl) 

608 

609 rmj = np.cross(rij, rkj) 

610 dmj = linalg.norm(rmj) 

611 dmj2 = dmj*dmj 

612 emj = rmj/dmj 

613 rnk = np.cross(rkj, rkl) 

614 dnk = linalg.norm(rnk) 

615 dnk2 = dnk*dnk 

616 enk = rnk/dnk 

617 emjenk = np.dot(emj, enk) 

618 if np.abs(emjenk) > 1.0: 

619 emjenk = np.sign(emjenk) 

620 

621 dddri = dkj/dmj2*rmj 

622 dddrl = -dkj/dnk2*rnk 

623 

624 gx = np.zeros(12) 

625 

626 gx[0:3] = dddri 

627 gx[3:6] = (rijrkj/dkj2-1.0)*dddri-rkjrkl/dkj2*dddrl 

628 gx[6:9] = (rkjrkl/dkj2-1.0)*dddrl-rijrkj/dkj2*dddri 

629 gx[9:12] = dddrl 

630 

631 d = np.sign(np.dot(rkj, np.cross(rmj, rnk)))*np.arccos(emjenk) 

632 

633 if dihedral.d0 is None: 

634 gx *= dihedral.k*np.sin(2.0 * d) 

635 else: 

636 dd = d-dihedral.d0 

637 dd = dd - np.around(dd / np.pi / 2.0) * np.pi * 2.0 

638 if dihedral.n is None: 

639 gx *= dihedral.k*dd 

640 else: 

641 gx *= -dihedral.k*dihedral.n*np.sin(dihedral.n*d - dihedral.d0) 

642 

643 dihedral.d = d 

644 

645 return i, j, k, l, gx 

646 

647def get_dihedral_potential_hessian(atoms, dihedral, morses=None, 

648 spectral=False): 

649 eps = 0.000001 

650 

651 i,j,k,l,g = get_dihedral_potential_gradient(atoms, dihedral) 

652 

653 Hx = np.zeros((12,12)) 

654 

655 dihedral_eps = Dihedral(dihedral.atomi, dihedral.atomj, 

656 dihedral.atomk, dihedral.atoml, 

657 dihedral.k, dihedral.d0, dihedral.n) 

658 indx = [3*i, 3*i+1, 3*i+2, 

659 3*j, 3*j+1, 3*j+2, 

660 3*k, 3*k+1, 3*k+2, 

661 3*l, 3*l+1, 3*l+2] 

662 for x in range(12): 

663 a = atoms.copy() 

664 positions = np.reshape(a.get_positions(),-1) 

665 positions[indx[x]] += eps 

666 a.set_positions(np.reshape(positions, (len(a),3))) 

667 i,j,k,l,geps = get_dihedral_potential_gradient(a, dihedral_eps) 

668 for y in range(12): 

669 Hx[x,y] += 0.5*(geps[y]-g[y])/eps 

670 Hx[y,x] += 0.5*(geps[y]-g[y])/eps 

671 

672 if dihedral.alpha is not None: 

673 rij = rel_pos_pbc(atoms, i, j) 

674 dij = linalg.norm(rij) 

675 rkj = rel_pos_pbc(atoms, k, j) 

676 dkj = linalg.norm(rkj) 

677 rkl = rel_pos_pbc(atoms, k, l) 

678 dkl = linalg.norm(rkl) 

679 Hx *= ( np.exp(dihedral.alpha[0]*(dihedral.rref[0]**2-dij**2)) 

680 *np.exp(dihedral.alpha[1]*(dihedral.rref[1]**2-dkj**2)) 

681 *np.exp(dihedral.alpha[2]*(dihedral.rref[2]**2-dkl**2)) ) 

682 

683 if morses is not None: 

684 for m in range(len(morses)): 

685 if ( morses[m].atomi == i or 

686 morses[m].atomi == j or 

687 morses[m].atomi == k or 

688 morses[m].atomi == l ): 

689 Hx *= get_morse_potential_eta(atoms, morses[m]) 

690 elif ( morses[m].atomj == i or 

691 morses[m].atomj == j or 

692 morses[m].atomj == k or 

693 morses[m].atomj == l ): 

694 Hx *= get_morse_potential_eta(atoms, morses[m]) 

695 

696 if spectral: 

697 eigvals, eigvecs = linalg.eigh(Hx) 

698 D = np.diag(np.abs(eigvals)) 

699 U = eigvecs 

700 Hx = np.dot(U,np.dot(D,np.transpose(U))) 

701 

702 return i, j, k, l, Hx 

703 

704def get_dihedral_potential_reduced_hessian(atoms, dihedral, morses=None): 

705 i = dihedral.atomi 

706 j = dihedral.atomj 

707 k = dihedral.atomk 

708 l = dihedral.atoml 

709 

710 rij = rel_pos_pbc(atoms, i, j) 

711 rkj = rel_pos_pbc(atoms, k, j) 

712 dkj = linalg.norm(rkj) 

713 dkj2 = dkj*dkj 

714 rkl = rel_pos_pbc(atoms, k, l) 

715 

716 rijrkj = np.dot(rij, rkj) 

717 rkjrkl = np.dot(rkj, rkl) 

718 

719 rmj = np.cross(rij, rkj) 

720 dmj = linalg.norm(rmj) 

721 dmj2 = dmj*dmj 

722 emj = rmj/dmj 

723 rnk = np.cross(rkj, rkl) 

724 dnk = linalg.norm(rnk) 

725 dnk2 = dnk*dnk 

726 enk = rnk/dnk 

727 emjenk = np.dot(emj, enk) 

728 if np.abs(emjenk) > 1.0: 

729 emjenk = np.sign(emjenk) 

730 

731 d = np.sign(np.dot(rkj, np.cross(rmj, rnk)))*np.arccos(emjenk) 

732 

733 dddri = dkj/dmj2*rmj 

734 dddrl = -dkj/dnk2*rnk 

735 

736 gx = np.zeros(12) 

737 

738 gx[0:3] = dddri 

739 gx[3:6] = (rijrkj/dkj2-1.0)*dddri-rkjrkl/dkj2*dddrl 

740 gx[6:9] = (rkjrkl/dkj2-1.0)*dddrl-rijrkj/dkj2*dddri 

741 gx[9:12] = dddrl 

742 

743 if dihedral.d0 is None: 

744 Hx = np.abs(2.0*dihedral.k*np.cos(2.0 * d))*np.tensordot(gx,gx,axes=0) 

745 if dihedral.n is None: 

746 Hx = dihedral.k*np.tensordot(gx,gx,axes=0) 

747 else: 

748 Hx = ( np.abs(-dihedral.k*dihedral.n**2 

749 *np.cos(dihedral.n*d-dihedral.d0))*np.tensordot(gx,gx,axes=0) ) 

750 

751 if dihedral.alpha is not None: 

752 rij = rel_pos_pbc(atoms, i, j) 

753 dij = linalg.norm(rij) 

754 rkj = rel_pos_pbc(atoms, k, j) 

755 dkj = linalg.norm(rkj) 

756 rkl = rel_pos_pbc(atoms, k, l) 

757 dkl = linalg.norm(rkl) 

758 Hx *= ( np.exp(dihedral.alpha[0]*(dihedral.rref[0]**2-dij**2)) 

759 *np.exp(dihedral.alpha[1]*(dihedral.rref[1]**2-dkj**2)) 

760 *np.exp(dihedral.alpha[2]*(dihedral.rref[2]**2-dkl**2)) ) 

761 

762 if morses is not None: 

763 for m in range(len(morses)): 

764 if ( morses[m].atomi == i or 

765 morses[m].atomi == j or 

766 morses[m].atomi == k or 

767 morses[m].atomi == l ): 

768 Hx *= get_morse_potential_eta(atoms, morses[m]) 

769 elif ( morses[m].atomj == i or 

770 morses[m].atomj == j or 

771 morses[m].atomj == k or 

772 morses[m].atomj == l ): 

773 Hx *= get_morse_potential_eta(atoms, morses[m]) 

774 

775 dihedral.d = d 

776 

777 return i, j, k, l, Hx 

778 

779def get_dihedral_potential_reduced_hessian_test(atoms, dihedral): 

780 i, j, k, l, gx = get_dihedral_potential_gradient(atoms, dihedral) 

781 

782 if dihedral.n is None: 

783 i, j, k, l, v = get_dihedral_potential_value(atoms, dihedral) 

784 Hx = np.tensordot(gx,gx,axes=0)/v/2.0 

785 else: 

786 arg = dihedral.n*dihedral.d - dihedral.d0 

787 Hx = ( np.tensordot(gx,gx,axes=0)/dihedral.k/np.sin(arg)/np.sin(arg) 

788 *np.cos(arg) ) 

789 

790 return i, j, k, l, Hx 

791 

792def get_vdw_potential_value(atoms, vdw): 

793 i = vdw.atomi 

794 j = vdw.atomj 

795 

796 rij = rel_pos_pbc(atoms, i, j) 

797 dij = linalg.norm(rij) 

798 

799 v = vdw.Aij/dij**12 - vdw.Bij/dij**6 

800 

801 vdw.r = dij 

802 

803 return i, j, v 

804 

805def get_vdw_potential_gradient(atoms, vdw): 

806 i = vdw.atomi 

807 j = vdw.atomj 

808 

809 rij = rel_pos_pbc(atoms, i, j) 

810 dij = linalg.norm(rij) 

811 eij = rij/dij 

812 

813 gr = (-12.0*vdw.Aij/dij**13+6.0*vdw.Bij/dij**7)*eij 

814 

815 gx = np.dot(Bx.T, gr) 

816 

817 vdw.r = dij 

818 

819 return i, j, gx 

820 

821def get_vdw_potential_hessian(atoms, vdw, spectral=False): 

822 i = vdw.atomi 

823 j = vdw.atomj 

824 

825 rij = rel_pos_pbc(atoms, i, j) 

826 dij = linalg.norm(rij) 

827 eij = rij/dij 

828 

829 Pij = np.tensordot(eij,eij,axes=0) 

830 Qij = np.eye(3)-Pij 

831 

832 Hr = ( (156.0*vdw.Aij/dij**14-42.0*vdw.Bij/dij**8)*Pij 

833 +(-12.0*vdw.Aij/dij**13+6.0*vdw.Bij/dij**7)/dij*Qij ) 

834 

835 Hx = np.dot(Bx.T, np.dot(Hr, Bx)) 

836 

837 if spectral: 

838 eigvals, eigvecs = linalg.eigh(Hx) 

839 D = np.diag(np.abs(eigvals)) 

840 U = eigvecs 

841 Hx = np.dot(U,np.dot(D,np.transpose(U))) 

842 

843 vdw.r = dij 

844 

845 return i, j, Hx 

846 

847def get_coulomb_potential_value(atoms, coulomb): 

848 i = coulomb.atomi 

849 j = coulomb.atomj 

850 

851 rij = rel_pos_pbc(atoms, i, j) 

852 dij = linalg.norm(rij) 

853 

854 v = coulomb.chargeij/dij 

855 

856 coulomb.r = dij 

857 

858 return i, j, v 

859 

860def get_coulomb_potential_gradient(atoms, coulomb): 

861 i = coulomb.atomi 

862 j = coulomb.atomj 

863 

864 rij = rel_pos_pbc(atoms, i, j) 

865 dij = linalg.norm(rij) 

866 eij = rij/dij 

867 

868 gr = -coulomb.chargeij/dij/dij*eij 

869 

870 gx = np.dot(Bx.T, gr) 

871 

872 coulomb.r = dij 

873 

874 return i, j, gx 

875 

876def get_coulomb_potential_hessian(atoms, coulomb, spectral=False): 

877 i = coulomb.atomi 

878 j = coulomb.atomj 

879 

880 rij = rel_pos_pbc(atoms, i, j) 

881 dij = linalg.norm(rij) 

882 eij = rij/dij 

883 

884 Pij = np.tensordot(eij,eij,axes=0) 

885 Qij = np.eye(3)-Pij 

886 

887 Hr = (2.0*coulomb.chargeij/dij**3)*Pij+(-coulomb.chargeij/dij/dij)/dij*Qij 

888 

889 Hx = np.dot(Bx.T, np.dot(Hr, Bx)) 

890 

891 if spectral: 

892 eigvals, eigvecs = linalg.eigh(Hx) 

893 D = np.diag(np.abs(eigvals)) 

894 U = eigvecs 

895 Hx = np.dot(U,np.dot(D,np.transpose(U))) 

896 

897 coulomb.r = dij 

898 

899 return i, j, Hx 

900 

901def rel_pos_pbc(atoms, i, j): 

902 """ 

903 Return difference between two atomic positions,  

904 correcting for jumps across PBC 

905 """ 

906 d = atoms.get_positions()[i,:]-atoms.get_positions()[j,:] 

907 g = linalg.inv(atoms.get_cell().T) 

908 f = np.floor(np.dot(g, d.T) + 0.5) 

909 d -= np.dot(atoms.get_cell().T, f).T 

910 return d