mlmm-toolkit 0.2.2.dev0__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.
- hessian_ff/__init__.py +50 -0
- hessian_ff/analytical_hessian.py +609 -0
- hessian_ff/constants.py +46 -0
- hessian_ff/forcefield.py +339 -0
- hessian_ff/loaders.py +608 -0
- hessian_ff/native/Makefile +8 -0
- hessian_ff/native/__init__.py +28 -0
- hessian_ff/native/analytical_hessian.py +88 -0
- hessian_ff/native/analytical_hessian_ext.cpp +258 -0
- hessian_ff/native/bonded.py +82 -0
- hessian_ff/native/bonded_ext.cpp +640 -0
- hessian_ff/native/loader.py +349 -0
- hessian_ff/native/nonbonded.py +118 -0
- hessian_ff/native/nonbonded_ext.cpp +1150 -0
- hessian_ff/prmtop_parmed.py +23 -0
- hessian_ff/system.py +107 -0
- hessian_ff/terms/__init__.py +14 -0
- hessian_ff/terms/angle.py +73 -0
- hessian_ff/terms/bond.py +44 -0
- hessian_ff/terms/cmap.py +406 -0
- hessian_ff/terms/dihedral.py +141 -0
- hessian_ff/terms/nonbonded.py +209 -0
- hessian_ff/tests/__init__.py +0 -0
- hessian_ff/tests/conftest.py +75 -0
- hessian_ff/tests/data/small/complex.parm7 +1346 -0
- hessian_ff/tests/data/small/complex.pdb +125 -0
- hessian_ff/tests/data/small/complex.rst7 +63 -0
- hessian_ff/tests/test_coords_input.py +44 -0
- hessian_ff/tests/test_energy_force.py +49 -0
- hessian_ff/tests/test_hessian.py +137 -0
- hessian_ff/tests/test_smoke.py +18 -0
- hessian_ff/tests/test_validation.py +40 -0
- hessian_ff/workflows.py +889 -0
- mlmm/__init__.py +36 -0
- mlmm/__main__.py +7 -0
- mlmm/_version.py +34 -0
- mlmm/add_elem_info.py +374 -0
- mlmm/advanced_help.py +91 -0
- mlmm/align_freeze_atoms.py +601 -0
- mlmm/all.py +3535 -0
- mlmm/bond_changes.py +231 -0
- mlmm/bool_compat.py +223 -0
- mlmm/cli.py +574 -0
- mlmm/cli_utils.py +166 -0
- mlmm/default_group.py +337 -0
- mlmm/defaults.py +467 -0
- mlmm/define_layer.py +526 -0
- mlmm/dft.py +1041 -0
- mlmm/energy_diagram.py +253 -0
- mlmm/extract.py +2213 -0
- mlmm/fix_altloc.py +464 -0
- mlmm/freq.py +1406 -0
- mlmm/harmonic_constraints.py +140 -0
- mlmm/hessian_cache.py +44 -0
- mlmm/hessian_calc.py +174 -0
- mlmm/irc.py +638 -0
- mlmm/mlmm_calc.py +2262 -0
- mlmm/mm_parm.py +945 -0
- mlmm/oniom_export.py +1983 -0
- mlmm/oniom_import.py +457 -0
- mlmm/opt.py +1742 -0
- mlmm/path_opt.py +1353 -0
- mlmm/path_search.py +2299 -0
- mlmm/preflight.py +88 -0
- mlmm/py.typed +1 -0
- mlmm/pysis_runner.py +45 -0
- mlmm/scan.py +1047 -0
- mlmm/scan2d.py +1226 -0
- mlmm/scan3d.py +1265 -0
- mlmm/scan_common.py +184 -0
- mlmm/summary_log.py +736 -0
- mlmm/trj2fig.py +448 -0
- mlmm/tsopt.py +2871 -0
- mlmm/utils.py +2309 -0
- mlmm/xtb_embedcharge_correction.py +475 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/METADATA +1159 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/RECORD +372 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/WHEEL +5 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/entry_points.txt +2 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/licenses/LICENSE +674 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/top_level.txt +4 -0
- pysisyphus/Geometry.py +1667 -0
- pysisyphus/LICENSE +674 -0
- pysisyphus/TableFormatter.py +63 -0
- pysisyphus/TablePrinter.py +74 -0
- pysisyphus/__init__.py +12 -0
- pysisyphus/calculators/AFIR.py +452 -0
- pysisyphus/calculators/AnaPot.py +20 -0
- pysisyphus/calculators/AnaPot2.py +48 -0
- pysisyphus/calculators/AnaPot3.py +12 -0
- pysisyphus/calculators/AnaPot4.py +20 -0
- pysisyphus/calculators/AnaPotBase.py +337 -0
- pysisyphus/calculators/AnaPotCBM.py +25 -0
- pysisyphus/calculators/AtomAtomTransTorque.py +154 -0
- pysisyphus/calculators/CFOUR.py +250 -0
- pysisyphus/calculators/Calculator.py +844 -0
- pysisyphus/calculators/CerjanMiller.py +24 -0
- pysisyphus/calculators/Composite.py +123 -0
- pysisyphus/calculators/ConicalIntersection.py +171 -0
- pysisyphus/calculators/DFTBp.py +430 -0
- pysisyphus/calculators/DFTD3.py +66 -0
- pysisyphus/calculators/DFTD4.py +84 -0
- pysisyphus/calculators/Dalton.py +61 -0
- pysisyphus/calculators/Dimer.py +681 -0
- pysisyphus/calculators/Dummy.py +20 -0
- pysisyphus/calculators/EGO.py +76 -0
- pysisyphus/calculators/EnergyMin.py +224 -0
- pysisyphus/calculators/ExternalPotential.py +264 -0
- pysisyphus/calculators/FakeASE.py +35 -0
- pysisyphus/calculators/FourWellAnaPot.py +28 -0
- pysisyphus/calculators/FreeEndNEBPot.py +39 -0
- pysisyphus/calculators/Gaussian09.py +18 -0
- pysisyphus/calculators/Gaussian16.py +726 -0
- pysisyphus/calculators/HardSphere.py +159 -0
- pysisyphus/calculators/IDPPCalculator.py +49 -0
- pysisyphus/calculators/IPIClient.py +133 -0
- pysisyphus/calculators/IPIServer.py +234 -0
- pysisyphus/calculators/LEPSBase.py +24 -0
- pysisyphus/calculators/LEPSExpr.py +139 -0
- pysisyphus/calculators/LennardJones.py +80 -0
- pysisyphus/calculators/MOPAC.py +219 -0
- pysisyphus/calculators/MullerBrownSympyPot.py +51 -0
- pysisyphus/calculators/MultiCalc.py +85 -0
- pysisyphus/calculators/NFK.py +45 -0
- pysisyphus/calculators/OBabel.py +87 -0
- pysisyphus/calculators/ONIOMv2.py +1129 -0
- pysisyphus/calculators/ORCA.py +893 -0
- pysisyphus/calculators/ORCA5.py +6 -0
- pysisyphus/calculators/OpenMM.py +88 -0
- pysisyphus/calculators/OpenMolcas.py +281 -0
- pysisyphus/calculators/OverlapCalculator.py +908 -0
- pysisyphus/calculators/Psi4.py +218 -0
- pysisyphus/calculators/PyPsi4.py +37 -0
- pysisyphus/calculators/PySCF.py +341 -0
- pysisyphus/calculators/PyXTB.py +73 -0
- pysisyphus/calculators/QCEngine.py +106 -0
- pysisyphus/calculators/Rastrigin.py +22 -0
- pysisyphus/calculators/Remote.py +76 -0
- pysisyphus/calculators/Rosenbrock.py +15 -0
- pysisyphus/calculators/SocketCalc.py +97 -0
- pysisyphus/calculators/TIP3P.py +111 -0
- pysisyphus/calculators/TransTorque.py +161 -0
- pysisyphus/calculators/Turbomole.py +965 -0
- pysisyphus/calculators/VRIPot.py +37 -0
- pysisyphus/calculators/WFOWrapper.py +333 -0
- pysisyphus/calculators/WFOWrapper2.py +341 -0
- pysisyphus/calculators/XTB.py +418 -0
- pysisyphus/calculators/__init__.py +81 -0
- pysisyphus/calculators/cosmo_data.py +139 -0
- pysisyphus/calculators/parser.py +150 -0
- pysisyphus/color.py +19 -0
- pysisyphus/config.py +133 -0
- pysisyphus/constants.py +65 -0
- pysisyphus/cos/AdaptiveNEB.py +230 -0
- pysisyphus/cos/ChainOfStates.py +725 -0
- pysisyphus/cos/FreeEndNEB.py +25 -0
- pysisyphus/cos/FreezingString.py +103 -0
- pysisyphus/cos/GrowingChainOfStates.py +71 -0
- pysisyphus/cos/GrowingNT.py +309 -0
- pysisyphus/cos/GrowingString.py +508 -0
- pysisyphus/cos/NEB.py +189 -0
- pysisyphus/cos/SimpleZTS.py +64 -0
- pysisyphus/cos/__init__.py +22 -0
- pysisyphus/cos/stiffness.py +199 -0
- pysisyphus/drivers/__init__.py +17 -0
- pysisyphus/drivers/afir.py +855 -0
- pysisyphus/drivers/barriers.py +271 -0
- pysisyphus/drivers/birkholz.py +138 -0
- pysisyphus/drivers/cluster.py +318 -0
- pysisyphus/drivers/diabatization.py +133 -0
- pysisyphus/drivers/merge.py +368 -0
- pysisyphus/drivers/merge_mol2.py +322 -0
- pysisyphus/drivers/opt.py +375 -0
- pysisyphus/drivers/perf.py +91 -0
- pysisyphus/drivers/pka.py +52 -0
- pysisyphus/drivers/precon_pos_rot.py +669 -0
- pysisyphus/drivers/rates.py +480 -0
- pysisyphus/drivers/replace.py +219 -0
- pysisyphus/drivers/scan.py +212 -0
- pysisyphus/drivers/spectrum.py +166 -0
- pysisyphus/drivers/thermo.py +31 -0
- pysisyphus/dynamics/Gaussian.py +103 -0
- pysisyphus/dynamics/__init__.py +20 -0
- pysisyphus/dynamics/colvars.py +136 -0
- pysisyphus/dynamics/driver.py +297 -0
- pysisyphus/dynamics/helpers.py +256 -0
- pysisyphus/dynamics/lincs.py +105 -0
- pysisyphus/dynamics/mdp.py +364 -0
- pysisyphus/dynamics/rattle.py +121 -0
- pysisyphus/dynamics/thermostats.py +128 -0
- pysisyphus/dynamics/wigner.py +266 -0
- pysisyphus/elem_data.py +3473 -0
- pysisyphus/exceptions.py +2 -0
- pysisyphus/filtertrj.py +69 -0
- pysisyphus/helpers.py +623 -0
- pysisyphus/helpers_pure.py +649 -0
- pysisyphus/init_logging.py +50 -0
- pysisyphus/intcoords/Bend.py +69 -0
- pysisyphus/intcoords/Bend2.py +25 -0
- pysisyphus/intcoords/BondedFragment.py +32 -0
- pysisyphus/intcoords/Cartesian.py +41 -0
- pysisyphus/intcoords/CartesianCoords.py +140 -0
- pysisyphus/intcoords/Coords.py +56 -0
- pysisyphus/intcoords/DLC.py +197 -0
- pysisyphus/intcoords/DistanceFunction.py +34 -0
- pysisyphus/intcoords/DummyImproper.py +70 -0
- pysisyphus/intcoords/DummyTorsion.py +72 -0
- pysisyphus/intcoords/LinearBend.py +105 -0
- pysisyphus/intcoords/LinearDisplacement.py +80 -0
- pysisyphus/intcoords/OutOfPlane.py +59 -0
- pysisyphus/intcoords/PrimTypes.py +286 -0
- pysisyphus/intcoords/Primitive.py +137 -0
- pysisyphus/intcoords/RedundantCoords.py +659 -0
- pysisyphus/intcoords/RobustTorsion.py +59 -0
- pysisyphus/intcoords/Rotation.py +147 -0
- pysisyphus/intcoords/Stretch.py +31 -0
- pysisyphus/intcoords/Torsion.py +101 -0
- pysisyphus/intcoords/Torsion2.py +25 -0
- pysisyphus/intcoords/Translation.py +45 -0
- pysisyphus/intcoords/__init__.py +61 -0
- pysisyphus/intcoords/augment_bonds.py +126 -0
- pysisyphus/intcoords/derivatives.py +10512 -0
- pysisyphus/intcoords/eval.py +80 -0
- pysisyphus/intcoords/exceptions.py +37 -0
- pysisyphus/intcoords/findiffs.py +48 -0
- pysisyphus/intcoords/generate_derivatives.py +414 -0
- pysisyphus/intcoords/helpers.py +235 -0
- pysisyphus/intcoords/logging_conf.py +10 -0
- pysisyphus/intcoords/mp_derivatives.py +10836 -0
- pysisyphus/intcoords/setup.py +962 -0
- pysisyphus/intcoords/setup_fast.py +176 -0
- pysisyphus/intcoords/update.py +272 -0
- pysisyphus/intcoords/valid.py +89 -0
- pysisyphus/interpolate/Geodesic.py +93 -0
- pysisyphus/interpolate/IDPP.py +55 -0
- pysisyphus/interpolate/Interpolator.py +116 -0
- pysisyphus/interpolate/LST.py +70 -0
- pysisyphus/interpolate/Redund.py +152 -0
- pysisyphus/interpolate/__init__.py +9 -0
- pysisyphus/interpolate/helpers.py +34 -0
- pysisyphus/io/__init__.py +22 -0
- pysisyphus/io/aomix.py +178 -0
- pysisyphus/io/cjson.py +24 -0
- pysisyphus/io/crd.py +101 -0
- pysisyphus/io/cube.py +220 -0
- pysisyphus/io/fchk.py +184 -0
- pysisyphus/io/hdf5.py +49 -0
- pysisyphus/io/hessian.py +72 -0
- pysisyphus/io/mol2.py +146 -0
- pysisyphus/io/molden.py +293 -0
- pysisyphus/io/orca.py +189 -0
- pysisyphus/io/pdb.py +269 -0
- pysisyphus/io/psf.py +79 -0
- pysisyphus/io/pubchem.py +31 -0
- pysisyphus/io/qcschema.py +34 -0
- pysisyphus/io/sdf.py +29 -0
- pysisyphus/io/xyz.py +61 -0
- pysisyphus/io/zmat.py +175 -0
- pysisyphus/irc/DWI.py +108 -0
- pysisyphus/irc/DampedVelocityVerlet.py +134 -0
- pysisyphus/irc/Euler.py +22 -0
- pysisyphus/irc/EulerPC.py +345 -0
- pysisyphus/irc/GonzalezSchlegel.py +187 -0
- pysisyphus/irc/IMKMod.py +164 -0
- pysisyphus/irc/IRC.py +878 -0
- pysisyphus/irc/IRCDummy.py +10 -0
- pysisyphus/irc/Instanton.py +307 -0
- pysisyphus/irc/LQA.py +53 -0
- pysisyphus/irc/ModeKill.py +136 -0
- pysisyphus/irc/ParamPlot.py +53 -0
- pysisyphus/irc/RK4.py +36 -0
- pysisyphus/irc/__init__.py +31 -0
- pysisyphus/irc/initial_displ.py +219 -0
- pysisyphus/linalg.py +411 -0
- pysisyphus/line_searches/Backtracking.py +88 -0
- pysisyphus/line_searches/HagerZhang.py +184 -0
- pysisyphus/line_searches/LineSearch.py +232 -0
- pysisyphus/line_searches/StrongWolfe.py +108 -0
- pysisyphus/line_searches/__init__.py +9 -0
- pysisyphus/line_searches/interpol.py +15 -0
- pysisyphus/modefollow/NormalMode.py +40 -0
- pysisyphus/modefollow/__init__.py +10 -0
- pysisyphus/modefollow/davidson.py +199 -0
- pysisyphus/modefollow/lanczos.py +95 -0
- pysisyphus/optimizers/BFGS.py +99 -0
- pysisyphus/optimizers/BacktrackingOptimizer.py +113 -0
- pysisyphus/optimizers/ConjugateGradient.py +98 -0
- pysisyphus/optimizers/CubicNewton.py +75 -0
- pysisyphus/optimizers/FIRE.py +113 -0
- pysisyphus/optimizers/HessianOptimizer.py +1176 -0
- pysisyphus/optimizers/LBFGS.py +228 -0
- pysisyphus/optimizers/LayerOpt.py +411 -0
- pysisyphus/optimizers/MicroOptimizer.py +169 -0
- pysisyphus/optimizers/NCOptimizer.py +90 -0
- pysisyphus/optimizers/Optimizer.py +1084 -0
- pysisyphus/optimizers/PreconLBFGS.py +260 -0
- pysisyphus/optimizers/PreconSteepestDescent.py +7 -0
- pysisyphus/optimizers/QuickMin.py +74 -0
- pysisyphus/optimizers/RFOptimizer.py +181 -0
- pysisyphus/optimizers/RSA.py +99 -0
- pysisyphus/optimizers/StabilizedQNMethod.py +248 -0
- pysisyphus/optimizers/SteepestDescent.py +23 -0
- pysisyphus/optimizers/StringOptimizer.py +173 -0
- pysisyphus/optimizers/__init__.py +41 -0
- pysisyphus/optimizers/closures.py +301 -0
- pysisyphus/optimizers/cls_map.py +58 -0
- pysisyphus/optimizers/exceptions.py +6 -0
- pysisyphus/optimizers/gdiis.py +280 -0
- pysisyphus/optimizers/guess_hessians.py +311 -0
- pysisyphus/optimizers/hessian_updates.py +355 -0
- pysisyphus/optimizers/poly_fit.py +285 -0
- pysisyphus/optimizers/precon.py +153 -0
- pysisyphus/optimizers/restrict_step.py +24 -0
- pysisyphus/pack.py +172 -0
- pysisyphus/peakdetect.py +948 -0
- pysisyphus/plot.py +1031 -0
- pysisyphus/run.py +2106 -0
- pysisyphus/socket_helper.py +74 -0
- pysisyphus/stocastic/FragmentKick.py +132 -0
- pysisyphus/stocastic/Kick.py +81 -0
- pysisyphus/stocastic/Pipeline.py +303 -0
- pysisyphus/stocastic/__init__.py +21 -0
- pysisyphus/stocastic/align.py +127 -0
- pysisyphus/testing.py +96 -0
- pysisyphus/thermo.py +156 -0
- pysisyphus/trj.py +824 -0
- pysisyphus/tsoptimizers/RSIRFOptimizer.py +56 -0
- pysisyphus/tsoptimizers/RSPRFOptimizer.py +182 -0
- pysisyphus/tsoptimizers/TRIM.py +59 -0
- pysisyphus/tsoptimizers/TSHessianOptimizer.py +463 -0
- pysisyphus/tsoptimizers/__init__.py +23 -0
- pysisyphus/wavefunction/Basis.py +239 -0
- pysisyphus/wavefunction/DIIS.py +76 -0
- pysisyphus/wavefunction/__init__.py +25 -0
- pysisyphus/wavefunction/build_ext.py +42 -0
- pysisyphus/wavefunction/cart2sph.py +190 -0
- pysisyphus/wavefunction/diabatization.py +304 -0
- pysisyphus/wavefunction/excited_states.py +435 -0
- pysisyphus/wavefunction/gen_ints.py +1811 -0
- pysisyphus/wavefunction/helpers.py +104 -0
- pysisyphus/wavefunction/ints/__init__.py +0 -0
- pysisyphus/wavefunction/ints/boys.py +193 -0
- pysisyphus/wavefunction/ints/boys_table_N_64_xasym_27.1_step_0.01.npy +0 -0
- pysisyphus/wavefunction/ints/cart_gto3d.py +176 -0
- pysisyphus/wavefunction/ints/coulomb3d.py +25928 -0
- pysisyphus/wavefunction/ints/diag_quadrupole3d.py +10036 -0
- pysisyphus/wavefunction/ints/dipole3d.py +8762 -0
- pysisyphus/wavefunction/ints/int2c2e3d.py +7198 -0
- pysisyphus/wavefunction/ints/int3c2e3d_sph.py +65040 -0
- pysisyphus/wavefunction/ints/kinetic3d.py +8240 -0
- pysisyphus/wavefunction/ints/ovlp3d.py +3777 -0
- pysisyphus/wavefunction/ints/quadrupole3d.py +15054 -0
- pysisyphus/wavefunction/ints/self_ovlp3d.py +198 -0
- pysisyphus/wavefunction/localization.py +458 -0
- pysisyphus/wavefunction/multipole.py +159 -0
- pysisyphus/wavefunction/normalization.py +36 -0
- pysisyphus/wavefunction/pop_analysis.py +134 -0
- pysisyphus/wavefunction/shells.py +1171 -0
- pysisyphus/wavefunction/wavefunction.py +504 -0
- pysisyphus/wrapper/__init__.py +11 -0
- pysisyphus/wrapper/exceptions.py +2 -0
- pysisyphus/wrapper/jmol.py +120 -0
- pysisyphus/wrapper/mwfn.py +169 -0
- pysisyphus/wrapper/packmol.py +71 -0
- pysisyphus/xyzloader.py +168 -0
- pysisyphus/yaml_mods.py +45 -0
- thermoanalysis/LICENSE +674 -0
- thermoanalysis/QCData.py +244 -0
- thermoanalysis/__init__.py +0 -0
- thermoanalysis/config.py +3 -0
- thermoanalysis/constants.py +20 -0
- thermoanalysis/thermo.py +1011 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Molecular integrals over Gaussian basis functions generated by sympleints.
|
|
3
|
+
See https://github.com/eljost/sympleints for more information.
|
|
4
|
+
|
|
5
|
+
sympleints version: 0.1.dev79+g63f1ef8.d20230515
|
|
6
|
+
symppy version: 1.10.1
|
|
7
|
+
|
|
8
|
+
sympleints was executed with the following arguments:
|
|
9
|
+
lmax = 4
|
|
10
|
+
lauxmax = 6
|
|
11
|
+
write = False
|
|
12
|
+
out_dir = devel_ints
|
|
13
|
+
keys = ['~2c2e', '~3c2e_sph']
|
|
14
|
+
sph = False
|
|
15
|
+
opt_basic = True
|
|
16
|
+
normalize = cgto
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import numpy
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def self_ovlp3d_00(ax, da, A, bx, db, B):
|
|
23
|
+
"""Cartesian 3D (ss) self overlap.
|
|
24
|
+
|
|
25
|
+
Generated code; DO NOT modify by hand!"""
|
|
26
|
+
|
|
27
|
+
result = numpy.zeros((1, 1), dtype=float)
|
|
28
|
+
|
|
29
|
+
x0 = (ax + bx) ** (-1.0)
|
|
30
|
+
|
|
31
|
+
# 1 item(s)
|
|
32
|
+
result[0, 0] = numpy.sum(5.568327996831708 * da * db * x0**1.5)
|
|
33
|
+
return result
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def self_ovlp3d_11(ax, da, A, bx, db, B):
|
|
37
|
+
"""Cartesian 3D (pp) self overlap.
|
|
38
|
+
|
|
39
|
+
Generated code; DO NOT modify by hand!"""
|
|
40
|
+
|
|
41
|
+
result = numpy.zeros((3, 3), dtype=float)
|
|
42
|
+
|
|
43
|
+
x0 = ax + bx
|
|
44
|
+
x1 = 2.784163998415854 * da * db * numpy.sqrt(x0 ** (-1.0)) / x0**2
|
|
45
|
+
|
|
46
|
+
# 3 item(s)
|
|
47
|
+
result[0, 0] = numpy.sum(x1)
|
|
48
|
+
result[0, 1] = numpy.sum(x1)
|
|
49
|
+
result[0, 2] = numpy.sum(x1)
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def self_ovlp3d_22(ax, da, A, bx, db, B):
|
|
54
|
+
"""Cartesian 3D (dd) self overlap.
|
|
55
|
+
|
|
56
|
+
Generated code; DO NOT modify by hand!"""
|
|
57
|
+
|
|
58
|
+
result = numpy.zeros((6, 6), dtype=float)
|
|
59
|
+
|
|
60
|
+
x0 = ax + bx
|
|
61
|
+
x1 = x0 ** (-1.0)
|
|
62
|
+
x2 = 1.392081999207927 * da * db
|
|
63
|
+
x3 = numpy.sqrt(x1) * x2 / x0**3
|
|
64
|
+
x4 = x1**1.5 * x2 / x0**2
|
|
65
|
+
|
|
66
|
+
# 6 item(s)
|
|
67
|
+
result[0, 0] = numpy.sum(x3)
|
|
68
|
+
result[0, 1] = numpy.sum(x4)
|
|
69
|
+
result[0, 2] = numpy.sum(x4)
|
|
70
|
+
result[0, 3] = numpy.sum(x3)
|
|
71
|
+
result[0, 4] = numpy.sum(x4)
|
|
72
|
+
result[0, 5] = numpy.sum(x3)
|
|
73
|
+
return result
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def self_ovlp3d_33(ax, da, A, bx, db, B):
|
|
77
|
+
"""Cartesian 3D (ff) self overlap.
|
|
78
|
+
|
|
79
|
+
Generated code; DO NOT modify by hand!"""
|
|
80
|
+
|
|
81
|
+
result = numpy.zeros((10, 10), dtype=float)
|
|
82
|
+
|
|
83
|
+
x0 = ax + bx
|
|
84
|
+
x1 = x0 ** (-1.0)
|
|
85
|
+
x2 = 0.6960409996039635 * da * db
|
|
86
|
+
x3 = numpy.sqrt(x1) * x2 / x0**4
|
|
87
|
+
x4 = x1**1.5 * x2 / x0**3
|
|
88
|
+
|
|
89
|
+
# 10 item(s)
|
|
90
|
+
result[0, 0] = numpy.sum(x3)
|
|
91
|
+
result[0, 1] = numpy.sum(x4)
|
|
92
|
+
result[0, 2] = numpy.sum(x4)
|
|
93
|
+
result[0, 3] = numpy.sum(x4)
|
|
94
|
+
result[0, 4] = numpy.sum(x4)
|
|
95
|
+
result[0, 5] = numpy.sum(x4)
|
|
96
|
+
result[0, 6] = numpy.sum(x3)
|
|
97
|
+
result[0, 7] = numpy.sum(x4)
|
|
98
|
+
result[0, 8] = numpy.sum(x4)
|
|
99
|
+
result[0, 9] = numpy.sum(x3)
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def self_ovlp3d_44(ax, da, A, bx, db, B):
|
|
104
|
+
"""Cartesian 3D (gg) self overlap.
|
|
105
|
+
|
|
106
|
+
Generated code; DO NOT modify by hand!"""
|
|
107
|
+
|
|
108
|
+
result = numpy.zeros((15, 15), dtype=float)
|
|
109
|
+
|
|
110
|
+
x0 = 0.5 / (ax + bx)
|
|
111
|
+
x1 = (ax + bx) ** (-1.0)
|
|
112
|
+
x2 = (x1 * (ax + bx) - 1.0) * A[0]
|
|
113
|
+
x3 = 1.772453850905516 * numpy.sqrt(x1)
|
|
114
|
+
x4 = x2**2 * x3
|
|
115
|
+
x5 = x0 * x3
|
|
116
|
+
x6 = 3.0 * x5
|
|
117
|
+
x7 = x0 * (3.0 * x4 + x6)
|
|
118
|
+
x8 = x4 + x5
|
|
119
|
+
x9 = x2 * x8
|
|
120
|
+
x10 = x2 * x5
|
|
121
|
+
x11 = x2 * (2.0 * x10 + x9)
|
|
122
|
+
x12 = 5.0 * x0 * (x11 + x7)
|
|
123
|
+
x13 = 4.0 * x0 * (2.0 * x10 + x9)
|
|
124
|
+
x14 = x11 + x7
|
|
125
|
+
x15 = x14 * x2
|
|
126
|
+
x16 = x2 * (x13 + x15)
|
|
127
|
+
x17 = x12 + x16
|
|
128
|
+
x18 = da * db
|
|
129
|
+
x19 = 0.02991993003418851 * x1 * x18
|
|
130
|
+
x20 = (x1 * (ax + bx) - 1.0) * A[1]
|
|
131
|
+
x21 = x20**2 * x3
|
|
132
|
+
x22 = x21 + x5
|
|
133
|
+
x23 = x18 * x22
|
|
134
|
+
x24 = 0.06666666666666667 * x3
|
|
135
|
+
x25 = x17 * x24
|
|
136
|
+
x26 = (x1 * (ax + bx) - 1.0) * A[2]
|
|
137
|
+
x27 = x26**2 * x3
|
|
138
|
+
x28 = x27 + x5
|
|
139
|
+
x29 = x18 * x28
|
|
140
|
+
x30 = x0 * (3.0 * x21 + x6)
|
|
141
|
+
x31 = x20 * x22
|
|
142
|
+
x32 = 2.0 * x5
|
|
143
|
+
x33 = x20 * (x20 * x32 + x31)
|
|
144
|
+
x34 = x30 + x33
|
|
145
|
+
x35 = x18 * x34
|
|
146
|
+
x36 = 0.1111111111111111 * x14 * x3
|
|
147
|
+
x37 = 0.3333333333333333 * x28
|
|
148
|
+
x38 = x0 * (3.0 * x27 + x6)
|
|
149
|
+
x39 = x26 * x28
|
|
150
|
+
x40 = x26 * (x26 * x32 + x39)
|
|
151
|
+
x41 = x38 + x40
|
|
152
|
+
x42 = 5.0 * x0 * (x30 + x33)
|
|
153
|
+
x43 = 8.0 * x5
|
|
154
|
+
x44 = x0 * (x20 * x43 + 4.0 * x31)
|
|
155
|
+
x45 = x20 * x34
|
|
156
|
+
x46 = x20 * (x44 + x45)
|
|
157
|
+
x47 = x42 + x46
|
|
158
|
+
x48 = x24 * x47
|
|
159
|
+
x49 = x18 * x8
|
|
160
|
+
x50 = 5.0 * x0 * (x38 + x40)
|
|
161
|
+
x51 = x0 * (x26 * x43 + 4.0 * x39)
|
|
162
|
+
x52 = x26 * x41
|
|
163
|
+
x53 = x26 * (x51 + x52)
|
|
164
|
+
x54 = x50 + x53
|
|
165
|
+
x55 = x24 * x54
|
|
166
|
+
|
|
167
|
+
# 15 item(s)
|
|
168
|
+
result[0, 0] = numpy.sum(
|
|
169
|
+
x19 * (7.0 * x0 * (x12 + x16) + x2 * (6.0 * x0 * (x13 + x15) + x17 * x2))
|
|
170
|
+
)
|
|
171
|
+
result[0, 1] = numpy.sum(x23 * x25)
|
|
172
|
+
result[0, 2] = numpy.sum(x25 * x29)
|
|
173
|
+
result[0, 3] = numpy.sum(x35 * x36)
|
|
174
|
+
result[0, 4] = numpy.sum(x14 * x23 * x37)
|
|
175
|
+
result[0, 5] = numpy.sum(x18 * x36 * x41)
|
|
176
|
+
result[0, 6] = numpy.sum(x48 * x49)
|
|
177
|
+
result[0, 7] = numpy.sum(x35 * x37 * x8)
|
|
178
|
+
result[0, 8] = numpy.sum(0.3333333333333333 * x23 * x41 * x8)
|
|
179
|
+
result[0, 9] = numpy.sum(x49 * x55)
|
|
180
|
+
result[0, 10] = numpy.sum(
|
|
181
|
+
x19 * (7.0 * x0 * (x42 + x46) + x20 * (6.0 * x0 * (x44 + x45) + x20 * x47))
|
|
182
|
+
)
|
|
183
|
+
result[0, 11] = numpy.sum(x29 * x48)
|
|
184
|
+
result[0, 12] = numpy.sum(0.1111111111111111 * x3 * x35 * x41)
|
|
185
|
+
result[0, 13] = numpy.sum(x23 * x55)
|
|
186
|
+
result[0, 14] = numpy.sum(
|
|
187
|
+
x19 * (7.0 * x0 * (x50 + x53) + x26 * (6.0 * x0 * (x51 + x52) + x26 * x54))
|
|
188
|
+
)
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
self_ovlp3d = {
|
|
193
|
+
(0, 0): self_ovlp3d_00,
|
|
194
|
+
(1, 1): self_ovlp3d_11,
|
|
195
|
+
(2, 2): self_ovlp3d_22,
|
|
196
|
+
(3, 3): self_ovlp3d_33,
|
|
197
|
+
(4, 4): self_ovlp3d_44,
|
|
198
|
+
}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# [1] https://doi.org/10.1002/jcc.540140615
|
|
2
|
+
# Comparison of the Boys and Pipek–Mezey localizations in the local
|
|
3
|
+
# correlation approach and automatic virtual basis selection
|
|
4
|
+
# Boughton, Pulay, 1993
|
|
5
|
+
# [2] https://doi.org/10.1063/1.2360264
|
|
6
|
+
# Fast noniterative orbital localization for large molecules
|
|
7
|
+
# Aquilante, Pedersen, 2006
|
|
8
|
+
# [3] https://doi.org/10.1063/1.3042233
|
|
9
|
+
# Constructing diabatic states from adiabatic states: Extending
|
|
10
|
+
# generalized Mulliken–Hush to multiple charge centers with Boys localization
|
|
11
|
+
# Subotnik, Yeganeh, Cave, Ratner, 2008
|
|
12
|
+
# [4] https://doi.org/10.1063/1.1681683
|
|
13
|
+
# Localized molecular orbitals for polyatomic molecules.
|
|
14
|
+
# I. A comparison of the Edmiston‐Ruedenberg and Boys localization methods
|
|
15
|
+
# Kleier, Halgren, Hall Jr., Lipscomb, 1974
|
|
16
|
+
# [5] https://doi.org/10.1063/1.4894472
|
|
17
|
+
# Diabatization based on the dipole and quadrupole: The DQ method
|
|
18
|
+
# Hoyer, Xu, Ma, Gagliardi, Truhlar, 2014
|
|
19
|
+
# [6] https://pubs.acs.org/doi/pdf/10.1021/acs.jctc.2c00261
|
|
20
|
+
# Implementation of Occupied and Virtual Edmiston−Ruedenberg
|
|
21
|
+
# Orbitals Using Cholesky Decomposed Integrals
|
|
22
|
+
# [7] https://doi.org/10.1063/1.1790971
|
|
23
|
+
# An efficient method for calculating maxima of homogeneous
|
|
24
|
+
# functions of orthogonal matrices: Applications to localized
|
|
25
|
+
# occupied orbitals
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
from functools import singledispatch
|
|
30
|
+
import itertools as it
|
|
31
|
+
from typing import Callable, Optional
|
|
32
|
+
import warnings
|
|
33
|
+
|
|
34
|
+
import numpy as np
|
|
35
|
+
from numpy.typing import NDArray
|
|
36
|
+
|
|
37
|
+
from pysisyphus.helpers_pure import rms
|
|
38
|
+
from pysisyphus.linalg import matrix_power, pivoted_cholesky
|
|
39
|
+
from pysisyphus.wavefunction import logger, Wavefunction
|
|
40
|
+
from pysisyphus.wavefunction.DIIS import DIIS
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
PI_QUART = np.pi / 4
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@singledispatch
|
|
47
|
+
def cholesky(C: NDArray[float]):
|
|
48
|
+
"""Localization via pivoted Cholesky factorization.
|
|
49
|
+
|
|
50
|
+
See [2].
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
C
|
|
55
|
+
Matrix of molecular orbital coefficients to be localized.
|
|
56
|
+
Shape is (naos, nmos).
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
C_loc
|
|
61
|
+
Localized molecular orbital coefficient matrix of shape (naos, nmos).
|
|
62
|
+
"""
|
|
63
|
+
naos, nmos = C.shape
|
|
64
|
+
|
|
65
|
+
# We can't use scipy's builtin Cholesky-factorization, as it does not
|
|
66
|
+
# support positive semi-definite matrices.
|
|
67
|
+
L, piv, _ = pivoted_cholesky(C @ C.T)
|
|
68
|
+
# Restore original ordering via permutation matrix.
|
|
69
|
+
P = np.zeros((naos, naos))
|
|
70
|
+
P[piv, np.arange(naos)] = 1
|
|
71
|
+
C_loc = P @ L[:, :nmos]
|
|
72
|
+
return C_loc
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@cholesky.register
|
|
76
|
+
def _(wf: Wavefunction):
|
|
77
|
+
"""Currently localizes only C_(α,occ) MOs."""
|
|
78
|
+
Cao, _ = wf.C_occ
|
|
79
|
+
return cholesky(Cao)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def rot_inplace(mat, rad, i, j):
|
|
83
|
+
"""Inplace rotation of matrix columns mat[:, i] and mat[:, j] by 'rad' radians."""
|
|
84
|
+
cos = np.cos(rad)
|
|
85
|
+
sin = np.sin(rad)
|
|
86
|
+
i_rot = cos * mat[:, i] + sin * mat[:, j]
|
|
87
|
+
j_rot = -sin * mat[:, i] + cos * mat[:, j]
|
|
88
|
+
mat[:, i] = i_rot
|
|
89
|
+
mat[:, j] = j_rot
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class JacobiSweepResult:
|
|
94
|
+
is_converged: bool
|
|
95
|
+
cur_cycle: int
|
|
96
|
+
C: NDArray[float]
|
|
97
|
+
P: float
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def jacobi_sweeps(
|
|
101
|
+
C: NDArray[float],
|
|
102
|
+
cost_func: Callable,
|
|
103
|
+
ab_func: Callable,
|
|
104
|
+
callback: Optional[Callable] = None,
|
|
105
|
+
max_cycles: int = 100,
|
|
106
|
+
dP_thresh: float = 1e-8,
|
|
107
|
+
) -> JacobiSweepResult:
|
|
108
|
+
"""Wrapper for 2x2 Jacobi-sweeps as used in localization/diabatization.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
C
|
|
113
|
+
MO coefficient matrix (shape naos x nmos) or rotation matrix (nstates x nstates).
|
|
114
|
+
cost_func
|
|
115
|
+
Function to be maximized/minimized.
|
|
116
|
+
ab_func
|
|
117
|
+
Function that returns A & B values, used to calculate the angle
|
|
118
|
+
for the 2x2 rotation.
|
|
119
|
+
callback
|
|
120
|
+
Function that is called after the 2x2 rotation took place. It takes three arguments:
|
|
121
|
+
(gamma, j, k).
|
|
122
|
+
max_cycles
|
|
123
|
+
Maximum number of macro cycles.
|
|
124
|
+
dP_thresh
|
|
125
|
+
Indicate convergence when change in cost function is equal or below
|
|
126
|
+
this threshold.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
C_loc
|
|
131
|
+
Localized molecular orbital coefficient matrix of shape (naos, nmos).
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
assert max_cycles > 0
|
|
135
|
+
C = C.copy()
|
|
136
|
+
_, nmos = C.shape
|
|
137
|
+
|
|
138
|
+
if callback is None:
|
|
139
|
+
callback = lambda *args: None
|
|
140
|
+
|
|
141
|
+
P_prev = 0.0
|
|
142
|
+
|
|
143
|
+
logger.info(f"Starting Jacobi sweeps.")
|
|
144
|
+
for i in range(max_cycles):
|
|
145
|
+
# Loop over pairs of MO indices and do 2x2 rotations.
|
|
146
|
+
for j, k in it.combinations(range(nmos), 2):
|
|
147
|
+
A, B = ab_func(j, k, C)
|
|
148
|
+
|
|
149
|
+
if (A**2 + B**2) <= 1e-12:
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
gamma = np.sign(B) * np.arccos(-A / np.sqrt(A**2 + B**2)) / 4
|
|
153
|
+
assert -PI_QUART <= gamma <= PI_QUART
|
|
154
|
+
# 2x2 MO rotations
|
|
155
|
+
rot_inplace(C, gamma, j, k)
|
|
156
|
+
callback(gamma, j, k)
|
|
157
|
+
# Outside of loop over orbital pairs
|
|
158
|
+
|
|
159
|
+
# Calculate the target cost function we want to maximize/minimize.
|
|
160
|
+
P = cost_func(C)
|
|
161
|
+
dP = P - P_prev
|
|
162
|
+
logger.info(f"{i:03d}: {P=: >12.8f} {dP=: >12.8f}")
|
|
163
|
+
if is_converged := (dP <= dP_thresh):
|
|
164
|
+
logger.info(f"Jacobi sweeps converged in {i+1} cycles.")
|
|
165
|
+
break
|
|
166
|
+
P_prev = P
|
|
167
|
+
# Outside macro cycles
|
|
168
|
+
|
|
169
|
+
result = JacobiSweepResult(
|
|
170
|
+
is_converged=is_converged,
|
|
171
|
+
cur_cycle=i,
|
|
172
|
+
C=C,
|
|
173
|
+
P=P,
|
|
174
|
+
)
|
|
175
|
+
return result
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@singledispatch
|
|
179
|
+
def pipek_mezey(C, S, ao_center_map, **kwargs) -> JacobiSweepResult:
|
|
180
|
+
"""Pipek-Mezey localization using Mulliken population analysis.
|
|
181
|
+
|
|
182
|
+
Python adaption of code found in orbloc.f90 of Multiwfn 3.8.
|
|
183
|
+
For now, only Mulliken population and localization exponent 2 is supported.
|
|
184
|
+
|
|
185
|
+
Parameters
|
|
186
|
+
----------
|
|
187
|
+
C
|
|
188
|
+
Matrix of molecular orbital coefficients to be localized.
|
|
189
|
+
Shape is (naos, nmos).
|
|
190
|
+
S
|
|
191
|
+
Overlap matrix of shape (naos x naos).
|
|
192
|
+
ao_center_map
|
|
193
|
+
Mapping between atom indices and AOs, centered at the respective atom.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
C_loc
|
|
198
|
+
Localized molecular orbital coefficient matrix of shape (naos, nmos).
|
|
199
|
+
"""
|
|
200
|
+
_, nmos = C.shape
|
|
201
|
+
centers = list(ao_center_map.keys())
|
|
202
|
+
|
|
203
|
+
SC = S @ C
|
|
204
|
+
|
|
205
|
+
def ab_func(j, k, C):
|
|
206
|
+
Q = SC * C
|
|
207
|
+
A = 0.0
|
|
208
|
+
B = 0.0
|
|
209
|
+
# Eq. (9) in [1]
|
|
210
|
+
for center in centers:
|
|
211
|
+
ao_inds = ao_center_map[center]
|
|
212
|
+
Qjk = (
|
|
213
|
+
C[ao_inds, j] * SC[ao_inds, k] + C[ao_inds, k] * SC[ao_inds, j]
|
|
214
|
+
).sum() / 2
|
|
215
|
+
Qjj = Q[ao_inds, j].sum()
|
|
216
|
+
Qkk = Q[ao_inds, k].sum()
|
|
217
|
+
A += (Qjk**2) - ((Qjj - Qkk) ** 2) / 4
|
|
218
|
+
B += Qjk * (Qjj - Qkk)
|
|
219
|
+
return A, B
|
|
220
|
+
|
|
221
|
+
def callback(gamma, j, k):
|
|
222
|
+
# The MO rotations invalidate the SC matrix product. We update it too.
|
|
223
|
+
rot_inplace(SC, gamma, j, k)
|
|
224
|
+
|
|
225
|
+
def cost_func(C):
|
|
226
|
+
# We wan't to maximize P and we monitor the progress. Eq. (8) in [1].
|
|
227
|
+
P = 0.0
|
|
228
|
+
for l in range(nmos):
|
|
229
|
+
for center in centers:
|
|
230
|
+
ao_inds = ao_center_map[center]
|
|
231
|
+
Q = (C[ao_inds, l][:, None] * C[:, l] * S[ao_inds, :]).sum()
|
|
232
|
+
P += Q**2
|
|
233
|
+
return P
|
|
234
|
+
|
|
235
|
+
logger.info("Pipek-Mezey localization")
|
|
236
|
+
return jacobi_sweeps(C, cost_func, ab_func, callback, **kwargs)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@pipek_mezey.register
|
|
240
|
+
def _(wf: Wavefunction) -> JacobiSweepResult:
|
|
241
|
+
"""Currently localizes only C_(α,occ) MOs."""
|
|
242
|
+
S = wf.S
|
|
243
|
+
Cao, _ = wf.C_occ
|
|
244
|
+
C_chol_loc = cholesky(Cao)
|
|
245
|
+
return pipek_mezey(C_chol_loc, S, wf.ao_center_map)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def get_fb_contract(moments_ints):
|
|
249
|
+
def contract(mo_j, mo_k):
|
|
250
|
+
return np.einsum(
|
|
251
|
+
"xkl,k,l->x",
|
|
252
|
+
moments_ints,
|
|
253
|
+
mo_j,
|
|
254
|
+
mo_k,
|
|
255
|
+
optimize=["einsum_path", (0, 1), (0, 1)],
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return contract
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def get_fb_ab_func(moments_ints):
|
|
262
|
+
contract = get_fb_contract(moments_ints)
|
|
263
|
+
|
|
264
|
+
def ab_func(j, k, C):
|
|
265
|
+
mo_j = C[:, j]
|
|
266
|
+
mo_k = C[:, k]
|
|
267
|
+
jrj = contract(mo_j, mo_j)
|
|
268
|
+
jrk = contract(mo_j, mo_k)
|
|
269
|
+
krk = contract(mo_k, mo_k)
|
|
270
|
+
A = (jrk**2).sum() - ((jrj - krk) ** 2).sum() / 4 # Eq. (9) in [4]
|
|
271
|
+
B = ((jrj - krk) * jrk).sum() # Eq. (10) in [4]
|
|
272
|
+
return A, B
|
|
273
|
+
|
|
274
|
+
return ab_func
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def get_fb_cost_func(moments_ints):
|
|
278
|
+
def cost_func(C):
|
|
279
|
+
vals = np.einsum(
|
|
280
|
+
"xkl,ki,li->ix",
|
|
281
|
+
moments_ints,
|
|
282
|
+
C,
|
|
283
|
+
C,
|
|
284
|
+
optimize=["einsum_path", (0, 1), (0, 1)],
|
|
285
|
+
)
|
|
286
|
+
val = ((vals[:, None, :] - vals) ** 2).sum()
|
|
287
|
+
return val
|
|
288
|
+
|
|
289
|
+
return cost_func
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
@singledispatch
|
|
293
|
+
def foster_boys(
|
|
294
|
+
C: NDArray[float], dip_ints: NDArray[float], **kwargs
|
|
295
|
+
) -> JacobiSweepResult:
|
|
296
|
+
"""Foster-Boys localization.
|
|
297
|
+
|
|
298
|
+
nMO nMO
|
|
299
|
+
___ ___
|
|
300
|
+
╲ ╲ 2
|
|
301
|
+
╲ ╲ | |
|
|
302
|
+
╱ ╱ | <i|R|i> - <j|R|j> |
|
|
303
|
+
╱ ╱ | |
|
|
304
|
+
‾‾‾ ‾‾‾
|
|
305
|
+
i = 1 j = 1
|
|
306
|
+
|
|
307
|
+
or similarily (see eq. (6) in [4] or the appendix of [5])
|
|
308
|
+
|
|
309
|
+
nMO
|
|
310
|
+
___
|
|
311
|
+
╲ 2
|
|
312
|
+
╲ | |
|
|
313
|
+
╱ | <i|R|i> |
|
|
314
|
+
╱ | |
|
|
315
|
+
‾‾‾
|
|
316
|
+
i = 1
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
dip_ints
|
|
321
|
+
Dipole moment integral matrices with shape (3, naos, naos).
|
|
322
|
+
C
|
|
323
|
+
Matrix of molecular orbital coefficients to be localized.
|
|
324
|
+
Shape is (naos, nmos).
|
|
325
|
+
kwargs
|
|
326
|
+
Additional keyword arguments that are passed jacobi_sweeps.
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
-------
|
|
330
|
+
C_loc
|
|
331
|
+
Localized molecular orbital coefficient matrix of shape (naos, nmos).
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
ab_func = get_fb_ab_func(dip_ints)
|
|
335
|
+
cost_func = get_fb_cost_func(dip_ints)
|
|
336
|
+
logger.info("Foster-Boys localization")
|
|
337
|
+
return jacobi_sweeps(C, cost_func, ab_func, **kwargs)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
@foster_boys.register
|
|
341
|
+
def _(wf: Wavefunction) -> JacobiSweepResult:
|
|
342
|
+
"""Currently localizes only C_(α,occ) MOs."""
|
|
343
|
+
Cao, _ = wf.C_occ
|
|
344
|
+
dip_ints = wf.dipole_ints()
|
|
345
|
+
C_chol_loc = cholesky(Cao)
|
|
346
|
+
return foster_boys(C_chol_loc, dip_ints)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def edmiston_ruedenberg_cost_func(L):
|
|
350
|
+
"""Edmiston-Ruedenberg cost function.
|
|
351
|
+
|
|
352
|
+
Eq. (2) in [7]."""
|
|
353
|
+
return np.einsum("Jpp,Jpp->", L, L, optimize="greedy")
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def edmiston_ruedenberg_grad(L):
|
|
357
|
+
"""Edmiston-Ruedenberg gradient.
|
|
358
|
+
|
|
359
|
+
Eq. (5) in [7]."""
|
|
360
|
+
g1 = np.einsum("Jpq,Jqq->pq", L, L, optimize="greedy")
|
|
361
|
+
g2 = np.einsum("Jqp,Jpp->pq", L, L, optimize="greedy")
|
|
362
|
+
return -4 * (g1 - g2)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def edmiston_ruedenberg(C, Lao, Sao, diis_cycles=5, max_cycles=100):
|
|
366
|
+
"""Edmiston-Ruedenberg localization using DF integrals and DIIS.
|
|
367
|
+
|
|
368
|
+
Parameters
|
|
369
|
+
----------
|
|
370
|
+
C
|
|
371
|
+
MO-coefficients of shape (naos, nmos); this means MOs should
|
|
372
|
+
be in columns.
|
|
373
|
+
|
|
374
|
+
Lao
|
|
375
|
+
Density fitting tensor obtained from contracting the 2e3c-matrix
|
|
376
|
+
with 2c2e**-0.5 in the AO basis. Must have shape (naux, nao, nao).
|
|
377
|
+
Same as in
|
|
378
|
+
Sao
|
|
379
|
+
Overlap matrix of shape (nao, nao) in the AO basis.
|
|
380
|
+
diis_cycles
|
|
381
|
+
Integer >= 0. If > 0, DIIS is employed to accelerate convergence.
|
|
382
|
+
max_cycles
|
|
383
|
+
Positive integer; maximum number of localization cycles.
|
|
384
|
+
|
|
385
|
+
Returns
|
|
386
|
+
-------
|
|
387
|
+
Crot
|
|
388
|
+
Edmiston-Ruedenberg localized orbitals.
|
|
389
|
+
"""
|
|
390
|
+
nmos = C.shape[1]
|
|
391
|
+
# We can't keep more error vectors than MOs
|
|
392
|
+
if nmos < diis_cycles:
|
|
393
|
+
warnings.warn(
|
|
394
|
+
f"Can keep at most {nmos} DIIS error vectors, but "
|
|
395
|
+
f"{diis_cycles} were requested!."
|
|
396
|
+
)
|
|
397
|
+
diis_cycles = min(diis_cycles, nmos)
|
|
398
|
+
if diis_cycles == 1:
|
|
399
|
+
diis_cycles = 0
|
|
400
|
+
started_to_store_diis = False
|
|
401
|
+
specs = {
|
|
402
|
+
"err_vecs": np.zeros((diis_cycles, nmos**2)),
|
|
403
|
+
"R_mats": np.zeros((diis_cycles, nmos, nmos)),
|
|
404
|
+
"D_mats": np.zeros((diis_cycles, nmos, nmos)),
|
|
405
|
+
}
|
|
406
|
+
diis = DIIS(specs)
|
|
407
|
+
|
|
408
|
+
D = np.eye(nmos)
|
|
409
|
+
C0 = C.copy()
|
|
410
|
+
Crot = C.copy()
|
|
411
|
+
for i in range(max_cycles):
|
|
412
|
+
# Transform cholesky integrals to MO basis, step (2) in [7].
|
|
413
|
+
Lpq = np.einsum("Luv,up,vq->Lpq", Lao, Crot, Crot, optimize="greedy")
|
|
414
|
+
f = edmiston_ruedenberg_cost_func(Lpq)
|
|
415
|
+
g = edmiston_ruedenberg_grad(Lpq)
|
|
416
|
+
gnorm = np.linalg.norm(g)
|
|
417
|
+
grms = rms(g)
|
|
418
|
+
# Construct transformation, step (3) in [7].
|
|
419
|
+
# Rji = (Xj Xi Xi Xi)
|
|
420
|
+
R = np.einsum("Jji,Jii->ji", Lpq, Lpq, optimize="greedy")
|
|
421
|
+
# DIIS error; lack of symmetry in R.
|
|
422
|
+
err = (R - R.T).flatten()
|
|
423
|
+
errrms = rms(err)
|
|
424
|
+
print(
|
|
425
|
+
f"Cycle {i:02d} f={f:.8f}, |g|={np.linalg.norm(g):.4f}, rms(g)={grms:>8.4e} "
|
|
426
|
+
f"rms(err)={errrms:>8.4e}"
|
|
427
|
+
)
|
|
428
|
+
if converged := grms <= 1e-4:
|
|
429
|
+
print("Edmiston-Ruedenberg localization converged!")
|
|
430
|
+
break
|
|
431
|
+
|
|
432
|
+
U = R @ matrix_power(R.T @ R, -0.5)
|
|
433
|
+
D = D @ U
|
|
434
|
+
if diis_cycles and (started_to_store_diis or (gnorm <= 2.0e-1)):
|
|
435
|
+
diis.store(
|
|
436
|
+
{
|
|
437
|
+
"err_vecs": err,
|
|
438
|
+
"R_mats": R,
|
|
439
|
+
"D_mats": D,
|
|
440
|
+
}
|
|
441
|
+
)
|
|
442
|
+
started_to_store_diis = True
|
|
443
|
+
if (diis_coeffs := diis.get_coeffs()) is not None:
|
|
444
|
+
D_diis = np.einsum("i,ijk->jk", diis_coeffs, diis.get("D_mats"))
|
|
445
|
+
C_diis = C0 @ D_diis
|
|
446
|
+
# DIIS-2 algorithm in [7]
|
|
447
|
+
R_diis = np.einsum("i,ijk->jk", diis_coeffs, diis.get("R_mats"))
|
|
448
|
+
S_diis = C_diis.T @ Sao @ C_diis
|
|
449
|
+
S_diis_inv = matrix_power(S_diis, -1.0)
|
|
450
|
+
# Generalized eta step
|
|
451
|
+
V = S_diis_inv @ R_diis @ matrix_power(R_diis.T @ S_diis_inv @ R_diis, -0.5)
|
|
452
|
+
# Recalculate D from DIIS results
|
|
453
|
+
D = D_diis @ V
|
|
454
|
+
# Update Crot, step (4) in [7]. This either uses the D matrix obtained from DIIS
|
|
455
|
+
# or the one previously calculated.
|
|
456
|
+
Crot = C0 @ D
|
|
457
|
+
# TODO: return JacobiSweepResult?
|
|
458
|
+
return Crot, f
|