freud icon indicating copy to clipboard operation
freud copied to clipboard

Weighted local density

Open scmartin opened this issue 4 years ago • 10 comments

I'm interested in using the local density submodule, but we would like to have the option to weight the calculation. I saw that you have a sort of linear weighting after a cutoff, but it would be nice to be able to use a custom weighting function based on the distance, r.

scmartin avatar Jul 31 '20 17:07 scmartin

@scmartin What weighting function do you have in mind? The function is used in the C++ internals, so you'd need a way to express that Python function in C++. If it's just one specific function you're thinking of, perhaps that could be an option to the class constructor, like weighting='linear' or weighting='quadratic'.

Here's the implementation: https://github.com/glotzerlab/freud/blob/2ae4a793b049f9c853c409ecdb55a060238e4467/cpp/density/LocalDensity.cc#L37-L50

bdice avatar Jul 31 '20 17:07 bdice

Another way to implement this would be to use a custom NeighborList object with the weights set to your desired values, and have an option for weighted=True that reads from the NeighborList weights. This would mirror the behavior of Steinhardt's weighted option. This might be cleaner because it would let users pick whatever weights they want. See the Steinhardt docs and this notebook for a code example.

bdice avatar Jul 31 '20 17:07 bdice

@bdice I was considering a gaussian weighting function. It would be nice to have a general weighting function, but I haven't looked at the C++ codebase yet, and haven't considered how to pass a python function to the C++ code.

scmartin avatar Jul 31 '20 17:07 scmartin

@bdice's suggestion to use the NeighborList weights is probably the most straightforward option right now. You can construct the exact set of neighbors that LocalDensity would by using the same query arguments, then assign the weights according to your function (e.g. a Gaussian). That would require a relatively simple change to the LocalDensity class in its current form.

It's certainly possible to enable a Python callback. It's not something we've done anywhere in freud, but Cython does have that functionality. Here's the example from the Cython docs. However, to avoid slowing down the default code path we would have to make sure that a callback to Python is only performed when the user requests it, the default code path should still be a constant. Also, since this would be a more complex solution, I would probably want to make sure that it's not functionality that we could enable using the current (weighted) NeighborList API, or at least that there's a compelling reason to choose the callback approach.

vyasr avatar Jul 31 '20 18:07 vyasr

@vyasr the neighbor list option seems like a reasonable approach that would make assigning the weights in python simple and flexible as a user, and then passing the weights to the local density function similar to the steinhardt ordered parameter.

scmartin avatar Jul 31 '20 18:07 scmartin

@scmartin would you be interested in trying to enable that? It should be pretty straightforward I think. If you look at the code snippet Bradley posted above, you would simply replace adding 1.0 with adding nb.weight (also in the else clause there). Then you would need to modify the APIs to indicate that you are providing a weighted NeighborList.

vyasr avatar Jul 31 '20 18:07 vyasr

I'll give it a shot

scmartin avatar Jul 31 '20 18:07 scmartin

@scmartin have you had any luck with this? Let us know if you need some pointers.

vyasr avatar Aug 30 '20 15:08 vyasr

Sorry, I haven't had a chance to implement it yet. I'm trying a different method for my analysis, so I'm this has taken a backseat while I try this new method.

scmartin avatar Aug 31 '20 01:08 scmartin

No worries, I just wanted to make sure that you weren't stuck spinning your wheels.

vyasr avatar Aug 31 '20 12:08 vyasr