Accessing python LAMMPS instance from Ovito

Dear OVITO developers,

Suppose I have a python script in which an MPI LAMMPS instance is running. Now suppose this simulation contains loops, during which I write files and analyze them with OVITO at each steps, that is the simulation pauses, calls an OVITO python scripts and resumes after it finishes.

Is there a way to pass the LAMMPS current configuration directly to OVITO and initialize a pipeline in a function? My understanding is that I should do a custom PythonSource That gathers the data in a DataCollection and initiate the pipeline that way.

I thought about something looking like:

from ovito.pipeline import Pipeline, PythonSource
from ovito.data import DataCollection
[...]

def create_model(lmp, frame: int, data: DataCollection):
    natoms = lmp.get_natoms()
    box = lmp.extract_box()
    matrix = make_matrix(box) # Some matrix written from the box
    pbc = get_pbc(box) # Getting pbc
    x = lmp.gather_atoms('x',1,3)
    particles = data.create_particles(count=natoms)
    coordinates = particles.create_property('Position')
    coordinates[:,:] = x
    cell = data.create_cell(matrix, pbc)

pipeline = Pipeline(source = PythonSource(function = create_model))

Is there no easier way to do so and insure all the information is passed to OVITO?

Yes, this is exactly what the function in the ovito.io.lammps module is for:

https://docs.ovito.org/python/modules/ovito_io_lammps.html

1 Like

While building a pipeline using a StaticSource object would be technically correct, it typically is not needed in this situation. You can apply modifiers to your model in-place using the DataCollection.apply method as shown in the code example for the ovito.io.lammps.lammps_to_ovito function.

1 Like

Ah thanks! That’s exactly what I was looking for and overlooked. I tried to look into the archives from the forum and did not see any related topics, so at least I hope this will help other people!

Unfortunately this does not work in my case. Importing the ovito Python lib provokes a bug in the LAMMPS instance by passing a 1.0 value to the lattice command and terminates the program.

Here are some minimal step to reproduce:


from mpi4py import MPI
from lammps import lammps
import ovito

lmp = lammps()

This results in the following when called using mpirun -n 1 python test.py:

LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-137-g78fc90f4df)
OMP_NUM_THREADS environment is not set. Defaulting to 1 thread. (src/comm.cpp:99)
  using 1 OpenMP thread(s) per MPI task
ERROR: Floating point number 1.0 in input script or data file is invalid (src/lattice.cpp:58)
LAMMPS Exception: ERROR: Floating point number 1.0 in input script or data file is invalid (src/lattice.cpp:58)
Traceback (most recent call last):
  File "/home/germain/Documents/Codes/Unicaen/Mead_lammps/test.py", line 12, in <module>
    lmp = lammps()
  File "/home/germain/.local/lib/python3.10/site-packages/lammps/core.py", line 531, in __init__
    raise(RuntimeError("Failed to initialize LAMMPS object"))
RuntimeError: Failed to initialize LAMMPS object
--------------------------------------------------------------------------
Primary job  terminated normally, but 1 process returned
a non-zero exit code. Per user-direction, the job has been aborted.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
mpirun detected that one or more processes exited with non-zero status, thus causing
the job to be terminated. The first process to do so was:

  Process name: [[16440,1],0]
  Exit code:    1
--------------------------------------------------------------------------

Commenting out the ovito import makes lammps terminate normally.

Ok, that is unexpected. Could you please provide some details about your environment? The following would be useful:

  1. How did you install LAMMPS and the lammps python module?
  2. How the ovito module (pip install or conda install)?
  3. Is this on the Linux or macOS platform?
  4. And are you running a LAMMPS simulation which calls a Python function, or are you running a Python program that invokes LAMMPS?
  1. LAMMPS was compiled and installed from source. The version used is the correct system version. The LAMMPS python module is the one from source.
  2. The ovito python module was installed through pip. The version from list is ovito 3.10.6.post2.
  3. This is an Ubuntu LTS 22.04.5 machine.
  4. This is a python program that instantiate a LAMMPS simulation. The idea is to keep the simulation running and pass data to OVITO from within the script in a loop. The result should then be used in the running simulation at each loop iteration.

Apparently the solution from this problem also solves this issue.

Is seems that loading the ovito Python library changes the locale settings compared to LAMMPS which in turns make it unable to parse floating point values with some of them (french, in my case).

Yes, I also suspected an interaction with the process-wide locale setting. OVITO (and its Python module), still contains a call to the function setlocale(LC_ALL, "C") during startup, which is necessary so that simulation data files can be parsed correctly, which generally use the “C” formatting of floating-point numbers, i.e. a dot as decimal separator. We probably should get rid of this somehow to avoid such unexpected interferences within the same process.

However, my expectation was that LAMMPS too would always use (and require) the “C” locale. Why is that not the case for you? Do you explicitly activate the French locale?

This would also be my expectation as well. However, I didn’t configure the machine I am using myself. This was done by my institution. This is also a daily routine computer so it is possible that at some point the locale were changed to ‘fr_fr’ or simply initially installed that way. It didn’t bother me when using both software individually, however, it seems to be important when calling OVITO Python lib and LAMMPS. Which is weird.

LAMMPS does not set any locale, which keeps in the “C” locale like any console application that does not explicitly set the locale.

I found that to be not sufficient for all use cases. In LAMMPS-GUI, I have put a call to

    qputenv("LC_ALL", "C.UTF-8");

before creating the QApplication class as the second call in the source of the main() function. This has suppressed all NLS related problems in LAMMPS-GUI thus far. LAMMPS-GUI uses the C-library interface for its LAMMPS instances (and runs them in a separate thread so they can be easily deleted and recreated in case of errors or configuration changes).

1 Like

Thanks, Axel, for the suggestion. Overriding the LC_ALL env variable in OVITO should be a more robust solution, yes - at least unless some other party or Python module calls setlocale(LC_ALL, "") first before we get the chance to set the env var. We’ll have to test whether this approach really solves all conflicts, including the one @Germain is facing.

One more thing I noticed is that macOS doesn’t have support for the C.UTF-8 locale, only Linux distributions do. Qt, however, really wants a UTF-8 locale - otherwise QCoreApplication will print a warning to the terminal. The only solution I’ve found so far is to fall back to the en_US.UTF-8 locale:

#ifndef Q_OS_MACOS
    qputenv("LC_ALL", "C.UTF-8");
#else
    qputenv("LC_ALL", "en_US.UTF-8");
#endif

Let me know if you have any other solution.

By the way: Modern versions of the OVITO Python module, if used in a non-GUI Python script, initialize a Qt application object only on demand - when they really need to, for example when rendering offscreen text (QFont) or when saving images (QImage::save).

A simple import ovito statement should not trigger the creation of a Qt application object (which would then make a call to setlocale(LC_ALL, "") in the constructor and thus activate the French locale). So I am still a bit surprised by the observation Germain made.

1 Like

No. My opportunities for testing on macOS are very limited.
That said, I have already plenty of workarounds for macOS in my GUI source tree, adding one more is not going to be a big deal.

This is part of the reason I first looked on the LAMMPS side. I was also puzzled because at some point, one LAMMPS MPI thread could go through the file while another could not (and hanged) which still make no sense to me… I am catching up on MPI at the moment but still have low experience on “locale” settings and shenanigans in Linux systems so I think there is something more to this but can’t figure out what. I guess this has to do with my system’s configuration so I’ll try to report to the referent colleague from the lab.

For what it’s worth, importing Ovito or not does not seems to affect LAMMPS of Python detection of locale, but it is still making the code crash when reading the file when set on “fr_FR.UTF-8”.