Source code for moffragmentor.sbu.sbucollection
# -*- coding: utf-8 -*-
"""Collection for MOF building blocks"""
from collections import Counter
from typing import List
from backports.cached_property import cached_property
from .sbu import SBU
[docs]class SBUCollection:
"""Container for a collection of SBUs"""
def __init__(self, sbus: List[SBU]):
"""Construct a SBUCollection.
Args:
sbus (List[SBU]): List of SBU objects.
Raises:
ValueError: If there is an unexpected number of SBUs
(inconsistency in the extracted indices and the SBUs).
"""
self.sbus = sbus
self._sbu_types = None
self._composition = None
self._unique_sbus = None
self._centers = [sbu.center for sbu in self.sbus]
self._indices = [sbu.get_indices() for sbu in self.sbus]
if len(self._indices) != len(self.sbus):
raise ValueError("Number of SBUs is inconsistent")
def __len__(self) -> int:
"""Return number of SBUs."""
return len(self.sbus)
def __getitem__(self, index) -> SBU:
"""Return SBU at index."""
return self.sbus[index]
def __iter__(self):
"""Iterate over SBUs (generator)."""
for sbu in self.sbus:
yield sbu
@property
def indices(self):
return set(sum(self._indices, []))
@property
def centers(self):
return self._centers
@cached_property
def smiles(self):
"""
Return a list of the SMILES strings of the SBUs.
Returns:
List[str]: A list of smiles strings.
"""
return [sbu.smiles for sbu in self.sbus]
@property
def sbu_types(self):
if not self._sbu_types:
self._get_unique()
return self._sbu_types
@property
def coordination_numbers(self):
return [sbu.coordination for sbu in self.sbus]
@property
def molar_masses(self):
return [sbu.molar_mass for sbu in self.sbus]
@property
def unique_sbus(self):
if not self._sbu_types:
self._get_unique()
return self._unique_sbus
@property
def sbu_properties(self):
return dict(zip(self.sbu_types, self.coordination_numbers))
def _get_unique(self):
all_strings = [str(sbu) for sbu in self.sbus]
unique_strings = set(all_strings)
unique_mapping = []
for string in all_strings:
for i, unique_string in enumerate(unique_strings):
if string == unique_string:
unique_mapping.append(i)
break
self._unique_sbus = unique_strings
self._sbu_types = unique_mapping
def _get_composition(self):
if self._composition is None:
composition = []
for mol in self.sbus:
composition.append(str(mol.composition))
composition_counter = Counter(composition)
self._composition = dict(composition_counter)
return self._composition
@property
def composition(self):
return self._get_composition()
def __repr__(self) -> str:
"""Return string representation."""
return f"SBUCollection({self.composition})"