Connectors¶
| Connector | Status | Extra |
|---|---|---|
| LeMaterial bulk companion | mattergraph_connectors.lematerial.LeMatBulk |
— |
| Materials Project | MaterialsProjectConnector (requires MP_API_KEY) |
[mp] |
| JARVIS | JarvisConnector (loads a subset of JARVIS-DFT 3D) |
[jarvis] |
| NOMAD | NOMADConnector (read-only public metadata; no API key for public reads) |
— |
| OPTIMADE | OptimadeConnector — COD, OQMD, AFLOW, MP, NOMAD and ~18 more through one client |
— |
| Local CSV/JSONL | inspect_local_content + import_local_content (or the web workbench) |
— |
| OQMD | No native connector; OQMDStubConnector raises. Use OptimadeConnector(provider="oqmd") |
— |
mp-api and jarvis-tools are optional extras, not hard dependencies:
pip install 'mattergraph-connectors[mp]' # Materials Project
pip install 'mattergraph-connectors[jarvis]' # JARVIS
pip install 'mattergraph-connectors[all]' # both
The LeMaterial companion adapter returns a MatterGraphDataset so users can inspect schema coverage, create candidate slices, export graphs, and prepare benchmark frames before converting rows into Material instances. It is a dataset adapter rather than a Connector.
The other connectors output Material instances so downstream code stays database-agnostic.
Shared HTTP policy¶
NOMAD and OPTIMADE use ConnectorHTTPPolicy: bounded request timeouts, at most five configured
retries, exponential backoff, numeric Retry-After handling capped at 60 seconds, and explicit
retryable status codes. Response caching is off by default. Contributors can opt into a bounded
process-local MemoryResponseCache; credentials and live connector execution are deliberately
absent from the web workbench.
from mattergraph_connectors import ConnectorHTTPPolicy, MemoryResponseCache, OptimadeConnector
policy = ConnectorHTTPPolicy(timeout_seconds=10, max_retries=2)
with OptimadeConnector(http_policy=policy, cache=MemoryResponseCache(16)) as connector:
materials = connector.fetch()
The local import path has different operational limits: CSV or JSONL only, 5 MiB, 5,000 rows, 100 returned issues, strict rejection by default, and no filesystem writes. See Local contributor workbench.
The connector contract¶
Every connector implements the Connector protocol and takes a single ConnectorQuery:
from mattergraph_connectors import ConnectorQuery, NOMADConnector
with NOMADConnector() as nomad:
materials = nomad.fetch(ConnectorQuery(elements=["Ti", "O"], max_records=5))
ConnectorQuery carries elements, source_ids, properties, max_records, and page_size.
The older keyword form (fetch(elements=[...], max_records=5)) still works and emits a
DeprecationWarning.
Two rules matter more than the shape:
- A connector that cannot honor a field raises rather than ignoring it. Asking NOMAD for
propertiesraises, because NOMAD entries carry none; asking Materials Project for a property it does not map raises and names what it does supply. Silently returning everything would leave the caller unable to tell the filter did nothing. - A connector that cannot answer raises rather than returning
[].OQMDStubConnectoris unimplemented, so it raises. An empty list is indistinguishable from a query that legitimately matched nothing — which is exactly how the JARVIS connector stayed silently dead for an unknown period.
Every ingested Material now carries a ProvenanceRecord naming its source, upstream id, and —
where the source is specific about it — the parameters behind the numbers:
material.provenance[0].source # "jarvis"
material.provenance[0].parameters # {"dataset": "dft_3d", "functional": "OptB88vdW"}
Elastic properties and averaging schemes¶
Materials Project and JARVIS both supply bulk and shear moduli, and both are ingested as the
canonical bulk_modulus / shear_modulus in GPa — but they do not report the same average:
| Source | Upstream field | Average | Recorded as |
|---|---|---|---|
| Materials Project | bulk_modulus["vrh"], shear_modulus["vrh"] |
Voigt–Reuss–Hill | extra["averaging_scheme"] = "vrh" |
| JARVIS dft_3d | bulk_modulus_kv, shear_modulus_gv |
Voigt | extra["averaging_scheme"] = "voigt" |
Voigt is an upper bound; VRH is not. Ranking both in one column biases the Voigt-sourced
candidates high, so Scorecard.report() reports any objective that mixes schemes under
mixed_averaging_schemes. Check it before trusting a cross-source shortlist.
Most Materials Project entries have no elastic tensor at all, so expect elastic coverage to be
sparse and read Scorecard.report()["coverage"] rather than assuming a full column. The MP
connector also carries homogeneous_poisson and universal_anisotropy into Material.metadata:
the first cross-checks the derived Poisson ratio, and the second flags records where a single
isotropic average misrepresents an anisotropic crystal.
From there, mattergraph.derived.elastic turns the two moduli into Young's modulus, Poisson's
ratio, a ductility indicator, and specific stiffness — see Scoring.
NOMAD public metadata¶
NOMADConnector queries NOMAD's public entries/query API and maps entry metadata into
MatterGraph Material objects. It is intentionally metadata-only in v0.1: it does not fetch NOMAD
archives, raw files, or derived scalar properties.
from mattergraph_connectors import ConnectorQuery, NOMADConnector
with NOMADConnector() as nomad:
materials = nomad.fetch(ConnectorQuery(elements=["Ti", "O"], max_records=5))
for material in materials:
print(material.material_id, material.formula)
Because these entries carry no computed values, their provenance records method="unknown"
rather than "dft" — the parser name is the only hint at what produced the upload.
The connector uses public reads by default, deterministic entry-id ordering, and after-value pagination. Public NOMAD metadata reads do not require an API key.
OPTIMADE¶
OPTIMADE is a common API across ~20 materials databases, so one connector reaches COD, OQMD, AFLOW, Materials Project and NOMAD without a per-source SDK.
from mattergraph_connectors import ConnectorQuery, OptimadeConnector
with OptimadeConnector(provider="cod") as cod:
materials = cod.fetch(ConnectorQuery(elements=["Ti", "O"], max_records=5))
| Provider | Status |
|---|---|
cod |
Verified working |
oqmd |
Verified working; also supplies three canonical properties (below) |
mp |
Listed; needs no key for OPTIMADE reads |
nmd |
Listed |
aflow |
Down upstream. /v1/info answers, but /v1/structures returns HTTP 500 for every query shape — including a bare request with no parameters — so there is no client-side workaround. The OPTIMADE providers dashboard reports 7/13 validator checks passing. Listed so it works when AFLOW repairs it. |
Any other OPTIMADE endpoint works via base_url=; the provider table is a convenience, not a
limit.
What OPTIMADE does and does not carry¶
The only REQUIRED field on a structure entry is structure_features. The standard defines no
physical property at all — no band gap, formation energy, hull energy, modulus, or density.
Provider properties are namespaced (_oqmd_stability), so they vary per database.
That makes two things true:
- Density is derived, not reported. It is computed from the cell and composition and
labelled
method="derived"withextra["derived_from"], so it is never mistaken for a value a source vouched for. - Elastic moduli never come from OPTIMADE. Materials Project and JARVIS remain the only sources; after this connector their role is property enrichment rather than discovery.
Dimensionality¶
Records carry nperiodic_dimensions into Material.dimensionality. When it is not 3, no
density is derived — a vacuum-padded monolayer's bulk density measures how much vacuum the
author added, not the material, and a Scorecard would otherwise rank that number against real
crystals. The structure is still kept; only the meaningless property is withheld, and the
provenance note says why.
OQMD hull convention¶
OptimadeConnector(provider="oqmd") maps three namespaced fields onto canonical names:
| OPTIMADE field | Canonical name | Unit |
|---|---|---|
_oqmd_band_gap |
band_gap |
eV |
_oqmd_delta_e |
formation_energy_per_atom |
eV/atom |
_oqmd_stability |
energy_above_hull |
eV/atom |
The third is a convention mismatch, and it is recorded rather than smoothed over. OQMD's
stability is a hull distance and goes negative for a phase below the current hull;
Materials Project's energy_above_hull is >= 0 by construction. Ranking both in one column
biases the OQMD-sourced candidates low — the same class of error as mixing Voigt with VRH
moduli. The value is never clamped, and carries
extra["hull_convention"] = "oqmd_hull_distance" so a mixed column can be spotted. A constraint
like energy_above_hull <= 0.05 will admit OQMD records that MP would have reported as 0.0.
Partial occupancy¶
COD reports chemical_formula_reduced: null for every partially-occupied record, because the
spec requires integer proportions and such records have formulas like H0.572O2Ti0.858. The
connector derives the formula from the cell it has already built instead of dropping the record.
chemical_formula_anonymous is never used as a fallback: "A2B" parses without error and would
silently write elements=['A0+','B'].
Tripo3D boundary¶
Tripo3D is useful to track as a future concept or form-factor visualization option, but it is not a scientific structure viewer and it is not a source of materials data, properties, provenance, or simulation state. Public MatterGraph should prioritize connector-backed records, real structure JSON, graph summaries, and EDA views before any generative 3D layer.