Skip to content

feature/SOF 7866#284

Merged
VsevolodX merged 14 commits intomainfrom
feature/SOF-7866
Apr 2, 2026
Merged

feature/SOF 7866#284
VsevolodX merged 14 commits intomainfrom
feature/SOF-7866

Conversation

@VsevolodX
Copy link
Copy Markdown
Member

@VsevolodX VsevolodX commented Mar 31, 2026

  • update: add EOS NB
  • update: add EOS NB
  • update: add EOS NB - clean
  • update: add utils
  • update: update intro NB

Summary by CodeRabbit

  • New Features

    • Added an end-to-end Equation of State notebook: scale materials, create/submit batch jobs, extract energies, fit EOS, and produce interactive energy–volume and derivative plots.
    • Added user-facing utilities for generating readable material labels, creating scaled variants, and building per-material records for batch EOS runs.
  • Documentation

    • Reorganized Thermodynamics TOC: introduced an Equation of State entry, renumbered subsections, and added a Formation Energy placeholder.

@review-notebook-app
Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an end-to-end Equation of State (EOS) workflow: new EOS notebook, EOS helper utilities, small API job helper updates, and an Introduction notebook TOC update linking the new workflow. Changes are additions and markdown updates; no public API removals.

Changes

Cohort / File(s) Summary
Introduction TOC
other/materials_designer/workflows/Introduction.ipynb
Updated Thermodynamics TOC: replaced "6.1 Surface Energy" with "6.1 Equation of State" (linking to the new notebook), reindexed subsequent subsections, and added "6.6 Formation Energy".
EOS Notebook
other/materials_designer/workflows/equation_of_state.ipynb
New Jupyter notebook implementing EOS: auth (OIDC), APIClient init, base material load, isotropic scaling, materials-set creation, workflow selection/mutation, per-material job creation/submission/polling, energy retrieval, plotting, and EOS fit using ASE.
API job helpers
utils/api.py
Adjusted create_job(...) return type to Union[dict, List[dict]] and added submit_jobs(endpoint, job_ids) -> None helper for submitting job IDs.
EOS utilities
utils/equation_of_state.py
New module with get_material_label(), scale_material() (validates scale, applies isotropic lattice scaling, names scaled material), and build_eos_candidate_records() to summarize scale/volume/atom-count records.
Dependencies
pyproject.toml
Bumped minimum mat3ra-made dependency from >=2025.8.13.post0 to >=2026.4.1.post0.

Sequence Diagram

sequenceDiagram
    actor User
    participant Browser as Browser / Jupyter
    participant APIClient as APIClient
    participant MaterialStore as Material Store
    participant WorkflowSvc as Workflow Service
    participant JobSvc as Job Service
    participant Compute as Compute Cluster
    participant Results as Results/Plotter

    User->>Browser: configure EOS params
    Browser->>APIClient: authenticate (OIDC)
    APIClient-->>Browser: session token
    Browser->>MaterialStore: load base material
    MaterialStore-->>Browser: material object
    loop for each scale
        Browser->>Browser: generate scaled material (scale_material)
        Browser->>APIClient: save/reuse scaled material + metadata
        APIClient-->>Browser: material ID
    end
    Browser->>WorkflowSvc: load/select EOS workflow
    WorkflowSvc-->>Browser: workflow object
    Browser->>JobSvc: create jobs for scaled materials
    JobSvc-->>Browser: job IDs
    Browser->>JobSvc: submit_jobs(job IDs)
    JobSvc->>Compute: submit jobs
    Compute-->>JobSvc: job status updates
    loop poll
        Browser->>JobSvc: poll job status
        JobSvc-->>Browser: statuses & results
    end
    Browser->>Results: extract energies & volumes
    Results-->>User: plot energy vs volume & fit EOS
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • timurbazhirov
  • pranabdas

Poem

🐰 I scaled each lattice, small and grand,
Hopped through jobs with steady hand,
Energies sang, curves came bright,
Plotly sketched the EOS light,
A bunny's hop—science feels right! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'feature/SOF 7866' is vague and generic, using only a ticket/issue reference without describing the actual changes made (adding equation-of-state workflow, utilities, and documentation updates). Provide a descriptive title like 'Add equation-of-state workflow notebook and supporting utilities' that summarizes the primary changes for a developer scanning pull request history.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/SOF-7866

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@other/materials_designer/workflows/equation_of_state.ipynb`:
- Around line 442-446: The saved_workflow returned by get_or_create_workflow
(and wrapped by Workflow.create as saved_workflow) is a cleaned/persisted copy
that strips unit-level special context; when calling create_jobs_for_materials
you must pass the original in-memory workflow (the variable named workflow) so
edits from section 4.3 (k-grid and other per-unit settings) are preserved.
Locate the calls to create_jobs_for_materials that currently use saved_workflow
(and any similar uses around the other occurrence at lines ~521-524) and change
them to use the original workflow variable instead; keep
get_or_create_workflow/get_or_create_workflow response handling for persistence
but do not use saved_workflow for job creation.
- Around line 635-653: The plot is incorrectly showing E/V instead of E(V);
remove the computed "energy_per_volume" column and update the plot call to use
"total_energy" (use plot_df and px.line with y="total_energy" instead of
"energy_per_volume"), adjust fig title and yaxis_title to reflect "Total Energy
(eV)" and ensure hover_data still includes "total_energy"; use the existing
symbols successful_df, plot_df, fig, and px.line when making these edits.

In `@utils/api.py`:
- Around line 297-309: The loop inside create_jobs_for_materials currently
accepts any response from create_job and silently flattens lists, breaking the
documented 1:1 contract; change the handling so that for each material the
response must be exactly one job: call create_job (function create_job), then if
the response is a list require len(response) == 1 and use that single item, if
the response is None or a list with length != 1 raise a clear exception (or
return an error) to fail fast; update the code paths that append to the jobs
list (jobs.extend / jobs.append) to only append the single validated job for the
current material to preserve strict material->job correspondence.

In `@utils/equation_of_state.py`:
- Around line 67-81: The function build_eos_candidate_records currently zips
materials and scale_factors which silently truncates mismatched inputs; before
iterating, add a length check comparing len(materials) and len(scale_factors)
and raise a clear exception (e.g., ValueError) if they differ, mentioning both
lengths and the function name to help debug; keep the rest of the function logic
intact so records are only built when the two sequences are the same length.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1caa4013-ad02-4ee1-abf6-bc1e343b24a7

📥 Commits

Reviewing files that changed from the base of the PR and between 2a91308 and 7bab1ea.

📒 Files selected for processing (4)
  • other/materials_designer/workflows/Introduction.ipynb
  • other/materials_designer/workflows/equation_of_state.ipynb
  • utils/api.py
  • utils/equation_of_state.py

utils/api.py Outdated
Comment on lines +297 to +309
response = create_job(
api_client=api_client,
materials=[material],
workflow=workflow,
project_id=project_id,
owner_id=owner_id,
prefix=job_name,
compute=compute,
)
if isinstance(response, list):
jobs.extend(response)
else:
jobs.append(response)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fail fast unless each material produces exactly one job.

create_jobs_for_materials() is documented as 1:1, but this branch silently flattens any list returned by create_job(). If one iteration yields 0 or >1 jobs, downstream code that zips materials with jobs will misassociate IDs, statuses, and results.

Proposed fix
         response = create_job(
             api_client=api_client,
             materials=[material],
             workflow=workflow,
             project_id=project_id,
             owner_id=owner_id,
             prefix=job_name,
             compute=compute,
         )
-        if isinstance(response, list):
-            jobs.extend(response)
-        else:
-            jobs.append(response)
+        created_jobs = response if isinstance(response, list) else [response]
+        if len(created_jobs) != 1:
+            raise ValueError(
+                f"Expected exactly one job for material index {index}, got {len(created_jobs)}."
+            )
+        jobs.append(created_jobs[0])
     return jobs
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/api.py` around lines 297 - 309, The loop inside
create_jobs_for_materials currently accepts any response from create_job and
silently flattens lists, breaking the documented 1:1 contract; change the
handling so that for each material the response must be exactly one job: call
create_job (function create_job), then if the response is a list require
len(response) == 1 and use that single item, if the response is None or a list
with length != 1 raise a clear exception (or return an error) to fail fast;
update the code paths that append to the jobs list (jobs.extend / jobs.append)
to only append the single validated job for the current material to preserve
strict material->job correspondence.

Comment on lines +67 to +81
def build_eos_candidate_records(materials: Sequence[Material], scale_factors: Sequence[float]) -> List[Dict[str, Any]]:
"""
Builds summary records for scaled EOS materials.
"""
records = []
for scale_factor, material in zip(scale_factors, materials):
records.append(
{
"scale_factor": scale_factor,
"material_name": get_material_label(material),
"volume": material.lattice.cell_volume,
"atoms": material.basis.number_of_atoms,
}
)
return records
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reject mismatched EOS inputs instead of truncating them.

If materials and scale_factors drift out of sync, this helper silently drops trailing items and produces an incomplete EOS table. Add a length check before iterating.

Proposed fix
 def build_eos_candidate_records(materials: Sequence[Material], scale_factors: Sequence[float]) -> List[Dict[str, Any]]:
     """
     Builds summary records for scaled EOS materials.
     """
+    if len(materials) != len(scale_factors):
+        raise ValueError("materials and scale_factors must have the same length.")
+
     records = []
     for scale_factor, material in zip(scale_factors, materials):
         records.append(
             {
                 "scale_factor": scale_factor,
🧰 Tools
🪛 Ruff (0.15.7)

[warning] 72-72: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/equation_of_state.py` around lines 67 - 81, The function
build_eos_candidate_records currently zips materials and scale_factors which
silently truncates mismatched inputs; before iterating, add a length check
comparing len(materials) and len(scale_factors) and raise a clear exception
(e.g., ValueError) if they differ, mentioning both lengths and the function name
to help debug; keep the rest of the function logic intact so records are only
built when the two sequences are the same length.

return "Material"


def get_isotropic_strain_matrix(scale_factor: float) -> Matrix3x3Schema:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should be in made

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
utils/equation_of_state.py (1)

47-53: ⚠️ Potential issue | 🟡 Minor

Prevent silent truncation when EOS inputs are mismatched.

At Line 52, zip(scale_factors, materials) drops trailing items when lengths differ. Add an explicit length check and use strict=True so mismatches fail fast with a clear error.

Suggested patch
 def build_eos_candidate_records(materials: Sequence[Material], scale_factors: Sequence[float]) -> List[Dict[str, Any]]:
     """
     Builds summary records for scaled EOS materials.
     """
+    if len(materials) != len(scale_factors):
+        raise ValueError(
+            f"build_eos_candidate_records: materials ({len(materials)}) and "
+            f"scale_factors ({len(scale_factors)}) must have the same length."
+        )
+
     records = []
-    for scale_factor, material in zip(scale_factors, materials):
+    for scale_factor, material in zip(scale_factors, materials, strict=True):
         records.append(
             {
                 "scale_factor": scale_factor,
                 "material_name": get_material_label(material),
                 "volume": material.lattice.cell_volume,
                 "atoms": material.basis.number_of_atoms,
             }
         )
     return records
#!/bin/bash
# Verify Python-version compatibility before adopting zip(..., strict=True)
# Expected: Python >= 3.10 in project constraints.
set -euo pipefail

fd -HI 'pyproject.toml|setup.cfg|setup.py|tox.ini|Pipfile|.python-version'
rg -n --iglob 'pyproject.toml' --iglob 'setup.cfg' --iglob 'setup.py' --iglob 'tox.ini' --iglob 'Pipfile' --iglob '.python-version' \
  'requires-python|python_requires|target-version|minversion|python_version'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/equation_of_state.py` around lines 47 - 53, The function
build_eos_candidate_records currently iterates with zip(scale_factors,
materials) which silently drops items if the sequences differ in length; update
the function to first assert or raise a clear ValueError when len(scale_factors)
!= len(materials) and then iterate using zip(scale_factors, materials,
strict=True) so mismatched inputs fail fast with a descriptive error; reference
the parameters scale_factors and materials and the function name
build_eos_candidate_records when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@utils/equation_of_state.py`:
- Around line 47-53: The function build_eos_candidate_records currently iterates
with zip(scale_factors, materials) which silently drops items if the sequences
differ in length; update the function to first assert or raise a clear
ValueError when len(scale_factors) != len(materials) and then iterate using
zip(scale_factors, materials, strict=True) so mismatched inputs fail fast with a
descriptive error; reference the parameters scale_factors and materials and the
function name build_eos_candidate_records when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 68865ac0-04be-4e49-bfc1-05caac5e9d2c

📥 Commits

Reviewing files that changed from the base of the PR and between 3f80e90 and 29d2df6.

📒 Files selected for processing (1)
  • utils/equation_of_state.py

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
other/materials_designer/workflows/equation_of_state.ipynb (1)

565-577: ⚠️ Potential issue | 🟠 Major

Enforce exactly one job per material in this loop.

Line 576 silently accepts multi-item responses and assumes non-empty lists. That can desynchronize material/job records and mislabel results.

Proposed fix
 for index, material in enumerate(saved_materials):
     job_name = f"{job_prefix} | scale={SCALE_FACTORS[index]:.4f}"
     job = create_job(
         api_client=client,
         materials=[material],
         workflow=workflow,
         project_id=project_id,
         owner_id=ACCOUNT_ID,
         prefix=job_name,
         compute=compute.to_dict(),
     )
-    jobs.append(job if not isinstance(job, list) else job[0])
+    created_jobs = job if isinstance(job, list) else [job]
+    if len(created_jobs) != 1:
+        raise ValueError(
+            f"Expected exactly one job for material index {index}, got {len(created_jobs)}."
+        )
+    jobs.append(created_jobs[0])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@other/materials_designer/workflows/equation_of_state.ipynb` around lines 565
- 577, The loop over saved_materials can receive lists from create_job and
currently accepts multi-item responses, causing misalignment; change the
handling in the loop that calls create_job (with symbols saved_materials,
SCALE_FACTORS, create_job, jobs, job_name) to enforce exactly one job per
material: validate the return value is a single job (not a list or empty), raise
or log an error if create_job returns a list or None/empty, and only append that
single job to jobs (do not silently pick job[0]); include clear error context
mentioning the material index and job_name so failures are explicit and won't
desynchronize records.
🧹 Nitpick comments (1)
utils/api.py (1)

211-229: Align create_job docstring with the declared return type.

The function is now typed as Union[dict, List[dict]], but the docstring still says it returns list[dict]. Please update the Returns section to match the actual contract.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/api.py` around lines 211 - 229, The docstring for create_job is out of
sync with its type signature: update the Returns section to reflect the declared
return type Union[dict, List[dict]] (i.e., explain that create_job may return a
single job dict or a list of job dicts depending on whether a single material or
multiple materials were passed), and include brief notes about the circumstances
when a dict vs a list[dict] is returned; update the Returns description and
example lines in the create_job docstring to match the function signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@other/materials_designer/workflows/equation_of_state.ipynb`:
- Around line 207-209: The code directly indexes projects[0] after calling
client.projects.list, which will raise if no default project exists; update the
logic around projects, project_id and the print statement to check if the
returned list is empty (e.g., if not projects) and fail fast with a clear error
message (or raise an exception/exit) before attempting to access projects[0];
ensure the error message includes the ACCOUNT_ID and suggests creating a default
project so the subsequent indexing and use of project_id is safe.
- Around line 491-516: The cluster-selection code using the clusters list and
CLUSTER_NAME can fail when clusters is empty or when CLUSTER_NAME doesn't match
any hostname; update the block (around the Compute import and the logic that
assigns cluster from clusters and CLUSTER_NAME) to first check if clusters is
empty and raise a clear exception or return early, then if CLUSTER_NAME is set
use next(...) but handle None by raising a descriptive error (or falling back to
clusters[0] only if you decide that's safe), and ensure any downstream use of
cluster assumes a valid object; include clear messages mentioning CLUSTER_NAME
and the available hostnames to aid debugging.

---

Duplicate comments:
In `@other/materials_designer/workflows/equation_of_state.ipynb`:
- Around line 565-577: The loop over saved_materials can receive lists from
create_job and currently accepts multi-item responses, causing misalignment;
change the handling in the loop that calls create_job (with symbols
saved_materials, SCALE_FACTORS, create_job, jobs, job_name) to enforce exactly
one job per material: validate the return value is a single job (not a list or
empty), raise or log an error if create_job returns a list or None/empty, and
only append that single job to jobs (do not silently pick job[0]); include clear
error context mentioning the material index and job_name so failures are
explicit and won't desynchronize records.

---

Nitpick comments:
In `@utils/api.py`:
- Around line 211-229: The docstring for create_job is out of sync with its type
signature: update the Returns section to reflect the declared return type
Union[dict, List[dict]] (i.e., explain that create_job may return a single job
dict or a list of job dicts depending on whether a single material or multiple
materials were passed), and include brief notes about the circumstances when a
dict vs a list[dict] is returned; update the Returns description and example
lines in the create_job docstring to match the function signature.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2bd44768-2174-48bc-bff4-247a6a2b8033

📥 Commits

Reviewing files that changed from the base of the PR and between f7a95a5 and 61fd933.

📒 Files selected for processing (3)
  • other/materials_designer/workflows/equation_of_state.ipynb
  • pyproject.toml
  • utils/api.py
✅ Files skipped from review due to trivial changes (1)
  • pyproject.toml

Comment on lines +207 to +209
"projects = client.projects.list({\"isDefault\": True, \"owner._id\": ACCOUNT_ID})\n",
"project_id = projects[0][\"_id\"]\n",
"print(f\"Using project: {projects[0]['name']} ({project_id})\")"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against missing default project before indexing.

projects[0] will crash when no default project exists for the selected owner. Add an explicit check and fail with a clear message.

Proposed fix
 projects = client.projects.list({"isDefault": True, "owner._id": ACCOUNT_ID})
-project_id = projects[0]["_id"]
+if not projects:
+    raise ValueError(f"No default project found for owner '{ACCOUNT_ID}'.")
+project_id = projects[0]["_id"]
 print(f"Using project: {projects[0]['name']} ({project_id})")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@other/materials_designer/workflows/equation_of_state.ipynb` around lines 207
- 209, The code directly indexes projects[0] after calling client.projects.list,
which will raise if no default project exists; update the logic around projects,
project_id and the print statement to check if the returned list is empty (e.g.,
if not projects) and fail fast with a clear error message (or raise an
exception/exit) before attempting to access projects[0]; ensure the error
message includes the ACCOUNT_ID and suggests creating a default project so the
subsequent indexing and use of project_id is safe.

Comment on lines +491 to +516
"clusters = client.clusters.list()\n",
"print(f\"Available clusters: {[c['hostname'] for c in clusters]}\")"
]
},
{
"cell_type": "markdown",
"id": "35",
"metadata": {},
"source": [
"### 5.2. Create compute configuration for the jobs"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36",
"metadata": {},
"outputs": [],
"source": [
"from mat3ra.ide.compute import Compute\n",
"\n",
"if CLUSTER_NAME:\n",
" cluster = next((c for c in clusters if CLUSTER_NAME in c[\"hostname\"]), None)\n",
"else:\n",
" cluster = clusters[0]\n",
"\n",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle empty cluster list and unmatched CLUSTER_NAME explicitly.

This block can fail when clusters is empty or when CLUSTER_NAME does not match any hostname, leading to downstream attribute errors.

Proposed fix
 clusters = client.clusters.list()
 print(f"Available clusters: {[c['hostname'] for c in clusters]}")
+if not clusters:
+    raise ValueError("No clusters available for this account.")
 
 if CLUSTER_NAME:
     cluster = next((c for c in clusters if CLUSTER_NAME in c["hostname"]), None)
+    if cluster is None:
+        raise ValueError(f"No cluster matched CLUSTER_NAME='{CLUSTER_NAME}'.")
 else:
     cluster = clusters[0]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@other/materials_designer/workflows/equation_of_state.ipynb` around lines 491
- 516, The cluster-selection code using the clusters list and CLUSTER_NAME can
fail when clusters is empty or when CLUSTER_NAME doesn't match any hostname;
update the block (around the Compute import and the logic that assigns cluster
from clusters and CLUSTER_NAME) to first check if clusters is empty and raise a
clear exception or return early, then if CLUSTER_NAME is set use next(...) but
handle None by raising a descriptive error (or falling back to clusters[0] only
if you decide that's safe), and ensure any downstream use of cluster assumes a
valid object; include clear messages mentioning CLUSTER_NAME and the available
hostnames to aid debugging.

)


def get_material_label(material: Material) -> str:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can move it to made.Material itself or remove

return "Material"


def scale_material(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could be in made

"scale_factor": scale_factor,
"material_name": get_material_label(material),
"volume": material.lattice.cell_volume,
"atoms": material.basis.number_of_atoms,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can remove this

@VsevolodX VsevolodX merged commit 52d420e into main Apr 2, 2026
5 checks passed
@VsevolodX VsevolodX deleted the feature/SOF-7866 branch April 2, 2026 05:06
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