Skip to content

How to set up an aftertreatment chain

An aftertreatment chain is a series of pipes downstream of the exhaust manifold, each carrying a different reactive closure: DOC for HC / CO oxidation, DPF for soot trap + regen, SCR for NOx reduction with urea injection. In aeolus1d each element is a single pipe. The reaction kinetics live in that pipe's [pipe.species] block (the reaction kind), while the thermal / mechanical model of the brick lives in a [pipe.catalyst] (gas + monolith-wall heat) and/or [pipe.filter] (soot trap + cake) sub-block — the chain is just the connection topology.

This tutorial wires a four-element chain (DOC → DPF → SCR → tail pipe) and shows where to set the kinetics knobs that ship today.

What you'll build

[exhaust manifold] → [DOC] → [DPF] → [SCR] → [tail pipe] → outlet BC
                                       ↑
                              urea injector (in-pipe source)

Each element is a pipe; the joins are junctions (kind = "passthrough" for a simple in-line join, or kind = "plenum" for a volume that can also split flow). The inlet feed for the chain is the engine's exhaust manifold — for this tutorial we'll replace it with a transient_mass_flow_inlet BC so the chain can be exercised in isolation.

Step 1 — geometry + species

[case]
name = "aftertreatment_chain"
t_end = 0.1
cfl = 0.4

[gas]
gamma = 1.33      # exhaust mixture, hotter than dry air
R_gas = 290.0

[[pipe]]
id = "doc_brick"
length = 0.12
n_cells = 24
diameter = 0.10
  [pipe.init]
  p = 1.05e5
  T = 700.0
  u = 10.0
  [pipe.species]
  name = "HC"          # primary column — the DOC's oxidised reactant
  Y_init = 5.0e-4
    [[pipe.species.extras]]
    name = "CO"
    Y_init = 2.0e-3

Species columns are declared per pipe: a single primary (name + Y_init) plus zero or more [[pipe.species.extras]] tables, each with its own name and Y_init. Columns are matched by name as gas crosses junctions, so a species only needs to appear on the pipes that carry it.

Each reactive brick expects a specific primary species — HC for the DOC (doc_oxidation), NH3 for the SCR (nh3_scr_kinetics) — so the bricks do not share one identical species block. Give each pipe the columns its own reaction reads; the bundled examples (46_doc.toml, 42_scr_urea_injector.toml) show the exact set for each.

Step 2 — DOC closure

The DOC is a two_phase_heat monolith (gas + solid-wall thermal mass) whose oxidation kinetics are set on [pipe.species] via reaction = "doc_oxidation" — a simultaneous HC + CO Arrhenius light-off (CO lights first, ~150 °C; HC ~250 °C):

  [pipe.catalyst]
  kind = "two_phase_heat"     # gas + monolith wall thermal
  rho_s_cs = 5.0e5            # ρ_s·c_s of the washcoat [J/(m³·K)]
  a_v = 4000.0               # specific surface area [m²/m³]
  h = 150.0                 # gas–solid heat transfer [W/(m²·K)]
  T_solid_init = 700.0

  [pipe.species]
  name = "HC"
  Y_init = 5.0e-4
  reaction = "doc_oxidation"
  A_hc_ox = 1.0e9            # HC branch (~250 °C light-off on Pt/Pd)
  Ea_hc_ox = 1.0e5
  LHV_hc = 43.5e6
  A_co_ox = 5.0e9            # CO branch (~150 °C)
  Ea_co_ox = 7.5e4
  LHV_co = 1.01e7
    [[pipe.species.extras]]
    name = "CO"
    Y_init = 2.0e-3

Instead of the explicit (rho_s_cs, a_v, h) datasheet you can give a monolith geometry spec and let aeolus1d resolve the thermal parameters from cell density and substrate — set cpsi, ofa and substrate (e.g. "cordierite") under kind = "two_phase_heat_var_nu". Supplying both forms at once is an error. See 74_twc.toml for the geometry form.

For a full elementary surface mechanism (rather than the bundled lumped kinetics) use kind = "mechanism" with mechanism_path pointing at a CHEMKIN .inp or Cantera .yaml/.yml file on disk plus an optional surface_init table of initial coverages. There is no aeolus1d://… pseudo-URI — mechanism_path is a real file path resolved against the process working directory.

Step 3 — DPF closure

The DPF is a [pipe.filter] of kind diesel_particulate_filter: a trap that pulls a PM species column out of the gas, a cake Darcy-resistance pressure drop, and regeneration that burns the stored soot. A plain DPF needs only the filter block — passive (NO₂-driven) and active (O₂-driven) regen are both sub-paths of [pipe.filter.regen], not a separate catalyst:

  [pipe.species]
  name = "CO"
  Y_init = 1.0e-3
    [[pipe.species.extras]]
    name = "O2"
    Y_init = 0.10
    [[pipe.species.extras]]
    name = "NO2"
    Y_init = 1.0e-4
    [[pipe.species.extras]]
    name = "PM1"
    Y_init = 1.0e-3      # particulate column captured by the trap

  [pipe.filter]
  kind = "diesel_particulate_filter"
    [pipe.filter.trap]
    pm_species_name = "PM1"          # which column to trap
    filtration_efficiency = 0.95     # fraction of incoming PM captured
    soot_loading_init = 3.0e-3       # pre-loaded cake [kg/m³]
    [pipe.filter.cake]
    resistance = 1.0e7               # cake Darcy resistance [Pa·s·m²/kg]
    mu_ref = 3.0e-5                  # gas viscosity [Pa·s]
    [pipe.filter.regen]
    A_o2 = 1.0e8                     # active O₂-pathway pre-exponential
    Ea_o2 = 1.5e5
    A_no2 = 5.5e3                    # passive NO₂-pathway pre-exponential
    Ea_no2 = 1.0e5
    [pipe.filter.thermal]
    Omega_cake = 1.5e6              # ρ_s·c_p,s of soot cake [J/(m³·K)]
    h_eff = 1.0e4                  # volumetric cake↔gas heat transfer [W/(m³·K)]
    T_cake_init = 700.0

The DPF integrates soot loading per-cell over the run; the GUI's plot dock surfaces the filter/soot_loading and filter/T_cake time series when the run is traced.

To put an SCR washcoat on the filter (an SCRF), add a [pipe.catalyst] block and an nh3_scr_kinetics reaction to the same pipe — see 43_scrf.toml.

Step 4 — SCR closure + urea injector

The SCR is again a two_phase_heat brick; its deNOx kinetics — NH₃ adsorption/desorption (Temkin coverage dependence via alpha_des), NH₃ oxidation, and standard SCR — are set through reaction = "nh3_scr_kinetics":

  [pipe.catalyst]
  kind = "two_phase_heat"
  rho_s_cs = 4.0e5
  a_v = 3500.0
  h = 120.0
  T_solid_init = 600.0

  [pipe.species]
  name = "NH3"
  Y_init = 0.0
  reaction = "nh3_scr_kinetics"
  A_ads = 1.0e5
  Ea_ads = 40.0e3
  A_des = 1.0e11
  Ea_des = 120.0e3
  alpha_des = 0.2          # Temkin coverage dependence (Cu-zeolite-like)
  A_ox = 1.0e8
  Ea_ox = 80.0e3
  A_scr = 5.0e8
  Ea_scr = 60.0e3
  W_cat = 2.0             # NH₃ storage capacity
  theta_init = 0.0
    [[pipe.species.extras]]
    name = "NO"
    Y_init = 6.0e-4
    [[pipe.species.extras]]
    name = "O2"
    Y_init = 0.10

  [pipe.urea]
  kind = "urea_spray"
  x_frac = 0.1           # inject at 10% of pipe length
  n_spray_cells = 1
  uws_conc = 0.325       # 32.5% AdBlue
  mdot_t = [0.0, 1.0]
  mdot_v = [0.0, 1.5e-5] # kg UWS/s ramp
  eta_conv = 1.0

The [pipe.urea] block adds the urea-to-NH₃ decomposition source (CO(NH₂)₂ + H₂O → 2 NH₃ + CO₂, ≈0.567 kg NH₃ per kg urea) to the named cell range. The SCR reaction then consumes the stored NH₃ against gas-phase NO to drive standard SCR. For a downstream ammonia-slip brick use reaction = "nh3_slip_catalyst" (see 45_two_stage_scr.toml).

Step 5 — connect the chain

# Junction between DOC and DPF.
[[junction]]
id = "doc_to_dpf"
kind = "plenum"
volume = 1.0e-4
  [junction.init]
  p = 1.05e5
  T = 700.0
  [[junction.ports]]
  pipe = "doc_brick"
  end = "right"
  area = 7.85e-3
  [[junction.ports]]
  pipe = "dpf_brick"
  end = "left"
  area = 7.85e-3

For a plain in-line join you can use kind = "passthrough" instead (it takes no volume/init) — that is what the bundled DOC / SCR examples use. Repeat for dpf_to_scr and scr_to_tail. Then a transient_mass_flow_inlet BC on the inlet end of the DOC (replaced by the engine's exhaust manifold in the real case) and a pressure_outlet on the tail-pipe right end.

Step 6 — run + verify

aeolus1d run /tmp/aftertreatment_chain.toml --out /tmp/at.h5 \
    --trace-dt 5e-4 --info-every-n 200

GUI inspection checklist:

  • DOC: select the pipe, plot the T(x) profile — should show light-off (temperature rise downstream) under hot inlet.
  • DPF: select the pipe, plot filter/soot_loading — should rise (loading) or drain (regen) depending on the balance of PM intake and regen temperature.
  • SCR: plot Y_NO mid-brick — should drop once urea injection fills the NH₃ storage.

Reference

  • examples/46_doc.toml — minimal DOC standalone.
  • examples/41_dpf_regen.toml — DPF with active + passive regen.
  • examples/42_scr_urea_injector.toml — SCR with urea injector.
  • examples/43_scrf.toml — SCR-coated filter (catalyst + filter on one pipe).
  • examples/45_two_stage_scr.toml — Cu-zeolite + V₂O₅ slip two-bed SCR.
  • examples/38_engine_turbo_scr.toml — engine + turbo feeding an SCR brick.
  • See Closures — reference table for the full catalyst / filter / urea / species kind list.
  • For DPF heater control (electrical regen assist), see examples/53_dpf_heater_ctrl.toml. ```