COPRA2 — User Documentation

Constructing Proxy Records from Age Models. Python/Qt6 reimplementation of the MATLAB/Octave toolbox. Version 2.0.0rc3.

Introduction

COPRA transforms dating (age–depth) uncertainties into proxy uncertainties. Given a set of dated depths with age errors and a proxy record measured along the same depth axis, it builds a Monte Carlo ensemble of age–depth models, interpolates the proxy onto each realisation, and reports the proxy time series with confidence bands. Every run records its random seed, so results are exactly reproducible.

The software offers two front ends over one shared computational core: a desktop application (copra-gui) and a command-line tool (copra-cli).

Installation

From PyPI (with pip)

The distribution name is copra2 (the name copra was already taken); the import package and the console commands keep the copra name:

pip install copra2          # command-line tool + Python API (no GUI)
pip install "copra2[gui]"   # add the PySide6/Qt6 desktop application

PySide6 is an optional dependency. The command-line tool (copra-cli) and the copra.core API work without it, so old systems where PySide6 cannot be installed can still use COPRA; add [gui] to enable the desktop app.

From source (developers)

cd copra_py
python -m venv .venv
source .venv/bin/activate      # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
Use the virtual-environment interpreter (.venv/bin/python). A system Python with a mismatched NumPy build will fail to import the numerical core.

Standalone application (end users)

A double-clickable application is built with PyInstaller and needs no Python installation:

pip install pyinstaller
pyinstaller packaging/copra.spec     # run from copra_py/
PlatformResultLaunch
macOSdist/COPRA.appDouble-click. On first launch, right-click → Open to bypass Gatekeeper (unsigned build).
Windowsdist/COPRA/COPRA.exeDouble-click.
Linuxdist/COPRA/COPRARun the binary.

PyInstaller does not cross-compile; build on the target platform.

Launching the app

From a source checkout:

copra-gui                  # entry point
python -m copra.gui        # equivalent

Or double-click the standalone application built above.

Input data formats

Input files are plain whitespace- or comma-separated text (.txt / .csv) with no column headers (lines starting with # or % are treated as comments). Depths must be strictly increasing and unique — no duplicate depths, no NaN values.

FileColumns (in order)Notes
Dating table (required) depth, age, age error [, upper age error] One row per dated level; age error is the 1σ uncertainty. An optional fourth column makes the error asymmetric: column 3 is then the lower and column 4 the upper 1σ error.
Proxy record (required) depth, proxy value [, value error] Measured along the same depth axis as the dating table. An optional third column gives the 1σ proxy-value error (off by default).
Layer count (optional) depth, age, depth error Layer-count age is relative to the first counted layer (first layer has age 0).

Example dating table (depth in mm, age in yr, error in yr):

0     0      0
120   980    45
250   2010   60
...

With asymmetric errors (columns: depth, age, lower error, upper error):

1      50     12.5   20.5
112    207.9  20.4   19.4
...

Asymmetric errors are sampled with a two-piece (split) normal — the lower error sets the spread below the age, the upper error above — so the Monte Carlo ensemble reflects the asymmetry. There is no MATLAB equivalent for this input.

Proxy errors (optional)

By default no proxy error is assumed. Two independent sources can be added and are folded in when the proxy is resampled onto the age-certain axis:

Desktop application

The window is split into a control panel (left), plot tabs (right) and a log/status area (bottom). Hover any input field for a tooltip.

  1. Select inputs. Choose the dating table and proxy record (and optionally a layer-count file). As soon as both required files are set, the review plots are drawn automatically.
  2. Set parameters. Number of Monte Carlo realisations, interpolation method, confidence-interval widths, an optional random seed, and the sample/proxy names (see Parameters).
  3. Review and treat. Inspect flagged age reversals and hiatus candidates; apply treatment if needed (see below).
  4. Run. The Monte Carlo model runs on a background thread with a progress bar; press Cancel to abort.
  5. Export. Write the results, ensemble, session and log to a chosen folder (File → Export results, or the Export button).

Menus

Plot tabs

TabShows
Age–depthThe editable review: dating points coloured by reversal severity, plus hiatus lines. All treatment (reversals, errors, hiatuses) is done on this plot. After a run it shows the mean age–depth model.
Treated age model → Age model ensembleRead-only result of the current treatment; not interactive. After a run the tab is renamed Age model ensemble and shows all Monte Carlo realisations.
ProxyThe raw, measured proxy record versus depth (the resampled mean proxy series after a run).
RealisationsThe proxy plotted against every age realisation (the full ensemble as a time series).

When a reversal or an automatic hiatus is detected, a warning line prefixed with ⚠️ appears in the log/status area at the bottom.

Reversals & hiatuses

An age reversal is a dating point whose age is out of order relative to its depth. COPRA classifies reversals as tractable (resolvable by widening the age error) or non-tractable (best removed). Treatment is declarative and stored in the session, so a run configured in the GUI remains reproducible.

All picking is done on the editable Age–depth plot; the Treated age model plot is the read-only result and is not interactive.

Automatic hiatus detection. COPRA flags gaps with an anomalously low growth rate as hiatuses. When one is found, its depth is written into the Hiatus depths field and drawn as a line on the Age–depth plot (and shown on the treated model); when none is found the field stays empty and no line is shown. Editing or clearing the field overrides the automatic value (auto-fill then stops). Note that an age reversal also produces a low-growth-rate gap, so a reversal can raise a spurious hiatus — treating the reversal removes it automatically.

Reusing an age model for another proxy

A single Monte Carlo age model can be applied to several proxy records measured on the same core without re-running the (expensive) simulation. After a run, load a different proxy file in the proxy picker: the Run button changes to Transfer. Clicking it (or using File → Replace proxy record) evaluates the computed age–depth realisations at the new proxy's depths (linear interpolation per realisation) and updates the Proxy and Realisations tabs immediately; the age model itself is unchanged.

The new proxy should cover the same depth range; depths outside the age model's range are dropped. To keep the original results safe, COPRA renames the sample (appending the new proxy's file name) and requires a new sample name when you export, so nothing is overwritten. Start a completely fresh project with File → Close.

Command line

The copra-cli command drives the same pipeline without a GUI.

# Guided, interactive session (prompts for files, parameters, treatment)
copra-cli interactive          # or just: copra-cli

# Inspect a dataset: reversals + hiatus candidates, no simulation
copra-cli check --dating DATING.txt --proxy PROXY.txt

# Run the age model and write outputs (+ optional plots)
copra-cli run --dating DATING.txt --proxy PROXY.txt \
    --M 2000 --interp pchip --seed 42 --output-dir output --plots

# Reversal treatment: remove point 3, widen point 6's error three times
copra-cli run --dating DATING.txt --proxy PROXY.txt \
    --remove-points 3 --increase-error 6 6 6

# Layer counting and an explicit hiatus depth
copra-cli run --dating DATING.txt --proxy PROXY.txt \
    --layercount LAYERS.txt --hiatus 389.5

# Reproduce a previous run exactly from its saved session
copra-cli reproduce output/d_<sample>_<date>.json

Options may also be supplied through a TOML file via --config run.toml (a [copra] table with the same keys); explicit command-line options override the file.

Output files

Each run writes four files. Names carry the sample name and the run date in ISO YYYY-MM-DD form.

FileContents
<sample>_<interp>_<date>.txt Results table: age, proxy mean, age and proxy confidence quantiles, and depth (tab-separated, one header line).
<sample>_ensemble_<date>.csv Full Monte Carlo ensemble: depth, proxy, and one column per age realisation.
d_<sample>_<date>.json Canonical session: inputs, parameters and the random seed.
log_COPRA_<date>.m Legacy MATLAB-readable run log.

Reproducibility

The JSON session is the authoritative record of a run. It stores the input file paths, all parameters and the resolved random seed. Feeding it back reruns the model to a bit-identical ensemble:

copra-cli reproduce output/d_sample_2026-09-13.json

If no seed is given, COPRA generates one and records it, so even “random” runs remain reproducible after the fact.

Parameters

ParameterMeaningDefault
MC realizations (--M) Number of Monte Carlo age models. More gives smoother statistics but is slower.2000
Interpolation (--interp) linear, pchip (monotone) or spline. pchip avoids overshoot.pchip
Proxy CI (%)Confidence-interval width for the proxy band (e.g. 95 → 2.5–97.5% quantiles).95
Age CI (%)Confidence-interval width for the age band. 95
Seed (--seed)Random seed; blank/omitted draws a fresh one and records it.random
Sample nameUsed in output file names. from dating file
Proxy nameAxis label on the plots. δ18O

Python API

The scientific core is a plain NumPy/SciPy package with no Qt or matplotlib dependency and can be scripted directly:

from copra.core.model import CopraSession
from copra.core.logging_ import run_session, save_results

session = CopraSession(
    dating_path="DATING.txt",
    proxy_path="PROXY.txt",
    M=2000,
    interp_method="pchip",
    samplename="mycore",
    seed=42,
)
run_session(session)                       # populates the ensemble + statistics
save_results(session, "output")            # writes the four output files

Package layout: copra.core (computation), copra.plotting (matplotlib figures), copra.gui (Qt6 application), copra.cli (command-line tool).

References

Breitenbach, S. F. M., Rehfeld, K., Goswami, B., Baldini, J. U. L., Ridley, H. E., Kennett, D. J., Prufer, K. M., Aquino, V. V., Asmerom, Y., Polyak, V. J., Cheng, H., Kurths, J., and Marwan, N. (2012): COnstructing Proxy Records from Age models (COPRA), Climate of the Past, 8, 1765–1779. doi:10.5194/cp-8-1765-2012

Project website: https://tocsy.pik-potsdam.de/copra2.php

Authors: Norbert Marwan and Sebastian F. M. Breitenbach (original and Python port).
Acknowledgements (original version): Kira Rehfeld, Bedartha Goswami, Daniel Juncu.