-
Notifications
You must be signed in to change notification settings - Fork 5
Implement raw parsing functions which only need the output file as input #291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
28b069a
d1f46c8
211887a
8bfa64f
643e9f6
ce3abac
559f623
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,34 +2,21 @@ | |
|
|
||
| import os | ||
| import warnings | ||
| from dataclasses import asdict, dataclass, field | ||
| from io import StringIO | ||
| from typing import Dict, List, Optional, Tuple, Union | ||
|
|
||
| import numpy as np | ||
| import pandas as pd | ||
| from ase.atoms import Atoms | ||
|
|
||
| from pyiron_lammps.output_raw import ( | ||
| parse_raw_dump_from_h5md, | ||
| parse_raw_dump_from_text, | ||
| parse_raw_lammps_log, | ||
| ) | ||
| from pyiron_lammps.structure import UnfoldingPrism | ||
| from pyiron_lammps.units import UnitConverter | ||
|
|
||
|
|
||
| @dataclass | ||
| class DumpData: | ||
| steps: List = field(default_factory=lambda: []) | ||
| natoms: List = field(default_factory=lambda: []) | ||
| cells: List = field(default_factory=lambda: []) | ||
| indices: List = field(default_factory=lambda: []) | ||
| forces: List = field(default_factory=lambda: []) | ||
| mean_forces: List = field(default_factory=lambda: []) | ||
| velocities: List = field(default_factory=lambda: []) | ||
| mean_velocities: List = field(default_factory=lambda: []) | ||
| unwrapped_positions: List = field(default_factory=lambda: []) | ||
| mean_unwrapped_positions: List = field(default_factory=lambda: []) | ||
| positions: List = field(default_factory=lambda: []) | ||
| computes: Dict = field(default_factory=lambda: {}) | ||
|
|
||
|
|
||
| def remap_indices_ase( | ||
| lammps_indices: Union[np.ndarray, List], | ||
| potential_elements: Union[np.ndarray, List], | ||
|
|
@@ -135,45 +122,6 @@ def parse_lammps_output( | |
| return hdf_output | ||
|
|
||
|
|
||
| def to_amat(l_list: Union[np.ndarray, List]) -> List: | ||
| lst = np.reshape(l_list, -1) | ||
| if len(lst) == 9: | ||
| ( | ||
| xlo_bound, | ||
| xhi_bound, | ||
| xy, | ||
| ylo_bound, | ||
| yhi_bound, | ||
| xz, | ||
| zlo_bound, | ||
| zhi_bound, | ||
| yz, | ||
| ) = lst | ||
|
|
||
| elif len(lst) == 6: | ||
| xlo_bound, xhi_bound, ylo_bound, yhi_bound, zlo_bound, zhi_bound = lst | ||
| xy, xz, yz = 0.0, 0.0, 0.0 | ||
| else: | ||
| raise ValueError("This format for amat not yet implemented: " + str(len(lst))) | ||
|
|
||
| # > xhi_bound - xlo_bound = xhi -xlo + MAX(0.0, xy, xz, xy + xz) - MIN(0.0, xy, xz, xy + xz) | ||
| # > xhili = xhi -xlo = xhi_bound - xlo_bound - MAX(0.0, xy, xz, xy + xz) + MIN(0.0, xy, xz, xy + xz) | ||
| xhilo = ( | ||
| (xhi_bound - xlo_bound) | ||
| - max([0.0, xy, xz, xy + xz]) | ||
| + min([0.0, xy, xz, xy + xz]) | ||
| ) | ||
|
|
||
| # > yhilo = yhi -ylo = yhi_bound -ylo_bound - MAX(0.0, yz) + MIN(0.0, yz) | ||
| yhilo = (yhi_bound - ylo_bound) - max([0.0, yz]) + min([0.0, yz]) | ||
|
|
||
| # > zhi - zlo = zhi_bound- zlo_bound | ||
| zhilo = zhi_bound - zlo_bound | ||
|
|
||
| cell = [[xhilo, 0, 0], [xy, yhilo, 0], [xz, yz, zhilo]] | ||
| return cell | ||
|
|
||
|
|
||
| def _parse_dump( | ||
| dump_h5_full_file_name: str, | ||
| dump_out_full_file_name: str, | ||
|
|
@@ -183,9 +131,12 @@ def _parse_dump( | |
| remap_indices_funct: callable = remap_indices_ase, | ||
| ) -> Dict: | ||
| if os.path.isfile(dump_h5_full_file_name): | ||
| return _collect_dump_from_h5md( | ||
| if not _check_ortho_prism(prism=prism): | ||
| raise RuntimeError( | ||
| "The Lammps output will not be mapped back to pyiron correctly." | ||
| ) | ||
| return parse_raw_dump_from_h5md( | ||
| file_name=dump_h5_full_file_name, | ||
| prism=prism, | ||
| ) | ||
|
Comment on lines
+134
to
140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# First, let's understand the file structure and locate key functions
echo "=== File structure check ==="
wc -l pyiron_lammps/output.py
echo -e "\n=== Examining H5MD and text parsing paths ==="
# Look at the parse_raw_dump_from_h5md function definition and its return
rg -n "def parse_raw_dump_from_h5md" pyiron_lammps/
echo -e "\n=== Check what parse_raw_dump_from_h5md returns ==="
fd -e py | xargs rg -l "parse_raw_dump_from_h5md" | head -5
echo -e "\n=== Checking remap_indices_funct usage in text path ==="
rg -n "remap_indices_funct" pyiron_lammps/output.py -A2 -B2
echo -e "\n=== Checking unfold_cell usage ==="
rg -n "unfold_cell" pyiron_lammps/output.py -A2 -B2
echo -e "\n=== Checking parse_raw_dump_from_text ==="
rg -n "def parse_raw_dump_from_text" pyiron_lammps/Repository: pyiron/pyiron_lammps Length of output: 1936 🏁 Script executed: #!/bin/bash
# Let's examine the actual implementation of these parsing functions
# and see what they return
echo "=== Finding parse_raw_dump_from_h5md implementation ==="
rg -A 30 "def parse_raw_dump_from_h5md" --type py
echo -e "\n=== Finding parse_raw_dump_from_text implementation ==="
rg -A 30 "def parse_raw_dump_from_text" --type py | head -60Repository: pyiron/pyiron_lammps Length of output: 3960 🏁 Script executed: #!/bin/bash
# Let's see the complete context of lines around 134-140 and 142-179
echo "=== Reading the complete _parse_dump method context ==="
sed -n '120,190p' pyiron_lammps/output.pyRepository: pyiron/pyiron_lammps Length of output: 2543 🏁 Script executed: #!/bin/bash
# Check if H5MD format includes type/atom_type information
echo "=== Searching for H5MD type/atom_type information ==="
rg -n "h5md.*type|h5md.*atom|particles/all" pyiron_lammps/output_raw.py -A5 -B5
echo -e "\n=== Check _check_ortho_prism implementation ==="
rg -n "def _check_ortho_prism" pyiron_lammps/output.py -A15
echo -e "\n=== Check unfold_cell implementation and prism attributes ==="
rg -n "def unfold_cell|prism.s|prism.pbc" pyiron_lammps/ --type py | head -20
echo -e "\n=== Look for tests that verify H5MD path ==="
fd -e py -path '*/test*' | xargs rg -l "h5md\|H5MD" 2>/dev/null | head -5Repository: pyiron/pyiron_lammps Length of output: 2129 🏁 Script executed: #!/bin/bash
# Check what UnfoldingPrism properties are used
echo "=== Check UnfoldingPrism attributes in _collect_dump_from_text ==="
sed -n '158,180p' pyiron_lammps/output.py
echo -e "\n=== Check if unfold_cell depends on prism state beyond R ==="
rg -B5 -A15 "def unfold_cell" --type py
echo -e "\n=== Check test files for H5MD usage ==="
find . -path '*/test*' -name '*.py' -exec rg -l "dump.*h5|h5md" {} \; 2>/dev/null | head -3Repository: pyiron/pyiron_lammps Length of output: 2424 🏁 Script executed: #!/bin/bash
# Check imports and understand what DumpData contains
echo "=== Check DumpData structure ==="
rg -n "class DumpData|def DumpData" pyiron_lammps/ --type py -A20 | head -40
echo -e "\n=== Check if indices are always expected in output ==="
rg -n "indices" pyiron_lammps/output.py | head -15
echo -e "\n=== Verify return values from parse functions are used correctly ==="
sed -n '130,160p' pyiron_lammps/output.pyRepository: pyiron/pyiron_lammps Length of output: 3785 🏁 Script executed: #!/bin/bash
# Get full unfold_cell implementation
echo "=== Full unfold_cell implementation ==="
sed -n '138,160p' pyiron_lammps/structure.py
echo -e "\n=== Check prism.s attribute and folding ==="
rg -n "self.s =" pyiron_lammps/structure.py -B5 -A2
echo -e "\n=== Check tests for H5MD output path ==="
sed -n '1,50p' tests/test_output.pyRepository: pyiron/pyiron_lammps Length of output: 2149 🏁 Script executed: #!/bin/bash
# Look at test_output.py to see if H5MD parsing is tested
echo "=== Search for H5MD-related tests ==="
rg -n "h5md\|H5MD\|dump_h5" tests/test_output.py -B3 -A5
echo -e "\n=== Check if there are integration tests that use H5MD output ==="
rg -n "def test.*h5|parse_raw_dump_from_h5md" tests/ -A10Repository: pyiron/pyiron_lammps Length of output: 940 🏁 Script executed: #!/bin/bash
# Check what happens when cells are orthogonal with non-identity folding
echo "=== Understanding UnfoldingPrism initialization and folding ==="
sed -n '50,120p' pyiron_lammps/structure.py
echo -e "\n=== Full definition of prism attributes ==="
rg -n "@property" pyiron_lammps/structure.py | head -10Repository: pyiron/pyiron_lammps Length of output: 2836 🏁 Script executed: #!/bin/bash
# Get the rest of unfold_cell implementation
echo "=== Complete unfold_cell implementation ==="
sed -n '138,165p' pyiron_lammps/structure.py
echo -e "\n=== Check what happens after rotation in unfold_cell ==="
rg -n "def unfold_cell" pyiron_lammps/structure.py -A30
echo -e "\n=== Look at test_full_job_output_h5 to see what's actually validated ==="
sed -n '335,380p' tests/test_output.pyRepository: pyiron/pyiron_lammps Length of output: 3952 🏁 Script executed: #!/bin/bash
# Check if there's a self.s attribute or folding matrix
echo "=== Search for self.s or folding related attributes ==="
rg -n "self\.s\s*=" pyiron_lammps/structure.py
echo -e "\n=== Check what the test does with H5MD output ==="
sed -n '335,400p' tests/test_output.py
echo -e "\n=== Check if output_dict from H5MD is compared to text output ==="
rg -n "test_full_job_output" tests/test_output.py -A60 | head -80Repository: pyiron/pyiron_lammps Length of output: 6300 🏁 Script executed: #!/bin/bash
# Look at the actual test data to understand what's being tested
echo "=== Check test folder structure ==="
find tests/static -name "*h5*" -o -name "*dump*" 2>/dev/null | head -10
echo -e "\n=== Check if there's a dump.h5 test file ==="
ls -la tests/static/full_job_h5/ 2>/dev/null | grep -E "dump|h5" || echo "Dir not listed"
echo -e "\n=== Check what assertions are made in the H5MD test ==="
sed -n '335,360p' tests/test_output.pyRepository: pyiron/pyiron_lammps Length of output: 1633 🏁 Script executed: #!/bin/bash
# Check what parse_lammps_output_files does with the dump dict
echo "=== Find parse_lammps_output_files definition ==="
rg -n "def parse_lammps_output_files" pyiron_lammps/ -A30
echo -e "\n=== Check if dump dict with missing indices causes issues ==="
rg -n "indices.*in.*output\|output.*indices" pyiron_lammps/output.py
echo -e "\n=== Check if indices are used in post-processing ==="
rg -n "\[.indices.\]\|\['indices'\]" pyiron_lammps/output.pyRepository: pyiron/pyiron_lammps Length of output: 230 🏁 Script executed: #!/bin/bash
# Let's check what parse_lammps_output_files actually does with the dump
echo "=== Full parse_lammps_output_files function ==="
rg -n "def parse_lammps_output_files" pyiron_lammps/ -A50 | head -80
echo -e "\n=== Check if _parse_dump result is further processed ==="
rg -n "dump.*=" pyiron_lammps/output.py | grep -E "_parse_dump|parse_raw_dump"Repository: pyiron/pyiron_lammps Length of output: 274 🏁 Script executed: #!/bin/bash
# Check what happens with the dump dict after _parse_dump
echo "=== Search for where _parse_dump is called ==="
rg -n "_parse_dump\(" pyiron_lammps/output.py -B2 -A5
echo -e "\n=== Check the full context around line 60-90 ==="
sed -n '50,100p' pyiron_lammps/output.pyRepository: pyiron/pyiron_lammps Length of output: 2482 🏁 Script executed: #!/bin/bash
# Continue reading from line 85 onwards to see how dump_dict is processed
echo "=== Continue parsing of dump_dict (lines 85-130) ==="
sed -n '85,130p' pyiron_lammps/output.py
echo -e "\n=== Check if indices key is ever accessed from dump_dict ==="
rg -n "dump_dict\[.*indices" pyiron_lammps/output.py
echo -e "\n=== Check what happens with remaining keys in dump_dict ==="
rg -n "for.*in.*dump_dict\|dump_dict\[" pyiron_lammps/output.pyRepository: pyiron/pyiron_lammps Length of output: 1764 🏁 Script executed: #!/bin/bash
# Look at the full processing logic
echo "=== Full output processing logic around lines 85-123 ==="
sed -n '85,123p' pyiron_lammps/output.pyRepository: pyiron/pyiron_lammps Length of output: 1462 🏁 Script executed: #!/bin/bash
# Verify if self.ns (folding parameters) are identity for orthogonal cells
echo "=== Check how self.ns is computed ==="
rg -n "self.ns" pyiron_lammps/structure.py
echo -e "\n=== Check what self.ns property returns ==="
sed -n '215,240p' pyiron_lammps/structure.py
echo -e "\n=== Verify that orthogonal cells have identity folding ==="
# For cubic cell like in test, check if ns would be (0, 0, 0)
python3 << 'EOF'
import numpy as np
# Cubic cell like in test
cell = np.eye(3) * 3.52 # Ni cubic FCC
# Simulate UnfoldingPrism initialization logic for orthogonal case
a, b, c = cell
an, bn, cn = [np.linalg.norm(v) for v in cell]
# For cubic/orthogonal, angles should be 90 degrees
alpha = np.arccos(np.dot(b, c) / (bn * cn))
beta = np.arccos(np.dot(a, c) / (an * cn))
gamma = np.arccos(np.dot(a, b) / (an * bn))
print(f"Cell angles (should be ~pi/2 for orthogonal):")
print(f"alpha={alpha:.4f} (pi/2={np.pi/2:.4f})")
print(f"beta={beta:.4f} (pi/2={np.pi/2:.4f})")
print(f"gamma={gamma:.4f} (pi/2={np.pi/2:.4f})")
# For orthogonal case, R should be identity
R = np.dot(np.linalg.inv(cell), cell) # Should be identity for orthogonal
print(f"\nR (should be identity):\n{R}")
# For orthogonal, folding parameters n1, n2, n3 should be 0
print(f"\nFor orthogonal cell, folding parameters should be 0")
EOFRepository: pyiron/pyiron_lammps Length of output: 150 🏁 Script executed: #!/bin/bash
# Now check what the actual ns property does
echo "=== Full ns property implementation ==="
sed -n '215,230p' pyiron_lammps/structure.pyRepository: pyiron/pyiron_lammps Length of output: 456 🏁 Script executed: #!/bin/bash
# Find the ns property definition
echo "=== Search for ns property ==="
rg -n "def ns\|@property" pyiron_lammps/structure.py | grep -A1 "ns"
echo -e "\n=== Get the ns property implementation ==="
rg -n "def ns" pyiron_lammps/structure.py -A10Repository: pyiron/pyiron_lammps Length of output: 138 🏁 Script executed: #!/bin/bash
# Check if there's an ns attribute set during initialization
echo "=== Search for ns attribute assignment ==="
rg -n "\.ns\s*=" pyiron_lammps/structure.py
echo -e "\n=== Check if ns comes from parent UnfoldingPrism class ==="
rg -n "class UnfoldingPrism" pyiron_lammps/structure.py
echo -e "\n=== Check imports to understand parent class ==="
head -20 pyiron_lammps/structure.py | grep -i "import\|from"Repository: pyiron/pyiron_lammps Length of output: 641 🏁 Script executed: #!/bin/bash
# Final verification: Check if H5MD test passes and what it validates
echo "=== Run the H5MD test to see if it passes ==="
cd tests && python3 -m pytest test_output.py::TestLammpsOutput::test_full_job_output_h5 -v 2>&1 | tail -20Repository: pyiron/pyiron_lammps Length of output: 1124 🏁 Script executed: #!/bin/bash
# Check comment about H5MD specification in the code
echo "=== H5MD specification comment ==="
sed -n '67,85p' pyiron_lammps/output_raw.py
echo -e "\n=== Check if there's any validation that cells are orthogonal ==="
rg -n "is_skewed\|orthogonal\|diagonal" pyiron_lammps/ --type py | head -10
echo -e "\n=== Verify what DumpData returns to downstream ==="
rg -n "class DumpData" pyiron_lammps/output_raw.py -A15Repository: pyiron/pyiron_lammps Length of output: 1771 🏁 Script executed: #!/bin/bash
# Check if indices field being empty vs missing causes any issues
echo "=== Check how parse_raw_dump_from_text handles indices ==="
sed -n '87,150p' pyiron_lammps/output_raw.py | grep -A20 "indices"
echo -e "\n=== Verify that H5MD doesn't even attempt to parse indices ==="
sed -n '67,85p' pyiron_lammps/output_raw.pyRepository: pyiron/pyiron_lammps Length of output: 1599 Address asymmetry in H5MD vs text dump parsing paths. The H5MD branch returns raw parsed data without applying the transformations that the text path applies, creating inconsistency:
🧰 Tools🪛 Ruff (0.14.10)135-137: Avoid specifying long messages outside the exception class (TRY003) 🤖 Prompt for AI Agents |
||
| elif os.path.exists(dump_out_full_file_name): | ||
| return _collect_dump_from_text( | ||
|
|
@@ -201,31 +152,6 @@ def _parse_dump( | |
| ) | ||
|
|
||
|
|
||
| def _collect_dump_from_h5md(file_name: str, prism: UnfoldingPrism) -> Dict: | ||
| import h5py | ||
|
|
||
| if not _check_ortho_prism(prism=prism): | ||
| raise RuntimeError( | ||
| "The Lammps output will not be mapped back to pyiron correctly." | ||
| ) | ||
|
|
||
| with h5py.File(file_name, mode="r", libver="latest", swmr=True) as h5md: | ||
| positions = [pos_i.tolist() for pos_i in h5md["/particles/all/position/value"]] | ||
| steps = [steps_i.tolist() for steps_i in h5md["/particles/all/position/step"]] | ||
| forces = [for_i.tolist() for for_i in h5md["/particles/all/force/value"]] | ||
| # following the explanation at: http://nongnu.org/h5md/h5md.html | ||
| cell = [ | ||
| np.eye(3) * np.array(cell_i.tolist()) | ||
| for cell_i in h5md["/particles/all/box/edges/value"] | ||
| ] | ||
| return { | ||
| "forces": forces, | ||
| "positions": positions, | ||
| "steps": steps, | ||
| "cells": cell, | ||
| } | ||
|
|
||
|
|
||
| def _collect_dump_from_text( | ||
| file_name: str, | ||
| prism: UnfoldingPrism, | ||
|
|
@@ -237,136 +163,36 @@ def _collect_dump_from_text( | |
| general purpose routine to extract static from a lammps dump file | ||
| """ | ||
| rotation_lammps2orig = prism.R.T | ||
| with open(file_name, "r") as f: | ||
| dump = DumpData() | ||
|
|
||
| for line in f: | ||
| if "ITEM: TIMESTEP" in line: | ||
| dump.steps.append(int(f.readline())) | ||
|
|
||
| elif "ITEM: BOX BOUNDS" in line: | ||
| c1 = np.fromstring(f.readline(), dtype=float, sep=" ") | ||
| c2 = np.fromstring(f.readline(), dtype=float, sep=" ") | ||
| c3 = np.fromstring(f.readline(), dtype=float, sep=" ") | ||
| cell = np.concatenate([c1, c2, c3]) | ||
| lammps_cell = to_amat(cell) | ||
| unfolded_cell = prism.unfold_cell(lammps_cell) | ||
| dump.cells.append(unfolded_cell) | ||
|
|
||
| elif "ITEM: NUMBER OF ATOMS" in line: | ||
| n = int(f.readline()) | ||
| dump.natoms.append(n) | ||
|
|
||
| elif "ITEM: ATOMS" in line: | ||
| # get column names from line | ||
| columns = line.lstrip("ITEM: ATOMS").split() | ||
|
|
||
| # Read line by line of snapshot into a string buffer | ||
| # Than parse using pandas for speed and column acces | ||
| buf = StringIO() | ||
| for _ in range(n): | ||
| buf.write(f.readline()) | ||
| buf.seek(0) | ||
| df = pd.read_csv( | ||
| buf, | ||
| nrows=n, | ||
| sep="\\s+", | ||
| header=None, | ||
| names=columns, | ||
| engine="c", | ||
| ) | ||
| df.sort_values(by="id", ignore_index=True, inplace=True) | ||
| # Coordinate transform lammps->pyiron | ||
| dump.indices.append( | ||
| remap_indices_funct( | ||
| lammps_indices=df["type"].array.astype(int), | ||
| potential_elements=potential_elements, | ||
| structure=structure, | ||
| ) | ||
| ) | ||
|
|
||
| force = np.stack( | ||
| [df["fx"].array, df["fy"].array, df["fz"].array], axis=1 | ||
| dump_lammps_dict = parse_raw_dump_from_text(file_name=file_name) | ||
| dump_dict = {} | ||
| for key, val in dump_lammps_dict.items(): | ||
| if key in ["cells"]: | ||
| dump_dict[key] = [prism.unfold_cell(cell=cell) for cell in val] | ||
| elif key in ["indices"]: | ||
| dump_dict[key] = [ | ||
| remap_indices_funct( | ||
| lammps_indices=indices, | ||
| potential_elements=potential_elements, | ||
| structure=structure, | ||
| ) | ||
| dump.forces.append(np.matmul(force, rotation_lammps2orig)) | ||
| if "f_mean_forces[1]" in columns: | ||
| force = np.stack( | ||
| [ | ||
| df["f_mean_forces[1]"].array, | ||
| df["f_mean_forces[2]"].array, | ||
| df["f_mean_forces[3]"].array, | ||
| ], | ||
| axis=1, | ||
| ) | ||
| dump.mean_forces.append(np.matmul(force, rotation_lammps2orig)) | ||
| if "vx" in columns and "vy" in columns and "vz" in columns: | ||
| v = np.stack( | ||
| [ | ||
| df["vx"].array, | ||
| df["vy"].array, | ||
| df["vz"].array, | ||
| ], | ||
| axis=1, | ||
| ) | ||
| dump.velocities.append(np.matmul(v, rotation_lammps2orig)) | ||
|
|
||
| if "f_mean_velocities[1]" in columns: | ||
| v = np.stack( | ||
| [ | ||
| df["f_mean_velocities[1]"].array, | ||
| df["f_mean_velocities[2]"].array, | ||
| df["f_mean_velocities[3]"].array, | ||
| ], | ||
| axis=1, | ||
| ) | ||
| dump.mean_velocities.append(np.matmul(v, rotation_lammps2orig)) | ||
|
|
||
| if "xsu" in columns: | ||
| direct_unwrapped_positions = np.stack( | ||
| [ | ||
| df["xsu"].array, | ||
| df["ysu"].array, | ||
| df["zsu"].array, | ||
| ], | ||
| axis=1, | ||
| ) | ||
| dump.unwrapped_positions.append( | ||
| np.matmul( | ||
| np.matmul(direct_unwrapped_positions, lammps_cell), | ||
| rotation_lammps2orig, | ||
| ) | ||
| ) | ||
|
|
||
| direct_positions = direct_unwrapped_positions - np.floor( | ||
| direct_unwrapped_positions | ||
| ) | ||
| dump.positions.append( | ||
| np.matmul( | ||
| np.matmul(direct_positions, lammps_cell), | ||
| rotation_lammps2orig, | ||
| ) | ||
| ) | ||
|
|
||
| if "f_mean_positions[1]" in columns: | ||
| pos = np.stack( | ||
| [ | ||
| df["f_mean_positions[1]"].array, | ||
| df["f_mean_positions[2]"].array, | ||
| df["f_mean_positions[3]"].array, | ||
| ], | ||
| axis=1, | ||
| ) | ||
| dump.mean_unwrapped_positions.append( | ||
| np.matmul(pos, rotation_lammps2orig) | ||
| ) | ||
| for k in columns: | ||
| if k.startswith("c_"): | ||
| kk = k.replace("c_", "") | ||
| if kk not in dump.computes.keys(): | ||
| dump.computes[kk] = [] | ||
| dump.computes[kk].append(df[k].array) | ||
|
|
||
| return asdict(dump) | ||
| for indices in val | ||
| ] | ||
| elif key in [ | ||
| "forces", | ||
| "mean_forces", | ||
| "velocities", | ||
| "mean_velocities", | ||
| "mean_unwrapped_positions", | ||
| ]: | ||
| dump_dict[key] = [np.matmul(v, rotation_lammps2orig) for v in val] | ||
| elif key in ["positions", "unwrapped_positions"]: | ||
| dump_dict[key] = [ | ||
| np.matmul(np.matmul(v, lammps_cell), rotation_lammps2orig) | ||
| for v, lammps_cell in zip(val, dump_lammps_dict["cells"]) | ||
| ] | ||
| else: | ||
| dump_dict[key] = val | ||
| return dump_dict | ||
|
|
||
|
|
||
| def _parse_log( | ||
|
|
@@ -405,44 +231,18 @@ def _collect_output_log( | |
| """ | ||
| general purpose routine to extract static from a lammps log file | ||
| """ | ||
| with open(file_name, "r") as f: | ||
| dfs = [] | ||
| read_thermo = False | ||
| for l in f: | ||
| l = l.lstrip() | ||
|
|
||
| if l.startswith("Step"): | ||
| thermo_lines = "" | ||
| read_thermo = True | ||
|
|
||
| if read_thermo: | ||
| if l.startswith("Loop") or l.startswith("ERROR"): | ||
| read_thermo = False | ||
| dfs.append( | ||
| pd.read_csv(StringIO(thermo_lines), sep="\\s+", engine="c") | ||
| ) | ||
|
|
||
| elif l.startswith("WARNING:"): | ||
| warnings.warn(f"A warning was found in the log:\n{l}") | ||
|
|
||
| else: | ||
| thermo_lines += l | ||
| df = parse_raw_lammps_log(file_name=file_name) | ||
|
|
||
| h5_dict = { | ||
| "Step": "steps", | ||
| "Temp": "temperature", | ||
| "PotEng": "energy_pot", | ||
| "TotEng": "energy_tot", | ||
| "Volume": "volume", | ||
| "LogStep": "LogStep", | ||
| } | ||
| if len(dfs) == 1: | ||
| df = dfs[0] | ||
| else: | ||
| h5_dict["LogStep"] = "LogStep" | ||
| for i in range(len(dfs)): | ||
| df = dfs[i] | ||
| df["LogStep"] = np.ones(len(df)) * i | ||
| df = pd.concat(dfs, ignore_index=True) | ||
| if "LogStep" not in df.columns: | ||
| del h5_dict["LogStep"] | ||
|
|
||
| for key in df.columns[df.columns.str.startswith("f_mean")]: | ||
| h5_dict[key] = key.replace("f_", "") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.