Can `fix python/move` operate on a certain group instead of `all`?

Dear LAMMPS developers and users,

In my simulation, the wall movement is specified by the spatiotemporal data written in a file (either ASCII or binary). I’ve known that there are mainly four ways in LAMMPS to specify the displacement/velocity. displace_atoms and velocity are not applicable because they are executed only once rather than at every time step. Since the velocity of wall movement can change with time, only fix move and fix python/move are applicable. However, fix move cannot read data from a file (one way is to use variable atomfile and variable delete at every timestep but this is too awkward and I need to prepare many data files).

Another way is to use fix python/move, where I can read data use Python’s reader. The only challenge is that fix python/move can only operate on all the atoms but I’m not sure. Examples in example/python/py_nve.py have assert(self.group_name == "all"). But in my simulation, I only want to specify the wall movement but not the fluid therein. The fluid movement is integrated by fix rheo. The cpp source checks whether an atom belongs to a group by mask[i] & groupbit, but how can this be done in Python lammps module? If it is not feasible, is there any other convenient way to implement this idea?

Thanks in advance!

==========================================

Whoops, I just forgot that one can specify the group in the Python function lmp.extract_variable. Maybe I can use this:

    def __init__(self, ptr, group_name="all"):
        super(NVE, self).__init__(ptr)

    def initial_integrate(self, vflag):
        x = self.lmp.numpy.extract_atom("x", group=self.group_name)
        v = self.lmp.numpy.extract_atom("v", group=self.group_name)
        for i in range(x.shape[0]):
            ...

Now here is another question: how can I debug this python code?

You cannot just make up stuff. The functions and arguments are all documented.

Create the same input without python (e.g. just using fix nve with a group != “all”) and compare the energies, forces, velocities.

Here is an example for how to apply fix nve to a group from Python. This is the input:

# 3d Lennard-Jones melt

units           lj
atom_style      atomic

lattice         fcc 0.8442
region          box block 0 10 0 10 0 10
create_box      1 box
create_atoms    1 box
mass            * 1.0

velocity        all create 3.0 87287 loop geom

pair_style      lj/cut 2.5
pair_coeff      1 1 1.0 1.0 2.5

neighbor        0.3 bin
neigh_modify    every 20 delay 0 check no

region          half block 0 5 0 10 0 10
group           half region half

fix             1 all python/move py_nve.NVE_Group

thermo          50
run             250

and here is the class that needs to be added to py_nve.py:

class NVE_Group(LAMMPSFixMove):
    """ Python implementation of fix/nve with group"""
    def __init__(self, ptr, group_name="half"):
        super(NVE_Group, self).__init__(ptr, group_name)
        assert(self.group_name == "half")

    def init(self):
        dt = self.lmp.extract_global("dt")
        ftm2v = self.lmp.extract_global("ftm2v")
        self.ntypes = self.lmp.extract_global("ntypes")
        self.dtv = dt
        self.dtf = 0.5 * dt * ftm2v
        group_index = self.lmp.available_ids("group").index(self.group_name)
        self.group_mask = 1 << group_index

    def initial_integrate(self, vflag):
        mass = self.lmp.numpy.extract_atom("mass")
        atype = self.lmp.numpy.extract_atom("type")
        mask = self.lmp.numpy.extract_atom("mask")
        x = self.lmp.numpy.extract_atom("x")
        v = self.lmp.numpy.extract_atom("v")
        f = self.lmp.numpy.extract_atom("f")
        nlocal = self.lmp.extract_setting("nlocal")

        for i in range(nlocal):
            if mask[i] & self.group_mask:
                dtfm = self.dtf / mass[int(atype[i])]
                v[i,:]+= dtfm * f[i,:]
                x[i,:] += self.dtv * v[i,:]

    def final_integrate(self):
        mass = self.lmp.numpy.extract_atom("mass")
        mask = self.lmp.numpy.extract_atom("mask")
        atype = self.lmp.numpy.extract_atom("type")
        v = self.lmp.numpy.extract_atom("v")
        f = self.lmp.numpy.extract_atom("f")
        nlocal = self.lmp.extract_setting("nlocal")

        for i in range(nlocal):
            if mask[i] & self.group_mask:
                dtfm = self.dtf / mass[int(atype[i])]
                v[i,:] += dtfm * f[i,:]

Thanks @akohlmey .

Sorry, I confused extract_atoms with extract_variables. extract_atoms does not receive the group argument. I just test the method you provided in the example script, it works.

Another question is how to obtain the atom tags. I’m going to use this command in the parallel mode. So I need to map the wall movement which is stored by global atom-IDs to atoms of each processor with local atom-IDs. In the callback function of fix external, tags could be easily obtained. But tags is not an argument here. I try to use

tag = lmp.numpy.extract_atoms('tag')

But I got None. Now that I can get mask, x, f, etc., by extract_atom, why can’t I get tag by the same method?

=====================
image
After checking the source code, I got the answer: I should use 'id' rather than tag to for atom tags extraction, which lets me think of what we specify in the dump command is id instead of tag. But I suggest this should be mentioned as a special case in the documentation of extract_atoms.

@jasmine969 Please note that my example only works when you do not delete groups. The list of groups is special, since it can have “holes” in them (unlike the list of variables, or computes, or fixes or dumps etc.). Thus the code in the LAMMPS library interface and particularly the LAMMPS python module needs to create a special case when querying groups so that it always returns a list of all 32 possible groups and then the unused groups have the value “None” in that list. Without these changes, LAMMPS will either crash with a segfault or produce incorrect group bitflags.

Corresponding changes are in a pending pull requests and have also been backported to the stable version.

1 Like