diff --git a/src/py/mat3ra/made/tools/build/defect/configuration.py b/src/py/mat3ra/made/tools/build/defect/configuration.py index b9bcafdf..c54acec8 100644 --- a/src/py/mat3ra/made/tools/build/defect/configuration.py +++ b/src/py/mat3ra/made/tools/build/defect/configuration.py @@ -36,15 +36,49 @@ class PointDefectConfiguration(BaseDefectConfiguration, InMemoryEntity): Args: crystal (Material): The Material object. defect_type (PointDefectTypeEnum): The type of the defect. - coordinate (List[float]): The crystal coordinate of the defect. + coordinate (Optional[List[float]]): The crystal coordinate of the defect. + approximate_coordinate (Optional[List[float]]): Approximate coordinate for the defect. Ignored, if coordinate is provided. + site_id (Optional[int]): The site ID for the defect in the crystal. Ignored, if coordinate is provided. chemical_element (Optional[str]): The chemical element. """ defect_type: PointDefectTypeEnum - coordinate: List[float] = [0, 0, 0] + coordinate: Optional[List[float]] = None + approximate_coordinate: Optional[List[float]] = None + site_id: Optional[int] = None chemical_element: Optional[str] = None use_cartesian_coordinates: bool = False + def __init__( + self, + crystal: Material, + defect_type: PointDefectTypeEnum, + coordinate: Optional[List[float]] = None, + site_id: Optional[int] = None, + approximate_coordinate: Optional[List[float]] = None, + chemical_element: Optional[str] = None, + use_cartesian_coordinates: bool = False, + ): + if coordinate is not None: + self.crystal = crystal + self.defect_type = defect_type + self.coordinate = coordinate + self.chemical_element = chemical_element + elif site_id is not None: + self.from_site_id( + crystal=crystal, defect_type=defect_type, site_id=site_id, chemical_element=chemical_element + ) + elif approximate_coordinate is not None: + self.from_approximate_coordinate( + crystal=crystal, + defect_type=defect_type, + approximate_coordinate=approximate_coordinate, + chemical_element=chemical_element, + use_cartesian_coordinates=use_cartesian_coordinates, + ) + else: + raise ValueError("At least one of site_id, coordinate, or approximate_coordinate must be provided.") + @classmethod def from_site_id( cls, crystal: Material, defect_type: PointDefectTypeEnum, site_id: int, chemical_element: Optional[str] = None @@ -52,7 +86,13 @@ def from_site_id( if not crystal: raise RuntimeError("Crystal is not defined") coordinate = crystal.coordinates_array[site_id] - return cls(crystal=crystal, defect_type=defect_type, coordinate=coordinate, chemical_element=chemical_element) + return cls( + crystal=crystal, + defect_type=defect_type, + site_id=site_id, + coordinate=coordinate, + chemical_element=chemical_element, + ) @classmethod def from_approximate_coordinate( @@ -74,18 +114,6 @@ def from_approximate_coordinate( crystal=crystal, defect_type=defect_type, site_id=closest_site_id, chemical_element=chemical_element ) - @classmethod - def from_dict(cls, crystal: Material, data: dict): - if "site_id" in data: - config = PointDefectConfiguration.from_site_id(crystal=crystal, **data) - elif "coordinate" in data: - config = PointDefectConfiguration(crystal=crystal, **data) - elif "approximate_coordinate" in data: - config = PointDefectConfiguration.from_approximate_coordinate(crystal=crystal, **data) - else: - raise ValueError(f"Invalid defect configuration: {data}") - return config - @property def _json(self): return { diff --git a/tests/py/unit/test_tools_build_defect.py b/tests/py/unit/test_tools_build_defect.py index d9ebda83..52f3cfee 100644 --- a/tests/py/unit/test_tools_build_defect.py +++ b/tests/py/unit/test_tools_build_defect.py @@ -48,7 +48,7 @@ def test_create_substitution(): def test_create_interstitial(): # Interstitial Ge at 0.5, 0.5, 0.5 position configuration = PointDefectConfiguration( - crystal=clean_material, defect_type="interstitial", chemical_element="Ge", position=[0.5, 0.5, 0.5] + crystal=clean_material, defect_type="interstitial", chemical_element="Ge", coordinate=[0.5, 0.5, 0.5] ) defect = create_defect(configuration)