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
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)
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)
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)
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)
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)
def test_init_raises_WavenumberError(self): # Due to a complex wavenumber with pytest.raises(WavenumberError): SWPContinuum(1j, "o", pot)
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)
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([
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)])