Skip to content

Refactor Cluster Materials nested lists into table schemas - #2153

Merged
bfoley12 merged 3 commits into
materialsproject:masterfrom
RajbanulAkhond:cluster-materials-table-schemas
Sep 16, 2026
Merged

bfoley12 merged 3 commits into
materialsproject:masterfrom
RajbanulAkhond:cluster-materials-table-schemas

Conversation

@RajbanulAkhond

Copy link
Copy Markdown
Contributor

Summary

This follow-up to #2142 implements the table-based representation discussed after the initial Cluster Materials schema was merged.

  • add Cluster in cluster.py for the clusters table
  • add ClusterPointGroup in cluster_point_group.py for the clusterPointGroups table
  • remove the nested clusters and clusterPointGroups fields from ClusterMaterial
  • represent Cluster.elements, FlatBandProperties.latticeDimensionalities, and FlatBandProperties.latticeIds as validated comma-separated strings
  • document Cluster.averageDistance explicitly in angstroms
  • retain the polar, piezoelectric, enantiomorphic, and Battery Explorer membership fields without duplicating Materials Project or Battery Explorer properties
  • retain the flat-band citation to Neves et al. (2024), DOI 10.1038/s41524-024-01220-x

During submission, each contribution will contain the main ClusterMaterial data and two named pandas DataFrames: clusters and clusterPointGroups. Cross-component count, distance, and label checks are handled by the external submission builder because the table rows are no longer nested in the main model.

Validation

  • all 5,306 source records validated
  • 8,891 clusters rows validated
  • 7,464 clusterPointGroups rows validated
  • 21 upstream Lux Arrow-compatibility tests passed
  • Black, Pydocstyle, Mypy, and repository-aligned lint checks passed

No data files or upload tooling are included in this pull request.

Copilot AI lite review requested due to automatic review settings September 10, 2026 01:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

A newly introduced validation constraint is likely too restrictive (dimensionalities max length), risking rejection of valid records as data scales.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR refactors the Cluster Materials Lux schema to move previously nested clusters and clusterPointGroups lists into separate table-style schemas, while keeping ClusterMaterial as the “main record” model and shifting certain validations to an external submission builder.

Changes:

  • Introduces new table row models: Cluster (for clusters) and ClusterPointGroup (for clusterPointGroups).
  • Updates FlatBandProperties to store latticeDimensionalities and latticeIds as validated comma-separated strings instead of lists.
  • Removes nested cluster structures and associated cross-field validators from ClusterMaterial, updating field descriptions accordingly.
File summaries
File Description
mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py Removes nested cluster/point-group models, updates FlatBandProperties to comma-separated string fields, and adjusts ClusterMaterial fields/descriptions accordingly.
mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/cluster.py Adds a table-schema Cluster model with validation for comma-separated elements and cluster invariants.
mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/cluster_point_group.py Adds a table-schema ClusterPointGroup model for point-group table rows.
mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/init.py Re-exports new public models (Cluster, ClusterPointGroup) alongside ClusterMaterial and FlatBandProperties.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/cluster.py Outdated

@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 refactor of lists to tables.
Some background on the need of an foreign key to the ClusterMaterial in Tables:

We deduplicate identical components (tables, structures) server side to save space, so if you have 2 ClusterMaterials with identical Clusters Tables, they actually share the same physical Table in our database. This causes an issue when you want to update the information for one of your ClusterMaterials: it will silently change the Table for all ClusterMaterials sharing that Table.

Adding in the unique identifier for the related ClusterMaterial causes the deduplication method to recognize each table as distinct.

Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/cluster.py Outdated
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/cluster.py
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py

@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.

PR is in good shape. I think after these changes we are good to go.

Comment on lines +37 to +45
def _split_comma_separated(value: str, field_name: str) -> list[str]:
"""Return canonical comma-separated values or raise a validation error."""
values = value.split(",")
if any(not item or item != item.strip() for item in values):
raise ValueError(
f"{field_name} must contain nonempty values separated by commas "
"without spaces"
)
return values

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. Can replace call sites with just value.split(",").
I suggest tolerating white spaces:

value = [v.strip() for v in value.split(",")]
...
return ",".join(values)

The above can be used in functions that call _spit_comma_separated where ... indicates that function's specific validation logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. The comma-separated validators now accept surrounding whitespace, validate each stripped entry, and store the canonical comma-separated representation without spaces.

Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py Outdated
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py Outdated
Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/cluster.py Outdated
Comment on lines +213 to +218
if not isinstance(cluster_material, ClusterMaterial):
raise TypeError("cluster_material must be a ClusterMaterial")
if not isinstance(clusters, pd.DataFrame):
raise TypeError("clusters must be a pandas DataFrame")
if not isinstance(cluster_groups, pd.DataFrame):
raise TypeError("cluster_groups must be a pandas DataFrame")

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: function header forces types

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. I removed the runtime isinstance checks and moved Cluster and ClusterPointGroup imports to the top of schema.py after eliminating the import cycle.

Comment thread mpcontribs-lux/mpcontribs/lux/projects/cluster_materials/schema.py Outdated
Comment on lines 136 to 141

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.

We can actually remove this here. When submitting contributions, set identifier=*material.materialId

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. materialId has been removed from ClusterMaterial. The submission builder now uses the source material ID as the top-level contribution identifier and retains it only in the two tables as their foreign key.

@bfoley12
bfoley12 merged commit a22c387 into materialsproject:master Sep 16, 2026
5 checks passed
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.

3 participants