bond_order_processing.calculations

  1__docformat__ = "google"
  2"""Calculations module."""
  3import numpy as np
  4from typing import Callable
  5from abc import ABC
  6from abc import abstractmethod
  7from .input_data import MayerBondOrders
  8from .input_data import CoordinatesOfAtoms
  9from typing import TypeAlias
 10from dataclasses import dataclass
 11
 12
 13@dataclass
 14class PairOfAtoms:
 15    """PairOfAtoms.
 16
 17    Object represents Pair of Atoms
 18
 19    Attributes:
 20        atom_1 (str): First atom name.
 21        atom_2 (str): Second atom name.
 22        MBO_min (float): Minimum Mayer bond order cut off.
 23        MBO_max (float | str):Max Mayer bond order cut off. Float or 'INF' - for infinite value.capitalize()
 24        id (str): Bond id eg. 'P-O'
 25
 26    """
 27
 28    atom_1: str = ''
 29    atom_2: str = ''
 30    MBO_min: float | str | None = None
 31    MBO_max: float | str | None = None
 32    id: str = ''
 33
 34
 35class Calculations(ABC):
 36    """Calculations base class."""
 37
 38    @abstractmethod
 39    def calculate(cls, *args, **kwars) -> type:
 40        pass
 41
 42    @abstractmethod
 43    def to_string(self, *args, **kwars) -> str:
 44        pass
 45
 46
 47class Statistics(ABC):
 48    """Statistics base class"""
 49    @abstractmethod
 50    def calculate_statistics(self) -> type:
 51        pass
 52
 53
 54class Histogram(Calculations):
 55    """Object represents histogram."""
 56    _histogram: Callable = np.histogram
 57    x: list[float] = []
 58    """Position of bin on x axis."""
 59    y: list[int] = []
 60    """Quantity."""
 61
 62    @classmethod
 63    def calculate(cls, values: list[float], bins: int):
 64        """Calculate histogram.
 65
 66        Args:
 67            values (list[float]): List of values.
 68            bins (int): Number of bins in histogram.
 69
 70        Returns:
 71            **Histogram**: Histogram object.
 72
 73        """
 74        histogram = cls._histogram(values, bins)
 75
 76        y = histogram[0]
 77        x = histogram[1]
 78        y = y.tolist()
 79        x = x.tolist()
 80
 81        first_loop = True
 82        new_x = []
 83        for item in x:
 84            if first_loop:
 85                first_loop = False
 86                previous = item
 87            else:
 88                new_x.append((item
 89                              + previous) / 2)
 90                previous = item
 91
 92        histogram = cls()
 93        histogram.x = new_x
 94        histogram.y = y
 95        return histogram
 96
 97    def to_string(self, bond_id: str, atom_symbol_1: str, atom_symbol_2: str)\
 98            -> str:
 99        """Make string from Histogram object
100
101        Args:
102            bond_id (str): eg. P-O.
103            atom_symbol_1 (str): Symbol of atom 1.
104            atom_symbol_2 (str): Symbol of atom 2.
105        Returns:
106            **str**: String.
107
108        """
109        string = f'Bond id: {bond_id} - atom_1_id: {atom_symbol_1}, atom_2_id: {atom_symbol_2}\n\n'
110        string = string + 'Interval/2' + ' ' + 'Count' + '\n\n'
111        for i in range(len(self.x)):
112            string = string + \
113                str(round(self.x[i], 9)) + ' ' + \
114                str(round(self.y[i], 9)) + '\n'
115
116        string = string + '\n'
117
118        return string
119
120
121@dataclass
122class CoordinationNumber:
123    """Object stores coordination number of given atom and
124    Mayer bond orders corresponding to the bonds in the
125    coordination polyhedron."""
126
127    id_atom_1: int
128    """Central atom id."""
129    cn: int
130    """Value of coordination number."""
131    bonds: dict[int, float]
132    """**Key** - ligand id, **value** - Mayer bond order."""
133
134
135class CoordinationNumbers(Calculations, Statistics):
136    """Generate list of CoordinationNumber objects and processes it."""
137    CoordinationNumber: type = CoordinationNumber
138
139    list_coordinations_number: list[CoordinationNumber]
140    """List of CoordinationNumber objects."""
141    id_of_bond: str
142    """Id of bond eg. 'P-O'"""
143    atom_symbol: str
144    """Symbol of atom."""
145    statistics: dict[int, float] | None = None
146    """**Key** - coordination number, **value** - percentages."""
147
148    @classmethod
149    def calculate(cls, mayer_bond_orders: MayerBondOrders,
150                  atom_symbol_1: str, atom_symbol_2: str,
151                  max_mayer_bond_order: float | str,
152                  min_mayer_bond_order: float,
153                  id_of_bond: str):
154        """Calculate CoordinationNumbers object.
155
156        Args:
157            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
158            atom_symbol_1 (str): Central atom symbol.
159            atom_symbol_2 (str): Ligand symbol.
160            max_mayer_bond_order (float): Max cut of radius, float or 'INF" if infinite value.
161            min_mayer_bond_order (float): Min cut of radius.
162            id_of_bond (str): id of bond eg. 'P-O'
163
164        Returns:
165            **CoordinationNumbers**: CoordinationNumbers object
166
167        """
168
169        if max_mayer_bond_order != "INF"\
170                and not (type(max_mayer_bond_order) is float):
171            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
172
173        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
174        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
175
176        list_coordinations_number = []
177        for atom_1_id in atom_1_ids:
178
179            coordination_number = cls.CoordinationNumber(atom_1_id, 0, {})
180
181            for atom_2_id in atom_2_ids:
182                if atom_1_id != atom_2_id:
183
184                    mbo = mayer_bond_orders\
185                        .get_mayer_bond_order_between_atoms(atom_1_id,
186                                                            atom_2_id)
187                    if (mbo > min_mayer_bond_order
188                            and max_mayer_bond_order == 'INF'):
189                        coordination_number.bonds.update({atom_2_id: mbo})
190                        coordination_number.cn += 1
191                    elif (type(max_mayer_bond_order) is float):
192                        if (mbo > min_mayer_bond_order
193                                and mbo < max_mayer_bond_order):
194                            coordination_number.bonds.update({atom_2_id: mbo})
195                            coordination_number.cn += 1
196                    else:
197                        continue
198
199            list_coordinations_number.append(coordination_number)
200
201        self = cls()
202        self.id_of_bond = id_of_bond
203        self.atom_symbol = atom_symbol_1
204        self.list_coordinations_number = list_coordinations_number
205
206        return self
207
208    def calculate_statistics(self):
209        """Calculate statistics of CoordinationNumbers.
210
211        Statistic are in "statistics" attribute.
212
213        Returns:
214            CoordinationNumbers: CoordinationNumbers object
215
216        """
217        cns = self._get_list_of_coordination_numbers()
218        quantities: dict = {}
219        for cn in cns:
220            for item in self.list_coordinations_number:
221                if item.cn == cn:
222                    if quantities.get(cn, None) is None:
223                        quantities.update({cn: 1})
224                    else:
225                        quantities[cn] = quantities[cn] + 1
226
227        number_of_atoms = len(self.list_coordinations_number)
228        statistics = {}
229        for key, value in quantities.items():
230            statistics.update({key: (value/number_of_atoms) * 100})
231
232        self.statistics = statistics
233
234        return self
235
236    def _get_list_of_coordination_numbers(self) -> list[int]:
237        cns = []
238        for item in self.list_coordinations_number:
239            if item.cn not in cns:
240                cns += [item.cn]
241
242        return cns
243
244    def to_string(self) -> str:
245        """Make string from CoordinationNumbers object.
246
247        Returns:
248            **str**: String.
249
250        """
251        string = "## CN of " + str(self.atom_symbol) + " bond: "\
252            + str(self.id_of_bond) + "\n\n"
253        for item in self.list_coordinations_number:
254            string = string + "id: " + str(item.id_atom_1) + " "\
255                + "CN: " + str(item.cn)
256
257            if item.cn != 0:
258                string += "\n" + "Bond orders (id: mbo): "
259
260            length = len(item.bonds)
261            i = 1
262            for key, value in item.bonds.items():
263                string += str(key) + ': ' + str(value)
264                if i < length:
265                    string += ', '
266                else:
267                    pass
268                i += 1
269
270            string += '\n'
271        string += '\n'
272
273        if self.statistics is not None:
274            string = string + "Statistics of: "\
275                + str(self.atom_symbol) + "\n\n" + "CN %\n"
276            for key, value in self.statistics.items():
277                string = string + str(key) + ' ' + str(round(value, 3)) + '\n'
278
279            string = string + '\n'
280
281        return string
282
283
284class QiUnits(Calculations, Statistics):
285    """Stores information about Qi units."""
286    id_of_bond: str
287    """Id of bonds in Qⁱ unit"""
288    atom_symbol_1: str
289    """Symbol of central atom"""
290    atom_symbol_2: str
291    """Symbol of ligands"""
292    q_i_units: dict[int, int] = {}
293    """Dictionary stores values of i of Qⁱ units. key - central atom id."""
294    statistics: dict[int, float] | None = None
295    """Dictionary stores percentages of Qⁱ units. key - value of i in Qⁱ"""
296
297    @classmethod
298    def calculate(cls, mayer_bond_orders: MayerBondOrders,
299                  atom_symbol_1: str,
300                  atom_symbol_2: str,
301                  max_mayer_bond_order: float | str,
302                  min_mayer_bond_order: float,
303                  id_of_bond: str):
304        """Calculate QiUnits object.
305
306        Args:
307            mayer_bond_orders (MayerBondOrders): Object MayerBondOrders.
308            atom_symbol_1 (str): Symbol of central atom.
309            atom_symbol_2 (str): Symbol of ligands.
310            max_mayer_bond_order (float | str): Max Mayer bond order, float or 'INF' for infinite maximum value.
311            min_mayer_bond_order (float): Min Mayer bond order.
312            id_of_bond (str): Name of bond eg. 'P-O'.
313
314        Raises:
315            ValueError: "Wrong type of max_mayer_bond_order!!!!"
316
317        Returns:
318            **QiUnits**: Returns QiUnits object.
319
320        """
321
322        if max_mayer_bond_order != "INF"\
323                and not (type(max_mayer_bond_order) is float):
324            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
325        elif max_mayer_bond_order == "INF":
326            inf = True
327            max_mayer_bond_order = -1
328            # -1 to prevent exception
329        else:
330            inf = False
331
332        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
333        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
334
335        self = cls()
336        self.id_of_bond = id_of_bond
337        self.atom_symbol_1 = atom_symbol_1
338        self.atom_symbol_2 = atom_symbol_2
339        self.q_i_units = {}
340        for atom_1_id in atom_1_ids:
341
342            self.q_i_units.update({atom_1_id: 0})
343
344            for atom_2_id in atom_2_ids:
345                mbo = mayer_bond_orders\
346                    .get_mayer_bond_order_between_atoms(atom_1_id,
347                                                        atom_2_id)
348                if (mbo > min_mayer_bond_order
349                        and (mbo < max_mayer_bond_order or inf)):
350
351                    for atom_3_id in atom_1_ids:
352                        mbo = mayer_bond_orders\
353                            .get_mayer_bond_order_between_atoms(atom_2_id,
354                                                                atom_3_id)
355                        if (mbo > min_mayer_bond_order
356                                and (mbo < max_mayer_bond_order or inf)
357                                and atom_3_id != atom_1_id):
358
359                            self.q_i_units[atom_1_id] += 1
360                            break
361
362                        else:
363                            continue
364
365        return self
366
367    def calculate_statistics(self):
368        """Calculate statistics in object QiUnits.
369
370        Returns:
371            **QiUnits**: QiUnits object.
372
373        """
374
375        unique_values = []
376        for value in self.q_i_units.values():
377            if value not in unique_values:
378                unique_values.append(value)
379
380        quantities = {}
381        for unique in unique_values:
382            quantities.update({unique: 0})
383            for value in self.q_i_units.values():
384                if value == unique:
385                    quantities[unique] += 1
386                else:
387                    continue
388
389        quantity_of_all_Q_i = len(self.q_i_units)
390
391        self.statistics = {}
392
393        for key, value in quantities.items():
394            self.statistics.update({key: (value/quantity_of_all_Q_i) * 100})
395
396        return self
397
398    def to_string(self) -> str:
399        """Generate string representing object.
400
401        Returns:
402            **str**: String.
403
404        """
405        string = "Q_i of " + str(self.atom_symbol_1) + ' bond id: '\
406            + str(self.id_of_bond) + "\n\n"
407
408        string += "id Q_i[i]\n"
409
410        for key, value in self.q_i_units.items():
411            string = string + str(key) + ' ' + str(value) + '\n'
412
413        string += '\n'
414
415        if self.statistics is not None:
416            string = string + 'Statistics of Q_i: ' + str(self.atom_symbol_1)\
417                + ', bond id: ' + str(self.id_of_bond) + '\n\n'
418
419            string += 'Q_i[i] [%]\n'
420
421            for key, value in self.statistics.items():
422                string = string + str(key) + ' ' + str(round(value, 3)) + '\n'
423
424        string += '\n'
425
426        return string
427
428
429@dataclass
430class Connection:
431    """An object represents connections between two elements."""
432    id_atom_2 = int
433    mayer_bond_order = float
434
435    atom_symbol_2: str
436    """Ligant atom symbol."""
437    bond_id: str
438    """Bond id eg. 'P-O'"""
439    quantity: int
440    """Quantity of given connections"""
441    bonds: dict[id_atom_2, mayer_bond_order]
442    """**key**- ligand id, **value**-mayer bond order."""
443
444
445class Connections(Calculations):
446    """Object represents connections of given atom to nearest neighbors.
447    """
448    atom_1_id: TypeAlias = int
449    Connection: type = Connection
450
451    connections: dict[atom_1_id, list[Connection]]
452    """Key - central atom, values - list to Connection objects."""
453    atom_symbol_1: str
454    """Symbol of central atom."""
455
456    @ classmethod
457    def calculate(cls, mayer_bond_orders: MayerBondOrders,
458                  atom_symbol_1: str,
459                  pairs_atoms_list: list[PairOfAtoms]
460                  ):
461        """Calculate Connections object.
462
463        Args:
464            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
465            atom_symbol_1 (str): Central atom symbol.
466            pairs_atoms_list (list[PairOfAtoms]): list of PairsOfAtoms objects.
467
468        Raises:
469            ValueError: "Wrong type of max_mayer_bond_order!!!!"
470
471        Returns:
472            **Connections**: Connections object.
473
474        """
475
476        pair_atom_list_containing_atom_1 = []
477        for pair_atom in pairs_atoms_list:
478            if pair_atom.atom_1 == atom_symbol_1\
479                    or pair_atom.atom_2 == atom_symbol_1:
480
481                pair_atom_list_containing_atom_1.append(pair_atom)
482            else:
483                continue
484
485        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
486        connections = {}
487        for atom_1_id in atom_1_ids:
488
489            connections.update({atom_1_id: []})
490
491            for pair_atoms in pair_atom_list_containing_atom_1:
492                if (v := pair_atoms.atom_1) != atom_symbol_1:
493                    atom_symbol_2 = v
494                else:
495                    atom_symbol_2 = pair_atoms.atom_2
496
497                connection = cls.Connection(
498                    atom_symbol_2, pair_atoms.id, 0, {})
499
500                atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
501
502                for atom_2_id in atom_2_ids:
503                    if pair_atoms.MBO_max != "INF"\
504                            and not (type(pair_atoms.MBO_max) is float):
505                        raise ValueError(
506                            "Wrong type of max_mayer_bond_order!!!!")
507
508                    mbo = mayer_bond_orders\
509                        .get_mayer_bond_order_between_atoms(atom_1_id,
510                                                            atom_2_id)
511
512                    if (mbo > pair_atoms.MBO_min
513                            and pair_atoms.MBO_max == 'INF'):
514
515                        connection.quantity += 1
516                        connection.bonds.update({atom_2_id: mbo})
517
518                    elif (pair_atoms.MBO_max != 'INF'):
519                        if (mbo > pair_atoms.MBO_min
520                                and pair_atoms.MBO_max > mbo):
521
522                            connection.quantity += 1
523                            connection.bonds.update({atom_2_id: mbo})
524
525                connections[atom_1_id].append(connection)
526
527        self = cls()
528        self.connections = connections
529        self.atom_symbol_1 = atom_symbol_1
530
531        return self
532
533    def to_string(self) -> str:
534        """Generates string representation of object.
535
536        Returns:
537            **str**: string.
538
539        """
540        string = '## Connections of: ' + str(self.atom_symbol_1) + '\n\n'
541
542        for atom_1_id, list_of_connections in self.connections.items():
543            string = string + "### Central atom id: " + str(atom_1_id) + "\n"
544
545            for connection in list_of_connections:
546
547                string = string + f"Bond id: {str(connection.bond_id)} "\
548                    + f"(second atom: {str(connection.atom_symbol_2)})\n"\
549                    + f"quantity: {connection.quantity}\n"\
550                    + "Bonds:\n"
551
552                string_id_line = "id: "
553                string_mbo_line = "mbo: "
554
555                for id, mbo in connection.bonds.items():
556                    string_id_line += f"{id} "
557                    string_mbo_line += f"{round(mbo, 3)} "
558
559                string = string + string_id_line + '\n'\
560                    + string_mbo_line + '\n\n'
561
562        return string
563
564
565class Covalence(Calculations):
566    """Object storages covalences of atoms"""
567    covalence: dict[int, float]
568    """Key - id of atom, value - covalence calculated from Mayer bond orders."""
569    atom_symbol: str
570    """Atom symbol."""
571
572    @ classmethod
573    def calculate(cls, mayer_bond_orders: MayerBondOrders,
574                  atom_symbol: str):
575        """Calculate Covalence object.
576
577        Args:
578            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
579            atom_symbol (str): Atom symbol.
580
581        Returns:
582            **Covalence**: Covalence object.
583
584        """
585
586        atom_ids = mayer_bond_orders.get_atoms_ids(atom_symbol)
587
588        self = cls()
589        self.atom_symbol = atom_symbol
590        self.covalence = {}
591        for id in atom_ids:
592            mbos = mayer_bond_orders.get_all_mayer_bond_orders_of_atom(id)
593            self.covalence.update({id: sum(mbos)})
594
595        return self
596
597    def to_string(self) -> str:
598        """Generates string representation of object.
599
600        Returns:
601            **str**: String.
602
603        """
604        string = f'Covalence of {self.atom_symbol}.\n\n'\
605            + 'id COV\n'
606
607        for id, value in self.covalence.items():
608            string = string + f'{id} {value:.3f}\n'
609        string += '\n'
610
611        return string
612
613
614class BondLength(Calculations):
615    """Object stored bond lengths of pairs of atoms."""
616    atom_id_1: TypeAlias = int
617    atom_id_2: TypeAlias = int
618
619    id_of_bond: str
620    """Id of bond eg. 'P-O'"""
621    atom_symbol_1: str
622    """Atom 1 symbol."""
623    atom_symbol_2: str
624    """Atom 2 symbol."""
625    lengths: dict[atom_id_1, dict[atom_id_2, float]]
626    """**values**- length between atoms."""
627    mbos: dict[atom_id_1, dict[atom_id_2, float]]
628    """**values**- Mayer bond orders"""
629
630    @ classmethod
631    def calculate(cls,
632                  mayer_bond_orders: MayerBondOrders,
633                  coordinates_of_atoms: CoordinatesOfAtoms,
634                  atom_symbol_1: str,
635                  atom_symbol_2: str,
636                  max_mayer_bond_order: float | str,
637                  min_mayer_bond_order: float,
638                  id_of_bond: str):
639        """Calculate BondLength object.
640
641        Args:
642            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
643            coordinates_of_atoms (CoordinatesOfAtoms): CoordinatesOfAtom object.
644            atom_symbol_1 (str): Symbol of atom 1.
645            atom_symbol_2 (str): Symbol of atom 2.
646            max_mayer_bond_order (float | str): max value of Mayer bond order or 'INF for infinite value.
647            min_mayer_bond_order (float): min value of Mayer bond order.
648            id_of_bond (str): id of bond eg. 'P-O'
649
650        Raises:
651            ValueError: "Wrong type of max_mayer_bond_order!!!!"
652
653        Returns:
654            **BondLength**: BondLength object.
655
656        """
657
658        if max_mayer_bond_order != "INF"\
659                and not (type(max_mayer_bond_order) is float):
660            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
661        elif max_mayer_bond_order == "INF":
662            inf = True
663            max_mayer_bond_order = -1
664            # -1 to prevent exception
665        else:
666            inf = False
667
668        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
669        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
670
671        self = cls()
672        self.id_of_bond = id_of_bond
673        self.atom_symbol_1 = atom_symbol_1
674        self.atom_symbol_2 = atom_symbol_2
675        self.lengths = {}
676        self.mbos = {}
677
678        for atom_1_id in atom_1_ids:
679            self.lengths.update({atom_1_id: {}})
680            self.mbos.update({atom_1_id: {}})
681            for atom_2_id in atom_2_ids:
682                mbo = mayer_bond_orders\
683                    .get_mayer_bond_order_between_atoms(atom_1_id,
684                                                        atom_2_id)
685
686                length = coordinates_of_atoms\
687                    .get_distance_between_atoms(atom_1_id, atom_2_id)
688
689                if mbo > min_mayer_bond_order and (
690                    mbo < max_mayer_bond_order
691                    or inf is True
692                ):
693                    self.lengths[atom_1_id].update({atom_2_id: length})
694                    self.mbos[atom_1_id].update({atom_2_id: mbo})
695                else:
696                    continue
697
698        # remove empty keys.
699
700        for key in list(self.lengths.keys()):
701            if self.lengths[key] == {}:
702                del self.lengths[key]
703                del self.mbos[key]
704
705        return self
706
707    def to_string(self) -> str:
708        """Generates string representation of object.
709
710        Returns:
711            **str**: String.
712
713        """
714        string = f'Bond lengths of bond id: {self.id_of_bond} '\
715            + f'(atoms: {self.atom_symbol_1}, {self.atom_symbol_2}):\n\n'\
716            + 'id_1 id_2 length mbo\n'
717
718        for key_1 in self.lengths.keys():
719            for key_2 in self.lengths[key_1].keys():
720                string = string + f'{key_1} {key_2} '\
721                    + f'{self.lengths[key_1][key_2]} '\
722                    + f'{self.mbos[key_1][key_2]}\n'
723
724        string += '\n'
725
726        return string
@dataclass
class PairOfAtoms:
14@dataclass
15class PairOfAtoms:
16    """PairOfAtoms.
17
18    Object represents Pair of Atoms
19
20    Attributes:
21        atom_1 (str): First atom name.
22        atom_2 (str): Second atom name.
23        MBO_min (float): Minimum Mayer bond order cut off.
24        MBO_max (float | str):Max Mayer bond order cut off. Float or 'INF' - for infinite value.capitalize()
25        id (str): Bond id eg. 'P-O'
26
27    """
28
29    atom_1: str = ''
30    atom_2: str = ''
31    MBO_min: float | str | None = None
32    MBO_max: float | str | None = None
33    id: str = ''

PairOfAtoms.

Object represents Pair of Atoms

Attributes:
  • atom_1 (str): First atom name.
  • atom_2 (str): Second atom name.
  • MBO_min (float): Minimum Mayer bond order cut off.
  • MBO_max (float | str): Max Mayer bond order cut off. Float or 'INF' - for infinite value.capitalize()
  • id (str): Bond id eg. 'P-O'
PairOfAtoms( atom_1: str = '', atom_2: str = '', MBO_min: float | str | None = None, MBO_max: float | str | None = None, id: str = '')
class Calculations(abc.ABC):
36class Calculations(ABC):
37    """Calculations base class."""
38
39    @abstractmethod
40    def calculate(cls, *args, **kwars) -> type:
41        pass
42
43    @abstractmethod
44    def to_string(self, *args, **kwars) -> str:
45        pass

Calculations base class.

@abstractmethod
def calculate(cls, *args, **kwars) -> type:
39    @abstractmethod
40    def calculate(cls, *args, **kwars) -> type:
41        pass
@abstractmethod
def to_string(self, *args, **kwars) -> str:
43    @abstractmethod
44    def to_string(self, *args, **kwars) -> str:
45        pass
class Statistics(abc.ABC):
48class Statistics(ABC):
49    """Statistics base class"""
50    @abstractmethod
51    def calculate_statistics(self) -> type:
52        pass

Statistics base class

@abstractmethod
def calculate_statistics(self) -> type:
50    @abstractmethod
51    def calculate_statistics(self) -> type:
52        pass
class Histogram(Calculations):
 55class Histogram(Calculations):
 56    """Object represents histogram."""
 57    _histogram: Callable = np.histogram
 58    x: list[float] = []
 59    """Position of bin on x axis."""
 60    y: list[int] = []
 61    """Quantity."""
 62
 63    @classmethod
 64    def calculate(cls, values: list[float], bins: int):
 65        """Calculate histogram.
 66
 67        Args:
 68            values (list[float]): List of values.
 69            bins (int): Number of bins in histogram.
 70
 71        Returns:
 72            **Histogram**: Histogram object.
 73
 74        """
 75        histogram = cls._histogram(values, bins)
 76
 77        y = histogram[0]
 78        x = histogram[1]
 79        y = y.tolist()
 80        x = x.tolist()
 81
 82        first_loop = True
 83        new_x = []
 84        for item in x:
 85            if first_loop:
 86                first_loop = False
 87                previous = item
 88            else:
 89                new_x.append((item
 90                              + previous) / 2)
 91                previous = item
 92
 93        histogram = cls()
 94        histogram.x = new_x
 95        histogram.y = y
 96        return histogram
 97
 98    def to_string(self, bond_id: str, atom_symbol_1: str, atom_symbol_2: str)\
 99            -> str:
100        """Make string from Histogram object
101
102        Args:
103            bond_id (str): eg. P-O.
104            atom_symbol_1 (str): Symbol of atom 1.
105            atom_symbol_2 (str): Symbol of atom 2.
106        Returns:
107            **str**: String.
108
109        """
110        string = f'Bond id: {bond_id} - atom_1_id: {atom_symbol_1}, atom_2_id: {atom_symbol_2}\n\n'
111        string = string + 'Interval/2' + ' ' + 'Count' + '\n\n'
112        for i in range(len(self.x)):
113            string = string + \
114                str(round(self.x[i], 9)) + ' ' + \
115                str(round(self.y[i], 9)) + '\n'
116
117        string = string + '\n'
118
119        return string

Object represents histogram.

x: list[float] = []

Position of bin on x axis.

y: list[int] = []

Quantity.

@classmethod
def calculate(cls, values: list[float], bins: int):
63    @classmethod
64    def calculate(cls, values: list[float], bins: int):
65        """Calculate histogram.
66
67        Args:
68            values (list[float]): List of values.
69            bins (int): Number of bins in histogram.
70
71        Returns:
72            **Histogram**: Histogram object.
73
74        """
75        histogram = cls._histogram(values, bins)
76
77        y = histogram[0]
78        x = histogram[1]
79        y = y.tolist()
80        x = x.tolist()
81
82        first_loop = True
83        new_x = []
84        for item in x:
85            if first_loop:
86                first_loop = False
87                previous = item
88            else:
89                new_x.append((item
90                              + previous) / 2)
91                previous = item
92
93        histogram = cls()
94        histogram.x = new_x
95        histogram.y = y
96        return histogram

Calculate histogram.

Arguments:
  • values (list[float]): List of values.
  • bins (int): Number of bins in histogram.
Returns:

Histogram: Histogram object.

def to_string(self, bond_id: str, atom_symbol_1: str, atom_symbol_2: str) -> str:
 98    def to_string(self, bond_id: str, atom_symbol_1: str, atom_symbol_2: str)\
 99            -> str:
100        """Make string from Histogram object
101
102        Args:
103            bond_id (str): eg. P-O.
104            atom_symbol_1 (str): Symbol of atom 1.
105            atom_symbol_2 (str): Symbol of atom 2.
106        Returns:
107            **str**: String.
108
109        """
110        string = f'Bond id: {bond_id} - atom_1_id: {atom_symbol_1}, atom_2_id: {atom_symbol_2}\n\n'
111        string = string + 'Interval/2' + ' ' + 'Count' + '\n\n'
112        for i in range(len(self.x)):
113            string = string + \
114                str(round(self.x[i], 9)) + ' ' + \
115                str(round(self.y[i], 9)) + '\n'
116
117        string = string + '\n'
118
119        return string

Make string from Histogram object

Arguments:
  • bond_id (str): eg. P-O.
  • atom_symbol_1 (str): Symbol of atom 1.
  • atom_symbol_2 (str): Symbol of atom 2.
Returns:

str: String.

@dataclass
class CoordinationNumber:
122@dataclass
123class CoordinationNumber:
124    """Object stores coordination number of given atom and
125    Mayer bond orders corresponding to the bonds in the
126    coordination polyhedron."""
127
128    id_atom_1: int
129    """Central atom id."""
130    cn: int
131    """Value of coordination number."""
132    bonds: dict[int, float]
133    """**Key** - ligand id, **value** - Mayer bond order."""

Object stores coordination number of given atom and Mayer bond orders corresponding to the bonds in the coordination polyhedron.

CoordinationNumber(id_atom_1: int, cn: int, bonds: dict[int, float])
id_atom_1: int

Central atom id.

cn: int

Value of coordination number.

bonds: dict[int, float]

Key - ligand id, value - Mayer bond order.

class CoordinationNumbers(Calculations, Statistics):
136class CoordinationNumbers(Calculations, Statistics):
137    """Generate list of CoordinationNumber objects and processes it."""
138    CoordinationNumber: type = CoordinationNumber
139
140    list_coordinations_number: list[CoordinationNumber]
141    """List of CoordinationNumber objects."""
142    id_of_bond: str
143    """Id of bond eg. 'P-O'"""
144    atom_symbol: str
145    """Symbol of atom."""
146    statistics: dict[int, float] | None = None
147    """**Key** - coordination number, **value** - percentages."""
148
149    @classmethod
150    def calculate(cls, mayer_bond_orders: MayerBondOrders,
151                  atom_symbol_1: str, atom_symbol_2: str,
152                  max_mayer_bond_order: float | str,
153                  min_mayer_bond_order: float,
154                  id_of_bond: str):
155        """Calculate CoordinationNumbers object.
156
157        Args:
158            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
159            atom_symbol_1 (str): Central atom symbol.
160            atom_symbol_2 (str): Ligand symbol.
161            max_mayer_bond_order (float): Max cut of radius, float or 'INF" if infinite value.
162            min_mayer_bond_order (float): Min cut of radius.
163            id_of_bond (str): id of bond eg. 'P-O'
164
165        Returns:
166            **CoordinationNumbers**: CoordinationNumbers object
167
168        """
169
170        if max_mayer_bond_order != "INF"\
171                and not (type(max_mayer_bond_order) is float):
172            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
173
174        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
175        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
176
177        list_coordinations_number = []
178        for atom_1_id in atom_1_ids:
179
180            coordination_number = cls.CoordinationNumber(atom_1_id, 0, {})
181
182            for atom_2_id in atom_2_ids:
183                if atom_1_id != atom_2_id:
184
185                    mbo = mayer_bond_orders\
186                        .get_mayer_bond_order_between_atoms(atom_1_id,
187                                                            atom_2_id)
188                    if (mbo > min_mayer_bond_order
189                            and max_mayer_bond_order == 'INF'):
190                        coordination_number.bonds.update({atom_2_id: mbo})
191                        coordination_number.cn += 1
192                    elif (type(max_mayer_bond_order) is float):
193                        if (mbo > min_mayer_bond_order
194                                and mbo < max_mayer_bond_order):
195                            coordination_number.bonds.update({atom_2_id: mbo})
196                            coordination_number.cn += 1
197                    else:
198                        continue
199
200            list_coordinations_number.append(coordination_number)
201
202        self = cls()
203        self.id_of_bond = id_of_bond
204        self.atom_symbol = atom_symbol_1
205        self.list_coordinations_number = list_coordinations_number
206
207        return self
208
209    def calculate_statistics(self):
210        """Calculate statistics of CoordinationNumbers.
211
212        Statistic are in "statistics" attribute.
213
214        Returns:
215            CoordinationNumbers: CoordinationNumbers object
216
217        """
218        cns = self._get_list_of_coordination_numbers()
219        quantities: dict = {}
220        for cn in cns:
221            for item in self.list_coordinations_number:
222                if item.cn == cn:
223                    if quantities.get(cn, None) is None:
224                        quantities.update({cn: 1})
225                    else:
226                        quantities[cn] = quantities[cn] + 1
227
228        number_of_atoms = len(self.list_coordinations_number)
229        statistics = {}
230        for key, value in quantities.items():
231            statistics.update({key: (value/number_of_atoms) * 100})
232
233        self.statistics = statistics
234
235        return self
236
237    def _get_list_of_coordination_numbers(self) -> list[int]:
238        cns = []
239        for item in self.list_coordinations_number:
240            if item.cn not in cns:
241                cns += [item.cn]
242
243        return cns
244
245    def to_string(self) -> str:
246        """Make string from CoordinationNumbers object.
247
248        Returns:
249            **str**: String.
250
251        """
252        string = "## CN of " + str(self.atom_symbol) + " bond: "\
253            + str(self.id_of_bond) + "\n\n"
254        for item in self.list_coordinations_number:
255            string = string + "id: " + str(item.id_atom_1) + " "\
256                + "CN: " + str(item.cn)
257
258            if item.cn != 0:
259                string += "\n" + "Bond orders (id: mbo): "
260
261            length = len(item.bonds)
262            i = 1
263            for key, value in item.bonds.items():
264                string += str(key) + ': ' + str(value)
265                if i < length:
266                    string += ', '
267                else:
268                    pass
269                i += 1
270
271            string += '\n'
272        string += '\n'
273
274        if self.statistics is not None:
275            string = string + "Statistics of: "\
276                + str(self.atom_symbol) + "\n\n" + "CN %\n"
277            for key, value in self.statistics.items():
278                string = string + str(key) + ' ' + str(round(value, 3)) + '\n'
279
280            string = string + '\n'
281
282        return string

Generate list of CoordinationNumber objects and processes it.

List of CoordinationNumber objects.

id_of_bond: str

Id of bond eg. 'P-O'

atom_symbol: str

Symbol of atom.

statistics: dict[int, float] | None = None

Key - coordination number, value - percentages.

@classmethod
def calculate( cls, mayer_bond_orders: bond_order_processing.input_data.MayerBondOrders, atom_symbol_1: str, atom_symbol_2: str, max_mayer_bond_order: float | str, min_mayer_bond_order: float, id_of_bond: str):
149    @classmethod
150    def calculate(cls, mayer_bond_orders: MayerBondOrders,
151                  atom_symbol_1: str, atom_symbol_2: str,
152                  max_mayer_bond_order: float | str,
153                  min_mayer_bond_order: float,
154                  id_of_bond: str):
155        """Calculate CoordinationNumbers object.
156
157        Args:
158            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
159            atom_symbol_1 (str): Central atom symbol.
160            atom_symbol_2 (str): Ligand symbol.
161            max_mayer_bond_order (float): Max cut of radius, float or 'INF" if infinite value.
162            min_mayer_bond_order (float): Min cut of radius.
163            id_of_bond (str): id of bond eg. 'P-O'
164
165        Returns:
166            **CoordinationNumbers**: CoordinationNumbers object
167
168        """
169
170        if max_mayer_bond_order != "INF"\
171                and not (type(max_mayer_bond_order) is float):
172            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
173
174        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
175        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
176
177        list_coordinations_number = []
178        for atom_1_id in atom_1_ids:
179
180            coordination_number = cls.CoordinationNumber(atom_1_id, 0, {})
181
182            for atom_2_id in atom_2_ids:
183                if atom_1_id != atom_2_id:
184
185                    mbo = mayer_bond_orders\
186                        .get_mayer_bond_order_between_atoms(atom_1_id,
187                                                            atom_2_id)
188                    if (mbo > min_mayer_bond_order
189                            and max_mayer_bond_order == 'INF'):
190                        coordination_number.bonds.update({atom_2_id: mbo})
191                        coordination_number.cn += 1
192                    elif (type(max_mayer_bond_order) is float):
193                        if (mbo > min_mayer_bond_order
194                                and mbo < max_mayer_bond_order):
195                            coordination_number.bonds.update({atom_2_id: mbo})
196                            coordination_number.cn += 1
197                    else:
198                        continue
199
200            list_coordinations_number.append(coordination_number)
201
202        self = cls()
203        self.id_of_bond = id_of_bond
204        self.atom_symbol = atom_symbol_1
205        self.list_coordinations_number = list_coordinations_number
206
207        return self

Calculate CoordinationNumbers object.

Arguments:
  • mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
  • atom_symbol_1 (str): Central atom symbol.
  • atom_symbol_2 (str): Ligand symbol.
  • max_mayer_bond_order (float): Max cut of radius, float or 'INF" if infinite value.
  • min_mayer_bond_order (float): Min cut of radius.
  • id_of_bond (str): id of bond eg. 'P-O'
Returns:

CoordinationNumbers: CoordinationNumbers object

def calculate_statistics(self):
209    def calculate_statistics(self):
210        """Calculate statistics of CoordinationNumbers.
211
212        Statistic are in "statistics" attribute.
213
214        Returns:
215            CoordinationNumbers: CoordinationNumbers object
216
217        """
218        cns = self._get_list_of_coordination_numbers()
219        quantities: dict = {}
220        for cn in cns:
221            for item in self.list_coordinations_number:
222                if item.cn == cn:
223                    if quantities.get(cn, None) is None:
224                        quantities.update({cn: 1})
225                    else:
226                        quantities[cn] = quantities[cn] + 1
227
228        number_of_atoms = len(self.list_coordinations_number)
229        statistics = {}
230        for key, value in quantities.items():
231            statistics.update({key: (value/number_of_atoms) * 100})
232
233        self.statistics = statistics
234
235        return self

Calculate statistics of CoordinationNumbers.

Statistic are in "statistics" attribute.

Returns:

CoordinationNumbers: CoordinationNumbers object

def to_string(self) -> str:
245    def to_string(self) -> str:
246        """Make string from CoordinationNumbers object.
247
248        Returns:
249            **str**: String.
250
251        """
252        string = "## CN of " + str(self.atom_symbol) + " bond: "\
253            + str(self.id_of_bond) + "\n\n"
254        for item in self.list_coordinations_number:
255            string = string + "id: " + str(item.id_atom_1) + " "\
256                + "CN: " + str(item.cn)
257
258            if item.cn != 0:
259                string += "\n" + "Bond orders (id: mbo): "
260
261            length = len(item.bonds)
262            i = 1
263            for key, value in item.bonds.items():
264                string += str(key) + ': ' + str(value)
265                if i < length:
266                    string += ', '
267                else:
268                    pass
269                i += 1
270
271            string += '\n'
272        string += '\n'
273
274        if self.statistics is not None:
275            string = string + "Statistics of: "\
276                + str(self.atom_symbol) + "\n\n" + "CN %\n"
277            for key, value in self.statistics.items():
278                string = string + str(key) + ' ' + str(round(value, 3)) + '\n'
279
280            string = string + '\n'
281
282        return string

Make string from CoordinationNumbers object.

Returns:

str: String.

@dataclass
class CoordinationNumbers.CoordinationNumber:
122@dataclass
123class CoordinationNumber:
124    """Object stores coordination number of given atom and
125    Mayer bond orders corresponding to the bonds in the
126    coordination polyhedron."""
127
128    id_atom_1: int
129    """Central atom id."""
130    cn: int
131    """Value of coordination number."""
132    bonds: dict[int, float]
133    """**Key** - ligand id, **value** - Mayer bond order."""

Object stores coordination number of given atom and Mayer bond orders corresponding to the bonds in the coordination polyhedron.

class QiUnits(Calculations, Statistics):
285class QiUnits(Calculations, Statistics):
286    """Stores information about Qi units."""
287    id_of_bond: str
288    """Id of bonds in Qⁱ unit"""
289    atom_symbol_1: str
290    """Symbol of central atom"""
291    atom_symbol_2: str
292    """Symbol of ligands"""
293    q_i_units: dict[int, int] = {}
294    """Dictionary stores values of i of Qⁱ units. key - central atom id."""
295    statistics: dict[int, float] | None = None
296    """Dictionary stores percentages of Qⁱ units. key - value of i in Qⁱ"""
297
298    @classmethod
299    def calculate(cls, mayer_bond_orders: MayerBondOrders,
300                  atom_symbol_1: str,
301                  atom_symbol_2: str,
302                  max_mayer_bond_order: float | str,
303                  min_mayer_bond_order: float,
304                  id_of_bond: str):
305        """Calculate QiUnits object.
306
307        Args:
308            mayer_bond_orders (MayerBondOrders): Object MayerBondOrders.
309            atom_symbol_1 (str): Symbol of central atom.
310            atom_symbol_2 (str): Symbol of ligands.
311            max_mayer_bond_order (float | str): Max Mayer bond order, float or 'INF' for infinite maximum value.
312            min_mayer_bond_order (float): Min Mayer bond order.
313            id_of_bond (str): Name of bond eg. 'P-O'.
314
315        Raises:
316            ValueError: "Wrong type of max_mayer_bond_order!!!!"
317
318        Returns:
319            **QiUnits**: Returns QiUnits object.
320
321        """
322
323        if max_mayer_bond_order != "INF"\
324                and not (type(max_mayer_bond_order) is float):
325            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
326        elif max_mayer_bond_order == "INF":
327            inf = True
328            max_mayer_bond_order = -1
329            # -1 to prevent exception
330        else:
331            inf = False
332
333        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
334        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
335
336        self = cls()
337        self.id_of_bond = id_of_bond
338        self.atom_symbol_1 = atom_symbol_1
339        self.atom_symbol_2 = atom_symbol_2
340        self.q_i_units = {}
341        for atom_1_id in atom_1_ids:
342
343            self.q_i_units.update({atom_1_id: 0})
344
345            for atom_2_id in atom_2_ids:
346                mbo = mayer_bond_orders\
347                    .get_mayer_bond_order_between_atoms(atom_1_id,
348                                                        atom_2_id)
349                if (mbo > min_mayer_bond_order
350                        and (mbo < max_mayer_bond_order or inf)):
351
352                    for atom_3_id in atom_1_ids:
353                        mbo = mayer_bond_orders\
354                            .get_mayer_bond_order_between_atoms(atom_2_id,
355                                                                atom_3_id)
356                        if (mbo > min_mayer_bond_order
357                                and (mbo < max_mayer_bond_order or inf)
358                                and atom_3_id != atom_1_id):
359
360                            self.q_i_units[atom_1_id] += 1
361                            break
362
363                        else:
364                            continue
365
366        return self
367
368    def calculate_statistics(self):
369        """Calculate statistics in object QiUnits.
370
371        Returns:
372            **QiUnits**: QiUnits object.
373
374        """
375
376        unique_values = []
377        for value in self.q_i_units.values():
378            if value not in unique_values:
379                unique_values.append(value)
380
381        quantities = {}
382        for unique in unique_values:
383            quantities.update({unique: 0})
384            for value in self.q_i_units.values():
385                if value == unique:
386                    quantities[unique] += 1
387                else:
388                    continue
389
390        quantity_of_all_Q_i = len(self.q_i_units)
391
392        self.statistics = {}
393
394        for key, value in quantities.items():
395            self.statistics.update({key: (value/quantity_of_all_Q_i) * 100})
396
397        return self
398
399    def to_string(self) -> str:
400        """Generate string representing object.
401
402        Returns:
403            **str**: String.
404
405        """
406        string = "Q_i of " + str(self.atom_symbol_1) + ' bond id: '\
407            + str(self.id_of_bond) + "\n\n"
408
409        string += "id Q_i[i]\n"
410
411        for key, value in self.q_i_units.items():
412            string = string + str(key) + ' ' + str(value) + '\n'
413
414        string += '\n'
415
416        if self.statistics is not None:
417            string = string + 'Statistics of Q_i: ' + str(self.atom_symbol_1)\
418                + ', bond id: ' + str(self.id_of_bond) + '\n\n'
419
420            string += 'Q_i[i] [%]\n'
421
422            for key, value in self.statistics.items():
423                string = string + str(key) + ' ' + str(round(value, 3)) + '\n'
424
425        string += '\n'
426
427        return string

Stores information about Qi units.

id_of_bond: str

Id of bonds in Qⁱ unit

atom_symbol_1: str

Symbol of central atom

atom_symbol_2: str

Symbol of ligands

q_i_units: dict[int, int] = {}

Dictionary stores values of i of Qⁱ units. key - central atom id.

statistics: dict[int, float] | None = None

Dictionary stores percentages of Qⁱ units. key - value of i in Qⁱ

@classmethod
def calculate( cls, mayer_bond_orders: bond_order_processing.input_data.MayerBondOrders, atom_symbol_1: str, atom_symbol_2: str, max_mayer_bond_order: float | str, min_mayer_bond_order: float, id_of_bond: str):
298    @classmethod
299    def calculate(cls, mayer_bond_orders: MayerBondOrders,
300                  atom_symbol_1: str,
301                  atom_symbol_2: str,
302                  max_mayer_bond_order: float | str,
303                  min_mayer_bond_order: float,
304                  id_of_bond: str):
305        """Calculate QiUnits object.
306
307        Args:
308            mayer_bond_orders (MayerBondOrders): Object MayerBondOrders.
309            atom_symbol_1 (str): Symbol of central atom.
310            atom_symbol_2 (str): Symbol of ligands.
311            max_mayer_bond_order (float | str): Max Mayer bond order, float or 'INF' for infinite maximum value.
312            min_mayer_bond_order (float): Min Mayer bond order.
313            id_of_bond (str): Name of bond eg. 'P-O'.
314
315        Raises:
316            ValueError: "Wrong type of max_mayer_bond_order!!!!"
317
318        Returns:
319            **QiUnits**: Returns QiUnits object.
320
321        """
322
323        if max_mayer_bond_order != "INF"\
324                and not (type(max_mayer_bond_order) is float):
325            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
326        elif max_mayer_bond_order == "INF":
327            inf = True
328            max_mayer_bond_order = -1
329            # -1 to prevent exception
330        else:
331            inf = False
332
333        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
334        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
335
336        self = cls()
337        self.id_of_bond = id_of_bond
338        self.atom_symbol_1 = atom_symbol_1
339        self.atom_symbol_2 = atom_symbol_2
340        self.q_i_units = {}
341        for atom_1_id in atom_1_ids:
342
343            self.q_i_units.update({atom_1_id: 0})
344
345            for atom_2_id in atom_2_ids:
346                mbo = mayer_bond_orders\
347                    .get_mayer_bond_order_between_atoms(atom_1_id,
348                                                        atom_2_id)
349                if (mbo > min_mayer_bond_order
350                        and (mbo < max_mayer_bond_order or inf)):
351
352                    for atom_3_id in atom_1_ids:
353                        mbo = mayer_bond_orders\
354                            .get_mayer_bond_order_between_atoms(atom_2_id,
355                                                                atom_3_id)
356                        if (mbo > min_mayer_bond_order
357                                and (mbo < max_mayer_bond_order or inf)
358                                and atom_3_id != atom_1_id):
359
360                            self.q_i_units[atom_1_id] += 1
361                            break
362
363                        else:
364                            continue
365
366        return self

Calculate QiUnits object.

Arguments:
  • mayer_bond_orders (MayerBondOrders): Object MayerBondOrders.
  • atom_symbol_1 (str): Symbol of central atom.
  • atom_symbol_2 (str): Symbol of ligands.
  • max_mayer_bond_order (float | str): Max Mayer bond order, float or 'INF' for infinite maximum value.
  • min_mayer_bond_order (float): Min Mayer bond order.
  • id_of_bond (str): Name of bond eg. 'P-O'.
Raises:
  • ValueError: "Wrong type of max_mayer_bond_order!!!!"
Returns:

QiUnits: Returns QiUnits object.

def calculate_statistics(self):
368    def calculate_statistics(self):
369        """Calculate statistics in object QiUnits.
370
371        Returns:
372            **QiUnits**: QiUnits object.
373
374        """
375
376        unique_values = []
377        for value in self.q_i_units.values():
378            if value not in unique_values:
379                unique_values.append(value)
380
381        quantities = {}
382        for unique in unique_values:
383            quantities.update({unique: 0})
384            for value in self.q_i_units.values():
385                if value == unique:
386                    quantities[unique] += 1
387                else:
388                    continue
389
390        quantity_of_all_Q_i = len(self.q_i_units)
391
392        self.statistics = {}
393
394        for key, value in quantities.items():
395            self.statistics.update({key: (value/quantity_of_all_Q_i) * 100})
396
397        return self

Calculate statistics in object QiUnits.

Returns:

QiUnits: QiUnits object.

def to_string(self) -> str:
399    def to_string(self) -> str:
400        """Generate string representing object.
401
402        Returns:
403            **str**: String.
404
405        """
406        string = "Q_i of " + str(self.atom_symbol_1) + ' bond id: '\
407            + str(self.id_of_bond) + "\n\n"
408
409        string += "id Q_i[i]\n"
410
411        for key, value in self.q_i_units.items():
412            string = string + str(key) + ' ' + str(value) + '\n'
413
414        string += '\n'
415
416        if self.statistics is not None:
417            string = string + 'Statistics of Q_i: ' + str(self.atom_symbol_1)\
418                + ', bond id: ' + str(self.id_of_bond) + '\n\n'
419
420            string += 'Q_i[i] [%]\n'
421
422            for key, value in self.statistics.items():
423                string = string + str(key) + ' ' + str(round(value, 3)) + '\n'
424
425        string += '\n'
426
427        return string

Generate string representing object.

Returns:

str: String.

@dataclass
class Connection:
430@dataclass
431class Connection:
432    """An object represents connections between two elements."""
433    id_atom_2 = int
434    mayer_bond_order = float
435
436    atom_symbol_2: str
437    """Ligant atom symbol."""
438    bond_id: str
439    """Bond id eg. 'P-O'"""
440    quantity: int
441    """Quantity of given connections"""
442    bonds: dict[id_atom_2, mayer_bond_order]
443    """**key**- ligand id, **value**-mayer bond order."""

An object represents connections between two elements.

Connection( atom_symbol_2: str, bond_id: str, quantity: int, bonds: dict[int, float])
atom_symbol_2: str

Ligant atom symbol.

bond_id: str

Bond id eg. 'P-O'

quantity: int

Quantity of given connections

bonds: dict[int, float]

key- ligand id, value-mayer bond order.

class Connections(Calculations):
446class Connections(Calculations):
447    """Object represents connections of given atom to nearest neighbors.
448    """
449    atom_1_id: TypeAlias = int
450    Connection: type = Connection
451
452    connections: dict[atom_1_id, list[Connection]]
453    """Key - central atom, values - list to Connection objects."""
454    atom_symbol_1: str
455    """Symbol of central atom."""
456
457    @ classmethod
458    def calculate(cls, mayer_bond_orders: MayerBondOrders,
459                  atom_symbol_1: str,
460                  pairs_atoms_list: list[PairOfAtoms]
461                  ):
462        """Calculate Connections object.
463
464        Args:
465            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
466            atom_symbol_1 (str): Central atom symbol.
467            pairs_atoms_list (list[PairOfAtoms]): list of PairsOfAtoms objects.
468
469        Raises:
470            ValueError: "Wrong type of max_mayer_bond_order!!!!"
471
472        Returns:
473            **Connections**: Connections object.
474
475        """
476
477        pair_atom_list_containing_atom_1 = []
478        for pair_atom in pairs_atoms_list:
479            if pair_atom.atom_1 == atom_symbol_1\
480                    or pair_atom.atom_2 == atom_symbol_1:
481
482                pair_atom_list_containing_atom_1.append(pair_atom)
483            else:
484                continue
485
486        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
487        connections = {}
488        for atom_1_id in atom_1_ids:
489
490            connections.update({atom_1_id: []})
491
492            for pair_atoms in pair_atom_list_containing_atom_1:
493                if (v := pair_atoms.atom_1) != atom_symbol_1:
494                    atom_symbol_2 = v
495                else:
496                    atom_symbol_2 = pair_atoms.atom_2
497
498                connection = cls.Connection(
499                    atom_symbol_2, pair_atoms.id, 0, {})
500
501                atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
502
503                for atom_2_id in atom_2_ids:
504                    if pair_atoms.MBO_max != "INF"\
505                            and not (type(pair_atoms.MBO_max) is float):
506                        raise ValueError(
507                            "Wrong type of max_mayer_bond_order!!!!")
508
509                    mbo = mayer_bond_orders\
510                        .get_mayer_bond_order_between_atoms(atom_1_id,
511                                                            atom_2_id)
512
513                    if (mbo > pair_atoms.MBO_min
514                            and pair_atoms.MBO_max == 'INF'):
515
516                        connection.quantity += 1
517                        connection.bonds.update({atom_2_id: mbo})
518
519                    elif (pair_atoms.MBO_max != 'INF'):
520                        if (mbo > pair_atoms.MBO_min
521                                and pair_atoms.MBO_max > mbo):
522
523                            connection.quantity += 1
524                            connection.bonds.update({atom_2_id: mbo})
525
526                connections[atom_1_id].append(connection)
527
528        self = cls()
529        self.connections = connections
530        self.atom_symbol_1 = atom_symbol_1
531
532        return self
533
534    def to_string(self) -> str:
535        """Generates string representation of object.
536
537        Returns:
538            **str**: string.
539
540        """
541        string = '## Connections of: ' + str(self.atom_symbol_1) + '\n\n'
542
543        for atom_1_id, list_of_connections in self.connections.items():
544            string = string + "### Central atom id: " + str(atom_1_id) + "\n"
545
546            for connection in list_of_connections:
547
548                string = string + f"Bond id: {str(connection.bond_id)} "\
549                    + f"(second atom: {str(connection.atom_symbol_2)})\n"\
550                    + f"quantity: {connection.quantity}\n"\
551                    + "Bonds:\n"
552
553                string_id_line = "id: "
554                string_mbo_line = "mbo: "
555
556                for id, mbo in connection.bonds.items():
557                    string_id_line += f"{id} "
558                    string_mbo_line += f"{round(mbo, 3)} "
559
560                string = string + string_id_line + '\n'\
561                    + string_mbo_line + '\n\n'
562
563        return string

Object represents connections of given atom to nearest neighbors.

connections: dict[int, list[bond_order_processing.calculations.Connection]]

Key - central atom, values - list to Connection objects.

atom_symbol_1: str

Symbol of central atom.

@classmethod
def calculate( cls, mayer_bond_orders: bond_order_processing.input_data.MayerBondOrders, atom_symbol_1: str, pairs_atoms_list: list[bond_order_processing.calculations.PairOfAtoms]):
457    @ classmethod
458    def calculate(cls, mayer_bond_orders: MayerBondOrders,
459                  atom_symbol_1: str,
460                  pairs_atoms_list: list[PairOfAtoms]
461                  ):
462        """Calculate Connections object.
463
464        Args:
465            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
466            atom_symbol_1 (str): Central atom symbol.
467            pairs_atoms_list (list[PairOfAtoms]): list of PairsOfAtoms objects.
468
469        Raises:
470            ValueError: "Wrong type of max_mayer_bond_order!!!!"
471
472        Returns:
473            **Connections**: Connections object.
474
475        """
476
477        pair_atom_list_containing_atom_1 = []
478        for pair_atom in pairs_atoms_list:
479            if pair_atom.atom_1 == atom_symbol_1\
480                    or pair_atom.atom_2 == atom_symbol_1:
481
482                pair_atom_list_containing_atom_1.append(pair_atom)
483            else:
484                continue
485
486        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
487        connections = {}
488        for atom_1_id in atom_1_ids:
489
490            connections.update({atom_1_id: []})
491
492            for pair_atoms in pair_atom_list_containing_atom_1:
493                if (v := pair_atoms.atom_1) != atom_symbol_1:
494                    atom_symbol_2 = v
495                else:
496                    atom_symbol_2 = pair_atoms.atom_2
497
498                connection = cls.Connection(
499                    atom_symbol_2, pair_atoms.id, 0, {})
500
501                atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
502
503                for atom_2_id in atom_2_ids:
504                    if pair_atoms.MBO_max != "INF"\
505                            and not (type(pair_atoms.MBO_max) is float):
506                        raise ValueError(
507                            "Wrong type of max_mayer_bond_order!!!!")
508
509                    mbo = mayer_bond_orders\
510                        .get_mayer_bond_order_between_atoms(atom_1_id,
511                                                            atom_2_id)
512
513                    if (mbo > pair_atoms.MBO_min
514                            and pair_atoms.MBO_max == 'INF'):
515
516                        connection.quantity += 1
517                        connection.bonds.update({atom_2_id: mbo})
518
519                    elif (pair_atoms.MBO_max != 'INF'):
520                        if (mbo > pair_atoms.MBO_min
521                                and pair_atoms.MBO_max > mbo):
522
523                            connection.quantity += 1
524                            connection.bonds.update({atom_2_id: mbo})
525
526                connections[atom_1_id].append(connection)
527
528        self = cls()
529        self.connections = connections
530        self.atom_symbol_1 = atom_symbol_1
531
532        return self

Calculate Connections object.

Arguments:
  • mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
  • atom_symbol_1 (str): Central atom symbol.
  • pairs_atoms_list (list[PairOfAtoms]): list of PairsOfAtoms objects.
Raises:
  • ValueError: "Wrong type of max_mayer_bond_order!!!!"
Returns:

Connections: Connections object.

def to_string(self) -> str:
534    def to_string(self) -> str:
535        """Generates string representation of object.
536
537        Returns:
538            **str**: string.
539
540        """
541        string = '## Connections of: ' + str(self.atom_symbol_1) + '\n\n'
542
543        for atom_1_id, list_of_connections in self.connections.items():
544            string = string + "### Central atom id: " + str(atom_1_id) + "\n"
545
546            for connection in list_of_connections:
547
548                string = string + f"Bond id: {str(connection.bond_id)} "\
549                    + f"(second atom: {str(connection.atom_symbol_2)})\n"\
550                    + f"quantity: {connection.quantity}\n"\
551                    + "Bonds:\n"
552
553                string_id_line = "id: "
554                string_mbo_line = "mbo: "
555
556                for id, mbo in connection.bonds.items():
557                    string_id_line += f"{id} "
558                    string_mbo_line += f"{round(mbo, 3)} "
559
560                string = string + string_id_line + '\n'\
561                    + string_mbo_line + '\n\n'
562
563        return string

Generates string representation of object.

Returns:

str: string.

@dataclass
class Connections.Connection:
430@dataclass
431class Connection:
432    """An object represents connections between two elements."""
433    id_atom_2 = int
434    mayer_bond_order = float
435
436    atom_symbol_2: str
437    """Ligant atom symbol."""
438    bond_id: str
439    """Bond id eg. 'P-O'"""
440    quantity: int
441    """Quantity of given connections"""
442    bonds: dict[id_atom_2, mayer_bond_order]
443    """**key**- ligand id, **value**-mayer bond order."""

An object represents connections between two elements.

class Covalence(Calculations):
566class Covalence(Calculations):
567    """Object storages covalences of atoms"""
568    covalence: dict[int, float]
569    """Key - id of atom, value - covalence calculated from Mayer bond orders."""
570    atom_symbol: str
571    """Atom symbol."""
572
573    @ classmethod
574    def calculate(cls, mayer_bond_orders: MayerBondOrders,
575                  atom_symbol: str):
576        """Calculate Covalence object.
577
578        Args:
579            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
580            atom_symbol (str): Atom symbol.
581
582        Returns:
583            **Covalence**: Covalence object.
584
585        """
586
587        atom_ids = mayer_bond_orders.get_atoms_ids(atom_symbol)
588
589        self = cls()
590        self.atom_symbol = atom_symbol
591        self.covalence = {}
592        for id in atom_ids:
593            mbos = mayer_bond_orders.get_all_mayer_bond_orders_of_atom(id)
594            self.covalence.update({id: sum(mbos)})
595
596        return self
597
598    def to_string(self) -> str:
599        """Generates string representation of object.
600
601        Returns:
602            **str**: String.
603
604        """
605        string = f'Covalence of {self.atom_symbol}.\n\n'\
606            + 'id COV\n'
607
608        for id, value in self.covalence.items():
609            string = string + f'{id} {value:.3f}\n'
610        string += '\n'
611
612        return string

Object storages covalences of atoms

covalence: dict[int, float]

Key - id of atom, value - covalence calculated from Mayer bond orders.

atom_symbol: str

Atom symbol.

@classmethod
def calculate( cls, mayer_bond_orders: bond_order_processing.input_data.MayerBondOrders, atom_symbol: str):
573    @ classmethod
574    def calculate(cls, mayer_bond_orders: MayerBondOrders,
575                  atom_symbol: str):
576        """Calculate Covalence object.
577
578        Args:
579            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
580            atom_symbol (str): Atom symbol.
581
582        Returns:
583            **Covalence**: Covalence object.
584
585        """
586
587        atom_ids = mayer_bond_orders.get_atoms_ids(atom_symbol)
588
589        self = cls()
590        self.atom_symbol = atom_symbol
591        self.covalence = {}
592        for id in atom_ids:
593            mbos = mayer_bond_orders.get_all_mayer_bond_orders_of_atom(id)
594            self.covalence.update({id: sum(mbos)})
595
596        return self

Calculate Covalence object.

Arguments:
  • mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
  • atom_symbol (str): Atom symbol.
Returns:

Covalence: Covalence object.

def to_string(self) -> str:
598    def to_string(self) -> str:
599        """Generates string representation of object.
600
601        Returns:
602            **str**: String.
603
604        """
605        string = f'Covalence of {self.atom_symbol}.\n\n'\
606            + 'id COV\n'
607
608        for id, value in self.covalence.items():
609            string = string + f'{id} {value:.3f}\n'
610        string += '\n'
611
612        return string

Generates string representation of object.

Returns:

str: String.

class BondLength(Calculations):
615class BondLength(Calculations):
616    """Object stored bond lengths of pairs of atoms."""
617    atom_id_1: TypeAlias = int
618    atom_id_2: TypeAlias = int
619
620    id_of_bond: str
621    """Id of bond eg. 'P-O'"""
622    atom_symbol_1: str
623    """Atom 1 symbol."""
624    atom_symbol_2: str
625    """Atom 2 symbol."""
626    lengths: dict[atom_id_1, dict[atom_id_2, float]]
627    """**values**- length between atoms."""
628    mbos: dict[atom_id_1, dict[atom_id_2, float]]
629    """**values**- Mayer bond orders"""
630
631    @ classmethod
632    def calculate(cls,
633                  mayer_bond_orders: MayerBondOrders,
634                  coordinates_of_atoms: CoordinatesOfAtoms,
635                  atom_symbol_1: str,
636                  atom_symbol_2: str,
637                  max_mayer_bond_order: float | str,
638                  min_mayer_bond_order: float,
639                  id_of_bond: str):
640        """Calculate BondLength object.
641
642        Args:
643            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
644            coordinates_of_atoms (CoordinatesOfAtoms): CoordinatesOfAtom object.
645            atom_symbol_1 (str): Symbol of atom 1.
646            atom_symbol_2 (str): Symbol of atom 2.
647            max_mayer_bond_order (float | str): max value of Mayer bond order or 'INF for infinite value.
648            min_mayer_bond_order (float): min value of Mayer bond order.
649            id_of_bond (str): id of bond eg. 'P-O'
650
651        Raises:
652            ValueError: "Wrong type of max_mayer_bond_order!!!!"
653
654        Returns:
655            **BondLength**: BondLength object.
656
657        """
658
659        if max_mayer_bond_order != "INF"\
660                and not (type(max_mayer_bond_order) is float):
661            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
662        elif max_mayer_bond_order == "INF":
663            inf = True
664            max_mayer_bond_order = -1
665            # -1 to prevent exception
666        else:
667            inf = False
668
669        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
670        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
671
672        self = cls()
673        self.id_of_bond = id_of_bond
674        self.atom_symbol_1 = atom_symbol_1
675        self.atom_symbol_2 = atom_symbol_2
676        self.lengths = {}
677        self.mbos = {}
678
679        for atom_1_id in atom_1_ids:
680            self.lengths.update({atom_1_id: {}})
681            self.mbos.update({atom_1_id: {}})
682            for atom_2_id in atom_2_ids:
683                mbo = mayer_bond_orders\
684                    .get_mayer_bond_order_between_atoms(atom_1_id,
685                                                        atom_2_id)
686
687                length = coordinates_of_atoms\
688                    .get_distance_between_atoms(atom_1_id, atom_2_id)
689
690                if mbo > min_mayer_bond_order and (
691                    mbo < max_mayer_bond_order
692                    or inf is True
693                ):
694                    self.lengths[atom_1_id].update({atom_2_id: length})
695                    self.mbos[atom_1_id].update({atom_2_id: mbo})
696                else:
697                    continue
698
699        # remove empty keys.
700
701        for key in list(self.lengths.keys()):
702            if self.lengths[key] == {}:
703                del self.lengths[key]
704                del self.mbos[key]
705
706        return self
707
708    def to_string(self) -> str:
709        """Generates string representation of object.
710
711        Returns:
712            **str**: String.
713
714        """
715        string = f'Bond lengths of bond id: {self.id_of_bond} '\
716            + f'(atoms: {self.atom_symbol_1}, {self.atom_symbol_2}):\n\n'\
717            + 'id_1 id_2 length mbo\n'
718
719        for key_1 in self.lengths.keys():
720            for key_2 in self.lengths[key_1].keys():
721                string = string + f'{key_1} {key_2} '\
722                    + f'{self.lengths[key_1][key_2]} '\
723                    + f'{self.mbos[key_1][key_2]}\n'
724
725        string += '\n'
726
727        return string

Object stored bond lengths of pairs of atoms.

id_of_bond: str

Id of bond eg. 'P-O'

atom_symbol_1: str

Atom 1 symbol.

atom_symbol_2: str

Atom 2 symbol.

lengths: dict[int, dict[int, float]]

values- length between atoms.

mbos: dict[int, dict[int, float]]

values- Mayer bond orders

@classmethod
def calculate( cls, mayer_bond_orders: bond_order_processing.input_data.MayerBondOrders, coordinates_of_atoms: bond_order_processing.input_data.CoordinatesOfAtoms, atom_symbol_1: str, atom_symbol_2: str, max_mayer_bond_order: float | str, min_mayer_bond_order: float, id_of_bond: str):
631    @ classmethod
632    def calculate(cls,
633                  mayer_bond_orders: MayerBondOrders,
634                  coordinates_of_atoms: CoordinatesOfAtoms,
635                  atom_symbol_1: str,
636                  atom_symbol_2: str,
637                  max_mayer_bond_order: float | str,
638                  min_mayer_bond_order: float,
639                  id_of_bond: str):
640        """Calculate BondLength object.
641
642        Args:
643            mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
644            coordinates_of_atoms (CoordinatesOfAtoms): CoordinatesOfAtom object.
645            atom_symbol_1 (str): Symbol of atom 1.
646            atom_symbol_2 (str): Symbol of atom 2.
647            max_mayer_bond_order (float | str): max value of Mayer bond order or 'INF for infinite value.
648            min_mayer_bond_order (float): min value of Mayer bond order.
649            id_of_bond (str): id of bond eg. 'P-O'
650
651        Raises:
652            ValueError: "Wrong type of max_mayer_bond_order!!!!"
653
654        Returns:
655            **BondLength**: BondLength object.
656
657        """
658
659        if max_mayer_bond_order != "INF"\
660                and not (type(max_mayer_bond_order) is float):
661            raise ValueError("Wrong type of max_mayer_bond_order!!!!")
662        elif max_mayer_bond_order == "INF":
663            inf = True
664            max_mayer_bond_order = -1
665            # -1 to prevent exception
666        else:
667            inf = False
668
669        atom_1_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_1)
670        atom_2_ids = mayer_bond_orders.get_atoms_ids(atom_symbol_2)
671
672        self = cls()
673        self.id_of_bond = id_of_bond
674        self.atom_symbol_1 = atom_symbol_1
675        self.atom_symbol_2 = atom_symbol_2
676        self.lengths = {}
677        self.mbos = {}
678
679        for atom_1_id in atom_1_ids:
680            self.lengths.update({atom_1_id: {}})
681            self.mbos.update({atom_1_id: {}})
682            for atom_2_id in atom_2_ids:
683                mbo = mayer_bond_orders\
684                    .get_mayer_bond_order_between_atoms(atom_1_id,
685                                                        atom_2_id)
686
687                length = coordinates_of_atoms\
688                    .get_distance_between_atoms(atom_1_id, atom_2_id)
689
690                if mbo > min_mayer_bond_order and (
691                    mbo < max_mayer_bond_order
692                    or inf is True
693                ):
694                    self.lengths[atom_1_id].update({atom_2_id: length})
695                    self.mbos[atom_1_id].update({atom_2_id: mbo})
696                else:
697                    continue
698
699        # remove empty keys.
700
701        for key in list(self.lengths.keys()):
702            if self.lengths[key] == {}:
703                del self.lengths[key]
704                del self.mbos[key]
705
706        return self

Calculate BondLength object.

Arguments:
  • mayer_bond_orders (MayerBondOrders): MayerBondOrders object.
  • coordinates_of_atoms (CoordinatesOfAtoms): CoordinatesOfAtom object.
  • atom_symbol_1 (str): Symbol of atom 1.
  • atom_symbol_2 (str): Symbol of atom 2.
  • max_mayer_bond_order (float | str): max value of Mayer bond order or 'INF for infinite value.
  • min_mayer_bond_order (float): min value of Mayer bond order.
  • id_of_bond (str): id of bond eg. 'P-O'
Raises:
  • ValueError: "Wrong type of max_mayer_bond_order!!!!"
Returns:

BondLength: BondLength object.

def to_string(self) -> str:
708    def to_string(self) -> str:
709        """Generates string representation of object.
710
711        Returns:
712            **str**: String.
713
714        """
715        string = f'Bond lengths of bond id: {self.id_of_bond} '\
716            + f'(atoms: {self.atom_symbol_1}, {self.atom_symbol_2}):\n\n'\
717            + 'id_1 id_2 length mbo\n'
718
719        for key_1 in self.lengths.keys():
720            for key_2 in self.lengths[key_1].keys():
721                string = string + f'{key_1} {key_2} '\
722                    + f'{self.lengths[key_1][key_2]} '\
723                    + f'{self.mbos[key_1][key_2]}\n'
724
725        string += '\n'
726
727        return string

Generates string representation of object.

Returns:

str: String.