Pipeline Customization#

The pipeline manages event execution order during each simulation period. BAM Engine uses explicit ordering: events run in the exact order listed, with no automatic dependency resolution. This matches the original BAM model specification and makes the execution flow predictable and debuggable.

The Default Pipeline#

The default pipeline executes 8 phases per period. Labor and credit market matching uses batch processing with vectorized NumPy operations. The goods market uses sequential processing where each consumer completes all visits before the next consumer starts.

Phase 1: Planning (6 events)

firms_decide_desired_production
firms_plan_breakeven_price
firms_plan_price
firms_decide_desired_labor
firms_decide_vacancies
firms_fire_excess_workers

Phase 2: Labor Market (4 setup + max_M rounds + wage bill)

calc_inflation_rate
adjust_minimum_wage
firms_decide_wage_offer
workers_decide_firms_to_apply
labor_market_round x max_M
firms_calc_wage_bill

labor_market_round x max_M expands to max_M batch matching rounds (default: 4). Each round processes all applications simultaneously using vectorized conflict resolution.

Phase 3: Credit Market (5 setup + max_H rounds + firing)

banks_decide_credit_supply
banks_decide_interest_rate
firms_decide_credit_demand
firms_calc_financial_fragility
firms_prepare_loan_applications
credit_market_round x max_H
firms_fire_workers

Phase 4: Production (5 events)

firms_pay_wages
workers_receive_wage
firms_run_production
update_avg_mkt_price
workers_update_contracts

Phase 5: Goods Market (5 events)

consumers_calc_propensity
consumers_decide_income_to_spend
consumers_decide_firms_to_visit
goods_market_round
consumers_finalize_purchases

Phase 6: Revenue (3 events)

firms_collect_revenue
firms_validate_debt_commitments
firms_pay_dividends

Phase 7: Bankruptcy (3 events)

firms_update_net_worth
mark_bankrupt_firms
mark_bankrupt_banks

Phase 8: Entry (2 events)

spawn_replacement_firms
spawn_replacement_banks

Manual Pipeline Modification#

For more control, modify the pipeline directly after initialization:

import bamengine as bam

sim = bam.Simulation.init(seed=42)

# Insert events at specific positions
sim.pipeline.insert_after("firms_adjust_price", "my_custom_event")
sim.pipeline.insert_before("firms_adjust_price", "pre_pricing_check")

# Remove an event
sim.pipeline.remove("labor_market_round_0")

# Replace an event
sim.pipeline.replace("firms_decide_desired_production", "my_production_rule")

All pipeline modifications should happen before calling sim.run() or sim.step().

Custom Pipeline YAML#

For full control over the event sequence, create a custom pipeline YAML file:

sim = bam.Simulation.init(pipeline_path="custom_pipeline.yml", seed=42)

YAML syntax:

events:
  # Simple event: execute once per period
  - firms_decide_desired_production

  # Repeated event: execute N times
  - labor_market_round x 4

  # Parameter substitution: use config values
  - labor_market_round x {max_M}
  - credit_market_round x {max_H}

Parameter substitution replaces {param_name} with the corresponding configuration value at pipeline load time. Available substitutions:

  • {max_M}: Number of labor market matching rounds

  • {max_H}: Number of credit market matching rounds

Planning-Phase Pricing (Alternative)#

BAM Engine provides an alternative pair of pricing events that run during the planning phase instead of the production phase:

  • firms_plan_breakeven_price: Breakeven from previous period’s costs / desired production

  • firms_plan_price: Price adjustment with breakeven floor

These are mutually exclusive with the production-phase pair (firms_calc_breakeven_price, firms_adjust_price). The default pipeline uses planning-phase pricing. To switch to production-phase pricing, create a custom pipeline that moves the pricing events:

events:
  # Planning (no pricing events)
  - firms_decide_desired_production
  - firms_decide_desired_labor
  - firms_decide_vacancies
  - firms_fire_excess_workers

  # ... labor and credit market phases ...

  # Production (pricing moved here)
  - firms_pay_wages
  - workers_receive_wage
  - firms_calc_breakeven_price
  - firms_adjust_price
  - firms_run_production
  - update_avg_mkt_price
  - workers_update_contracts

Inspecting the Pipeline#

View the current pipeline to verify event ordering:

sim = bam.Simulation.init(seed=42)

# List all events in execution order
for entry in sim.pipeline:
    print(entry.name)

# Check total event count
print(f"Pipeline has {len(sim.pipeline)} events")

This is especially useful after applying hooks to verify insertion points.

Tips#

  • Explicit ordering is intentional: BAM Engine deliberately avoids topological sorting. The execution order is a core part of the model specification.

  • Hook activation is explicit: Always call sim.use_events() after init; declaring @event(after=...) alone does nothing.

  • Modify before running: Pipeline changes should happen between Simulation.init() and sim.run(), not during execution.

  • Batch matching: Labor and credit markets use vectorized batch matching with conflict resolution. The goods market uses sequential processing.

See also