I am trying to develop a Python workflow that can perform multiple-walker simulations to optimize a set of parameters. I am using LAMMPS to perform my MD simulations, and I use the commands provided here to do that. However, the program fails to run with the following error message:
ERROR: Units command after simulation box is defined (src/input.cpp:2003)
ERROR on proc 0: Too many nested levels of input scripts (src/input.cpp:342)
This is the section where the code fails
def compute(self, index: int):
"""
Searches for LAMMPS input files matching a specific index pattern
and prints the list of matched filenames.
Args:
index (int): The numerical identifier used to filter input files.
Typically corresponds to a walker or simulation ID.
"""
# Collect all LAMMPS input files matching the pattern "*_{index}.inp"
# This allows for batch execution of multiple simulation setups indexed by a shared identifier.
_input_files = glob.glob(f"*_{index}.inp")
# Initialize a LAMMPS handler instance.
# This object interfaces with the LAMMPS simulation engine and allows execution of input scripts.
_lammps_handler = lammps.lammps()
# Loop over each matched input file and attempt to run it through the LAMMPS engine.
for _file in _input_files:
try:
# Execute the LAMMPS input script.
# This will parse and run the simulation defined in the .inp file.
_lammps_handler.file(_file)
except lammps.MPIAbortException:
# Catch and silently ignore MPIAbortException.
# This exception typically indicates a controlled termination from within LAMMPS,
# such as due to a simulation error or convergence failure.
# Suppressing it allows the loop to continue with remaining input files.
pass
except Exception as _exception:
# Catch any other unexpected exceptions and print the error message.
# This helps with debugging malformed input files or runtime issues
# without halting the entire batch execution.
print(_exception)
_lammps_handler.close()
I can run the input file separately and I have verified that the file is a valid input file. Any guidance on why is this happening would be much appreciated.
You cannot run multiple input files in the same LAMMPS instance after each other.
You either need to close the LAMMPS instance and create a new one for each input, or you need to use the “clear” command to reset the state of the LAMMPS instance.
BTW: this kind of processing can also be done with LAMMPS directly without the python interface by using a loop over a file style variable (and issuing “clear” in between).
1 Like
Thank you Prof. Kohlmeyer. I need to use Python because I need to also use a custom minimizer to minimize an error parameter, and we already had the framework ready in python. As a follow up question, can we capture the output of the files into individual log files?
Hi @HemanthHaridas,
This is what the log command is for.
This forces you to use Python for the minimization but it might be easier to call Python from LAMMPS and set up the wortlkflow in the later. Have you looked at the python command? This might avoid you some overengineering.
1 Like
Thank you! I will look into calling python from LAMMPS.
As a follow up question to the above topic: My code works perfectly fine when I run the code in serial mode. However, I would like the code to be parallelized over the number of walkers, for efficiency reasons. Copied below is the logic that I have written currently:
# MPI init section
_comm = MPI.COMM_WORLD
_size = _comm.Get_size()
_rank = _comm.Get_rank()
_root = (_rank == 0)
# gather list of walkers generated on root
if _root:
walkers = create_walkers(values=numpy.array(_values), margin=_margin, num_walkers=_num_walkers)
else:
walkers = None
# Scatter walkers to all ranks
_this_ranks_walker = _comm.scatter(walkers, root=0)
# evaluate walkers in parallel
_this_ranks_walker.create_lammps_param_set(constraints=_constraints, counters=_counters, index=_rank)
_this_ranks_walker.compute(index=_rank)
_this_ranks_walker.evaluate(index=_rank)
Copied below is the compute function from the module
def compute(self, index: int):
"""
Searches for LAMMPS input files matching a specific index pattern
and prints the list of matched filenames.
Args:
index (int): The numerical identifier used to filter input files.
Typically corresponds to a walker or simulation ID.
"""
# Collect all LAMMPS input files matching the pattern "*_{index}.inp"
# This allows for batch execution of multiple simulation setups indexed by a shared identifier.
_input_files = glob.glob(f"*_{index}.inp")
# Loop over each matched input file and attempt to run it through the LAMMPS engine.
for _file in _input_files:
try:
# Execute the LAMMPS input script.
# This will parse and run the simulation defined in the .inp file.
# Initialize a LAMMPS handler instance.
# This object interfaces with the LAMMPS simulation engine and allows execution of input scripts.
_lammps_handler = lammps.lammps(
cmdargs=["-log", f"{_file[:-4]}.log"]
)
_lammps_handler.file(_file)
_lammps_handler.close()
except lammps.MPIAbortException:
# Catch and silently ignore MPIAbortException.
# This exception typically indicates a controlled termination from within LAMMPS,
# such as due to a simulation error or convergence failure.
# Suppressing it allows the loop to continue with remaining input files.
pass
except Exception as _exception:
# Catch any other unexpected exceptions and print the error message.
# This helps with debugging malformed input files or runtime issues
# without halting the entire batch execution.
print(_exception)
However, when I execute the code, it only runs the first set of files. My understanding from the documentation is that if I import mpi4py it would run the lammps instance in parallel. Is there a workaround for this issue?
This is a standard MPI programming issue. You have to decide how to partition your world communicator and create individual sub-communicators with comm.Split() and then pass those sub-communicators to LAMMPS. Otherwise all LAMMPS instances will use the world communicator and you have a big mess on your hands as you already noticed.
There is an example in the python/example/split.py file.
1 Like