From b901ad2635143ad18abcc5970df994437615ae27 Mon Sep 17 00:00:00 2001 From: hechtprojects Date: Tue, 22 Oct 2024 15:59:33 +0200 Subject: [PATCH 1/5] readme restructured --- README.md | 186 +++++++++++++++++++++++++++--------------------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 67ecfc8..852b3f2 100644 --- a/README.md +++ b/README.md @@ -22,68 +22,38 @@ format. To be fast and usable on modern HPC (**H**igh **P**erformance **C**omputing) hardware, the methods are optimized to run also in parallel. -# Description +# How to cite AMEP -The **AMEP** Python library provides a unified framework for handling -both particle-based and continuum simulation data. It is made for the analysis -of molecular-dynamics (MD), Brownian-dynamics (BD), and continuum simulation -data of condensed matter systems and active matter systems in particular. -**AMEP** provides a huge variety of analysis methods for both data types that -allow to evaluate various dynamic and static observables based on the -trajectories of the particles or the time evolution of continuum fields. For -fast and efficient data handling, **AMEP** provides a unified framework for -loading and storing simulation data and analysis results in a compressed, -HDF5-based data format. **AMEP** is written purely in Python and uses powerful -libraries such as NumPy, SciPy, Matplotlib, and scikit-image commonly used in -computational physics. Therefore, understanding, modifying, and building up on -the provided framework is comparatively easy. All evaluation functions are -optimized to run efficiently on HPC hardware to provide fast computations. To -plot and visualize simulation data and analysis results, **AMEP** provides an -optimized plotting framework based on the Matplotlib Python library, which -allows to easily plot and animate particles, fields, and lines. Compared to -other analysis libraries, the huge variety of analysis methods combined with -the possibility to handle both most common data types used in soft-matter -physics and in the active matter community in particular, enables the analysis -of a much broader class of simulation data including not only classical -molecular-dynamics or Brownian-dynamics simulations but also any kind of -numerical solutions of partial differential equations. The following table -gives an overview on the observables provided by **AMEP** and on their -capability of running in parallel and processing particle-based and continuum -simulation data. +If you use **AMEP** for a project that leads to a scientific publication, please acknowledge +the use of **AMEP** within the body of your publication for example by copying or adapting +the following formulation: + +*Data analysis for this publication utilized the AMEP library [1].* +> [1] L. Hecht, K.-R. Dormann, K. L. Spanheimer, M. Ebrahimi, M. Cordts, S. Mandal, +> A. K. Mukhopadhyay, and B. Liebchen, AMEP: The Active Matter Evaluation Package for Python, +> *arXiv [Cond-Mat.Soft]* (2024). Available at: http://arxiv.org/abs/2404.16533. -| Observable | Parallel | Particles | Fields | -|:-----------|:--------:|:---------:|:------:| -| **Spatial Correlation Functions:** |||| -| RDF (radial pair distribution function) | ✔ | ✔ | ❌ | -| PCF2d (2d pair correlation function) | ✔ | ✔ | ❌ | -| PCFangle (angular pair correlation function) | ✔ | ✔ | ❌ | -| SFiso (isotropic static structure factor) | ✔ | ✔ | ✔ | -| SF2d (2d static structure factor) | ✔ | ✔ | ✔ | -| SpatialVelCor (spatial velocity correlation function) | ✔ | ✔ | ❌ | -| PosOrderCor (positional order correlation function) | ✔ | ✔ | ❌ | -| HexOrderCor (hexagonal order correlation function) | ✔ | ✔ | ❌ | -| **Local Order:** |||| -| Voronoi tesselation | ❌ | ✔ | ❌ | -| Local density | ❌ | ✔ | ✔ | -| Local packing fraction | ❌ | ✔ | ❌ | -| k-atic bond order parameter | ❌ | ✔ | ❌ | -| Next/nearest neighbor search | ❌ | ✔ | ❌ | -| **Time Correlation Functions:** |||| -| MSD (mean square displacement) | ❌ | ✔ | ❌ | -| VACF (velocity autocorrelation function) | ❌ | ✔ | ❌ | -| OACF (orientation autocorrelation function) | ❌ | ✔ | ❌ | -| **Cluster Analysis:** |||| -| Clustersize distribution | ❌ | ✔ | ✔ | -| Cluster growth | ❌ | ✔ | ✔ | -| Radius of gyration | ❌ | ✔ | ✔ | -| Linear extension | ❌ | ✔ | ✔ | -| Center of mass | ❌ | ✔ | ✔ | -| Gyration tensor | ❌ | ✔ | ✔ | -| Inertia tensor | ❌ | ✔ | ✔ | -| **Miscellaneous:** |||| -| Translational/rotational kinetic energy | ❌ | ✔ | ❌ | -| Kinetic temperature | ❌ | ✔ | ❌ | +The pre-print is freely available on [arXiv](https://arxiv.org/abs/2404.16533). To cite this reference, +you can use the following BibTeX entry: + +```bibtex +@misc{hecht2024amep, + title = {AMEP: The Active Matter Evaluation Package for Python}, + author = {Lukas Hecht and + Kay-Robert Dormann and + Kai Luca Spanheimer and + Mahdieh Ebrahimi and + Malte Cordts and + Suvendu Mandal and + Aritra K. Mukhopadhyay and + Benno Liebchen}, + year = {2024}, + eprint = {2404.16533}, + archivePrefix = {arXiv}, + primaryClass = {cond-mat.soft} +} +``` # Installation @@ -146,40 +116,6 @@ Anaconda installation path. to download FFmpeg and to get further information on how to install FFmpeg on your machine. -# Citation - -If you use **AMEP** for a project that leads to a scientific publication, please acknowledge -the use of **AMEP** within the body of your publication for example by copying or adapting -the following formulation: - -*Data analysis for this publication utilized the AMEP library [1].* - -> [1] L. Hecht, K.-R. Dormann, K. L. Spanheimer, M. Ebrahimi, M. Cordts, S. Mandal, -> A. K. Mukhopadhyay, and B. Liebchen, AMEP: The Active Matter Evaluation Package for Python, -> *arXiv [Cond-Mat.Soft]* (2024). Available at: http://arxiv.org/abs/2404.16533. - -The pre-print is freely available on [arXiv](https://arxiv.org/abs/2404.16533). To cite this reference, -you can use the following BibTeX entry: - -```bibtex -@misc{hecht2024amep, - title = {AMEP: The Active Matter Evaluation Package for Python}, - author = {Lukas Hecht and - Kay-Robert Dormann and - Kai Luca Spanheimer and - Mahdieh Ebrahimi and - Malte Cordts and - Suvendu Mandal and - Aritra K. Mukhopadhyay and - Benno Liebchen}, - year = {2024}, - eprint = {2404.16533}, - archivePrefix = {arXiv}, - primaryClass = {cond-mat.soft} -} -``` - - # Getting started The following example briefly demonstrates the **AMEP** workflow. A typical @@ -218,6 +154,70 @@ fig.savefig(rdf.name + '.pdf') For more detailed examples, check the [examples](https://github.com/amepproject/amep/tree/main/examples) directory. +# Project description + +The **AMEP** Python library provides a unified framework for handling +both particle-based and continuum simulation data. It is made for the analysis +of molecular-dynamics (MD), Brownian-dynamics (BD), and continuum simulation +data of condensed matter systems and active matter systems in particular. +**AMEP** provides a huge variety of analysis methods for both data types that +allow to evaluate various dynamic and static observables based on the +trajectories of the particles or the time evolution of continuum fields. For +fast and efficient data handling, **AMEP** provides a unified framework for +loading and storing simulation data and analysis results in a compressed, +HDF5-based data format. **AMEP** is written purely in Python and uses powerful +libraries such as NumPy, SciPy, Matplotlib, and scikit-image commonly used in +computational physics. Therefore, understanding, modifying, and building up on +the provided framework is comparatively easy. All evaluation functions are +optimized to run efficiently on HPC hardware to provide fast computations. To +plot and visualize simulation data and analysis results, **AMEP** provides an +optimized plotting framework based on the Matplotlib Python library, which +allows to easily plot and animate particles, fields, and lines. Compared to +other analysis libraries, the huge variety of analysis methods combined with +the possibility to handle both most common data types used in soft-matter +physics and in the active matter community in particular, enables the analysis +of a much broader class of simulation data including not only classical +molecular-dynamics or Brownian-dynamics simulations but also any kind of +numerical solutions of partial differential equations. The following table +gives an overview on the observables provided by **AMEP** and on their +capability of processing particle-based and continuum +simulation data. + + +| Observable | Particles | Fields | +|:----------:|:---------:|:------:| +| **Spatial Correlation Functions:** ||| +| RDF (radial pair distribution function) | ✔ | ➖ | +| PCF2d (2d pair correlation function) | ✔ | ➖ | +| PCFangle (angular pair correlation function) | ✔ | ➖ | +| SFiso (isotropic static structure factor) | ✔ | ✔ | +| SF2d (2d static structure factor) | ✔ | ✔ | +| SpatialVelCor (spatial velocity correlation function) | ✔ | ➖ | +| PosOrderCor (positional order correlation function) | ✔ | ➖ | +| HexOrderCor (hexagonal order correlation function) | ✔ | ➖ | +| **Local Order:** ||| +| Voronoi tesselation | ✔ | ➖ | +| Local density | ✔ | ✔ | +| Local packing fraction | ✔ | ➖ | +| k-atic bond order parameter | ✔ | ➖ | +| Next/nearest neighbor search | ✔ | ➖ | +| **Time Correlation Functions:** ||| +| MSD (mean square displacement) | ✔ | ➖ | +| VACF (velocity autocorrelation function) | ✔ | ➖ | +| OACF (orientation autocorrelation function) | ✔ | ➖ | +| **Cluster Analysis:** ||| +| Clustersize distribution | ✔ | ✔ | +| Cluster growth | ✔ | ✔ | +| Radius of gyration | ✔ | ✔ | +| Linear extension | ✔ | ✔ | +| Center of mass | ✔ | ✔ | +| Gyration tensor | ✔ | ✔ | +| Inertia tensor | ✔ | ✔ | +| **Miscellaneous:** ||| +| Translational/rotational kinetic energy | ✔ | ➖ | +| Kinetic temperature | ✔ | ➖ | + + # Module descriptions In the following, we provide a list of all **AMEP** modules together with a From 03ff184e64dd8f2f21295f62954488ea8c55fa29 Mon Sep 17 00:00:00 2001 From: hechtprojects Date: Tue, 22 Oct 2024 18:16:55 +0200 Subject: [PATCH 2/5] website restructured; plot.particles and plot.fields type hint corrected --- README.md | 2 +- amep/load.py | 13 +- amep/plot.py | 4 +- amep/reader.py | 470 +----------------- doc/source/conf.py | 18 +- .../datastructures/particle_data_reader.md | 20 - doc/source/{user_guide => }/howto_cite.rst | 6 +- doc/source/index.rst | 6 +- .../datastructures/field_data.rst | 0 .../datastructures/function_flow.rst | 0 .../{ => user_guide}/datastructures/index.rst | 4 - doc/source/user_guide/index.rst | 2 +- 12 files changed, 26 insertions(+), 519 deletions(-) delete mode 100644 doc/source/datastructures/particle_data_reader.md rename doc/source/{user_guide => }/howto_cite.rst (95%) rename doc/source/{ => user_guide}/datastructures/field_data.rst (100%) rename doc/source/{ => user_guide}/datastructures/function_flow.rst (100%) rename doc/source/{ => user_guide}/datastructures/index.rst (84%) diff --git a/README.md b/README.md index 852b3f2..1a9e189 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ simulation data. | Observable | Particles | Fields | -|:----------:|:---------:|:------:| +|:-----------|:---------:|:------:| | **Spatial Correlation Functions:** ||| | RDF (radial pair distribution function) | ✔ | ➖ | | PCF2d (2d pair correlation function) | ✔ | ➖ | diff --git a/amep/load.py b/amep/load.py index d155936..d552a35 100644 --- a/amep/load.py +++ b/amep/load.py @@ -33,7 +33,7 @@ import os import h5py -from .reader import LammpsReader, H5amepReader, ContinuumReader, GSDReader +from .reader import LammpsReader, H5amepReader, ContinuumReader from .trajectory import ParticleTrajectory,FieldTrajectory from .base import TRAJFILENAME, BaseEvalData, BaseDatabase, LOADMODES from .base import check_path, get_module_logger @@ -226,16 +226,7 @@ def traj( **kwargs ) return FieldTrajectory(reader) - elif mode == 'gsd': - reader = GSDReader( - directory, - savedir, - trajfile = trajfile, - deleteold = deleteold, - verbose = verbose, - **kwargs - ) - return ParticleTrajectory(reader) + # here one has to check both the amep version with which the file has been # created (reader.version) and the data type (particles or fields) - # the latter is needed to decide whether a ParticleTrajectory or a diff --git a/amep/plot.py b/amep/plot.py index ca3b7e6..8e3ba75 100644 --- a/amep/plot.py +++ b/amep/plot.py @@ -909,7 +909,7 @@ def box(axis: mpl.axes.Axes, box_boundary: np.ndarray, **kwargs) -> None: def particles( - ax: mpl.axes, coords: np.ndarray, box_boundary: np.ndarray, + ax: mpl.axes.Axes, coords: np.ndarray, box_boundary: np.ndarray, radius: np.ndarray | float, scalefactor: float = 1.0, values: np.ndarray | None = None, cmap: list | str = 'viridis', set_ax_limits: bool = True, @@ -1081,7 +1081,7 @@ def particles( def field( - ax: mpl.axes, density: np.ndarray, X: np.ndarray, Y: np.ndarray, + ax: mpl.axes.Axes, density: np.ndarray, X: np.ndarray, Y: np.ndarray, cmap: list | str = 'plasma', box_boundary: np.ndarray | None = None, vmin: float | None = None, vmax: float | None = None, cscale: str = 'lin', verbose: bool = False, **kwargs diff --git a/amep/reader.py b/amep/reader.py index 16e93c6..be74704 100644 --- a/amep/reader.py +++ b/amep/reader.py @@ -37,7 +37,6 @@ import warnings import h5py import string -from gsd import hoomd import numpy as np from tqdm.autonotebook import tqdm @@ -1095,471 +1094,4 @@ def __detect_delimiter( if delimiter == []: return None - return delimiter - - -class GSDReader(BaseReader): - '''Reads GSD files and writes the containing data to an hdf5 file. - ''' - - def __init__( - self, directory: str, savedir: str, start: float = 0.0, - stop: float = 1.0, nth: int = 1, filename: str = 'trajectory.gsd', - trajfile: str = TRAJFILENAME, deleteold: bool = False, - verbose: bool = False) -> None: - r''' - Reader for simulation data in the gsd file format (hoomd-blue). - - TODO in progress - - real-time not in gsd file - - Parameters - ---------- - directory : str - Simulation directory. - savedir : str - Directory in which the trajectory file will be stored. - start : float, optional - Start reading data from this fraction of the whole trajectory. - The default is None. - stop : float, optional - Stop reading data from this fraction of the whole trajectory. - The default is None. - nth : int, optional - Read each nth dump file. The default is None. - filename : str, optional - File name of the gsd trajectory file. The default is 'trajectory.gsd'. - trajfile : str, optional - Name of the hdf5 trajectory file that is created when an object of - this class is initialized. The default is TRAJFILENAME. - deleteold : bool, optional - If True, an existing old h5amep trajectory file # - will be removed. The default is False. - verbose : bool, optional - If True, runtime information is printed. The default is False. - - Returns - ------- - None. - - ''' - # init class logger - self.__log = get_class_logger(__name__, self.__class__.__name__) - - # back up trajectory file - if os.path.exists(os.path.join(savedir, trajfile)): - # rename trajectory to backup filename "#+" - if os.path.exists(os.path.join(savedir, "#"+trajfile)): - if verbose: - self.__log.info( - f"Existing old file #{trajfile} will be replaced." - ) - os.remove(os.path.join(savedir, "#"+trajfile)) - os.rename( - os.path.join(savedir, trajfile), - os.path.join(savedir, "#"+trajfile) - ) - if verbose: - self.__log.info( - f"Renamed {trajfile} to #{trajfile}." - ) - # super(LammpsReader, self).__init__(directory, start, stop, nth, "#temp#"+trajfile) - super().__init__(os.path.abspath(savedir), start, stop, nth, "#temp#"+trajfile) - self.directory = directory - - try: - # self.__filename = filename # important: self.filename ≠ self.__filename - - # load gsd file - gsd_file = hoomd.open(os.path.join(directory,filename)) - - first = int(self.start*len(gsd_file)) # first frame index - last = int(self.stop*len(gsd_file)) # last frame index - - # select part of gsd.hoomd.HOOMDTrajectory ( = gsd.hoomd._HOOMDTrajectoryView ) - gsd_file = gsd_file[first:last:self.nth] - - # total number of files - self.__nframes = len(gsd_file) - - # array of number of time steps - steps = np.zeros(self.__nframes, dtype=int) - - # load data from dump files - with h5py.File(os.path.join(self.savedir, "#temp#"+trajfile), 'a') as root: - # Set type of h5amep file to particle - root.attrs["type"] = "particle" - - # If no ID is specified only one warning is issued to the user. - # Trigger idwarning is set to false: - idwarning=False - - # loop through all dump files - for n, gsd_frame in enumerate(tqdm(gsd_file)): - - # get number of time steps - step = gsd_frame.configuration.step - - # get total number of atoms - N = gsd_frame.particles.N - - # create new group for the given step in the 'frames' group - if str(step) not in root['frames'].keys(): - frame = root['frames'].create_group(str(step)) - else: - frame = root['frames'][str(step)] - - # get boundaries of the simulation box - gsd_box = gsd_frame.configuration.box - if np.any(gsd_box[3:] != 0): - raise Exception(f"GSDReader: box tilt factors {gsd_box[3:]} must be 0.") - box=np.zeros((3,2)) - box[:,0]=-gsd_box[:3]/2 - box[:,1]=gsd_box[:3]/2 # hoomd-gsd box always centered around 0 - - # add box to hdf5 file - if 'box' not in frame.keys(): - frame.create_dataset('box', - (3, 2), - data=box, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['box'][:] = box - - # get center of the simulation box - center = (box[:, 1]+box[:, 0])/2 - - # add center to hdf5 file - if 'center' not in frame.keys(): - frame.create_dataset('center', - (3,), - data=center, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['center'][:] = center - - print(center) - continue - - # extract the data - data = np.zeros((N, nparams), dtype=DTYPE) - # ignore other lines (N+9 and larger) - # (LAMMPS sometimes adds an empty line at the end - # which would cause problems) - for l, line in enumerate(lines[9:N+9]): - data[l] = np.fromstring(line, sep=' ') - - # add data to hdf5 file - coords = np.zeros((N, 3), dtype=DTYPE) - uwcoords = np.zeros((N, 3), dtype=DTYPE) # unwrapped - velocities = np.zeros((N, 3), dtype=DTYPE) - forces = np.zeros((N, 3), dtype=DTYPE) - orientations = np.zeros((N, 3), dtype=DTYPE) - omegas = np.zeros((N, 3), dtype=DTYPE) - torque = np.zeros((N, 3), dtype=DTYPE) - angmom = np.zeros((N, 3), dtype=DTYPE) - - # sort data by id if available - if "id" in keys: - sorting = np.argsort(data[:, keys.index("id")]) - data = data[sorting, :] - else: - # Warn user if data could not be sorted. - idwarning = True - # side-note from the documentation: - # """Repetitions of a particular warning for the same - # source location are typically suppressed.""" - - unwrapped_available = False - d = 0 - for i, key in enumerate(keys): - if key == 'x': - coords[:, 0] = data[:, i] - if not np.all((data[:, i] == 0.0)): - d += 1 - elif key == 'y': - coords[:, 1] = data[:, i] - if not np.all((data[:, i] == 0.0)): - d += 1 - elif key == 'z': - coords[:, 2] = data[:, i] - if not np.all((data[:, i] == 0.0)): - d += 1 - elif key == 'xu': - uwcoords[:, 0] = data[:, i] - unwrapped_available = True - elif key == 'yu': - uwcoords[:, 1] = data[:, i] - unwrapped_available = True - elif key == 'zu': - uwcoords[:, 2] = data[:, i] - unwrapped_available = True - elif key == 'vx': - velocities[:, 0] = data[:, i] - elif key == 'vy': - velocities[:, 1] = data[:, i] - elif key == 'vz': - velocities[:, 2] = data[:, i] - elif key == 'fx': - forces[:, 0] = data[:, i] - elif key == 'fy': - forces[:, 1] = data[:, i] - elif key == 'fz': - forces[:, 2] = data[:, i] - elif key == 'mux': - orientations[:, 0] = data[:, i] - elif key == 'muy': - orientations[:, 1] = data[:, i] - elif key == 'muz': - orientations[:, 2] = data[:, i] - elif key == 'omegax': - omegas[:, 0] = data[:, i] - elif key == 'omegay': - omegas[:, 1] = data[:, i] - elif key == 'omegaz': - omegas[:, 2] = data[:, i] - elif key == 'tqx': - torque[:, 0] = data[:, i] - elif key == 'tqy': - torque[:, 1] = data[:, i] - elif key == 'tqz': - torque[:, 2] = data[:, i] - elif key == 'angmomx': - angmom[:, 0] = data[:, i] - elif key == 'angmomy': - angmom[:, 1] = data[:, i] - elif key == 'angmomz': - angmom[:, 2] = data[:, i] - elif key == 'type': - if key not in frame.keys(): - frame.create_dataset(key, - (N,), - data=data[:, i], - dtype=int, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame[key][:] = data[:, i] - elif key == 'id': - if key not in frame.keys(): - frame.create_dataset(key, - (N,), - data=data[:, i], - dtype=int, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame[key][:] = data[:, i] - else: - if key not in frame.keys(): - frame.create_dataset(key, - (N,), - data=data[:, i], - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame[key][:] = data[:, i] - - if 'coords' not in frame.keys(): - frame.create_dataset('coords', - (N, 3), - data=coords, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['coords'][:] = coords - - if 'uwcoords' not in frame.keys() and unwrapped_available: - frame.create_dataset('uwcoords', - (N, 3), - data=uwcoords, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - elif 'uwcoords' in frame.keys() and unwrapped_available: - frame['uwcoords'][:] = uwcoords - - if 'velocities' not in frame.keys(): - frame.create_dataset('velocities', - (N, 3), - data=velocities, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['velocities'][:] = velocities - - if 'forces' not in frame.keys(): - frame.create_dataset('forces', - (N, 3), - data=forces, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['forces'][:] = forces - - if 'orientations' not in frame.keys(): - frame.create_dataset('orientations', - (N, 3), - data=orientations, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['orientations'][:] = orientations - - if 'omegas' not in frame.keys(): - frame.create_dataset('omegas', - (N, 3), - data=omegas, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['omegas'][:] = omegas - - if 'torque' not in frame.keys(): - frame.create_dataset('torque', - (N, 3), - data=torque, - dtype=DTYPE, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - else: - frame['torque'][:] = torque - - # spatial dimension - frame.attrs['d'] = d - - # add type if not specified - if 'type' not in frame.keys(): - frame.create_dataset('type', - (N,), - data=np.ones(N), - dtype=int, - compression=COMPRESSION, - shuffle=SHUFFLE, - fletcher32=FLETCHER) - - steps[n] = step - - del lines - - if idwarning: - # Warn user if data could not be sorted. - self.__log.warning( - "No IDs specified. Data may be unsorted between "\ - "individual frames." - ) - - self.steps = steps - # get time step from log file (this also sets self.times) - self.dt = self.__get_timestep_from_logfile() - self.d = d - except Exception as e: - os.remove(os.path.join(savedir, "#temp#"+trajfile)) - # print("LammpsReader: loading dump files failed.") - if "LammpsReader: no dump files in this directory." in e.args[0]: - # print(e) - # we should not raise an error in this case. - pass - # print(f"LammpsReader: error while loading dump files. {e}") - raise - else: - # if no exception. rename #temp# and delete #. - if os.path.exists(os.path.join(savedir, trajfile)) and verbose: - # This case should not occur if AMEP is used properly. - # Possible scenario: - # two instances of AMEP reading and writing in the same directory. - self.__log.info( - f"File {trajfile} already exists. "\ - "Overwriting existing file." - ) - os.rename(os.path.join(savedir, "#temp#"+trajfile), os.path.join(savedir, trajfile)) - self.filename = trajfile - - # delete old trajectory file # if specified by user. - if deleteold and os.path.exists(os.path.join(savedir, "#"+trajfile)): - os.remove(os.path.join(savedir, "#"+trajfile)) - if verbose: - self.__log.info( - f"Deleted old trajectory file #{trajfile}" - ) - finally: - pass - - - def __sorter(self, item): - r''' - Returns the time step of a dump file that is given - in the filename of the dump file. - - INPUT: - item: dump-file name (str) - - OUTPUT: - time step (float) - ''' - key = self.__dumps.split('*')[0] - basedir, basename = os.path.split(item) - if key=='': - return float(basename.split('.')[0]) - return float(basename.split(key)[1].split('.')[0]) - - - def __get_timestep_from_logfile(self): - r''' - Reads the time step from the log.lammps file. - - Returns - ------- - dt : float - Time step. - ''' - if os.path.exists(os.path.join(self.directory, 'log.lammps')): - with open(os.path.join( - self.directory, 'log.lammps' - ), encoding="utf-8") as f: - lines = f.readlines() - relevant = [line for line in lines if line.startswith('timestep')] - if len(relevant)>=1: - dt = float(relevant[-1].split('timestep')[-1]) - else: - dt = 1 - self.__log.warning( - "No timestep mentioned in logfile. Using dt=1. "\ - "The timestep can be set manually by traj.dt=
." - ) - if len(relevant)>1: - self.__log.warning( - "More than one timestep found. Using last mention, "\ - f"dt={dt}. "\ - "The timestep can be set manually by traj.dt=
." - ) - else: - self.__log.warning( - "No log file found. Using dt=1. "\ - "The timestep can be set manually by traj.dt=
." - ) - dt = 1 - - return dt + return delimiter \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py index b2145f1..56891cf 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -9,7 +9,7 @@ project = 'AMEP' copyright = '2023-2024, Lukas Hecht, Kay-Robert Dormann, Kai Luca Spanheimer' author = 'Lukas Hecht, Kay-Robert Dormann, Kai Luca Spanheimer' -release = '1.0.2' +release = '1.0.3' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -51,7 +51,7 @@ "url": "https://github.com/amepproject/amep", # required # Icon class (if "type": "fontawesome"), or path to local image (if "type": "local") "icon": "fa-brands fa-square-github", - # The type of image to be used (see below for details) + # The type of image to be used "type": "fontawesome", }, { @@ -61,8 +61,16 @@ "url": "https://pypi.org/project/amep/", # required # Icon class (if "type": "fontawesome"), or path to local image (if "type": "local") "icon": "fa-brands fa-python", - # The type of image to be used (see below for details) + # The type of image to be used "type": "fontawesome", } - ] - } + ], + #"switcher": { + # "json_url": "https://amepproject.de/switcher.json", + # "version_match": release + #}, + #"check_switcher": True, + #"navbar_persistent": ["search-button.html", "theme-switcher.html"], + #"navbar_end": ["version-switcher.html", "icon-links.html"] + # "navbar_start": ["navbar_logo", "version-switcher"] + } diff --git a/doc/source/datastructures/particle_data_reader.md b/doc/source/datastructures/particle_data_reader.md deleted file mode 100644 index e77ffe4..0000000 --- a/doc/source/datastructures/particle_data_reader.md +++ /dev/null @@ -1,20 +0,0 @@ -# Creating a new data reader - -If you want to implement a reader for a particle based simulation data format. -You need to read out the following data: - - -For each timestep: -1. Timestep -2. Simulation time -3. Simulation Box -4. Center of the Box -5. particle coordinates -6. Unwrapped particle coordinates -7. particle velocities -8. forces -9. orientations -10. rotation speeds -11. torques -12. Angular momenta - diff --git a/doc/source/user_guide/howto_cite.rst b/doc/source/howto_cite.rst similarity index 95% rename from doc/source/user_guide/howto_cite.rst rename to doc/source/howto_cite.rst index d423787..0dac878 100644 --- a/doc/source/user_guide/howto_cite.rst +++ b/doc/source/howto_cite.rst @@ -1,6 +1,6 @@ -===================== -How to cite **AMEP** -===================== +============ +How to Cite +============ If you use **AMEP** for a project that leads to a scientific publication, please acknowledge the use of **AMEP** within the body of your publication for example by copying or adapting diff --git a/doc/source/index.rst b/doc/source/index.rst index 26b512e..8d63828 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,8 +3,8 @@ :align: center -AMEP documentation -================== +AMEP 1.0.3 documentation +======================== .. include:: ../../README.md :parser: myst_parser.sphinx_ @@ -17,7 +17,7 @@ Table of Contents :maxdepth: 2 gettingstarted/index - datastructures/index + howto_cite user_guide/index api diff --git a/doc/source/datastructures/field_data.rst b/doc/source/user_guide/datastructures/field_data.rst similarity index 100% rename from doc/source/datastructures/field_data.rst rename to doc/source/user_guide/datastructures/field_data.rst diff --git a/doc/source/datastructures/function_flow.rst b/doc/source/user_guide/datastructures/function_flow.rst similarity index 100% rename from doc/source/datastructures/function_flow.rst rename to doc/source/user_guide/datastructures/function_flow.rst diff --git a/doc/source/datastructures/index.rst b/doc/source/user_guide/datastructures/index.rst similarity index 84% rename from doc/source/datastructures/index.rst rename to doc/source/user_guide/datastructures/index.rst index 1af028d..0a3fb5c 100644 --- a/doc/source/datastructures/index.rst +++ b/doc/source/user_guide/datastructures/index.rst @@ -11,7 +11,3 @@ the sections below. .. toctree:: field_data - -.. toctree:: - - particle_data_reader diff --git a/doc/source/user_guide/index.rst b/doc/source/user_guide/index.rst index e2b9bfd..fa39e0f 100644 --- a/doc/source/user_guide/index.rst +++ b/doc/source/user_guide/index.rst @@ -15,7 +15,7 @@ your research. .. toctree:: - howto_cite + datastructures/index .. toctree:: From 0ccaec144a62a6c595296caaab4b76ba8182014b Mon Sep 17 00:00:00 2001 From: Kay-Robert Dormann Date: Tue, 22 Oct 2024 18:33:12 +0200 Subject: [PATCH 3/5] fixed add_particle test --- test/test_trajectory.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_trajectory.py b/test/test_trajectory.py index f582cb4..4132c2a 100644 --- a/test/test_trajectory.py +++ b/test/test_trajectory.py @@ -118,6 +118,7 @@ def test_get_particle_info(self): def test_ptype_type(self): self.traj.add_particle_info(1, "key", "value") + self.assertRaises(TypeError, self.traj.add_particle_info, "asdf") self.traj.add_particle_info("asdf", "key2", "value2") self.assertTrue( isinstance(self.traj.get_particle_info(1), dict), From 889dfb7716e5f794aa621fa0274ecda904f57ff3 Mon Sep 17 00:00:00 2001 From: Kay-Robert Dormann Date: Tue, 22 Oct 2024 18:44:08 +0200 Subject: [PATCH 4/5] fixed error 40 --- test/test_trajectory.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_trajectory.py b/test/test_trajectory.py index 4132c2a..7cead9e 100644 --- a/test/test_trajectory.py +++ b/test/test_trajectory.py @@ -118,8 +118,7 @@ def test_get_particle_info(self): def test_ptype_type(self): self.traj.add_particle_info(1, "key", "value") - self.assertRaises(TypeError, self.traj.add_particle_info, "asdf") - self.traj.add_particle_info("asdf", "key2", "value2") + self.assertRaises(TypeError, self.traj.add_particle_info, "asdf", "key2", "value2") self.assertTrue( isinstance(self.traj.get_particle_info(1), dict), f'''Invalid type. Got {type(self.traj.get_particle_info(1))} From 8b0fe49df693114b2c110a338ea04f058df88a16 Mon Sep 17 00:00:00 2001 From: Kay-Robert Dormann Date: Tue, 22 Oct 2024 19:00:07 +0200 Subject: [PATCH 5/5] speed up tests --- test/test_evaluate.py | 6 +++--- test/test_plot.py | 4 ++-- test/test_trajectory.py | 6 +----- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/test/test_evaluate.py b/test/test_evaluate.py index 5ba16b6..edd3fb9 100644 --- a/test/test_evaluate.py +++ b/test/test_evaluate.py @@ -85,12 +85,12 @@ def msd(frame, start=None): msd_eval.name = "msd" msd_eval.save(RESULT_DIR/"msd_eval.h5") pcf2d = PCF2d(traj, - nav=2, nxbins=2000, nybins=2000, + nav=2, nxbins=50, nybins=50, njobs=4, skip=0.9 ) pcf2d.save(RESULT_DIR/"pcf2d.h5") pcfangle = PCFangle( - traj, nav=2, ndbins=1000, nabins=1000, + traj, nav=2, ndbins=50, nabins=50, njobs=4, rmax=8.0, skip=0.9 ) pcfangle.save(RESULT_DIR/"pcfangle.h5") @@ -109,7 +109,7 @@ def test_correlation(self): """Test order parameter evaluation. TO BE IMPLEMENTED """ - svc = SpatialVelCor(self.particle_traj, skip=0.9, nav=5, njobs=4) + svc = SpatialVelCor(self.particle_traj, skip=0.9, nav=2, njobs=4) svc.save(RESULT_DIR/"svc.h5") rdfcalc = RDF( diff --git a/test/test_plot.py b/test/test_plot.py index 7a3a05b..4944715 100644 --- a/test/test_plot.py +++ b/test/test_plot.py @@ -127,8 +127,8 @@ def test_animation(self): p_trajectory = choice([traj for traj in self.trajs if isinstance(traj, ParticleTrajectory)]) out_particles = PLOT_DIR/"particle_vid.gif" - plot.animate_trajectory(f_trajectory, out_field, ftype="c") - plot.animate_trajectory(p_trajectory, out_particles) + plot.animate_trajectory(f_trajectory, out_field, ftype="c", nth=10) + plot.animate_trajectory(p_trajectory, out_particles, nth=50) def test_ll_video(self): """Test the low level video interface.""" diff --git a/test/test_trajectory.py b/test/test_trajectory.py index 7cead9e..04181ad 100644 --- a/test/test_trajectory.py +++ b/test/test_trajectory.py @@ -124,11 +124,7 @@ def test_ptype_type(self): f'''Invalid type. Got {type(self.traj.get_particle_info(1))} instead of dict.''' ) - self.assertTrue( - isinstance(self.traj.get_particle_info("asdf"), dict), - f'''Invalid type. Got {type(self.traj.get_particle_info(1))} - instead of dict.''' - ) + self.assertRaises(TypeError, self.traj.get_particle_info, "asdf") def test_delete_particle_info(self): # delete particle info