Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated requirements, removed unnecessary numpy patch #443

Merged
merged 1 commit into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
# The executor is the environment in which the steps below will be executed - below will use a python 3.8 container
# Change the version below to your required version of python
docker:
- image: cimg/python:3.9
- image: cimg/python:3.10
# Checkout the code as the first step. This is a dedicated CircleCI step.
# The python orb's install-packages step will install the dependencies from a Pipfile via Pipenv by default.
# Here we're making sure we use just use the system-wide pip. By default it uses the project root's requirements.txt.
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.11"]
python-version: ["3.10", "3.11", "3.12"]
include:
- python-version: "3.9"
numpy-version: "1.26.4"
- python-version: "3.10"
numpy-version: "2.1.3"

steps:
- uses: actions/checkout@v2
Expand All @@ -29,9 +29,9 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
python -m pip install mdtraj
#python -m pip install mdtraj # removed as long as mdtraj is not supporting numpy2
python -m pip install .
if [ -f requirements.txt ]; then pip install --upgrade -r requirements.txt; fi
if [ -f requirements.txt ]; then pip install --upgrade -r requirements.txt; fi
#- name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
Expand Down
8 changes: 5 additions & 3 deletions pytim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
from . import observables, utilities, datafiles
from .version import __version__
import warnings
from .patches import patchNumpy, patchMDTRAJ_ReplacementTables
patchNumpy()
patchMDTRAJ_ReplacementTables()
try: # waiting for numpy2 support in mdtraj>=1.10.2
from .patches import patchMDTRAJ_ReplacementTables
patchMDTRAJ_ReplacementTables()
except:
pass

warnings.filterwarnings(
"ignore",
Expand Down
18 changes: 10 additions & 8 deletions pytim/examples/example_mdtraj.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
loaded with MDTraj (http://mdtraj.org/)
(see also the openmm interoperability)
"""
try:
import mdtraj
import pytim
from pytim.datafiles import WATER_GRO, WATER_XTC

import mdtraj
import pytim
from pytim.datafiles import WATER_GRO, WATER_XTC

t = mdtraj.load_xtc(WATER_XTC, top=WATER_GRO)
inter = pytim.ITIM(t)
for step in t[:]:
print("surface atoms: "+repr(inter.atoms.indices))
t = mdtraj.load_xtc(WATER_XTC, top=WATER_GRO)
inter = pytim.ITIM(t)
for step in t[:]:
print("surface atoms: "+repr(inter.atoms.indices))
except:
pass # for package testing, in case mdtraj is not available or has compatibility issues
3 changes: 3 additions & 0 deletions pytim/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,10 @@ def _():

>>> # mdtraj
>>> try:
... from packaging.version import Version
... import mdtraj
... if Version(mdtraj.__version__) < Version('1.10.2'): # numpy2 support
... pass
... try:
... import numpy as np
... import MDAnalysis as mda
Expand Down
13 changes: 8 additions & 5 deletions pytim/itim.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,14 @@ class ITIM(Interface):


>>> # pytim can be used also on top of mdtraj (MDAnalysis must be present,though)
>>> import mdtraj
>>> import pytim
>>> from pytim.datafiles import WATER_GRO, WATER_XTC
>>> t = mdtraj.load_xtc(WATER_XTC,top=WATER_GRO)
>>> inter = pytim.ITIM(t)
>>> try:
... import mdtraj
... import pytim
... from pytim.datafiles import WATER_GRO, WATER_XTC
... t = mdtraj.load_xtc(WATER_XTC,top=WATER_GRO)
... inter = pytim.ITIM(t)
... except (ModuleNotFoundError,ValueError): # ValueError to handle mdtraj not supporting numpy2
... pass


.. _MDAnalysis: http://www.mdanalysis.org/
Expand Down
4 changes: 2 additions & 2 deletions pytim/observables/basic_observables.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ class Distance(Observable):
>>> u = mda.Universe(pytim.datafiles.WATER_GRO)
>>> d1 = pytim.observables.Distance().compute(u.atoms[:9],u.atoms[:9])
>>> d2 = pytim.observables.RelativePosition(spherical=True).compute(u.atoms[:9],u.atoms[:9])[:,0]
>>> np.all(np.isclose(d1,d2))
>>> all(np.isclose(d1,d2))
True

>>> d1 = pytim.observables.Distance('xy').compute(u.atoms[:9],u.atoms[:9])
>>> d2 = pytim.observables.RelativePosition('xy',spherical=True).compute(u.atoms[:9],u.atoms[:9])[:,0]
>>> np.all(np.isclose(d1,d2))
>>> all(np.isclose(d1,d2))
True

"""
Expand Down
10 changes: 5 additions & 5 deletions pytim/observables/contactangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,24 @@ class ContactAngle(object):
>>> for ts in u.trajectory[::]:
... CA.sample()
>>> # Instantaneous contact angle (last frame) by fitting a circle...
>>> np.round(CA.contact_angle,2)
>>> print(np.round(CA.contact_angle,2))
90.58

>>>
>>> # ... and using an elliptical fit:
>>> left, right = CA.contact_angles
>>> # left angle
>>> np.round(np.abs(left),2)
>>> print(np.round(np.abs(left),2))
79.95

>>> # right angle
>>> np.round(right,2)
>>> print(np.round(right,2))
83.84

>>> # Contact angles from the averaged binned statistics of
>>> # surface atoms' radial distance as a function of the azimuthal angle
>>> list(np.round(CA.mean_contact_angles,2))
[96.2, 100.68]
>>> np.around(CA.mean_contact_angles,1).tolist()
[96.2, 100.7]

"""

Expand Down
10 changes: 5 additions & 5 deletions pytim/observables/correlator.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def sample(self, group):
RuntimeError(
'Cannot compute survival probability without a reference')
sampled = self.observable.compute(group)
self.timeseries.append(list(sampled.flatten()))
self.timeseries.append(sampled.flatten().tolist())

if self.shape is None:
self.shape = sampled.shape
Expand All @@ -149,13 +149,13 @@ def _sample_intermittent(self, group):
# the residence function (1 if in the reference group, 0 otherwise)
mask = np.isin(self.reference, group)
# append the residence function to its timeseries
self.maskseries.append(list(mask))
self.maskseries.append(mask.tolist())
if self.observable is not None:
# this copies a vector of zeros with the correct shape
sampled = self.reference_obs.copy()
obs = self.observable.compute(group)
sampled[np.where(mask)] = obs
self.timeseries.append(list(sampled.flatten()))
self.timeseries.append(sampled.flatten().tolist())
else:
self.timeseries = self.maskseries
if self.shape is None:
Expand Down Expand Up @@ -249,7 +249,7 @@ def correlation(self, normalized=True, continuous=True):
>>> print (np.allclose(corr, [ c0, c1, c2, c3]))
True
>>> # check normalization
>>> np.all(vv.correlation(continuous=False) == corr/corr[0])
>>> print(np.all(vv.correlation(continuous=False) == corr/corr[0]))
True
>>> # not normalizd, continuous
>>> corr = vv.correlation(normalized=False,continuous=True)
Expand All @@ -258,7 +258,7 @@ def correlation(self, normalized=True, continuous=True):
>>> print (np.allclose(corr, [ c0, c1, c2, c3]))
True
>>> # check normalization
>>> np.all(vv.correlation(continuous=True) == corr/corr[0])
>>> print(np.all(vv.correlation(continuous=True) == corr/corr[0]))
True

"""
Expand Down
2 changes: 1 addition & 1 deletion pytim/observables/distributionfunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ def sample(self, g1=None, g2=None, kargs1=None, kargs2=None):
self.count += count

box = self.universe.dimensions
self.volume += np.product(box[:3])
self.volume += np.prod(box[:3])
if self.g2 is None or len(self.g2) == 0:
self.n_normalize += len(self.g1)
else:
Expand Down
4 changes: 2 additions & 2 deletions pytim/observables/free_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ class FreeVolume(object):
>>> FV = pytim.observables.FreeVolume(u,npoints = nsamples)
>>> np.random.seed(1) # ensure reproducibility of test
>>> free, err = FV.compute()
>>> np.isclose(free,1.0-0.6802,rtol=1e-3)
>>> print(np.isclose(free,1.0-0.6802,rtol=1e-3))
True
>>> np.random.seed(1) # ensure reproducibility of test
>>> lst, _ = FV._compute()
>>> np.isclose(free,1.0-len(lst)*1.0/nsamples, rtol=1e-6)
>>> print(np.isclose(free,1.0-len(lst)*1.0/nsamples, rtol=1e-6))
True

"""
Expand Down
2 changes: 1 addition & 1 deletion pytim/observables/orientation.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def compute(self, inp, **kargs):
>>> condition = np.logical_and(u.atoms.sides==0,u.atoms.layers==1)
>>> group = u.atoms[condition]
>>> costheta, phi = biv.compute(group)
>>> np.all(np.isclose([costheta[0],phi[0]], [0.6533759236335754, 0.10778185716460659]))
>>> print(all(np.isclose([costheta[0],phi[0]], [0.6533759236335754, 0.10778185716460659])))
True
"""

Expand Down
21 changes: 11 additions & 10 deletions pytim/observables/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,18 +311,19 @@ def _():
>>> inter = pytim.ITIM(u,cluster_cut=3.5,alpha=2.5)
>>> print(inter.normal)
2
>>> np.set_printoptions(precision=8)
>>> np.random.seed(1) # for the MC normalization
>>> stdprof = pytim.observables.Profile()
>>> stdprof.sample(u.atoms)
>>> print(stdprof.get_values(binwidth=0.5)[2][:6])
[0.09229169 0.10959639 0.08075523 0.10959639 0.09805993 0.09805993]
>>> vals = stdprof.get_values(binwidth=0.5)[2]
>>> print(np.around(vals[:6],decimals=3))
[0.092 0.11 0.081 0.11 0.098 0.098]


>>> prof = pytim.observables.Profile(interface=inter)
>>> prof.sample(u.atoms)
>>> vals = prof.get_values(binwidth=0.5)[2]
>>> print(vals[len(vals)//2-3:len(vals)//2+3])
[0.07344066 0.04300743 0.02803522 inf 0. 0. ]
>>> print(np.around(vals[len(vals)//2-3:len(vals)//2+3],decimals=3))
[0.073 0.043 0.028 inf 0. 0. ]



Expand Down Expand Up @@ -353,15 +354,15 @@ def _():
>>> np.random.seed(1) # for the MC normalization
>>> stdprof = pytim.observables.Profile()
>>> stdprof.sample(u.atoms)
>>> print(stdprof.get_values(binwidth=0.5)[2][:6])
[0.09229169 0.10959639 0.08075523 0.10959639 0.09805993 0.09805993]
>>> vals = stdprof.get_values(binwidth=0.5)[2]
>>> print(np.around(vals[:6],decimals=3))
[0.092 0.11 0.081 0.11 0.098 0.098]

>>> prof = pytim.observables.Profile(interface=inter)
>>> prof.sample(u.atoms)
>>> vals = prof.get_values(binwidth=1.0)[2]
>>> print(vals[len(vals)//2-4:len(vals)//2+2])
[0.09554818 0.09796541 0.05555127 0. inf 0. ]

>>> print(np.around(vals[len(vals)//2-4:len(vals)//2+2],decimals=3))
[0.096 0.098 0.056 0. inf 0. ]

"""

Expand Down
28 changes: 10 additions & 18 deletions pytim/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,14 @@
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
from __future__ import print_function


def patchNumpy():
# this try/except block patches numpy and provides _validate_lengths
# to skimage<=1.14.1
import numpy
try:
numpy.lib.arraypad._validate_lengths
except AttributeError:
def patch_validate_lengths(ar, crop_width):
return numpy.lib.arraypad._as_pairs(crop_width, ar.ndim, as_index=True)
numpy.lib.arraypad._validate_lengths = patch_validate_lengths


def patchTrajectory(trajectory, interface):
""" Patch the MDAnalysis trajectory class

this patch makes the layer assignement being automatically
called whenever a new frame is loaded.
"""
from importlib.metadata import version
if int(version('numpy').split('.')[0])<2 : return
try:
trajectory.interface
trajectory.interface = interface
Expand Down Expand Up @@ -110,11 +99,14 @@ def patchMDTRAJ(trajectory, universe):

Example:

>>> import mdtraj
>>> import pytim
>>> from pytim.datafiles import WATER_GRO, WATER_XTC
>>> t = mdtraj.load_xtc(WATER_XTC,top=WATER_GRO)
>>> inter = pytim.ITIM(t)
>>> try:
... import mdtraj
... import pytim
... from pytim.datafiles import WATER_GRO, WATER_XTC
... t = mdtraj.load_xtc(WATER_XTC,top=WATER_GRO)
... inter = pytim.ITIM(t)
... except:
... pass


"""
Expand Down
2 changes: 1 addition & 1 deletion pytim/sanity_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _check_universe(self, input_obj):
patchMDTRAJ(input_obj, self.interface.universe)
os.remove(_file.name)
return 'mdtraj'
except ImportError:
except (ImportError,ValueError): # ValueError to handle mdtraj not supporting numpy2
pass
try:
import os
Expand Down
2 changes: 1 addition & 1 deletion pytim/utilities_dbscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def _():
>>> print (np.sort(c2)[-2:])
[ 0 9335]

>>> print ((np.all(c1==c2), np.all(l1==l2)))
>>> print ((all(c1==c2), all(l1==l2)))
(True, True)

"""
Expand Down
4 changes: 2 additions & 2 deletions pytim/utilities_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ def polygonalArea(points):
>>> s1 = np.sin(2*np.pi/5.) ; s2 = np.sin(4*np.pi/5.)
>>> pentagon = np.array([[1,0,0],[c1,s1,0],[-c2,s2,0],[-c2,-s2,0],[c1,-s1,0]])
>>> A = 0.25 * np.sqrt(25+10*np.sqrt(5)) * 100./ (50+10*np.sqrt(5))
>>> np.isclose(pytim.utilities.polygonalArea(pentagon),A)
>>> print(np.isclose(pytim.utilities.polygonalArea(pentagon),A))
True

>>> # now let's rotate it:
>>> rotated = np.dot(EulerRotation(0,np.pi/2.,0),pentagon.T).T
>>> np.isclose(pytim.utilities.polygonalArea(rotated),A)
>>> print(np.isclose(pytim.utilities.polygonalArea(rotated),A))
True

"""
Expand Down
2 changes: 1 addition & 1 deletion requirements.testing.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mdtraj
pytest==8.1.1
codecov==2.1.13
pytest-cov==5.0.0
packaging
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
cython>=0.24.1
numpy>=1.26.4,<2.0.0
numpy>=2.1.3
scipy>=1.6.0
gsd>3.0.0
MDAnalysis>=2.7.0
setuptools
MDAnalysis>=2.8.0
PyWavelets>=0.5.2
scikit-image>=0.14.2
scikit-image>=0.24.0
sphinx>=1.4.3
matplotlib
pytest
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ def run_tests(self):
# requirements files see:
# https://packaging.python.org/en/latest/requirements.html
install_requires=[
'numpy>=1.26.4,<2.0.0', 'cython>=0.24.1','gsd>=3.0.0','MDAnalysis>=2.7.0'
'numpy>=2.1.3', 'cython>=0.24.1','gsd>=3.0.0','MDAnalysis>=2.8.0'
],

# List additional groups of dependencies here (e.g. development
# dependencies). You can install these using the following syntax,
# for example:
# $ pip install -e .[dev,test]
tests_require=['nose>=1.3.7', 'coverage'],
tests_require=['nose>=1.3.7', 'coverage', 'scikit-image'],
# If there are data files included in your packages that need to be
# installed, specify them here. If using Python 2.6 or less, then these
# have to be included in MANIFEST.in as well.
Expand Down