# Ontology Mapper

> >

- **Type:** Skill
- **Install:** `agentstack add skill-heshamfs-materials-simulation-skills-ontology-mapper`
- **Verified:** Pending review
- **Seller:** [HeshamFS](https://agentstack.voostack.com/s/heshamfs)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [HeshamFS](https://github.com/HeshamFS)
- **Source:** https://github.com/HeshamFS/materials-simulation-skills/tree/main/skills/ontology/ontology-mapper

## Install

```sh
agentstack add skill-heshamfs-materials-simulation-skills-ontology-mapper
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Ontology Mapper

## Goal

Translate real-world materials science descriptions into standardized ontology annotations. Given terms like "FCC copper" or structured data like `{"material": "iron", "structure": "BCC", "lattice_a": 2.87}`, produce the corresponding ontology classes and properties for any registered ontology.

## Requirements

- Python 3.10+
- No external dependencies (Python standard library only)
- Requires ontology-explorer's summary JSON and `ontology_registry.json`
- Per-ontology mapping config (`_mappings.json`) for ontology-specific synonyms and labels

## Inputs to Gather

| Input | Description | Example |
|-------|-------------|---------|
| Ontology | Ontology name from registry | `cmso`, `asmo` |
| Term(s) | Natural-language materials concept(s) | `"unit cell"`, `"FCC,copper,lattice"` |
| Crystal system | One of the 7 crystal systems | `cubic`, `hexagonal` |
| Bravais lattice | Lattice type (symbol or common name) | `FCC`, `cF`, `BCC` |
| Space group | Space group number (1-230) | `225` |
| Lattice parameters | a, b, c in angstroms; alpha, beta, gamma in degrees | `a=3.615` |
| Sample description | JSON dict with material properties | `{"material":"copper","structure":"FCC"}` |

## Decision Guidance

```
What do you need to map?
├── A concept or term to find its ontology class
│   └── concept_mapper.py --ontology  --term ""
├── Crystal structure parameters to ontology terms
│   └── crystal_mapper.py --ontology  --bravais  --space-group  --a 
├── A full sample description to ontology annotations
│   └── sample_annotator.py --ontology  --sample ''
└── Multiple terms at once
    └── concept_mapper.py --ontology  --terms "term1,term2,term3"
```

> **Ontology scope — crystal/sample annotation is CMSO-only.** `crystal_mapper.py`
> and `sample_annotator.py` emit crystal-structure vocabulary (Crystalline Material,
> Crystal Structure, Unit Cell, Space Group, lattice properties). This vocabulary is
> defined by **CMSO**. **ASMO is a simulation-methods ontology and does not define any
> crystal/sample classes** — so for ASMO use the concept-mapping path
> (`concept_mapper.py`, which resolves terms like DFT, NPT, timestep, PBE to real ASMO
> classes) only. If `sample_annotator.py`/`crystal_mapper.py` is run with an ontology
> whose summary lacks the required classes (e.g. `--ontology asmo`), each unresolvable
> term is flagged in `results.validation_warnings` and given `confidence: 0.0` rather
> than silently emitting an invalid term.

## Script Outputs (JSON Fields)

| Script | Key Outputs |
|--------|-------------|
| `scripts/concept_mapper.py` | `results.matches`, `results.unmatched`, `results.suggestions` |
| `scripts/crystal_mapper.py` | `results.ontology_classes`, `results.ontology_properties`, `results.effective_system`, `results.bravais_lattice`, `results.validation_warnings` |
| `scripts/sample_annotator.py` | `results.annotations`, `results.sample_type`, `results.material_type`, `results.unmapped_fields`, `results.suggested_properties`, `results.validation_warnings` |

## Workflow

1. If the user provides natural-language terms, use `concept_mapper.py` to find matching ontology classes.
2. If the user describes crystal structure parameters, use `crystal_mapper.py` to map them and validate constraints.
3. For a complete sample description, use `sample_annotator.py` to produce full ontology annotations.
4. Review any validation warnings (e.g., lattice parameter mismatches for the crystal system).
5. Check `unmapped_fields` and `suggested_properties` for completeness.

## Conversational Workflow Example

```
User: I'm setting up an MD simulation of BCC iron with lattice parameter 2.87 angstroms.
      What CMSO terms should I use?

Agent: Let me map your iron sample to CMSO ontology terms.

[Runs: sample_annotator.py --ontology cmso --sample '{"material":"iron","structure":"BCC","lattice_a":2.87,"space_group":229}' --json]

Your BCC iron simulation maps to these CMSO annotations:

- **Sample**: Atomic Scale Sample (subclass of Computational Sample)
- **Material**: Crystalline Material
- **Unit Cell**: Bravais lattice = "cI" (body-centered cubic)
- **Space Group**: number = 229 (Im-3m)
- **Lattice**: a = 2.87 Å
- **Element**: Fe

Suggested additions:
- Number of atoms in the simulation cell
- Simulation cell vectors and angles
```

## CLI Examples

```bash
# Map a single concept
python3 skills/ontology/ontology-mapper/scripts/concept_mapper.py \
  --ontology cmso --term "space group" --json

# Map multiple terms
python3 skills/ontology/ontology-mapper/scripts/concept_mapper.py \
  --ontology cmso --terms "FCC,copper,lattice constant" --json

# Map crystal parameters (with ontology-specific labels)
python3 skills/ontology/ontology-mapper/scripts/crystal_mapper.py \
  --ontology cmso --bravais FCC --space-group 225 --a 3.615 --json

# Map crystal parameters (generic labels, no ontology specified)
python3 skills/ontology/ontology-mapper/scripts/crystal_mapper.py \
  --bravais FCC --space-group 225 --a 3.615 --json

# Annotate a full sample
python3 skills/ontology/ontology-mapper/scripts/sample_annotator.py \
  --ontology cmso \
  --sample '{"material":"copper","structure":"FCC","space_group":225,"lattice_a":3.615}' \
  --json
```

## Adding a New Ontology

To support a new ontology, create a `_mappings.json` in `references/`:

```json
{
  "ontology": "myonto",
  "synonyms": { "simulation method": "Simulation Method", ... },
  "property_synonyms": { "timestep": "has timestep", ... },
  "material_type_rules": { "keyword_rules": [...], "default": "Material" },
  "sample_schema": { "sample_class": "Simulation", ... },
  "crystal_output": { "base_classes": [...], "property_map": {...} },
  "annotation_routing": { "unit_cell_indicators": [...], ... }
}
```

Then add `"mappings_file": "myonto_mappings.json"` to the ontology's entry in `ontology_registry.json`. No code changes needed.

**Only include the `sample_schema`, `crystal_output`, `material_type_rules` and
`annotation_routing` blocks if every class/property they name actually exists in that
ontology's summary.** `sample_annotator.py` validates emitted terms against the loaded
summary and flags any that are undefined (`results.validation_warnings`, `confidence: 0.0`).
For example, `asmo_mappings.json` deliberately ships **only** `synonyms` and
`property_synonyms` because ASMO is a simulation-methods ontology with no crystal/sample
vocabulary — its concept terms (DFT, NPT, timestep, PBE) all resolve, but a crystal/sample
config would emit unresolvable terms.

## Error Handling

| Error | Cause | Resolution |
|-------|-------|------------|
| `space_group must be between 1 and 230` | Invalid space group number | Use a valid space group number |
| `a must be positive` | Non-positive lattice parameter | Provide positive values in angstroms |
| `Unrecognized Bravais lattice ''` | Bravais symbol/name not in the recognized set | Use a common name (FCC, BCC, HCP) or a Pearson symbol (cF, cI, hP, ...) |
| `Term exceeds maximum length of 200 characters` | A `--term`/`--terms` entry is too long | Shorten the term |
| `Too many terms (max 100)` | More than 100 terms supplied | Split into smaller batches |
| `Sample must be a non-empty dict` | Empty or missing sample data | Provide a valid JSON sample dict |
| `Sample has too many keys (max 100)` | Oversized sample dict | Reduce the number of sample keys |
| Validation warnings (lattice) | Lattice parameters inconsistent with crystal system | Check that a=b=c for cubic, etc. |
| `results.validation_warnings` (terms) | Emitted class/property not defined in the chosen ontology (e.g. crystal terms for ASMO) | Use CMSO for crystal/sample annotation; use ASMO only for concept mapping |

## Interpretation Guidance

- **Confidence scores**: 1.0 = exact label match, 0.9 = synonym-table match, 0.7 = substring match, 0.5 = description match. Note: the per-ontology synonym table is consulted *before* exact-label matching, so a term that is both a synonym key and a class label (e.g. `space group`, `unit cell`, `atom`) is reported as a 0.9 synonym match even though it coincides exactly with a class label — the matched class and IRI are still correct.
- **`sample_annotator.py` validation warnings**: every emitted class/property is checked against the loaded ontology summary. Terms not defined in that ontology are flagged in `results.validation_warnings` (and the corresponding annotation gets a `validation_warning` field with `confidence: 0.0`). This is how the annotator signals that a crystal/sample term cannot resolve to an IRI in the chosen ontology (e.g. running `--ontology asmo` on a crystalline sample — see below).
- **Validation warnings**: indicate potential mistakes (e.g., specifying a!=b for cubic). These are warnings, not errors — the mapping still proceeds.
- **Unmapped fields**: input keys that the annotator doesn't recognize. These may need manual mapping.
- **Suggested properties**: additional ontology properties that would make the annotation more complete.

## Verification checklist

- [ ] Confirmed `results.validation_warnings` is empty (or every entry is explained) — a non-empty list means an emitted class/property is **not defined in the chosen ontology** and was given `confidence: 0.0`; do not report such terms as valid annotations.
- [ ] Recorded the `match_type` and `confidence` for each concept match and confirmed the chosen term is acceptable for its tier (1.0 exact, 0.9 synonym, 0.7 substring, 0.5 description); for any `substring_*` or `description_class` match, verified the matched class is actually the intended concept and not an incidental string hit.
- [ ] For crystal mappings, recorded `results.effective_system` and `results.bravais_lattice` (the resolved Pearson symbol, e.g. `cF`/`cI`), and confirmed the input Bravais/space-group/system are mutually consistent (no "space group N implies X but Y was specified" warning in `validation_warnings`).
- [ ] Checked lattice-parameter constraints against `effective_system` — confirmed no warnings such as "Cubic requires a=b" / angle-90 violations, or explicitly justified each one (warnings are advisory, the mapping still proceeds).
- [ ] Listed `results.unmatched` (concept) and `results.unmapped_fields` (sample) and confirmed nothing materially important was silently dropped; ran the emitted `class_browser.py` suggestion for any unmatched term that should have resolved.
- [ ] Reviewed `results.suggested_properties` and recorded which missing fields (elements, space_group, lattice_a, ...) are intentionally omitted vs. should be added before the annotation is considered complete.

## Common pitfalls & rationalizations

| Tempting shortcut | Why it's wrong / what to do |
|-------------------|-----------------------------|
| "The script printed annotations, so the sample is correctly annotated." | Emission is not validation. `sample_annotator.py` will emit a term and then flag it with `validation_warning` / `confidence: 0.0` if it is not in the ontology — always read `results.validation_warnings` before trusting the output. |
| "I'll annotate this crystalline sample with `--ontology asmo`." | ASMO is a simulation-methods ontology with **no crystal/sample vocabulary**; every crystal term comes back at `confidence: 0.0`. Use CMSO for crystal/sample annotation; use ASMO only via the concept-mapping path. |
| "It matched the term, so the mapping is high-confidence." | A match can be a 0.7 substring or 0.5 description hit (e.g. an incidental substring inside an unrelated label). Check `confidence`/`match_type`; treat anything below an exact/synonym match as a candidate to verify, not a fact. |
| "`space group` matched a class label, so that's a 1.0 exact match." | The per-ontology synonym table is consulted **before** exact-label matching, so synonym-key terms (`space group`, `unit cell`, `atom`) report as 0.9 synonym matches even when they equal a class label. The matched class/IRI is still correct — do not "correct" the confidence. |
| "The space group is valid (1–230), so my crystal system is fine." | A valid space group can still contradict an explicitly given `--system` or Bravais lattice. Read `effective_system` and check for a "space group N implies X but Y was specified" entry in `validation_warnings`. |
| "My sample has a `structure` field, so the Bravais lattice resolved." | In the sample path `strict_bravais=False`: free-text structures (e.g. `rocksalt`, `perovskite`) are passed through unmapped with a warning, leaving `bravais_lattice` null. Verify `results.bravais_lattice` is the expected Pearson symbol, or supply FCC/BCC/HCP/a Pearson code. |

## Security

### Input Validation
- `--ontology` is validated against registered ontology names in `ontology_registry.json` (fixed allowlist)
- `--term` and `--terms` are length-limited and used only for substring matching against pre-processed synonym tables (never interpolated into code)
- `--bravais` is validated against a fixed set of recognized lattice type symbols
- `--space-group` is validated as an integer between 1 and 230
- Lattice parameters (`--a`, `--b`, `--c`, `--alpha`, `--beta`, `--gamma`) are validated as finite positive numbers
- `--sample` JSON is parsed with `json.loads()` and validated as a non-empty dict; keys and values are type-checked

### File Access
- Scripts read pre-processed JSON files from the `references/` directory: `ontology_registry.json`, `*_mappings.json`, `*_summary.json`, `crystal_systems.json`, `element_data.json` (all read-only)
- No scripts write to the filesystem; all output goes to stdout
- No network access is required

### Tool Restrictions
- **Read**: Used to inspect script source, reference files, and ontology data
- **Grep**: Used to search reference files for mapping patterns or ontology terms
- **Glob**: Used to locate reference files and ontology data
- Notably, this skill has **no Bash or Write access**, giving it the lowest attack surface of all skills

### Safety Measures
- No `eval()`, `exec()`, or dynamic code generation
- No subprocess calls of any kind; all logic runs within Python scripts invoked by the agent
- No file writes; the skill is purely read-only and analytical
- Minimal tool surface (Read, Grep, Glob only) means the agent cannot execute arbitrary commands or modify the filesystem

## Limitations

- Concept mapping uses string matching and a per-ontology synonym table; it does not understand arbitrary natural language
- Crystal system validation checks basic constraints only (not all crystallographic rules)
- The element resolver recognizes common element names and symbols but may miss unusual spellings
- Bravais lattice aliases cover common usage (FCC, BCC, HCP) but not all crystallographic notation variants

## References

- [Mapping Patterns](references/mapping_patterns.md) — common mapping examples
- [Crystal Systems](references/crystal_systems.json) — crystal system definitions and Bravais lattices
- [Element Data](references/element_data.json) — periodic table data
- [CMSO Mappings](references/cmso_mappings.json) — CMSO-specific synonym tables and annotation config
- [CMSO Guide](../ontology-explorer/references/cmso_guide.md) — CMSO ontology overview
- [Ontology Explorer](../ontology-explorer/) — sibling skill; `scripts/class_browser.py --ontology  --search ` browses classes when a concept is unmatched

## Version History

| Date | Version | Changes |
|------|---------|---------|
| 2026-06-23 | 1.2 | Validate emitted terms against the loaded ontology (ASMO crystal/sample terms now flagged, not silently emitted); document ASMO is concept-mapping only; clarify synonym-vs-exact confidence precedence; self-contained class_browser suggestion; harden input validation (term/sample size caps, Bravais allowlist) |
| 2026-02-25 | 1.1 | Refactored for multi-ontology support: externalized CMSO-specific knowledge to config |
| 2026-02-25 | 1.0 | Initial release with CMSO mapping support |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [HeshamFS](https://github.com/HeshamFS)
- **Source:** [HeshamFS/materials-simulation-skills](https://github.com/HeshamFS/materials-simulation-skills)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** yes

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-heshamfs-materials-simulation-skills-ontology-mapper
- Seller: https://agentstack.voostack.com/s/heshamfs
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
