Activity System¶
Strategy-based activity calculations for aerosol thermodynamics using ideal, kappa-Kohler, and BAT models.
Overview¶
The activity system provides a unified interface for computing chemical activity in aerosol particles. Activity determines how species partition between gas and particle phases, controls water uptake and hygroscopic growth, and drives phase equilibria in organic-water mixtures.
This feature is built around user-facing APIs exposed via particula.particles:
ActivityIdealMolar,ActivityIdealMass- Ideal activity strategies based on Raoult's LawActivityKappaParameter- Kappa hygroscopic parameter model for water activityActivityNonIdealBinary- BAT model for non-ideal organic-water mixturesActivityIdealMolarBuilder,ActivityIdealMassBuilder, etc. - Validated, unit-aware buildersActivityFactory- Factory for selecting strategies by name
Integration with equilibria calculations is provided through particula.equilibria:
LiquidVaporPartitioningStrategy- Liquid-vapor equilibrium using activityEquilibria- Runnable wrapper for equilibria strategies
Key Benefits¶
- Consistent dynamics workflow: Use the same strategy-based API as condensation, coagulation, and wall loss
- Multiple activity models: Choose from ideal, kappa-Kohler, or BAT (non-ideal) models based on your system
- Builder/factory validation: Configure activity using unit-aware builders with automatic conversion and validation
- Equilibria integration: Combine activity strategies with liquid-vapor partitioning for thermodynamic equilibrium
- Extensible design: Add new activity models by subclassing
ActivityStrategy
Who It's For¶
This feature is designed for:
- Aerosol modelers: Computing water activity for hygroscopic growth and cloud droplet activation
- Chamber experiment analysts: Modeling organic aerosol partitioning with realistic thermodynamics
- Model developers: Implementing custom activity models while reusing particula's infrastructure
- Researchers: Comparing ideal vs. non-ideal activity effects on aerosol behavior
Capabilities¶
Unified activity API in particula.particles¶
Activity strategies are exposed alongside other particle components:
import particula as par
# Strategy classes
par.particles.ActivityIdealMolar
par.particles.ActivityIdealMass
par.particles.ActivityKappaParameter
par.particles.ActivityNonIdealBinary
# Builder classes
par.particles.ActivityIdealMolarBuilder
par.particles.ActivityIdealMassBuilder
par.particles.ActivityKappaParameterBuilder
par.particles.ActivityNonIdealBinaryBuilder
# Factory class
par.particles.ActivityFactory
All activity strategies share a common interface:
- Call
activity(mass_concentration)to compute activity from mass concentrations - Call
partial_pressure(pure_vapor_pressure, mass_concentration)to compute partial pressures
Available strategies¶
| Strategy | Description | Use Case |
|---|---|---|
ActivityIdealMolar |
Raoult's Law based on mole fractions | Simple mixtures, dilute solutions |
ActivityIdealMass |
Ideal activity based on mass fractions | Mass-based calculations |
ActivityKappaParameter |
Kappa hygroscopic parameter model | Hygroscopic growth, CCN activation |
ActivityNonIdealBinary |
BAT model for non-ideal mixtures | Organic-water aerosol thermodynamics |
Ideal activity strategies¶
For systems where activity coefficients are approximately 1, use the ideal strategies:
import numpy as np
import particula as par
# Ideal molar activity (Raoult's Law)
strategy = par.particles.ActivityIdealMolar(
molar_mass=np.array([18.015e-3, 200.0e-3]), # kg/mol: water, organic
)
# Mass concentrations (kg/m^3)
mass = np.array([0.5e-9, 0.5e-9])
# Compute activity (returns mole fractions for ideal mixing)
activity = strategy.activity(mass_concentration=mass)
Kappa parameter activity¶
For hygroscopic aerosols, the kappa parameter provides a single-parameter representation of water activity:
import numpy as np
import particula as par
# Kappa parameter strategy
strategy = par.particles.ActivityKappaParameter(
kappa=np.array([0.0, 0.61]), # water, ammonium sulfate
density=np.array([1000.0, 1770.0]), # kg/m^3
molar_mass=np.array([18.015e-3, 132.14e-3]), # kg/mol
water_index=0,
)
# Compute water activity at given composition
mass = np.array([0.7e-9, 0.3e-9]) # 70% water, 30% salt
activity = strategy.activity(mass_concentration=mass)
# activity[0] gives water activity
Non-ideal activity (BAT model)¶
For organic-water mixtures with significant non-ideality, use the BAT model:
import particula as par
# Build non-ideal activity strategy
strategy = (
par.particles.ActivityNonIdealBinaryBuilder()
.set_molar_mass(200.0e-3, "kg/mol")
.set_oxygen2carbon(0.5)
.set_density(1200.0, "kg/m^3")
.build()
)
# Compute activity
mass = np.array([0.5e-9, 0.5e-9]) # water, organic
activity = strategy.activity(mass_concentration=mass)
Builder usage patterns¶
Builders provide validated configuration with automatic unit conversion:
import numpy as np
import particula as par
# Molar activity with unit conversion
molar_activity = (
par.particles.ActivityIdealMolarBuilder()
.set_molar_mass(np.array([18.015, 200.0]), "g/mol") # converts to kg/mol
.build()
)
# Kappa activity with all parameters
kappa_activity = (
par.particles.ActivityKappaParameterBuilder()
.set_kappa(np.array([0.0, 0.61]))
.set_density(np.array([1.0, 1.77]), "g/cm^3") # converts to kg/m^3
.set_molar_mass(np.array([18.015, 132.14]), "g/mol")
.set_water_index(0)
.build()
)
Factory usage for dynamic selection¶
The factory enables runtime strategy selection by name:
import numpy as np
import particula as par
factory = par.particles.ActivityFactory()
# Select ideal molar strategy
ideal = factory.get_strategy(
strategy_type="ideal_molar",
parameters={
"molar_mass": np.array([18.015e-3, 200.0e-3]),
},
)
# Select kappa strategy
kappa = factory.get_strategy(
strategy_type="kappa",
parameters={
"kappa": np.array([0.0, 0.3]),
"density": np.array([1000.0, 1500.0]),
"density_units": "kg/m^3",
"molar_mass": np.array([18.015, 342.29]),
"molar_mass_units": "g/mol",
"water_index": 0,
},
)
Integration with equilibria¶
Activity strategies integrate with liquid-vapor partitioning calculations:
import numpy as np
import particula as par
# Create partitioning strategy
partitioning = par.equilibria.LiquidVaporPartitioningStrategy(
water_activity=0.75, # 75% RH
)
# Solve for equilibrium
result = partitioning.solve(
c_star_j_dry=np.array([1e-6, 1e-4, 1e-2]), # saturation concentrations
concentration_organic_matter=np.array([1.0, 5.0, 10.0]), # ug/m^3
molar_mass=np.array([200.0, 200.0, 200.0]), # g/mol
oxygen2carbon=np.array([0.2, 0.3, 0.5]),
density=np.array([1200.0, 1200.0, 1200.0]), # kg/m^3
)
# Access results
print(f"Partition coefficients: {result.partition_coefficients}")
print(f"Alpha phase water: {result.alpha_phase.water_concentration}")
Getting Started¶
Quick start: ideal activity calculation¶
import numpy as np
import particula as par
# 1. Create activity strategy
strategy = par.particles.ActivityIdealMolar(
molar_mass=np.array([18.015e-3, 200.0e-3]), # kg/mol
)
# 2. Define mass concentrations
mass = np.array([0.5e-9, 0.5e-9]) # kg/m^3
# 3. Compute activity
activity = strategy.activity(mass_concentration=mass)
print(f"Activity: {activity}")
# 4. Compute partial pressures
pure_pressure = np.array([3169.0, 1e-3]) # Pa
partial_p = strategy.partial_pressure(
pure_vapor_pressure=pure_pressure,
mass_concentration=mass,
)
print(f"Partial pressures: {partial_p}")
Prerequisites¶
particulaversion 0.2.6 or later installed- Basic familiarity with NumPy arrays
- Understanding of aerosol thermodynamics (helpful but not required)
Typical Workflows¶
1. Choose an activity model¶
Select the appropriate strategy based on your system:
- Simple mixtures: Use
ActivityIdealMolarorActivityIdealMass - Hygroscopic aerosols: Use
ActivityKappaParameterwith known kappa values - Organic-water mixtures: Use
ActivityNonIdealBinary(BAT model)
2. Configure with a builder¶
Use builders for validated configuration:
strategy = (
par.particles.ActivityNonIdealBinaryBuilder()
.set_molar_mass(200.0, "g/mol")
.set_oxygen2carbon(0.4)
.set_density(1.2, "g/cm^3")
.build()
)
3. Compute activity or partial pressure¶
Call the strategy methods with mass concentration arrays:
activity = strategy.activity(mass_concentration=mass)
partial_p = strategy.partial_pressure(pure_vapor_pressure, mass_concentration=mass)
4. Integrate with equilibria¶
Combine with partitioning strategies for full thermodynamic calculations:
partitioning = par.equilibria.LiquidVaporPartitioningStrategy(
water_activity=target_rh,
)
result = partitioning.solve(...)
Use Cases¶
Use case 1: Hygroscopic growth calculation¶
Scenario: Calculate water activity for ammonium sulfate aerosol at different water contents.
Solution: Use ActivityKappaParameter with known kappa values and compute activity across a range of compositions.
Use case 2: Organic aerosol partitioning¶
Scenario: Model gas-particle partitioning of organic compounds using realistic non-ideal thermodynamics.
Solution: Use ActivityNonIdealBinary with BAT model parameters, then integrate with LiquidVaporPartitioningStrategy for equilibrium calculations.
Use case 3: Comparing activity models¶
Scenario: Evaluate the effect of non-ideal activity on partitioning predictions.
Solution: Create both ideal and non-ideal strategies, compute activity at the same compositions, and compare results.
Configuration¶
Strategy Parameters¶
| Strategy | Parameter | Description | Units |
|---|---|---|---|
ActivityIdealMolar |
molar_mass |
Species molar masses | kg/mol |
ActivityIdealMass |
(none) | No parameters required | - |
ActivityKappaParameter |
kappa |
Hygroscopic parameters | dimensionless |
density |
Species densities | kg/m^3 | |
molar_mass |
Species molar masses | kg/mol | |
water_index |
Index of water species | int | |
ActivityNonIdealBinary |
molar_mass |
Organic molar mass | kg/mol |
oxygen2carbon |
O:C ratio | dimensionless | |
density |
Organic density | kg/m^3 |
Factory Strategy Types¶
| Type Name | Strategy Class |
|---|---|
"ideal_mass" |
ActivityIdealMass |
"ideal_molar" |
ActivityIdealMolar |
"kappa" |
ActivityKappaParameter |
"non_ideal_binary" |
ActivityNonIdealBinary |
Best Practices¶
- Match model to system: Use ideal strategies for simple mixtures, kappa for inorganic hygroscopic aerosols, and BAT for organic-water systems
- Use builder validation: Set parameters through builders to ensure unit conversion and validity checks
- Check activity ranges: Activity values should be in [0, 1] for condensed phases
- Consider temperature effects: The BAT model includes temperature-dependent parameters; ensure consistency
- Validate with experiments: Compare model predictions against measured hygroscopic growth or partitioning data
- Use consistent units: Mass concentrations are expected in kg/m^3; use builders for automatic conversion
Limitations¶
- Binary organic-water only:
ActivityNonIdealBinaryassumes a binary organic-water system; multi-organic mixtures use mean properties - No solid-liquid equilibria: Current strategies handle liquid-vapor systems only
- Temperature range: BAT model parameters are optimized for ambient temperatures (250-310 K)
- Kappa model assumptions: Assumes volume additivity and spherical particles
Related Documentation¶
- Theory: Activity Theory - Mathematical foundations
- Theory: Equilibria Theory - Partitioning equations
- Examples: Activity Examples - Working code examples
- Tutorial: Activity Tutorial - Interactive notebook
FAQ¶
Which activity model should I use?¶
- For dilute aqueous solutions:
ActivityIdealMolar(Raoult's Law) - For hygroscopic inorganics:
ActivityKappaParameterwith measured kappa values - For organic aerosols:
ActivityNonIdealBinary(BAT model)
How do I get activity coefficients?¶
Activity = activity coefficient x mole fraction. For ideal strategies, the activity coefficient is 1. For non-ideal strategies, you can compute activity coefficients by dividing activity by mole fraction.
Can I use custom activity models?¶
Yes. Subclass ActivityStrategy from particula.particles.activity_strategies and implement the activity() and partial_pressure() methods.
How does activity connect to equilibria?¶
Activity determines the effective concentration that drives phase equilibrium. The LiquidVaporPartitioningStrategy uses BAT model activity internally to compute gas-particle partitioning.