Skip to content

Commit

Permalink
Merge pull request #171 from Exabyte-io/feature/SOF-7456
Browse files Browse the repository at this point in the history
Feature/SOF-7456 adjustments for Twisted Interface Builder
  • Loading branch information
VsevolodX authored Nov 6, 2024
2 parents bdc76a7 + 75ac321 commit 2987cdd
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 13 deletions.
67 changes: 54 additions & 13 deletions src/py/mat3ra/made/tools/build/interface/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
rotate,
translate_by_vector,
add_vacuum_sides,
add_vacuum,
)
from ...analyze import get_chemical_formula
from ...convert import to_ase, from_ase, to_pymatgen, PymatgenInterface, ASEAtoms
Expand All @@ -28,7 +29,7 @@
ConvertGeneratedItemsPymatgenStructureMixin,
)

from .enums import StrainModes
from .enums import StrainModes, angle_to_supercell_matrix_values_for_hex
from .configuration import (
InterfaceConfiguration,
NanoRibbonTwistedInterfaceConfiguration,
Expand Down Expand Up @@ -243,7 +244,7 @@ def _generate(self, configuration: _ConfigurationType) -> List[Material]:
def _update_material_name(
self, material: Material, configuration: NanoRibbonTwistedInterfaceConfiguration
) -> Material:
material.name = f"Twisted Nanoribbon Interface ({configuration.twist_angle:.2f}°)"
material.name = f"Twisted Nanoribbon Interface ({configuration.twist_angle:.2f} degrees)"
return material


Expand All @@ -252,13 +253,16 @@ class CommensurateLatticeTwistedInterfaceBuilderParameters(BaseModel):
Parameters for the commensurate lattice interface builder.
Args:
max_repetition_int (int): The maximum search range for commensurate lattices.
max_supercell_matrix_int (Optional[int]): The maximum integer for the transformation matrices.
If not provided, it will be determined based on the target angle and the lattice vectors automatically.
limit_max_int (Optional[int]): The limit for the maximum integer for the transformation matrices when searching
angle_tolerance (float): The tolerance for the angle between the commensurate lattices
and the target angle, in degrees.
return_first_match (bool): Whether to return the first match or all matches.
"""

max_repetition_int: int = 10
max_supercell_matrix_int: Optional[int] = None
limit_max_int: Optional[int] = 42
angle_tolerance: float = 0.1
return_first_match: bool = False

Expand All @@ -270,36 +274,65 @@ class CommensurateLatticeTwistedInterfaceBuilder(BaseBuilder):
def _generate(self, configuration: _ConfigurationType) -> List[_GeneratedItemType]:
film = configuration.film
# substrate = configuration.substrate
max_search = self.build_parameters.max_repetition_int
a = film.lattice.vector_arrays[0][:2]
b = film.lattice.vector_arrays[1][:2]
commensurate_lattice_pairs = self.__generate_commensurate_lattices(
configuration, a, b, max_search, configuration.twist_angle
max_int = self.build_parameters.max_supercell_matrix_int or self.__get_initial_guess_for_max_int(
film, configuration.twist_angle
)
commensurate_lattice_pairs: List[CommensurateLatticePair] = []
while not commensurate_lattice_pairs and max_int < self.build_parameters.limit_max_int:
print(f"Trying max_int = {max_int}")
commensurate_lattice_pairs = self.__generate_commensurate_lattices(
configuration, a, b, max_int, configuration.twist_angle
)
max_int += 1

return commensurate_lattice_pairs

def __get_initial_guess_for_max_int(self, film, target_angle: float) -> int:
"""
Determine the maximum integer for the transformation matrices based on the target angle.
Args:
a (List[float]): The a lattice vector.
b (List[float]): The b lattice vector.
target_angle (float): The target twist angle, in degrees.
Returns:
int: The maximum integer for the transformation matrices.
"""
if film.lattice.type == "HEX":
# getting max int of the matrix that has angle closest to target angle
xy_supercell_matrix_for_closest_angle = min(
angle_to_supercell_matrix_values_for_hex, key=lambda x: abs(x["angle"] - target_angle)
)
# Get maximum absolute value from the supercell matrix values
return max(abs(x) for row in xy_supercell_matrix_for_closest_angle["xy_supercell"] for x in row)
return 1

def __generate_commensurate_lattices(
self,
configuration: TwistedInterfaceConfiguration,
a: List[float],
b: List[float],
max_search: int = 10,
max_supercell_matrix_element_int: int,
target_angle: float = 0.0,
) -> List[CommensurateLatticePair]:
"""
Generate all commensurate lattices for a given search range and filter by closeness to target angle.
Generate all commensurate lattices for a given target angle and filter by closeness to target angle.
Args:
configuration (TwistedInterfaceConfiguration): The configuration for the twisted interface.
a (List[float]): The a lattice vector.
b (List[float]): The b lattice vector.
max_search (int): The maximum search range.
target_angle (float): The target angle, in degrees.
max_supercell_matrix_element_int (int): The maximum integer for the transformation matrices.
target_angle (float): The target twist angle, in degrees.
Returns:
List[CommensurateLatticePair]: The list of commensurate lattice pairs
"""
matrices = create_2d_supercell_matrices(max_search)
# Generate the supercell matrices using the calculated max_supercell_matrix_element_int
matrices = create_2d_supercell_matrices(max_supercell_matrix_element_int)
matrix_ab = np.array([a, b])
matrix_ab_inverse = np.linalg.inv(matrix_ab)

Expand Down Expand Up @@ -342,8 +375,10 @@ def _post_process(
new_film = translate_by_vector(
new_film, [0, 0, item.configuration.distance_z], use_cartesian_coordinates=True
)
interface = merge_materials([new_substrate, new_film])
interface = merge_materials([new_substrate, new_film], merge_dangerously=True)
interface.metadata["actual_twist_angle"] = item.angle
if item.configuration.vacuum != 0:
interface = add_vacuum(interface, item.configuration.vacuum)
interfaces.append(interface)
return interfaces

Expand All @@ -354,3 +389,9 @@ def _update_material_metadata(self, material, configuration) -> Material:
"actual_twist_angle"
]
return updated_material

def _update_material_name(
self, material: Material, configuration: NanoRibbonTwistedInterfaceConfiguration
) -> Material:
material.name = f"Twisted Bilayer Interface ({material.metadata['actual_twist_angle']:.2f} degrees)"
return material
1 change: 1 addition & 0 deletions src/py/mat3ra/made/tools/build/interface/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class TwistedInterfaceConfiguration(BaseConfiguration):
substrate: Optional[Material] = None
twist_angle: float = 0.0
distance_z: float = 3.0
vacuum: float = 0.0

@property
def _json(self):
Expand Down
54 changes: 54 additions & 0 deletions src/py/mat3ra/made/tools/build/interface/enums.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from enum import Enum
from typing import TypedDict, List


class StrainModes(str, Enum):
Expand All @@ -10,3 +11,56 @@ class StrainModes(str, Enum):
class SupercellTypes(str, Enum):
hexagonal = "hexagonal"
orthogonal = "orthogonal"


class SupercellMatrix(TypedDict):
angle: float
xy_supercell: List[List[int]]


# Tabulation from https://github.com/qtm-iisc/Twister/blob/474156a2a59f2b9d59350b32de56864a9496f848/examples/Homobilayer_hex/hex.table
# Maps twist angle to supercell matrix values for homo-material hexagonal supercells bilayer
angle_to_supercell_matrix_values_for_hex: List[SupercellMatrix] = [
{"angle": 60.0, "xy_supercell": [[0, 1], [-1, 1]]},
{"angle": 21.7867892983, "xy_supercell": [[1, 2], [-2, 3]]},
{"angle": 13.1735511073, "xy_supercell": [[2, 3], [-3, 5]]},
{"angle": 9.4300079079, "xy_supercell": [[3, 4], [-4, 7]]},
{"angle": 7.34099301663, "xy_supercell": [[4, 5], [-5, 9]]},
{"angle": 6.00898319777, "xy_supercell": [[5, 6], [-6, 11]]},
{"angle": 5.08584780812, "xy_supercell": [[6, 7], [-7, 13]]},
{"angle": 4.40845500794, "xy_supercell": [[7, 8], [-8, 15]]},
{"angle": 3.89023816901, "xy_supercell": [[8, 9], [-9, 17]]},
{"angle": 3.48100608947, "xy_supercell": [[9, 10], [-10, 19]]},
{"angle": 3.14965742639, "xy_supercell": [[10, 11], [-11, 21]]},
{"angle": 2.87589463363, "xy_supercell": [[11, 12], [-12, 23]]},
{"angle": 2.64590838119, "xy_supercell": [[12, 13], [-13, 25]]},
{"angle": 2.44997727662, "xy_supercell": [[13, 14], [-14, 27]]},
{"angle": 2.28105960973, "xy_supercell": [[14, 15], [-15, 29]]},
{"angle": 2.1339296666, "xy_supercell": [[15, 16], [-16, 31]]},
{"angle": 2.00462783069, "xy_supercell": [[16, 17], [-17, 33]]},
{"angle": 1.89009907347, "xy_supercell": [[17, 18], [-18, 35]]},
{"angle": 1.78794861038, "xy_supercell": [[18, 19], [-19, 37]]},
{"angle": 1.69627269352, "xy_supercell": [[19, 20], [-20, 39]]},
{"angle": 1.61353890116, "xy_supercell": [[20, 21], [-21, 41]]},
{"angle": 1.53849981837, "xy_supercell": [[21, 22], [-22, 43]]},
{"angle": 1.47012972578, "xy_supercell": [[22, 23], [-23, 45]]},
{"angle": 1.40757744635, "xy_supercell": [[23, 24], [-24, 47]]},
{"angle": 1.35013073557, "xy_supercell": [[24, 25], [-25, 49]]},
{"angle": 1.29718904759, "xy_supercell": [[25, 26], [-26, 51]]},
{"angle": 1.24824246553, "xy_supercell": [[26, 27], [-27, 53]]},
{"angle": 1.20285522748, "xy_supercell": [[27, 28], [-28, 55]]},
{"angle": 1.16065271985, "xy_supercell": [[28, 29], [-29, 57]]},
{"angle": 1.12131111538, "xy_supercell": [[29, 30], [-30, 59]]},
{"angle": 1.08454904916, "xy_supercell": [[30, 31], [-31, 61]]},
{"angle": 1.05012087979, "xy_supercell": [[31, 32], [-32, 63]]},
{"angle": 1.01781119445, "xy_supercell": [[32, 33], [-33, 65]]},
{"angle": 0.987430297814, "xy_supercell": [[33, 34], [-34, 67]]},
{"angle": 0.958810485525, "xy_supercell": [[34, 35], [-35, 69]]},
{"angle": 0.931802947264, "xy_supercell": [[35, 36], [-36, 71]]},
{"angle": 0.906275178895, "xy_supercell": [[36, 37], [-37, 73]]},
{"angle": 0.882108808579, "xy_supercell": [[37, 38], [-38, 75]]},
{"angle": 0.859197761631, "xy_supercell": [[38, 39], [-39, 77]]},
{"angle": 0.8374467041, "xy_supercell": [[39, 40], [-40, 79]]},
{"angle": 0.816769716893, "xy_supercell": [[40, 41], [-41, 81]]},
{"angle": 0.0, "xy_supercell": [[1, 0], [0, 1]]},
]

0 comments on commit 2987cdd

Please sign in to comment.