Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Wall loss fitting prelim #427

Merged
merged 14 commits into from
Jan 16, 2024
1 change: 1 addition & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ parts:
sections:
- file: examples/wall_loss/chamber_smps_data
- file: examples/wall_loss/wall_loss_forward_simulation
- file: examples/wall_loss/forward_fit_simple
- file: examples/lagrangian/lagrangian_intro
sections:
- file: examples/lagrangian/basic_lagrangian_box
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/wall_loss/chamber_smps_data.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
"metadata": {},
"outputs": [],
"source": [
"# 1 convert to dn/dlogDp\n",
"# 1 convert to dn/dDp\n",
"stream_smps_2d.data = convert.convert_sizer_dn(\n",
" diameter=np.array(stream_smps_2d.header, dtype=float),\n",
" dn_dlogdp=stream_smps_2d.data,\n",
Expand Down
646 changes: 646 additions & 0 deletions docs/examples/wall_loss/forward_fit_simple.ipynb

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions docs/examples/wall_loss/ktp_fits.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
ktp_fits
9.114052578201235377e+00
1.056410118397569153e+00
8.603020104153245029e-01
7.286903885282755011e-01
6.143790155101150896e-01
4.683403011824088802e-01
2.261290201180816417e-01
7.938569470737081302e-01
1.236364213294667697e-01
2.037340385477289517e-01
4.034193294551781328e+00
9.682521668505555956e-02
3.843420712626977043e-01
3.079963755986986906e-01
2.090019848554948989e-01
1.864405270290740019e-02
3.500866924013069648e-01
1.996353182015291050e-01
3.041341740204304145e-01
1.749759101214403978e-01
1.688639371712058745e-01
5.139506188290942079e-01
3.359766187966383710e-01
3.015341445928835795e-01
2.662682003934179753e-01
2.973109238698287693e-01
4.444325626562330434e-01
3.505578700593284247e-01
12 changes: 6 additions & 6 deletions docs/examples/wall_loss/wall_loss_forward_simulation.ipynb

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions particula/util/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,3 +547,42 @@ def data_shape_check(
raise ValueError("Header list must be a single entry if data_new \
is 1D.")
return data


def distribution_convert_pdf_pms(
x_array: np.ndarray,
distribution: np.ndarray,
to_pdf: bool = True
) -> np.ndarray:
"""
Convert between a probability density function (PDF) and a probability
mass spectrum (PMS) based on the specified direction.

Args:
x_array
An array of radii corresponding to the bins of the distribution,
shape (m).
distribution
The concentration values of the distribution (either PDF or PMS)
at the given radii. Supports broadcasting across x_array (n,m).
to_PDF
Direction of conversion. If True, converts PMS to PDF. If False,
converts PDF to PMS.

Returns:
converted_distribution
The converted distribution array (either PDF or PMS).
"""

# Calculate the differences between consecutive x_array values for bin
# widths.
delta_x_array = np.empty_like(x_array)
delta_x_array[:-1] = np.diff(x_array)
# For the last bin, extrapolate the width assuming constant growth
# rate from the last two bins.
delta_x_array[-1] = delta_x_array[-2]**2 / delta_x_array[-3]

# Converting PMS to PDF by dividing the PMS values by the bin widths. or
# Converting PDF to PMS by multiplying the PDF values by the bin widths.
return distribution / delta_x_array if to_pdf \
else distribution * delta_x_array
36 changes: 36 additions & 0 deletions particula/util/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,39 @@ def mask_outliers(
# invert the mask to get true= non-outliers and false=outliers
mask = np.logical_not(mask)
return mask


def distribution_integration(
distribution: np.ndarray,
x_array: Optional[np.ndarray] = None,
axis: int = 0
) -> np.ndarray:
"""
Performs either PDF integration or PMS integration based on the input.
This function supports broadcasting where x_array has shape (m,) and
distribution has shape (n, m).

Args:
-----
distribution: The distribution array to integrate.
It should have a shape of (n, m).
x_array: The x-values array for PDF
integration. It should have a shape of (m,).
If None, PMS integration is performed. Defaults to None.
axis: The axis along which to perform the integration
for PDF or the sum for PMS.
Defaults to 0.

Return:
-------
np.ndarray: The result of the integration. If PDF integration is
performed, the result will have a shape of (n,) if axis=0 or (m,)
if axis=1. If PMS integration is performed, the result will be a
single value if axis=None, or an array with reduced dimensionality
otherwise.
"""
if x_array is not None:
# Perform PDF integration along the specified axis
return np.trapz(y=distribution, x=x_array, axis=axis)
# Perform PMS integration
return np.sum(distribution, axis=axis)