Beispiel #1
0
    def _add_one_continuum_state(self):
        r"""
        Add two continuum state to the basis set, depending on the
        already existing continuum states.

        This is an overriding of the inherited
        :meth:`siegpy.analyticbasisset.AnalyticBasisSet._add_one_continuum_state`
        method to account for the parity of the continuum states in the
        1D SWP case.


        Returns
        -------
        SWPBasisSet
            The same basis set with one more continuum state.
        """
        cont = self.continuum
        kmax = cont[-1].wavenumber
        hk = cont[1].wavenumber - cont[0].wavenumber
        # Add a continuum state to the basis set
        self += SWPContinuum(
            kmax + hk,
            cont.parity,
            self.potential,
            grid=self.grid,
            analytic=self.analytic,
        )
        return self
Beispiel #2
0
 def test_scal_prod_raises_TypeError(self):
     # Scalar product with continuum1DSWP not implemented
     c = SWPContinuum(1.0, "e", bnd1.potential)
     with pytest.raises(TypeError):
         bnd1.scal_prod(c)
     # Scalar product not implemented for SWPSiegert, even if
     # bound state
     # (TODO: make the bound states scalar product possible ?)
     with pytest.raises(TypeError):
         bnd1.scal_prod(bnd1)
Beispiel #3
0
    def _evaluate_integrand(q, k, test, eta, potential):
        r"""
        Evaluate the integrand used to compute the strength function
        "on-the-fly."

        Parameters
        ----------
        q: float
            Wavenumber of the continuum state considered.
        k: float
            Wavenumber for which the strength function is evaluated.
        test: Function
            Test function.
        eta: float
            Infinitesimal for integration (if ``None``, default to 10
            times the value of the grid-step of the continuum basis
            set).
        potential: Potential
            Potential of the currently studied analytical case.

        Returns
        -------
        complex
            Value of the integrand.
        """
        # Even states contribution
        c_p = SWPContinuum(q, "e", potential)
        sp_p = c_p.scal_prod(test)
        # Odd states contribution
        if not test.is_even:
            c_m = SWPContinuum(q, "o", potential)
            sp_m = c_m.scal_prod(test)
        else:
            sp_m = 0.0
        # Add both contributions
        cont_contrib = abs(sp_p)**2 + abs(sp_m)**2
        # Return the evaluation of the integrand
        return eta * cont_contrib / ((q**2 / 2.0 - k**2 / 2.0)**2 + eta**2)
Beispiel #4
0
    def find_continuum_states(cls,
                              pot,
                              kmax,
                              hk,
                              kmin=None,
                              even_only=False,
                              analytic=True,
                              grid=None):
        r"""
        Initialize a BasisSet instance made of SWPContinuum instances.
        The basis set has :math:`2*n_k` elements if ``even_only=False``,
        :math:`n_k` elements otherwise (where :math:`n_k` is the number
        of continuum states defined by the grid step ``hk`` and the
        minimal and maximal values of the wavenumber grid ``kmin`` and
        ``kmax``).

        Parameters
        ----------
        pot: SWPotential
            1D Square-Well Potential for which we look for the continuum
            states.
        kmax: float
            Wavenumber of the last continuum state.
        hk: float
            Grid step of the wavenumber grid.
        kmin: float
            Wavenumber of the first continuum state (optional)
        even_only: bool
            If ``True``, only even continuum states are created (default
            to ``False``)
        analytic: bool
            If ``True``, the scalar products will be computed
            analytically (default to ``True``).
        grid: numpy array or list or set
            Discretization grid of the wavefunctions of the continuum
            states (optional).

        Returns
        -------
        SWPBasisSet
            Basis set of all continuum states defined by the grid of
            wavenumbers.

        Raises
        ------
        WavenumberError
            If ``hk``, ``kmin`` or ```kmax`` is not strictly positive.


        Examples

        Let us start by defining a potential:

        >>> from siegpy.swpbasisset import SWPBasisSet
        >>> bs_ref = SWPBasisSet.from_file("doc/notebooks/siegerts.dat")
        >>> pot = bs_ref.potential

        The continuum states are found, given a potential and a grid
        of initial wavenumbers (note that the minimal and maximal
        wavenumber cannot be 0)

        >>> hk = 1; kmax = 3
        >>> bs = SWPBasisSet.find_continuum_states(pot, kmax, hk)
        >>> bs.wavenumbers
        [1.0, 1.0, 2.0, 2.0, 3.0, 3.0]

        It is possible to find only the even continuum states:

        >>> p = pot
        >>> bs = SWPBasisSet.find_continuum_states(p, kmax, hk, even_only=True)
        >>> bs.wavenumbers
        [1.0, 2.0, 3.0]
        >>> assert len(bs.even) == 3 and bs.odd.is_empty

        The minimal wavenumber can set:

        >>> bs = SWPBasisSet.find_continuum_states(pot, kmax, hk, kmin=3)
        >>> bs.wavenumbers
        [3.0, 3.0]
        """
        # Check the given values
        if kmax <= 0.0:
            raise WavenumberError(
                "The maximal wavenumber must be strictly positive.")
        if hk <= 0.0:
            raise WavenumberError(
                "The wavenumber grid step must be striclty positive")
        if kmin is None:
            kmin = hk
        elif kmin <= 0.0:
            raise WavenumberError(
                "The minimal wavenumber must be strictly positive.")
        # Initialize the grid of wavenumbers
        kgrid = np.arange(kmin, kmax + hk / 2, hk)
        # Initialize the basis set with the even states
        cont = [
            SWPContinuum(k, "e", pot, grid=grid, analytic=analytic)
            for k in kgrid
        ]
        # Add the odd continuum states to the basis set, if required
        if not even_only:
            cont += [
                SWPContinuum(k, "o", pot, grid=grid, analytic=analytic)
                for k in kgrid
            ]
        # Return a basis set made of the continuum states
        return cls(states=cont)
Beispiel #5
0
 def test_compute_wavefunction_raises_ValueError(self):
     # wrong grid: complex grid
     cplx_grid = 0.0j * np.zeros(len(xgrid))
     cplx_grid[0] = 1.0j  # Now it will raise an error
     with pytest.raises(ValueError):
         SWPContinuum(k, "e", pot, grid=cplx_grid)
Beispiel #6
0
 def test_parity_raises_ParityError(self, wrong_parity):
     # All other value than the correct parity (here, 'e') raise a
     # ParityError.
     with pytest.raises(ParityError):
         SWPContinuum(1, wrong_parity, pot)
Beispiel #7
0
 def test_init_raises_WavenumberError(self):
     # Due to a complex wavenumber
     with pytest.raises(WavenumberError):
         SWPContinuum(1j, "o", pot)
Beispiel #8
0
class TestSWPContinuum:
    def test_init_raises_WavenumberError(self):
        # Due to a complex wavenumber
        with pytest.raises(WavenumberError):
            SWPContinuum(1j, "o", pot)

    @pytest.mark.parametrize(
        "value, expected",
        [
            (c_e == SWPContinuum(k, "e", pot, grid=xgrid), True),
            (c_e == c_o, False),
            (c_e == Rectangular(-2.0, 2.0), False),
            (c_e != 1, True),
        ],
    )
    def test_eq(self, value, expected):
        assert value == expected

    @pytest.mark.parametrize("wrong_parity", [1, "toto", None])
    def test_parity_raises_ParityError(self, wrong_parity):
        # All other value than the correct parity (here, 'e') raise a
        # ParityError.
        with pytest.raises(ParityError):
            SWPContinuum(1, wrong_parity, pot)

    @pytest.mark.parametrize(
        "value, expected",
        [
            (c_e.is_even, True),
            (c_o.is_even, False),
            (c_e.is_odd, False),
            (c_o.is_odd, True),
        ],
    )
    def test_is_parity(self, value, expected):
        assert value == expected

    @pytest.mark.parametrize(
        "state, expected",
        [(c_e_with_grid, c_e_expected), (c_o_with_grid, c_o_expected)],
    )
    def test_compute_wavefunction(self, state, expected):
        np.testing.assert_array_almost_equal(state.values, expected)

    def test_compute_wavefunction_raises_ValueError(self):
        # wrong grid: complex grid
        cplx_grid = 0.0j * np.zeros(len(xgrid))
        cplx_grid[0] = 1.0j  # Now it will raise an error
        with pytest.raises(ValueError):
            SWPContinuum(k, "e", pot, grid=cplx_grid)

    @pytest.mark.parametrize(
        "value, expected",
        [
            (c_e.scal_prod(r1), -0.90635923273823826 - 1.0929535715333105j),
            (c_o.scal_prod(r1), 0.0j),
            (c_e.scal_prod(r1p), 8.1518896862942469 + 0.90334965979254944j),
            (c_o.scal_prod(r1p), 0.044058371125370144 - 0.091660394131671374j),
            (c_e.scal_prod(r1m), -0.62073133482877063 + 8.1782662389604024j),
            (c_o.scal_prod(r1m),
             -0.044058371125370144 + 0.091660394131671374j),
            (c_e.scal_prod(r2p), -0.46402741449617413 - 0.53088816154466156j),
            (c_o.scal_prod(r2p), 0.30059494527010172 - 0.58538480308246721j),
            (c_e.scal_prod(r2m), -0.43585286304346693 - 0.55425261681753712j),
            (c_o.scal_prod(r2m), -0.26937227999135543 + 0.60039259120519894j),
            (c_e.scal_prod(g1), -0.072629271280681904 - 0.087581632731056958j),
            (c_o.scal_prod(g1), 0.0j),
            (c_e.scal_prod(g2), -0.044201378011213856 - 0.053301221214571481j),
            (c_o.scal_prod(g2), -0.077013178199935931 - 0.037017898720824186j),
        ],
    )
    def test_analytical_scal_prod(self, value, expected):
        decimal = 14
        np.testing.assert_almost_equal(value, expected, decimal=decimal)

    @pytest.mark.parametrize(
        "value, expected",
        [
            (c_e_na.scal_prod(r_na_1),
             0.26626637332669501 + 0.32108326720237679j),
            (c_o_na.scal_prod(r_na_1), 0.0j),
            (c_e_na.scal_prod(r_na_k0_1),
             -0.52973455183891471 - 0.63879226854430993j),
            (c_e_na.scal_prod(r_na_3),
             -0.49218097140147571 - 0.59350744285884549j),
            (c_o_na.scal_prod(r_na_3),
             1.5309260929446813 + 0.7358697353142144j),
            (c_e_na.scal_prod(r_na_k0_3),
             0.0052031824473088156 - 0.94598903180912952j),
            (c_e_na.scal_prod(g_na_1),
             -0.22338282414061131 - 0.26937117937892679j),
            (c_o_na.scal_prod(g_na_1), 0.0j),
            (c_e_na.scal_prod(g_na_k0_1),
             -0.22341030109728754 - 0.26940431308226365j),
            (c_e_na.scal_prod(g_na_2),
             -0.16205020291442584 - 0.19541186501508359j),
            (c_o_na.scal_prod(g_na_2),
             0.0017661284228762 + 0.0008489243609226155j),
            (c_e_na.scal_prod(g_na_k0_2),
             -0.16248453420586526 - 0.19555059652396745j),
        ],
    )
    def test_numerical_scal_prod(self, value, expected):
        decimal = 14
        np.testing.assert_almost_equal(value, expected, decimal=decimal)

    def test_scal_prod_raises_TypeError(self):
        # Scalar product not implemented for SWPSiegert,
        # even if it is known that it is zero for bound state.(TODO?)
        with pytest.raises(TypeError):
            c_e.scal_prod(bnd1)
Beispiel #9
0
siegerts_with_grid = SWPBasisSet.from_file(filename, grid=xgrid, nres=5)
siegerts_na_with_grid = SWPBasisSet.from_file(filename,
                                              nres=5,
                                              grid=xgrid,
                                              analytic=False)
bnd1 = siegerts_with_grid.bounds[0]
bnd2 = siegerts_with_grid.bounds[1]
res_na_1 = siegerts_na_with_grid.resonants[0]
res_na_2 = siegerts_na_with_grid.resonants[1]
h = 2.0
pot = bnd1.potential

# Variables for continuum states
k = 1.0
qq = q(k, pot.depth)
c_e = SWPContinuum(k, "e", pot)
c_o = SWPContinuum(k, "o", pot)
c_e_with_grid = SWPContinuum(k, "e", pot, grid=xgrid)
c_e_expected = np.array([
    -0.360072 + 0.434201j,
    -0.188472 + 0.227273j,
    0.107958 - 0.130183j,
    0.014460 - 0.017436j,
    -0.111701 + 0.134697j,
    0.014460 - 0.017436j,
    0.107958 - 0.130183j,
    -0.188472 + 0.227273j,
    -0.360072 + 0.434201j,
])
c_o_with_grid = SWPContinuum(k, "o", pot, grid=xgrid)
c_o_expected = np.array([
Beispiel #10
0
siegerts = SWPBasisSet.from_file(filename, nres=5)
bounds = SWPBasisSet.from_file(filename, bounds_only=True)
bnds = siegerts.bounds
abnds = siegerts.antibounds
res = siegerts.resonants
ares = siegerts.antiresonants
cont = siegerts.continuum
pot = siegerts.potential
l = pot.width
xgrid = np.linspace(-l / 2, l / 2, 5)
siegerts_grid = SWPBasisSet.from_file(filename, nres=5, grid=xgrid)

# Analytical continuum SWPBasisSet
k = 1.0
k_2 = 2.0
c_e = SWPContinuum(k, "e", pot, grid=xgrid)
c_o = SWPContinuum(k, "o", pot, grid=xgrid)
c_e_2 = SWPContinuum(k_2, "e", pot, grid=xgrid)
c_o_2 = SWPContinuum(k_2, "o", pot, grid=xgrid)
r = Rectangular.from_center_and_width(0.25, 2.0)
r_even = Rectangular(-1.0, 1.0)
bnds_grid = siegerts_grid.bounds
exact_grid = siegerts_grid.bounds + [c_e, c_o, c_e_2, c_o_2]
kgrid = np.arange(0.1, 5.2, 1.0)
time_grid = [0.0, 1.0]


class TestSWPBasisSet:
    def test_init_raises_ValueError_not_SWPEigenstate(self):
        with pytest.raises(ValueError):
            SWPBasisSet(states=[Eigenstate([-1, 0, 1], [2, 1, 0], 1.0)])