mstk 0.3.3.dev11__tar.gz → 0.3.4__tar.gz
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.
- {mstk-0.3.3.dev11 → mstk-0.3.4}/PKG-INFO +9 -1
- {mstk-0.3.3.dev11 → mstk-0.3.4}/README.md +8 -0
- mstk-0.3.4/mstk/errors.py +14 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/typer/zft.py +1 -1
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/reporter/statedatareporter.py +17 -5
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/utils.py +9 -4
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/scheduler/slurm.py +2 -2
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/simsys/ommexporter.py +10 -7
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/connectivity.py +35 -4
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/geometry.py +30 -4
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/pdb.py +1 -1
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/molecule.py +51 -17
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/trajectory.py +11 -4
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/utils/__init__.py +9 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk.egg-info/PKG-INFO +9 -1
- mstk-0.3.4/scripts/analyze-rdf.py +136 -0
- mstk-0.3.4/scripts/logplot.py +212 -0
- mstk-0.3.4/scripts/topconv.py +87 -0
- mstk-0.3.4/scripts/trjconv.py +87 -0
- mstk-0.3.4/scripts/wham-pp.py +115 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/setup.py +1 -1
- mstk-0.3.3.dev11/mstk/errors.py +0 -30
- mstk-0.3.3.dev11/scripts/analyze-rdf.py +0 -129
- mstk-0.3.3.dev11/scripts/logplot.py +0 -156
- mstk-0.3.3.dev11/scripts/topconv.py +0 -65
- mstk-0.3.3.dev11/scripts/trjconv.py +0 -66
- mstk-0.3.3.dev11/scripts/wham-pp.py +0 -108
- {mstk-0.3.3.dev11 → mstk-0.3.4}/LICENSE +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/canny.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/energy_kernels.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/ewald.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/fitting.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/neighborlist.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/series.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/structure.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/analyzer/vle.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/chem/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/chem/constant.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/chem/element.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/chem/formula.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/chem/rdkit.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/data/forcefield/SPICA_v1.zfp +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/data/forcefield/primitive.zff +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/data/forcefield/primitive.zft +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/dff_utils.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/errors.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/ffterm.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/forcefield.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/io/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/io/padua.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/io/ppf.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/io/zff.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/io/zfp.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/typer/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/forcefield/typer/typer.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/misc/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/misc/docmeta.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/misc/singleton.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/force.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/grofile.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/reporter/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/reporter/checkpointreporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/reporter/drudetemperaturereporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/reporter/groreporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/reporter/viscosityreporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/ommhelper/unit.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/scheduler/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/scheduler/pbsjob.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/scheduler/remote_slurm.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/scheduler/scheduler.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/simsys/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/simsys/gmxexporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/simsys/lmpexporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/simsys/namdexporter.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/simsys/system.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/atom.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/lammps.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/msd.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/psf.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/smi.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/xyz.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/io/zmat.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/residue.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/topology.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/unitcell.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/topology/virtualsite.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/frame.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/handler.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/combined_trj.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/dcd.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/gro.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/lammps.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/xtc.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/trajectory/io/xyz.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/wrapper/__init__.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/wrapper/gauss.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/wrapper/gmx.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/wrapper/packmol.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk/wrapper/panedr.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk.egg-info/SOURCES.txt +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk.egg-info/dependency_links.txt +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/mstk.egg-info/top_level.txt +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/scripts/ffconv.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/scripts/quick-sim.py +0 -0
- {mstk-0.3.3.dev11 → mstk-0.3.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mstk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Molecular simulation toolkit
|
|
5
5
|
Home-page: https://github.com/z-gong/mstk
|
|
6
6
|
Author: Zheng Gong
|
|
@@ -69,3 +69,11 @@ https://mstk.readthedocs.io/en/latest/index.html
|
|
|
69
69
|
|
|
70
70
|
- [ ] Take bond order into consideration for force field assignment
|
|
71
71
|
- [ ] Re-organize algorithms scattered in topology and analyzer modules
|
|
72
|
+
|
|
73
|
+
## Known issue
|
|
74
|
+
`mstk` use `chemfiles` to write `XTC` trajectory. However, lastest `chemfiles` is buggy under WSL for writing binary trajectory format.
|
|
75
|
+
If you are working under WSL, please install `chemfiles 0.10.2`.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
conda install chemfiles-lib=0.10.2 chemfiles-python=0.10.2
|
|
79
|
+
```
|
|
@@ -56,3 +56,11 @@ https://mstk.readthedocs.io/en/latest/index.html
|
|
|
56
56
|
|
|
57
57
|
- [ ] Take bond order into consideration for force field assignment
|
|
58
58
|
- [ ] Re-organize algorithms scattered in topology and analyzer modules
|
|
59
|
+
|
|
60
|
+
## Known issue
|
|
61
|
+
`mstk` use `chemfiles` to write `XTC` trajectory. However, lastest `chemfiles` is buggy under WSL for writing binary trajectory format.
|
|
62
|
+
If you are working under WSL, please install `chemfiles 0.10.2`.
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
conda install chemfiles-lib=0.10.2 chemfiles-python=0.10.2
|
|
66
|
+
```
|
|
@@ -98,7 +98,7 @@ class ZftTyper(Typer):
|
|
|
98
98
|
|
|
99
99
|
Notes
|
|
100
100
|
-----
|
|
101
|
-
* SMARTS is parsed by using
|
|
101
|
+
* SMARTS is parsed by using RDKit package. Make sure it is installed.
|
|
102
102
|
* In type definition file, empty lines are ignored, and comments should start with ##.
|
|
103
103
|
|
|
104
104
|
'''
|
|
@@ -122,7 +122,7 @@ class StateDataReporter(object):
|
|
|
122
122
|
'''
|
|
123
123
|
|
|
124
124
|
def __init__(self, file, reportInterval, step=True, time=False, potentialEnergy=True,
|
|
125
|
-
kineticEnergy=False, totalEnergy=False, temperature=True, volume=
|
|
125
|
+
kineticEnergy=False, totalEnergy=False, temperature=True, volume=True, box=True,
|
|
126
126
|
density=True, progress=False, remainingTime=False, speed=True, elapsedTime=False,
|
|
127
127
|
separator='\t', systemMass=None, totalSteps=None, append=False,
|
|
128
128
|
cvs=None, pressure=True, pxx=False, pyy=False, pzz=False, extra={}):
|
|
@@ -314,8 +314,7 @@ class StateDataReporter(object):
|
|
|
314
314
|
|
|
315
315
|
bool_press = [self._pxx, self._pyy, self._pzz]
|
|
316
316
|
if any(bool_press):
|
|
317
|
-
|
|
318
|
-
values.extend(self._compute_anisotropic_pressure(simulation.context, state, indexes))
|
|
317
|
+
values.extend(self._compute_anisotropic_pressure(simulation.context, state, *bool_press))
|
|
319
318
|
|
|
320
319
|
if self._extra:
|
|
321
320
|
values.extend(self._extra.values())
|
|
@@ -467,9 +466,20 @@ class StateDataReporter(object):
|
|
|
467
466
|
|
|
468
467
|
return p_kinetic + p_virial
|
|
469
468
|
|
|
470
|
-
def _compute_anisotropic_pressure(self, context
|
|
469
|
+
def _compute_anisotropic_pressure(self, context, state, pxx, pyy, pzz):
|
|
471
470
|
'''
|
|
472
471
|
Compute the anisotropic pressure of a rectangular system
|
|
472
|
+
|
|
473
|
+
Parameters
|
|
474
|
+
----------
|
|
475
|
+
context : mm.Context
|
|
476
|
+
state : mm.State
|
|
477
|
+
pxx : bool
|
|
478
|
+
Whether or not the Pxx be calculated
|
|
479
|
+
pyy : bool
|
|
480
|
+
Whether or not the Pyy be calculated
|
|
481
|
+
pzz : bool
|
|
482
|
+
Whether or not the Pzz be calculated
|
|
473
483
|
'''
|
|
474
484
|
box = state.getPeriodicBoxVectors(asNumpy=True)
|
|
475
485
|
positions = state.getPositions(asNumpy=True)
|
|
@@ -485,7 +495,9 @@ class StateDataReporter(object):
|
|
|
485
495
|
|
|
486
496
|
scale = 0.0001
|
|
487
497
|
pressures = []
|
|
488
|
-
for index in
|
|
498
|
+
for index, _bool in enumerate([pxx, pyy, pzz]):
|
|
499
|
+
if not _bool:
|
|
500
|
+
continue
|
|
489
501
|
scale_array = np.array([1.0, 1.0, 1.0])
|
|
490
502
|
scale_array[index] = 1 + scale
|
|
491
503
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import openmm
|
|
2
|
-
import openmm.openmm as mm
|
|
3
1
|
import numpy as np
|
|
4
|
-
|
|
2
|
+
import openmm
|
|
3
|
+
from openmm import openmm as mm, app
|
|
5
4
|
from .grofile import GroFile
|
|
6
5
|
from .unit import kelvin, bar, nm, ps
|
|
7
6
|
|
|
@@ -68,6 +67,12 @@ def apply_mc_barostat(system, pcoupl, P, T, nsteps=100, logger=None):
|
|
|
68
67
|
'''
|
|
69
68
|
Add a MonteCarlo barostat to the system and return the index of the added barostat
|
|
70
69
|
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
system : mm.System
|
|
73
|
+
pcoupl : str
|
|
74
|
+
The type of barostat. Can be one of the following: iso, semi-iso, aniso, xy, z.
|
|
75
|
+
|
|
71
76
|
Returns
|
|
72
77
|
-------
|
|
73
78
|
idx : index of the added barostat force
|
|
@@ -80,7 +85,7 @@ def apply_mc_barostat(system, pcoupl, P, T, nsteps=100, logger=None):
|
|
|
80
85
|
force = mm.MonteCarloMembraneBarostat(P * bar, 0 * bar * nm, T * kelvin,
|
|
81
86
|
mm.MonteCarloMembraneBarostat.XYIsotropic,
|
|
82
87
|
mm.MonteCarloMembraneBarostat.ZFree, nsteps)
|
|
83
|
-
elif pcoupl == '
|
|
88
|
+
elif pcoupl == 'aniso':
|
|
84
89
|
msg = 'Anisotropic barostat'
|
|
85
90
|
force = mm.MonteCarloAnisotropicBarostat([P * bar] * 3, T * kelvin, True, True, True, nsteps)
|
|
86
91
|
elif pcoupl == 'xy':
|
|
@@ -109,8 +109,8 @@ class Slurm(Scheduler):
|
|
|
109
109
|
workdir = Path(workdir).absolute().as_posix()
|
|
110
110
|
sh = sh or self.sh
|
|
111
111
|
sh_basename = Path(sh).stem
|
|
112
|
-
out =
|
|
113
|
-
err =
|
|
112
|
+
out = sh_basename + '.out'
|
|
113
|
+
err = sh_basename + '.err'
|
|
114
114
|
node_cmd = f'#SBATCH --nodes={self.n_node}\n' if self.n_node > 0 else ''
|
|
115
115
|
gpu_cmd = f'#SBATCH --gres=gpu:{self.n_gpu}\n' if self.n_gpu > 0 else ''
|
|
116
116
|
dep_cmd = f'#SBATCH --dependency=afterok:{id_prior}\n' if id_prior is not None else '' # id_prior can be 0
|
|
@@ -143,26 +143,29 @@ class OpenMMExporter:
|
|
|
143
143
|
elif angle_class == SDKAngleTerm:
|
|
144
144
|
logger.debug('Setting up SDK angles...')
|
|
145
145
|
aforce = mm.CustomCompoundBondForce(
|
|
146
|
-
3, 'k*(theta-theta0)^2+step(rmin-r)*
|
|
147
|
-
'
|
|
146
|
+
3, 'k*(theta-theta0)^2+step(rmin-r)*LJ;'
|
|
147
|
+
'LJ=C*epsilon*((sigma/r)^n-(sigma/r)^m)+epsilon;'
|
|
148
148
|
'theta=angle(p1,p2,p3);'
|
|
149
149
|
'r=distance(p1,p3);'
|
|
150
|
-
'
|
|
150
|
+
'C=n/(n-m)*(n/m)^(m/(n-m));'
|
|
151
|
+
'rmin=(n/m)^(1/(n-m))*sigma')
|
|
151
152
|
aforce.addPerBondParameter('theta0')
|
|
152
153
|
aforce.addPerBondParameter('k')
|
|
153
154
|
aforce.addPerBondParameter('epsilon')
|
|
154
155
|
aforce.addPerBondParameter('sigma')
|
|
156
|
+
aforce.addPerBondParameter('n')
|
|
157
|
+
aforce.addPerBondParameter('m')
|
|
155
158
|
for angle in top.angles:
|
|
156
159
|
if angle in system.constrain_angles:
|
|
157
160
|
continue
|
|
158
161
|
aterm = system.angle_terms[angle]
|
|
159
162
|
if type(aterm) != SDKAngleTerm:
|
|
160
163
|
continue
|
|
161
|
-
vdw = ff.get_vdw_term(ff.atom_types[angle.atom1.type], ff.atom_types[angle.
|
|
162
|
-
if type(vdw) != MieTerm
|
|
163
|
-
raise Exception(f'Corresponding
|
|
164
|
+
vdw = ff.get_vdw_term(ff.atom_types[angle.atom1.type], ff.atom_types[angle.atom3.type])
|
|
165
|
+
if type(vdw) != MieTerm:
|
|
166
|
+
raise Exception(f'Corresponding MieTerm for {aterm} not found in FF')
|
|
164
167
|
aforce.addBond([angle.atom1.id, angle.atom2.id, angle.atom3.id],
|
|
165
|
-
[aterm.theta, aterm.k, vdw.epsilon, vdw.sigma])
|
|
168
|
+
[aterm.theta, aterm.k, vdw.epsilon, vdw.sigma, vdw.repulsion, vdw.attraction])
|
|
166
169
|
elif angle_class == LinearAngleTerm:
|
|
167
170
|
logger.debug('Setting up linear angles...')
|
|
168
171
|
aforce = mm.CustomCompoundBondForce(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from .atom import Atom
|
|
3
|
+
from .geometry import periodic_distance, periodic_angle, periodic_dihedral
|
|
3
4
|
|
|
4
5
|
__all__ = [
|
|
5
6
|
'Bond',
|
|
@@ -115,14 +116,21 @@ class Bond():
|
|
|
115
116
|
'''
|
|
116
117
|
return self.atom1.is_drude or self.atom2.is_drude
|
|
117
118
|
|
|
118
|
-
def evaluate(self):
|
|
119
|
+
def evaluate(self, cell=None):
|
|
119
120
|
'''
|
|
120
121
|
Evaluate the length of this bond
|
|
121
122
|
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
box : UnitCell, Optional
|
|
126
|
+
|
|
122
127
|
Returns
|
|
123
128
|
-------
|
|
124
129
|
value : float
|
|
125
130
|
'''
|
|
131
|
+
if cell:
|
|
132
|
+
return periodic_distance(self.atom1.position, self.atom2.position, cell.size)
|
|
133
|
+
|
|
126
134
|
delta = self.atom2.position - self.atom1.position
|
|
127
135
|
return float(np.sqrt(delta.dot(delta)))
|
|
128
136
|
|
|
@@ -225,14 +233,21 @@ class Angle():
|
|
|
225
233
|
|
|
226
234
|
return bond12, bond23
|
|
227
235
|
|
|
228
|
-
def evaluate(self):
|
|
236
|
+
def evaluate(self, cell=None):
|
|
229
237
|
'''
|
|
230
238
|
Evaluate the value of this angle in unit of radian
|
|
231
239
|
|
|
240
|
+
Parameters
|
|
241
|
+
----------
|
|
242
|
+
cell : UnitCell, Optional
|
|
243
|
+
|
|
232
244
|
Returns
|
|
233
245
|
-------
|
|
234
246
|
value : float
|
|
235
247
|
'''
|
|
248
|
+
if cell:
|
|
249
|
+
return periodic_angle(self.atom1.position, self.atom2.position, self.atom3.position, cell)
|
|
250
|
+
|
|
236
251
|
vec1 = self.atom1.position - self.atom2.position
|
|
237
252
|
vec2 = self.atom3.position - self.atom2.position
|
|
238
253
|
cos = vec1.dot(vec2) / np.sqrt(vec1.dot(vec1) * vec2.dot(vec2))
|
|
@@ -361,14 +376,22 @@ class Dihedral():
|
|
|
361
376
|
|
|
362
377
|
return angle123, angle234
|
|
363
378
|
|
|
364
|
-
def evaluate(self):
|
|
379
|
+
def evaluate(self, cell=None):
|
|
365
380
|
'''
|
|
366
381
|
Evaluate the value of this dihedral in unit of radian
|
|
367
382
|
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
cell : UnitCell, Optional
|
|
386
|
+
|
|
368
387
|
Returns
|
|
369
388
|
-------
|
|
370
389
|
value : float
|
|
371
390
|
'''
|
|
391
|
+
if cell:
|
|
392
|
+
return periodic_dihedral(self.atom1.position, self.atom2.position, self.atom3.position, self.atom4.position,
|
|
393
|
+
cell.size)
|
|
394
|
+
|
|
372
395
|
vec1 = self.atom2.position - self.atom1.position
|
|
373
396
|
vec2 = self.atom3.position - self.atom2.position
|
|
374
397
|
vec3 = self.atom4.position - self.atom3.position
|
|
@@ -450,15 +473,23 @@ class Improper():
|
|
|
450
473
|
'''
|
|
451
474
|
return self.atom1, self.atom2, self.atom3, self.atom4
|
|
452
475
|
|
|
453
|
-
def evaluate(self):
|
|
476
|
+
def evaluate(self, cell=None):
|
|
454
477
|
'''
|
|
455
478
|
Evaluate the value of this improper torsion in unit of radian.
|
|
456
479
|
The improper is defined as the angle between plane a1-a2-a3 and a2-a3-a4.
|
|
457
480
|
|
|
481
|
+
Parameters
|
|
482
|
+
----------
|
|
483
|
+
cell : UnitCell, Optional
|
|
484
|
+
|
|
458
485
|
Returns
|
|
459
486
|
-------
|
|
460
487
|
value : float
|
|
461
488
|
'''
|
|
489
|
+
if cell:
|
|
490
|
+
return periodic_dihedral(self.atom1.position, self.atom2.position, self.atom3.position, self.atom4.position,
|
|
491
|
+
cell.size)
|
|
492
|
+
|
|
462
493
|
vec1 = self.atom2.position - self.atom1.position
|
|
463
494
|
vec2 = self.atom3.position - self.atom2.position
|
|
464
495
|
vec3 = self.atom4.position - self.atom3.position
|
|
@@ -62,6 +62,22 @@ def grow_particle(pos1, pos2, bond, angle):
|
|
|
62
62
|
return pos2 + w * bond
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
def relocate_hydrogen(hydrogen):
|
|
66
|
+
'''
|
|
67
|
+
Update the position of a hydrogen atom according to the parent atom and other neighbors of parent
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
hydrogen : Atom
|
|
72
|
+
'''
|
|
73
|
+
vector = np.array([0., 0., 0.])
|
|
74
|
+
parent = hydrogen.bond_partners[0]
|
|
75
|
+
for atom in parent.bond_partners:
|
|
76
|
+
if atom is not hydrogen:
|
|
77
|
+
vector += atom.position - parent.position
|
|
78
|
+
hydrogen.position = parent.position - vector / np.sqrt(np.dot(vector, vector)) * 0.1 # bXH = 0.1 nm
|
|
79
|
+
|
|
80
|
+
|
|
65
81
|
def periodic_distance(pos1, pos2, box, distance_max=None):
|
|
66
82
|
'''
|
|
67
83
|
Calculate the distance between two points under periodic boundary condition
|
|
@@ -155,7 +171,7 @@ def periodic_dihedral(pos1, pos2, pos3, pos4, box):
|
|
|
155
171
|
return sign * value
|
|
156
172
|
|
|
157
173
|
|
|
158
|
-
def find_clusters(elements, func):
|
|
174
|
+
def find_clusters(elements, func, show_progress=False):
|
|
159
175
|
'''
|
|
160
176
|
Group elements into clusters
|
|
161
177
|
|
|
@@ -175,7 +191,12 @@ def find_clusters(elements, func):
|
|
|
175
191
|
flag = [0] * n_element
|
|
176
192
|
n_cluster = 0
|
|
177
193
|
clusters = []
|
|
178
|
-
|
|
194
|
+
if show_progress:
|
|
195
|
+
from tqdm import tqdm
|
|
196
|
+
_iterator = tqdm(range(n_element))
|
|
197
|
+
else:
|
|
198
|
+
_iterator = range(n_element)
|
|
199
|
+
for i in _iterator:
|
|
179
200
|
if flag[i]:
|
|
180
201
|
continue
|
|
181
202
|
path = {i}
|
|
@@ -203,7 +224,7 @@ def find_clusters(elements, func):
|
|
|
203
224
|
return clusters
|
|
204
225
|
|
|
205
226
|
|
|
206
|
-
def find_clusters_consecutive(elements, func):
|
|
227
|
+
def find_clusters_consecutive(elements, func, show_progress=False):
|
|
207
228
|
'''
|
|
208
229
|
Group elements into clusters. If element i and j are in the same group, all elements between i and j will also be put in the same group.
|
|
209
230
|
|
|
@@ -223,7 +244,12 @@ def find_clusters_consecutive(elements, func):
|
|
|
223
244
|
flag = [0] * n_element
|
|
224
245
|
n_cluster = 0
|
|
225
246
|
clusters = []
|
|
226
|
-
|
|
247
|
+
if show_progress:
|
|
248
|
+
from tqdm import tqdm
|
|
249
|
+
_iterator = tqdm(range(n_element))
|
|
250
|
+
else:
|
|
251
|
+
_iterator = range(n_element)
|
|
252
|
+
for i in _iterator:
|
|
227
253
|
if not flag[i]:
|
|
228
254
|
n_cluster += 1
|
|
229
255
|
flag[i] = n_cluster
|
|
@@ -176,7 +176,7 @@ class Pdb:
|
|
|
176
176
|
atom_name = atom.type if atom_type else atom.name
|
|
177
177
|
resname = atom.residue.name
|
|
178
178
|
resid = atom.residue.id + 1
|
|
179
|
-
line = 'HETATM%5d %4s
|
|
179
|
+
line = 'HETATM%5d %4s %-4s %4d %8.3f%8.3f%8.3f %2s\n' % (
|
|
180
180
|
(atom.id + 1) % 100000, atom_name[:4], resname[:4], resid % 10000,
|
|
181
181
|
pos[0], pos[1], pos[2], atom.symbol[:2])
|
|
182
182
|
string += line
|
|
@@ -214,27 +214,22 @@ class Molecule():
|
|
|
214
214
|
The `rdkit.Chem.Mol` object associated with this molecule.
|
|
215
215
|
|
|
216
216
|
It is required by ZftTyper typing engine, which performs SMARTS matching on the molecule.
|
|
217
|
-
The
|
|
218
|
-
If
|
|
217
|
+
The `rdmol` attribute will be assigned if the molecule is initialized from SMILES or RDKit Molecule.
|
|
218
|
+
If it is not available, a RDKit molecule will be constructed from atoms and bonds.
|
|
219
|
+
The positions will not be preserved.
|
|
219
220
|
|
|
220
221
|
Returns
|
|
221
222
|
-------
|
|
222
223
|
rdmol : rdkit.Chem.Mol
|
|
223
224
|
'''
|
|
224
|
-
if not self._is_rdmol_valid:
|
|
225
|
-
self._construct_rdmol()
|
|
226
|
-
|
|
227
|
-
return self._rdmol
|
|
228
|
-
|
|
229
|
-
def _construct_rdmol(self):
|
|
230
|
-
'''
|
|
231
|
-
Construct a RDKit molecule from atoms and bonds. The positions will not be preserved.
|
|
232
|
-
'''
|
|
233
225
|
try:
|
|
234
226
|
from rdkit import Chem
|
|
235
227
|
except ImportError:
|
|
236
228
|
raise ImportError('RDKit not found')
|
|
237
229
|
|
|
230
|
+
if self._is_rdmol_valid:
|
|
231
|
+
return self._rdmol
|
|
232
|
+
|
|
238
233
|
if any(b.order == Bond.Order.UNSPECIFIED for b in self.bonds):
|
|
239
234
|
logger.warning(f'Not all bond orders are specified in {self}')
|
|
240
235
|
|
|
@@ -256,6 +251,38 @@ class Molecule():
|
|
|
256
251
|
self._rdmol = rwmol.GetMol()
|
|
257
252
|
self._is_rdmol_valid = True
|
|
258
253
|
|
|
254
|
+
return self._rdmol
|
|
255
|
+
|
|
256
|
+
def generate_conformers(self, n_conformer=1):
|
|
257
|
+
'''
|
|
258
|
+
Generate several conformers with RDKit.
|
|
259
|
+
|
|
260
|
+
The positions will be generated from only elements and bonds. The chiral center will not be respected.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
n_conformer : int
|
|
265
|
+
How many conformers to generate
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
molecules : list of Molecule
|
|
270
|
+
Each conformer will be a independent molecule object
|
|
271
|
+
'''
|
|
272
|
+
try:
|
|
273
|
+
from rdkit.Chem import AllChem as Chem
|
|
274
|
+
except ImportError:
|
|
275
|
+
raise ImportError('RDKit not found')
|
|
276
|
+
|
|
277
|
+
molecules = []
|
|
278
|
+
rdmol = Chem.Mol(self.rdmol)
|
|
279
|
+
Chem.EmbedMultipleConfs(rdmol, numConfs=n_conformer, clearConfs=True)
|
|
280
|
+
for i in range(rdmol.GetNumConformers()):
|
|
281
|
+
molecules.append(Molecule.from_rdmol(rdmol, name=self.name))
|
|
282
|
+
rdmol.RemoveConformer(i)
|
|
283
|
+
|
|
284
|
+
return molecules
|
|
285
|
+
|
|
259
286
|
@property
|
|
260
287
|
def topology(self):
|
|
261
288
|
'''
|
|
@@ -317,6 +344,8 @@ class Molecule():
|
|
|
317
344
|
The angle, dihedral and improper involving this atom are untouched.
|
|
318
345
|
Therefore, you may call `generate_angle_dihedral_improper` to refresh the connectivity.
|
|
319
346
|
|
|
347
|
+
# TODO This operation is extremely slow
|
|
348
|
+
|
|
320
349
|
Parameters
|
|
321
350
|
----------
|
|
322
351
|
atom : Atom
|
|
@@ -351,13 +380,14 @@ class Molecule():
|
|
|
351
380
|
If update_topology is True, the topology this molecule belongs to will update its atom list and assign id for all atoms and residues.
|
|
352
381
|
Otherwise, you have to re-init the topology manually so that the topological information is correct.
|
|
353
382
|
|
|
383
|
+
# TODO This operation is extremely slow
|
|
384
|
+
|
|
354
385
|
Returns
|
|
355
386
|
-------
|
|
356
387
|
ids_removed : list of int
|
|
357
388
|
The number of atoms removed
|
|
358
389
|
'''
|
|
359
390
|
hydrogens = []
|
|
360
|
-
ids_removed = []
|
|
361
391
|
for atom in self.atoms[:]:
|
|
362
392
|
if atom.symbol != 'H' or len(atom.bonds) != 1:
|
|
363
393
|
continue
|
|
@@ -366,11 +396,13 @@ class Molecule():
|
|
|
366
396
|
continue
|
|
367
397
|
neigh.mass += atom.mass
|
|
368
398
|
neigh.charge += atom.charge
|
|
369
|
-
for conn in self.bonds[:] + self.angles[:] + self.dihedrals[:] + self.impropers[:]:
|
|
370
|
-
if atom in conn.atoms:
|
|
371
|
-
self.remove_connectivity(conn)
|
|
372
|
-
ids_removed.append(atom.id_in_mol)
|
|
373
399
|
hydrogens.append(atom)
|
|
400
|
+
ids_hydrogens = [atom.id_in_mol for atom in hydrogens]
|
|
401
|
+
|
|
402
|
+
for conn in self.bonds[:] + self.angles[:] + self.dihedrals[:] + self.impropers[:]:
|
|
403
|
+
ids_set = {atom.id_in_mol for atom in conn.atoms}
|
|
404
|
+
if ids_set.intersection(ids_hydrogens):
|
|
405
|
+
self.remove_connectivity(conn)
|
|
374
406
|
|
|
375
407
|
for atom in hydrogens:
|
|
376
408
|
self.remove_atom(atom, update_topology=False)
|
|
@@ -378,7 +410,7 @@ class Molecule():
|
|
|
378
410
|
if self._topology is not None and update_topology:
|
|
379
411
|
self._topology.update_molecules(self._topology.molecules, deepcopy=False)
|
|
380
412
|
|
|
381
|
-
return
|
|
413
|
+
return ids_hydrogens
|
|
382
414
|
|
|
383
415
|
def add_residue(self, name, atoms, update_topology=True):
|
|
384
416
|
'''
|
|
@@ -563,6 +595,8 @@ class Molecule():
|
|
|
563
595
|
Note that when a bond get removed, the relevant angles, dihedrals and impropers are still there.
|
|
564
596
|
You may call `generate_angle_dihedral_improper` to refresh connectivity.
|
|
565
597
|
|
|
598
|
+
# TODO This operation is extremely slow
|
|
599
|
+
|
|
566
600
|
Parameters
|
|
567
601
|
----------
|
|
568
602
|
connectivity : [Bond, Angle, Dihedral, Improper]
|
|
@@ -76,6 +76,9 @@ class Trajectory():
|
|
|
76
76
|
def __del__(self):
|
|
77
77
|
self.close()
|
|
78
78
|
|
|
79
|
+
def __repr__(self):
|
|
80
|
+
return f'<Trajectory: {self.n_frame} frames {self.n_atom} atoms>'
|
|
81
|
+
|
|
79
82
|
def close(self):
|
|
80
83
|
'''
|
|
81
84
|
Close the opened trajectory file(s).
|
|
@@ -97,7 +100,8 @@ class Trajectory():
|
|
|
97
100
|
this method should not be used because all the frames actually point to the same frame.
|
|
98
101
|
In this case, use :func:`read_frames` instead.
|
|
99
102
|
|
|
100
|
-
i_frame should be in the range of [
|
|
103
|
+
i_frame should be in the range of [-1, n_frame), otherwise and Exception will be raised.
|
|
104
|
+
-1 means the last frame.
|
|
101
105
|
|
|
102
106
|
Parameters
|
|
103
107
|
----------
|
|
@@ -123,6 +127,8 @@ class Trajectory():
|
|
|
123
127
|
# Reset the information in self.frame in case the frames read from different trajectory files pollute each other for CombinedTrajectory
|
|
124
128
|
self.frame.reset()
|
|
125
129
|
|
|
130
|
+
if i_frame == -1:
|
|
131
|
+
i_frame = self.n_frame - 1
|
|
126
132
|
self._handler.read_frame(i_frame, self.frame)
|
|
127
133
|
return self.frame
|
|
128
134
|
|
|
@@ -134,7 +140,8 @@ class Trajectory():
|
|
|
134
140
|
Instead, a new Frame object is constructed for each frame.
|
|
135
141
|
This method should be called when you want to multiprocess several frames in parallel.
|
|
136
142
|
|
|
137
|
-
All the items in i_frames should be in the range of
|
|
143
|
+
All the items in i_frames should be in the range of [-1, n_frame), otherwise and Exception will be raised.
|
|
144
|
+
-1 means the last frame.
|
|
138
145
|
|
|
139
146
|
Parameters
|
|
140
147
|
----------
|
|
@@ -153,6 +160,8 @@ class Trajectory():
|
|
|
153
160
|
|
|
154
161
|
frames = [Frame(self.n_atom) for _ in i_frames]
|
|
155
162
|
for ii, i_frame in enumerate(i_frames):
|
|
163
|
+
if i_frame == -1:
|
|
164
|
+
i_frame = self.n_frame - 1
|
|
156
165
|
self._handler.read_frame(i_frame, frames[ii])
|
|
157
166
|
return frames
|
|
158
167
|
|
|
@@ -219,8 +228,6 @@ class Trajectory():
|
|
|
219
228
|
|
|
220
229
|
'''
|
|
221
230
|
trj = Trajectory(file, 'r')
|
|
222
|
-
if i_frame == -1:
|
|
223
|
-
i_frame = trj.n_frame - 1
|
|
224
231
|
frame = trj.read_frame(i_frame)
|
|
225
232
|
trj.close()
|
|
226
233
|
return frame
|
|
@@ -7,6 +7,7 @@ import subprocess
|
|
|
7
7
|
import random
|
|
8
8
|
import string
|
|
9
9
|
import numpy as np
|
|
10
|
+
from typing import Iterable
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def greatest_common_divisor(numbers):
|
|
@@ -187,3 +188,11 @@ def align_mpl_axis(ax1, ax2):
|
|
|
187
188
|
|
|
188
189
|
ax1.set(ylim=ylims1)
|
|
189
190
|
ax2.set(ylim=ylims2)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def flatten(it):
|
|
194
|
+
for x in it:
|
|
195
|
+
if (isinstance(x, Iterable) and not isinstance(x, str)):
|
|
196
|
+
yield from flatten(x)
|
|
197
|
+
else:
|
|
198
|
+
yield x
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mstk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Molecular simulation toolkit
|
|
5
5
|
Home-page: https://github.com/z-gong/mstk
|
|
6
6
|
Author: Zheng Gong
|
|
@@ -69,3 +69,11 @@ https://mstk.readthedocs.io/en/latest/index.html
|
|
|
69
69
|
|
|
70
70
|
- [ ] Take bond order into consideration for force field assignment
|
|
71
71
|
- [ ] Re-organize algorithms scattered in topology and analyzer modules
|
|
72
|
+
|
|
73
|
+
## Known issue
|
|
74
|
+
`mstk` use `chemfiles` to write `XTC` trajectory. However, lastest `chemfiles` is buggy under WSL for writing binary trajectory format.
|
|
75
|
+
If you are working under WSL, please install `chemfiles 0.10.2`.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
conda install chemfiles-lib=0.10.2 chemfiles-python=0.10.2
|
|
79
|
+
```
|