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,346 @@
1
+ import numpy as np
2
+ from scipy.special import erf
3
+ from multioptpy.Utils.bond_connectivity import BondConnectivity
4
+ from multioptpy.Utils.calc_tools import Calculationtools
5
+
6
+
7
+ class ShortRangeCorrectionHessian:
8
+ """
9
+ Class for calculating short-range correction to model Hessians, excluding bonded atom pairs.
10
+
11
+ This class computes the second derivatives of the short-range part of
12
+ the Coulomb operator used in range-separated hybrid functionals (e.g., ωB97X-D).
13
+ The short-range part is defined as (1-erf(ω*r))/r, where ω is the range-separation parameter.
14
+
15
+ References:
16
+ [1] J.-D. Chai and M. Head-Gordon, J. Chem. Phys., 2008, 128, 084106 (ωB97X)
17
+ [2] J.-D. Chai and M. Head-Gordon, Phys. Chem. Chem. Phys., 2008, 10, 6615 (ωB97X-D)
18
+ """
19
+ def __init__(self, omega=0.2, cx_sr=0.78, scaling_factor=0.5):
20
+ """Initialize the ShortRangeCorrectionHessian class.
21
+
22
+ Parameters:
23
+ -----------
24
+ omega : float
25
+ Range-separation parameter in Bohr^-1 (default: 0.2 for ωB97X-D)
26
+ cx_sr : float
27
+ Short-range DFT exchange coefficient (default: 0.78 for ωB97X-D)
28
+ scaling_factor : float
29
+ Overall scaling factor for the correction (default: 0.5)
30
+ """
31
+ self.omega = omega # Range-separation parameter (Bohr^-1)
32
+ self.cx_sr = cx_sr # Short-range exchange coefficient
33
+ self.scaling_factor = scaling_factor # Overall scaling factor
34
+ self.sr_cutoff = 15.0 # Cutoff distance for short-range interactions (Bohr)
35
+
36
+ def detect_bonds(self, coord, element_list):
37
+ """Detect bonded atom pairs in the molecule.
38
+
39
+ Parameters:
40
+ -----------
41
+ coord : numpy.ndarray
42
+ Atomic coordinates (Bohr)
43
+ element_list : list
44
+ List of element symbols
45
+
46
+ Returns:
47
+ --------
48
+ set
49
+ Set of tuples (i,j) representing bonded atom pairs
50
+ """
51
+ # Use BondConnectivity class from MultiOptPy to detect bonds
52
+ bc = BondConnectivity()
53
+ bond_matrix = bc.bond_connect_matrix(element_list, coord)
54
+
55
+ # Create a set of bonded atom pairs
56
+ bonded_pairs = set()
57
+ for i in range(len(coord)):
58
+ for j in range(i+1, len(coord)):
59
+ if bond_matrix[i, j] == 1:
60
+ bonded_pairs.add((i, j))
61
+ bonded_pairs.add((j, i))
62
+
63
+ return bonded_pairs
64
+
65
+ def sr_coulomb(self, r):
66
+ """Calculate short-range Coulomb potential.
67
+
68
+ V_SR(r) = (1 - erf(ω*r)) / r
69
+
70
+ Parameters:
71
+ -----------
72
+ r : float
73
+ Distance between two atoms (Bohr)
74
+
75
+ Returns:
76
+ --------
77
+ float
78
+ Short-range Coulomb potential
79
+ """
80
+ if r < 1e-10:
81
+ # Use limit as r→0 (Taylor expansion)
82
+ return 2 * self.omega / np.sqrt(np.pi)
83
+ return (1.0 - erf(self.omega * r)) / r
84
+
85
+ def sr_coulomb_first_derivative(self, r):
86
+ """Calculate first derivative of short-range Coulomb potential.
87
+
88
+ dV_SR(r)/dr = -V_SR(r)/r - 2ω/√π * exp(-ω²r²)/r
89
+
90
+ Parameters:
91
+ -----------
92
+ r : float
93
+ Distance between two atoms
94
+
95
+ Returns:
96
+ --------
97
+ float
98
+ First derivative of short-range Coulomb potential
99
+ """
100
+ if r < 1e-10:
101
+ # Use limit as r→0 (Taylor expansion)
102
+ return -2 * self.omega**3 / (3 * np.sqrt(np.pi))
103
+
104
+ # Error function term
105
+ erf_term = erf(self.omega * r)
106
+
107
+ # Exponential term
108
+ exp_term = 2 * self.omega * np.exp(-(self.omega * r)**2) / (np.sqrt(np.pi) * r)
109
+
110
+ # Coulomb term
111
+ coulomb_term = (erf_term - 1.0) / r**2
112
+
113
+ return exp_term + coulomb_term
114
+
115
+ def sr_coulomb_second_derivative(self, r):
116
+ """Calculate second derivative of short-range Coulomb potential.
117
+
118
+ d²V_SR(r)/dr² = 2(1-erf(ω*r))/r³ + 2erf(ω*r)/r³ + 4ω/(√π*r²)*e^(-ω²r²) + 2ω³/√π*e^(-ω²r²)
119
+
120
+ Parameters:
121
+ -----------
122
+ r : float
123
+ Distance between two atoms
124
+
125
+ Returns:
126
+ --------
127
+ float
128
+ Second derivative of short-range Coulomb potential
129
+ """
130
+ if r < 1e-10:
131
+ # Use limit as r→0 (Taylor expansion)
132
+ return 0.0
133
+
134
+ # Error function term
135
+ erf_term = erf(self.omega * r)
136
+
137
+ # Exponential terms
138
+ exp_factor = np.exp(-(self.omega * r)**2) / np.sqrt(np.pi)
139
+ exp_term1 = 4 * self.omega * exp_factor / r**2
140
+ exp_term2 = 2 * (self.omega**3) * exp_factor
141
+
142
+ # Coulomb term
143
+ coulomb_term = 2 * (2 * erf_term - 1) / r**3
144
+
145
+ return coulomb_term + exp_term1 + exp_term2
146
+
147
+ def estimate_atomic_charges(self, element_list):
148
+ """Estimate atomic charges based on Pauling electronegativity.
149
+
150
+ Parameters:
151
+ -----------
152
+ element_list : list
153
+ List of element symbols
154
+
155
+ Returns:
156
+ --------
157
+ numpy.ndarray
158
+ Estimated atomic charges
159
+ """
160
+ # Pauling electronegativity values
161
+ electronegativity = {
162
+ 'H': 2.20, 'He': 0.00,
163
+ 'Li': 0.98, 'Be': 1.57, 'B': 2.04, 'C': 2.55, 'N': 3.04,
164
+ 'O': 3.44, 'F': 3.98, 'Ne': 0.00,
165
+ 'Na': 0.93, 'Mg': 1.31, 'Al': 1.61, 'Si': 1.90, 'P': 2.19,
166
+ 'S': 2.58, 'Cl': 3.16, 'Ar': 0.00,
167
+ 'K': 0.82, 'Ca': 1.00, 'Sc': 1.36, 'Ti': 1.54, 'V': 1.63,
168
+ 'Cr': 1.66, 'Mn': 1.55, 'Fe': 1.83, 'Co': 1.88, 'Ni': 1.91,
169
+ 'Cu': 1.90, 'Zn': 1.65, 'Ga': 1.81, 'Ge': 2.01, 'As': 2.18,
170
+ 'Se': 2.55, 'Br': 2.96, 'Kr': 0.00
171
+ }
172
+
173
+ n_atoms = len(element_list)
174
+ charges = np.zeros(n_atoms)
175
+
176
+ # Calculate average electronegativity (reference value)
177
+ en_values = [electronegativity.get(element, 2.0) for element in element_list]
178
+ avg_en = sum(en_values) / len(en_values)
179
+
180
+ # Assign charges based on electronegativity differences
181
+ for i, element in enumerate(element_list):
182
+ en = electronegativity.get(element, 2.0)
183
+ charges[i] = 0.2 * (avg_en - en) # Scale by 0.2
184
+
185
+ return charges
186
+
187
+ def calculate_pair_hessian(self, r_vec, r_ij, atomic_charges, atom_i, atom_j):
188
+ """Calculate Hessian contribution from short-range Coulomb between atom pair.
189
+
190
+ Parameters:
191
+ -----------
192
+ r_vec : numpy.ndarray
193
+ Relative position vector from atom i to atom j
194
+ r_ij : float
195
+ Distance between atoms i and j
196
+ atomic_charges : numpy.ndarray
197
+ Array of atomic charges
198
+ atom_i, atom_j : int
199
+ Atom indices
200
+
201
+ Returns:
202
+ --------
203
+ numpy.ndarray
204
+ 3x3 Hessian block matrix
205
+ """
206
+ # Return zeros if beyond cutoff distance
207
+ if r_ij > self.sr_cutoff:
208
+ return np.zeros((3, 3))
209
+
210
+ # Unit direction vector
211
+ r_unit = r_vec / r_ij
212
+
213
+ # Charge-based coefficient
214
+ q_i = atomic_charges[atom_i]
215
+ q_j = atomic_charges[atom_j]
216
+ q_factor = q_i * q_j * self.cx_sr * self.scaling_factor
217
+
218
+ # Calculate second derivative
219
+ d2v = self.sr_coulomb_second_derivative(r_ij)
220
+
221
+ # Calculate tensor using outer product
222
+ r_outer = np.outer(r_unit, r_unit)
223
+
224
+ # Calculate Hessian block
225
+ identity = np.eye(3)
226
+ hessian_block = q_factor * (d2v * r_outer +
227
+ self.sr_coulomb_first_derivative(r_ij) / r_ij * (identity - r_outer))
228
+
229
+ return hessian_block
230
+
231
+ def calculate_correction_hessian(self, coord, element_list):
232
+ """Calculate complete short-range correction Hessian, excluding bonded pairs.
233
+
234
+ Parameters:
235
+ -----------
236
+ coord : numpy.ndarray
237
+ Atomic coordinates (Bohr)
238
+ element_list : list
239
+ List of element symbols
240
+
241
+ Returns:
242
+ --------
243
+ numpy.ndarray
244
+ Short-range correction Hessian
245
+ """
246
+ n_atoms = len(coord)
247
+ hessian = np.zeros((3 * n_atoms, 3 * n_atoms))
248
+
249
+ # Detect bonded atom pairs
250
+ bonded_pairs = self.detect_bonds(coord, element_list)
251
+
252
+ # Estimate atomic charges
253
+ atomic_charges = self.estimate_atomic_charges(element_list)
254
+
255
+ # Number of bonded pairs and total pairs for statistics
256
+ num_total_pairs = n_atoms * (n_atoms - 1) // 2
257
+ num_bonded_pairs = len(bonded_pairs) // 2 # Divide by 2 because we stored both (i,j) and (j,i)
258
+ print(f"Detected {num_bonded_pairs} bonded pairs out of {num_total_pairs} total pairs")
259
+ print(f"Short-range correction will be applied to {num_total_pairs - num_bonded_pairs} non-bonded pairs only")
260
+
261
+ # Loop over all atom pairs
262
+ for i in range(n_atoms):
263
+ for j in range(i+1, n_atoms):
264
+ # Skip bonded atom pairs
265
+ if (i, j) in bonded_pairs or (j, i) in bonded_pairs:
266
+ continue
267
+
268
+ # Calculate interatomic vector and distance
269
+ r_vec = coord[j] - coord[i]
270
+ r_ij = np.linalg.norm(r_vec)
271
+
272
+ # Calculate Hessian block for this pair
273
+ hess_block = self.calculate_pair_hessian(
274
+ r_vec, r_ij, atomic_charges, i, j
275
+ )
276
+
277
+ # Add to the Hessian matrix
278
+ for a in range(3):
279
+ for b in range(3):
280
+ # Diagonal blocks
281
+ hessian[3*i+a, 3*i+b] += hess_block[a, b]
282
+ hessian[3*j+a, 3*j+b] += hess_block[a, b]
283
+
284
+ # Off-diagonal blocks
285
+ hessian[3*i+a, 3*j+b] -= hess_block[a, b]
286
+ hessian[3*j+a, 3*i+b] -= hess_block[a, b]
287
+
288
+ return hessian
289
+
290
+ def apply_correction(self, base_hessian, coord, element_list):
291
+ """Apply short-range correction to an existing Hessian.
292
+
293
+ Parameters:
294
+ -----------
295
+ base_hessian : numpy.ndarray
296
+ Base model Hessian
297
+ coord : numpy.ndarray
298
+ Atomic coordinates (Bohr)
299
+ element_list : list
300
+ List of element symbols
301
+
302
+ Returns:
303
+ --------
304
+ numpy.ndarray
305
+ Corrected Hessian
306
+ """
307
+ tools = Calculationtools()
308
+ # Calculate short-range correction
309
+ correction = self.calculate_correction_hessian(coord, element_list)
310
+ correction = tools.project_out_hess_tr_and_rot_for_coord(correction, element_list, coord, display_eigval=False)
311
+ # Add correction to base Hessian
312
+ corrected_hessian = base_hessian + correction
313
+
314
+ corrected_hessian = 0.5 * (corrected_hessian + corrected_hessian.T) # Symmetrize
315
+ # Remove translational and rotational modes
316
+
317
+ return corrected_hessian
318
+
319
+ def main(self, coord, element_list, base_hessian):
320
+ """Main method to apply short-range correction to a model Hessian.
321
+
322
+ Parameters:
323
+ -----------
324
+ coord : numpy.ndarray
325
+ Atomic coordinates (Bohr)
326
+ element_list : list
327
+ List of element symbols
328
+ base_hessian : numpy.ndarray
329
+ Base model Hessian
330
+
331
+ Returns:
332
+ --------
333
+ numpy.ndarray
334
+ Hessian with short-range correction
335
+ """
336
+ print(f"Applying short-range correction (ω={self.omega:.3f}) to model Hessian...")
337
+ print("The correction will be applied only to non-bonded atom pairs.")
338
+
339
+ # Apply correction
340
+ corrected_hessian = self.apply_correction(base_hessian, coord, element_list)
341
+
342
+ # Handle NaN values
343
+ corrected_hessian = np.nan_to_num(corrected_hessian, nan=0.0)
344
+
345
+ print("Short-range correction applied successfully")
346
+ return corrected_hessian