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,106 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import qcengine as qcng
|
|
3
|
+
import qcelemental as qcel
|
|
4
|
+
|
|
5
|
+
from pysisyphus.calculators.Calculator import Calculator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QCEngine(Calculator):
|
|
9
|
+
|
|
10
|
+
def __init__(self, program, model, keywords=None, connectivity=None,
|
|
11
|
+
bond_order=1, **kwargs):
|
|
12
|
+
super().__init__(**kwargs)
|
|
13
|
+
|
|
14
|
+
self.program = program
|
|
15
|
+
self.model = model
|
|
16
|
+
if keywords is None:
|
|
17
|
+
keywords = dict()
|
|
18
|
+
self.keywords = dict(keywords)
|
|
19
|
+
self.connectivity = connectivity
|
|
20
|
+
self.bond_order = int(bond_order)
|
|
21
|
+
|
|
22
|
+
# TODO: pal, memory
|
|
23
|
+
|
|
24
|
+
def get_molecule(self, atoms, coords):
|
|
25
|
+
c3d = coords.reshape(-1, 3)# * BOHR2ANG
|
|
26
|
+
mol_inp = {
|
|
27
|
+
"symbols": atoms,
|
|
28
|
+
"geometry": c3d,
|
|
29
|
+
"molecular_charge": self.charge,
|
|
30
|
+
"molecular_multiplicity": self.mult,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if self.program == "openmm":
|
|
34
|
+
if self.connectivity is None:
|
|
35
|
+
self.log( "No connectivity specified! Using hacky connectivity "
|
|
36
|
+
f"guess with bond-order={self.bond_order}")
|
|
37
|
+
connectivity = qcel.molutil.guess_connectivity(atoms, c3d,
|
|
38
|
+
threshold=1.3)
|
|
39
|
+
self.connectivity = [(at1, at2, self.bond_order)
|
|
40
|
+
for at1, at2 in connectivity]
|
|
41
|
+
mol_inp["connectivity"] = self.connectivity
|
|
42
|
+
|
|
43
|
+
molecule = qcel.models.Molecule.from_data(mol_inp)
|
|
44
|
+
|
|
45
|
+
return molecule
|
|
46
|
+
|
|
47
|
+
def compute(self, molecule, driver):
|
|
48
|
+
inp = {
|
|
49
|
+
"molecule": molecule,
|
|
50
|
+
"driver": driver,
|
|
51
|
+
"model": self.model,
|
|
52
|
+
"keywords": self.keywords,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
result = qcng.compute(inp, program=self.program, return_dict=True)
|
|
56
|
+
self.calc_counter += 1
|
|
57
|
+
return result
|
|
58
|
+
|
|
59
|
+
def keep_stdout(self, res):
|
|
60
|
+
if "stdout" in res:
|
|
61
|
+
with open(self.make_fn(f"qce_{self.program}_stdout"), "w") as handle:
|
|
62
|
+
handle.write(res["stdout"])
|
|
63
|
+
|
|
64
|
+
def get_energy(self, atoms, coords, **prepare_kwargs):
|
|
65
|
+
mol = self.get_molecule(atoms, coords)
|
|
66
|
+
|
|
67
|
+
res = self.compute(mol, driver="energy")
|
|
68
|
+
self.keep_stdout(res)
|
|
69
|
+
|
|
70
|
+
results = {
|
|
71
|
+
"energy": res["return_result"],
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return results
|
|
75
|
+
|
|
76
|
+
def get_forces(self, atoms, coords, **prepare_kwargs):
|
|
77
|
+
mol = self.get_molecule(atoms, coords)
|
|
78
|
+
|
|
79
|
+
res = self.compute(mol, driver="gradient")
|
|
80
|
+
self.keep_stdout(res)
|
|
81
|
+
|
|
82
|
+
results = {
|
|
83
|
+
"energy": res["properties"]["return_energy"],
|
|
84
|
+
"forces": -np.array(res["return_result"]),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return results
|
|
88
|
+
|
|
89
|
+
def get_hessian(self, atoms, coords, **prepare_kwargs):
|
|
90
|
+
mol = self.get_molecule(atoms, coords)
|
|
91
|
+
|
|
92
|
+
res = self.compute(mol, driver="hessian")
|
|
93
|
+
self.keep_stdout(res)
|
|
94
|
+
|
|
95
|
+
size = 3 * len(atoms)
|
|
96
|
+
shape = (size, size)
|
|
97
|
+
|
|
98
|
+
results = {
|
|
99
|
+
"energy": res["properties"]["return_energy"],
|
|
100
|
+
"hessian": np.array(res["return_result"]).reshape(shape),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
def __str__(self):
|
|
106
|
+
return f"QCECalculator({self.name})"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pysisyphus.calculators.AnaPotBase import AnaPotBase
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Rastrigin(AnaPotBase):
|
|
7
|
+
"""
|
|
8
|
+
http://www.sfu.ca/~ssurjano/rastr.html
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
# d == 2
|
|
13
|
+
# f(x) = 10*d + sum_(i+1)^d (x_i**2 - 10*cos(2*pi*x_i))
|
|
14
|
+
V_str = "20 + x**2 - 10*cos(2*pi*x) + y**2 - 10*cos(2*pi*y)"
|
|
15
|
+
xlim = (-5.12, 5.12)
|
|
16
|
+
ylim = xlim
|
|
17
|
+
levels = np.linspace(0, 50, 50)
|
|
18
|
+
minima = ((0., 0., 0.), )
|
|
19
|
+
super().__init__(V_str=V_str, xlim=xlim, ylim=ylim, levels=levels, minima=minima)
|
|
20
|
+
|
|
21
|
+
def __str__(self):
|
|
22
|
+
return "Rastrigin calculator"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import tarfile
|
|
3
|
+
|
|
4
|
+
from fabric import Connection
|
|
5
|
+
import yaml
|
|
6
|
+
|
|
7
|
+
from pysisyphus.calculators.Calculator import Calculator
|
|
8
|
+
from pysisyphus.helpers_pure import json_to_results
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Remote(Calculator):
|
|
12
|
+
def __init__(self, remote_calc, host, prefix="", **kwargs):
|
|
13
|
+
super().__init__(**kwargs)
|
|
14
|
+
|
|
15
|
+
self.remote_calc = remote_calc
|
|
16
|
+
self.host = host
|
|
17
|
+
self.prefix = prefix
|
|
18
|
+
|
|
19
|
+
self.calc_inp = yaml.dump(self.remote_calc)
|
|
20
|
+
self.tar_fn = "pysis.tar.gz"
|
|
21
|
+
self.yaml_fn = "inp.yaml"
|
|
22
|
+
self.run_dict = {
|
|
23
|
+
"geom": {
|
|
24
|
+
"fn": None,
|
|
25
|
+
},
|
|
26
|
+
"calc": {
|
|
27
|
+
"run_func": None,
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
self.run_dict["calc"].update(remote_calc)
|
|
31
|
+
|
|
32
|
+
def run_calculation(self, atoms, coords, run_func="get_energy"):
|
|
33
|
+
con = Connection(self.host)
|
|
34
|
+
res = con.run("mktemp -d", hide=True)
|
|
35
|
+
tmp_dir = res.stdout.strip()
|
|
36
|
+
|
|
37
|
+
xyz_str = self.prepare_xyz_string(atoms, coords)
|
|
38
|
+
run_dict = self.run_dict.copy()
|
|
39
|
+
run_dict["geom"]["fn"] = xyz_str
|
|
40
|
+
# Inline xyz coordinates
|
|
41
|
+
run_dict["calc"]["run_func"] = run_func
|
|
42
|
+
|
|
43
|
+
# Create YAML input for remote calculation
|
|
44
|
+
with open(self.yaml_fn, "w") as handle:
|
|
45
|
+
yaml.dump(run_dict, handle)
|
|
46
|
+
|
|
47
|
+
with con.cd(tmp_dir):
|
|
48
|
+
tmp_parent = Path(tmp_dir).parent
|
|
49
|
+
tar_target = tmp_parent / self.tar_fn
|
|
50
|
+
con.put(self.yaml_fn, tmp_dir)
|
|
51
|
+
# yaml_str = yaml.dump(run_dict)
|
|
52
|
+
# con.run(f"cat > {self.yaml_fn} <<EOL\n{yaml_str}\nEOL")
|
|
53
|
+
# Execute pysis with prefix, e.g. activation of conda env or venv
|
|
54
|
+
with con.prefix(self.prefix):
|
|
55
|
+
con.run(f"pysis {self.yaml_fn}", hide=True)
|
|
56
|
+
# Pack the whole directory
|
|
57
|
+
con.run(f"tar -czf {tar_target} .")
|
|
58
|
+
# and download it.
|
|
59
|
+
con.get(tar_target, self.tar_fn)
|
|
60
|
+
con.run(f"rm -r {tmp_dir}")
|
|
61
|
+
return self.parse_results()
|
|
62
|
+
|
|
63
|
+
def parse_results(self):
|
|
64
|
+
with tarfile.open(self.tar_fn, "r:gz") as tfile:
|
|
65
|
+
as_json = tfile.extractfile("./calculator_000.000.results").read()
|
|
66
|
+
results = json_to_results(as_json)
|
|
67
|
+
return results
|
|
68
|
+
|
|
69
|
+
def get_energy(self, atoms, coords, **prepare_kwargs):
|
|
70
|
+
return self.run_calculation(atoms, coords, run_func="get_energy")
|
|
71
|
+
|
|
72
|
+
def get_forces(self, atoms, coords, **prepare_kwargs):
|
|
73
|
+
return self.run_calculation(atoms, coords, run_func="get_forces")
|
|
74
|
+
|
|
75
|
+
def get_hessian(self, atoms, coords, **prepare_kwargs):
|
|
76
|
+
return self.run_calculation(atoms, coords, run_func="get_hessian")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pysisyphus.calculators.AnaPotBase import AnaPotBase
|
|
4
|
+
|
|
5
|
+
class Rosenbrock(AnaPotBase):
|
|
6
|
+
|
|
7
|
+
def __init__(self):
|
|
8
|
+
V_str = "(1-x)**2 + 100*(y - x**2)**2"
|
|
9
|
+
xlim = (-2.5, 2.5)
|
|
10
|
+
ylim = (-1.5, 3.5)
|
|
11
|
+
levels = np.logspace(-5, 10, 50, base=2)
|
|
12
|
+
super().__init__(V_str=V_str, xlim=xlim, ylim=ylim, levels=levels)
|
|
13
|
+
|
|
14
|
+
def __str__(self):
|
|
15
|
+
return "Rosenbrock calculator"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import socket
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.calculators.Calculator import Calculator
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SocketCalc(Calculator):
|
|
10
|
+
|
|
11
|
+
valid_requests = ("energy", "forces", "hessian")
|
|
12
|
+
|
|
13
|
+
def __init__(self, *args, host="localhost", port=8080, **kwargs):
|
|
14
|
+
super().__init__(*args, **kwargs)
|
|
15
|
+
|
|
16
|
+
self.port = port
|
|
17
|
+
self.host = host
|
|
18
|
+
|
|
19
|
+
def listen_for(self, atoms, coords, request):
|
|
20
|
+
request = request.lower()
|
|
21
|
+
assert request.lower() in self.valid_requests, \
|
|
22
|
+
f"Invalid request '{request}'! Valid requests are '{self.valid_requests}'."
|
|
23
|
+
|
|
24
|
+
request_for = {
|
|
25
|
+
"atoms": atoms,
|
|
26
|
+
"coords": coords.tolist(),
|
|
27
|
+
"request": request,
|
|
28
|
+
}
|
|
29
|
+
request_for = json.dumps(request_for).encode("utf-8")
|
|
30
|
+
|
|
31
|
+
# Create socket
|
|
32
|
+
sock = socket.socket()
|
|
33
|
+
# Allow reuse
|
|
34
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
35
|
+
sock.bind((self.host, self.port))
|
|
36
|
+
|
|
37
|
+
sock.listen(0)
|
|
38
|
+
while True:
|
|
39
|
+
client, address = sock.accept()
|
|
40
|
+
|
|
41
|
+
with client:
|
|
42
|
+
self.log(f"Got connection from {address}")
|
|
43
|
+
|
|
44
|
+
# Send atom, coordinates and the request type
|
|
45
|
+
client.sendall(request_for)
|
|
46
|
+
|
|
47
|
+
to_json = b""
|
|
48
|
+
while True:
|
|
49
|
+
data = client.recv(1024)
|
|
50
|
+
to_json += data
|
|
51
|
+
|
|
52
|
+
# Read until linebreak is found
|
|
53
|
+
if b"\n" in data:
|
|
54
|
+
self.log("Found linebreaking. Stop listening.")
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
# Try to parse received data as JSON
|
|
58
|
+
results = dict()
|
|
59
|
+
try:
|
|
60
|
+
to_json.decode("utf-8")
|
|
61
|
+
results = json.loads(to_json)
|
|
62
|
+
except json.JSONDecodeError:
|
|
63
|
+
self.log("JSON decode error")
|
|
64
|
+
|
|
65
|
+
# Check if all required fields are present in the results. The
|
|
66
|
+
# energy has to be always present.
|
|
67
|
+
if ("energy" in results) and (request in results):
|
|
68
|
+
self.log("All required fields are present in the received JSON. "
|
|
69
|
+
"Breaking.")
|
|
70
|
+
break
|
|
71
|
+
else:
|
|
72
|
+
self.log("Could not parse received data as JSON!")
|
|
73
|
+
|
|
74
|
+
sock.close()
|
|
75
|
+
|
|
76
|
+
# energy has to be always present
|
|
77
|
+
results = {key: results[key] for key in ("energy", request)}
|
|
78
|
+
|
|
79
|
+
if "forces" in results:
|
|
80
|
+
results["forces"] = np.array(results["forces"], dtype=float)
|
|
81
|
+
|
|
82
|
+
if "hessian" in results:
|
|
83
|
+
results["hessian"] = np.array(results["hessian"],
|
|
84
|
+
dtype=float).reshape(-1, 3*len(atoms))
|
|
85
|
+
return results
|
|
86
|
+
|
|
87
|
+
def get_energy(self, atoms, coords):
|
|
88
|
+
result = self.listen_for(atoms, coords, "energy")
|
|
89
|
+
return result
|
|
90
|
+
|
|
91
|
+
def get_forces(self, atoms, coords):
|
|
92
|
+
result = self.listen_for(atoms, coords, "forces")
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
def get_hessian(self, atoms, coords):
|
|
96
|
+
result = self.listen_for(atoms, coords, "hessian")
|
|
97
|
+
return result
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pysisyphus.constants import ANG2BOHR, AU2KJPERMOL
|
|
4
|
+
from pysisyphus.calculators.Calculator import Calculator
|
|
5
|
+
from pysisyphus.calculators.LennardJones import LennardJones
|
|
6
|
+
|
|
7
|
+
# [1] https://aip.scitation.org/doi/abs/10.1063/1.445869
|
|
8
|
+
# Jorgensen, 1983
|
|
9
|
+
# [2] https://pubs.acs.org/doi/pdf/10.1021/ja00344a001
|
|
10
|
+
# Jorgensen, 1983
|
|
11
|
+
# Not yet implemented
|
|
12
|
+
# OPC3, https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4991989/
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TIP3P(Calculator):
|
|
16
|
+
"""Transferable Intermolecular Potential 3 Point"""
|
|
17
|
+
rOH = 0.9572 * ANG2BOHR
|
|
18
|
+
aHOH = 104.52 # deg
|
|
19
|
+
# Charges
|
|
20
|
+
qH = +0.4170
|
|
21
|
+
qO = -2*qH
|
|
22
|
+
sigma = 3.15061 * ANG2BOHR
|
|
23
|
+
epsilon = 0.6364 / AU2KJPERMOL
|
|
24
|
+
|
|
25
|
+
# rc = 5 Å in Bohr
|
|
26
|
+
def __init__(self, rc=9.44863062728914):
|
|
27
|
+
super().__init__()
|
|
28
|
+
|
|
29
|
+
# Cutoff distance
|
|
30
|
+
self.rc = rc
|
|
31
|
+
self.lj = LennardJones(sigma=self.sigma, epsilon=self.epsilon, rc=self.rc)
|
|
32
|
+
|
|
33
|
+
self.charges = np.array((self.qO, self.qH, self.qH))
|
|
34
|
+
"""
|
|
35
|
+
coulomb_energy = (multiple of elem. charge * multiple of elem. charge)
|
|
36
|
+
/ (distance in bohr) * 1 / (4 * pi * vacuum permittivity)
|
|
37
|
+
|
|
38
|
+
coulomb_prefactor converts everything to atomic units and it is ... drum
|
|
39
|
+
roll ... 1.
|
|
40
|
+
from scipy.constants import value as pcval
|
|
41
|
+
self.coulomb_prefactor = (1 / (4 * np.pi) * pcval("elementary charge")**2
|
|
42
|
+
/ pcval("Hartree energy") / pcval("Bohr radius")
|
|
43
|
+
/ pcval("vacuum electric permittivity")
|
|
44
|
+
)
|
|
45
|
+
"""
|
|
46
|
+
self.coulomb_prefactor = 1
|
|
47
|
+
|
|
48
|
+
def coulomb(self, coords3d):
|
|
49
|
+
waters = coords3d.shape[0] // 3
|
|
50
|
+
if waters == 1:
|
|
51
|
+
return 0., np.zeros((3, 3))
|
|
52
|
+
stencil = np.array((0, 1, 2))
|
|
53
|
+
# Pair indices of the interacting water molecules
|
|
54
|
+
a, b = np.triu_indices(waters, 1)
|
|
55
|
+
|
|
56
|
+
# Pair indices of the respective interacting atoms
|
|
57
|
+
# a: 0, 1, 2, 0, 1, 2, 0, 1, 2, ...
|
|
58
|
+
a = (3*np.repeat(a, 3)[:, None] + stencil).flatten()
|
|
59
|
+
# b: 3, 3, 3, 4, 4, 4, 5, 5, 5, ...
|
|
60
|
+
b = np.repeat((3 * b[:, None] + stencil).flatten(), 3)
|
|
61
|
+
|
|
62
|
+
# Pair coordinate differences
|
|
63
|
+
diffs = coords3d[a] - coords3d[b] # Shape: (Interacting pairs, 3)
|
|
64
|
+
# Distances
|
|
65
|
+
rs = np.linalg.norm(diffs, axis=1)
|
|
66
|
+
|
|
67
|
+
# Assemble water charges for all atoms/coordinates
|
|
68
|
+
charges = np.tile(self.charges, coords3d.shape[0] // 3)
|
|
69
|
+
# Keep the uncontracted pair-energies, as we still need them for the
|
|
70
|
+
# gradient.
|
|
71
|
+
pair_energies = self.coulomb_prefactor * charges[a] * charges[b] / rs
|
|
72
|
+
energy = pair_energies.sum()
|
|
73
|
+
|
|
74
|
+
# See the LennardJones calculator for the explicit derivation of the
|
|
75
|
+
# derivative of 1/r**n.
|
|
76
|
+
products = (pair_energies / rs**2)[:, None] * diffs
|
|
77
|
+
|
|
78
|
+
gradient = np.zeros_like(coords3d)
|
|
79
|
+
# Every pair (a, b) contributes to the total gradient of atoms a and b.
|
|
80
|
+
for i, prod in enumerate(products):
|
|
81
|
+
gradient[a[i]] -= prod
|
|
82
|
+
gradient[b[i]] += prod
|
|
83
|
+
|
|
84
|
+
return energy, -gradient
|
|
85
|
+
|
|
86
|
+
def calculate(self, coords3d):
|
|
87
|
+
coulomb_energy, coulomb_forces = self.coulomb(coords3d)
|
|
88
|
+
|
|
89
|
+
# Lennard-Jones interaction between Oxygens only
|
|
90
|
+
o_coords3d = coords3d[::3]
|
|
91
|
+
lj_energy, lj_forces = self.lj.calculate(o_coords3d)
|
|
92
|
+
|
|
93
|
+
forces = np.zeros_like(coords3d)
|
|
94
|
+
forces[::3] += lj_forces
|
|
95
|
+
|
|
96
|
+
forces = coulomb_forces.copy()
|
|
97
|
+
# Add LennardJones forces to oxygens
|
|
98
|
+
forces[::3] += lj_forces
|
|
99
|
+
energy = coulomb_energy + lj_energy
|
|
100
|
+
|
|
101
|
+
return energy, forces
|
|
102
|
+
|
|
103
|
+
def get_energy(self, atoms, coords):
|
|
104
|
+
energy, _ = self.calculate(coords.reshape(-1, 3))
|
|
105
|
+
return {"energy": energy}
|
|
106
|
+
|
|
107
|
+
def get_forces(self, atoms, coords):
|
|
108
|
+
energy, forces = self.calculate(coords.reshape(-1, 3))
|
|
109
|
+
return {"energy": energy,
|
|
110
|
+
"forces": forces.flatten(),
|
|
111
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# [1] https://doi.org/10.1002/jcc.26495
|
|
2
|
+
# Habershon, 2021
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_trans_torque_forces(
|
|
8
|
+
mfrag,
|
|
9
|
+
a_coords3d,
|
|
10
|
+
b_coords3d,
|
|
11
|
+
a_mats,
|
|
12
|
+
b_mats,
|
|
13
|
+
m,
|
|
14
|
+
frags,
|
|
15
|
+
N_inv,
|
|
16
|
+
weight_func=None,
|
|
17
|
+
skip=True,
|
|
18
|
+
kappa=1,
|
|
19
|
+
do_trans=True,
|
|
20
|
+
):
|
|
21
|
+
mcoords3d = a_coords3d[mfrag]
|
|
22
|
+
gm = mcoords3d.mean(axis=0)
|
|
23
|
+
|
|
24
|
+
if weight_func is None:
|
|
25
|
+
|
|
26
|
+
def weight_func(m, n, a, b):
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
trans_vec = np.zeros(3)
|
|
30
|
+
rot_vec = np.zeros(3)
|
|
31
|
+
for n, nfrag in enumerate(frags):
|
|
32
|
+
if skip and (m == n):
|
|
33
|
+
continue
|
|
34
|
+
amn = a_mats[(m, n)]
|
|
35
|
+
bnm = b_mats[(n, m)]
|
|
36
|
+
for a in amn:
|
|
37
|
+
for b in bnm:
|
|
38
|
+
rd = b_coords3d[b] - a_coords3d[a]
|
|
39
|
+
gd = a_coords3d[a] - gm
|
|
40
|
+
weight = weight_func(m, n, a, b)
|
|
41
|
+
|
|
42
|
+
rot_vec += weight * np.cross(rd, gd)
|
|
43
|
+
if do_trans:
|
|
44
|
+
trans_vec += weight * abs(rd.dot(gd)) * rd / np.linalg.norm(rd)
|
|
45
|
+
trans_vec *= N_inv
|
|
46
|
+
rot_vec *= N_inv
|
|
47
|
+
forces = kappa * (np.cross(-rot_vec, mcoords3d - gm) + trans_vec[None, :])
|
|
48
|
+
return forces
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TransTorque:
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
frags,
|
|
55
|
+
iter_frags,
|
|
56
|
+
a_mats,
|
|
57
|
+
b_mats,
|
|
58
|
+
weight_func=None,
|
|
59
|
+
skip=True,
|
|
60
|
+
kappa=1.0,
|
|
61
|
+
b_coords3d=None,
|
|
62
|
+
do_trans=True,
|
|
63
|
+
):
|
|
64
|
+
"""Translational and torque forces.
|
|
65
|
+
See A.4. [1], Eqs. (A3) - (A5).
|
|
66
|
+
"""
|
|
67
|
+
self.frags = frags
|
|
68
|
+
self.iter_frags = iter_frags
|
|
69
|
+
self.a_mats = a_mats
|
|
70
|
+
self.b_mats = b_mats
|
|
71
|
+
self.weight_func = weight_func
|
|
72
|
+
self.kappa = kappa
|
|
73
|
+
self.skip = skip
|
|
74
|
+
self.b_coords3d = b_coords3d
|
|
75
|
+
self.do_trans = do_trans
|
|
76
|
+
|
|
77
|
+
self.set_N_invs()
|
|
78
|
+
|
|
79
|
+
def set_N_invs(self):
|
|
80
|
+
Ns = np.zeros(len(self.frags))
|
|
81
|
+
for m, mfrag in enumerate(self.frags):
|
|
82
|
+
for n, _ in enumerate(self.iter_frags):
|
|
83
|
+
if self.skip and (m == n):
|
|
84
|
+
continue
|
|
85
|
+
amn = self.a_mats[(m, n)]
|
|
86
|
+
bnm = self.b_mats[(n, m)]
|
|
87
|
+
Ns[m] += len(amn) * len(bnm)
|
|
88
|
+
Ns[m] *= 3 * len(mfrag)
|
|
89
|
+
self.N_invs = np.divide(1, Ns, out=np.zeros_like(Ns), where=Ns != 0)
|
|
90
|
+
|
|
91
|
+
def get_forces(self, atoms, coords, kappa=None):
|
|
92
|
+
if kappa is None:
|
|
93
|
+
kappa = self.kappa
|
|
94
|
+
c3d = coords.reshape(-1, 3)
|
|
95
|
+
forces = np.zeros_like(c3d)
|
|
96
|
+
|
|
97
|
+
b_coords3d = c3d if self.b_coords3d is None else self.b_coords3d
|
|
98
|
+
|
|
99
|
+
for m, mfrag in enumerate(self.frags):
|
|
100
|
+
N_inv = self.N_invs[m]
|
|
101
|
+
tt_forces = get_trans_torque_forces(
|
|
102
|
+
mfrag,
|
|
103
|
+
c3d,
|
|
104
|
+
b_coords3d,
|
|
105
|
+
self.a_mats,
|
|
106
|
+
self.b_mats,
|
|
107
|
+
m,
|
|
108
|
+
self.iter_frags,
|
|
109
|
+
N_inv,
|
|
110
|
+
weight_func=self.weight_func,
|
|
111
|
+
skip=self.skip,
|
|
112
|
+
do_trans=self.do_trans,
|
|
113
|
+
kappa=kappa,
|
|
114
|
+
)
|
|
115
|
+
forces[mfrag] = tt_forces
|
|
116
|
+
|
|
117
|
+
return {"energy": 1, "forces": forces.flatten()}
|
|
118
|
+
|
|
119
|
+
def get_forces_naive(self, atoms, coords, kappa=None):
|
|
120
|
+
if kappa is None:
|
|
121
|
+
kappa = self.kappa
|
|
122
|
+
|
|
123
|
+
AR = self.a_mats
|
|
124
|
+
Ns = np.zeros(len(self.frags))
|
|
125
|
+
for m, mfrag in enumerate(self.frags):
|
|
126
|
+
for n, nfrag in enumerate(self.frags):
|
|
127
|
+
if m == n:
|
|
128
|
+
continue
|
|
129
|
+
Ns[m] += len(AR[(n, m)]) * len(AR[(m, n)])
|
|
130
|
+
Ns[m] *= 3 * len(mfrag)
|
|
131
|
+
|
|
132
|
+
c3d = coords.reshape(-1, 3).copy()
|
|
133
|
+
f3d = np.zeros_like(c3d)
|
|
134
|
+
vts = np.zeros((len(self.frags), 3))
|
|
135
|
+
vrs = np.zeros((len(self.frags), 3))
|
|
136
|
+
for m, mfrag in enumerate(self.frags):
|
|
137
|
+
gm = c3d[mfrag].mean(axis=0)
|
|
138
|
+
c3dm = c3d[mfrag]
|
|
139
|
+
for n, nfrag in enumerate(self.frags):
|
|
140
|
+
if m == n:
|
|
141
|
+
continue
|
|
142
|
+
for a in AR[(m, n)]:
|
|
143
|
+
for b in AR[(n, m)]:
|
|
144
|
+
rdiff = c3d[b] - c3d[a]
|
|
145
|
+
rdiffn = np.linalg.norm(rdiff)
|
|
146
|
+
rg = c3d[a] - gm
|
|
147
|
+
quot = rdiff / rdiffn
|
|
148
|
+
dot = rdiff.dot(rg)
|
|
149
|
+
vts[m] += abs(dot) * quot
|
|
150
|
+
vrs[m] += np.cross(rdiff, rg)
|
|
151
|
+
vts[m] /= Ns[m]
|
|
152
|
+
vrs[m] /= Ns[m]
|
|
153
|
+
if not self.do_trans:
|
|
154
|
+
vts[m] = 0.0
|
|
155
|
+
f3d[mfrag] = kappa * (-np.cross(vrs[m], c3dm-gm[None, :]) + vts[m])
|
|
156
|
+
|
|
157
|
+
forces = f3d.flatten()
|
|
158
|
+
return {"energy": 1, "forces": forces}
|
|
159
|
+
|
|
160
|
+
# def get_forces(self, atoms, coords, kappa=None):
|
|
161
|
+
# return self.get_forces_naive(atoms, coords, kappa=kappa)
|