Skip to main content

Mapping Files

Mapping files describe how project-specific CSV, REDCap, or CDISC-ODM fields become Beacon v2 records. They can also augment the built-in cBioPortal mapping or define reviewed terminology decisions for SDTM Dataset-JSON and Dataset-XML. Built-in BFF routes can use a small optional mapping to describe their synthesized dataset and cohort. The examples below cover the full Mapping V2 contract and its smaller profiles.

Google Colab version

A runnable notebook is available in Google Colab, with a local copy in the repository.

The notebook clones the latest main branch and reports the Convert-Pheno version and Git commit used.

Files Required​

A REDCap conversion normally uses:

  1. The data export in CSV format
  2. The REDCap data dictionary in CSV format
  3. A Convert-Pheno mapping file in YAML or JSON format

The data dictionary explains REDCap field types, labels, choices, notes, and ranges. The mapping file makes the project-specific semantic decisions.

CSV needs only the source file and mapping. REDCap-origin ODM uses the same redcap mapping profile and dictionary as REDCap CSV. Standard or OpenClinica ODM uses source.profile: cdisc-odm and resolves labels, data types, and coded values from metadata embedded in the XML, without a REDCap dictionary.

cBioPortal uses source.profile: cbioportal. Its package metadata already defines patients, samples, study identity, and case-list links, so a mapping is optional and is used only for additional project-specific clinical columns.

Dataset-JSON and Dataset-XML use source.profile: sdtm. Their structural SDTM mapping is built in, so the optional mapping contains only terminology rules. Dataset-XML still requires Define-XML independently of this optional mapping.

OMOP, PXF, FHIR, openEHR, i2b2, PCORnet, and Sentinel already have structural conversion rules in the software. Their optional mapping is a metadata overlay: it can name synthesized datasets and cohorts, but cannot replace individual or biosample field mappings.

Recipe: CSV To Validated BFF​

A small end-to-end example

Suppose a project gives you this semicolon-delimited clinical.csv:

participant_id;sex;diagnosis
P001;Female;ASTHMA_LOCAL
P002;Male;

The values are deliberately simple, but the important detail is realistic: ASTHMA_LOCAL is a project label, not an ontology term. A first Mapping V2 file can translate that label while asking Convert-Pheno to find the actual NCIT concept:

mapping.yaml
mappingVersion: 2

source:
profile: csv

target:
model: beacon
schemaVersion: '2.0.0'

project:
id: csv-bff-recipe
version: '1.0'

defaults:
ontology: ncit

records: {}

beacon:
individuals:
id:
sourceFields: [participant_id]
primaryKey: participant_id
missingValue: NA

sex:
sourceField: sex
query: {from: value}

diseases:
rules:
- sourceField: diagnosis
when: {nonEmpty: true}
diseaseCode:
query:
from: value
aliases:
ASTHMA_LOCAL: Asthma

Now convert the CSV and ask for a terminology audit in the same run:

mkdir -p output

convert-pheno \
-icsv clinical.csv \
--separator ';' \
--mapping-file mapping.yaml \
--search exact \
--term-audit output/terminology.tsv \
-obff output/individuals.json

individuals.json is the BFF result. terminology.tsv explains how each ontology decision was made. In this example, Female, Male, and Asthma should be exact database matches. If a term is unresolved, correct the alias or mapping and run the command again; do not lower the search threshold merely to obtain a result.

Advanced: tool-assisted terminology validation

An LLM can help draft a mapping if it can query the same source metadata, terminology databases, audit report, and target validator used by the person reviewing the result. A term proposed from model memory alone is not evidence.

For example, when the LLM proposes a direct NCIT term, it can verify the pair against the database bundle selected by share/db/manifest.json:

sqlite3 share/db/v0/ncit.db \
"SELECT 'NCIT:' || id, label FROM NCIT_table WHERE id = 'C28397' COLLATE NOCASE;"

Record which ontology release you checked. Its version and checksum are in share/db/manifest.json.

Two checks remain separate:

  • Does the code exist, and does its label match? Check the ontology database.
  • Does it mean the same thing as the source value? Check the source documentation and ask a domain expert when the meaning is unclear.

If the audit says configured or direct_mapping, Convert-Pheno copied the term from the mapping file. Verify that term separately against the selected database and record the result.

Finally, validate the generated BFF with bff-tools:

bff-tools validate -i output/individuals.json -nc -ne

Review every reported path. With some Beacon v2 schema releases, a disease may produce an ageOfOnset oneOf message because the schema's object alternatives overlap. That specific message is a known schema ambiguity, not evidence of an incorrect ontology lookup. Retain it in the validation record, but do not use it to dismiss any other validation issue.

Tooling can automate repeated conversion and validation runs. A person still has to resolve ambiguous clinical meanings and approve the mapping. For restricted data, use an approved environment and disclose only the source information needed for the task.

Mapping V2 At A Glance​

Two independent versions are declared at the top of every mapping:

KeyMeaning
mappingVersion: 2Version of the Convert-Pheno mapping language
target.schemaVersion: '2.0.0'Beacon v2 schema version targeted by the mapping
project.versionVersion assigned by your project to this mapping
Breaking mapping format

Mapping V2 is intentionally not compatible with the pre-V2 layout. Removed constructs such as fieldTermLabels, valueTermLabels, targetFields, and baselineFieldsToPropagate are not accepted. This prevents old configuration from being interpreted with new semantics.

Compact REDCap mapping
mappingVersion: 2

source:
profile: redcap

target:
model: beacon
schemaVersion: '2.0.0'

project:
id: my_study
version: '1.0'

defaults:
ontology: ncit

records:
visitId:
sourceField: redcap_event_name
baseline:
strategy: firstNonNull
sourceFields: [sex, diagnosis]

beacon:
individuals:
id:
sourceFields: [record_id, redcap_event_name]
primaryKey: record_id
separator: ':'

sex:
sourceField: sex
query: { from: value }

diseases:
rules:
- sourceField: diagnosis
when: { nonEmpty: true }
diseaseCode:
query:
from: value
aliases:
UC: Ulcerative Colitis
CD: Crohn Disease
ageOfOnset: { sourceField: age_at_diagnosis }

info:
sourceFields: [record_id, redcap_event_name]

The top-level sections have distinct responsibilities:

SectionRequired forPurpose
sourceAll profilesDeclares the normalized source profile
targetAll profilesDeclares the target model and Beacon schema version
projectAll profilesIdentifies and versions the project mapping
defaultsTabular and sdtm profilesSets the default ontology for term lookup
recordsTabular profilesDefines visit and longitudinal baseline behavior
beaconTabular or metadata-only profilesContains entity rules or dataset/cohort defaults
terminologysdtmContains DOMAIN.FIELD terminology rules

Supported default ontologies are ncit, icd10, ohdsi, cdisc, omim, and hpo. Individual term rules may select another supported ontology.

The route still determines how the input is parsed. source.profile describes the record and metadata contract consumed by the mapping:

ProfileUse
csvCSV input
redcapREDCap CSV or a REDCap-origin ODM export with an external dictionary
cdisc-odmStandard or vendor ODM with embedded MetaDataVersion, ItemDef, and CodeList metadata
cbioportalcBioPortal patient and sample clinical tables discovered from a study package
sdtmDataset-JSON or Dataset-XML terminology enrichment; structural mapping remains built in
omop, pxf, fhir, openehr, i2b2, pcornet, sentinelOptional dataset and cohort metadata for the matching built-in BFF route

ODM mappings use stable ItemOID values as source fields. A REDCap ODM export can reuse its corresponding REDCap mapping. Other ODM documents need rules tailored to their own item identifiers, but do not need a fabricated REDCap dictionary when the required metadata is embedded.

Compact SDTM Terminology Mapping​

For Dataset-JSON and Dataset-XML, omit records and beacon. Key each terminology decision by the SDTM domain and variable:

mappingVersion: 2
source: { profile: sdtm }
target: { model: beacon, schemaVersion: '2.0.0' }
project: { id: my_study, version: '1.0' }
defaults: { ontology: ncit }

terminology:
AE.AESEV:
query:
from: value
aliases:
MILD_GRADE: Mild
MH.MHDECOD:
terms:
Asthma: { id: 'NCIT:C28397', label: Asthma }

The alias key is the source value; its value is the reviewed database label. Aliases are selective: this example translates MILD_GRADE, while an unlisted value such as SEVERE is queried unchanged. Case-only aliases are unnecessary because lookup is case-insensitive. terms bypasses lookup for known values. Define-XML nci:ExtCodeID identifiers take precedence over a label query and are looked up exactly to obtain the canonical NCIT display. See Terminology Search for the full precedence and audit fields.

Compact Dataset And Cohort Metadata​

Built-in routes do not need field-level mapping rules. To identify the BFF dataset produced from an OMOP export, for example, provide only project and entity metadata:

mappingVersion: 2
source: { profile: omop }
target: { model: beacon, schemaVersion: '2.0.0' }

project:
id: study-123
version: '1.0'
description: Example study

beacon:
datasets:
defaults:
name: Example dataset
externalUrl: https://example.org/studies/study-123
cohorts:
defaults:
name: Main cohort
cohortType: study-defined

Use it only when requesting entity-aware BFF output:

convert-pheno \
-iomop omop-export/ \
--mapping-file study-metadata.yaml \
-obff --entities individuals datasets cohorts \
--out-dir bff-out/

project.id becomes datasets.id and, unless explicitly overridden, datasets.name; it also supplies the default cohort ID <project.id>-cohort. beacon.datasets.defaults and beacon.cohorts.defaults can override those values and add the other properties accepted by the Beacon v2 entities.

The mapping is optional. Without it, source-derived metadata is used where available, followed by the existing generic dataset-1 and cohort-1 defaults. Project metadata is not currently copied into individual or biosample records.

Reading A Rule​

Each repeated section contains ordered rules. A rule keeps its source selector and Beacon target properties together:

diseases:
rules:
- sourceField: diagnosis
when: { nonEmpty: true }
diseaseCode:
query:
from: value
aliases:
UC: Ulcerative Colitis

Here, diagnosis is the source column. Empty cells are skipped. The recorded value is used as the ontology query, after applying the optional alias.

Source selectors can make that behavior explicit:

KeyMeaning
sourceFieldSource column or ODM ItemOID evaluated by the rule
optionalAllows the field to be absent from compatible exports
when.nonEmptyRequires a non-empty value
when.valuesAccepts only the listed values
when.notValuesRejects the listed values

Repeated ODM item groups are evaluated occurrence by occurrence. Companion sourceField values are taken from the same occurrence; ambiguous repeated values in scalar sections are rejected rather than flattened.

Ontology queries can come from different places:

FormUse
query: { from: value }Search using the recorded value
query: { from: field }Search using the source column name
query: { from: fieldNote }Search using the REDCap dictionary field note
query: Hemoglobin MeasurementSearch a fixed label
term: { id: 'NCIT:C...', label: ... }Use a known ontology term without a database search
termsSelect reviewed terms by source value without a database search

The location of from changes its meaning. Inside query, it selects the text used for ontology lookup. A direct value mapping such as id: { from: sourceValue } copies a scalar value and does not query an ontology database.

Use exact terms when the identifier is already curated. Otherwise, use a query and review terminology resolution with --term-audit.

Scalar targets do not perform terminology lookup:

FormResult
{ from: sourceValue }Uses the current rule value
{ from: individualId }Uses the generated BFF individual ID
{ sourceField: age }Uses another named source field
{ literal: value }Uses a fixed string, number, or boolean

How Defaults Are Reused​

defaults has a specific scope according to where it appears:

LocationApplies to
Top-level defaults.ontologyOntology queries that do not select another ontology
beacon.individuals.<section>.defaultsEvery rule in that repeated individual section only
beacon.biosamples.defaultsEvery rule under beacon.biosamples.rules
beacon.datasets.defaults and beacon.cohorts.defaultsMetadata for the synthesized entity, not rule inheritance

A collection default is not an output record. Before conversion, Convert-Pheno copies it into each sibling rule and then applies the values written on that rule. This lets each rule declare only what differs:

treatments:
defaults:
routeOfAdministration: { query: Oral Route of Administration }
doseIntervals:
quantity:
unit: { query: Milligram }
rules:
- sourceField: aspirin_status
treatmentCode: { query: aspirin }
doseIntervals:
quantity:
value: { sourceField: aspirin_dose }
- sourceField: infliximab_status
treatmentCode: { query: infliximab }
routeOfAdministration: { query: Intravenous Route of Administration }
doseIntervals:
quantity:
value: { sourceField: infliximab_dose }

Both rules inherit Milligram. The aspirin rule also inherits the oral route; the infliximab rule replaces only that route with the intravenous route.

The merge is recursive: rule values override matching defaults, while unmentioned defaults remain in place. Arrays are replaced rather than joined, and setting an optional property to null removes its inherited value. Defaults apply only to target properties and only within their section; sourceField, optional, and when always remain visible on each rule.

Longitudinal Values​

records.baseline can make a value recorded only at baseline available to later rows for the same primaryKey:

records:
baseline:
strategy: firstNonNull
sourceFields: [sex, diagnosis]

Rows must be ordered so the first non-empty value appears before rows that need it. Propagation affects target mapping only. The raw row preserved under info.REDCap_columns or info.CSV_columns remains unchanged, so provenance continues to reflect the input file. Generic ODM uses the occurrence-aware info.CDISC_ODM block instead.

Other Beacon Entities​

The individual mapping supports scalar demographic terms plus repeated diseases, exposures, interventionsOrProcedures, measures, phenotypicFeatures, and treatments rules. Target property names follow the Beacon v2 camelCase schema.

beacon.biosamples contains executable mapping rules, not just metadata. A biosample is emitted when its source condition matches and an ID is available:

beacon:
biosamples:
defaults:
id: { from: sourceValue }
individualId: { from: individualId }
biosampleStatus:
term: { id: 'NCIT:C126101', label: Not Available }
rules:
- sourceField: sample_id
when: { nonEmpty: true }
sampleOriginType: { query: Whole Blood }
collectionDate: { sourceField: collection_date }

Rules can also populate sampleOriginDetail, obtentionProcedure, notes, measurements, and selected info fields. Request biosamples explicitly in entity-aware BFF output.

beacon.datasets.defaults and beacon.cohorts.defaults provide metadata for entities synthesized from the converted individuals. Full authoring mappings and compact metadata overlays use the same entity-default contract.

Validation And Provenance​

Before conversion, Convert-Pheno rejects duplicate keys, validates the mapping against share/schema/mapping-v2.json, checks mapping and Beacon versions, and verifies the selected source profile and referenced fields.

Generated BFF retains source content under its format-specific info block by default. Use --no-source-info to omit that copy and --term-audit FILE to record direct terms, identifier lookups, label searches, and fallbacks.

Run And Review​

Convert REDCap directly to Phenopackets:

convert-pheno -iredcap redcap.csv \
--redcap-dictionary dictionary.csv \
--mapping-file mapping.yaml \
-opxf phenopackets.json

Write individuals and mapped biosamples as separate BFF files:

convert-pheno -iredcap redcap.csv \
--redcap-dictionary dictionary.csv \
--mapping-file mapping.yaml \
-obff \
--entities individuals biosamples \
--out-dir bff-output/

For standard or OpenClinica ODM with embedded metadata, select the ODM profile and omit the REDCap dictionary:

convert-pheno -icdisc-odm study.xml \
--mapping-file odm-mapping.yaml \
-obff individuals.json

For terminology review, add --term-audit terminology.tsv. Exact search is the default; similarity modes and audit columns are documented under Terminology Search.

Continue with REDCap, CSV, Dataset-JSON, or Dataset-XML.