From a71a3fe9b4b219ed417c7d6e9d10e17007cb29bc Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Tue, 16 Dec 2025 17:58:22 +0100 Subject: [PATCH 01/10] Better bin determination in LabelHistogram, more args for TBLite off-graph model, no duplicates in FilterAllowedMolecules --- ipsuite/analysis/bin_property.py | 12 ++++++------ ipsuite/analysis/molecules.py | 5 +++-- ipsuite/models/tblite.py | 13 ++++++++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/ipsuite/analysis/bin_property.py b/ipsuite/analysis/bin_property.py index ac3adadf..3074bdb8 100644 --- a/ipsuite/analysis/bin_property.py +++ b/ipsuite/analysis/bin_property.py @@ -16,11 +16,12 @@ class LabelHistogram(base.AnalyseAtoms): ---------- data: list List of Atoms objects. - bins: int - Number of bins in the histogram. + bins: int | str + Number of bins in the histogram, or string indicating how to find the number of bins. See + https://numpy.org/devdocs/reference/generated/numpy.histogram_bin_edges.html#numpy.histogram_bin_edges """ - bins: int = zntrack.params(None) + bins: int | str = zntrack.params("auto") x_lim: tuple = zntrack.params(None) y_lim: tuple = zntrack.params(None) plots_dir: pathlib.Path = zntrack.outs_path(zntrack.nwd / "plots") @@ -43,9 +44,8 @@ def get_hist(self): "min": np.min(labels), } - if self.bins is None: - self.bins = int(np.ceil(len(labels) / 100)) - counts, bin_edges = np.histogram(labels, self.bins) + bin_edges = np.histogram_bin_edges(labels, bins=self.bins) + counts, bin_edges = np.histogram(labels, bins=bin_edges) return counts, bin_edges def get_plots(self, counts, bin_edges): diff --git a/ipsuite/analysis/molecules.py b/ipsuite/analysis/molecules.py index c9b018ae..ecfe5de6 100644 --- a/ipsuite/analysis/molecules.py +++ b/ipsuite/analysis/molecules.py @@ -33,7 +33,7 @@ class AllowedStructuresFilter(base.IPSNode): def run(self): molecules = self.molecules + [rdkit2ase.smiles2atoms(s) for s in self.smiles] mapping = BarycenterMapping() - self.outliers = [] + outliers_set = set() for idx, atoms in enumerate(tqdm.tqdm(self.data)): _, mols = mapping.forward_mapping(atoms) for mol in mols: @@ -46,7 +46,8 @@ def run(self): raise ValueError(f"Outlier found at index {idx} for molecule {mol}") else: print(f"Outlier found at index {idx} for molecule {mol}") - self.outliers.append(idx) + outliers_set.add(idx) + self.outliers = list(outliers_set) @property def excluded_frames(self) -> list[ase.Atoms]: diff --git a/ipsuite/models/tblite.py b/ipsuite/models/tblite.py index d29f3d56..f931a1a1 100644 --- a/ipsuite/models/tblite.py +++ b/ipsuite/models/tblite.py @@ -14,6 +14,10 @@ class TBLiteModel: The method to use for the calculator. verbosity : int The verbosity level of the calculator. + charge : int + The charge of the structure + multiplicity : int + The spin multiplicity of the structure .. [1] https://tblite.readthedocs.io/en/latest/ @@ -36,6 +40,8 @@ class TBLiteModel: method: str = "GFN2-xTB" verbosity: int = 0 + charge: int = 0 + multiplicity: int = 1 def get_calculator(self, **kwargs): """Get an xtb ase calculator.""" @@ -48,5 +54,10 @@ def get_calculator(self, **kwargs): ) raise - calc = TBLite(method=self.method, verbosity=self.verbosity) + calc = TBLite( + method=self.method, + verbosity=self.verbosity, + charge=self.charge, + multiplicity=self.multiplicity, + ) return calc From cca694182976182abb4534bded0f5aadade0c87b Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Tue, 16 Dec 2025 18:13:16 +0100 Subject: [PATCH 02/10] Fixed docstring line too long --- ipsuite/analysis/bin_property.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipsuite/analysis/bin_property.py b/ipsuite/analysis/bin_property.py index 3074bdb8..665f1bb4 100644 --- a/ipsuite/analysis/bin_property.py +++ b/ipsuite/analysis/bin_property.py @@ -17,9 +17,9 @@ class LabelHistogram(base.AnalyseAtoms): data: list List of Atoms objects. bins: int | str - Number of bins in the histogram, or string indicating how to find the number of bins. See - https://numpy.org/devdocs/reference/generated/numpy.histogram_bin_edges.html#numpy.histogram_bin_edges - """ + Number of bins in the histogram, or string indicating how to find the number of bins. + See https://numpy.org/devdocs/reference/generated/numpy.histogram_bin_edges.html#numpy.histogram_bin_edges + """ # noqa: E501 bins: int | str = zntrack.params("auto") x_lim: tuple = zntrack.params(None) From d4f9d484ed71258218233d9c9deaa3d460653540 Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Tue, 16 Dec 2025 19:17:39 +0100 Subject: [PATCH 03/10] Fixed test integration/configuration_selection/test_index.py::test_chained, assumed 1 bin edge before --- .../configuration_selection/test_index.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/integration/configuration_selection/test_index.py b/tests/integration/configuration_selection/test_index.py index 3a6a507a..a744b4d1 100644 --- a/tests/integration/configuration_selection/test_index.py +++ b/tests/integration/configuration_selection/test_index.py @@ -7,7 +7,7 @@ def test_index_chained(proj_path, traj_file): - with ips.Project() as project: + with ips.Project(remove_existing_graph=True) as project: data = ips.AddData(file=traj_file) pre_selection = ips.IndexSelection( data=data.frames, @@ -19,11 +19,13 @@ def test_index_chained(proj_path, traj_file): data=pre_selection.frames, indices=[0, 1, 2], name="selection" ) - histogram = ips.EnergyHistogram(data=selection.frames) - - project.repro() + histogram = ips.EnergyHistogram(data=selection.frames, bins='auto') - assert histogram.labels_df.to_dict()["bin_edges"][0] == pytest.approx( + project.repro(force=True) + + bin_edges = histogram.labels_df.to_dict()['bin_edges'] + num_edges = len(bin_edges) + assert bin_edges[num_edges-1] == pytest.approx( 0.0952380952380952 ) @@ -42,8 +44,12 @@ def test_index_chained(proj_path, traj_file): histogram = ips.EnergyHistogram(data=selection.frames) project.repro() + histogram = zntrack.from_rev(name=histogram.name) - assert histogram.labels_df.to_dict()["bin_edges"][0] == pytest.approx( + + bin_edges = histogram.labels_df.to_dict()['bin_edges'] + num_edges = len(bin_edges) + assert histogram.labels_df.to_dict()["bin_edges"][num_edges-1] == pytest.approx( 0.3333333333333333 ) From e8fabc679dd22ece37da4bdc967eaffa90fe7168 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:17:54 +0000 Subject: [PATCH 04/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/integration/configuration_selection/test_index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/configuration_selection/test_index.py b/tests/integration/configuration_selection/test_index.py index a744b4d1..4b74bac1 100644 --- a/tests/integration/configuration_selection/test_index.py +++ b/tests/integration/configuration_selection/test_index.py @@ -22,7 +22,7 @@ def test_index_chained(proj_path, traj_file): histogram = ips.EnergyHistogram(data=selection.frames, bins='auto') project.repro(force=True) - + bin_edges = histogram.labels_df.to_dict()['bin_edges'] num_edges = len(bin_edges) assert bin_edges[num_edges-1] == pytest.approx( From e86bbe5ef64cf853fc86238b5c24db16b8fc7fe1 Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Tue, 16 Dec 2025 19:24:20 +0100 Subject: [PATCH 05/10] Removed keyword arguments in test test_index --- tests/integration/configuration_selection/test_index.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/configuration_selection/test_index.py b/tests/integration/configuration_selection/test_index.py index 4b74bac1..88d60838 100644 --- a/tests/integration/configuration_selection/test_index.py +++ b/tests/integration/configuration_selection/test_index.py @@ -7,7 +7,7 @@ def test_index_chained(proj_path, traj_file): - with ips.Project(remove_existing_graph=True) as project: + with ips.Project() as project: data = ips.AddData(file=traj_file) pre_selection = ips.IndexSelection( data=data.frames, @@ -21,7 +21,7 @@ def test_index_chained(proj_path, traj_file): histogram = ips.EnergyHistogram(data=selection.frames, bins='auto') - project.repro(force=True) + project.repro() bin_edges = histogram.labels_df.to_dict()['bin_edges'] num_edges = len(bin_edges) From ec3add81233ec4de910f513b07caf9b25451dffb Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Wed, 17 Dec 2025 11:57:51 +0100 Subject: [PATCH 06/10] Closing figures --- ipsuite/analysis/bond_stretch.py | 2 ++ ipsuite/analysis/forces.py | 1 + ipsuite/analysis/md.py | 1 + ipsuite/analysis/sensitivity.py | 3 +++ ipsuite/bootstrap/surface_mods.py | 1 + ipsuite/configuration_selection/base.py | 1 + ipsuite/configuration_selection/filter.py | 1 + ipsuite/configuration_selection/threshold.py | 1 + 8 files changed, 11 insertions(+) diff --git a/ipsuite/analysis/bond_stretch.py b/ipsuite/analysis/bond_stretch.py index a75d2fc2..31b2a3b5 100644 --- a/ipsuite/analysis/bond_stretch.py +++ b/ipsuite/analysis/bond_stretch.py @@ -104,6 +104,8 @@ def run(self): e_fig.savefig(self.plots_dir / f"energy_{chem_symbols[0]}_{chem_symbols[1]}.png") f_fig.savefig(self.plots_dir / f"force_{chem_symbols[0]}_{chem_symbols[1]}.png") + plt.close(fig=e_fig) + plt.close(fig=f_fig) def get_plots( self, diff --git a/ipsuite/analysis/forces.py b/ipsuite/analysis/forces.py index 3e3dcc12..c92236c2 100644 --- a/ipsuite/analysis/forces.py +++ b/ipsuite/analysis/forces.py @@ -96,3 +96,4 @@ def run(self): plt.tight_layout() plt.savefig(self.figure_path) + plt.close() diff --git a/ipsuite/analysis/md.py b/ipsuite/analysis/md.py index c4639e71..617138d6 100644 --- a/ipsuite/analysis/md.py +++ b/ipsuite/analysis/md.py @@ -30,6 +30,7 @@ def run(self): ax.set_xlabel("Step") fig.tight_layout() fig.savefig(self.figure) + plt.close() self.density = { "density": np.mean(densities[self.start : self.end]), diff --git a/ipsuite/analysis/sensitivity.py b/ipsuite/analysis/sensitivity.py index d949ad0b..e11a90f1 100644 --- a/ipsuite/analysis/sensitivity.py +++ b/ipsuite/analysis/sensitivity.py @@ -83,6 +83,7 @@ def run(self): fig, ax = plt.subplots() nonuniform_imshow(ax, r_ij[0, :, 0], r_ij[0, :, 1], mean_forces) fig.savefig(self.plots / "2d_forces.png") + plt.close() fig, ax = plt.subplots() ax.scatter(d_ij[0], np.sum(std_forces, axis=1)) @@ -90,6 +91,7 @@ def run(self): ax.set_xlabel(r"distance $d ~ / ~ \AA$") ax.set_ylabel(r"standard deviation $\sigma ~ / ~ a.u.$") fig.savefig(self.plots / "std_forces.png") + plt.close() def _compute_std_leave_one_out(data): # Leave-One-Out Cross-Validation @@ -159,3 +161,4 @@ def run(self): ax.set_xlabel(r"Distance $r ~ / ~ \AA$") ax.set_yscale("log") fig.savefig(self.sensitivity_plot, bbox_inches="tight") + plt.close() diff --git a/ipsuite/bootstrap/surface_mods.py b/ipsuite/bootstrap/surface_mods.py index 342c7e5c..3d966f63 100644 --- a/ipsuite/bootstrap/surface_mods.py +++ b/ipsuite/bootstrap/surface_mods.py @@ -196,3 +196,4 @@ def plot_ture_vs_pred(x, y, z, name, height, plots_dir): fig.suptitle(rf"Additive {height} $\AA$ over the surface") fig.savefig(plots_dir / f"{name}-{height}-heat.png") + plt.close() diff --git a/ipsuite/configuration_selection/base.py b/ipsuite/configuration_selection/base.py index db736103..0daf2c26 100644 --- a/ipsuite/configuration_selection/base.py +++ b/ipsuite/configuration_selection/base.py @@ -88,6 +88,7 @@ def _get_plot(self, atoms_lst: typing.List[ase.Atoms], indices: typing.List[int] ax.scatter(indices, line_data[indices], c="r") ax.set_xlabel("Configuration") fig.savefig(self.img_selection, bbox_inches="tight") + plt.close() class BatchConfigurationSelection(ConfigurationSelection): diff --git a/ipsuite/configuration_selection/filter.py b/ipsuite/configuration_selection/filter.py index 59469bca..047104a2 100644 --- a/ipsuite/configuration_selection/filter.py +++ b/ipsuite/configuration_selection/filter.py @@ -60,6 +60,7 @@ def run(self): ax[2].hist([values[i] for i in self.filtered_indices], bins=100) ax[2].set_title("Excluded") fig.savefig(self.histogram, bbox_inches="tight") + plt.close() @property def frames(self) -> list[ase.Atoms]: diff --git a/ipsuite/configuration_selection/threshold.py b/ipsuite/configuration_selection/threshold.py index 077c3d4f..3c71e5cb 100644 --- a/ipsuite/configuration_selection/threshold.py +++ b/ipsuite/configuration_selection/threshold.py @@ -140,3 +140,4 @@ def _get_plot(self, atoms_lst: typing.List[ase.Atoms], indices: typing.List[int] ax.set_xlabel("configuration") fig.savefig(self.img_selection, bbox_inches="tight") + plt.close() From 9647a8eb439cdb33b088cec950b2fc6bd24682be Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Wed, 17 Dec 2025 16:09:38 +0100 Subject: [PATCH 07/10] Added cutoff argument to anylsis.molecules.AllowedStructuresFilter, added log_file out to ASEGeoOpt node --- ipsuite/analysis/molecules.py | 6 +++++- ipsuite/calculators/ase_geoopt.py | 3 ++- ipsuite/geometry/graphs.py | 35 +++++++++++++++++++++++++------ ipsuite/geometry/mapping.py | 7 ++++++- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/ipsuite/analysis/molecules.py b/ipsuite/analysis/molecules.py index ecfe5de6..4df947ef 100644 --- a/ipsuite/analysis/molecules.py +++ b/ipsuite/analysis/molecules.py @@ -21,18 +21,22 @@ class AllowedStructuresFilter(base.IPSNode): The molecules that are allowed. smiles : list[str], optional The SMILES strings of the allowed molecules. + cutoffs : dict[str, float] | None, optional + The cutoffs for each element. + If None, use the `ase.data.covalent_radii`. Default: None """ data: list[ase.Atoms] = zntrack.deps() molecules: list[ase.Atoms] = zntrack.deps(default_factory=list) smiles: list[str] = zntrack.params(default_factory=list) + cutoffs: dict[str, float] | None = zntrack.params(None) fail: bool = zntrack.params(False) outliers: list[int] = zntrack.outs() def run(self): molecules = self.molecules + [rdkit2ase.smiles2atoms(s) for s in self.smiles] - mapping = BarycenterMapping() + mapping = BarycenterMapping(cutoffs=self.cutoffs) outliers_set = set() for idx, atoms in enumerate(tqdm.tqdm(self.data)): _, mols = mapping.forward_mapping(atoms) diff --git a/ipsuite/calculators/ase_geoopt.py b/ipsuite/calculators/ase_geoopt.py index 48d7997b..7f59da6b 100644 --- a/ipsuite/calculators/ase_geoopt.py +++ b/ipsuite/calculators/ase_geoopt.py @@ -79,6 +79,7 @@ class ASEGeoOpt(base.IPSNode): sampling_rate: int = zntrack.params(1) maxstep: int = zntrack.params(None) + log_file: pathlib.Path = zntrack.outs_path(zntrack.nwd / "opt.log") traj_file: pathlib.Path = zntrack.outs_path(zntrack.nwd / "structures.h5") def run(self): # noqa: C901 @@ -105,7 +106,7 @@ def run(self): # noqa: C901 db = znh5md.IO(self.traj_file) optimizer = getattr(ase.optimize, self.optimizer) - dyn = optimizer(atoms, **self.init_kwargs) + dyn = optimizer(atoms, logfile=self.log_file, **self.init_kwargs) for step, _ in enumerate(dyn.irun(**self.run_kwargs)): stop = [] diff --git a/ipsuite/geometry/graphs.py b/ipsuite/geometry/graphs.py index 42030e33..f98f3367 100644 --- a/ipsuite/geometry/graphs.py +++ b/ipsuite/geometry/graphs.py @@ -1,23 +1,46 @@ import ase import networkx as nx import numpy as np -from ase.neighborlist import build_neighbor_list +from ase.neighborlist import build_neighbor_list, natural_cutoffs -def atoms_to_graph(atoms: ase.Atoms) -> nx.Graph: +def atoms_to_graph(atoms: ase.Atoms, cutoffs: dict[str, float] | None = None) -> nx.Graph: """Converts ASE Atoms into a Graph based on their bond connectivity. + + Args: + atoms (ase.Atoms): Atoms instance to convert + cutoffs (dict[str, float] | None): cutoffs of each atom. + Dictionary with keys for the symbols and values of the cutoff radii. + If None, use the `ase.data.covalent_radii`. Default: None + + Returns: + G (nx.Graph): Connectivity graph """ # This can be optimized by reusing the NL! - nl = build_neighbor_list(atoms, self_interaction=False) + if cutoffs is not None: + cutoffs = natural_cutoffs(atoms, **cutoffs) + nl = build_neighbor_list(atoms, self_interaction=False, cutoffs=cutoffs) cm = nl.get_connectivity_matrix(sparse=False) G = nx.from_numpy_array(cm) return G -def identify_molecules(atoms: ase.Atoms) -> list[np.ndarray]: - """Identifies molecules in a structure based on the connected subgraphs.""" - G = atoms_to_graph(atoms) +def identify_molecules( + atoms: ase.Atoms, cutoffs: dict[str, float] | None = None +) -> list[np.ndarray]: + """Identifies molecules in a structure based on the connected subgraphs. + + Args: + atoms (ase.Atoms): Atoms instance to identify molecules in + cutoffs (dict[str, float] | None): cutoffs of each element. + Dictionary with keys for the symbols and values of the cutoff radii. + If None, use the `ase.data.covalent_radii`. Default: None + + Returns: + c_list (np.ndarray): Array of lists of connected atom indices + """ + G = atoms_to_graph(atoms, cutoffs=cutoffs) components = nx.connected_components(G) c_list = [np.array(list(c)) for c in components] return c_list diff --git a/ipsuite/geometry/mapping.py b/ipsuite/geometry/mapping.py index 579afa9b..d064efb6 100644 --- a/ipsuite/geometry/mapping.py +++ b/ipsuite/geometry/mapping.py @@ -25,15 +25,20 @@ class BarycenterMapping: frozen: bool If True, the neighbor list is only constructed for the first configuration. The indices of the molecules will be frozen for all configurations. + cutoffs: dict[str, float] | None + cutoffs of each element. + Dictionary with keys for the symbols and values of the cutoff radii. + If None, use the `ase.data.covalent_radii`. Default: None """ frozen: bool = False + cutoffs: dict[str, float] | None = None _components: t.Any | None = None def forward_mapping(self, atoms: ase.Atoms) -> tuple[ase.Atoms, list[ase.Atoms]]: if self._components is None: - components = graphs.identify_molecules(atoms) + components = graphs.identify_molecules(atoms, cutoffs=self.cutoffs) else: components = self._components From c40dc4b3c984b758386300fca7dac9be031d17b7 Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Thu, 18 Dec 2025 11:09:15 +0100 Subject: [PATCH 08/10] Fixed __init__ using mkinit --- docs/source/index.rst | 2 +- ipsuite/__init__.py | 47 +++++++- ipsuite/__init__.pyi | 263 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 5 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 76bb3bf8..e50f7196 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -17,7 +17,7 @@ Welcome to IPSuite's documentation! What is IPS? <_get_started/ips> Getting Started <_get_started/quickstart> IPSuite <_nodes/ipsuite> - Modules <_nodes/modlules> + Modules <_nodes/modules> Indices and tables diff --git a/ipsuite/__init__.py b/ipsuite/__init__.py index 05a6c80a..f3ee7aac 100644 --- a/ipsuite/__init__.py +++ b/ipsuite/__init__.py @@ -1,11 +1,50 @@ """The ipsuite package.""" -import lazy_loader as lazy - +# from ipsuite.utils.helpers import setup_ase from ipsuite.utils.logs import setup_logging -__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) - setup_logging(__name__) setup_ase() + +# fmt: off +# +import lazy_loader + + +__getattr__, __dir__, __all__ = lazy_loader.attach_stub(__name__, __file__) + +__all__ = ['ASEMD', 'ASEMDSafeSampling', 'ATOMS_LST', 'AddData', 'AddDataH5MD', + 'AllowedStructuresFilter', 'AnalyseAtoms', 'AnalyseDensity', + 'AnalyseGlobalForceSensitivity', 'AnalyseSingleForceSensitivity', + 'AnalyseStructureMeanForce', 'ApplyCalculator', 'Atoms', + 'BarycenterMapping', 'Berendsen', 'BondStretchAnalyses', + 'BoxHeatUp', 'BoxOscillatingRampModifier', 'BoxScale', + 'CalibrationMetrics', 'Check', 'CollectMDSteps', + 'ComparePredictions', 'ConfigurationSelection', 'ConnectivityCheck', + 'DebugCheck', 'DensityCheck', 'DipoleHistogram', 'EnergyHistogram', + 'EnergySpikeCheck', 'EnergyUncertaintyHistogram', 'FilterOutlier', + 'FixedBondLengthConstraint', 'FixedLayerConstraint', + 'FixedSphereConstraint', 'Flatten', 'ForceAngles', + 'ForceDecomposition', 'ForceUncertaintyDecomposition', + 'ForcesHistogram', 'ForcesUncertaintyHistogram', 'HasAtoms', + 'HasOrIsAtoms', 'HasSelectedConfigurations', 'HookeanConstraint', + 'IPSNode', 'IndexSelection', 'LangevinThermostat', 'MD22Dataset', + 'MDStability', 'MoveSingleParticle', 'NPTThermostat', 'NaNCheck', + 'NodeWithCalculator', 'NodeWithThermostat', 'Prediction', + 'PredictionMetrics', 'PressureRampModifier', 'ProcessAtoms', + 'ProcessSingleAtom', 'Project', 'RandomSelection', 'RattleAnalysis', + 'RattleAtoms', 'RescaleBoxModifier', 'RotateMolecules', + 'STATIC_PATH', 'SVCRBarostat', 'SplitSelection', 'StressHistogram', + 'SurfaceRasterMetrics', 'SurfaceRasterScan', 'TemperatureCheck', + 'TemperatureOscillatingRampModifier', 'TemperatureRampModifier', + 'ThresholdCheck', 'ThresholdSelection', 'TranslateMolecules', + 'UNION_ATOMS_OR_ATOMS_LST', 'UniformArangeSelection', + 'UniformEnergeticSelection', 'UniformTemporalSelection', + 'VelocityVerletDynamic', 'WrapModifier', 'analysis', 'ase_sim', + 'base', 'bootstrap', 'calc', 'calculators', 'combine', + 'configuration_generation', 'configuration_selection', 'conftest', + 'data_loading', 'datasets', 'docs', 'doctest_namespace', 'dynamics', + 'fields', 'geometry', 'helpers', 'interfaces', 'log', 'md', + 'metrics', 'models', 'nodes', 'project', 'static_data', 'utils', + 'version'] diff --git a/ipsuite/__init__.pyi b/ipsuite/__init__.pyi index a63c4cdf..30e2bbb8 100644 --- a/ipsuite/__init__.pyi +++ b/ipsuite/__init__.pyi @@ -226,6 +226,269 @@ __all__ = [ # Project "Project", # Calc +] + +from . import analysis +from . import base +from . import bootstrap +from . import calc +from . import calculators +from . import configuration_generation +from . import configuration_selection +from . import conftest +from . import data_loading +from . import datasets +from . import dynamics +from . import fields +from . import geometry +from . import interfaces +from . import models +from . import nodes +from . import project +from . import static_data +from . import utils +from . import version + +from .analysis import ( + AllowedStructuresFilter, + AnalyseDensity, + AnalyseGlobalForceSensitivity, + AnalyseSingleForceSensitivity, + AnalyseStructureMeanForce, + BondStretchAnalyses, + BoxHeatUp, + BoxScale, + CalibrationMetrics, + CollectMDSteps, + DipoleHistogram, + EnergyHistogram, + EnergyUncertaintyHistogram, + ForceAngles, + ForceDecomposition, + ForceUncertaintyDecomposition, + ForcesHistogram, + ForcesUncertaintyHistogram, + MDStability, + MoveSingleParticle, + Prediction, + PredictionMetrics, + RattleAnalysis, + StressHistogram, +) +from .base import ( + AnalyseAtoms, + Check, + ComparePredictions, + Flatten, + IPSNode, + ProcessAtoms, + ProcessSingleAtom, + interfaces, +) +from .bootstrap import ( + RattleAtoms, + RotateMolecules, + SurfaceRasterMetrics, + SurfaceRasterScan, + TranslateMolecules, +) +from .calc import ( + ApplyCalculator, +) +from .configuration_selection import ( + ConfigurationSelection, + FilterOutlier, + IndexSelection, + RandomSelection, + SplitSelection, + ThresholdSelection, + UniformArangeSelection, + UniformEnergeticSelection, + UniformTemporalSelection, +) +from .conftest import ( + doctest_namespace, + project, +) +from .data_loading import ( + AddData, + AddDataH5MD, +) +from .datasets import ( + MD22Dataset, +) +from .dynamics import ( + ASEMD, + ASEMDSafeSampling, + Berendsen, + BoxOscillatingRampModifier, + ConnectivityCheck, + DebugCheck, + DensityCheck, + EnergySpikeCheck, + FixedBondLengthConstraint, + FixedLayerConstraint, + FixedSphereConstraint, + HookeanConstraint, + LangevinThermostat, + NPTThermostat, + NaNCheck, + PressureRampModifier, + RescaleBoxModifier, + SVCRBarostat, + TemperatureCheck, + TemperatureOscillatingRampModifier, + TemperatureRampModifier, + ThresholdCheck, + VelocityVerletDynamic, + WrapModifier, +) +from .fields import ( + Atoms, +) +from .geometry import ( + BarycenterMapping, +) +from .interfaces import ( + ATOMS_LST, + HasAtoms, + HasOrIsAtoms, + HasSelectedConfigurations, + NodeWithCalculator, + NodeWithThermostat, + ProcessAtoms, + UNION_ATOMS_OR_ATOMS_LST, +) +from .nodes import ( + nodes, +) +from .project import ( + Project, + log, +) +from .static_data import ( + STATIC_PATH, +) +from .utils import ( + ase_sim, + combine, + docs, + helpers, + md, + metrics, +) + +__all__ = [ + "ASEMD", + "ASEMDSafeSampling", + "ATOMS_LST", + "AddData", + "AddDataH5MD", + "AllowedStructuresFilter", + "AnalyseAtoms", + "AnalyseDensity", + "AnalyseGlobalForceSensitivity", + "AnalyseSingleForceSensitivity", + "AnalyseStructureMeanForce", "ApplyCalculator", + "Atoms", + "BarycenterMapping", + "Berendsen", + "BondStretchAnalyses", + "BoxHeatUp", + "BoxOscillatingRampModifier", + "BoxScale", + "CalibrationMetrics", + "Check", + "CollectMDSteps", + "ComparePredictions", + "ConfigurationSelection", + "ConnectivityCheck", + "DebugCheck", + "DensityCheck", + "DipoleHistogram", + "EnergyHistogram", + "EnergySpikeCheck", + "EnergyUncertaintyHistogram", + "FilterOutlier", + "FixedBondLengthConstraint", + "FixedLayerConstraint", + "FixedSphereConstraint", + "Flatten", + "ForceAngles", + "ForceDecomposition", + "ForceUncertaintyDecomposition", + "ForcesHistogram", + "ForcesUncertaintyHistogram", + "HasAtoms", + "HasOrIsAtoms", + "HasSelectedConfigurations", + "HookeanConstraint", + "IPSNode", + "IndexSelection", + "LangevinThermostat", + "MD22Dataset", + "MDStability", + "MoveSingleParticle", + "NPTThermostat", + "NaNCheck", + "NodeWithCalculator", + "NodeWithThermostat", + "Prediction", + "PredictionMetrics", + "PressureRampModifier", + "ProcessAtoms", + "ProcessSingleAtom", + "Project", + "RandomSelection", + "RattleAnalysis", + "RattleAtoms", + "RescaleBoxModifier", + "RotateMolecules", + "STATIC_PATH", + "SVCRBarostat", + "SplitSelection", + "StressHistogram", + "SurfaceRasterMetrics", + "SurfaceRasterScan", + "TemperatureCheck", + "TemperatureOscillatingRampModifier", + "TemperatureRampModifier", + "ThresholdCheck", + "ThresholdSelection", + "TranslateMolecules", + "UNION_ATOMS_OR_ATOMS_LST", + "UniformArangeSelection", + "UniformEnergeticSelection", + "UniformTemporalSelection", + "VelocityVerletDynamic", "WrapModifier", + "analysis", + "ase_sim", + "base", + "bootstrap", + "calc", + "calculators", + "combine", + "configuration_generation", + "configuration_selection", + "conftest", + "data_loading", + "datasets", + "docs", + "doctest_namespace", + "dynamics", + "fields", + "geometry", + "helpers", + "interfaces", + "log", + "md", + "metrics", + "models", + "nodes", + "project", + "static_data", + "utils", + "version", ] From 2eaefd23fd5fc36abc953d2e3e15f02dc873c410 Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Thu, 18 Dec 2025 11:30:12 +0100 Subject: [PATCH 09/10] Changed pyproject to make ruff not format __init__pyi and pass checks for __init__.py and __init__.pyi --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 088c6e8e..ed15281b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,6 +84,7 @@ exclude = [ "node_modules", "venv", "tests", + "ipsuite/__init__.pyi", ] # Same as Black. @@ -98,6 +99,10 @@ ignore = [ "B905", # not supported in older python versions ] +[tool.ruff.lint.per-file-ignores] +"ipsuite/__init__.py*" = ["E402", "F811", "I001"] + + [tool.codespell] ignore-words-list = "dscribe" skip = "poetry.lock,ipsuite/static_data/*,docs/source/examples/06_Bootstrapping_Datasets.ipynb,*.out" From f89876dd3aedc2e5017cd67a9617e17849b2a55c Mon Sep 17 00:00:00 2001 From: TobiasDijkhuis Date: Wed, 14 Jan 2026 14:57:16 +0100 Subject: [PATCH 10/10] Added documentation for mkinit for creation of __init__.py(i) --- docs/source/_get_started/ips.rst | 2 +- ipsuite/__init__.py | 8 + ipsuite/__init__.pyi | 424 ++++++------------------------- 3 files changed, 88 insertions(+), 346 deletions(-) diff --git a/docs/source/_get_started/ips.rst b/docs/source/_get_started/ips.rst index 50034569..abfeeb9e 100644 --- a/docs/source/_get_started/ips.rst +++ b/docs/source/_get_started/ips.rst @@ -26,4 +26,4 @@ Sort of like a Jigsaw multiple nodes can be connected together in order to creat IPSuite provides various Nodes in order to meet the needs of MPL creation and training. .. figure:: ../images/mlp.png - :alt: MLP Develepment Process. + :alt: MLP Development Process. diff --git a/ipsuite/__init__.py b/ipsuite/__init__.py index f3ee7aac..a69f2493 100644 --- a/ipsuite/__init__.py +++ b/ipsuite/__init__.py @@ -1,6 +1,14 @@ """The ipsuite package.""" # +# IPSuite uses `lazy-loader` to only load the necessary subpackages and functions. To make sure that all the +# functions and nodes are exposed to the API and static type checkers, `mkinit` can automatically generate +# the `__init__.py` files. Before committing changes, please run (while in the `ipsuite` source directory) +# +# mkinit --relative --lazy_loader_typed -w +# +# and add the changed `__init__.py` and `__init__.pyi` files to the commit. + from ipsuite.utils.helpers import setup_ase from ipsuite.utils.logs import setup_logging diff --git a/ipsuite/__init__.pyi b/ipsuite/__init__.pyi index 30e2bbb8..510c0f13 100644 --- a/ipsuite/__init__.pyi +++ b/ipsuite/__init__.pyi @@ -125,109 +125,6 @@ from .project import Project from .version import __version__ # Update __all__ for lazy loading -__all__ = [ - "__version__", - # Base - "Flatten", - "base", - # Models - "EnsembleModel", - "CP2KModel", - "TBLiteModel", - "ORCAModel", - "MACEMPModel", - "GenericASEModel", - "TorchDFTD3", - # Configuration Selection - "IndexSelection", - "RandomSelection", - "SplitSelection", - "UniformArangeSelection", - "UniformEnergeticSelection", - "UniformTemporalSelection", - "ThresholdSelection", - "FilterOutlier", - # Configuration Generation - "Packmol", - "MultiPackmol", - "Smiles2Atoms", - "Smiles2Conformers", - "Smiles2Gromacs", - # Data - "AddData", - "AddDataH5MD", - # Datasets - "MD22Dataset", - # Bootstrap - "RattleAtoms", - "TranslateMolecules", - "RotateMolecules", - "SurfaceRasterScan", - "SurfaceRasterMetrics", - # Analysis - "DipoleHistogram", - "EnergyHistogram", - "ForcesHistogram", - "StressHistogram", - "ForcesUncertaintyHistogram", - "EnergyUncertaintyHistogram", - "PredictionMetrics", - "ForceAngles", - "RattleAnalysis", - "Prediction", - "CalibrationMetrics", - "BoxScale", - "BoxHeatUp", - "DebugCheck", - "NaNCheck", - "ConnectivityCheck", - "EnergySpikeCheck", - "MDStability", - "MoveSingleParticle", - "AnalyseGlobalForceSensitivity", - "AnalyseSingleForceSensitivity", - "ForceUncertaintyDecomposition", - "ForceDecomposition", - "ThresholdCheck", - "TemperatureCheck", - "AnalyseDensity", - "DensityCheck", - "CollectMDSteps", - "AllowedStructuresFilter", - "AnalyseStructureMeanForce", - # Calculators - "CP2KSinglePoint", - "ASEGeoOpt", - "ASEMD", - "ASEMDSafeSampling", - "xTBSinglePoint", - "LJSinglePoint", - "EMTSinglePoint", - "OrcaSinglePoint", - "LammpsSimulator", - "MixCalculator", - "LangevinThermostat", - "VelocityVerletDynamic", - "Berendsen", - "NPTThermostat", - "SVCRBarostat", - "RescaleBoxModifier", - "BoxOscillatingRampModifier", - "TemperatureRampModifier", - "TemperatureOscillatingRampModifier", - "FixedSphereConstraint", - "FixedLayerConstraint", - "FixedBondLengthConstraint", - "HookeanConstraint", - "PressureRampModifier", - "PlumedModel", - # Geometry - "BarycenterMapping", - # Project - "Project", - # Calc -] - from . import analysis from . import base from . import bootstrap @@ -249,246 +146,83 @@ from . import static_data from . import utils from . import version -from .analysis import ( - AllowedStructuresFilter, - AnalyseDensity, - AnalyseGlobalForceSensitivity, - AnalyseSingleForceSensitivity, - AnalyseStructureMeanForce, - BondStretchAnalyses, - BoxHeatUp, - BoxScale, - CalibrationMetrics, - CollectMDSteps, - DipoleHistogram, - EnergyHistogram, - EnergyUncertaintyHistogram, - ForceAngles, - ForceDecomposition, - ForceUncertaintyDecomposition, - ForcesHistogram, - ForcesUncertaintyHistogram, - MDStability, - MoveSingleParticle, - Prediction, - PredictionMetrics, - RattleAnalysis, - StressHistogram, -) -from .base import ( - AnalyseAtoms, - Check, - ComparePredictions, - Flatten, - IPSNode, - ProcessAtoms, - ProcessSingleAtom, - interfaces, -) -from .bootstrap import ( - RattleAtoms, - RotateMolecules, - SurfaceRasterMetrics, - SurfaceRasterScan, - TranslateMolecules, -) -from .calc import ( - ApplyCalculator, -) -from .configuration_selection import ( - ConfigurationSelection, - FilterOutlier, - IndexSelection, - RandomSelection, - SplitSelection, - ThresholdSelection, - UniformArangeSelection, - UniformEnergeticSelection, - UniformTemporalSelection, -) -from .conftest import ( - doctest_namespace, - project, -) -from .data_loading import ( - AddData, - AddDataH5MD, -) -from .datasets import ( - MD22Dataset, -) -from .dynamics import ( - ASEMD, - ASEMDSafeSampling, - Berendsen, - BoxOscillatingRampModifier, - ConnectivityCheck, - DebugCheck, - DensityCheck, - EnergySpikeCheck, - FixedBondLengthConstraint, - FixedLayerConstraint, - FixedSphereConstraint, - HookeanConstraint, - LangevinThermostat, - NPTThermostat, - NaNCheck, - PressureRampModifier, - RescaleBoxModifier, - SVCRBarostat, - TemperatureCheck, - TemperatureOscillatingRampModifier, - TemperatureRampModifier, - ThresholdCheck, - VelocityVerletDynamic, - WrapModifier, -) -from .fields import ( - Atoms, -) -from .geometry import ( - BarycenterMapping, -) -from .interfaces import ( - ATOMS_LST, - HasAtoms, - HasOrIsAtoms, - HasSelectedConfigurations, - NodeWithCalculator, - NodeWithThermostat, - ProcessAtoms, - UNION_ATOMS_OR_ATOMS_LST, -) -from .nodes import ( - nodes, -) -from .project import ( - Project, - log, -) -from .static_data import ( - STATIC_PATH, -) -from .utils import ( - ase_sim, - combine, - docs, - helpers, - md, - metrics, -) +from .analysis import (AllowedStructuresFilter, AnalyseDensity, + AnalyseGlobalForceSensitivity, + AnalyseSingleForceSensitivity, + AnalyseStructureMeanForce, BondStretchAnalyses, + BoxHeatUp, BoxScale, CalibrationMetrics, CollectMDSteps, + DipoleHistogram, EnergyHistogram, + EnergyUncertaintyHistogram, ForceAngles, + ForceDecomposition, ForceUncertaintyDecomposition, + ForcesHistogram, ForcesUncertaintyHistogram, + MDStability, MoveSingleParticle, Prediction, + PredictionMetrics, RattleAnalysis, StressHistogram,) +from .base import (AnalyseAtoms, Check, ComparePredictions, Flatten, IPSNode, + ProcessAtoms, ProcessSingleAtom, interfaces,) +from .bootstrap import (RattleAtoms, RotateMolecules, SurfaceRasterMetrics, + SurfaceRasterScan, TranslateMolecules,) +from .calc import (ApplyCalculator,) +from .configuration_selection import (ConfigurationSelection, FilterOutlier, + IndexSelection, RandomSelection, + SplitSelection, ThresholdSelection, + UniformArangeSelection, + UniformEnergeticSelection, + UniformTemporalSelection,) +from .conftest import (doctest_namespace, project,) +from .data_loading import (AddData, AddDataH5MD,) +from .datasets import (MD22Dataset,) +from .dynamics import (ASEMD, ASEMDSafeSampling, Berendsen, + BoxOscillatingRampModifier, ConnectivityCheck, + DebugCheck, DensityCheck, EnergySpikeCheck, + FixedBondLengthConstraint, FixedLayerConstraint, + FixedSphereConstraint, HookeanConstraint, + LangevinThermostat, NPTThermostat, NaNCheck, + PressureRampModifier, RescaleBoxModifier, SVCRBarostat, + TemperatureCheck, TemperatureOscillatingRampModifier, + TemperatureRampModifier, ThresholdCheck, + VelocityVerletDynamic, WrapModifier,) +from .fields import (Atoms,) +from .geometry import (BarycenterMapping,) +from .interfaces import (ATOMS_LST, HasAtoms, HasOrIsAtoms, + HasSelectedConfigurations, NodeWithCalculator, + NodeWithThermostat, ProcessAtoms, + UNION_ATOMS_OR_ATOMS_LST,) +from .nodes import (nodes,) +from .project import (Project, log,) +from .static_data import (STATIC_PATH,) +from .utils import (ase_sim, combine, docs, helpers, md, metrics,) -__all__ = [ - "ASEMD", - "ASEMDSafeSampling", - "ATOMS_LST", - "AddData", - "AddDataH5MD", - "AllowedStructuresFilter", - "AnalyseAtoms", - "AnalyseDensity", - "AnalyseGlobalForceSensitivity", - "AnalyseSingleForceSensitivity", - "AnalyseStructureMeanForce", - "ApplyCalculator", - "Atoms", - "BarycenterMapping", - "Berendsen", - "BondStretchAnalyses", - "BoxHeatUp", - "BoxOscillatingRampModifier", - "BoxScale", - "CalibrationMetrics", - "Check", - "CollectMDSteps", - "ComparePredictions", - "ConfigurationSelection", - "ConnectivityCheck", - "DebugCheck", - "DensityCheck", - "DipoleHistogram", - "EnergyHistogram", - "EnergySpikeCheck", - "EnergyUncertaintyHistogram", - "FilterOutlier", - "FixedBondLengthConstraint", - "FixedLayerConstraint", - "FixedSphereConstraint", - "Flatten", - "ForceAngles", - "ForceDecomposition", - "ForceUncertaintyDecomposition", - "ForcesHistogram", - "ForcesUncertaintyHistogram", - "HasAtoms", - "HasOrIsAtoms", - "HasSelectedConfigurations", - "HookeanConstraint", - "IPSNode", - "IndexSelection", - "LangevinThermostat", - "MD22Dataset", - "MDStability", - "MoveSingleParticle", - "NPTThermostat", - "NaNCheck", - "NodeWithCalculator", - "NodeWithThermostat", - "Prediction", - "PredictionMetrics", - "PressureRampModifier", - "ProcessAtoms", - "ProcessSingleAtom", - "Project", - "RandomSelection", - "RattleAnalysis", - "RattleAtoms", - "RescaleBoxModifier", - "RotateMolecules", - "STATIC_PATH", - "SVCRBarostat", - "SplitSelection", - "StressHistogram", - "SurfaceRasterMetrics", - "SurfaceRasterScan", - "TemperatureCheck", - "TemperatureOscillatingRampModifier", - "TemperatureRampModifier", - "ThresholdCheck", - "ThresholdSelection", - "TranslateMolecules", - "UNION_ATOMS_OR_ATOMS_LST", - "UniformArangeSelection", - "UniformEnergeticSelection", - "UniformTemporalSelection", - "VelocityVerletDynamic", - "WrapModifier", - "analysis", - "ase_sim", - "base", - "bootstrap", - "calc", - "calculators", - "combine", - "configuration_generation", - "configuration_selection", - "conftest", - "data_loading", - "datasets", - "docs", - "doctest_namespace", - "dynamics", - "fields", - "geometry", - "helpers", - "interfaces", - "log", - "md", - "metrics", - "models", - "nodes", - "project", - "static_data", - "utils", - "version", -] +__all__ = ['ASEMD', 'ASEMDSafeSampling', 'ATOMS_LST', 'AddData', 'AddDataH5MD', + 'AllowedStructuresFilter', 'AnalyseAtoms', 'AnalyseDensity', + 'AnalyseGlobalForceSensitivity', 'AnalyseSingleForceSensitivity', + 'AnalyseStructureMeanForce', 'ApplyCalculator', 'Atoms', + 'BarycenterMapping', 'Berendsen', 'BondStretchAnalyses', + 'BoxHeatUp', 'BoxOscillatingRampModifier', 'BoxScale', + 'CalibrationMetrics', 'Check', 'CollectMDSteps', + 'ComparePredictions', 'ConfigurationSelection', 'ConnectivityCheck', + 'DebugCheck', 'DensityCheck', 'DipoleHistogram', 'EnergyHistogram', + 'EnergySpikeCheck', 'EnergyUncertaintyHistogram', 'FilterOutlier', + 'FixedBondLengthConstraint', 'FixedLayerConstraint', + 'FixedSphereConstraint', 'Flatten', 'ForceAngles', + 'ForceDecomposition', 'ForceUncertaintyDecomposition', + 'ForcesHistogram', 'ForcesUncertaintyHistogram', 'HasAtoms', + 'HasOrIsAtoms', 'HasSelectedConfigurations', 'HookeanConstraint', + 'IPSNode', 'IndexSelection', 'LangevinThermostat', 'MD22Dataset', + 'MDStability', 'MoveSingleParticle', 'NPTThermostat', 'NaNCheck', + 'NodeWithCalculator', 'NodeWithThermostat', 'Prediction', + 'PredictionMetrics', 'PressureRampModifier', 'ProcessAtoms', + 'ProcessSingleAtom', 'Project', 'RandomSelection', 'RattleAnalysis', + 'RattleAtoms', 'RescaleBoxModifier', 'RotateMolecules', + 'STATIC_PATH', 'SVCRBarostat', 'SplitSelection', 'StressHistogram', + 'SurfaceRasterMetrics', 'SurfaceRasterScan', 'TemperatureCheck', + 'TemperatureOscillatingRampModifier', 'TemperatureRampModifier', + 'ThresholdCheck', 'ThresholdSelection', 'TranslateMolecules', + 'UNION_ATOMS_OR_ATOMS_LST', 'UniformArangeSelection', + 'UniformEnergeticSelection', 'UniformTemporalSelection', + 'VelocityVerletDynamic', 'WrapModifier', 'analysis', 'ase_sim', + 'base', 'bootstrap', 'calc', 'calculators', 'combine', + 'configuration_generation', 'configuration_selection', 'conftest', + 'data_loading', 'datasets', 'docs', 'doctest_namespace', 'dynamics', + 'fields', 'geometry', 'helpers', 'interfaces', 'log', 'md', + 'metrics', 'models', 'nodes', 'project', 'static_data', 'utils', + 'version']