diff --git a/gui/tests/env.js b/gui/tests/env.js index eef93eb2081037b4b6eb8cb950aaa74254b496a8..1229b90c75f549bce4b06c4d23061fcd49ed45e1 100644 --- a/gui/tests/env.js +++ b/gui/tests/env.js @@ -2077,7 +2077,7 @@ window.nomadEnv = { "name": "parsers/edmft", "description": "NOMAD parser for EDMFT.", "plugin_package": "electronicparsers", - "level": 0, + "level": 2, "aliases": [ "parsers/edmft" ], @@ -2220,7 +2220,7 @@ window.nomadEnv = { "name": "parsers/magres", "description": "NOMAD parser for MAGRES.", "plugin_package": "electronicparsers", - "level": 0, + "level": 1, "aliases": [ "parsers/magres" ], @@ -2481,7 +2481,7 @@ window.nomadEnv = { "name": "parsers/tbstudio", "description": "NOMAD parser for TBSTUDIO.", "plugin_package": "electronicparsers", - "level": 0, + "level": 1, "aliases": [ "parsers/tbstudio" ], @@ -2533,7 +2533,7 @@ window.nomadEnv = { "name": "parsers/w2dynamics", "description": "NOMAD parser for W2DYNAMICS.", "plugin_package": "electronicparsers", - "level": 0, + "level": 2, "aliases": [ "parsers/w2dynamics" ], @@ -2555,7 +2555,7 @@ window.nomadEnv = { "name": "parsers/wannier90", "description": "NOMAD parser for WANNIER90.", "plugin_package": "electronicparsers", - "level": 0, + "level": 1, "aliases": [ "parsers/wannier90" ], diff --git a/nomad/app/v1/routers/systems.py b/nomad/app/v1/routers/systems.py index 36748041d27430c43d74e9282662dcbcd449a1be..8c7e375aa9563d1e1a76590d6ca7576591014230 100644 --- a/nomad/app/v1/routers/systems.py +++ b/nomad/app/v1/routers/systems.py @@ -26,15 +26,12 @@ from fastapi import APIRouter, Depends, Path, Query, status, HTTPException from fastapi.responses import Response import ase.io import ase.build -from MDAnalysis.lib.util import NamedStream -from MDAnalysis.coordinates.PDB import PDBWriter from nomad.units import ureg from nomad.utils import strip, deep_get, query_list_to_dict from nomad.atomutils import Formula, wrap_positions, unwrap_positions from nomad.normalizing.common import ( ase_atoms_from_nomad_atoms, - mda_universe_from_nomad_atoms, ) from nomad.datamodel.metainfo.system import Atoms as NOMADAtoms from .entries import answer_entry_archive_request @@ -72,36 +69,16 @@ def write_pdb(atoms: NOMADAtoms, entry_id: str = None, formula: str = None) -> s lines.append( f'REMARK 285 C: {cell[2, 0]:.3f}, {cell[2, 1]:.3f}, {cell[2, 2]:.3f}\n' ) - else: - lines.append( - 'REMARK 285 UNITARY VALUES FOR THE UNIT CELL SET BECAUSE UNIT CELL INFORMATION\n' - ) - lines.append( - 'REMARK 285 WAS MISSING. PROTEIN DATA BANK CONVENTIONS REQUIRE THAT CRYST1\n' - ) - lines.append( - 'REMARK 285 RECORD IS INCLUDED, BUT THE VALUES ON THIS RECORD ARE MEANINGLESS.\n' - ) if pbc is not None: pbc = ['TRUE' if x else 'FALSE' for x in pbc] lines.append(f'REMARK 285 PBC (A, B, C): {pbc[0]}, {pbc[1]}, {pbc[2]}\n') - mda_string_stream = StringIO() - mda_named_stream = NamedStream( - mda_string_stream, f'temp.{format}', close=False, reset=False - ) - writer = PDBWriter(mda_named_stream, remarks='') - universe = mda_universe_from_nomad_atoms(atoms) - writer.write(universe) - writer.close() - - # We skip the title line that is written by MDA (cannot be disabled otherwise) - mda_string_stream.seek(0) - for line in mda_string_stream.readlines(): - if not line.startswith(('REMARK', 'TITLE')): - lines.append(line) - + stream = StringIO() + atoms = ase_atoms_from_nomad_atoms(atoms) + ase.io.write(stream, atoms, format='proteindatabank') + stream.seek(0) content = ''.join(lines) + content += stream.read() return content diff --git a/nomad/atomutils.py b/nomad/atomutils.py index c95aab394953d144f510fe5a461ff744d8eb9477..07e9959918b2373c75426b692d8cd765d50c5c86 100644 --- a/nomad/atomutils.py +++ b/nomad/atomutils.py @@ -23,16 +23,11 @@ import itertools import logging import math import re -import warnings -from array import array -from collections import namedtuple from functools import reduce -from itertools import chain from string import ascii_uppercase from typing import ( TYPE_CHECKING, Any, - Callable, Dict, Iterable, List, @@ -43,27 +38,15 @@ from typing import ( import ase.data import ase.geometry -import MDAnalysis -import MDAnalysis.analysis.rdf as MDA_RDF -import networkx import numpy as np from ase import Atoms from ase.formula import Formula as ASEFormula from ase.utils import pbc2pbc -from MDAnalysis.core._get_readers import get_reader_for -from MDAnalysis.core.topology import Topology -from MDAnalysis.core.universe import Universe -from nptyping import Int, NDArray -from pymatgen.core import Composition -from pymatgen.core.periodic_table import get_el_sp -from scipy import sparse +from nptyping import NDArray from scipy.spatial import Voronoi # pylint: disable=no-name-in-module -from scipy.stats import linregress from nomad.aflow_prototypes import aflow_prototypes from nomad.constants import atomic_masses -from nomad.metainfo import MSection -from nomad.units import ureg valid_elements = set(ase.data.chemical_symbols[1:]) @@ -944,6 +927,8 @@ class Formula: # Try if can be interpreted as fractional formula except Exception: try: + from pymatgen.core import Composition + self.ase_formula = ASEFormula( Composition(formula).get_integer_formula_and_factor()[0] ) @@ -1150,6 +1135,8 @@ class Formula: def _formula_iupac(self) -> str: """Returns the IUPAC formula.""" + from pymatgen.core.periodic_table import get_el_sp + count = self.count() counts = count.values() symbols = list(count.keys()) @@ -1274,1129 +1261,3 @@ class Formula: Chemical formula as a string. """ return ''.join(symb + (str(n) if n > 1 else '') for symb, n in dct.items()) - - -def create_empty_universe( - n_atoms: int, - n_frames: int = 1, - n_residues: int = 1, - n_segments: int = 1, - atom_resindex: NDArray[Int] = None, - residue_segindex: NDArray[Int] = None, - flag_trajectory: bool = False, - flag_velocities: bool = False, - flag_forces: bool = False, - timestep: float = None, -) -> MDAnalysis.Universe: - """Create a blank Universe - - This function was adapted from the function empty() within the MDA class Universe(). - The only difference is that the Universe() class is imported directly here, whereas in the - original function is is passed as a function argument, since the function there is a classfunction. - - Useful for building a Universe without requiring existing files, - for example for system building. - - If `flag_trajectory` is set to True, a - :class:`MDAnalysis.coordinates.memory.MemoryReader` will be - attached to the Universe. - - Parameters - ---------- - n_atoms: int - number of Atoms in the Universe - n_residues: int, default 1 - number of Residues in the Universe, defaults to 1 - n_segments: int, default 1 - number of Segments in the Universe, defaults to 1 - atom_resindex: array like, optional - mapping of atoms to residues, e.g. with 6 atoms, - `atom_resindex=[0, 0, 1, 1, 2, 2]` would put 2 atoms - into each of 3 residues. - residue_segindex: array like, optional - mapping of residues to segments - flag_trajectory: bool, optional - if True, attaches a :class:`MDAnalysis.coordinates.memory.MemoryReader` - allowing coordinates to be set and written. Default is False - flag_velocities: bool, optional - include velocities in the :class:`MDAnalysis.coordinates.memory.MemoryReader` - flag_forces: bool, optional - include forces in the :class:`MDAnalysis.coordinates.memory.MemoryReader` - - Returns - ------- - MDAnalysis.Universe object - - Examples - -------- - For example to create a new Universe with 6 atoms in 2 residues, with - positions for the atoms and a mass attribute: - - >>> u = mda.Universe.empty(6, 2, - atom_resindex=np.array([0, 0, 0, 1, 1, 1]), - flag_trajectory=True, - ) - >>> u.add_TopologyAttr('masses') - - .. versionadded:: 0.17.0 - .. versionchanged:: 0.19.0 - The attached Reader when flag_trajectory=True is now a MemoryReader - .. versionchanged:: 1.0.0 - Universes can now be created with 0 atoms - """ - - if not n_atoms: - n_residues = 0 - n_segments = 0 - - if atom_resindex is None: - warnings.warn( - 'Residues specified but no atom_resindex given. ' - 'All atoms will be placed in first Residue.', - UserWarning, - ) - - if residue_segindex is None: - warnings.warn( - 'Segments specified but no segment_resindex given. ' - 'All residues will be placed in first Segment', - UserWarning, - ) - - topology = Topology( - n_atoms, - n_residues, - n_segments, - atom_resindex=atom_resindex, - residue_segindex=residue_segindex, - ) - - universe = Universe(topology) - - if flag_trajectory: - coords = np.zeros((n_frames, n_atoms, 3), dtype=np.float32) - vels = np.zeros_like(coords) if flag_velocities else None - forces = np.zeros_like(coords) if flag_forces else None - - # grab and attach a MemoryReader - universe.trajectory = get_reader_for(coords)( - coords, - order='fac', - n_atoms=n_atoms, - velocities=vels, - forces=forces, - dt=timestep, - ) - - return universe - - -def archive_to_universe( - archive, - system_index: int = 0, - method_index: int = -1, - model_index: int = -1, -) -> MDAnalysis.Universe: - """Extract the topology from a provided run section of an archive entry - - Input: - - archive_sec_run: section run of an EntryArchive - - system_index: list index of archive.run[].system to be used for topology extraction - - method_index: list index of archive.run[].method to be used for atom parameter (charges and masses) extraction - - model_index: list index of archive.run[].method[].force_field.model for bond list extraction - - Variables: - - n_frames (int): - - n_atoms (int): - - atom_names (str, shape=(n_atoms)): - - atom_types (str, shape=(n_atoms)): - - atom_resindex (str, shape=(n_atoms)): - - atom_segids (str, shape=(n_atoms)): - - n_segments (int): Segments correspond to a group of the same type of molecules. - - n_residues (int): The number of distinct residues (nb - individual molecules are also denoted as a residue). - - resnames (str, shape=(n_residues)): The name of each residue. - - residue_segindex (int, shape=(n_residues)): The segment index that each residue belongs to. - - residue_molnums (int, shape=(n_residues)): The molecule index that each residue belongs to. - - residue_moltypes (int, shape=(n_residues)): The molecule type of each residue. - - n_molecules (int): - - masses (float, shape=(n_atoms)): atom masses, units = amu - - charges (float, shape=(n_atoms)): atom partial charges, units = e - - positions (float, shape=(n_frames,n_atoms,3)): atom positions - - velocities (float, shape=(n_frames,n_atoms,3)): atom velocities - - dimensions (float, shape=(n_frames,6)): box dimensions (nb - currently assuming a cubic box!) - - bonds (tuple, shape=([])): list of tuples with the atom indices of each bond - """ - - try: - sec_run = archive.run[-1] - sec_system = sec_run.system - sec_system_top = sec_run.system[system_index] - sec_atoms = sec_system_top.atoms - sec_atoms_group = sec_system_top.atoms_group - sec_calculation = sec_run.calculation - sec_method = ( - sec_run.method[method_index] if sec_run.get('method') is not None else None - ) - except IndexError: - logging.warning( - 'Supplied indices or necessary sections do not exist in archive. Cannot build the MDA universe.' - ) - return None - - n_atoms = sec_atoms.get('n_atoms') - if n_atoms is None: - logging.warning('No atoms found in the archive. Cannot build the MDA universe.') - return None - - n_frames = len(sec_system) if sec_system is not None else None - atom_names = sec_atoms.get('labels') - model_atom_parameters = sec_method.get('atom_parameters') - atom_types = ( - [atom.label for atom in model_atom_parameters] - if model_atom_parameters - else atom_names - ) - atom_resindex = np.arange(n_atoms) - atoms_segindices = np.empty(n_atoms) - atom_segids = np.array(range(n_atoms), dtype='object') - molecule_groups = sec_atoms_group - n_segments = len(molecule_groups) - - n_residues = 0 - n_molecules = 0 - residue_segindex = [] - resnames = [] - residue_moltypes = [] - residue_min_atom_index = [] - residue_n_atoms = [] - molecule_n_res = [] - for mol_group_ind, mol_group in enumerate(molecule_groups): - atoms_segindices[mol_group.atom_indices] = mol_group_ind - atom_segids[mol_group.atom_indices] = mol_group.label - molecules = mol_group.atoms_group if mol_group.atoms_group is not None else [] - for mol in molecules: - monomer_groups = mol.atoms_group - mol_res_counter = 0 - if monomer_groups: - for mon_group in monomer_groups: - monomers = mon_group.atoms_group - for mon in monomers: - resnames.append(mon.label) - residue_segindex.append(mol_group_ind) - residue_moltypes.append(mol.label) - residue_min_atom_index.append(np.min(mon.atom_indices)) - residue_n_atoms.append(len(mon.atom_indices)) - n_residues += 1 - mol_res_counter += 1 - else: # no monomers => whole molecule is it's own residue - resnames.append(mol.label) - residue_segindex.append(mol_group_ind) - residue_moltypes.append(mol.label) - residue_min_atom_index.append(np.min(mol.atom_indices)) - residue_n_atoms.append(len(mol.atom_indices)) - n_residues += 1 - mol_res_counter += 1 - molecule_n_res.append(mol_res_counter) - n_molecules += 1 - - # reorder the residues by atom_indices - residue_data = np.array( - [ - [ - residue_min_atom_index[i], - residue_n_atoms[i], - residue_segindex[i], - residue_moltypes[i], - resnames[i], - ] - for i in range(len(residue_min_atom_index)) - ], - dtype=object, - ) - residue_data = np.array(sorted(residue_data, key=lambda x: x[0], reverse=False)).T - residue_n_atoms = residue_data[1].astype(int) - residue_segindex = residue_data[2].astype(int) - residue_moltypes = residue_data[3] - resnames = residue_data[4] - res_index_counter = 0 - for i_residue, res_n_atoms in enumerate(residue_n_atoms): - atom_resindex[res_index_counter : res_index_counter + res_n_atoms] = i_residue # type: ignore - res_index_counter += res_n_atoms - residue_molnums = np.array(range(n_residues)) - mol_index_counter = 0 - for i_molecule, n_res in enumerate(molecule_n_res): - residue_molnums[mol_index_counter : mol_index_counter + n_res] = i_molecule - mol_index_counter += n_res - - # get the atom masses and charges - - masses = np.empty(n_atoms) - charges = np.empty(n_atoms) - atom_parameters = ( - sec_method.get('atom_parameters') if sec_method is not None else [] - ) - atom_parameters = atom_parameters if atom_parameters is not None else [] - - for atom_ind, atom in enumerate(atom_parameters): - if atom.get('mass'): - masses[atom_ind] = ureg.convert( - atom.mass.magnitude, atom.mass.units, ureg.amu - ) - if atom.get('charge'): - charges[atom_ind] = ureg.convert( - atom.charge.magnitude, atom.charge.units, ureg.e - ) - - # get the atom positions, velocites, and box dimensions - positions = np.empty(shape=(n_frames, n_atoms, 3)) - velocities = np.empty(shape=(n_frames, n_atoms, 3)) - dimensions = np.empty(shape=(n_frames, 6)) - for frame_ind, frame in enumerate(sec_system): - sec_atoms_fr = frame.get('atoms') - if sec_atoms_fr is not None: - positions_frame = sec_atoms_fr.positions - positions[frame_ind] = ( - ureg.convert( - positions_frame.magnitude, positions_frame.units, ureg.angstrom - ) - if positions_frame is not None - else None - ) - velocities_frame = sec_atoms_fr.velocities - velocities[frame_ind] = ( - ureg.convert( - velocities_frame.magnitude, - velocities_frame.units, - ureg.angstrom / ureg.picosecond, - ) - if velocities_frame is not None - else None - ) - latt_vec_tmp = sec_atoms_fr.get('lattice_vectors') - if latt_vec_tmp is not None: - length_conversion = ureg.convert( - 1.0, sec_atoms_fr.lattice_vectors.units, ureg.angstrom - ) - dimensions[frame_ind] = [ - sec_atoms_fr.lattice_vectors.magnitude[0][0] * length_conversion, - sec_atoms_fr.lattice_vectors.magnitude[1][1] * length_conversion, - sec_atoms_fr.lattice_vectors.magnitude[2][2] * length_conversion, - 90, - 90, - 90, - ] # TODO: extend to non-cubic boxes - - # get the bonds # TODO extend to multiple storage options for interactions - bonds = sec_atoms.bond_list - if bonds is None: - bonds = get_bond_list_from_model_contributions( - sec_run, method_index=-1, model_index=-1 - ) - - # get the system times - system_timestep = 1.0 * ureg.picosecond - - def approx(a, b, rel_tol=1e-09, abs_tol=0.0): - return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) - - system_times = [calc.time for calc in sec_calculation if calc.system_ref] - if system_times: - try: - method = archive.workflow2.method - system_timestep = ( - method.integration_timestep * method.coordinate_save_frequency - ) - except Exception: - logging.warning( - 'Cannot find the system times. MDA universe will contain non-physical times and timestep.' - ) - else: - time_steps = [ - system_times[i_time] - system_times[i_time - 1] - for i_time in range(1, len(system_times)) - ] - if all(approx(time_steps[0], time_step) for time_step in time_steps): - system_timestep = ureg.convert( - time_steps[0].magnitude, ureg.second, ureg.picosecond - ) - else: - logging.warning( - 'System times are not equally spaced. Cannot set system times in MDA universe.' - ' MDA universe will contain non-physical times and timestep.' - ) - - system_timestep = ureg.convert( - system_timestep, system_timestep._units, ureg.picoseconds - ) - - # create the Universe - metainfo_universe = create_empty_universe( - n_atoms, - n_frames=n_frames, - n_residues=n_residues, - n_segments=n_segments, - atom_resindex=atom_resindex, - residue_segindex=residue_segindex, - flag_trajectory=True, - flag_velocities=True, - timestep=system_timestep.magnitude, - ) - - # set the positions and velocities - for frame_ind, frame in enumerate(metainfo_universe.trajectory): - metainfo_universe.atoms.positions = positions[frame_ind] - metainfo_universe.atoms.velocities = velocities[frame_ind] - - # add the atom attributes - metainfo_universe.add_TopologyAttr('name', atom_names) - metainfo_universe.add_TopologyAttr('type', atom_types) - metainfo_universe.add_TopologyAttr('mass', masses) - metainfo_universe.add_TopologyAttr('charge', charges) - if n_segments != 0: - metainfo_universe.add_TopologyAttr('segids', np.unique(atom_segids)) - if n_residues != 0: - metainfo_universe.add_TopologyAttr('resnames', resnames) - metainfo_universe.add_TopologyAttr('resids', np.unique(atom_resindex) + 1) - metainfo_universe.add_TopologyAttr('resnums', np.unique(atom_resindex) + 1) - if len(residue_molnums) > 0: - metainfo_universe.add_TopologyAttr('molnums', residue_molnums) - if len(residue_moltypes) > 0: - metainfo_universe.add_TopologyAttr('moltypes', residue_moltypes) - - # add the box dimensions - for frame_ind, frame in enumerate(metainfo_universe.trajectory): - metainfo_universe.atoms.dimensions = dimensions[frame_ind] - - # add the bonds - if hasattr(metainfo_universe, 'bonds'): - logging.warning('archive_to_universe() failed, universe already has bonds.') - return None - metainfo_universe.add_TopologyAttr('bonds', bonds) - - return metainfo_universe - - -class BeadGroup(object): - # see https://github.com/MDAnalysis/mdanalysis/issues/1891#issuecomment-387138110 - # by @richardjgowers with performance improvements - def __init__(self, atoms, compound='fragments'): - """Initialize with an AtomGroup instance. - Will split based on keyword 'compounds' (residues or fragments). - """ - self._atoms = atoms - self.compound = compound - self._nbeads = len(getattr(self._atoms, self.compound)) - # for caching - self._cache = {} - self._cache['positions'] = None - self.__last_frame = None - - def __len__(self): - return self._nbeads - - @property - def positions(self): - # cache positions for current frame - if self.universe.trajectory.frame != self.__last_frame: - self._cache['positions'] = self._atoms.center_of_mass( - unwrap=True, compound=self.compound - ) - self.__last_frame = self.universe.trajectory.frame - return self._cache['positions'] - - @property # type: ignore - @MDAnalysis.lib.util.cached('universe') - def universe(self): - return self._atoms.universe - - -def __log_indices(first: int, last: int, num: int = 100): - ls = np.logspace(0, np.log10(last - first + 1), num=num) - return np.unique(np.int_(ls) - 1 + first) - - -def __correlation(function, positions: List[float]): - iterator = iter(positions) - start_frame = next(iterator) - return map(lambda f: function(start_frame, f), chain([start_frame], iterator)) - - -def shifted_correlation_average( - function: Callable, - times: NDArray, - positions: NDArray, - index_distribution: Callable = __log_indices, - correlation: Callable = __correlation, - segments: int = 10, - window: float = 0.5, - skip: int = 0, -) -> tuple[NDArray, NDArray]: - """ - Code adapted from MDevaluate module: https://github.com/mdevaluate/mdevaluate.git - - Calculate the time series for a correlation function. - - The times at which the correlation is calculated are determined automatically by the - function given as ``index_distribution``. The default is a logarithmic distribution. - - The function has been edited so that the average is always calculated, i.e., average=True below. - - Args: - function: The function that should be correlated - positions: The coordinates of the simulation data - index_distribution (opt.): - A function that returns the indices for which the timeseries - will be calculated - correlation (function, opt.): - The correlation function - segments (int, opt.): - The number of segments the time window will be shifted - window (float, opt.): - The fraction of the simulation the time series will cover - skip (float, opt.): - The fraction of the trajectory that will be skipped at the beginning, - if this is None the start index of the frames slice will be used, - which defaults to 0. - counter (bool, opt.): - If True, returns length of frames (in general number of particles specified) - average (bool, opt.): - If True, - Returns: - tuple: - A list of length N that contains the indices of the frames at which - the time series was calculated and a numpy array of shape (segments, N) - that holds the (non-avaraged) correlation data - - if has_counter == True: adds number of counts to output tupel. - if average is returned it will be weighted. - - Example: - Calculating the mean square displacement of a coordinates object named ``coords``: - - >>> indices, data = shifted_correlation(msd, coords) - """ - if window + skip >= 1: - warnings.warn( - 'Invalid parameters for shifted_correlation(), ' 'resetting to defaults.', - UserWarning, - ) - window = 0.5 - skip = 0 - - start_frames = np.unique( - np.linspace( - len(positions) * skip, - len(positions) * (1 - window), - num=segments, - endpoint=False, - dtype=int, - ) - ) - num_frames = int(len(positions) * (window)) - - idx = index_distribution(0, num_frames) - - def correlate(start_frame): - shifted_idx = idx + start_frame - return correlation(function, map(positions.__getitem__, shifted_idx)) - - correlation_times = np.array([times[i] for i in idx]) - times[0] - - result: NDArray - for i_start_frame, start_frame in enumerate(start_frames): - if i_start_frame == 0: - result = np.array(list(correlate(start_frame))) - else: - result += np.array(list(correlate(start_frame))) - result = np.array(result) - result = result / len(start_frames) - - return correlation_times, result - - -def _calc_diffusion_constant( - times: NDArray, values: NDArray, dim: int = 3 -) -> tuple[float, float]: - """ - Determines the diffusion constant from a fit of the mean squared displacement - vs. time according to the Einstein relation. - """ - linear_model = linregress(times, values) - slope = linear_model.slope - error = linear_model.rvalue - return slope * 1 / (2 * dim), error - - -def _get_molecular_bead_groups( - universe: MDAnalysis.Universe, moltypes: List[str] = None -) -> Dict[str, BeadGroup]: - """ - Creates bead groups based on the molecular types as defined by the MDAnalysis universe. - """ - if moltypes is None: - atoms_moltypes = getattr(universe.atoms, 'moltypes', []) - moltypes = np.unique(atoms_moltypes) - bead_groups = {} - for moltype in moltypes: - ags_by_moltype = universe.select_atoms('moltype ' + moltype) - ags_by_moltype = ags_by_moltype[ - ags_by_moltype.masses > abs(1e-2) - ] # remove any virtual/massless sites (needed for, e.g., 4-bead water models) - bead_groups[moltype] = BeadGroup(ags_by_moltype, compound='fragments') - - return bead_groups - - -def calc_molecular_rdf( - universe: MDAnalysis.Universe, - n_traj_split: int = 10, - n_prune: int = 1, - interval_indices=None, - max_mols: int = 5000, -) -> Dict: - """ - Calculates the radial distribution functions between for each unique pair of - molecule types as a function of their center of mass distance. - - interval_indices: 2D array specifying the groups of the n_traj_split intervals to be averaged - max_mols: the maximum number of molecules per bead group for calculating the rdf, for efficiency purposes. - """ - # TODO 5k default for max_mols was set after > 50k was giving problems. Should do further testing to see where the appropriate limit should be set. - if ( - not universe - or not universe.trajectory - or universe.trajectory[0].dimensions is None - ): - return {} - - n_frames = universe.trajectory.n_frames - if n_frames < n_traj_split: - n_traj_split = 1 - frames_start = np.array([0]) - frames_end = np.array([n_frames]) - n_frames_split = np.array([n_frames]) - interval_indices = [[0]] - else: - run_len = int(n_frames / n_traj_split) - frames_start = np.arange(n_traj_split) * run_len - frames_end = frames_start + run_len - frames_end[-1] = n_frames - n_frames_split = frames_end - frames_start - if np.sum(n_frames_split) != n_frames: - logging.error( - 'Something went wrong with input parameters in calc_molecular_rdf().' - 'Radial distribution functions will not be calculated.' - ) - return {} - if not interval_indices: - interval_indices = [[i] for i in range(n_traj_split)] - - bead_groups = _get_molecular_bead_groups(universe) - if not bead_groups: - return bead_groups - moltypes = [moltype for moltype in bead_groups.keys()] - del_list = [ - i_moltype - for i_moltype, moltype in enumerate(moltypes) - if bead_groups[moltype]._nbeads > max_mols - ] - moltypes = np.delete(moltypes, del_list).tolist() - - min_box_dimension = np.min(universe.trajectory[0].dimensions[:3]) - max_rdf_dist = min_box_dimension / 2 - n_bins = 200 - n_smooth = 2 - - rdf_results: Dict[str, Any] = {} - rdf_results['n_smooth'] = n_smooth - rdf_results['n_prune'] = n_prune - rdf_results['type'] = 'molecular' - rdf_results['types'] = [] - rdf_results['variables_name'] = [] - rdf_results['bins'] = [] - rdf_results['value'] = [] - rdf_results['frame_start'] = [] - rdf_results['frame_end'] = [] - for i, moltype_i in enumerate(moltypes): - for j, moltype_j in enumerate(moltypes): - if j > i: - continue - elif ( - i == j and bead_groups[moltype_i].positions.shape[0] == 1 - ): # skip if only 1 mol in group - continue - - if i == j: - exclusion_block = (1, 1) # remove self-distance - else: - exclusion_block = None - pair_type = f'{moltype_i}-{moltype_j}' - rdf_results_interval: Dict[str, Any] = {} - rdf_results_interval['types'] = [] - rdf_results_interval['variables_name'] = [] - rdf_results_interval['bins'] = [] - rdf_results_interval['value'] = [] - rdf_results_interval['frame_start'] = [] - rdf_results_interval['frame_end'] = [] - for i_interval in range(n_traj_split): - rdf_results_interval['types'].append(pair_type) - rdf_results_interval['variables_name'].append(['distance']) - rdf = MDA_RDF.InterRDF( - bead_groups[moltype_i], - bead_groups[moltype_j], - range=(0, max_rdf_dist), - exclusion_block=exclusion_block, - nbins=n_bins, - ).run(frames_start[i_interval], frames_end[i_interval], n_prune) - rdf_results_interval['frame_start'].append(frames_start[i_interval]) - rdf_results_interval['frame_end'].append(frames_end[i_interval]) - - rdf_results_interval['bins'].append( - rdf.results.bins[int(n_smooth / 2) : -int(n_smooth / 2)] - * ureg.angstrom - ) - rdf_results_interval['value'].append( - np.convolve( - rdf.results.rdf, np.ones((n_smooth,)) / n_smooth, mode='same' - )[int(n_smooth / 2) : -int(n_smooth / 2)] - ) - - flag_logging_error = False - for interval_group in interval_indices: - split_weights = n_frames_split[np.array(interval_group)] / np.sum( - n_frames_split[np.array(interval_group)] - ) - if abs(np.sum(split_weights) - 1.0) > 1e-6: - flag_logging_error = True - continue - rdf_values_avg = ( - split_weights[0] * rdf_results_interval['value'][interval_group[0]] - ) - for i_interval, interval in enumerate(interval_group[1:]): - if ( - rdf_results_interval['types'][interval] - != rdf_results_interval['types'][interval - 1] - ): - flag_logging_error = True - continue - if ( - rdf_results_interval['variables_name'][interval] - != rdf_results_interval['variables_name'][interval - 1] - ): - flag_logging_error = True - continue - if not ( - rdf_results_interval['bins'][interval] - == rdf_results_interval['bins'][interval - 1] - ).all(): - flag_logging_error = True - continue - rdf_values_avg += ( - split_weights[i_interval + 1] - * rdf_results_interval['value'][interval] - ) - if flag_logging_error: - logging.error( - 'Something went wrong in calc_molecular_rdf(). Some interval groups were skipped.' - ) - rdf_results['types'].append( - rdf_results_interval['types'][interval_group[0]] - ) - rdf_results['variables_name'].append( - rdf_results_interval['variables_name'][interval_group[0]] - ) - rdf_results['bins'].append( - rdf_results_interval['bins'][interval_group[0]] - ) - rdf_results['value'].append(rdf_values_avg) - rdf_results['frame_start'].append( - int(rdf_results_interval['frame_start'][interval_group[0]]) - ) - rdf_results['frame_end'].append( - int(rdf_results_interval['frame_end'][interval_group[-1]]) - ) - - return rdf_results - - -def calc_molecular_mean_squared_displacements( - universe: MDAnalysis.Universe, max_mols: int = 5000 -) -> Dict: - """ - Calculates the mean squared displacement for the center of mass of each - molecule type. - - max_mols: the maximum number of molecules per bead group for calculating the msd, for efficiency purposes. - 50k was tested and is very fast and does not seem to have any memory issues. - """ - - def parse_jumps( - universe: MDAnalysis.Universe, selection: MDAnalysis.AtomGroup - ): # TODO Add output declaration - """ - See __get_nojump_positions(). - """ - __ = universe.trajectory[0] - prev = np.array(selection.positions) - box = universe.trajectory[0].dimensions[:3] - sparse_data = namedtuple('SparseData', ['data', 'row', 'col']) # type: ignore[name-match] - jump_data = ( - sparse_data(data=array('b'), row=array('l'), col=array('l')), - sparse_data(data=array('b'), row=array('l'), col=array('l')), - sparse_data(data=array('b'), row=array('l'), col=array('l')), - ) - - for i_frame, _ in enumerate(universe.trajectory[1:]): - curr = np.array(selection.positions) - delta = ((curr - prev) / box).round().astype(np.int8) - prev = np.array(curr) - for d in range(3): - (col,) = np.where(delta[:, d] != 0) - jump_data[d].col.extend(col) - jump_data[d].row.extend([i_frame] * len(col)) - jump_data[d].data.extend(delta[col, d]) - - return jump_data - - def generate_nojump_matrices( - universe: MDAnalysis.Universe, selection: MDAnalysis.AtomGroup - ): # TODO Add output declaration - """ - See __get_nojump_positions(). - """ - jump_data = parse_jumps(universe, selection) - n_frames = len(universe.trajectory) - n_atoms = selection.positions.shape[0] - - nojump_matrices = tuple( - sparse.csr_matrix( - (np.array(m.data), (m.row, m.col)), shape=(n_frames, n_atoms) - ) - for m in jump_data - ) - return nojump_matrices - - def get_nojump_positions( - universe: MDAnalysis.Universe, selection: MDAnalysis.AtomGroup - ) -> NDArray: - """ - Unwraps the positions to create a continuous trajectory without jumps across periodic boundaries. - """ - nojump_matrices = generate_nojump_matrices(universe, selection) - box = universe.trajectory[0].dimensions[:3] - - nojump_positions = [] - for i_frame, __ in enumerate(universe.trajectory): - delta = ( - np.array( - np.vstack([m[:i_frame, :].sum(axis=0) for m in nojump_matrices]).T - ) - * box - ) - nojump_positions.append(selection.positions - delta) - - return np.array(nojump_positions) - - def mean_squared_displacement(start: NDArray, current: NDArray): - """ - Calculates mean square displacement between current and initial (start) coordinates. - """ - vec = start - current - return (vec**2).sum(axis=1).mean() - - if ( - not universe - or not universe.trajectory - or universe.trajectory[0].dimensions is None - ): - return {} - - n_frames = universe.trajectory.n_frames - if n_frames < 50: - warnings.warn( - 'At least 50 frames required to calculate molecular' - ' mean squared displacements, skipping.', - UserWarning, - ) - return {} - - dt = getattr(universe.trajectory, 'dt') - if dt is None: - warnings.warn( - 'Universe is missing time step, cannot calculate molecular' - ' mean squared displacements, skipping.', - UserWarning, - ) - return {} - times = np.arange(n_frames) * dt - - bead_groups = _get_molecular_bead_groups(universe) - if bead_groups is {}: - return bead_groups - - moltypes = [moltype for moltype in bead_groups.keys()] - del_list = [] - for i_moltype, moltype in enumerate(moltypes): - if bead_groups[moltype]._nbeads > max_mols: - if max_mols > 50000: - warnings.warn( - 'Calculating mean squared displacements for more than 50k molecules.' - ' Expect long processing times!', - UserWarning, - ) - try: - # select max_mols nr. of rnd molecules from this moltype - moltype_indices = np.array( - [atom._ix for atom in bead_groups[moltype]._atoms] - ) - molnums = universe.atoms.molnums[moltype_indices] - molnum_types = np.unique(molnums) - molnum_types_rnd = np.sort( - np.random.choice(molnum_types, size=max_mols) - ) - atom_indices_rnd = np.concatenate( - [np.where(molnums == molnum)[0] for molnum in molnum_types_rnd] - ) - selection = ' '.join([str(i) for i in atom_indices_rnd]) - selection = f'index {selection}' - ags_moltype_rnd = universe.select_atoms(selection) - bead_groups[moltype] = BeadGroup(ags_moltype_rnd, compound='fragments') - warnings.warn( - 'Maximum number of molecules for calculating the msd has been reached.' - ' Will make a random selection for calculation.' - ) - except Exception: - warnings.warn( - 'Error in selecting random molecules for large group when calculating msd. Skipping this molecule type.' - ) - del_list.append(i_moltype) - - for index in sorted(del_list, reverse=True): - del moltypes[index] - - msd_results: Dict[str, Any] = {} - msd_results['type'] = 'molecular' - msd_results['direction'] = 'xyz' - msd_results['value'] = [] - msd_results['times'] = [] - msd_results['diffusion_constant'] = [] - msd_results['error_diffusion_constant'] = [] - for moltype in moltypes: - positions = get_nojump_positions(universe, bead_groups[moltype]) - results = shifted_correlation_average( - mean_squared_displacement, times, positions - ) - if results: - msd_results['value'].append(results[1]) - msd_results['times'].append(results[0]) - diffusion_constant, error = _calc_diffusion_constant(*results) - msd_results['diffusion_constant'].append(diffusion_constant) - msd_results['error_diffusion_constant'].append(error) - - msd_results['types'] = moltypes - msd_results['times'] = np.array(msd_results['times']) * ureg.picosecond - msd_results['value'] = np.array(msd_results['value']) * ureg.angstrom**2 - msd_results['diffusion_constant'] = ( - np.array(msd_results['diffusion_constant']) * ureg.angstrom**2 / ureg.picosecond - ) - msd_results['error_diffusion_constant'] = np.array( - msd_results['error_diffusion_constant'] - ) - - return msd_results - - -def calc_radius_of_gyration( - universe: MDAnalysis.Universe, molecule_atom_indices: NDArray -) -> Dict: - """ - Calculates the radius of gyration as a function of time for the atoms 'molecule_atom_indices'. - """ - if ( - not universe - or not universe.trajectory - or universe.trajectory[0].dimensions is None - ): - return {} - selection = ' '.join([str(i) for i in molecule_atom_indices]) - selection = f'index {selection}' - molecule = universe.select_atoms(selection) - rg_results: Dict[str, Any] = {} - rg_results['type'] = 'molecular' - rg_results['times'] = [] - rg_results['value'] = [] - time_unit = hasattr(universe.trajectory.time, 'units') - for __ in universe.trajectory: - rg_results['times'].append( - universe.trajectory.time.magnitude - if time_unit - else universe.trajectory.time - ) - rg_results['value'].append(molecule.radius_of_gyration()) - rg_results['n_frames'] = len(rg_results['times']) - rg_results['times'] = ( - np.array(rg_results['times']) * time_unit - if time_unit - else np.array(rg_results['times']) - ) - rg_results['value'] = np.array(rg_results['value']) * ureg.angstrom - - return rg_results - - -def calc_molecular_radius_of_gyration( - universe: MDAnalysis.Universe, system_topology: MSection -) -> List[Dict]: - """ - Calculates the radius of gyration as a function of time for each polymer in the system. - """ - if not system_topology: - return [] - - rg_results = [] - for molgroup in system_topology: - for molecule in molgroup.get('atoms_group'): - sec_monomer_groups = molecule.get('atoms_group') - group_type = sec_monomer_groups[0].type if sec_monomer_groups else None - if group_type != 'monomer_group': - continue - rg_result = calc_radius_of_gyration(universe, molecule.atom_indices) - rg_result['label'] = molecule.label + '-index_' + str(molecule.index) - rg_result['atomsgroup_ref'] = molecule - rg_results.append(rg_result) - - return rg_results - - -def get_molecules_from_bond_list( - n_particles: int, - bond_list: List[tuple], - particle_types: List[str] = None, - particles_typeid: array = None, -) -> List[Dict]: - """ - Returns a list of dictionaries with molecule info from each instance in the list of bonds. - """ - system_graph = networkx.empty_graph(n_particles) - system_graph.add_edges_from([(i[0], i[1]) for i in bond_list]) - molecules = [ - system_graph.subgraph(c).copy() - for c in networkx.connected_components(system_graph) - ] - molecule_info: List[Dict] = [] - molecule_dict: Dict = {} - for mol in molecules: - molecule_dict = {} - molecule_dict['indices'] = np.array(mol.nodes()) - molecule_dict['bonds'] = np.array(mol.edges()) - molecule_dict['type'] = 'molecule' - molecule_dict['is_molecule'] = True - if particles_typeid is None and len(particle_types) == n_particles: - molecule_dict['names'] = [ - particle_types[int(x)] - for x in sorted(np.array(molecule_dict['indices'])) - ] - if particle_types is not None and particles_typeid is not None: - molecule_dict['names'] = [ - particle_types[particles_typeid[int(x)]] - for x in sorted(np.array(molecule_dict['indices'])) - ] - molecule_info.append(molecule_dict) - return molecule_info - - -def is_same_molecule(mol_1: dict, mol_2: dict) -> bool: - """ - Checks whether the 2 input molecule dictionary (see "get_molecules_from_bond_list()" above) - represent the same molecule type, i.e., same particle types and corresponding bond connections. - """ - - def get_bond_list_dict(mol): - mol_shift = np.min(mol['indices']) - mol_bonds_shift = mol['bonds'] - mol_shift - bond_list = [ - sorted((mol['names'][i], mol['names'][j])) for i, j in mol_bonds_shift - ] - bond_list_names, bond_list_counts = np.unique( - bond_list, axis=0, return_counts=True - ) - - return { - bond[0] + '-' + bond[1]: bond_list_counts[i_bond] - for i_bond, bond in enumerate(bond_list_names) - } - - if sorted(mol_1['names']) != sorted(mol_2['names']): - return False - - bond_list_dict_1 = get_bond_list_dict(mol_1) - bond_list_dict_2 = get_bond_list_dict(mol_2) - - if bond_list_dict_1 == bond_list_dict_2: - return True - - return False - - -def get_composition(children_names: List[str]) -> str: - """ - Generates a generalized "chemical formula" based on the provided list `children_names`, - with the format X(m)Y(n) for children_names X and Y of quantities m and n, respectively. - """ - children_count_tup = np.unique(children_names, return_counts=True) - formula = ''.join([f'{name}({count})' for name, count in zip(*children_count_tup)]) - return formula - - -def get_bond_list_from_model_contributions( - sec_run: MSection, method_index: int = -1, model_index: int = -1 -) -> List[tuple]: - """ - Generates bond list of tuples using the list of bonded force field interactions stored under run[].method[].force_field.model[]. - - bond_list: List[tuple] - """ - contributions = [] - if sec_run.m_xpath( - f'method[{method_index}].force_field.model[{model_index}].contributions' - ): - contributions = ( - sec_run.method[method_index].force_field.model[model_index].contributions - ) - bond_list = [] - for contribution in contributions: - if contribution.type != 'bond': - continue - - atom_indices = contribution.atom_indices - if ( - contribution.n_interactions - ): # all bonds have been grouped into one contribution - bond_list = [tuple(indices) for indices in atom_indices] - else: - bond_list.append(tuple(contribution.atom_indices)) - - return bond_list diff --git a/nomad/datamodel/metainfo/simulation/workflow.py b/nomad/datamodel/metainfo/simulation/workflow.py index 8d9f2e172623c956f7d32e7d72bf59788cc038d5..a53db33ecc43112b05ad8fe2fbcce57ee243b732 100644 --- a/nomad/datamodel/metainfo/simulation/workflow.py +++ b/nomad/datamodel/metainfo/simulation/workflow.py @@ -66,12 +66,6 @@ from nomad.datamodel.metainfo.simulation.calculation import ( RadiusOfGyrationValues as RadiusOfGyrationValuesCalculation, EnergyEntry, ) -from nomad.atomutils import archive_to_universe -from nomad.atomutils import ( - calc_molecular_rdf, - calc_molecular_mean_squared_displacements, - calc_molecular_radius_of_gyration, -) # TODO remove this after reprocessing with the new schema defined in @@ -2208,7 +2202,18 @@ class MolecularDynamicsResults(ThermodynamicsResults): def normalize(self, archive, logger): super().normalize(archive, logger) - universe = archive_to_universe(archive) + try: + from simulationworkflowschema.molecular_dynamics import archive_to_universe + from simulationworkflowschema.molecular_dynamics import ( + calc_molecular_rdf, + calc_molecular_mean_squared_displacements, + calc_molecular_radius_of_gyration, + ) + + universe = archive_to_universe(archive) + except Exception: + universe = None + if universe is None: return diff --git a/nomad/normalizing/common.py b/nomad/normalizing/common.py index 60c2e62696919ccd65b01386b4427dc951a6f45c..7f85a845aeab5a1937e80d9af0fddb55e52ccda7 100644 --- a/nomad/normalizing/common.py +++ b/nomad/normalizing/common.py @@ -20,7 +20,6 @@ from math import isnan from ase import Atoms from typing import List, Set, Any, Optional, Dict, Union from nptyping import NDArray -import MDAnalysis as mda from matid import SymmetryAnalyzer # pylint: disable=import-error from matid.symmetry.wyckoffset import WyckoffSet as WyckoffSetMatID # pylint: disable=import-error import matid.geometry # pylint: disable=import-error @@ -273,46 +272,6 @@ def ase_atoms_from_structure(system: Structure) -> Atoms: ) -def mda_universe_from_nomad_atoms(system: Atoms, logger=None) -> mda.Universe: - """Returns an instance of mda.Universe from a NOMAD Atoms-section. - - Args: - system: The atoms to transform - - Returns: - A new mda.Universe created from the given data. - """ - n_atoms = len(system.positions) - n_residues = 1 - atom_resindex = [0] * n_atoms - residue_segindex = [0] - - universe = mda.Universe.empty( - n_atoms, - n_residues=n_residues, - atom_resindex=atom_resindex, - residue_segindex=residue_segindex, - trajectory=True, - ) - - # Add positions - universe.atoms.positions = system.positions.to(ureg.angstrom).magnitude - - # Add atom attributes - atom_names = system.labels - universe.add_TopologyAttr('name', atom_names) - universe.add_TopologyAttr('type', atom_names) - universe.add_TopologyAttr('element', atom_names) - - # Add the box dimensions - if system.lattice_vectors is not None: - universe.atoms.dimensions = atomutils.cell_to_cellpar( - system.lattice_vectors.to(ureg.angstrom).magnitude, degrees=True - ) - - return universe - - def structures_2d(original_atoms, logger=None): conv_atoms = None prim_atoms = None diff --git a/pyproject.toml b/pyproject.toml index 28fe31cf809d4ab2801b977022ed6f607dd155e6..e371a58c268f02b9efc1d20ed7eb35b0ba29c085 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,8 +29,6 @@ dependencies = [ 'lxml>=5.2', 'lxml-html-clean>=0.1.0', 'matid>=2.1.2', - 'mdanalysis==2.7.0', - 'networkx>=2.6.3', 'nptyping~=1.4.4', 'numpy>=1.22.4,<2.0.0', 'openpyxl>=3.0.0', diff --git a/requirements-dev.txt b/requirements-dev.txt index c5effa20ce226adcc984cd78be40d51d8304015b..30a9c097c109beaefd5b7cc22dad291f6c72505a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -22,12 +22,12 @@ basicauth==0.4.1 # via -r requirements.txt, nomad-lab (pyproject.toml) beautifulsoup4==4.12.3 # via -r requirements.txt, nomad-lab (pyproject.toml) billiard==4.2.0 # via celery, -r requirements.txt bitarray==2.9.2 # via -r requirements.txt, nomad-lab (pyproject.toml) -build==1.2.1 # via nomad-lab (pyproject.toml) +build==1.2.2 # via nomad-lab (pyproject.toml) cachetools==5.5.0 # via -r requirements.txt, nomad-lab (pyproject.toml) celery==5.4.0 # via -r requirements.txt, nomad-lab (pyproject.toml) certifi==2024.8.30 # via elasticsearch, httpcore, httpx, netcdf4, requests, -r requirements.txt certipy==0.1.3 # via jupyterhub, -r requirements.txt -cffi==1.17.0 ; platform_python_implementation != 'PyPy' # via cryptography, -r requirements.txt +cffi==1.17.1 ; platform_python_implementation != 'PyPy' # via cryptography, -r requirements.txt cftime==1.6.4 # via netcdf4, -r requirements.txt charset-normalizer==3.3.2 # via requests, -r requirements.txt click==8.1.7 # via celery, click-didyoumean, click-plugins, click-repl, mkdocs, mkdocs-click, uvicorn, -r requirements.txt, nomad-lab (pyproject.toml) @@ -57,7 +57,6 @@ et-xmlfile==1.1.0 # via openpyxl, -r requirements.txt execnet==2.1.1 # via pytest-xdist executing==2.1.0 # via devtools fastapi==0.99.1 # via h5grove, -r requirements.txt, nomad-lab (pyproject.toml) -fasteners==0.19 # via mdanalysis, -r requirements.txt filelock==3.3.1 # via -r requirements.txt, nomad-lab (pyproject.toml) fonttools==4.53.1 # via matplotlib, -r requirements.txt fqdn==1.5.1 # via jsonschema, -r requirements.txt @@ -65,7 +64,6 @@ ghp-import==2.1.0 # via mkdocs gitdb==4.0.11 # via gitpython, -r requirements.txt gitpython==3.1.43 # via mkdocs-git-revision-date-localized-plugin, -r requirements.txt, nomad-lab (pyproject.toml) greenlet==3.0.3 ; (python_full_version < '3.13' and platform_machine == 'AMD64') or (python_full_version < '3.13' and platform_machine == 'WIN32') or (python_full_version < '3.13' and platform_machine == 'aarch64') or (python_full_version < '3.13' and platform_machine == 'amd64') or (python_full_version < '3.13' and platform_machine == 'ppc64le') or (python_full_version < '3.13' and platform_machine == 'win32') or (python_full_version < '3.13' and platform_machine == 'x86_64') # via sqlalchemy, -r requirements.txt -griddataformats==1.0.2 # via mdanalysis, -r requirements.txt gunicorn==21.2.0 # via -r requirements.txt, nomad-lab (pyproject.toml) h11==0.14.0 # via httpcore, uvicorn, -r requirements.txt h5grove==1.3.0 # via -r requirements.txt, nomad-lab (pyproject.toml) @@ -89,7 +87,7 @@ jaraco-functools==4.0.2 # via keyring jeepney==0.8.0 ; sys_platform == 'linux' # via keyring, secretstorage jinja2==3.1.4 # via jupyterhub, mkdocs, mkdocs-macros-plugin, mkdocs-material, sphinx, -r requirements.txt jmespath==1.0.1 # via -r requirements.txt, nomad-lab (pyproject.toml) -joblib==1.4.2 # via mdanalysis, pymatgen, scikit-learn, -r requirements.txt +joblib==1.4.2 # via pymatgen, scikit-learn, -r requirements.txt jsonpointer==3.0.0 # via jsonschema, -r requirements.txt jsonschema==4.17.3 # via jupyter-telemetry, oauthenticator, -r requirements.txt, nomad-lab (pyproject.toml) jupyter-telemetry==0.1.0 # via jupyterhub, -r requirements.txt @@ -108,43 +106,40 @@ mako==1.3.5 # via alembic, -r requirements.txt markdown==3.7 # via mkdocs, mkdocs-click, mkdocs-material, pymdown-extensions markupsafe==2.1.5 # via jinja2, mako, mkdocs, -r requirements.txt, nomad-lab (pyproject.toml) matid==2.1.2 # via -r requirements.txt, nomad-lab (pyproject.toml) -matplotlib==3.9.2 # via ase, mdanalysis, pymatgen, -r requirements.txt -mda-xdrlib==0.2.0 # via mdanalysis, pyedr, -r requirements.txt -mdanalysis==2.7.0 # via -r requirements.txt, nomad-lab (pyproject.toml) +matplotlib==3.9.2 # via ase, pymatgen, -r requirements.txt +mda-xdrlib==0.2.0 # via pyedr, -r requirements.txt mergedeep==1.3.4 # via mkdocs, mkdocs-get-deps mistune==3.0.2 # via m2r, -r requirements.txt mkdocs==1.6.1 # via mkdocs-git-revision-date-localized-plugin, mkdocs-macros-plugin, mkdocs-material, mkdocs-redirects, nomad-lab (pyproject.toml) mkdocs-click==0.8.1 # via nomad-lab (pyproject.toml) mkdocs-get-deps==0.2.0 # via mkdocs -mkdocs-git-revision-date-localized-plugin==1.2.7 # via nomad-lab (pyproject.toml) +mkdocs-git-revision-date-localized-plugin==1.2.8 # via nomad-lab (pyproject.toml) mkdocs-glightbox==0.4.0 # via nomad-lab (pyproject.toml) mkdocs-macros-plugin==1.0.5 # via nomad-lab (pyproject.toml) mkdocs-material==9.5.34 # via nomad-lab (pyproject.toml) mkdocs-material-extensions==1.3.1 # via mkdocs-material, nomad-lab (pyproject.toml) mkdocs-redirects==1.2.1 # via nomad-lab (pyproject.toml) -mmtf-python==1.1.3 # via mdanalysis, -r requirements.txt mongoengine==0.29.0 # via -r requirements.txt, nomad-lab (pyproject.toml) mongomock==4.1.2 # via optimade, -r requirements.txt monty==2024.7.30 # via pymatgen, -r requirements.txt -more-itertools==10.4.0 # via jaraco-classes, jaraco-functools +more-itertools==10.5.0 # via jaraco-classes, jaraco-functools mpmath==1.3.0 # via sympy, -r requirements.txt -mrcfile==1.5.3 # via griddataformats, -r requirements.txt -msgpack==1.0.8 # via mmtf-python, -r requirements.txt, nomad-lab (pyproject.toml) +msgpack==1.1.0 # via -r requirements.txt, nomad-lab (pyproject.toml) mypy==1.0.1 # via nomad-lab (pyproject.toml) mypy-extensions==1.0.0 # via mypy names==0.3.0 # via nomad-lab (pyproject.toml) netcdf4==1.6.5 # via -r requirements.txt, nomad-lab (pyproject.toml) -networkx==3.3 # via matid, pymatgen, -r requirements.txt, nomad-lab (pyproject.toml) +networkx==3.3 # via matid, pymatgen, -r requirements.txt nh3==0.2.18 # via readme-renderer nomad-openbis==1.0.0 # via -r requirements.txt, nomad-lab (pyproject.toml) nptyping==1.4.4 # via -r requirements.txt, nomad-lab (pyproject.toml) -numpy==1.26.4 # via ase, cftime, contourpy, griddataformats, h5grove, h5py, matid, matplotlib, mdanalysis, mrcfile, netcdf4, nptyping, pandas, pyedr, pymatgen, rdkit, scikit-learn, scipy, spglib, tifffile, xarray, -r requirements.txt, nomad-lab (pyproject.toml) +numpy==1.26.4 # via ase, cftime, contourpy, h5grove, h5py, matid, matplotlib, netcdf4, nptyping, pandas, pyedr, pymatgen, rdkit, scikit-learn, scipy, spglib, tifffile, xarray, -r requirements.txt, nomad-lab (pyproject.toml) oauthenticator==15.1.0 # via -r requirements.txt, nomad-lab (pyproject.toml) oauthlib==3.2.2 # via jupyterhub, -r requirements.txt openpyxl==3.1.5 # via -r requirements.txt, nomad-lab (pyproject.toml) optimade==0.22.1 # via -r requirements.txt, nomad-lab (pyproject.toml) orjson==3.10.7 # via h5grove, -r requirements.txt, nomad-lab (pyproject.toml) -packaging==24.1 # via build, deprecation, gunicorn, jupyterhub, matplotlib, mdanalysis, mkdocs, mongomock, pint, plotly, pytest, sphinx, xarray, -r requirements.txt +packaging==24.1 # via build, deprecation, gunicorn, jupyterhub, matplotlib, mkdocs, mongomock, pint, plotly, pytest, sphinx, xarray, -r requirements.txt paginate==0.5.7 # via mkdocs-material palettable==3.3.3 # via pymatgen, -r requirements.txt pamela==1.2.0 ; sys_platform != 'win32' # via jupyterhub, -r requirements.txt @@ -155,7 +150,7 @@ pathspec==0.12.1 # via mkdocs pillow==10.4.0 # via matplotlib, rdkit, -r requirements.txt pint==0.17 # via -r requirements.txt, nomad-lab (pyproject.toml) pkginfo==1.11.1 # via twine -platformdirs==4.2.2 # via mkdocs-get-deps +platformdirs==4.3.2 # via mkdocs-get-deps plotly==5.24.0 # via pymatgen, -r requirements.txt pluggy==1.5.0 # via pytest prometheus-client==0.20.0 # via jupyterhub, -r requirements.txt @@ -211,10 +206,10 @@ rfc3987==1.3.8 # via jsonschema, -r requirements.txt rope==0.21.0 # via nomad-lab (pyproject.toml) ruamel-yaml==0.18.6 # via jupyter-telemetry, oauthenticator, pymatgen, -r requirements.txt, nomad-lab (pyproject.toml) ruamel-yaml-clib==0.2.8 ; python_full_version < '3.13' and platform_python_implementation == 'CPython' # via ruamel-yaml, -r requirements.txt -ruff==0.6.3 # via nomad-lab (pyproject.toml) +ruff==0.6.4 # via nomad-lab (pyproject.toml) runstats==2.0.0 # via -r requirements.txt, nomad-lab (pyproject.toml) scikit-learn==1.5.1 # via matid, -r requirements.txt, nomad-lab (pyproject.toml) -scipy==1.14.1 # via ase, griddataformats, mdanalysis, pymatgen, scikit-learn, -r requirements.txt, nomad-lab (pyproject.toml) +scipy==1.14.1 # via ase, pymatgen, scikit-learn, -r requirements.txt, nomad-lab (pyproject.toml) secretstorage==3.3.3 ; sys_platform == 'linux' # via keyring sentinels==1.0.0 # via mongomock, -r requirements.txt six==1.16.0 # via asttokens, basicauth, elasticsearch-dsl, html5lib, isodate, pybtex, python-dateutil, rdflib, rfc3339-validator, validators, -r requirements.txt @@ -238,16 +233,16 @@ tabulate==0.8.9 # via nomad-openbis, pymatgen, -r requirements.txt, no tenacity==9.0.0 # via plotly, -r requirements.txt termcolor==2.4.0 # via mkdocs-macros-plugin texttable==1.7.0 # via nomad-openbis, -r requirements.txt -threadpoolctl==3.5.0 # via mdanalysis, scikit-learn, -r requirements.txt +threadpoolctl==3.5.0 # via scikit-learn, -r requirements.txt tifffile==2024.8.30 # via h5grove, -r requirements.txt -tomli==2.0.1 ; python_full_version == '3.11' # via coverage +tomli==2.0.1 ; python_full_version <= '3.11' # via coverage toposort==1.10 # via -r requirements.txt, nomad-lab (pyproject.toml) tornado==6.4.1 # via jupyterhub, -r requirements.txt -tqdm==4.66.5 # via mdanalysis, pyedr, pymatgen, twine, -r requirements.txt +tqdm==4.66.5 # via pyedr, pymatgen, twine, -r requirements.txt traitlets==5.14.3 # via jupyter-telemetry, jupyterhub, -r requirements.txt twine==3.4.2 # via nomad-lab (pyproject.toml) typed-ast==1.5.5 # via nomad-lab (pyproject.toml) -types-python-dateutil==2.9.0.20240821 # via arrow, -r requirements.txt +types-python-dateutil==2.9.0.20240906 # via arrow, -r requirements.txt typing-extensions==4.12.2 # via alembic, fastapi, jwcrypto, mypy, pydantic, sqlalchemy, -r requirements.txt typish==1.9.3 # via nptyping, -r requirements.txt tzdata==2024.1 # via celery, pandas, -r requirements.txt @@ -255,7 +250,7 @@ uncertainties==3.2.2 # via pymatgen, -r requirements.txt unidecode==1.3.2 # via -r requirements.txt, nomad-lab (pyproject.toml) uri-template==1.3.0 # via jsonschema, -r requirements.txt urllib3==1.26.20 # via docker, elasticsearch, nomad-openbis, requests, -r requirements.txt -uv==0.4.4 # via nomad-lab (pyproject.toml) +uv==0.4.8 # via nomad-lab (pyproject.toml) uvicorn==0.30.6 # via h5grove, -r requirements.txt, nomad-lab (pyproject.toml) uvloop==0.20.0 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32' # via uvicorn, -r requirements.txt validators==0.18.2 # via -r requirements.txt, nomad-lab (pyproject.toml) diff --git a/requirements-plugins.txt b/requirements-plugins.txt index 3b54d480d53d1df6c21e14bee3a8b4a0a0da5918..aaed4c6dabc56b77ae2c657898e95fdbe47455df 100644 --- a/requirements-plugins.txt +++ b/requirements-plugins.txt @@ -14,7 +14,7 @@ asteval==1.0.2 # via lmfit asttokens==2.4.1 # via stack-data, -c requirements-dev.txt async-lru==2.0.4 # via jupyterlab async-property==0.2.2 # via python-keycloak, -c requirements-dev.txt -atomisticparsers @ git+https://github.com/nomad-coe/atomistic-parsers.git@cedaf4191abe315001f6b55a9690dcd21116e9b7 # via -r default_plugins.txt +atomisticparsers @ git+https://github.com/nomad-coe/atomistic-parsers.git@eebca28ebe83b3c945e922910b18a16ec36e8122 # via -r default_plugins.txt attrs==24.2.0 # via jsonschema, -c requirements-dev.txt babel==2.16.0 # via jupyterlab-server, -c requirements-dev.txt beautifulsoup4==4.12.3 # via nbconvert, -c requirements-dev.txt @@ -24,7 +24,8 @@ blinker==1.8.2 # via flask blosc2==2.7.1 # via tables cachetools==5.5.0 # via nomad-lab, -c requirements-dev.txt certifi==2024.8.30 # via elasticsearch, httpcore, httpx, netcdf4, requests, -c requirements-dev.txt -cffi==1.17.0 # via argon2-cffi-bindings, cryptography, pyzmq, -c requirements-dev.txt +cffi==1.17.0 ; platform_python_implementation == 'PyPy' # via argon2-cffi-bindings, pyzmq, -c requirements-dev.txt +cffi==1.17.1 ; platform_python_implementation != 'PyPy' # via argon2-cffi-bindings, cryptography, pyzmq, -c requirements-dev.txt cftime==1.6.4 # via netcdf4, -c requirements-dev.txt charset-normalizer==3.3.2 # via requests, -c requirements-dev.txt click==8.1.7 # via asr, click-default-group, dask, flask, nomad-lab, pynxtools, -c requirements-dev.txt @@ -48,13 +49,13 @@ docstring-parser==0.16 # via nomad-lab, -c requirements-dev.txt eelsdbconverter @ git+https://github.com/nomad-coe/nomad-parser-eelsdb.git@788eb03dc71ef9b164e2a5ccb9c0209b546f5c38 # via -r default_plugins.txt elasticsearch==7.17.1 # via elasticsearch-dsl, -c requirements-dev.txt elasticsearch-dsl==7.4.0 # via nomad-lab, -c requirements-dev.txt -electronicparsers @ git+https://github.com/nomad-coe/electronic-parsers.git@637a5d67fe84f8e4f1b18fdb2dd2df7ba199d1a9 # via -r default_plugins.txt +electronicparsers @ git+https://github.com/nomad-coe/electronic-parsers.git@8d4ba60e1893afad1ad43df1bf0a0911f17bffc0 # via -r default_plugins.txt entrypoints==0.4 # via ipyparallel et-xmlfile==1.1.0 # via openpyxl, -c requirements-dev.txt executing==2.1.0 # via stack-data, -c requirements-dev.txt fabio==2024.4.0 # via pyfai, silx fairmat-readers-xrd==0.0.6 # via pynxtools-xrd -fasteners==0.19 # via mdanalysis, zarr, -c requirements-dev.txt +fasteners==0.19 # via mdanalysis, zarr fastjsonschema==2.20.0 # via nbformat findiff==0.10.0 # via pynxtools-stm flask==3.0.3 # via asr @@ -63,7 +64,7 @@ fonttools==4.53.1 # via matplotlib, -c requirements-dev.txt fqdn==1.5.1 # via jsonschema, -c requirements-dev.txt fsspec==2024.6.1 # via dask, hyperspy greenlet==3.0.3 ; (python_full_version < '3.13' and platform_machine == 'AMD64') or (python_full_version < '3.13' and platform_machine == 'WIN32') or (python_full_version < '3.13' and platform_machine == 'aarch64') or (python_full_version < '3.13' and platform_machine == 'amd64') or (python_full_version < '3.13' and platform_machine == 'ppc64le') or (python_full_version < '3.13' and platform_machine == 'win32') or (python_full_version < '3.13' and platform_machine == 'x86_64') # via sqlalchemy, -c requirements-dev.txt -griddataformats==1.0.2 # via mdanalysis, -c requirements-dev.txt +griddataformats==1.0.2 # via mdanalysis h11==0.14.0 # via httpcore, -c requirements-dev.txt h5grove==1.3.0 # via jupyterlab-h5web, -c requirements-dev.txt h5py==3.11.0 # via electronicparsers, fabio, h5grove, hdf5plugin, hyperspy, ifes-apt-tc-data-modeling, jupyterlab-h5web, kikuchipy, nionswift, nomad-lab, orix, phonopy, pyfai, pynxtools, pynxtools-mpes, pynxtools-xps, pyxem, silx, workflowparsers, -c requirements-dev.txt @@ -120,14 +121,14 @@ matplotlib==3.9.2 # via ase, asr, diffsims, hyperspy, kikuchipy, matplot matplotlib-inline==0.1.7 # via ipykernel, ipython matplotlib-scalebar==0.8.1 # via orix mda-xdrlib==0.2.0 # via mdanalysis, pyedr, -c requirements-dev.txt -mdanalysis==2.7.0 # via atomisticparsers, nomad-lab, -c requirements-dev.txt +mdanalysis==2.7.0 # via atomisticparsers, nomad-lab, nomad-schema-plugin-simulation-workflow mergedeep==1.3.4 # via pynxtools, -c requirements-dev.txt mistune==3.0.2 # via nbconvert, -c requirements-dev.txt -mmtf-python==1.1.3 # via mdanalysis, -c requirements-dev.txt +mmtf-python==1.1.3 # via mdanalysis monty==2024.7.30 # via pymatgen, -c requirements-dev.txt mpmath==1.3.0 # via sympy, -c requirements-dev.txt -mrcfile==1.5.3 # via griddataformats, -c requirements-dev.txt -msgpack==1.0.8 # via blosc2, mmtf-python, -c requirements-dev.txt +mrcfile==1.5.3 # via griddataformats +msgpack==1.1.0 # via blosc2, mmtf-python, -c requirements-dev.txt natsort==8.4.0 # via hyperspy nbclient==0.10.0 # via nbconvert nbconvert==7.16.4 # via jupyter, jupyter-server @@ -135,7 +136,7 @@ nbformat==5.10.4 # via jupyter-server, nbclient, nbconvert ndindex==1.8 # via blosc2 nest-asyncio==1.6.0 # via ipykernel netcdf4==1.6.5 # via electronicparsers, -c requirements-dev.txt -networkx==3.3 # via matid, nomad-lab, pymatgen, radioactivedecay, scikit-image, -c requirements-dev.txt +networkx==3.3 # via matid, nomad-lab, nomad-schema-plugin-simulation-workflow, pymatgen, radioactivedecay, scikit-image, -c requirements-dev.txt niondata==15.6.3 # via nionswift, nionswift-io nionswift==16.11.0 # via pynxtools-em nionswift-io==15.2.1 # via nionswift @@ -151,7 +152,7 @@ nomad-normalizer-plugin-spectra @ git+https://github.com/nomad-coe/nomad-normali nomad-normalizer-plugin-system @ git+https://github.com/nomad-coe/nomad-normalizer-plugin-system.git@01523ddbc85676a40af40f4747f5f13676f34c0f # via -r default_plugins.txt nomad-porous-materials @ git+https://github.com/FAIRmat-NFDI/nomad-porous-materials.git@522f4a3208077f534f1c5e886527ee2104283d0b # via -r default_plugins.txt nomad-schema-plugin-run @ git+https://github.com/nomad-coe/nomad-schema-plugin-run.git@92d120dc4c5f7f4bcd94990ed009f8ac0019acec # via atomisticparsers, databaseparsers, electronicparsers, nomad-schema-plugin-simulation-workflow, simulationparsers, workflowparsers, -r default_plugins.txt -nomad-schema-plugin-simulation-workflow @ git+https://github.com/nomad-coe/nomad-schema-plugin-simulation-workflow.git@c9bd20c0447aaf22a6477cb39bdf03dea4c597f8 # via atomisticparsers, databaseparsers, electronicparsers, nomad-normalizer-plugin-simulation-workflow, workflowparsers, -r default_plugins.txt +nomad-schema-plugin-simulation-workflow @ git+https://github.com/nomad-coe/nomad-schema-plugin-simulation-workflow.git@5631278b983072a6e7cb6fea40c4b3ca49b7b804 # via atomisticparsers, databaseparsers, electronicparsers, nomad-normalizer-plugin-simulation-workflow, workflowparsers, -r default_plugins.txt nomad-simulations==0.0.1 # via -r default_plugins.txt notebook==7.1.3 # via jupyter notebook-shim==0.2.4 # via jupyterlab, notebook @@ -177,7 +178,7 @@ pexpect==4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32' # via phonopy==2.11.0 # via asr, workflowparsers pillow==10.4.0 # via fabio, imageio, matplotlib, nionswift, rdkit, scikit-image, -c requirements-dev.txt pint==0.17 # via fairmat-readers-xrd, hyperspy, nomad-lab, pynxtools-xps, pynxtools-xrd, rosettasciio, -c requirements-dev.txt -platformdirs==4.2.2 # via jupyter-core, pooch, xraydb, -c requirements-dev.txt +platformdirs==4.3.2 # via jupyter-core, pooch, xraydb, -c requirements-dev.txt plotly==5.24.0 # via asr, pymatgen, -c requirements-dev.txt pooch==1.8.2 # via kikuchipy, orix prettytable==3.11.0 # via hyperspy @@ -233,7 +234,7 @@ ruamel-yaml==0.18.6 # via pymatgen, -c requirements-dev.txt ruamel-yaml-clib==0.2.8 ; python_full_version < '3.13' and platform_python_implementation == 'CPython' # via ruamel-yaml, -c requirements-dev.txt scikit-image==0.22.0 # via hyperspy, kikuchipy, pyxem scikit-learn==1.5.1 # via kikuchipy, matid, nomad-lab, pyxem, -c requirements-dev.txt -scipy==1.14.1 # via ase, atomisticparsers, diffsims, findiff, griddataformats, hyperspy, kikuchipy, lmfit, mdanalysis, niondata, nionswift, nomad-lab, orix, pyfai, pymatgen, pyxem, radioactivedecay, scikit-image, scikit-learn, sparse, xraydb, -c requirements-dev.txt +scipy==1.14.1 # via ase, atomisticparsers, diffsims, findiff, griddataformats, hyperspy, kikuchipy, lmfit, mdanalysis, niondata, nionswift, nomad-lab, nomad-schema-plugin-simulation-workflow, orix, pyfai, pymatgen, pyxem, radioactivedecay, scikit-image, scikit-learn, sparse, xraydb, -c requirements-dev.txt send2trash==1.8.3 # via jupyter-server setuptools==73.0.1 # via pynxtools-xps, radioactivedecay silx==2.1.1 # via pyfai @@ -260,7 +261,7 @@ tqdm==4.66.5 # via diffsims, hyperspy, ipyparallel, kikuchipy, mdan traitlets==5.14.3 # via comm, ipykernel, ipyparallel, ipython, ipywidgets, jupyter-client, jupyter-console, jupyter-core, jupyter-events, jupyter-server, jupyterlab, matplotlib-inline, nbclient, nbconvert, nbformat, qtconsole, -c requirements-dev.txt traits==6.4.3 # via hyperspy, pyxem transforms3d==0.4.2 # via diffsims, pyxem -types-python-dateutil==2.9.0.20240821 # via arrow, -c requirements-dev.txt +types-python-dateutil==2.9.0.20240906 # via arrow, -c requirements-dev.txt typing-extensions==4.12.2 # via ipython, jwcrypto, pydantic, sqlalchemy, tables, -c requirements-dev.txt typish==1.9.3 # via nptyping, -c requirements-dev.txt tzdata==2024.1 # via pandas, tzlocal, -c requirements-dev.txt diff --git a/requirements.txt b/requirements.txt index 49a969c73627e8b2777802781340c7a3a9e1127b..54ecbb99060d235c7569b45d1fcebe9dc9a6467f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,7 +21,7 @@ cachetools==5.5.0 # via nomad-lab (pyproject.toml) celery==5.4.0 # via nomad-lab (pyproject.toml) certifi==2024.8.30 # via elasticsearch, httpcore, httpx, netcdf4, requests certipy==0.1.3 # via jupyterhub -cffi==1.17.0 ; platform_python_implementation != 'PyPy' # via cryptography +cffi==1.17.1 ; platform_python_implementation != 'PyPy' # via cryptography cftime==1.6.4 # via netcdf4 charset-normalizer==3.3.2 # via requests click==8.1.7 # via celery, click-didyoumean, click-plugins, click-repl, uvicorn, nomad-lab (pyproject.toml) @@ -46,14 +46,12 @@ email-validator==1.3.1 # via optimade escapism==1.0.1 # via dockerspawner et-xmlfile==1.1.0 # via openpyxl fastapi==0.99.1 # via h5grove, nomad-lab (pyproject.toml) -fasteners==0.19 # via mdanalysis filelock==3.3.1 # via nomad-lab (pyproject.toml) fonttools==4.53.1 # via matplotlib fqdn==1.5.1 # via jsonschema gitdb==4.0.11 # via gitpython gitpython==3.1.43 # via nomad-lab (pyproject.toml) greenlet==3.0.3 ; (python_full_version < '3.13' and platform_machine == 'AMD64') or (python_full_version < '3.13' and platform_machine == 'WIN32') or (python_full_version < '3.13' and platform_machine == 'aarch64') or (python_full_version < '3.13' and platform_machine == 'amd64') or (python_full_version < '3.13' and platform_machine == 'ppc64le') or (python_full_version < '3.13' and platform_machine == 'win32') or (python_full_version < '3.13' and platform_machine == 'x86_64') # via sqlalchemy -griddataformats==1.0.2 # via mdanalysis gunicorn==21.2.0 # via nomad-lab (pyproject.toml) h11==0.14.0 # via httpcore, uvicorn h5grove==1.3.0 # via nomad-lab (pyproject.toml) @@ -72,7 +70,7 @@ isoduration==20.11.0 # via jsonschema itsdangerous==2.2.0 # via nomad-lab (pyproject.toml) jinja2==3.1.4 # via jupyterhub, sphinx jmespath==1.0.1 # via nomad-lab (pyproject.toml) -joblib==1.4.2 # via mdanalysis, pymatgen, scikit-learn +joblib==1.4.2 # via pymatgen, scikit-learn jsonpointer==3.0.0 # via jsonschema jsonschema==4.17.3 # via jupyter-telemetry, oauthenticator, nomad-lab (pyproject.toml) jupyter-telemetry==0.1.0 # via jupyterhub @@ -89,28 +87,25 @@ m2r==0.2.1 # via nomad-lab (pyproject.toml) mako==1.3.5 # via alembic markupsafe==2.1.5 # via jinja2, mako matid==2.1.2 # via nomad-lab (pyproject.toml) -matplotlib==3.9.2 # via ase, mdanalysis, pymatgen -mda-xdrlib==0.2.0 # via mdanalysis, pyedr -mdanalysis==2.7.0 # via nomad-lab (pyproject.toml) +matplotlib==3.9.2 # via ase, pymatgen +mda-xdrlib==0.2.0 # via pyedr mistune==3.0.2 # via m2r -mmtf-python==1.1.3 # via mdanalysis mongoengine==0.29.0 # via nomad-lab (pyproject.toml) mongomock==4.1.2 # via optimade monty==2024.7.30 # via pymatgen mpmath==1.3.0 # via sympy -mrcfile==1.5.3 # via griddataformats -msgpack==1.0.8 # via mmtf-python, nomad-lab (pyproject.toml) +msgpack==1.1.0 # via nomad-lab (pyproject.toml) netcdf4==1.6.5 # via nomad-lab (pyproject.toml) -networkx==3.3 # via matid, pymatgen, nomad-lab (pyproject.toml) +networkx==3.3 # via matid, pymatgen nomad-openbis==1.0.0 # via nomad-lab (pyproject.toml) nptyping==1.4.4 # via nomad-lab (pyproject.toml) -numpy==1.26.4 # via ase, cftime, contourpy, griddataformats, h5grove, h5py, matid, matplotlib, mdanalysis, mrcfile, netcdf4, nptyping, pandas, pyedr, pymatgen, rdkit, scikit-learn, scipy, spglib, tifffile, xarray, nomad-lab (pyproject.toml) +numpy==1.26.4 # via ase, cftime, contourpy, h5grove, h5py, matid, matplotlib, netcdf4, nptyping, pandas, pyedr, pymatgen, rdkit, scikit-learn, scipy, spglib, tifffile, xarray, nomad-lab (pyproject.toml) oauthenticator==15.1.0 # via nomad-lab (pyproject.toml) oauthlib==3.2.2 # via jupyterhub openpyxl==3.1.5 # via nomad-lab (pyproject.toml) optimade==0.22.1 # via nomad-lab (pyproject.toml) orjson==3.10.7 # via h5grove, nomad-lab (pyproject.toml) -packaging==24.1 # via deprecation, gunicorn, jupyterhub, matplotlib, mdanalysis, mongomock, pint, plotly, sphinx, xarray +packaging==24.1 # via deprecation, gunicorn, jupyterhub, matplotlib, mongomock, pint, plotly, sphinx, xarray palettable==3.3.3 # via pymatgen pamela==1.2.0 ; sys_platform != 'win32' # via jupyterhub pandas==2.2.2 # via nomad-openbis, panedr, pymatgen, xarray, nomad-lab (pyproject.toml) @@ -158,7 +153,7 @@ ruamel-yaml==0.18.6 # via jupyter-telemetry, oauthenticator, pymatgen ruamel-yaml-clib==0.2.8 ; python_full_version < '3.13' and platform_python_implementation == 'CPython' # via ruamel-yaml runstats==2.0.0 # via nomad-lab (pyproject.toml) scikit-learn==1.5.1 # via matid, nomad-lab (pyproject.toml) -scipy==1.14.1 # via ase, griddataformats, mdanalysis, pymatgen, scikit-learn, nomad-lab (pyproject.toml) +scipy==1.14.1 # via ase, pymatgen, scikit-learn, nomad-lab (pyproject.toml) sentinels==1.0.0 # via mongomock six==1.16.0 # via basicauth, elasticsearch-dsl, html5lib, isodate, pybtex, python-dateutil, rdflib, rfc3339-validator, validators smmap==5.0.1 # via gitdb @@ -180,13 +175,13 @@ sympy==1.13.2 # via pymatgen tabulate==0.8.9 # via nomad-openbis, pymatgen, nomad-lab (pyproject.toml) tenacity==9.0.0 # via plotly texttable==1.7.0 # via nomad-openbis -threadpoolctl==3.5.0 # via mdanalysis, scikit-learn +threadpoolctl==3.5.0 # via scikit-learn tifffile==2024.8.30 # via h5grove toposort==1.10 # via nomad-lab (pyproject.toml) tornado==6.4.1 # via jupyterhub -tqdm==4.66.5 # via mdanalysis, pyedr, pymatgen +tqdm==4.66.5 # via pyedr, pymatgen traitlets==5.14.3 # via jupyter-telemetry, jupyterhub -types-python-dateutil==2.9.0.20240821 # via arrow +types-python-dateutil==2.9.0.20240906 # via arrow typing-extensions==4.12.2 # via alembic, fastapi, jwcrypto, pydantic, sqlalchemy typish==1.9.3 # via nptyping tzdata==2024.1 # via celery, pandas diff --git a/tests/app/v1/routers/test_systems.py b/tests/app/v1/routers/test_systems.py index fe261c95348a121c3ec87207d9c0dea6aefc88a5..debb8bdef085c2f6a3950386e9cbb53c7a161309 100644 --- a/tests/app/v1/routers/test_systems.py +++ b/tests/app/v1/routers/test_systems.py @@ -225,10 +225,11 @@ REMARK 285 A: 5.000, 0.000, 0.000 REMARK 285 B: 0.000, 5.000, 0.000 REMARK 285 C: 0.000, 0.000, 5.000 REMARK 285 PBC (A, B, C): TRUE, TRUE, TRUE -CRYST1 5.000 5.000 5.000 90.00 90.00 90.00 P 1 1 -ATOM 1 C UNK X 1 0.000 0.000 0.000 1.00 0.00 C -ATOM 2 H UNK X 1 1.000 1.000 1.000 1.00 0.00 H -END +CRYST1 5.000 5.000 5.000 90.00 90.00 90.00 P 1 +MODEL 1 +ATOM 1 C MOL 1 0.000 0.000 0.000 1.00 0.00 C +ATOM 2 H MOL 1 1.000 1.000 1.000 1.00 0.00 H +ENDMDL """, 'CH.pdb', id='pdb', @@ -308,13 +309,10 @@ def test_formats_with_cell( pytest.param( 'pdb', """TITLE NOMAD ENTRY ID: systems_entry_1 -REMARK 285 UNITARY VALUES FOR THE UNIT CELL SET BECAUSE UNIT CELL INFORMATION -REMARK 285 WAS MISSING. PROTEIN DATA BANK CONVENTIONS REQUIRE THAT CRYST1 -REMARK 285 RECORD IS INCLUDED, BUT THE VALUES ON THIS RECORD ARE MEANINGLESS. -CRYST1 1.000 1.000 1.000 90.00 90.00 90.00 P 1 1 -ATOM 1 N UNK X 1 0.000 0.000 0.000 1.00 0.00 N -ATOM 2 O UNK X 1 1.000 1.000 1.000 1.00 0.00 O -END +MODEL 1 +ATOM 1 N MOL 1 0.000 0.000 0.000 1.00 0.00 N +ATOM 2 O MOL 1 1.000 1.000 1.000 1.00 0.00 O +ENDMDL """, 'NO.pdb', id='pdb',