Package 'SyncER'

Title: Synchronicity Testing for Event Records
Description: Evaluation of synchronous deposition across different event records using a log-ratio approach, and syncing age-depth models based on the availability of isochrons. Following the methodology of Wils & Ramisch (2026) <doi:10.1038/s41598-026-67943-7>. The synthetic example dataset used in the examples, tests and vignette is distributed separately in the companion data package 'SyncERdata'.
Authors: Katleen Wils [aut, cre]
Maintainer: Katleen Wils <[email protected]>
License: GPL (>= 3)
Version: 1.0.0
Built: 2026-10-09 16:57:23 UTC
Source: https://github.com/katleenwils/syncer

Help Index


Write input files for age-depth modelling and return the updated record metadata

Description

Single entry point for turning record metadata into rbacon/rplum-ready CSV input files. It treats record_data as the initial input data: any new synchronized ages are included and the CSV(s) are rebuilt. The updated record_data (re-keyed to the folder generation that was written) is returned.

Usage

age_model_input(
  record_data,
  adjusted_ages = NULL,
  update_records = FALSE,
  radiocarbon_sample_names = "sample",
  lead_sample_names = "210Pb_sample",
  original_ages = TRUE,
  base_dir = syncer_base_dir(),
  verbose = TRUE
)

Arguments

record_data

Named list of record metadata (output from read_record_data(), or the return value of a previous age_model_input() call). Each element is a data frame with at least event, depth, C14_age, C14_error and cc columns.

adjusted_ages

Optional output from synchronize_ages() (or a c() combination of several) with the new synchronized ages to add (default: NULL). When NULL, the current record_data is written as-is (the initial input).

update_records

Logical; when TRUE the existing folders that record_data is keyed to are overwritten in place. When FALSE (default) and adjusted_ages is supplied, a new folder generation is created ("_synced" for the first synchronization, then "_synced_1", "_synced_2", ...).

radiocarbon_sample_names

Character vector of the event label(s) used for your radiocarbon samples in the input file (default: "sample").

lead_sample_names

Character vector of the event label(s) used for your Pb-210 (lead) samples (default: "210Pb_sample"); leave blank if you only consider radiocarbon ages.

original_ages

Logical or named logical vector indicating whether the new age-depth models should also use the original ages alongside the synchronized ages (default: TRUE). Set to FALSE to build the models from the synchronized ages only (e.g. a record with poor accuracy); adjust it per record with a named vector such as c("core1" = FALSE). Records not listed fall back to TRUE. Passed through to build_age_input().

base_dir

Character string specifying the output directory (default: syncer_base_dir(), i.e. the directory chosen with syncer_setup(), or a temporary directory if none was chosen). Use the same folder as the coredir in rbacon/rplum.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Invisibly, a named list with the same structure as record_data: the record frames with the new synchronized ages baked in, keyed by the folder generation that was written (unchanged keys when update_records = TRUE). Assign it and pass it to the next age_model_input() call.


Assign ages to non-synchronous horizons to use as older/younger than inputs

Description

Assigns a reference age to test horizons that were excluded from secondary synchronization so they can be used as "older than"/"younger than" constraints in the age-depth model. Each excluded horizon receives the synchronized age of the horizon group it belongs to: e.g. an excluded "synchro-test-wrong" layer takes the age computed for its group "synchro-test". The member-to-group mapping comes from horizon_groups (as passed to synchronize_ages()). Exclusions are parsed with the same logic as synchronize_ages() (named for per-record, unnamed for global).

Usage

assign_nonsynchro_age(
  adjusted_ages,
  nonsynchro_horizons,
  event_stats,
  horizon_groups = NULL,
  verbose = TRUE
)

Arguments

adjusted_ages

Output from synchronize_ages() containing synchronized ages.

nonsynchro_horizons

Named or unnamed character vector specifying non-synchronized horizons (same format as in synchronize_ages()).

event_stats

Output from process_event_ages() containing record metadata.

horizon_groups

Named list mapping each horizon group to its member labels, as passed to synchronize_ages() / compute_synchronized_ages(). Used to map an excluded member label to the group whose synchronized age it should take (default: NULL).

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Details

If an excluded horizon has no synchronized age for its group (it was excluded altogether, so no group age was ever computed), it is skipped with a warning; compute an age for it separately with synchronize_ages() using the method of your choice ("mean", "ageofrecord", "Bayesian", ...).

Value

Named list with one element per excluded horizon, each containing a data frame with columns: record, adjusted_age, adjusted_error.


Bayesian combination of age probabilty density functions

Description

Combines multiple posterior age distributions using Bayesian product of probability density functions. Uses kernel density estimation to construct PDFs from samples, multiplies densities in log-space to avoid underflow, normalizes using trapezoidal integration, and calculates moment-matched statistics. This is the recommended method for combining ages from multiple records with overlapping distributions.

Usage

bayesian_age_combination(
  samples_list,
  return_full_pdf = FALSE,
  n_grid = 2000,
  bw = "nrd0"
)

Arguments

samples_list

List of numeric vectors containing posterior samples from different records.

return_full_pdf

Logical indicating whether to return the full combined PDF (default: FALSE).

n_grid

Integer specifying number of grid points for kernel density estimation (default: 2000).

bw

Character string or numeric value specifying bandwidth method for KDE (default: "nrd0").

Value

List containing:

  • mean: Numeric mean of the combined distribution

  • sd: Numeric standard deviation of the combined distribution

  • pdf: (if return_full_pdf = TRUE) List with x (grid points) and pdf (density values)


Determine current BP datum (year - 1950)

Description

Returns the number of years elapsed since the radiocarbon BP datum (1950), calculated from the current system date. Used as the default offset/ age_offset argument throughout SyncER to avoid negative age values.

Usage

bp_datum()

Value

Integer: current year minus 1950.


Build input data structures compatible with Bacon and Plum age-depth modelling

Description

Prepares radiocarbon and Pb210 data frames in the format required by the rbacon/rplum age-depth modelling software.

Usage

build_age_input(
  record_data,
  record_name,
  radiocarbon_sample_names = "sample",
  lead_sample_names = "210Pb_sample",
  adjusted_ages = NULL,
  original_ages = TRUE
)

Arguments

record_data

A data frame containing record data with at least columns: event, depth, C14_age, C14_error, and cc (calibration curve indicator).

record_name

Character string used to identify the record.

radiocarbon_sample_names

Character vector of the event label(s) given to the radiocarbon samples you want to include (default: "sample").

lead_sample_names

Character vector of the event label(s) given to the Pb-210 (lead) samples you want to include (default: "210Pb_sample"); leave blank if you only consider radiocarbon ages.

adjusted_ages

Optional list output from synchronize_ages() containing adjusted ages, errors, and depths per horizon (default: NULL).

original_ages

Logical or named logical vector indicating whether to include original radiocarbon ages when adjusted_ages are provided (default: TRUE).

Value

A named list with elements:

  • c14: Data frame formatted for rbacon C14 input

  • pb210: Data frame formatted for rplum containing Pb210 and C14 input, or NULL if no Pb210 data is present


Interpolate event ages from MCMC runs of Raw Bacon/Plum output files

Description

Performs all age interpolation and computation logic from raw rbacon/rplum .out file content.

Usage

compute_event_ages(
  raw_out_data,
  record_data,
  event_types,
  max_depths,
  isochrons,
  test_horizons,
  instantaneous_event_depths = NULL,
  thick = NULL,
  synced = ""
)

Arguments

raw_out_data

Named list of character vectors (raw lines from each .out file), one element per record folder.

record_data

Named list of data frames representing each record's metadata (output from read_record_data()).

event_types

Character vector of all event type names present in your dataset.

max_depths

Named vector containing the depths to which the age models are calculated for each record.

isochrons

Character vector of deposit names that are known to be synchronous.

test_horizons

Character vector of event deposits for which synchronicity should be tested.

instantaneous_event_depths

Optional named list of depth intervals classified as instantaneous deposits per record that should not be considered for event-free depths.

thick

The rbacon/rplum section thickness; single numeric, named list per record, or NULL (default), in which case it is derived per record from the model as max_depths[record] / (n_cols - 3), i.e. the modelled depth range divided by the number of rbacon/rplum sections.

synced

Character string suffix to identify synchronized folders (default: "").

Value

Named list of data frames, one per processed record folder, containing depth columns plus one column per event with interpolated ages.


Calculate synchronicity validation thresholds based on isochron ages and errors

Description

Calculates empirically-based validation thresholds and confidence levels from synchronized age data for use in subsequent synchronicity testing. Calculates the coefficient of variation (CV = sigma/mu) from synchronized ages, multiplies by user-specified sigma values to generate age difference thresholds, and converts sigma values to confidence levels using the standard normal distribution. The age offset is added before calculating CV to ensure consistency accross calculations. These thresholds can be directly used in verify_synchronicity() for synchronicity testing.

Usage

compute_isochron_thresholds(
  adjusted_ages,
  sigma_multiplier = 2,
  age_offset = bp_datum()
)

Arguments

adjusted_ages

Output from synchronize_ages() containing synchronized ages and errors.

sigma_multiplier

Numeric value or named vector giving the user-defined confidence level on the age interval, expressed as a standard-deviation multiplier (default: 2, i.e. ~95.4\ sets how wide an age difference each isochron's assigned error implies, and therefore what age_difference values are reasonable when testing nearby unknown deposits. Supply a named vector to use a different multiplier per horizon.

age_offset

Numeric offset value that was added to ages to avoid negative values (default: bp_datum(), i.e. the current year minus 1950). This offset is added before calculating the coefficient of variation to ensure CV is based on offset ages.

Value

Named list containing:

  • validation_thresholds: Named numeric vector of age difference thresholds (as proportions)

  • confidence_levels: Named numeric vector of corresponding confidence levels (as proportions)

  • sigma_values: Named numeric vector of sigma multipliers used per horizon

  • empirical_cv: Named numeric vector of empirical coefficients of variation

  • age_offset: The age offset value used during threshold calculation

Examples

if (requireNamespace("SyncERdata", quietly = TRUE)) {
  # Set-up: synchronized ages from the example data of the companion package SyncERdata
  isochrons     <- paste0("isochron", 1:7)
  event_stats   <- process_event_ages(SyncERdata::out_data_ages_synced, isochrons)
  adjusted_ages <- synchronize_ages(event_stats, horizons = isochrons, verbose = FALSE)

  # Single sigma for all horizons
  thresholds <- compute_isochron_thresholds(adjusted_ages, sigma_multiplier = 2)

  # Different sigma per horizon
  thresholds <- compute_isochron_thresholds(
    adjusted_ages,
    sigma_multiplier = c(horizon1 = 2, horizon2 = 1, horizon3 = 1.5)
  )

  # With custom age offset
  thresholds <- compute_isochron_thresholds(
    adjusted_ages,
    sigma_multiplier = 2,
    age_offset = 100
  )

  # Use in verify_synchronicity (its first argument is the result of
  # compute_synchronicity_values(); the thresholds are passed to that function)
  synchro <- compute_synchronicity_values(
    event_stats,
    event_names = names(thresholds$validation_thresholds),
    confidence_level = thresholds$confidence_levels,
    age_difference = thresholds$validation_thresholds
  )
  verify_synchronicity(
    synchro,
    event_names = names(thresholds$validation_thresholds)
  )
}

Calculate overall synchronicity score using additive log-ratios

Description

Calculates overall synchronicity scores (i.e. the probability that all horizons are simultaneously synchronous) across multiple records using additive log-ratio (ALR) transformation. Uses the first record alphabetically as reference. The reference record's Monte Carlo resample is drawn once and shared across every non-reference column, since all comparisons are against the same single (uncertain) reference record; each non-reference record is independently resampled, reflecting that their age models are unrelated.

Usage

compute_overall_synchronicity(
  samples_list,
  conf_level,
  age_diff_log_bounds,
  n_samples = 10000,
  seed = 5128
)

Arguments

samples_list

Named list of numeric vectors containing posterior age samples, one per record.

conf_level

Numeric value specifying the confidence level for the test (e.g., 0.95).

age_diff_log_bounds

Two-element numeric vector with log-space age difference bounds.

n_samples

Integer number of Monte Carlo draws per record (default: 10000).

seed

Integer random seed for reproducibility (default: 5128).

Value

Named list containing:

  • overall_score: Numeric value representing the proportion of joint Monte Carlo draws (rows of the (k-1)-dimensional ALR distribution) for which every non-reference record is simultaneously within bounds of the shared reference draw for that row. This is the joint probability that all considered records are synchronous.

  • overall_precision: Numeric value representing the smallest age-difference tolerance (as a proportion) for which overall_score's joint (all-records-simultaneously) requirement would reach conf_level, or NA if the distribution is unsuitable

  • n_records: Integer count of records included in the analysis

  • ref_record: Character string identifying the reference record used as denominator in ALR


Compute synchronicity score and precision for considered event deposits

Description

Performs all pairwise comparisons and overall calculations of synchronicity score and synchronicity precision.

Usage

compute_synchronicity_values(
  event_stats,
  event_names,
  confidence_level = 0.95,
  age_difference = 0.05,
  horizon_groups = NULL,
  n_samples = 10000,
  seed = 5128
)

Arguments

event_stats

Output from process_event_ages().

event_names

Character vector of event names to test.

confidence_level

Numeric value or named vector giving the confidence level (a ratio) at which synchronicity is tested (default: 0.95). Only correlations whose synchronicity score exceeds this value pass the test: e.g. with confidence_level = 0.95, only pairs scoring higher than 0.95 are counted as passes. Supply a named vector to use different confidence levels per horizon.

age_difference

Numeric value or named vector giving the maximum age difference between two records that is still considered synchronous (default: 0.05). Interpreted in one of two ways depending on its magnitude:

  • Values < 1 are treated as a relative (proportional) age difference. For example, age_difference = 0.05 means the synchronicity score reports the confidence with which the maximum age difference between the two records is 5\

  • Values >= 1 are treated as an absolute age difference in years (e.g. 10 for 10 yr), converted internally to a relative difference using the horizon's mean age.

Supply a named vector to set different values for different horizons; include one unnamed (or last) value to act as the default for any horizon not named.

horizon_groups

Named list mapping group names to character vectors of horizon names that belong to each group (e.g., list(tephra = c("tephra1", "tephra1a"))). When NULL (default) each horizon in event_names is treated as standalone. Use this to explicitly declare which horizon names across records belong to the same depositional event.

n_samples

Integer number of Monte Carlo samples drawn per pairwise comparison (default: 10000).

seed

Integer random seed for reproducibility (default: 5128).

Value

Named list with elements:

  • results: Pairwise log-ratio results

  • overall_scores: Overall synchronicity scores per horizon group

  • viz_data: Data frame of visualization inputs (one row per pairwise comparison)

  • all_scores: Data frame of all pairwise scores

  • summary: List with total, positives, negatives, min_score, max_score, positive_pct, negative_pct


Compute synchronized ages

Description

Age synchronization function that calculates age for considered isochrons using one of five possible methods.

Usage

compute_synchronized_ages(
  event_stats,
  method = NULL,
  horizons = NULL,
  nonsynchro_horizons = NULL,
  excluded_records = NULL,
  age_record = NULL,
  age_value = NULL,
  age_error = NULL,
  age_cc = NULL,
  offset = bp_datum(),
  seed = 5128,
  n_samples = 10000,
  bayes_plot_opts = list(),
  horizon_groups = NULL,
  verbose = TRUE
)

Arguments

event_stats

List containing processed age data and summaries (output from process_event_ages()).

method

Character string or named character vector specifying the synchronization method(s) used to assign a fixed age (and thus set the age difference between records to zero) for each horizon. Supply a single string to apply one method to every horizon in horizons, or a named vector (c(isochron1 = "mean_fixederror", isochron2 = "age")) to use different methods for different horizons. Any horizon listed in horizons but not named here falls back to "mean". One of the following (default: NULL, i.e. "mean" for every horizon):

  • "mean" uses the mean and standard deviation of the available age estimates across records. Recommended when the actual age is unknown (default).

  • "mean_fixederror" uses the mean of the available age estimates but applies an arbitrarily small, user-supplied error (via age_error). Recommended when the actual age is unknown and you want to be very strict for synchronicity testing.

  • "Bayesian" combines the per-record age PDFs using the Bayesian rules for combination of probabilities (Bayes 1763; Doran and Hodgson 1975; see https://c14.arch.ox.ac.uk/oxcal3/math_ca.htm#comb). This will generate a plot with the age PDFs of the considered event across the different records, and the resulting age combination. Recommended only when the actual age is unknown but the age-depth models are assumed to be accurate.

  • "ageofrecord" adopts the age estimate of one specific record (chosen via age_record). Recommended when there are clear indications that one age model is more accurate than the others.

  • "age" assigns a specific, externally-known age and error (via age_value, age_error and age_cc). Recommended when independent calibrated age information is available.

horizons

Character vector of the horizon names to synchronize (default: NULL). Include every horizon you want to assign a fixed age to. Horizons listed here without an explicit entry in method are synchronized with "mean" (unless a single method value is supplied that applies to every horizon).

nonsynchro_horizons

Horizons that were tested but are considered not synchronous, and so should not be age-matched across records (default: NULL). Name an entry after a record (list("core2_synced" = "synchro-test-wrong")) to drop that record's layer from the horizon's calculation and from its synchronized age, while the other records still synchronize it. Use the key "global" (or an unnamed entry) to drop a horizon in every record, which is useful for a name variant you never want matched. To skip a standalone horizon altogether, simply leave it out of horizons. Horizon names are matched exactly, so use horizon_groups to declare the name variants of a single event. Pass the same value to assign_nonsynchro_age() to give these horizons an older-than/younger-than reference age instead.

excluded_records

Character vector or named list of records to exclude from the pooled ("mean", "mean_fixederror", "Bayesian") age calculations (default: NULL) - e.g. a record with unreliable age information. Pass a character vector (c("core3")) to exclude the record(s) for every horizon, or a named list (list("isochron3" = "core3")) to exclude a record only for specific horizons.

age_record

Character string naming the record whose age estimate is adopted when method = "ageofrecord" (default: NULL).

age_value

Numeric value or named vector giving the age(s) to assign when method = "age" (default: NULL). Name the entries after the horizons (c("isochron2" = 1100, "isochron5" = 4100)) when several horizons use this method.

age_error

Numeric value or named vector of age errors (default: NULL). Required for method = "age" (1-sigma error on age_value) and for method = "mean_fixederror" (the small fixed error to apply); name the entries after the horizons when several are involved (c("isochron1" = 10, "isochron2" = 20)).

age_cc

Numeric value or named vector of calibration-curve codes used with method = "age" (default: NULL; 0 = no calibration / calendar ages, 1 = IntCal20, 2 = Marine20, 3 = SHCal20).

offset

Numeric offset correction value (default: bp_datum(), i.e. the current year minus 1950).

seed

Integer random seed for reproducibility (default: 5128).

n_samples

Integer number of Monte Carlo samples drawn per record by the methods that resample posterior ages (default: 10000).

bayes_plot_opts

Named list of Bayesian plot layout options. Supported keys: fig_width, fig_height, plot_range_sigma, posterior_lwd, combined_lwd, legend_pos.

horizon_groups

Named list mapping group names to character vectors of horizon names that belong to each group (e.g., list(tephra = c("tephra1", "tephra1a"))). When NULL (default) each horizon in horizons is treated as standalone. Use this to explicitly declare which horizon names across records belong to the same depositional event.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Named list with two elements:

  • adjusted_ages: Named list of data frames (one per horizon) with columns record, adjusted_age, adjusted_error, cc

  • bayesian_plot_data: Named list (one entry per Bayesian horizon) with raw plot data - pass each element to plot_bayesian_age_combination() to draw to the console or save a PDF


Load and store event ages from Bacon/Plum output files

Description

Wrapper function that reads rbacon/rplum .out files and returns a named list of processed event ages. Combines read_age_model_output() and compute_event_ages() into a single call. When reload_existing is TRUE, the previously exported CSV folder is returned instead.

Usage

load_event_ages(
  folder_path = syncer_input_dir(),
  record_data,
  event_types,
  max_depths,
  isochrons,
  test_horizons,
  synced = "",
  reload_existing = FALSE,
  instantaneous_event_depths = NULL,
  thick = NULL,
  output_dir = syncer_output_dir(),
  verbose = TRUE
)

Arguments

folder_path

Character string giving the parent directory that contains per-record rbacon/rplum output sub-folders (default: the directory set by syncer_setup(), or the current working directory if unset, matching the coredir used by rbacon/rplum and age_model_input()). Ignored when reload_existing = TRUE.

record_data

Named list of data frames representing each record's metadata (output from read_record_data()).

event_types

Character vector of all event type names present in your dataset.

max_depths

Named numeric vector of maximum depths per record.

isochrons

Character vector of deposit names known to be synchronous.

test_horizons

Character vector of event deposits for which synchronicity should be tested.

synced

Character string suffix identifying synchronized output folders (default: "").

reload_existing

Logical; when TRUE reads from an already-exported CSV folder instead of re-processing .out files (default: FALSE).

instantaneous_event_depths

Optional named list of depth intervals classified as instantaneous deposits per record that should not be considered for event-free depths.

thick

The rbacon/rplum section thickness used during age-depth modelling; single numeric, named list per record, or NULL (default), in which case it is derived per record from the model as max_depths[record] / (n_cols - 3).

output_dir

Character string specifying where the previously-exported out_data_ages folder lives; only used when reload_existing = TRUE (default: syncer_output_dir(), i.e. the SyncER_outputs folder in the working directory).

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Named list of data frames, one per processed record, containing depth columns plus one column per event with interpolated ages.


Derive event-type variables from a defined horizon group

Description

Expands a single horizon_groups definition into the event_types, isochrons, test_events, isochron_groups, and test_horizon_groups values consumed by the rest of the SyncER workflow (load_event_ages(), compute_synchronicity_values(), synchronize_ages(), etc.). Combine with list2env() to unpack the result into your script in a single line, e.g. list2env(load_horizon_names(horizon_groups), environment()).

Usage

load_horizon_names(horizon_groups)

Arguments

horizon_groups

Named list, one entry per event type present in your records. Each entry is itself a list with:

  • role: one of "isochron", "test", or "other".

  • members: optional character vector of the actual per-record labels that belong to this group (defaults to the entry's own name when omitted, i.e. a standalone horizon). Only needed when several differently-named labels in your records should be compared together as one group (e.g. a deliberately incorrect "-wrong" variant).

Value

A named list with elements event_types, isochrons, test_events, isochron_groups, and test_horizon_groups.


Plot Bayesian age combination results

Description

Automatically draws the Bayesian posterior combination figure for one horizon group from the raw data returned by compute_synchronized_ages()$bayesian_plot_data. Records that contributed to the combined result are drawn as solid lines; records excluded from the combination (via excluded_records) are drawn as dashed lines and labelled "(excluded)" in the legend. Prints to the active graphics device (console) and, when output_dir is supplied, also saves a PDF.

Usage

plot_bayesian_age_combination(pd, output_dir = NULL, verbose = TRUE)

Arguments

pd

Named list for a single horizon, as stored in compute_synchronized_ages()$bayesian_plot_data. Must contain elements samples_list_shifted, combined_pdf_x, combined_pdf_vals, valid_records, mu_comb, sigma_comb, group_name, and bayes_opts. May also contain excluded_samples_shifted and excluded_records (shifted posterior samples and names of records excluded from the combination); when absent, no excluded records are drawn.

output_dir

Character string; directory the PDF is saved to. Pass NULL to skip PDF output.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Invisibly returns NULL.


Create synchronicity evaluation plots per pairwise comparison of records

Description

Generates a two-panel visualization for a single event in two records: (1) histogram of log-ratio values with fitted normal distribution & statistics, confidence intervals, and age difference thresholds; (2) age probability density function (PDFs) for both records shown as histograms with frequency gradients.

Usage

plot_pairwise_synchronicity_evaluation(
  Amin,
  Amax,
  Bmin,
  Bmax,
  ABlr,
  sheet1_name,
  sheet2_name,
  column_name,
  col1 = NULL,
  col2 = NULL,
  age_diff_log_bounds = NULL,
  conf_log_bounds = NULL,
  conf_level = 0.95,
  variant1 = NULL,
  variant2 = NULL,
  plot_opts = list()
)

Arguments

Amin

Numeric minimum age range for record A.

Amax

Numeric maximum age range for record A.

Bmin

Numeric minimum age range for record B.

Bmax

Numeric maximum age range for record B.

ABlr

Numeric vector of log-ratio values (log(A/B)).

sheet1_name

Character string identifying record A.

sheet2_name

Character string identifying record B.

column_name

Character string identifying the event/horizon being compared.

col1

Numeric vector of posterior age samples for record 1 (default: NULL).

col2

Numeric vector of posterior age samples for record 2 (default: NULL).

age_diff_log_bounds

Two-element numeric vector specifying log-space age difference thresholds (shown as green lines on histogram plot).

conf_log_bounds

Two-element numeric vector specifying confidence interval bounds in log-space (shown as blue shading on histogram plot).

conf_level

Numeric value specifying the confidence level used (e.g., 0.95).

variant1

Optional character string specifying exact horizon name in record 1 (for generic horizon groups) (default: NULL).

variant2

Optional character string specifying exact horizon name in record 2 (for generic horizon groups) (default: NULL).

plot_opts

Named list of plot layout options:

  • n_bins: histogram resolution (default: 500)

  • base_size: ggplot base font size in pt (default: 10)

  • label_size: record label text size (default: 3)

  • annotation_size: statistical annotation text size (default: 3)

  • minor_break_by: x-axis minor tick spacing in cal yrs (default: 100)

  • x_n_breaks: approximate number of major x-axis breaks (default: 10)

  • age_axis_label: age distribution panel's x-axis label (default: "Age (cal yrs BP)")

Value

No return value. Creates a composite plot with two panels displayed in the current graphics device.


Plot synchronicity evaluation plots per horizon across all records

Description

Produces per-horizon PDF files and console visualizations from a compute_synchronicity_values() result.

Usage

plot_synchronicity_evaluation(
  synchro_result,
  output_dir = syncer_output_dir(),
  offset = bp_datum(),
  synced = "",
  fig_width = 10,
  fig_height = 8,
  plot_opts = list(),
  verbose = TRUE
)

Arguments

synchro_result

The list returned by compute_synchronicity_values().

output_dir

Character string specifying the directory the PDF files will be saved to (default: syncer_output_dir(), i.e. the SyncER_outputs folder in the working directory).

offset

Numeric offset correction value applied to ages before plotting (default: bp_datum(), i.e. the current year minus 1950).

synced

Character string appended to PDF file names (default: "").

fig_width

Numeric width of output PDF figures in inches (default: 10).

fig_height

Numeric height of output PDF figures in inches (default: 8).

plot_opts

Named list of plot layout options:

  • n_bins: histogram resolution (default: 500)

  • base_size: ggplot base font size in pt (default: 10)

  • label_size: record label text size (default: 3)

  • annotation_size: statistical annotation text size (default: 3)

  • minor_break_by: x-axis minor tick spacing in cal yrs (default: 100)

  • x_n_breaks: approximate number of major x-axis breaks (default: 10)

  • age_axis_label: age distribution panel's x-axis label (default: "Age (cal yrs BP)")

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Invisibly returns NULL.


Prepare age data for log-ratio transformation and calculate basic statistics

Description

Extracts event-specific age columns from rbacon/rplum output, applies offset correction, and calculates summary statistics. Filters columns matching event deposit patterns, applies offset to avoid negative ages for post-1950 deposits, and ensures the record top is at age 0. This function takes the direct output from load_event_ages() and processes it in memory.

Usage

process_event_ages(out_data, event_deposits, offset = bp_datum())

Arguments

out_data

Named list of data frames or data.tables containing age data (output from load_event_ages()).

event_deposits

Character vector of event deposit names to extract (typically isochrons or test_events). Columns whose name starts with any of these names are selected.

offset

Numeric value added to every age so that the age reference point becomes, for example, the year the (most recent) records were retrieved rather than 1950 AD (default: bp_datum(), i.e. the current year minus 1950). Because the synchronicity test uses log-transformations, the age dataset may not contain zero or negative values. Set it manually if you want a different reference point, but use the same offset consistently throughout the workflow.

Value

A named list with two elements:

  • processed: List of data frames with offset-corrected ages for each record

  • summaries: List of summary data frames containing min, max, mean, and sd (sigma) for each event column


Read age results of age-depth modelling for each of the event horizons

Description

Reads a folder of CSV files containing all age information for events, one file per record, and returns a named list of data frames. This is the inverse operation of write_age_output_data(), and allows you to reload previously saved results without recalculating or load age info into SyncER in case the age-depth models were not constructed using rbacon/rplum.

Usage

read_age_data(folder_path = syncer_output_dir(), synced = "", verbose = TRUE)

Arguments

folder_path

Character string specifying the location of the folder to be read (default: syncer_output_dir(), i.e. the SyncER_outputs folder in the working directory).

synced

Character string suffix for the input folder name (default: ""); use "_synced" for synchronized data.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

A named list of data frames, where each element corresponds to one record. List names match the CSV file names (without extension).

Examples

if (requireNamespace("SyncERdata", quietly = TRUE)) {
  # Set-up: save the example data of the companion package SyncERdata to a
  # temporary folder (stands in for "path/to/folder")
  folder <- tempdir()
  write_age_output_data(SyncERdata::out_data_ages, folder, verbose = FALSE)
  write_age_output_data(SyncERdata::out_data_ages_synced, folder,
                        synced = "_synced", verbose = FALSE)

  # Read non-synchronized data
  out_data <- read_age_data(folder)

  # Read synchronized data
  out_data_synced <- read_age_data(folder, synced = "_synced")

  # Use with process_event_ages
  event_stats <- process_event_ages(out_data, event_deposits = c("tephra", "flood"))
}

Read Bacon/Plum age-depth modelling output files

Description

Reads raw lines from rbacon/rplum .out files for a set of records into a named list. Call this function to obtain raw age data, then pass the result to compute_event_ages() for computation of event ages, and finally call write_age_output_data() to save the processed ages in your folder.

Usage

read_age_model_output(
  folder_path = syncer_input_dir(),
  synced = "",
  max_depths = NULL,
  instantaneous_event_depths = NULL,
  verbose = TRUE
)

Arguments

folder_path

Character string giving the parent directory that contains the per-record rbacon/rplum output sub-folders (default: the directory set by syncer_setup(), or the current working directory if unset, matching the coredir used by rbacon/rplum and age_model_input()).

synced

Character string suffix used to identify synchronized output folders (default: ""; non-empty values such as "_synced" select only folders ending with that suffix).

max_depths

Named numeric vector of original core depths (cm), used only for progress reporting. Pass NULL to skip depth messages.

instantaneous_event_depths

Optional named list of excluded depth intervals per record, used only for progress reporting.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Named list of character vectors (one element per folder / record), where each element contains the raw text lines of the corresponding .out file.


Load age input data and event depths

Description

Loads age input dates (radiocarbon and/or 210Pb) and event depths of all records from a folder of CSV files and calculates maximum depths and sedimentation rates for each record. The function reads every .csv file in the folder, where each file represents one sediment record. For records missing required columns ('depth' or 'C14_age'), warnings are issued and NA values are returned.

Usage

read_record_data(
  folder_path = syncer_input_dir(),
  file_name = "record_data_input"
)

Arguments

folder_path

Character string specifying the path to the folder containing your input file (default: the directory set by syncer_setup(), or the current working directory if unset).

file_name

Character string specifying the name of the subfolder (inside folder_path) that holds your input CSV files (default: "record_data_input"). This folder holds one CSV file per record (named <record>.csv), and each file gives, for every dated sample and for the record top, the depth, C14_age and C14_error, together with the radiocarbon calibration curve code in the cc column (0 = no calibration / calendar ages, 1 = IntCal20, 2 = Marine20, 3 = SHCal20). The file must also list the depths of the considered event deposits; these depths may be given either as event-free depth or as total depth.

Value

A named list with three elements:

  • record_data: Named list of data frames, one per record (each CSV file becomes one element)

  • max_depths: Named numeric vector containing the maximum depth value for each record

  • sedrates: Named numeric vector containing an estimated sedimentation rate for each record (calculated as oldest C14 age divided by its depth)


Set up SyncER working directory and output folder

Description

Optional first step of a SyncER script: choose the folder SyncER should work in (holding your record_data_input folder and the age-depth model folders, and receiving all output in a SyncER_outputs subfolder). The choice is remembered for the rest of the R session (via options(SyncER.wd = ...)) and used as the default location by the other SyncER functions, so you only need to set it once, at the top of your script. If the folder does not exist yet, it is created. Your R working directory (getwd()) is never changed. If you never call this function, input is read from the current working directory and output is written to a per-session temporary directory (see syncer_output_dir), so SyncER never writes to your file space without being asked to.

Usage

syncer_setup(wd = getOption("SyncER.wd"), verbose = TRUE)

Arguments

wd

Character string giving the directory SyncER should use. If omitted, first checks options(SyncER.wd = ...); if that is unset and the session is interactive, asks for a path via readline(). Leave blank (or pass "") to use the current working directory.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Invisibly returns the path to the SyncER_outputs directory.

Examples

# Use a temporary directory (never write to your own file space in examples)
old <- options(SyncER.wd = getOption("SyncER.wd"))
syncer_setup(wd = tempdir())
options(old) # restore the previous setting

Computes synchronized ages and plots Bayesian age combinations if used

Description

Calls compute_synchronized_ages() and saves Bayesian combination plots to PDF if used as a matching method.

Usage

synchronize_ages(
  event_stats,
  output_dir = syncer_output_dir(),
  method = NULL,
  horizons = NULL,
  nonsynchro_horizons = NULL,
  excluded_records = NULL,
  age_record = NULL,
  age_value = NULL,
  age_error = NULL,
  age_cc = NULL,
  offset = bp_datum(),
  seed = 5128,
  n_samples = 10000,
  bayes_plot_opts = list(),
  horizon_groups = NULL,
  verbose = TRUE
)

Arguments

event_stats

List containing processed age data and summaries (output from process_event_ages()).

output_dir

Character string specifying the directory Bayesian plot PDFs will be saved to (default: syncer_output_dir(), i.e. the SyncER_outputs folder in the working directory).

method

Character string or named character vector specifying the synchronization method(s) used to assign a fixed age (and thus set the age difference between records to zero) for each horizon. Supply a single string to apply one method to every horizon in horizons, or a named vector (c(isochron1 = "mean_fixederror", isochron2 = "age")) to use different methods for different horizons. Any horizon listed in horizons but not named here falls back to "mean". One of the following (default: NULL, i.e. "mean" for every horizon):

  • "mean" uses the mean and standard deviation of the available age estimates across records. Recommended when the actual age is unknown (default).

  • "mean_fixederror" uses the mean of the available age estimates but applies an arbitrarily small, user-supplied error (via age_error). Recommended when the actual age is unknown and you want to be very strict for synchronicity testing.

  • "Bayesian" combines the per-record age PDFs using the Bayesian rules for combination of probabilities (Bayes 1763; Doran and Hodgson 1975; see https://c14.arch.ox.ac.uk/oxcal3/math_ca.htm#comb). This will generate a plot with the age PDFs of the considered event across the different records, and the resulting age combination. Recommended only when the actual age is unknown but the age-depth models are assumed to be accurate.

  • "ageofrecord" adopts the age estimate of one specific record (chosen via age_record). Recommended when there are clear indications that one age model is more accurate than the others.

  • "age" assigns a specific, externally-known age and error (via age_value, age_error and age_cc). Recommended when independent calibrated age information is available.

horizons

Character vector of the horizon names to synchronize (default: NULL). Include every horizon you want to assign a fixed age to. Horizons listed here without an explicit entry in method are synchronized with "mean" (unless a single method value is supplied that applies to every horizon).

nonsynchro_horizons

Horizons that were tested but are considered not synchronous, and so should not be age-matched across records (default: NULL). Name an entry after a record (list("core2_synced" = "synchro-test-wrong")) to drop that record's layer from the horizon's calculation and from its synchronized age, while the other records still synchronize it. Use the key "global" (or an unnamed entry) to drop a horizon in every record, which is useful for a name variant you never want matched. To skip a standalone horizon altogether, simply leave it out of horizons. Horizon names are matched exactly, so use horizon_groups to declare the name variants of a single event. Pass the same value to assign_nonsynchro_age() to give these horizons an older-than/younger-than reference age instead.

excluded_records

Character vector or named list of records to exclude from the pooled ("mean", "mean_fixederror", "Bayesian") age calculations (default: NULL) - e.g. a record with unreliable age information. Pass a character vector (c("core3")) to exclude the record(s) for every horizon, or a named list (list("isochron3" = "core3")) to exclude a record only for specific horizons.

age_record

Character string naming the record whose age estimate is adopted when method = "ageofrecord" (default: NULL).

age_value

Numeric value or named vector giving the age(s) to assign when method = "age" (default: NULL). Name the entries after the horizons (c("isochron2" = 1100, "isochron5" = 4100)) when several horizons use this method.

age_error

Numeric value or named vector of age errors (default: NULL). Required for method = "age" (1-sigma error on age_value) and for method = "mean_fixederror" (the small fixed error to apply); name the entries after the horizons when several are involved (c("isochron1" = 10, "isochron2" = 20)).

age_cc

Numeric value or named vector of calibration-curve codes used with method = "age" (default: NULL; 0 = no calibration / calendar ages, 1 = IntCal20, 2 = Marine20, 3 = SHCal20).

offset

Numeric offset correction value (default: bp_datum(), i.e. the current year minus 1950).

seed

Integer random seed for reproducibility (default: 5128).

n_samples

Integer number of Monte Carlo samples drawn per record by the methods that resample posterior ages (default: 10000).

bayes_plot_opts

Named list of Bayesian plot layout options passed to compute_synchronized_ages(). Supported keys: fig_width, fig_height, plot_range_sigma, posterior_lwd, combined_lwd, legend_pos.

horizon_groups

Named list mapping group names to character vectors of horizon names that belong to each group (e.g., list(tephra = c("tephra1", "tephra1a"))). When NULL (default) each horizon in horizons is treated as standalone. Use this to explicitly declare which horizon names across records belong to the same depositional event.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Named list of synchronized ages (one element per horizon), as returned by compute_synchronized_ages()$adjusted_ages.


Write and plot synchronicity testing results for evaluation

Description

Saves a CSV of horizon statistics, prints a summary to the console, and produces per-horizon visualizations of the age PDFs and log-ratio distributions. Call compute_synchronicity_values() first and pass its result here.

Usage

verify_synchronicity(
  synchro_result,
  event_names,
  output_dir = syncer_output_dir(),
  group_name = NULL,
  synced = "",
  isochron = FALSE,
  offset = bp_datum(),
  fig_width = 10,
  fig_height = 8,
  plot_opts = list(),
  verbose = TRUE
)

Arguments

synchro_result

The list returned by compute_synchronicity_values().

event_names

Character vector of event names being tested. Falls back to naming the CSV file when group_name is not supplied.

output_dir

Character string specifying the directory the statistics CSV will be saved to (default: syncer_output_dir(), i.e. the SyncER_outputs folder in the working directory).

group_name

Character string used to name the CSV file (as "<group_name>_stats.csv"), representing the horizon group being tested as a whole rather than every individual horizon name in event_names. When NULL (default), defaults to "isochron" if isochron = TRUE, or to all of event_names pasted together otherwise.

synced

Character string appended to output filenames (default: "").

isochron

Logical; when TRUE a warning is shown if >10\ fail, and the CSV file is named "isochron" by default (default: FALSE).

offset

Numeric offset correction value passed to plot_synchronicity_evaluation() (default: bp_datum(), i.e. the current year minus 1950).

fig_width

Numeric width of output PDF figures in inches (default: 10).

fig_height

Numeric height of output PDF figures in inches (default: 8).

plot_opts

Named list of plot layout options:

  • n_bins: histogram resolution (default: 500)

  • base_size: ggplot base font size in pt (default: 10)

  • label_size: record label text size (default: 3)

  • annotation_size: statistical annotation text size (default: 3)

  • minor_break_by: x-axis minor tick spacing in cal yrs (default: 100)

  • x_n_breaks: approximate number of major x-axis breaks (default: 10)

  • age_axis_label: age distribution panel's x-axis label (default: "Age (cal yrs BP)")

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

Invisibly returns synchro_result unchanged.


Write age data (including event ages) into CSV files

Description

Each record's age information (including event ages) is written to a separate CSV file inside an output folder, with file names matching the list element names, and each row represents a single MCMC simulation.

Usage

write_age_output_data(
  out_data,
  folder_path = syncer_output_dir(),
  synced = "",
  verbose = TRUE
)

Arguments

out_data

Named list of data frames where each element will become a separate CSV file.

folder_path

Character string specifying the location where the output folder should be saved (default: syncer_output_dir(), i.e. the SyncER_outputs folder in the working directory).

synced

Character string suffix for the output folder name (default: ""); use "_synced" for synchronized data.

verbose

Logical; if TRUE (default), progress and summary messages are printed via message(). Set to FALSE to suppress them.

Value

No return value. Writes one CSV file per record and prints a success message with the folder path.