openmm / openmmexampleplugin

An example of how to write a plugin for OpenMM
30 stars 22 forks source link

Swig wrappers / std:vector #7

Closed jlmaccal closed 8 years ago

jlmaccal commented 10 years ago

I'm having a problem calling any routine that takes a std:vector as input or output. This code used to work fine when my plugin was part of the openmm tree. Now, it fails at runtime with errors like:

    TypeError: in method 'MeldForce_addDistProfileRestraint', argument 7 of type 'std::vector< double,std::allocator< double > >'

In this example, I am trying to pass a numpy array, which used to work fine. I'm sure this has something to do with type maps, but I have no idea where to even start.

peastman commented 10 years ago

Is this different from #6? It sounds like exactly the same problem.

jlmaccal commented 10 years ago

I don't think so. Why would you say they are the same problem?

jlmaccal commented 10 years ago

This is after setting a bunch of environment variables to make sure that everything is compiled with libc++. The link error goes away, but now errors like this pop up every time std::vector is used.

peastman commented 10 years ago

Oh, I see. Is the problem just with numpy arrays? Or does it also fail with regular Python lists?

peastman commented 10 years ago

I think what you need to do is add the following to exampleplugin.i:

namespace std {
  %template(vectord) vector<double>;
};

That will tell it to generate a wrapper type of std::vector. Or something like that! I don't claim to really understand SWIG.

jlmaccal commented 10 years ago

The code works fine with a list, but it doesn't know what to do with a numpy array.

I have that line included. I also include std_vector.i. It doesn't seem to help.

jlmaccal commented 10 years ago

OK,

So I need lines like:

namespace std {
  %template(vectord) vector<double>;
};

Without those, it doesn't work with lists. But, I still don't know how to make it work with arrays.

jlmaccal commented 10 years ago

OK, I think I'm starting to make progress...

In OpenMM, I think all arguments get passed through stripUnits before being passed to the swig wrapper. Among the first lines of that function:

for arg in args:
    if 'numpy' in sys.modules and isinstance(arg, numpy.ndarray):
           arg = arg.tolist()

So, the unit handling code is implicitly converting all ndarray objects into lists as a part of stripping off the units.

peastman commented 10 years ago

I hadn't even realized it did that. stripUnits() is called from pythonprepend_all.i:

%pythonprepend %{
try: args=stripUnits(args)
except UnboundLocalError: pass
%}

Perhaps we just need to include the same in the plugin?

jlmaccal commented 10 years ago

Perhaps we just need to include the same in the plugin?

Yes, I think so. I'm going to look into this.

peastman commented 10 years ago

That would also provide the advantage that you could specify units on all your arguments and they would work automatically. stripUnits() is a public member of the simtk.openmm module, so there's no need to reimplement it.