Open bdice opened 3 years ago
What types of system
are you typically working with when this comes up? Is this in the context of OVITO? If you actually have a Box
and numpy arrays of positions/indices, then (especially with Box.compute_distances
, no need to do that yourself) this is as simple as:
distances = box.compute_distances(points[indices[:, 0]], points[indices[:, 1]])
NeighborList.from_arrays(...)
Admittedly the NeighborList.from_arrays
API is a little bit clunky, and of course the from_system
call becomes necessary if you're working with other inputs.
I'm not opposed to adding this function if it really is the best path forward, but I think the fact that something this straightforward is an annoyance suggests room for improvement in the existing APIs. For one, since as of #738 we're brainstorming API breaks for freud 3.0 we should consider moving num_query_points
and num_points
to the end of the arg list of from_arrays
so that num_points
can default to num_query_points
like everywhere else in freud
. Second, We we should consider extracting the first half of NeighborQuery.from_system
into a separate function that just handles the conversion of various input types into a (box, points)
tuple (with box
always being a Box
object rather than any valid input to Box.from_box
). Then we'd have a simpler way to get this data without building a NeighborQuery
, which is a roundabout way to import data from other sources (assuming that's why you're doing it here).
There are a few motivating cases for this. Sometimes I want to use another package to find neighbors, and I get back arrays of indices. Sometimes polymers/"bonds" in a GSD file also need this (e.g. to find the center of mass or radius of gyration). Being able to quickly combine (box, positions), indices
into a NeighborList is purely a matter of brevity. This is simply a convenience API that would wrap the full from_arrays
and replace the long snippet above with something more concise.
Regarding your idea of splitting the logic in NeighborQuery.from_system
, I think a similar thing is already happening via the _RawPoints
class, which is just a container for a box and points. I don't think we need to improve anything there? https://github.com/glotzerlab/freud/blob/ff9d561c2b8d719eea8e7167f083da3fbcc296a6/freud/locality.pyx#L365-L368
The workflow you're suggesting makes sense, but I think it highlights the fact that there are any number of convenience APIs that we could implement that are fundamentally built around needing to coerce different input types into a (box, points)
tuple. The conversion to a NeighborList
is fine and could be added on top of that, but just the conversion from external objects to (box, points)
would be useful to expose to users, especially if they need to do some more bespoke logic before inputting the data into freud
(either for NeighborList
construction or directly into a compute
after some modification). If we wanted to expose _RawPoints
publicly (probably renamed), then one option would be to implement __iter__
so that it could be transparently coerced via unpacking box, points = RawPoints(...)
.
Is your feature request related to a problem? Please describe. Occasionally I need to construct a NeighborList from bond topology data, which is currently somewhat hard to do. I've written the pattern below at least a dozen times, and it would be much better as a single function.
Describe the solution you'd like A new class method like
NeighborList.from_system(system, indices, weights)
would be helpful.Here's a rough implementation that needs to be improved/tested. Note that this snippet will break with #738 (distances need to be replaced by vectors).