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
multioptpy/optimizer.py
ADDED
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import copy
|
|
3
|
+
|
|
4
|
+
from multioptpy.Parameters.parameter import UnitValueLib, atomic_mass
|
|
5
|
+
from multioptpy.Utils.calc_tools import Calculationtools
|
|
6
|
+
|
|
7
|
+
from multioptpy.Optimizer.adabelief import Adabelief
|
|
8
|
+
#from multioptpy.Optimizer.fastadabelief import FastAdabelief
|
|
9
|
+
#from multioptpy.Optimizer.adaderivative import Adaderivative
|
|
10
|
+
#from multioptpy.Optimizer.sadam import SAdam
|
|
11
|
+
#from multioptpy.Optimizer.samsgrad import SAMSGrad
|
|
12
|
+
#from multioptpy.Optimizer.QHAdam import QHAdam
|
|
13
|
+
#from multioptpy.Optimizer.adamax import AdaMax
|
|
14
|
+
#from multioptpy.Optimizer.yogi import YOGI
|
|
15
|
+
#from multioptpy.Optimizer.nadam import NAdam
|
|
16
|
+
from multioptpy.Optimizer.fire import FIRE
|
|
17
|
+
from multioptpy.Optimizer.abc_fire import ABC_FIRE
|
|
18
|
+
from multioptpy.Optimizer.fire2 import FIRE2
|
|
19
|
+
#from multioptpy.Optimizer.adadiff import AdaDiff
|
|
20
|
+
#from multioptpy.Optimizer.adamod import Adamod
|
|
21
|
+
from multioptpy.Optimizer.radam import RADAM
|
|
22
|
+
from multioptpy.Optimizer.eve import EVE
|
|
23
|
+
#from multioptpy.Optimizer.adamw import AdamW
|
|
24
|
+
from multioptpy.Optimizer.adam import Adam
|
|
25
|
+
#from multioptpy.Optimizer.adafactor import Adafactor
|
|
26
|
+
from multioptpy.Optimizer.prodigy import Prodigy
|
|
27
|
+
#from multioptpy.Optimizer.adabound import AdaBound
|
|
28
|
+
#from multioptpy.Optimizer.adadelta import Adadelta
|
|
29
|
+
from multioptpy.Optimizer.conjugate_gradient import ConjgateGradient
|
|
30
|
+
#from multioptpy.Optimizer.hybrid_rfo import HybridRFO
|
|
31
|
+
#from multioptpy.Optimizer.rfo import RationalFunctionOptimization
|
|
32
|
+
#from multioptpy.Optimizer.ric_rfo import RedundantInternalRFO
|
|
33
|
+
from multioptpy.Optimizer.rsprfo import EnhancedRSPRFO
|
|
34
|
+
from multioptpy.Optimizer.rsirfo import RSIRFO
|
|
35
|
+
#from multioptpy.Optimizer.newton import Newton
|
|
36
|
+
from multioptpy.Optimizer.lbfgs import LBFGS
|
|
37
|
+
from multioptpy.Optimizer.tr_lbfgs import TRLBFGS
|
|
38
|
+
#from multioptpy.Optimizer.rmspropgrave import RMSpropGrave
|
|
39
|
+
from multioptpy.Optimizer.lookahead import LookAhead
|
|
40
|
+
from multioptpy.Optimizer.lars import LARS
|
|
41
|
+
from multioptpy.Optimizer.gdiis import GDIIS
|
|
42
|
+
from multioptpy.Optimizer.ediis import EDIIS
|
|
43
|
+
from multioptpy.Optimizer.gediis import GEDIIS
|
|
44
|
+
from multioptpy.Optimizer.c2diis import C2DIIS
|
|
45
|
+
from multioptpy.Optimizer.adiis import ADIIS
|
|
46
|
+
from multioptpy.Optimizer.kdiis import KrylovDIIS as KDIIS
|
|
47
|
+
from multioptpy.Optimizer.gpr_step import GPRStep
|
|
48
|
+
from multioptpy.Optimizer.gan_step import GANStep
|
|
49
|
+
from multioptpy.Optimizer.rl_step import RLStepSizeOptimizer
|
|
50
|
+
from multioptpy.Optimizer.geodesic_step import GeodesicStepper
|
|
51
|
+
from multioptpy.Optimizer.linesearch import LineSearch
|
|
52
|
+
from multioptpy.Optimizer.component_wise_scaling import ComponentWiseScaling
|
|
53
|
+
from multioptpy.Optimizer.coordinate_locking import CoordinateLocking
|
|
54
|
+
from multioptpy.Optimizer.trust_radius import TrustRadius
|
|
55
|
+
from multioptpy.Optimizer.gradientdescent import GradientDescent, MassWeightedGradientDescent
|
|
56
|
+
from multioptpy.Optimizer.gpmin import GPmin
|
|
57
|
+
from multioptpy.Optimizer.trim import TRIM
|
|
58
|
+
|
|
59
|
+
optimizer_mapping = {
|
|
60
|
+
"adabelief": Adabelief,
|
|
61
|
+
"radam": RADAM,
|
|
62
|
+
"eve": EVE,
|
|
63
|
+
"prodigy": Prodigy,
|
|
64
|
+
"abcfire": ABC_FIRE,
|
|
65
|
+
"fire2": FIRE2,
|
|
66
|
+
"fire": FIRE,
|
|
67
|
+
"mwgradientdescent": MassWeightedGradientDescent,
|
|
68
|
+
"gradientdescent": GradientDescent,
|
|
69
|
+
"steepest_descent": GradientDescent,
|
|
70
|
+
"gpmin": GPmin,
|
|
71
|
+
"tr_lbfgs": TRLBFGS,
|
|
72
|
+
"lbfgs": LBFGS,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
specific_cases = {
|
|
76
|
+
"ranger": {"optimizer": RADAM, "lookahead": LookAhead(), "lars": None},
|
|
77
|
+
"rangerlars": {"optimizer": RADAM, "lookahead": LookAhead(), "lars": LARS()},
|
|
78
|
+
"adam": {"optimizer": Adam, "lookahead": LookAhead(), "lars": None},
|
|
79
|
+
"adamlars": {"optimizer": Adam, "lookahead": None, "lars": LARS()},
|
|
80
|
+
"adamlookahead": {"optimizer": Adam, "lookahead": LookAhead(), "lars": None},
|
|
81
|
+
"adamlookaheadlars": {"optimizer": Adam, "lookahead": LookAhead(), "lars": LARS()},
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
quasi_newton_mapping = {
|
|
85
|
+
"rsirfo_bfgs_dd": {"delta": 0.50, "rfo_type": 1},
|
|
86
|
+
"rsirfo_bfgs": {"delta": 0.50, "rfo_type": 1},
|
|
87
|
+
"rsirfo_block_bfgs_dd": {"delta": 0.50, "rfo_type": 1},
|
|
88
|
+
"rsirfo_block_bfgs": {"delta": 0.50, "rfo_type": 1},
|
|
89
|
+
"rsirfo_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
90
|
+
"rsirfo_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
91
|
+
"rsirfo_block_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
92
|
+
"rsirfo_block_fsb_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
93
|
+
"rsirfo_block_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
94
|
+
"rsirfo_block_cfd_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
95
|
+
"rsirfo_block_cfd_fsb_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
96
|
+
"rsirfo_block_cfd_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
97
|
+
"rsirfo_cfd_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
98
|
+
"rsirfo_cfd_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
99
|
+
"rsirfo_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
100
|
+
"rsirfo_block_bofill_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
101
|
+
"rsirfo_block_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
102
|
+
"rsirfo_block_cfd_bofill_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
103
|
+
"rsirfo_block_cfd_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
104
|
+
"rsirfo_cfd_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
105
|
+
"rsirfo_pcfd_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
106
|
+
"rsirfo_msp": {"delta": 0.50, "rfo_type": 1},
|
|
107
|
+
"rsirfo_sr1": {"delta": 0.50, "rfo_type": 1},
|
|
108
|
+
"rsirfo_psb": {"delta": 0.50, "rfo_type": 1},
|
|
109
|
+
"rsirfo_flowchart": {"delta": 0.50, "rfo_type": 1},
|
|
110
|
+
|
|
111
|
+
"rsprfo_bfgs_dd": {"delta": 0.50, "rfo_type": 1},
|
|
112
|
+
"rsprfo_bfgs": {"delta": 0.50, "rfo_type": 1},
|
|
113
|
+
"rsprfo_block_bfgs_dd": {"delta": 0.50, "rfo_type": 1},
|
|
114
|
+
"rsprfo_block_bfgs": {"delta": 0.50, "rfo_type": 1},
|
|
115
|
+
"rsprfo_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
116
|
+
"rsprfo_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
117
|
+
"rsprfo_block_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
118
|
+
"rsprfo_block_fsb_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
119
|
+
"rsprfo_block_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
120
|
+
"rsprfo_block_cfd_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
121
|
+
"rsprfo_block_cfd_fsb_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
122
|
+
"rsprfo_block_cfd_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
123
|
+
"rsprfo_cfd_fsb_dd": {"delta": 0.50, "rfo_type": 1},
|
|
124
|
+
"rsprfo_cfd_fsb": {"delta": 0.50, "rfo_type": 1},
|
|
125
|
+
"rsprfo_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
126
|
+
"rsprfo_block_bofill_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
127
|
+
"rsprfo_block_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
128
|
+
"rsprfo_block_cfd_bofill_weighted": {"delta": 0.50, "rfo_type": 1},
|
|
129
|
+
"rsprfo_block_cfd_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
130
|
+
"rsprfo_cfd_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
131
|
+
"rsprfo_pcfd_bofill": {"delta": 0.50, "rfo_type": 1},
|
|
132
|
+
"rsprfo_msp": {"delta": 0.50, "rfo_type": 1},
|
|
133
|
+
"rsprfo_sr1": {"delta": 0.50, "rfo_type": 1},
|
|
134
|
+
"rsprfo_psb": {"delta": 0.50, "rfo_type": 1},
|
|
135
|
+
"rsprfo_flowchart": {"delta": 0.50, "rfo_type": 1},
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class CalculateMoveVector:
|
|
141
|
+
def __init__(self, DELTA, element_list, saddle_order=0, FC_COUNT=-1, temperature=0.0, model_hess_flag=None, max_trust_radius=None, min_trust_radius=None):
|
|
142
|
+
self.DELTA = DELTA
|
|
143
|
+
self.temperature = temperature
|
|
144
|
+
np.set_printoptions(precision=12, floatmode="fixed", suppress=True)
|
|
145
|
+
self.unitval = UnitValueLib()
|
|
146
|
+
self.FC_COUNT = FC_COUNT
|
|
147
|
+
self.MAX_MAX_FORCE_SWITCHING_THRESHOLD = 0.0050
|
|
148
|
+
self.MIN_MAX_FORCE_SWITCHING_THRESHOLD = 0.0010
|
|
149
|
+
self.MAX_RMS_FORCE_SWITCHING_THRESHOLD = 0.05
|
|
150
|
+
self.MIN_RMS_FORCE_SWITCHING_THRESHOLD = 0.005
|
|
151
|
+
|
|
152
|
+
self.max_trust_radius = max_trust_radius
|
|
153
|
+
self.min_trust_radius = min_trust_radius
|
|
154
|
+
self.CALC_TRUST_RADII = TrustRadius()
|
|
155
|
+
if self.max_trust_radius is not None:
|
|
156
|
+
if self.max_trust_radius <= 0.0:
|
|
157
|
+
print("max_trust_radius must be greater than 0.0")
|
|
158
|
+
exit()
|
|
159
|
+
|
|
160
|
+
self.CALC_TRUST_RADII.set_max_trust_radius(self.max_trust_radius)
|
|
161
|
+
if self.max_trust_radius is None:
|
|
162
|
+
if saddle_order > 0:
|
|
163
|
+
self.max_trust_radius = 0.1
|
|
164
|
+
self.trust_radii = 0.1
|
|
165
|
+
else:
|
|
166
|
+
self.max_trust_radius = 0.5
|
|
167
|
+
self.trust_radii = 0.5
|
|
168
|
+
else:
|
|
169
|
+
if saddle_order > 0:
|
|
170
|
+
self.trust_radii = min(self.max_trust_radius, 0.1)
|
|
171
|
+
else:
|
|
172
|
+
self.trust_radii = self.max_trust_radius if type(self.max_trust_radius) is float else 0.5
|
|
173
|
+
|
|
174
|
+
if self.min_trust_radius is not None:
|
|
175
|
+
if self.min_trust_radius <= 0.0:
|
|
176
|
+
print("min_trust_radius must be greater than 0.0")
|
|
177
|
+
exit()
|
|
178
|
+
if self.trust_radii < self.min_trust_radius:
|
|
179
|
+
print("min_trust_radius must be smaller than max_trust_radius")
|
|
180
|
+
exit()
|
|
181
|
+
|
|
182
|
+
self.CALC_TRUST_RADII.set_min_trust_radius(self.min_trust_radius)
|
|
183
|
+
|
|
184
|
+
self.min_trust_radius = min_trust_radius if min_trust_radius is not None else 0.01
|
|
185
|
+
|
|
186
|
+
self.saddle_order = saddle_order
|
|
187
|
+
self.iter = 0
|
|
188
|
+
self.element_list = element_list
|
|
189
|
+
self.model_hess_flag = model_hess_flag
|
|
190
|
+
|
|
191
|
+
def initialization(self, method):
|
|
192
|
+
"""
|
|
193
|
+
Initializes the optimizer instances based on the provided method names.
|
|
194
|
+
|
|
195
|
+
This function parses a list of method strings. Each string defines a
|
|
196
|
+
base optimizer (e.g., LBFGS, FIRE, RSIRFO) and optionally
|
|
197
|
+
a set of enhancements (e.g., "lookahead", "gdiis", "lars")
|
|
198
|
+
which are chained together.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
method (list[str]): A list of method name strings.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
list: A list of initialized base optimizer instances.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
# --- Helper Function to Handle Enhancements ---
|
|
208
|
+
|
|
209
|
+
def _append_enhancements(lower_m, is_newton_method, specific_lookahead=None, specific_lars=None):
|
|
210
|
+
"""
|
|
211
|
+
Private helper to append all enhancement instances for a given method.
|
|
212
|
+
This avoids duplicating this logic in every 'if/elif' block.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
lower_m (str): The lowercased method name string.
|
|
216
|
+
is_newton_method (bool): Flag indicating if the base optimizer is a quasi-Newton method.
|
|
217
|
+
specific_lookahead (object, optional): A pre-defined LookAhead instance from 'specific_cases'.
|
|
218
|
+
specific_lars (object, optional): A pre-defined LARS instance from 'specific_cases'.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
# Handle LookAhead and LARS, prioritizing 'specific_cases' config
|
|
222
|
+
if specific_lookahead is not None:
|
|
223
|
+
lookahead_instances.append(specific_lookahead)
|
|
224
|
+
else:
|
|
225
|
+
lookahead_instances.append(LookAhead() if "lookahead" in lower_m else None)
|
|
226
|
+
|
|
227
|
+
if specific_lars is not None:
|
|
228
|
+
lars_instances.append(specific_lars)
|
|
229
|
+
else:
|
|
230
|
+
lars_instances.append(LARS() if "lars" in lower_m else None)
|
|
231
|
+
|
|
232
|
+
# LineSearch
|
|
233
|
+
linesearch_instances.append(LineSearch() if "linesearch" in lower_m else None)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# DIIS family
|
|
237
|
+
gdiis_instances.append(GDIIS() if "gdiis" in lower_m else None)
|
|
238
|
+
kdiis_instances.append(KDIIS() if "kdiis" in lower_m else None)
|
|
239
|
+
adiis_instances.append(ADIIS() if "adiis" in lower_m else None)
|
|
240
|
+
c2diis_instances.append(C2DIIS() if "c2diis" in lower_m else None)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# Handle mutually exclusive EDIIS/GEDIIS
|
|
244
|
+
if "gediis" in lower_m:
|
|
245
|
+
gediis_instances.append(GEDIIS())
|
|
246
|
+
ediis_instances.append(None)
|
|
247
|
+
else:
|
|
248
|
+
ediis_instances.append(EDIIS() if "ediis" in lower_m else None)
|
|
249
|
+
gediis_instances.append(None)
|
|
250
|
+
|
|
251
|
+
# Coordinate transformations
|
|
252
|
+
coordinate_locking_instances.append(CoordinateLocking() if "coordinate_locking" in lower_m else None)
|
|
253
|
+
coordinate_wise_scaling_instances.append(ComponentWiseScaling() if "component_wise_scaling" in lower_m else None)
|
|
254
|
+
|
|
255
|
+
# ML-based step optimizers
|
|
256
|
+
gpr_step_instances.append(GPRStep() if "gpr_step" in lower_m else None)
|
|
257
|
+
gan_step_instances.append(GANStep() if "gan_step" in lower_m else None)
|
|
258
|
+
rl_step_instances.append(RLStepSizeOptimizer() if "rl_step" in lower_m else None)
|
|
259
|
+
|
|
260
|
+
# Other step modifiers
|
|
261
|
+
geodesic_step_instances.append(GeodesicStepper(element_list=self.element_list) if "geodesic_step" in lower_m else None)
|
|
262
|
+
|
|
263
|
+
# TRIM is only relevant for quasi-Newton methods
|
|
264
|
+
if is_newton_method:
|
|
265
|
+
trim_step_instances.append(TRIM(saddle_order=self.saddle_order) if "trim" in lower_m else None)
|
|
266
|
+
else:
|
|
267
|
+
trim_step_instances.append(None)
|
|
268
|
+
|
|
269
|
+
# --- End of Helper Function ---
|
|
270
|
+
|
|
271
|
+
# Initialize lists to store instances for each method
|
|
272
|
+
optimizer_instances = []
|
|
273
|
+
newton_tag = []
|
|
274
|
+
lookahead_instances = []
|
|
275
|
+
lars_instances = []
|
|
276
|
+
gdiis_instances = []
|
|
277
|
+
ediis_instances = []
|
|
278
|
+
gediis_instances = []
|
|
279
|
+
c2diis_instances = []
|
|
280
|
+
adiis_instances = []
|
|
281
|
+
kdiis_instances = []
|
|
282
|
+
coordinate_locking_instances = []
|
|
283
|
+
coordinate_wise_scaling_instances = []
|
|
284
|
+
gpr_step_instances = []
|
|
285
|
+
gan_step_instances = []
|
|
286
|
+
rl_step_instances = []
|
|
287
|
+
geodesic_step_instances = []
|
|
288
|
+
trim_step_instances = []
|
|
289
|
+
linesearch_instances = []
|
|
290
|
+
|
|
291
|
+
# Loop over each requested method string
|
|
292
|
+
for i, m in enumerate(method):
|
|
293
|
+
lower_m = m.lower()
|
|
294
|
+
optimizer_added = False
|
|
295
|
+
is_newton = False
|
|
296
|
+
optimizer = None
|
|
297
|
+
|
|
298
|
+
# 1. Check hard-coded specific cases (e.g., "ranger")
|
|
299
|
+
if lower_m in specific_cases:
|
|
300
|
+
case = specific_cases[lower_m]
|
|
301
|
+
optimizer = case["optimizer"]()
|
|
302
|
+
is_newton = False
|
|
303
|
+
optimizer_instances.append(optimizer)
|
|
304
|
+
newton_tag.append(is_newton)
|
|
305
|
+
_append_enhancements(lower_m,
|
|
306
|
+
is_newton,
|
|
307
|
+
specific_lookahead=case.get("lookahead"),
|
|
308
|
+
specific_lars=case.get("lars"))
|
|
309
|
+
optimizer_added = True
|
|
310
|
+
|
|
311
|
+
# 2. Check quasi-Newton methods
|
|
312
|
+
elif any(key in lower_m for key in quasi_newton_mapping):
|
|
313
|
+
for key, settings in quasi_newton_mapping.items():
|
|
314
|
+
if key in lower_m:
|
|
315
|
+
print(key)
|
|
316
|
+
if "rsprfo" in key:
|
|
317
|
+
optimizer = EnhancedRSPRFO(method=m, saddle_order=self.saddle_order, element_list=self.element_list, trust_radius_max=self.max_trust_radius, trust_radius_min=self.min_trust_radius)
|
|
318
|
+
elif "rsirfo" in key:
|
|
319
|
+
optimizer = RSIRFO(method=m, saddle_order=self.saddle_order, element_list=self.element_list, trust_radius_max=self.max_trust_radius, trust_radius_min=self.min_trust_radius)
|
|
320
|
+
else:
|
|
321
|
+
print(f"This method is not implemented: {m}. Thus, exiting.")
|
|
322
|
+
exit()
|
|
323
|
+
|
|
324
|
+
optimizer.DELTA = settings["delta"]
|
|
325
|
+
if "linesearch" in settings:
|
|
326
|
+
optimizer.linesearchflag = True
|
|
327
|
+
|
|
328
|
+
is_newton = True
|
|
329
|
+
optimizer_instances.append(optimizer)
|
|
330
|
+
newton_tag.append(is_newton)
|
|
331
|
+
_append_enhancements(lower_m, is_newton)
|
|
332
|
+
optimizer_added = True
|
|
333
|
+
break # Exit inner loop once match is found
|
|
334
|
+
|
|
335
|
+
# 3. Check standard gradient-based optimizers
|
|
336
|
+
if not optimizer_added:
|
|
337
|
+
for key, optimizer_class in optimizer_mapping.items():
|
|
338
|
+
if key in lower_m:
|
|
339
|
+
optimizer = optimizer_class()
|
|
340
|
+
if lower_m == "mwgradientdescent":
|
|
341
|
+
optimizer.element_list = self.element_list
|
|
342
|
+
optimizer.atomic_mass = atomic_mass
|
|
343
|
+
|
|
344
|
+
is_newton = False
|
|
345
|
+
optimizer_instances.append(optimizer)
|
|
346
|
+
newton_tag.append(is_newton)
|
|
347
|
+
_append_enhancements(lower_m, is_newton)
|
|
348
|
+
optimizer_added = True
|
|
349
|
+
break # Exit inner loop once match is found
|
|
350
|
+
|
|
351
|
+
# 4. Check Conjugate Gradient methods
|
|
352
|
+
# Define CG keys. Put "cg" last so "cg_pr" matches first if present.
|
|
353
|
+
cg_keys = ["cg_pr", "cg_fr", "cg_hs", "cg_dy", "cg"]
|
|
354
|
+
if not optimizer_added:
|
|
355
|
+
for key in cg_keys:
|
|
356
|
+
if key in lower_m:
|
|
357
|
+
# Use the matched key (e.g., "cg" or "cg_pr") for the constructor,
|
|
358
|
+
optimizer = ConjgateGradient(method=key)
|
|
359
|
+
is_newton = False
|
|
360
|
+
optimizer_instances.append(optimizer)
|
|
361
|
+
newton_tag.append(is_newton)
|
|
362
|
+
# Pass the full 'lower_m' string to check for other enhancements
|
|
363
|
+
_append_enhancements(lower_m, is_newton)
|
|
364
|
+
optimizer_added = True
|
|
365
|
+
break # Found a cg match, exit inner loop
|
|
366
|
+
|
|
367
|
+
# 5. Handle default case (method not found)
|
|
368
|
+
if not optimizer_added:
|
|
369
|
+
print(f"This method is not implemented: {m}. Thus, Default method (FIRE) is used.")
|
|
370
|
+
optimizer = FIRE()
|
|
371
|
+
is_newton = False
|
|
372
|
+
optimizer_instances.append(optimizer)
|
|
373
|
+
newton_tag.append(is_newton)
|
|
374
|
+
_append_enhancements(lower_m, is_newton)
|
|
375
|
+
|
|
376
|
+
# --- End of loop ---
|
|
377
|
+
|
|
378
|
+
# Store all instance lists as class attributes
|
|
379
|
+
# These are used by other methods in the class
|
|
380
|
+
self.method = method
|
|
381
|
+
self.newton_tag = newton_tag
|
|
382
|
+
self.lookahead_instances = lookahead_instances
|
|
383
|
+
self.lars_instances = lars_instances
|
|
384
|
+
self.gdiis_instances = gdiis_instances
|
|
385
|
+
self.ediis_instances = ediis_instances
|
|
386
|
+
self.gediis_instances = gediis_instances
|
|
387
|
+
self.c2diis_instances = c2diis_instances
|
|
388
|
+
self.adiis_instances = adiis_instances
|
|
389
|
+
self.kdiis_instances = kdiis_instances
|
|
390
|
+
self.coordinate_locking_instances = coordinate_locking_instances
|
|
391
|
+
self.coordinate_wise_scaling_instances = coordinate_wise_scaling_instances
|
|
392
|
+
self.gpr_step_instances = gpr_step_instances
|
|
393
|
+
self.gan_step_instances = gan_step_instances
|
|
394
|
+
self.rl_step_instances = rl_step_instances
|
|
395
|
+
self.geodesic_step_instances = geodesic_step_instances
|
|
396
|
+
self.trim_step_instances = trim_step_instances
|
|
397
|
+
self.linesearch_instances = linesearch_instances
|
|
398
|
+
return optimizer_instances
|
|
399
|
+
|
|
400
|
+
def update_trust_radius_conditionally(self, optimizer_instances, B_e, pre_B_e, pre_B_g, pre_move_vector, geom_num_list):
|
|
401
|
+
"""
|
|
402
|
+
Refactored method to handle trust radius updates and conditions.
|
|
403
|
+
"""
|
|
404
|
+
# Early exit if no full-coordinate count and no Hessian flag
|
|
405
|
+
if self.FC_COUNT == -1 and not self.model_hess_flag is not None:
|
|
406
|
+
return
|
|
407
|
+
|
|
408
|
+
# Determine if there's a model Hessian to use
|
|
409
|
+
model_hess = None
|
|
410
|
+
for i in range(len(optimizer_instances)):
|
|
411
|
+
if self.newton_tag[i]:
|
|
412
|
+
model_hess = optimizer_instances[i].hessian + optimizer_instances[i].bias_hessian
|
|
413
|
+
break
|
|
414
|
+
|
|
415
|
+
# Update trust radii only if we have a Hessian or if FC_COUNT is not -1
|
|
416
|
+
if not (model_hess is None and self.FC_COUNT == -1) and True in self.newton_tag:
|
|
417
|
+
self.trust_radii = self.CALC_TRUST_RADII.update_trust_radii(
|
|
418
|
+
B_e, pre_B_e, pre_B_g, pre_move_vector, model_hess, geom_num_list, self.trust_radii
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
if self.min_trust_radius is not None:
|
|
422
|
+
print("user_difined_min_trust_radius: ", self.min_trust_radius)
|
|
423
|
+
|
|
424
|
+
if self.max_trust_radius is not None:
|
|
425
|
+
print("user_difined_max_trust_radius: ", self.max_trust_radius)
|
|
426
|
+
else:
|
|
427
|
+
# If saddle order is positive, constrain the trust radii
|
|
428
|
+
if self.saddle_order > 0:
|
|
429
|
+
self.trust_radii = min(self.trust_radii, self.max_trust_radius if self.max_trust_radius is not None else 0.1)
|
|
430
|
+
|
|
431
|
+
# If this is the first iteration but not full-coordinate -1 check
|
|
432
|
+
if self.iter == 0 and self.FC_COUNT != -1:
|
|
433
|
+
if self.saddle_order > 0:
|
|
434
|
+
self.trust_radii = min(self.trust_radii, self.max_trust_radius if self.max_trust_radius is not None else 0.1)
|
|
435
|
+
|
|
436
|
+
def handle_projection_constraint(self, projection_constrain):
|
|
437
|
+
"""
|
|
438
|
+
Constrain the trust radii if projection constraint is enabled.
|
|
439
|
+
"""
|
|
440
|
+
if projection_constrain:
|
|
441
|
+
if self.max_trust_radius is not None:
|
|
442
|
+
pass
|
|
443
|
+
else:
|
|
444
|
+
self.trust_radii = min(self.trust_radii, self.max_trust_radius if self.max_trust_radius is not None else 0.1)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def switch_move_vector(self,
|
|
449
|
+
B_g,
|
|
450
|
+
move_vector_list,
|
|
451
|
+
method_list=None,
|
|
452
|
+
max_rms_force_switching_threshold=0.05,
|
|
453
|
+
min_rms_force_switching_threshold=0.005,
|
|
454
|
+
steepness=10.0,
|
|
455
|
+
offset=0.5):
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
if len(method_list) == 1:
|
|
459
|
+
return copy.copy(move_vector_list[0]), method_list
|
|
460
|
+
|
|
461
|
+
rms_force = abs(np.sqrt(np.square(B_g).mean()))
|
|
462
|
+
|
|
463
|
+
if rms_force > max_rms_force_switching_threshold:
|
|
464
|
+
|
|
465
|
+
print(f"Switching to {method_list[0]}")
|
|
466
|
+
return copy.copy(move_vector_list[0]), method_list
|
|
467
|
+
elif min_rms_force_switching_threshold < rms_force <= max_rms_force_switching_threshold:
|
|
468
|
+
|
|
469
|
+
x_j = (rms_force - min_rms_force_switching_threshold) / (
|
|
470
|
+
max_rms_force_switching_threshold - min_rms_force_switching_threshold
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
f_val = 1 / (1 + np.exp(-steepness * (x_j - offset)))
|
|
474
|
+
combined_vector = (
|
|
475
|
+
np.array(move_vector_list[0], dtype="float64") * f_val
|
|
476
|
+
+ np.array(move_vector_list[1], dtype="float64") * (1.0 - f_val)
|
|
477
|
+
)
|
|
478
|
+
print(f"Weighted switching: {f_val:.3f} {method_list[0]} {method_list[1]}")
|
|
479
|
+
return combined_vector, method_list
|
|
480
|
+
else:
|
|
481
|
+
|
|
482
|
+
print(f"Switching to {method_list[1]}")
|
|
483
|
+
return copy.copy(move_vector_list[1]), method_list
|
|
484
|
+
|
|
485
|
+
def update_move_vector_list(
|
|
486
|
+
self,
|
|
487
|
+
optimizer_instances,
|
|
488
|
+
B_g,
|
|
489
|
+
pre_B_g,
|
|
490
|
+
pre_geom,
|
|
491
|
+
B_e,
|
|
492
|
+
pre_B_e,
|
|
493
|
+
pre_move_vector,
|
|
494
|
+
initial_geom_num_list,
|
|
495
|
+
g,
|
|
496
|
+
pre_g,
|
|
497
|
+
):
|
|
498
|
+
"""
|
|
499
|
+
Update a list of move vectors from multiple optimizer instances,
|
|
500
|
+
including optional enhancements through various techniques.
|
|
501
|
+
"""
|
|
502
|
+
move_vector_list = []
|
|
503
|
+
|
|
504
|
+
tmp_hess = None
|
|
505
|
+
for i in range(len(optimizer_instances)):
|
|
506
|
+
if self.newton_tag[i]:
|
|
507
|
+
tmp_hess = optimizer_instances[i].hessian + optimizer_instances[i].bias_hessian
|
|
508
|
+
break
|
|
509
|
+
# Enhancement techniques and their parameter configurations
|
|
510
|
+
# Format: [list_of_instances, method_name, [parameters]]
|
|
511
|
+
enhancement_config = [
|
|
512
|
+
# Base optimizer - separate handling
|
|
513
|
+
|
|
514
|
+
# Trust region and momentum techniques
|
|
515
|
+
[self.lars_instances, "apply_lars", [B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector,
|
|
516
|
+
initial_geom_num_list, g, pre_g]],
|
|
517
|
+
[self.lookahead_instances, "apply_lookahead", [B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector,
|
|
518
|
+
initial_geom_num_list, g, pre_g]],
|
|
519
|
+
|
|
520
|
+
# linesearch
|
|
521
|
+
[self.linesearch_instances, "apply_linesearch", [B_g, pre_B_g, B_e, pre_B_e]],
|
|
522
|
+
|
|
523
|
+
# DIIS family techniques
|
|
524
|
+
[self.ediis_instances, "apply_ediis", [B_e, B_g]],
|
|
525
|
+
[self.gdiis_instances, "apply_gdiis", [B_g, pre_B_g]],
|
|
526
|
+
[self.c2diis_instances, "apply_c2diis", [B_g, pre_B_g]],
|
|
527
|
+
[self.adiis_instances, "apply_adiis", [B_e, B_g]],
|
|
528
|
+
[self.kdiis_instances, "apply_kdiis", [B_e, B_g]],
|
|
529
|
+
[self.gediis_instances, "apply_gediis", [B_e, B_g, pre_B_g]],
|
|
530
|
+
|
|
531
|
+
# Coordinate transformation techniques
|
|
532
|
+
[self.coordinate_locking_instances, "apply_coordinate_locking", [B_e, B_g]],
|
|
533
|
+
[self.coordinate_wise_scaling_instances, "apply_coordinate_scaling", [B_e, B_g]],
|
|
534
|
+
|
|
535
|
+
# ML-based step prediction techniques
|
|
536
|
+
[self.gpr_step_instances, "apply_ml_step", [B_e, B_g]],
|
|
537
|
+
|
|
538
|
+
# GAN-based step prediction techniques
|
|
539
|
+
[self.gan_step_instances, "apply_gan_step", [B_e, B_g]],
|
|
540
|
+
|
|
541
|
+
# Reinforcement learning-based step prediction techniques
|
|
542
|
+
[self.rl_step_instances, "apply_rl_step", [B_g, pre_B_g, B_e, pre_B_e]],
|
|
543
|
+
# Geodesic stepping techniques
|
|
544
|
+
[self.geodesic_step_instances, "apply_geodesic_step", []],
|
|
545
|
+
# TRIM step adjustment techniques
|
|
546
|
+
[self.trim_step_instances, "apply_trim_step", [B_g, tmp_hess, self.trust_radii]],
|
|
547
|
+
]
|
|
548
|
+
|
|
549
|
+
for i, optimizer_instance in enumerate(optimizer_instances):
|
|
550
|
+
# Get initial move vector from base optimizer
|
|
551
|
+
tmp_move_vector = optimizer_instance.run(
|
|
552
|
+
self.geom_num_list,
|
|
553
|
+
B_g,
|
|
554
|
+
pre_B_g,
|
|
555
|
+
pre_geom,
|
|
556
|
+
B_e,
|
|
557
|
+
pre_B_e,
|
|
558
|
+
pre_move_vector,
|
|
559
|
+
initial_geom_num_list,
|
|
560
|
+
g,
|
|
561
|
+
pre_g
|
|
562
|
+
)
|
|
563
|
+
tmp_move_vector = np.array(tmp_move_vector, dtype="float64")
|
|
564
|
+
|
|
565
|
+
# Apply each enhancement technique if available
|
|
566
|
+
for instance_list, method_name, base_params in enhancement_config:
|
|
567
|
+
if i < len(instance_list) and instance_list[i] is not None:
|
|
568
|
+
tmp_move_vector = self._apply_enhancement(
|
|
569
|
+
instance_list[i],
|
|
570
|
+
method_name,
|
|
571
|
+
[self.geom_num_list] + base_params + [tmp_move_vector]
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
move_vector_list.append(tmp_move_vector)
|
|
575
|
+
|
|
576
|
+
return move_vector_list
|
|
577
|
+
|
|
578
|
+
def _apply_enhancement(self, instance, method_name, params):
|
|
579
|
+
"""
|
|
580
|
+
Helper method to apply enhancement techniques to the move vector.
|
|
581
|
+
|
|
582
|
+
Parameters:
|
|
583
|
+
-----------
|
|
584
|
+
instance : object
|
|
585
|
+
The enhancement technique instance
|
|
586
|
+
method_name : str
|
|
587
|
+
The name of the method to use (for logging/debugging)
|
|
588
|
+
params : list
|
|
589
|
+
Parameters to pass to the run method
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
--------
|
|
593
|
+
numpy.ndarray
|
|
594
|
+
The modified move vector
|
|
595
|
+
"""
|
|
596
|
+
# For LARS, special handling is needed as it returns a scaling factor
|
|
597
|
+
if method_name == "apply_lars":
|
|
598
|
+
trust_delta = instance.run(*params)
|
|
599
|
+
# Last parameter is the move vector
|
|
600
|
+
return params[-1] * trust_delta
|
|
601
|
+
else:
|
|
602
|
+
# Standard run pattern for most enhancement techniques
|
|
603
|
+
return instance.run(*params)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def calc_move_vector(self, iter, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector, initial_geom_num_list, g, pre_g, optimizer_instances, projection_constrain=False, print_flag=True):#geom_num_list:Bohr
|
|
607
|
+
natom = len(geom_num_list)
|
|
608
|
+
|
|
609
|
+
###
|
|
610
|
+
#-------------------------------------------------------------
|
|
611
|
+
geom_num_list = geom_num_list.reshape(natom*3, 1)
|
|
612
|
+
B_g = B_g.reshape(natom*3, 1)
|
|
613
|
+
pre_B_g = pre_B_g.reshape(natom*3, 1)
|
|
614
|
+
pre_geom = pre_geom.reshape(natom*3, 1)
|
|
615
|
+
g = g.reshape(natom*3, 1)
|
|
616
|
+
pre_g = pre_g.reshape(natom*3, 1)
|
|
617
|
+
pre_move_vector = pre_move_vector.reshape(natom*3, 1)
|
|
618
|
+
initial_geom_num_list = initial_geom_num_list.reshape(natom*3, 1)
|
|
619
|
+
#-------------------------------------------------------------
|
|
620
|
+
###
|
|
621
|
+
self.iter = iter
|
|
622
|
+
self.geom_num_list = geom_num_list
|
|
623
|
+
|
|
624
|
+
#-------------------------------------------------------------
|
|
625
|
+
# update trust radii
|
|
626
|
+
#-------------------------------------------------------------
|
|
627
|
+
self.update_trust_radius_conditionally(optimizer_instances, B_e, pre_B_e, pre_B_g, pre_move_vector, geom_num_list)
|
|
628
|
+
self.handle_projection_constraint(projection_constrain)
|
|
629
|
+
|
|
630
|
+
#---------------------------------
|
|
631
|
+
#calculate move vector
|
|
632
|
+
#---------------------------------
|
|
633
|
+
|
|
634
|
+
move_vector_list = self.update_move_vector_list(optimizer_instances,
|
|
635
|
+
B_g,
|
|
636
|
+
pre_B_g,
|
|
637
|
+
pre_geom,
|
|
638
|
+
B_e,
|
|
639
|
+
pre_B_e,
|
|
640
|
+
pre_move_vector,
|
|
641
|
+
initial_geom_num_list,
|
|
642
|
+
g,
|
|
643
|
+
pre_g)
|
|
644
|
+
|
|
645
|
+
#---------------------------------
|
|
646
|
+
# switch step update method
|
|
647
|
+
#---------------------------------
|
|
648
|
+
move_vector, optimizer_instances = self.switch_move_vector(B_g,
|
|
649
|
+
move_vector_list,
|
|
650
|
+
optimizer_instances,
|
|
651
|
+
max_rms_force_switching_threshold=0.05,
|
|
652
|
+
min_rms_force_switching_threshold=0.005
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
if print_flag:
|
|
656
|
+
print("==================================================================================")
|
|
657
|
+
|
|
658
|
+
if np.linalg.norm(move_vector) > self.trust_radii:
|
|
659
|
+
move_vector = self.trust_radii * move_vector/np.linalg.norm(move_vector)
|
|
660
|
+
|
|
661
|
+
if print_flag:
|
|
662
|
+
print("trust radii (unit. ang.): ", self.trust_radii)
|
|
663
|
+
print("step radii (unit. ang.): ", np.linalg.norm(move_vector))
|
|
664
|
+
new_geometry = (geom_num_list - move_vector)
|
|
665
|
+
|
|
666
|
+
new_geometry = new_geometry.reshape(natom, 3)
|
|
667
|
+
move_vector = move_vector.reshape(natom, 3)
|
|
668
|
+
|
|
669
|
+
for i in range(len(optimizer_instances)):
|
|
670
|
+
if print_flag:
|
|
671
|
+
print(f"Optimizer instance {i}: ", optimizer_instances[i])
|
|
672
|
+
if self.newton_tag[i]:
|
|
673
|
+
tmp_hess = optimizer_instances[i].hessian
|
|
674
|
+
tmp_bias_hess = optimizer_instances[i].bias_hessian
|
|
675
|
+
display_eigvals(tmp_hess, tmp_bias_hess, self.element_list, new_geometry)
|
|
676
|
+
if print_flag:
|
|
677
|
+
print("==================================================================================")
|
|
678
|
+
new_geometry *= self.unitval.bohr2angstroms #Bohr -> ang.
|
|
679
|
+
#new_lambda_list : a.u.
|
|
680
|
+
#new_geometry : angstrom
|
|
681
|
+
#move_vector : bohr
|
|
682
|
+
#lambda_movestep : a.u.
|
|
683
|
+
|
|
684
|
+
return new_geometry, np.array(move_vector, dtype="float64"), optimizer_instances
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def display_eigvals(hessian, bias_hessian, element_list, geom):
|
|
689
|
+
|
|
690
|
+
if bias_hessian is not None:
|
|
691
|
+
tmp_hess = hessian
|
|
692
|
+
H = Calculationtools().project_out_hess_tr_and_rot_for_coord(tmp_hess + bias_hessian, element_list, geom, display_eigval=False)
|
|
693
|
+
else:
|
|
694
|
+
tmp_hess = hessian
|
|
695
|
+
H = Calculationtools().project_out_hess_tr_and_rot_for_coord(tmp_hess, element_list, geom, display_eigval=False)
|
|
696
|
+
H = (H + H.T) / 2 # Make sure H is symmetric
|
|
697
|
+
evals, _ = np.linalg.eigh(H)
|
|
698
|
+
|
|
699
|
+
# Filter eigenvalues with absolute value greater than 1e-10
|
|
700
|
+
filtered_evals = evals[np.abs(evals) > 1e-10]
|
|
701
|
+
filtered_evals = np.sort(filtered_evals)
|
|
702
|
+
num_values = len(filtered_evals)
|
|
703
|
+
|
|
704
|
+
print(f"EIGENVALUES (NORMAL COORDINATE, NUMBER OF VALUES: {num_values}):")
|
|
705
|
+
for i in range(0, num_values, 6):
|
|
706
|
+
line = ' '.join(f'{v:12.8f}' for v in filtered_evals[i:i+6])
|
|
707
|
+
print(line)
|
|
708
|
+
|
|
709
|
+
|