예제 #1
0
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
예제 #2
0
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)
예제 #3
0
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))