class FourierFilter: """The FourierFilter class is used to exlude a given range in the current function by a back Fourier Transform of that section, followed by a difference from the non-excluded function, and then a forward transform of the difference function Can currently do: a real space function -> reciprocal space function -> real space function :examples: >>> import numpy >>> from pystog import FourierFilter >>> ff = FourierFilter() >>> r, gr = numpy.loadtxt("my_gofr_file.txt",unpack=True) >>> q = numpy.linspace(0., 25., 2500) >>> q, sq = transformer.G_to_S(r, gr, q) >>> q_ft, sq_ft, q, sq, r, gr = ff.G_using_F(r, gr, q, sq, 1.5) """ def __init__(self): self.converter = Converter() self.transformer = Transformer() # g(r) def g_using_F(self, r, gr, q, fq, cutoff, dgr=None, dfq=None, **kwargs): """Fourier filters real space :math:`g(r)` using the reciprocal space :math:`Q[S(Q)-1]` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`Q[S(Q)-1]` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`Q[S(Q)-1]` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`Q[S(Q)-1]`, and the filtered :math:`r` and :math:`g(r)`. Thus, [:math:`Q_{FF}`, :math:`Q[S(Q)-1]_{FF}`, :math:`Q`, :math:`Q[S(Q)-1]`, :math:`r_{FF}`, :math:`g(r)_{FF}]` :rtype: tuple of numpy.array """ # setup qmin, qmax, and get low-r region to back transform qmin = min(q) qmax = max(q) r_tmp, gr_tmp_initial, dgr_tmp_initial = self.transformer.apply_cropping( r, gr, 0.0, cutoff, dy=dgr) # Shift low-r so it goes to 1 at "high-r" for this section. Reduces the # sinc function issue. gr_tmp = gr_tmp_initial + 1 # Transform the shifted low-r region to F(Q) to get F(Q)_ft q_ft, fq_ft, dfq_ft = self.transformer.g_to_F(r_tmp, gr_tmp, q, dgr=dgr_tmp_initial, **kwargs) q_ft, fq_ft, dfq_ft = self.transformer.apply_cropping(q_ft, fq_ft, qmin, qmax, dy=dfq_ft) # Subtract F(Q)_ft from original F(Q) = delta_F(Q) q, fq, dfq = self.transformer.apply_cropping(q, fq, qmin, qmax, dy=dfq) fq = (fq - fq_ft) dfq = np.sqrt(dfq**2 + dfq_ft**2) # Transform delta_F(Q) for g(r) with low-r removed r, gr, dgr = self.transformer.F_to_g(q, fq, r, dfq=dfq, **kwargs) return q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr def g_using_S(self, r, gr, q, sq, cutoff, dgr=None, dsq=None, **kwargs): """Fourier filters real space :math:`g(r)` using the reciprocal space :math:`S(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param sq: :math:`S(Q)` vector :type sq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`S(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`S(Q)`, and the filtered :math:`r` and :math:`g(r)`. Thus, [:math:`Q_{FF}`, :math:`S(Q)_{FF}`, :math:`Q`, :math:`S(Q)`, :math:`r_{FF}`, :math:`g(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.S_to_F(q, sq, dsq=dsq) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.g_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) sq_ft, dsq_ft = self.converter.F_to_S(q_ft, fq_ft, dfq=dfq_ft) sq, dsq = self.converter.F_to_S(q, fq, dfq=dfq) return q_ft, sq_ft, q, sq, r, gr, dsq_ft, dsq, dgr def g_using_FK(self, r, gr, q, fq, cutoff, dgr=None, dfq=None, **kwargs): """Fourier filters real space :math:`g(r)` using the reciprocal space :math:`F(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`F(Q)` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`F(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`F(Q)`, and the filtered :math:`r` and :math:`g(r)`. Thus, [:math:`Q_{FF}`, :math:`F(Q)_{FF}`, :math:`Q`, :math:`F(Q)`, :math:`r_{FF}`, :math:`g(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.FK_to_F(q, fq, dfq=dfq, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.g_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) fq_ft, dfq_ft = self.converter.F_to_FK(q_ft, fq_ft, dfq=dfq_ft, **kwargs) fq, dfq = self.converter.F_to_FK(q, fq, dfq=dfq, **kwargs) return q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr def g_using_DCS(self, r, gr, q, dcs, cutoff, dgr=None, ddcs=None, **kwargs): """Fourier filters real space :math:`g(r)` using the reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` vector :type dcs: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`\\frac{d \\sigma}{d \\Omega}(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, and the filtered :math:`r` and :math:`g(r)`. Thus, [:math:`Q_{FF}`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)_{FF}`, :math:`Q`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, :math:`r_{FF}`, :math:`g(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.DCS_to_F(q, dcs, ddcs=ddcs, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.g_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) dcs_ft, ddcs_ft = self.converter.F_to_DCS(q_ft, fq_ft, dfq=dfq_ft, **kwargs) dcs, ddcs = self.converter.F_to_DCS(q_ft, fq, dfq=dfq, **kwargs) return q_ft, dcs_ft, q, dcs, r, gr, ddcs_ft, ddcs, dgr # G(R) = PDF def G_using_F(self, r, gr, q, fq, cutoff, dgr=None, dfq=None, **kwargs): """Fourier filters real space :math:`G_{PDFFIT}(r)` using the reciprocal space :math:`Q[S(Q)-1]` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`Q[S(Q)-1]` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`Q[S(Q)-1]` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`Q[S(Q)-1]`, and the filtered :math:`r` and :math:`G_{PDFFIT}(r)`. Thus, [:math:`Q_{FF}`, :math:`Q[S(Q)-1]_{FF}`, :math:`Q`, :math:`Q[S(Q)-1]`, :math:`r_{FF}`, :math:`G_{PDFFIT}(r)_{FF}]` :rtype: tuple of numpy.array """ gr, dgr = self.converter.G_to_g(r, gr, dgr=dgr, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.g_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) gr, dgr = self.converter.g_to_G(r, gr, dgr=dgr, **kwargs) return q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr def G_using_S(self, r, gr, q, sq, cutoff, dgr=None, dsq=None, **kwargs): """Fourier filters real space :math:`G_{PDFFIT}(r)` using the reciprocal space :math:`S(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`S(Q)` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`S(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`S(Q)`, and the filtered :math:`r` and :math:`G_{PDFFIT}(r)`. Thus, [:math:`Q_{FF}`, :math:`S(Q)_{FF}`, :math:`Q`, :math:`S(Q)`, :math:`r_{FF}`, :math:`G_{PDFFIT}(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.S_to_F(q, sq, dsq=dsq) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.G_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) sq_ft, dsq_ft = self.converter.F_to_S(q_ft, fq_ft, dfq_ft) sq, dsq = self.converter.F_to_S(q, fq, dfq) return q_ft, sq_ft, q, sq, r, gr, dsq_ft, dsq, dgr def G_using_FK(self, r, gr, q, fq, cutoff, dgr=None, dfq=None, **kwargs): """Fourier filters real space :math:`G_{PDFFIT}(r)` using the reciprocal space :math:`F(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`F(Q)` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`F(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`F(Q)`, and the filtered :math:`r` and :math:`G_{PDFFIT}(r)`. Thus, [:math:`Q_{FF}`, :math:`F(Q)_{FF}`, :math:`Q`, :math:`F(Q)`, :math:`r_{FF}`, :math:`G_{PDFFIT}(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.FK_to_F(q, fq, dfq=dfq, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.G_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) fq_ft, dfq_ft = self.converter.F_to_FK(q_ft, fq_ft, dfq=dfq_ft, **kwargs) fq, dfq = self.converter.F_to_FK(q, fq, dfq=dfq, **kwargs) return q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr def G_using_DCS(self, r, gr, q, dcs, cutoff, dgr=None, ddcs=None, **kwargs): """Fourier filters real space :math:`G_{PDFFIT}(r)` using the reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` vector :type dcs: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`\\frac{d \\sigma}{d \\Omega}(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, and the filtered :math:`r` and :math:`G_{PDFFIT}(r)`. Thus, [:math:`Q_{FF}`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)_{FF}`, :math:`Q`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, :math:`r_{FF}`, :math:`G_{PDFFIT}(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.DCS_to_F(q, dcs, ddcs=ddcs, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.G_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) dcs_ft, ddcs_ft = self.converter.F_to_DCS(q_ft, fq_ft, dfq=dfq_ft, **kwargs) dcs, ddcs = self.converter.F_to_DCS(q, fq, dfq=dfq, **kwargs) return q_ft, dcs_ft, q, dcs, r, gr, ddcs_ft, ddcs, dgr # Keen's G(r) def GK_using_F(self, r, gr, q, fq, cutoff, dgr=None, dfq=None, **kwargs): """Fourier filters real space :math:`G_{Keen Version}(r)` using the reciprocal space :math:`Q[S(Q)-1]` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`Q[S(Q)-1]` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`Q[S(Q)-1]` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`Q[S(Q)-1]`, and the filtered :math:`r` and :math:`G_{Keen Version}(r)`. Thus, [:math:`Q_{FF}`, :math:`Q[S(Q)-1]_{FF}`, :math:`Q`, :math:`Q[S(Q)-1]`, :math:`r_{FF}`, :math:`G_{Keen Version}(r)_{FF}]` :rtype: tuple of numpy.array """ gr, dgr = self.converter.GK_to_g(r, gr, dgr=dgr, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.g_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) gr, dgr = self.converter.g_to_GK(r, gr, dgr=dgr, **kwargs) return q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr def GK_using_S(self, r, gr, q, sq, cutoff, dgr=None, dsq=None, **kwargs): """Fourier filters real space :math:`G_{Keen Version}(r)` using the reciprocal space :math:`S(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`S(Q)` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`S(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`S(Q)`, and the filtered :math:`r` and :math:`G_{Keen Version}(r)`. Thus, [:math:`Q_{FF}`, :math:`S(Q)_{FF}`, :math:`Q`, :math:`S(Q)`, :math:`r_{FF}`, :math:`G_{Keen Version}(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.S_to_F(q, sq, dsq=dsq) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.GK_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) sq_ft, dsq_ft = self.converter.F_to_S(q_ft, fq_ft, dfq=dfq_ft) sq, dsq = self.converter.F_to_S(q, fq, dfq=dfq) return q_ft, sq_ft, q, sq, r, gr, dsq_ft, dsq, dgr def GK_using_FK(self, r, gr, q, fq, cutoff, dgr=None, dfq=None, **kwargs): """Fourier filters real space :math:`G_{Keen Version}(r)` using the reciprocal space :math:`F(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`F(Q)` vector :type fq: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`F(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`F(Q)`, and the filtered :math:`r` and :math:`G_{Keen Version}(r)`. Thus, [:math:`Q_{FF}`, :math:`F(Q)_{FF}`, :math:`Q`, :math:`F(Q)`, :math:`r_{FF}`, :math:`G_{Keen Version}(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.FK_to_F(q, fq, dfq=dfq, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.GK_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) fq_ft, dfq_ft = self.converter.F_to_FK(q_ft, fq_ft, dfq=dfq_ft, **kwargs) fq, dfq = self.converter.F_to_FK(q, fq, dfq=dfq, **kwargs) return q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr def GK_using_DCS(self, r, gr, q, dcs, cutoff, dgr=None, ddcs=None, **kwargs): """Fourier filters real space :math:`G_{Keen Version}(r)` using the reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` vector :type dcs: numpy.array or list :param cutoff: The :math:`r_{max}` value to filter from 0. to this cutoff :type cutoff: float :return: A tuple of the :math:`Q` and :math:`\\frac{d \\sigma}{d \\Omega}(Q)` for the 0. to cutoff transform, the corrected :math:`Q` and :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, and the filtered :math:`r` and :math:`G_{Keen Version}(r)`. Thus, [:math:`Q_{FF}`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)_{FF}`, :math:`Q`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, :math:`r_{FF}`, :math:`G_{Keen Version}(r)_{FF}]` :rtype: tuple of numpy.array """ fq, dfq = self.converter.DCS_to_F(q, dcs, ddcs=ddcs, **kwargs) q_ft, fq_ft, q, fq, r, gr, dfq_ft, dfq, dgr = self.GK_using_F(r, gr, q, fq, cutoff, dgr=dgr, dfq=dfq, **kwargs) dcs_ft, ddcs_ft = self.converter.F_to_DCS(q_ft, fq_ft, dfq=dfq_ft, **kwargs) dcs, ddcs = self.converter.F_to_DCS(q, fq, dfq=dfq, **kwargs) return q_ft, dcs_ft, q, dcs, r, gr, ddcs_ft, ddcs, dgr
class Transformer: """ The Transformer class is used to Fourier transform between the difference spaces. Either: a reciprocal space function -> real space function or a real space function -> reciprocal space function :examples: >>> import numpy >>> from pystog import Transformer >>> transformer = Transformer() >>> q, sq = numpy.loadtxt("my_sofq_file.txt",unpack=True) >>> r = numpy.linspace(0., 25., 2500) >>> r, gr, dgr = transformer.S_to_G(q, sq, r) >>> q = numpy.linspace(0., 25., 2500) >>> q, sq, dsq = transformer.G_to_S(r, gr, q) """ def __init__(self): self.converter = Converter() def _low_x_correction(self, xin, yin, xout, yout, **kwargs): """ Omitted low-x range correction performed in the space you have transformed to. Does so by assumming a linear extrapolation to zero. Original author: Jack Carpenter :param xin: domain vector for space to be transformed from :type xin: numpy.array or list :param yin: range vector for space to be transformed from :type yin: numpy.array or list :param xout: domain vector for space to be transformed to :type xout: numpy.array or list :param yin: range vector for space to be transformed to :type yin: numpy.array or list :return: range vector for space transformed to with correction applied :rtype: numpy.array """ """ TODO: Refactor correction to just 1) peform linear extrapolation in space before transform 2) transform with extrapolated function Compare that implementation to this one. Replace this if equal (within tolerance) """ lorch_flag = kwargs.get('lorch', False) xmin = min(xin) xmax = max(xin) yin_xmin = yin[0] np.pi / xmax PiOverXmax = np.pi / xmax correction = np.zeros_like(yout) for i, x in enumerate(xout): v = xmin * x if lorch_flag: vm = xmin * (x - PiOverXmax) vp = xmin * (x + PiOverXmax) term1 = (vm * np.sin(vm) + np.cos(vm) - 1.) / \ (x - PiOverXmax)**2. term2 = (vp * np.sin(vp) + np.cos(vp) - 1.) / \ (x + PiOverXmax)**2. F1 = (term1 - term2) / (2. * PiOverXmax) F2 = ( np.sin(vm) / (x - PiOverXmax) - np.sin(vp) / # noqa (x + PiOverXmax)) / (2. * PiOverXmax) else: F1 = (2. * v * np.sin(v) - (v * v - 2.) * np.cos(v) - 2.) F1 = np.divide(F1, x * x * x, out=np.zeros_like(F1), where=x != 0) F2 = (np.sin(v) - v * np.cos(v)) F2 = np.divide(F2, x * x, out=np.zeros_like(F2), where=x != 0) num = F1 * yin_xmin factor = np.divide(num, xmin, out=np.zeros_like(num), where=xmin != 0) correction[i] = (2 / np.pi) * (factor - F2) yout += correction return yout def apply_cropping(self, x, y, xmin, xmax, dy=None): """ Utility to crop x and y based on xmin and xmax along x. Provides the capability to specify the (Qmin,Qmax) or (Rmin,Rmax) in the Fourier transform :param x: domain vector :type x: numpy.array or list :param y: range vector :type y: numpy.array or list :param xmin: minimum x-value for crop :type xmin: float :param xmax: maximum x-value for crop :type xmax: float :param dy: uncertainty vector :type dy: numpy.array or list :return: vector pair (x,y) with cropping applied :rtype: (numpy.array, numpy.array, numpy.array) """ if dy is not None: err = np.asarray(dy) else: err = np.zeros_like(y) indices = np.logical_and(x >= xmin, x <= xmax) return x[indices], y[indices], err[indices] def fourier_transform(self, xin, yin, xout, xmin=None, xmax=None, dyin=None, **kwargs): """ The Fourier transform function. The kwargs argument allows for different modifications: Lorch dampening, omitted low-x range correction, :param xin: domain vector for space to be transformed from :type xin: numpy.array or list :param yin: range vector for space to be transformed from :type yin: numpy.array or list :param xout: domain vector for space to be transformed to :type xout: numpy.array or list :param xmin: minimum x-value for crop :type xmin: float :param xmax: maximum x-value for crop :type xmax: float :param dyin: uncertainty vector for yin :type dyin: numpy.array or list :return: vector pair of transformed domain, range vectors, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ if xmax is None: xmax = max(xin) if xmin is None: xmin = min(xin) xin, yin, err = self.apply_cropping(xin, yin, xmin, xmax, dyin) factor = np.ones_like(yin) if kwargs.get('lorch', False): PiOverXmax = np.pi / xmax num = np.sin(PiOverXmax * xin) denom = PiOverXmax * xin factor = np.divide(num, denom, where=denom != 0) yout = np.zeros_like(xout) eout = np.zeros_like(xout) for i, x in enumerate(xout): kernel = factor * yin * np.sin(xin * x) ekernel = np.square(factor * err * np.sin(xin * x)) yout[i] = np.trapz(kernel, x=xin) eout[i] = np.sqrt( (np.diff(xin)**2 * (ekernel[1:] + ekernel[:-1]) / 2).sum()) if kwargs.get('OmittedXrangeCorrection', False): self._low_x_correction(xin, yin, xout, yout, **kwargs) return xout, yout, eout # Reciprocal -> Real Space Transforms # def F_to_G(self, q, fq, r, dfq=None, **kwargs): """ Transforms from reciprocal space :math:`Q[S(Q)-1]` to real space :math:`G_{PDFFIT}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`Q[S(Q)-1]` vector :type fq: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dfq: uncertainty on :math:`Q[S(Q)-1]` :type dfq: numpy.array or list :return: :math:`r`, :math:`G_{PDFFIT}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ r, gr, dgr = self.fourier_transform(q, fq, r, dyin=dfq, **kwargs) gr *= 2. / np.pi dgr *= 2. / np.pi return r, gr, dgr def F_to_GK(self, q, fq, r, dfq=None, **kwargs): """ Transforms from reciprocal space :math:`Q[S(Q)-1]` to real space :math:`G_{Keen Version}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`Q[S(Q)-1]` vector :type fq: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dfq: uncertainty on :math:`Q[S(Q)-1]` :type dfq: numpy.array or list :return: :math:`r`, :math:`G_{Keen Version}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ r, gr, dgr = self.F_to_G(q, fq, r, dfq, **kwargs) gr, dgr = self.converter.G_to_GK(r, gr, dgr, **kwargs) return r, gr, dgr def F_to_g(self, q, fq, r, dfq=None, **kwargs): """ Transforms from reciprocal space :math:`Q[S(Q)-1]` to real space :math:`g(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq: :math:`Q[S(Q)-1]` vector :type fq: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dfq: uncertainty on :math:`Q[S(Q)-1]` :type dfq: numpy.array or list :return: :math:`r`, :math:`g(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ r, gr, dgr = self.F_to_G(q, fq, r, dfq, **kwargs) gr, dgr = self.converter.G_to_g(r, gr, dgr, **kwargs) return r, gr, dgr # S(Q) def S_to_G(self, q, sq, r, dsq=None, **kwargs): """ Transforms from reciprocal space :math:`S(Q)` to real space :math:`G_{PDFFIT}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param sq: :math:`S(Q)` vector :type sq: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dsq: :math:`S(Q)` uncertainties :type dsq: numpy.array or list :return: :math:`r`, :math:`G_{PDFFIT}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.S_to_F(q, sq, dsq) return self.F_to_G(q, fq, r, dfq, **kwargs) def S_to_GK(self, q, sq, r, dsq=None, **kwargs): """ Transforms from reciprocal space :math:`S(Q)` to real space :math:`G_{Keen Version}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param sq: :math:`S(Q)` vector :type sq: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dsq: :math:`S(Q)` uncertainties :type dsq: numpy.array or list :return: :math:`r`, :math:`G_{Keen Version}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.S_to_F(q, sq, dsq) return self.F_to_GK(q, fq, r, dfq, **kwargs) def S_to_g(self, q, sq, r, dsq=None, **kwargs): """ Transforms from reciprocal space :math:`S(Q)` to real space :math:`g(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param sq: :math:`S(Q)` vector :type sq: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dsq: :math:`S(Q)` uncertainties :type dsq: numpy.array or list :return: :math:`r`, :math:`g(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.S_to_F(q, sq, dsq) return self.F_to_g(q, fq, r, dfq, **kwargs) # Keen's F(Q) def FK_to_G(self, q, fq_keen, r, dfq_keen=None, **kwargs): """ Transforms from reciprocal space :math:`F(Q)` to real space :math:`G_{PDFFIT}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq_keen: :math:`F(Q)` vector :type fq_keen: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dfq_keen: :math:`F(Q)` vector uncertainties :type dfq_keen: numpy.array or list :return: :math:`r`, :math:`G_{PDFFIT}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.FK_to_F(q, fq_keen, dfq_keen, **kwargs) return self.F_to_G(q, fq, r, dfq, **kwargs) def FK_to_GK(self, q, fq_keen, r, dfq_keen=None, **kwargs): """ Transforms from reciprocal space :math:`F(Q)` to real space :math:`G_{Keen Version}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq_keen: :math:`F(Q)` vector :type fq_keen: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dfq_keen: :math:`F(Q)` vector uncertainties :type dfq_keen: numpy.array or list :return: :math:`r`, :math:`G_{Keen Version}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.FK_to_F(q, fq_keen, dfq_keen, **kwargs) return self.F_to_GK(q, fq, r, dfq, **kwargs) def FK_to_g(self, q, fq_keen, r, dfq_keen=None, **kwargs): """ Transforms from reciprocal space :math:`F(Q)` to real space :math:`g(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param fq_keen: :math:`F(Q)` vector :type fq_keen: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param dfq_keen: :math:`F(Q)` vector uncertainties :type dfq_keen: numpy.array or list :return: :math:`r`, :math:`g(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.FK_to_F(q, fq_keen, dfq_keen, **kwargs) return self.F_to_g(q, fq, r, dfq, **kwargs) # Differential cross-section = d_simga / d_Omega def DCS_to_G(self, q, dcs, r, ddcs=None, **kwargs): """ Transforms from reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` to real space :math:`G_{PDFFIT}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param dcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` vector :type dcs: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param ddcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` uncertainties :type ddcs: numpy.array or list :return: :math:`r`, :math:`G_{PDFFIT}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.DCS_to_F(q, dcs, ddcs, **kwargs) return self.F_to_G(q, fq, r, dfq, **kwargs) def DCS_to_GK(self, q, dcs, r, ddcs=None, **kwargs): """ Transforms from reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` to real space :math:`G_{Keen Version}(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param dcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` vector :type dcs: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param ddcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` uncertainties :type ddcs: numpy.array or list :return: :math:`r`, :math:`G_{Keen Version}(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.DCS_to_F(q, dcs, ddcs, **kwargs) return self.F_to_GK(q, fq, r, dfq, **kwargs) def DCS_to_g(self, q, dcs, r, ddcs=None, **kwargs): """ Transforms from reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` to real space :math:`g(r)` :param q: :math:`Q`-space vector :type q: numpy.array or list :param dcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` vector :type dcs: numpy.array or list :param r: :math:`r`-space vector :type r: numpy.array or list :param ddcs: :math:`\\frac{d \\sigma}{d \\Omega}(Q)` uncertainties :type ddcs: numpy.array or list :return: :math:`r`, :math:`g(r)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ fq, dfq = self.converter.DCS_to_F(q, dcs, ddcs, **kwargs) return self.F_to_g(q, fq, r, dfq, **kwargs) # Real -> Reciprocal Space Transforms # # G(R) = PDF def G_to_F(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{PDFFIT}(r)` to reciprocal space :math:`Q[S(Q)-1]` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{PDFFIT}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`Q[S(Q)-1]`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ return self.fourier_transform(r, gr, q, dyin=dgr, **kwargs) def G_to_S(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{PDFFIT}(r)` to reciprocal space :math:`S(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{PDFFIT}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`S(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ q, fq, dfq = self.G_to_F(r, gr, q, dgr=dgr, **kwargs) sq, dsq = self.converter.F_to_S(q, fq, dfq=dfq) return q, sq, dsq def G_to_FK(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{PDFFIT}(r)` to reciprocal space :math:`F(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{PDFFIT}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`F(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ q, fq, dfq = self.G_to_F(r, gr, q, dgr=dgr, **kwargs) fq, dfq = self.converter.F_to_FK(q, fq, dfq=dfq, **kwargs) return q, fq, dfq def G_to_DCS(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{PDFFIT}(r)` to reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{PDFFIT}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{PDFFIT}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ q, fq, dfq = self.G_to_F(r, gr, q, dgr=dgr, **kwargs) dcs, ddcs = self.converter.F_to_DCS(q, fq, dfq=dfq, **kwargs) return q, dcs, ddcs # Keen's G(r) def GK_to_F(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{Keen Version}(r)` to reciprocal space :math:`Q[S(Q)-1]` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{Keen Version}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`Q[S(Q)-1]`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.GK_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_F(r, _gr, q, dgr=_dgr, **kwargs) def GK_to_S(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{Keen Version}(r)` to reciprocal space :math:`S(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{Keen Version}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`S(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.GK_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_S(r, _gr, q, dgr=_dgr, **kwargs) def GK_to_FK(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{Keen Version}(r)` to reciprocal space :math:`F(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{Keen Version}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`F(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.GK_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_FK(r, _gr, q, dgr=_dgr, **kwargs) def GK_to_DCS(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`G_{Keen Version}(r)` to reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`G_{Keen Version}(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`G_{Keen Version}(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.GK_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_DCS(r, _gr, q, dgr=_dgr, **kwargs) # g(r) def g_to_F(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`g(r)` to reciprocal space :math:`Q[S(Q)-1]` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`g(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`Q[S(Q)-1]`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.g_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_F(r, _gr, q, dgr=_dgr, **kwargs) def g_to_S(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`g(r)` to reciprocal space :math:`S(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`g(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`S(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.g_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_S(r, _gr, q, dgr=_dgr, **kwargs) def g_to_FK(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`g(r)` to reciprocal space :math:`F(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`g(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`F(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.g_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_FK(r, _gr, q, dgr=_dgr, **kwargs) def g_to_DCS(self, r, gr, q, dgr=None, **kwargs): """ Transforms from real space :math:`g(r)` to reciprocal space :math:`\\frac{d \\sigma}{d \\Omega}(Q)` :param r: :math:`r`-space vector :type r: numpy.array or list :param gr: :math:`g(r)` vector :type gr: numpy.array or list :param q: :math:`Q`-space vector :type q: numpy.array or list :param dgr: :math:`g(r)` uncertainties :type dgr: numpy.array or list :return: :math:`Q`, :math:`\\frac{d \\sigma}{d \\Omega}(Q)`, and uncertainties :rtype: numpy.array, numpy.array, numpy.array """ _gr, _dgr = self.converter.g_to_G(r, gr, dgr=dgr, **kwargs) return self.G_to_DCS(r, _gr, q, dgr=_dgr, **kwargs)
class TestConverterReciprocalSpaceBase(unittest.TestCase): rtol = 1e-5 atol = 1e-8 def initialize_material(self): # setup input data self.kwargs = self.material.kwargs # setup the tolerance self.first = self.material.reciprocal_space_first self.last = self.material.reciprocal_space_last data = load_data(self.material.reciprocal_space_filename) self.q = data[:, get_index_of_function("Q", ReciprocalSpaceHeaders)] self.sq = data[:, get_index_of_function("S(Q)", ReciprocalSpaceHeaders)] self.fq = data[:, get_index_of_function("Q[S(Q)-1]", ReciprocalSpaceHeaders)] self.fq_keen = data[:, get_index_of_function("FK(Q)", ReciprocalSpaceHeaders)] self.dcs = data[:, get_index_of_function("DCS(Q)", ReciprocalSpaceHeaders )] # targets for 1st peaks self.sq_target = self.material.sq_target self.fq_target = self.material.fq_target self.fq_keen_target = self.material.fq_keen_target self.dcs_target = self.material.dcs_target def setUp(self): unittest.TestCase.setUp(self) self.converter = Converter() def tearDown(self): unittest.TestCase.tearDown(self) # S(Q) tests def S_to_F(self): fq, dfq = self.converter.S_to_F(self.q, self.sq, np.ones_like(self.q), **self.kwargs) assert_allclose(fq[self.first:self.last], self.fq_target, rtol=self.rtol, atol=self.atol) assert_allclose(dfq, np.ones_like(self.q) * self.q) def S_to_FK(self): fq_keen, dfq_keen = self.converter.S_to_FK(self.q, self.sq, np.ones_like(self.q), **self.kwargs) assert_allclose(fq_keen[self.first:self.last], self.fq_keen_target, rtol=self.rtol, atol=self.atol) assert_allclose(dfq_keen, np.ones_like(self.q) * self.kwargs['<b_coh>^2']) def S_to_DCS(self): dcs, ddcs = self.converter.S_to_DCS(self.q, self.sq, np.ones_like(self.q), **self.kwargs) assert_allclose(dcs[self.first:self.last], self.dcs_target, rtol=self.rtol, atol=self.atol) assert_allclose(ddcs, np.ones_like(self.q) * self.kwargs['<b_coh>^2']) # Q[S(Q)-1] tests def F_to_S(self): sq, dsq = self.converter.F_to_S(self.q, self.fq, np.ones_like(self.q), **self.kwargs) assert_allclose(sq[self.first:self.last], self.sq_target, rtol=self.rtol, atol=self.atol) assert_allclose(dsq, np.ones_like(self.q) / self.q) def F_to_FK(self): fq_keen, dfq_keen = self.converter.F_to_FK(self.q, self.fq, np.ones_like(self.q), **self.kwargs) assert_allclose(fq_keen[self.first:self.last], self.fq_keen_target, rtol=self.rtol, atol=self.atol) assert_allclose( dfq_keen, np.ones_like(self.q) * self.kwargs['<b_coh>^2'] / self.q) def F_to_DCS(self): dcs, ddcs = self.converter.F_to_DCS(self.q, self.fq, np.ones_like(self.q), **self.kwargs) assert_allclose(dcs[self.first:self.last], self.dcs_target, rtol=self.rtol, atol=self.atol) assert_allclose( ddcs, np.ones_like(self.q) * self.kwargs['<b_coh>^2'] / self.q) # FK(Q) tests def FK_to_S(self): sq, dsq = self.converter.FK_to_S(self.q, self.fq_keen, np.ones_like(self.q), **self.kwargs) assert_allclose(sq[self.first:self.last], self.sq_target, rtol=self.rtol, atol=self.atol) assert_allclose(dsq, np.ones_like(self.q) / self.kwargs['<b_coh>^2']) def FK_to_F(self): fq, dfq = self.converter.FK_to_F(self.q, self.fq_keen, np.ones_like(self.q), **self.kwargs) assert_allclose(fq[self.first:self.last], self.fq_target, rtol=self.rtol, atol=self.atol) assert_allclose( dfq, np.ones_like(self.q) / self.kwargs['<b_coh>^2'] * self.q) def FK_to_DCS(self): dcs, ddcs = self.converter.FK_to_DCS(self.q, self.fq_keen, np.ones_like(self.q), **self.kwargs) assert_allclose(dcs[self.first:self.last], self.dcs_target, rtol=self.rtol, atol=self.atol) assert_allclose(ddcs, np.ones_like(self.q)) # DCS(Q) tests def DCS_to_S(self): sq, dsq = self.converter.DCS_to_S(self.q, self.dcs, np.ones_like(self.q), **self.kwargs) assert_allclose(sq[self.first:self.last], self.sq_target, rtol=self.rtol, atol=self.atol) assert_allclose(dsq, np.ones_like(self.q) / self.kwargs['<b_coh>^2']) def DCS_to_F(self): fq, dfq = self.converter.DCS_to_F(self.q, self.dcs, np.ones_like(self.q), **self.kwargs) assert_allclose(fq[self.first:self.last], self.fq_target, rtol=self.rtol, atol=self.atol) assert_allclose( dfq, np.ones_like(self.q) / self.kwargs['<b_coh>^2'] * self.q) def DCS_to_FK(self): fq_keen, dfq_keen = self.converter.DCS_to_FK(self.q, self.dcs, np.ones_like(self.q), **self.kwargs) assert_allclose(fq_keen[self.first:self.last], self.fq_keen_target, rtol=self.rtol, atol=self.atol) assert_allclose(dfq_keen, np.ones_like(self.q))