% FASTMIE Vectorized version of BHMIE 
%   Calculates the amplitude scattering matrix elements and efficiencies
%   for extinction, total scattering, and backscattering for a given size
%   parameter and relative refractive index. This code maintains the
%   calling syntax of E. Boss' BHMIE translation.
%
%   [S1,S2,Qb,Qc,Qbb] = FASTMIE(X,M,NANG) 
%   X and M are the scalar size parameter (2*pi*r/lambda) and relative 
%   refractive index of the particle. NANG is the number of angles between
%   0 and 90 degrees; matrix elements are calculated at 2*NANG-1 angles
%   including 0, 90, and 180 degrees.
%
%   [S1,S2,Qb,Qc,Qbb] = FASTMIE(X,M,[],THETA)
%   Same as above, but use user-specified THETA vector (radians).
%
%   FASTMIE returns
%   S1 and S2 are 2*NANG-1 x 1 vectors of scattering matrix elements;
%   Qb, Qc, and Qbb are scalar extinction, total scattering, and
%   backscattering efficiencies.
%
% Wayne H. Slade
% University of Maine
% 10 Aug 2005

% 3 May 2006 added ability to specify angles for which to calculate 
% scattering matrix elements


function [s1, s2, Q_scat, Q_ext, Q_back] = fastmie(x, m, nang, varargin);

    if any([length(m) length(x)]~=1)
        error('m, x must be scalar')
	end
 
	if ~(length(nang)==1 | isempty(nang))
        error('nang must be scalar or empty matrix')
	end
	
	if isempty(nang)
		theta = varargin{1}(:);
	else
		theta = linspace(0,pi, nang*2-1); % calculated at (nang*2-1) angles for agreement with bhmie		
	end	
	
	nstop = ceil(2+x+4*x.^(1/3));
	n=(1:nstop)';
	
	jx = besselj(n+0.5, x) .* sqrt(0.5*pi/x);
	jmx = besselj(n+0.5, m*x) .* sqrt(0.5*pi/(m*x));
	yx = bessely(n+0.5, x) .* sqrt(0.5*pi/x);
	hx = jx +  j*yx;
	
	j1x =  [ sin(x)/x;        jx(1:nstop-1)];
	j1mx = [ sin(m*x)/(m*x);  jmx(1:nstop-1)];
	y1x =  [ -cos(x)/x;       yx(1:nstop-1)];
	h1x = j1x + j*y1x;
    
    d_jx =  x.*j1x - n.*jx;          % derivative of spherical bessel j_n(x)
	d_jmx = (m*x).*j1mx - n.*jmx;    % derivative of spherical bessel j_n(mx)
	d_hx =  x.*h1x - n.*hx;
    
    an = ((m^2).*jmx.*d_jx - jx.*d_jmx) ./ ((m^2).*jmx.*d_hx - hx.*d_jmx);
    bn = (jmx.*d_jx - jx.*d_jmx) ./ (jmx.*d_hx - hx.*d_jmx);

    % calculate pi and tau
    [pi_n, tau_n] = mie_pt(theta, nstop);   % pi and tau will be (nmax x length(theta))
       
	p = repmat((2*n+1)./(n.*(n+1)), 1, length(theta)) .* pi_n;
	t = repmat((2*n+1)./(n.*(n+1)), 1, length(theta)) .* tau_n;
    AN = repmat(an, 1, length(theta));
    BN = repmat(bn, 1, length(theta));
	s1 = sum( AN.*p + BN.*t ).'; % transpose s1,s2 for dim agreement with bhmie
	s2 = sum( AN.*t + BN.*p ).';
    
    Q_scat = (2/x.^2) * sum((2*n+1).*(abs(an).^2 + abs(bn).^2)); % bh p103
    Q_ext = (2/x.^2) * sum((2*n+1).*real(an + bn));
        
    Q_back = (1/x.^2) * abs( sum((2*n+1).*((-1).^n).*(an-bn)) ).^2; 
    
return
    
    
function [pi_n, tau_n] = mie_pt(theta, nmax)
	% Bohren and Huffman (1983), p. 94 - 95
    % (adapted the code from Christian Matzler)
    %
    % theta (radians) should be (1 x M), where M is the number of angles to consider
    % nmax is scalar
    % pi and tau will be (nmax x M)
    
    theta = theta(:)';   % ensure that cos_theta is a row vector
    u = cos(theta);
    
    pi_n = zeros(nmax, length(u));
    tau_n = zeros(nmax, length(u));
    pi_n(1,:) = 1;
    tau_n(1,:) = u;
    pi_n(2,:) = 3*u;
    tau_n(2,:) = 3*cos(2*acos(u));
    
	for n = 3:nmax
		p1 = (2*n-1)./(n-1).*pi_n(n-1,:).*u;
		p2 = n./(n-1).*pi_n(n-2,:);
		pi_n(n,:) = p1 - p2;
		t1 = n.*u.*pi_n(n,:);
		t2 = (n+1).*pi_n(n-1,:);
		tau_n(n,:) = t1 - t2;
	end
    
return
    
    

