MolSym 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. molsym-0.2.1/LICENSE.txt +21 -0
  2. molsym-0.2.1/MolSym.egg-info/PKG-INFO +83 -0
  3. molsym-0.2.1/MolSym.egg-info/SOURCES.txt +45 -0
  4. molsym-0.2.1/MolSym.egg-info/dependency_links.txt +1 -0
  5. molsym-0.2.1/MolSym.egg-info/requires.txt +4 -0
  6. molsym-0.2.1/MolSym.egg-info/top_level.txt +1 -0
  7. molsym-0.2.1/PKG-INFO +83 -0
  8. molsym-0.2.1/README.md +66 -0
  9. molsym-0.2.1/molsym/__init__.py +5 -0
  10. molsym-0.2.1/molsym/molecule.py +268 -0
  11. molsym-0.2.1/molsym/pgdetect/__init__.py +0 -0
  12. molsym-0.2.1/molsym/pgdetect/flowchart.py +124 -0
  13. molsym-0.2.1/molsym/pgdetect/flowchart_helper.py +498 -0
  14. molsym-0.2.1/molsym/salcs/__init__.py +11 -0
  15. molsym-0.2.1/molsym/salcs/cartesian_coordinates.py +69 -0
  16. molsym-0.2.1/molsym/salcs/function_set.py +28 -0
  17. molsym-0.2.1/molsym/salcs/internal_coordinates.py +201 -0
  18. molsym-0.2.1/molsym/salcs/linear_functions.py +73 -0
  19. molsym-0.2.1/molsym/salcs/projection_op.py +191 -0
  20. molsym-0.2.1/molsym/salcs/salc.py +232 -0
  21. molsym-0.2.1/molsym/salcs/salc_tools.py +105 -0
  22. molsym-0.2.1/molsym/salcs/spherical_harmonics.py +300 -0
  23. molsym-0.2.1/molsym/symmetrize.py +72 -0
  24. molsym-0.2.1/molsym/symtext/Ih_irrep_mats.py +1141 -0
  25. molsym-0.2.1/molsym/symtext/__init__.py +0 -0
  26. molsym-0.2.1/molsym/symtext/character_table.py +526 -0
  27. molsym-0.2.1/molsym/symtext/general_irrep_mats.py +529 -0
  28. molsym-0.2.1/molsym/symtext/goat.py +114 -0
  29. molsym-0.2.1/molsym/symtext/irrep_mats.py +760 -0
  30. molsym-0.2.1/molsym/symtext/linear_helper.py +0 -0
  31. molsym-0.2.1/molsym/symtext/multiplication_table.py +453 -0
  32. molsym-0.2.1/molsym/symtext/point_group.py +82 -0
  33. molsym-0.2.1/molsym/symtext/symel.py +592 -0
  34. molsym-0.2.1/molsym/symtext/symtext.py +278 -0
  35. molsym-0.2.1/molsym/symtext/symtext_helper.py +295 -0
  36. molsym-0.2.1/molsym/symtools.py +236 -0
  37. molsym-0.2.1/pyproject.toml +36 -0
  38. molsym-0.2.1/setup.cfg +4 -0
  39. molsym-0.2.1/test/test_find_pg.py +33 -0
  40. molsym-0.2.1/test/test_ics.py +69 -0
  41. molsym-0.2.1/test/test_molecule.py +60 -0
  42. molsym-0.2.1/test/test_new_generator.py +59 -0
  43. molsym-0.2.1/test/test_old_bugs.py +18 -0
  44. molsym-0.2.1/test/test_projection_op.py +586 -0
  45. molsym-0.2.1/test/test_psi4_pgbits.py +22 -0
  46. molsym-0.2.1/test/test_salc_tools.py +494 -0
  47. molsym-0.2.1/test/test_symtext.py +265 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Stephen M. Goodlett, Nathaniel L. Kitzmiller
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.4
2
+ Name: MolSym
3
+ Version: 0.2.1
4
+ Summary: A program for molecular symmetry detection and SALC construction
5
+ Author-email: Stephen Goodlett <smg13363@uga.edu>, Nate Kitzmiller <nathaniel.kitzmiller@uga.edu>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/NASymmetry/MolSym
8
+ Project-URL: Documentation, https://molsym.readthedocs.io
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE.txt
13
+ Requires-Dist: numpy>=1.23.4
14
+ Provides-Extra: qcel
15
+ Requires-Dist: qcelemental>=0.25.1; extra == "qcel"
16
+ Dynamic: license-file
17
+
18
+ <p align="center">
19
+ <img src="molsym_logo_v3.svg" width="400" alt=""/>
20
+ </p>
21
+ <table align="center">
22
+ <tr>
23
+ <th>Documentation</th>
24
+ <th>CI</th>
25
+ <th>Coverage</th>
26
+ <th>Citation</th>
27
+ </tr>
28
+ <tr>
29
+   <td align="center">
30
+ <a href='https://molsym.readthedocs.io/en/latest/?badge=latest'>
31
+ <img src='https://readthedocs.org/projects/molsym/badge/?version=latest' alt='Documentation Status' />
32
+ </a>
33
+ </td>
34
+   <td align="center">
35
+ <a href=https://github.com/NASymmetry/MolSym/actions/workflows/workflow.yml>
36
+ <img src=https://github.com/NASymmetry/MolSym/actions/workflows/workflow.yml/badge.svg>
37
+ </a>
38
+ </td>
39
+ <td align="center">
40
+ <a href=https://codecov.io/gh/NASymmetry/MolSym>
41
+ <img src=https://codecov.io/gh/NASymmetry/MolSym/branch/main/graph/badge.svg?token=NQDJ0QYLB0>
42
+ </a>
43
+ </td>
44
+ <td align="center">
45
+ <a href=https://doi.org/10.1063/5.0216738>
46
+ <img src=https://img.shields.io/badge/JCP-10.1063/5.0216738-purple.svg>
47
+ </a>
48
+ </td>
49
+ </tr>
50
+ </table>
51
+
52
+ # MolSym
53
+ A python package for handling molecular symmetry.
54
+
55
+
56
+ ## Capabilities
57
+ - [Point group detection](https://github.com/NASymmetry/MolSym/wiki/Point-group-detection)
58
+ - [Molecule symmetrization](https://github.com/NASymmetry/MolSym/wiki/Symmetrizing-a-molecule)
59
+ - Symmetry element generation
60
+ - Character table generation
61
+ - SALC generation for [atomic basis functions](https://github.com/NASymmetry/MolSym/wiki/SALCs#spherical-harmonics), [internal coordinates](https://github.com/NASymmetry/MolSym/wiki/SALCs#internal-coordinates), and [cartesian coordinates](https://github.com/NASymmetry/MolSym/wiki/SALCs#cartesian-coordinates)
62
+
63
+ ## Installing
64
+ As of now we do not have a better way to install the code other than cloning from GitHub.
65
+ Create a new conda environment with:
66
+
67
+ `conda create -n "NameYourEnvironment" python=3.X`
68
+
69
+ MolSym is tested with Python 3.9-3.13, but should work for more recent versions and some older versions as well.
70
+
71
+ `git clone git@github.com:NASymmetry/MolSym.git`
72
+
73
+ Install the necessary dependencies using `pip`.
74
+
75
+ `pip install -r <Path to MolSym directory>/requirements.tx`
76
+
77
+ Alternatively, most Python environments come equipped with all but one dependency, so if `pip` is not desired, installing `QCElemental` is all that should be required.
78
+
79
+ `conda install -c conda-forge qcelemental`
80
+
81
+ Finally append the MolSym directory to your `PYTHONPATH`.
82
+
83
+ `export PYTHONPATH=$PYTHONPATH:<Path to MolSym directory>`
@@ -0,0 +1,45 @@
1
+ LICENSE.txt
2
+ README.md
3
+ pyproject.toml
4
+ MolSym.egg-info/PKG-INFO
5
+ MolSym.egg-info/SOURCES.txt
6
+ MolSym.egg-info/dependency_links.txt
7
+ MolSym.egg-info/requires.txt
8
+ MolSym.egg-info/top_level.txt
9
+ molsym/__init__.py
10
+ molsym/molecule.py
11
+ molsym/symmetrize.py
12
+ molsym/symtools.py
13
+ molsym/pgdetect/__init__.py
14
+ molsym/pgdetect/flowchart.py
15
+ molsym/pgdetect/flowchart_helper.py
16
+ molsym/salcs/__init__.py
17
+ molsym/salcs/cartesian_coordinates.py
18
+ molsym/salcs/function_set.py
19
+ molsym/salcs/internal_coordinates.py
20
+ molsym/salcs/linear_functions.py
21
+ molsym/salcs/projection_op.py
22
+ molsym/salcs/salc.py
23
+ molsym/salcs/salc_tools.py
24
+ molsym/salcs/spherical_harmonics.py
25
+ molsym/symtext/Ih_irrep_mats.py
26
+ molsym/symtext/__init__.py
27
+ molsym/symtext/character_table.py
28
+ molsym/symtext/general_irrep_mats.py
29
+ molsym/symtext/goat.py
30
+ molsym/symtext/irrep_mats.py
31
+ molsym/symtext/linear_helper.py
32
+ molsym/symtext/multiplication_table.py
33
+ molsym/symtext/point_group.py
34
+ molsym/symtext/symel.py
35
+ molsym/symtext/symtext.py
36
+ molsym/symtext/symtext_helper.py
37
+ test/test_find_pg.py
38
+ test/test_ics.py
39
+ test/test_molecule.py
40
+ test/test_new_generator.py
41
+ test/test_old_bugs.py
42
+ test/test_projection_op.py
43
+ test/test_psi4_pgbits.py
44
+ test/test_salc_tools.py
45
+ test/test_symtext.py
@@ -0,0 +1,4 @@
1
+ numpy>=1.23.4
2
+
3
+ [qcel]
4
+ qcelemental>=0.25.1
@@ -0,0 +1 @@
1
+ molsym
molsym-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.4
2
+ Name: MolSym
3
+ Version: 0.2.1
4
+ Summary: A program for molecular symmetry detection and SALC construction
5
+ Author-email: Stephen Goodlett <smg13363@uga.edu>, Nate Kitzmiller <nathaniel.kitzmiller@uga.edu>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/NASymmetry/MolSym
8
+ Project-URL: Documentation, https://molsym.readthedocs.io
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE.txt
13
+ Requires-Dist: numpy>=1.23.4
14
+ Provides-Extra: qcel
15
+ Requires-Dist: qcelemental>=0.25.1; extra == "qcel"
16
+ Dynamic: license-file
17
+
18
+ <p align="center">
19
+ <img src="molsym_logo_v3.svg" width="400" alt=""/>
20
+ </p>
21
+ <table align="center">
22
+ <tr>
23
+ <th>Documentation</th>
24
+ <th>CI</th>
25
+ <th>Coverage</th>
26
+ <th>Citation</th>
27
+ </tr>
28
+ <tr>
29
+   <td align="center">
30
+ <a href='https://molsym.readthedocs.io/en/latest/?badge=latest'>
31
+ <img src='https://readthedocs.org/projects/molsym/badge/?version=latest' alt='Documentation Status' />
32
+ </a>
33
+ </td>
34
+   <td align="center">
35
+ <a href=https://github.com/NASymmetry/MolSym/actions/workflows/workflow.yml>
36
+ <img src=https://github.com/NASymmetry/MolSym/actions/workflows/workflow.yml/badge.svg>
37
+ </a>
38
+ </td>
39
+ <td align="center">
40
+ <a href=https://codecov.io/gh/NASymmetry/MolSym>
41
+ <img src=https://codecov.io/gh/NASymmetry/MolSym/branch/main/graph/badge.svg?token=NQDJ0QYLB0>
42
+ </a>
43
+ </td>
44
+ <td align="center">
45
+ <a href=https://doi.org/10.1063/5.0216738>
46
+ <img src=https://img.shields.io/badge/JCP-10.1063/5.0216738-purple.svg>
47
+ </a>
48
+ </td>
49
+ </tr>
50
+ </table>
51
+
52
+ # MolSym
53
+ A python package for handling molecular symmetry.
54
+
55
+
56
+ ## Capabilities
57
+ - [Point group detection](https://github.com/NASymmetry/MolSym/wiki/Point-group-detection)
58
+ - [Molecule symmetrization](https://github.com/NASymmetry/MolSym/wiki/Symmetrizing-a-molecule)
59
+ - Symmetry element generation
60
+ - Character table generation
61
+ - SALC generation for [atomic basis functions](https://github.com/NASymmetry/MolSym/wiki/SALCs#spherical-harmonics), [internal coordinates](https://github.com/NASymmetry/MolSym/wiki/SALCs#internal-coordinates), and [cartesian coordinates](https://github.com/NASymmetry/MolSym/wiki/SALCs#cartesian-coordinates)
62
+
63
+ ## Installing
64
+ As of now we do not have a better way to install the code other than cloning from GitHub.
65
+ Create a new conda environment with:
66
+
67
+ `conda create -n "NameYourEnvironment" python=3.X`
68
+
69
+ MolSym is tested with Python 3.9-3.13, but should work for more recent versions and some older versions as well.
70
+
71
+ `git clone git@github.com:NASymmetry/MolSym.git`
72
+
73
+ Install the necessary dependencies using `pip`.
74
+
75
+ `pip install -r <Path to MolSym directory>/requirements.tx`
76
+
77
+ Alternatively, most Python environments come equipped with all but one dependency, so if `pip` is not desired, installing `QCElemental` is all that should be required.
78
+
79
+ `conda install -c conda-forge qcelemental`
80
+
81
+ Finally append the MolSym directory to your `PYTHONPATH`.
82
+
83
+ `export PYTHONPATH=$PYTHONPATH:<Path to MolSym directory>`
molsym-0.2.1/README.md ADDED
@@ -0,0 +1,66 @@
1
+ <p align="center">
2
+ <img src="molsym_logo_v3.svg" width="400" alt=""/>
3
+ </p>
4
+ <table align="center">
5
+ <tr>
6
+ <th>Documentation</th>
7
+ <th>CI</th>
8
+ <th>Coverage</th>
9
+ <th>Citation</th>
10
+ </tr>
11
+ <tr>
12
+   <td align="center">
13
+ <a href='https://molsym.readthedocs.io/en/latest/?badge=latest'>
14
+ <img src='https://readthedocs.org/projects/molsym/badge/?version=latest' alt='Documentation Status' />
15
+ </a>
16
+ </td>
17
+   <td align="center">
18
+ <a href=https://github.com/NASymmetry/MolSym/actions/workflows/workflow.yml>
19
+ <img src=https://github.com/NASymmetry/MolSym/actions/workflows/workflow.yml/badge.svg>
20
+ </a>
21
+ </td>
22
+ <td align="center">
23
+ <a href=https://codecov.io/gh/NASymmetry/MolSym>
24
+ <img src=https://codecov.io/gh/NASymmetry/MolSym/branch/main/graph/badge.svg?token=NQDJ0QYLB0>
25
+ </a>
26
+ </td>
27
+ <td align="center">
28
+ <a href=https://doi.org/10.1063/5.0216738>
29
+ <img src=https://img.shields.io/badge/JCP-10.1063/5.0216738-purple.svg>
30
+ </a>
31
+ </td>
32
+ </tr>
33
+ </table>
34
+
35
+ # MolSym
36
+ A python package for handling molecular symmetry.
37
+
38
+
39
+ ## Capabilities
40
+ - [Point group detection](https://github.com/NASymmetry/MolSym/wiki/Point-group-detection)
41
+ - [Molecule symmetrization](https://github.com/NASymmetry/MolSym/wiki/Symmetrizing-a-molecule)
42
+ - Symmetry element generation
43
+ - Character table generation
44
+ - SALC generation for [atomic basis functions](https://github.com/NASymmetry/MolSym/wiki/SALCs#spherical-harmonics), [internal coordinates](https://github.com/NASymmetry/MolSym/wiki/SALCs#internal-coordinates), and [cartesian coordinates](https://github.com/NASymmetry/MolSym/wiki/SALCs#cartesian-coordinates)
45
+
46
+ ## Installing
47
+ As of now we do not have a better way to install the code other than cloning from GitHub.
48
+ Create a new conda environment with:
49
+
50
+ `conda create -n "NameYourEnvironment" python=3.X`
51
+
52
+ MolSym is tested with Python 3.9-3.13, but should work for more recent versions and some older versions as well.
53
+
54
+ `git clone git@github.com:NASymmetry/MolSym.git`
55
+
56
+ Install the necessary dependencies using `pip`.
57
+
58
+ `pip install -r <Path to MolSym directory>/requirements.tx`
59
+
60
+ Alternatively, most Python environments come equipped with all but one dependency, so if `pip` is not desired, installing `QCElemental` is all that should be required.
61
+
62
+ `conda install -c conda-forge qcelemental`
63
+
64
+ Finally append the MolSym directory to your `PYTHONPATH`.
65
+
66
+ `export PYTHONPATH=$PYTHONPATH:<Path to MolSym directory>`
@@ -0,0 +1,5 @@
1
+ from .molecule import Molecule
2
+ from .pgdetect.flowchart import find_point_group
3
+ from .symtext.symtext import Symtext
4
+ from .symmetrize import symmetrize
5
+ from .import salcs
@@ -0,0 +1,268 @@
1
+ import numpy as np
2
+ from dataclasses import dataclass
3
+ from copy import deepcopy
4
+ import sys
5
+ global_tol = 1e-8 # TODO It would be nice to get rid of this...
6
+
7
+ @dataclass
8
+ class Atom():
9
+ """
10
+ Dataclass for storing atom information
11
+
12
+ :param Z: Atomic number of atom.
13
+ :param mass: Mass of atom in amu as defined by QCElemental.
14
+ :param xyz: Position vector of atom in Cartesian coordinates.
15
+ :type Z: int
16
+ :type mass: float
17
+ :type xyz: NumPy array of shape (3,)
18
+ """
19
+ Z:int
20
+ mass:float
21
+ xyz:np.array
22
+
23
+ @dataclass
24
+ class SEA():
25
+ """
26
+ SEA: symmetry equivalent atoms.
27
+ SEAs are atoms that can be swapped with no distinguishable change in the molecule.
28
+
29
+ :param label: Optionally defines rotor type of SEA set (e.g. Single Atom, Linear, Spherical, Regular Polygon, Oblate Symmetric Top, etc.)
30
+ :param subset: Sublist of atom indices in molecule that constitute the SEA set
31
+ :param axis: Optionally defines possible rotational symmetry vector
32
+ :type label: str or None
33
+ :type subset: NumPy array of integers
34
+ :type axis: NumPy array of shape (3,) or None
35
+ """
36
+ label:str
37
+ subset:np.array
38
+ axis:np.array
39
+
40
+ class Molecule():
41
+ """
42
+ Class dealing with molecule relevant information.
43
+ Typically initiated from a QCSchema object.
44
+ """
45
+ def __init__(self, atoms, coords, masses) -> None:
46
+ self.tol = 1e-5
47
+ self.atoms = np.asarray(atoms)
48
+ try:
49
+ self.natoms = len(self.atoms)
50
+ except TypeError:
51
+ self.natoms = 1
52
+ self.coords = np.asarray(coords)
53
+ self.masses = np.asarray(masses)
54
+
55
+ @classmethod
56
+ def from_schema(cls, schema):
57
+ """
58
+ Class method for constructing a Molecule from a QCSchema object
59
+
60
+ :param schema: Schema dictionary to be converted to Molecule
61
+ :type schema: dict
62
+ :rtype: molsym.Molecule
63
+ """
64
+ import qcelemental as qcel
65
+ atoms = schema["symbols"]
66
+ natoms = len(atoms)
67
+ coords = np.reshape(schema["geometry"], (natoms,3))
68
+ # As of now, QCElemental seems to have issues assigning masses, so I do it
69
+ masses = np.zeros(natoms)
70
+ for (idx, symb) in enumerate(atoms):
71
+ masses[idx] = qcel.periodictable.to_mass(symb)
72
+ return cls(atoms, coords, masses)
73
+
74
+ @classmethod
75
+ def from_psi4_molecule(cls, mol):
76
+ """
77
+ Class method for constructing a Molecule from a QCSchema object
78
+
79
+ :param schema: Schema dictionary to be converted to Molecule
80
+ :type schema: dict
81
+ :rtype: molsym.Molecule
82
+ """
83
+ if "psi4" not in sys.modules:
84
+ raise ImportError("Psi4 is required to use this function")
85
+ atoms = [mol.symbol(i) for i in range(mol.natom())]
86
+ coords = mol.geometry().to_array()
87
+ masses = [mol.mass(i) for i in range(mol.natom())]
88
+ return cls(atoms, coords, masses)
89
+
90
+ @classmethod
91
+ def from_file(cls, fn, keep_angstrom=False):
92
+ """
93
+ Class method for constructing a Molecule from an *.xyz file
94
+
95
+ :param fn: Filename
96
+ :type fn: str
97
+ :rtype: molsym.Molecule
98
+ """
99
+ import qcelemental as qcel
100
+ with open(fn, "r") as lfn:
101
+ strang = lfn.read()
102
+
103
+ schema = qcel.models.Molecule.from_data(strang).dict()
104
+ if keep_angstrom:
105
+ schema["geometry"] *= qcel.constants.bohr2angstroms
106
+ return cls.from_schema(schema)
107
+
108
+ @classmethod
109
+ def from_psi4_schema(cls, schema):
110
+ """
111
+ Class method for constructing a Molecule from a QCSchema object generated in Psi4.
112
+ Schemas coming from Psi4 are different for some reason?
113
+
114
+ :param schema: Schema dictionary to be converted to Molecule
115
+ :type schema: dict
116
+ :rtype: molsym.Molecule
117
+ """
118
+ import qcelemental as qcel
119
+ atoms = schema["elem"] # was symbols
120
+ natoms = len(atoms)
121
+ coords = np.reshape(schema["geom"], (natoms,3)) # was geometry
122
+ # As of now, QCElemental seems to have issues assigning masses, so I do it
123
+ masses = np.zeros(natoms)
124
+ for (idx, symb) in enumerate(atoms):
125
+ masses[idx] = qcel.periodictable.to_mass(symb)
126
+ return cls(atoms, coords, masses)
127
+
128
+ def to_xyz_string(self, already_angstrom=False):
129
+ import qcelemental as qcel
130
+ # Will save xyz in Angstrom, undoing the previous
131
+ # Ang->Bohr from Molecule.from_schema
132
+ if already_angstrom:
133
+ self.coords /= qcel.constants.bohr2angstroms
134
+ qcmol = qcel.models.Molecule(
135
+ **{"symbols": self.atoms,
136
+ "geometry": self.coords})
137
+ return qcmol.to_string("xyz")
138
+
139
+ def __repr__(self) -> str:
140
+ rstr = "MolSym Molecule:\n"
141
+ for i in range(self.natoms):
142
+ rstr += f" {self.atoms[i]:3s} {self.coords[i,0]:12.8f}"
143
+ rstr += f" {self.coords[i,1]:12.8f} {self.coords[i,2]:12.8f}\n"
144
+ return rstr
145
+
146
+ def __str__(self) -> str:
147
+ return self.__repr__()
148
+
149
+ def __getitem__(self, i):
150
+ return Molecule(self.atoms[i], self.coords[i,:], self.masses[i])
151
+
152
+ def __len__(self):
153
+ return self.natoms
154
+
155
+ def __eq__(self, other):
156
+ # Select higher tolerance
157
+ if self.tol >= other.tol:
158
+ eq_tol = self.tol
159
+ else:
160
+ eq_tol = other.tol
161
+ if isinstance(other, Molecule):
162
+ c1 = (other.atoms == self.atoms).all()
163
+ c2 = (other.masses == self.masses).all()
164
+ c3 = np.allclose(other.coords, self.coords, atol=eq_tol)
165
+ return c1 and c2 and c3
166
+
167
+ def find_com(self):
168
+ """
169
+ Get center of mass of molecule.
170
+
171
+ :return: Center of mass
172
+ :rtype: NumPy array of shape (3,)
173
+ """
174
+ com = np.zeros(3)
175
+ for i in range(self.natoms):
176
+ com += self.masses[i]*self.coords[i,:]
177
+ return com / sum(self.masses)
178
+
179
+ def is_at_com(self):
180
+ """
181
+ Checks if molecule is at center of mass already.
182
+
183
+ :rtype: bool
184
+ """
185
+ if sum(abs(self.find_com())) < self.tol:
186
+ return True
187
+ else:
188
+ return False
189
+
190
+ def translate(self, r):
191
+ """
192
+ Translates Cartesian positions of all atoms in molecule in place by vector r.
193
+
194
+ :param r: Translation vector
195
+ :type r: NumPy array of shape (3,)
196
+ """
197
+ for i in range(self.natoms):
198
+ self.coords[i,:] -= r
199
+
200
+ def transform(self, M):
201
+ """
202
+ Transform coordinates of molecule by matrix M and return new molecule.
203
+
204
+ :param M: Transformation matrix (e.g. rotation, reflection, etc.)
205
+ :type M: NumPy array (3,3)
206
+ :return: Molecule with transformed atom coordinates
207
+ :rtype: molsym.Molecule
208
+ """
209
+ new_mol = deepcopy(self)
210
+ new_mol.coords = np.dot(new_mol.coords,np.transpose(M))
211
+ return new_mol
212
+
213
+ def distance_matrix(self):
214
+ """
215
+ Calculates the interatomic distance matrix as all pairwise distances between atoms.
216
+
217
+ :return: Interatomic distance matrix
218
+ :rtype: NumPy array of shape (self.natoms,self.natoms)
219
+ """
220
+ dm = np.zeros((self.natoms,self.natoms))
221
+ for i in range(self.natoms):
222
+ for j in range(i,self.natoms):
223
+ dm[i,j] = np.sqrt(sum((self.coords[i,:]-self.coords[j,:])**2))
224
+ dm[j,i] = dm[i,j]
225
+ return dm
226
+
227
+ def find_SEAs(self):
228
+ """
229
+ Find sets of symmetry equivalent atoms.
230
+ Permutations of the distance matrix reveal which atoms form symmetry equivalent sets.
231
+
232
+ :return: List of symmetry equivalent atom sets
233
+ :rtype: List[molsym.SEA]
234
+ """
235
+ dm = self.distance_matrix()
236
+ out = []
237
+ for i in range(self.natoms):
238
+ for j in range(i+1,self.natoms):
239
+ a_idx = np.argsort(dm[i,:])
240
+ b_idx = np.argsort(dm[j,:])
241
+ z = dm[i,a_idx] - dm[j,b_idx]
242
+ chk = True
243
+ for k in z:
244
+ if abs(k) < self.tol:
245
+ continue
246
+ else:
247
+ chk = False
248
+ if chk:
249
+ out.append((i,j))
250
+ skip = []
251
+ SEAs = []
252
+ for i in range(self.natoms):
253
+ if i in skip:
254
+ continue
255
+ else:
256
+ collect = [i]
257
+
258
+ for k in out:
259
+ if i in k:
260
+ if i == k[0]:
261
+ collect.append(k[1])
262
+ skip.append(k[1])
263
+ else:
264
+ collect.append(k[0])
265
+ skip.append(k[0])
266
+ SEAs.append(SEA("", collect, np.zeros(3)))
267
+ return SEAs
268
+
File without changes