lammpskit.ecellmodel.track_filament_evolution

lammpskit.ecellmodel.track_filament_evolution(file_list, analysis_name, time_step, dump_interval_steps, output_dir=os.getcwd())[source]

Comprehensive temporal tracking of filament formation and evolution dynamics.

Processes time-series trajectory data to analyze and visualize the complete evolution of conductive filament formation, connectivity transitions, and structural characteristics in HfTaO electrochemical memory devices. Provides detailed time-resolved analysis essential for understanding switching mechanisms, device reliability, and optimization of resistive memory operation through systematic cluster analysis and visualization.

Parameters:
  • file_list (list of str) –

    List of file paths to sequential trajectory files representing temporal evolution. Files should be ordered and contain atomic coordinates with species information compatible with OVITO cluster analysis. Examples:

    • Single Trajectory: [“complete_switching_cycle.lammpstrj”]

    • Multi-Frame Sequence: [“frame_0001.lammpstrj”, “frame_0002.lammpstrj”, …]

    • Process Segments: [“formation.lammpstrj”, “retention.lammpstrj”, “dissolution.lammpstrj”]

  • analysis_name (str) – Base identifier for output file naming and analysis organization. Used to generate descriptive filenames for all output plots and data files. Should reflect the temporal analysis context. Examples: “switching_cycle”, “formation_dynamics”, “retention_study”, “dissolution_analysis”

  • time_step (float) – Simulation time step in picoseconds (ps) used for temporal axis conversion. Defines the fundamental temporal resolution of molecular dynamics simulation. Typical values: 0.0001-0.002 ps for atomic-scale MD simulations.

  • dump_interval_steps (int) – Number of simulation steps between consecutive trajectory frame outputs. Used to calculate actual time intervals between analyzed frames. Example: dump_interval_steps=5000 with time_step=0.0002 gives 1 ps between frames.

  • output_dir (str, optional) – Directory path for saving generated time series plots and analysis figures. Default: current working directory. Creates directory structure if non-existent. Recommended: dedicated analysis subdirectory for organized output management.

Returns:

evolution_figures – Comprehensive dictionary of matplotlib Figure objects for temporal analysis:

Connectivity Analysis: - ‘connection’: Binary connectivity state evolution (1=connected, 0=broken) - ‘gap’: Filament gap evolution showing discontinuity magnitude (Å) - ‘separation’: Inter-cluster separation distance when disconnected (Å)

Filament Morphology Evolution: - ‘filament_gap_and_size’: Dual-axis plot of gap vs. atom count - ‘filament_lower_part’: Lower filament height and size evolution - ‘filament_upper_part’: Upper filament depth and size evolution

Detailed Structural Characteristics: - ‘filament_height’: Lower filament penetration depth (scatter plot) - ‘filament_depth’: Upper filament penetration depth (scatter plot) - ‘filament_size_up’: Upper filament atom count evolution - ‘filament_size_down’: Lower filament atom count evolution

All figures include statistical analysis (mean ± std) and frequency analysis with publication-ready formatting for scientific reporting.

Return type:

dict[str, plt.Figure]

Raises:
  • FileNotFoundError – If any trajectory file in file_list does not exist or is inaccessible.

  • ValueError – If OVITO cluster analysis fails for any trajectory frame or if temporal sequence contains inconsistent data structures.

  • RuntimeError – If memory limitations are exceeded during large-scale time series analysis.

Notes

Temporal Analysis Framework:

Time Axis Calculation: ` actual_time = timestep × time_step × dump_interval_steps ` Where timestep is extracted from LAMMPS trajectory headers.

Connectivity State Analysis: - Connected State: Filament spans complete electrode separation (connection = 1) - Broken State: Incomplete filament with measurable gap (connection = 0) - Frequency Analysis: Percentage of time spent in connected state - Switching Events: Transitions between connected/disconnected states

Statistical Characterization: Each temporal series includes comprehensive statistical analysis: - Mean Values: Average behavior over analysis time window - Standard Deviation: Variability and stability assessment - Frequency Metrics: State occupation probabilities - Trend Analysis: Long-term evolution patterns

Performance Characteristics: - Processing Speed: ~1-5 minutes per trajectory file depending on complexity - Memory Usage: O(N_frames × N_atoms) for trajectory sequence processing - Temporal Resolution: Limited by dump_interval_steps and simulation time_step - Statistical Accuracy: Requires sufficient frames for reliable statistics (≥50 frames)

Integration with LAMMPSKit Analysis Pipeline: - Cluster Analysis: Uses analyze_clusters() for frame-by-frame structural analysis - Visualization: Leverages plotting utilities for publication-ready time series - Data Processing: Compatible with displacement analysis and atomic distribution functions - Workflow Integration: Supports batch processing and automated analysis pipelines

Examples

Basic filament evolution tracking:

>>> from lammpskit.ecellmodel.filament_layer_analysis import track_filament_evolution
>>> # Analyze complete switching cycle evolution
>>> trajectory_files = ["switching_cycle.lammpstrj"]
>>>
>>> evolution_figures = track_filament_evolution(trajectory_files,
...                                            analysis_name="switching_dynamics",
...                                            time_step=0.0002,  # 0.2 fs
...                                            dump_interval_steps=5000)  # 1 ps intervals
>>>
>>> print(f"Generated {len(evolution_figures)} temporal analysis plots")
>>>
>>> # Examine connectivity evolution
>>> connection_fig = evolution_figures['connection']
>>> gap_fig = evolution_figures['gap']
>>> print("Basic filament evolution analysis completed")

Multi-phase switching analysis:

>>> # Analyze distinct switching phases with high temporal resolution
>>> phase_files = ["formation.lammpstrj", "retention.lammpstrj", "dissolution.lammpstrj"]
>>> phase_names = ["formation", "retention", "dissolution"]
>>>
>>> all_phase_analyses = {}
>>> for phase_file, phase_name in zip(phase_files, phase_names):
...     try:
...         phase_figures = track_filament_evolution([phase_file],
...                                                analysis_name=f"{phase_name}_analysis",
...                                                time_step=0.0001,  # High resolution
...                                                dump_interval_steps=1000,  # 0.1 ps intervals
...                                                output_dir=f"./analysis_{phase_name}")
...         all_phase_analyses[phase_name] = phase_figures
...         print(f"Completed {phase_name} phase analysis: {len(phase_figures)} plots")
...     except Exception as e:
...         print(f"Error analyzing {phase_name} phase: {e}")
>>>
>>> total_plots = sum(len(figs) for figs in all_phase_analyses.values())
>>> print(f"Multi-phase analysis completed: {total_plots} total plots")

Long-term cycling study:

>>> # Extended cycling analysis for endurance characterization
>>> cycling_files = [f"cycle_{i:03d}.lammpstrj" for i in range(1, 101)]  # 100 cycles
>>>
>>> cycling_evolution = track_filament_evolution(cycling_files,
...                                            analysis_name="endurance_study",
...                                            time_step=0.0005,
...                                            dump_interval_steps=10000,  # 5 ps intervals
...                                            output_dir="./endurance_analysis")
>>>
>>> print(f"Endurance study completed: {len(cycling_evolution)} analysis plots")
>>>
>>> # Focus on key endurance metrics
>>> connection_evolution = cycling_evolution['connection']
>>> gap_evolution = cycling_evolution['gap']
>>> size_evolution = cycling_evolution['filament_gap_and_size']
>>> print("Long-term cycling analysis available for device optimization")

High-resolution formation dynamics:

>>> # Detailed analysis of initial filament formation with fine temporal resolution
>>> formation_files = ["initial_formation.lammpstrj"]
>>>
>>> # Ultra-high temporal resolution for formation kinetics
>>> formation_analysis = track_filament_evolution(formation_files,
...                                             analysis_name="formation_kinetics",
...                                             time_step=0.00005,  # 0.05 fs steps
...                                             dump_interval_steps=500,   # 0.025 ps intervals
...                                             output_dir="./formation_study")
>>>
>>> print("High-resolution formation dynamics analysis:")
>>> print(f"  Total figures: {len(formation_analysis)}")
>>> print("  Available analyses:", list(formation_analysis.keys()))
>>>
>>> # Examine detailed morphology evolution
>>> lower_evolution = formation_analysis['filament_lower_part']
>>> upper_evolution = formation_analysis['filament_upper_part']
>>> height_evolution = formation_analysis['filament_height']
>>> depth_evolution = formation_analysis['filament_depth']

Comparative evolution analysis:

>>> # Compare filament evolution under different conditions
>>> conditions = ["low_voltage", "medium_voltage", "high_voltage"]
>>> evolution_comparison = {}
>>>
>>> for condition in conditions:
...     try:
...         condition_file = f"{condition}_evolution.lammpstrj"
...         condition_analysis = track_filament_evolution([condition_file],
...                                                     analysis_name=f"{condition}_evolution",
...                                                     time_step=0.0002,
...                                                     dump_interval_steps=2500,  # 0.5 ps intervals
...                                                     output_dir=f"./comparison_{condition}")
...         evolution_comparison[condition] = condition_analysis
...         print(f"Completed {condition} evolution analysis")
...     except Exception as e:
...         print(f"Error analyzing {condition}: {e}")
>>>
>>> print(f"Comparative evolution analysis: {len(evolution_comparison)} conditions")
>>> print("Available for voltage-dependent switching optimization")

Advanced statistical analysis integration:

>>> # Detailed analysis with custom statistical processing
>>> trajectory_files = ["device_operation.lammpstrj"]
>>>
>>> evolution_data = track_filament_evolution(trajectory_files,
...                                         analysis_name="statistical_analysis",
...                                         time_step=0.0001,
...                                         dump_interval_steps=5000,
...                                         output_dir="./statistical_study")
>>>
>>> print("Statistical Evolution Analysis Results:")
>>> print(f"  Connection evolution: {evolution_data['connection']}")
>>> print(f"  Gap evolution: {evolution_data['gap']}")
>>> print(f"  Separation evolution: {evolution_data['separation']}")
>>> print(f"  Lower filament evolution: {evolution_data['filament_lower_part']}")
>>> print(f"  Upper filament evolution: {evolution_data['filament_upper_part']}")
>>>
>>> # Note: Statistical summaries are automatically included in plot legends
>>> # as mean ± std and frequency analysis for connectivity states

Error handling and validation:

>>> # Robust evolution tracking with comprehensive error handling
>>> import os
>>> import glob
>>>
>>> # Auto-discover trajectory files
>>> trajectory_pattern = "evolution_*.lammpstrj"
>>> discovered_files = sorted(glob.glob(trajectory_pattern))
>>>
>>> if len(discovered_files) >= 5:  # Require minimum frames for statistics
...     try:
...         evolution_analysis = track_filament_evolution(discovered_files,
...                                                     analysis_name="auto_discovery",
...                                                     time_step=0.0002,
...                                                     dump_interval_steps=5000)
...         print(f"Auto-discovery analysis: {len(evolution_analysis)} plots generated")
...         print(f"Processed {len(discovered_files)} trajectory frames")
...     except FileNotFoundError as e:
...         print(f"File access error: {e}")
...     except ValueError as e:
...         print(f"Cluster analysis error: {e}")
...     except Exception as e:
...         print(f"Unexpected error: {e}")
... else:
...     print(f"Insufficient files found: {len(discovered_files)} (minimum: 5)")

Integration with other LAMMPSKit functions:

>>> # Combine evolution tracking with single-frame analysis
>>> from lammpskit.ecellmodel.filament_layer_analysis import analyze_clusters
>>>
>>> # Time series evolution analysis
>>> time_series_files = ["evolution.lammpstrj"]
>>> evolution_plots = track_filament_evolution(time_series_files, "evolution_study",
...                                          time_step=0.0002, dump_interval_steps=5000)
>>>
>>> # Detailed single-frame analysis for specific timepoints
>>> key_frames = ["initial.lammpstrj", "intermediate.lammpstrj", "final.lammpstrj"]
>>> frame_analyses = {}
>>>
>>> for frame_file in key_frames:
...     try:
...         frame_name = frame_file.replace(".lammpstrj", "")
...         cluster_data = analyze_clusters(frame_file)
...         frame_analyses[frame_name] = {
...             "timestep": cluster_data[0],
...             "connected": cluster_data[1],
...             "total_atoms": cluster_data[2] + cluster_data[5],
...             "gap": cluster_data[9]
...         }
...         print(f"Frame analysis {frame_name}: Connected={cluster_data[1]}")
...     except Exception as e:
...         print(f"Error analyzing {frame_file}: {e}")
>>>
>>> print("Comprehensive Analysis Summary:")
>>> print(f"  Evolution tracking: {len(evolution_plots)} time series plots")
>>> print(f"  Frame-by-frame analysis: {len(frame_analyses)} detailed snapshots")
>>>
>>> # Results provide both temporal trends and detailed structural snapshots
>>> # for complete filament formation and switching characterization

Performance optimization for large datasets:

>>> # Efficient processing of extensive time series data
>>> import numpy as np
>>>
>>> # Process large trajectory sequence with progress monitoring
>>> large_trajectory_files = [f"large_study_{i:04d}.lammpstrj" for i in range(1, 1001)]  # 1000 frames
>>>
>>> # Check file existence before processing
>>> existing_files = [f for f in large_trajectory_files if os.path.exists(f)]
>>>
>>> if len(existing_files) >= 100:  # Proceed if sufficient data
...     try:
...         print(f"Processing {len(existing_files)} trajectory files...")
...         large_evolution = track_filament_evolution(existing_files[:100],  # Limit for demonstration
...                                                  analysis_name="large_scale_study",
...                                                  time_step=0.001,
...                                                  dump_interval_steps=10000,
...                                                  output_dir="./large_scale_analysis")
...         print(f"Large-scale evolution analysis completed: {len(large_evolution)} plots")
...     except MemoryError:
...         print("Memory limitation reached - consider processing in batches")
...     except Exception as e:
...         print(f"Processing error: {e}")
... else:
...     print(f"Insufficient data files: {len(existing_files)} available")