def two_doublets(v1, v2, J, w=0.5, points=10000): """Return a plot for a first-order AX system. Parameters ---------- v1, v2 : float The chemical shifts in Hz for the two signals J : float The coupling constant in Hz w: float, optional (default = 0.5) The peak width at half-height (in Hz) points : int, optional (default = 10000) The number of data points in the lineshape Returns ------- hv.Curve() object """ peak1 = (v1, 1) couplings = [(J, 1)] peak2 = (v2, 1) peaklist = multiplet(peak1, couplings) + multiplet(peak2, couplings) x, y = lineshape_from_peaklist(peaklist, w=w, points=points) return hv.Curve(zip(x, y)).options(axiswise=True, invert_xaxis=True, xlabel='𝜈', ylabel='intensity')
def test_first_order_spin_system(): v, J = rioux() spectrum = first_order_spin_system(v, J) m1 = multiplet((430, 1), [(7, 1), (15, 1)]) m2 = multiplet((265, 1), [(7, 1), (1.5, 1)]) m3 = multiplet((300, 1), [(15, 1), (1.5, 1)]) m = reduce_peaks(sorted(m1 + m2 + m3)) # x = np.array([i[0] for i in spectrum]) # y = np.array([i[1] for i in spectrum]) # mplplot_stick(spectrum) assert np.allclose(spectrum, m)
def test_multiplet(): refspec = [(293.0, 0.75), (300.0, 1.5), (307.0, 0.75), (432.5, 0.0625), (439.5, 0.3125), (446.5, 0.625), (453.5, 0.625), (460.5, 0.3125), (467.5, 0.0625), (1193.0, 0.5), (1200.0, 1.0), (1207.0, 0.5)] v1 = (1200, 2) v2 = (450, 2) v3 = (300, 3) J12 = 7 J23 = 7 m1 = multiplet(v1, [(J12, 2)]) m2 = multiplet(v2, [(J12, 2), (J23, 3)]) m3 = multiplet(v3, [(J23, 2)]) testspec = reduce_peaks(sorted(m1 + m2 + m3)) np.testing.assert_array_almost_equal(testspec, refspec, decimal=2)
def test_multiplet_allows_singlet(): refspec = [(1200.0, 2.0)] # GIVEN a signal # WHEN multiplet is called with an empty J list testspec = multiplet((1200.0, 2.0), []) # THEN the returned peaklist only contains the original signal assert np.allclose(refspec, testspec)
def n_plus_one(J, n, v=100, i=1.0, w=0.5): """Given n and coupling constant J, return the lineshape for the corresponding n + 1 multiplet. Parameters ---------- J: float the coupling constant in Hz n: int the number of neighboring nuclei (the 'n' in the 'n + 1' rule) v: float, optional (default = 100) the center of the multiplet (in Hz) i: float, optional (default = 1.0) The total of the individual peak's max intensities. Analogous to the integration of the signal when w = 0.5. w: float, optional (default = 0.5) The peak width at half-height (in Hz) Returns ------- hv.Curve() object Formatted 'NMR-style' with labeled axes and the x-axis reversed """ singlet = (v, i) # center at 100 Hz; intensity 1 couplings = [(J, n)] peaklist = multiplet(singlet, couplings) x, y = lineshape_from_peaklist(peaklist, w=w) return hv.Curve(zip(x, y)) \ .options(axiswise=True, invert_xaxis=True) \ .redim(y=hv.Dimension('intensity'), x=hv.Dimension('𝜈 (Hz)'))
def ABX3(Jab, Jax, Jbx, Vab, Vcentr): """ Simulation of the AB part of an ABX3 spin system. Parameters --------- Jab : float the Ha-Hb coupling constant (Hz). Jax : float the Ha-Hb coupling constant (Hz). Jbx : float the Ha-Hb coupling constant (Hz). Vab : float the difference in the frequencies (Hz) of Ha and Hb in the absence of coupling. Positive when vb > va. Vcentr : float the frequency (Hz) for the center of the AB signal. Returns ------- [(float, float)...] a list of (frequency, intensity) tuples. """ # First: simulate two quartets for va and vb ("Jab turned off") va = Vcentr - Vab / 2 vb = Vcentr + Vab / 2 a_quartet = multiplet((va, 1), [(Jax, 3)]) b_quartet = multiplet((vb, 1), [(Jbx, 3)]) res = [] # Then: for each pair of a and b singlets in the quartets, calculate an # AB quartet ("Turn Jab on"). for i in range(4): dv = b_quartet[i][0] - a_quartet[i][0] abcenter = (b_quartet[i][0] + a_quartet[i][0]) / 2 sub_abq = AB(Jab, dv, abcenter, normalize=True) scale_factor = a_quartet[i][1] scaled_sub_abq = [(v, i * scale_factor) for v, i in sub_abq] res.extend(scaled_sub_abq) return res
def n_coupling(*j_args, v=100.0, i=1.0, w=0.5, points=4000, limits=None): """Given parameters for a first-order multiplet, return a holoviews plot for it. Parameters ---------- j_args: float One or more coupling constants, in Hz v: float, optional (default = 100.0 Hz) The frequency of the center of the multiplet, in Hz i: float, optional (default = 1.0) The intensity of the signal. When w = 0.5 Hz, i = the total of the peak heights, e.g. a doublet would default to two peaks with height 0.5. w: float, optional (default = 0.5 Hz) points: int, optional (default = 4000 datapoints) limits: (int or float, int or float), optional A tuple of minimum and maximum frequencies (Hz) for the plot. Returns ------- hv.Curve() object Formatted 'NMR-style' with labeled axes and the x-axis reversed """ couplings = [(j, 1) for j in j_args] peaklist = multiplet((v, i), couplings) # TODO: will n_coupling merit its own limit/points defaults, or just use lineshape_from_peaklist's? if not limits: limits = (v - 20, v + 20) x, y = lineshape_from_peaklist(peaklist, w=w, points=points, limits=limits) return hv.Curve(zip(x, y)) \ .options(axiswise=True, invert_xaxis=True, height=300, responsive=True ) \ .redim(y=hv.Dimension('intensity'), x=hv.Dimension('𝜈 (Hz)'))
def __init__(self, v, I, J, w=0.5): self.v = v self.I = I self.J = J self.w = w self._peaklist = multiplet((v, I), J)
def _refresh(self): self._peaklist = multiplet((self.v, self.I), self.J)