add a complicated force in lammps

I just posted a 12Aug patch that added a callable public
function to fix external, which allows the driver
program to set the energy, in addition to the forces, e.g.
during the callback. This should allow it to be
used for minimization, if (but only if) you set the
forces and energy consistently. See the doc page for details.

Steve

Hi Steve,

I recompiled the lammps library, and add the

fix->set_energy(EP);

in my driver code, after fix->set_callback(…). However, it has linking problems undefined reference to LAMMPS_NS::FixExternal::set_energy(). I could access every other public method of fixexternal, but not this one only. I did add fix_modify in the input script. Wondering why…Thanks,

Xue

Hi Steve,

I found out the bug. We should add virtual void set_energy(double){} to fix.h, or it will cause undefined reference error.

Thanks!

Xue

no - you just need to cast the ptr to the fix in your driver
program to (FixExternal *) and include fix_external.h.
set_energy() is a public method
of FixExternal, not of Fix.

You must have already had to do something like this
for invoking set_callback() since it also is not
defined in fix.h, but only in fix_external.h.

Steve

Hi steve,

I don’t think that will do, since I was doing exactly what you mentioned, and got error. The thing is adding the external energy to minimizatinon needs to invoke fix_modify command. So we need to have virtual void set_energy in the fix class. So when lammps read the input , it understands which fix to modify via fix id and go to the corresponding member function. This way, it does work.

What do you think?

XUE

I think fix external is written correctly, for both the set_callback()
and set_energy() calls. I’m guessing the problem
is with how you are calling it - please post the snippet
of code that does this.

The fix_modify command does need to be invoked, but that
is in the input script that defines fix external. I don’t see
what that has to do with calling functions within the fix
itself.

Steve

Hi Steve,

Here is the input file: I used 3 for the fix ID.

fix 3 all external pf/callback 1 1
fix_modify 3 energy yes
min_style cg
dump 1 allAtoms custom 100 Configuration*.dump x y z

lmp->input->file(lammps_input);

int ifix = lmp->modify->find_fix(“3”);
FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix];
fix->set_callback(optForce_callback,&info);

lmp->input->one(“minimize 0 1.e-16 100000 100000”);

and then in the call back function, I did:

// invoke my force to cal the external force f_ext and energy EP.
Myforce (xcoord,f_ext,natoms, &EP); // where EP is energy (type double)

int ifix = info->lmp->modify->find_fix(“3”);
FixExternal *fix = (FixExternal *) info->lmp->modify->fix[ifix];
fix->set_energy(EP); // want to set fixexternal.user energy to the value of EP.

If I do not add the virtual void set_energy(double) in the fix.h , the linking process would output undefined reference of set_energy(double). Is there anything wrong with my calling of set_energy. Even if I put fix->set_energy in the main driver code, it still does not work. But if I add the line “virtual void set_energy(double) in the fix.h”, it works correctly. Note that I used “minimize” command in the main driver code to find local minimum.

Thanks,

Xue

I’m assuming your callback function and main driver program
both include fix.h and fix_external.h
and are using the LAMMPS namespace.

If so, I don’t see how this can work:
fix->set_callback(optForce_callback,&info);
and this doesn’t:
fix->set_energy(EP);

since both functions are defined in fix_external.h
and neither in fix.h.

You are using the newest fix_external.h that has
both defined?

Maybe Axel has a suggestion.

What is the exact syntax of the link error?

Steve

Hi Steve,

Yes I do include every header files.

The exact error is just undefined reference to LAMMPS_NS::FixExternal::set_energy(double). However, in fix_external we definitely defined. So the only possible reason for not defining it is because fix.h does not define set_energy. Since we use fix_modify in the input script to invoke adding external energy during minimization. I can indeed use every other fix_external member functions, but not set_energy(double). And All all the other member functions in the fix_external are declared as virtual functions in fix.h. I think this is the reason why. Through search in fix.h, the linker found the set_energy(double), and go to the proper fix type to invoke this function.

I compare fix_addforce.h, all its memeber functions are also declared as virtual functions in fix.h. and for No need to declare set_callback, may be because it is a call back function , no need for the help of fix.h. I am not sure how the virtual function works, but here are the thoughts when I compile and link the codes. And things work when add in the virtual function.

Thanks,

Xue

Hi Steve,

Yes I do include every header files.

The exact error is just undefined reference to
LAMMPS_NS::FixExternal::set_energy(double). However, in fix_external we
definitely defined. So the only possible reason for not defining it is
because fix.h does not define set_energy. Since we use fix_modify in the
input script to invoke adding external energy during minimization. I can
indeed use every other fix_external member functions, but not
set_energy(double). And All all the other member functions in the
fix_external are declared as virtual functions in fix.h. I think this is the
reason why. Through search in fix.h, the linker found the
set_energy(double), and go to the proper fix type to invoke this function.

no, this logic does not hold.

there is no need at all to have a virtual Fix::set_energy(double);

set_energy is a member of FixExternal only and that is why you cast
the Fix pointer to a FixExternal pointer.
what you do with fix_modify is irrerelevant, since that uses a
different mechanism to get to the information.

a more likely explanation is that you mask with the modification to
fix.h, that your lammps library is not fully up-to-date and that you
are actually not really adding the energy.

I compare fix_addforce.h, all its memeber functions are also declared as
virtual functions in fix.h. and for No need to declare set_callback, may be
because it is a call back function , no need for the help of fix.h. I am not
sure how the virtual function works, but here are the thoughts when I
compile and link the codes. And things work when add in the virtual
function.

this is irrelevant. you can add functions to derived classes any which
way you like.
i would suggest you first check your lammps library, if it is complete
by doing the equivalent of this command.

nm liblammps_linux.a | c++filt | grep FixExternal

it should look something like this:

0000000000000030 T LAMMPS_NS::FixExternal::post_force(int)
0000000000000160 T LAMMPS_NS::FixExternal::set_energy(double)
00000000000001c0 T LAMMPS_NS::FixExternal::copy_arrays(int, int, int)
0000000000000260 T LAMMPS_NS::FixExternal::grow_arrays(int)
0000000000000180 T LAMMPS_NS::FixExternal::memory_usage()
0000000000000250 T LAMMPS_NS::FixExternal::set_callback(void
(*)(void*, long, int, int*, double**, double**), void*)
00000000000001f0 T LAMMPS_NS::FixExternal::pack_exchange(int, double*)
0000000000000170 T LAMMPS_NS::FixExternal::compute_scalar()
0000000000000150 T LAMMPS_NS::FixExternal::min_post_force(int)
0000000000000220 T LAMMPS_NS::FixExternal::unpack_exchange(int, double*)
0000000000000380 T LAMMPS_NS::FixExternal::init()
0000000000000010 T LAMMPS_NS::FixExternal::setup(int)
0000000000000000 T LAMMPS_NS::FixExternal::setmask()
0000000000000020 T LAMMPS_NS::FixExternal::min_setup(int)
0000000000000440 T
LAMMPS_NS::FixExternal::FixExternal(LAMMPS_NS::LAMMPS*, int, char**)
0000000000000440 T
LAMMPS_NS::FixExternal::FixExternal(LAMMPS_NS::LAMMPS*, int, char**)
0000000000000650 T LAMMPS_NS::FixExternal::~FixExternal()
00000000000003c0 T LAMMPS_NS::FixExternal::~FixExternal()
00000000000003c0 T LAMMPS_NS::FixExternal::~FixExternal()
0000000000000000 V vtable for LAMMPS_NS::FixExternal
                 U
LAMMPS_NS::FixExternal::FixExternal(LAMMPS_NS::LAMMPS*, int, char**)
0000000000000000 W LAMMPS_NS::Fix*
LAMMPS_NS::Modify::fix_creator<LAMMPS_NS::FixExternal>(LAMMPS_NS::LAMMPS*,
int, char**)

axel.

yes, re-build LAMMPS as a library, and I’m guessing
it will work, w/out any changes to fix.h

If you just add the new fix_external,h, you will be
able to compile, but not to link to LAMMPS as a lib,
unless you re-build, e.g.

make makelib
make -f Makefile.lib g++

Steve

Hi guys,

Maybe my logic was wrong, but it indeed adds in the external energy correctly. When I used the 14Aug version, I did delete everything and rebuild the lammps as a library via:

make makeshlib
make -f Makefile.shlib linux

Anyway, So lammps is being updated again? I can delete my current workable version(fix.h being modified) and use the new download one and rebuild?

Thanks,

Xue

Anyway, So lammps is being updated again? I can delete my current workable version(fix.h being modified) and use the new >download one and rebuild?

There was just one update to LAMMPS, to add the set_energy() call.
I believe that if you grab the current version, build it as a lib,
it will work for you with no modification. Let us know if that’s
not the case.

Steve