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.