Skip to content

Quick Start

This page shows the current user path: build a model, run it once, then read the requested score.

Add NeoMC To Your Build

NeoMC currently builds from source:

cmake
add_subdirectory(path/to/neomc)

add_executable(my_transport main.cc)
target_link_libraries(
  my_transport
  PRIVATE
    neomc_simulation
    neomc_physics_data_importers
)

Enable importers when configuring the parent build:

bash
cmake -S . -B build -DNEOMC_BUILD_IMPORTERS=ON
cmake --build build --parallel

Build The Problem

Start with material definitions. This example uses an aluminum slab:

cpp
std::vector<MaterialDefinition> materials =
    material_definitions_from_inputs({
        MaterialInputDefinition{
            .name = "aluminum",
            .density_g_cm3 = 2.70,
            .temperature_kelvin = 293.6,
            .components = {
                element_atom_fraction("Al", 1.0),
            },
        },
    });

auto geometry = std::make_shared<RectilinearGrid>(
    make_rectilinear_grid(
        RectilinearGridInputDefinition{
            .x_edges = {0.0, 1.0},
            .y_edges = {-2.0, 2.0},
            .z_edges = {-2.0, 2.0},
            .material_names = {"aluminum"},
            .observable_regions = {ObservableId{0}},
            .region_names = {"target"},
        },
        materials));

Ask for energy deposited in the target:

cpp
ObservableSetDefinition observables = make_observable_set_definition(
    ObservableSetInputDefinition{
        .observables = {
            ObservableInputDefinition{
                .observable_id = ObservableId{0},
                .quantity = ObservableQuantity::edep,
                .target = ObservableTargetKind::volume,
                .region = "target",
            },
        },
    },
    *geometry);

Define a 1 MeV photon beam:

cpp
SimulationSourceDefinition source{
    .kind = SimulationSourceKind::independent,
    .independent = IndependentSourceDefinition{
        .spatial = SourceSpatialDefinition{
            .mode = SourceSpatialMode::point,
            .position = {1.0e-6, 0.0, 0.0},
        },
        .angular = SourceAngularDefinition{
            .mode = SourceAngularMode::fixed_direction,
            .direction = {1.0, 0.0, 0.0},
        },
        .energy = SourceEnergyDefinition{
            .distribution = SourceScalarDistribution{
                .mode = SourceScalarDistributionMode::delta,
                .value = 1.0e6,
            },
        },
        .particle_type = ParticleType::photon,
        .master_seed = 47,
    },
};

Resolve the coupled electromagnetic package from a named data installation:

cpp
const CoupledEmPhysicsProfile profile =
    CoupledEmPhysicsProfile::neomc_reference_epdl_eedl;

CoupledEmSimulationPackage em =
    resolve_coupled_em_simulation_package(
        CoupledEmDataLibraryDefinition{
            .root = physics_data_root,
        },
        materials,
        make_coupled_em_transport_config(profile),
        make_coupled_em_material_process_config(profile));

The resolver loads only the elements used by the model and records the source files and hashes in the runtime data. It does not add photonuclear data or invent missing material-specific tables.

Run

Put the pieces into SimulationModel and call the one-shot entry point:

cpp
SimulationTransportSessionResult result = run_simulation_model(
    SimulationModel{
        .geometry = hold_geometry(geometry),
        .materials = materials,
        .observables = observables,
        .packages = SimulationPackageSet{
            .coupled_em = std::move(em),
            .required_capabilities = {
                SimulationRequiredTransportCapability{
                    .package = TransportPackageId::coupled_em,
                    .capability = "em_photon_transport",
                    .minimum_status =
                        TransportCapabilityStatus::implemented,
                },
            },
        },
        .source = std::move(source),
        .run = SimulationRunSettings{
            .histories = 10000,
            .worker_threads = 4,
        },
    });

Package objects present in SimulationPackageSet are enabled automatically. required_capabilities states what the application expects and makes model compilation fail if that boundary is not available.

Read The Result

Retrieve the score by package, observable type, response and id:

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

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

Read value, standard_error, units and histories together. Then inspect the package summary and data provenance:

cpp
const SimulationPackageResultSummary &transport =
    require_simulation_package_result(
        result, TransportPackageId::coupled_em);

std::cout << "tracks = " << transport.tracks << '\n'
          << "deposited = " << transport.deposited_energy << " eV\n"
          << "escaped = " << transport.escaped_energy << " eV\n";

if (result.coupled_em_data) {
  std::cout << result.coupled_em_data->library_version << '\n';
}

Continue with your first simulation for the meaning of each model component, or physics data for resolver and provenance details.

NeoMC user documentation.