{"id":18708990,"url":"https://github.com/abelcarreras/posym","last_synced_at":"2025-08-21T00:32:02.805Z","repository":{"id":41860982,"uuid":"351606301","full_name":"abelcarreras/posym","owner":"abelcarreras","description":"Point symmetry analysis tool for theoretical chemistry objects","archived":false,"fork":false,"pushed_at":"2025-03-06T18:11:14.000Z","size":687,"stargazers_count":20,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-30T17:40:42.493Z","etag":null,"topics":["continuous","normal-modes","operator","point-symmetry","python","quantum-chemistry","symmetry","wave-function"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abelcarreras.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-25T23:41:27.000Z","updated_at":"2025-03-02T16:47:03.000Z","dependencies_parsed_at":"2023-12-05T14:25:54.552Z","dependency_job_id":"c32d9352-ee2d-4a46-9f57-6dcb8623b53a","html_url":"https://github.com/abelcarreras/posym","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/abelcarreras/posym","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abelcarreras%2Fposym","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abelcarreras%2Fposym/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abelcarreras%2Fposym/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abelcarreras%2Fposym/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abelcarreras","download_url":"https://codeload.github.com/abelcarreras/posym/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abelcarreras%2Fposym/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271409446,"owners_count":24754715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["continuous","normal-modes","operator","point-symmetry","python","quantum-chemistry","symmetry","wave-function"],"created_at":"2024-11-07T12:25:55.358Z","updated_at":"2025-08-21T00:32:02.411Z","avatar_url":"https://github.com/abelcarreras.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/abelcarreras/posym/)\n[![PyPI version](https://badge.fury.io/py/posym.svg)](https://badge.fury.io/py/posym)\n[![Test and Deploy](https://github.com/abelcarreras/posym/actions/workflows/python-publish.yml/badge.svg?branch=master)](https://github.com/abelcarreras/posym/actions/workflows/python-publish.yml)\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7261326.svg)](https://doi.org/10.5281/zenodo.7261326)\n\nPoSym\n=====\n\nA point symmetry analysis tool written in python designed for theoretical chemistry.\nThis tool makes use of continuous symmetry measures (CSM) to provide a robust implementation\nto compute the symmetry of chemistry objects such as normal modes, wave function and electronic density.\n\nFeatures\n--------\n- Use as simple calculator for irreducible representations supporting direct sum and product\n- Continuous symmetry measures (CSM) expressed in the basis or irreducible representation\n- Determine symmetry of: \n  - normal modes \n  - functions defined in gaussian basis (molecular orbitals, electronic densities, operators)\n  - wave functions defined as a slater determinant\n  - wave functions defined as linear combination of slater determinants (Multi-reference/CI)\n- Autogenerated high precision symmetry tables\n- Compatibility with PySCF (https://pyscf.org) and PyQchem (http://www.github.com/abelcarreras/pyqchem)\n- Designed to be easily extendable to other objects by subclassing the `SymmetryObject` main class\n\nRequisites\n----------\n- numpy\n- scipy\n- pandas\n- yaml\n\nUse as a simple symmetry calculation\n------------------------------------\nPosym allows to create basic continuous symmetry python objects that can be operated using \ndirect sum (+) and direct product (*).\n\n```python\nfrom posym import PointGroup, SymmetryObject\n\npg = PointGroup(group='Td')\nprint(pg)\n\na1 = SymmetryObject(group='Td', rep='A1')\na2 = SymmetryObject(group='Td', rep='A2')\ne = SymmetryObject(group='Td', rep='E')\nt1 = SymmetryObject(group='Td', rep='T1')\n\nprint('t1 * t1:', t1 * t1)\nprint('t1 * e:', t1 * e)\nprint('e * (e + a1):', e * (e + a1))\n```\n\nDetermine the symmetry of normal modes\n--------------------------------------\nSymmetry objects can be obtained from normal modes using `SymmetryModes`.\n\n```python\nfrom posym import SymmetryNormalModes\n\ncoordinates = [[0.00000, 0.0000000, -0.0808819],\n               [-1.43262, 0.0000000, -1.2823700],\n               [1.43262, 0.0000000, -1.2823700]]\n\nsymbols = ['O', 'H', 'H']\n\nnormal_modes = [[[0., 0., -0.075],\n                 [-0.381, -0., 0.593],\n                 [0.381, -0., 0.593]],  # mode 1\n\n                [[-0., -0., 0.044],\n                 [-0.613, -0., -0.35],\n                 [0.613, 0., -0.35]],  # mode 2\n\n                [[-0.073, -0., -0.],\n                 [0.583, 0., 0.397],\n                 [0.583, 0., -0.397]]]  # mode 3\n\nfrequencies = [1737.01, 3988.5, 4145.43]\n\nsym_modes_gs = SymmetryNormalModes(group='c2v', coordinates=coordinates, modes=normal_modes, symbols=symbols)\nfor i in range(len(normal_modes)):\n  print('Mode {:2}: {:8.3f} :'.format(i + 1, frequencies[i]), sym_modes_gs.get_state_mode(i))\n\nprint('Total symmetry: ', sym_modes_gs)\n\n```\n\nDetermine the symmetry of a molecular geometry\n----------------------------------------------\nContinuous symmetry measure (CSM) is obtained using `measure` method.\n\n```python\nfrom posym import SymmetryMolecule\n\ncoordinates = [[0.0000000000, 0.0000000000, 0.0000000000],\n               [0.5541000000, 0.7996000000, 0.4965000000],\n               [0.6833000000, -0.8134000000, -0.2536000000],\n               [-0.7782000000, -0.3735000000, 0.6692000000],\n               [-0.4593000000, 0.3874000000, -0.9121000000]]\n\nsymbols = ['C', 'H', 'H', 'H', 'H']\n\nsym_geom = SymmetryMolecule(group='Td', coordinates=coordinates, symbols=symbols)\nprint('Symmetry measure Td : ', sym_geom.measure)\n\nsym_geom = SymmetryMolecule(group='C3v', coordinates=coordinates, symbols=symbols)\nprint('Symmetry measure C3v : ', sym_geom.measure)\n\nsym_geom = SymmetryMolecule(group='C4v', coordinates=coordinates, symbols=symbols)\nprint('Symmetry measure C4v : ', sym_geom.measure)\n```\n\nDefine basis set functions in gaussian basis\n--------------------------------------------\nDefine basis function as linear combination of gaussian that act as normal python functions \n```python\nfrom posym.basis import PrimitiveGaussian, BasisFunction\n\n# Oxigen atom\nsa = PrimitiveGaussian(alpha=130.70932)\nsb = PrimitiveGaussian(alpha=23.808861)\nsc = PrimitiveGaussian(alpha=6.4436083)\ns_O = BasisFunction([sa, sb, sc],\n                    [0.154328969, 0.535328136, 0.444634536],\n                    center=[0.0000000000, 0.000000000, -0.0808819]) # Bohr\n\nsa = PrimitiveGaussian(alpha=5.03315132)\nsb = PrimitiveGaussian(alpha=1.1695961)\nsc = PrimitiveGaussian(alpha=0.3803890)\ns2_O = BasisFunction([sa, sb, sc],\n                     [-0.099967228, 0.399512825, 0.700115461],\n                     center=[0.0000000000, 0.000000000, -0.0808819])\n\npxa = PrimitiveGaussian(alpha=5.0331513, l=[1, 0, 0])\npxb = PrimitiveGaussian(alpha=1.1695961, l=[1, 0, 0])\npxc = PrimitiveGaussian(alpha=0.3803890, l=[1, 0, 0])\n\npya = PrimitiveGaussian(alpha=5.0331513, l=[0, 1, 0])\npyb = PrimitiveGaussian(alpha=1.1695961, l=[0, 1, 0])\npyc = PrimitiveGaussian(alpha=0.3803890, l=[0, 1, 0])\n\npza = PrimitiveGaussian(alpha=5.0331513, l=[0, 0, 1])\npzb = PrimitiveGaussian(alpha=1.1695961, l=[0, 0, 1])\npzc = PrimitiveGaussian(alpha=0.3803890, l=[0, 0, 1])\n\npx_O = BasisFunction([pxa, pxb, pxc],\n                     [0.155916268, 0.6076837186, 0.3919573931],\n                     center=[0.0000000000, 0.000000000, -0.0808819])\npy_O = BasisFunction([pya, pyb, pyc],\n                     [0.155916268, 0.6076837186, 0.3919573931],\n                     center=[0.0000000000, 0.000000000, -0.0808819])\npz_O = BasisFunction([pza, pzb, pzc],\n                     [0.155916268, 0.6076837186, 0.3919573931],\n                     center=[0.0000000000, 0.000000000, -0.0808819])\n\n# Hydrogen atoms\nsa = PrimitiveGaussian(alpha=3.42525091)\nsb = PrimitiveGaussian(alpha=0.62391373)\nsc = PrimitiveGaussian(alpha=0.1688554)\ns_H = BasisFunction([sa, sb, sc],\n                    [0.154328971, 0.535328142, 0.444634542],\n                    center=[-1.43262, 0.000000000, -1.28237])\n\ns2_H = BasisFunction([sa, sb, sc],\n                     [0.154328971, 0.535328142, 0.444634542],\n                     center=[1.43262, 0.000000000, -1.28237])\n\nbasis_set = [s_O, s2_O, px_O, py_O, pz_O, s_H, s2_H]\n\n# Operate with basis functions in analytic form\n\npx_O2 = px_O * px_O\nprint('integral from -inf to inf:', px_O2.integrate)\n\n# plot functions\nfrom matplotlib import pyplot as plt\nimport numpy as np\n\nxrange = np.linspace(-5, 5, 100)\nplt.plot(xrange, [s_O(x, 0, 0) for x in xrange] , label='s_O')\nplt.plot(xrange, [px_O(x, 0, 0) for x in xrange] , label='px_O')\nplt.legend()\n\n```\n\nCreate molecular orbitals from basis set\n----------------------------------------\nDefine molecular orbitals straightforwardly from molecular orbitals coefficients using usual operators\n```python\n\n# Orbital 1\no1 = s_O * 0.994216442 + s2_O * 0.025846814 + px_O * 0.0 + py_O * 0.0 + pz_O * -0.004164076 + s_H * -0.005583712 + s2_H * -0.005583712\n\n# Orbital 2\no2 = s_O * 0.23376666 + s2_O * -0.844456594 + px_O * 0.0 + py_O * 0.0 + pz_O * 0.122829781 + s_H * -0.155593214 + s2_H * -0.155593214\n\n# Orbital 3\no3 = s_O * 0.0 + s2_O * 0.0 + px_O * 0.612692349 + py_O * 0.0 + pz_O * 0.0 + s_H * -0.44922168 + s2_H * 0.449221684\n\n# Orbital 4\no4 = s_O * -0.104033343 + s2_O * 0.538153649 + px_O * 0.0 + py_O * 0.0 + pz_O * 0.755880259 + s_H * -0.295107107 + s2_H * -0.2951071074\n\n# Orbital 5\no5 = s_O * 0.0 + s2_O * 0.0 + px_O * 0.0 + py_O * -1.0 + pz_O * 0.0 + s_H * 0.0 + s2_H * 0.0\n\n# Orbital 6\no6 = s_O * -0.125818566 + s2_O * 0.820120983 + px_O * 0.0 + py_O * 0.0 + pz_O * -0.763538862 + s_H * -0.769155124 + s2_H * -0.769155124\n\n\n# Check orthogonality\nprint('\u003co1|o1\u003e: ', (o1*o1).integrate)\nprint('\u003co2|o2\u003e: ', (o2*o2).integrate)\nprint('\u003co1|o2\u003e: ', (o1*o2).integrate)\n```\n\nAnalyze symmetry of molecular orbitals\n--------------------------------------\nGet symmetry of molecular orbitals defined as `BasisFunction` type objects\n\n```python\nfrom posym import SymmetryGaussianLinear\n\nsym_o1 = SymmetryGaussianLinear('c2v', o1)\nsym_o2 = SymmetryGaussianLinear('c2v', o2)\nsym_o3 = SymmetryGaussianLinear('c2v', o3)\nsym_o4 = SymmetryGaussianLinear('c2v', o4)\nsym_o5 = SymmetryGaussianLinear('c2v', o5)\nsym_o6 = SymmetryGaussianLinear('c2v', o6)\n\nprint('Symmetry O1: ', sym_o1)\nprint('Symmetry O2: ', sym_o2)\nprint('Symmetry O3: ', sym_o3)\nprint('Symmetry O4: ', sym_o4)\nprint('Symmetry O5: ', sym_o5)\nprint('Symmetry O6: ', sym_o6)\n\n# Operate molecular orbitals symmetries to get the symmetry of non-degenerate wave functions\n\n# restricted close shell\nsym_wf_gs = sym_o1 * sym_o1 * sym_o2 * sym_o2 * sym_o3 * sym_o3 * sym_o4 * sym_o4 * sym_o5 * sym_o5\nprint('Symmetry WF (ground state): ', sym_wf_gs)\n\n# restricted open shell\nsym_wf_excited_1 = sym_o1 * sym_o1 * sym_o2 * sym_o2 * sym_o3 * sym_o3 * sym_o4 * sym_o4 * sym_o5 * sym_o6\nprint('Symmetry WF (excited state 1): ', sym_wf_excited_1)\n\n# restricted close shell\nsym_wf_excited_2 = sym_o1 * sym_o1 * sym_o2 * sym_o2 * sym_o3 * sym_o3 * sym_o4 * sym_o4 * sym_o6 * sym_o6\nprint('Symmetry WF (excited state 2): ', sym_wf_excited_2)\n\n```\n\nCompute the symmetry of wave functions defined as a Slater determinant\n----------------------------------------------------------------------\nUse `SymmetryWaveFunction` class to determine the symmetry of a wave function\nfrom a set of occupied molecular orbitals defined as `BasisFunction` objects\n\n```python\nfrom posym import SymmetrySingleDeterminant\nfrom posym.tools import build_orbital\n\n# get orbitals from basis set and MO coefficients\norbital1 = build_orbital(basis_set, coefficients['alpha'][0])  # A1\norbital2 = build_orbital(basis_set, coefficients['alpha'][1])  # A1\norbital3 = build_orbital(basis_set, coefficients['alpha'][2])  # T1\norbital4 = build_orbital(basis_set, coefficients['alpha'][3])  # T1\norbital5 = build_orbital(basis_set, coefficients['alpha'][4])  # T1\n\nwf_sym = SymmetrySingleDeterminant('Td',\n                                   alpha_orbitals=[orbital1, orbital2, orbital5],\n                                   beta_orbitals=[orbital1, orbital2, orbital4],\n                                   center=[0, 0, 0])\n\nprint('Configuration 1: ', wf_sym)  # T1 + T2\n\nwf_sym = SymmetrySingleDeterminant('Td',\n                                   alpha_orbitals=[orbital1, orbital2, orbital3],\n                                   beta_orbitals=[orbital1, orbital2, orbital3],\n                                   center=[0, 0, 0])\n\nprint('Configuration 2: ', wf_sym)  # A1 + E\n\n```\n\nCompute the symmetry of multi-reference wave functions\n------------------------------------------------------\nUse `SymmetryWaveFunctionCI` class to determine the symmetry of multi-reference wave function\n(defined as a liner combination of Slater determinants) from a set of \noccupied molecular orbitals defined as `BasisFunction` objects and a *configurations* dictionary.\n\n```python\nfrom posym import SymmetryMultiDeterminant\n\nconfigurations = [{'amplitude': -0.03216, 'occupations': {'alpha': [1, 1, 0, 0, 1], 'beta': [1, 1, 1, 0, 0]}},\n                  {'amplitude': 0.70637, 'occupations': {'alpha': [1, 1, 0, 1, 0], 'beta': [1, 1, 1, 0, 0]}},\n                  {'amplitude': 0.03216, 'occupations': {'alpha': [1, 1, 1, 0, 0], 'beta': [1, 1, 0, 0, 1]}},\n                  {'amplitude': -0.70637, 'occupations': {'alpha': [1, 1, 1, 0, 0], 'beta': [1, 1, 0, 1, 0]}}]\n\nwf_sym = SymmetryMultiDeterminant('Td',\n                                  orbitals=[orbital1, orbital2, orbital3, orbital4, orbital5],\n                                  configurations=configurations,\n                                  center=[0, 0, 0])\n\nprint('State 1: ', wf_sym)  # T1\n\n\n```\n\nCompatible with pySCF\n---------------------\nUsage of helper functions to interface with pySCF\n\n```python\nfrom posym import SymmetryGaussianLinear\nfrom posym.tools import get_basis_set_pyscf, build_orbital\nfrom pyscf import gto, scf\nimport numpy as np\n\n\nr = 1  # O-H distance\nalpha = np.deg2rad(104.5)  # H-O-H angle\n\nmol_pyscf = gto.M(atom=[['O', [0, 0, 0]],\n                        ['H', [-r, 0, 0]],\n                        ['H', [r*np.cos(np.pi - alpha), r*np.sin(np.pi - alpha), 0]]],\n                  basis='3-21g',\n                  charge=0,\n                  spin=0)\n\n# run pySCF calculation\npyscf_scf = scf.RHF(mol_pyscf)\npyscf_scf = pyscf_scf.run()\n\n# get electronic structure data\nmo_coefficients = pyscf_scf.mo_coeff.T\noverlap_matrix = pyscf_scf.get_ovlp(mol_pyscf)\nbasis_set = get_basis_set_pyscf(mol_pyscf)\n\n# compute symmetry of Molecular orbitals\nprint('\\nMO symmetry')\nfor i, orbital_vect in enumerate(mo_coefficients):\n    orb = build_orbital(basis_set, orbital_vect)\n    sym_orb = SymmetryGaussianLinear('c2v', orb)\n    print('orbital {}: {}'.format(i, sym_orb))\n\n```\n\nCombine with PyQchem to create useful automations\n-------------------------------------------------\nPyQchem (https://github.com/abelcarreras/PyQchem) is a Python interface \nfor Q-Chem (https://www.q-chem.com). PyQchem can be used to obtain \nwave functions and normal modes as Python objects that can be directly used in Posym.\n\n```python\nfrom pyqchem import get_output_from_qchem, QchemInput, Structure\nfrom pyqchem.parsers.basic import basic_parser_qchem\nfrom posym import SymmetryGaussianLinear\n# convenient functions to connect pyqchem - posym\nfrom posym.tools import get_basis_set, build_orbital\n\n# define molecules\nbutadiene = Structure(coordinates=[[-1.07076839, -2.13175980, 0.03234382],\n                                   [-0.53741536, -3.05918866, 0.04995793],\n                                   [-2.14073783, -2.12969357, 0.04016267],\n                                   [-0.39112115, -0.95974916, 0.00012984],\n                                   [0.67884827, -0.96181542, -0.00769025],\n                                   [-1.15875076, 0.37505495, -0.02522296],\n                                   [-0.62213437, 1.30041753, -0.05065831],\n                                   [-2.51391203, 0.37767199, -0.01531698],\n                                   [-3.04726506, 1.30510083, -0.03293196],\n                                   [-3.05052841, -0.54769055, 0.01011971]],\n                      symbols=['C', 'H', 'H', 'C', 'H', 'C', 'H', 'C', 'H', 'H'])\n\n# create qchem input\nqc_input = QchemInput(butadiene,\n                      jobtype='sp',\n                      exchange='hf',\n                      basis='sto-3g',\n                      )\n\n# calculate and parse qchem output\ndata, ee = get_output_from_qchem(qc_input,\n                                 read_fchk=True,\n                                 processors=4,\n                                 parser=basic_parser_qchem)\n\n# extract required information from Q-Chem calculation\ncoordinates = ee['structure'].get_coordinates()\nmo_coefficients = ee['coefficients']['alpha']\nbasis = ee['basis']\n\n# print results\nprint('Molecular orbitals (alpha) symmetry')\nbasis_set = get_basis_set(coordinates, basis)\nfor i, orbital_coeff in enumerate(mo_coefficients):\n  orbital = build_orbital(basis_set, orbital_coeff)\n  sym_orbital = SymmetryGaussianLinear('c2v', orbital)\n  print('Symmetry O{}: '.format(i + 1), sym_orbital)\n\n\n```\n\nTry an [interactive example](https://colab.research.google.com/github/abelcarreras/posym) in Google Colab\n\nBibliography\n------------\nThis software is based on the theory described in the following works:\n\nPinsky M, Dryzun C, Casanova D, Alemany P, Avnir D, J Comput Chem. 29:2712-21 (2008) [[link]](https://doi.org/10.1002/jcc.20990)  \nPinsky M, Casanova D, Alemany P, Alvarez S, Avnir D, Dryzun C, Kizner Z, Sterkin A. J Comput Chem. 29:190-7 (2008) [[link]](https:///doi/10.1002/jcc.20772)  \nCasanova D, Alemany P. Phys Chem Chem Phys. 12(47):15523–9 (2010) [[link]](https://doi.org/10.1039/C0CP01326A)  \nCasanova D, Alemany P, Falceto A, Carreras A, Alvarez S. J Comput Chem 34(15):1321–31 (2013) [[link]](https://doi.org/10.1002/jcc.23257)  \nA. Carreras, E. Bernuz, X. Marugan, M. Llunell, P. Alemany, Chem. Eur. J. 25, 673 – 691 (2019) [[link]](https://doi.org/10.1002/chem.201801682)\n\nContact info\n------------\nAbel Carreras  \nabelcarreras83@gmail.com\n\nMultiverse Computing SL  \nDonostia-San Sebastian (Spain)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabelcarreras%2Fposym","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabelcarreras%2Fposym","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabelcarreras%2Fposym/lists"}