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,106 @@
1
+ import numpy as np
2
+ from multioptpy.Parameters.parameter import GNB_radii_lib
3
+
4
+ class MorseApproxHessian:
5
+ """
6
+ A simple class to generate a model Hessian based on the second derivative
7
+ of a Morse potential, using GNB_radii_lib for covalent radii to estimate
8
+ equilibrium bond distances. This is a highly simplified illustration.
9
+
10
+ In this version, the covalent radii are obtained from GNB_radii_lib(element).
11
+ """
12
+
13
+ def __init__(self, De=0.10, a=0.20):
14
+ """
15
+ Parameters
16
+ ----------
17
+ De : float
18
+ Dissociation energy in arbitrary units (e.g., Hartree).
19
+ a : float
20
+ Range parameter for the Morse potential.
21
+ """
22
+ self.De = De
23
+ self.a = a
24
+
25
+ def estimate_bond_length(self, elem1, elem2):
26
+ """
27
+ Estimate equilibrium bond length using GNB_radii_lib for each element.
28
+ """
29
+ r1 = GNB_radii_lib(elem1)
30
+ r2 = GNB_radii_lib(elem2)
31
+ return r1 + r2
32
+
33
+ def compute_morse_second_derivative(self, r_current, r_eq):
34
+ """
35
+ Compute the second derivative of the Morse potential with respect to r,
36
+ evaluated at r_current.
37
+
38
+ V(r) = De * [1 - exp(-a * (r - r_eq))]^2
39
+
40
+ For simplicity, use a general expanded form for the second derivative:
41
+ d^2V/dr^2 = De * a^2 [ -2 e^{-x} + 4 e^{-2x} ]
42
+ where x = a (r - r_eq).
43
+ """
44
+ x = self.a * (r_current - r_eq)
45
+ # Expanded form for d^2V/dr^2
46
+ second_derivative = self.De * (self.a ** 2) * (-2.0 * np.exp(-x) + 4.0 * np.exp(-2.0 * x))
47
+ return second_derivative
48
+
49
+ def create_model_hessian(self, coord, element_list):
50
+ """
51
+ Create a simple Hessian matrix for pairwise bonds as if
52
+ each interaction is an independent Morse potential.
53
+
54
+ Parameters
55
+ ----------
56
+ coord : numpy.ndarray
57
+ Shape (N, 3) array of 3D coordinates for N atoms (in Å).
58
+ element_list : list
59
+ List of element symbols corresponding to the coordinates.
60
+
61
+ Returns
62
+ -------
63
+ numpy.ndarray
64
+ Hessian matrix of shape (3N, 3N).
65
+ """
66
+ n_atoms = len(element_list)
67
+ hessian_size = 3 * n_atoms
68
+ hessian = np.zeros((hessian_size, hessian_size), dtype=float)
69
+
70
+ # Pairwise approach to generate naive bond Hessian elements
71
+ for i in range(n_atoms - 1):
72
+ for j in range(i + 1, n_atoms):
73
+ # Estimate the equilibrium bond length
74
+ r_eq = self.estimate_bond_length(element_list[i], element_list[j])
75
+
76
+ # Current distance
77
+ vec_ij = coord[j] - coord[i]
78
+ dist_ij = np.linalg.norm(vec_ij)
79
+
80
+ # Compute second derivative for the Morse potential
81
+ d2V = self.compute_morse_second_derivative(dist_ij, r_eq)
82
+
83
+ # Handle direction vector
84
+ if dist_ij > 1.0e-12:
85
+ direction = vec_ij / dist_ij
86
+ else:
87
+ direction = np.zeros(3)
88
+
89
+ # Construct the 3x3 block k_ij * (direction outer direction)
90
+ bond_k = d2V * np.outer(direction, direction)
91
+
92
+ # Indices in the full Hessian
93
+ block_i = slice(3 * i, 3 * i + 3)
94
+ block_j = slice(3 * j, 3 * j + 3)
95
+
96
+ # Update diagonal blocks
97
+ hessian[block_i, block_i] += bond_k
98
+ hessian[block_j, block_j] += bond_k
99
+ # Update off-diagonal blocks
100
+ hessian[block_i, block_j] -= bond_k
101
+ hessian[block_j, block_i] -= bond_k
102
+
103
+ # Symmetrize just in case
104
+ hessian = 0.5 * (hessian + hessian.T)
105
+ return hessian
106
+
@@ -0,0 +1,144 @@
1
+ import numpy as np
2
+ import itertools
3
+
4
+ from multioptpy.Parameters.parameter import UnitValueLib, covalent_radii_lib
5
+ from multioptpy.Utils.calc_tools import Calculationtools
6
+ from multioptpy.Parameters.parameter import number_element
7
+ from multioptpy.Coordinate.redundant_coordinate import RedundantInternalCoordinates
8
+ from multioptpy.Utils.bond_connectivity import BondConnectivity
9
+
10
+
11
+ class SchlegelApproxHessian:
12
+ def __init__(self):
13
+ #Lindh's approximate hessian
14
+ #ref: Journal of Molecular Structure: THEOCHEM Volumes 398–399, 30 June 1997, Pages 55-61
15
+ #ref: Theoret. Chim. Acta (Berl.) 66, 333–340 (1984)
16
+ self.bohr2angstroms = UnitValueLib().bohr2angstroms
17
+ self.hartree2kcalmol = UnitValueLib().hartree2kcalmol
18
+
19
+
20
+ def return_schlegel_const(self, element_1, element_2):
21
+ if type(element_1) is int:
22
+ element_1 = number_element(element_1)
23
+ if type(element_2) is int:
24
+ element_2 = number_element(element_2)
25
+
26
+ parameter_B_matrix = [[0.2573, 0.3401, 0.6937, 0.7126, 0.8335, 0.9491, 0.9491],
27
+ [0.3401, 0.9652, 1.2843, 1.4725, 1.6549, 1.7190, 1.7190],
28
+ [0.6937, 1.2843, 1.6925, 1.8238, 2.1164, 2.3185, 2.3185],
29
+ [0.7126, 1.4725, 1.8238, 2.0203, 2.2137, 2.5206, 2.5206],
30
+ [0.8335, 1.6549, 2.1164, 2.2137, 2.3718, 2.5110, 2.5110],
31
+ [0.9491, 1.7190, 2.3185, 2.5206, 2.5110, 2.5110, 2.5110],
32
+ [0.9491, 1.7190, 2.3185, 2.5206, 2.5110, 2.5110, 2.5110]]# Bohr
33
+
34
+ first_period_table = ["H", "He"]
35
+ second_period_table = ["Li", "Be", "B", "C", "N", "O", "F", "Ne"]
36
+ third_period_table = ["K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br","Kr"]
37
+ fourth_period_table = ["Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc","Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te","I", "Xe"]
38
+ fifth_period_table = ["Cs", "Ba", "La","Ce","Pr","Nd","Pm","Sm", "Eu", "Gd", "Tb", "Dy" ,"Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn"]
39
+ if element_1 in first_period_table:
40
+ idx_1 = 0
41
+ elif element_1 in second_period_table:
42
+ idx_1 = 1
43
+ elif element_1 in third_period_table:
44
+ idx_1 = 2
45
+ elif element_1 in fourth_period_table:
46
+ idx_1 = 3
47
+ elif element_1 in fifth_period_table:
48
+ idx_1 = 4
49
+ else:
50
+ idx_1 = 5
51
+
52
+ if element_2 in first_period_table:
53
+ idx_2 = 0
54
+ elif element_2 in second_period_table:
55
+ idx_2 = 1
56
+ elif element_2 in third_period_table:
57
+ idx_2 = 2
58
+ elif element_2 in fourth_period_table:
59
+ idx_2 = 3
60
+ elif element_2 in fifth_period_table:
61
+ idx_2 = 4
62
+ else:
63
+ idx_2 = 5
64
+
65
+
66
+ const_b = parameter_B_matrix[idx_1][idx_2]
67
+
68
+ return const_b
69
+
70
+
71
+ def guess_schlegel_hessian(self, coord, element_list):
72
+ #coord: cartecian coord, Bohr (atom num × 3)
73
+ BC = BondConnectivity()
74
+ b_c_mat = BC.bond_connect_matrix(element_list, coord)
75
+ val_num = len(coord)*3
76
+ connectivity_table = [BC.bond_connect_table(b_c_mat), BC.angle_connect_table(b_c_mat), BC.dihedral_angle_connect_table(b_c_mat)]
77
+ #RIC_approx_diag_hessian = []
78
+ RIC_approx_diag_hessian = [0.0 for i in range(self.RIC_variable_num)]
79
+ RIC_idx_list = [[i[0], i[1]] for i in itertools.combinations([j for j in range(len(coord))] , 2)]
80
+
81
+ for idx_list in connectivity_table:
82
+ for idx in idx_list:
83
+ if len(idx) == 2:
84
+ tmp_idx = sorted([idx[0], idx[1]])
85
+ distance = np.linalg.norm(coord[idx[0]] - coord[idx[1]])
86
+
87
+ elem_1 = element_list[idx[0]]
88
+ elem_2 = element_list[idx[1]]
89
+ const_b = self.return_schlegel_const(elem_1, elem_2)
90
+ tmpnum = RIC_idx_list.index(tmp_idx)
91
+ F = 1.734 / (distance - const_b) ** 3
92
+ RIC_approx_diag_hessian[tmpnum] += F
93
+
94
+ elif len(idx) == 3:
95
+ tmp_idx_1 = sorted([idx[0], idx[1]])
96
+ tmp_idx_2 = sorted([idx[1], idx[2]])
97
+ elem_1 = element_list[idx[0]]
98
+ elem_2 = element_list[idx[1]]
99
+ elem_3 = element_list[idx[2]]
100
+ tmpnum_1 = RIC_idx_list.index(tmp_idx_1)
101
+ tmpnum_2 = RIC_idx_list.index(tmp_idx_2)
102
+ if elem_1 == "H" or elem_3 == "H":
103
+ RIC_approx_diag_hessian[tmpnum_1] += 0.160
104
+ RIC_approx_diag_hessian[tmpnum_2] += 0.160
105
+ else:
106
+ RIC_approx_diag_hessian[tmpnum_1] += 0.250
107
+ RIC_approx_diag_hessian[tmpnum_2] += 0.250
108
+
109
+ elif len(idx) == 4:
110
+ tmp_idx_1 = sorted([idx[0], idx[1]])
111
+ tmp_idx_2 = sorted([idx[1], idx[2]])
112
+ tmp_idx_3 = sorted([idx[2], idx[3]])
113
+ elem_2 = element_list[idx[1]]
114
+ elem_3 = element_list[idx[2]]
115
+ distance = np.linalg.norm(coord[idx[1]] - coord[idx[2]])
116
+ bond_length = covalent_radii_lib(elem_2) + covalent_radii_lib(elem_3)
117
+ tmpnum_1 = RIC_idx_list.index(tmp_idx_1)
118
+ tmpnum_2 = RIC_idx_list.index(tmp_idx_2)
119
+ tmpnum_3 = RIC_idx_list.index(tmp_idx_3)
120
+ RIC_approx_diag_hessian[tmpnum_1] += 0.0023 -1* 0.07 * (distance - bond_length)
121
+ RIC_approx_diag_hessian[tmpnum_2] += 0.0023 -1* 0.07 * (distance - bond_length)
122
+ RIC_approx_diag_hessian[tmpnum_3] += 0.0023 -1* 0.07 * (distance - bond_length)
123
+
124
+
125
+ RIC_approx_hessian = np.array(np.diag(RIC_approx_diag_hessian), dtype="float64")
126
+ return RIC_approx_hessian
127
+
128
+
129
+ def main(self, coord, element_list, cart_gradient):
130
+ #coord: Bohr
131
+ print("generating Schlegel's approximate hessian...")
132
+
133
+ b_mat = RedundantInternalCoordinates().B_matrix(coord)
134
+ self.RIC_variable_num = len(b_mat)
135
+
136
+
137
+ int_approx_hess = self.guess_schlegel_hessian(coord, element_list)
138
+ cart_hess = np.dot(b_mat.T, np.dot(int_approx_hess, b_mat))
139
+
140
+ cart_hess = np.nan_to_num(cart_hess, nan=0.0)
141
+ #eigenvalue, _ = np.linalg.eig(cart_hess)
142
+ #print(sorted(eigenvalue))
143
+ hess_proj = Calculationtools().project_out_hess_tr_and_rot_for_coord(cart_hess, element_list, coord)
144
+ return hess_proj#cart_hess
@@ -0,0 +1,322 @@
1
+ import numpy as np
2
+ import itertools
3
+
4
+ from multioptpy.Parameters.parameter import UnitValueLib, covalent_radii_lib, UFF_VDW_distance_lib, D3Parameters, triple_covalent_radii_lib
5
+ from multioptpy.Utils.calc_tools import Calculationtools
6
+ from multioptpy.Parameters.parameter import UFF_VDW_distance_lib, number_element
7
+ from multioptpy.Coordinate.redundant_coordinate import RedundantInternalCoordinates
8
+ from multioptpy.Utils.bond_connectivity import BondConnectivity
9
+
10
+
11
+ class SchlegelD3ApproxHessian:
12
+ def __init__(self):
13
+ """
14
+ Schlegel's approximate Hessian with D3 dispersion corrections and special handling for cyano groups
15
+ References:
16
+ - Schlegel: Journal of Molecular Structure: THEOCHEM Volumes 398–399, 30 June 1997, Pages 55-61
17
+ - D3: S. Grimme, J. Antony, S. Ehrlich, H. Krieg, J. Chem. Phys., 2010, 132, 154104
18
+ """
19
+ self.bohr2angstroms = UnitValueLib().bohr2angstroms
20
+ self.hartree2kcalmol = UnitValueLib().hartree2kcalmol
21
+
22
+ # D3 dispersion parameters
23
+ self.d3_params = D3Parameters()
24
+
25
+ # Cyano group parameters - enhanced force constants
26
+ self.cn_stretch_factor = 2.0 # Enhance stretch force constants for C≡N triple bond
27
+ self.cn_angle_factor = 1.5 # Enhance angle force constants involving C≡N
28
+ self.cn_torsion_factor = 0.5 # Reduce torsion force constants involving C≡N (more flexible)
29
+
30
+ def detect_cyano_groups(self, coord, element_list):
31
+ """Detect C≡N triple bonds in the structure"""
32
+ cyano_atoms = [] # List of (C_idx, N_idx) tuples
33
+
34
+ for i in range(len(coord)):
35
+ if element_list[i] != 'C':
36
+ continue
37
+
38
+ for j in range(len(coord)):
39
+ if i == j or element_list[j] != 'N':
40
+ continue
41
+
42
+ # Calculate distance between C and N
43
+ r_ij = np.linalg.norm(coord[i] - coord[j])
44
+
45
+ # Check if distance is close to a triple bond length
46
+ cn_triple_bond = triple_covalent_radii_lib('C') + triple_covalent_radii_lib('N')
47
+
48
+ if abs(r_ij - cn_triple_bond) < 0.3: # Within 0.3 bohr of ideal length
49
+ # Check if C is connected to only one other atom (besides N)
50
+ connections_to_c = 0
51
+ for k in range(len(coord)):
52
+ if k == i or k == j:
53
+ continue
54
+
55
+ r_ik = np.linalg.norm(coord[i] - coord[k])
56
+ cov_dist = covalent_radii_lib(element_list[i]) + covalent_radii_lib(element_list[k])
57
+
58
+ if r_ik < 1.3 * cov_dist: # Using 1.3 as a factor to account for bond length variations
59
+ connections_to_c += 1
60
+
61
+ # If C has only one other connection, it's likely a terminal cyano group
62
+ if connections_to_c <= 1:
63
+ cyano_atoms.append((i, j))
64
+
65
+ return cyano_atoms
66
+
67
+ def return_schlegel_const(self, element_1, element_2):
68
+ """Return Schlegel's constant for a given element pair"""
69
+ if type(element_1) is int:
70
+ element_1 = number_element(element_1)
71
+ if type(element_2) is int:
72
+ element_2 = number_element(element_2)
73
+
74
+ parameter_B_matrix = [
75
+ [0.2573, 0.3401, 0.6937, 0.7126, 0.8335, 0.9491, 0.9491],
76
+ [0.3401, 0.9652, 1.2843, 1.4725, 1.6549, 1.7190, 1.7190],
77
+ [0.6937, 1.2843, 1.6925, 1.8238, 2.1164, 2.3185, 2.3185],
78
+ [0.7126, 1.4725, 1.8238, 2.0203, 2.2137, 2.5206, 2.5206],
79
+ [0.8335, 1.6549, 2.1164, 2.2137, 2.3718, 2.5110, 2.5110],
80
+ [0.9491, 1.7190, 2.3185, 2.5206, 2.5110, 2.5110, 2.5110],
81
+ [0.9491, 1.7190, 2.3185, 2.5206, 2.5110, 2.5110, 2.5110]
82
+ ] # Bohr
83
+
84
+ first_period_table = ["H", "He"]
85
+ second_period_table = ["Li", "Be", "B", "C", "N", "O", "F", "Ne"]
86
+ third_period_table = ["Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar"]
87
+ fourth_period_table = ["K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br","Kr"]
88
+ fifth_period_table = ["Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc","Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te","I", "Xe"]
89
+ sixth_period_table = ["Cs", "Ba", "La","Ce","Pr","Nd","Pm","Sm", "Eu", "Gd", "Tb", "Dy" ,"Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn"]
90
+
91
+ if element_1 in first_period_table:
92
+ idx_1 = 0
93
+ elif element_1 in second_period_table:
94
+ idx_1 = 1
95
+ elif element_1 in third_period_table:
96
+ idx_1 = 2
97
+ elif element_1 in fourth_period_table:
98
+ idx_1 = 3
99
+ elif element_1 in fifth_period_table:
100
+ idx_1 = 4
101
+ elif element_1 in sixth_period_table:
102
+ idx_1 = 5
103
+ else:
104
+ idx_1 = 6
105
+
106
+ if element_2 in first_period_table:
107
+ idx_2 = 0
108
+ elif element_2 in second_period_table:
109
+ idx_2 = 1
110
+ elif element_2 in third_period_table:
111
+ idx_2 = 2
112
+ elif element_2 in fourth_period_table:
113
+ idx_2 = 3
114
+ elif element_2 in fifth_period_table:
115
+ idx_2 = 4
116
+ elif element_2 in sixth_period_table:
117
+ idx_2 = 5
118
+ else:
119
+ idx_2 = 6
120
+
121
+ const_b = parameter_B_matrix[idx_1][idx_2]
122
+ return const_b
123
+
124
+ def d3_damping_function(self, r_ij, r0):
125
+ """Calculate D3 rational damping function"""
126
+ a1 = self.d3_params.a1
127
+ a2 = self.d3_params.a2
128
+
129
+ # Rational damping function for C6 term
130
+ damp = 1.0 / (1.0 + 6.0 * (r_ij / (a1 * r0)) ** a2)
131
+ return damp
132
+
133
+ def get_d3_parameters(self, elem1, elem2):
134
+ """Get D3 parameters for a pair of elements"""
135
+ # Get R4/R2 values
136
+ r4r2_1 = self.d3_params.get_r4r2(elem1)
137
+ r4r2_2 = self.d3_params.get_r4r2(elem2)
138
+
139
+ # C6 coefficients
140
+ c6_1 = r4r2_1 ** 2
141
+ c6_2 = r4r2_2 ** 2
142
+ c6 = np.sqrt(c6_1 * c6_2)
143
+
144
+ # C8 coefficients
145
+ c8 = 3.0 * c6 * np.sqrt(r4r2_1 * r4r2_2)
146
+
147
+ # r0 parameter (vdW radii)
148
+ r0 = np.sqrt(UFF_VDW_distance_lib(elem1) * UFF_VDW_distance_lib(elem2))
149
+
150
+ return c6, c8, r0
151
+
152
+ def calc_d3_correction(self, r_ij, elem1, elem2):
153
+ """Calculate D3 dispersion correction to the force constant"""
154
+ # Get D3 parameters
155
+ c6, c8, r0 = self.get_d3_parameters(elem1, elem2)
156
+
157
+ # Damping functions
158
+ damp6 = self.d3_damping_function(r_ij, r0)
159
+
160
+ # D3 energy contribution (simplified)
161
+ e_disp = -self.d3_params.s6 * c6 / r_ij**6 * damp6
162
+
163
+ # Approximate second derivative (force constant)
164
+ fc_disp = self.d3_params.s6 * c6 * (42.0 / r_ij**8) * damp6
165
+
166
+ return fc_disp * 0.01 # Scale factor to match overall Hessian scale
167
+
168
+ def guess_schlegel_hessian(self, coord, element_list):
169
+ """
170
+ Calculate approximate Hessian using Schlegel's approach augmented with D3 dispersion
171
+ and special handling for cyano groups
172
+ """
173
+ # Detect cyano groups
174
+ cyano_atoms = self.detect_cyano_groups(coord, element_list)
175
+ cyano_set = set()
176
+ for c_idx, n_idx in cyano_atoms:
177
+ cyano_set.add(c_idx)
178
+ cyano_set.add(n_idx)
179
+
180
+ # Setup connectivity tables using BondConnectivity utility
181
+ BC = BondConnectivity()
182
+ b_c_mat = BC.bond_connect_matrix(element_list, coord)
183
+ connectivity_table = [BC.bond_connect_table(b_c_mat),
184
+ BC.angle_connect_table(b_c_mat),
185
+ BC.dihedral_angle_connect_table(b_c_mat)]
186
+
187
+ # Initialize RIC index list for all atom pairs
188
+ RIC_idx_list = [[i[0], i[1]] for i in itertools.combinations(range(len(coord)), 2)]
189
+ self.RIC_variable_num = len(RIC_idx_list)
190
+ RIC_approx_diag_hessian = [0.0] * self.RIC_variable_num
191
+
192
+ # Process connectivity table to build Hessian
193
+ for idx_list in connectivity_table:
194
+ for idx in idx_list:
195
+ # Bond stretching terms
196
+ if len(idx) == 2:
197
+ tmp_idx = sorted([idx[0], idx[1]])
198
+ distance = np.linalg.norm(coord[idx[0]] - coord[idx[1]])
199
+
200
+ elem_1 = element_list[idx[0]]
201
+ elem_2 = element_list[idx[1]]
202
+ const_b = self.return_schlegel_const(elem_1, elem_2)
203
+ tmpnum = RIC_idx_list.index(tmp_idx)
204
+
205
+ # Base Schlegel force constant
206
+ F = 1.734 / (distance - const_b) ** 3
207
+
208
+ # Check if this is a cyano bond
209
+ is_cyano_bond = False
210
+ for c_idx, n_idx in cyano_atoms:
211
+ if (idx[0] == c_idx and idx[1] == n_idx) or (idx[0] == n_idx and idx[1] == c_idx):
212
+ is_cyano_bond = True
213
+ break
214
+
215
+ # Add D3 dispersion contribution
216
+ d3_correction = self.calc_d3_correction(distance, elem_1, elem_2)
217
+
218
+ if is_cyano_bond:
219
+ # Enhanced force constant for C≡N triple bond
220
+ RIC_approx_diag_hessian[tmpnum] += self.cn_stretch_factor * F + d3_correction
221
+ else:
222
+ RIC_approx_diag_hessian[tmpnum] += F + d3_correction
223
+
224
+ # Angle bending terms
225
+ elif len(idx) == 3:
226
+ tmp_idx_1 = sorted([idx[0], idx[1]])
227
+ tmp_idx_2 = sorted([idx[1], idx[2]])
228
+ elem_1 = element_list[idx[0]]
229
+ elem_2 = element_list[idx[1]]
230
+ elem_3 = element_list[idx[2]]
231
+ tmpnum_1 = RIC_idx_list.index(tmp_idx_1)
232
+ tmpnum_2 = RIC_idx_list.index(tmp_idx_2)
233
+
234
+ # Check if angle involves cyano group
235
+ is_cyano_angle = (idx[0] in cyano_set or idx[1] in cyano_set or idx[2] in cyano_set)
236
+
237
+ # Base Schlegel force constant
238
+ if elem_1 == "H" or elem_3 == "H":
239
+ F_angle = 0.160
240
+ else:
241
+ F_angle = 0.250
242
+
243
+ # Add D3 dispersion contribution
244
+ d3_r1 = np.linalg.norm(coord[idx[0]] - coord[idx[1]])
245
+ d3_r2 = np.linalg.norm(coord[idx[1]] - coord[idx[2]])
246
+ d3_correction_1 = self.calc_d3_correction(d3_r1, elem_1, elem_2) * 0.2
247
+ d3_correction_2 = self.calc_d3_correction(d3_r2, elem_2, elem_3) * 0.2
248
+
249
+ if is_cyano_angle:
250
+ # Enhanced angle force constants for angles involving C≡N
251
+ RIC_approx_diag_hessian[tmpnum_1] += self.cn_angle_factor * F_angle + d3_correction_1
252
+ RIC_approx_diag_hessian[tmpnum_2] += self.cn_angle_factor * F_angle + d3_correction_2
253
+ else:
254
+ RIC_approx_diag_hessian[tmpnum_1] += F_angle + d3_correction_1
255
+ RIC_approx_diag_hessian[tmpnum_2] += F_angle + d3_correction_2
256
+
257
+ # Torsion (dihedral) terms
258
+ elif len(idx) == 4:
259
+ tmp_idx_1 = sorted([idx[0], idx[1]])
260
+ tmp_idx_2 = sorted([idx[1], idx[2]])
261
+ tmp_idx_3 = sorted([idx[2], idx[3]])
262
+ elem_1 = element_list[idx[0]]
263
+ elem_2 = element_list[idx[1]]
264
+ elem_3 = element_list[idx[2]]
265
+ elem_4 = element_list[idx[3]]
266
+ distance = np.linalg.norm(coord[idx[1]] - coord[idx[2]])
267
+ bond_length = covalent_radii_lib(elem_2) + covalent_radii_lib(elem_3)
268
+ tmpnum_1 = RIC_idx_list.index(tmp_idx_1)
269
+ tmpnum_2 = RIC_idx_list.index(tmp_idx_2)
270
+ tmpnum_3 = RIC_idx_list.index(tmp_idx_3)
271
+
272
+ # Base Schlegel torsion force constant
273
+ F_torsion = 0.0023 - 0.07 * (distance - bond_length)
274
+
275
+ # Check if torsion involves cyano group
276
+ is_cyano_torsion = (idx[0] in cyano_set or idx[1] in cyano_set or
277
+ idx[2] in cyano_set or idx[3] in cyano_set)
278
+
279
+ # Add D3 dispersion contribution
280
+ d3_r1 = np.linalg.norm(coord[idx[0]] - coord[idx[1]])
281
+ d3_r2 = np.linalg.norm(coord[idx[1]] - coord[idx[2]])
282
+ d3_r3 = np.linalg.norm(coord[idx[2]] - coord[idx[3]])
283
+ d3_correction_1 = self.calc_d3_correction(d3_r1, elem_1, elem_2) * 0.05
284
+ d3_correction_2 = self.calc_d3_correction(d3_r2, elem_2, elem_3) * 0.05
285
+ d3_correction_3 = self.calc_d3_correction(d3_r3, elem_3, elem_4) * 0.05
286
+
287
+ if is_cyano_torsion:
288
+ # Reduced torsion force constants for torsions involving C≡N
289
+ RIC_approx_diag_hessian[tmpnum_1] += self.cn_torsion_factor * F_torsion + d3_correction_1
290
+ RIC_approx_diag_hessian[tmpnum_2] += self.cn_torsion_factor * F_torsion + d3_correction_2
291
+ RIC_approx_diag_hessian[tmpnum_3] += self.cn_torsion_factor * F_torsion + d3_correction_3
292
+ else:
293
+ RIC_approx_diag_hessian[tmpnum_1] += F_torsion + d3_correction_1
294
+ RIC_approx_diag_hessian[tmpnum_2] += F_torsion + d3_correction_2
295
+ RIC_approx_diag_hessian[tmpnum_3] += F_torsion + d3_correction_3
296
+
297
+ # Convert to numpy array
298
+ RIC_approx_hessian = np.diag(RIC_approx_diag_hessian).astype("float64")
299
+ return RIC_approx_hessian
300
+
301
+ def main(self, coord, element_list, cart_gradient):
302
+ """Main method to calculate the approximate Hessian"""
303
+ print("Generating Schlegel's approximate Hessian with D3 dispersion correction...")
304
+
305
+ # Calculate B matrix for redundant internal coordinates
306
+ b_mat = RedundantInternalCoordinates().B_matrix(coord)
307
+ self.RIC_variable_num = len(b_mat)
308
+
309
+ # Calculate approximate Hessian in internal coordinates
310
+ int_approx_hess = self.guess_schlegel_hessian(coord, element_list)
311
+
312
+ # Convert to Cartesian coordinates
313
+ cart_hess = np.dot(b_mat.T, np.dot(int_approx_hess, b_mat))
314
+
315
+ # Handle NaN values
316
+ cart_hess = np.nan_to_num(cart_hess, nan=0.0)
317
+
318
+ # Project out translational and rotational modes
319
+ hess_proj = Calculationtools().project_out_hess_tr_and_rot_for_coord(cart_hess, element_list, coord)
320
+
321
+ return hess_proj
322
+