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,376 @@
1
+ import glob
2
+ import os
3
+ import copy
4
+ import numpy as np
5
+ import torch
6
+
7
+ # --- SQM2 ---
8
+ from multioptpy.SQM.sqm2.sqm2_core import SQM2Calculator
9
+ # ---
10
+
11
+ from multioptpy.Utils.calc_tools import Calculationtools
12
+ from multioptpy.Parameters.parameter import UnitValueLib, element_number
13
+ from multioptpy.fileio import xyz2list
14
+ from multioptpy.Visualization.visualization import NEBVisualizer
15
+
16
+ # --- Constants (from SQM2Calculator reference) ---
17
+ ANG2BOHR = 1.8897261246257704
18
+ ANGSTROM_TO_BOHR = ANG2BOHR
19
+ BOHR_TO_ANGSTROM = 1.0 / ANG2BOHR
20
+ # ---
21
+
22
+ """
23
+ Experimental semiempirical electronic structure approach inspired by GFN-xTB (SQM2)
24
+
25
+ This module provides calculator utility helpers wrapping the Python implementation
26
+ of an experimental semiempirical electronic structure approach (SQM2).
27
+ """
28
+
29
+ class Calculation:
30
+ def __init__(self, **kwarg):
31
+ if UnitValueLib is not None:
32
+ UVL = UnitValueLib()
33
+ self.bohr2angstroms = UVL.bohr2angstroms
34
+ else:
35
+ self.bohr2angstroms = BOHR_TO_ANGSTROM
36
+
37
+ # Optional keys
38
+ self.START_FILE = kwarg.get("START_FILE")
39
+ self.N_THREAD = kwarg.get("N_THREAD", 1)
40
+ self.SET_MEMORY = kwarg.get("SET_MEMORY")
41
+ self.FUNCTIONAL = kwarg.get("FUNCTIONAL")
42
+ self.FC_COUNT = kwarg.get("FC_COUNT", -1)
43
+ self.BPA_FOLDER_DIRECTORY = kwarg.get("BPA_FOLDER_DIRECTORY", "./")
44
+ self.Model_hess = kwarg.get("Model_hess")
45
+ self.unrestrict = kwarg.get("unrestrict", False)
46
+ self.dft_grid = kwarg.get("dft_grid")
47
+ self.hessian_flag = False
48
+
49
+ self.device = kwarg.get("device", "cpu")
50
+ self.dtype = kwarg.get("dtype", torch.float64)
51
+
52
+ # The main calculator instance will be created on-the-fly
53
+ # as it requires geometry (xyz) upon initialization.
54
+ self.calculator = None
55
+
56
+ def numerical_hessian(self, geom_num_list, element_list, total_charge):
57
+ """
58
+ Calculate numerical Hessian using finite differences of gradients (SQM2).
59
+
60
+ Args:
61
+ geom_num_list: Atomic positions in Angstrom (n_atoms, 3)
62
+ element_list: Atomic numbers (n_atoms,)
63
+ total_charge: Total molecular charge
64
+
65
+ Returns:
66
+ Hessian matrix (3*n_atoms, 3*n_atoms) in Hartree/Bohr^2
67
+ """
68
+ numerical_delivative_delta = 1.0e-4 # in Angstrom
69
+ geom_num_list = np.array(geom_num_list, dtype="float64")
70
+ n_atoms = len(geom_num_list)
71
+ hessian = np.zeros((3*n_atoms, 3*n_atoms))
72
+ count = 0
73
+
74
+ # SQM2Calculator also requires spin (assuming 0 for singlet)
75
+ spin = 0
76
+
77
+ for a in range(n_atoms):
78
+ for i in range(3):
79
+ for b in range(n_atoms):
80
+ for j in range(3):
81
+ if count > 3*b + j:
82
+ continue
83
+ tmp_grad = []
84
+ for direction in [1, -1]:
85
+ shifted = geom_num_list.copy() # Angstrom
86
+ shifted[a, i] += direction * numerical_delivative_delta
87
+
88
+ # --- Get SQM2 gradient ---
89
+ # Re-initialize SQM2Calculator (required as xyz is in __init__)
90
+ calc = SQM2Calculator(
91
+ xyz=shifted,
92
+ element_list=element_list,
93
+ charge=total_charge,
94
+ spin=spin
95
+ )
96
+
97
+ # .total_gradient returns (Energy, Gradient)
98
+ # Input: Angstrom, Output: (Hartree, Hartree/Bohr)
99
+ _, grad_np = calc.total_gradient(shifted)
100
+
101
+ tmp_grad.append(grad_np[b, j])
102
+
103
+ # Finite difference
104
+ # val = (Hartree/Bohr) / Angstrom
105
+ val = (tmp_grad[0] - tmp_grad[1]) / (2*numerical_delivative_delta)
106
+
107
+ # Convert units to Hartree/Bohr^2
108
+ hessian[3*a+i, 3*b+j] = val * ANGSTROM_TO_BOHR
109
+ hessian[3*b+j, 3*a+i] = val * ANGSTROM_TO_BOHR
110
+ count += 1
111
+ return hessian
112
+
113
+
114
+ def exact_hessian(self, element_number_list, total_charge, positions):
115
+ """
116
+ Calculate exact Hessian using automatic differentiation (SQM2).
117
+
118
+ Args:
119
+ element_number_list: Atomic numbers (n_atoms,)
120
+ total_charge: Total molecular charge
121
+ positions: Atomic positions in Angstrom (n_atoms, 3)
122
+
123
+ Returns:
124
+ Projected Hessian matrix (3*n_atoms, 3*n_atoms) in Hartree/Bohr^2
125
+ """
126
+
127
+ # Assume spin=0 (singlet)
128
+ spin = 0
129
+
130
+ # Initialize SQM2Calculator (Input: Angstrom)
131
+ calc = SQM2Calculator(
132
+ xyz=positions,
133
+ element_list=element_number_list,
134
+ charge=total_charge,
135
+ spin=spin
136
+ )
137
+
138
+ # Calculate Hessian
139
+ # Input: Angstrom, Output: (Hartree/Bohr^2)
140
+ exact_hess_np = calc.total_hessian(positions)
141
+
142
+ # Project out translation and rotation
143
+ if Calculationtools is not None:
144
+ exact_hess_np = Calculationtools().project_out_hess_tr_and_rot_for_coord(
145
+ exact_hess_np, element_number_list.tolist(), positions, display_eigval=False
146
+ )
147
+ self.Model_hess = exact_hess_np
148
+
149
+
150
+ def single_point(self, file_directory, element_number_list, iter_index, electric_charge_and_multiplicity, method="", geom_num_list=None):
151
+ """
152
+ Calculate single point energy and gradient (SQM2).
153
+ """
154
+ print("Warning: SQM2 is an experimental method and does not be suitable for production use.")
155
+ finish_frag = False
156
+
157
+ if isinstance(element_number_list[0], str):
158
+ tmp = copy.copy(element_number_list)
159
+ element_number_list = []
160
+ if element_number is not None:
161
+ for elem in tmp:
162
+ element_number_list.append(element_number(elem))
163
+ element_number_list = np.array(element_number_list)
164
+
165
+ try:
166
+ os.mkdir(file_directory)
167
+ except Exception:
168
+ pass
169
+
170
+ if file_directory is None:
171
+ file_list = ["dummy"]
172
+ else:
173
+ file_list = glob.glob(file_directory+"/*_[0-9].xyz")
174
+
175
+ total_charge = int(electric_charge_and_multiplicity[0])
176
+ # SQM2 EHTCalculator requires spin (multiplicity - 1)
177
+ spin = int(electric_charge_and_multiplicity[1]) - 1
178
+
179
+ for num, input_file in enumerate(file_list):
180
+ try:
181
+ if geom_num_list is None and xyz2list is not None:
182
+ tmp_positions, _, electric_charge_and_multiplicity = xyz2list(input_file, electric_charge_and_multiplicity)
183
+ else:
184
+ tmp_positions = geom_num_list
185
+
186
+ positions = np.array(tmp_positions, dtype="float64").reshape(-1, 3) # Angstrom
187
+
188
+ # --- SQM2 Energy and Gradient Calculation ---
189
+ # Initialize SQM2Calculator (Input: Angstrom)
190
+ calc = SQM2Calculator(
191
+ xyz=positions,
192
+ element_list=element_number_list,
193
+ charge=total_charge,
194
+ spin=spin
195
+ )
196
+
197
+ # Get energy and gradient
198
+ # Input: Angstrom, Output: (Hartree, Hartree/Bohr)
199
+ e, g = calc.total_gradient(positions)
200
+
201
+ # Output coordinates are in Bohr
202
+ positions_bohr = positions * ANGSTROM_TO_BOHR
203
+
204
+ S_mat = calc.get_overlap_matrix() # Get overlap matrix S (torch.Tensor)
205
+ natom = len(element_number_list)
206
+ if S_mat is not None and natom <= 10:
207
+ print("Overlap matrix S:")
208
+
209
+ for i in range(len(S_mat)):
210
+ print(" ".join([f"{S_mat[i, j].item():9.6f}" for j in range(len(S_mat))]))
211
+
212
+ # Get EHT MO energies and coefficients
213
+ #mo_energies = calc.get_eht_mo_energy().detach().cpu().numpy()
214
+ #mo_coefficients = calc.get_eht_mo_coeff().detach().cpu().numpy()
215
+ #if natom <= 10:
216
+ # print("Molecular Orbital Energies (Hartree):")
217
+ # for i, ene in enumerate(mo_energies):
218
+ # print(f"MO {i+1:2d}: {ene:12.6f} Hartree")
219
+ # print("Molecular Orbital Coefficients:")
220
+ # for i in range(len(mo_coefficients)):
221
+ # print(f"MO {i+1:2d}:"+" ".join([f"{mo_coefficients[i, j]:9.6f}" for j in range(len(mo_coefficients))]))
222
+ print("Notice: This output is displayed only for small molecules (n_atoms <= 10).")
223
+ # Save results
224
+ self.energy = e
225
+ self.gradient = g
226
+ self.coordinate = positions_bohr # Bohr
227
+
228
+ if self.FC_COUNT == -1 or isinstance(iter_index, str):
229
+ if self.hessian_flag:
230
+ self.exact_hessian(element_number_list, total_charge, positions) # Angstrom
231
+ elif iter_index % self.FC_COUNT == 0 or self.hessian_flag:
232
+ self.exact_hessian(element_number_list, total_charge, positions) # Angstrom
233
+
234
+ except Exception as error:
235
+ print(error)
236
+
237
+ return np.array([0]), np.array([0]), positions, finish_frag
238
+
239
+ # e (Hartree), g (Hartree/Bohr), positions_bohr (Bohr)
240
+ return e, g, positions_bohr, finish_frag
241
+
242
+ def single_point_no_directory(self, positions, element_number_list, electric_charge_and_multiplicity):
243
+ """
244
+ Calculate single point energy and gradient without file I/O (SQM2).
245
+
246
+ Args:
247
+ positions: Atomic positions in Angstrom (n_atoms, 3)
248
+ """
249
+ finish_frag = False
250
+ if isinstance(element_number_list[0], str):
251
+ tmp = copy.copy(element_number_list)
252
+ element_number_list = []
253
+ if element_number is not None:
254
+ for elem in tmp:
255
+ element_number_list.append(element_number(elem))
256
+ element_number_list = np.array(element_number_list)
257
+ try:
258
+ positions = np.array(positions, dtype='float64') # Angstrom
259
+ total_charge = int(electric_charge_and_multiplicity[0])
260
+ spin = int(electric_charge_and_multiplicity[1]) - 1
261
+
262
+ # --- SQM2 Energy and Gradient Calculation ---
263
+ calc = SQM2Calculator(
264
+ xyz=positions,
265
+ element_list=element_number_list,
266
+ charge=total_charge,
267
+ spin=spin
268
+ )
269
+ # Input: Angstrom, Output: (Hartree, Hartree/Bohr)
270
+ e, g = calc.total_gradient(positions)
271
+
272
+ self.energy = e
273
+ self.gradient = g
274
+ except Exception as error:
275
+ print(error)
276
+ print("This molecule could not be optimized.")
277
+ finish_frag = True
278
+ return np.array([0]), np.array([0]), finish_frag
279
+
280
+ # e (Hartree), g (Hartree/Bohr)
281
+ return e, g, finish_frag
282
+
283
+
284
+ class CalculationEngine:
285
+ def calculate(self, file_directory, optimize_num, pre_total_velocity, config):
286
+ raise NotImplementedError
287
+
288
+ def _get_file_list(self, file_directory):
289
+ return sum([sorted(glob.glob(os.path.join(file_directory, f"*_" + "[0-9]" * i + ".xyz"))) for i in range(1, 7)], [])
290
+
291
+ def _process_visualization(self, energy_list, gradient_list, num_list, optimize_num, config):
292
+ try:
293
+ if getattr(config, 'save_pict', False):
294
+ visualizer = NEBVisualizer(config)
295
+ tmp_ene_list = np.array(energy_list, dtype='float64') * config.hartree2kcalmol
296
+ visualizer.plot_energy(num_list, tmp_ene_list - tmp_ene_list[0], optimize_num)
297
+ print("energy graph plotted.")
298
+ gradient_norm_list = [np.sqrt(np.linalg.norm(g)**2/(len(g)*3)) for g in gradient_list]
299
+ visualizer.plot_gradient(num_list, gradient_norm_list, optimize_num)
300
+ print("gradient graph plotted.")
301
+ except Exception as e:
302
+ print(f"Visualization error: {e}")
303
+
304
+
305
+ class SQM2Engine(CalculationEngine):
306
+ """SQM2 calculation engine wrapping SQM2Calculator"""
307
+ def __init__(self, param_file=None, device="cpu", dtype=torch.float64):
308
+ # SQM2Calculator holds parameters internally, not needed here
309
+ self.device = device
310
+ self.dtype = dtype
311
+ # SQM2Calculator is instantiated in the calculate method as it requires xyz
312
+
313
+ def calculate(self, file_directory, optimize_num, pre_total_velocity, config):
314
+ gradient_list = []
315
+ energy_list = []
316
+ geometry_num_list = []
317
+ gradient_norm_list = []
318
+ delete_pre_total_velocity = []
319
+ num_list = []
320
+
321
+ os.makedirs(file_directory, exist_ok=True)
322
+ file_list = self._get_file_list(file_directory)
323
+
324
+ if xyz2list is None:
325
+ raise ImportError("xyz2list is required for this method")
326
+
327
+ geometry_list_tmp, element_list, _ = xyz2list(file_list[0], None)
328
+ element_number_list = []
329
+ if element_number is not None:
330
+ for elem in element_list:
331
+ element_number_list.append(element_number(elem))
332
+ element_number_list = np.array(element_number_list, dtype='int')
333
+
334
+ for num, input_file in enumerate(file_list):
335
+ try:
336
+ print(input_file)
337
+ positions, _, electric_charge_and_multiplicity = xyz2list(input_file, None)
338
+ positions = np.array(positions, dtype='float64').reshape(-1, 3) # Angstrom
339
+ total_charge = int(electric_charge_and_multiplicity[0])
340
+ spin = int(electric_charge_and_multiplicity[1]) - 1
341
+
342
+ # --- SQM2 Energy and Gradient Calculation ---
343
+ calc = SQM2Calculator(
344
+ xyz=positions,
345
+ element_list=element_number_list,
346
+ charge=total_charge,
347
+ spin=spin
348
+ )
349
+ # Input: Angstrom, Output: (Hartree, Hartree/Bohr)
350
+ e, g = calc.total_gradient(positions)
351
+
352
+ print("\n")
353
+ energy_list.append(e) # Hartree
354
+ gradient_list.append(g) # Hartree/Bohr
355
+ gradient_norm_list.append(np.sqrt(np.linalg.norm(g)**2/(len(g)*3)))
356
+ geometry_num_list.append(positions) # Angstrom
357
+ num_list.append(num)
358
+ except Exception as error:
359
+ print(error)
360
+ print("This molecule could not be optimized.")
361
+ if optimize_num != 0:
362
+ delete_pre_total_velocity.append(num)
363
+
364
+ self._process_visualization(energy_list, gradient_list, num_list, optimize_num, config)
365
+
366
+ if optimize_num != 0 and len(pre_total_velocity) != 0:
367
+ pre_total_velocity = np.array(pre_total_velocity, dtype='float64').tolist()
368
+ for i in sorted(delete_pre_total_velocity, reverse=True):
369
+ pre_total_velocity.pop(i)
370
+ pre_total_velocity = np.array(pre_total_velocity, dtype='float64')
371
+
372
+ # (Hartree, Hartree/Bohr, Angstrom, velocity)
373
+ return (np.array(energy_list, dtype='float64'),
374
+ np.array(gradient_list, dtype='float64'),
375
+ np.array(geometry_num_list, dtype='float64'),
376
+ pre_total_velocity)