A .bch batch is a directory, not a single file. The directory name is the batch name (e.g. MONTANA CARBON SAMPLES.bch). All content lives in subdirectories:
<BatchName>.bch/
├── Results/
│ ├── <BatchName>.rec # raw scan data (required)
│ ├── ReprocessedData.prn # processed results table (required)
│ ├── ReprocessedData.MPC # binary mirror of .prn (not parsed)
│ ├── ReprocessedExtra.prn # extra columns table (not parsed)
│ └── Result1.dat # additional output (not parsed)
└── Method/
├── Setups/ # *.set per-analysis method definitions
├── Parameters/ # *.par analysis timing / peak schedules
├── Events/ # *.evt valve/event sequences (+ *.spr sprite files)
├── Source/ # *.src gas source configuration per gas species (not parsed)
├── Refs/ # *.ref reference material definitions (not parsed)
├── Stds/ # *.std standard definitions (not parsed)
├── Samples/ # *.lst sample lists (not parsed)
├── PeakDetect/ # peak detection params (not parsed)
├── Graph/ # graph display settings (not parsed)
├── XY/ # window position/size files (not parsed)
├── Originals/ # backup copies of all Method files at run start
├── Definition.mth # batch-level settings (not parsed)
└── GasCorrections.def # gas correction definitions (not parsed)
Each .bch folder also contains a top-level <BatchName>.prn (and sometimes <BatchName>Extra.prn) alongside the Results/ directory. These are the original on-the-fly outputs written by Callisto during or immediately after acquisition, and their timestamps match the run date. Results/ReprocessedData.prn is a later replay/reprocessing output — produced by running Callisto's "Replay" function, possibly on a different machine or newer software version, sometimes years after the original run. The two files have identical column structure but differ slightly in numeric values (last few significant digits of floating-point results) and in how invalid rows are handled: the original tends to carry a carryover ratio value from the previous peak into blank/failed-acquisition rows, while ReprocessedData.prn zeros those fields out. Results/ReprocessedData.prn is the version used by isoextract — it lives alongside the .rec file in the structured Results/ directory and its zeroing behaviour for invalid rows is more conservative.
Method/Originals/ mirrors the full Method/ tree and captures the state at run time. The files in Method/ may be edited after acquisition.
Plain-text file. One file per batch; contains all scan blocks for all analyses in sequence.
Version tag. Callisto writes v5.0>N~ or v3.0 where N is an internal counter. The >N~ suffix is static padding from the Callisto source (InStr() substring match is used to read it back); strip at > to get the clean version string.
Each block starts with a marker line and a fixed header, then raw scan data:
<type> # "S" = Sample, "R" = Reference, "B" = Blank/background
<name> # analysis name (may encode dataset_id as _P_<id>_G_)
<weight> # float, mg (may be 0 if not entered)
<method> # method name, e.g. "NCS" or "NCS.set" (strip .set if present)
<row_width> # number of data columns per scan
<scan_count> # number of scans expected
[~<scan_id>] # v5.0 only: scan identifier line beginning with "~"
<scan data …>
One value per line. Columns repeat in order [beam1, beam2, …, beamN, time_s] — the last column is time in seconds. Values for all columns of one scan are laid out consecutively; row_width includes the time column so n_beams = row_width - 1. Blocks end when a block-marker line or EOF is encountered.
One scan per line, tab-separated. Columns are [beam1_a, beam2_a, …, beamN_a, extra0, extra1, extra2, extra3, time_counter, …]. All leading float columns are beam currents (amperes); integer columns follow. extra[4] (0-indexed from the first extra column, i.e. index n_beams + 4) is a hardware time counter.
The counter is a 10 Hz absolute clock shared across all blocks in the run (1 tick = 0.1 s). At 1 Hz data collection the counter increments by 10 per scan; at 10 Hz by 1 per scan. The counter is stored as a uint16 and wraps at 65536 (~109 minutes at 1 Hz); isoextract unwraps it before computing time.
The hardware discards the first 2 scans of each block (stabilisation delay) before writing to the file, so counter[0] is already 2 × dt_ticks past block start. To produce block-relative elapsed time starting at 2 × dt — matching the convention in v3.0 files where time_s[0] ≈ 2 × dt — isoextract adds that offset back:
dt_ticks = counter[1] − counter[0] (scan period in counter ticks)
time_s[i] = (counter_unwrapped[i] − counter_unwrapped[0] + 2 × dt_ticks) / 10.0
Both time_s (computed, block-relative seconds) and time_counter_raw (the original uint16 values as stored in the file, before unwrapping) are emitted in traces for v5.0 blocks.
Plain-text, tab-separated. Produced by Callisto's post-processing ("replay") step.
line 0: system description (e.g. "SerCon 'Callisto CF-IRMS' system : IN1215 Gulf Bio")
line 1: timestamp (HH:MM:SS\tMM-DD-YYYY)
line 2: blank
line 3: "Data from file : <absolute Windows path>" (not used in parsing)
line 4: section label (e.g. "Un-Drift Corrected")
line 5: column headers (tab-separated)
line 6: column units (tab-separated; leading tabs align with structural cols)
lines 7…: data rows (tab-separated, first field = N)
When drift correction is enabled a second section follows immediately after the first, with a label line (e.g. "Drift Corrected"), its own headers/units lines, and data rows in the same format.
| Column | Content |
|---|---|
N |
sequential integer row index |
Type |
block type (S / R / B) |
Name |
analysis name |
Weight/Vol |
weight in µg (may be 0) |
Status |
quality flag; leading # is stripped |
All remaining columns are measurement outputs. Each gas species produces a group of columns. For an NCS (N + C + S) batch the column pattern is:
Beam Area [no unit] total beam area for the gas species
N (Sam) [ug] nitrogen amount
15N (Sam) [DeltaAir] δ15N value
None (Sam) [blank] second isotope slot (empty if only one delta)
Ratio 1 raw ratio beam2/beam1
Ratio 2 raw ratio beam3/beam1
Beam Area … next gas species
C (Sam) [ug] …
13C (Sam) [DeltaPDB]
…
The * prefix on a units string (e.g. *DeltaCDT) indicates the measurement did not pass a quality check in Callisto.
One .set file per analysis method. 15-line plain text (lines[11..14] present only in newer format):
| Line (0-indexed) | Field | Notes |
|---|---|---|
| 0 | description |
free text label |
| 1 | reference_file |
basename of .ref used for this method |
| 2 | analysis_timing_file |
basename of .par (without extension) |
| 3 | run_mode |
Normal, Linearity, etc. |
| 4 | event_sequence_file |
basename of .evt; NONE / NONE.evt means no events |
| 5 | auto_sampler_sequence_file |
basename of .spr autosampler file |
| 6 | multicollector_file |
basename of .mcp; Default.mcp uses the shared Setups file |
| 7 | peak_centre_file |
basename of .pcn |
| 8 | line_9 |
unknown |
| 9 | data_rate_hz |
0 = 1 Hz, 1 = 10 Hz |
| 10 | line_11 |
unknown |
| 11 | line_12 |
unknown (optional) |
| 12 | line_13 |
unknown (optional) |
| 13 | element_by_tcd |
True / False |
| 14 | line_15 |
unknown (optional) |
Defines the peak schedule for one analysis run. The file is divided into three sections:
| Line | Field |
|---|---|
| 0 | description |
| 1–13 | various (not decoded) |
| 14 | total_time_s — total run duration in seconds |
| 15–17 | unknown |
| 18 | n_peaks — number of peak entries |
| 19 | n_peaks_total (usually equals n_peaks) |
Each peak occupies up to 20 lines (6 timing + 14 data fields + 1 optional):
| Offset | Field |
|---|---|
| +0 | base1_start_s |
| +1 | base1_end_s |
| +2 | integrate_start_s |
| +3 | integrate_end_s |
| +4 | base2_start_s |
| +5 | base2_end_s |
| +6 | active — True / False |
| +7 | type — Sample / Reference |
| +8 | isotope1_idx — integer index; maps to isotope name (see below) |
| +9 | gas source name (empty; populated in section 3 instead) |
| +10 | unknown integer |
| +11 | unknown integer |
| +12 | gas_idx (skip) |
| +13 | isotope2_idx — same mapping |
| +14 | mode1 — delta reference scale, e.g. DeltaAir, DeltaPDB, DeltaCDT |
| +15 | mode2 — second isotope scale, or 0 if absent |
| +16 | unknown integer |
| +17 | unknown integer |
| +18 | linear_regression — True / False |
| +19 | group — integer grouping index |
| +20 | auto_dilute — True / False (optional; present in newer format) |
| Index | Isotope |
|---|---|
| 0 | 15N |
| 1 | 13C |
| 2 | 18O |
| 7 | 34S |
| 8 | 2H |
After the per-peak block, 48 lines of unknown global settings are followed by one pair of lines per peak:
<gas_species> # e.g. "N2", "CO2", "SO2", "HD"
<at_time_s> # integer; time offset in seconds to align this peak when stitching analyses
gas_species is the gas name that links this peak to a .src file. It indicates which gas species was measured for the peak (e.g. N2, CO2, SO2, HD).
Defines the valve open/close schedule for a run. Two format versions:
Version 1 (no version header):
<description>
<total_run_time_s>
<n_events>
[for each event:]
<time_s>
<event_command> # e.g. "E 8 VALVE ON"
<side> # "L" or "R"
Version 2 (begins with Version 2):
Version 2
<description>
<total_run_time_s>
<n_events>
[for each event:]
<time_s>
<event_command>
<side>
<comment> # optional label
Valve commands reference hardware valve numbers (e.g. E 8 VALVE ON opens valve 8). The ! prefix on the first event is a Callisto convention marking the initial state.
Defines which Faraday cups are active and their resistor/amplifier configuration. One shared .mcp file per batch; individual .set files reference it via multicollector_file.
1
False/True
Default
1
<format> # 3 or 4
Layout per beam (17 lines total):
<mass> # calibration-gas mass (integer); not a stable assignment — omitted from output
<enabled>
<beam_num>
<slot>
<res_type>
<denominator_beam_num> # 0 = self (reference beam)
<res_val1>
<res_val2>
<color_fg>
<color_bg>
<flag2> # True if res_val2 is active
<usage_type> # I-Ratio / P-Ratio / P-only / Spare
<label1>…<label4>
<enabled> # True/False — beam start marker
<beam_num>
<slot>
<res_type>
<denominator_beam_num>
<res_val1>
<res_val2>
<color_fg>
<color_bg>
<flag2>
<usage_type>
<label1>…<label4>
[<mass>] # optional; present for some beams, absent for others
res_type |
Meaning |
|---|---|
| 1 | Standard-gain I-type resistor |
| 2 | P-type (high-gain) |
| 3 | High-ohm I-type |
| 4 | P-only (no ratio output) |
res_val1 and res_val2 are stored in units of 1/1,000,000 Ω (i.e. multiply by 10⁶ to get ohms). flag2 = True means res_val2 is the active resistance.
The .mcp file contains a mass field in format 3 and optionally in format 4. This field reflects the calibration-gas mass used during the most recent peak-centre calibration — it is not a stable per-beam property and is inconsistent across batches and formats. The mass field is therefore not included in the JSON output.
The actual mass monitored by each beam is determined implicitly by the gas species and the delta isotope being calculated:
| Delta value | Gas | Beam ratio | Mass ratio |
|---|---|---|---|
| δ¹⁵N | N₂ | beam2 / beam1 | 29 / 28 |
| δ¹³C | CO₂ | beam2 / beam1 | 45 / 44 |
| δ¹⁸O | CO₂ | beam3 / beam1 | 46 / 44 |
| δ³⁴S | SO₂ | beam2 / beam1 | 66 / 64 |
| δ²H | H₂/HD | beam2 / beam1 | 3 / 2 |
These ratios are fixed by the SerCon Callisto instrument design (3-cup Faraday array with beam1 always on the major isotope). The Ratio 1 and Ratio 2 columns in the .prn output correspond to beam2/beam1 and beam3/beam1 respectively.
For N₂ and CO₂ the cups sit on consecutive masses (Δm = 1). For SO₂ the magnetic field is tuned so that beam1 lands on mass 64 (³²SO₂) and beam2 lands on mass 66 (³⁴SO₂), skipping mass 65 (³³SO₂). This was confirmed empirically: raw Ratio 1 values for SO₂ scale correctly with δ³⁴S and have the right order of magnitude for a 66/64 beam-current ratio (~0.045 for CDT-equivalent samples). The Ratio 2 column for SO₂ does not correspond to a clean isotope ratio and the Callisto software marks the second-isotope delta slot as None in its output.
.rec blocks → method field → .set file (Method/Setups/<method>.set)
.set → analysis_timing_file → .par (Method/Parameters/<name>.par)
.set → event_sequence_file → .evt (Method/Events/<name>.evt)
.set → multicollector_file → .mcp (Method/Setups/MultiCollector_A.mcp)
.prn rows → N column → .rec block index (1-based)
The .rec and .prn row order must be aligned: the N-th data row in the .prn corresponds to the N-th scan block in the .rec.
isoextract writes one <BatchName>.bch.json file beside the .bch directory. Top-level keys, in order:
meta
header
collectors (omitted if no .mcp found)
methods (omitted if no .set files found)
timings (omitted if no .par files found)
events (omitted if no .evt files found)
data
results
| Field | Type | Content |
|---|---|---|
isoextract_version |
string | tool version |
file_type |
string | "bch" |
file_size_bytes |
integer | combined size of all files in the .bch directory |
complete |
bool | true if parsing completed without error |
| Field | Content |
|---|---|
source |
relative path to Results/ReprocessedData.prn |
system_description |
line 0 of the .prn (e.g. "SerCon 'Callisto CF-IRMS' system : IN1215 Gulf Bio") |
timestamp |
line 1 of the .prn (HH:MM:SS\tMM-DD-YYYY) |
Parsed from Method/Setups/MultiCollector_A.mcp.
| Field | Content |
|---|---|
source |
relative path to the .mcp file |
format |
integer MCP format version (3 or 4) |
beams |
array of beam objects (see below) |
Each beam object:
| Field | Type | Content |
|---|---|---|
beam_num |
int | beam number (1-based) |
enabled |
bool | whether this collector is active |
slot |
int | physical slot in the collector array |
res_type |
int | resistor type (1=I-type, 2=P-type, 3=high-ohm I-type, 4=P-only) |
resistance_1_ohm |
int | primary resistor in ohms |
resistance_2_ohm |
int | secondary resistor in ohms |
active_resistance_ohm |
int | whichever resistance is currently active (flag2 selects) |
usage_type |
string | omitted if "Spare"; otherwise e.g. "I-Ratio", "P-Ratio" |
denominator_beam_num |
int | omitted if 0 (self = reference beam) |
Array; one entry per distinct method name used by any .rec block. Each element:
| Field | Content |
|---|---|
method |
method name without .set extension (e.g. "NCS") |
source |
relative path to the .set file |
description |
free-text label |
reference_file |
.ref basename |
analysis_timing_file |
.par basename (without extension) |
run_mode |
e.g. "Normal", "Linearity" |
event_sequence_file |
.evt basename; "NONE" if absent |
auto_sampler_sequence_file |
.spr basename |
multicollector_file |
.mcp basename |
peak_centre_file |
.pcn basename |
data_rate_hz |
integer: 1 or 10 |
element_by_tcd |
bool (newer format only) |
Array; one entry per distinct .par file referenced by the methods. Each element:
| Field | Content |
|---|---|
timing |
timing name without .par extension (e.g. "NCS") |
source |
relative path to the .par file |
description |
free-text label |
total_time_s |
total run duration in seconds |
peaks |
array of peak objects (see below) |
Each peak object contains timing windows, isotope info, and gas species:
| Field | Type | Content |
|---|---|---|
gas_species |
string | gas measured (e.g. "N2", "CO2", "SO2", "HD") |
active |
bool | whether this peak is enabled |
type |
string | "Sample" or "Reference" |
base1_start_s … base2_end_s |
int | baseline and integration window boundaries |
mode1 |
string | delta reference scale (e.g. "DeltaAir", "DeltaPDB", "DeltaCDT") |
isotope1 |
string | e.g. "15N", "13C", "34S" (omitted if index unrecognised) |
isotope2 |
string | second isotope (omitted if absent) |
mode2 |
string | second isotope scale (omitted if absent or "0") |
linear_regression |
bool | |
group |
int | grouping index |
at_time_s |
int | time offset for stitching analyses |
auto_dilute |
bool | optional; present in newer format only |
Array; one entry per distinct .evt file referenced by methods. Each element:
| Field | Content |
|---|---|
event |
event sequence name without .evt extension (e.g. "NCS") |
source |
relative path to the .evt file |
total_run_time_s |
total run duration in seconds |
description |
optional free-text label |
events |
array of { time_s, event, side, [comment] } objects |
Raw scan traces from the .rec file.
| Field | Content |
|---|---|
source |
relative path to the .rec file |
version |
version string from the .rec header (e.g. "v5.0", "v3.0") |
blocks |
array of block objects (see below) |
Each block object:
| Field | Type | Content |
|---|---|---|
type |
string | "S" / "R" / "B" |
name |
string | analysis name from the .rec header |
method |
string | method name (.set suffix stripped) |
n_scans |
int | number of scans actually read |
weight |
float | sample weight in mg (omitted if 0 / absent) |
scan_id |
string | v5.0 scan identifier line (omitted for v3.0) |
acquisition_duration_s |
float | max(time_s) − min(time_s) |
traces |
object | per-beam and time arrays (see below) |
traces keys:
time_s— block-relative elapsed seconds (float array); present for both v3.0 and v5.0time_counter_raw— original uint16 hardware counter values as stored in the.recfile, before overflow unwrapping (integer array; v5.0 only)beam1_a…beamN_a— beam currents in amperes
For v3.0 files time_s is stored directly in the .rec file (first scan ≈ 2 × dt). For v5.0 files it is derived from the hardware counter with overflow unwrapping and the 2-scan offset added back, so the first scan is also at 2 × dt (see the .rec v5.0 section above).
Columnar measurement results from Results/ReprocessedData.prn.
| Field | Content |
|---|---|
source |
relative path to ReprocessedData.prn |
columns |
array of column objects |
Each column object:
| Field | Content |
|---|---|
label |
column name from the .prn header |
units |
units string (omitted if blank); *-prefixed means quality check failed |
values |
array of values (number or string; null for missing) |
values_drift_corrected |
array from the second .prn section (omitted if no drift section) |
Structural columns (id, name, type, dataset_id, weight, status) always appear first, followed by all measurement columns in .prn order. Because multiple gas sections repeat column names like "Ratio 1" and "Beam Area", columns are preserved in full — duplicate names appear as separate column objects.
| Path pattern | Purpose |
|---|---|
Method/Source/*.src |
Ion source settings per gas species (type code, pressures, voltages) |
Method/Refs/*.ref |
Reference material δ-values used for normalisation |
Method/Stds/*.std |
Working standard definitions |
Method/Samples/*.lst |
Sample list / run queue |
Method/PeakDetect/*.def |
Automatic peak detection parameters |
Method/Graph/*.def |
Graph axis and display settings |
Method/XY/* |
GUI window positions |
Method/Definition.mth |
Batch-level method envelope |
Method/GasCorrections.def |
Gas-specific isotope correction factors |
Method/Originals/ |
Pre-run backup of all method files |
Results/ReprocessedData.MPC |
Binary mirror of .prn (proprietary format) |
Results/ReprocessedExtra.prn |
Additional computed columns |