Inverse Models
Size Distribution Inversion
Theory
The size distribution can be found from the inverse of the response function using Tikhonov regularization.
$L_1$ and $L_2$ are the Euclidian norms of the solution and the intial guess.
$L_1 = \left\lVert \bf{A}\rm{π} - \rm{π£}\right\rVert_2$
$L_2 = \left\lVert\bf{L}(\rm{π} - \rm{π_i})\right\rVert_2$
where $\rm{π}$ is the true size distribution, $\bf{A}$ is the convolution matrix, π£ is the measured response vector, $\bf{L}$ is a weights matrix, and $\rm{π_i}$ is an initial guess. To solve for the inverse, a balance is sought between the $L_1$ and $L_2$ norms.
$π_{inv} = \arg \min\{L_1^2 + \lambda^2 L_2^2\}$
where $\lambda$ is the regularization parameter. Taking $\bf{L} = \bf{I}$ (weight matrix equals the identity Matrix π) and $\rm{π_i} = \bf{S}^{-1}\rm{π£}$ as initial guess (Matrix π), the regularized inverse is computed via:
$π_{inv} = (\bf{A}^{\rm{T}}\bf{A} + \lambda^{\rm{2}} \bf{I})^{\rm{-1}}(\bf{A}^{\rm{T}} \rm{π£} + \lambda^2\bf{S}^{-1} \rm{π£})$
The regularization parameter $\lambda$ "interpolates" between the noisy least-square inverse ($\lambda = 0$) and the initial guess ($\lambda >> 1$). The optimal regularization parameter is found using the L-curve method. The optimal $\lambda_{opt}$ is found using the L-curve method. The L-curve is defined as a plot of $\log(L_1)$ vs. $\log(L_2)$, where $L_1$ and $L_2$ are obtained for a series of discrete $\lambda$ values. The $\lambda_{opt}$ is found at the corner of the L-curve, which is mathematically defined as the point where where the curvature of the L-curve is maximum. Here, the corner of the L-curve is found using the iterative algorithm described in Talukdar and Swihart (2003). The curvature is calculated using Eq. (14) in Hansen (2000), which requires the first and second derivatives of $d\ln(L_i)^2/d\lambda$. These derivatives of $d\ln(L_i)^2/d\lambda$ are estimated numerically.
See session 3 of the Tutorial for an interactive explanation on how Tikhonov regularization works.
Example
The L-curve search method is implemented in the rinv function. Also check out the new rinv2 function, which has much faster performance and is based on generalized cross validation. It also allows to specify higher order inversions. The default implementation gives near identical results to rinv.
πβ±βΏα΅ = rinv(π£.N, Ξ΄, Ξ»β=0.1, Ξ»β=1.0);
The function takes the response vector to be inverted, the DMA grid to read the matrices, and an upper and lower search bound for the optimal regularization parameter.
df = CSV.read("example_data.csv", DataFrame)
t, p, lpm = 293.15, 940e2, 1.666e-5
rβ, rβ, l = 9.37e-3,1.961e-2,0.44369
Ξ = DMAconfig(t,p,1lpm,4lpm,rβ,rβ,l,0.0,:+,6,:cylindrical)
Ξ΄ = setupDMA(Ξ, vtoz(Ξ,10000), vtoz(Ξ,10), 120)
π£ = (df,:Dp,:Rcn,Ξ΄) |> interpolateDataFrameOntoΞ΄
πβ±βΏα΅ = rinv(π£.N, Ξ΄, Ξ»β=0.1, Ξ»β=1.0)
πβ±βΏα΅Β² = rinv2(π£.N, Ξ΄, Ξ»β=0.1, Ξ»β=1.0)
The file example_data.csv
is a comma delimited text files that contains diameter and a resonse vector. The function interpolateDataFrameOntoΞ΄ takes the columns :Dp and :Rcn from the DataFrame df and creates a response distribution of the type SizeDistribution that matches the DMA grid Ξ΄. Finally, πβ±βΏα΅ is computed using the rinv function.
The method was compared to the inverted size distribution given by the manufacturer Aerosol Instrument Manager (AIM) software, assuming no diffusion correction in either method. Figure 3 in the manuscript shows excellent correspondence between this package and the commercial software.
CCN Inversion
Size resolved CCN measurements have a long history (e.g. Cruz and Pandis, 1997, Snider et al., 2006). Particles are typically dried, charge neutralized, and passed through the DMA.At the exit, the flow is split between a CPC that measures all particles and a CCN counter that measures particles that form cloud droplets at a water supersaturation set by the instrument. In this configuration the DMA voltage can either be stepped or continuously scanned. The ratio of CCN-to-CPC response function is used to determine the fraction of particles that activate at a given diameter. The diameter where 50% of the particles activate is taken to be the activation diameter. The activation of particles into cloud droplets is proportional to the volume of solute in the particle. Therefore, larger multiply charged particles activate first. This leads to a bias in the inferred D50 diameter if the activated fraction is computed from the ratio of the raw response functions (Petters et al., 2007, 2009).
The CCN transmission function is modeled using a cumulative Gauss integral
$T_{af} = \frac{1}{2}\left[1 + \mathrm{erf}\left(\frac{d-\mu}{\sigma}\right) \right]$
This function is applied to the mobility size distribution. Then the response function is computed. Empirically, activated fraction can be computed using from the ratio of size distributions and response functions.
To predict the ratio of π£αΆαΆβΏ/π£αΆβΏ in terms of the activated fraction model Taf:
$π^{\mathrm{cn}} = (\bf{A}^{\rm{T}}\bf{A} + \lambda^{\rm{2}} \bf{I})^{\rm{-1}}(\bf{A}^{\rm{T}} \rm{π£^{\mathrm{cn}}} + \lambda^2 \bf{S}^{-1} \rm{π£^{\mathrm{cn}}})$
$\left( \frac{π£^{\mathrm{ccn}}}{π£^{\mathrm{cn}}} \right)_{\mathrm{model}} = \frac{\mathbf{A}[T_{af}\; .*\; π^{\mathrm{cn}}]}{\mathbf{A}π^{\mathrm{cn}}}$
This mirrors the approach in Petters et al. (2007). The model + fit can be solved using this package as follows.
παΆβΏ = (π'π + Ξ»^2π)^(-1) * (π'π£αΆβΏ + Ξ»^2 * π^(-1)*π£αΆβΏ)
model(x,p) = (Ξ΄.π*(παΆβΏ.N.*Taf(παΆβΏ, p[1], p[2])))./(Ξ΄.π*παΆβΏ.N)
fit = curve_fit(model, Ξ΄.Dp, π£αΆαΆβΏ.N./π£αΆβΏ.N, [65.0, 3.0])
The example below includes a hidden threholding step. (See complete example in the examples folder) Thresholding is performed for bins with low counts, which results in NaN and Inf in ππ. This is necessary because at low concentrations a bin may have zero or very low concentration, resulting in unrealistic or NaN/InF values in the activated fraction array. Thus if counts/concentration is below the threshold, the activated fraction is forced to one for large diameters and zero for small diameters. The noise threshold may need to be adjusted for different datasets.
The code loads the CCN (π£αΆαΆβΏ) and CN (π£αΆβΏ) response functions from file. The activated fraction is computed through the ratio of the distributions using one of the SizeDistribution Number Operators.
ππ = π£αΆαΆβΏ/π£αΆβΏ
And here is the complete example showing how to fit the ππ response curve.
t, p, lpm = 293.15, 940e2, 1.666e-5
rβ, rβ, l = 9.37e-3,1.961e-2,0.44369
Ξ = DMAconfig(t,p,1lpm,4lpm,rβ,rβ,l,0.0,:+,6,:cylindrical)
Ξ΄ = setupDMA(Ξ, vtoz(Ξ,10000), vtoz(Ξ,10), 120)
# Load a simple comma delimited text file - file contains :Dp, :Rcn, :Rccn
df = CSV.read("example_data.csv", DataFrame)
π£αΆβΏ = (df,:Dp,:Rcn,Ξ΄) |> interpolateDataFrameOntoΞ΄ # CN response distribution
π£αΆαΆβΏ = (df,:Dp,:Rccn,Ξ΄) |> interpolateDataFrameOntoΞ΄; # CCN response distribution
ππ = π£αΆαΆβΏ/π£αΆβΏ
Taf(π,ΞΌ,Ο) = @. 0.5 * (1.0 + erf((π.Dp - ΞΌ)./(sqrt(2.0Ο))))
π, π, π, Ξ» = Ξ΄.π, Ξ΄.π, Ξ΄.π, 0.5
παΆβΏ = (π'π + Ξ»^2π)^(-1) * (π'π£αΆβΏ + Ξ»^2 * π^(-1)*π£αΆβΏ)
model(x,p) = (π * (παΆβΏ.N .* Taf(παΆβΏ, p[1], p[2])))./( π * παΆβΏ.N)
fit = curve_fit(model, ππ.Dp, ππ.N, [65.0, 3.0])
Ax = fit.param
afmodel = model(Ξ΄.Dp, Ax)
Tandem DMA Inversion
A complete example for tandem DMA inversion is provided in inversion3.jl
in the examples folder, which reproduces Figure 3 in Petters (2021).
Briefly, the code for inversion contains these key features:
Ξβ, Ξβ, Ξ΄β, Ξ΄β = initializeDMAs(Dd, k)
Ax = [[1300.0, 60.0, 1.4], [2000.0, 200.0, 1.6]]
παΆβΏ = DMALognormalDistribution(Ax, Ξ΄β)
gf, ge, π = TDMAmatrix(παΆβΏ, Dd, Ξβ, Ξβ, Ξ΄β, k)
model = TDMA1Dpdf(παΆβΏ, Ξβ, Ξβ, (Dd, 0.8, 5.0, k));
The initializeDMAs sets up the grids for DMA 1 and 2, Ax are the parameters for the assumed size distribution, παΆβΏ is the instantiation of that size distribution. gf, ge, and π are the growth factor bin midpoints, growth factor bin edges and the convolution matrix, and model is the forward model function.
The code below is to invert the data. xβ is the initial guess, lb,ub the lower and ope bounds, and xΞ»1 and xΞ»2 are the inverted solutions for the two main methods stated in the manuscript.
xβ = N1./sum(N1)
lb, ub = zeros(k), ones(k)
xΞ»1 = invert(π, N1, LβxβB(2, xβ, lb, ub))
e1 = @> sqrt.(sum((xΞ»1 .- f).^2.0)./k) round(digits = 3)
xΞ»2 = invert(π, N1, LβDβB(0, 0.001, lb, ub))
e2 = @> sqrt.(sum((xΞ»2 .- f).^2.0)./k) round(digits = 3)