bond_order_processing.input_data

  1__docformat__ = "google"
  2"""Input data module."""
  3from abc import ABC
  4from abc import abstractmethod
  5import re
  6from dataclasses import dataclass
  7from math import degrees
  8from math import acos
  9from enum import Enum
 10import numpy as np
 11from numpy.typing import NDArray
 12from typing import TypeAlias
 13from typing import Optional
 14
 15
 16x: TypeAlias = float
 17"""x-cartesian coordinate"""
 18y: TypeAlias = float
 19"""y-cartesian coordinate"""
 20z: TypeAlias = float
 21"""z-cartesian coordinate"""
 22vector: TypeAlias = tuple[x, y, z]
 23"""euclidean vector"""
 24deg: TypeAlias = float
 25"""angle in degrees"""
 26
 27
 28class LoadedData(Enum):
 29    """Enumeration used by **InputDataFromCPMD**."""
 30    UnitCell = 1
 31    MayerBondOrders = 2
 32    Populations = 3
 33    CoordinatesOfAtoms = 4
 34
 35
 36class Constants:
 37    """This class holds constants used in calculations in module
 38    **input_data**."""
 39    _CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR: float = 0.52917720859
 40    """The length of the bohr radius in angstroms."""
 41
 42
 43@dataclass
 44class UnitCell(Constants):
 45    """Unit cell.
 46
 47    Object represent unit cell.
 48
 49    Attributes:
 50        a (float): Angstroms
 51        b (float): Angstroms
 52        c (float): Angstroms
 53        lattice_vectors (tuple[vector]): Table represents lattice vectors.
 54        alfa (deg): deg
 55        beta (deg): deg
 56        gamma (deg): deg
 57
 58    """
 59
 60    lattice_vectors: tuple[vector] | tuple = ()
 61    converted_to_angstroms: bool = False
 62
 63    a: float = 0
 64    b: float = 0
 65    c: float = 0
 66
 67    alfa: deg = 0
 68    beta: deg = 0
 69    gamma: deg = 0
 70
 71    def calculate_edges_lengths(self) -> tuple[x, y, z] | None:
 72        """Calculate edge lengths
 73
 74        Example:
 75        >>> unit_cell = UnitCell()
 76        >>> unit_cell.lattice_vectors = ((1, 0, 0),\
 77                                         (0, 1, 0),\
 78                                         (0, 0, 1))
 79        >>> unit_cell.calculate_edges_lengths()
 80        (1.0, 1.0, 1.0)
 81        >>> unit_cell.a
 82        1.0
 83
 84        Returns:
 85            **tuple[x, y, z] | None**: To calculate edges lattice_vectors
 86                                   are required else returns None
 87        """
 88        if self.lattice_vectors == ():
 89            return None
 90        else:
 91            self.a = (self.lattice_vectors[0][0] ** 2
 92                      + self.lattice_vectors[0][1] ** 2
 93                      + self.lattice_vectors[0][2] ** 2) ** (1/2)
 94            self.b = (self.lattice_vectors[1][0] ** 2
 95                      + self.lattice_vectors[1][1] ** 2
 96                      + self.lattice_vectors[1][2] ** 2) ** (1/2)
 97            self.c = (self.lattice_vectors[2][0] ** 2
 98                      + self.lattice_vectors[2][1] ** 2
 99                      + self.lattice_vectors[2][2] ** 2) ** (1/2)
100            return (self.a, self.b, self.c)
101
102    def calculate_interaxial_angles(self) -> tuple[deg, deg, deg] | None:
103        """Calculate interaxial angles.
104
105        Example:
106        >>> unit_cell = UnitCell()
107        >>> unit_cell.lattice_vectors = ((1, 1, 0),\
108                                         (0, 1, 0),\
109                                         (0, 0, 1))
110        >>> angles = unit_cell.calculate_interaxial_angles()
111        >>> round(angles[0], 1)
112        90.0
113        >>> round(angles[1], 1)
114        90.0
115        >>> round(angles[2], 1)
116        45.0
117
118        Returns:
119            **tuple[deg, deg, deg] | None**: To calculate angles lattice_vectors
120                                         are required else returns None
121        """
122        if self.lattice_vectors == ():
123            return None
124        else:
125            if self.a == 0 or self.b == 0 or self.c == 0:
126                self.calculate_edges_lengths()
127
128            self.alfa = degrees(acos((
129                self.lattice_vectors[1][0]
130                * self.lattice_vectors[2][0]
131                + self.lattice_vectors[1][1]
132                * self.lattice_vectors[2][1]
133                + self.lattice_vectors[1][2]
134                * self.lattice_vectors[2][2])
135                / (self.b * self.c)))
136
137            self.beta = degrees(acos((
138                self.lattice_vectors[0][0]
139                * self.lattice_vectors[2][0]
140                + self.lattice_vectors[0][1]
141                * self.lattice_vectors[2][1]
142                + self.lattice_vectors[0][2]
143                * self.lattice_vectors[2][2])
144                / (self.a * self.c)))
145
146            self.gamma = degrees(acos((
147                self.lattice_vectors[0][0]
148                * self.lattice_vectors[1][0]
149                + self.lattice_vectors[0][1]
150                * self.lattice_vectors[1][1]
151                + self.lattice_vectors[0][2]
152                * self.lattice_vectors[1][2])
153                / (self.a * self.b)))
154
155            return (self.alfa, self.beta, self.gamma)
156
157    def convert_cell_data_to_angstroms(self) -> None:
158        """Convert cell data to angstroms.
159
160        You can use it to convert data in lattice_vectors, a, b and c
161        from Bohr units to angstroms.
162
163        Example:
164        >>> unit_cell = UnitCell()
165        >>> unit_cell.lattice_vectors = ((1, 1, 0),\
166                                         (0, 1, 0),\
167                                         (0, 0, 1))
168        >>> unit_cell.convert_cell_data_to_angstroms()
169        >>> unit_cell.lattice_vectors
170        ((0.52917720859, 0.52917720859, 0.0), (0.0, 0.52917720859, 0.0), \
171(0.0, 0.0, 0.52917720859))
172
173        """
174        if self.converted_to_angstroms is False:
175            new_lattice_vectors = []
176            for vector in self.lattice_vectors:
177                new_lattice_vectors.append((
178                    vector[0] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR,
179                    vector[1] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR,
180                    vector[2] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR))
181
182            self.lattice_vectors = tuple(new_lattice_vectors)
183
184            if self.a != 0 and self.b != 0 and self.c != 0:
185                self.a = self.a\
186                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
187                self.b = self.b\
188                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
189                self.c = self.c\
190                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
191
192            self.converted_to_angstroms = True
193
194
195class Populations:
196    """Populations from MULLIKEN, LOWDIN analysis."""
197
198    mulliken: dict[int, tuple[str, float]] = {}
199    lodwin: dict[int, tuple[str, float]] = {}
200    valence: dict[int, tuple[str, float]] = {}
201
202    def __init__(self) -> None:
203        pass
204
205
206class MayerBondOrders:
207    """Object stores Mayer bond orders of atoms pairs."""
208    rows = list[float]
209    """Type alias."""
210    mayer_bond_orders: list[rows] = []
211    horizontal_atom_symbol: dict[int, str] = {}
212    atom_id: list[int] = []
213    vertical_atom_symbol: dict[int, str] = {}
214
215    def __init__(self, mayer_bond_orders: list[rows],
216                 atom_id: list[int],
217                 horizontal_atom_symbol: dict[int, str] = {},
218                 vertical_atom_symbol: dict[int, str] = {}):
219
220        if (len(mayer_bond_orders) == len(atom_id) and
221           len(mayer_bond_orders[0]) == len(atom_id)):
222            self.mayer_bond_orders = mayer_bond_orders
223            self.atom_id = atom_id
224        else:
225            raise ValueError("Size of mayer_bond_orders must fit"
226                             + "to horizontal_atom_id and "
227                             + "vertical_atom_id!!!")
228
229        if (horizontal_atom_symbol != {} and vertical_atom_symbol != {}
230            and len(horizontal_atom_symbol) == len(mayer_bond_orders)
231                and len(vertical_atom_symbol) == len(mayer_bond_orders[0])):
232            self.horizontal_atom_symbol = horizontal_atom_symbol
233            self.vertical_atom_symbol = vertical_atom_symbol
234        elif (horizontal_atom_symbol == {}
235              and vertical_atom_symbol == {}):
236            pass
237        else:
238            raise ValueError("Size of mayer_bond_orders must fit"
239                             + "to horizontal_atom_symbol and "
240                             + "vertical_atom_symbol!!!")
241
242    def get_mayer_bond_order_between_atoms(self, atom_id_1: int, atom_id_2:
243                                           int) -> float:
244        """Get mayer bond order between atoms.
245
246        Args:
247            atom_id_1 (int): first atom id (row)
248            atom_id_2 (int): second atom id (column)
249
250        Returns:
251            **float**: bond order
252        """
253
254        row = self.mayer_bond_orders[self.atom_id.index(atom_id_2)]
255        return row[self.atom_id.index(atom_id_1)]
256
257    def get_atoms_ids(self, atom_symbol: str) -> list[int]:
258        """Get atoms ids in MayerBondOrders.
259
260        Args:
261            atom_symbol (str): Symbol of atom eg. P, Fe, ...
262
263        Returns:
264            **list[int]**: list of ids
265        """
266        ids = []
267        for key, value in self.horizontal_atom_symbol.items():
268            if value == atom_symbol:
269                ids.append(key)
270
271        return ids
272
273    def check_atom_symbol_in_MBO(self, atom_symbol: str) -> bool:
274        """Check atom symbol in MayerBondOrders object.
275
276        Args:
277            atom_symbol (str): Symbol of atom eg. 'P'.
278
279        Returns:
280            **bool**: True if in MayerBondOrders object.
281
282        """
283        if self.get_atoms_ids(atom_symbol) == []:
284            return False
285        else:
286            return True
287
288    def get_atom_symbols(self, atom_id_1: int, atom_id_2:
289                         int) -> tuple[str, str] | None:
290        """Get atom symbols of pair of atoms.
291
292        Args:
293            atom_id_1 (int): atom 1 id
294            atom_id_2 (int): atom 2 id
295
296        Returns:
297            **tuple(str, str) | None**: Symbol of atom 1 and atom 2,
298                                    if wrong id of atoms returns None or
299                                    atoms symbols have not been used.
300
301        """
302        atom_1 = self.horizontal_atom_symbol.get(atom_id_1, None)
303        atom_2 = self.vertical_atom_symbol.get(atom_id_2, None)
304
305        if atom_1 is None or atom_2 is None:
306            return None
307        else:
308            return (atom_1, atom_2)
309
310    def get_all_mayer_bond_orders_of_atom(self, atom_id) -> list[float]:
311        """Returns list of mayer bond orders of atom of given id.
312
313        Args:
314            atom_id (int): atom id.
315
316        Returns:
317            **list[float]**: list of mayer bond orders.
318        """
319        row = self.mayer_bond_orders[self.atom_id.index(atom_id)]
320        return row
321
322    def get_mayer_bond_orders_list_between_two_atoms(self, atom_symbol_1: str,
323                                                     atom_symbol_2: str
324                                                     ) -> list[float]:
325        """Get Mayer bond orders list between two atoms.
326
327        Args:
328            atom_symbol_1 (str): atom symbol eg. "Fe"
329            atom_symbol_2 (str): atom symbol eg. "Fe"
330
331        Returns:
332            **list[float]**: list of mayer bond orders
333        """
334        mayer_bond_orders = []
335        for atom_id_1 in self.atom_id:
336            if atom_symbol_1 == self.vertical_atom_symbol.get(atom_id_1):
337                for atom_id_2 in range(atom_id_1 + 1, len(self.atom_id) + 1):
338                    if atom_symbol_2 == self.vertical_atom_symbol.get(atom_id_2):
339                        mayer_bond_orders.append(
340                            self.get_mayer_bond_order_between_atoms(atom_id_1,
341                                                                    atom_id_2))
342
343        return mayer_bond_orders
344
345
346class CoordinatesOfAtoms(Constants):
347    """Object represents coordinates of atoms.
348
349    Args:
350        atom_coordinates_table (list[tuple[atom_id, str, x, y, z]], optional): \
351        Table with atom coordinates.
352
353    Attributes:
354        ids (list[atom_id]): ids of atoms.
355        atom_symbols (dict[atom_id, str]): \
356        Dictionary storing symbols of atoms, key is atom id.
357
358    Types:
359        atom_id = int
360
361    """
362
363    atom_id: TypeAlias = int
364    """Type alias"""
365    ids: list[atom_id]
366    _coordinates: dict[atom_id, vector]
367    atom_symbols: dict[atom_id, str]
368    _unit_cell: UnitCell | None
369
370    def __init__(self, atom_coordinates_table: list[tuple[atom_id, str, x, y,
371                                                          z]] = []) -> None:
372
373        self.ids = []
374        self._coordinates = {}
375        self.atom_symbols = {}
376        self._unit_cell = None
377
378        if atom_coordinates_table != []:
379            while atom_coordinates_table != []:
380                row = atom_coordinates_table.pop(0)
381                self.ids.append(row[0])
382                self.atom_symbols.update({row[0]: row[1]})
383                self._coordinates.update({row[0]: (row[2], row[3], row[4])})
384
385    def add_new_atom(self, id: int, atom_symbol: str, coordinates:
386                     tuple[x, y, z]) -> None:
387        """Add new atom coordinates to CoordinatesOfAtoms object.
388
389        Args:
390            id (int): id of new atom.
391            atom_symbol (str): Symbol of new atom.
392            coordinates (tuple[x, y, z]): Coordinates of new atom.
393
394        """
395        self.ids.append(id)
396        self.atom_symbols.update({id: atom_symbol})
397        self._coordinates.update({id: coordinates})
398
399    def get_atom_coordinates(self, id: int) -> tuple[x, y, z] | None:
400        """Get atoms coordinates.
401
402        Args:
403            id (int): atom id
404
405        Returns:
406            **tuple[x, y, z] | None**: Returns atom coordinates or None if atom of
407                                   given id does not exist.
408
409        """
410        return self._coordinates.get(id, None)
411
412    def get_atom_coordinates_converted_in_angstrom(self, id: int)\
413            -> tuple[x, y, z] | None:
414        """Get atom coordinates converted in angstroms if they were stored as
415        Bohr units. Not change stored values.
416
417        Example:
418        >>> coordinates_of_atoms = CoordinatesOfAtoms()
419        >>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
420        >>> coordinates_of_atoms.get_atom_coordinates_converted_in_angstrom(1)
421        (0.52917720859, 0.52917720859, 0.52917720859)
422
423        Args:
424            id (int): atom id
425
426        Returns:
427            **tuple[x, y, z]**: coordinates in angstroms
428
429        """
430        temp_coordinates = self._coordinates.get(id, None)
431        if temp_coordinates is not None:
432            coordinates = (
433                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
434                * temp_coordinates[0],
435                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
436                * temp_coordinates[1],
437                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
438                * temp_coordinates[2])
439            return coordinates
440        else:
441            return None
442
443    def convert_stored_coordinates_to_angstroms(self) -> None:
444        """Converts stored coordinates from bohr units to angstroms.
445
446        Example:
447        >>> coordinates_of_atoms = CoordinatesOfAtoms()
448        >>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
449        >>> coordinates_of_atoms.add_new_atom(2, 'P', (0, 0, 0))
450        >>> coordinates_of_atoms.convert_stored_coordinates_to_angstroms()
451        >>> coordinates_of_atoms.get_atom_coordinates(1)
452        (0.52917720859, 0.52917720859, 0.52917720859)
453
454        """
455
456        for id, coord in self._coordinates.items():
457            self._coordinates[id] = (
458                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[0],
459                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[1],
460                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[2],
461            )
462
463    def get_atom_symbol(self, id: int) -> str | None:
464        """Get atom symbol
465
466        Args:
467            id (int): atom id
468
469        Returns:
470            **Union[str, None]**: Returns atom symbol or None if atom of
471                        given id does not exist.
472
473        """
474        return self.atom_symbols.get(id)
475
476    @property
477    def coordinates(self) -> list[vector]:
478        coordinates = [value for value in self._coordinates.values()]
479        return coordinates
480
481    def add_unit_cell(self, unit_cell: UnitCell):
482        self._unit_cell = unit_cell
483
484    def remove_unit_cell(self):
485        self._unit_cell = None
486
487    def get_distance_between_atoms(self, atom_id_1: int, atom_id_2: int)\
488            -> float | None:
489        """ Calculate distance between two atoms.
490
491        Args:
492            atom_id_1 (int): id of first atom
493             atom_id_2 (int): id of second atom
494        Returns:
495            **float | None**: Distance in angstroms or Bohr units.
496
497        """
498
499        if type(self._unit_cell) is not UnitCell:
500            raise Exception("Unit cell not added or wrong type of"
501                            + " unit_cell, use .add_unit_cell(self, unit_cell) method!!!")
502
503        atom_coord_1_v = self._coordinates.get(atom_id_1, None)
504        atom_coord_2_v = self._coordinates.get(atom_id_2, None)
505
506        if atom_coord_1_v is None or atom_coord_2_v is None:
507            return None
508        else:
509            atom_coord_1 = np.array(atom_coord_1_v)
510            atom_coord_2 = np.array(atom_coord_2_v)
511
512        vector_between_atoms = atom_coord_1 - atom_coord_2
513
514        length = float(np.linalg.norm(vector_between_atoms))
515
516        lattice_vectors_list = []
517        for vector in self._unit_cell.lattice_vectors:
518            lattice_vectors_list.append(np.array(vector))
519
520        def get_lower_distance(length: float, vector_1: NDArray,
521                               vector_2: NDArray) -> float:
522            vector_between_atoms = vector_1 - vector_2
523
524            new_length = float(np.linalg.norm(vector_between_atoms))
525
526            if new_length < length:
527                length = new_length
528
529            return length
530
531        for vector in lattice_vectors_list:
532            atom_2_coord_in_neighboring_unit = atom_coord_2 + vector
533
534            length = get_lower_distance(length, atom_coord_1,
535                                        atom_2_coord_in_neighboring_unit)
536
537        for vector in lattice_vectors_list:
538            atom_2_coord_in_neighboring_unit = atom_coord_2 - vector
539
540            length = get_lower_distance(length, atom_coord_1,
541                                        atom_2_coord_in_neighboring_unit)
542
543        for i in range(3):
544            for j in range(i + 1, 3):
545                translation = lattice_vectors_list[i] + lattice_vectors_list[j]
546                atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
547
548                length = get_lower_distance(length, atom_coord_1,
549                                            atom_2_coord_in_neighboring_unit)
550
551                atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
552
553                length = get_lower_distance(length, atom_coord_1,
554                                            atom_2_coord_in_neighboring_unit)
555
556                translation = lattice_vectors_list[i] - lattice_vectors_list[j]
557                atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
558
559                length = get_lower_distance(length, atom_coord_1,
560                                            atom_2_coord_in_neighboring_unit)
561
562                atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
563
564                length = get_lower_distance(length, atom_coord_1,
565                                            atom_2_coord_in_neighboring_unit)
566
567        translation = lattice_vectors_list[0] + lattice_vectors_list[1]\
568            + lattice_vectors_list[2]
569
570        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
571
572        length = get_lower_distance(length, atom_coord_1,
573                                    atom_2_coord_in_neighboring_unit)
574
575        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
576
577        length = get_lower_distance(length, atom_coord_1,
578                                    atom_2_coord_in_neighboring_unit)
579
580        translation = lattice_vectors_list[0] - lattice_vectors_list[1]\
581            + lattice_vectors_list[2]
582
583        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
584
585        length = get_lower_distance(length, atom_coord_1,
586                                    atom_2_coord_in_neighboring_unit)
587
588        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
589
590        length = get_lower_distance(length, atom_coord_1,
591                                    atom_2_coord_in_neighboring_unit)
592
593        translation = lattice_vectors_list[0] - lattice_vectors_list[1]\
594            - lattice_vectors_list[2]
595
596        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
597
598        length = get_lower_distance(length, atom_coord_1,
599                                    atom_2_coord_in_neighboring_unit)
600
601        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
602
603        length = get_lower_distance(length, atom_coord_1,
604                                    atom_2_coord_in_neighboring_unit)
605
606        translation = lattice_vectors_list[0] + lattice_vectors_list[1]\
607            - lattice_vectors_list[2]
608
609        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
610
611        length = get_lower_distance(length, atom_coord_1,
612                                    atom_2_coord_in_neighboring_unit)
613
614        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
615
616        length = get_lower_distance(length, atom_coord_1,
617                                    atom_2_coord_in_neighboring_unit)
618
619        return length
620
621
622class InputData(ABC):
623    """Input data.
624
625    Load data from file and create objects.
626
627    """
628
629    populations: Populations | None = None
630    unit_cell: UnitCell | None = None
631    mayer_bond_orders: MayerBondOrders | None = None
632    coordinates_of_atoms: CoordinatesOfAtoms | None = None
633
634    def __init__(self, Populations: type = Populations,
635                 UnitCell: type = UnitCell,
636                 MayerBondOrders: type = MayerBondOrders,
637                 CoordinatesOfAtoms: type = CoordinatesOfAtoms):
638        """Constructor.
639
640        Args:
641            Populations (type, optional): Defaults to Populations.
642            UnitCell (type, optional): Defaults to UnitCell.
643            MayerBondOrders (type, optional): Defaults to MayerBondOrders.
644            CoordinatesOfAtoms (type, optional): Defaults to CoordinatesOfAtoms.
645
646        """
647
648        self.Populations = Populations
649        self.UnitCell = UnitCell
650        self.MayerBondOrders = MayerBondOrders
651        self.CoordinatesOfAtoms = CoordinatesOfAtoms
652        self.LoadedData = LoadedData
653
654    @abstractmethod
655    def load_input_data(self, path: str, *args) -> None:
656        """Load input data from file.
657
658        Args:
659            path (str): Path to file.
660            *args: LoadData.UnitCell, LoadedData.MayerBondOrders,\
661                LoadData.Populations or LoadData.CoordinatesOfAtoms
662
663        """
664        pass
665
666    @staticmethod
667    def check_is_correct_file(data_in_file: str, fingerprint: str) -> bool:
668        if fingerprint in data_in_file:
669            return True
670        else:
671            return False
672
673
674class InputDataFromCPMD(InputData):
675    """Loads data from CPMD file and create objects."""
676    _fingerprint: str = "The CPMD consortium"
677    _fingerprint_beginning_populations: str = "POPULATION ANALYSIS FROM PROJECTED"\
678        + " WAVEFUNCTIONS"
679    _fingerprint_end_populations: str = "ChkSum\(POP_MUL\)"
680    _fingerprint_coordinates_of_atoms: str = "ATOM             COORDINATES"\
681        + "                   CHARGES"
682    _fingerprint_end_coordinates_of_atoms: str = "ChkSum\(CHARGES\)"
683    _fingerprint_mayer_bond_orders: str = "MAYER BOND ORDERS FROM PROJECTED"\
684        + " WAVEFUNCTIONS"
685
686    _fingerprints_unit_cell: tuple[str, str, str] = ("LATTICE VECTOR A1\(BOHR\):",
687                                                     "LATTICE VECTOR A2\(BOHR\):",
688                                                     "LATTICE VECTOR A3\(BOHR\):")
689
690    _valid_population_columns_names: tuple[str, str, str, str] = (
691        'ATOM', 'MULLIKEN', 'LOWDIN', 'VALENCE')
692
693    _valid_coordinatios_columns_names: tuple[str, str, str] = (
694        'X', 'Y', 'Z')
695
696    def load_input_data(self, path: str, *args) -> None:
697        """Loads input data from CPMD file.
698
699        Args:
700            path (str): path to file
701            *args: LoadData.UnitCell, LoadedData.MayerBondOrders,
702            LoadData.Populations or LoadData.CoordinatesOfAtoms
703
704        """
705        with open(path, 'r') as file:
706            data = file.read()
707
708        if self.check_is_correct_file(data, self._fingerprint) is not True:
709            raise Exception("Wrong input file!")
710        else:
711            if self.LoadedData.UnitCell in args:
712                self.unit_cell = self._load_unit_cell(data)
713            if self.LoadedData.MayerBondOrders in args:
714                self.mayer_bond_orders = \
715                    self._load_mayer_bond_orders(data)
716            if self.LoadedData.Populations in args:
717                self.populations = self._load_populations(data)
718            if self.LoadedData.CoordinatesOfAtoms in args:
719                self.coordinates_of_atoms = \
720                    self._load_coordinates_of_atoms(data)
721
722    def return_data(self, loaded_data: LoadedData)\
723            -> Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms\
724            | None:
725        """ Returns loaded data.
726
727        Args:
728
729        Returns:
730            **Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms**:
731
732        """
733        if loaded_data is LoadedData.UnitCell:
734            return self.unit_cell
735        elif loaded_data is LoadedData.MayerBondOrders:
736            return self.mayer_bond_orders
737        elif loaded_data is LoadedData.Populations:
738            return self.populations
739        elif loaded_data is LoadedData.CoordinatesOfAtoms:
740            return self.coordinates_of_atoms
741        else:
742            raise TypeError("Type is not LoadedData!!!!")
743
744    def _load_populations(self, file: str) -> Populations | None:
745
746        rows = self._get_rows_of_data_from_file(file,
747                                                self._fingerprint_beginning_populations,
748                                                self._fingerprint_end_populations)
749        labels: list = []
750        if rows is not None:
751            for row in rows:
752                have_string = True if re.search('[a-zA-Z]+', row) is \
753                    not None else False
754
755                have_number = True if re.search('[0-9]+', row) is \
756                    not None else False
757
758                if have_string and not have_number:
759                    labels = row.split()
760                    populations = Populations()
761                    continue
762                elif have_string and have_number:
763                    splited = row.split()
764                    if len(labels) + 1 != len(splited):
765                        raise Exception(
766                            'Wrong quantity of columns in input file!')
767                    else:
768                        populations = self._add_populations_attributes(
769                            populations, splited, labels)
770            return populations
771        else:
772            return None
773
774    @classmethod
775    def _add_populations_attributes(cls, populations: Populations,
776                                    splited: list, labels: list[str])\
777            -> Populations:
778        i = 0
779        for item in splited:
780            if i == 0:
781                id = int(item)
782            elif labels[i-1] == cls._valid_population_columns_names[0]:
783                symbol = item
784            elif labels[i-1] == cls._valid_population_columns_names[1]:
785                mulliken_value = float(item)
786            elif labels[i-1] == cls._valid_population_columns_names[2]:
787                lowdin_value = float(item)
788            elif labels[i-1] == cls._valid_population_columns_names[3]:
789                valence_value = float(item)
790            i += 1
791
792        populations.lodwin.update({id: (symbol, lowdin_value)})
793        populations.mulliken.update({id: (symbol, mulliken_value)})
794        populations.valence.update({id: (symbol, valence_value)})
795
796        return populations
797
798    def _load_coordinates_of_atoms(self, file: str)\
799            -> CoordinatesOfAtoms | None:
800        rows = self._get_rows_of_data_from_file(file,
801                                                self._fingerprint_coordinates_of_atoms,
802                                                self._fingerprint_end_coordinates_of_atoms)
803        if rows is not None:
804            for row in rows:
805                have_string = True if re.search('[a-zA-Z]+', row) is \
806                    not None else False
807
808                have_number = True if re.search('[0-9]+', row) is \
809                    not None else False
810
811                if have_string and not have_number:
812                    labels = row.split()
813                    coordinates_of_atoms = self.CoordinatesOfAtoms()
814                    continue
815                elif have_string and have_number:
816                    splited = row.split()
817                    if len(labels) + 2 != len(splited):
818                        raise Exception(
819                            'Wrong quantity of columns in input file!')
820                    else:
821                        coordinates_of_atoms = self._add_coordinations_attributes(
822                            coordinates_of_atoms, splited, labels
823                        )
824            return coordinates_of_atoms
825        else:
826            return None
827
828    @classmethod
829    def _add_coordinations_attributes(cls, coordinates_of_atoms:
830                                      CoordinatesOfAtoms,
831                                      splited: list, labels: list[str])\
832            -> CoordinatesOfAtoms:
833        i = 0
834        for item in splited:
835            if i == 0:
836                atom_id = int(item)
837            elif i == 1:
838                atom_symbol = item
839            elif labels[i - 2] == cls._valid_coordinatios_columns_names[0]:
840                x = float(item)
841            elif labels[i - 2] == cls._valid_coordinatios_columns_names[1]:
842                y = float(item)
843            elif labels[i - 2] == cls._valid_coordinatios_columns_names[2]:
844                z = float(item)
845            i += 1
846
847        coordinates_of_atoms.add_new_atom(atom_id, atom_symbol, (x, y, z))
848        return coordinates_of_atoms
849
850    @staticmethod
851    def _get_rows_of_data_from_file(file: str,
852                                    finger_print_begin: str, finger_print_end)\
853            -> list[str] | None:
854        """Get rows fo data from file
855
856        Args:
857            finger_print_begin (str): fingerprint on beginning of data
858            finger_print_end (str): fingerprint on end of data
859
860        Returns:
861            **list[str]**: rows of string data
862
863        """
864
865        regex = f'(?<={finger_print_begin})[\s\S]*' \
866            + f'(?={finger_print_end})'
867
868        match = re.search(regex, file)
869        if match is not None:
870            return match[0].split('\n')
871        else:
872            return None
873
874    def _load_mayer_bond_orders(self, file: str) -> MayerBondOrders:
875        match = re.search(
876            f"(?<={self._fingerprint_mayer_bond_orders}\n\n)([\S ]+\n)*", file)
877        if match is None:
878            raise Exception("Mayers bond orders aren't in file or wrong file"
879                            + "format!!!!")
880        rows = match[0].split('\n')
881        rows = [row for row in rows if row != '']
882        number_of_atoms = int(rows[-1].split()[0])
883        n = number_of_atoms // 8
884        m = 1 if number_of_atoms % 8 > 0 else 0
885        number_of_tables = m + n
886
887        number_of_rows = (len(rows)) * number_of_tables
888        match = re.search(
889            f"(?<={self._fingerprint_mayer_bond_orders}\n\n)([\S ]+\n*){{{number_of_rows}}}", file)
890
891        if match is None:
892            raise Exception("Mayers bond orders aren't in file or wrong file"
893                            + "format!!!!")
894        rows_full_table = []
895        tables = match[0].split('\n\n')
896        first_table = True
897        for table in tables:
898            splited = table.split('\n')
899            i = 0
900            for item in splited:
901                if first_table:
902                    row = item.split()
903                    rows_full_table.append(row)
904                elif i == 0:
905                    row = item.split()
906                    rows_full_table[i].extend(row)
907                else:
908                    row = item.split()
909                    rows_full_table[i].extend(row[2:])
910                i += 1
911            first_table = False
912
913        row_horizontal = rows_full_table.pop(0)
914        i = 0
915        j = 0
916        horizontal_atom_symbol = {}
917        horizontal_atom_id = []
918        for item in row_horizontal:
919            if i % 2 == 0:
920                j += 1
921                horizontal_atom_id.append(int(item))
922            else:
923                horizontal_atom_symbol.update(
924                    {horizontal_atom_id[j - 1]: str(item)})
925            i += 1
926
927        vertical_atom_symbol = {}
928        vertical_atom_id = []
929        new_rows_full_table = []
930        for row in rows_full_table:
931            vertical_atom_id.append(int(row.pop(0)))
932            vertical_atom_symbol.update(
933                {vertical_atom_id[-1]: str(row.pop(0))})
934            row_f = [float(item) for item in row]
935            new_rows_full_table.append(row_f)
936
937        if horizontal_atom_id == vertical_atom_id:
938            mayer_bond_order = self.MayerBondOrders(new_rows_full_table,
939                                                    horizontal_atom_id,
940                                                    horizontal_atom_symbol,
941                                                    vertical_atom_symbol)
942        else:
943            raise Exception(
944                "The condition: 'horizontal_atom_id == vertical_atom_id' "
945                + "must be met ")
946        return mayer_bond_order
947
948    @classmethod
949    def _load_unit_cell(cls, file: str):
950        vectors = []
951        for item in cls._fingerprints_unit_cell:
952            regex = f'(?<={item})[ \S]+'
953            match = re.search(regex, file)
954            if match is None:
955                raise Exception(" wrong file format!!!!")
956            row = match[0].split()
957            row_f = [float(item) for item in row]
958            vectors.append(row_f)
959        unit_cell = UnitCell()
960        unit_cell.lattice_vectors = tuple(item
961                                          for item in vectors)
962        return unit_cell
x: TypeAlias = <class 'float'>

x-cartesian coordinate

y: TypeAlias = <class 'float'>

y-cartesian coordinate

z: TypeAlias = <class 'float'>

z-cartesian coordinate

vector: TypeAlias = tuple[float, float, float]

euclidean vector

deg: TypeAlias = <class 'float'>

angle in degrees

class LoadedData(enum.Enum):
29class LoadedData(Enum):
30    """Enumeration used by **InputDataFromCPMD**."""
31    UnitCell = 1
32    MayerBondOrders = 2
33    Populations = 3
34    CoordinatesOfAtoms = 4

Enumeration used by InputDataFromCPMD.

UnitCell = <LoadedData.UnitCell: 1>
MayerBondOrders = <LoadedData.MayerBondOrders: 2>
Populations = <LoadedData.Populations: 3>
CoordinatesOfAtoms = <LoadedData.CoordinatesOfAtoms: 4>
Inherited Members
enum.Enum
name
value
class Constants:
37class Constants:
38    """This class holds constants used in calculations in module
39    **input_data**."""
40    _CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR: float = 0.52917720859
41    """The length of the bohr radius in angstroms."""

This class holds constants used in calculations in module input_data.

@dataclass
class UnitCell(Constants):
 44@dataclass
 45class UnitCell(Constants):
 46    """Unit cell.
 47
 48    Object represent unit cell.
 49
 50    Attributes:
 51        a (float): Angstroms
 52        b (float): Angstroms
 53        c (float): Angstroms
 54        lattice_vectors (tuple[vector]): Table represents lattice vectors.
 55        alfa (deg): deg
 56        beta (deg): deg
 57        gamma (deg): deg
 58
 59    """
 60
 61    lattice_vectors: tuple[vector] | tuple = ()
 62    converted_to_angstroms: bool = False
 63
 64    a: float = 0
 65    b: float = 0
 66    c: float = 0
 67
 68    alfa: deg = 0
 69    beta: deg = 0
 70    gamma: deg = 0
 71
 72    def calculate_edges_lengths(self) -> tuple[x, y, z] | None:
 73        """Calculate edge lengths
 74
 75        Example:
 76        >>> unit_cell = UnitCell()
 77        >>> unit_cell.lattice_vectors = ((1, 0, 0),\
 78                                         (0, 1, 0),\
 79                                         (0, 0, 1))
 80        >>> unit_cell.calculate_edges_lengths()
 81        (1.0, 1.0, 1.0)
 82        >>> unit_cell.a
 83        1.0
 84
 85        Returns:
 86            **tuple[x, y, z] | None**: To calculate edges lattice_vectors
 87                                   are required else returns None
 88        """
 89        if self.lattice_vectors == ():
 90            return None
 91        else:
 92            self.a = (self.lattice_vectors[0][0] ** 2
 93                      + self.lattice_vectors[0][1] ** 2
 94                      + self.lattice_vectors[0][2] ** 2) ** (1/2)
 95            self.b = (self.lattice_vectors[1][0] ** 2
 96                      + self.lattice_vectors[1][1] ** 2
 97                      + self.lattice_vectors[1][2] ** 2) ** (1/2)
 98            self.c = (self.lattice_vectors[2][0] ** 2
 99                      + self.lattice_vectors[2][1] ** 2
100                      + self.lattice_vectors[2][2] ** 2) ** (1/2)
101            return (self.a, self.b, self.c)
102
103    def calculate_interaxial_angles(self) -> tuple[deg, deg, deg] | None:
104        """Calculate interaxial angles.
105
106        Example:
107        >>> unit_cell = UnitCell()
108        >>> unit_cell.lattice_vectors = ((1, 1, 0),\
109                                         (0, 1, 0),\
110                                         (0, 0, 1))
111        >>> angles = unit_cell.calculate_interaxial_angles()
112        >>> round(angles[0], 1)
113        90.0
114        >>> round(angles[1], 1)
115        90.0
116        >>> round(angles[2], 1)
117        45.0
118
119        Returns:
120            **tuple[deg, deg, deg] | None**: To calculate angles lattice_vectors
121                                         are required else returns None
122        """
123        if self.lattice_vectors == ():
124            return None
125        else:
126            if self.a == 0 or self.b == 0 or self.c == 0:
127                self.calculate_edges_lengths()
128
129            self.alfa = degrees(acos((
130                self.lattice_vectors[1][0]
131                * self.lattice_vectors[2][0]
132                + self.lattice_vectors[1][1]
133                * self.lattice_vectors[2][1]
134                + self.lattice_vectors[1][2]
135                * self.lattice_vectors[2][2])
136                / (self.b * self.c)))
137
138            self.beta = degrees(acos((
139                self.lattice_vectors[0][0]
140                * self.lattice_vectors[2][0]
141                + self.lattice_vectors[0][1]
142                * self.lattice_vectors[2][1]
143                + self.lattice_vectors[0][2]
144                * self.lattice_vectors[2][2])
145                / (self.a * self.c)))
146
147            self.gamma = degrees(acos((
148                self.lattice_vectors[0][0]
149                * self.lattice_vectors[1][0]
150                + self.lattice_vectors[0][1]
151                * self.lattice_vectors[1][1]
152                + self.lattice_vectors[0][2]
153                * self.lattice_vectors[1][2])
154                / (self.a * self.b)))
155
156            return (self.alfa, self.beta, self.gamma)
157
158    def convert_cell_data_to_angstroms(self) -> None:
159        """Convert cell data to angstroms.
160
161        You can use it to convert data in lattice_vectors, a, b and c
162        from Bohr units to angstroms.
163
164        Example:
165        >>> unit_cell = UnitCell()
166        >>> unit_cell.lattice_vectors = ((1, 1, 0),\
167                                         (0, 1, 0),\
168                                         (0, 0, 1))
169        >>> unit_cell.convert_cell_data_to_angstroms()
170        >>> unit_cell.lattice_vectors
171        ((0.52917720859, 0.52917720859, 0.0), (0.0, 0.52917720859, 0.0), \
172(0.0, 0.0, 0.52917720859))
173
174        """
175        if self.converted_to_angstroms is False:
176            new_lattice_vectors = []
177            for vector in self.lattice_vectors:
178                new_lattice_vectors.append((
179                    vector[0] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR,
180                    vector[1] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR,
181                    vector[2] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR))
182
183            self.lattice_vectors = tuple(new_lattice_vectors)
184
185            if self.a != 0 and self.b != 0 and self.c != 0:
186                self.a = self.a\
187                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
188                self.b = self.b\
189                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
190                self.c = self.c\
191                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
192
193            self.converted_to_angstroms = True

Unit cell.

Object represent unit cell.

Attributes:
  • a (float): Angstroms
  • b (float): Angstroms
  • c (float): Angstroms
  • lattice_vectors (tuple[vector]): Table represents lattice vectors.
  • alfa (deg): deg
  • beta (deg): deg
  • gamma (deg): deg
UnitCell( lattice_vectors: tuple[tuple[float, float, float]] | tuple = (), converted_to_angstroms: bool = False, a: float = 0, b: float = 0, c: float = 0, alfa: float = 0, beta: float = 0, gamma: float = 0)
def calculate_edges_lengths(self) -> tuple[float, float, float] | None:
 72    def calculate_edges_lengths(self) -> tuple[x, y, z] | None:
 73        """Calculate edge lengths
 74
 75        Example:
 76        >>> unit_cell = UnitCell()
 77        >>> unit_cell.lattice_vectors = ((1, 0, 0),\
 78                                         (0, 1, 0),\
 79                                         (0, 0, 1))
 80        >>> unit_cell.calculate_edges_lengths()
 81        (1.0, 1.0, 1.0)
 82        >>> unit_cell.a
 83        1.0
 84
 85        Returns:
 86            **tuple[x, y, z] | None**: To calculate edges lattice_vectors
 87                                   are required else returns None
 88        """
 89        if self.lattice_vectors == ():
 90            return None
 91        else:
 92            self.a = (self.lattice_vectors[0][0] ** 2
 93                      + self.lattice_vectors[0][1] ** 2
 94                      + self.lattice_vectors[0][2] ** 2) ** (1/2)
 95            self.b = (self.lattice_vectors[1][0] ** 2
 96                      + self.lattice_vectors[1][1] ** 2
 97                      + self.lattice_vectors[1][2] ** 2) ** (1/2)
 98            self.c = (self.lattice_vectors[2][0] ** 2
 99                      + self.lattice_vectors[2][1] ** 2
100                      + self.lattice_vectors[2][2] ** 2) ** (1/2)
101            return (self.a, self.b, self.c)

Calculate edge lengths

Example:

>>> unit_cell = UnitCell()
>>> unit_cell.lattice_vectors = ((1, 0, 0),                                         (0, 1, 0),                                         (0, 0, 1))
>>> unit_cell.calculate_edges_lengths()
(1.0, 1.0, 1.0)
>>> unit_cell.a
1.0
Returns:

tuple[x, y, z] | None: To calculate edges lattice_vectors are required else returns None

def calculate_interaxial_angles(self) -> tuple[float, float, float] | None:
103    def calculate_interaxial_angles(self) -> tuple[deg, deg, deg] | None:
104        """Calculate interaxial angles.
105
106        Example:
107        >>> unit_cell = UnitCell()
108        >>> unit_cell.lattice_vectors = ((1, 1, 0),\
109                                         (0, 1, 0),\
110                                         (0, 0, 1))
111        >>> angles = unit_cell.calculate_interaxial_angles()
112        >>> round(angles[0], 1)
113        90.0
114        >>> round(angles[1], 1)
115        90.0
116        >>> round(angles[2], 1)
117        45.0
118
119        Returns:
120            **tuple[deg, deg, deg] | None**: To calculate angles lattice_vectors
121                                         are required else returns None
122        """
123        if self.lattice_vectors == ():
124            return None
125        else:
126            if self.a == 0 or self.b == 0 or self.c == 0:
127                self.calculate_edges_lengths()
128
129            self.alfa = degrees(acos((
130                self.lattice_vectors[1][0]
131                * self.lattice_vectors[2][0]
132                + self.lattice_vectors[1][1]
133                * self.lattice_vectors[2][1]
134                + self.lattice_vectors[1][2]
135                * self.lattice_vectors[2][2])
136                / (self.b * self.c)))
137
138            self.beta = degrees(acos((
139                self.lattice_vectors[0][0]
140                * self.lattice_vectors[2][0]
141                + self.lattice_vectors[0][1]
142                * self.lattice_vectors[2][1]
143                + self.lattice_vectors[0][2]
144                * self.lattice_vectors[2][2])
145                / (self.a * self.c)))
146
147            self.gamma = degrees(acos((
148                self.lattice_vectors[0][0]
149                * self.lattice_vectors[1][0]
150                + self.lattice_vectors[0][1]
151                * self.lattice_vectors[1][1]
152                + self.lattice_vectors[0][2]
153                * self.lattice_vectors[1][2])
154                / (self.a * self.b)))
155
156            return (self.alfa, self.beta, self.gamma)

Calculate interaxial angles.

Example:

>>> unit_cell = UnitCell()
>>> unit_cell.lattice_vectors = ((1, 1, 0),                                         (0, 1, 0),                                         (0, 0, 1))
>>> angles = unit_cell.calculate_interaxial_angles()
>>> round(angles[0], 1)
90.0
>>> round(angles[1], 1)
90.0
>>> round(angles[2], 1)
45.0
Returns:

tuple[deg, deg, deg] | None: To calculate angles lattice_vectors are required else returns None

def convert_cell_data_to_angstroms(self) -> None:
158    def convert_cell_data_to_angstroms(self) -> None:
159        """Convert cell data to angstroms.
160
161        You can use it to convert data in lattice_vectors, a, b and c
162        from Bohr units to angstroms.
163
164        Example:
165        >>> unit_cell = UnitCell()
166        >>> unit_cell.lattice_vectors = ((1, 1, 0),\
167                                         (0, 1, 0),\
168                                         (0, 0, 1))
169        >>> unit_cell.convert_cell_data_to_angstroms()
170        >>> unit_cell.lattice_vectors
171        ((0.52917720859, 0.52917720859, 0.0), (0.0, 0.52917720859, 0.0), \
172(0.0, 0.0, 0.52917720859))
173
174        """
175        if self.converted_to_angstroms is False:
176            new_lattice_vectors = []
177            for vector in self.lattice_vectors:
178                new_lattice_vectors.append((
179                    vector[0] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR,
180                    vector[1] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR,
181                    vector[2] * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR))
182
183            self.lattice_vectors = tuple(new_lattice_vectors)
184
185            if self.a != 0 and self.b != 0 and self.c != 0:
186                self.a = self.a\
187                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
188                self.b = self.b\
189                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
190                self.c = self.c\
191                    * self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
192
193            self.converted_to_angstroms = True

Convert cell data to angstroms.

You can use it to convert data in lattice_vectors, a, b and c from Bohr units to angstroms.

Example:

>>> unit_cell = UnitCell()
>>> unit_cell.lattice_vectors = ((1, 1, 0),                                         (0, 1, 0),                                         (0, 0, 1))
>>> unit_cell.convert_cell_data_to_angstroms()
>>> unit_cell.lattice_vectors
((0.52917720859, 0.52917720859, 0.0), (0.0, 0.52917720859, 0.0), (0.0, 0.0, 0.52917720859))
class Populations:
196class Populations:
197    """Populations from MULLIKEN, LOWDIN analysis."""
198
199    mulliken: dict[int, tuple[str, float]] = {}
200    lodwin: dict[int, tuple[str, float]] = {}
201    valence: dict[int, tuple[str, float]] = {}
202
203    def __init__(self) -> None:
204        pass

Populations from MULLIKEN, LOWDIN analysis.

class MayerBondOrders:
207class MayerBondOrders:
208    """Object stores Mayer bond orders of atoms pairs."""
209    rows = list[float]
210    """Type alias."""
211    mayer_bond_orders: list[rows] = []
212    horizontal_atom_symbol: dict[int, str] = {}
213    atom_id: list[int] = []
214    vertical_atom_symbol: dict[int, str] = {}
215
216    def __init__(self, mayer_bond_orders: list[rows],
217                 atom_id: list[int],
218                 horizontal_atom_symbol: dict[int, str] = {},
219                 vertical_atom_symbol: dict[int, str] = {}):
220
221        if (len(mayer_bond_orders) == len(atom_id) and
222           len(mayer_bond_orders[0]) == len(atom_id)):
223            self.mayer_bond_orders = mayer_bond_orders
224            self.atom_id = atom_id
225        else:
226            raise ValueError("Size of mayer_bond_orders must fit"
227                             + "to horizontal_atom_id and "
228                             + "vertical_atom_id!!!")
229
230        if (horizontal_atom_symbol != {} and vertical_atom_symbol != {}
231            and len(horizontal_atom_symbol) == len(mayer_bond_orders)
232                and len(vertical_atom_symbol) == len(mayer_bond_orders[0])):
233            self.horizontal_atom_symbol = horizontal_atom_symbol
234            self.vertical_atom_symbol = vertical_atom_symbol
235        elif (horizontal_atom_symbol == {}
236              and vertical_atom_symbol == {}):
237            pass
238        else:
239            raise ValueError("Size of mayer_bond_orders must fit"
240                             + "to horizontal_atom_symbol and "
241                             + "vertical_atom_symbol!!!")
242
243    def get_mayer_bond_order_between_atoms(self, atom_id_1: int, atom_id_2:
244                                           int) -> float:
245        """Get mayer bond order between atoms.
246
247        Args:
248            atom_id_1 (int): first atom id (row)
249            atom_id_2 (int): second atom id (column)
250
251        Returns:
252            **float**: bond order
253        """
254
255        row = self.mayer_bond_orders[self.atom_id.index(atom_id_2)]
256        return row[self.atom_id.index(atom_id_1)]
257
258    def get_atoms_ids(self, atom_symbol: str) -> list[int]:
259        """Get atoms ids in MayerBondOrders.
260
261        Args:
262            atom_symbol (str): Symbol of atom eg. P, Fe, ...
263
264        Returns:
265            **list[int]**: list of ids
266        """
267        ids = []
268        for key, value in self.horizontal_atom_symbol.items():
269            if value == atom_symbol:
270                ids.append(key)
271
272        return ids
273
274    def check_atom_symbol_in_MBO(self, atom_symbol: str) -> bool:
275        """Check atom symbol in MayerBondOrders object.
276
277        Args:
278            atom_symbol (str): Symbol of atom eg. 'P'.
279
280        Returns:
281            **bool**: True if in MayerBondOrders object.
282
283        """
284        if self.get_atoms_ids(atom_symbol) == []:
285            return False
286        else:
287            return True
288
289    def get_atom_symbols(self, atom_id_1: int, atom_id_2:
290                         int) -> tuple[str, str] | None:
291        """Get atom symbols of pair of atoms.
292
293        Args:
294            atom_id_1 (int): atom 1 id
295            atom_id_2 (int): atom 2 id
296
297        Returns:
298            **tuple(str, str) | None**: Symbol of atom 1 and atom 2,
299                                    if wrong id of atoms returns None or
300                                    atoms symbols have not been used.
301
302        """
303        atom_1 = self.horizontal_atom_symbol.get(atom_id_1, None)
304        atom_2 = self.vertical_atom_symbol.get(atom_id_2, None)
305
306        if atom_1 is None or atom_2 is None:
307            return None
308        else:
309            return (atom_1, atom_2)
310
311    def get_all_mayer_bond_orders_of_atom(self, atom_id) -> list[float]:
312        """Returns list of mayer bond orders of atom of given id.
313
314        Args:
315            atom_id (int): atom id.
316
317        Returns:
318            **list[float]**: list of mayer bond orders.
319        """
320        row = self.mayer_bond_orders[self.atom_id.index(atom_id)]
321        return row
322
323    def get_mayer_bond_orders_list_between_two_atoms(self, atom_symbol_1: str,
324                                                     atom_symbol_2: str
325                                                     ) -> list[float]:
326        """Get Mayer bond orders list between two atoms.
327
328        Args:
329            atom_symbol_1 (str): atom symbol eg. "Fe"
330            atom_symbol_2 (str): atom symbol eg. "Fe"
331
332        Returns:
333            **list[float]**: list of mayer bond orders
334        """
335        mayer_bond_orders = []
336        for atom_id_1 in self.atom_id:
337            if atom_symbol_1 == self.vertical_atom_symbol.get(atom_id_1):
338                for atom_id_2 in range(atom_id_1 + 1, len(self.atom_id) + 1):
339                    if atom_symbol_2 == self.vertical_atom_symbol.get(atom_id_2):
340                        mayer_bond_orders.append(
341                            self.get_mayer_bond_order_between_atoms(atom_id_1,
342                                                                    atom_id_2))
343
344        return mayer_bond_orders

Object stores Mayer bond orders of atoms pairs.

MayerBondOrders( mayer_bond_orders: list[list[float]], atom_id: list[int], horizontal_atom_symbol: dict[int, str] = {}, vertical_atom_symbol: dict[int, str] = {})
216    def __init__(self, mayer_bond_orders: list[rows],
217                 atom_id: list[int],
218                 horizontal_atom_symbol: dict[int, str] = {},
219                 vertical_atom_symbol: dict[int, str] = {}):
220
221        if (len(mayer_bond_orders) == len(atom_id) and
222           len(mayer_bond_orders[0]) == len(atom_id)):
223            self.mayer_bond_orders = mayer_bond_orders
224            self.atom_id = atom_id
225        else:
226            raise ValueError("Size of mayer_bond_orders must fit"
227                             + "to horizontal_atom_id and "
228                             + "vertical_atom_id!!!")
229
230        if (horizontal_atom_symbol != {} and vertical_atom_symbol != {}
231            and len(horizontal_atom_symbol) == len(mayer_bond_orders)
232                and len(vertical_atom_symbol) == len(mayer_bond_orders[0])):
233            self.horizontal_atom_symbol = horizontal_atom_symbol
234            self.vertical_atom_symbol = vertical_atom_symbol
235        elif (horizontal_atom_symbol == {}
236              and vertical_atom_symbol == {}):
237            pass
238        else:
239            raise ValueError("Size of mayer_bond_orders must fit"
240                             + "to horizontal_atom_symbol and "
241                             + "vertical_atom_symbol!!!")
rows = list[float]

Type alias.

def get_mayer_bond_order_between_atoms(self, atom_id_1: int, atom_id_2: int) -> float:
243    def get_mayer_bond_order_between_atoms(self, atom_id_1: int, atom_id_2:
244                                           int) -> float:
245        """Get mayer bond order between atoms.
246
247        Args:
248            atom_id_1 (int): first atom id (row)
249            atom_id_2 (int): second atom id (column)
250
251        Returns:
252            **float**: bond order
253        """
254
255        row = self.mayer_bond_orders[self.atom_id.index(atom_id_2)]
256        return row[self.atom_id.index(atom_id_1)]

Get mayer bond order between atoms.

Arguments:
  • atom_id_1 (int): first atom id (row)
  • atom_id_2 (int): second atom id (column)
Returns:

float: bond order

def get_atoms_ids(self, atom_symbol: str) -> list[int]:
258    def get_atoms_ids(self, atom_symbol: str) -> list[int]:
259        """Get atoms ids in MayerBondOrders.
260
261        Args:
262            atom_symbol (str): Symbol of atom eg. P, Fe, ...
263
264        Returns:
265            **list[int]**: list of ids
266        """
267        ids = []
268        for key, value in self.horizontal_atom_symbol.items():
269            if value == atom_symbol:
270                ids.append(key)
271
272        return ids

Get atoms ids in MayerBondOrders.

Arguments:
  • atom_symbol (str): Symbol of atom eg. P, Fe, ...
Returns:

list[int]: list of ids

def check_atom_symbol_in_MBO(self, atom_symbol: str) -> bool:
274    def check_atom_symbol_in_MBO(self, atom_symbol: str) -> bool:
275        """Check atom symbol in MayerBondOrders object.
276
277        Args:
278            atom_symbol (str): Symbol of atom eg. 'P'.
279
280        Returns:
281            **bool**: True if in MayerBondOrders object.
282
283        """
284        if self.get_atoms_ids(atom_symbol) == []:
285            return False
286        else:
287            return True

Check atom symbol in MayerBondOrders object.

Arguments:
  • atom_symbol (str): Symbol of atom eg. 'P'.
Returns:

bool: True if in MayerBondOrders object.

def get_atom_symbols(self, atom_id_1: int, atom_id_2: int) -> tuple[str, str] | None:
289    def get_atom_symbols(self, atom_id_1: int, atom_id_2:
290                         int) -> tuple[str, str] | None:
291        """Get atom symbols of pair of atoms.
292
293        Args:
294            atom_id_1 (int): atom 1 id
295            atom_id_2 (int): atom 2 id
296
297        Returns:
298            **tuple(str, str) | None**: Symbol of atom 1 and atom 2,
299                                    if wrong id of atoms returns None or
300                                    atoms symbols have not been used.
301
302        """
303        atom_1 = self.horizontal_atom_symbol.get(atom_id_1, None)
304        atom_2 = self.vertical_atom_symbol.get(atom_id_2, None)
305
306        if atom_1 is None or atom_2 is None:
307            return None
308        else:
309            return (atom_1, atom_2)

Get atom symbols of pair of atoms.

Arguments:
  • atom_id_1 (int): atom 1 id
  • atom_id_2 (int): atom 2 id
Returns:

tuple(str, str) | None: Symbol of atom 1 and atom 2, if wrong id of atoms returns None or atoms symbols have not been used.

def get_all_mayer_bond_orders_of_atom(self, atom_id) -> list[float]:
311    def get_all_mayer_bond_orders_of_atom(self, atom_id) -> list[float]:
312        """Returns list of mayer bond orders of atom of given id.
313
314        Args:
315            atom_id (int): atom id.
316
317        Returns:
318            **list[float]**: list of mayer bond orders.
319        """
320        row = self.mayer_bond_orders[self.atom_id.index(atom_id)]
321        return row

Returns list of mayer bond orders of atom of given id.

Arguments:
  • atom_id (int): atom id.
Returns:

list[float]: list of mayer bond orders.

def get_mayer_bond_orders_list_between_two_atoms(self, atom_symbol_1: str, atom_symbol_2: str) -> list[float]:
323    def get_mayer_bond_orders_list_between_two_atoms(self, atom_symbol_1: str,
324                                                     atom_symbol_2: str
325                                                     ) -> list[float]:
326        """Get Mayer bond orders list between two atoms.
327
328        Args:
329            atom_symbol_1 (str): atom symbol eg. "Fe"
330            atom_symbol_2 (str): atom symbol eg. "Fe"
331
332        Returns:
333            **list[float]**: list of mayer bond orders
334        """
335        mayer_bond_orders = []
336        for atom_id_1 in self.atom_id:
337            if atom_symbol_1 == self.vertical_atom_symbol.get(atom_id_1):
338                for atom_id_2 in range(atom_id_1 + 1, len(self.atom_id) + 1):
339                    if atom_symbol_2 == self.vertical_atom_symbol.get(atom_id_2):
340                        mayer_bond_orders.append(
341                            self.get_mayer_bond_order_between_atoms(atom_id_1,
342                                                                    atom_id_2))
343
344        return mayer_bond_orders

Get Mayer bond orders list between two atoms.

Arguments:
  • atom_symbol_1 (str): atom symbol eg. "Fe"
  • atom_symbol_2 (str): atom symbol eg. "Fe"
Returns:

list[float]: list of mayer bond orders

class CoordinatesOfAtoms(Constants):
347class CoordinatesOfAtoms(Constants):
348    """Object represents coordinates of atoms.
349
350    Args:
351        atom_coordinates_table (list[tuple[atom_id, str, x, y, z]], optional): \
352        Table with atom coordinates.
353
354    Attributes:
355        ids (list[atom_id]): ids of atoms.
356        atom_symbols (dict[atom_id, str]): \
357        Dictionary storing symbols of atoms, key is atom id.
358
359    Types:
360        atom_id = int
361
362    """
363
364    atom_id: TypeAlias = int
365    """Type alias"""
366    ids: list[atom_id]
367    _coordinates: dict[atom_id, vector]
368    atom_symbols: dict[atom_id, str]
369    _unit_cell: UnitCell | None
370
371    def __init__(self, atom_coordinates_table: list[tuple[atom_id, str, x, y,
372                                                          z]] = []) -> None:
373
374        self.ids = []
375        self._coordinates = {}
376        self.atom_symbols = {}
377        self._unit_cell = None
378
379        if atom_coordinates_table != []:
380            while atom_coordinates_table != []:
381                row = atom_coordinates_table.pop(0)
382                self.ids.append(row[0])
383                self.atom_symbols.update({row[0]: row[1]})
384                self._coordinates.update({row[0]: (row[2], row[3], row[4])})
385
386    def add_new_atom(self, id: int, atom_symbol: str, coordinates:
387                     tuple[x, y, z]) -> None:
388        """Add new atom coordinates to CoordinatesOfAtoms object.
389
390        Args:
391            id (int): id of new atom.
392            atom_symbol (str): Symbol of new atom.
393            coordinates (tuple[x, y, z]): Coordinates of new atom.
394
395        """
396        self.ids.append(id)
397        self.atom_symbols.update({id: atom_symbol})
398        self._coordinates.update({id: coordinates})
399
400    def get_atom_coordinates(self, id: int) -> tuple[x, y, z] | None:
401        """Get atoms coordinates.
402
403        Args:
404            id (int): atom id
405
406        Returns:
407            **tuple[x, y, z] | None**: Returns atom coordinates or None if atom of
408                                   given id does not exist.
409
410        """
411        return self._coordinates.get(id, None)
412
413    def get_atom_coordinates_converted_in_angstrom(self, id: int)\
414            -> tuple[x, y, z] | None:
415        """Get atom coordinates converted in angstroms if they were stored as
416        Bohr units. Not change stored values.
417
418        Example:
419        >>> coordinates_of_atoms = CoordinatesOfAtoms()
420        >>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
421        >>> coordinates_of_atoms.get_atom_coordinates_converted_in_angstrom(1)
422        (0.52917720859, 0.52917720859, 0.52917720859)
423
424        Args:
425            id (int): atom id
426
427        Returns:
428            **tuple[x, y, z]**: coordinates in angstroms
429
430        """
431        temp_coordinates = self._coordinates.get(id, None)
432        if temp_coordinates is not None:
433            coordinates = (
434                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
435                * temp_coordinates[0],
436                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
437                * temp_coordinates[1],
438                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
439                * temp_coordinates[2])
440            return coordinates
441        else:
442            return None
443
444    def convert_stored_coordinates_to_angstroms(self) -> None:
445        """Converts stored coordinates from bohr units to angstroms.
446
447        Example:
448        >>> coordinates_of_atoms = CoordinatesOfAtoms()
449        >>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
450        >>> coordinates_of_atoms.add_new_atom(2, 'P', (0, 0, 0))
451        >>> coordinates_of_atoms.convert_stored_coordinates_to_angstroms()
452        >>> coordinates_of_atoms.get_atom_coordinates(1)
453        (0.52917720859, 0.52917720859, 0.52917720859)
454
455        """
456
457        for id, coord in self._coordinates.items():
458            self._coordinates[id] = (
459                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[0],
460                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[1],
461                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[2],
462            )
463
464    def get_atom_symbol(self, id: int) -> str | None:
465        """Get atom symbol
466
467        Args:
468            id (int): atom id
469
470        Returns:
471            **Union[str, None]**: Returns atom symbol or None if atom of
472                        given id does not exist.
473
474        """
475        return self.atom_symbols.get(id)
476
477    @property
478    def coordinates(self) -> list[vector]:
479        coordinates = [value for value in self._coordinates.values()]
480        return coordinates
481
482    def add_unit_cell(self, unit_cell: UnitCell):
483        self._unit_cell = unit_cell
484
485    def remove_unit_cell(self):
486        self._unit_cell = None
487
488    def get_distance_between_atoms(self, atom_id_1: int, atom_id_2: int)\
489            -> float | None:
490        """ Calculate distance between two atoms.
491
492        Args:
493            atom_id_1 (int): id of first atom
494             atom_id_2 (int): id of second atom
495        Returns:
496            **float | None**: Distance in angstroms or Bohr units.
497
498        """
499
500        if type(self._unit_cell) is not UnitCell:
501            raise Exception("Unit cell not added or wrong type of"
502                            + " unit_cell, use .add_unit_cell(self, unit_cell) method!!!")
503
504        atom_coord_1_v = self._coordinates.get(atom_id_1, None)
505        atom_coord_2_v = self._coordinates.get(atom_id_2, None)
506
507        if atom_coord_1_v is None or atom_coord_2_v is None:
508            return None
509        else:
510            atom_coord_1 = np.array(atom_coord_1_v)
511            atom_coord_2 = np.array(atom_coord_2_v)
512
513        vector_between_atoms = atom_coord_1 - atom_coord_2
514
515        length = float(np.linalg.norm(vector_between_atoms))
516
517        lattice_vectors_list = []
518        for vector in self._unit_cell.lattice_vectors:
519            lattice_vectors_list.append(np.array(vector))
520
521        def get_lower_distance(length: float, vector_1: NDArray,
522                               vector_2: NDArray) -> float:
523            vector_between_atoms = vector_1 - vector_2
524
525            new_length = float(np.linalg.norm(vector_between_atoms))
526
527            if new_length < length:
528                length = new_length
529
530            return length
531
532        for vector in lattice_vectors_list:
533            atom_2_coord_in_neighboring_unit = atom_coord_2 + vector
534
535            length = get_lower_distance(length, atom_coord_1,
536                                        atom_2_coord_in_neighboring_unit)
537
538        for vector in lattice_vectors_list:
539            atom_2_coord_in_neighboring_unit = atom_coord_2 - vector
540
541            length = get_lower_distance(length, atom_coord_1,
542                                        atom_2_coord_in_neighboring_unit)
543
544        for i in range(3):
545            for j in range(i + 1, 3):
546                translation = lattice_vectors_list[i] + lattice_vectors_list[j]
547                atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
548
549                length = get_lower_distance(length, atom_coord_1,
550                                            atom_2_coord_in_neighboring_unit)
551
552                atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
553
554                length = get_lower_distance(length, atom_coord_1,
555                                            atom_2_coord_in_neighboring_unit)
556
557                translation = lattice_vectors_list[i] - lattice_vectors_list[j]
558                atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
559
560                length = get_lower_distance(length, atom_coord_1,
561                                            atom_2_coord_in_neighboring_unit)
562
563                atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
564
565                length = get_lower_distance(length, atom_coord_1,
566                                            atom_2_coord_in_neighboring_unit)
567
568        translation = lattice_vectors_list[0] + lattice_vectors_list[1]\
569            + lattice_vectors_list[2]
570
571        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
572
573        length = get_lower_distance(length, atom_coord_1,
574                                    atom_2_coord_in_neighboring_unit)
575
576        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
577
578        length = get_lower_distance(length, atom_coord_1,
579                                    atom_2_coord_in_neighboring_unit)
580
581        translation = lattice_vectors_list[0] - lattice_vectors_list[1]\
582            + lattice_vectors_list[2]
583
584        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
585
586        length = get_lower_distance(length, atom_coord_1,
587                                    atom_2_coord_in_neighboring_unit)
588
589        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
590
591        length = get_lower_distance(length, atom_coord_1,
592                                    atom_2_coord_in_neighboring_unit)
593
594        translation = lattice_vectors_list[0] - lattice_vectors_list[1]\
595            - lattice_vectors_list[2]
596
597        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
598
599        length = get_lower_distance(length, atom_coord_1,
600                                    atom_2_coord_in_neighboring_unit)
601
602        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
603
604        length = get_lower_distance(length, atom_coord_1,
605                                    atom_2_coord_in_neighboring_unit)
606
607        translation = lattice_vectors_list[0] + lattice_vectors_list[1]\
608            - lattice_vectors_list[2]
609
610        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
611
612        length = get_lower_distance(length, atom_coord_1,
613                                    atom_2_coord_in_neighboring_unit)
614
615        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
616
617        length = get_lower_distance(length, atom_coord_1,
618                                    atom_2_coord_in_neighboring_unit)
619
620        return length

Object represents coordinates of atoms.

Arguments:
  • atom_coordinates_table (list[tuple[atom_id, str, x, y, z]], optional): Table with atom coordinates.
Attributes:
  • ids (list[atom_id]): ids of atoms.
  • atom_symbols (dict[atom_id, str]): Dictionary storing symbols of atoms, key is atom id.
Types:

atom_id = int

CoordinatesOfAtoms( atom_coordinates_table: list[tuple[int, str, float, float, float]] = [])
371    def __init__(self, atom_coordinates_table: list[tuple[atom_id, str, x, y,
372                                                          z]] = []) -> None:
373
374        self.ids = []
375        self._coordinates = {}
376        self.atom_symbols = {}
377        self._unit_cell = None
378
379        if atom_coordinates_table != []:
380            while atom_coordinates_table != []:
381                row = atom_coordinates_table.pop(0)
382                self.ids.append(row[0])
383                self.atom_symbols.update({row[0]: row[1]})
384                self._coordinates.update({row[0]: (row[2], row[3], row[4])})
atom_id: TypeAlias = <class 'int'>

Type alias

def add_new_atom( self, id: int, atom_symbol: str, coordinates: tuple[float, float, float]) -> None:
386    def add_new_atom(self, id: int, atom_symbol: str, coordinates:
387                     tuple[x, y, z]) -> None:
388        """Add new atom coordinates to CoordinatesOfAtoms object.
389
390        Args:
391            id (int): id of new atom.
392            atom_symbol (str): Symbol of new atom.
393            coordinates (tuple[x, y, z]): Coordinates of new atom.
394
395        """
396        self.ids.append(id)
397        self.atom_symbols.update({id: atom_symbol})
398        self._coordinates.update({id: coordinates})

Add new atom coordinates to CoordinatesOfAtoms object.

Arguments:
  • id (int): id of new atom.
  • atom_symbol (str): Symbol of new atom.
  • coordinates (tuple[x, y, z]): Coordinates of new atom.
def get_atom_coordinates(self, id: int) -> tuple[float, float, float] | None:
400    def get_atom_coordinates(self, id: int) -> tuple[x, y, z] | None:
401        """Get atoms coordinates.
402
403        Args:
404            id (int): atom id
405
406        Returns:
407            **tuple[x, y, z] | None**: Returns atom coordinates or None if atom of
408                                   given id does not exist.
409
410        """
411        return self._coordinates.get(id, None)

Get atoms coordinates.

Arguments:
  • id (int): atom id
Returns:

tuple[x, y, z] | None: Returns atom coordinates or None if atom of given id does not exist.

def get_atom_coordinates_converted_in_angstrom(self, id: int) -> tuple[float, float, float] | None:
413    def get_atom_coordinates_converted_in_angstrom(self, id: int)\
414            -> tuple[x, y, z] | None:
415        """Get atom coordinates converted in angstroms if they were stored as
416        Bohr units. Not change stored values.
417
418        Example:
419        >>> coordinates_of_atoms = CoordinatesOfAtoms()
420        >>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
421        >>> coordinates_of_atoms.get_atom_coordinates_converted_in_angstrom(1)
422        (0.52917720859, 0.52917720859, 0.52917720859)
423
424        Args:
425            id (int): atom id
426
427        Returns:
428            **tuple[x, y, z]**: coordinates in angstroms
429
430        """
431        temp_coordinates = self._coordinates.get(id, None)
432        if temp_coordinates is not None:
433            coordinates = (
434                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
435                * temp_coordinates[0],
436                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
437                * temp_coordinates[1],
438                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR
439                * temp_coordinates[2])
440            return coordinates
441        else:
442            return None

Get atom coordinates converted in angstroms if they were stored as Bohr units. Not change stored values.

Example:

>>> coordinates_of_atoms = CoordinatesOfAtoms()
>>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
>>> coordinates_of_atoms.get_atom_coordinates_converted_in_angstrom(1)
(0.52917720859, 0.52917720859, 0.52917720859)
Arguments:
  • id (int): atom id
Returns:

tuple[x, y, z]: coordinates in angstroms

def convert_stored_coordinates_to_angstroms(self) -> None:
444    def convert_stored_coordinates_to_angstroms(self) -> None:
445        """Converts stored coordinates from bohr units to angstroms.
446
447        Example:
448        >>> coordinates_of_atoms = CoordinatesOfAtoms()
449        >>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
450        >>> coordinates_of_atoms.add_new_atom(2, 'P', (0, 0, 0))
451        >>> coordinates_of_atoms.convert_stored_coordinates_to_angstroms()
452        >>> coordinates_of_atoms.get_atom_coordinates(1)
453        (0.52917720859, 0.52917720859, 0.52917720859)
454
455        """
456
457        for id, coord in self._coordinates.items():
458            self._coordinates[id] = (
459                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[0],
460                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[1],
461                self._CONSTANT_TO_CALCULATE_ANGSTROMS_FROM_BOHR * coord[2],
462            )

Converts stored coordinates from bohr units to angstroms.

Example:

>>> coordinates_of_atoms = CoordinatesOfAtoms()
>>> coordinates_of_atoms.add_new_atom(1, 'P', (1, 1, 1))
>>> coordinates_of_atoms.add_new_atom(2, 'P', (0, 0, 0))
>>> coordinates_of_atoms.convert_stored_coordinates_to_angstroms()
>>> coordinates_of_atoms.get_atom_coordinates(1)
(0.52917720859, 0.52917720859, 0.52917720859)
def get_atom_symbol(self, id: int) -> str | None:
464    def get_atom_symbol(self, id: int) -> str | None:
465        """Get atom symbol
466
467        Args:
468            id (int): atom id
469
470        Returns:
471            **Union[str, None]**: Returns atom symbol or None if atom of
472                        given id does not exist.
473
474        """
475        return self.atom_symbols.get(id)

Get atom symbol

Arguments:
  • id (int): atom id
Returns:

Union[str, None]: Returns atom symbol or None if atom of given id does not exist.

def add_unit_cell(self, unit_cell: bond_order_processing.input_data.UnitCell):
482    def add_unit_cell(self, unit_cell: UnitCell):
483        self._unit_cell = unit_cell
def remove_unit_cell(self):
485    def remove_unit_cell(self):
486        self._unit_cell = None
def get_distance_between_atoms(self, atom_id_1: int, atom_id_2: int) -> float | None:
488    def get_distance_between_atoms(self, atom_id_1: int, atom_id_2: int)\
489            -> float | None:
490        """ Calculate distance between two atoms.
491
492        Args:
493            atom_id_1 (int): id of first atom
494             atom_id_2 (int): id of second atom
495        Returns:
496            **float | None**: Distance in angstroms or Bohr units.
497
498        """
499
500        if type(self._unit_cell) is not UnitCell:
501            raise Exception("Unit cell not added or wrong type of"
502                            + " unit_cell, use .add_unit_cell(self, unit_cell) method!!!")
503
504        atom_coord_1_v = self._coordinates.get(atom_id_1, None)
505        atom_coord_2_v = self._coordinates.get(atom_id_2, None)
506
507        if atom_coord_1_v is None or atom_coord_2_v is None:
508            return None
509        else:
510            atom_coord_1 = np.array(atom_coord_1_v)
511            atom_coord_2 = np.array(atom_coord_2_v)
512
513        vector_between_atoms = atom_coord_1 - atom_coord_2
514
515        length = float(np.linalg.norm(vector_between_atoms))
516
517        lattice_vectors_list = []
518        for vector in self._unit_cell.lattice_vectors:
519            lattice_vectors_list.append(np.array(vector))
520
521        def get_lower_distance(length: float, vector_1: NDArray,
522                               vector_2: NDArray) -> float:
523            vector_between_atoms = vector_1 - vector_2
524
525            new_length = float(np.linalg.norm(vector_between_atoms))
526
527            if new_length < length:
528                length = new_length
529
530            return length
531
532        for vector in lattice_vectors_list:
533            atom_2_coord_in_neighboring_unit = atom_coord_2 + vector
534
535            length = get_lower_distance(length, atom_coord_1,
536                                        atom_2_coord_in_neighboring_unit)
537
538        for vector in lattice_vectors_list:
539            atom_2_coord_in_neighboring_unit = atom_coord_2 - vector
540
541            length = get_lower_distance(length, atom_coord_1,
542                                        atom_2_coord_in_neighboring_unit)
543
544        for i in range(3):
545            for j in range(i + 1, 3):
546                translation = lattice_vectors_list[i] + lattice_vectors_list[j]
547                atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
548
549                length = get_lower_distance(length, atom_coord_1,
550                                            atom_2_coord_in_neighboring_unit)
551
552                atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
553
554                length = get_lower_distance(length, atom_coord_1,
555                                            atom_2_coord_in_neighboring_unit)
556
557                translation = lattice_vectors_list[i] - lattice_vectors_list[j]
558                atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
559
560                length = get_lower_distance(length, atom_coord_1,
561                                            atom_2_coord_in_neighboring_unit)
562
563                atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
564
565                length = get_lower_distance(length, atom_coord_1,
566                                            atom_2_coord_in_neighboring_unit)
567
568        translation = lattice_vectors_list[0] + lattice_vectors_list[1]\
569            + lattice_vectors_list[2]
570
571        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
572
573        length = get_lower_distance(length, atom_coord_1,
574                                    atom_2_coord_in_neighboring_unit)
575
576        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
577
578        length = get_lower_distance(length, atom_coord_1,
579                                    atom_2_coord_in_neighboring_unit)
580
581        translation = lattice_vectors_list[0] - lattice_vectors_list[1]\
582            + lattice_vectors_list[2]
583
584        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
585
586        length = get_lower_distance(length, atom_coord_1,
587                                    atom_2_coord_in_neighboring_unit)
588
589        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
590
591        length = get_lower_distance(length, atom_coord_1,
592                                    atom_2_coord_in_neighboring_unit)
593
594        translation = lattice_vectors_list[0] - lattice_vectors_list[1]\
595            - lattice_vectors_list[2]
596
597        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
598
599        length = get_lower_distance(length, atom_coord_1,
600                                    atom_2_coord_in_neighboring_unit)
601
602        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
603
604        length = get_lower_distance(length, atom_coord_1,
605                                    atom_2_coord_in_neighboring_unit)
606
607        translation = lattice_vectors_list[0] + lattice_vectors_list[1]\
608            - lattice_vectors_list[2]
609
610        atom_2_coord_in_neighboring_unit = atom_coord_2 + translation
611
612        length = get_lower_distance(length, atom_coord_1,
613                                    atom_2_coord_in_neighboring_unit)
614
615        atom_2_coord_in_neighboring_unit = atom_coord_2 - translation
616
617        length = get_lower_distance(length, atom_coord_1,
618                                    atom_2_coord_in_neighboring_unit)
619
620        return length

Calculate distance between two atoms.

Arguments:
  • atom_id_1 (int): id of first atom atom_id_2 (int): id of second atom
Returns:

float | None: Distance in angstroms or Bohr units.

class InputData(abc.ABC):
623class InputData(ABC):
624    """Input data.
625
626    Load data from file and create objects.
627
628    """
629
630    populations: Populations | None = None
631    unit_cell: UnitCell | None = None
632    mayer_bond_orders: MayerBondOrders | None = None
633    coordinates_of_atoms: CoordinatesOfAtoms | None = None
634
635    def __init__(self, Populations: type = Populations,
636                 UnitCell: type = UnitCell,
637                 MayerBondOrders: type = MayerBondOrders,
638                 CoordinatesOfAtoms: type = CoordinatesOfAtoms):
639        """Constructor.
640
641        Args:
642            Populations (type, optional): Defaults to Populations.
643            UnitCell (type, optional): Defaults to UnitCell.
644            MayerBondOrders (type, optional): Defaults to MayerBondOrders.
645            CoordinatesOfAtoms (type, optional): Defaults to CoordinatesOfAtoms.
646
647        """
648
649        self.Populations = Populations
650        self.UnitCell = UnitCell
651        self.MayerBondOrders = MayerBondOrders
652        self.CoordinatesOfAtoms = CoordinatesOfAtoms
653        self.LoadedData = LoadedData
654
655    @abstractmethod
656    def load_input_data(self, path: str, *args) -> None:
657        """Load input data from file.
658
659        Args:
660            path (str): Path to file.
661            *args: LoadData.UnitCell, LoadedData.MayerBondOrders,\
662                LoadData.Populations or LoadData.CoordinatesOfAtoms
663
664        """
665        pass
666
667    @staticmethod
668    def check_is_correct_file(data_in_file: str, fingerprint: str) -> bool:
669        if fingerprint in data_in_file:
670            return True
671        else:
672            return False

Input data.

Load data from file and create objects.

InputData( Populations: type = <class 'bond_order_processing.input_data.Populations'>, UnitCell: type = <class 'bond_order_processing.input_data.UnitCell'>, MayerBondOrders: type = <class 'bond_order_processing.input_data.MayerBondOrders'>, CoordinatesOfAtoms: type = <class 'bond_order_processing.input_data.CoordinatesOfAtoms'>)
635    def __init__(self, Populations: type = Populations,
636                 UnitCell: type = UnitCell,
637                 MayerBondOrders: type = MayerBondOrders,
638                 CoordinatesOfAtoms: type = CoordinatesOfAtoms):
639        """Constructor.
640
641        Args:
642            Populations (type, optional): Defaults to Populations.
643            UnitCell (type, optional): Defaults to UnitCell.
644            MayerBondOrders (type, optional): Defaults to MayerBondOrders.
645            CoordinatesOfAtoms (type, optional): Defaults to CoordinatesOfAtoms.
646
647        """
648
649        self.Populations = Populations
650        self.UnitCell = UnitCell
651        self.MayerBondOrders = MayerBondOrders
652        self.CoordinatesOfAtoms = CoordinatesOfAtoms
653        self.LoadedData = LoadedData

Constructor.

Arguments:
  • Populations (type, optional): Defaults to Populations.
  • UnitCell (type, optional): Defaults to UnitCell.
  • MayerBondOrders (type, optional): Defaults to MayerBondOrders.
  • CoordinatesOfAtoms (type, optional): Defaults to CoordinatesOfAtoms.
@abstractmethod
def load_input_data(self, path: str, *args) -> None:
655    @abstractmethod
656    def load_input_data(self, path: str, *args) -> None:
657        """Load input data from file.
658
659        Args:
660            path (str): Path to file.
661            *args: LoadData.UnitCell, LoadedData.MayerBondOrders,\
662                LoadData.Populations or LoadData.CoordinatesOfAtoms
663
664        """
665        pass

Load input data from file.

Arguments:
  • path (str): Path to file.
  • *args: LoadData.UnitCell, LoadedData.MayerBondOrders, LoadData.Populations or LoadData.CoordinatesOfAtoms
@staticmethod
def check_is_correct_file(data_in_file: str, fingerprint: str) -> bool:
667    @staticmethod
668    def check_is_correct_file(data_in_file: str, fingerprint: str) -> bool:
669        if fingerprint in data_in_file:
670            return True
671        else:
672            return False
class InputDataFromCPMD(InputData):
675class InputDataFromCPMD(InputData):
676    """Loads data from CPMD file and create objects."""
677    _fingerprint: str = "The CPMD consortium"
678    _fingerprint_beginning_populations: str = "POPULATION ANALYSIS FROM PROJECTED"\
679        + " WAVEFUNCTIONS"
680    _fingerprint_end_populations: str = "ChkSum\(POP_MUL\)"
681    _fingerprint_coordinates_of_atoms: str = "ATOM             COORDINATES"\
682        + "                   CHARGES"
683    _fingerprint_end_coordinates_of_atoms: str = "ChkSum\(CHARGES\)"
684    _fingerprint_mayer_bond_orders: str = "MAYER BOND ORDERS FROM PROJECTED"\
685        + " WAVEFUNCTIONS"
686
687    _fingerprints_unit_cell: tuple[str, str, str] = ("LATTICE VECTOR A1\(BOHR\):",
688                                                     "LATTICE VECTOR A2\(BOHR\):",
689                                                     "LATTICE VECTOR A3\(BOHR\):")
690
691    _valid_population_columns_names: tuple[str, str, str, str] = (
692        'ATOM', 'MULLIKEN', 'LOWDIN', 'VALENCE')
693
694    _valid_coordinatios_columns_names: tuple[str, str, str] = (
695        'X', 'Y', 'Z')
696
697    def load_input_data(self, path: str, *args) -> None:
698        """Loads input data from CPMD file.
699
700        Args:
701            path (str): path to file
702            *args: LoadData.UnitCell, LoadedData.MayerBondOrders,
703            LoadData.Populations or LoadData.CoordinatesOfAtoms
704
705        """
706        with open(path, 'r') as file:
707            data = file.read()
708
709        if self.check_is_correct_file(data, self._fingerprint) is not True:
710            raise Exception("Wrong input file!")
711        else:
712            if self.LoadedData.UnitCell in args:
713                self.unit_cell = self._load_unit_cell(data)
714            if self.LoadedData.MayerBondOrders in args:
715                self.mayer_bond_orders = \
716                    self._load_mayer_bond_orders(data)
717            if self.LoadedData.Populations in args:
718                self.populations = self._load_populations(data)
719            if self.LoadedData.CoordinatesOfAtoms in args:
720                self.coordinates_of_atoms = \
721                    self._load_coordinates_of_atoms(data)
722
723    def return_data(self, loaded_data: LoadedData)\
724            -> Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms\
725            | None:
726        """ Returns loaded data.
727
728        Args:
729
730        Returns:
731            **Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms**:
732
733        """
734        if loaded_data is LoadedData.UnitCell:
735            return self.unit_cell
736        elif loaded_data is LoadedData.MayerBondOrders:
737            return self.mayer_bond_orders
738        elif loaded_data is LoadedData.Populations:
739            return self.populations
740        elif loaded_data is LoadedData.CoordinatesOfAtoms:
741            return self.coordinates_of_atoms
742        else:
743            raise TypeError("Type is not LoadedData!!!!")
744
745    def _load_populations(self, file: str) -> Populations | None:
746
747        rows = self._get_rows_of_data_from_file(file,
748                                                self._fingerprint_beginning_populations,
749                                                self._fingerprint_end_populations)
750        labels: list = []
751        if rows is not None:
752            for row in rows:
753                have_string = True if re.search('[a-zA-Z]+', row) is \
754                    not None else False
755
756                have_number = True if re.search('[0-9]+', row) is \
757                    not None else False
758
759                if have_string and not have_number:
760                    labels = row.split()
761                    populations = Populations()
762                    continue
763                elif have_string and have_number:
764                    splited = row.split()
765                    if len(labels) + 1 != len(splited):
766                        raise Exception(
767                            'Wrong quantity of columns in input file!')
768                    else:
769                        populations = self._add_populations_attributes(
770                            populations, splited, labels)
771            return populations
772        else:
773            return None
774
775    @classmethod
776    def _add_populations_attributes(cls, populations: Populations,
777                                    splited: list, labels: list[str])\
778            -> Populations:
779        i = 0
780        for item in splited:
781            if i == 0:
782                id = int(item)
783            elif labels[i-1] == cls._valid_population_columns_names[0]:
784                symbol = item
785            elif labels[i-1] == cls._valid_population_columns_names[1]:
786                mulliken_value = float(item)
787            elif labels[i-1] == cls._valid_population_columns_names[2]:
788                lowdin_value = float(item)
789            elif labels[i-1] == cls._valid_population_columns_names[3]:
790                valence_value = float(item)
791            i += 1
792
793        populations.lodwin.update({id: (symbol, lowdin_value)})
794        populations.mulliken.update({id: (symbol, mulliken_value)})
795        populations.valence.update({id: (symbol, valence_value)})
796
797        return populations
798
799    def _load_coordinates_of_atoms(self, file: str)\
800            -> CoordinatesOfAtoms | None:
801        rows = self._get_rows_of_data_from_file(file,
802                                                self._fingerprint_coordinates_of_atoms,
803                                                self._fingerprint_end_coordinates_of_atoms)
804        if rows is not None:
805            for row in rows:
806                have_string = True if re.search('[a-zA-Z]+', row) is \
807                    not None else False
808
809                have_number = True if re.search('[0-9]+', row) is \
810                    not None else False
811
812                if have_string and not have_number:
813                    labels = row.split()
814                    coordinates_of_atoms = self.CoordinatesOfAtoms()
815                    continue
816                elif have_string and have_number:
817                    splited = row.split()
818                    if len(labels) + 2 != len(splited):
819                        raise Exception(
820                            'Wrong quantity of columns in input file!')
821                    else:
822                        coordinates_of_atoms = self._add_coordinations_attributes(
823                            coordinates_of_atoms, splited, labels
824                        )
825            return coordinates_of_atoms
826        else:
827            return None
828
829    @classmethod
830    def _add_coordinations_attributes(cls, coordinates_of_atoms:
831                                      CoordinatesOfAtoms,
832                                      splited: list, labels: list[str])\
833            -> CoordinatesOfAtoms:
834        i = 0
835        for item in splited:
836            if i == 0:
837                atom_id = int(item)
838            elif i == 1:
839                atom_symbol = item
840            elif labels[i - 2] == cls._valid_coordinatios_columns_names[0]:
841                x = float(item)
842            elif labels[i - 2] == cls._valid_coordinatios_columns_names[1]:
843                y = float(item)
844            elif labels[i - 2] == cls._valid_coordinatios_columns_names[2]:
845                z = float(item)
846            i += 1
847
848        coordinates_of_atoms.add_new_atom(atom_id, atom_symbol, (x, y, z))
849        return coordinates_of_atoms
850
851    @staticmethod
852    def _get_rows_of_data_from_file(file: str,
853                                    finger_print_begin: str, finger_print_end)\
854            -> list[str] | None:
855        """Get rows fo data from file
856
857        Args:
858            finger_print_begin (str): fingerprint on beginning of data
859            finger_print_end (str): fingerprint on end of data
860
861        Returns:
862            **list[str]**: rows of string data
863
864        """
865
866        regex = f'(?<={finger_print_begin})[\s\S]*' \
867            + f'(?={finger_print_end})'
868
869        match = re.search(regex, file)
870        if match is not None:
871            return match[0].split('\n')
872        else:
873            return None
874
875    def _load_mayer_bond_orders(self, file: str) -> MayerBondOrders:
876        match = re.search(
877            f"(?<={self._fingerprint_mayer_bond_orders}\n\n)([\S ]+\n)*", file)
878        if match is None:
879            raise Exception("Mayers bond orders aren't in file or wrong file"
880                            + "format!!!!")
881        rows = match[0].split('\n')
882        rows = [row for row in rows if row != '']
883        number_of_atoms = int(rows[-1].split()[0])
884        n = number_of_atoms // 8
885        m = 1 if number_of_atoms % 8 > 0 else 0
886        number_of_tables = m + n
887
888        number_of_rows = (len(rows)) * number_of_tables
889        match = re.search(
890            f"(?<={self._fingerprint_mayer_bond_orders}\n\n)([\S ]+\n*){{{number_of_rows}}}", file)
891
892        if match is None:
893            raise Exception("Mayers bond orders aren't in file or wrong file"
894                            + "format!!!!")
895        rows_full_table = []
896        tables = match[0].split('\n\n')
897        first_table = True
898        for table in tables:
899            splited = table.split('\n')
900            i = 0
901            for item in splited:
902                if first_table:
903                    row = item.split()
904                    rows_full_table.append(row)
905                elif i == 0:
906                    row = item.split()
907                    rows_full_table[i].extend(row)
908                else:
909                    row = item.split()
910                    rows_full_table[i].extend(row[2:])
911                i += 1
912            first_table = False
913
914        row_horizontal = rows_full_table.pop(0)
915        i = 0
916        j = 0
917        horizontal_atom_symbol = {}
918        horizontal_atom_id = []
919        for item in row_horizontal:
920            if i % 2 == 0:
921                j += 1
922                horizontal_atom_id.append(int(item))
923            else:
924                horizontal_atom_symbol.update(
925                    {horizontal_atom_id[j - 1]: str(item)})
926            i += 1
927
928        vertical_atom_symbol = {}
929        vertical_atom_id = []
930        new_rows_full_table = []
931        for row in rows_full_table:
932            vertical_atom_id.append(int(row.pop(0)))
933            vertical_atom_symbol.update(
934                {vertical_atom_id[-1]: str(row.pop(0))})
935            row_f = [float(item) for item in row]
936            new_rows_full_table.append(row_f)
937
938        if horizontal_atom_id == vertical_atom_id:
939            mayer_bond_order = self.MayerBondOrders(new_rows_full_table,
940                                                    horizontal_atom_id,
941                                                    horizontal_atom_symbol,
942                                                    vertical_atom_symbol)
943        else:
944            raise Exception(
945                "The condition: 'horizontal_atom_id == vertical_atom_id' "
946                + "must be met ")
947        return mayer_bond_order
948
949    @classmethod
950    def _load_unit_cell(cls, file: str):
951        vectors = []
952        for item in cls._fingerprints_unit_cell:
953            regex = f'(?<={item})[ \S]+'
954            match = re.search(regex, file)
955            if match is None:
956                raise Exception(" wrong file format!!!!")
957            row = match[0].split()
958            row_f = [float(item) for item in row]
959            vectors.append(row_f)
960        unit_cell = UnitCell()
961        unit_cell.lattice_vectors = tuple(item
962                                          for item in vectors)
963        return unit_cell

Loads data from CPMD file and create objects.

def load_input_data(self, path: str, *args) -> None:
697    def load_input_data(self, path: str, *args) -> None:
698        """Loads input data from CPMD file.
699
700        Args:
701            path (str): path to file
702            *args: LoadData.UnitCell, LoadedData.MayerBondOrders,
703            LoadData.Populations or LoadData.CoordinatesOfAtoms
704
705        """
706        with open(path, 'r') as file:
707            data = file.read()
708
709        if self.check_is_correct_file(data, self._fingerprint) is not True:
710            raise Exception("Wrong input file!")
711        else:
712            if self.LoadedData.UnitCell in args:
713                self.unit_cell = self._load_unit_cell(data)
714            if self.LoadedData.MayerBondOrders in args:
715                self.mayer_bond_orders = \
716                    self._load_mayer_bond_orders(data)
717            if self.LoadedData.Populations in args:
718                self.populations = self._load_populations(data)
719            if self.LoadedData.CoordinatesOfAtoms in args:
720                self.coordinates_of_atoms = \
721                    self._load_coordinates_of_atoms(data)

Loads input data from CPMD file.

Arguments:
  • path (str): path to file
  • *args: LoadData.UnitCell, LoadedData.MayerBondOrders,
  • LoadData.Populations or LoadData.CoordinatesOfAtoms
723    def return_data(self, loaded_data: LoadedData)\
724            -> Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms\
725            | None:
726        """ Returns loaded data.
727
728        Args:
729
730        Returns:
731            **Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms**:
732
733        """
734        if loaded_data is LoadedData.UnitCell:
735            return self.unit_cell
736        elif loaded_data is LoadedData.MayerBondOrders:
737            return self.mayer_bond_orders
738        elif loaded_data is LoadedData.Populations:
739            return self.populations
740        elif loaded_data is LoadedData.CoordinatesOfAtoms:
741            return self.coordinates_of_atoms
742        else:
743            raise TypeError("Type is not LoadedData!!!!")

Returns loaded data.

Args:

Returns:

Populations | UnitCell | MayerBondOrders | CoordinatesOfAtoms: