From 29690a1bc94560eac83f8f309ac75067d7ebf88c Mon Sep 17 00:00:00 2001 From: usaikia Date: Fri, 28 Jul 2023 17:35:22 +0200 Subject: [PATCH 1/2] Upgrade the aimsgb structure factory --- .../atomistics/structure/factories/aimsgb.py | 146 +++++++++++------- 1 file changed, 89 insertions(+), 57 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/factories/aimsgb.py b/pyiron_atomistics/atomistics/structure/factories/aimsgb.py index 9bc1df782..32f508f8b 100644 --- a/pyiron_atomistics/atomistics/structure/factories/aimsgb.py +++ b/pyiron_atomistics/atomistics/structure/factories/aimsgb.py @@ -2,8 +2,10 @@ # Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department # Distributed under the terms of "New BSD License", see the LICENSE file. -from structuretoolkit.build import grainboundary, get_grainboundary_info -from pyiron_atomistics.atomistics.structure.atoms import ase_to_pyiron +from pyiron.atomistics.structure.atoms import pyiron_to_pymatgen, pymatgen_to_pyiron +from pymatgen.io.ase import AseAtomsAdaptor +from aimsgb import GBInformation, GrainBoundary, Grain + __author__ = "Ujjal Saikia" __copyright__ = ( @@ -19,75 +21,105 @@ class AimsgbFactory: @staticmethod - def info(axis, max_sigma): + def info(axis, + max_sigma=15, + specific=False, + table_view=False + ): """ - Provides a list of possible GB structures for a given rotational axis and upto the given maximum sigma value. - + A dictionary with information including possible sigma, CSL matrix, GB plane, + rotation angle and rotation matrix. Args: - axis : Rotational axis for the GB you want to construct (for example, axis=[1,0,0]) - max_sigma (int) : The maximum value of sigma upto which you want to consider for your - GB (for example, sigma=5) + axis ([u, v, w]): Rotation axis. + max_sigma (int): The largest sigma value. Dafult value is 15. + specific (bool): Whether collecting information for a specific sigma. + Dafult value is False. + table_view (bool): Display output in a tabuler format. Default value is True. Returns: - A list of possible GB structures in the format: + A aimsgb.GBInformation object or display a table depending on + the value of table_view parameter. - {sigma value: {'theta': [theta value], - 'plane': the GB planes") - 'rot_matrix': array([the rotational matrix]), - 'csl': [array([the csl matrix])]}} - - To construct the grain boundary select a GB plane and sigma value from the list and pass it to the - GBBuilder.gb_build() function along with the rotational axis and initial bulk structure. + To construct the grain boundary select a GB plane and sigma value from + the table and pass it to the GBBuilder.build() function along with + the rotational axis and initial bulk structure. """ - return get_grainboundary_info(axis=axis, max_sigma=max_sigma) + if table_view: + return print(GBInformation(axis, max_sigma, specific).__str__()) + else: + return GBInformation(axis, max_sigma, specific) @staticmethod - def build( - axis, - sigma, - plane, - initial_struct, - to_primitive=False, - delete_layer="0b0t0b0t", - add_if_dist=0.0, - uc_a=1, - uc_b=1, - ): + def build(axis, + sigma, + plane, + initial_struct, + uc_a=1, + uc_b=1, + vacuum=0.0, + gap=0.0, + delete_layer='0b0t0b0t', + tol=0.25, + to_primitive=False + ): """ - Generate a grain boundary structure based on the aimsgb.GrainBoundary module. + A grain boundary (GB) object. The initial structure can be cubic or non-cubic + crystal. If non-cubic, the crystal will be transferred to conventional cell. + The generated GB could be either tilted or twisted based on the given GB + plane. If the GB plane is parallel to the rotation axis, the generated GB + will be a twisted one. Otherwise, tilted. Build grain boundary based on + rotation axis, sigma, GB plane, grain size, initial_struct and vacuum thickness. + Build an interface structure by stacking two grains along a given direction. + The grain_b a- and b-vectors will be forced to be the grain_a's a- and b-vectors. Args: - axis : Rotational axis for the GB you want to construct (for example, axis=[1,0,0]) - sigma (int) : The sigma value of the GB you want to construct (for example, sigma=5) - plane: The grain boundary plane of the GB you want to construct (for example, plane=[2,1,0]) - initial_struct : Initial bulk structure from which you want to construct the GB (a pyiron - structure object). - delete_layer : To delete layers of the GB. For example, delete_layer='1b0t1b0t'. The first - 4 characters is for first grain and the other 4 is for second grain. b means - bottom layer and t means top layer. Integer represents the number of layers - to be deleted. The first t and second b from the left hand side represents - the layers at the GB interface. Default value is delete_layer='0b0t0b0t', which - means no deletion of layers. - add_if_dist : If you want to add extra interface distance, you can specify add_if_dist. - Default value is add_if_dist=0.0 - to_primitive : To generate primitive or non-primitive GB structure. Default value is - to_primitive=False + axis ([u, v, w]): Rotation axis. + sigma (int): The area ratio between the unit cell of CSL and the + given crystal lattice. + plane ([h, k, l]): Miller index of GB plane. If the GB plane is parallel + to the rotation axis, the generated GB will be a twist GB. If they + are perpendicular, the generated GB will be a tilt GB. + initial_struct (Grain): Initial input structure. Must be an object of + pyiron_atomistics.atomistics.structure.atoms.Atoms uc_a (int): Number of unit cell of grain A. Default to 1. uc_b (int): Number of unit cell of grain B. Default to 1. + vacuum (float): Vacuum space between the surface of the grains in Angstroms. Default to 0.0 + gap (float): Gap between the GB interface of the grains in Angstroms. Default to 0.0 + delete_layer (str): Delete top and bottom layers of the first and the second grains. + 8 characters in total. The first 4 characters is for the first grain and + the other 4 is for the second grain. "b" means bottom layer and "t" means + top layer. Integer represents the number of layers to be deleted. + Default to "0b0t0b0t", which means no deletion of layers. The + direction of top and bottom layers is based on the given direction. + tol (float): Tolerance factor in Angstrom to determnine if sites are + in the same layer. Default to 0.25. + to_primitive (bool): Whether to get primitive structure of GB. Default to False. + Returns: :class:`.Atoms`: final grain boundary structure """ - return ase_to_pyiron( - grainboundary( - axis=axis, - sigma=sigma, - plane=plane, - initial_struct=initial_struct, - to_primitive=to_primitive, - delete_layer=delete_layer, - add_if_dist=add_if_dist, - uc_a=uc_a, - uc_b=uc_b, - ) - ) + basis_pmg = AseAtomsAdaptor.get_structure(initial_struct) + + basis_pmg = Grain(lattice=basis_pmg.lattice, + species=basis_pmg.species, + coords=basis_pmg.frac_coords) + + gb = GrainBoundary(axis=axis, + sigma=sigma, + plane=plane, + initial_struct=basis_pmg, + uc_a=uc_a, + uc_b=uc_b) + + structure = Grain.stack_grains(grain_a=gb.grain_a, + grain_b=gb.grain_b, + vacuum=vacuum, + gap=gap, + direction=gb.direction, + delete_layer=delete_layer, + tol=tol, + to_primitive=to_primitive) + + return pymatgen_to_pyiron(structure) + From 6f79cc086df6f64ef92817f81ad6cfe6ccfd4552 Mon Sep 17 00:00:00 2001 From: usaikia Date: Sun, 6 Aug 2023 13:53:28 +0200 Subject: [PATCH 2/2] Changes suggested by Jan and Liam --- .../atomistics/structure/factories/aimsgb.py | 111 ++---------------- 1 file changed, 10 insertions(+), 101 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/factories/aimsgb.py b/pyiron_atomistics/atomistics/structure/factories/aimsgb.py index 32f508f8b..5ba616839 100644 --- a/pyiron_atomistics/atomistics/structure/factories/aimsgb.py +++ b/pyiron_atomistics/atomistics/structure/factories/aimsgb.py @@ -2,9 +2,9 @@ # Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department # Distributed under the terms of "New BSD License", see the LICENSE file. -from pyiron.atomistics.structure.atoms import pyiron_to_pymatgen, pymatgen_to_pyiron -from pymatgen.io.ase import AseAtomsAdaptor -from aimsgb import GBInformation, GrainBoundary, Grain +from pyiron_atomistics.atomistics.structure.atoms import ase_to_pyiron +from structuretoolkit.build import get_grainboundary_info, grainboundary +import functools __author__ = "Ujjal Saikia" @@ -21,105 +21,14 @@ class AimsgbFactory: @staticmethod - def info(axis, - max_sigma=15, - specific=False, - table_view=False - ): - """ - A dictionary with information including possible sigma, CSL matrix, GB plane, - rotation angle and rotation matrix. - Args: - axis ([u, v, w]): Rotation axis. - max_sigma (int): The largest sigma value. Dafult value is 15. - specific (bool): Whether collecting information for a specific sigma. - Dafult value is False. - table_view (bool): Display output in a tabuler format. Default value is True. - - Returns: - A aimsgb.GBInformation object or display a table depending on - the value of table_view parameter. - - To construct the grain boundary select a GB plane and sigma value from - the table and pass it to the GBBuilder.build() function along with - the rotational axis and initial bulk structure. - """ + @functools.wraps(get_grainboundary_info) + def info(*args, table_view=False, **kwargs): if table_view: - return print(GBInformation(axis, max_sigma, specific).__str__()) + print(get_grainboundary_info(*args, **kwargs).__str__()) else: - return GBInformation(axis, max_sigma, specific) + return get_grainboundary_info(*args, **kwargs) @staticmethod - def build(axis, - sigma, - plane, - initial_struct, - uc_a=1, - uc_b=1, - vacuum=0.0, - gap=0.0, - delete_layer='0b0t0b0t', - tol=0.25, - to_primitive=False - ): - """ - A grain boundary (GB) object. The initial structure can be cubic or non-cubic - crystal. If non-cubic, the crystal will be transferred to conventional cell. - The generated GB could be either tilted or twisted based on the given GB - plane. If the GB plane is parallel to the rotation axis, the generated GB - will be a twisted one. Otherwise, tilted. Build grain boundary based on - rotation axis, sigma, GB plane, grain size, initial_struct and vacuum thickness. - Build an interface structure by stacking two grains along a given direction. - The grain_b a- and b-vectors will be forced to be the grain_a's a- and b-vectors. - - Args: - axis ([u, v, w]): Rotation axis. - sigma (int): The area ratio between the unit cell of CSL and the - given crystal lattice. - plane ([h, k, l]): Miller index of GB plane. If the GB plane is parallel - to the rotation axis, the generated GB will be a twist GB. If they - are perpendicular, the generated GB will be a tilt GB. - initial_struct (Grain): Initial input structure. Must be an object of - pyiron_atomistics.atomistics.structure.atoms.Atoms - uc_a (int): Number of unit cell of grain A. Default to 1. - uc_b (int): Number of unit cell of grain B. Default to 1. - vacuum (float): Vacuum space between the surface of the grains in Angstroms. Default to 0.0 - gap (float): Gap between the GB interface of the grains in Angstroms. Default to 0.0 - delete_layer (str): Delete top and bottom layers of the first and the second grains. - 8 characters in total. The first 4 characters is for the first grain and - the other 4 is for the second grain. "b" means bottom layer and "t" means - top layer. Integer represents the number of layers to be deleted. - Default to "0b0t0b0t", which means no deletion of layers. The - direction of top and bottom layers is based on the given direction. - tol (float): Tolerance factor in Angstrom to determnine if sites are - in the same layer. Default to 0.25. - to_primitive (bool): Whether to get primitive structure of GB. Default to False. - - - Returns: - :class:`.Atoms`: final grain boundary structure - """ - basis_pmg = AseAtomsAdaptor.get_structure(initial_struct) - - basis_pmg = Grain(lattice=basis_pmg.lattice, - species=basis_pmg.species, - coords=basis_pmg.frac_coords) - - gb = GrainBoundary(axis=axis, - sigma=sigma, - plane=plane, - initial_struct=basis_pmg, - uc_a=uc_a, - uc_b=uc_b) - - structure = Grain.stack_grains(grain_a=gb.grain_a, - grain_b=gb.grain_b, - vacuum=vacuum, - gap=gap, - direction=gb.direction, - delete_layer=delete_layer, - tol=tol, - to_primitive=to_primitive) - - return pymatgen_to_pyiron(structure) - + @functools.wraps(grainboundary) + def build(*args, **kwargs): + return ase_to_pyiron(grainboundary(*args, **kwargs))