From a6e62c4e561002536689ae7697a887318ceea8e9 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:24:58 -0700 Subject: [PATCH 1/9] update: add vacuum to slab defect gen --- src/py/mat3ra/made/tools/build/defect/builders.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index 0ab99396..d66646dc 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -137,6 +137,7 @@ def merge_slab_and_defect(self, material: Material, isolated_defect: Material) - material_name=material.name, merge_dangerously=True, ) + new_material = add_vacuum(new_material, self.build_parameters.vacuum_thickness) return new_material From 02394380312f7c3f97506169e3f15a11392b0cf7 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Mon, 21 Oct 2024 20:07:05 -0700 Subject: [PATCH 2/9] update: add fractional layers support to slab defects --- .../made/tools/build/defect/builders.py | 96 ++++++++++++++++++- .../made/tools/build/defect/configuration.py | 4 +- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index d66646dc..6fb41abc 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -115,18 +115,104 @@ class SlabDefectBuilder(DefectBuilder): _BuildParametersType = SlabDefectBuilderParameters _DefaultBuildParameters = SlabDefectBuilderParameters() - def create_material_with_additional_layers(self, material: Material, added_thickness: int = 1) -> Material: + def create_material_with_additional_layers( + self, material: Material, added_thickness: Union[int, float] = 1 + ) -> Material: + """ + Adds a number of layers to the material. + + Args: + material: The original material. + added_thickness: The thickness to add. + + Returns: + A new Material instance with the added layers. + """ + if isinstance(added_thickness, int): + return self.create_material_with_additional_layers_int(material, added_thickness) + elif isinstance(added_thickness, float): + return self.create_material_with_additional_layers_float(material, added_thickness) + else: + raise TypeError("added_thickness must be an integer or float for this method.") + + def create_material_with_additional_layers_int(self, material: Material, added_thickness: int = 1) -> Material: + """ + Adds an integer number of layers to the material. + + Args: + material: The original material. + added_thickness: The number of whole layers to add. + + Returns: + A new Material instance with the added layers. + """ + if not isinstance(added_thickness, int): + raise TypeError("added_thickness must be an integer for this method.") + new_material = material.clone() termination = Termination.from_string(new_material.metadata.get("build").get("termination")) - build_config = new_material.metadata.get("build").get("configuration") + build_config = new_material.metadata.get("build").get("configuration").copy() + if build_config["type"] != "SlabConfiguration": raise ValueError("Material is not a slab.") build_config.pop("type") - build_config["thickness"] = build_config["thickness"] + added_thickness + build_config["thickness"] += added_thickness + new_slab_config = SlabConfiguration(**build_config) - material_with_additional_layer = create_slab(new_slab_config, termination) + material_with_additional_layers = create_slab(new_slab_config, termination) + + return material_with_additional_layers + + def create_material_with_additional_layers_float( + self, material: Material, added_thickness: float = 1.0 + ) -> Material: + """ + Adds a fractional number of layers to the material. - return material_with_additional_layer + Args: + material: The original material. + added_thickness: The fractional thickness to add. + + Returns: + A new Material instance with the fractional layer added. + """ + if not isinstance(added_thickness, float): + raise TypeError("added_thickness must be a float for this method.") + + whole_layers = int(added_thickness) + fractional_part = added_thickness - whole_layers + + if whole_layers > 0: + material_with_additional_layers = self.create_material_with_additional_layers_int(material, whole_layers) + else: + material_with_additional_layers = material.clone() + + if fractional_part > 0.0: + material_with_additional_layers = self.create_material_with_additional_layers_int( + material_with_additional_layers, 1 + ) + + original_c = material.lattice.c + new_c = material_with_additional_layers.lattice.c + added_layers = whole_layers + 1 + layer_height = (new_c - original_c) / added_layers + + added_fractional_thickness = fractional_part * layer_height + + original_max_z = get_atomic_coordinates_extremum(material, "max", "z", use_cartesian_coordinates=True) + added_layers_min_z = original_max_z + whole_layers * layer_height + added_layers_max_z = added_layers_min_z + added_fractional_thickness + + added_layers_max_z_crystal = material_with_additional_layers.basis.cell.convert_point_to_crystal( + [0, 0, added_layers_max_z] + )[2] + + material_with_additional_layers = filter_by_box( + material=material_with_additional_layers, + min_coordinate=[0, 0, added_layers_min_z], + max_coordinate=[1, 1, added_layers_max_z_crystal], + ) + return material_with_additional_layers def merge_slab_and_defect(self, material: Material, isolated_defect: Material) -> Material: new_vacuum = isolated_defect.lattice.c - material.lattice.c diff --git a/src/py/mat3ra/made/tools/build/defect/configuration.py b/src/py/mat3ra/made/tools/build/defect/configuration.py index 33d62081..13c035b4 100644 --- a/src/py/mat3ra/made/tools/build/defect/configuration.py +++ b/src/py/mat3ra/made/tools/build/defect/configuration.py @@ -109,10 +109,10 @@ class SlabDefectConfiguration(BaseDefectConfiguration, InMemoryEntity): Args: crystal (Material): The Material object. - number_of_added_layers (int): The number of added layers. + number_of_added_layers (Union[int, float]): The number of added layers to the slab. """ - number_of_added_layers: int = 1 + number_of_added_layers: Union[int, float] = 1 @property def _json(self): From 0fa6b7dc8a99088b72c5b06608d521d7ee5b6cd9 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Mon, 21 Oct 2024 20:08:55 -0700 Subject: [PATCH 3/9] update: fix a mistake --- .../made/tools/build/defect/builders.py | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index 6fb41abc..1dd44ee1 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -187,31 +187,31 @@ def create_material_with_additional_layers_float( else: material_with_additional_layers = material.clone() - if fractional_part > 0.0: - material_with_additional_layers = self.create_material_with_additional_layers_int( - material_with_additional_layers, 1 - ) - - original_c = material.lattice.c - new_c = material_with_additional_layers.lattice.c - added_layers = whole_layers + 1 - layer_height = (new_c - original_c) / added_layers - - added_fractional_thickness = fractional_part * layer_height - - original_max_z = get_atomic_coordinates_extremum(material, "max", "z", use_cartesian_coordinates=True) - added_layers_min_z = original_max_z + whole_layers * layer_height - added_layers_max_z = added_layers_min_z + added_fractional_thickness - - added_layers_max_z_crystal = material_with_additional_layers.basis.cell.convert_point_to_crystal( - [0, 0, added_layers_max_z] - )[2] - - material_with_additional_layers = filter_by_box( - material=material_with_additional_layers, - min_coordinate=[0, 0, added_layers_min_z], - max_coordinate=[1, 1, added_layers_max_z_crystal], - ) + if fractional_part > 0.0: + material_with_additional_layers = self.create_material_with_additional_layers_int( + material_with_additional_layers, 1 + ) + + original_c = material.lattice.c + new_c = material_with_additional_layers.lattice.c + added_layers = whole_layers + 1 + layer_height = (new_c - original_c) / added_layers + + added_fractional_thickness = fractional_part * layer_height + + original_max_z = get_atomic_coordinates_extremum(material, "max", "z", use_cartesian_coordinates=True) + added_layers_min_z = original_max_z + whole_layers * layer_height + added_layers_max_z = added_layers_min_z + added_fractional_thickness + + added_layers_max_z_crystal = material_with_additional_layers.basis.cell.convert_point_to_crystal( + [0, 0, added_layers_max_z] + )[2] + + material_with_additional_layers = filter_by_box( + material=material_with_additional_layers, + min_coordinate=[0, 0, added_layers_min_z], + max_coordinate=[1, 1, added_layers_max_z_crystal], + ) return material_with_additional_layers def merge_slab_and_defect(self, material: Material, isolated_defect: Material) -> Material: From d0d4655c9440a445828926aefef6ac6c962d493c Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Mon, 21 Oct 2024 20:54:51 -0700 Subject: [PATCH 4/9] chore: shorten function --- .../mat3ra/made/tools/build/defect/builders.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index 1dd44ee1..ad04182e 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -146,8 +146,6 @@ def create_material_with_additional_layers_int(self, material: Material, added_t Returns: A new Material instance with the added layers. """ - if not isinstance(added_thickness, int): - raise TypeError("added_thickness must be an integer for this method.") new_material = material.clone() termination = Termination.from_string(new_material.metadata.get("build").get("termination")) @@ -176,9 +174,6 @@ def create_material_with_additional_layers_float( Returns: A new Material instance with the fractional layer added. """ - if not isinstance(added_thickness, float): - raise TypeError("added_thickness must be a float for this method.") - whole_layers = int(added_thickness) fractional_part = added_thickness - whole_layers @@ -191,25 +186,16 @@ def create_material_with_additional_layers_float( material_with_additional_layers = self.create_material_with_additional_layers_int( material_with_additional_layers, 1 ) - - original_c = material.lattice.c new_c = material_with_additional_layers.lattice.c - added_layers = whole_layers + 1 - layer_height = (new_c - original_c) / added_layers - - added_fractional_thickness = fractional_part * layer_height - + layer_height = (new_c - material.lattice.c) / (whole_layers + 1) original_max_z = get_atomic_coordinates_extremum(material, "max", "z", use_cartesian_coordinates=True) - added_layers_min_z = original_max_z + whole_layers * layer_height - added_layers_max_z = added_layers_min_z + added_fractional_thickness - + added_layers_max_z = original_max_z + added_thickness * layer_height added_layers_max_z_crystal = material_with_additional_layers.basis.cell.convert_point_to_crystal( [0, 0, added_layers_max_z] )[2] material_with_additional_layers = filter_by_box( material=material_with_additional_layers, - min_coordinate=[0, 0, added_layers_min_z], max_coordinate=[1, 1, added_layers_max_z_crystal], ) return material_with_additional_layers From 2554ce8fe0b560a82fa1447cdd1d3a56eeefdd5a Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:07:46 -0700 Subject: [PATCH 5/9] chore: revert some lines --- src/py/mat3ra/made/tools/build/defect/builders.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index ad04182e..d430724c 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -149,12 +149,12 @@ def create_material_with_additional_layers_int(self, material: Material, added_t new_material = material.clone() termination = Termination.from_string(new_material.metadata.get("build").get("termination")) - build_config = new_material.metadata.get("build").get("configuration").copy() + build_config = new_material.metadata.get("build").get("configuration") if build_config["type"] != "SlabConfiguration": raise ValueError("Material is not a slab.") build_config.pop("type") - build_config["thickness"] += added_thickness + build_config["thickness"] = build_config["thickness"] + added_thickness new_slab_config = SlabConfiguration(**build_config) material_with_additional_layers = create_slab(new_slab_config, termination) From f54b37c1bc763006d7edc91bbf4040de925c90d4 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:30:55 -0700 Subject: [PATCH 6/9] update: add from dict to allow for condtons --- .../made/tools/build/defect/configuration.py | 48 +++++++++++++++++-- .../mat3ra/made/tools/build/defect/enums.py | 6 +++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/configuration.py b/src/py/mat3ra/made/tools/build/defect/configuration.py index 13c035b4..609caf84 100644 --- a/src/py/mat3ra/made/tools/build/defect/configuration.py +++ b/src/py/mat3ra/made/tools/build/defect/configuration.py @@ -1,4 +1,4 @@ -from typing import Optional, List, Union +from typing import Optional, List, Union, Generic, TypeVar from pydantic import BaseModel from mat3ra.code.entity import InMemoryEntity @@ -10,9 +10,10 @@ SphereCoordinateCondition, BoxCoordinateCondition, TriangularPrismCoordinateCondition, - PlaneCoordinateCondition, + PlaneCoordinateCondition, CoordinateCondition, ) -from .enums import PointDefectTypeEnum, SlabDefectTypeEnum, AtomPlacementMethodEnum, ComplexDefectTypeEnum +from .enums import PointDefectTypeEnum, SlabDefectTypeEnum, AtomPlacementMethodEnum, ComplexDefectTypeEnum, \ + CoordinatesShapeEnum class BaseDefectConfiguration(BaseModel): @@ -188,6 +189,9 @@ def _json(self): } +CoordinateConditionType = TypeVar('CoordinateConditionType', bound=CoordinateCondition) + + class IslandSlabDefectConfiguration(SlabDefectConfiguration): """ Configuration for an island slab defect. @@ -207,8 +211,46 @@ class IslandSlabDefectConfiguration(SlabDefectConfiguration): BoxCoordinateCondition, TriangularPrismCoordinateCondition, PlaneCoordinateCondition, + CoordinateConditionType ] = CylinderCoordinateCondition() + @classmethod + def from_dict(cls, crystal: Material, data: dict): + if "condition" in data: + condition = cls.get_coordinate_condition(data["condition"]["shape"], data["condition"]["params"]) + return cls(crystal=crystal, condition=condition, **data) + else: + return cls(crystal=crystal, **data) + + def get_coordinate_condition(self, shape: CoordinatesShapeEnum, dict_params: dict): + if shape == CoordinatesShapeEnum.CYLINDER: + return CylinderCoordinateCondition( + center_position=dict_params['center_position'], + radius=dict_params['radius'], + min_z=dict_params['min_z'], + max_z=dict_params['max_z'] + ) + elif shape == 'sphere': + return SphereCoordinateCondition( + center_position=dict_params['center_position'], + radius=dict_params['radius'] + ) + elif shape == 'box': + return BoxCoordinateCondition( + min_coordinates=dict_params['min_coordinates'], + max_coordinates=dict_params['max_coordinates'] + ) + elif shape == 'triangular_prism': + return TriangularPrismCoordinateCondition( + position_on_surface_1=dict_params['position_on_surface_1'], + position_on_surface_2=dict_params['position_on_surface_2'], + position_on_surface_3=dict_params['position_on_surface_3'], + min_z=dict_params['min_z'], + max_z=dict_params['max_z'] + ) + else: + raise ValueError(f"Unsupported island shape: {shape}") + @property def _json(self): return { diff --git a/src/py/mat3ra/made/tools/build/defect/enums.py b/src/py/mat3ra/made/tools/build/defect/enums.py index a169ad69..0b28080f 100644 --- a/src/py/mat3ra/made/tools/build/defect/enums.py +++ b/src/py/mat3ra/made/tools/build/defect/enums.py @@ -26,3 +26,9 @@ class AtomPlacementMethodEnum(str, Enum): EQUIDISTANT = "equidistant" # Places the atom at the existing or extrapolated crystal site closest to the given coordinate. CRYSTAL_SITE = "crystal_site" + +class CoordinatesShapeEnum(str, Enum): + SPHERE = "sphere" + CYLINDER = "cylinder" + BOX = "rectangle" + TRIANGULAR_PRISM = "triangular_prism" From 6a9eeb56c43b307cd65057421033aba597ed1327 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:02:39 -0700 Subject: [PATCH 7/9] update: fix signatures and types --- .../made/tools/build/defect/configuration.py | 82 ++++++++++++------- .../mat3ra/made/tools/build/defect/enums.py | 1 + 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/configuration.py b/src/py/mat3ra/made/tools/build/defect/configuration.py index 609caf84..7eda27cd 100644 --- a/src/py/mat3ra/made/tools/build/defect/configuration.py +++ b/src/py/mat3ra/made/tools/build/defect/configuration.py @@ -10,10 +10,16 @@ SphereCoordinateCondition, BoxCoordinateCondition, TriangularPrismCoordinateCondition, - PlaneCoordinateCondition, CoordinateCondition, + PlaneCoordinateCondition, + CoordinateCondition, +) +from .enums import ( + PointDefectTypeEnum, + SlabDefectTypeEnum, + AtomPlacementMethodEnum, + ComplexDefectTypeEnum, + CoordinatesShapeEnum, ) -from .enums import PointDefectTypeEnum, SlabDefectTypeEnum, AtomPlacementMethodEnum, ComplexDefectTypeEnum, \ - CoordinatesShapeEnum class BaseDefectConfiguration(BaseModel): @@ -189,10 +195,10 @@ def _json(self): } -CoordinateConditionType = TypeVar('CoordinateConditionType', bound=CoordinateCondition) +CoordinateConditionType = TypeVar("CoordinateConditionType", bound=CoordinateCondition) -class IslandSlabDefectConfiguration(SlabDefectConfiguration): +class IslandSlabDefectConfiguration(SlabDefectConfiguration, Generic[CoordinateConditionType]): """ Configuration for an island slab defect. @@ -211,42 +217,56 @@ class IslandSlabDefectConfiguration(SlabDefectConfiguration): BoxCoordinateCondition, TriangularPrismCoordinateCondition, PlaneCoordinateCondition, - CoordinateConditionType + CoordinateConditionType, ] = CylinderCoordinateCondition() @classmethod - def from_dict(cls, crystal: Material, data: dict): - if "condition" in data: - condition = cls.get_coordinate_condition(data["condition"]["shape"], data["condition"]["params"]) - return cls(crystal=crystal, condition=condition, **data) - else: - return cls(crystal=crystal, **data) - - def get_coordinate_condition(self, shape: CoordinatesShapeEnum, dict_params: dict): - if shape == CoordinatesShapeEnum.CYLINDER: + def from_dict(cls, crystal: Material, condition: dict, **kwargs): + """ + Creates an IslandSlabDefectConfiguration instance from a dictionary. + + Args: + crystal (Material): The material object. + condition (dict): The dictionary with shape and other parameters for the condition. + kwargs: Other configuration parameters (like number_of_added_layers). + """ + condition_obj = cls.get_coordinate_condition(shape=condition["shape"], dict_params=condition) + return cls(crystal=crystal, condition=condition_obj, **kwargs) + + @staticmethod + def get_coordinate_condition(shape: CoordinatesShapeEnum, dict_params: dict): + """ + Returns the appropriate coordinate condition based on the shape provided. + + Args: + shape (CoordinatesShapeEnum): Shape of the island (e.g., cylinder, box, etc.). + dict_params (dict): Parameters for the shape condition. + + Returns: + CoordinateCondition: The appropriate condition object. + """ + if shape == "cylinder": return CylinderCoordinateCondition( - center_position=dict_params['center_position'], - radius=dict_params['radius'], - min_z=dict_params['min_z'], - max_z=dict_params['max_z'] + center_position=dict_params.get("center_position", [0.5, 0.5]), + radius=dict_params["radius"], + min_z=dict_params["min_z"], + max_z=dict_params["max_z"], ) - elif shape == 'sphere': + elif shape == "sphere": return SphereCoordinateCondition( - center_position=dict_params['center_position'], - radius=dict_params['radius'] + center_position=dict_params.get("center_position", [0.5, 0.5]), radius=dict_params["radius"] ) - elif shape == 'box': + elif shape == "box": return BoxCoordinateCondition( - min_coordinates=dict_params['min_coordinates'], - max_coordinates=dict_params['max_coordinates'] + min_coordinate=dict_params["min_coordinate"], max_coordinate=dict_params["max_coordinate"] ) - elif shape == 'triangular_prism': + elif shape == "triangular_prism": return TriangularPrismCoordinateCondition( - position_on_surface_1=dict_params['position_on_surface_1'], - position_on_surface_2=dict_params['position_on_surface_2'], - position_on_surface_3=dict_params['position_on_surface_3'], - min_z=dict_params['min_z'], - max_z=dict_params['max_z'] + position_on_surface_1=dict_params["position_on_surface_1"], + position_on_surface_2=dict_params["position_on_surface_2"], + position_on_surface_3=dict_params["position_on_surface_3"], + min_z=dict_params["min_z"], + max_z=dict_params["max_z"], ) else: raise ValueError(f"Unsupported island shape: {shape}") diff --git a/src/py/mat3ra/made/tools/build/defect/enums.py b/src/py/mat3ra/made/tools/build/defect/enums.py index 0b28080f..bdc22279 100644 --- a/src/py/mat3ra/made/tools/build/defect/enums.py +++ b/src/py/mat3ra/made/tools/build/defect/enums.py @@ -27,6 +27,7 @@ class AtomPlacementMethodEnum(str, Enum): # Places the atom at the existing or extrapolated crystal site closest to the given coordinate. CRYSTAL_SITE = "crystal_site" + class CoordinatesShapeEnum(str, Enum): SPHERE = "sphere" CYLINDER = "cylinder" From dff5a05517dcb9f0485349fa4d7e197f22202e24 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Wed, 23 Oct 2024 18:58:16 -0700 Subject: [PATCH 8/9] update: move fractional layer logic to a function --- .../made/tools/build/defect/builders.py | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index d430724c..07a735a1 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -183,21 +183,42 @@ def create_material_with_additional_layers_float( material_with_additional_layers = material.clone() if fractional_part > 0.0: - material_with_additional_layers = self.create_material_with_additional_layers_int( - material_with_additional_layers, 1 - ) - new_c = material_with_additional_layers.lattice.c - layer_height = (new_c - material.lattice.c) / (whole_layers + 1) - original_max_z = get_atomic_coordinates_extremum(material, "max", "z", use_cartesian_coordinates=True) - added_layers_max_z = original_max_z + added_thickness * layer_height - added_layers_max_z_crystal = material_with_additional_layers.basis.cell.convert_point_to_crystal( - [0, 0, added_layers_max_z] - )[2] - - material_with_additional_layers = filter_by_box( - material=material_with_additional_layers, - max_coordinate=[1, 1, added_layers_max_z_crystal], + material_with_additional_layers = self.add_fractional_layer( + material_with_additional_layers, whole_layers, fractional_part ) + + return material_with_additional_layers + + def add_fractional_layer( + self, + material: Material, + whole_layers: int, + fractional_thickness: float, + ) -> Material: + """ + Adds a fractional layer to the material. + + Args: + material: The original material. + fractional_thickness: The fractional thickness to add. + + Returns: + A new Material instance with the fractional layer added. + """ + material_with_additional_layers = self.create_material_with_additional_layers_int(material, 1) + new_c = material_with_additional_layers.lattice.c + layer_height = (new_c - material.lattice.c) / (whole_layers + 1) + original_max_z = get_atomic_coordinates_extremum(material, "max", "z", use_cartesian_coordinates=True) + added_layers_max_z = original_max_z + (whole_layers + fractional_thickness) * layer_height + added_layers_max_z_crystal = material_with_additional_layers.basis.cell.convert_point_to_crystal( + [0, 0, added_layers_max_z] + )[2] + + material_with_additional_layers = filter_by_box( + material=material_with_additional_layers, + max_coordinate=[1, 1, added_layers_max_z_crystal], + ) + return material_with_additional_layers def merge_slab_and_defect(self, material: Material, isolated_defect: Material) -> Material: @@ -209,8 +230,9 @@ def merge_slab_and_defect(self, material: Material, isolated_defect: Material) - material_name=material.name, merge_dangerously=True, ) - new_material = add_vacuum(new_material, self.build_parameters.vacuum_thickness) - return new_material + new_material.to_crystal() + new_material_with_vacuum = add_vacuum(new_material, self.build_parameters.vacuum_thickness) + return new_material_with_vacuum class AdatomSlabDefectBuilder(SlabDefectBuilder): From 9853b80c2a7e841d06c64ed55c520e684607ed97 Mon Sep 17 00:00:00 2001 From: VsevolodX <79542055+VsevolodX@users.noreply.github.com> Date: Wed, 23 Oct 2024 19:04:44 -0700 Subject: [PATCH 9/9] update: add vacuum when needed only --- src/py/mat3ra/made/tools/build/defect/builders.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/py/mat3ra/made/tools/build/defect/builders.py b/src/py/mat3ra/made/tools/build/defect/builders.py index 07a735a1..95f7f9a5 100644 --- a/src/py/mat3ra/made/tools/build/defect/builders.py +++ b/src/py/mat3ra/made/tools/build/defect/builders.py @@ -231,8 +231,9 @@ def merge_slab_and_defect(self, material: Material, isolated_defect: Material) - merge_dangerously=True, ) new_material.to_crystal() - new_material_with_vacuum = add_vacuum(new_material, self.build_parameters.vacuum_thickness) - return new_material_with_vacuum + if self.build_parameters.auto_add_vacuum and get_atomic_coordinates_extremum(new_material, "max", "z") > 1: + new_material = add_vacuum(new_material, self.build_parameters.vacuum_thickness) + return new_material class AdatomSlabDefectBuilder(SlabDefectBuilder):