@@ -174,7 +174,7 @@ impl CellList {
174174 let n_cells = self . cells . shape ( ) ;
175175 let n_cells = [ n_cells[ 0 ] , n_cells[ 1 ] , n_cells[ 2 ] ] ;
176176
177- // find the cell in which this atom should go
177+ // find the subcell in which this atom ' should go'
178178 let cell_index = [
179179 f64:: floor ( fractional[ 0 ] * n_cells[ 0 ] as f64 ) as i32 ,
180180 f64:: floor ( fractional[ 1 ] * n_cells[ 1 ] as f64 ) as i32 ,
@@ -250,10 +250,28 @@ impl CellList {
250250 let shift = CellShift ( cell_shift) + atom_i. shift - atom_j. shift ;
251251 let shift_is_zero = shift[ 0 ] == 0 && shift[ 1 ] == 0 && shift[ 2 ] == 0 ;
252252
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+ }
257275 }
258276
259277 if self . unit_cell . is_infinite ( ) && !shift_is_zero {
@@ -426,21 +444,15 @@ mod tests {
426444 let neighbors = NeighborsList :: new ( & positions, cell, 3.0 ) ;
427445
428446 let expected = [
429- ( Vector3D :: new ( 0.0 , -1.0 , -1.0 ) , [ -1 , 0 , 0 ] ) ,
430447 ( Vector3D :: new ( 1.0 , 0.0 , -1.0 ) , [ -1 , 0 , 1 ] ) ,
431448 ( Vector3D :: new ( 1.0 , -1.0 , 0.0 ) , [ -1 , 1 , 0 ] ) ,
432- ( Vector3D :: new ( -1.0 , 0.0 , -1.0 ) , [ 0 , -1 , 0 ] ) ,
433449 ( Vector3D :: new ( 0.0 , 1.0 , -1.0 ) , [ 0 , -1 , 1 ] ) ,
434- ( Vector3D :: new ( -1.0 , -1.0 , 0.0 ) , [ 0 , 0 , -1 ] ) ,
435450 ( Vector3D :: new ( 1.0 , 1.0 , 0.0 ) , [ 0 , 0 , 1 ] ) ,
436- ( Vector3D :: new ( 0.0 , -1.0 , 1.0 ) , [ 0 , 1 , -1 ] ) ,
437451 ( 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 ] ) ,
440452 ( Vector3D :: new ( 0.0 , 1.0 , 1.0 ) , [ 1 , 0 , 0 ] ) ,
441453 ] ;
442454
443- assert_eq ! ( neighbors. pairs. len( ) , 12 ) ;
455+ assert_eq ! ( neighbors. pairs. len( ) , 6 ) ;
444456 for ( pair, ( vector, shifts) ) in neighbors. pairs . iter ( ) . zip ( & expected) {
445457 assert_eq ! ( pair. first, 0 ) ;
446458 assert_eq ! ( pair. second, 0 ) ;
@@ -480,4 +492,26 @@ mod tests {
480492 assert_ulps_eq ! ( pair. distance, 2.0 ) ;
481493 }
482494 }
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+ }
483517}
0 commit comments