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,159 @@
|
|
|
1
|
+
# [1] https://doi.org/10.1002/jcc.26495
|
|
2
|
+
# Habershon, 2021
|
|
3
|
+
|
|
4
|
+
import itertools as it
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from pysisyphus.helpers_pure import get_molecular_radius
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HardSphere:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
geom,
|
|
15
|
+
frags,
|
|
16
|
+
kappa=1.0,
|
|
17
|
+
permutations=False,
|
|
18
|
+
frag_radii=None,
|
|
19
|
+
radii_offset=0.9452,
|
|
20
|
+
):
|
|
21
|
+
"""Intra-Image Inter-Molecular Hard-Sphere force.
|
|
22
|
+
|
|
23
|
+
See A.2. in [1], Eq. (A1).
|
|
24
|
+
"""
|
|
25
|
+
self.frags = frags
|
|
26
|
+
self.kappa = kappa
|
|
27
|
+
|
|
28
|
+
self.frag_num = len(self.frags)
|
|
29
|
+
self.frag_sizes = np.array([len(frag) for frag in self.frags])
|
|
30
|
+
self.pair_inds = np.array(list(it.combinations(range(self.frag_num), 2)))
|
|
31
|
+
it_func = it.permutations if permutations else it.combinations
|
|
32
|
+
self.pair_inds = np.array(list(it_func(range(self.frag_num), 2)))
|
|
33
|
+
self.frag_inds = np.array([m for m, n in self.pair_inds])
|
|
34
|
+
|
|
35
|
+
c3d = geom.coords3d
|
|
36
|
+
frag_c3ds = [c3d[frag] for frag in self.frags]
|
|
37
|
+
self.frag_radii = frag_radii
|
|
38
|
+
if self.frag_radii is None:
|
|
39
|
+
self.frag_radii = [
|
|
40
|
+
get_molecular_radius(frag_c3d, min_offset=radii_offset)
|
|
41
|
+
for frag_c3d in frag_c3ds
|
|
42
|
+
]
|
|
43
|
+
self.radii_sums = np.array(
|
|
44
|
+
[self.frag_radii[i] + self.frag_radii[j] for i, j in self.pair_inds]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def get_forces(self, atoms, coords, kappa=None):
|
|
48
|
+
if kappa is None:
|
|
49
|
+
kappa = self.kappa
|
|
50
|
+
c3d = coords.reshape(-1, 3)
|
|
51
|
+
|
|
52
|
+
# Break early when only 1 fragment is present
|
|
53
|
+
if len(self.pair_inds) == 0:
|
|
54
|
+
return {"energy": 1, "forces": np.zeros_like(coords)}
|
|
55
|
+
|
|
56
|
+
centroids = np.array([c3d[frag].mean(axis=0) for frag in self.frags])
|
|
57
|
+
mm, nn = np.array(self.pair_inds).T
|
|
58
|
+
gdiffs = centroids[mm] - centroids[nn]
|
|
59
|
+
# Add small number to avoid division by zero in 'frag_gradient' calculation
|
|
60
|
+
gnorms = np.linalg.norm(gdiffs, axis=1) + 1e-16
|
|
61
|
+
H = (gnorms < self.radii_sums).astype(int)
|
|
62
|
+
N = H.copy()
|
|
63
|
+
N *= 3 * self.frag_sizes[self.frag_inds]
|
|
64
|
+
N_invs = np.divide(1, N, out=np.zeros_like(N).astype(float), where=N != 0)
|
|
65
|
+
phi = kappa * N_invs * (gnorms - self.radii_sums)
|
|
66
|
+
frag_gradient = (phi * H / gnorms)[:, None] * gdiffs
|
|
67
|
+
gradient = np.zeros_like(c3d)
|
|
68
|
+
# Distribute gradient onto fragments
|
|
69
|
+
for frag_ind, ff in zip(self.frag_inds, frag_gradient):
|
|
70
|
+
gradient[self.frags[frag_ind]] += ff
|
|
71
|
+
forces = -gradient.flatten()
|
|
72
|
+
|
|
73
|
+
f3d = forces.reshape(-1, 3)
|
|
74
|
+
f3d -= f3d.mean(axis=0)[None, :]
|
|
75
|
+
|
|
76
|
+
return {"energy": 1, "forces": forces}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class PWHardSphere:
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
geom,
|
|
83
|
+
frags,
|
|
84
|
+
sub_frags,
|
|
85
|
+
kappa=1.0,
|
|
86
|
+
):
|
|
87
|
+
"""Inter-Molecular pairwise Hard-Sphere forces between atoms.
|
|
88
|
+
|
|
89
|
+
Hardsphere forces are only applied between certain atoms of given fragments,
|
|
90
|
+
but the whole fragment is moved. Can be used to remove atom inter-molecular
|
|
91
|
+
atom clashes.
|
|
92
|
+
"""
|
|
93
|
+
self.frags = frags
|
|
94
|
+
self.sub_frags = sub_frags
|
|
95
|
+
self.kappa = kappa
|
|
96
|
+
|
|
97
|
+
self.frag_num = len(self.frags)
|
|
98
|
+
self.frag_sizes = np.array([len(frag) for frag in self.frags])
|
|
99
|
+
self.pair_inds = np.array(list(it.combinations(range(self.frag_num), 2)))
|
|
100
|
+
cov_rads = geom.covalent_radii
|
|
101
|
+
self.pair_atom_inds = list()
|
|
102
|
+
self.pair_cov_radii = list()
|
|
103
|
+
for m, n in self.pair_inds:
|
|
104
|
+
frag_m = self.sub_frags[m]
|
|
105
|
+
frag_n = self.sub_frags[n]
|
|
106
|
+
painds = list()
|
|
107
|
+
pcr = list()
|
|
108
|
+
for fm in frag_m:
|
|
109
|
+
crm = cov_rads[m]
|
|
110
|
+
for fn in frag_n:
|
|
111
|
+
crn = cov_rads[m]
|
|
112
|
+
crsum = crm + crn
|
|
113
|
+
painds.append([fm, fn])
|
|
114
|
+
pcr.append(crsum)
|
|
115
|
+
self.pair_atom_inds.append(painds)
|
|
116
|
+
self.pair_cov_radii.append(pcr)
|
|
117
|
+
|
|
118
|
+
def get_forces(self, atoms, coords, kappa=None):
|
|
119
|
+
if kappa is None:
|
|
120
|
+
kappa = self.kappa
|
|
121
|
+
c3d = coords.reshape(-1, 3)
|
|
122
|
+
|
|
123
|
+
# Break early when only 1 fragment is present
|
|
124
|
+
if len(self.pair_inds) == 0:
|
|
125
|
+
return {"energy": 1, "forces": np.zeros_like(coords)}
|
|
126
|
+
|
|
127
|
+
forces = np.zeros_like(c3d)
|
|
128
|
+
centroids = np.array([c3d[frag].mean(axis=0) for frag in self.frags])
|
|
129
|
+
N = 1.0
|
|
130
|
+
N_inv = 1 / N
|
|
131
|
+
for (m, n), pai, pcr in zip(
|
|
132
|
+
self.pair_inds, self.pair_atom_inds, self.pair_cov_radii
|
|
133
|
+
):
|
|
134
|
+
frag_m = self.frags[m]
|
|
135
|
+
frag_n = self.frags[n]
|
|
136
|
+
centr_m = centroids[m]
|
|
137
|
+
centr_n = centroids[n]
|
|
138
|
+
dcentr = centr_m - centr_n
|
|
139
|
+
force_dir = dcentr / np.linalg.norm(dcentr)
|
|
140
|
+
for (am, an), crmn in zip(pai, pcr):
|
|
141
|
+
amn = c3d[am] - c3d[an]
|
|
142
|
+
distmn = np.linalg.norm(amn)
|
|
143
|
+
diff = distmn - crmn
|
|
144
|
+
fact = int(distmn < crmn)
|
|
145
|
+
if not fact:
|
|
146
|
+
continue
|
|
147
|
+
# Magnitude of applied force
|
|
148
|
+
magn = kappa * N_inv * diff
|
|
149
|
+
force = magn * force_dir
|
|
150
|
+
# Distribute half of the force onto each fragment
|
|
151
|
+
force_2 = force / 2
|
|
152
|
+
# The signs below depend on the difference centr_m - centr_n above
|
|
153
|
+
forces[frag_m] -= force_2
|
|
154
|
+
forces[frag_n] += force_2
|
|
155
|
+
|
|
156
|
+
forces -= forces.mean(axis=0)[None, :]
|
|
157
|
+
forces = forces.flatten()
|
|
158
|
+
|
|
159
|
+
return {"energy": 1, "forces": forces}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.spatial.distance import pdist, squareform
|
|
3
|
+
|
|
4
|
+
from pysisyphus.calculators.Calculator import Calculator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class IDPPCalculator(Calculator):
|
|
8
|
+
|
|
9
|
+
def __init__(self, target):
|
|
10
|
+
self.target = squareform(target)
|
|
11
|
+
|
|
12
|
+
super().__init__(base_name="idpp")
|
|
13
|
+
|
|
14
|
+
def get_forces(self, atoms, coords):
|
|
15
|
+
coords_reshaped = coords.reshape((-1, 3))
|
|
16
|
+
|
|
17
|
+
D = []
|
|
18
|
+
for c in coords_reshaped:
|
|
19
|
+
Di = coords_reshaped - c
|
|
20
|
+
D.append(Di)
|
|
21
|
+
D = np.array(D)
|
|
22
|
+
|
|
23
|
+
curr_pdist = pdist(coords_reshaped)
|
|
24
|
+
curr_square = squareform(curr_pdist)
|
|
25
|
+
curr_diff = curr_square - self.target
|
|
26
|
+
|
|
27
|
+
curr_square = curr_square + np.eye(curr_square.shape[0])
|
|
28
|
+
|
|
29
|
+
# The bigger the differences 'curr_diff', the bigger the energy.
|
|
30
|
+
# The smaller the current distances 'current_pdist', the bigger
|
|
31
|
+
# the energy.
|
|
32
|
+
energy = 0.5 * (curr_diff**2 / curr_square**4).sum()
|
|
33
|
+
|
|
34
|
+
# Adapted from ASE IDPP calculator
|
|
35
|
+
# https://gitlab.com/ase/ase/blob/master/ase/neb.py, GPL2
|
|
36
|
+
forces = -2 * ((curr_diff *
|
|
37
|
+
(1 - 2 * curr_diff / curr_square) /
|
|
38
|
+
curr_square**5)[...,np.newaxis] * D).sum(0)
|
|
39
|
+
|
|
40
|
+
results = {
|
|
41
|
+
"energy" : energy,
|
|
42
|
+
"forces": forces.flatten()
|
|
43
|
+
}
|
|
44
|
+
return results
|
|
45
|
+
|
|
46
|
+
def __str__(self):
|
|
47
|
+
return "IDPP calculator"
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import struct
|
|
2
|
+
import socket
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.socket_helper import send_closure, recv_closure, get_fmts
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def ipi_client(
|
|
10
|
+
addr, atoms, energy_getter, forces_getter, hessian_getter=None, hdrlen=12
|
|
11
|
+
):
|
|
12
|
+
atom_num = len(atoms)
|
|
13
|
+
# Number of entries in a Caretsian forces/coords vector
|
|
14
|
+
cartesians = 3 * atom_num
|
|
15
|
+
# Formats needed for struct.pack, to cast variables to bytes.
|
|
16
|
+
# Bytes needed, to store a forces/coords vector
|
|
17
|
+
floats_bytes = 8 * cartesians
|
|
18
|
+
# Virial is hardcoded to the zero vector.
|
|
19
|
+
VIRIAL = struct.pack("d" * 9, *np.zeros(9))
|
|
20
|
+
ZERO = struct.pack("i", 0)
|
|
21
|
+
|
|
22
|
+
fmts = get_fmts(cartesians)
|
|
23
|
+
|
|
24
|
+
# Unix socket is hardcoded right now, but may also be inet-socket
|
|
25
|
+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
26
|
+
addr = str(addr)
|
|
27
|
+
sock.connect(addr)
|
|
28
|
+
|
|
29
|
+
send_msg = send_closure(sock, hdrlen, fmts)
|
|
30
|
+
recv_msg = recv_closure(sock, hdrlen, fmts)
|
|
31
|
+
|
|
32
|
+
counter = 0
|
|
33
|
+
while True:
|
|
34
|
+
try:
|
|
35
|
+
# Lets start talking
|
|
36
|
+
recv_msg(expect="STATUS") # The server initiates with a STATUS
|
|
37
|
+
send_msg("READY")
|
|
38
|
+
|
|
39
|
+
status = recv_msg(expect="STATUS")
|
|
40
|
+
if status == "NEEDPOS":
|
|
41
|
+
send_msg("HAVEPOS")
|
|
42
|
+
_ = recv_msg(4, fmt="int")[0] # Recive atom num from IPI
|
|
43
|
+
coords = np.array(
|
|
44
|
+
recv_msg(floats_bytes, "floats")
|
|
45
|
+
) # Receive current coords
|
|
46
|
+
assert coords.size % 3 == 0 # Assert Cartesian coordinates
|
|
47
|
+
send_msg(atom_num, "int")
|
|
48
|
+
# Just send back the current coordinates or translate all atoms in +X
|
|
49
|
+
coords.reshape(-1, 3)[:, 0] += 1
|
|
50
|
+
send_msg(coords, "floats")
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
# When the optimization converged EXIT will be returned .. not documented!
|
|
54
|
+
if status == "EXIT":
|
|
55
|
+
print("Exited!")
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
# It seems we have to send READY two times ... not documented!
|
|
59
|
+
send_msg("READY")
|
|
60
|
+
# The server then returns POSDATA.
|
|
61
|
+
recv_msg(expect="POSDATA")
|
|
62
|
+
# Receive cell vectors, inverse cell vectors and number of atoms ...
|
|
63
|
+
# but we don't use them here, so we don't even try to convert them to something.
|
|
64
|
+
sock.recv(72) # cell
|
|
65
|
+
sock.recv(72) # icell
|
|
66
|
+
ipi_atom_num = recv_msg(4, fmt="int")[0]
|
|
67
|
+
assert ipi_atom_num == atom_num
|
|
68
|
+
# ... and the current coordinates.
|
|
69
|
+
coords = np.array(recv_msg(floats_bytes, "floats"))
|
|
70
|
+
|
|
71
|
+
recv_msg(expect="STATUS")
|
|
72
|
+
# Indicate, that calculation is possible
|
|
73
|
+
send_msg("HAVEDATA")
|
|
74
|
+
get_what = recv_msg()
|
|
75
|
+
# Acutal QC calculations
|
|
76
|
+
if get_what == "GETENERGY":
|
|
77
|
+
energy = energy_getter(coords)
|
|
78
|
+
print(f"Calculated energy: {energy:.6f}, counter={counter}")
|
|
79
|
+
send_msg("ENERGYREADY")
|
|
80
|
+
send_msg(energy, "float")
|
|
81
|
+
if get_what == "GETFORCE":
|
|
82
|
+
forces, energy = forces_getter(coords)
|
|
83
|
+
print(f"Calculated energy & forces: {energy:.6f}, counter={counter}")
|
|
84
|
+
send_msg("FORCEREADY")
|
|
85
|
+
# Send everything to the server
|
|
86
|
+
send_msg(energy, "float")
|
|
87
|
+
send_msg(atom_num, "int")
|
|
88
|
+
send_msg(forces, "floats")
|
|
89
|
+
send_msg(VIRIAL, packed=True)
|
|
90
|
+
# We don't want to send additional information, so just send 0.
|
|
91
|
+
send_msg(ZERO, packed=True)
|
|
92
|
+
elif get_what == "GETHESSIAN":
|
|
93
|
+
hessian, energy = hessian_getter(coords)
|
|
94
|
+
hessian_packed = struct.pack("d" * cartesians ** 2, *hessian.flatten())
|
|
95
|
+
print(f"Calculated energy & Hessian: {energy:.6f}, counter={counter}")
|
|
96
|
+
send_msg("HESSIANREADY")
|
|
97
|
+
# Send everything to the server
|
|
98
|
+
send_msg(energy, "float")
|
|
99
|
+
send_msg(atom_num, "int")
|
|
100
|
+
send_msg(hessian_packed, packed=True)
|
|
101
|
+
|
|
102
|
+
counter += 1
|
|
103
|
+
except Exception as err:
|
|
104
|
+
raise err
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def calc_ipi_client(addr, atoms, calc, queue=None, **kwargs):
|
|
108
|
+
assert calc is not None, "Supplied calculator must not be None!"
|
|
109
|
+
|
|
110
|
+
def energy_getter(coords):
|
|
111
|
+
if queue is not None:
|
|
112
|
+
queue.put(("coords", coords))
|
|
113
|
+
results = calc.get_energy(atoms, coords)
|
|
114
|
+
energy = results["energy"]
|
|
115
|
+
return energy
|
|
116
|
+
|
|
117
|
+
def forces_getter(coords):
|
|
118
|
+
if queue is not None:
|
|
119
|
+
queue.put(("coords", coords))
|
|
120
|
+
results = calc.get_forces(atoms, coords)
|
|
121
|
+
forces = results["forces"]
|
|
122
|
+
energy = results["energy"]
|
|
123
|
+
return forces, energy
|
|
124
|
+
|
|
125
|
+
def hessian_getter(coords):
|
|
126
|
+
if queue is not None:
|
|
127
|
+
queue.put(("coords", coords))
|
|
128
|
+
results = calc.get_hessian(atoms, coords)
|
|
129
|
+
hessian = results["hessian"]
|
|
130
|
+
energy = results["energy"]
|
|
131
|
+
return hessian, energy
|
|
132
|
+
|
|
133
|
+
ipi_client(addr, atoms, energy_getter, forces_getter, hessian_getter, **kwargs)
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import socket
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.calculators.Calculator import Calculator
|
|
7
|
+
from pysisyphus.socket_helper import (
|
|
8
|
+
send_closure,
|
|
9
|
+
recv_closure,
|
|
10
|
+
get_fmts,
|
|
11
|
+
EYE3,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class IPIServer(Calculator):
|
|
16
|
+
listen_kinds = ("coords", "energy", "forces", "hessian")
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
*args,
|
|
21
|
+
address=None,
|
|
22
|
+
host=None,
|
|
23
|
+
port=None,
|
|
24
|
+
unlink=True,
|
|
25
|
+
hdrlen=12,
|
|
26
|
+
max_retries=0,
|
|
27
|
+
verbose=False,
|
|
28
|
+
**kwargs,
|
|
29
|
+
):
|
|
30
|
+
super().__init__(*args, **kwargs)
|
|
31
|
+
self.address = address
|
|
32
|
+
self.host = host
|
|
33
|
+
self.port = port
|
|
34
|
+
if self.host:
|
|
35
|
+
assert self.port is not None
|
|
36
|
+
self.hdrlen = hdrlen
|
|
37
|
+
self.max_retries = max_retries
|
|
38
|
+
self.verbose = verbose
|
|
39
|
+
|
|
40
|
+
if self.address and unlink:
|
|
41
|
+
self.unlink(self.address)
|
|
42
|
+
|
|
43
|
+
if self.address:
|
|
44
|
+
family = socket.AF_UNIX
|
|
45
|
+
bind_args = (self.address,)
|
|
46
|
+
else:
|
|
47
|
+
family = socket.AF_INET
|
|
48
|
+
bind_args = (self.host, self.port)
|
|
49
|
+
|
|
50
|
+
# Create socket
|
|
51
|
+
self.sock = socket.socket(family, socket.SOCK_STREAM)
|
|
52
|
+
self.sock.bind(*bind_args)
|
|
53
|
+
self.sock.listen(1)
|
|
54
|
+
|
|
55
|
+
self.fmts = None
|
|
56
|
+
self.send_msg = None
|
|
57
|
+
self.recv_msg = None
|
|
58
|
+
self.reset_client_connection()
|
|
59
|
+
|
|
60
|
+
def unlink(self, address):
|
|
61
|
+
try:
|
|
62
|
+
os.unlink(address)
|
|
63
|
+
except OSError as err:
|
|
64
|
+
if os.path.exists(address):
|
|
65
|
+
raise err
|
|
66
|
+
|
|
67
|
+
def reset_client_connection(self):
|
|
68
|
+
self.log("Resetting client connection info.")
|
|
69
|
+
try:
|
|
70
|
+
self.conn.close()
|
|
71
|
+
except AttributeError:
|
|
72
|
+
self.log("No client connection present.")
|
|
73
|
+
self._client_conn = None
|
|
74
|
+
self._client_address = None
|
|
75
|
+
self.cur_retries = 0
|
|
76
|
+
|
|
77
|
+
def listen_for_client_atom_num(self, atom_num):
|
|
78
|
+
client_atom_num = self.recv_msg(4, fmt="int")[0]
|
|
79
|
+
self.log(
|
|
80
|
+
f"Client sent number of atoms: {client_atom_num}, expecting {atom_num}."
|
|
81
|
+
)
|
|
82
|
+
assert atom_num == client_atom_num
|
|
83
|
+
return atom_num
|
|
84
|
+
|
|
85
|
+
def listen_for_energy(self):
|
|
86
|
+
send_msg = self.send_msg
|
|
87
|
+
recv_msg = self.recv_msg
|
|
88
|
+
|
|
89
|
+
send_msg("GETENERGY")
|
|
90
|
+
recv_msg(expect="ENERGYREADY")
|
|
91
|
+
energy = recv_msg(8, fmt="float")[0]
|
|
92
|
+
results = {
|
|
93
|
+
"energy": energy,
|
|
94
|
+
}
|
|
95
|
+
return results
|
|
96
|
+
|
|
97
|
+
def listen_for_forces(self, atom_num):
|
|
98
|
+
send_msg = self.send_msg
|
|
99
|
+
recv_msg = self.recv_msg
|
|
100
|
+
|
|
101
|
+
send_msg("GETFORCE")
|
|
102
|
+
recv_msg(expect="FORCEREADY")
|
|
103
|
+
energy = recv_msg(8, fmt="float")[0]
|
|
104
|
+
self.listen_for_client_atom_num(atom_num)
|
|
105
|
+
coord_num = 3 * atom_num
|
|
106
|
+
forces = recv_msg(coord_num * 8, fmt="floats", expect="forces")
|
|
107
|
+
recv_msg(72, fmt="nine_floats", expect="virial")
|
|
108
|
+
recv_msg(4, fmt="int", expect="zero")
|
|
109
|
+
results = {
|
|
110
|
+
"energy": energy,
|
|
111
|
+
"forces": np.array(forces),
|
|
112
|
+
}
|
|
113
|
+
return results
|
|
114
|
+
|
|
115
|
+
def listen_for_hessian(self, atom_num):
|
|
116
|
+
send_msg = self.send_msg
|
|
117
|
+
recv_msg = self.recv_msg
|
|
118
|
+
|
|
119
|
+
send_msg("GETHESSIAN")
|
|
120
|
+
recv_msg(expect="HESSIANREADY")
|
|
121
|
+
energy = recv_msg(8, fmt="float")[0]
|
|
122
|
+
self.listen_for_client_atom_num(atom_num)
|
|
123
|
+
coord_num = 3 * atom_num
|
|
124
|
+
hessian = recv_msg(coord_num ** 2 * 8, fmt="floats_sq", expect="Hessian")
|
|
125
|
+
hessian = np.array(hessian).reshape(-1, coord_num)
|
|
126
|
+
results = {
|
|
127
|
+
"energy": energy,
|
|
128
|
+
"hessian": hessian,
|
|
129
|
+
}
|
|
130
|
+
return results
|
|
131
|
+
|
|
132
|
+
def listen_for(self, atoms, coords, kind="forces"):
|
|
133
|
+
assert kind in self.listen_kinds
|
|
134
|
+
|
|
135
|
+
atom_num = len(atoms)
|
|
136
|
+
coords_num = len(coords)
|
|
137
|
+
|
|
138
|
+
# Setup connection
|
|
139
|
+
if (self._client_conn is None) or (self._client_address is None):
|
|
140
|
+
self.log("Waiting for a connection.")
|
|
141
|
+
self._client_conn, self._client_address = self.sock.accept()
|
|
142
|
+
if self._client_address != "":
|
|
143
|
+
conn_msg = f"Got new connection from {self._client_address}."
|
|
144
|
+
else:
|
|
145
|
+
conn_msg = "Got new connection."
|
|
146
|
+
self.log(conn_msg)
|
|
147
|
+
# Create send/receive functions for this connection
|
|
148
|
+
self.fmts = get_fmts(coords_num)
|
|
149
|
+
self.send_msg = send_closure(
|
|
150
|
+
self._client_conn, self.hdrlen, self.fmts, verbose=self.verbose
|
|
151
|
+
)
|
|
152
|
+
self.recv_msg = recv_closure(
|
|
153
|
+
self._client_conn, self.hdrlen, self.fmts, verbose=self.verbose
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Reuse existing connection self._client_conn, wrapped in the
|
|
157
|
+
# functions below.
|
|
158
|
+
send_msg = self.send_msg
|
|
159
|
+
recv_msg = self.recv_msg
|
|
160
|
+
|
|
161
|
+
# Lets start talking
|
|
162
|
+
send_msg("STATUS")
|
|
163
|
+
recv_msg(expect="READY")
|
|
164
|
+
|
|
165
|
+
# This path handles a coordinate update through the client.
|
|
166
|
+
if kind == "coords":
|
|
167
|
+
send_msg("NEEDPOS")
|
|
168
|
+
# TODO: allow skipping the update
|
|
169
|
+
recv_msg(expect="HAVEPOS")
|
|
170
|
+
# Send current atom number and coordinates
|
|
171
|
+
send_msg(atom_num, fmt="int")
|
|
172
|
+
send_msg(coords, fmt="floats")
|
|
173
|
+
# Receive atom number and potentially modified coordinates from the client.
|
|
174
|
+
self.listen_for_client_atom_num(atom_num)
|
|
175
|
+
new_coords = recv_msg(atom_num * 3 * 8, fmt="floats")
|
|
176
|
+
results = {"coords": np.array(new_coords)}
|
|
177
|
+
# The path below leads to sending of coordinates and calculation of
|
|
178
|
+
# energy and maybe its derivatives by the client.
|
|
179
|
+
else:
|
|
180
|
+
send_msg("STATUS")
|
|
181
|
+
recv_msg(expect="READY")
|
|
182
|
+
send_msg("POSDATA")
|
|
183
|
+
# Send cell vectors, inverse cell vectors, number of atoms and coordinates
|
|
184
|
+
send_msg(EYE3, packed=True) # cell vectors
|
|
185
|
+
send_msg(EYE3, packed=True) # inverse cell vectors
|
|
186
|
+
send_msg(atom_num, fmt="int")
|
|
187
|
+
send_msg(coords, fmt="floats")
|
|
188
|
+
send_msg("STATUS")
|
|
189
|
+
recv_msg(expect="HAVEDATA")
|
|
190
|
+
if kind == "energy":
|
|
191
|
+
results = self.listen_for_energy()
|
|
192
|
+
elif kind == "forces":
|
|
193
|
+
results = self.listen_for_forces(atom_num)
|
|
194
|
+
elif kind == "hessian":
|
|
195
|
+
results = self.listen_for_hessian(atom_num)
|
|
196
|
+
return results
|
|
197
|
+
|
|
198
|
+
def retried_listen_for(self, atoms, coords):
|
|
199
|
+
while self.cur_retries < self.max_retries:
|
|
200
|
+
try:
|
|
201
|
+
result = self.listen_for(atoms, coords)
|
|
202
|
+
break
|
|
203
|
+
except Exception as err:
|
|
204
|
+
self.log(f"Caught exception: {err}.")
|
|
205
|
+
self.cur_retries += 1
|
|
206
|
+
self.reset_client_connection()
|
|
207
|
+
result = self.listen_for(atoms, coords)
|
|
208
|
+
return result
|
|
209
|
+
|
|
210
|
+
def __del__(self):
|
|
211
|
+
self.send_msg("STATUS")
|
|
212
|
+
_ = self.recv_msg()
|
|
213
|
+
self.send_msg("EXIT")
|
|
214
|
+
self.log("Sent EXIT to client.")
|
|
215
|
+
self.reset_client_connection()
|
|
216
|
+
# self.unlink(self.address)
|
|
217
|
+
|
|
218
|
+
def get_energy(self, atoms, coords):
|
|
219
|
+
return self.listen_for(atoms, coords, kind="energy")
|
|
220
|
+
|
|
221
|
+
# def get_forces(self, atoms, coords):
|
|
222
|
+
# if self.max_retries:
|
|
223
|
+
# result = self.retried_listen_for(atoms, coords)
|
|
224
|
+
# else:
|
|
225
|
+
# result = self.listen_for(atoms, coords)
|
|
226
|
+
|
|
227
|
+
# def get_coords(self, atoms, coords):
|
|
228
|
+
# return self.listen_for(atoms, coords, kind="coords")
|
|
229
|
+
|
|
230
|
+
def get_forces(self, atoms, coords):
|
|
231
|
+
return self.listen_for(atoms, coords, kind="forces")
|
|
232
|
+
|
|
233
|
+
def get_hessian(self, atoms, coords):
|
|
234
|
+
return self.listen_for(atoms, coords, kind="hessian")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from pysisyphus.calculators.AnaPotBase import AnaPotBase
|
|
2
|
+
from pysisyphus.calculators.LEPSExpr import LEPSExpr
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LEPSBase(AnaPotBase):
|
|
6
|
+
|
|
7
|
+
def __init__(self, pot_type="leps"):
|
|
8
|
+
leps_expr = LEPSExpr()
|
|
9
|
+
V_expr, xlim, ylim, levels = leps_expr.get_expr(pot_type)
|
|
10
|
+
V_str = str(V_expr)
|
|
11
|
+
|
|
12
|
+
super().__init__(V_str=V_str, xlim=xlim, ylim=ylim, levels=levels)
|
|
13
|
+
|
|
14
|
+
def __str__(self):
|
|
15
|
+
return "LEPSBase calculator"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if __name__ == "__main__":
|
|
19
|
+
import matplotlib.pyplot as plt
|
|
20
|
+
choices = "leps harmonic tot dimer".split()
|
|
21
|
+
for c in choices:
|
|
22
|
+
lp = LEPSBase(pot_type=c)
|
|
23
|
+
lp.plot()
|
|
24
|
+
plt.show()
|