-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature/SOF 7397 #151
feature/SOF 7397 #151
Changes from 46 commits
4f049c6
af0f656
15a99d0
20b79c3
7279daa
6939b39
95337d6
b53ce87
50658ad
b90b7ab
71987fb
11db833
b49ca69
f304dcb
a97b7c3
9e98b26
425892d
c7f8d53
3861d28
83325e3
e512d29
678eda1
a879f52
7cb6053
07cf54c
2b0805a
7d410a7
2ecd3cf
34eec9e
e8f403a
4d44046
830140a
9e3642c
49e148b
aa757fc
460a321
1eea222
ee92a58
9d4c882
427994e
bf561bb
bccdeb1
88d95cd
b34ae4c
37db051
3806063
ccf9702
ae3cdcb
5fca5dc
e8a22a1
98a4358
3697be4
a42ebbd
e8f4947
f84e873
963822a
5f2dcf4
8ce0856
4c6a391
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
from typing import Any, List, Optional | ||
|
||
import numpy as np | ||
from mat3ra.made.tools.modify import translate_to_z_level | ||
from pydantic import BaseModel | ||
from ase.build.tools import niggli_reduce | ||
from pymatgen.analysis.interfaces.coherent_interfaces import ( | ||
|
@@ -144,9 +145,11 @@ class ZSLStrainMatchingInterfaceBuilder(ConvertGeneratedItemsPymatgenStructureMi | |
|
||
def _generate(self, configuration: InterfaceConfiguration) -> List[PymatgenInterface]: | ||
generator = ZSLGenerator(**self.build_parameters.strain_matching_parameters.dict()) | ||
substrate_down = translate_to_z_level(configuration.substrate_configuration.bulk, "bottom") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. substrate_with_atoms_translated_to_bottom |
||
film_down = translate_to_z_level(configuration.film_configuration.bulk, "bottom") | ||
builder = CoherentInterfaceBuilder( | ||
substrate_structure=to_pymatgen(configuration.substrate_configuration.bulk), | ||
film_structure=to_pymatgen(configuration.film_configuration.bulk), | ||
substrate_structure=to_pymatgen(substrate_down), | ||
film_structure=to_pymatgen(film_down), | ||
substrate_miller=configuration.substrate_configuration.miller_indices, | ||
film_miller=configuration.film_configuration.miller_indices, | ||
zslgen=generator, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from typing import Union, Optional | ||
|
||
from mat3ra.made.material import Material | ||
from .builders import ( | ||
SlabPerturbationBuilder, | ||
DistancePreservingSlabPerturbationBuilder, | ||
CellMatchingDistancePreservingSlabPerturbationBuilder, | ||
) | ||
from .configuration import PerturbationConfiguration | ||
from .builders import PerturbationFunctionHolder # type: ignore | ||
|
||
|
||
def create_perturbation( | ||
configuration: PerturbationConfiguration, | ||
preserve_distance: Optional[bool] = False, | ||
builder: Union[ | ||
SlabPerturbationBuilder, | ||
DistancePreservingSlabPerturbationBuilder, | ||
CellMatchingDistancePreservingSlabPerturbationBuilder, | ||
None, | ||
] = None, | ||
) -> Material: | ||
""" | ||
Return a material with a perturbation applied. | ||
|
||
Args: | ||
configuration: The configuration of the perturbation to be applied. | ||
preserve_distance: If True, the builder that preserves the distance between atoms is used. | ||
builder: The builder to be used to create the perturbation. | ||
|
||
Returns: | ||
The material with the perturbation applied. | ||
""" | ||
if builder is None: | ||
builder = SlabPerturbationBuilder() | ||
if preserve_distance: | ||
builder = CellMatchingDistancePreservingSlabPerturbationBuilder() | ||
return builder.get_material(configuration) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from typing import List, Optional, Any | ||
|
||
from mat3ra.made.material import Material | ||
from mat3ra.made.tools.build import BaseBuilder | ||
|
||
from .configuration import PerturbationConfiguration | ||
from ...modify import wrap_material, translate_to_z_level | ||
from ...utils import PerturbationFunctionHolder | ||
|
||
|
||
class PerturbationBuilder(BaseBuilder): | ||
_ConfigurationType: type(PerturbationConfiguration) = PerturbationConfiguration # type: ignore | ||
_GeneratedItemType: Material = Material | ||
_PostProcessParametersType: Any = None | ||
|
||
@staticmethod | ||
def _prepare_material(configuration): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't we have _pre_process or something like that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we didn't implement that |
||
new_material = configuration.material.clone() | ||
new_material = translate_to_z_level(new_material, "center") | ||
if configuration.use_cartesian_coordinates: | ||
new_material.to_cartesian() | ||
return new_material | ||
|
||
@staticmethod | ||
def _set_new_coordinates(new_material, new_coordinates): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be inside material class or basis class |
||
new_basis = new_material.basis.copy() | ||
new_basis.coordinates.values = new_coordinates | ||
new_basis.to_crystal() | ||
new_material.basis = new_basis | ||
return new_material | ||
|
||
def _generate(self, configuration: _ConfigurationType) -> List[_GeneratedItemType]: | ||
"""Generate materials with applied continuous perturbation based on the given configuration.""" | ||
new_material = self.create_perturbed_slab(configuration) | ||
return [new_material] | ||
|
||
def _post_process( | ||
self, | ||
items: List[_GeneratedItemType], | ||
post_process_parameters: Optional[_PostProcessParametersType], | ||
) -> List[Material]: | ||
return [wrap_material(item) for item in items] | ||
|
||
def _update_material_name(self, material: Material, configuration: _ConfigurationType) -> Material: | ||
perturbation_details = f"Perturbation: {configuration.perturbation_function[1].get('type')}" | ||
material.name = f"{material.name} ({perturbation_details})" | ||
return material | ||
|
||
|
||
class SlabPerturbationBuilder(PerturbationBuilder): | ||
def create_perturbed_slab(self, configuration): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and elsewhere - type hints |
||
new_material = self._prepare_material(configuration) | ||
perturbation_function, _ = configuration.perturbation_function | ||
new_coordinates = [perturbation_function(coord) for coord in new_material.basis.coordinates.values] | ||
new_material = self._set_new_coordinates(new_material, new_coordinates) | ||
return new_material | ||
|
||
|
||
class DistancePreservingSlabPerturbationBuilder(SlabPerturbationBuilder): | ||
def create_perturbed_slab(self, configuration): | ||
new_material = self._prepare_material(configuration) | ||
perturbation_function, perturbation_json = configuration.perturbation_function | ||
coord_transformation_function = PerturbationFunctionHolder.get_coord_transformation(perturbation_json) | ||
new_coordinates = [ | ||
perturbation_function(coord_transformation_function(coord)) | ||
for coord in new_material.basis.coordinates.values | ||
] | ||
new_material = self._set_new_coordinates(new_material, new_coordinates) | ||
return new_material | ||
|
||
|
||
class CellMatchingDistancePreservingSlabPerturbationBuilder(DistancePreservingSlabPerturbationBuilder): | ||
def _transform_cell_vectors(self, configuration: PerturbationConfiguration) -> List[List[float]]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
perturbation_function, perturbation_json = configuration.perturbation_function | ||
coord_transformation_function = PerturbationFunctionHolder.get_coord_transformation(perturbation_json) | ||
cell_vectors = configuration.material.basis.cell.vectors_as_array | ||
return [perturbation_function(coord_transformation_function(coord)) for coord in cell_vectors] | ||
|
||
def create_perturbed_slab(self, configuration: PerturbationConfiguration): | ||
new_material = super().create_perturbed_slab(configuration) | ||
new_lattice_vectors = self._transform_cell_vectors(configuration) | ||
new_lattice = new_material.lattice.copy() | ||
new_lattice = new_lattice.from_vectors_array(new_lattice_vectors) | ||
new_material.lattice = new_lattice | ||
|
||
new_basis = new_material.basis.copy() | ||
new_basis.to_cartesian() | ||
new_basis.cell = new_basis.cell.from_vectors_array(new_lattice_vectors) | ||
new_basis.to_crystal() | ||
new_material.basis = new_basis | ||
return new_material |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from typing import Callable, Dict, Tuple | ||
|
||
from mat3ra.code.entity import InMemoryEntity | ||
from mat3ra.made.material import Material | ||
from pydantic import BaseModel | ||
|
||
from ...utils import PerturbationFunctionHolder | ||
|
||
|
||
class PerturbationConfiguration(BaseModel, InMemoryEntity): | ||
material: Material | ||
perturbation_function: Tuple[Callable, Dict] = PerturbationFunctionHolder.sine_wave() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to call things for what they are if this is a tuple, we should call it a tuple, or object, or There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I restructured instead |
||
use_cartesian_coordinates: bool = True | ||
|
||
class Config: | ||
arbitrary_types_allowed = True | ||
|
||
@property | ||
def _json(self): | ||
_, perturbation_function_json = self.perturbation_function | ||
return { | ||
"type": self.get_cls_name(), | ||
"material": self.material.to_json(), | ||
"perturbation_function": perturbation_function_json, | ||
"use_cartesian_coordinates": self.use_cartesian_coordinates, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type hint