lammpskit.ecellmodel.read_displacement_data

lammpskit.ecellmodel.read_displacement_data(filepath, loop_start, loop_end, repeat_count=0)[source]

Read spatially-binned displacement data from LAMMPS thermodynamic output files.

Parses binwise averaged displacement and mobility analysis data generated by LAMMPS simulations, extracting loop-specific datasets for temporal analysis of ion migration, atomic redistribution, and electrochemical switching dynamics in HfTaO memory devices. Handles multi-loop data structures with automatic chunk detection and validation.

Parameters:
  • filepath (str) – Path to LAMMPS thermodynamic output file containing binwise averaged data. Expected format: Header lines (3) + Nchunks line + loop data blocks. Common files: “Hf_mobility.dat”, “O_mobility.dat”, “temperature.dat”

  • loop_start (int) – Starting loop index (inclusive) for data extraction. Corresponds to simulation timestep ranges or voltage cycle iterations. Minimum value: 0.

  • loop_end (int) – Ending loop index (inclusive) for data extraction. Must be ≥ loop_start. Determines the temporal range of analysis.

  • repeat_count (int, optional) – Number of times the first timestep is repeated in the data file structure. Used for correcting file parsing when initial conditions are duplicated. Default: 0 (no repetition correction applied).

Returns:

thermo – List of displacement data arrays, one per requested loop. Each array has shape (Nchunks, N_columns) where:

  • Nchunks: Number of spatial bins along analysis direction (typically z-axis)

  • N_columns: Data columns per bin (typically 6-8 columns)

Standard Column Structure: - Column 0: Chunk/bin ID number - Column 1: Spatial position (Angstroms) - Column 2: Atom count per bin - Column 3: Total displacement magnitude (Angstroms) - Column 4: Z-direction displacement (Angstroms) - Column 5: Lateral displacement (Angstroms) - Column 6: Outward displacement vector (Angstroms) - Column 7: Temperature or density (context-dependent)

Return type:

list of np.ndarray

Raises:
  • FileNotFoundError – If the specified filepath does not exist or is not accessible.

  • ValueError – If loop_start > loop_end or if file contains invalid data structure.

  • EOFError – If expected loop data is missing, truncated, or has insufficient rows.

  • TypeError – If Nchunks header line cannot be parsed as integer or is malformed.

Notes

File Format Requirements: - Header Structure: 3 comment lines (starting with #) followed by Nchunks line - Nchunks Line: Format “# <unused> <Nchunks>” where Nchunks = spatial bins - Loop Blocks: Each loop contains Nchunks data rows + 4 separator lines - Data Validation: Automatic verification of chunk count consistency

Performance Characteristics: - Memory Usage: O(N_loops × Nchunks × N_columns) for output storage - I/O Efficiency: Streaming read with selective row extraction - Error Resilience: Comprehensive validation with descriptive error messages - Typical Speed: ~1-10 MB/s depending on file size and chunk count

Electrochemical Analysis Context: Essential for processing mobility analysis outputs where spatial discretization enables tracking of: - Ion Migration: Species-specific displacement patterns along electric field - Thermal Effects: Temperature-dependent mobility and diffusion coefficients - Interface Dynamics: Electrode-oxide boundary phenomena and charge injection - Temporal Evolution: Loop-by-loop analysis of switching cycle progression

Integration with LAMMPSKit Workflow: - Input Generation: LAMMPS compute ave/chunk commands generate compatible files - Species Processing: Combine with extract_element_label_from_filename() for automation - Visualization: Output arrays integrate with plot_displacement_timeseries() - Analysis Pipelines: Essential component of plot_displacement_comparison() workflow

Examples

Basic displacement data loading:

>>> from lammpskit.ecellmodel.filament_layer_analysis import read_displacement_data
>>> # Load mobility data for 100 simulation loops
>>> displacement_data = read_displacement_data("Hf_mobility.dat",
...                                           loop_start=0, loop_end=99)
>>> print(f"Loaded {len(displacement_data)} loops")
>>> print(f"Each loop contains {displacement_data[0].shape[0]} spatial bins")
>>> print(f"Data columns per bin: {displacement_data[0].shape[1]}")

Temporal analysis workflow:

>>> # Analyze displacement evolution across switching cycles
>>> early_loops = read_displacement_data("O_mobility.dat", 0, 49)      # First 50 loops
>>> late_loops = read_displacement_data("O_mobility.dat", 950, 999)    # Last 50 loops
>>>
>>> # Compare initial vs final displacement profiles
>>> early_avg = np.mean([loop[:, 4] for loop in early_loops], axis=0)  # Z-displacement
>>> late_avg = np.mean([loop[:, 4] for loop in late_loops], axis=0)
>>> displacement_change = late_avg - early_avg
>>> print(f"Max displacement change: {displacement_change.max():.3f} Å")

Error handling and validation:

>>> # Robust file processing with error handling
>>> try:
...     data = read_displacement_data("temperature.dat", 10, 15)
...     print(f"Successfully loaded temperature data: {len(data)} loops")
... except FileNotFoundError:
...     print("Temperature file not found - skipping thermal analysis")
... except EOFError as e:
...     print(f"Incomplete data file: {e}")
... except TypeError as e:
...     print(f"File format error: {e}")

Batch processing integration:

>>> # Process multiple species files in automated workflow
>>> mobility_files = ["Hf_mobility.dat", "Ta_mobility.dat", "O_mobility.dat"]
>>> species_labels = ["Hf", "Ta", "O"]
>>> loop_range = (0, 100)
>>>
>>> all_displacement_data = {}
>>> for filename, species in zip(mobility_files, species_labels):
...     try:
...         data = read_displacement_data(filename, *loop_range)
...         all_displacement_data[species] = data
...         print(f"{species}: {len(data)} loops, {data[0].shape[0]} bins")
...     except Exception as e:
...         print(f"Failed to process {species}: {e}")

Data structure analysis:

>>> # Examine file structure and spatial binning
>>> data = read_displacement_data("Hf_mobility.dat", 0, 0)  # Single loop
>>> loop_data = data[0]
>>>
>>> spatial_positions = loop_data[:, 1]  # Bin center positions
>>> bin_spacing = spatial_positions[1] - spatial_positions[0]
>>> analysis_range = spatial_positions[-1] - spatial_positions[0]
>>>
>>> print(f"Spatial resolution: {bin_spacing:.2f} Å per bin")
>>> print(f"Analysis range: {analysis_range:.1f} Å")
>>> print(f"Electrode separation: ~{analysis_range:.0f} Å")

Integration with time series plotting:

>>> # Prepare data for displacement time series visualization
>>> loop_data = read_displacement_data("O_mobility.dat", 0, 50)
>>> z_displacements = np.array([loop[:, 4] for loop in loop_data])  # Shape: (51, Nbins)
>>>
>>> # Extract time evolution for specific spatial bin (e.g., center of device)
>>> center_bin = z_displacements.shape[1] // 2
>>> center_evolution = z_displacements[:, center_bin]
>>> print(f"Center bin displacement range: {center_evolution.min():.3f} to {center_evolution.max():.3f} Å")