@@ -174,7 +174,7 @@ impl CellList {
174
174
let n_cells = self . cells . shape ( ) ;
175
175
let n_cells = [ n_cells[ 0 ] , n_cells[ 1 ] , n_cells[ 2 ] ] ;
176
176
177
- // find the cell in which this atom should go
177
+ // find the subcell in which this atom ' should go'
178
178
let cell_index = [
179
179
f64:: floor ( fractional[ 0 ] * n_cells[ 0 ] as f64 ) as i32 ,
180
180
f64:: floor ( fractional[ 1 ] * n_cells[ 1 ] as f64 ) as i32 ,
@@ -250,10 +250,28 @@ impl CellList {
250
250
let shift = CellShift ( cell_shift) + atom_i. shift - atom_j. shift ;
251
251
let shift_is_zero = shift[ 0 ] == 0 && shift[ 1 ] == 0 && shift[ 2 ] == 0 ;
252
252
253
- if atom_i. index == atom_j. index && shift_is_zero {
254
- // only create pair with the same atom twice
255
- // if the pair spans more than one unit cell
256
- continue ;
253
+ if atom_i. index == atom_j. index {
254
+ if shift_is_zero {
255
+ // only create pair with the same atom twice
256
+ // if the pair spans more than one unit cell
257
+ continue ;
258
+ }
259
+
260
+ if ( shift[ 0 ] + shift[ 1 ] + shift[ 2 ] < 0 ) ||
261
+ (
262
+ ( shift[ 0 ] + shift[ 1 ] + shift[ 2 ] == 0 ) &&
263
+ ( shift[ 2 ] < 0 || ( shift[ 2 ] == 0 && shift[ 1 ] < 0 ) )
264
+ )
265
+ {
266
+ // When creating pairs between an atom
267
+ // and one of its periodic images, the
268
+ // code generate multiple redundant
269
+ // pairs (e.g. with shifts 0 1 1 and 0
270
+ // -1 -1); and we want to only keep one
271
+ // of these. We keep the pair in the
272
+ // positive half plane of shifts.
273
+ continue ;
274
+ }
257
275
}
258
276
259
277
if self . unit_cell . is_infinite ( ) && !shift_is_zero {
@@ -426,21 +444,15 @@ mod tests {
426
444
let neighbors = NeighborsList :: new ( & positions, cell, 3.0 ) ;
427
445
428
446
let expected = [
429
- ( Vector3D :: new ( 0.0 , -1.0 , -1.0 ) , [ -1 , 0 , 0 ] ) ,
430
447
( Vector3D :: new ( 1.0 , 0.0 , -1.0 ) , [ -1 , 0 , 1 ] ) ,
431
448
( Vector3D :: new ( 1.0 , -1.0 , 0.0 ) , [ -1 , 1 , 0 ] ) ,
432
- ( Vector3D :: new ( -1.0 , 0.0 , -1.0 ) , [ 0 , -1 , 0 ] ) ,
433
449
( Vector3D :: new ( 0.0 , 1.0 , -1.0 ) , [ 0 , -1 , 1 ] ) ,
434
- ( Vector3D :: new ( -1.0 , -1.0 , 0.0 ) , [ 0 , 0 , -1 ] ) ,
435
450
( Vector3D :: new ( 1.0 , 1.0 , 0.0 ) , [ 0 , 0 , 1 ] ) ,
436
- ( Vector3D :: new ( 0.0 , -1.0 , 1.0 ) , [ 0 , 1 , -1 ] ) ,
437
451
( Vector3D :: new ( 1.0 , 0.0 , 1.0 ) , [ 0 , 1 , 0 ] ) ,
438
- ( Vector3D :: new ( -1.0 , 1.0 , 0.0 ) , [ 1 , -1 , 0 ] ) ,
439
- ( Vector3D :: new ( -1.0 , 0.0 , 1.0 ) , [ 1 , 0 , -1 ] ) ,
440
452
( Vector3D :: new ( 0.0 , 1.0 , 1.0 ) , [ 1 , 0 , 0 ] ) ,
441
453
] ;
442
454
443
- assert_eq ! ( neighbors. pairs. len( ) , 12 ) ;
455
+ assert_eq ! ( neighbors. pairs. len( ) , 6 ) ;
444
456
for ( pair, ( vector, shifts) ) in neighbors. pairs . iter ( ) . zip ( & expected) {
445
457
assert_eq ! ( pair. first, 0 ) ;
446
458
assert_eq ! ( pair. second, 0 ) ;
@@ -480,4 +492,26 @@ mod tests {
480
492
assert_ulps_eq ! ( pair. distance, 2.0 ) ;
481
493
}
482
494
}
495
+
496
+ #[ test]
497
+ fn small_cell_large_cutoffs ( ) {
498
+ let cell = UnitCell :: cubic ( 0.5 ) ;
499
+ let positions = [ Vector3D :: new ( 0.0 , 0.0 , 0.0 ) ] ;
500
+ let neighbors = NeighborsList :: new ( & positions, cell, 0.6 ) ;
501
+
502
+ let expected = [
503
+ ( Vector3D :: new ( 0.0 , 0.0 , 0.5 ) , [ 0 , 0 , 1 ] ) ,
504
+ ( Vector3D :: new ( 0.0 , 0.5 , 0.0 ) , [ 0 , 1 , 0 ] ) ,
505
+ ( Vector3D :: new ( 0.5 , 0.0 , 0.0 ) , [ 1 , 0 , 0 ] ) ,
506
+ ] ;
507
+
508
+ assert_eq ! ( neighbors. pairs. len( ) , 3 ) ;
509
+ for ( pair, ( vector, shifts) ) in neighbors. pairs . iter ( ) . zip ( & expected) {
510
+ assert_eq ! ( pair. first, 0 ) ;
511
+ assert_eq ! ( pair. second, 0 ) ;
512
+ assert_ulps_eq ! ( pair. distance, 0.5 ) ;
513
+ assert_ulps_eq ! ( pair. vector, vector) ;
514
+ assert_eq ! ( & pair. cell_shift_indices, shifts) ;
515
+ }
516
+ }
483
517
}
0 commit comments