Skip to content

feature/SOF-8009 Feat: AFIR - #356

Open
VsevolodX wants to merge 5 commits into
mainfrom
feature/SOF-8009
Open

feature/SOF-8009 Feat: AFIR#356
VsevolodX wants to merge 5 commits into
mainfrom
feature/SOF-8009

Conversation

@VsevolodX

@VsevolodX VsevolodX commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Added a Chemistry workflow section introducing machine-learning force-field reaction path discovery.
    • Added a tutorial notebook demonstrating AFIR/MACE-guided Claisen rearrangement exploration.
    • Added configurable molecular systems, optimization settings, force ramps, models, convergence criteria, and output options.
    • Included structure loading, relaxation, transition-state refinement, vibrational analysis, connected-minima validation, visualization, and export of reaction materials, trajectories, figures, and metadata.

@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

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an MLFF reaction-path discovery category and a complete AFIR/MACE Claisen rearrangement notebook. The workflow prepares structures, searches and refines the reaction path, validates the transition state, stores materials, and exports analysis results.

Changes

AFIR/MACE reaction path discovery

Layer / File(s) Summary
Workflow setup and reactant preparation
other/materials_designer/workflows/Introduction.ipynb, other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb
Adds the workflow link, configuration controls, molecule loading, MACE setup, and reactant relaxation.
AFIR path search and transition-state refinement
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb
Applies staged artificial forces, reconstructs physical energies, relaxes the product, and refines the transition state with the dimer method.
Transition-state validation and output storage
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb
Analyzes vibrational modes, verifies connected minima, generates figures, stores materials, serializes results, and adds references.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: 🟠 High · up to 143fd

The AFIR workflow can currently generate incorrect reaction paths by accepting invalid atom selections, continuing after failed optimization stages, using an invalid transition mode, or misidentifying endpoint minima. These correctness risks can lead to misleading exported results and should be fixed before merging.

Possibly related PRs

Suggested reviewers: timurbazhirov

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PubChem
  participant MACE
  participant ASE
  participant MaterialsStorage
  User->>PubChem: Fetch reactant if no local upload exists
  PubChem-->>User: Return molecular structure
  User->>MACE: Configure calculator
  MACE->>ASE: Evaluate energies and forces
  ASE-->>User: Return relaxed structures and reaction path
  User->>MaterialsStorage: Save reactant, transition state, and product metadata
  MaterialsStorage-->>User: Return stored materials and exported results
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies the main AFIR feature added by the pull request, although the branch prefix and “Feat:” label add minor noise.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/SOF-8009

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb (2)

486-490: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Clear the vibration cache before the run.

Vibrations stores each displacement result in the transition_state_vibrations cache folder and reuses any file it finds. vibrations.clean() runs only at the end of this cell. If an earlier run stopped between run() and clean(), the next run reuses results computed for a different geometry, and the reported frequencies are wrong without any error.

🛠️ Proposed fix
 vibrations = Vibrations(transition_state, name="transition_state_vibrations")
+vibrations.clean()
 vibrations.run()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 486 - 490, Update the vibration setup around the Vibrations
instance to clear the existing transition_state_vibrations cache before calling
vibrations.run(), ensuring stale displacement results are not reused while
preserving the existing summary flow.

285-300: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Close the trajectory writer before you read the file.

trajectory stays open for the rest of the notebook. Cell 5.1 reads AFIR_TRAJECTORY_PATH while the writer still holds it. On the Emscripten filesystem used by JupyterLite, unflushed frames can make the reconstructed path shorter than the search actually produced. Close the writer at the end of the ramp.

🛠️ Proposed fix
-structure.set_constraint()
+structure.set_constraint()
+trajectory.close()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 285 - 300, Close the trajectory writer after the AFIR_FORCE_RAMP
loop completes and before any later cell reads AFIR_TRAJECTORY_PATH. Add the
close operation immediately after the final structure.set_constraint() call,
using the existing trajectory object created as Trajectory.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`:
- Around line 161-167: Ensure FOLDER is created before the molecule_path
existence check and fetched-structure write, so both molecule and materials
outputs can use it on the first run. Update the PubChem request in
fetch_pubchem_structure to call quote with safe="" and configure urlopen with an
explicit timeout.
- Around line 493-503: Guard the imaginary_mode_indices lookup after its
comprehension in the cell at
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb:493-503
by raising a clear error when no qualifying modes exist, stating that the
transition state was not confirmed and that SADDLE_FMAX, the dimer step limit,
or IMAGINARY_MODE_THRESHOLD may need adjustment; the later reuse at
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb:646-651
requires no direct change because the earlier cell now fails fast.

---

Nitpick comments:
In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`:
- Around line 486-490: Update the vibration setup around the Vibrations instance
to clear the existing transition_state_vibrations cache before calling
vibrations.run(), ensuring stale displacement results are not reused while
preserving the existing summary flow.
- Around line 285-300: Close the trajectory writer after the AFIR_FORCE_RAMP
loop completes and before any later cell reads AFIR_TRAJECTORY_PATH. Add the
close operation immediately after the final structure.set_constraint() call,
using the existing trajectory object created as Trajectory.
🪄 Autofix

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 Plus

Run ID: 94f5cd18-6ec3-45b3-8d07-d4f0e27fb4fd

📥 Commits

Reviewing files that changed from the base of the PR and between 46cfbb4 and 3b088bc.

📒 Files selected for processing (2)
  • other/materials_designer/workflows/Introduction.ipynb
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb

Comment thread other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb (2)

559-560: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Use one complete validity gate before exporting a transition state.

The workflow continues after an unconverged dimer. It substitutes mode 0 when no reaction mode exists. It accepts multiple qualifying imaginary modes by selecting the first. It also accepts any two distinct relaxed structures without confirming that they match the reactant and product.

Compute one transition_state_valid value only after all checks pass: converged saddle, exactly one qualifying imaginary mode, converged endpoint relaxations, and endpoints that map to the relaxed reactant and product. Export a transition-state material only when this value is True. Otherwise, label the structure as a transition-state candidate.

  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb#L559-L560: prevent downstream transition-state processing after a non-converged saddle.
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb#L592-L605: require exactly one qualifying imaginary mode before selecting reaction_mode.
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb#L629-L651: verify both endpoint optimizations and match the endpoints to reactant and product.
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb#L743-L751: do not export an invalid candidate with the transition state name.
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb#L781-L786: serialize the complete validity result.

Also applies to: 592-605, 629-651, 743-751, 781-786

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 559 - 560, Update the reaction-path workflow to compute a single
transition_state_valid result only after confirming a converged saddle, exactly
one qualifying imaginary mode, converged endpoint relaxations, and endpoints
matching the relaxed reactant and product; remove fallback mode selection and
first-match acceptance. Gate transition-state export and naming on this value,
labeling invalid results as transition-state candidates, and serialize the
complete validity result.

351-351: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Set a finite step limit and require convergence for both relaxations.

ASE defaults BFGS.run to 100,000,000 steps. Store each return value and stop the workflow when either is False. Pass a shared RELAXATION_MAX_STEPS to both calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb` at
line 351, Update both relaxation calls using BFGS.run to pass the shared
RELAXATION_MAX_STEPS limit and capture each return value. After both
relaxations, stop the workflow if either result is False, while preserving the
existing fmax and logfile settings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`:
- Around line 559-560: Update the reaction-path workflow to compute a single
transition_state_valid result only after confirming a converged saddle, exactly
one qualifying imaginary mode, converged endpoint relaxations, and endpoints
matching the relaxed reactant and product; remove fallback mode selection and
first-match acceptance. Gate transition-state export and naming on this value,
labeling invalid results as transition-state candidates, and serialize the
complete validity result.
- Line 351: Update both relaxation calls using BFGS.run to pass the shared
RELAXATION_MAX_STEPS limit and capture each return value. After both
relaxations, stop the workflow if either result is False, while preserving the
existing fmax and logfile settings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 80ab3414-e525-4712-b07a-1ebb23c00339

📥 Commits

Reviewing files that changed from the base of the PR and between bc9ea77 and c91f992.

📒 Files selected for processing (1)
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb (2)

625-634: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Verify that the two endpoints match the intended minima.

connects_two_minima only proves that the forward and reverse relaxations differ in one tracked distance. Two unrelated minima can satisfy that test. The notebook then sets transition_state_found to True even when neither endpoint matches the optimized reactant and product.

Compare both relaxed endpoints with reactant and product, accept either direction ordering, and set transition_state_found only when both matches succeed. Otherwise report the result as an unassigned saddle connection.

Also applies to: 768-768

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 625 - 634, Update the endpoint-validation logic around
connects_two_minima and transition_state_found to compare both relaxed endpoints
against reactant and product using the existing distance-matching mechanism.
Accept either forward/reactant with reverse/product or the opposite ordering,
and set transition_state_found only when one complete pairing matches; otherwise
report the saddle connection as unassigned.

577-590: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Require exactly one reaction mode before mode following.

When no qualifying imaginary mode exists, Line 590 uses mode 0 and continues with a non-reaction mode. When multiple modes exist, it silently selects the first one. Both cases contradict the first-order-saddle requirement and can produce invalid connected minima and exported results. Stop unless exactly one mode passes the threshold.

Proposed fix
-    if not imaginary_mode_indices:
-        print("⚠️ No imaginary mode above the threshold — this structure is not a transition state.")
-
-    reaction_mode = vibrations.get_mode(imaginary_mode_indices[0] if imaginary_mode_indices else 0)
+    if len(imaginary_mode_indices) != 1:
+        raise RuntimeError(
+            "Transition state validation failed: expected exactly one imaginary mode above "
+            f"{IMAGINARY_MODE_THRESHOLD} cm⁻¹, found {len(imaginary_mode_indices)}."
+        )
+
+    reaction_mode = vibrations.get_mode(imaginary_mode_indices[0])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 577 - 590, Update the imaginary-mode validation around
imaginary_mode_indices and reaction_mode so execution stops unless exactly one
mode exceeds IMAGINARY_MODE_THRESHOLD. Remove the fallback to mode 0, select the
sole qualifying index only after validation, and prevent subsequent
mode-following, minima generation, or export logic from running for zero or
multiple qualifying modes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`:
- Around line 232-237: Update the TRACKED_PAIRS validation that computes
out_of_range to also reject negative atom indices and pairs whose two atom
indices are identical, while preserving the existing upper-bound and
error-reporting behavior. Ensure invalid pairs are reported before molecule
indexing or reaction-direction processing.
- Around line 383-384: Update the AFIR force-ramping loop around BFGS.run(...)
to capture its convergence boolean and stop immediately when a stage fails to
converge within AFIR_MAX_STEPS_PER_STAGE. Raise a clear error identifying the
failed force stage instead of passing its final geometry to the next stage;
retain the existing progression for converged stages.

---

Outside diff comments:
In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`:
- Around line 625-634: Update the endpoint-validation logic around
connects_two_minima and transition_state_found to compare both relaxed endpoints
against reactant and product using the existing distance-matching mechanism.
Accept either forward/reactant with reverse/product or the opposite ordering,
and set transition_state_found only when one complete pairing matches; otherwise
report the saddle connection as unassigned.
- Around line 577-590: Update the imaginary-mode validation around
imaginary_mode_indices and reaction_mode so execution stops unless exactly one
mode exceeds IMAGINARY_MODE_THRESHOLD. Remove the fallback to mode 0, select the
sole qualifying index only after validation, and prevent subsequent
mode-following, minima generation, or export logic from running for zero or
multiple qualifying modes.
🪄 Autofix

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 Plus

Run ID: 452d47e5-7cfc-4273-9306-532c32c74040

📥 Commits

Reviewing files that changed from the base of the PR and between c91f992 and 143fd32.

📒 Files selected for processing (1)
  • other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb

Comment on lines +232 to +237
"out_of_range = {label: pair for label, pair in TRACKED_PAIRS.items() if max(pair) >= len(molecule)}\n",
"if out_of_range:\n",
" raise ValueError(\n",
" f\"{out_of_range} out of range for {MOLECULE_NAME}, which has {len(molecule)} atoms. \"\n",
" \"Set the pairs in 1.2 from the listing above.\"\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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject negative and duplicate atom indices.

Line 232 only rejects indices above the atom count. Python accepts negative indices, so -1 silently selects the last atom and can search a different reaction. A pair with the same atom twice also creates a zero-length reaction direction later.

Proposed fix
-    out_of_range = {label: pair for label, pair in TRACKED_PAIRS.items() if max(pair) >= len(molecule)}
-    if out_of_range:
+    invalid_pairs = {
+        label: pair
+        for label, pair in TRACKED_PAIRS.items()
+        if min(pair) < 0 or max(pair) >= len(molecule) or pair[0] == pair[1]
+    }
+    if invalid_pairs:
         raise ValueError(
-            f"{out_of_range} out of range for {MOLECULE_NAME}, which has {len(molecule)} atoms. "
-            "Set the pairs in 1.2 from the listing above."
+            f"{invalid_pairs} contains invalid atom pairs for {MOLECULE_NAME}, which has {len(molecule)} atoms. "
+            "Use distinct, non-negative indices from the listing in 2.1."
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"out_of_range = {label: pair for label, pair in TRACKED_PAIRS.items() if max(pair) >= len(molecule)}\n",
"if out_of_range:\n",
" raise ValueError(\n",
" f\"{out_of_range} out of range for {MOLECULE_NAME}, which has {len(molecule)} atoms. \"\n",
" \"Set the pairs in 1.2 from the listing above.\"\n",
" )\n",
"invalid_pairs = {\n",
" label: pair\n",
" for label, pair in TRACKED_PAIRS.items()\n",
" if min(pair) < 0 or max(pair) >= len(molecule) or pair[0] == pair[1]\n",
"}\n",
"if invalid_pairs:\n",
" raise ValueError(\n",
" f\"{invalid_pairs} contains invalid atom pairs for {MOLECULE_NAME}, which has {len(molecule)} atoms. \"\n",
" \"Use distinct, non-negative indices from the listing in 2.1.\"\n",
" )\n",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 232 - 237, Update the TRACKED_PAIRS validation that computes
out_of_range to also reject negative atom indices and pairs whose two atom
indices are identical, while preserving the existing upper-bound and
error-reporting behavior. Ensure invalid pairs are reported before molecule
indexing or reaction-direction processing.

Comment on lines +383 to +384
" distances = \", \".join(f\"{label} = {structure.get_distance(*pair):.2f} Å\" for label, pair in TRACKED_PAIRS.items())\n",
" print(f\"α = {artificial_force:.1f} eV/Å → {distances}\")\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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
file="other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb"
python3 - <<'PY'
import json
from pathlib import Path
p = Path("other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb")
nb = json.loads(p.read_text())
for i, cell in enumerate(nb.get("cells", [])):
    text = "".join(cell.get("source", []))
    if "AFIR_MAX_STEPS_PER_STAGE" in text or "distances = " in text or "artificial_force" in text:
        print(f"\n--- cell {i} ({cell.get('cell_type')}) ---")
        for n, line in enumerate(text.splitlines(), 1):
            print(f"{n:4}: {line}")
PY

Repository: mat3ra/api-examples

Length of output: 7070


🏁 Script executed:

#!/bin/bash
set -e
file="other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb"
test -f "$file"
python3 - "$file" <<'PY'
import json, sys
p = sys.argv[1]
nb = json.load(open(p))
for i, c in enumerate(nb["cells"]):
    s = "".join(c.get("source", []))
    if any(x in s for x in ("AFIR_MAX_STEPS_PER_STAGE", "BFGS(structure", "distances = ", "artificial_force =")):
        print(f"--- cell {i} ---")
        print(s)
PY

Repository: mat3ra/api-examples

Length of output: 4638


🏁 Script executed:

pwd
git ls-files other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb
wc -l other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb
sed -n '350,410p' other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb

Repository: mat3ra/api-examples

Length of output: 2436


🌐 Web query:

ASE Optimizer converged fmax BFGS run steps maximum force get_forces implementation

💡 Result:

In the Atomic Simulation Environment (ASE), structure optimizers like BFGS follow a standardized interface for convergence and execution [1][2]. Convergence Criteria (fmax) The fmax parameter represents the maximum allowed force component on any individual atom [1]. An optimization run is considered converged when the force on every atom is less than fmax: max_a |F_a| < fmax [1][2] In the internal implementation, this is typically evaluated by calculating the norm of the forces for each atom and checking if the maximum value satisfies the criterion [3]. Execution (run steps) The run method controls the optimization process, accepting both fmax and a maximum number of steps as arguments [4][2]. The optimizer will terminate if: 1. The convergence criterion (fmax) is met [4][3]. 2. The number of optimization steps exceeds the specified maximum [4][3]. Implementation Details The base Optimizer class handles the main loop of the optimization, which includes retrieving forces, logging progress, and checking for convergence [3]. - Forces: Calculators attached to the Atoms object provide the forces via the get_forces method [1][5]. - Recent API Changes: ASE has been transitioning its internal API to use a gradient-based approach, where optimizers increasingly rely on get_gradient (which returns a flattened array of the negative forces) rather than directly calling get_forces in all contexts [6]. - Hessian Estimation: Optimizers like BFGS maintain an estimate of the Hessian (curvature of the potential energy surface), which is updated at each step to refine the step direction [1][7][2]. For users, the standard usage is typically: dyn = BFGS(atoms) dyn.run(fmax=0.05, steps=100) [1][4]

Citations:


🌐 Web query:

site:ase-lib.org/_modules/ase/optimize/optimize.py "forces**2" "converged"

💡 Result:

The matching ASE source is:

ase.optimize.optimize — specifically the Optimizer.converged() and gradient_converged() methods. The current implementation delegates convergence testing to self.optimizable.converged(...); it does not contain the literal forces**2 expression there. (docs.ase-lib.org)

The force-norm calculation appears in related modules, such as ase.mep.neb and ase.mep.dimer. (docs.ase-lib.org)

Citations:


Stop the force ramp when an AFIR stage does not converge. The loop ignores the boolean returned by BFGS.run(...) and passes the final geometry to the next force stage. Raise a clear error when the stage reaches AFIR_MAX_STEPS_PER_STAGE without meeting AFIR_FMAX.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@other/materials_designer/workflows/local/reaction_path_afir_mace.ipynb`
around lines 383 - 384, Update the AFIR force-ramping loop around BFGS.run(...)
to capture its convergence boolean and stop immediately when a stage fails to
converge within AFIR_MAX_STEPS_PER_STAGE. Raise a clear error identifying the
failed force stage instead of passing its final geometry to the next stage;
retain the existing progression for converged stages.

@VsevolodX VsevolodX changed the title feature/SOF 8009 feature/SOF-8009 Feat: AFIR Aug 13, 2026
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