Skip to content

Commit

Permalink
organize repo
Browse files Browse the repository at this point in the history
  • Loading branch information
ireaml committed Mar 30, 2022
0 parents commit 6a13870
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# perovskites-oct-distortions
Collection of python functions useful to manipulate the structures of hybrid organic/inorganic perovskites.
Main directory contains:
- `rotations.py` : functions to apply random rotations to the organic molecules occupiying the A site in your perovskite. Useful to break symmetries, avoid the polar parallel arrangement (if your cation has a dipole moment, e.g. formamdinium)
- folder `octahedral_distortions`: hosts the file `oct_distortions.py`. This contains the function `get_tilting_angles`, which calculates the average of the Pb-I-Pb angles in your structure. Values close to 180º indicate small tilting while angles deviating from 180º point towards significant tilting of the octahedra.
21 changes: 21 additions & 0 deletions license
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Laboratory of Computational Chemistry and Biochemistry - EPFL

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
84 changes: 84 additions & 0 deletions rotations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Funtions to rotate the molecules in the A cation position, useful to avoid all molecules being parallel
import random
from copy import deepcopy
from pymatgen.core.structure import Structure
import numpy as np

def get_center_of_mass(
structure: Structure,
sites_indexes: list
) -> np.array:
"""
Calculates center of mass for sites specified as sites_indexes
"""
center = np.zeros(3)
total_weight= 0
for index in sites_indexes:
site = structure[index]
wt = site.species.weight
center += site.coords * wt
total_weight += wt
return center/ total_weight

def get_a_cation_sites(
struct: Structure,
a_cation_center_species: str='C',
radius_cutoff: float = 3.5, # in Angstroms
) -> list:
"""
Get the indices of the A cation sites in the structure.
Args:
struct (Structure): structure
a_cation_center_species (str, optional): Species of the A cation center. Defaults to 'C'.
radius_cutoff (float, optional): Radius cutoff for finding the neighbours of the A cation center. \
Defaults to 3.5 Angstroms.
"""
# Get the central atom of all A cations, by default Carbon (e.g, A_cation = formamidinium)
carbon_sites = [(index, site) for index, site in enumerate(struct) if site.species_string == a_cation_center_species]
fa_molecules = []
count = 0
for index, carbon in carbon_sites:
# Get the indices of all atoms bonded to the central atom
neighbors = struct.get_neighbors(carbon, r= radius_cutoff)
print([site.species_string for site in neighbors]) # Make sure we're getting the right atoms
fa_molecules.append([index,])
fa_molecules[count] += ([site.index for site in neighbors])
count += 1
# assert all elements in list have the same length
assert len(set([len(molecule) for molecule in fa_molecules])) == 1
return fa_molecules

def rotate_a_cation(
struct: Structure,
fa_molecules: list,
maximum_angle: int = 180, # in degrees
rotation_axis: list=[0,1,0],
):
"""
Rotates A cation molecules by random angles chosen between -maximum_angle and +maximum_angle.
Args:
struct (Structure): structure
fa_molecules (list): list of lists with the indices of the sites for each molecule (e.g. [[0,1,2,3], [4,5,6,7]])
maximum_angle (int, optional): Random angles will be chosen between [-maximum_angle, +maximum_angle] Defaults to 180 degrees.
rotation_axis (list, optional): Vector to rotate around. \
For formamidinium, the vector defined between the two Nitrogens (for FA). Defaults to [0,1,0].
Returns:
Structure: structure with A cation molecules rotated
"""
struct_rotated = deepcopy(struct)
# Need to perturb structure to break symmetries. \
# Otherwise, it breaks some of the FA molecules when rotating (does weird shit with the H bonded to the C)
struct_rotated.perturb(distance = 0.000001)
for sites in fa_molecules:
angle = random.randrange(-maximum_angle, maximum_angle)
#print(f"Rotating by {angle} degrees")
center_of_mass = get_center_of_mass(struct_rotated, sites)
struct_rotated.rotate_sites(
indices = sites,
theta = angle * np.pi / 180,
axis = rotation_axis,
anchor = center_of_mass, # struct_rotated[sites[0]].coords,
to_unit_cell = False,
)
return struct_rotated

0 comments on commit 6a13870

Please sign in to comment.