From a75b0c9739e3a4a94409ac397ae45f65b908275a Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Thu, 19 Mar 2026 16:33:37 -0700 Subject: [PATCH 1/4] schematize atlas search result for synthesis --- emmet-core/emmet/core/synthesis/core.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/emmet-core/emmet/core/synthesis/core.py b/emmet-core/emmet/core/synthesis/core.py index 1c3f605526..2909eb0f4e 100644 --- a/emmet-core/emmet/core/synthesis/core.py +++ b/emmet-core/emmet/core/synthesis/core.py @@ -1,5 +1,3 @@ -from typing import Any - from pydantic import BaseModel, Field from emmet.core.synthesis.materials import ExtractedMaterial @@ -60,6 +58,21 @@ class SynthesisRecipe(BaseModel): ) +class AtlasSearchText(BaseModel): + """Schematize MongoDB Atlas search text match.""" + + value: str | None = None + type: str | None = None + + +class AtlasSearchHighlight(BaseModel): + """Schematize MongoDB Atlas search highlight match.""" + + score: float | None = None + path: str | None = None + texts: list[AtlasSearchText] | None = None + + @arrow_incompatible class SynthesisSearchResultModel(SynthesisRecipe): """ @@ -71,7 +84,7 @@ class SynthesisSearchResultModel(SynthesisRecipe): None, description="Search score.", ) - highlights: list[Any] | None = Field( + highlights: list[AtlasSearchHighlight] | None = Field( None, description="Search highlights.", ) From e140dbcbf5d2d05231001428364fc007815525e0 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Thu, 19 Mar 2026 16:45:52 -0700 Subject: [PATCH 2/4] ensure surface properties structure is pmg structure and not cif --- emmet-core/emmet/core/surface_properties.py | 23 ++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/emmet-core/emmet/core/surface_properties.py b/emmet-core/emmet/core/surface_properties.py index 3d82f5569b..3adb420e76 100644 --- a/emmet-core/emmet/core/surface_properties.py +++ b/emmet-core/emmet/core/surface_properties.py @@ -1,7 +1,17 @@ -from pydantic import BaseModel, Field +"""Define schemas for surfaces and heterostructures.""" + +from __future__ import annotations + +from pydantic import BaseModel, Field, field_validator +from typing import TYPE_CHECKING + +from pymatgen.core import Structure from emmet.core.types.pymatgen_types.structure_adapter import StructureType +if TYPE_CHECKING: + from typing import Any + class SurfaceEntry(BaseModel): """ @@ -28,9 +38,9 @@ class SurfaceEntry(BaseModel): description="Whether it is a reconstructed surface.", ) - structure: str | None = Field( + structure: StructureType | None = Field( None, - description="CIF of slab structure.", + description="Slab structure.", ) work_function: float | None = Field( @@ -53,6 +63,13 @@ class SurfaceEntry(BaseModel): description="Whether the surface has wulff entry.", ) + @field_validator("structure", mode="before") + def get_structure_from_cif(cls, v: Any) -> Structure | None: + """Transform legacy CIF data to pymatgen Structure.""" + if isinstance(v, str): + return Structure.from_str(v, fmt="cif") + return v + class SurfacePropDoc(BaseModel): """ From da3088f83c16645ee1775c614034ce9d1b69ad57 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Thu, 19 Mar 2026 17:07:28 -0700 Subject: [PATCH 3/4] grain bdys: cif --> structure --- emmet-core/emmet/core/grain_boundary.py | 27 ++++++++++++++++++++++++- emmet-core/tests/test_model_fields.py | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/emmet-core/emmet/core/grain_boundary.py b/emmet-core/emmet/core/grain_boundary.py index 1b8779471c..208636a4ab 100644 --- a/emmet-core/emmet/core/grain_boundary.py +++ b/emmet-core/emmet/core/grain_boundary.py @@ -1,9 +1,18 @@ +from __future__ import annotations + from pydantic import BaseModel, Field +from pymatgen.core import Structure +from typing import TYPE_CHECKING from emmet.core.types.enums import ValueEnum from emmet.core.types.pymatgen_types.grain_boundary_adapter import GrainBoundaryType +from emmet.core.types.pymatgen_types.structure_adapter import StructureType from emmet.core.types.typing import DateTimeType +if TYPE_CHECKING: + from typing import Any + from typing_extensions import Self + class GBTypeEnum(ValueEnum): """ @@ -68,7 +77,7 @@ class GrainBoundaryDoc(BaseModel): w_sep: float | None = Field(None, description="Work of separation in J/m^2.") - cif: str | None = Field(None, description="CIF file of the structure.") + structure: StructureType | None = Field(None, description="Structure.") chemsys: str | None = Field( None, description="Dash-delimited string of elements in the material." @@ -77,3 +86,19 @@ class GrainBoundaryDoc(BaseModel): last_updated: DateTimeType = Field( description="Timestamp for the most recent calculation for this Material document.", ) + + @classmethod + def _migrate_schema(cls, config: dict[str, Any]) -> Self: + """Pipe legacy CIF data into a pymatgen structure.""" + if isinstance(cif_str := config.pop("cif", None), str) and not config.get( + "structure" + ): + config["structure"] = Structure.from_str(cif_str, fmt="cif") + return cls(**config) + + @property + def cif(self) -> str | None: + """Support accessing legacy CIF from structure field.""" + if self.structure: + return self.structure.to(fmt="cif") + return None diff --git a/emmet-core/tests/test_model_fields.py b/emmet-core/tests/test_model_fields.py index eeae509150..de15b9495f 100644 --- a/emmet-core/tests/test_model_fields.py +++ b/emmet-core/tests/test_model_fields.py @@ -259,7 +259,7 @@ "final_structure", "pretty_formula", "w_sep", - "cif", + "structure", "chemsys", "last_updated", ], From d346564c194c12667b3a73bf78660be86b0a3597 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Fri, 20 Mar 2026 09:40:17 -0700 Subject: [PATCH 4/4] remove arrow incompat marker for synth doc --- emmet-core/emmet/core/synthesis/core.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/emmet-core/emmet/core/synthesis/core.py b/emmet-core/emmet/core/synthesis/core.py index 2909eb0f4e..16d5d0e391 100644 --- a/emmet-core/emmet/core/synthesis/core.py +++ b/emmet-core/emmet/core/synthesis/core.py @@ -4,7 +4,6 @@ from emmet.core.synthesis.operations import Operation from emmet.core.synthesis.reaction import ReactionFormula from emmet.core.types.enums import ValueEnum -from emmet.core.utils import arrow_incompatible class SynthesisTypeEnum(str, ValueEnum): @@ -73,7 +72,6 @@ class AtlasSearchHighlight(BaseModel): texts: list[AtlasSearchText] | None = None -@arrow_incompatible class SynthesisSearchResultModel(SynthesisRecipe): """ Model for a document containing synthesis recipes