Skip to content

Allow custom input#276

Merged
jan-janssen merged 2 commits intomainfrom
patch_input_dict
Nov 27, 2025
Merged

Allow custom input#276
jan-janssen merged 2 commits intomainfrom
patch_input_dict

Conversation

@jan-janssen
Copy link
Copy Markdown
Member

@jan-janssen jan-janssen commented Nov 27, 2025

Summary by CodeRabbit

  • New Features

    • Added an optional configuration parameter to customize LAMMPS input scripts for static, MD, and minimize runs, allowing users to replace or append input controls.
  • Bug Fixes / Behavior

    • Ensures user-provided controls override matching defaults while preserving final-line semantics.
  • Tests

    • Updated tests to verify that custom control entries are applied in generated input scripts.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 27, 2025

Walkthrough

Adds an optional input_control_file parameter and a helper _modify_input_dict to the LAMMPS file interface; the helper replaces input lines whose first token matches keys from the dict, appends unused key/value entries, and is applied in static, md, and minimize branches while preserving final-line semantics.

Changes

Cohort / File(s) Summary
LAMMPS input customization
pyiron_lammps/compatibility/file.py
Add optional input_control_file: Optional[dict] = None to lammps_file_interface_function. Add _modify_input_dict(input_control_file, lmp_str_lst) to replace lines by first-token matches and append unused entries. Integrate helper into static, md, and minimize flows, preserving final-line behavior.
Tests updated
tests/test_compatibility_file.py
Update MD test call to pass input_control_file={"thermo_modify": "flush yes"} and adjust expectations so thermo_modify flush yes replaces the previously generated thermo_modify line.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Files to review closely:
    • pyiron_lammps/compatibility/file.py — matching logic (first-token), handling of excluded last-line behavior, and appending of unused entries.
    • tests/test_compatibility_file.py — ensure test reflects intended replacement and no regressions in other generated lines.
  • Edge cases to validate: empty or comment lines, multi-word keys/commands, whitespace variations, and interactions when input_control_file is None or contains keys not present in input.

Poem

🐰 I hopped through lines of LAMMPS code,
Swapped tokens with a gentle shove,
Appended secrets left untold,
Kept the last line safe with love,
Now inputs sing — hop, hop, approve! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Allow custom input' is overly vague and generic, failing to convey the specific nature of the change. Revise the title to be more specific about the change, such as 'Add input_control_file parameter to LAMMPS interface' or 'Support custom input control file overrides in LAMMPS calculations'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch patch_input_dict

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.

@codecov
Copy link
Copy Markdown

codecov bot commented Nov 27, 2025

Codecov Report

❌ Patch coverage is 95.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.51%. Comparing base (9bfba4c) to head (d7855ba).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pyiron_lammps/compatibility/file.py 95.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #276      +/-   ##
==========================================
+ Coverage   92.47%   92.51%   +0.03%     
==========================================
  Files           8        8              
  Lines         930      948      +18     
==========================================
+ Hits          860      877      +17     
- Misses         70       71       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9bfba4c and 470066c.

📒 Files selected for processing (1)
  • pyiron_lammps/compatibility/file.py (5 hunks)
🧰 Additional context used
🪛 Ruff (0.14.6)
pyiron_lammps/compatibility/file.py

197-197: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


201-201: Ambiguous variable name: l

(E741)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: unittest_matrix (windows-latest, 3.14)

units: str = "metal",
lmp_command: str = "mpiexec -n 1 --oversubscribe lmp_mpi -in lmp.in",
resource_path: Optional[str] = None,
input_control_file: Optional[dict] = None,
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

Fix docstring inconsistency with type hint.

The type hint specifies Optional[dict], but the docstring at line 80 indicates (str|list|dict). These should match to avoid confusion.

Apply this diff to correct the docstring:

-        input_control_file (str|list|dict): Option to modify the LAMMPS input file directly
+        input_control_file (dict): Option to modify the LAMMPS input file directly

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In pyiron_lammps/compatibility/file.py around line 27 (parameter declaration)
and line 80 (docstring), the type hint for input_control_file is Optional[dict]
but the docstring lists (str|list|dict); update the docstring at line 80 to
match the type hint by changing the parameter type to Optional[dict] (e.g.,
"input_control_file (Optional[dict]): ...") and mention that the default is
None; ensure the wording reflects that only a dict or None is accepted.


def _modify_input_dict(
input_control_file: Optional[dict] = None,
lmp_str_lst: list[str] = [],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Avoid mutable default argument.

Using a mutable list [] as a default argument is a well-known Python pitfall, as the same list object is reused across function calls, potentially causing unexpected behavior.

Apply this diff to fix:

 def _modify_input_dict(
     input_control_file: Optional[dict] = None,
-    lmp_str_lst: list[str] = [],
+    lmp_str_lst: Optional[list[str]] = None,
 ):
+    if lmp_str_lst is None:
+        lmp_str_lst = []
     if input_control_file is not None:

Based on static analysis hints.

📝 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
lmp_str_lst: list[str] = [],
def _modify_input_dict(
input_control_file: Optional[dict] = None,
lmp_str_lst: Optional[list[str]] = None,
):
if lmp_str_lst is None:
lmp_str_lst = []
if input_control_file is not None:
🧰 Tools
🪛 Ruff (0.14.6)

197-197: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)

🤖 Prompt for AI Agents
In pyiron_lammps/compatibility/file.py around line 197, the function parameter
lmp_str_lst currently uses a mutable default (list[]) which can be shared across
calls; change the signature to accept None (e.g., lmp_str_lst:
Optional[list[str]] = None) and inside the function set lmp_str_lst = [] if it
is None. Add the necessary Optional import from typing if not present and keep
the original type semantics.

Comment thread pyiron_lammps/compatibility/file.py Outdated
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: 1

♻️ Duplicate comments (2)
pyiron_lammps/compatibility/file.py (2)

27-27: Docstring still inconsistent with type hint.

This issue was flagged in a previous review. The type hint at line 27 specifies Optional[dict], but the docstring at line 80 says (str|list|dict).

Also applies to: 80-80


197-197: Mutable default argument still present.

This issue was flagged in a previous review. Using [] as a default argument causes the same list object to be reused across calls.

🧹 Nitpick comments (2)
pyiron_lammps/compatibility/file.py (1)

195-214: Consider adding type annotation for dict values and a return type.

The function assumes input_control_file values are strings (used in string concatenation at line 204/210). Adding explicit typing would improve clarity and catch misuse early.

 def _modify_input_dict(
-    input_control_file: Optional[dict] = None,
-    lmp_str_lst: list[str] = [],
-):
+    input_control_file: Optional[dict[str, str]] = None,
+    lmp_str_lst: Optional[list[str]] = None,
+) -> list[str]:
+    if lmp_str_lst is None:
+        lmp_str_lst = []
tests/test_compatibility_file.py (1)

76-121: Consider adding test coverage for static and minimize modes with input_control_file.

Currently only test_calc_md_npt exercises the input_control_file parameter. Adding similar tests for static and minimize modes would ensure the feature works across all calculation types.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 470066c and d7855ba.

📒 Files selected for processing (2)
  • pyiron_lammps/compatibility/file.py (5 hunks)
  • tests/test_compatibility_file.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pyiron_lammps/compatibility/file.py (1)
pyiron_lammps/compatibility/calculate.py (1)
  • calc_static (308-309)
🪛 Ruff (0.14.6)
pyiron_lammps/compatibility/file.py

197-197: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


201-201: Ambiguous variable name: l

(E741)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: unittest_matrix (windows-latest, 3.14)
🔇 Additional comments (4)
pyiron_lammps/compatibility/file.py (3)

108-113: LGTM!

The logic correctly preserves the final run 0 command by excluding it from modification and appending it afterward.


127-131: LGTM!

The MD flow correctly applies input modifications before the run command is appended.


141-145: LGTM!

The minimize flow correctly preserves the final minimize command by the same pattern used for static.

tests/test_compatibility_file.py (1)

94-94: LGTM!

The test correctly validates that input_control_file={"thermo_modify": "flush yes"} replaces the default thermo_modify format float %20.15g line.

Also applies to: 116-116

Comment on lines +201 to +207
for l in lmp_str_lst:
key = l.split()[0]
if key in input_control_file.keys():
lmp_tmp_lst.append(key + " " + input_control_file[key])
keys_used.append(key)
else:
lmp_tmp_lst.append(l)
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

Potential IndexError on empty or whitespace-only lines.

If lmp_str_lst contains an empty string or a line with only whitespace, l.split() returns an empty list and [0] will raise an IndexError.

Apply this diff to handle edge cases:

         for l in lmp_str_lst:
-            key = l.split()[0]
-            if key in input_control_file.keys():
+            parts = l.split()
+            if not parts:
+                lmp_tmp_lst.append(l)
+                continue
+            key = parts[0]
+            if key in input_control_file:
                 lmp_tmp_lst.append(key + " " + input_control_file[key])
                 keys_used.append(key)
             else:
                 lmp_tmp_lst.append(l)

Also renamed l to a clearer variable name like line to address the ambiguous variable name warning (E741).

📝 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
for l in lmp_str_lst:
key = l.split()[0]
if key in input_control_file.keys():
lmp_tmp_lst.append(key + " " + input_control_file[key])
keys_used.append(key)
else:
lmp_tmp_lst.append(l)
for l in lmp_str_lst:
parts = l.split()
if not parts:
lmp_tmp_lst.append(l)
continue
key = parts[0]
if key in input_control_file:
lmp_tmp_lst.append(key + " " + input_control_file[key])
keys_used.append(key)
else:
lmp_tmp_lst.append(l)
🧰 Tools
🪛 Ruff (0.14.6)

201-201: Ambiguous variable name: l

(E741)

🤖 Prompt for AI Agents
In pyiron_lammps/compatibility/file.py around lines 201 to 207, the loop uses
l.split()[0] which will raise IndexError for empty or whitespace-only lines and
the variable name `l` is ambiguous; change the loop variable to `line`, call
line.split() once into parts, check if parts is non-empty before accessing
parts[0], and if empty or whitespace-only append the original line to
lmp_tmp_lst (or skip replacement) so behavior is preserved for blank lines while
avoiding the IndexError.

@jan-janssen jan-janssen merged commit b789d91 into main Nov 27, 2025
21 checks passed
@jan-janssen jan-janssen deleted the patch_input_dict branch November 27, 2025 15:12
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.

1 participant