Skip to content

Commit 67c24ff

Browse files
committed
Less stringy more efficient algoirthm. Use a local class to key of the
map rather than creating a string 'key'.
1 parent 5f2ddf1 commit 67c24ff

File tree

1 file changed

+67
-50
lines changed
  • descriptor/qsarmolecular/src/main/java/org/openscience/cdk/geometry/surface

1 file changed

+67
-50
lines changed

descriptor/qsarmolecular/src/main/java/org/openscience/cdk/geometry/surface/NeighborList.java

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.ArrayList;
2626
import java.util.HashMap;
2727
import java.util.List;
28+
import java.util.Map;
29+
import java.util.Objects;
2830

2931
/**
3032
* Creates a list of atoms neighboring each atom in the molecule.
@@ -41,85 +43,100 @@
4143
*/
4244
public class NeighborList {
4345

44-
HashMap<String, List<Integer>> boxes;
45-
double boxSize;
46-
IAtom[] atoms;
46+
Map<Key, List<Integer>> boxes;
47+
double boxSize;
48+
IAtom[] atoms;
49+
50+
/**
51+
* Custom key class for looking up items in the map.
52+
*/
53+
private final class Key {
54+
private final int x, y, z;
55+
56+
public Key(IAtom atom) {
57+
double x = atom.getPoint3d().x;
58+
double y = atom.getPoint3d().y;
59+
double z = atom.getPoint3d().z;
60+
this.x = (int) (Math.floor(x / boxSize));
61+
this.y = (int) (Math.floor(y / boxSize));
62+
this.z = (int) (Math.floor(z / boxSize));
63+
}
64+
65+
public Key(int x, int y, int z) {
66+
this.x = x;
67+
this.y = y;
68+
this.z = z;
69+
}
70+
71+
@Override
72+
public boolean equals(Object o) {
73+
if (this == o) return true;
74+
if (o == null || getClass() != o.getClass()) return false;
75+
Key key = (Key) o;
76+
return x == key.x &&
77+
y == key.y &&
78+
z == key.z;
79+
}
80+
81+
@Override
82+
public int hashCode() {
83+
return Objects.hash(x, y, z);
84+
}
85+
}
4786

4887
public NeighborList(IAtom[] atoms, double radius) {
4988
this.atoms = atoms;
5089
this.boxes = new HashMap<>();
5190
this.boxSize = 2 * radius;
5291
for (int i = 0; i < atoms.length; i++) {
53-
String key = getKeyString(atoms[i]);
92+
Key key = new Key(atoms[i]);
5493
List<Integer> arl = this.boxes.get(key);
5594
if (arl == null)
5695
this.boxes.put(key, arl = new ArrayList<>());
5796
arl.add(i);
5897
}
5998
}
6099

61-
private String getKeyString(IAtom atom) {
62-
double x = atom.getPoint3d().x;
63-
double y = atom.getPoint3d().y;
64-
double z = atom.getPoint3d().z;
65-
66-
int k1, k2, k3;
67-
k1 = (int) (Math.floor(x / boxSize));
68-
k2 = (int) (Math.floor(y / boxSize));
69-
k3 = (int) (Math.floor(z / boxSize));
70-
71-
return (k1 + " " + k2 + " " + k3 + " ");
72-
}
73-
74-
private int[] getKeyArray(IAtom atom) {
75-
double x = atom.getPoint3d().x;
76-
double y = atom.getPoint3d().y;
77-
double z = atom.getPoint3d().z;
78-
79-
int k1, k2, k3;
80-
k1 = (int) (Math.floor(x / boxSize));
81-
k2 = (int) (Math.floor(y / boxSize));
82-
k3 = (int) (Math.floor(z / boxSize));
83-
84-
return (new int[]{k1, k2, k3});
85-
}
86-
87100
public int getNumberOfNeighbors(int i) {
88101
return getNeighbors(i).length;
89102
}
90103

91-
public int[] getNeighbors(int ii) {
92-
double maxDist2 = this.boxSize * this.boxSize;
93-
94-
IAtom ai = this.atoms[ii];
95-
int[] key = getKeyArray(ai);
96-
List<Integer> nlist = new ArrayList<>();
97-
98-
int[] bval = {-1, 0, 1};
104+
/**
105+
* Get the neighbors that are with the given radius of atom i.
106+
* @param i atom index
107+
* @return atom indexs within that radius
108+
*/
109+
public int[] getNeighbors(int i) {
110+
List<Integer> result = new ArrayList<>();
111+
double maxDist2 = this.boxSize * this.boxSize;
112+
IAtom atom = this.atoms[i];
113+
Key key = new Key(atom);
114+
int[] bval = {-1, 0, 1};
99115
for (int x : bval) {
100116
for (int y : bval) {
101117
for (int z : bval) {
102-
String keyj = (key[0] + x) + " " + (key[1] + y) + " " + (key[2] + z) + " ";
103-
if (boxes.containsKey(keyj)) {
104-
List<Integer> nbrs = boxes.get(keyj);
118+
Key probe = new Key(key.x+x, key.y+y, key.z+z);
119+
List<Integer> nbrs = boxes.get(probe);
120+
if (nbrs != null) {
105121
for (Integer nbr : nbrs) {
106-
if (nbr != ii) {
122+
if (nbr != i) {
107123
IAtom aj = atoms[nbr];
108-
double x12 = aj.getPoint3d().x - ai.getPoint3d().x;
109-
double y12 = aj.getPoint3d().y - ai.getPoint3d().y;
110-
double z12 = aj.getPoint3d().z - ai.getPoint3d().z;
124+
double x12 = aj.getPoint3d().x - atom.getPoint3d().x;
125+
double y12 = aj.getPoint3d().y - atom.getPoint3d().y;
126+
double z12 = aj.getPoint3d().z - atom.getPoint3d().z;
111127
double d2 = x12 * x12 + y12 * y12 + z12 * z12;
112-
if (d2 < maxDist2) nlist.add(nbr);
128+
if (d2 < maxDist2) result.add(nbr);
113129
}
114130
}
115131
}
116132
}
117133
}
118134
}
119-
Object[] tmp = nlist.toArray();
120-
int[] ret = new int[tmp.length];
121-
for (int j = 0; j < tmp.length; j++)
122-
ret[j] = (Integer) tmp[j];
135+
136+
// convert to primitive array
137+
int[] ret = new int[result.size()];
138+
for (int j = 0; j < ret.length; j++)
139+
ret[j] = result.get(j);
123140
return (ret);
124141
}
125142
}

0 commit comments

Comments
 (0)