Skip to content

Post-Processing Functions Tutorial

AeroViz exposes its post-processing as a flat set of top-level functions, grouped into four namespaces — chemistry, optical, size, and voc. Each call is self-contained: it takes a DataFrame (or a few), runs one calculation, and returns a DataFrame or dict.

Legacy API deprecated

The old DataProcess(...) factory class — e.g. dp = DataProcess('Chemistry', Path('./output')) followed by dp.ReConstrc_basic(df_chem) — still exists but is deprecated and will be removed in a future release. New code should use the top-level functions described on this page. The functions take exactly the same inputs and return the same results — they just skip the constructor boilerplate and the path_out argument. If you want a CSV, call .to_csv() on the returned DataFrame yourself.

Basic Usage

from AeroViz import reconstruct_mass, mie, psd_distributions

# Each call is independent — no need to pre-instantiate a processor
result = reconstruct_mass(df_chem)
ext = mie(df_pnsd, df_RI, wavelength=550)
psd = psd_distributions(df_pnsd)

You can also import each function from its namespace:

from AeroViz import chemistry, optical, size, voc

result = chemistry.reconstruct_mass(df_chem)
ext    = optical.mie(df_pnsd, df_RI, wavelength=550)

Function Overview

Namespace Functions
chemistry reconstruct_mass, split_oc_ec, partition_ratios, isoropia, volume_ri, kappa, growth_factor
optical optical_basic, improve, mie, gas_extinction, retrieve_ri, brown_carbon
size psd_stats, psd_distributions, merge_psd
voc voc_potentials

Size Distribution

Basic Statistics

from AeroViz import psd_stats

result = psd_stats(df_pnsd)
# result['number']   - Number distribution
# result['surface']  - Surface area distribution
# result['volume']   - Volume distribution
# result['other']    - Mode statistics

Number / Surface / Volume Distributions

from AeroViz import psd_distributions

dists = psd_distributions(df_pnsd)
# dists['number'], dists['surface'], dists['volume']
# dists['properties'] - concatenated GMD/GSD/mode per weighting

SMPS-APS Merging

from AeroViz import merge_psd

# v4 (recommended, requires PM2.5 reference)
result = merge_psd(smps_data, aps_data, df_pm25=pm25_data, version=4)

merged   = result['data']            # recommended merged dN/dlogDp (every version)
density  = result['density']         # estimated effective density (g/cm³)
# v3/v4 variants: result['data_dn'], result['data_dndsdv'], result['data_cor_dn']

version selects the algorithm: 1 (original power-law), 2 (simplified), 3 (dN/dS/dV refinement), 4 (PM2.5 fitness, default and recommended). v4 requires df_pm25.

Using the SizeDist Class

For per-row distribution conversions (extinction, dry PSD, lung deposition), use the SizeDist class directly:

from AeroViz.dataProcess.SizeDistr import SizeDist

psd = SizeDist(df_pnsd, state='dlogdp', weighting='n')

# Distribution conversion
surface    = psd.to_surface()
volume     = psd.to_volume()
extinction = psd.to_extinction(df_RI, method='internal')
dry        = psd.to_dry(df_gRH)

# Statistics
props = psd.properties()
stats = psd.mode_statistics()

# Lung deposition (ICRP 66)
lung = psd.lung_deposition(activity='light')

Chemistry

Mass Reconstruction

from AeroViz import reconstruct_mass

result = reconstruct_mass(df_chem, df_ref=df_pm25)
# result['mass']        - Reconstructed mass (AS, AN, OM, Soil, SS, EC, total)
# result['volume']      - Component volumes (*_volume + total_dry)
# result['NH4_status']  - Ammonium status DataFrame ('ratio', 'status'); status is Enough / Deficiency
# result['RI_550']      - Refractive index at 550 nm (RI_dry, RI_wet)
# result['density_rec'] - Reconstructed density

Volume and Refractive Index

from AeroViz import volume_ri

ri = volume_ri(df_volume, df_alwc=df_alwc)
# Columns: n_dry, k_dry, n_amb, k_amb, gRH

Hygroscopicity (kappa)

from AeroViz import kappa, growth_factor

gf  = growth_factor(df_volume, df_alwc)        # gRH = (V_wet / V_dry)^(1/3)
kap = kappa(df_data, diameter=0.5)             # df_data needs gRH, AT, RH

Gas-Particle Partitioning

from AeroViz import partition_ratios

ratios = partition_ratios(df_data)
# SOR, NOR, NOR_2, NTR, epls_SO42-, epls_NO3-, epls_NH4+, epls_Cl-

OC / EC Split

from AeroViz import split_oc_ec

result = split_oc_ec(df_lcres, df_mass=df_pm25)
# result['basic']  - OC/EC + POC/SOC/WSOC/WISOC + status flags
# result['ratio']  - Per-species PM / OC ratios

ISORROPIA II

from pathlib import Path
from AeroViz import isoropia

# Keeps path_out: ISORROPIA shells out to a Windows binary
result = isoropia(df_ions, df_met, path_out=Path('./isoropia_run'))
# result['input'], result['output'] (pH, ALWC, gas/aerosol partitioning)

Optical

Basic Optical Properties

from AeroViz import optical_basic

basic = optical_basic(df_sca, df_abs, df_mass=df_mass, df_no2=df_no2, df_temp=df_temp)
# Derived columns: extinction, SSA, MEE, MSE, MAE, Ångström exponents, etc.

IMPROVE Extinction

from AeroViz import improve

# df_RH must be a Series (e.g. met['RH']), not a single-column DataFrame.
result = improve(df_mass, df_RH, method='revised')
# method = 'revised' | 'modified' | 'localized'
# result['dry'], result['wet'], result['ALWC'], result['fRH']
# Expected: result['dry'] / result['wet'] have columns
#   AS, AN, OM, Soil, SS, EC, total  (lowercase 'total' = the per-species sum)
result['dry']['total'].mean()    # mean total dry extinction (Mm-1)

Mie Calculation

from AeroViz import mie

# Single-material RI (Series of complex numbers)
ext = mie(df_pnsd, df_RI_complex, wavelength=550)
# Columns: extinction, scattering, absorption (Mm⁻¹)

# Species mixing-table RI (DataFrame with *_volume_ratio columns)
ext = mie(df_pnsd, df_mix_table, wavelength=550, mixing='internal')
# mixing = 'internal' | 'external' | 'both'

# Per-bin distribution instead of totals
dext = mie(df_pnsd, df_RI_complex, wavelength=550, distribution=True)

mie replaces the legacy Mie / extinction_distribution / extinction_full triplet. Behavior is controlled by the shape of ri and the mixing / distribution keywords.

Gas Extinction

from AeroViz import gas_extinction

g = gas_extinction(df_no2, df_temp)
# Columns: ScatteringByGas, AbsorptionByGas, ExtinctionByGas

Refractive Index Retrieval

from AeroViz import retrieve_ri

ri = retrieve_ri(df_optical, df_pnsd, dlogdp=0.014, wavelength=550)
# Columns: re_real, re_imaginary

Brown Carbon Separation

from AeroViz import brown_carbon

bc_brc = brown_carbon(df_abs, ref_wavelength=880, aae_bc=1.0)
# Splits multi-wavelength absorption into BC vs BrC components

VOC

from AeroViz import voc_potentials

result = voc_potentials(df_voc)
# result['Conc']  - mass concentration per species (ug/m3)
# result['OFP']   - Ozone Formation Potential per species (ug O3/m3)
# result['SOAP']  - SOAP per species
# result['LOH']   - OH-reactivity per species
# Each frame also has per-class '*_total' columns and a grand 'Total' column,
# so the grand total OFP is result['OFP']['Total'].

Input Format Requirements

Size Distribution

# Columns are particle diameters (nm)
df_pnsd.columns = [11.8, 13.6, 15.7, ..., 523.3]

# Index is time
df_pnsd.index = DatetimeIndex

Chemical Composition

# Required columns
columns = [
    'SO42-', 'NO3-', 'NH4+',      # Ions
    'OC', 'EC',                    # Carbon
    'Na+', 'Cl-',                  # Sea salt
    'Al', 'Fe', 'Ti',              # Crustal elements
    'PM25'                         # Mass
]

VOC

# Columns are species names
df_voc.columns = ['Benzene', 'Toluene', 'Ethylbenzene', ...]

# Units: ppb or ug/m3

Output Handling

The new functions return DataFrames or dicts of DataFrames; they do not write files. If you want CSVs, call .to_csv() yourself:

result = reconstruct_mass(df_chem)
result['mass'].to_csv('./output/mass.csv')

(Exception: isoropia still keeps path_out, because the underlying calculation shells out to a Windows binary that reads/writes temp files on disk.)