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,718 @@
1
+ from multioptpy.Parameters.parameter import UnitValueLib, UFF_VDW_distance_lib, UFF_VDW_well_depth_lib, GNB_VDW_radii_lib, GNB_VDW_well_depth_lib
2
+ from multioptpy.Utils.calc_tools import torch_rotate_around_axis, torch_align_vector_with_z
3
+ from multioptpy.Optimizer.fire import FIRE
4
+
5
+ import torch
6
+ import copy
7
+ import random
8
+ import math
9
+
10
+ class AsymmetricEllipsoidalLJPotential:
11
+ def __init__(self, **kwarg):
12
+ #ref.: https://doi.org/10.26434/chemrxiv-2024-6www6
13
+ self.config = kwarg
14
+ UVL = UnitValueLib()
15
+ self.hartree2kcalmol = UVL.hartree2kcalmol
16
+ self.bohr2angstroms = UVL.bohr2angstroms
17
+ self.hartree2kjmol = UVL.hartree2kjmol
18
+ self.element_list = self.config["element_list"]
19
+ self.file_directory = self.config["file_directory"]
20
+ self.rot_angle_list = []
21
+ npot = len(self.config["asymmetric_ellipsoidal_repulsive_potential_eps"])
22
+ for i in range(npot):
23
+ self.rot_angle_list.append(random.uniform(0, 2*math.pi))
24
+ self.nangle = npot
25
+ self.rot_angle_list = torch.tensor([self.rot_angle_list], dtype=torch.float64, requires_grad=True)
26
+
27
+ self.lj_repulsive_order = 12.0
28
+ self.lj_attractive_order = 6.0
29
+
30
+ self.micro_iteration = 15000 * npot
31
+ self.rand_search_iteration = 1000 * npot
32
+ self.threshold = 1e-7
33
+ self.init = True
34
+
35
+ self.energy_analysis_dict = None
36
+ self.energy_save_flag = False
37
+ return
38
+
39
+ def save_state(self):
40
+ with open(self.file_directory + "/asym_ellipsoid_v1.xyz", "a") as f:
41
+ f.write(str(len(self.tmp_geom_num_list_for_save)) + "\n")
42
+ f.write("AsymmetricEllipsoid\n")
43
+ for i in range(len(self.tmp_geom_num_list_for_save)):
44
+ f.write(self.tmp_element_list_for_save[i] + " " + str(self.tmp_geom_num_list_for_save[i][0].item()) + " " + str(self.tmp_geom_num_list_for_save[i][1].item()) + " " + str(self.tmp_geom_num_list_for_save[i][2].item()) + "\n")
45
+
46
+ return
47
+
48
+ def save_part_ene(self):
49
+ with open(self.file_directory + "/asym_ellipsoid_p_ene.txt", "a") as f:
50
+ f.write(str(self.energy_analysis_dict)+"\n")
51
+
52
+ return
53
+
54
+ def calc_potential(self, geom_num_list, rot_angle_list, bias_pot_params):
55
+ energy = 0.0
56
+ """
57
+ self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"],
58
+ self.config["asymmetric_ellipsoidal_repulsive_potential_offtgt"],
59
+
60
+ """
61
+ rot_angle_list = rot_angle_list[0]
62
+ tmp_geom_num_list_for_save = geom_num_list * self.bohr2angstroms # save the geometry with asymmetric ellipsoid
63
+ tmp_element_list_for_save = self.element_list
64
+
65
+
66
+ # interaction between substrate and asymmetric ellipsoid
67
+ for pot_i in range(len(bias_pot_params)):
68
+
69
+ tgt_atom_list = [i for i in range(len(geom_num_list)) if not i+1 in self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_i] + self.config["asymmetric_ellipsoidal_repulsive_potential_offtgt"][pot_i]]
70
+ root_atom = self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_i][0] - 1
71
+ LJ_atom = self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_i][1] - 1
72
+
73
+ asym_elip_eps = bias_pot_params[pot_i][0] / self.hartree2kjmol
74
+ asym_elip_sig_xp = bias_pot_params[pot_i][1] / self.bohr2angstroms
75
+ asym_elip_sig_xm = bias_pot_params[pot_i][2] / self.bohr2angstroms
76
+ asym_elip_sig_yp = bias_pot_params[pot_i][3] / self.bohr2angstroms
77
+ asym_elip_sig_ym = bias_pot_params[pot_i][4] / self.bohr2angstroms
78
+ asym_elip_sig_zp = bias_pot_params[pot_i][5] / self.bohr2angstroms
79
+ asym_elip_sig_zm = bias_pot_params[pot_i][6] / self.bohr2angstroms
80
+ asym_elip_dist = bias_pot_params[pot_i][7] / self.bohr2angstroms
81
+
82
+ # rotate the asymmetric ellipsoid
83
+ LJ_vec = geom_num_list[LJ_atom] - geom_num_list[root_atom]
84
+ LJ_vec = LJ_vec / torch.norm(LJ_vec)
85
+ LJ_center = geom_num_list[root_atom] + LJ_vec * asym_elip_dist
86
+ z_axis_adjust_rot_mat = torch_align_vector_with_z(LJ_vec)
87
+ z_axis_adjusted_tmp_geom_num_list = torch.matmul(z_axis_adjust_rot_mat, (geom_num_list - geom_num_list[root_atom]).T).T
88
+ z_axis_adjusted_LJ_center = torch.matmul(z_axis_adjust_rot_mat, (LJ_center - geom_num_list[root_atom]).reshape(3, 1)).T
89
+
90
+ rot_mat = torch_rotate_around_axis(rot_angle_list[pot_i], axis="z")
91
+ rotated_z_axis_adjusted_tmp_geom_num_list = torch.matmul(rot_mat, z_axis_adjusted_tmp_geom_num_list.T).T
92
+
93
+
94
+ LJ_vec_for_save = tmp_geom_num_list_for_save[LJ_atom] - tmp_geom_num_list_for_save[root_atom]
95
+ LJ_vec_for_save = LJ_vec_for_save / torch.norm(LJ_vec_for_save)
96
+ LJ_center_for_save = tmp_geom_num_list_for_save[root_atom] + LJ_vec_for_save * asym_elip_dist * self.bohr2angstroms
97
+ z_axis_adjust_rot_mat_for_save = torch_align_vector_with_z(LJ_vec_for_save)
98
+ z_axis_adjusted_tmp_geom_num_list_for_save = torch.matmul(z_axis_adjust_rot_mat_for_save, (tmp_geom_num_list_for_save - tmp_geom_num_list_for_save[root_atom]).T).T
99
+ z_axis_adjusted_LJ_center_for_save = torch.matmul(z_axis_adjust_rot_mat_for_save, (LJ_center_for_save - tmp_geom_num_list_for_save[root_atom]).reshape(3, 1)).T
100
+ rotated_z_axis_adjusted_tmp_geom_num_list_for_save = torch.matmul(rot_mat, z_axis_adjusted_tmp_geom_num_list_for_save.T).T
101
+
102
+
103
+ tgt_atom_pos = rotated_z_axis_adjusted_tmp_geom_num_list[tgt_atom_list] - z_axis_adjusted_LJ_center[0]
104
+ tgt_atom_eps = torch.tensor([GNB_VDW_well_depth_lib(self.element_list[tgt_atom]) for tgt_atom in tgt_atom_list], dtype=torch.float64)
105
+ tgt_atom_sig = torch.tensor([GNB_VDW_radii_lib(self.element_list[tgt_atom]) / 2.0 for tgt_atom in tgt_atom_list], dtype=torch.float64)
106
+
107
+
108
+ x, y, z = tgt_atom_pos[:, 0], tgt_atom_pos[:, 1], tgt_atom_pos[:, 2]
109
+
110
+
111
+ x_sig = torch.where(x > 0, torch.sqrt(2 ** (14 / 6) * asym_elip_sig_xp * tgt_atom_sig), torch.sqrt(2 ** (14 / 6) * asym_elip_sig_xm * tgt_atom_sig))
112
+ y_sig = torch.where(y > 0, torch.sqrt(2 ** (14 / 6) * asym_elip_sig_yp * tgt_atom_sig), torch.sqrt(2 ** (14 / 6) * asym_elip_sig_ym * tgt_atom_sig))
113
+ z_sig = torch.where(z > 0, torch.sqrt(2 ** (14 / 6) * asym_elip_sig_zp * tgt_atom_sig), torch.sqrt(2 ** (14 / 6) * asym_elip_sig_zm * tgt_atom_sig))
114
+
115
+ x_eps = torch.sqrt(asym_elip_eps * tgt_atom_eps)
116
+ y_eps = torch.sqrt(asym_elip_eps * tgt_atom_eps)
117
+ z_eps = torch.sqrt(asym_elip_eps * tgt_atom_eps)
118
+
119
+
120
+ r_ell = torch.sqrt((x / x_sig) ** 2 + (y / y_sig) ** 2 + (z / z_sig) ** 2)
121
+ r_ell_norm = torch.linalg.norm(r_ell, dim=-1)
122
+
123
+ lj_eps = 1 / torch.sqrt((x / r_ell_norm / x_eps) ** 2 + (y / r_ell_norm / y_eps) ** 2 + (z / r_ell_norm / z_eps) ** 2)
124
+ eps = torch.sqrt(lj_eps * tgt_atom_eps)
125
+
126
+
127
+ r_ell_inv = 1 / r_ell
128
+ tmp_ene = eps * ((r_ell_inv ** self.lj_repulsive_order) - 2 * (r_ell_inv ** self.lj_attractive_order))
129
+
130
+
131
+ if self.energy_save_flag:
132
+ for i, tgt_atom in enumerate(tgt_atom_list):
133
+ self.energy_analysis_dict["ell_" + str(pot_i) + "_atom" + str(tgt_atom + 1)] = tmp_ene[i].item()
134
+
135
+ energy = energy + torch.sum(tmp_ene)
136
+
137
+
138
+ #--------------
139
+ tmp_geom_num_list_for_save = torch.cat([rotated_z_axis_adjusted_tmp_geom_num_list_for_save, z_axis_adjusted_LJ_center_for_save], dim=0)
140
+
141
+ ellipsoid_list = torch.tensor([[asym_elip_sig_xp, 0.0, 0.0+asym_elip_dist],
142
+ [-1*asym_elip_sig_xm, 0.0, 0.0+asym_elip_dist],
143
+ [0.0, asym_elip_sig_yp, 0.0+asym_elip_dist],
144
+ [0.0, -1*asym_elip_sig_ym, 0.0+asym_elip_dist],
145
+ [0.0, 0.0, asym_elip_sig_zp+asym_elip_dist],
146
+ [0.0, 0.0, -1*asym_elip_sig_zm+asym_elip_dist]], dtype=torch.float64) * self.bohr2angstroms
147
+ tmp_geom_num_list_for_save = torch.cat((tmp_geom_num_list_for_save, ellipsoid_list), dim=0)
148
+ tmp_element_list_for_save = tmp_element_list_for_save + ["x", "X", "X", "X", "X", "X", "X"]
149
+
150
+ #--------------
151
+
152
+ # interaction between asymmetric ellipsoid and asymmetric ellipsoid
153
+ if len(bias_pot_params) > 1:
154
+ for pot_i in range(len(bias_pot_params)):
155
+ root_atom_i = self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_i][0] - 1
156
+ LJ_atom_i = self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_i][1] - 1
157
+ asym_elip_eps_i = bias_pot_params[pot_i][0] / self.hartree2kjmol
158
+ asym_elip_sig_xp_i = bias_pot_params[pot_i][1] / self.bohr2angstroms
159
+ asym_elip_sig_xm_i = bias_pot_params[pot_i][2] / self.bohr2angstroms
160
+ asym_elip_sig_yp_i = bias_pot_params[pot_i][3] / self.bohr2angstroms
161
+ asym_elip_sig_ym_i = bias_pot_params[pot_i][4] / self.bohr2angstroms
162
+ asym_elip_sig_zp_i = bias_pot_params[pot_i][5] / self.bohr2angstroms
163
+ asym_elip_sig_zm_i = bias_pot_params[pot_i][6] / self.bohr2angstroms
164
+ asym_elip_dist_i = bias_pot_params[pot_i][7] / self.bohr2angstroms
165
+ # rotate the asymmetric ellipsoid
166
+ LJ_vec_i = geom_num_list[LJ_atom_i] - geom_num_list[root_atom_i]
167
+ LJ_vec_i = LJ_vec_i / torch.norm(LJ_vec_i)
168
+ LJ_center_i = geom_num_list[root_atom_i] + LJ_vec_i * asym_elip_dist_i
169
+
170
+ for pot_j in range(pot_i+1, len(bias_pot_params)):
171
+ if pot_i > pot_j:
172
+ continue
173
+
174
+ root_atom_j = self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_j][0] - 1
175
+ LJ_atom_j = self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"][pot_j][1] - 1
176
+ asym_elip_eps_j = bias_pot_params[pot_j][0] / self.hartree2kjmol
177
+ asym_elip_sig_xp_j = bias_pot_params[pot_j][1] / self.bohr2angstroms
178
+ asym_elip_sig_xm_j = bias_pot_params[pot_j][2] / self.bohr2angstroms
179
+ asym_elip_sig_yp_j = bias_pot_params[pot_j][3] / self.bohr2angstroms
180
+ asym_elip_sig_ym_j = bias_pot_params[pot_j][4] / self.bohr2angstroms
181
+ asym_elip_sig_zp_j = bias_pot_params[pot_j][5] / self.bohr2angstroms
182
+ asym_elip_sig_zm_j = bias_pot_params[pot_j][6] / self.bohr2angstroms
183
+ asym_elip_dist_j = bias_pot_params[pot_j][7] / self.bohr2angstroms
184
+ # rotate the asymmetric ellipsoid
185
+ LJ_vec_j = geom_num_list[LJ_atom_j] - geom_num_list[root_atom_j]
186
+ LJ_vec_j = LJ_vec_j / torch.norm(LJ_vec_j)
187
+ LJ_center_j = geom_num_list[root_atom_j] + LJ_vec_j * asym_elip_dist_j
188
+
189
+
190
+ #-----------------------------------
191
+
192
+ z_axis_adjust_rot_mat_i = torch_align_vector_with_z(LJ_vec_i)
193
+ z_axis_adjusted_LJ_center_j_i = torch.matmul(z_axis_adjust_rot_mat_i, (LJ_center_j - geom_num_list[root_atom_i]).reshape(3, 1)).T
194
+
195
+ z_axis_adjusted_LJ_center_i = torch.matmul(z_axis_adjust_rot_mat_i, (LJ_center_i - geom_num_list[root_atom_i]).reshape(3, 1)).T
196
+
197
+ rot_mat_i = torch_rotate_around_axis(rot_angle_list[pot_i])
198
+ rotated_z_axis_adjusted_LJ_center_j_i = torch.matmul(rot_mat_i, z_axis_adjusted_LJ_center_j_i.T).T
199
+
200
+
201
+
202
+ z_axis_adjust_rot_mat_j = torch_align_vector_with_z(LJ_vec_j)
203
+ z_axis_adjusted_LJ_center_i_j = torch.matmul(z_axis_adjust_rot_mat_j, (LJ_center_i - geom_num_list[root_atom_j]).reshape(3, 1)).T
204
+
205
+ z_axis_adjusted_LJ_center_j = torch.matmul(z_axis_adjust_rot_mat_j, (LJ_center_j - geom_num_list[root_atom_j]).reshape(3, 1)).T
206
+
207
+ rot_mat_j = torch_rotate_around_axis(rot_angle_list[pot_j])
208
+ rotated_z_axis_adjusted_LJ_center_i_j = torch.matmul(rot_mat_j, z_axis_adjusted_LJ_center_i_j.T).T
209
+
210
+ pos_j = rotated_z_axis_adjusted_LJ_center_j_i[0] - z_axis_adjusted_LJ_center_i[0]
211
+
212
+ x_j = pos_j[0]
213
+ y_j = pos_j[1]
214
+ z_j = pos_j[2]
215
+
216
+ if x_j > 0:
217
+ x_i_sig = 2 ** (7 / 6) * asym_elip_sig_xp_i
218
+ x_i_eps = asym_elip_eps_i
219
+ else:
220
+ x_i_sig = 2 ** (7 / 6) * asym_elip_sig_xm_i
221
+ x_i_eps = asym_elip_eps_i
222
+
223
+ if y_j > 0:
224
+ y_i_sig = 2 ** (7 / 6) * asym_elip_sig_yp_i
225
+ y_i_eps = asym_elip_eps_i
226
+ else:
227
+ y_i_sig = 2 ** (7 / 6) * asym_elip_sig_ym_i
228
+ y_i_eps = asym_elip_eps_i
229
+
230
+ if z_j > 0:
231
+ z_i_sig = 2 ** (7 / 6) * asym_elip_sig_zp_i
232
+ z_i_eps = asym_elip_eps_i
233
+ else:
234
+ z_i_sig = 2 ** (7 / 6) * asym_elip_sig_zm_i
235
+ z_i_eps = asym_elip_eps_i
236
+
237
+ r_ell_i = torch.sqrt((x_j / x_i_sig) ** 2 + (y_j / y_i_sig) ** 2 + (z_j / z_i_sig) ** 2)
238
+ r_ell_i_norm = torch.linalg.norm(r_ell_i)
239
+ lj_eps_i = 1 / torch.sqrt((x_j / r_ell_i_norm / x_i_eps) ** 2 + (y_j / r_ell_i_norm / y_i_eps) ** 2 + (z_j / r_ell_i_norm / z_i_eps) ** 2 )
240
+
241
+ pos_i = rotated_z_axis_adjusted_LJ_center_i_j[0] - z_axis_adjusted_LJ_center_j[0]
242
+
243
+ x_i = pos_i[0]
244
+ y_i = pos_i[1]
245
+ z_i = pos_i[2]
246
+
247
+ if x_i > 0:
248
+ x_j_sig = 2 ** (7 / 6) * asym_elip_sig_xp_j
249
+ x_j_eps = asym_elip_eps_j
250
+ else:
251
+ x_j_sig = 2 ** (7 / 6) * asym_elip_sig_xm_j
252
+ x_j_eps = asym_elip_eps_j
253
+
254
+ if y_i > 0:
255
+ y_j_sig = 2 ** (7 / 6) * asym_elip_sig_yp_j
256
+ y_j_eps = asym_elip_eps_j
257
+ else:
258
+ y_j_sig = 2 ** (7 / 6) * asym_elip_sig_ym_j
259
+ y_j_eps = asym_elip_eps_j
260
+
261
+ if z_i > 0:
262
+ z_j_sig = 2 ** (7 / 6) * asym_elip_sig_zp_j
263
+ z_j_eps = asym_elip_eps_j
264
+ else:
265
+ z_j_sig = 2 ** (7 / 6) * asym_elip_sig_zm_j
266
+ z_j_eps = asym_elip_eps_j
267
+
268
+ r_ell_j = torch.sqrt((x_i / x_j_sig) ** 2 + (y_i / y_j_sig) ** 2 + (z_i / z_j_sig) ** 2)
269
+ r_ell_j_norm = torch.linalg.norm(r_ell_j)
270
+ lj_eps_j = 1 / torch.sqrt((x_i / r_ell_j_norm / x_j_eps) ** 2 + (y_i / r_ell_j_norm / y_j_eps) ** 2 + (z_i / r_ell_j_norm / z_j_eps) ** 2 )
271
+
272
+ eps = torch.sqrt(lj_eps_i * lj_eps_j)
273
+ r_ell = torch.sqrt(r_ell_i * r_ell_j)
274
+
275
+ energy = energy + eps * (((1/r_ell) ** self.lj_repulsive_order) -2 * ((1/r_ell) ** self.lj_attractive_order))
276
+
277
+ self.tmp_geom_num_list_for_save = tmp_geom_num_list_for_save
278
+ self.tmp_element_list_for_save = tmp_element_list_for_save
279
+ return energy
280
+
281
+ def rand_search(self, geom_num_list, bias_pot_params):
282
+ max_energy = 1e+10
283
+ print("rand_search")
284
+
285
+ for i in range(self.rand_search_iteration):
286
+ tmp_rot_angle_list = [random.uniform(0, 2*math.pi) for j in range(len(self.config["asymmetric_ellipsoidal_repulsive_potential_eps"]))]
287
+ tmp_rot_angle_list = torch.tensor([tmp_rot_angle_list], dtype=torch.float64, requires_grad=True)
288
+ energy = self.calc_potential(geom_num_list, tmp_rot_angle_list, bias_pot_params)
289
+ if energy < max_energy:
290
+ print("energy: ", energy.item())
291
+ max_energy = energy
292
+ self.rot_angle_list = tmp_rot_angle_list
293
+ print("rand_search done")
294
+ print("max_energy: ", max_energy.item())
295
+ return
296
+
297
+
298
+ def microiteration(self, geom_num_list, bias_pot_params):
299
+ if self.init:
300
+ self.rand_search(geom_num_list, bias_pot_params)
301
+ self.init = False
302
+
303
+ prev_rot_grad = torch.zeros_like(self.rot_angle_list)
304
+ Opt = FIRE()
305
+ Opt.display_flag = False
306
+
307
+ for j in range(self.micro_iteration):
308
+ rot_grad = torch.func.jacrev(self.calc_potential, argnums=1)(geom_num_list, self.rot_angle_list, bias_pot_params)
309
+ if torch.linalg.norm(rot_grad) < self.threshold:
310
+ print("Converged!")
311
+ print("M. itr: ", j)
312
+ print("energy: ", self.calc_potential(geom_num_list, self.rot_angle_list, bias_pot_params).item())
313
+ break
314
+
315
+ tmp_rot_angle_list = copy.copy(self.rot_angle_list.clone().detach().numpy())
316
+ tmp_rot_grad = copy.copy(rot_grad.clone().detach().numpy())
317
+ tmp_prev_rot_grad = copy.copy(prev_rot_grad.clone().detach().numpy())
318
+ move_vector = Opt.run(tmp_rot_angle_list[0], tmp_rot_grad[0], tmp_prev_rot_grad[0])
319
+ move_vector = torch.tensor(move_vector, dtype=torch.float64)
320
+ self.rot_angle_list = self.rot_angle_list - 1.0 * move_vector
321
+ # update rot_angle_list
322
+ if j % 100 == 0:
323
+ print("M. itr: ", j)
324
+ print("energy: ", self.calc_potential(geom_num_list, self.rot_angle_list, bias_pot_params).item())
325
+ print("rot_angle_list: ", self.rot_angle_list.detach().numpy())
326
+ print("rot_grad: ", rot_grad.detach().numpy())
327
+
328
+
329
+ prev_rot_grad = rot_grad
330
+ else:
331
+ print("Not converged...")
332
+ raise
333
+
334
+ self.energy_analysis_dict = {}
335
+ self.energy_save_flag = True
336
+ energy = self.calc_potential(geom_num_list, self.rot_angle_list, bias_pot_params)
337
+ self.energy_save_flag = False
338
+ self.save_part_ene()
339
+ return energy
340
+
341
+
342
+ def calc_energy(self, geom_num_list, bias_pot_params):
343
+ """
344
+ # required variables: self.config["asymmetric_ellipsoidal_repulsive_potential_eps"],
345
+ self.config["asymmetric_ellipsoidal_repulsive_potential_sig"],
346
+ self.config["asymmetric_ellipsoidal_repulsive_potential_dist"],
347
+ self.config["asymmetric_ellipsoidal_repulsive_potential_atoms"],
348
+ self.config["asymmetric_ellipsoidal_repulsive_potential_offtgt"],
349
+ bias_pot_params[n][0] : asymmetric_ellipsoidal_repulsive_potential_eps
350
+ bias_pot_params[n][1:7] : asymmetric_ellipsoidal_repulsive_potential_sig
351
+ bias_pot_params[n][7] : asymmetric_ellipsoidal_repulsive_potential_dist
352
+ """
353
+ energy = self.microiteration(geom_num_list, bias_pot_params)
354
+ return energy
355
+
356
+ def calc_pot_for_eff_hess(self, coord_and_ell_angle, bias_pot_params):
357
+ geom_num_list = coord_and_ell_angle[:len(self.element_list)*3].reshape(-1, 3)
358
+ rot_angle_list = coord_and_ell_angle[len(self.element_list)*3:].reshape(1, self.nangle)
359
+ energy = self.calc_potential(geom_num_list, rot_angle_list, bias_pot_params)
360
+ return energy
361
+
362
+
363
+ def calc_eff_hessian(self, geom_num_list, bias_pot_params):# effective hessian
364
+ transformed_geom_num_list = geom_num_list.reshape(-1, 1)
365
+ transformed_angle_list = self.rot_angle_list.reshape(-1, 1)
366
+ coord_and_ell_angle = torch.cat((transformed_geom_num_list, transformed_angle_list), dim=0)
367
+ combined_hess = torch.func.hessian(self.calc_pot_for_eff_hess, argnums=0)(coord_and_ell_angle, bias_pot_params).reshape(len(self.element_list)*3+self.nangle, len(self.element_list)*3+self.nangle)
368
+ coupling_hess_1 = combined_hess[:len(self.element_list)*3, len(self.element_list)*3:]
369
+ coupling_hess_2 = combined_hess[len(self.element_list)*3:, :len(self.element_list)*3]
370
+ angle_hess = combined_hess[len(self.element_list)*3:, len(self.element_list)*3:]
371
+ eff_hess = -1 * torch.matmul(torch.matmul(coupling_hess_1, torch.linalg.inv(angle_hess)), coupling_hess_2)
372
+ return eff_hess
373
+
374
+
375
+ class AsymmetricEllipsoidalLJPotentialv2:
376
+ def __init__(self, **kwarg):
377
+ #ref.: https://doi.org/10.26434/chemrxiv-2024-6www6
378
+ self.config = kwarg
379
+ UVL = UnitValueLib()
380
+ self.hartree2kcalmol = UVL.hartree2kcalmol
381
+ self.bohr2angstroms = UVL.bohr2angstroms
382
+ self.hartree2kjmol = UVL.hartree2kjmol
383
+ self.element_list = self.config["element_list"]
384
+ self.file_directory = self.config["file_directory"]
385
+ self.rot_angle_list = []
386
+ for i in range(len(self.config["asymmetric_ellipsoidal_repulsive_potential_v2_eps"])):
387
+ self.rot_angle_list.append(random.uniform(0, 2*math.pi))
388
+ self.nangle = len(self.config["asymmetric_ellipsoidal_repulsive_potential_v2_eps"])
389
+ self.rot_angle_list = torch.tensor([self.rot_angle_list], dtype=torch.float64, requires_grad=True)
390
+
391
+ self.lj_repulsive_order = 12.0
392
+ self.lj_attractive_order = 6.0
393
+
394
+ self.micro_iteration = 15000 * len(self.config["asymmetric_ellipsoidal_repulsive_potential_v2_eps"])
395
+ self.rand_search_iteration = 1000 * len(self.config["asymmetric_ellipsoidal_repulsive_potential_v2_eps"])
396
+ self.threshold = 1e-7
397
+ self.init = True
398
+ self.save_flag = False
399
+ return
400
+
401
+ def save_state(self):
402
+ with open(self.file_directory + "/asym_ellipsoid_v2.xyz", "a") as f:
403
+ f.write(str(len(self.tmp_geom_num_list_for_save)) + "\n")
404
+ f.write("AsymmetricEllipsoid\n")
405
+ for i in range(len(self.tmp_geom_num_list_for_save)):
406
+ f.write(self.tmp_element_list_for_save[i] + " " + str(self.tmp_geom_num_list_for_save[i][0].item()) + " " + str(self.tmp_geom_num_list_for_save[i][1].item()) + " " + str(self.tmp_geom_num_list_for_save[i][2].item()) + "\n")
407
+
408
+ return
409
+
410
+ def calc_potential(self, geom_num_list, rot_angle_list, bias_pot_params):
411
+ energy = 0.0
412
+ """
413
+ self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"],
414
+ self.config["asymmetric_ellipsoidal_repulsive_potential_v2_offtgt"],
415
+
416
+ """
417
+ rot_angle_list = rot_angle_list[0]
418
+ tmp_geom_num_list_for_save = geom_num_list * self.bohr2angstroms # save the geometry with asymmetric ellipsoid
419
+ tmp_element_list_for_save = self.element_list
420
+
421
+
422
+ # interaction between substrate and asymmetric ellipsoid
423
+ for pot_i in range(len(bias_pot_params)):
424
+ tgt_atom_list = [i for i in range(len(geom_num_list)) if not i+1 in self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_i] + self.config["asymmetric_ellipsoidal_repulsive_potential_v2_offtgt"][pot_i]]
425
+ root_atom = self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_i][0] - 1
426
+ LJ_atom = self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_i][1] - 1
427
+
428
+ asym_elip_eps = bias_pot_params[pot_i][0] / self.hartree2kjmol
429
+ asym_elip_sig_xp = bias_pot_params[pot_i][1] / self.bohr2angstroms
430
+ asym_elip_sig_xm = bias_pot_params[pot_i][2] / self.bohr2angstroms
431
+ asym_elip_sig_yp = bias_pot_params[pot_i][3] / self.bohr2angstroms
432
+ asym_elip_sig_ym = bias_pot_params[pot_i][4] / self.bohr2angstroms
433
+ asym_elip_sig_zp = bias_pot_params[pot_i][5] / self.bohr2angstroms
434
+ asym_elip_sig_zm = bias_pot_params[pot_i][6] / self.bohr2angstroms
435
+ asym_elip_dist = bias_pot_params[pot_i][7] / self.bohr2angstroms
436
+
437
+ # rotate the asymmetric ellipsoid
438
+ LJ_vec = geom_num_list[LJ_atom] - geom_num_list[root_atom]
439
+ LJ_vec = LJ_vec / torch.norm(LJ_vec)
440
+ LJ_center = geom_num_list[root_atom] + LJ_vec * asym_elip_dist
441
+ z_axis_adjust_rot_mat = torch_align_vector_with_z(LJ_vec)
442
+ z_axis_adjusted_tmp_geom_num_list = torch.matmul(z_axis_adjust_rot_mat, (geom_num_list - geom_num_list[root_atom]).T).T
443
+ z_axis_adjusted_LJ_center = torch.matmul(z_axis_adjust_rot_mat, (LJ_center - geom_num_list[root_atom]).reshape(3, 1)).T
444
+
445
+ rot_mat = torch_rotate_around_axis(rot_angle_list[pot_i], axis="z")
446
+ rotated_z_axis_adjusted_tmp_geom_num_list = torch.matmul(rot_mat, z_axis_adjusted_tmp_geom_num_list.T).T
447
+
448
+ if self.save_flag:
449
+ LJ_vec_for_save = tmp_geom_num_list_for_save[LJ_atom] - tmp_geom_num_list_for_save[root_atom]
450
+ LJ_vec_for_save = LJ_vec_for_save / torch.norm(LJ_vec_for_save)
451
+ LJ_center_for_save = tmp_geom_num_list_for_save[root_atom] + LJ_vec_for_save * asym_elip_dist * self.bohr2angstroms
452
+ z_axis_adjust_rot_mat_for_save = torch_align_vector_with_z(LJ_vec_for_save)
453
+ z_axis_adjusted_tmp_geom_num_list_for_save = torch.matmul(z_axis_adjust_rot_mat_for_save, (tmp_geom_num_list_for_save - tmp_geom_num_list_for_save[root_atom]).T).T
454
+ z_axis_adjusted_LJ_center_for_save = torch.matmul(z_axis_adjust_rot_mat_for_save, (LJ_center_for_save - tmp_geom_num_list_for_save[root_atom]).reshape(3, 1)).T
455
+ rotated_z_axis_adjusted_tmp_geom_num_list_for_save = torch.matmul(rot_mat, z_axis_adjusted_tmp_geom_num_list_for_save.T).T
456
+
457
+ tgt_atom_pos = rotated_z_axis_adjusted_tmp_geom_num_list[tgt_atom_list] - z_axis_adjusted_LJ_center[0]
458
+ tgt_atom_eps = torch.tensor([UFF_VDW_well_depth_lib(self.element_list[tgt_atom]) for tgt_atom in tgt_atom_list], dtype=torch.float64)
459
+ tgt_atom_sig = torch.tensor([UFF_VDW_distance_lib(self.element_list[tgt_atom]) / 2.0 for tgt_atom in tgt_atom_list], dtype=torch.float64)
460
+
461
+ x, y, z = tgt_atom_pos[:, 0], tgt_atom_pos[:, 1], tgt_atom_pos[:, 2]
462
+
463
+ x_sig = torch.where(x > 0, (asym_elip_sig_xp + tgt_atom_sig) ** (7 / 6), (asym_elip_sig_xm + tgt_atom_sig) ** (7 / 6))
464
+ y_sig = torch.where(y > 0, (asym_elip_sig_yp + tgt_atom_sig) ** (7 / 6), (asym_elip_sig_ym + tgt_atom_sig) ** (7 / 6))
465
+ z_sig = torch.where(z > 0, (asym_elip_sig_zp + tgt_atom_sig) ** (7 / 6), (asym_elip_sig_zm + tgt_atom_sig) ** (7 / 6))
466
+
467
+ x_eps = torch.sqrt(asym_elip_eps * tgt_atom_eps)
468
+ y_eps = torch.sqrt(asym_elip_eps * tgt_atom_eps)
469
+ z_eps = torch.sqrt(asym_elip_eps * tgt_atom_eps)
470
+
471
+ r_ell = torch.sqrt((x / x_sig) ** 2 + (y / y_sig) ** 2 + (z / z_sig) ** 2)
472
+ r_ell_norm = torch.linalg.norm(r_ell, dim=-1)
473
+
474
+ lj_eps = 1 / torch.sqrt((x / r_ell_norm / x_eps) ** 2 + (y / r_ell_norm / y_eps) ** 2 + (z / r_ell_norm / z_eps) ** 2)
475
+ eps = torch.sqrt(lj_eps * tgt_atom_eps)
476
+
477
+ r_ell_inv = 1 / r_ell
478
+ tmp_ene = eps * ((r_ell_inv ** self.lj_repulsive_order) - 2 * (r_ell_inv ** self.lj_attractive_order))
479
+
480
+ energy = energy + torch.sum(tmp_ene)
481
+
482
+ #--------------
483
+ if self.save_flag:
484
+ tmp_geom_num_list_for_save = torch.cat([rotated_z_axis_adjusted_tmp_geom_num_list_for_save, z_axis_adjusted_LJ_center_for_save], dim=0)
485
+
486
+ ellipsoid_list = torch.tensor([[asym_elip_sig_xp, 0.0, 0.0+asym_elip_dist],
487
+ [-1*asym_elip_sig_xm, 0.0, 0.0+asym_elip_dist],
488
+ [0.0, asym_elip_sig_yp, 0.0+asym_elip_dist],
489
+ [0.0, -1*asym_elip_sig_ym, 0.0+asym_elip_dist],
490
+ [0.0, 0.0, asym_elip_sig_zp+asym_elip_dist],
491
+ [0.0, 0.0, -1*asym_elip_sig_zm+asym_elip_dist]], dtype=torch.float64) * self.bohr2angstroms
492
+ tmp_geom_num_list_for_save = torch.cat((tmp_geom_num_list_for_save, ellipsoid_list), dim=0)
493
+ tmp_element_list_for_save = tmp_element_list_for_save + ["x", "X", "X", "X", "X", "X", "X"]
494
+
495
+ #--------------
496
+
497
+ # interaction between asymmetric ellipsoid and asymmetric ellipsoid
498
+ if len(bias_pot_params) > 1:
499
+ for pot_i in range(len(bias_pot_params)):
500
+ asym_elip_eps_i = bias_pot_params[pot_i][0] / self.hartree2kjmol
501
+ asym_elip_sig_xp_i = bias_pot_params[pot_i][1] / self.bohr2angstroms
502
+ asym_elip_sig_xm_i = bias_pot_params[pot_i][2] / self.bohr2angstroms
503
+ asym_elip_sig_yp_i = bias_pot_params[pot_i][3] / self.bohr2angstroms
504
+ asym_elip_sig_ym_i = bias_pot_params[pot_i][4] / self.bohr2angstroms
505
+ asym_elip_sig_zp_i = bias_pot_params[pot_i][5] / self.bohr2angstroms
506
+ asym_elip_sig_zm_i = bias_pot_params[pot_i][6] / self.bohr2angstroms
507
+ asym_elip_dist_i = bias_pot_params[pot_i][7] / self.bohr2angstroms
508
+
509
+ root_atom_i = self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_i][0] - 1
510
+ LJ_atom_i = self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_i][1] - 1
511
+
512
+ # rotate the asymmetric ellipsoid
513
+ LJ_vec_i = geom_num_list[LJ_atom_i] - geom_num_list[root_atom_i]
514
+ LJ_vec_i = LJ_vec_i / torch.norm(LJ_vec_i)
515
+ LJ_center_i = geom_num_list[root_atom_i] + LJ_vec_i * asym_elip_dist_i
516
+
517
+ for pot_j in range(pot_i+1, len(bias_pot_params)):
518
+ if pot_i > pot_j:
519
+ continue
520
+
521
+
522
+
523
+ root_atom_j = self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_j][0] - 1
524
+ LJ_atom_j = self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"][pot_j][1] - 1
525
+ asym_elip_eps_j = bias_pot_params[pot_j][0] / self.hartree2kjmol
526
+ asym_elip_sig_xp_j = bias_pot_params[pot_j][1] / self.bohr2angstroms
527
+ asym_elip_sig_xm_j = bias_pot_params[pot_j][2] / self.bohr2angstroms
528
+ asym_elip_sig_yp_j = bias_pot_params[pot_j][3] / self.bohr2angstroms
529
+ asym_elip_sig_ym_j = bias_pot_params[pot_j][4] / self.bohr2angstroms
530
+ asym_elip_sig_zp_j = bias_pot_params[pot_j][5] / self.bohr2angstroms
531
+ asym_elip_sig_zm_j = bias_pot_params[pot_j][6] / self.bohr2angstroms
532
+ asym_elip_dist_j = bias_pot_params[pot_j][7] / self.bohr2angstroms
533
+ # rotate the asymmetric ellipsoid
534
+ LJ_vec_j = geom_num_list[LJ_atom_j] - geom_num_list[root_atom_j]
535
+ LJ_vec_j = LJ_vec_j / torch.norm(LJ_vec_j)
536
+ LJ_center_j = geom_num_list[root_atom_j] + LJ_vec_j * asym_elip_dist_j
537
+
538
+
539
+ #-----------------------------------
540
+
541
+ z_axis_adjust_rot_mat_i = torch_align_vector_with_z(LJ_vec_i)
542
+ z_axis_adjusted_LJ_center_j_i = torch.matmul(z_axis_adjust_rot_mat_i, (LJ_center_j - geom_num_list[root_atom_i]).reshape(3, 1)).T
543
+
544
+ z_axis_adjusted_LJ_center_i = torch.matmul(z_axis_adjust_rot_mat_i, (LJ_center_i - geom_num_list[root_atom_i]).reshape(3, 1)).T
545
+
546
+ rot_mat_i = torch_rotate_around_axis(rot_angle_list[pot_i])
547
+ rotated_z_axis_adjusted_LJ_center_j_i = torch.matmul(rot_mat_i, z_axis_adjusted_LJ_center_j_i.T).T
548
+
549
+
550
+
551
+ z_axis_adjust_rot_mat_j = torch_align_vector_with_z(LJ_vec_j)
552
+ z_axis_adjusted_LJ_center_i_j = torch.matmul(z_axis_adjust_rot_mat_j, (LJ_center_i - geom_num_list[root_atom_j]).reshape(3, 1)).T
553
+
554
+ z_axis_adjusted_LJ_center_j = torch.matmul(z_axis_adjust_rot_mat_j, (LJ_center_j - geom_num_list[root_atom_j]).reshape(3, 1)).T
555
+
556
+ rot_mat_j = torch_rotate_around_axis(rot_angle_list[pot_j])
557
+ rotated_z_axis_adjusted_LJ_center_i_j = torch.matmul(rot_mat_j, z_axis_adjusted_LJ_center_i_j.T).T
558
+
559
+ pos_j = rotated_z_axis_adjusted_LJ_center_j_i[0] - z_axis_adjusted_LJ_center_i[0]
560
+
561
+ x_j = pos_j[0]
562
+ y_j = pos_j[1]
563
+ z_j = pos_j[2]
564
+
565
+ if x_j > 0:
566
+ x_i_sig = asym_elip_sig_xp_i * 2 ** (7 / 6)
567
+ x_i_eps = asym_elip_eps_i
568
+ else:
569
+ x_i_sig = asym_elip_sig_xm_i * 2 ** (7 / 6)
570
+ x_i_eps = asym_elip_eps_i
571
+
572
+ if y_j > 0:
573
+ y_i_sig = asym_elip_sig_yp_i * 2 ** (7 / 6)
574
+ y_i_eps = asym_elip_eps_i
575
+ else:
576
+ y_i_sig = asym_elip_sig_ym_i * 2 ** (7 / 6)
577
+ y_i_eps = asym_elip_eps_i
578
+
579
+ if z_j > 0:
580
+ z_i_sig = asym_elip_sig_zp_i * 2 ** (7 / 6)
581
+ z_i_eps = asym_elip_eps_i
582
+ else:
583
+ z_i_sig = asym_elip_sig_zm_i * 2 ** (7 / 6)
584
+ z_i_eps = asym_elip_eps_i
585
+
586
+ r_ell_i = torch.sqrt((x_j / x_i_sig) ** 2 + (y_j / y_i_sig) ** 2 + (z_j / z_i_sig) ** 2)
587
+ r_ell_i_norm = torch.linalg.norm(r_ell_i)
588
+ lj_eps_i = 1 / torch.sqrt((x_j / r_ell_i_norm / x_i_eps) ** 2 + (y_j / r_ell_i_norm / y_i_eps) ** 2 + (z_j / r_ell_i_norm / z_i_eps) ** 2 )
589
+
590
+ pos_i = rotated_z_axis_adjusted_LJ_center_i_j[0] - z_axis_adjusted_LJ_center_j[0]
591
+
592
+ x_i = pos_i[0]
593
+ y_i = pos_i[1]
594
+ z_i = pos_i[2]
595
+
596
+ if x_i > 0:
597
+ x_j_sig = asym_elip_sig_xp_j * 2 ** (7 / 6)
598
+ x_j_eps = asym_elip_eps_j
599
+ else:
600
+ x_j_sig = asym_elip_sig_xm_j * 2 ** (7 / 6)
601
+ x_j_eps = asym_elip_eps_j
602
+
603
+ if y_i > 0:
604
+ y_j_sig = asym_elip_sig_yp_j * 2 ** (7 / 6)
605
+ y_j_eps = asym_elip_eps_j
606
+ else:
607
+ y_j_sig = asym_elip_sig_ym_j * 2 ** (7 / 6)
608
+ y_j_eps = asym_elip_eps_j
609
+
610
+ if z_i > 0:
611
+ z_j_sig = asym_elip_sig_zp_j * 2 ** (7 / 6)
612
+ z_j_eps = asym_elip_eps_j
613
+ else:
614
+ z_j_sig = asym_elip_sig_zm_j * 2 ** (7 / 6)
615
+ z_j_eps = asym_elip_eps_j
616
+
617
+ r_ell_j = torch.sqrt((x_i / x_j_sig) ** 2 + (y_i / y_j_sig) ** 2 + (z_i / z_j_sig) ** 2)
618
+ r_ell_j_norm = torch.linalg.norm(r_ell_j)
619
+ lj_eps_j = 1 / torch.sqrt((x_i / r_ell_j_norm / x_j_eps) ** 2 + (y_i / r_ell_j_norm / y_j_eps) ** 2 + (z_i / r_ell_j_norm / z_j_eps) ** 2 )
620
+
621
+ eps = torch.sqrt(lj_eps_i * lj_eps_j)
622
+ r_ell = torch.sqrt(r_ell_i * r_ell_j)
623
+
624
+ energy = energy + eps * (((1/r_ell) ** self.lj_repulsive_order) -2 * ((1/r_ell) ** self.lj_attractive_order))
625
+
626
+ self.tmp_geom_num_list_for_save = tmp_geom_num_list_for_save
627
+ self.tmp_element_list_for_save = tmp_element_list_for_save
628
+ return energy
629
+
630
+ def rand_search(self, geom_num_list, bias_pot_params):
631
+ max_energy = 1e+10
632
+ print("rand_search")
633
+ for i in range(self.rand_search_iteration):
634
+ tmp_rot_angle_list = [random.uniform(0, 2*math.pi) for j in range(len(self.config["asymmetric_ellipsoidal_repulsive_potential_v2_eps"]))]
635
+ tmp_rot_angle_list = torch.tensor([tmp_rot_angle_list], dtype=torch.float64, requires_grad=True)
636
+ energy = self.calc_potential(geom_num_list, tmp_rot_angle_list, bias_pot_params)
637
+ if energy < max_energy:
638
+ print("Energy: ", energy)
639
+ max_energy = energy
640
+ self.rot_angle_list = tmp_rot_angle_list
641
+ print("rand_search done")
642
+ print("max_energy: ", max_energy.item())
643
+ return
644
+
645
+
646
+ def microiteration(self, geom_num_list, bias_pot_params):
647
+ if self.init:
648
+ self.rand_search(geom_num_list, bias_pot_params)
649
+ self.init = False
650
+
651
+ prev_rot_grad = torch.zeros_like(self.rot_angle_list)
652
+ Opt = FIRE()
653
+ Opt.display_flag = False
654
+
655
+ for j in range(self.micro_iteration):
656
+ rot_grad = torch.func.jacrev(self.calc_potential, argnums=1)(geom_num_list, self.rot_angle_list, bias_pot_params)
657
+ if torch.linalg.norm(rot_grad) < self.threshold:
658
+ print("Converged!")
659
+ print("M. itr: ", j)
660
+ self.save_flag = True
661
+ energy = self.calc_potential(geom_num_list, self.rot_angle_list, bias_pot_params)
662
+ print("energy: ", energy.item())
663
+ break
664
+
665
+ tmp_rot_angle_list = copy.copy(self.rot_angle_list.clone().detach().numpy())
666
+ tmp_rot_grad = copy.copy(rot_grad.clone().detach().numpy())
667
+ tmp_prev_rot_grad = copy.copy(prev_rot_grad.clone().detach().numpy())
668
+ move_vector = Opt.run(tmp_rot_angle_list[0], tmp_rot_grad[0], tmp_prev_rot_grad[0])
669
+ move_vector = torch.tensor(move_vector, dtype=torch.float64)
670
+ self.rot_angle_list = self.rot_angle_list - 1.0 * move_vector
671
+ # update rot_angle_list
672
+ if j % 100 == 0:
673
+ print("M. itr: ", j)
674
+ print("energy: ", self.calc_potential(geom_num_list, self.rot_angle_list, bias_pot_params).item())
675
+ print("rot_angle_list: ", self.rot_angle_list.detach().numpy())
676
+ print("rot_grad: ", rot_grad.detach().numpy())
677
+
678
+ prev_rot_grad = rot_grad
679
+ else:
680
+ print("Not converged...")
681
+ energy = None
682
+ raise
683
+
684
+
685
+ return energy
686
+
687
+
688
+ def calc_energy(self, geom_num_list, bias_pot_params):
689
+ """
690
+ # required variables: self.config["asymmetric_ellipsoidal_repulsive_potential_v2_eps"],
691
+ self.config["asymmetric_ellipsoidal_repulsive_potential_v2_sig"],
692
+ self.config["asymmetric_ellipsoidal_repulsive_potential_v2_dist"],
693
+ self.config["asymmetric_ellipsoidal_repulsive_potential_v2_atoms"],
694
+ self.config["asymmetric_ellipsoidal_repulsive_potential_v2_offtgt"],
695
+ bias_pot_params[n][0] : asymmetric_ellipsoidal_repulsive_potential_v2_eps
696
+ bias_pot_params[n][1:7] : asymmetric_ellipsoidal_repulsive_potential_v2_sig
697
+ bias_pot_params[n][7] : asymmetric_ellipsoidal_repulsive_potential_v2_dist
698
+ """
699
+ energy = self.microiteration(geom_num_list, bias_pot_params)
700
+ return energy
701
+
702
+ def calc_pot_for_eff_hess(self, coord_and_ell_angle, bias_pot_params):
703
+ geom_num_list = coord_and_ell_angle[:len(self.element_list)*3].reshape(-1, 3)
704
+ rot_angle_list = coord_and_ell_angle[len(self.element_list)*3:].reshape(1, self.nangle)
705
+ energy = self.calc_potential(geom_num_list, rot_angle_list, bias_pot_params)
706
+ return energy
707
+
708
+
709
+ def calc_eff_hessian(self, geom_num_list, bias_pot_params):# effective hessian
710
+ transformed_geom_num_list = geom_num_list.reshape(-1, 1)
711
+ transformed_angle_list = self.rot_angle_list.reshape(-1, 1)
712
+ coord_and_ell_angle = torch.cat((transformed_geom_num_list, transformed_angle_list), dim=0)
713
+ combined_hess = torch.func.hessian(self.calc_pot_for_eff_hess, argnums=0)(coord_and_ell_angle, bias_pot_params).reshape(len(self.element_list)*3+self.nangle, len(self.element_list)*3+self.nangle)
714
+ coupling_hess_1 = combined_hess[:len(self.element_list)*3, len(self.element_list)*3:]
715
+ coupling_hess_2 = combined_hess[len(self.element_list)*3:, :len(self.element_list)*3]
716
+ angle_hess = combined_hess[len(self.element_list)*3:, len(self.element_list)*3:]
717
+ eff_hess = -1 * torch.matmul(torch.matmul(coupling_hess_1, torch.linalg.inv(angle_hess)), coupling_hess_2)
718
+ return eff_hess