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} Å")