Skip to content

Observables

Observables define what the simulation measures. Build ObservableSetInputDefinition, bind names to a concrete geometry with make_observable_set_definition, and pass the result to SimulationModel.

Events And Quantities

The current valid pairs are defined directly by the public enums and runtime validation:

EventQuantities
energy_depositedep, dose, hits
track_steptrack_length, track_length_flux, response_weighted_flux, microscopic_reaction_rate, microscopic_differential_reaction_rate
boundary_crossingsurface_current, surface_flux, surface_angular_current, crossing_count, hits
point_fluxpoint_flux, response_weighted_flux, microscopic_reaction_rate
secondary_handoffhits
nuclear_reactionsecondary_multiplicity
nuclear_reaction_secondaryhits, secondary_energy
history_endpulse_height, linear_combination

coincidence_count is produced by a HistoryCoincidenceDefinition, not authored as a direct event/quantity pair.

Estimators

  • analog: score sampled deposits, steps, crossings, products or completed history responses.
  • expected_value: score a conditional response such as point flux, microscopic reaction rate, differential reaction rate or detector-response folding.
  • derived: created by a history-level linear combination.

The runtime rejects an estimator that is not implemented for the requested event and quantity.

Targets

Targets are:

  • any;
  • volume, selected by named region or observable-region id;
  • boundary;
  • plane, with normal, offset, tolerance and crossing direction;
  • point, optionally averaged over a finite cylinder or sphere.

Plane observables can define a circular aperture. Point estimators can select source, collision, positron-annihilation or photoelectric-relaxation contributions where the package supports that origin.

Axes

Available axes are:

  • energy;
  • direction cosine mu;
  • surface-relative cosine surface_mu;
  • signed projected surface angle;
  • time;
  • x, y and z position;
  • multiplicity.

Every axis uses explicit increasing edges. The supported axes depend on the event. Spatial track-step meshes split path segments at each crossed mesh plane instead of assigning a whole step to its midpoint.

An energy axis can apply a Gaussian detector response with GaussianEnergyResponseDefinition. response_weighted_flux instead folds a tabulated energy response into the estimator.

Common Definitions

Volume dose:

cpp
ObservableInputDefinition{
    .observable_id = ObservableId{1},
    .event = ObservableEventKind::energy_deposit,
    .quantity = ObservableQuantity::dose,
    .target = ObservableTargetKind::volume,
    .region = "detector",
    .mass_g = detector_mass_g,
};

Surface current:

cpp
ObservableInputDefinition{
    .observable_id = ObservableId{2},
    .event = ObservableEventKind::boundary_crossing,
    .quantity = ObservableQuantity::surface_current,
    .particle = ParticleType::neutron,
    .target = ObservableTargetKind::plane,
    .plane_normal = {1.0, 0.0, 0.0},
    .plane_offset_cm = 10.0,
};

Runtime-bound microscopic reaction rate:

cpp
ObservableInputDefinition{
    .observable_id = ObservableId{3},
    .event = ObservableEventKind::track_step,
    .quantity = ObservableQuantity::microscopic_reaction_rate,
    .estimator = ObservableEstimator::expected_value,
    .particle = ParticleType::neutron,
    .target = ObservableTargetKind::volume,
    .region = "foil",
    .volume_cm3 = foil_volume_cm3,
    .target_nuclide = al27,
    .mt = 107,
};

For an evaluated microscopic response, model compilation binds the response from the same package data used by transport. The observable does not carry a second private cross-section table.

Differential elastic response:

cpp
ObservableInputDefinition{
    .observable_id = ObservableId{4},
    .event = ObservableEventKind::track_step,
    .quantity =
        ObservableQuantity::microscopic_differential_reaction_rate,
    .estimator = ObservableEstimator::expected_value,
    .particle = ParticleType::alpha,
    .target = ObservableTargetKind::volume,
    .region = "helium",
    .volume_cm3 = target_volume_cm3,
    .target_nuclide = he4,
    .mt = 2,
    .microscopic_reaction_direction_cosine = 0.5,
    .microscopic_reaction_reference_frame =
        ReactionSecondaryReferenceFrame::center_of_mass,
};

The reference frame is part of the observable. Current neutron differential elastic responses use the laboratory frame; evaluated alpha two-body MT2 responses use the center-of-mass frame. Compilation binds the differential cross section to the evaluated angular law in the transport package.

History-Level Derived Results

HistoryLinearCombinationDefinition combines source bins before second moments are accumulated. Use it when covariance matters, such as molecular stoichiometry or an activation response assembled from several cells.

cpp
ObservableSetInputDefinition input{
    .observables = {
        ObservableInputDefinition{
            .observable_id = ObservableId{10},
            .event = ObservableEventKind::track_step,
            .quantity =
                ObservableQuantity::microscopic_reaction_rate,
            .estimator = ObservableEstimator::expected_value,
            .particle = ParticleType::neutron,
            .target = ObservableTargetKind::volume,
            .region = "cell-a",
            .volume_cm3 = cell_a_volume_cm3,
            .target_nuclide = target_nuclide,
            .mt = 102,
        },
        ObservableInputDefinition{
            .observable_id = ObservableId{11},
            .event = ObservableEventKind::track_step,
            .quantity =
                ObservableQuantity::microscopic_reaction_rate,
            .estimator = ObservableEstimator::expected_value,
            .particle = ParticleType::neutron,
            .target = ObservableTargetKind::volume,
            .region = "cell-b",
            .volume_cm3 = cell_b_volume_cm3,
            .target_nuclide = target_nuclide,
            .mt = 102,
        },
    },
    .history_linear_combinations = {
        HistoryLinearCombinationDefinition{
            .observable_id = ObservableId{20},
            .response_id = "combined-production-rate",
            .units = "reactions/source",
            .terms = {
                HistoryLinearCombinationTerm{
                    .source_observable_id = ObservableId{10},
                    .source_bin = 0,
                    .coefficient = 1.0,
                },
                HistoryLinearCombinationTerm{
                    .source_observable_id = ObservableId{11},
                    .source_bin = 0,
                    .coefficient = 2.0,
                },
            },
        },
    },
};

HistoryCoincidenceDefinition multiplies two pulse-height-bin responses within each history. It preserves correlation between emissions from the same source event.

cpp
input.history_coincidences.push_back(
    HistoryCoincidenceDefinition{
        .observable_id = ObservableId{30},
        .response_id = "detector-a-and-b",
        .units = "count/source",
        .first_pulse_height_observable_id = ObservableId{1},
        .first_bin = 4,
        .second_pulse_height_observable_id = ObservableId{2},
        .second_bin = 7,
    });

Combining already reduced means and standard errors cannot recover this covariance.

Result Rows

Each SimulationObservableRow carries:

  • package, observable id, type, response id and estimator;
  • mean, standard error, units and history counts;
  • score sums and squared sums;
  • active bin bounds;
  • physical response identity and reaction metadata where applicable.

Use find_simulation_observable_rows for a set of bins and require_simulation_observable_row for one required response.

cpp
const SimulationObservableRow &total =
    require_simulation_observable_row(
        result,
        TransportPackageId::coupled_em,
        "energy_deposit_edep",
        "total",
        ObservableId{0});

std::cout << total.value << " +/- " << total.standard_error
          << " " << total.units << '\n';

for (const SimulationObservableRow *bin :
     find_simulation_observable_rows(
         result,
         TransportPackageId::coupled_em,
         "energy_deposit_edep",
         ObservableId{1})) {
  std::cout << bin->energy_min_ev << ','
            << bin->energy_max_ev << ','
            << bin->value << ','
            << bin->standard_error << '\n';
}

NeoMC user documentation.