예제 #1
0
def test_dn1_lentz():
    '''
    Test down recursion beginning with Lentz continued fraction algorithm
    against Python down recursion starting with 0.
    '''
    m = 1.5 + 0.1j
    xs = np.logspace(-1,4,6)
    zs = m * xs
    nstops = np.array([miescatlib.nstop(x) for x in xs])
    # n to start down recurrence from
    nmxs = np.array([max(nstop, int(np.ceil(abs(z)))) for (nstop, z) in
                     zip(nstops, zs)]) + 25
    #increase past Bohren & Huffman suggestion

    # error bounds for lentz
    eps1 = 1e-3
    eps2 = 1e-16

    for z, nstop, nmx in zip(zs, nstops, nmxs):
        python_dn = mie_specfuncs.log_der_1(z, nmx, nstop)
        lentz_start = mieangfuncs.lentz_dn1(z, nstop, eps1, eps2)
        fortran_dn = mieangfuncs.dn_1_down(z, nstop, nstop, lentz_start)

        assert_allclose(fortran_dn, python_dn, rtol = 1e-12)

        # check also Lentz ill-conditioning workaround
        lentz_illconditioned = mieangfuncs.lentz_dn1(z, nstop, 1., eps2)
        assert_allclose(lentz_illconditioned, lentz_start, rtol = 1e-12)
예제 #2
0
def scat_coeffs(s, optics):
  x_arr = array([optics.wavevec * s.r]) #size param
  m_arr = array([s.n/optics.index]) #use medium index parameter?

  # Check that the scatterer is in a range we can compute for
  if x_arr.max() > 1e3:
    raise UnrealizableScatterer(self, s, "radius too large, field "+
                                      "calculation would take forever")
  lmax = miescatlib.nstop(x_arr[0])
  return miescatlib.scatcoeffs(m_arr[0], x_arr[0], lmax)
예제 #3
0
파일: mie.py 프로젝트: tdimiduk/holopy
    def _scat_coeffs_internal(self, s, optics):
        x_arr = optics.wavevec * _ensure_array(s.r)
        m_arr = _ensure_array(s.n) / optics.index

        # Check that the scatterer is in a range we can compute for
        if x_arr.max() > 1e3:
            raise UnrealizableScatterer(self, s, "radius too large, field "+
                                        "calculation would take forever")

        if len(x_arr) == 1 and len(m_arr) == 1:
            # Could just use scatcoeffs_multi here, but jerome is in favor of
            # keeping the simpler single layer code here
            lmax = miescatlib.nstop(x_arr[0])
            return  miescatlib.internal_coeffs(m_arr[0], x_arr[0], lmax)
예제 #4
0
    def _scat_coeffs_internal(self, s, optics):
        x_arr = optics.wavevec * _ensure_array(s.r)
        m_arr = _ensure_array(s.n) / optics.index

        # Check that the scatterer is in a range we can compute for
        if x_arr.max() > 1e3:
            raise UnrealizableScatterer(
                self, s,
                "radius too large, field " + "calculation would take forever")

        if len(x_arr) == 1 and len(m_arr) == 1:
            # Could just use scatcoeffs_multi here, but jerome is in favor of
            # keeping the simpler single layer code here
            lmax = miescatlib.nstop(x_arr[0])
            return miescatlib.internal_coeffs(m_arr[0], x_arr[0], lmax)
예제 #5
0
def test_mie_internal_coeffs():
    if os.name == 'nt':
        raise SkipTest()

    m = 1.5 + 0.1j
    x = 50.
    n_stop = miescatlib.nstop(x)
    al, bl = miescatlib.scatcoeffs(m, x, n_stop)
    cl, dl = miescatlib.internal_coeffs(m, x, n_stop)
    n = np.arange(n_stop)+1
    jlx = spherical_jn(n, x)
    jlmx = spherical_jn(n, m*x)
    hlx = jlx + 1.j * spherical_yn(n, x)

    assert_allclose(cl, (jlx - hlx * bl) / jlmx, rtol = 1e-6, atol = 1e-6)
    assert_allclose(dl, (jlx - hlx * al)/ (m * jlmx), rtol = 1e-6, atol = 1e-6)
예제 #6
0
파일: mie.py 프로젝트: sid6155330/holopy
    def _scat_coeffs_internal(self, s, medium_wavevec, medium_index):
        '''
        Calculate expansion coefficients for Lorenz-Mie electric field
        inside a sphere.
        '''
        x_arr = medium_wavevec * ensure_array(s.r)
        m_arr = ensure_array(s.n) / medium_index

        # Check that the scatterer is in a range we can compute for
        if x_arr.max() > 1e3:
            msg = "radius too large, field calculation would take forever"
            raise InvalidScatterer(s, msg)

        if len(x_arr) == 1 and len(m_arr) == 1:
            # Could just use scatcoeffs_multi here, but jerome is in favor of
            # keeping the simpler single layer code here
            lmax = miescatlib.nstop(x_arr[0])
            return  miescatlib.internal_coeffs(m_arr[0], x_arr[0], lmax)
예제 #7
0
파일: mie.py 프로젝트: sid6155330/holopy
    def _scat_coeffs(self, s, medium_wavevec, medium_index):
        '''
        Calculate Mie scattering coefficients.

        Parameters
        ----------
        s : :mod:`scatterer.Sphere` object
        medium_wavevec : float
            Wave vector in the medium, k = 2 * pi * n_med / lambda_0
        medium_index : float
            Medium refractive index

        Returns
        -------
        ndarray (2, n), complex
           Lorenz-Mie scattering coefficients a_n and b_n

        Notes
        -----
        See Bohren & Huffman for mathematical description.

        '''
        if (ensure_array(s.r) == 0).any():
            raise InvalidScatterer(s, "Radius is zero")
        x_arr = ensure_array(medium_wavevec * ensure_array(s.r))
        m_arr = ensure_array(ensure_array(s.n) / medium_index)

        # Check that the scatterer is in a range we can compute for
        if x_arr.max() > 1e3:
            msg =  "radius too large, field calculation would take forever"
            raise InvalidScatterer(s, msg)

        if len(x_arr) == 1 and len(m_arr) == 1:
            # Could just use scatcoeffs_multi here, but jerome is in favor of
            # keeping the simpler single layer code here
            lmax = miescatlib.nstop(x_arr[0])
            return  miescatlib.scatcoeffs(m_arr[0], x_arr[0], lmax, self.eps1,
                                          self.eps2)
        else:
            return scatcoeffs_multi(m_arr, x_arr, self.eps1, self.eps2)
예제 #8
0
def test_mie_bndy_conds():
    '''
    Check that appropriate boundary conditions are satisfied:
    m^2 E_radial continuous (bound charge Gaussian pillbox)
    E_parallel continuous (Amperian loop)

    Checks to do (all on E_x):
    theta = 0, phi = 0 (theta component)
    theta = 90, phi = 0 (radial component)
    theta = 90, phi = 90 (phi component)
    '''
    m = 1.2 + 0.01j
    x = 10.
    pol = np.array([1., 0.]) # assume x polarization
    n_stop = miescatlib.nstop(x)
    asbs = miescatlib.scatcoeffs(m, x, n_stop)
    csds = miescatlib.internal_coeffs(m, x, n_stop)

    # define field points
    eps = 1e-6 # get just inside/outside boundary
    kr_ext = np.ones(3) * (x + eps)
    kr_int = np.ones(3) * (x - eps)
    thetas = np.array([0., pi/2., pi/2.])
    phis = np.array([0., 0., pi/2.])
    points_int = np.vstack((kr_int, thetas, phis))
    points_ext = np.vstack((kr_ext, thetas, phis))

    # calc escat
    es_x, es_y, es_z = mieangfuncs.mie_fields(points_ext, asbs, pol, 1, 1)
    # calc eint
    eint_x, eint_y, eint_z = mieangfuncs.mie_internal_fields(points_int, m,
                                                             csds, pol)
    # theta check
    assert_allclose(eint_x[0], es_x[0] + exp(1.j * (x + eps)), rtol = 5e-6)
    # r check
    assert_allclose(m**2 * eint_x[1], es_x[1] + 1., rtol = 5e-6)
    # phi check
    assert_allclose(eint_x[2], es_x[2] + 1., rtol = 5e-6)
예제 #9
0
def test_mie_multisphere_singlesph():
    '''
    Check that fields from mie_fields and tmatrix_fields are consistent
    at several points. This includes a check on the radial component of E_scat.
    '''
    # sphere params
    x = 5.
    m = 1.2+0.1j
    pol = np.array([1., 0.]) # assume x polarization

    # points to check
    # at last two points: E_s
    kr = np.ones(4) * 6.
    thetas = np.array([0., pi/3., pi/2., pi/2.])
    phis = np.array([0., pi/6., 0., pi/2.])
    field_pts = np.vstack((kr, thetas, phis))

    # calculate fields with Mie
    n_stop_mie = miescatlib.nstop(x)
    asbs = miescatlib.scatcoeffs(m, x, n_stop_mie)
    emie_x, emie_y, emie_z = mieangfuncs.mie_fields(field_pts, asbs, pol, 1, 1)

    # calculate fields with Multisphere
    with SuppressOutput():
        _, lmax, amn0, conv = scsmfo_min.amncalc(
            1, 0., 0., 0., m.real, m.imag, x, 100, 1e-6, 1e-8, 1e-8, 1,
            (0., 0.))
    # increase qeps1 from usual here
    limit = lmax**2 + 2 * lmax
    amn = amn0[:, 0:limit, :]
    etm_x, etm_y, etm_z = mieangfuncs.tmatrix_fields(field_pts, amn, lmax,
                                                     0., pol, 1)

    assert_allclose(etm_x, emie_x, rtol = 1e-6, atol = 1e-6)
    assert_allclose(etm_y, emie_y, rtol = 1e-6, atol = 1e-6)
    assert_allclose(etm_z, emie_z, rtol = 1e-6, atol = 1e-6)
예제 #10
0
def test_mie_amplitude_scattering_matrices():
    '''
    Test calculation of Mie amplitude scattering matrix elements.
    We will check the following:
        far-field matrix elements (direct comparison with [Bohren1983]_)
        near-field matrix for kr ~ 10 differs from far-field result
        near-field matrix for kr ~ 10^4 is close to far-field result

    While radiometric quantities (such as cross sections) implicitly test
    the Mie scattering coefficients, they do not involve any angular
    quantities.
    '''

    # scattering units
    m = 1.55
    x = 2. * pi * 0.525 / 0.6328

    asbs = miescatlib.scatcoeffs(m, x, miescatlib.nstop(x))
    amp_scat_mat = mieangfuncs.asm_mie_far(asbs, theta)
    amp_scat_mat_asym = mieangfuncs.asm_mie_fullradial(asbs, np.array([kr_asym,
                                                                       theta,
                                                                       phi]))
    amp_scat_mat_near = mieangfuncs.asm_mie_fullradial(asbs, np.array([kr,
                                                                      theta,
                                                                      phi]))

    # gold results directly from B/H p.482.
    location = os.path.split(os.path.abspath(__file__))[0]
    gold_name = os.path.join(location, 'gold',
                             'gold_mie_scat_matrix')
    with open(gold_name + '.yaml') as gold_file:
        gold_dict = yaml.safe_load(gold_file)
    
    gold = np.array([gold_dict['S11'], gold_dict['pol'],
                     gold_dict['S33'], gold_dict['S34']])


    # B/H gives real scattering matrix elements, which are related
    # to the amplitude scatering elements.  See p. 65.
    def massage_into_bh_form(asm):
        S2, S3, S4, S1 = np.ravel(asm)
        S11 = 0.5 * (abs(asm)**2).sum()
        S12 = 0.5 * (abs(S2)**2 - abs(S1)**2)
        S33 = real(S1 * conj(S2))
        S34 = imag(S2 * conj(S1))
        deg_of_pol = -S12/S11
        # normalization factors: see comment lines 40-44 on p. 479
        asm_fwd = mieangfuncs.asm_mie_far(asbs, 0.)
        S11_fwd = 0.5 * (abs(asm_fwd)**2).sum()
        results = np.array([S11/S11_fwd, deg_of_pol, S33 / S11, S34 / S11])
        return results

    # off-diagonal elements should be zero
    assert_allclose(np.ravel(amp_scat_mat)[1:3], np.zeros(2))

    # check far-field computation
    assert_allclose(massage_into_bh_form(amp_scat_mat), gold,
                    rtol = 1e-5)

    # check asymptotic behavior of near field matrix
    asym = massage_into_bh_form(amp_scat_mat_asym)
    assert_allclose(asym, gold, rtol = 1e-4, atol = 5e-5)

    # check that the near field is different
    try:
        assert_allclose(amp_scat_mat, amp_scat_mat_near)
    except AssertionError:
        pass
    else:
        raise AssertionError("Near-field amplitude scattering matrix " +
                             "suspiciously close to far-field result.")