From ddace68bccc7c8c8821fa188426c0dd2fa5a7fb9 Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Sat, 6 Nov 2021 11:33:19 +0100 Subject: [PATCH 1/7] functions signatures --- pyiron_atomistics/atomistics/structure/analyse.py | 4 ++++ pyiron_atomistics/atomistics/structure/pyscal.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index cb9aa0de3..089c85ce2 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -531,6 +531,10 @@ def pyscal_diamond_structure(self, mode="total", ovito_compatibility=False): def pyscal_voronoi_volume(self): """ Calculate the Voronoi volume of atoms """ return analyse_voronoi_volume(atoms=self._structure) + + def pyscal_find_solids(self, neighbor_method="cutoff", cutoff=0, bonds=6, threshold=0.5, avgthreshold=0.6, cluster=False): + return analyse_find_solids() + def get_voronoi_vertices(self, epsilon=2.5e-4, distance_threshold=0, width_buffer=10): """ diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index 3b2d9cd7d..907e02488 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -242,6 +242,9 @@ def analyse_voronoi_volume(atoms): return np.array([atom.volume for atom in atoms]) +def analyse_find_solids(atoms, neighbor_method="cutoff", cutoff=0, bonds=6, threshold=0.5, avgthreshold=0.6, cluster=False): + + def publication(): return { "pyscal": { From 9bf9948559a67984306faeaa45e99235659da4fe Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Sat, 6 Nov 2021 20:32:57 +0100 Subject: [PATCH 2/7] define get system and add function body --- .../atomistics/structure/analyse.py | 20 ++++++-- .../atomistics/structure/pyscal.py | 49 +++++++++++-------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index 089c85ce2..eabbee085 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -8,7 +8,7 @@ from scipy.sparse import coo_matrix from scipy.spatial import Voronoi from pyiron_atomistics.atomistics.structure.pyscal import get_steinhardt_parameter_structure, analyse_cna_adaptive, \ - analyse_centro_symmetry, analyse_diamond_structure, analyse_voronoi_volume + analyse_centro_symmetry, analyse_diamond_structure, analyse_voronoi_volume, get_system, analyse_find_solids from pyiron_atomistics.atomistics.structure.strain import Strain from pyiron_base.generic.util import Deprecator from scipy.spatial import ConvexHull @@ -532,9 +532,23 @@ def pyscal_voronoi_volume(self): """ Calculate the Voronoi volume of atoms """ return analyse_voronoi_volume(atoms=self._structure) - def pyscal_find_solids(self, neighbor_method="cutoff", cutoff=0, bonds=6, threshold=0.5, avgthreshold=0.6, cluster=False): - return analyse_find_solids() + def pyscal_find_solids(self, atoms, neighbor_method="cutoff", + cutoff=0, bonds=0.5, + threshold=0.5, avgthreshold=0.6, + cluster=False, q=6, right=True, + return_sys=False, + ): + return analyse_find_solids(atoms=atoms, + neighbor_method=neighbor_method, + cutoff=cutoff, bonds=bonds, + threshold=threshold, + avgthreshold=avgthreshold, + cluster=cluster, q=q, + right=right, return_sys=return_sys, + ) + def pyscal_system(self): + return get_system(self) def get_voronoi_vertices(self, epsilon=2.5e-4, distance_threshold=0, width_buffer=10): """ diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index 907e02488..6faf11155 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -43,15 +43,10 @@ def get_steinhardt_parameter_structure(atoms, neighbor_method="cutoff", cutoff=0 numpy.ndarray: (number of q's, number of atoms) shaped array of q parameters numpy.ndarray: If `clustering=True`, an additional per-atom array of cluster ids is also returned """ - s.publication_add(publication()) + sys = get_system(atoms) q = (4, 6) if q is None else q if clustering == False: n_clusters = None - sys = pc.System() - sys.read_inputfile( - pyiron_atomistics.atomistics.structure.atoms.pyiron_to_ase(atoms), - format='ase' - ) sys.find_neighbors( method=neighbor_method, @@ -90,9 +85,7 @@ def analyse_centro_symmetry(atoms, num_neighbors=12): Returns: csm (list) : list of centrosymmetry parameter """ - s.publication_add(publication()) - sys = pc.System() - sys.read_inputfile(atoms, format="ase") + sys = get_system(atoms) return np.array(sys.calculate_centrosymmetry(nmax=num_neighbors)) @@ -113,9 +106,7 @@ def analyse_diamond_structure(atoms, mode="total", ovito_compatibility=False): Returns: (depends on `mode`) """ - s.publication_add(publication()) - sys = pc.System() - sys.read_inputfile(atoms, format="ase") + sys = get_system(atoms) diamond_dict = sys.identify_diamond() ovito_identifiers = [ @@ -186,7 +177,7 @@ def analyse_cna_adaptive(atoms, mode="total", ovito_compatibility=False): Returns: (depends on `mode`) """ - s.publication_add(publication()) + sys = get_system(atoms) if mode not in ["total", "numeric", "str"]: raise ValueError("Unsupported mode") @@ -199,8 +190,6 @@ def analyse_cna_adaptive(atoms, mode="total", ovito_compatibility=False): 'CommonNeighborAnalysis.counts.ICO' ] - sys = pc.System() - sys.read_inputfile(atoms, format="ase") cna = sys.calculate_cna() if mode == "total": @@ -234,16 +223,34 @@ def analyse_voronoi_volume(atoms): Args: atoms : (pyiron_atomistics.structure.atoms.Atoms): The structure to analyze. """ - s.publication_add(publication()) - sys = pc.System() - sys.read_inputfile(atoms, format="ase") + sys = get_system(atoms) sys.find_neighbors(method="voronoi") atoms = sys.atoms return np.array([atom.volume for atom in atoms]) - -def analyse_find_solids(atoms, neighbor_method="cutoff", cutoff=0, bonds=6, threshold=0.5, avgthreshold=0.6, cluster=False): - +def get_system(atoms): + s.publication_add(publication()) + sys = pc.System() + sys.read_inputfile( + pyiron_atomistics.atomistics.structure.atoms.pyiron_to_ase(atoms), + format="ase", + ) + return sys + +def analyse_find_solids(atoms, neighbor_method="cutoff", + cutoff=0, bonds=0.5, + threshold=0.5, avgthreshold=0.6, + cluster=False, q=6, right=True, + return_sys=False, + ): + sys = get_system(atoms) + sys.find_neighbors(method=neighbor_method, cutoff=cutoff) + sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff) + if return_sys: + return sys + atoms = sys.atoms + solids = [atom for atom in atoms if atom.solid] + return len(solids) def publication(): return { From 0d769c28680f42f632cd31e39b02093fca94e366 Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Sun, 7 Nov 2021 14:28:17 +0100 Subject: [PATCH 3/7] fix atoms as argument --- pyiron_atomistics/atomistics/structure/analyse.py | 6 +++--- pyiron_atomistics/atomistics/structure/pyscal.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index eabbee085..335852a1a 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -532,13 +532,13 @@ def pyscal_voronoi_volume(self): """ Calculate the Voronoi volume of atoms """ return analyse_voronoi_volume(atoms=self._structure) - def pyscal_find_solids(self, atoms, neighbor_method="cutoff", + def pyscal_find_solids(self, neighbor_method="cutoff", cutoff=0, bonds=0.5, threshold=0.5, avgthreshold=0.6, cluster=False, q=6, right=True, return_sys=False, ): - return analyse_find_solids(atoms=atoms, + return analyse_find_solids(atoms=self._structure, neighbor_method=neighbor_method, cutoff=cutoff, bonds=bonds, threshold=threshold, @@ -548,7 +548,7 @@ def pyscal_find_solids(self, atoms, neighbor_method="cutoff", ) def pyscal_system(self): - return get_system(self) + return get_system(self._structure) def get_voronoi_vertices(self, epsilon=2.5e-4, distance_threshold=0, width_buffer=10): """ diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index 6faf11155..c3cddb098 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -245,7 +245,7 @@ def analyse_find_solids(atoms, neighbor_method="cutoff", ): sys = get_system(atoms) sys.find_neighbors(method=neighbor_method, cutoff=cutoff) - sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff) + sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff, cluster=cluster) if return_sys: return sys atoms = sys.atoms From 587a8e3e28d78cd511f60ff95404694749bba81a Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Tue, 9 Nov 2021 10:29:55 +0100 Subject: [PATCH 4/7] documentation --- .../atomistics/structure/analyse.py | 24 ++++++++++++++ .../atomistics/structure/pyscal.py | 31 ++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index 335852a1a..434a715e3 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -538,6 +538,25 @@ def pyscal_find_solids(self, neighbor_method="cutoff", cluster=False, q=6, right=True, return_sys=False, ): + """ + Get the number of solids or the corresponding pyscal system. + Calls necessary pyscal methods as described in https://pyscal.org/en/latest/methods/03_solidliquid.html. + + Args: + neighbor_method (str, optional): Method used to get neighborlist. See pyscal documentation. Defaults to "cutoff". + cutoff (int, optional): Adaptive if 0. Defaults to 0. + bonds (float, optional): Number or fraction of bonds to consider atom as solid. Defaults to 0.5. + threshold (float, optional): See pyscal documentation. Defaults to 0.5. + avgthreshold (float, optional): See pyscal documentation. Defaults to 0.6. + cluster (bool, optional): See pyscal documentation. Defaults to False. + q (int, optional): Steinhard parameter to calculate. Defaults to 6. + right (bool, optional): See pyscal documentation. Defaults to True. + return_sys (bool, optional): Whether to return number of solid atoms or pyscal system. Defaults to False. + + Returns: + int: number of solids, + pyscal system: pyscal system when return_sys=True + """ return analyse_find_solids(atoms=self._structure, neighbor_method=neighbor_method, cutoff=cutoff, bonds=bonds, @@ -548,6 +567,11 @@ def pyscal_find_solids(self, neighbor_method="cutoff", ) def pyscal_system(self): + """Returns a pyscal system constructed from the structure + + Returns: + pyscal system: See pyscal documentation + """ return get_system(self._structure) def get_voronoi_vertices(self, epsilon=2.5e-4, distance_threshold=0, width_buffer=10): diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index c3cddb098..e47f4ec73 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -229,6 +229,16 @@ def analyse_voronoi_volume(atoms): return np.array([atom.volume for atom in atoms]) def get_system(atoms): + """ + Converts atoms to ase atoms and than to a pyscal system. + Also adds the pyscal publication. + + Args: + atoms (pyiron atoms): Structure to convert. + + Returns: + Pyscal system: See the pyscal documentation. + """ s.publication_add(publication()) sys = pc.System() sys.read_inputfile( @@ -243,9 +253,28 @@ def analyse_find_solids(atoms, neighbor_method="cutoff", cluster=False, q=6, right=True, return_sys=False, ): + """ + Get the number of solids or the corresponding pyscal system. + Calls necessary pyscal methods as described in https://pyscal.org/en/latest/methods/03_solidliquid.html. + + Args: + neighbor_method (str, optional): Method used to get neighborlist. See pyscal documentation. Defaults to "cutoff". + cutoff (int, optional): Adaptive if 0. Defaults to 0. + bonds (float, optional): Number or fraction of bonds to consider atom as solid. Defaults to 0.5. + threshold (float, optional): See pyscal documentation. Defaults to 0.5. + avgthreshold (float, optional): See pyscal documentation. Defaults to 0.6. + cluster (bool, optional): See pyscal documentation. Defaults to False. + q (int, optional): Steinhard parameter to calculate. Defaults to 6. + right (bool, optional): See pyscal documentation. Defaults to True. + return_sys (bool, optional): Whether to return number of solid atoms or pyscal system. Defaults to False. + + Returns: + int: number of solids, + pyscal system: pyscal system when return_sys=True + """ sys = get_system(atoms) sys.find_neighbors(method=neighbor_method, cutoff=cutoff) - sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff, cluster=cluster) + sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff, cluster=cluster, right=right) if return_sys: return sys atoms = sys.atoms From 5e16a533f6554d8a1d1efd5f906ae0b382cfe1e1 Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Tue, 9 Nov 2021 10:47:04 +0100 Subject: [PATCH 5/7] codacy --- pyiron_atomistics/atomistics/structure/analyse.py | 7 ++++--- pyiron_atomistics/atomistics/structure/pyscal.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index 434a715e3..c7e74c353 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -531,7 +531,7 @@ def pyscal_diamond_structure(self, mode="total", ovito_compatibility=False): def pyscal_voronoi_volume(self): """ Calculate the Voronoi volume of atoms """ return analyse_voronoi_volume(atoms=self._structure) - + def pyscal_find_solids(self, neighbor_method="cutoff", cutoff=0, bonds=0.5, threshold=0.5, avgthreshold=0.6, @@ -556,7 +556,7 @@ def pyscal_find_solids(self, neighbor_method="cutoff", Returns: int: number of solids, pyscal system: pyscal system when return_sys=True - """ + """ return analyse_find_solids(atoms=self._structure, neighbor_method=neighbor_method, cutoff=cutoff, bonds=bonds, @@ -567,7 +567,8 @@ def pyscal_find_solids(self, neighbor_method="cutoff", ) def pyscal_system(self): - """Returns a pyscal system constructed from the structure + """ + Creates pyscal system from the structure Returns: pyscal system: See pyscal documentation diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index e47f4ec73..8c2943271 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -238,7 +238,7 @@ def get_system(atoms): Returns: Pyscal system: See the pyscal documentation. - """ + """ s.publication_add(publication()) sys = pc.System() sys.read_inputfile( From 4e42254190c7351048538e2865dcf951d83ba857 Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Tue, 9 Nov 2021 10:56:05 +0100 Subject: [PATCH 6/7] codacy2 --- pyiron_atomistics/atomistics/structure/analyse.py | 2 +- pyiron_atomistics/atomistics/structure/pyscal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index c7e74c353..2a1ced25d 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -572,7 +572,7 @@ def pyscal_system(self): Returns: pyscal system: See pyscal documentation - """ + """ return get_system(self._structure) def get_voronoi_vertices(self, epsilon=2.5e-4, distance_threshold=0, width_buffer=10): diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index 8c2943271..3e070a8dc 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -271,7 +271,7 @@ def analyse_find_solids(atoms, neighbor_method="cutoff", Returns: int: number of solids, pyscal system: pyscal system when return_sys=True - """ + """ sys = get_system(atoms) sys.find_neighbors(method=neighbor_method, cutoff=cutoff) sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff, cluster=cluster, right=right) From e48212efa422262d514a879b5990d8b5982c1c4c Mon Sep 17 00:00:00 2001 From: Niklas Leimeroth Date: Tue, 9 Nov 2021 12:02:57 +0100 Subject: [PATCH 7/7] naming convention and move to atoms --- pyiron_atomistics/atomistics/structure/analyse.py | 11 +---------- pyiron_atomistics/atomistics/structure/atoms.py | 3 +++ pyiron_atomistics/atomistics/structure/pyscal.py | 14 +++++++------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/analyse.py b/pyiron_atomistics/atomistics/structure/analyse.py index 2a1ced25d..99a911366 100644 --- a/pyiron_atomistics/atomistics/structure/analyse.py +++ b/pyiron_atomistics/atomistics/structure/analyse.py @@ -8,7 +8,7 @@ from scipy.sparse import coo_matrix from scipy.spatial import Voronoi from pyiron_atomistics.atomistics.structure.pyscal import get_steinhardt_parameter_structure, analyse_cna_adaptive, \ - analyse_centro_symmetry, analyse_diamond_structure, analyse_voronoi_volume, get_system, analyse_find_solids + analyse_centro_symmetry, analyse_diamond_structure, analyse_voronoi_volume, pyiron_to_pyscal_system, analyse_find_solids from pyiron_atomistics.atomistics.structure.strain import Strain from pyiron_base.generic.util import Deprecator from scipy.spatial import ConvexHull @@ -566,15 +566,6 @@ def pyscal_find_solids(self, neighbor_method="cutoff", right=right, return_sys=return_sys, ) - def pyscal_system(self): - """ - Creates pyscal system from the structure - - Returns: - pyscal system: See pyscal documentation - """ - return get_system(self._structure) - def get_voronoi_vertices(self, epsilon=2.5e-4, distance_threshold=0, width_buffer=10): """ Get voronoi vertices of the box. diff --git a/pyiron_atomistics/atomistics/structure/atoms.py b/pyiron_atomistics/atomistics/structure/atoms.py index 811be8792..9fe922a08 100644 --- a/pyiron_atomistics/atomistics/structure/atoms.py +++ b/pyiron_atomistics/atomistics/structure/atoms.py @@ -12,6 +12,7 @@ import warnings import seekpath from pyiron_atomistics.atomistics.structure.atom import Atom, ase_to_pyiron as ase_to_pyiron_atom +from pyiron_atomistics.atomistics.structure.pyscal import pyiron_to_pyscal_system from pyiron_atomistics.atomistics.structure.neighbors import Neighbors, Tree from pyiron_atomistics.atomistics.structure._visualize import Visualize from pyiron_atomistics.atomistics.structure.analyse import Analyse @@ -2435,6 +2436,8 @@ def to_pymatgen(self): def to_ovito(self): return pyiron_to_ovito(self) + def to_pyscal_system(self): + return pyiron_to_pyscal_system(self) class _CrystalStructure(Atoms): """ diff --git a/pyiron_atomistics/atomistics/structure/pyscal.py b/pyiron_atomistics/atomistics/structure/pyscal.py index 3e070a8dc..b0df522bc 100644 --- a/pyiron_atomistics/atomistics/structure/pyscal.py +++ b/pyiron_atomistics/atomistics/structure/pyscal.py @@ -43,7 +43,7 @@ def get_steinhardt_parameter_structure(atoms, neighbor_method="cutoff", cutoff=0 numpy.ndarray: (number of q's, number of atoms) shaped array of q parameters numpy.ndarray: If `clustering=True`, an additional per-atom array of cluster ids is also returned """ - sys = get_system(atoms) + sys = pyiron_to_pyscal_system(atoms) q = (4, 6) if q is None else q if clustering == False: n_clusters = None @@ -85,7 +85,7 @@ def analyse_centro_symmetry(atoms, num_neighbors=12): Returns: csm (list) : list of centrosymmetry parameter """ - sys = get_system(atoms) + sys = pyiron_to_pyscal_system(atoms) return np.array(sys.calculate_centrosymmetry(nmax=num_neighbors)) @@ -106,7 +106,7 @@ def analyse_diamond_structure(atoms, mode="total", ovito_compatibility=False): Returns: (depends on `mode`) """ - sys = get_system(atoms) + sys = pyiron_to_pyscal_system(atoms) diamond_dict = sys.identify_diamond() ovito_identifiers = [ @@ -177,7 +177,7 @@ def analyse_cna_adaptive(atoms, mode="total", ovito_compatibility=False): Returns: (depends on `mode`) """ - sys = get_system(atoms) + sys = pyiron_to_pyscal_system(atoms) if mode not in ["total", "numeric", "str"]: raise ValueError("Unsupported mode") @@ -223,12 +223,12 @@ def analyse_voronoi_volume(atoms): Args: atoms : (pyiron_atomistics.structure.atoms.Atoms): The structure to analyze. """ - sys = get_system(atoms) + sys = pyiron_to_pyscal_system(atoms) sys.find_neighbors(method="voronoi") atoms = sys.atoms return np.array([atom.volume for atom in atoms]) -def get_system(atoms): +def pyiron_to_pyscal_system(atoms): """ Converts atoms to ase atoms and than to a pyscal system. Also adds the pyscal publication. @@ -272,7 +272,7 @@ def analyse_find_solids(atoms, neighbor_method="cutoff", int: number of solids, pyscal system: pyscal system when return_sys=True """ - sys = get_system(atoms) + sys = pyiron_to_pyscal_system(atoms) sys.find_neighbors(method=neighbor_method, cutoff=cutoff) sys.find_solids(bonds=bonds, threshold=threshold, avgthreshold=avgthreshold, q=q, cutoff=cutoff, cluster=cluster, right=right) if return_sys: