Skip to content

Add two_d_mxenes lux project - #2180

Open
ahgesch wants to merge 31 commits into
materialsproject:masterfrom
ahgesch:master
Open

ahgesch wants to merge 31 commits into
materialsproject:masterfrom
ahgesch:master

Conversation

@ahgesch

@ahgesch ahgesch commented Oct 8, 2026

Copy link
Copy Markdown

Add two_d_mxenes lux project: schema for 2D MXene structures and properties

@bfoley12, this PR adds the MPContribs-lux schema for the two_d_mxenes project and is ready for review.

Summary

The project describes two-dimensional MXenes Mn+1XnTx: one record per relaxed structure, identified by its transition metal M, non-metal X (C, N), thickness n (1–3), termination T (none, F, O), layer stacking and termination site. Each record contains the structure, descriptors computed from it, and computed energetic and elastic properties. The schema is designed for non-bulk (slab) materials and is intended to support a future MPContribs app for them.

All changes are under mpcontribs-lux/ (16 new files; no existing files modified):

path contents
projects/two_d_mxenes/schemas/ MXeneEntry, MXeneLabel, MXeneStructure, StructureDescriptors, MXeneProperties, Energetics, ElasticProperties, CalculationSettings
projects/two_d_mxenes/pipelines/ structure check, Excel overview, properties template and loader, MPContribs contribution builder, Parquet export
projects/two_d_mxenes/README.md, pipelines/README.md, schemas/README.md labelling rules, validation phases, accepted data, conformance, upload procedure, field reference
tests/projects/two_d_mxenes/test_two_d_mxenes.py 95 tests
test_data/by_user/two_d_mxenes/ one sample structure (Hf₂CF₂, 19 lines)

Validation phases

Each structure passes through eight phases. A failure in any phase produces no record, and every rule is tested for both acceptance and rejection.

phase checks
1. Discovery CONTCAR files are collected; files in label folders are entries; files nested inside an entry folder are auxiliary calculations and are skipped; files anywhere else are errors
2. Parsing and chemistry the structure parses; exactly one transition metal, one of C/N and at most one of F/O, with Mn+1Xn stoichiometry; M, X, T and n are inferred from the atoms
3. Label the folder label is a known stacking (t, h, h1a, h1b, h2) allowed for n, with a -1/-2 termination-site suffix exactly when the MXene is terminated
4. Structure consistent species and coordinates; sheet in the a–b plane; single-element atomic layers; descriptors computed
5. Cross-validation the composition matches the labels; the measured O/P coordination sequence matches the stacking; the measured outer-metal coordination matches the termination site on both surfaces
6. Uniqueness one structure per mxeneId; when several claim the same ID, all are rejected
7. Properties known columns with matching header units; finite numeric values; C11 and C12 given together; every row matches a valid structure
8. Export contributions use only the declared columns and units, which parse with the client's unit registry; records convert to Arrow and round-trip through Parquet

Accepted and rejected data

accepted rejected
relaxed slabs in POSCAR/CONTCAR format unparseable or truncated files
any transition metal M; X = C or N; T = F, O or none other elements (e.g. Cl, S, OH terminations, B for MBenes)
n = 1, 2, 3 n ≥ 4
terminations on both surfaces, one termination species one-sided, partial or mixed terminations
a single metal species, stoichiometric sheets double-metal MXenes, vacancies, non-stoichiometric compositions
any in-plane cell, including supercells, with the normal along c; sheets split across the periodic boundary sheets not in the a–b plane; reconstructed sheets whose layers overlap along the normal
structures whose measured stacking and termination site match the label structures whose geometry contradicts the label (rejected, never relabelled)
numeric properties in the declared units (eV/atom, N/m), blank when unknown text, NaN or infinity; undeclared columns; different units in headers; incomplete elastic constants

Conformance with MPContribs requirements

  • Schemas in projects/two_d_mxenes/schemas, with a description and unit on every field; all models pass the Arrow compatibility test.
  • Project name two_d_mxenes (3–31 alphanumeric/underscore characters).
  • 21 data columns (limit 50). camelCase names without underscores, nested at most 2 levels. Values are strings with pint units; None marks text columns and "" dimensionless ones. No NaN, unset keys or lists.
  • One pymatgen structure per contribution, an identifier and a formula per contribution, and the project other metadata keys pass the API's key validation.
  • Layout follows lux project scaffold: a project README, pip-extra-requirements.txt, tests under tests/projects/two_d_mxenes, and data under test_data/by_user/two_d_mxenes.
  • pre-commit (ruff, black, pyupgrade and file checks) passes on all files.

Design decisions for review

  1. The identifier is mxeneId (e.g. Ti3C2O2-h1a-2), and the formula goes in formula. 2D slabs have no mp- IDs, and several structures share a formula. With the default unique_identifiers=True, a formula identifier would retain only one structure per formula. The MPContribs-lux upload example states that identifiers may be arbitrary.
  2. Structure storage. MXeneStructure stores lattice, species and fractional coordinates as plain arrays. It does not subclass emmet's StructureMetadata, whose volume and density depend on the vacuum of a slab model. We can align with emmet types if preferred.
  3. Descriptors are stored fields, not computed_fields, so they are present in Parquet.
  4. Units. 2D elastic constants and moduli are in N/m (per sheet area, independent of an effective thickness). Energies are in eV/atom and lengths in Å.
  5. Termination-site convention. For n = 1, site 1 is octahedral and site 2 prismatic. For n ≥ 2, site 1 gives the outer metal layers the coordination of the inner metal layers, and site 2 the opposite. The rule is implemented in labels.expected_termination_coordination.
  6. Pipeline code alongside the schemas in pipelines/, following alab/pipelines.
  7. Optional openpyxl (in pip-extra-requirements.txt) for the Excel overview. It is not in the lux CI requirements, so the workbook test is skipped in CI; the grid logic is tested independently. It can be added to the extras requirements if preferred.
  8. Project other metadata. The API rejects keys containing ., so project_other() nests column descriptions (geometry → a). The upload notebook in mpcontribs-lux/examples passes dotted keys to update_project, which this validation appears to reject.
  9. Strict models. All models use extra="forbid" and allow_inf_nan=False.

Testing

Clean environments built from requirements/requirements-ubuntu-latest_py3.1{1,2}_extras.txt (emmet-core 0.86.2, pymatgen 2025.10.7), run with the CI command pytest -n auto -x:

scope Python 3.11 Python 3.12
tests/projects/two_d_mxenes + tests/test_models_for_arrow_compatibility.py 122 passed, 2 skipped 122 passed, 2 skipped

The two skips are the workbook test (openpyxl) and the unit-registry test (pint), neither of which is in the lux CI requirements. With both installed, all 95 project tests pass.

test group phases
labels: label parsing, stacking/thickness rules, core and termination-site rules for every n and stacking 3, 5
structure: pymatgen round-trip, descriptors, sheets split across the cell, coordination detection, formula formatting, distorted sheets 2, 4
entry: wrong stacking, wrong or mixed termination sites, wrong composition, supercells, rejected compositions 2, 5
properties and template: derived moduli and stability, template round-trip and refresh, rejected inputs 7
pipeline and overview: folder trees, auxiliary files, duplicates, collected failures, report, grid states, scope exclusions, workbook 1, 6
export: declared columns and units, identifier, project metadata keys, unit registry, Parquet round-trip, Arrow compatibility 8

test_autogen.py and tests/projects/esoteric_ephemera require Git LFS files that were unavailable in the test environment. They are not affected by this PR.

Developed with the assistance of Claude, as suggested in the MPContribs onboarding guidance.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m

ahgesch and others added 29 commits September 21, 2026 19:28
Add initial README file with author information.
- labels.py: M/X/T/n/stacking/termination-site vocabularies and rules
- structure.py: arrow-friendly structure + descriptors derived from it
  (thickness, vacuum, bond lengths, measured O/P coordination sequence)
- properties.py, calculation.py: draft spreadsheet-backed properties and
  project-level DFT settings
- mxene.py: MXeneEntry, cross-validating labels against the structure
- pipelines/build_contributions.py: CONTCAR tree + spreadsheet -> entries
- tests and sample Hf2CF2 structure; README with spreadsheet spec

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
…data

- Site 1 = octahedral, site 2 = prismatic outer-metal coordination;
  MXeneEntry now rejects structures that disagree with their site label
- Move sample CONTCAR to MXENE_DATA/Hf/m2x/h-1/ (its real location) and
  test the pipeline directly on the repo test data
- Document site meanings in labels.py and README

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
- check_dataset() validates all CONTCARs and collects failures instead of
  stopping at the first one
- Command-line entry point prints valid/failed counts, a composition
  summary, and each failing file with its error

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
- Termination site rule: for n=1, site 1 = octahedral and site 2 =
  prismatic outer metal layers; for n>=2, site 1 = same coordination as
  the inner metal layers of the stacking (O for t/h1b, P for h1a/h2) and
  site 2 = opposite
- CONTCARs in sub-folders of an entry folder (supercells, phonons, d2, ...)
  are skipped by check_dataset and build_entries instead of failing
- Failure messages are one line instead of full pydantic tracebacks
- Summary table of measured outer-metal coordination for every
  (n, stacking, site) label, including failed structures
- Optional --report CSV with one row per CONTCAR

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
- StructureDescriptors.reducedFormula (also the MPContribs identifier) is
  now written in M, X, T order without grouping, e.g. Hf3C2F2 instead of
  pymatgen's Hf3(CF)2
- Mixed-species layer errors report the z positions and suggest the
  structure may be strongly distorted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
- New pipelines/dataset_overview.py and --overview option on the check
  command: one row per M-X system, one column per feasible structure
  (n / termination / stacking label), with a good / problem / missing
  symbol in every cell, hover comments on problem cells, per-row and
  per-column totals, and Problems, Missing and All files sheets
- Terminations outside the study (pristine and O for Hf, Re) are shaded
- Check records now store the structure each file claims (cellId), so
  failed files are placed on the grid
- All files claiming the same structure are now flagged as duplicates,
  instead of accepting whichever was found first
- infer_chemistry() factored out of MXeneEntry.from_structure

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
Documentation
- README.md (project): labelling rules including the n-dependent
  termination-site rule, checks, record contents, workflow, extending
  the dataset, and a PR guide for human and AI contributors
- pipelines/README.md: command-line usage, output files, error
  catalogue with remedies, properties spreadsheet, step-by-step
  MPContribs upload, upload errors, API summary, tolerances
- schemas/README.md: field reference generated from the models

Pipeline
- --template FILE.csv writes one row per valid structure with read-only
  structure columns and blank property columns (units in headers);
  re-running keeps entered values and moves orphaned rows aside
- load_properties accepts template files, checks header units and
  rejects half-filled elastic constants
- build_entries(skip_invalid=True) to upload the valid part of a dataset
- MPCONTRIBS_COLUMNS / MPCONTRIBS_COLUMN_DESCRIPTIONS for init_columns,
  project_other() for server-safe project metadata
- Contribution identifier is now mxeneId (formula identifiers would be
  deduplicated by MPContribs' default unique_identifiers=True); formula
  goes in the formula field; consistent column types
- write_parquet / read_parquet for the full records

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
Documentation
- Project README defines the schema independently of any dataset: labelling
  rules, eight validation phases, accepted and rejected data, record
  contents, conformance with MPContribs and MPContribs-lux requirements,
  test coverage by phase, extension points and contribution guidelines
- pipelines/README.md and schemas/README.md rewritten in the same terms;
  field reference regenerated from the models
- Field descriptions and docstrings no longer refer to a specific dataset;
  the stacking nomenclature cites its source

Behaviour
- Overview rows are created for every transition metal in the data (by
  atomic number); all combinations are in scope unless excluded with
  --out-of-scope M:T (replaces the hard-coded study scope)
- Template rows are ordered by atomic number
- Unsupported elements are reported explicitly by infer_chemistry

Tests
- Grid-state logic tested without openpyxl; scope exclusion parsing
- Accepted supercells; rejected mixed terminations, other elements, MBenes,
  double-metal sheets, n = 4, one-sided terminations, vacancies
- Column units parsed with the MPContribs client's unit registry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
@bfoley12
bfoley12 self-requested a review October 8, 2026 17:53

@bfoley12 bfoley12 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start!

Mostly styling changes and being stricter about limiting fields.

Major change we need to talk about - happy to set up a call if it is not clear:

  • classes in schemas/structure.py seem to be subsets of pymatgen.Structure. It is much simpler to store this info as a pymatgen.Structure.
    • internally, we do not allow Contributions.data (what you describe in mxene.py) to contain list-typed fields (as lists are better represented as Tables). The structure classes have several lists, which would get rejected at submission.
    • Instead, we should submit the data during submit_contributions as a structure with their respective contributions, then users would derive views as the see fit (structure.py would be your own internal representation, not stored here)
    • If these are absoultely necessary representations and include non-pymatgen.Structure information, we can come up with alternate strategies

I did not review pipelines here. My primary concern is the data representation, so subsequent reviews will address pipelines. If the primary use case of classes in structures.py is to be used in the pipelines, then we should move those into something like pipelines/schemas - not totally settled on the name yet.

Comment on lines +142 to +159
@property
def core_sequence(self) -> list[str]:
"""Measured coordination of the layers between the outer metal layers."""
seq = self.descriptors.coordinationSequence
return seq[1:-1] if self.labels.termination else seq

@property
def termination_coordination(self) -> tuple[str, str] | None:
"""Measured coordination of the bottom and top outer metal layers.

This is set by the termination site: `O` if the termination sits
staggered with respect to the X layer beneath the outer metal, `P` if
it sits directly above an X atom. None for pristine MXenes.
"""
if not self.labels.termination:
return None
seq = self.descriptors.coordinationSequence
return seq[0], seq[-1]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear: these are not be fields that are submitted as data?

Comment on lines +90 to +93
_FOLDER_LABEL = re.compile(r"^(?P<stacking>h1a|h1b|h2|h|t)(?:-(?P<site>[12]))?$")

_MODEL_CONFIG = ConfigDict(extra="forbid", allow_inf_nan=False)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these to top of file with other module-level constants


from pydantic import BaseModel, ConfigDict, Field

_MODEL_CONFIG = ConfigDict(extra="forbid", allow_inf_nan=False)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove _MODEL_CONFIG and inline it within the class


model_config = _MODEL_CONFIG

code: str | None = Field(None, description="Simulation code, e.g. `VASP`.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know all possible codes, or is this high cardinality? If it is a small collection of codes, add a Literal[...]

Comment on lines +28 to +39
functional: str | None = Field(
None,
description="Exchange-correlation functional, e.g. `PBE`.",
)
vdwCorrection: str | None = Field(
None,
description="Dispersion correction, e.g. `DFT-D3`, or null if none.",
)
pseudopotentials: list[str] | None = Field(
None,
description="Pseudopotential (e.g. PAW POTCAR) labels used for each element.",
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to code, are these easy to enumerate? If not, can you cap the length to something reasonable (ie. longest known value + 50%)? I like to limit the amount of arbitrary strings present.

from pydantic import BaseModel, ConfigDict, Field, model_validator
from pymatgen.core import Composition, Structure

_MODEL_CONFIG = ConfigDict(extra="forbid", allow_inf_nan=False)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove in favor of inlining

Comment on lines +24 to +31
metals = [el.symbol for el in composition if el.is_transition_metal]
nonmetals = [el.symbol for el in composition if el.symbol in {"C", "N"}]
terms = [el.symbol for el in composition if el.symbol in {"F", "O"}]
others = sorted(
el.symbol
for el in composition
if not el.is_transition_metal and el.symbol not in {"C", "N", "F", "O"}
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor to single iteration instead of 4

return "".join(parts)


class MXeneStructure(BaseModel):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this different from a pymatgen.Structure? It looks like you use only specific fields from pymatgen.Structure (def from_structure).

If this is truly not a subset of a pymatgen structure, representation gets tricky since we do not allow lists for fields in a contribution.

If it is a subset of a pymatgen structure, we can remove this class and just upload structures directly. I can explain more as we refine.

Comment on lines +105 to +108
reducedFormula: str = Field(
description="Reduced chemical formula of the slab in M, X, T order, "
"e.g. `Hf2CF2` or `Ti3C2O2`.",
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as other string fields: try to restrict with literals, fall back to length


from pydantic import BaseModel, ConfigDict, Field

_MODEL_CONFIG = ConfigDict(extra="forbid", allow_inf_nan=False)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline

@ahgesch

ahgesch commented Oct 8, 2026

Copy link
Copy Markdown
Author

Great start!

Mostly styling changes and being stricter about limiting fields.

Major change we need to talk about - happy to set up a call if it is not clear:

  • classes in schemas/structure.py seem to be subsets of pymatgen.Structure. It is much simpler to store this info as a pymatgen.Structure.

    • internally, we do not allow Contributions.data (what you describe in mxene.py) to contain list-typed fields (as lists are better represented as Tables). The structure classes have several lists, which would get rejected at submission.
    • Instead, we should submit the data during submit_contributions as a structure with their respective contributions, then users would derive views as the see fit (structure.py would be your own internal representation, not stored here)
    • If these are absoultely necessary representations and include non-pymatgen.Structure information, we can come up with alternate strategies

I did not review pipelines here. My primary concern is the data representation, so subsequent reviews will address pipelines. If the primary use case of classes in structures.py is to be used in the pipelines, then we should move those into something like pipelines/schemas - not totally settled on the name yet.

We can totally swap to using pymatgen Structure objects instead of a custom class. Also, I am happy to move the computations over to the pipelines folder, leaving just models and validators in schema, with the recommended syntax changes.

One question for you, are sequences as strings, like "O-P-O" and "F-Hf-C-Hf-F" acceptable as data fields, or should these be set up as tables?

… pipelines

Schema (mpcontribs-lux/.../two_d_mxenes/schemas)
- MXeneEntry is exactly the contribution `data`: no list fields; the relaxed
  structure is submitted as a pymatgen Structure in `structures`
- Remove MXeneStructure; structure.py is replaced by descriptors.py, which
  holds only StructureDescriptors (scalars and validated strings)
- Layer and coordination sequences are strings (e.g. `F-Hf-C-Hf-F`, `O-P-O`)
- Restrict every string: metal is a Literal of the 40 transition metals;
  mxeneId, formula and sequences have patterns and maximum lengths; the
  space-group symbol must be one spglib produces and match its number
- Bounds on all numeric fields; units declared in json_schema_extra
- MXeneEntry also checks the layer sequence and mxeneId against the labels
- ElasticProperties checks derived moduli and stability for consistency
- model_config declared in each class; module constants at the top of
  labels.py; Google-style docstrings throughout
- core_sequence / termination_coordination properties removed; the
  implied sequences are MXeneLabel.layer_sequence / coordination_sequence

Pipelines
- structure_analysis.py: chemistry inference (single pass over the
  elements), layer grouping, coordination, descriptors, entry_from_structure
- upload.py: CalculationSettings (moved from schemas; code Literal["VASP"],
  emmet RunType functional, Literal dispersion correction / POTCAR set /
  elastic method, patterned POTCAR symbols and version, k-point mesh as
  three integers, strain amplitude and point count); MPContribs columns
  and descriptions generated from the schema; to_contribution(entry,
  structure); project_other; Parquet with optional structure column
- build_contributions.py: MXeneRecord (entry, structure, path),
  build_records; numeric spreadsheet cells validated explicitly and only
  empty cells treated as missing

Docs and tests updated; 143 project tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
bfoley12

This comment was marked as duplicate.

@bfoley12

Copy link
Copy Markdown
Collaborator

One question for you, are sequences as strings, like "O-P-O" and "F-Hf-C-Hf-F" acceptable as data fields, or should these be set up as tables?

Yes, those are totally ok. In fact, we store information similarly internally. The issue is more around lists of numbers or objects and abuse that can come from it.

…enance

Review comments
- derived_elastic_properties returns a TypedDict (DerivedElastic)
- ElasticProperties passes cast(float, self.c12) to the derivation
- C11 = 0 is rejected by a validator (moduli undefined); the derivation
  also raises on c11 = 0. Negative C11 stays valid (unstable sheet)
- terminationSite and spaceGroupNumber declare no unit and are stored as
  text columns (categories); n and nSites stay dimensionless numbers

Wider data contract (checks no longer specific to single-metal MXenes)
- Labels: metals, nonmetals and terminations are element lists (strings
  ordered by atomic number, joined by `-`), e.g. Ti-V-Nb-Mo, C-N, O-F;
  nMetals; optional configuration index (`-c<k>` label suffix) for
  several arrangements of one composition and stacking (e.g. SQS)
- Vocabulary: T = F, Cl, Br, I, O, S, Se, Te; n = 1-4
- Descriptors: layers may mix elements of one role (`Ti/V`); new
  metalArrangement (single, out-of-plane ordered, in-plane mixed);
  formula and sequence patterns sized for up to 10 metals and M5X4T2
- MXeneEntry cross-checks generalized: labelled elements and
  M_(n+1)X_n(T_2) proportions from the reduced formula; role of every
  layer; metal arrangement; stacking and termination site as before
- mxeneId is <reducedFormula>-<label>; reduced formulas list metals, X
  and terminations, each by atomic number (single-metal IDs unchanged)

Elastic data
- Optional C22 for non-hexagonal cells (with C66); Young's modulus and
  Poisson's ratio only for C22 = C11; Born criteria of an orthotropic
  sheet; elastic data of a non-hexagonal cell must include C22

Provenance
- New Provenance model: method DFT (default) or MLIP with the potential's
  name; read from the properties spreadsheet (load_provenance)
- Relative stacking energies compare one reduced formula and one method

Settings, overview, typing
- codeVersion accepts the OUTCAR build tag; POTCAR symbols accept
  multi-part suffixes; PotcarSet is pymatgen's list (subset test)
- Overview rows per metal/X system, including alloy and carbonitride
  systems; columns extend to the n and terminations found in the data
- The project passes mypy with the pydantic plugin

Tests and docs
- Tests for ordered, solid-solution and high-entropy sheets,
  carbonitrides, mixed and Janus terminations, configurations, C22,
  provenance and the overview; READMEs and field reference updated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gc97mYBH8XSmaL2oDocZ9m
@ahgesch

ahgesch commented Oct 14, 2026

Copy link
Copy Markdown
Author

Great changes. This is pretty much ready to go, just a few minor comments regarding formatting and type checking.

I see you added a lot of bounds to your fields, thanks. Just double check that they are loose enough that you won't have to edit these models every time you want to submit new data!

I think we are good to go once you address this round.

Hi Brandon. Sorry to do this, but I introduced some changes that are going to need to be re-reviewed. In the nature of making sure my checks weren't too tight, I talked to Dr. Chongze Hu, and he said he would like this schema to be used both for the current dataset (single transition metal MXenes) and future datasets (high entropy alloy MXenes). Thus, some of my columns have been adjusted to account for future material systems.

That being said, I have implemented your recommended changes regarding type casting, annotating, etc. so it should be MP compliant.

Thanks!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants