Skip to main content

STRUcture DEtermination Libary

STRUDEL is a python library for determining the structure of molecules from their rotational constants of moments of inertia. The main improvement over other codes is that the moments of inertia/rotational constants can be weighted according to their uncertainties.

The structure is defined via internal coordinates in the Z-matrix formalism.

Examples for different molecules are provided in the examples folder.

Example Usage

An examplary workflow is explained for propargyl chloride (C3H3Cl). First, the libraray is imported and the masses for the different isotopes are defined for easier handling

import mol_strudel as strudel
import numpy as np


m_H = 1.0078250321
m_D = 2.01410175
m_C12 = 12.0000000000
m_C13 = 13.0033548378
m_Cl35 = 34.96885268
m_Cl37 = 36.96590259

Then, the function creating the internal coordinates matrix is defined

def fzmat(params):
    r_CH_A, r_CC_T, r_CC_S, r_CCl, r_CH_2, a_HCC, a_CCC, a_CCCl, a_ClCH, d_CCClH = params
    zmat = np.array([
        [0, 0, 0, 0, 0, 0],
        [1, 0, 0, r_CH_A, 0, 0],
        [2, 1, 0, 1, 90, 0],
        [2, 3, 1, r_CC_T, a_HCC, 180],
        [4, 2, 3, 1, 90, 0],
        [4, 5, 2, r_CC_S, a_CCC, 180],
        [6, 4, 5, r_CCl, a_CCCl, 180],
        [6, 7, 4, r_CH_2, a_ClCH, d_CCClH],
        [6, 7, 4, r_CH_2, a_ClCH, -d_CCClH],
    ])
    return zmat

The function fzmat creates the z-matrix. Each row describes the position of one atom relative to other atoms.

The first three numbers in each row are the indices of the reference atoms $a$, $b$, and $c$. The last three values are the radius $R$, angle $\Theta$, and dihedral angle $\Phi$.

The position of the new atom $d$ is defined via

  • its bond length to the atom $a$
  • its bond angle with atom $b$
  • its dihedral angle atom to $c$

This means that the atom in the first row is just in the origin. Please note, that indexing starts at 1 and hence the reference atoms for the first atom are all zero. The second atom is defined relative to the first atom and has a distance of r_CH_A. The third atom is then at a distance of 1 Angstrom from the second atom and at an angle of 90 Degree relative to the first atom.

Also note, taht the third and fifth atom are dummy atoms which are just used to define the structure but are not actually real atoms.

Afterwards, the masses of the isotopologues are defined

masses = np.array([
    [m_H, m_C12, 0, m_C12, 0, m_C12, m_Cl35, m_H, m_H],
    [m_D, m_C12, 0, m_C12, 0, m_C12, m_Cl35, m_H, m_H],
    [m_H, m_C12, 0, m_C12, 0, m_C12, m_Cl37, m_H, m_H],
    [m_D, m_C12, 0, m_C12, 0, m_C12, m_Cl37, m_H, m_H],
    [m_H, m_C12, 0, m_C12, 0, m_C13, m_Cl35, m_H, m_H],
    [m_H, m_C12, 0, m_C12, 0, m_C13, m_Cl37, m_H, m_H],
    [m_H, m_C12, 0, m_C13, 0, m_C12, m_Cl35, m_H, m_H],
    [m_H, m_C12, 0, m_C13, 0, m_C12, m_Cl37, m_H, m_H],
    [m_H, m_C13, 0, m_C12, 0, m_C12, m_Cl35, m_H, m_H],
    [m_H, m_C13, 0, m_C12, 0, m_C12, m_Cl37, m_H, m_H],
])

Each row is an isotopologue and the order of atoms is according to their definition in the z-matrix. The dummy atoms have a mass of zero.

Next, the rotational constants of the isotopologues are defined in the same order

# Rotational Parameters
B_0_exp = np.array(
    [
        [24299.739404, 3079.762495, 2777.65244],
        [23397.636723, 2890.312631, 2611.556823],
        [24147.307989, 3013.784157, 2721.929399],
        [23238.887481, 2828.830778, 2559.327354],
        [23465.113821, 3080.022163, 2766.525818],
        [23310.529001, 3013.966014, 2711.016153],
        [24272.241064, 3048.650844, 2751.964431],
        [24119.956454, 2982.295123, 2695.875144],
        [24101.738526, 2979.670648, 2693.485206],
        [23947.670529, 2915.162456, 2638.790717],
    ]
)

# Be - B0 values
alpha_QCC = np.array(
    [
        [114.9820879, 7.4759909, 10.7019012],
        [95.7796453, 6.4698322, 9.3984037],
        [113.5229352, 7.3526254, 10.4489849],
        [94.3300681, 6.3749714, 9.1839139],
        [107.9798532, 7.195414, 10.4935982],
        [106.532603, 7.0785797, 10.2445339],
        [114.4201338, 7.4643048, 10.615563],
        [112.9717285, 7.3380333, 10.3608491],
        [114.0019731, 7.202077, 10.2734707],
        [112.5372614, 7.0818831, 10.0283921],
    ]
)

# Uncertainties of B_0_exp
sigmas = np.array(
    [
        [0.000230, 0.000033, 0.000032],
        [0.054316, 0.004242, 0.004011],
        [0.000380, 0.000036, 0.000036],
        [0.203992, 0.013291, 0.012110],
        [0.014902, 0.002095, 0.001858],
        [0.016068, 0.003551, 0.004317],
        [0.014402, 0.001453, 0.001835],
        [0.021238, 0.002602, 0.002907],
        [0.007242, 0.001064, 0.001030],
        [0.009461, 0.001602, 0.001610],
    ]
)

B_e_SE = B_0_exp + alpha_QCC

Here, we have defined both the $B_0$ values and the $B_e - B_0$ values (from quantum chemical calculations) as we want to determine a semi-experimental equilibrium structure $r_e^\text{SE}$. In addition, the uncertainties of the rotational constants are defined as sigmas.

The last piece of data we need are the initial parameters

p0 = [1.06, 1.20, 1.45, 1.79, 1.09, 90, 89, 112, 107, 122]

With all the data prepared, the structure can be fitted by running

popt, pcov, perr = strudel.fit_rotational_constants(fzmat, masses, B_e_SE, p0=p0, sigmas=None)

Afterwards, the results can be displayed by running

output = strudel.summarize_results(fzmat, masses, popt, perr, B_e_SE, sigmas=sigmas)
print(output['report_params'])
print()
print(output['report_stats'])
print()
print(output['report_residuals'])
print()
print(output['report_coords'])

The complete code is found in the examples folder.

Metadata

Release files for mol-strudel 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mol-strudel 1.0.2
File Size Uploaded
mol_strudel-1.0.2.tar.gz 10.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mol-strudel 1.0.2
File Interpreter ABI Platform
mol_strudel-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 17.4 kB

Release files / mol_strudel-1.0.2.tar.gz

Download URL mol_strudel-1.0.2.tar.gz
Size 10.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ecda66a922ac4667c7cdbfce21d7831202b53962b2be4b3d771da899763235af
BLAKE2b-256 checksum
How to use checksums
8cfcbae117eb82075d1b29e06317fbe64c2abe3ee2d6df4e04aee55daea2a9aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.13.0

Release files / mol_strudel-1.0.2-py3-none-any.whl

Download URL mol_strudel-1.0.2-py3-none-any.whl
Size 7.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a10c4079ef07764f321c4feff1306eeff711313854454e30b4d4ef924456a2eb
BLAKE2b-256 checksum
How to use checksums
b3d9472b3f442ea0f2c672c82cb9a09b1ef8363b992ec2fde73ae8b72c6193d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.13.0

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page