2 This program is free software: you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation, either version 3 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 (C)opyright Gerolf Ziegenhain 2008 <gerolf@ziegenhain.com>
17 Based on the algorithm in S. Stoddard JCP(1978)27:291
29 #include "Numeric/arrayobject.h"
44 #define MAGIC_MIN 1e10
45 #define MAGIC_MAX -1e10
47 #define MAX(a,b) (a>b)?a:b
48 #define MIN(a,b) (a>b)?b:a
53 #define USAGE "-h help\n" \
55 "-n use neighborlist (radius)\n" \
56 "-l use linked lists\n" \
57 "-f infile (name)\n" \
62 #define SQ(a) ((a)*(a))
64 /* --------------------------------------------------------------------------------------------- */
66 typedef struct s_linkedlist
{
67 unsigned int particle
;
68 struct s_linkedlist
*next
;
71 /* --------------------------------------------------------------------------------------------- */
75 unsigned int NCellSide
[3], NCell
;
76 float CellLength
[3], CellLengthI
[3];
77 t_linkedlist
**CellList
;
80 /* --------------------------------------------------------------------------------------------- */
82 double SqDist (double pos1
, double pos2
, int dim
) {
83 if (Periodic
[dim
] == TRUE
)
84 return SQ( fmod(pos1
-pos2
,Length
[dim
]) );
89 /* --------------------------------------------------------------------------------------------- */
91 void DetermineBoxLength (unsigned int n
, float *x
, float *y
, float *z
, float *lx
, float *ly
, float *lz
) {
92 printf ("Determine boxlength\n");
93 min
[X
] = min
[Y
] = min
[Z
] = MAGIC_MIN
;
94 max
[X
] = max
[Y
] = max
[Z
] = MAGIC_MAX
;
96 for (i
= 0; i
< n
; i
++) {
97 min
[X
] = MIN(min
[X
],x
[i
]);
98 min
[Y
] = MIN(min
[Y
],y
[i
]);
99 min
[Z
] = MIN(min
[Z
],z
[i
]);
100 max
[X
] = MAX(max
[X
],x
[i
]);
101 max
[Y
] = MAX(max
[Y
],y
[i
]);
102 max
[Z
] = MAX(max
[Z
],z
[i
]);
109 unsigned int ShiftFlag
= FALSE
;
126 for (i
= 0; i
< n
; i
++) {
132 for (j
= 0; j
< 3; j
++) {
138 *(lx
) = max
[X
] - min
[X
];
139 *(ly
) = max
[Y
] - min
[Y
];
140 *(lz
) = max
[Z
] - min
[Z
];
143 /* --------------------------------------------------------------------------------------------- */
145 void LinkedListInsert (unsigned int particle
, t_linkedlist
**list
) {
146 t_linkedlist
*new = (t_linkedlist
*)calloc (1, sizeof (t_linkedlist
));
150 new->particle
= particle
;
154 /* --------------------------------------------------------------------------------------------- */
156 void LinkedListPrint (t_linkedlist
*list
) {
157 t_linkedlist
*ptr
= list
;
158 while (ptr
!= NULL
) {
163 /* --------------------------------------------------------------------------------------------- */
165 #define CoordinateToCell(x,y,z) (int) ( floor (x*CellLengthI[X]) + floor (y*CellLengthI[Y])*NCellSide[X] + floor (z*CellLengthI[Z])*NCellSide[X]*NCellSide[Y] )
168 int *BuildLinkedList (int n
, float *x
, float *y
, float *z
, float RcNeighbor
) {
169 printf ("Build linked list\n");
172 float CellSize
= RcNeighbor
;
173 NCellSide
[X
] = (unsigned int) ceil (Length
[X
] / CellSize
);
174 NCellSide
[Y
] = (unsigned int) ceil (Length
[Y
] / CellSize
);
175 NCellSide
[Z
] = (unsigned int) ceil (Length
[Z
] / CellSize
);
176 NCell
= NCellSide
[X
] * NCellSide
[Y
] * NCellSide
[Z
];
178 CellLength
[X
] = Length
[X
] / (float)NCellSide
[X
];
179 CellLength
[Y
] = Length
[Y
] / (float)NCellSide
[Y
];
180 CellLength
[Z
] = Length
[Z
] / (float)NCellSide
[Z
];
182 CellLengthI
[X
] = (float)NCellSide
[X
] / Length
[X
];
183 CellLengthI
[Y
] = (float)NCellSide
[Y
] / Length
[Y
];
184 CellLengthI
[Z
] = (float)NCellSide
[Z
] / Length
[Z
];
186 CellList
= (t_linkedlist
**) calloc (NCell
, sizeof (t_linkedlist
));
188 for (i
= 0; i
< n
; i
++)
189 LinkedListInsert (i
, CellList
+ CoordinateToCell (x
[i
], y
[i
], z
[i
]) );
194 /* --------------------------------------------------------------------------------------------- */
196 int *BuildNeighborList (int n
, float *x
, float *y
, float *z
, float RcNeighbor
) {
197 printf ("Build neighbos list\n");
198 return BuildLinkedList (n
, x
, y
, z
, RcNeighbor
);
201 /* --------------------------------------------------------------------------------------------- */
203 void MoleculeListNeighbor (int Atoms
, float *x
, float *y
, float *z
, float RcClusterSq
) {
204 printf ("Clustering: neighbor list\n");
205 double start
= clock();
208 float RcCluster
= sqrt (RcClusterSq
);
209 int i
, j
, k
, Lk
, Size
, *List
,*Spectrum
,s
,n
;
215 List
= (INT
*) malloc (sizeof (INT
) * Atoms
);
216 Spectrum
= (INT
*) malloc (sizeof (INT
) * Atoms
+1);
217 if (!List
|| !Spectrum
)
220 for (i
= 0; i
< Atoms
; i
++)
223 #define NOT_YET_CLUSTERED(i) (i == List[i])
224 for (i
= 0; i
< Atoms
; i
++) {
225 if (NOT_YET_CLUSTERED(i
)) {
229 // sum over all neighbor cells
230 for (m
[X
] = -1; m
[X
] <= 1; m
[X
]++) {
231 xCell
[X
] = x
[j
]+(float)m
[X
]*RcCluster
;
232 if (xCell
[X
] < min
[X
] || xCell
[X
] > max
[X
]) continue;
234 for (m
[Y
] = -1; m
[Y
] <= 1; m
[Y
]++) {
235 xCell
[Y
] = y
[j
]+(float)m
[Y
]*RcCluster
;
236 if (xCell
[Y
] < min
[Y
] || xCell
[Y
] > max
[Y
]) continue;
238 for (m
[Z
] = -1; m
[Z
] <= 1; m
[Z
]++) {
239 xCell
[Z
] = z
[j
]+(float)m
[Z
]*RcCluster
;
240 if (xCell
[Z
] < min
[Z
] || xCell
[Z
] > max
[Z
]) continue;
242 // sum over all particles in cell
243 for (ptr
= *(CellList
+ CoordinateToCell (xCell
[X
], xCell
[Y
], xCell
[Z
])); ptr
!= NULL
; ptr
= ptr
->next
) {
245 //if (k <= i) continue;
246 if (NOT_YET_CLUSTERED(k
)) {
247 #define RSQ(j,k) SqDist(x[j],x[k],X) + SqDist(y[j],y[k],Y) + SqDist(z[j],z[k],Z)
249 if (RSQ(j
,k
) <= RcClusterSq
) { Lk
= List
[k
]; List
[k
] = List
[j
]; List
[j
] = Lk
; }
263 double stop
= clock();
265 for (i
= 0; i
< Atoms
+1; i
++)
267 for (i
= 0; i
< Atoms
; i
++) {
269 Size
= 1; j
= List
[i
]; List
[i
] = -1;
270 while (j
!= i
) { Size
++; k
= List
[j
]; List
[j
] = -1; j
= k
; }
271 //Bestimmung der Groesse des Clusters im Startteilchen i
275 printf("\nCoherent Clusters below %4.4f A\n", RcClusterSq
);
276 printf("Size Times Atoms\n");
277 for (i
= 0; i
< Atoms
+1; i
++) // Atoms + 1 because 0 is also a possible Count
279 if ((s
= Spectrum
[i
]) != 0)
280 printf ("%6d %6d %6d\n", i
, s
, i
*s
);
287 /* --------------------------------------------------------------------------------------------- */
289 void MoleculeList (int Atoms
, float *x
, float *y
, float *z
, float RcClusterSq
) {
290 printf ("Clustering\n");
291 double start
= clock();
293 FLOAT Xj
, Yj
, Zj
, RSq
, z0
=0.0;
295 INT i
, j
, k
, Lk
, Size
, *List
,*Spectrum
,s
,n
;
297 List
= (INT
*) malloc (sizeof (INT
) * Atoms
);
298 Spectrum
= (INT
*) malloc (sizeof (INT
) * Atoms
+1);
299 if (!List
|| !Spectrum
)
302 for (i
= 0; i
< Atoms
; i
++)
305 for (i
= 0; i
< Atoms
-1; i
++) {
307 j
= i
; Xj
= x
[j
]; Yj
= y
[j
]; Zj
= z
[j
];
309 for (k
= i
+1; k
< Atoms
; k
++) {
312 RSq
= SqDist(Xj
,x
[k
],X
) + SqDist(Yj
,y
[k
],Y
) + SqDist(Zj
,z
[k
],Z
);
313 if (RSq
<= RcClusterSq
) { List
[k
] = List
[j
]; List
[j
] = Lk
; }
316 j
= List
[j
]; Xj
= x
[j
]; Yj
= y
[j
]; Zj
= z
[j
];
321 double stop
= clock();
323 for (i
= 0; i
< Atoms
+1; i
++)
325 for (i
= 0; i
< Atoms
; i
++) {
327 Size
= 1; j
= List
[i
]; List
[i
] = -1;
328 while (j
!= i
) { Size
++; k
= List
[j
]; List
[j
] = -1; j
= k
; }
329 //Bestimmung der Groesse des Clusters im Startteilchen i
333 printf("\nCoherent Clusters below %4.4f A\n", RcClusterSq
);
334 printf("Size Times Atoms\n");
335 for (i
= 0; i
< Atoms
+1; i
++) // Atoms + 1 because 0 is also a possible Count
337 if ((s
= Spectrum
[i
]) != 0)
338 printf ("%6d %6d %6d\n", i
, s
, i
*s
);
345 /* --------------------------------------------------------------------------------------------- */
347 static PyObject
* clusterdetector(PyObject
*self
, PyObject
*args
) {
348 PyObject
*inx
, *iny
, *inz
;
349 PyArrayObject
*xx
, *yy
, *zz
;
353 if (!PyArg_ParseTuple (args
, "OOOd|i", &inx
, &iny
, &inz
, &rcut
, &list
))
356 xx
= (PyArrayObject
*)PyArray_ContiguousFromObject (inx
, PyArray_DOUBLE
, 1, 0);
357 yy
= (PyArrayObject
*)PyArray_ContiguousFromObject (iny
, PyArray_DOUBLE
, 1, 0);
358 zz
= (PyArrayObject
*)PyArray_ContiguousFromObject (inz
, PyArray_DOUBLE
, 1, 0);
360 int n
= xx
->dimensions
[0];
362 float *x
= (float *) calloc (n
, sizeof (float));
363 float *y
= (float *) calloc (n
, sizeof (float));
364 float *z
= (float *) calloc (n
, sizeof (float));
368 x
[i
] = (float)*(double*) (xx
->data
+i
*xx
->strides
[0]);
369 y
[i
] = (float)*(double*) (yy
->data
+i
*yy
->strides
[0]);
370 z
[i
] = (float)*(double*) (zz
->data
+i
*zz
->strides
[0]);
373 DetermineBoxLength (n
, x
, y
, z
, &(Length
[X
]), &(Length
[Y
]), &(Length
[Z
]));
375 float RcClusterSq
, RcCluster
= 0.;
376 float RcNeighbor
= 0;
377 RcNeighbor
= RcCluster
;
380 BuildNeighborList (n
, x
, y
, z
, RcNeighbor
);
381 MoleculeListNeighbor (n
, x
, y
, z
, RcClusterSq
);
383 MoleculeList (n
, x
, y
, z
, RcClusterSq
);
391 return PyFloat_FromDouble (Length
[Z
]);
395 static struct PyMethodDef cluster_methods
[] = {
396 {"clusterdetector", clusterdetector
, 1},
400 PyMODINIT_FUNC
initcluster (void) {
401 Py_InitModule ("cluster", cluster_methods
);