Working with MCTAL Files

This tutorial covers how to use KIKA to work with MCNP MCTAL output files, including parsing, accessing tally data, data analysis, and visualization.

Loading MCTAL Files

Start by loading a MCTAL file:

import kika
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path

# Parse a mctal file
mctal = kika.read_mctal('path/to/mctalfile.m')

MCTAL File Structure

The parsed MCTAL file is represented by a Mctal object containing header information and tally data.

# The Mctal object itself provides a nicely formatted summary
mctal

# Display specific header information
print(f"Code: {mctal.code_name} {mctal.ver}")
print(f"Problem ID: {mctal.probid}")
print(f"Number of particle histories: {mctal.nps:.2e}")
print(f"Problem Title: {mctal.problem_id}")

# Display tally information
print(f"Number of tallies: {mctal.ntal}")
print(f"Tally numbers: {mctal.tally_numbers}")

Working with Tallies

Tallies are the main output of MCNP simulations. The Mctal class provides access to all tallies in the MCTAL file:

# Get a list of all tally IDs
tally_ids = list(mctal.tally.keys())
print(f"Available tally IDs: {tally_ids}")

# Access a specific tally
tally_id = tally_ids[0]  # Select first tally as example
tally = mctal.tally[tally_id]

# Display the tally information
display(tally)

# Display tally dimensions and structure
print(f"Tally name: {tally.name}")
print(f"Tally dimensions: {tally.get_dimensions()}")

# Display energy bin structure if available
if tally.energies:
    print("Energy bin boundaries:")
    for i, energy in enumerate(tally.energies):
        print(f"  Bin {i}: {energy:.6e} MeV")

Converting to DataFrame

For more advanced data analysis, KIKA allows you to convert tally data to pandas DataFrames:

# Convert tally to DataFrame
tally_df = tally.to_dataframe()

# Display the DataFrame
display(tally_df)

# For energy-integrated data (if available)
integral_df = tally.get_integral_energy_dataframe()
if not integral_df.empty:
    print("Energy-integrated data as DataFrame:")
    display(integral_df)

Working with Multidimensional Data

KIKA supports multidimensional data analysis using xarray, which provides labeled N-dimensional arrays:

# Convert tally data to xarray Dataset
ds = tally.to_xarray()
display(ds)

# Extracting slices of multidimensional data
dims = tally.get_dimensions()
print(f"Tally dimensions: {dims}")

# Get a slice for a specific energy value
results, errors = tally.get_slice(energy=tally.energies[2])
print(f"Results for selected energy bin: {results}")
print(f"Errors for selected energy bin: {errors}")

# Get a slice for a specific segment
results, errors = tally.get_slice(segment=1)  # Segment numbering starts at 0
print(f"Results for second segment: {results}")
print(f"Errors for second segment: {errors}")

Working with Energy-Integrated Data

For tallies with energy bins, KIKA provides methods to access energy-integrated data:

# Get the energy-integrated data
integral_data = tally.get_integral_energy_data()

# Display the energy-integrated data
print(f"Result: {integral_data['Result']}")
print(f"Error: {integral_data['Error']}")

# Convert to DataFrame for tabular view
integral_df = tally.get_integral_energy_dataframe()
display(integral_df)

Analyzing Tally Convergence

Use TFC (Tally Fluctuation Chart) data to analyze tally convergence:

# Check if TFC data is available
if hasattr(tally, 'tfc_nps') and tally.tfc_nps and len(tally.tfc_nps) > 0:
    print(f"Tally has {len(tally.tfc_nps)} TFC data points")

    # Show some TFC data values
    print("Sample of TFC data:")
    print(f"{'NPS':<12} {'Result':<15} {'Error':<10} {'FOM':<10}")
    for i in range(min(5, len(tally.tfc_nps))):  # Show up to first 5 points
        print(f"{tally.tfc_nps[i]:<12} {tally.tfc_results[i]:<15.6e} {tally.tfc_errors[i]:<10.6f} {tally.tfc_fom[i]:<10.2f}")

    # Plot TFC data using the built-in method
    tally.plot_tfc_data(figsize=(15, 4))

    # Plot without error bars for clearer visualization
    tally.plot_tfc_data(figsize=(15, 4), show_error_bars=False)
else:
    print("No TFC data available for this tally.")

Working with Perturbations

MCNP perturbation data is stored in the MCTAL file for perturbed tallies:

# Find tallies with perturbation data
tallies_with_pert = [tid for tid in tally_ids if hasattr(mctal.tally[tid], 'perturbation') and mctal.tally[tid].perturbation]

if tallies_with_pert:
    # Get the first tally with perturbation data
    tally_id = tallies_with_pert[0]
    tally = mctal.tally[tally_id]

    # Display the perturbation collection
    print(f"Perturbation collection for Tally {tally_id}:")
    display(tally.perturbation)

    # Get list of perturbation IDs
    pert_ids = list(tally.perturbation.keys())

    if pert_ids:
        # Access a specific perturbation
        pert_id = pert_ids[0]
        pert = tally.perturbation[pert_id]

        # Display the perturbation details
        display(pert)

Converting Perturbation Data to DataFrames

For better analysis, perturbation data can be converted to pandas DataFrames:

if tallies_with_pert:
    tally_id = tallies_with_pert[0]
    tally = mctal.tally[tally_id]

    # Convert all perturbations to a DataFrame
    pert_df = tally.perturbation.to_dataframe()

    print("All perturbations as DataFrame:")
    display(pert_df)

    # Analyze a single perturbation
    if pert_ids:
        pert_id = pert_ids[0]
        single_pert = tally.perturbation[pert_id]
        single_df = single_pert.to_dataframe()

        print(f"Perturbation {pert_id} as DataFrame:")
        display(single_df)