FundamentalsWorking with Impurities

Working with Impurities

BioSNICAR models four built-in light-absorbing particle (LAP) types that can be mixed into any ice layer. Each has distinct spectral properties and uses consistent naming throughout the API.

Built-in impurity types

NameKeyUnitSpectral signature
Black carbonblack_carbonppbStrong broadband absorption, especially in visible
Snow algaesnow_algaecells/mLVisible absorption with carotenoid and chlorophyll features
Glacier algaeglacier_algaecells/mLVisible absorption with carotenoid and chlorophyll features
Mineral dustdustppbWeak, spectrally flat visible absorption

These names work everywhere — in run_model(), parameter_sweep(), Emulator.build(), and retrieve().

Setting concentrations

Scalar (surface layer only)

from biosnicar import run_model
 
outputs = run_model(black_carbon=5000, glacier_algae=50000)

Per-layer list

outputs = run_model(glacier_algae=[40000, 10000, 0])

Combining multiple impurities

outputs = run_model(
    black_carbon=5000,
    glacier_algae=50000,
    dust=1000,
)

Impact on albedo

How different impurities affect the spectral albedo

Impurities primarily affect visible wavelengths (0.3–0.7 µm). Black carbon has the strongest effect per unit mass due to its high mass absorption coefficient. Algae show characteristic absorption features from photosynthetic pigments. Dust has a relatively flat, weak spectral signature, making it difficult to distinguish spectrally from other darkening agents at typical environmental concentrations.

Optical property files

Each impurity key in inputs.yaml points to a specific optical property dataset inside the consolidated archive data/OP_data/480band/lap.npz. The defaults are:

KeyDefault fileDescription
black_carbonbc_ChCB_rn40_dns1270.npzChang & Charalampopoulos (1990), r=40 nm, density 1270 kg/m³
snow_algaesnow_algae_empirical_Chevrollier2023.npzEmpirical measurements from Chevrollier et al. (2023)
glacier_algaeice_algae_empirical_Chevrollier2023.npzEmpirical measurements from Chevrollier et al. (2023)
dustdust_greenland_Cook_CENTRAL_20190911.npzGreenland Ice Sheet mid-ablation zone, central estimate

These are sensible defaults, but the lap.npz archive ships with 40 optical property datasets that you can swap in depending on your study site or research question.

Available datasets

Black carbon and brown carbon (5 variants):

File stemDescription
bc_ChCB_rn40_dns1270Black carbon, Chang & Charalampopoulos (1990) (default)
brC_Kirch_BCsdBrown carbon, Kirchstetter et al.
brC_Kirch_BCsd_slfcotBrown carbon, sulfate-coated
mie_sot_ChC90_dns_1317Mie soot, density 1317 kg/m³
miecot_slfsot_ChC90_dns_1317Mie soot, sulfate-coated

Mineral dust (24 variants):

File stemDescription
dust_greenland_Cook_CENTRAL_20190911Greenland, central estimate (default)
dust_greenland_Cook_HIGH_20190911Greenland, high absorption estimate
dust_greenland_Cook_LOW_20190911Greenland, low absorption estimate
dust_greenland_central_size1size5Greenland, 5 size bins
dust_balkanski_central_size1size5Balkanski et al., 5 size bins
dust_skiles_size1size5Skiles et al., 5 size bins
dust_mars_size1size5Martian dust, 5 size bins

Volcanic ash (6 variants):

File stemDescription
volc_ash_eyja_central_size1size5Eyjafjallajökull ash, 5 size bins
volc_ash_mtsthelens_20081011Mount St. Helens ash

Algae (5 variants):

File stemDescription
snow_algae_empirical_Chevrollier2023Snow algae, empirical (default for snow_algae)
ice_algae_empirical_Chevrollier2023Glacier algae, empirical (default for glacier_algae)
Cook2020_glacier_algae_4_40Cook et al. (2020), 4–40 µm cells
Glacier_Algae_ISIn situ glacier algae measurements
snw_alg_r025um_chla020_chlb025_cara150_carb140Bio-optical model output

Swapping optical properties

To use a different dataset, change the FILE field in inputs.yaml. For example, to switch from the default Greenland dust to Skiles dust:

IMPURITIES:
  dust:
    FILE: "dust_skiles_size3.npz"   # was: dust_greenland_Cook_CENTRAL_20190911.npz
    COATED: False
    UNIT: 0
    CONC: [0, 0]

Or to use sulfate-coated brown carbon instead of uncoated black carbon:

IMPURITIES:
  black_carbon:
    FILE: "brC_Kirch_BCsd_slfcot.npz"
    COATED: True        # use coated extinction coefficients
    UNIT: 0
    CONC: [0, 0]

The FILE value (minus .npz) must match a stem in lap.npz. To see all available stems programmatically:

import numpy as np
 
lap = np.load("data/OP_data/480band/lap.npz", allow_pickle=False)
print(lap["_names"])

Each stem stores three spectral arrays (480 values each): mass extinction coefficient (ext_cff_mss or ext_xsc for cell-count-based impurities), single-scattering albedo (ss_alb), and asymmetry parameter (asm_prm).

YAML fields reference

FieldValuesMeaning
FILEAny stem in lap.npz + .npzWhich optical property dataset to use
COATEDTrue / FalseUse coated-particle extinction coefficients
UNIT0 = ppb (mass), 1 = cells/mLHow concentration values are interpreted
CONClist of numbersDefault concentration per layer

Bio-optical model

BioSNICAR includes a bio-optical module (biosnicar/biooptical/) for computing algal optical properties from pigment concentrations. This is useful when empirical optical properties are not available for your algal species.

Two cell geometries are supported:

  • Spherical cells (Mie theory) — typical for snow algae
  • Cylindrical cells (geometric optics) — typical for glacier algae (long chains of cells)

The model takes intracellular pigment concentrations, cell size, and density, and produces optical property files that can be loaded into BioSNICAR. Most users will use the default empirical optical properties that ship with the repository.

Adding new impurity types

To add a particle type not included in the 40 shipped datasets:

  1. Compute spectral optical properties (MAC, single-scattering albedo, asymmetry parameter) at 480 wavelengths
  2. Add it to the LAP archive (data/OP_data/480band/lap.npz) using the build script in scripts/build_consolidated_npz.py
  3. Add an entry to inputs.yaml:
    IMPURITIES:
      my_new_impurity:
        FILE: "my_impurity_file.npz"
        COATED: False
        UNIT: 0          # 0 = ppb (mass), 1 = cells/mL (count)
        CONC: [0, 0]     # default concentration per layer
  4. Use the YAML key as the parameter name everywhere:
    run_model(my_new_impurity=500)
    parameter_sweep(params={"my_new_impurity": [0, 100, 1000]})