From 5fca11e0e4654847932947eaeb36304cf49278c9 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Tue, 11 Aug 2026 13:32:44 -0700 Subject: [PATCH 1/2] fix: pass the material to PointsGridDataProvider at every call site wode's PointsGridDataProvider now derives KPPRA and the reciprocal vector ratios from the material rather than assuming a single atom and omitting the ratios. It raises when the atom count cannot be derived, so every construction must supply `material=`. 34 call sites across 17 notebooks plus `apply_scf_kgrid`, which is the one notebooks reach indirectly -- it now takes `material` and threads it through, covering interfacial_energy and surface_energy. Multi-material notebooks resolve the material per unit rather than guessing: - valence_band_offset: three pw_scf units on three slabs of differing atom count, resolved from the subworkflow's role via materials_by_role. Raises on an unrecognised name instead of falling back to the interface material, which would have silently persisted the wrong KPPRA for both slabs. - defect_formation_energy: the single pw_scf is the defective cell; the pristine energy is fetched, not computed. - equation_of_state: base_material -- create_strain(scale_factor=) is isotropic, so atom count and ratios are invariant across the series. Ordering: this must merge before the new wode publishes. config.yml pins bare `mat3ra-wode`, so JupyterLite takes latest at runtime; the published wode ignores `material=` (extra='allow'), making this change a no-op until then. Co-Authored-By: Claude Opus 5 (1M context) --- ...int_substitution_graphene_simulation.ipynb | 4 ++-- .../workflows/band_gap.ipynb | 6 +++--- .../workflows/band_structure.ipynb | 6 +++--- .../workflows/band_structure_hse.ipynb | 10 +++++----- .../workflows/band_structure_magn.ipynb | 4 ++-- .../workflows/defect_formation_energy.ipynb | 2 +- .../workflows/dielectric_tensor.ipynb | 6 +++--- .../workflows/equation_of_state.ipynb | 4 ++-- .../workflows/formation_energy.ipynb | 2 +- .../workflows/interfacial_energy.ipynb | 3 ++- .../workflows/phonon_dos_dispersion.ipynb | 4 ++-- .../workflows/relaxation.ipynb | 2 +- .../workflows/surface_energy.ipynb | 3 ++- .../workflows/total_energy.ipynb | 4 ++-- .../total_energy_post_processing.ipynb | 4 ++-- .../workflows/valence_band_offset.ipynb | 20 ++++++++++++++++++- .../workflows/zero_point_energy.ipynb | 4 ++-- src/py/mat3ra/notebooks_utils/workflow.py | 6 ++++-- tests/py/unit/test_workflow_utils.py | 15 +++++++++++++- 19 files changed, 72 insertions(+), 37 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_substitution_graphene_simulation.ipynb b/other/materials_designer/specific_examples/defect_point_substitution_graphene_simulation.ipynb index 89cd2feed..a4a5d9fed 100644 --- a/other/materials_designer/specific_examples/defect_point_substitution_graphene_simulation.ipynb +++ b/other/materials_designer/specific_examples/defect_point_substitution_graphene_simulation.ipynb @@ -426,12 +426,12 @@ "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "if SCF_KGRID is not None:\n", " unit = bs_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " bs_subworkflow.set_unit(unit)\n", "\n", "if KPATH is not None:\n", diff --git a/other/materials_designer/workflows/band_gap.ipynb b/other/materials_designer/workflows/band_gap.ipynb index 4d7fef9de..7bb2f819a 100644 --- a/other/materials_designer/workflows/band_gap.ipynb +++ b/other/materials_designer/workflows/band_gap.ipynb @@ -393,20 +393,20 @@ "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "if SCF_KGRID is not None:\n", " for unit_name in [\"pw_scf\", \"pw_scf_hse\"]:\n", " unit = bg_subworkflow.get_unit_by_name(name=unit_name)\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " bg_subworkflow.set_unit(unit)\n", "\n", "if NSCF_KGRID is not None:\n", " unit = bg_subworkflow.get_unit_by_name(name=\"pw_nscf\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=NSCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=NSCF_KGRID, isEdited=True).get_context_item_data())\n", " bg_subworkflow.set_unit(unit)\n", "\n", "if ECUTWFC is not None:\n", diff --git a/other/materials_designer/workflows/band_structure.ipynb b/other/materials_designer/workflows/band_structure.ipynb index 920b61230..59ba6e933 100644 --- a/other/materials_designer/workflows/band_structure.ipynb +++ b/other/materials_designer/workflows/band_structure.ipynb @@ -403,13 +403,13 @@ "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "if SCF_KGRID is not None:\n", " unit = bs_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " bs_subworkflow.set_unit(unit)\n", "\n", "if KPATH is not None:\n", @@ -421,7 +421,7 @@ "if NSCF_KGRID is not None:\n", " unit = bs_subworkflow.get_unit_by_name(name=\"pw_nscf\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=NSCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=NSCF_KGRID, isEdited=True).get_context_item_data())\n", " bs_subworkflow.set_unit(unit)\n", "\n", "if ECUTWFC is not None:\n", diff --git a/other/materials_designer/workflows/band_structure_hse.ipynb b/other/materials_designer/workflows/band_structure_hse.ipynb index f31eb0bcc..8999edd87 100644 --- a/other/materials_designer/workflows/band_structure_hse.ipynb +++ b/other/materials_designer/workflows/band_structure_hse.ipynb @@ -407,19 +407,19 @@ "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "if SCF_KGRID is not None:\n", " unit = preliminary_scf_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " preliminary_scf_subworkflow.set_unit(unit)\n", "\n", " unit = main_hse_subworkflow.get_unit_by_name(name=\"pw_scf_bands_hse\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", - " unit.add_context(PointsGridDataProvider(name=\"qgrid\", dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, name=\"qgrid\", dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " main_hse_subworkflow.set_unit(unit)\n", "\n", "if KPATH is not None:\n", @@ -440,7 +440,7 @@ "if QGRID is not None:\n", " unit = main_hse_subworkflow.get_unit_by_name(name=\"pw_scf_bands_hse\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(name=\"qgrid\", dimensions=QGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, name=\"qgrid\", dimensions=QGRID, isEdited=True).get_context_item_data())\n", " main_hse_subworkflow.set_unit(unit)\n", "\n", "bands_unit = main_hse_subworkflow.get_unit_by_name(name=\"bands\")\n", diff --git a/other/materials_designer/workflows/band_structure_magn.ipynb b/other/materials_designer/workflows/band_structure_magn.ipynb index bbbfbb0d2..a948e6324 100644 --- a/other/materials_designer/workflows/band_structure_magn.ipynb +++ b/other/materials_designer/workflows/band_structure_magn.ipynb @@ -430,13 +430,13 @@ "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "if SCF_KGRID is not None:\n", " unit = bs_subworkflow.get_unit_by_name(name=\"pw_scf_magn\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " bs_subworkflow.set_unit(unit)\n", "\n", "if KPATH is not None:\n", diff --git a/other/materials_designer/workflows/defect_formation_energy.ipynb b/other/materials_designer/workflows/defect_formation_energy.ipynb index fa92265c2..664d3e016 100644 --- a/other/materials_designer/workflows/defect_formation_energy.ipynb +++ b/other/materials_designer/workflows/defect_formation_energy.ipynb @@ -457,7 +457,7 @@ "\n", "# K-grid for the defective-cell SCF.\n", "if SCF_KGRID is not None:\n", - " new_context = PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", + " new_context = PointsGridDataProvider(material=defective_material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", " for subworkflow in defect_workflow.subworkflows:\n", " unit = subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " if unit:\n", diff --git a/other/materials_designer/workflows/dielectric_tensor.ipynb b/other/materials_designer/workflows/dielectric_tensor.ipynb index e5ef233cd..96639f975 100644 --- a/other/materials_designer/workflows/dielectric_tensor.ipynb +++ b/other/materials_designer/workflows/dielectric_tensor.ipynb @@ -408,21 +408,21 @@ "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "# SCF electronic k-grid (pw.x)\n", "if SCF_KGRID is not None:\n", " unit = dielectric_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " dielectric_subworkflow.set_unit(unit)\n", "\n", "# NSCF electronic k-grid (pw.x) -- the grid epsilon.x integrates over\n", "if NSCF_KGRID is not None:\n", " unit = dielectric_subworkflow.get_unit_by_name(name=\"pw_nscf\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=NSCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=NSCF_KGRID, isEdited=True).get_context_item_data())\n", " dielectric_subworkflow.set_unit(unit)\n", "\n", "# Energy cutoffs on every pw.x unit\n", diff --git a/other/materials_designer/workflows/equation_of_state.ipynb b/other/materials_designer/workflows/equation_of_state.ipynb index 9ab1944aa..d03e74496 100644 --- a/other/materials_designer/workflows/equation_of_state.ipynb +++ b/other/materials_designer/workflows/equation_of_state.ipynb @@ -424,14 +424,14 @@ "from mat3ra.wode.context.providers import PointsGridDataProvider\n", "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", - " new_context_relax = PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data()\n", + " new_context_relax = PointsGridDataProvider(material=base_material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data()\n", " relaxation_subworkflow = workflow.subworkflows[0]\n", " unit_to_modify_relax = relaxation_subworkflow.get_unit_by_name(name_regex=\"relax\")\n", " unit_to_modify_relax.add_context(new_context_relax)\n", " relaxation_subworkflow.set_unit(unit_to_modify_relax)\n", "\n", "if SCF_KGRID is not None:\n", - " new_context_scf = PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", + " new_context_scf = PointsGridDataProvider(material=base_material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", " total_energy_subworkflow = workflow.subworkflows[1 if ADD_RELAXATION else 0]\n", " unit_to_modify_scf = total_energy_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " unit_to_modify_scf.add_context(new_context_scf)\n", diff --git a/other/materials_designer/workflows/formation_energy.ipynb b/other/materials_designer/workflows/formation_energy.ipynb index d2f8efc64..d1125b41c 100644 --- a/other/materials_designer/workflows/formation_energy.ipynb +++ b/other/materials_designer/workflows/formation_energy.ipynb @@ -448,7 +448,7 @@ "from mat3ra.wode.context.providers import PointsGridDataProvider\n", "\n", "if SCF_KGRID is not None:\n", - " new_context = PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", + " new_context = PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", " for subworkflow in formation_workflow.subworkflows:\n", " unit = subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " if unit:\n", diff --git a/other/materials_designer/workflows/interfacial_energy.ipynb b/other/materials_designer/workflows/interfacial_energy.ipynb index f265de0d7..1fb3b988d 100644 --- a/other/materials_designer/workflows/interfacial_energy.ipynb +++ b/other/materials_designer/workflows/interfacial_energy.ipynb @@ -459,7 +459,8 @@ " raise ValueError(\"N_INTERFACES must be either 1 (vacuum) or 2 (periodic stack)\")\n", "\n", "interfacial_workflow.name = MY_WORKFLOW_NAME\n", - "interfacial_workflow = apply_scf_kgrid(interfacial_workflow, scf_kgrid=SCF_KGRID)\n", + "interfacial_workflow = apply_scf_kgrid(interfacial_workflow, scf_kgrid=SCF_KGRID,\n", + " material=interface_material)\n", "\n", "for subworkflow in interfacial_workflow.subworkflows:\n", " if \"set-n-interfaces\" not in [unit.name for unit in subworkflow.units]:\n", diff --git a/other/materials_designer/workflows/phonon_dos_dispersion.ipynb b/other/materials_designer/workflows/phonon_dos_dispersion.ipynb index ac2cc4210..20472e800 100644 --- a/other/materials_designer/workflows/phonon_dos_dispersion.ipynb +++ b/other/materials_designer/workflows/phonon_dos_dispersion.ipynb @@ -411,7 +411,7 @@ "def set_grid(subworkflow, unit_name, dimensions, name=None):\n", " unit = subworkflow.get_unit_by_name(name=unit_name)\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=dimensions, isEdited=True, **({\"name\": name} if name else {})).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=dimensions, isEdited=True, **({\"name\": name} if name else {})).get_context_item_data())\n", " subworkflow.set_unit(unit)\n", "\n", "\n", @@ -426,7 +426,7 @@ "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "# SCF electronic k-grid (pw.x)\n", diff --git a/other/materials_designer/workflows/relaxation.ipynb b/other/materials_designer/workflows/relaxation.ipynb index c299af382..07e426d76 100644 --- a/other/materials_designer/workflows/relaxation.ipynb +++ b/other/materials_designer/workflows/relaxation.ipynb @@ -377,7 +377,7 @@ " for unit_name in relax_unit_names:\n", " unit = swf.get_unit_by_name(name=unit_name)\n", " if unit:\n", - " unit.add_context(PointsGridDataProvider(dimensions=KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=KGRID, isEdited=True).get_context_item_data())\n", " swf.set_unit(unit)\n", "\n", "if ECUTWFC is not None:\n", diff --git a/other/materials_designer/workflows/surface_energy.ipynb b/other/materials_designer/workflows/surface_energy.ipynb index e98e13fc4..b46852cf2 100644 --- a/other/materials_designer/workflows/surface_energy.ipynb +++ b/other/materials_designer/workflows/surface_energy.ipynb @@ -377,7 +377,8 @@ "from mat3ra.notebooks_utils.ipython.entity.workflow.visualize import visualize_workflow\n", "\n", "surface_workflow.name = MY_WORKFLOW_NAME\n", - "surface_workflow = apply_scf_kgrid(surface_workflow, scf_kgrid=SCF_KGRID, first_only=True)\n", + "surface_workflow = apply_scf_kgrid(surface_workflow, scf_kgrid=SCF_KGRID, first_only=True,\n", + " material=bulk_material)\n", "\n", "visualize_workflow(surface_workflow)" ] diff --git a/other/materials_designer/workflows/total_energy.ipynb b/other/materials_designer/workflows/total_energy.ipynb index dc40720fd..6b2e81711 100644 --- a/other/materials_designer/workflows/total_energy.ipynb +++ b/other/materials_designer/workflows/total_energy.ipynb @@ -377,7 +377,7 @@ "from mat3ra.wode.context.providers import PointsGridDataProvider\n", "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", - " new_context_relax = PointsGridDataProvider(dimensions=RELAXATION_KGRID,\n", + " new_context_relax = PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID,\n", " isEdited=True).get_context_item_data() if ADD_RELAXATION else None\n", " relaxation_subworkflow = workflow.subworkflows[0]\n", " unit_to_modify_relax = relaxation_subworkflow.get_unit_by_name(name_regex=\"relax\")\n", @@ -385,7 +385,7 @@ " relaxation_subworkflow.set_unit(unit_to_modify_relax)\n", "\n", "if SCF_KGRID is not None:\n", - " new_context_scf = PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", + " new_context_scf = PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", " band_gap_subworkflow = workflow.subworkflows[1 if ADD_RELAXATION else 0]\n", " unit_to_modify_scf = band_gap_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " unit_to_modify_scf.add_context(new_context_scf)\n", diff --git a/other/materials_designer/workflows/total_energy_post_processing.ipynb b/other/materials_designer/workflows/total_energy_post_processing.ipynb index ac1ec85aa..0ab88dca9 100644 --- a/other/materials_designer/workflows/total_energy_post_processing.ipynb +++ b/other/materials_designer/workflows/total_energy_post_processing.ipynb @@ -464,12 +464,12 @@ "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n", " workflow.subworkflows[0].set_unit(unit)\n", "\n", "if SCF_KGRID is not None:\n", " unit = pp_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", " pp_subworkflow.set_unit(unit)\n", "\n", "visualize_workflow(workflow)" diff --git a/other/materials_designer/workflows/valence_band_offset.ipynb b/other/materials_designer/workflows/valence_band_offset.ipynb index 7567289af..92c78a0a9 100644 --- a/other/materials_designer/workflows/valence_band_offset.ipynb +++ b/other/materials_designer/workflows/valence_band_offset.ipynb @@ -436,6 +436,22 @@ "\n", "scf_unit_names = [\"pw_scf\", \"pw_bands\"]\n", "\n", + "\n", + "# Each espresso subworkflow runs on a different slab, so KPPRA and the reciprocal vector\n", + "# ratios differ per unit; resolve from the subworkflow's role rather than guessing.\n", + "def material_for(subworkflow_name):\n", + " name = subworkflow_name.lower()\n", + " if \"left\" in name:\n", + " return materials_by_role[\"substrate\"]\n", + " if \"right\" in name:\n", + " return materials_by_role[\"film\"]\n", + " if \"interface\" in name:\n", + " return materials_by_role[\"interface\"]\n", + " raise ValueError(\n", + " f\"Cannot tell which material {subworkflow_name!r} runs on, so its KPPRA and reciprocal \"\n", + " f\"vector ratios would be wrong. Expected the subworkflow name to carry its role.\"\n", + " )\n", + "\n", "for subworkflow in workflow.subworkflows:\n", " if subworkflow.application.name != APPLICATION_NAME:\n", " continue\n", @@ -444,7 +460,9 @@ "\n", " if SCF_KGRID is not None and \"pw_scf\" in unit_names:\n", " unit = subworkflow.get_unit_by_name(name=\"pw_scf\")\n", - " unit.add_context(PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data())\n", + " unit.add_context(PointsGridDataProvider(material=material_for(subworkflow.name),\n", + " dimensions=SCF_KGRID,\n", + " isEdited=True).get_context_item_data())\n", " subworkflow.set_unit(unit)\n", "\n", " if KPATH is not None and \"pw_bands\" in unit_names:\n", diff --git a/other/materials_designer/workflows/zero_point_energy.ipynb b/other/materials_designer/workflows/zero_point_energy.ipynb index 0827dcf19..55029e0d8 100644 --- a/other/materials_designer/workflows/zero_point_energy.ipynb +++ b/other/materials_designer/workflows/zero_point_energy.ipynb @@ -406,7 +406,7 @@ "from mat3ra.wode.context.providers import PlanewaveCutoffsContextProvider, PointsGridDataProvider\n", "\n", "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n", - " new_context_relax = PointsGridDataProvider(dimensions=RELAXATION_KGRID,\n", + " new_context_relax = PointsGridDataProvider(material=material, dimensions=RELAXATION_KGRID,\n", " isEdited=True).get_context_item_data() if ADD_RELAXATION else None\n", " relaxation_subworkflow = workflow.subworkflows[0]\n", " unit_to_modify_relax = relaxation_subworkflow.get_unit_by_name(name_regex=\"relax\")\n", @@ -414,7 +414,7 @@ " relaxation_subworkflow.set_unit(unit_to_modify_relax)\n", "\n", "if SCF_KGRID is not None:\n", - " new_context_scf = PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", + " new_context_scf = PointsGridDataProvider(material=material, dimensions=SCF_KGRID, isEdited=True).get_context_item_data()\n", " zpe_subworkflow = workflow.subworkflows[1 if ADD_RELAXATION else 0]\n", " unit_to_modify_scf = zpe_subworkflow.get_unit_by_name(name=\"pw_scf\")\n", " unit_to_modify_scf.add_context(new_context_scf)\n", diff --git a/src/py/mat3ra/notebooks_utils/workflow.py b/src/py/mat3ra/notebooks_utils/workflow.py index 3e324813a..e5de259fe 100644 --- a/src/py/mat3ra/notebooks_utils/workflow.py +++ b/src/py/mat3ra/notebooks_utils/workflow.py @@ -63,7 +63,7 @@ def patch_workflow_qe_input( def apply_scf_kgrid( - workflow: Workflow, scf_kgrid=None, *, unit_name: str = "pw_scf", first_only: bool = False + workflow: Workflow, scf_kgrid=None, *, material=None, unit_name: str = "pw_scf", first_only: bool = False ) -> Workflow: """ Attaches an edited SCF k-grid context to units named `unit_name`. @@ -71,12 +71,14 @@ def apply_scf_kgrid( Args: workflow: Workflow with subworkflows. scf_kgrid: K-grid dimensions, e.g. [4, 4, 1]. If None, the workflow is returned unchanged. + material: Material the grid applies to. KPPRA is per reciprocal atom and the reciprocal + vector ratios come from the lattice, so both are derived from it. unit_name: Name of the unit to attach the k-grid context to. first_only: If True, only patch the first matching subworkflow. """ if scf_kgrid is None: return workflow - context = PointsGridDataProvider(dimensions=scf_kgrid, isEdited=True).get_context_item_data() + context = PointsGridDataProvider(material=material, dimensions=scf_kgrid, isEdited=True).get_context_item_data() for subworkflow in workflow.subworkflows: if unit_name not in [unit.name for unit in subworkflow.units]: continue diff --git a/tests/py/unit/test_workflow_utils.py b/tests/py/unit/test_workflow_utils.py index ad4323be7..f8dbbcc81 100644 --- a/tests/py/unit/test_workflow_utils.py +++ b/tests/py/unit/test_workflow_utils.py @@ -1,3 +1,5 @@ +from types import SimpleNamespace + import pytest from mat3ra.notebooks_utils.workflow import apply_scf_kgrid, patch_workflow_qe_input from mat3ra.standata.workflows import WorkflowStandata @@ -49,9 +51,17 @@ def _surface_workflow(): return Workflow.create(config) +def _material_stub(number_of_atoms=2, reciprocal_vector_ratios=[1.0, 1.0, 0.5]): + """Stands in for `mat3ra.made.Material`, whose import needs scipy.""" + return SimpleNamespace( + basis=SimpleNamespace(number_of_atoms=number_of_atoms), + lattice=SimpleNamespace(reciprocal_vector_ratios=reciprocal_vector_ratios), + ) + + def test_apply_scf_kgrid_updates_pw_scf_context(): workflow = _surface_workflow() - apply_scf_kgrid(workflow, scf_kgrid=SCF_KGRID, first_only=True) + apply_scf_kgrid(workflow, scf_kgrid=SCF_KGRID, first_only=True, material=_material_stub()) unit = next( subworkflow.get_unit_by_name(name="pw_scf") for subworkflow in workflow.subworkflows @@ -59,3 +69,6 @@ def test_apply_scf_kgrid_updates_pw_scf_context(): ) kgrid_item = next(item for item in unit.context if item.get("name") == "kgrid") assert kgrid_item["data"]["dimensions"] == SCF_KGRID + # KPPRA is per reciprocal atom, and the ratios come from the lattice -- both via `material`. + assert kgrid_item["data"]["gridMetricValue"] == 4 * 4 * 1 * 2 + assert kgrid_item["data"]["reciprocalVectorRatios"] == [1.0, 1.0, 0.5] From caaef9c7a08e1d0159a3e856ec9b0be98e0a1475 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Tue, 11 Aug 2026 13:58:20 -0700 Subject: [PATCH 2/2] chore: pin mat3ra-wode to the SOF-7990 commit for CI The tests assert the derived KPPRA and reciprocal vector ratios, which only exist in the unpublished wode change this depends on; against the published version they read -1. Pin to the branch commit so CI exercises the real code. Repoint to the released version once wode publishes. Co-Authored-By: Claude Opus 5 (1M context) --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9dd8433f4..dc52f2555 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,8 @@ workflows = [ "mat3ra-notebooks-utils[materials]", "mat3ra-esse", "mat3ra-mode", - "mat3ra-wode", + # SOF-7990: repoint to the released version once wode publishes. + "mat3ra-wode @ git+https://github.com/mat3ra/wode.git@e80eb1627c1ebfb29f764503cc28bdb08f323a53", "mat3ra-ade", "mat3ra-prode", "mat3ra-ide",