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.
- multioptpy/Calculator/__init__.py +0 -0
- multioptpy/Calculator/ase_calculation_tools.py +424 -0
- multioptpy/Calculator/ase_tools/__init__.py +0 -0
- multioptpy/Calculator/ase_tools/fairchem.py +28 -0
- multioptpy/Calculator/ase_tools/gamess.py +19 -0
- multioptpy/Calculator/ase_tools/gaussian.py +165 -0
- multioptpy/Calculator/ase_tools/mace.py +28 -0
- multioptpy/Calculator/ase_tools/mopac.py +19 -0
- multioptpy/Calculator/ase_tools/nwchem.py +31 -0
- multioptpy/Calculator/ase_tools/orca.py +22 -0
- multioptpy/Calculator/ase_tools/pygfn0.py +37 -0
- multioptpy/Calculator/dxtb_calculation_tools.py +344 -0
- multioptpy/Calculator/emt_calculation_tools.py +458 -0
- multioptpy/Calculator/gpaw_calculation_tools.py +183 -0
- multioptpy/Calculator/lj_calculation_tools.py +314 -0
- multioptpy/Calculator/psi4_calculation_tools.py +334 -0
- multioptpy/Calculator/pwscf_calculation_tools.py +189 -0
- multioptpy/Calculator/pyscf_calculation_tools.py +327 -0
- multioptpy/Calculator/sqm1_calculation_tools.py +611 -0
- multioptpy/Calculator/sqm2_calculation_tools.py +376 -0
- multioptpy/Calculator/tblite_calculation_tools.py +352 -0
- multioptpy/Calculator/tersoff_calculation_tools.py +818 -0
- multioptpy/Constraint/__init__.py +0 -0
- multioptpy/Constraint/constraint_condition.py +834 -0
- multioptpy/Coordinate/__init__.py +0 -0
- multioptpy/Coordinate/polar_coordinate.py +199 -0
- multioptpy/Coordinate/redundant_coordinate.py +638 -0
- multioptpy/IRC/__init__.py +0 -0
- multioptpy/IRC/converge_criteria.py +28 -0
- multioptpy/IRC/dvv.py +544 -0
- multioptpy/IRC/euler.py +439 -0
- multioptpy/IRC/hpc.py +564 -0
- multioptpy/IRC/lqa.py +540 -0
- multioptpy/IRC/modekill.py +662 -0
- multioptpy/IRC/rk4.py +579 -0
- multioptpy/Interpolation/__init__.py +0 -0
- multioptpy/Interpolation/adaptive_interpolation.py +283 -0
- multioptpy/Interpolation/binomial_interpolation.py +179 -0
- multioptpy/Interpolation/geodesic_interpolation.py +785 -0
- multioptpy/Interpolation/interpolation.py +156 -0
- multioptpy/Interpolation/linear_interpolation.py +473 -0
- multioptpy/Interpolation/savitzky_golay_interpolation.py +252 -0
- multioptpy/Interpolation/spline_interpolation.py +353 -0
- multioptpy/MD/__init__.py +0 -0
- multioptpy/MD/thermostat.py +185 -0
- multioptpy/MEP/__init__.py +0 -0
- multioptpy/MEP/pathopt_bneb_force.py +443 -0
- multioptpy/MEP/pathopt_dmf_force.py +448 -0
- multioptpy/MEP/pathopt_dneb_force.py +130 -0
- multioptpy/MEP/pathopt_ewbneb_force.py +207 -0
- multioptpy/MEP/pathopt_gpneb_force.py +512 -0
- multioptpy/MEP/pathopt_lup_force.py +113 -0
- multioptpy/MEP/pathopt_neb_force.py +225 -0
- multioptpy/MEP/pathopt_nesb_force.py +205 -0
- multioptpy/MEP/pathopt_om_force.py +153 -0
- multioptpy/MEP/pathopt_qsm_force.py +174 -0
- multioptpy/MEP/pathopt_qsmv2_force.py +304 -0
- multioptpy/ModelFunction/__init__.py +7 -0
- multioptpy/ModelFunction/avoiding_model_function.py +29 -0
- multioptpy/ModelFunction/binary_image_ts_search_model_function.py +47 -0
- multioptpy/ModelFunction/conical_model_function.py +26 -0
- multioptpy/ModelFunction/opt_meci.py +50 -0
- multioptpy/ModelFunction/opt_mesx.py +47 -0
- multioptpy/ModelFunction/opt_mesx_2.py +49 -0
- multioptpy/ModelFunction/seam_model_function.py +27 -0
- multioptpy/ModelHessian/__init__.py +0 -0
- multioptpy/ModelHessian/approx_hessian.py +147 -0
- multioptpy/ModelHessian/calc_params.py +227 -0
- multioptpy/ModelHessian/fischer.py +236 -0
- multioptpy/ModelHessian/fischerd3.py +360 -0
- multioptpy/ModelHessian/fischerd4.py +398 -0
- multioptpy/ModelHessian/gfn0xtb.py +633 -0
- multioptpy/ModelHessian/gfnff.py +709 -0
- multioptpy/ModelHessian/lindh.py +165 -0
- multioptpy/ModelHessian/lindh2007d2.py +707 -0
- multioptpy/ModelHessian/lindh2007d3.py +822 -0
- multioptpy/ModelHessian/lindh2007d4.py +1030 -0
- multioptpy/ModelHessian/morse.py +106 -0
- multioptpy/ModelHessian/schlegel.py +144 -0
- multioptpy/ModelHessian/schlegeld3.py +322 -0
- multioptpy/ModelHessian/schlegeld4.py +559 -0
- multioptpy/ModelHessian/shortrange.py +346 -0
- multioptpy/ModelHessian/swartd2.py +496 -0
- multioptpy/ModelHessian/swartd3.py +706 -0
- multioptpy/ModelHessian/swartd4.py +918 -0
- multioptpy/ModelHessian/tshess.py +40 -0
- multioptpy/Optimizer/QHAdam.py +61 -0
- multioptpy/Optimizer/__init__.py +0 -0
- multioptpy/Optimizer/abc_fire.py +83 -0
- multioptpy/Optimizer/adabelief.py +58 -0
- multioptpy/Optimizer/adabound.py +68 -0
- multioptpy/Optimizer/adadelta.py +65 -0
- multioptpy/Optimizer/adaderivative.py +56 -0
- multioptpy/Optimizer/adadiff.py +68 -0
- multioptpy/Optimizer/adafactor.py +70 -0
- multioptpy/Optimizer/adam.py +65 -0
- multioptpy/Optimizer/adamax.py +62 -0
- multioptpy/Optimizer/adamod.py +83 -0
- multioptpy/Optimizer/adamw.py +65 -0
- multioptpy/Optimizer/adiis.py +523 -0
- multioptpy/Optimizer/afire_neb.py +282 -0
- multioptpy/Optimizer/block_hessian_update.py +709 -0
- multioptpy/Optimizer/c2diis.py +491 -0
- multioptpy/Optimizer/component_wise_scaling.py +405 -0
- multioptpy/Optimizer/conjugate_gradient.py +82 -0
- multioptpy/Optimizer/conjugate_gradient_neb.py +345 -0
- multioptpy/Optimizer/coordinate_locking.py +405 -0
- multioptpy/Optimizer/dic_rsirfo.py +1015 -0
- multioptpy/Optimizer/ediis.py +417 -0
- multioptpy/Optimizer/eve.py +76 -0
- multioptpy/Optimizer/fastadabelief.py +61 -0
- multioptpy/Optimizer/fire.py +77 -0
- multioptpy/Optimizer/fire2.py +249 -0
- multioptpy/Optimizer/fire_neb.py +92 -0
- multioptpy/Optimizer/gan_step.py +486 -0
- multioptpy/Optimizer/gdiis.py +609 -0
- multioptpy/Optimizer/gediis.py +203 -0
- multioptpy/Optimizer/geodesic_step.py +433 -0
- multioptpy/Optimizer/gpmin.py +633 -0
- multioptpy/Optimizer/gpr_step.py +364 -0
- multioptpy/Optimizer/gradientdescent.py +78 -0
- multioptpy/Optimizer/gradientdescent_neb.py +52 -0
- multioptpy/Optimizer/hessian_update.py +433 -0
- multioptpy/Optimizer/hybrid_rfo.py +998 -0
- multioptpy/Optimizer/kdiis.py +625 -0
- multioptpy/Optimizer/lars.py +21 -0
- multioptpy/Optimizer/lbfgs.py +253 -0
- multioptpy/Optimizer/lbfgs_neb.py +355 -0
- multioptpy/Optimizer/linesearch.py +236 -0
- multioptpy/Optimizer/lookahead.py +40 -0
- multioptpy/Optimizer/nadam.py +64 -0
- multioptpy/Optimizer/newton.py +200 -0
- multioptpy/Optimizer/prodigy.py +70 -0
- multioptpy/Optimizer/purtubation.py +16 -0
- multioptpy/Optimizer/quickmin_neb.py +245 -0
- multioptpy/Optimizer/radam.py +75 -0
- multioptpy/Optimizer/rfo_neb.py +302 -0
- multioptpy/Optimizer/ric_rfo.py +842 -0
- multioptpy/Optimizer/rl_step.py +627 -0
- multioptpy/Optimizer/rmspropgrave.py +65 -0
- multioptpy/Optimizer/rsirfo.py +1647 -0
- multioptpy/Optimizer/rsprfo.py +1056 -0
- multioptpy/Optimizer/sadam.py +60 -0
- multioptpy/Optimizer/samsgrad.py +63 -0
- multioptpy/Optimizer/tr_lbfgs.py +678 -0
- multioptpy/Optimizer/trim.py +273 -0
- multioptpy/Optimizer/trust_radius.py +207 -0
- multioptpy/Optimizer/trust_radius_neb.py +121 -0
- multioptpy/Optimizer/yogi.py +60 -0
- multioptpy/OtherMethod/__init__.py +0 -0
- multioptpy/OtherMethod/addf.py +1150 -0
- multioptpy/OtherMethod/dimer.py +895 -0
- multioptpy/OtherMethod/elastic_image_pair.py +629 -0
- multioptpy/OtherMethod/modelfunction.py +456 -0
- multioptpy/OtherMethod/newton_traj.py +454 -0
- multioptpy/OtherMethod/twopshs.py +1095 -0
- multioptpy/PESAnalyzer/__init__.py +0 -0
- multioptpy/PESAnalyzer/calc_irc_curvature.py +125 -0
- multioptpy/PESAnalyzer/cmds_analysis.py +152 -0
- multioptpy/PESAnalyzer/koopman_analysis.py +268 -0
- multioptpy/PESAnalyzer/pca_analysis.py +314 -0
- multioptpy/Parameters/__init__.py +0 -0
- multioptpy/Parameters/atomic_mass.py +20 -0
- multioptpy/Parameters/atomic_number.py +22 -0
- multioptpy/Parameters/covalent_radii.py +44 -0
- multioptpy/Parameters/d2.py +61 -0
- multioptpy/Parameters/d3.py +63 -0
- multioptpy/Parameters/d4.py +103 -0
- multioptpy/Parameters/dreiding.py +34 -0
- multioptpy/Parameters/gfn0xtb_param.py +137 -0
- multioptpy/Parameters/gfnff_param.py +315 -0
- multioptpy/Parameters/gnb.py +104 -0
- multioptpy/Parameters/parameter.py +22 -0
- multioptpy/Parameters/uff.py +72 -0
- multioptpy/Parameters/unit_values.py +20 -0
- multioptpy/Potential/AFIR_potential.py +55 -0
- multioptpy/Potential/LJ_repulsive_potential.py +345 -0
- multioptpy/Potential/__init__.py +0 -0
- multioptpy/Potential/anharmonic_keep_potential.py +28 -0
- multioptpy/Potential/asym_elllipsoidal_potential.py +718 -0
- multioptpy/Potential/electrostatic_potential.py +69 -0
- multioptpy/Potential/flux_potential.py +30 -0
- multioptpy/Potential/gaussian_potential.py +101 -0
- multioptpy/Potential/idpp.py +516 -0
- multioptpy/Potential/keep_angle_potential.py +146 -0
- multioptpy/Potential/keep_dihedral_angle_potential.py +105 -0
- multioptpy/Potential/keep_outofplain_angle_potential.py +70 -0
- multioptpy/Potential/keep_potential.py +99 -0
- multioptpy/Potential/mechano_force_potential.py +74 -0
- multioptpy/Potential/nanoreactor_potential.py +52 -0
- multioptpy/Potential/potential.py +896 -0
- multioptpy/Potential/spacer_model_potential.py +221 -0
- multioptpy/Potential/switching_potential.py +258 -0
- multioptpy/Potential/universal_potential.py +34 -0
- multioptpy/Potential/value_range_potential.py +36 -0
- multioptpy/Potential/void_point_potential.py +25 -0
- multioptpy/SQM/__init__.py +0 -0
- multioptpy/SQM/sqm1/__init__.py +0 -0
- multioptpy/SQM/sqm1/sqm1_core.py +1792 -0
- multioptpy/SQM/sqm2/__init__.py +0 -0
- multioptpy/SQM/sqm2/calc_tools.py +95 -0
- multioptpy/SQM/sqm2/sqm2_basis.py +850 -0
- multioptpy/SQM/sqm2/sqm2_bond.py +119 -0
- multioptpy/SQM/sqm2/sqm2_core.py +303 -0
- multioptpy/SQM/sqm2/sqm2_data.py +1229 -0
- multioptpy/SQM/sqm2/sqm2_disp.py +65 -0
- multioptpy/SQM/sqm2/sqm2_eeq.py +243 -0
- multioptpy/SQM/sqm2/sqm2_overlapint.py +704 -0
- multioptpy/SQM/sqm2/sqm2_qm.py +578 -0
- multioptpy/SQM/sqm2/sqm2_rep.py +66 -0
- multioptpy/SQM/sqm2/sqm2_srb.py +70 -0
- multioptpy/Thermo/__init__.py +0 -0
- multioptpy/Thermo/normal_mode_analyzer.py +865 -0
- multioptpy/Utils/__init__.py +0 -0
- multioptpy/Utils/bond_connectivity.py +264 -0
- multioptpy/Utils/calc_tools.py +884 -0
- multioptpy/Utils/oniom.py +96 -0
- multioptpy/Utils/pbc.py +48 -0
- multioptpy/Utils/riemann_curvature.py +208 -0
- multioptpy/Utils/symmetry_analyzer.py +482 -0
- multioptpy/Visualization/__init__.py +0 -0
- multioptpy/Visualization/visualization.py +156 -0
- multioptpy/WFAnalyzer/MO_analysis.py +104 -0
- multioptpy/WFAnalyzer/__init__.py +0 -0
- multioptpy/Wrapper/__init__.py +0 -0
- multioptpy/Wrapper/autots.py +1239 -0
- multioptpy/Wrapper/ieip_wrapper.py +93 -0
- multioptpy/Wrapper/md_wrapper.py +92 -0
- multioptpy/Wrapper/neb_wrapper.py +94 -0
- multioptpy/Wrapper/optimize_wrapper.py +76 -0
- multioptpy/__init__.py +5 -0
- multioptpy/entrypoints.py +916 -0
- multioptpy/fileio.py +660 -0
- multioptpy/ieip.py +340 -0
- multioptpy/interface.py +1086 -0
- multioptpy/irc.py +529 -0
- multioptpy/moleculardynamics.py +432 -0
- multioptpy/neb.py +1267 -0
- multioptpy/optimization.py +1553 -0
- multioptpy/optimizer.py +709 -0
- multioptpy-1.20.2.dist-info/METADATA +438 -0
- multioptpy-1.20.2.dist-info/RECORD +246 -0
- multioptpy-1.20.2.dist-info/WHEEL +5 -0
- multioptpy-1.20.2.dist-info/entry_points.txt +9 -0
- multioptpy-1.20.2.dist-info/licenses/LICENSE +674 -0
- multioptpy-1.20.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BondCalculator:
|
|
5
|
+
def __init__(self, element_list, params):
|
|
6
|
+
self.element_list = element_list
|
|
7
|
+
|
|
8
|
+
#self.k_bond_list = []
|
|
9
|
+
self.r0_bond_list = []
|
|
10
|
+
self.paulingEN_list = []
|
|
11
|
+
|
|
12
|
+
for element in element_list:
|
|
13
|
+
#self.k_bond_list.append(params.k_bond[element])
|
|
14
|
+
self.r0_bond_list.append(params.eeq_covalent_radii[element])
|
|
15
|
+
self.paulingEN_list.append(params.paulingEN[element])
|
|
16
|
+
|
|
17
|
+
#self.k_bond_list = torch.tensor(self.k_bond_list, dtype=torch.float64)
|
|
18
|
+
self.r0_bond_list = torch.tensor(self.r0_bond_list, dtype=torch.float64)
|
|
19
|
+
self.paulingEN_list = torch.tensor(self.paulingEN_list, dtype=torch.float64)
|
|
20
|
+
|
|
21
|
+
self.en_polynominal_param = params.en_polynominal_param
|
|
22
|
+
self._calc_corrected_r0_and_en_diff2_matrix()
|
|
23
|
+
self.eta = params.eta_bond
|
|
24
|
+
self.k_en = params.k_en_bond
|
|
25
|
+
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
def get_en_poly_index(self, atomic_number):
|
|
29
|
+
if not isinstance(atomic_number, int) or atomic_number <= 0:
|
|
30
|
+
raise ValueError("Atomic number must be a positive integer.")
|
|
31
|
+
if atomic_number <= 2: # Z = 1-2 (H, He)
|
|
32
|
+
return 0
|
|
33
|
+
elif atomic_number <= 10: # Z = 3-10 (Li-Ne)
|
|
34
|
+
return 1
|
|
35
|
+
elif atomic_number <= 18: # Z = 11-18 (Na-Ar)
|
|
36
|
+
return 2
|
|
37
|
+
elif atomic_number <= 36: # Z = 19-36 (K-Kr)
|
|
38
|
+
return 3
|
|
39
|
+
elif atomic_number <= 54: # Z = 37-54 (Rb-Xe)
|
|
40
|
+
return 4
|
|
41
|
+
else: # Z = 55- (Cs-)
|
|
42
|
+
return 5
|
|
43
|
+
|
|
44
|
+
def _calc_corrected_r0_and_en_diff2_matrix(self):
|
|
45
|
+
en_diff2_matrix = torch.zeros((len(self.element_list), len(self.element_list)), dtype=torch.float64)
|
|
46
|
+
corrected_r0_matrix = torch.zeros((len(self.element_list), len(self.element_list)), dtype=torch.float64)
|
|
47
|
+
for i in range(len(self.element_list)):
|
|
48
|
+
for j in range(len(self.element_list)):
|
|
49
|
+
r0_ij = self.r0_bond_list[i] + self.r0_bond_list[j]
|
|
50
|
+
|
|
51
|
+
c_i = self.en_polynominal_param[self.get_en_poly_index(int(self.element_list[i])+1)]
|
|
52
|
+
c_j = self.en_polynominal_param[self.get_en_poly_index(int(self.element_list[j])+1)]
|
|
53
|
+
c = 0.5 * (c_i + c_j)
|
|
54
|
+
c_1 = c[0]
|
|
55
|
+
c_2 = c[1]
|
|
56
|
+
|
|
57
|
+
en_diff = torch.abs(self.paulingEN_list[i] - self.paulingEN_list[j])
|
|
58
|
+
corrected_r0_matrix[i, j] = r0_ij * (1.0 - c_1 * en_diff + c_2 * (en_diff ** 2))
|
|
59
|
+
en_diff2_matrix[i, j] = en_diff ** 2
|
|
60
|
+
|
|
61
|
+
self.corrected_r0_matrix = corrected_r0_matrix
|
|
62
|
+
self.en_diff2_matrix = en_diff2_matrix
|
|
63
|
+
return corrected_r0_matrix, en_diff2_matrix
|
|
64
|
+
|
|
65
|
+
def calculation(self, xyz): # xyz: (N, 3) torch tensor
|
|
66
|
+
N = xyz.shape[0]
|
|
67
|
+
diff = xyz.unsqueeze(1) - xyz.unsqueeze(0)
|
|
68
|
+
# r is the (N, N) matrix of pairwise distances. Diagonal is 0.0
|
|
69
|
+
r = torch.linalg.norm(diff, dim=-1)
|
|
70
|
+
|
|
71
|
+
k_bond_ij = 1.0 #torch.sqrt(self.k_bond_list.unsqueeze(1) * self.k_bond_list.unsqueeze(0))
|
|
72
|
+
r0_ij = self.corrected_r0_matrix
|
|
73
|
+
en_diff2_ij = self.en_diff2_matrix
|
|
74
|
+
|
|
75
|
+
# --- Modifications ---
|
|
76
|
+
|
|
77
|
+
# 1. Calculate the cutoff matrix for bond determination
|
|
78
|
+
cutoff_matrix = 1.25 * r0_ij
|
|
79
|
+
|
|
80
|
+
# 2. Create a mask for pairs where the current distance r is <= the cutoff
|
|
81
|
+
mask = (r <= cutoff_matrix)
|
|
82
|
+
|
|
83
|
+
# 3. Always set the diagonal (i=i) to False to exclude self-interaction
|
|
84
|
+
mask.fill_diagonal_(False)
|
|
85
|
+
|
|
86
|
+
# 4. Calculate the energy term for all pairs
|
|
87
|
+
energy_term = -1.0 * k_bond_ij * torch.exp(self.eta * (1.0 * self.k_en * en_diff2_ij) * (r - r0_ij) ** 2.0)
|
|
88
|
+
|
|
89
|
+
# 5. Use torch.where to select the energy term only for masked pairs.
|
|
90
|
+
# Set 0.0 for False pairs (non-bonded pairs and the diagonal).
|
|
91
|
+
bond_energy_matrix = torch.where(mask, energy_term, 0.0)
|
|
92
|
+
|
|
93
|
+
# The previous .fill_diagonal_(0.0) is no longer needed.
|
|
94
|
+
# --- End of modifications ---
|
|
95
|
+
|
|
96
|
+
energy = torch.sum(bond_energy_matrix) / 2.0
|
|
97
|
+
return energy # shape: scalar
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def energy(self, xyz):
|
|
101
|
+
xyz = torch.tensor(xyz, dtype=torch.float64)
|
|
102
|
+
energy = self.calculation(xyz)
|
|
103
|
+
return energy
|
|
104
|
+
|
|
105
|
+
def gradient(self, xyz):
|
|
106
|
+
xyz = torch.tensor(xyz, dtype=torch.float64)
|
|
107
|
+
energy = self.calculation(xyz)
|
|
108
|
+
gradient = torch.func.jacrev(self.calculation)(xyz)
|
|
109
|
+
return energy, gradient
|
|
110
|
+
|
|
111
|
+
def hessian(self, xyz):
|
|
112
|
+
xyz = torch.tensor(xyz, dtype=torch.float64)
|
|
113
|
+
energy = self.calculation(xyz)
|
|
114
|
+
hessian = torch.func.hessian(self.calculation)(xyz)
|
|
115
|
+
return energy, hessian
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
from multioptpy.SQM.sqm2.sqm2_data import SQM2Parameters
|
|
4
|
+
from multioptpy.SQM.sqm2.sqm2_rep import RepulsionCalculator
|
|
5
|
+
from multioptpy.SQM.sqm2.sqm2_srb import SRBCalculator
|
|
6
|
+
from multioptpy.SQM.sqm2.sqm2_disp import DispersionCalculator
|
|
7
|
+
from multioptpy.SQM.sqm2.sqm2_eeq import IESEnergyCalculator
|
|
8
|
+
from multioptpy.SQM.sqm2.sqm2_qm import EHTCalculator
|
|
9
|
+
from multioptpy.SQM.sqm2.sqm2_basis import BasisSet
|
|
10
|
+
from multioptpy.SQM.sqm2.sqm2_bond import BondCalculator
|
|
11
|
+
|
|
12
|
+
ANG2BOHR = 1.8897261246257704
|
|
13
|
+
|
|
14
|
+
class SQM2Calculator:
|
|
15
|
+
def __init__(self, xyz, element_list, charge, spin):# xyz: (N,3) in Angstrom, element_list: atomic numbers (1-indexed)
|
|
16
|
+
# ref.: https://doi.org/10.26434/chemrxiv.8326202.v1
|
|
17
|
+
sqm_params = SQM2Parameters()
|
|
18
|
+
self.element_list = np.array(element_list, dtype=np.int64) - 1 # 0-indexed
|
|
19
|
+
self.xyz = np.array(xyz, dtype=np.float64)
|
|
20
|
+
self.xyz = self.xyz * ANG2BOHR # Angstrom -> Bohr
|
|
21
|
+
self.charge = charge
|
|
22
|
+
self.spin = spin
|
|
23
|
+
|
|
24
|
+
self.repulsion_calculator = RepulsionCalculator(self.element_list, sqm_params)
|
|
25
|
+
self.srb_calculator = SRBCalculator(self.element_list, sqm_params)
|
|
26
|
+
self.dispersion_calculator = DispersionCalculator(self.element_list, sqm_params)
|
|
27
|
+
self.ies_calculator = IESEnergyCalculator(self.element_list, charge, sqm_params)
|
|
28
|
+
self.basis_set = BasisSet(self.element_list, sqm_params)
|
|
29
|
+
#print(self.basis_set.basis)
|
|
30
|
+
self.eht_calculator = EHTCalculator(self.element_list, charge, spin, sqm_params, self.basis_set)
|
|
31
|
+
self.bond_calculator = BondCalculator(self.element_list, sqm_params)
|
|
32
|
+
self.sqm_params = sqm_params
|
|
33
|
+
|
|
34
|
+
def get_overlap_matrix(self):
|
|
35
|
+
if not self.eht_calculator:
|
|
36
|
+
raise ValueError("EHT calculator is not initialized.")
|
|
37
|
+
return self.eht_calculator.get_overlap_integral_matrix()
|
|
38
|
+
|
|
39
|
+
def get_eht_mo_energy(self):
|
|
40
|
+
if not self.eht_calculator:
|
|
41
|
+
raise ValueError("EHT calculator is not initialized.")
|
|
42
|
+
return self.eht_calculator.get_mo_energy()
|
|
43
|
+
|
|
44
|
+
def get_eht_mo_coeff(self):
|
|
45
|
+
if not self.eht_calculator:
|
|
46
|
+
raise ValueError("EHT calculator is not initialized.")
|
|
47
|
+
return self.eht_calculator.get_mo_coeff()
|
|
48
|
+
|
|
49
|
+
def total_energy(self, xyz): # xyz: ndarray (N,3) in Angstrom
|
|
50
|
+
xyz = xyz * ANG2BOHR # Angstrom -> Bohr
|
|
51
|
+
|
|
52
|
+
repulsion_energy = self.repulsion_calculator.energy(xyz)
|
|
53
|
+
srb_energy = self.srb_calculator.energy(xyz)
|
|
54
|
+
ies_energy = self.ies_calculator.energy(xyz)
|
|
55
|
+
|
|
56
|
+
eeq_charge = self.ies_calculator.eeq_charge(xyz)
|
|
57
|
+
eeq_charge = eeq_charge.detach().numpy()
|
|
58
|
+
|
|
59
|
+
cn = self.ies_calculator.cn(xyz)
|
|
60
|
+
cn = cn.detach().numpy()
|
|
61
|
+
dispersion_energy = self.dispersion_calculator.energy(xyz)
|
|
62
|
+
eht_energy = self.eht_calculator.energy(xyz, eeq_charge, cn)
|
|
63
|
+
#bond_energy = self.bond_calculator.energy(xyz)
|
|
64
|
+
total_energy = repulsion_energy + srb_energy + ies_energy + dispersion_energy + eht_energy
|
|
65
|
+
total_energy = float(total_energy.item())
|
|
66
|
+
print("Total Energy:", total_energy)
|
|
67
|
+
|
|
68
|
+
return total_energy # in Hartree: float
|
|
69
|
+
|
|
70
|
+
def total_gradient(self, xyz): # xyz: ndarray (N,3) in Angstrom
|
|
71
|
+
xyz = xyz * ANG2BOHR # Angstrom -> Bohr
|
|
72
|
+
eeq_charge = self.ies_calculator.eeq_charge(xyz)
|
|
73
|
+
eeq_charge = eeq_charge.detach().numpy()
|
|
74
|
+
_, d_eeq_charge = self.ies_calculator.d_eeq_charge_d_xyz(xyz)
|
|
75
|
+
#print("d_eeq_charge:", d_eeq_charge)
|
|
76
|
+
d_eeq_charge = d_eeq_charge.detach().numpy()
|
|
77
|
+
cn = self.ies_calculator.cn(xyz)
|
|
78
|
+
cn = cn.detach().numpy()
|
|
79
|
+
_, d_cn = self.ies_calculator.d_cn_d_xyz(xyz)
|
|
80
|
+
#print("d_cn:", d_cn)
|
|
81
|
+
d_cn = d_cn.detach().numpy()
|
|
82
|
+
#eht_energy = self.eht_calculator.energy(xyz, eeq_charge, cn)#, eeq_charge, cn, d_eeq_charge, d_cn)
|
|
83
|
+
eht_energy, eht_gradient = self.eht_calculator.gradient(xyz, eeq_charge, cn, d_eeq_charge, d_cn)
|
|
84
|
+
eht_gradient = torch.nan_to_num(eht_gradient, nan=0.0, posinf=0.0, neginf=0.0)
|
|
85
|
+
repulsion_energy, repulsion_gradient = self.repulsion_calculator.gradient(xyz)
|
|
86
|
+
repulsion_gradient = torch.nan_to_num(repulsion_gradient, nan=0.0, posinf=0.0, neginf=0.0)
|
|
87
|
+
|
|
88
|
+
srb_energy, srb_gradient = self.srb_calculator.gradient(xyz)
|
|
89
|
+
srb_gradient = torch.nan_to_num(srb_gradient, nan=0.0, posinf=0.0, neginf=0.0)
|
|
90
|
+
ies_energy, ies_gradient = self.ies_calculator.gradient(xyz)
|
|
91
|
+
ies_gradient = torch.nan_to_num(ies_gradient, nan=0.0, posinf=0.0, neginf=0.0)
|
|
92
|
+
dispersion_energy, dispersion_gradient = self.dispersion_calculator.gradient(xyz)
|
|
93
|
+
dispersion_gradient = torch.nan_to_num(dispersion_gradient, nan=0.0, posinf=0.0, neginf=0.0)
|
|
94
|
+
|
|
95
|
+
total_energy = repulsion_energy + srb_energy + ies_energy + dispersion_energy + eht_energy
|
|
96
|
+
total_gradient = repulsion_gradient + srb_gradient + ies_gradient + dispersion_gradient + eht_gradient
|
|
97
|
+
print("Total gradient norm:", torch.norm(total_gradient).item())
|
|
98
|
+
total_energy = float(total_energy.item())
|
|
99
|
+
total_gradient = total_gradient.detach().numpy()
|
|
100
|
+
return total_energy, total_gradient # gradient: ndarray (N,3) in Bohr
|
|
101
|
+
|
|
102
|
+
def total_hessian(self, xyz): # xyz: ndarray (N,3) in Angstrom
|
|
103
|
+
xyz = xyz * ANG2BOHR # Angstrom -> Bohr
|
|
104
|
+
eeq_charge = self.ies_calculator.eeq_charge(xyz)
|
|
105
|
+
eeq_charge = eeq_charge.detach().numpy()
|
|
106
|
+
|
|
107
|
+
_, d_eeq_charge = self.ies_calculator.d_eeq_charge_d_xyz(xyz)
|
|
108
|
+
_, dd_eeq_charge = self.ies_calculator.d2_eeq_charge_d_xyz2(xyz)
|
|
109
|
+
d_eeq_charge = d_eeq_charge.detach().numpy()
|
|
110
|
+
dd_eeq_charge = dd_eeq_charge.detach().numpy()
|
|
111
|
+
#print("dd_eeq_charge:", dd_eeq_charge)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
cn = self.ies_calculator.cn(xyz)
|
|
115
|
+
cn = cn.detach().numpy()
|
|
116
|
+
_, d_cn = self.ies_calculator.d_cn_d_xyz(xyz)
|
|
117
|
+
d_cn = d_cn.detach().numpy()
|
|
118
|
+
_, dd_cn = self.ies_calculator.d2_cn_d_xyz2(xyz)
|
|
119
|
+
dd_cn = dd_cn.detach().numpy()
|
|
120
|
+
#print("dd_cn:", dd_cn)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
eht_hessian = self.eht_calculator.hessian(xyz, eeq_charge, cn, d_eeq_charge, dd_eeq_charge, d_cn, dd_cn)
|
|
124
|
+
eht_hessian = torch.nan_to_num(eht_hessian, nan=0.0, posinf=0.0, neginf=0.0)
|
|
125
|
+
|
|
126
|
+
repulsion_energy, repulsion_hessian = self.repulsion_calculator.hessian(xyz)
|
|
127
|
+
repulsion_hessian = torch.nan_to_num(repulsion_hessian, nan=0.0, posinf=0.0, neginf=0.0)
|
|
128
|
+
srb_energy, srb_hessian = self.srb_calculator.hessian(xyz)
|
|
129
|
+
srb_hessian = torch.nan_to_num(srb_hessian, nan=0.0, posinf=0.0, neginf=0.0)
|
|
130
|
+
ies_energy, ies_hessian = self.ies_calculator.hessian(xyz)
|
|
131
|
+
ies_hessian = torch.nan_to_num(ies_hessian, nan=0.0, posinf=0.0, neginf=0.0)
|
|
132
|
+
dispersion_energy, dispersion_hessian = self.dispersion_calculator.hessian(xyz)
|
|
133
|
+
dispersion_hessian = torch.nan_to_num(dispersion_hessian, nan=0.0, posinf=0.0, neginf=0.0)
|
|
134
|
+
#bond_energy, bond_hessian = self.bond_calculator.hessian(xyz)
|
|
135
|
+
#bond_hessian = torch.nan_to_num(bond_hessian, nan=0.0, posinf=0.0, neginf=0.0)
|
|
136
|
+
|
|
137
|
+
total_energy = repulsion_energy + srb_energy + ies_energy + dispersion_energy #+ bond_energy
|
|
138
|
+
total_hessian = eht_hessian + repulsion_hessian + srb_hessian + ies_hessian + dispersion_hessian #+ bond_hessian
|
|
139
|
+
|
|
140
|
+
total_energy = float(total_energy.item())
|
|
141
|
+
total_hessian = total_hessian.detach().numpy()
|
|
142
|
+
|
|
143
|
+
return total_hessian # hessian: ndarray (3N,3N) in Bohr
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if __name__ == "__main__":
|
|
147
|
+
|
|
148
|
+
print("\nStarting structural optimization for H2O using steepest descent...\n")
|
|
149
|
+
element_list = np.array([8, 1, 1])# O, H, H
|
|
150
|
+
xyz = np.array([[0.0000, 0.0000, 0.0173],
|
|
151
|
+
[0.0000, 0.7572, -0.4692],
|
|
152
|
+
[0.0000, -0.7572, -0.4692]])#(Angstrom)
|
|
153
|
+
xyz = np.array(xyz)
|
|
154
|
+
charge = 0
|
|
155
|
+
spin = 0
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
calculator = SQM2Calculator(xyz, element_list, charge, spin)
|
|
159
|
+
|
|
160
|
+
E_total = calculator.total_energy(xyz)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# Parameters for optimization
|
|
165
|
+
max_iter = 40
|
|
166
|
+
lr = 0.1 # Learning rate (adjusted for Angstrom units; may need tuning)
|
|
167
|
+
threshold = 1e-3 # Convergence threshold for gradient norm
|
|
168
|
+
xyz_ang = xyz
|
|
169
|
+
for iter in range(max_iter):
|
|
170
|
+
|
|
171
|
+
# Get total energy and gradient (gradient is dE/dx where x internal is Bohr)
|
|
172
|
+
total_energy, total_gradient_bohr = calculator.total_gradient(xyz_ang)
|
|
173
|
+
|
|
174
|
+
total_gradient_ang = total_gradient_bohr * ANG2BOHR
|
|
175
|
+
|
|
176
|
+
# Update xyz in Angstrom
|
|
177
|
+
xyz_ang = xyz_ang - lr * total_gradient_ang
|
|
178
|
+
|
|
179
|
+
# Check convergence
|
|
180
|
+
grad_norm = np.linalg.norm(total_gradient_ang)
|
|
181
|
+
print(f"Iteration {iter + 1}: Energy = {total_energy:.6f}, Gradient Norm = {grad_norm:.6f}")
|
|
182
|
+
xyz_ang = xyz_ang
|
|
183
|
+
if grad_norm < threshold:
|
|
184
|
+
print("Optimization converged.")
|
|
185
|
+
break
|
|
186
|
+
|
|
187
|
+
# Display optimized structure
|
|
188
|
+
optimized_xyz = xyz_ang
|
|
189
|
+
elements = ['O', 'H', 'H'] # Corresponding to atomic numbers [8,1,1]
|
|
190
|
+
|
|
191
|
+
print("\nOptimized Structure:")
|
|
192
|
+
for i in range(len(elements)):
|
|
193
|
+
print(f"{elements[i]} {optimized_xyz[i, 0]:.6f} {optimized_xyz[i, 1]:.6f} {optimized_xyz[i, 2]:.6f}")
|
|
194
|
+
|
|
195
|
+
print("\nStarting structural optimization for H3N using steepest descent...\n")
|
|
196
|
+
element_list = np.array([5, 1, 1, 1])# B, H, H, H
|
|
197
|
+
xyz = np.array([[ -3.51351354, 0.43156059, 0.00000000],
|
|
198
|
+
[ -3.18019165, -0.51125250, 0.00000000],
|
|
199
|
+
[ -3.18017444, 0.90296076, 0.81649673],
|
|
200
|
+
[ -3.18017444, 0.90296076, -0.81649673]])#(Angstrom)
|
|
201
|
+
xyz = np.array(xyz)
|
|
202
|
+
charge = 0
|
|
203
|
+
spin = 0
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
calculator = SQM2Calculator(xyz, element_list, charge, spin)
|
|
207
|
+
|
|
208
|
+
E_total = calculator.total_energy(xyz)
|
|
209
|
+
|
|
210
|
+
#=============================================================================================
|
|
211
|
+
|
|
212
|
+
# Parameters for optimization
|
|
213
|
+
max_iter = 50
|
|
214
|
+
lr = 0.1 # Learning rate (adjusted for Angstrom units; may need tuning)
|
|
215
|
+
threshold = 5e-3 # Convergence threshold for gradient norm
|
|
216
|
+
xyz_ang = xyz
|
|
217
|
+
for iter in range(max_iter):
|
|
218
|
+
|
|
219
|
+
# Get total energy and gradient (gradient is dE/dx where x internal is Bohr)
|
|
220
|
+
total_energy, total_gradient_bohr = calculator.total_gradient(xyz_ang)
|
|
221
|
+
|
|
222
|
+
total_gradient_ang = total_gradient_bohr * ANG2BOHR
|
|
223
|
+
|
|
224
|
+
# Update xyz in Angstrom
|
|
225
|
+
xyz_ang = xyz_ang - lr * total_gradient_ang
|
|
226
|
+
|
|
227
|
+
# Check convergence
|
|
228
|
+
grad_norm = np.linalg.norm(total_gradient_ang)
|
|
229
|
+
print(f"Iteration {iter + 1}: Energy = {total_energy:.6f}, Gradient Norm = {grad_norm:.6f}")
|
|
230
|
+
xyz_ang = xyz_ang
|
|
231
|
+
if grad_norm < threshold:
|
|
232
|
+
print("Optimization converged.")
|
|
233
|
+
break
|
|
234
|
+
|
|
235
|
+
# Display optimized structure
|
|
236
|
+
optimized_xyz = xyz_ang
|
|
237
|
+
elements = ['B', 'H', 'H', 'H'] # Corresponding to atomic numbers [5,1,1,1]
|
|
238
|
+
|
|
239
|
+
print("\nOptimized Structure:")
|
|
240
|
+
for i in range(len(elements)):
|
|
241
|
+
print(f"{elements[i]} {optimized_xyz[i, 0]:.6f} {optimized_xyz[i, 1]:.6f} {optimized_xyz[i, 2]:.6f}")
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
print("\nStarting structural optimization for Pd(PH3) using steepest descent...\n")
|
|
247
|
+
|
|
248
|
+
element_list = np.array([28, 15, 1, 1, 1])
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
xyz = np.array([[0.0000, 0.0000, 2.3000], # Pd
|
|
252
|
+
[0.0000, 0.0000, 0.0000], # P
|
|
253
|
+
[1.3900, 0.0000, -0.3300], # H1 (P-H 1.42 A, Pd-P-H 100 deg)
|
|
254
|
+
[-0.6950, 1.2038, -0.3300], # H2
|
|
255
|
+
[-0.6950, -1.2038, -0.3300]]) # H3 (Angstrom)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
xyz = np.array(xyz)
|
|
259
|
+
charge = 0
|
|
260
|
+
spin = 0
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
calculator = SQM2Calculator(xyz, element_list, charge, spin)
|
|
264
|
+
|
|
265
|
+
E_total = calculator.total_energy(xyz)
|
|
266
|
+
|
|
267
|
+
# Parameters for optimization
|
|
268
|
+
max_iter = 40
|
|
269
|
+
lr = 0.1 # Learning rate (adjusted for Angstrom units; may need tuning)
|
|
270
|
+
threshold = 1e-2 # Convergence threshold for gradient norm
|
|
271
|
+
xyz_ang = xyz
|
|
272
|
+
for iter in range(max_iter):
|
|
273
|
+
|
|
274
|
+
# Get total energy and gradient (gradient is dE/dx where x internal is Bohr)
|
|
275
|
+
total_energy, total_gradient_bohr = calculator.total_gradient(xyz_ang)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
total_gradient_ang = total_gradient_bohr * ANG2BOHR
|
|
279
|
+
|
|
280
|
+
# Update xyz in Angstrom
|
|
281
|
+
xyz_ang = xyz_ang - lr * total_gradient_ang
|
|
282
|
+
|
|
283
|
+
# Check convergence
|
|
284
|
+
grad_norm = np.linalg.norm(total_gradient_ang)
|
|
285
|
+
print(f"Iteration {iter + 1}: Energy = {total_energy:.6f}, Gradient Norm = {grad_norm:.6f}")
|
|
286
|
+
xyz_ang = xyz_ang
|
|
287
|
+
if grad_norm < threshold:
|
|
288
|
+
print("Optimization converged.")
|
|
289
|
+
break
|
|
290
|
+
|
|
291
|
+
# Display optimized structure
|
|
292
|
+
optimized_xyz = xyz_ang
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
elements = ['Pd', 'P', 'H', 'H', 'H'] # Corresponding to atomic numbers [46,15,1,1,1]
|
|
296
|
+
|
|
297
|
+
print("\nOptimized Structure:")
|
|
298
|
+
for i in range(len(elements)):
|
|
299
|
+
print(f"{elements[i]} {optimized_xyz[i, 0]:.6f} {optimized_xyz[i, 1]:.6f} {optimized_xyz[i, 2]:.6f}")
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|