MultiOptPy 1.20.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. multioptpy/Calculator/__init__.py +0 -0
  2. multioptpy/Calculator/ase_calculation_tools.py +424 -0
  3. multioptpy/Calculator/ase_tools/__init__.py +0 -0
  4. multioptpy/Calculator/ase_tools/fairchem.py +28 -0
  5. multioptpy/Calculator/ase_tools/gamess.py +19 -0
  6. multioptpy/Calculator/ase_tools/gaussian.py +165 -0
  7. multioptpy/Calculator/ase_tools/mace.py +28 -0
  8. multioptpy/Calculator/ase_tools/mopac.py +19 -0
  9. multioptpy/Calculator/ase_tools/nwchem.py +31 -0
  10. multioptpy/Calculator/ase_tools/orca.py +22 -0
  11. multioptpy/Calculator/ase_tools/pygfn0.py +37 -0
  12. multioptpy/Calculator/dxtb_calculation_tools.py +344 -0
  13. multioptpy/Calculator/emt_calculation_tools.py +458 -0
  14. multioptpy/Calculator/gpaw_calculation_tools.py +183 -0
  15. multioptpy/Calculator/lj_calculation_tools.py +314 -0
  16. multioptpy/Calculator/psi4_calculation_tools.py +334 -0
  17. multioptpy/Calculator/pwscf_calculation_tools.py +189 -0
  18. multioptpy/Calculator/pyscf_calculation_tools.py +327 -0
  19. multioptpy/Calculator/sqm1_calculation_tools.py +611 -0
  20. multioptpy/Calculator/sqm2_calculation_tools.py +376 -0
  21. multioptpy/Calculator/tblite_calculation_tools.py +352 -0
  22. multioptpy/Calculator/tersoff_calculation_tools.py +818 -0
  23. multioptpy/Constraint/__init__.py +0 -0
  24. multioptpy/Constraint/constraint_condition.py +834 -0
  25. multioptpy/Coordinate/__init__.py +0 -0
  26. multioptpy/Coordinate/polar_coordinate.py +199 -0
  27. multioptpy/Coordinate/redundant_coordinate.py +638 -0
  28. multioptpy/IRC/__init__.py +0 -0
  29. multioptpy/IRC/converge_criteria.py +28 -0
  30. multioptpy/IRC/dvv.py +544 -0
  31. multioptpy/IRC/euler.py +439 -0
  32. multioptpy/IRC/hpc.py +564 -0
  33. multioptpy/IRC/lqa.py +540 -0
  34. multioptpy/IRC/modekill.py +662 -0
  35. multioptpy/IRC/rk4.py +579 -0
  36. multioptpy/Interpolation/__init__.py +0 -0
  37. multioptpy/Interpolation/adaptive_interpolation.py +283 -0
  38. multioptpy/Interpolation/binomial_interpolation.py +179 -0
  39. multioptpy/Interpolation/geodesic_interpolation.py +785 -0
  40. multioptpy/Interpolation/interpolation.py +156 -0
  41. multioptpy/Interpolation/linear_interpolation.py +473 -0
  42. multioptpy/Interpolation/savitzky_golay_interpolation.py +252 -0
  43. multioptpy/Interpolation/spline_interpolation.py +353 -0
  44. multioptpy/MD/__init__.py +0 -0
  45. multioptpy/MD/thermostat.py +185 -0
  46. multioptpy/MEP/__init__.py +0 -0
  47. multioptpy/MEP/pathopt_bneb_force.py +443 -0
  48. multioptpy/MEP/pathopt_dmf_force.py +448 -0
  49. multioptpy/MEP/pathopt_dneb_force.py +130 -0
  50. multioptpy/MEP/pathopt_ewbneb_force.py +207 -0
  51. multioptpy/MEP/pathopt_gpneb_force.py +512 -0
  52. multioptpy/MEP/pathopt_lup_force.py +113 -0
  53. multioptpy/MEP/pathopt_neb_force.py +225 -0
  54. multioptpy/MEP/pathopt_nesb_force.py +205 -0
  55. multioptpy/MEP/pathopt_om_force.py +153 -0
  56. multioptpy/MEP/pathopt_qsm_force.py +174 -0
  57. multioptpy/MEP/pathopt_qsmv2_force.py +304 -0
  58. multioptpy/ModelFunction/__init__.py +7 -0
  59. multioptpy/ModelFunction/avoiding_model_function.py +29 -0
  60. multioptpy/ModelFunction/binary_image_ts_search_model_function.py +47 -0
  61. multioptpy/ModelFunction/conical_model_function.py +26 -0
  62. multioptpy/ModelFunction/opt_meci.py +50 -0
  63. multioptpy/ModelFunction/opt_mesx.py +47 -0
  64. multioptpy/ModelFunction/opt_mesx_2.py +49 -0
  65. multioptpy/ModelFunction/seam_model_function.py +27 -0
  66. multioptpy/ModelHessian/__init__.py +0 -0
  67. multioptpy/ModelHessian/approx_hessian.py +147 -0
  68. multioptpy/ModelHessian/calc_params.py +227 -0
  69. multioptpy/ModelHessian/fischer.py +236 -0
  70. multioptpy/ModelHessian/fischerd3.py +360 -0
  71. multioptpy/ModelHessian/fischerd4.py +398 -0
  72. multioptpy/ModelHessian/gfn0xtb.py +633 -0
  73. multioptpy/ModelHessian/gfnff.py +709 -0
  74. multioptpy/ModelHessian/lindh.py +165 -0
  75. multioptpy/ModelHessian/lindh2007d2.py +707 -0
  76. multioptpy/ModelHessian/lindh2007d3.py +822 -0
  77. multioptpy/ModelHessian/lindh2007d4.py +1030 -0
  78. multioptpy/ModelHessian/morse.py +106 -0
  79. multioptpy/ModelHessian/schlegel.py +144 -0
  80. multioptpy/ModelHessian/schlegeld3.py +322 -0
  81. multioptpy/ModelHessian/schlegeld4.py +559 -0
  82. multioptpy/ModelHessian/shortrange.py +346 -0
  83. multioptpy/ModelHessian/swartd2.py +496 -0
  84. multioptpy/ModelHessian/swartd3.py +706 -0
  85. multioptpy/ModelHessian/swartd4.py +918 -0
  86. multioptpy/ModelHessian/tshess.py +40 -0
  87. multioptpy/Optimizer/QHAdam.py +61 -0
  88. multioptpy/Optimizer/__init__.py +0 -0
  89. multioptpy/Optimizer/abc_fire.py +83 -0
  90. multioptpy/Optimizer/adabelief.py +58 -0
  91. multioptpy/Optimizer/adabound.py +68 -0
  92. multioptpy/Optimizer/adadelta.py +65 -0
  93. multioptpy/Optimizer/adaderivative.py +56 -0
  94. multioptpy/Optimizer/adadiff.py +68 -0
  95. multioptpy/Optimizer/adafactor.py +70 -0
  96. multioptpy/Optimizer/adam.py +65 -0
  97. multioptpy/Optimizer/adamax.py +62 -0
  98. multioptpy/Optimizer/adamod.py +83 -0
  99. multioptpy/Optimizer/adamw.py +65 -0
  100. multioptpy/Optimizer/adiis.py +523 -0
  101. multioptpy/Optimizer/afire_neb.py +282 -0
  102. multioptpy/Optimizer/block_hessian_update.py +709 -0
  103. multioptpy/Optimizer/c2diis.py +491 -0
  104. multioptpy/Optimizer/component_wise_scaling.py +405 -0
  105. multioptpy/Optimizer/conjugate_gradient.py +82 -0
  106. multioptpy/Optimizer/conjugate_gradient_neb.py +345 -0
  107. multioptpy/Optimizer/coordinate_locking.py +405 -0
  108. multioptpy/Optimizer/dic_rsirfo.py +1015 -0
  109. multioptpy/Optimizer/ediis.py +417 -0
  110. multioptpy/Optimizer/eve.py +76 -0
  111. multioptpy/Optimizer/fastadabelief.py +61 -0
  112. multioptpy/Optimizer/fire.py +77 -0
  113. multioptpy/Optimizer/fire2.py +249 -0
  114. multioptpy/Optimizer/fire_neb.py +92 -0
  115. multioptpy/Optimizer/gan_step.py +486 -0
  116. multioptpy/Optimizer/gdiis.py +609 -0
  117. multioptpy/Optimizer/gediis.py +203 -0
  118. multioptpy/Optimizer/geodesic_step.py +433 -0
  119. multioptpy/Optimizer/gpmin.py +633 -0
  120. multioptpy/Optimizer/gpr_step.py +364 -0
  121. multioptpy/Optimizer/gradientdescent.py +78 -0
  122. multioptpy/Optimizer/gradientdescent_neb.py +52 -0
  123. multioptpy/Optimizer/hessian_update.py +433 -0
  124. multioptpy/Optimizer/hybrid_rfo.py +998 -0
  125. multioptpy/Optimizer/kdiis.py +625 -0
  126. multioptpy/Optimizer/lars.py +21 -0
  127. multioptpy/Optimizer/lbfgs.py +253 -0
  128. multioptpy/Optimizer/lbfgs_neb.py +355 -0
  129. multioptpy/Optimizer/linesearch.py +236 -0
  130. multioptpy/Optimizer/lookahead.py +40 -0
  131. multioptpy/Optimizer/nadam.py +64 -0
  132. multioptpy/Optimizer/newton.py +200 -0
  133. multioptpy/Optimizer/prodigy.py +70 -0
  134. multioptpy/Optimizer/purtubation.py +16 -0
  135. multioptpy/Optimizer/quickmin_neb.py +245 -0
  136. multioptpy/Optimizer/radam.py +75 -0
  137. multioptpy/Optimizer/rfo_neb.py +302 -0
  138. multioptpy/Optimizer/ric_rfo.py +842 -0
  139. multioptpy/Optimizer/rl_step.py +627 -0
  140. multioptpy/Optimizer/rmspropgrave.py +65 -0
  141. multioptpy/Optimizer/rsirfo.py +1647 -0
  142. multioptpy/Optimizer/rsprfo.py +1056 -0
  143. multioptpy/Optimizer/sadam.py +60 -0
  144. multioptpy/Optimizer/samsgrad.py +63 -0
  145. multioptpy/Optimizer/tr_lbfgs.py +678 -0
  146. multioptpy/Optimizer/trim.py +273 -0
  147. multioptpy/Optimizer/trust_radius.py +207 -0
  148. multioptpy/Optimizer/trust_radius_neb.py +121 -0
  149. multioptpy/Optimizer/yogi.py +60 -0
  150. multioptpy/OtherMethod/__init__.py +0 -0
  151. multioptpy/OtherMethod/addf.py +1150 -0
  152. multioptpy/OtherMethod/dimer.py +895 -0
  153. multioptpy/OtherMethod/elastic_image_pair.py +629 -0
  154. multioptpy/OtherMethod/modelfunction.py +456 -0
  155. multioptpy/OtherMethod/newton_traj.py +454 -0
  156. multioptpy/OtherMethod/twopshs.py +1095 -0
  157. multioptpy/PESAnalyzer/__init__.py +0 -0
  158. multioptpy/PESAnalyzer/calc_irc_curvature.py +125 -0
  159. multioptpy/PESAnalyzer/cmds_analysis.py +152 -0
  160. multioptpy/PESAnalyzer/koopman_analysis.py +268 -0
  161. multioptpy/PESAnalyzer/pca_analysis.py +314 -0
  162. multioptpy/Parameters/__init__.py +0 -0
  163. multioptpy/Parameters/atomic_mass.py +20 -0
  164. multioptpy/Parameters/atomic_number.py +22 -0
  165. multioptpy/Parameters/covalent_radii.py +44 -0
  166. multioptpy/Parameters/d2.py +61 -0
  167. multioptpy/Parameters/d3.py +63 -0
  168. multioptpy/Parameters/d4.py +103 -0
  169. multioptpy/Parameters/dreiding.py +34 -0
  170. multioptpy/Parameters/gfn0xtb_param.py +137 -0
  171. multioptpy/Parameters/gfnff_param.py +315 -0
  172. multioptpy/Parameters/gnb.py +104 -0
  173. multioptpy/Parameters/parameter.py +22 -0
  174. multioptpy/Parameters/uff.py +72 -0
  175. multioptpy/Parameters/unit_values.py +20 -0
  176. multioptpy/Potential/AFIR_potential.py +55 -0
  177. multioptpy/Potential/LJ_repulsive_potential.py +345 -0
  178. multioptpy/Potential/__init__.py +0 -0
  179. multioptpy/Potential/anharmonic_keep_potential.py +28 -0
  180. multioptpy/Potential/asym_elllipsoidal_potential.py +718 -0
  181. multioptpy/Potential/electrostatic_potential.py +69 -0
  182. multioptpy/Potential/flux_potential.py +30 -0
  183. multioptpy/Potential/gaussian_potential.py +101 -0
  184. multioptpy/Potential/idpp.py +516 -0
  185. multioptpy/Potential/keep_angle_potential.py +146 -0
  186. multioptpy/Potential/keep_dihedral_angle_potential.py +105 -0
  187. multioptpy/Potential/keep_outofplain_angle_potential.py +70 -0
  188. multioptpy/Potential/keep_potential.py +99 -0
  189. multioptpy/Potential/mechano_force_potential.py +74 -0
  190. multioptpy/Potential/nanoreactor_potential.py +52 -0
  191. multioptpy/Potential/potential.py +896 -0
  192. multioptpy/Potential/spacer_model_potential.py +221 -0
  193. multioptpy/Potential/switching_potential.py +258 -0
  194. multioptpy/Potential/universal_potential.py +34 -0
  195. multioptpy/Potential/value_range_potential.py +36 -0
  196. multioptpy/Potential/void_point_potential.py +25 -0
  197. multioptpy/SQM/__init__.py +0 -0
  198. multioptpy/SQM/sqm1/__init__.py +0 -0
  199. multioptpy/SQM/sqm1/sqm1_core.py +1792 -0
  200. multioptpy/SQM/sqm2/__init__.py +0 -0
  201. multioptpy/SQM/sqm2/calc_tools.py +95 -0
  202. multioptpy/SQM/sqm2/sqm2_basis.py +850 -0
  203. multioptpy/SQM/sqm2/sqm2_bond.py +119 -0
  204. multioptpy/SQM/sqm2/sqm2_core.py +303 -0
  205. multioptpy/SQM/sqm2/sqm2_data.py +1229 -0
  206. multioptpy/SQM/sqm2/sqm2_disp.py +65 -0
  207. multioptpy/SQM/sqm2/sqm2_eeq.py +243 -0
  208. multioptpy/SQM/sqm2/sqm2_overlapint.py +704 -0
  209. multioptpy/SQM/sqm2/sqm2_qm.py +578 -0
  210. multioptpy/SQM/sqm2/sqm2_rep.py +66 -0
  211. multioptpy/SQM/sqm2/sqm2_srb.py +70 -0
  212. multioptpy/Thermo/__init__.py +0 -0
  213. multioptpy/Thermo/normal_mode_analyzer.py +865 -0
  214. multioptpy/Utils/__init__.py +0 -0
  215. multioptpy/Utils/bond_connectivity.py +264 -0
  216. multioptpy/Utils/calc_tools.py +884 -0
  217. multioptpy/Utils/oniom.py +96 -0
  218. multioptpy/Utils/pbc.py +48 -0
  219. multioptpy/Utils/riemann_curvature.py +208 -0
  220. multioptpy/Utils/symmetry_analyzer.py +482 -0
  221. multioptpy/Visualization/__init__.py +0 -0
  222. multioptpy/Visualization/visualization.py +156 -0
  223. multioptpy/WFAnalyzer/MO_analysis.py +104 -0
  224. multioptpy/WFAnalyzer/__init__.py +0 -0
  225. multioptpy/Wrapper/__init__.py +0 -0
  226. multioptpy/Wrapper/autots.py +1239 -0
  227. multioptpy/Wrapper/ieip_wrapper.py +93 -0
  228. multioptpy/Wrapper/md_wrapper.py +92 -0
  229. multioptpy/Wrapper/neb_wrapper.py +94 -0
  230. multioptpy/Wrapper/optimize_wrapper.py +76 -0
  231. multioptpy/__init__.py +5 -0
  232. multioptpy/entrypoints.py +916 -0
  233. multioptpy/fileio.py +660 -0
  234. multioptpy/ieip.py +340 -0
  235. multioptpy/interface.py +1086 -0
  236. multioptpy/irc.py +529 -0
  237. multioptpy/moleculardynamics.py +432 -0
  238. multioptpy/neb.py +1267 -0
  239. multioptpy/optimization.py +1553 -0
  240. multioptpy/optimizer.py +709 -0
  241. multioptpy-1.20.2.dist-info/METADATA +438 -0
  242. multioptpy-1.20.2.dist-info/RECORD +246 -0
  243. multioptpy-1.20.2.dist-info/WHEEL +5 -0
  244. multioptpy-1.20.2.dist-info/entry_points.txt +9 -0
  245. multioptpy-1.20.2.dist-info/licenses/LICENSE +674 -0
  246. multioptpy-1.20.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,458 @@
1
+ import glob
2
+ import os
3
+ from collections import defaultdict
4
+ from math import log, sqrt
5
+ import numpy as np
6
+ from abc import ABC, abstractmethod
7
+
8
+ from multioptpy.Utils.calc_tools import Calculationtools
9
+ from multioptpy.Parameters.parameter import UnitValueLib, element_number, number_element
10
+ from multioptpy.fileio import xyz2list
11
+ from multioptpy.Visualization.visualization import NEBVisualizer
12
+
13
+
14
+ class EMT:
15
+ """
16
+ A standalone Python implementation of the Effective Medium Theory (EMT)
17
+ potential.
18
+
19
+ This implementation is suitable for calculating energy, forces, and Hessians
20
+ on atomic clusters. The Hessian is calculated via finite differences.
21
+
22
+ Notes on units:
23
+ - Input coordinates for calculation are expected in Angstroms.
24
+ - Internal calculations are performed using eV and Angstroms.
25
+ - Output energy is in Hartree.
26
+ - Output forces are in Hartree/Bohr.
27
+ - Output Hessian is in Hartree/Bohr^2.
28
+ """
29
+
30
+ # Physical constants for internal use and unit conversion
31
+ BOHR = UnitValueLib().bohr2angstroms # Angstroms
32
+ EV_TO_HARTREE = 1 / UnitValueLib().hartree2eV
33
+ EV_PER_ANG_TO_HARTREE_PER_BOHR = EV_TO_HARTREE / BOHR
34
+ HARTREE_PER_BOHR_SQ_TO_EV_PER_ANG_SQ = 1 / (EV_TO_HARTREE / BOHR**2)
35
+
36
+ # Atomic data
37
+ CHEMICAL_SYMBOLS = {
38
+ 1: 'H', 6: 'C', 7: 'N', 8: 'O', 13: 'Al', 29: 'Cu', 46: 'Pd',
39
+ 47: 'Ag', 78: 'Pt', 79: 'Au', 28: 'Ni'
40
+ }
41
+ ATOMIC_NUMBERS = {v: k for k, v in CHEMICAL_SYMBOLS.items()}
42
+
43
+ PARAMETERS = {
44
+ # E0 s0 V0 eta2 kappa lambda n0
45
+ # eV bohr eV bohr^-1 bohr^-1 bohr^-1 bohr^-3
46
+ 'Al': (-3.28, 3.00, 1.493, 1.240, 2.000, 1.169, 0.00700),
47
+ 'Cu': (-3.51, 2.67, 2.476, 1.652, 2.740, 1.906, 0.00910),
48
+ 'Ag': (-2.96, 3.01, 2.132, 1.652, 2.790, 1.892, 0.00547),
49
+ 'Au': (-3.80, 3.00, 2.321, 1.674, 2.873, 2.182, 0.00703),
50
+ 'Ni': (-4.44, 2.60, 3.673, 1.669, 2.757, 1.948, 0.01030),
51
+ 'Pd': (-3.90, 2.87, 2.773, 1.818, 3.107, 2.155, 0.00688),
52
+ 'Pt': (-5.85, 2.90, 4.067, 1.812, 3.145, 2.192, 0.00802),
53
+ 'H': (-3.21, 1.31, 0.132, 2.652, 2.790, 3.892, 0.00547),
54
+ 'C': (-3.50, 1.81, 0.332, 1.652, 2.790, 1.892, 0.01322),
55
+ 'N': (-5.10, 1.88, 0.132, 1.652, 2.790, 1.892, 0.01222),
56
+ 'O': (-4.60, 1.95, 0.332, 1.652, 2.790, 1.892, 0.00850)
57
+ }
58
+ BETA = 1.809 # (16 * pi / 3)**(1.0 / 3) / 2**0.5
59
+
60
+ def __init__(self, symbols, asap_cutoff=False):
61
+ self.symbols = symbols
62
+ self.numbers = np.array([self.ATOMIC_NUMBERS[s] for s in symbols])
63
+ self.asap_cutoff = asap_cutoff
64
+
65
+ self.positions = None
66
+ self.energy_ev = 0.0
67
+ self.forces_ev_per_ang = None
68
+
69
+ self._initialize_parameters()
70
+
71
+ def _initialize_parameters(self):
72
+ self.rc, self.rc_list, self.acut = self._calc_cutoff()
73
+
74
+ unique_numbers, self.ia2iz = np.unique(self.numbers, return_inverse=True)
75
+ self.par = defaultdict(lambda: np.empty(len(unique_numbers)))
76
+ for i, Z in enumerate(unique_numbers):
77
+ sym = self.CHEMICAL_SYMBOLS[Z]
78
+ if sym not in self.PARAMETERS:
79
+ raise NotImplementedError(f'No EMT-potential for {sym}')
80
+
81
+ p = self.PARAMETERS[sym]
82
+ s0 = p[1] * self.BOHR
83
+ eta2 = p[3] / self.BOHR
84
+ kappa = p[4] / self.BOHR
85
+ gamma1, gamma2 = self._calc_gammas(s0, eta2, kappa)
86
+
87
+ self.par['Z'][i] = Z
88
+ self.par['E0'][i] = p[0]
89
+ self.par['s0'][i] = s0
90
+ self.par['V0'][i] = p[2]
91
+ self.par['eta2'][i] = eta2
92
+ self.par['kappa'][i] = kappa
93
+ self.par['lambda'][i] = p[5] / self.BOHR
94
+ self.par['n0'][i] = p[6] / self.BOHR**3
95
+ self.par['inv12gamma1'][i] = 1.0 / (12.0 * gamma1)
96
+ self.par['neghalfv0overgamma2'][i] = -0.5 * p[2] / gamma2
97
+
98
+ self.chi = self.par['n0'][None, :] / self.par['n0'][:, None]
99
+
100
+ def _calc_cutoff(self):
101
+ if self.asap_cutoff:
102
+ relevant_pars = {
103
+ symb: p for symb, p in self.PARAMETERS.items()
104
+ if self.ATOMIC_NUMBERS[symb] in self.numbers
105
+ }
106
+ else:
107
+ relevant_pars = self.PARAMETERS
108
+
109
+ max_s0_bohr = max(par[1] for par in relevant_pars.values())
110
+ maxseq = max_s0_bohr * self.BOHR
111
+ r1nn = self.BETA * maxseq
112
+ rc = r1nn * 0.5 * (sqrt(3.0) + 2.0)
113
+ r4nn = r1nn * 2.0
114
+ eps = 1e-4
115
+ acut = log(1.0 / eps - 1.0) / (r4nn - rc)
116
+ rc_list = rc * 1.045 if self.asap_cutoff else rc + 0.5
117
+ return rc, rc_list, acut
118
+
119
+ def _calc_gammas(self, s0, eta2, kappa):
120
+ n = np.array([12, 6, 24])
121
+ r = self.BETA * s0 * np.sqrt([1.0, 2.0, 3.0])
122
+ w = 1.0 / (1.0 + np.exp(self.acut * (r - self.rc)))
123
+ x = n * w / 12.0
124
+ gamma1 = np.dot(x, np.exp(-eta2 * (r - self.BETA * s0)))
125
+ gamma2 = np.dot(x, np.exp(-kappa / self.BETA * (r - self.BETA * s0)))
126
+ return gamma1, gamma2
127
+
128
+ def _get_energy_and_forces_internal(self, positions_angstrom):
129
+ """Calculates energy and forces in internal units (eV, eV/A)."""
130
+ self.positions = positions_angstrom
131
+ natoms = len(self.positions)
132
+
133
+ self.energies = np.zeros(natoms)
134
+ self.forces_ev_per_ang = np.zeros((natoms, 3))
135
+ self.deds = np.zeros(natoms)
136
+
137
+ ps = {}
138
+ for a1 in range(natoms):
139
+ diffs = self.positions - self.positions[a1]
140
+ dists = np.linalg.norm(diffs, axis=1)
141
+ neighbor_indices = np.where((dists > 1e-9) & (dists < self.rc_list))[0]
142
+ if len(neighbor_indices) == 0: continue
143
+
144
+ a2, d, r = neighbor_indices, diffs[neighbor_indices], dists[neighbor_indices]
145
+ w, dwdroverw = self._calc_theta(r)
146
+ dsigma1s, dsigma1o = self._calc_dsigma1(a1, a2, r, w)
147
+ dsigma2s, dsigma2o = self._calc_dsigma2(a1, a2, r, w)
148
+ ps[a1] = {
149
+ 'a2': a2, 'd': d, 'r': r, 'invr': 1.0 / r, 'w': w,
150
+ 'dwdroverw': dwdroverw, 'dsigma1s': dsigma1s, 'dsigma1o': dsigma1o,
151
+ 'dsigma2s': dsigma2s, 'dsigma2o': dsigma2o,
152
+ }
153
+
154
+ for a1, p in ps.items(): self._calc_e_c_a2(a1, p['dsigma1s'])
155
+ for a1, p in ps.items(): self._calc_pairwise_forces(a1, **p)
156
+
157
+ self.energies -= self.par['E0'][self.ia2iz]
158
+ self.energy_ev = np.sum(self.energies)
159
+ return self.energy_ev, self.forces_ev_per_ang
160
+
161
+ def calculate_energy_and_forces(self, positions_angstrom):
162
+ """Calculates energy and forces, returning them in atomic units."""
163
+ energy_ev, forces_ev_ang = self._get_energy_and_forces_internal(positions_angstrom)
164
+ energy_hartree = energy_ev * self.EV_TO_HARTREE
165
+ forces_hartree_per_bohr = forces_ev_ang * self.EV_PER_ANG_TO_HARTREE_PER_BOHR
166
+ return energy_hartree, forces_hartree_per_bohr
167
+
168
+ def calculate_hessian(self, positions_angstrom, fd_step=1e-5):
169
+ """
170
+ Calculates the Hessian matrix by vectorized finite differences, returning
171
+ it in atomic units (Hartree/Bohr^2).
172
+ A smaller finite difference step is used for better numerical accuracy.
173
+ """
174
+ num_atoms = len(positions_angstrom)
175
+ hessian_ev_per_ang_sq = np.zeros((num_atoms * 3, num_atoms * 3))
176
+
177
+ for i in range(num_atoms):
178
+ for j in range(3):
179
+ # Central difference method for higher accuracy
180
+ pos_plus = positions_angstrom.copy()
181
+ pos_plus[i, j] += fd_step
182
+ _, forces_plus = self._get_energy_and_forces_internal(pos_plus)
183
+
184
+ pos_minus = positions_angstrom.copy()
185
+ pos_minus[i, j] -= fd_step
186
+ _, forces_minus = self._get_energy_and_forces_internal(pos_minus)
187
+
188
+ # Gradient is negative force: g = -F
189
+ # Hessian H_ij = d(g_i)/d(r_j) = d(-F_i)/d(r_j)
190
+ # Using central differences: H_ij approx - (F_i(r+h) - F_i(r-h)) / (2h)
191
+ # The column of the Hessian corresponding to displacement 'k' is d(g)/dr_k = -dF/dr_k
192
+ hessian_col = -(forces_plus.flatten() - forces_minus.flatten()) / (2 * fd_step)
193
+ hessian_ev_per_ang_sq[:, i * 3 + j] = hessian_col
194
+
195
+ # Symmetrize the Hessian to reduce numerical noise
196
+ hessian_ev_per_ang_sq = 0.5 * (hessian_ev_per_ang_sq + hessian_ev_per_ang_sq.T)
197
+
198
+ # Convert to atomic units
199
+ hessian_hartree_per_bohr_sq = hessian_ev_per_ang_sq / self.HARTREE_PER_BOHR_SQ_TO_EV_PER_ANG_SQ
200
+ return hessian_hartree_per_bohr_sq
201
+
202
+ def _calc_theta(self, r):
203
+ w = 1.0 / (1.0 + np.exp(self.acut * (r - self.rc)))
204
+ dwdroverw = self.acut * (w - 1.0)
205
+ return w, dwdroverw
206
+
207
+ def _calc_dsigma1(self, a1, a2, r, w):
208
+ s0s, s0o = self.par['s0'][self.ia2iz[a1]], self.par['s0'][self.ia2iz[a2]]
209
+ eta2s, eta2o = self.par['eta2'][self.ia2iz[a1]], self.par['eta2'][self.ia2iz[a2]]
210
+ chi = self.chi[self.ia2iz[a1], self.ia2iz[a2]]
211
+ dsigma1s = np.exp(-eta2o * (r - self.BETA * s0o)) * chi * w
212
+ dsigma1o = np.exp(-eta2s * (r - self.BETA * s0s)) / chi * w
213
+ return dsigma1s, dsigma1o
214
+
215
+ def _calc_dsigma2(self, a1, a2, r, w):
216
+ s0s, s0o = self.par['s0'][self.ia2iz[a1]], self.par['s0'][self.ia2iz[a2]]
217
+ kappas, kappao = self.par['kappa'][self.ia2iz[a1]], self.par['kappa'][self.ia2iz[a2]]
218
+ chi = self.chi[self.ia2iz[a1], self.ia2iz[a2]]
219
+ dsigma2s = np.exp(-kappao * (r / self.BETA - s0o)) * chi * w
220
+ dsigma2o = np.exp(-kappas * (r / self.BETA - s0s)) / chi * w
221
+ return dsigma2s, dsigma2o
222
+
223
+ def _calc_e_c_a2(self, a1, dsigma1s):
224
+ sigma1 = np.sum(dsigma1s)
225
+ if sigma1 < 1e-20: return
226
+
227
+ iz1 = self.ia2iz[a1]
228
+ e0s, v0s, eta2s = self.par['E0'][iz1], self.par['V0'][iz1], self.par['eta2'][iz1]
229
+ lmds, kappas, inv12gamma1s = self.par['lambda'][iz1], self.par['kappa'][iz1], self.par['inv12gamma1'][iz1]
230
+
231
+ ds = -np.log(sigma1 * inv12gamma1s) / (self.BETA * eta2s)
232
+ lmdsds = lmds * ds
233
+ expneglmdds = np.exp(-lmdsds)
234
+ self.energies[a1] += e0s * (1.0 + lmdsds) * expneglmdds
235
+ self.deds[a1] += -e0s * lmds * lmdsds * expneglmdds
236
+
237
+ sixv0expnegkppds = 6.0 * v0s * np.exp(-kappas * ds)
238
+ self.energies[a1] += sixv0expnegkppds
239
+ self.deds[a1] += -kappas * sixv0expnegkppds
240
+ self.deds[a1] /= -self.BETA * eta2s * sigma1
241
+
242
+ def _calc_pairwise_forces(self, a1, a2, d, invr, dwdroverw, dsigma1s, dsigma1o, dsigma2s, dsigma2o, **kwargs):
243
+ iz1, iz2 = self.ia2iz[a1], self.ia2iz[a2]
244
+ eta2s, eta2o = self.par['eta2'][iz1], self.par['eta2'][iz2]
245
+ ddsigma1sdr = dsigma1s * (dwdroverw - eta2o)
246
+ ddsigma1odr = dsigma1o * (dwdroverw - eta2s)
247
+ dedrs = self.deds[a1] * ddsigma1sdr
248
+ dedro = self.deds[a2] * ddsigma1odr
249
+ f_cohesive = (dedrs + dedro) * invr
250
+
251
+ neghalfv0overgamma2s, neghalfv0overgamma2o = self.par['neghalfv0overgamma2'][iz1], self.par['neghalfv0overgamma2'][iz2]
252
+ kappas, kappao = self.par['kappa'][iz1], self.par['kappa'][iz2]
253
+ es, eo = neghalfv0overgamma2s * dsigma2s, neghalfv0overgamma2o * dsigma2o
254
+ self.energies[a1] += 0.5 * np.sum(es)
255
+ self.energies[a2] += 0.5 * np.sum(eo)
256
+ dedrs_pair = es * (dwdroverw - kappao / self.BETA)
257
+ dedro_pair = eo * (dwdroverw - kappas / self.BETA)
258
+ f_pair = (dedrs_pair + dedro_pair) * invr
259
+
260
+ f_total_mag = f_cohesive + f_pair
261
+ f_pairs_vec = f_total_mag[:, None] * d
262
+
263
+ self.forces_ev_per_ang[a1] += np.sum(f_pairs_vec, axis=0)
264
+ np.add.at(self.forces_ev_per_ang, a2, -f_pairs_vec)
265
+
266
+ class EMTCore:
267
+ """
268
+ Core calculator for EMT potential, using the standalone implementation.
269
+ This class acts as a wrapper and cache for the EMT calculator.
270
+ """
271
+ def __init__(self):
272
+ self.UVL = UnitValueLib()
273
+ self._calculator_cache = {}
274
+
275
+ def _get_calculator(self, atom_symbols):
276
+ symbols_tuple = tuple(sorted(set(atom_symbols)))
277
+ if symbols_tuple not in self._calculator_cache:
278
+ self._calculator_cache[symbols_tuple] = EMT(symbols_tuple)
279
+
280
+ calc = self._calculator_cache[symbols_tuple]
281
+ calc.symbols = atom_symbols
282
+ calc.numbers = np.array([calc.ATOMIC_NUMBERS[s] for s in atom_symbols])
283
+ calc._initialize_parameters()
284
+ return calc
285
+
286
+ def calculate_energy_and_gradient(self, coords_bohr, atom_symbols):
287
+ """Calculates EMT energy (Hartree) and gradient (Hartree/Bohr)."""
288
+ if coords_bohr.shape[0] == 0:
289
+ return {"energy": 0.0, "gradient": np.zeros_like(coords_bohr)}
290
+
291
+ coords_angstrom = coords_bohr * self.UVL.bohr2angstroms
292
+ calculator = self._get_calculator(atom_symbols)
293
+
294
+ try:
295
+ energy_hartree, forces_hartree_per_bohr = calculator.calculate_energy_and_forces(coords_angstrom)
296
+ gradient_hartree_bohr = -forces_hartree_per_bohr
297
+ return {"energy": energy_hartree, "gradient": gradient_hartree_bohr}
298
+ except NotImplementedError as e:
299
+ print(f"Error during EMT calculation: {e}")
300
+ return {"energy": 0.0, "gradient": np.zeros_like(coords_bohr)}
301
+
302
+ def calculate_hessian(self, coords_bohr, atom_symbols):
303
+
304
+ """Calculates EMT Hessian (Hartree/Bohr^2) via finite differences."""
305
+ print("Warning: EMT Hessian calculation is not tested well. Use with caution.")
306
+ if coords_bohr.shape[0] == 0:
307
+ return {"hessian": np.zeros((0,0))}
308
+
309
+ # FIX: Convert coordinates from Bohr to Angstrom for Hessian calculation
310
+ coords_angstrom = coords_bohr * self.UVL.bohr2angstroms
311
+ calculator = self._get_calculator(atom_symbols)
312
+
313
+ hessian_hartree_per_bohr_sq = calculator.calculate_hessian(coords_angstrom)
314
+ return {"hessian": hessian_hartree_per_bohr_sq}
315
+
316
+
317
+ class Calculation:
318
+ def __init__(self, **kwarg):
319
+ UVL = UnitValueLib()
320
+ self.bohr2angstroms = UVL.bohr2angstroms
321
+ self.atom_symbol = kwarg.get("atom_symbol", None)
322
+ self.FC_COUNT = kwarg.get("FC_COUNT", -1)
323
+ self.Model_hess = kwarg.get("Model_hess")
324
+ self.hessian_flag = kwarg.get("hessian_flag", False)
325
+ self.calculator = EMTCore()
326
+ self.energy = None
327
+ self.gradient = None
328
+ self.coordinate = None
329
+
330
+ def exact_hessian(self, element_list, positions_bohr):
331
+ """Calculates and projects the Hessian."""
332
+ results = self.calculator.calculate_hessian(positions_bohr, element_list)
333
+ exact_hess = results['hessian']
334
+ element_number_list = [element_number(elem) for elem in element_list]
335
+ self.Model_hess = Calculationtools().project_out_hess_tr_and_rot_for_coord(
336
+ exact_hess, element_number_list, positions_bohr, display_eigval=False
337
+ )
338
+
339
+ def single_point(self, file_directory, element_list, iter, electric_charge_and_multiplicity, geom_num_list=None):
340
+ """Executes an EMT single point calculation."""
341
+ finish_frag = False
342
+ e, g, positions_bohr = None, None, None
343
+
344
+ try:
345
+ os.makedirs(file_directory, exist_ok=True)
346
+ except (OSError, TypeError):
347
+ pass
348
+
349
+ if element_list is not None and len(element_list) > 0 and (type(element_list[0]) is np.int64 or type(element_list[0]) is int or type(element_list[0]) is np.int32):
350
+ element_list = [number_element(elem) for elem in element_list]
351
+
352
+ if file_directory is None:
353
+ file_list = ["dummy"]
354
+ else:
355
+ file_list = sorted(glob.glob(os.path.join(file_directory, "*_[0-9].xyz")))
356
+ if not file_list and geom_num_list is None:
357
+ raise FileNotFoundError(f"No XYZ files found in {file_directory}")
358
+
359
+ for num, input_file in enumerate(file_list):
360
+ try:
361
+ if geom_num_list is None:
362
+ positions_angstrom, read_elements, _ = xyz2list(input_file, electric_charge_and_multiplicity)
363
+
364
+ if element_list is None or len(element_list) == 0:
365
+ element_list = read_elements
366
+ else:
367
+ positions_angstrom = geom_num_list
368
+
369
+ if self.atom_symbol is None and (element_list is not None and len(element_list) > 0):
370
+ unique_elements = set(element_list)
371
+ if len(unique_elements) == 1:
372
+ self.atom_symbol = unique_elements.pop()
373
+ print(f"System type detected as homo-atomic. Atom symbol set to '{self.atom_symbol}'.")
374
+ else:
375
+ print(f"System type detected as hetero-atomic: {unique_elements}")
376
+
377
+ positions_bohr = np.array(positions_angstrom, dtype="float64") / self.bohr2angstroms
378
+ results = self.calculator.calculate_energy_and_gradient(positions_bohr, element_list)
379
+ e, g = results['energy'], results['gradient']
380
+
381
+ if self.FC_COUNT == -1 or isinstance(iter, str):
382
+ if self.hessian_flag: self.exact_hessian(element_list, positions_bohr)
383
+ elif iter % self.FC_COUNT == 0 or self.hessian_flag:
384
+ self.exact_hessian(element_list, positions_bohr)
385
+ break
386
+ except Exception as error:
387
+ print(f"Error during EMT calculation for {input_file}: {error}")
388
+ finish_frag = True
389
+ return np.array([0]), np.array([0]), np.array([0]), finish_frag
390
+
391
+ self.energy, self.gradient, self.coordinate = e, g, positions_bohr
392
+ return e, g, positions_bohr, finish_frag
393
+
394
+ class CalculationEngine(ABC):
395
+ @abstractmethod
396
+ def calculate(self, file_directory, optimize_num, pre_total_velocity, config):
397
+ pass
398
+
399
+ def _get_file_list(self, file_directory):
400
+ return sum([sorted(glob.glob(os.path.join(file_directory, f"*_" + "[0-9]" * i + ".xyz"))) for i in range(1, 7)], [])
401
+
402
+ def _process_visualization(self, energy_list, gradient_list, num_list, optimize_num, config):
403
+ try:
404
+ if hasattr(config, 'save_pict') and config.save_pict:
405
+ self.UVL = UnitValueLib()
406
+ visualizer = NEBVisualizer(config)
407
+ tmp_ene_list = np.array(energy_list, dtype="float64") * self.UVL.hartree2kcalmol
408
+ visualizer.plot_energy(num_list, tmp_ene_list - tmp_ene_list[0], optimize_num)
409
+ print("energy graph plotted.")
410
+ gradient_norm_list = [np.linalg.norm(g) for g in gradient_list if hasattr(g, 'size') and g.size > 0]
411
+ visualizer.plot_gradient(num_list, gradient_norm_list, optimize_num)
412
+ print("gradient graph plotted.")
413
+ except Exception as e:
414
+ print(f"Visualization error: {e}")
415
+
416
+ class EMTEngine(CalculationEngine):
417
+ def __init__(self, **kwargs):
418
+ super().__init__()
419
+ self.calculator = EMTCore()
420
+ self.UVL = UnitValueLib()
421
+ self.bohr2angstroms = self.UVL.bohr2angstroms
422
+
423
+ def calculate(self, file_directory, optimize_num, pre_total_velocity, config):
424
+ gradient_list, energy_list, geometry_num_list, num_list = [], [], [], []
425
+ delete_pre_total_velocity = []
426
+ os.makedirs(file_directory, exist_ok=True)
427
+ file_list = self._get_file_list(file_directory)
428
+
429
+ if not file_list:
430
+ print(f"No XYZ files found in directory: {file_directory}")
431
+ return np.array([]), np.array([]), np.array([]), pre_total_velocity
432
+
433
+ for num, input_file in enumerate(file_list):
434
+ try:
435
+ print(f"Processing file: {input_file}")
436
+ positions_angstrom, element_list, _ = xyz2list(input_file, None)
437
+
438
+ if element_list is None or len(element_list) == 0:
439
+ raise ValueError("Element list from file is empty.")
440
+
441
+ positions_bohr = np.array(positions_angstrom, dtype='float64').reshape(-1, 3) / self.bohr2angstroms
442
+ results = self.calculator.calculate_energy_and_gradient(positions_bohr, element_list)
443
+
444
+ energy_list.append(results['energy'])
445
+ gradient_list.append(results['gradient'])
446
+ geometry_num_list.append(positions_angstrom)
447
+ num_list.append(num)
448
+ except Exception as error:
449
+ print(f"Error processing {input_file}: {error}")
450
+ if optimize_num != 0: delete_pre_total_velocity.append(num)
451
+
452
+ self._process_visualization(energy_list, gradient_list, num_list, optimize_num, config)
453
+ if optimize_num != 0 and hasattr(pre_total_velocity, '__len__') and len(pre_total_velocity) > 0 and delete_pre_total_velocity:
454
+ pre_total_velocity = np.delete(np.array(pre_total_velocity), delete_pre_total_velocity, axis=0)
455
+ return (np.array(energy_list, dtype='float64'),
456
+ np.array(gradient_list, dtype='float64'),
457
+ np.array(geometry_num_list, dtype='float64'),
458
+ pre_total_velocity)
@@ -0,0 +1,183 @@
1
+ import glob
2
+ import os
3
+ import numpy as np
4
+ from abc import ABC, abstractmethod
5
+
6
+ try:
7
+ from ase import Atoms
8
+ from ase.vibrations import Vibrations
9
+ from gpaw import GPAW
10
+ except ImportError:
11
+ print("ASE or GPAW is not installed. Please install them to use this module.")
12
+
13
+ from multioptpy.Utils.calc_tools import Calculationtools
14
+ from multioptpy.Parameters.parameter import UnitValueLib, number_element
15
+ from multioptpy.fileio import xyz2list
16
+ from multioptpy.Visualization.visualization import NEBVisualizer
17
+
18
+ class Calculation:
19
+ def __init__(self, **kwarg):
20
+ UVL = UnitValueLib()
21
+ self.bohr2angstroms = UVL.bohr2angstroms
22
+ self.hartree2eV = UVL.hartree2eV
23
+
24
+ self.START_FILE = kwarg["START_FILE"]
25
+ self.N_THREAD = kwarg["N_THREAD"]
26
+ self.SET_MEMORY = kwarg["SET_MEMORY"]
27
+ self.FUNCTIONAL = kwarg["FUNCTIONAL"]
28
+ self.FC_COUNT = kwarg["FC_COUNT"]
29
+ self.BPA_FOLDER_DIRECTORY = kwarg["BPA_FOLDER_DIRECTORY"]
30
+ self.Model_hess = kwarg["Model_hess"]
31
+ self.hessian_flag = False
32
+
33
+ def calc_exact_hess(self, atom_obj, positions, element_list):
34
+ vib = Vibrations(atom_obj, delta=0.001)
35
+ vib.run()
36
+ result_vib = vib.get_vibrations()
37
+ exact_hess = result_vib.get_hessian_2d()
38
+ vib.clean()
39
+ exact_hess = exact_hess / self.hartree2eV * (self.bohr2angstroms ** 2)
40
+ if type(element_list[0]) is str:
41
+ exact_hess = Calculationtools().project_out_hess_tr_and_rot_for_coord(exact_hess, element_list, positions)
42
+ else:
43
+ exact_hess = Calculationtools().project_out_hess_tr_and_rot_for_coord(exact_hess, [number_element(elem_num) for elem_num in element_list], positions)
44
+ self.Model_hess = exact_hess
45
+ return exact_hess
46
+
47
+ def single_point(self, file_directory, element_list, iter, electric_charge_and_multiplicity, method, geom_num_list=None):
48
+ finish_frag = False
49
+ try:
50
+ os.mkdir(file_directory)
51
+ except:
52
+ pass
53
+
54
+ if file_directory is None:
55
+ file_list = ["dummy"]
56
+ else:
57
+ file_list = glob.glob(file_directory + "/*_[0-9].xyz")
58
+
59
+ for num, input_file in enumerate(file_list):
60
+ try:
61
+ if geom_num_list is None:
62
+ positions, _, electric_charge_and_multiplicity = xyz2list(input_file, electric_charge_and_multiplicity)
63
+ else:
64
+ positions = geom_num_list
65
+
66
+ positions = np.array(positions, dtype="float64")
67
+ atom_obj = Atoms(element_list, positions)
68
+ atom_obj.calc = GPAW(mode='lcao', xc=self.FUNCTIONAL, txt=None) # You can configure GPAW parameters as needed
69
+
70
+ e = atom_obj.get_potential_energy(apply_constraint=False) / self.hartree2eV
71
+ g = -1 * atom_obj.get_forces(apply_constraint=False) * self.bohr2angstroms / self.hartree2eV
72
+
73
+ if self.FC_COUNT == -1 or type(iter) is str:
74
+ if self.hessian_flag:
75
+ _ = self.calc_exact_hess(atom_obj, positions, element_list)
76
+ elif iter % self.FC_COUNT == 0 or self.hessian_flag:
77
+ _ = self.calc_exact_hess(atom_obj, positions, element_list)
78
+ except Exception as error:
79
+ print(error)
80
+ print("This molecule could not be optimized.")
81
+ finish_frag = True
82
+ return np.array([0]), np.array([0]), np.array([0]), finish_frag
83
+
84
+ positions /= self.bohr2angstroms
85
+ self.energy = e
86
+ self.gradient = g
87
+ self.coordinate = positions
88
+
89
+ return e, g, positions, finish_frag
90
+
91
+ class GPAWEngine(ABC):
92
+ @abstractmethod
93
+ def calculate(self, file_directory, optimize_num, pre_total_velocity, config):
94
+ pass
95
+
96
+ def _get_file_list(self, file_directory):
97
+ return sum([sorted(glob.glob(os.path.join(file_directory, f"*_" + "[0-9]" * i + ".xyz")))
98
+ for i in range(1, 7)], [])
99
+
100
+ def _process_visualization(self, energy_list, gradient_list, num_list, optimize_num, config):
101
+ try:
102
+ if config.save_pict:
103
+ visualizer = NEBVisualizer(config)
104
+ tmp_ene_list = np.array(energy_list, dtype="float64") * config.hartree2kcalmol
105
+ visualizer.plot_energy(num_list, tmp_ene_list - tmp_ene_list[0], optimize_num)
106
+ print("energy graph plotted.")
107
+ gradient_norm_list = [np.sqrt(np.linalg.norm(g) ** 2 / (len(g) * 3)) for g in gradient_list]
108
+ visualizer.plot_gradient(num_list, gradient_norm_list, optimize_num)
109
+ print("gradient graph plotted.")
110
+ except Exception as e:
111
+ print(f"Visualization error: {e}")
112
+
113
+ class GPAWASEEngine(GPAWEngine):
114
+ def calculate(self, file_directory, optimize_num, pre_total_velocity, config):
115
+ gradient_list = []
116
+ energy_list = []
117
+ geometry_num_list = []
118
+ num_list = []
119
+ delete_pre_total_velocity = []
120
+
121
+ os.makedirs(file_directory, exist_ok=True)
122
+ file_list = self._get_file_list(file_directory)
123
+
124
+ if not file_list:
125
+ print("No input files found in directory.")
126
+ return (np.array([], dtype="float64"),
127
+ np.array([], dtype="float64"),
128
+ np.array([], dtype="float64"),
129
+ pre_total_velocity)
130
+
131
+ geometry_list_tmp, element_list, _ = xyz2list(file_list[0], None)
132
+
133
+ hess_count = 0
134
+ for num, input_file in enumerate(file_list):
135
+ try:
136
+ print(f"\n{input_file}\n")
137
+ positions, _, electric_charge_and_multiplicity = xyz2list(input_file, None)
138
+
139
+ positions = np.array(positions, dtype="float64")
140
+ atom_obj = Atoms(element_list, positions)
141
+ atom_obj.calc = GPAW(mode='lcao', xc=config.FUNCTIONAL, txt=None)
142
+
143
+ e = atom_obj.get_potential_energy(apply_constraint=False) / config.hartree2eV
144
+ g = -1 * atom_obj.get_forces(apply_constraint=False) * config.bohr2angstroms / config.hartree2eV
145
+
146
+ energy_list.append(e)
147
+ gradient_list.append(g)
148
+ geometry_num_list.append(positions / config.bohr2angstroms)
149
+ num_list.append(num)
150
+
151
+ if config.FC_COUNT == -1 or isinstance(optimize_num, str):
152
+ pass
153
+ elif optimize_num % config.FC_COUNT == 0:
154
+ vib = Vibrations(atom_obj, delta=0.001)
155
+ vib.run()
156
+ result_vib = vib.get_vibrations()
157
+ exact_hess = result_vib.get_hessian_2d()
158
+ vib.clean()
159
+ exact_hess = exact_hess / config.hartree2eV * (config.bohr2angstroms ** 2)
160
+ calc_tools = Calculationtools()
161
+ exact_hess = calc_tools.project_out_hess_tr_and_rot_for_coord(exact_hess, element_list, positions)
162
+ np.save(os.path.join(config.NEB_FOLDER_DIRECTORY, f"tmp_hessian_{hess_count}.npy"), exact_hess)
163
+ hess_count += 1
164
+
165
+ except Exception as error:
166
+ print(f"Error: {error}")
167
+ print("This molecule could not be optimized.")
168
+ if optimize_num != 0:
169
+ delete_pre_total_velocity.append(num)
170
+
171
+ self._process_visualization(energy_list, gradient_list, num_list, optimize_num, config)
172
+
173
+ if optimize_num != 0 and len(pre_total_velocity) != 0:
174
+ pre_total_velocity = np.array(pre_total_velocity, dtype="float64")
175
+ pre_total_velocity = pre_total_velocity.tolist()
176
+ for i in sorted(delete_pre_total_velocity, reverse=True):
177
+ pre_total_velocity.pop(i)
178
+ pre_total_velocity = np.array(pre_total_velocity, dtype="float64")
179
+
180
+ return (np.array(energy_list, dtype="float64"),
181
+ np.array(gradient_list, dtype="float64"),
182
+ np.array(geometry_num_list, dtype="float64"),
183
+ pre_total_velocity)