4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
17 * GROMACS: A message-passing parallel molecular dynamics implementation
18 * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19 * Comp. Phys. Comm. 91, 43-56 (1995)
21 * Also check out our WWW page:
22 * http://md.chem.rug.nl/~gmx
27 * GRowing Old MAkes el Chrono Sweat
29 static char *SRCID_ns_c
= "$Id$";
60 * E X C L U S I O N H A N D L I N G
62 typedef unsigned long t_excl
;
65 static void SETEXCL_(t_excl e
[],atom_id i
,atom_id j
)
66 { e
[j
] = e
[j
] | (1<<i
); }
67 static void RMEXCL_(t_excl e
[],atom_id i
,atom_id j
)
68 { e
[j
]=e
[j
] & ~(1<<i
); }
69 static bool ISEXCL_(t_excl e
[],atom_id i
,atom_id j
)
70 { return (bool)(e
[j
] & (1<<i
)); }
71 static bool NOTEXCL_(t_excl e
[],atom_id i
,atom_id j
)
72 { return !(ISEXCL(e
,i
,j
)); }
74 #define SETEXCL(e,i,j) (e)[((atom_id) j)] |= (1<<((atom_id) i))
75 #define RMEXCL(e,i,j) (e)[((atom_id) j)] &= (~(1<<((atom_id) i)))
76 #define ISEXCL(e,i,j) (bool) ((e)[((atom_id) j)] & (1<<((atom_id) i)))
77 #define NOTEXCL(e,i,j) !(ISEXCL(e,i,j))
80 /************************************************
82 * U T I L I T I E S F O R N S
84 ************************************************/
86 static int NLI_INC
= 1000;
87 static int NLJ_INC
= 16384;
89 static void reallocate_nblist(t_nblist
*nl
)
92 fprintf(debug
,"reallocating neigborlist il_code=%d, maxnri=%d\n",
93 nl
->il_code
,nl
->maxnri
);
94 srenew(nl
->iinr
, nl
->maxnri
+2);
95 srenew(nl
->gid
, nl
->maxnri
+2);
96 srenew(nl
->shift
, nl
->maxnri
+2);
97 srenew(nl
->jindex
, nl
->maxnri
+2);
100 static void init_nblist(t_nblist
*nl
,int homenr
,int il_code
)
102 nl
->il_code
= il_code
;
103 /* maxnri is influenced by the number of shifts (maximum is 8)
104 * and the number of energy groups.
105 * If it is not enough, nl memory will be reallocated during the run.
106 * 4 seems to be a reasonable factor, which only causes reallocation
107 * during runs with tiny and many energygroups.
109 nl
->maxnri
= homenr
*4;
117 reallocate_nblist(nl
);
124 static unsigned int nbf_index(bool bCoul
,bool bRF
,bool bBham
,
125 bool bTab
,bool bWater
,bool bEwald
)
127 /* lot of redundancy here,
128 * since we cant have RF and EWALD simultaneously...
132 eNR_LJC
, eNR_QQ
, eNR_BHAM
, eNR_QQ
,
133 eNR_LJCRF
, eNR_QQRF
, eNR_BHAMRF
, eNR_QQRF
,
134 eNR_TAB
, eNR_COULTAB
, eNR_BHAMTAB
, eNR_COULTAB
,
135 eNR_TAB
, eNR_COULTAB
, eNR_BHAMTAB
, eNR_COULTAB
,
136 eNR_LJC_WAT
, eNR_QQ_WAT
, eNR_BHAM_WAT
, eNR_QQ_WAT
,
137 eNR_LJCRF_WAT
, eNR_QQRF_WAT
, eNR_BHAMRF_WAT
, eNR_QQRF_WAT
,
138 eNR_TAB_WAT
, eNR_COULTAB_WAT
,eNR_BHAMTAB_WAT
,eNR_COULTAB_WAT
,
139 eNR_TAB_WAT
, eNR_COULTAB_WAT
,eNR_BHAMTAB_WAT
,eNR_COULTAB_WAT
,
140 eNR_LJC_EW
, eNR_QQ_EW
, eNR_BHAM_EW
, eNR_QQ_EW
,
141 eNR_LJC_EW
, eNR_QQ_EW
, eNR_BHAM_EW
, eNR_QQ_EW
,
142 eNR_TAB
, eNR_COULTAB
, eNR_BHAMTAB
, eNR_COULTAB
,
143 eNR_TAB
, eNR_COULTAB
, eNR_BHAMTAB
, eNR_COULTAB
,
144 eNR_LJC_WAT_EW
, eNR_QQ_WAT_EW
, eNR_BHAM_WAT_EW
,eNR_QQ_WAT_EW
,
145 eNR_LJC_WAT_EW
, eNR_QQ_WAT_EW
, eNR_BHAM_WAT_EW
,eNR_QQ_WAT_EW
,
146 eNR_TAB_WAT
, eNR_COULTAB_WAT
,eNR_BHAMTAB_WAT
,eNR_COULTAB_WAT
,
147 eNR_TAB_WAT
, eNR_COULTAB_WAT
,eNR_BHAMTAB_WAT
,eNR_COULTAB_WAT
152 ni
= bCoul
| (bBham
<< 1) | (bRF
<< 2) | (bTab
<< 3) | (bWater
<< 4)
158 void init_neighbor_list(FILE *log
,t_forcerec
*fr
,int homenr
)
160 /* Make maxlr tunable! (does not seem to be a big difference though)
161 * This parameter determines the number of i particles in a long range
162 * neighbourlist. Too few means many function calls, too many means
165 int maxsr
,maxsr_wat
,maxlr
,maxlr_wat
;
167 maxsr
= homenr
-fr
->nWatMol
*3;
169 fatal_error(0,"%s, %d: Negative number of short range atoms.\n"
170 "Call your Gromacs dealer for assistance.",__FILE__
,__LINE__
);
171 maxsr_wat
= fr
->nWatMol
;
172 maxlr
= max(maxsr
/10,50);
173 maxlr_wat
= max(maxsr_wat
/10,50);
175 init_nblist(&fr
->nlist_sr
[eNL_VDW
],maxsr
,
176 nbf_index(FALSE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,FALSE
,fr
->bEwald
));
177 init_nblist(&fr
->nlist_sr
[eNL_QQ
],maxsr
,
178 nbf_index(TRUE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,FALSE
,fr
->bEwald
));
180 init_nblist(&fr
->nlist_sr
[eNL_FREE
],maxsr
,
181 fr
->bBHAM
? eNR_BHAM_FREE
: eNR_LJC_FREE
);
183 init_nblist(&fr
->nlist_sr
[eNL_VDW_WAT
],maxsr_wat
,
184 nbf_index(FALSE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,TRUE
,fr
->bEwald
));
185 init_nblist(&fr
->nlist_sr
[eNL_QQ_WAT
],maxsr_wat
,
186 nbf_index(TRUE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,TRUE
,fr
->bEwald
));
188 if (fr
->bTwinRange
) {
189 fprintf(log
,"Allocating space for long range neighbour list of %d atoms\n",
191 init_nblist(&fr
->nlist_lr
[eNL_VDW
],maxlr
,
192 nbf_index(FALSE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,FALSE
,fr
->bEwald
));
193 init_nblist(&fr
->nlist_lr
[eNL_QQ
],maxlr
,
194 nbf_index(TRUE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,FALSE
,fr
->bEwald
));
196 init_nblist(&fr
->nlist_lr
[eNL_FREE
],maxlr
,
197 fr
->bBHAM
? eNR_BHAM_FREE
: eNR_LJC_FREE
);
199 init_nblist(&fr
->nlist_lr
[eNL_VDW_WAT
],maxlr_wat
,
200 nbf_index(FALSE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,TRUE
,fr
->bEwald
));
201 init_nblist(&fr
->nlist_lr
[eNL_QQ_WAT
],maxlr_wat
,
202 nbf_index(TRUE
,fr
->bRF
,fr
->bBHAM
,fr
->bTab
,TRUE
,fr
->bEwald
));
207 static void reset_nblist(t_nblist
*nl
)
211 if (nl
->maxnri
> 0) {
213 if (nl
->maxnrj
> 1) {
220 static void reset_neighbor_list(t_forcerec
*fr
,bool bLR
,int eNL
)
225 reset_nblist(&(fr
->nlist_lr
[eNL
]));
227 for(i
=0; (i
<eNL_NR
); i
++)
228 reset_nblist(&(fr
->nlist_sr
[i
]));
232 static gmx_inline
void new_i_nblist(t_nblist
*nlist
,
233 int ftype
,int i_atom
,int shift
,int gid
)
237 if (nlist
->maxnrj
<= nlist
->nrj
+ NLJ_INC
-1) {
239 fprintf(debug
,"Adding %5d J particles for nblist %s\n",NLJ_INC
,
240 interaction_function
[ftype
].longname
);
242 nlist
->maxnrj
+= NLJ_INC
;
243 srenew(nlist
->jjnr
,nlist
->maxnrj
);
248 /* Check whether we have to increase the i counter */
249 if ((nlist
->iinr
[nri
] != i_atom
) ||
250 (nlist
->shift
[nri
] != shift
) ||
251 (nlist
->gid
[nri
] != gid
)) {
252 /* This is something else. Now see if any entries have
253 * been added in the list of the previous atom.
255 if ((nlist
->jindex
[nri
+1] > nlist
->jindex
[nri
]) &&
256 (nlist
->iinr
[nri
] != -1)) {
258 /* If so increase the counter */
261 if (nlist
->nri
>= nlist
->maxnri
) {
262 nlist
->maxnri
+= NLI_INC
;
263 reallocate_nblist(nlist
);
266 /* Set the number of neighbours and the atom number */
267 nlist
->jindex
[nri
+1] = nlist
->jindex
[nri
];
268 nlist
->iinr
[nri
] = i_atom
;
269 nlist
->gid
[nri
] = gid
;
270 nlist
->shift
[nri
] = shift
;
275 #define aswap(v,i,j) { \
283 static void quicksort(atom_id v
[], int left
, int right
)
287 if (left
>= right
) /* Do nothing if array contains */
288 return; /* fewer than two elements */
289 aswap(v
,left
,(left
+right
)/2); /* Move partition element */
290 last
=left
; /* to v[0] */
291 for(i
=left
+1; (i
<=right
); i
++) /* partition */
292 if (v
[i
] < v
[left
]) {
294 aswap(v
,last
,i
); /* watch out for macro trick */
296 aswap(v
,left
,last
); /* restore partition element */
297 quicksort(v
,left
,last
-1);
298 quicksort(v
,last
+1,right
);
302 static gmx_inline
void close_i_nblist(t_nblist
*nlist
)
304 int nri
= nlist
->nri
;
306 nlist
->jindex
[nri
+1] = nlist
->nrj
;
309 static gmx_inline
void close_nblist(t_nblist
*nlist
)
311 if (nlist
->maxnri
> 0) {
312 int nri
= nlist
->nri
;
314 if ((nlist
->jindex
[nri
+1] > nlist
->jindex
[nri
]) &&
315 (nlist
->iinr
[nri
] != -1)) {
317 nlist
->jindex
[nri
+2] = nlist
->nrj
;
322 static gmx_inline
void close_neighbor_list(t_forcerec
*fr
,bool bLR
,int eNL
)
327 close_nblist(&(fr
->nlist_lr
[eNL
]));
329 for(i
=0; (i
<eNL_NR
); i
++)
330 close_nblist(&(fr
->nlist_sr
[i
]));
334 static void add_j_to_nblist(t_nblist
*nlist
,int j_atom
)
338 nlist
->jjnr
[nrj
] = j_atom
;
342 static gmx_inline
void put_in_list(bool bHaveLJ
[],
343 int nWater
,int ngid
,t_mdatoms
*md
,
344 int icg
,int jgid
,int nj
,atom_id jjcg
[],
345 atom_id index
[],atom_id a
[],
346 t_excl bExcl
[],int shift
,
347 t_forcerec
*fr
,bool bLR
,bool bCoulOnly
)
349 t_nblist
*vdw
,*coul
,*free
=NULL
;
351 int i
,j
,jcg
,igid
,gid
,ind_ij
;
352 atom_id jj
,jj0
,jj1
,i_atom
,j_atom
;
356 unsigned short *cENER
;
359 bool bWater
,bFree
,bFreeJ
,bNotEx
,*bPert
;
362 /* Quicksort the charge groups in the neighbourlist to obtain
363 * better caching properties. We do this only for the short range,
364 * i.e. when we use the nlist more than once
367 quicksort(jjcg
,0,nj
-1);
369 /* Copy some pointers */
370 charge
= md
->chargeA
;
373 bPert
= md
->bPerturbed
;
375 /* Check whether this molecule is a water molecule */
377 nicg
= index
[icg
+1]-i0
;
378 bWater
= (((type
[a
[i0
]] == nWater
) && (nicg
== 3)) &&
379 (!bPert
[a
[i0
]]) && (!bPert
[a
[i0
+1]]) && (!bPert
[a
[i0
+2]]));
385 vdw
= &fr
->nlist_lr
[eNL_VDW_WAT
];
386 coul
= &fr
->nlist_lr
[eNL_QQ_WAT
];
389 vdw
= &fr
->nlist_lr
[eNL_VDW
];
390 coul
= &fr
->nlist_lr
[eNL_QQ
];
393 free
= &fr
->nlist_lr
[eNL_FREE
];
397 vdw
= &fr
->nlist_sr
[eNL_VDW_WAT
];
398 coul
= &fr
->nlist_sr
[eNL_QQ_WAT
];
401 vdw
= &fr
->nlist_sr
[eNL_VDW
];
402 coul
= &fr
->nlist_sr
[eNL_QQ
];
405 free
= &fr
->nlist_sr
[eNL_FREE
];
408 /* Loop over the atoms in the i charge group */
409 for(i
=0; (i
<nicg
); i
++) {
411 igid
= cENER
[i_atom
];
412 gid
= GID(igid
,jgid
,ngid
);
414 /* Create new i_atom for each energy group */
416 new_i_nblist(vdw
,bLR
? F_LJLR
: F_LJ
,i_atom
,shift
,gid
);
417 new_i_nblist(coul
,bLR
? F_LR
: F_SR
,i_atom
,shift
,gid
);
419 new_i_nblist(free
,F_DVDL
,i_atom
,shift
,gid
);
421 /* Loop over the j charge groups */
422 for(j
=0; (j
<nj
); j
++) {
425 if (bWater
&& (jcg
==icg
))
428 /* Check for large charge groups */
436 if (bWater
&& !fr
->bPert
) {
438 for(jj
=jj0
; (jj
<jj1
); jj
++) {
441 add_j_to_nblist(coul
,j_atom
);
445 for(jj
=jj0
; (jj
<jj1
); jj
++) {
448 if (bHaveLJ
[type
[j_atom
]])
449 add_j_to_nblist(vdw
,j_atom
);
450 else if (charge
[j_atom
] != 0)
451 add_j_to_nblist(coul
,j_atom
);
456 /* Finally loop over the atoms in the j-charge group */
457 bFree
= bPert
[i_atom
];
459 for(jj
=jj0
; (jj
<jj1
); jj
++) {
461 bFreeJ
= bFree
|| bPert
[j_atom
];
462 bNotEx
= NOTEXCL(bExcl
,i
,j_atom
);
466 add_j_to_nblist(free
,j_atom
);
468 /* This is done whether or not bWater is set */
469 add_j_to_nblist(coul
,j_atom
);
471 if (bHaveLJ
[type
[j_atom
]])
472 add_j_to_nblist(vdw
,j_atom
);
473 else if (qi
*charge
[j_atom
] != 0)
474 add_j_to_nblist(coul
,j_atom
);
480 close_i_nblist(coul
);
483 close_i_nblist(free
);
487 void setexcl(int nri
,atom_id ia
[],t_block
*excl
,bool b
,
494 for(i
=0; (i
<nri
); i
++) {
496 for(k
=excl
->index
[inr
]; (k
<excl
->index
[inr
+1]); k
++) {
497 SETEXCL(bexcl
,i
,excl
->a
[k
]);
502 for(i
=0; (i
<nri
); i
++) {
504 for(k
=excl
->index
[inr
]; (k
<excl
->index
[inr
+1]); k
++) {
505 RMEXCL(bexcl
,i
,excl
->a
[k
]);
511 int calc_naaj(int icg
,int cgtot
)
515 if ((cgtot
% 2) == 1) {
516 /* Odd number of charge groups, easy */
519 else if ((cgtot
% 4) == 0) {
520 /* Multiple of four is hard */
542 fprintf(log
,"naaj=%d\n",naaj
);
547 /************************************************
549 * S I M P L E C O R E S T U F F
551 ************************************************/
553 static real
calc_image_rect(rvec xi
,rvec xj
,rvec box_size
,
554 rvec b_inv
,int *shift
)
562 /* Compute diff vector */
567 /* Perform NINT operation, using trunc operation, therefore
568 * we first add 1.5 then subtract 1 again
577 /* Correct diff vector for translation */
578 ddx
=tx
*box_size
[XX
]-dx
;
579 ddy
=ty
*box_size
[YY
]-dy
;
580 ddz
=tz
*box_size
[ZZ
]-dz
;
582 /* Distance squared */
583 r2
=(ddx
*ddx
)+(ddy
*ddy
)+(ddz
*ddz
);
585 *shift
=XYZ2IS(tx
,ty
,tz
);
590 static void ns_inner_rect(rvec x
[],int icg
,int njcg
,atom_id jcg
[],
591 bool bBox
,rvec box_size
,rvec b_inv
,real rcut2
,
592 t_block
*cgs
,t_ns_buf
**ns_buf
,unsigned short gid
[])
596 atom_id cg_j
,*cgindex
,*cga
;
599 cgindex
= cgs
->index
;
603 for(j
=0; (j
<njcg
); j
++) {
605 nrj
= cgindex
[cg_j
+1]-cgindex
[cg_j
];
606 if (calc_image_rect(x
[icg
],x
[cg_j
],box_size
,b_inv
,&shift
) < rcut2
) {
607 jgid
= gid
[cga
[cgindex
[cg_j
]]];
608 nsbuf
= &ns_buf
[jgid
][shift
];
609 if (nsbuf
->ncg
>= MAX_CG
)
610 fatal_error(0,"Too many charge groups (%d) in buffer",nsbuf
->ncg
);
611 nsbuf
->jcg
[nsbuf
->ncg
++]=cg_j
;
616 for(j
=0; (j
<njcg
); j
++) {
618 nrj
= cgindex
[cg_j
+1]-cgindex
[cg_j
];
619 if ((rcut2
== 0) || (distance2(x
[icg
],x
[cg_j
]) < rcut2
)) {
620 jgid
= gid
[cga
[cgindex
[cg_j
]]];
621 nsbuf
= &ns_buf
[jgid
][CENTRAL
];
622 if (nsbuf
->ncg
>= MAX_CG
)
623 fatal_error(0,"Too many charge groups (%d) in buffer",nsbuf
->ncg
);
624 nsbuf
->jcg
[nsbuf
->ncg
++]=cg_j
;
631 static int ns_simple_core(t_forcerec
*fr
,
634 rvec box_size
,t_excl bexcl
[],
635 int ngid
,t_ns_buf
**ns_buf
,
638 static atom_id
*aaj
=NULL
;
641 int nsearch
,icg
,jcg
,i0
,nri
,nn
;
644 t_block
*cgs
=&(top
->blocks
[ebCGS
]);
645 t_block
*excl
=&(top
->atoms
.excl
);
652 for(jcg
=0; (jcg
<cgs
->nr
); jcg
++) {
654 aaj
[jcg
+cgs
->nr
]=jcg
;
657 rlist2
= sqr(fr
->rlist
);
659 bBox
= (fr
->eBox
!= ebtNONE
);
661 for(m
=0; (m
<DIM
); m
++)
662 b_inv
[m
]=divide(1.0,box_size
[m
]);
665 for (icg
=fr
->cg0
; (icg
<fr
->hcg
); icg
++) {
666 i0
= cgs
->index
[icg
];
667 nri
= cgs
->index
[icg
+1]-i0
;
668 i_atoms
= &(cgs
->a
[i0
]);
669 setexcl(nri
,i_atoms
,excl
,TRUE
,bexcl
);
671 naaj
=calc_naaj(icg
,cgs
->nr
);
672 ns_inner_rect(fr
->cg_cm
,icg
,naaj
,&(aaj
[icg
]),
673 bBox
,box_size
,b_inv
,rlist2
,cgs
,ns_buf
,md
->cENER
);
676 for(nn
=0; (nn
<ngid
); nn
++) {
677 for(k
=0; (k
<SHIFTS
); k
++) {
678 nsbuf
= &(ns_buf
[nn
][k
]);
679 if (nsbuf
->ncg
> 0) {
680 put_in_list(bHaveLJ
,fr
->nWater
,
681 ngid
,md
,icg
,nn
,nsbuf
->ncg
,nsbuf
->jcg
,
682 cgs
->index
,cgs
->a
,bexcl
,k
,fr
,FALSE
,FALSE
);
683 nsbuf
->ncg
=nsbuf
->nj
=0;
687 setexcl(nri
,i_atoms
,excl
,FALSE
,bexcl
);
689 close_neighbor_list(fr
,FALSE
,-1);
694 /************************************************
696 * N S 5 G R I D S T U F F
698 ************************************************/
699 static bool get_dx(int cx
,int Nx
,int tx
,int delta
,int *dx0
,int *dx1
)
708 } else if (tx
== 0) {
730 #define sqr(x) ((x)*(x))
731 #define calc_dx2(XI,YI,ZI,y) (sqr(XI-y[XX])+sqr(YI-y[YY])+sqr(ZI-y[ZZ]))
732 #define calc_cyl_dx2(XI,YI,y) (sqr(XI-y[XX])+sqr(YI-y[YY]))
733 /****************************************************
735 * F A S T N E I G H B O R S E A R C H I N G
737 * Optimized neighboursearching routine using grid
738 * of at least 5x5x5, see GROMACS manual
740 ****************************************************/
742 static void do_longrange(FILE *log
,t_topology
*top
,t_forcerec
*fr
,
743 int ngid
,t_mdatoms
*md
,int icg
,
745 atom_id lr
[],t_excl bexcl
[],int shift
,
746 rvec x
[],rvec box_size
,t_nrnb
*nrnb
,
747 real lambda
,real
*dvdlambda
,
748 t_groups
*grps
,bool bCoulOnly
,
749 bool bDoForces
,bool bHaveLJ
[])
753 for(i
=0; (i
<eNL_NR
); i
++) {
754 if ((fr
->nlist_lr
[i
].nri
> fr
->nlist_lr
[i
].maxnri
-32) || bDoForces
) {
755 close_neighbor_list(fr
,TRUE
,i
);
757 /* Evaluate the forces */
758 do_fnbf(log
,fr
,x
,fr
->flr
,md
,
759 grps
->estat
.ee
[egLJLR
],grps
->estat
.ee
[egLR
],box_size
,
760 nrnb
,lambda
,dvdlambda
,TRUE
,i
);
762 reset_neighbor_list(fr
,TRUE
,i
);
767 /* Put the long range particles in a list */
768 put_in_list(bHaveLJ
,fr
->nWater
,
769 ngid
,md
,icg
,jgid
,nlr
,lr
,top
->blocks
[ebCGS
].index
,
770 top
->blocks
[ebCGS
].a
,bexcl
,shift
,fr
,TRUE
,bCoulOnly
);
774 static int ns5_core(FILE *log
,t_forcerec
*fr
,int cg_index
[],
775 rvec box_size
,int ngid
,
776 t_topology
*top
,t_groups
*grps
,
777 t_grid
*grid
,rvec x
[],t_excl bexcl
[],
778 t_nrnb
*nrnb
,t_mdatoms
*md
,
779 real lambda
,real
*dvdlambda
,
782 static atom_id
**nl_lr_ljc
,**nl_lr_coul
,**nl_sr
=NULL
;
783 static int *nlr_ljc
,*nlr_coul
,*nsr
;
785 t_block
*cgs
=&(top
->blocks
[ebCGS
]);
786 unsigned short *gid
=md
->cENER
;
787 atom_id
*i_atoms
,*cgsatoms
=cgs
->a
,*cgsindex
=cgs
->index
;
788 int tx
,ty
,tz
,cx
,cy
,cz
,dx
,dy
,dz
,cj
;
789 int dx0
,dx1
,dy0
,dy1
,dz0
,dz1
;
790 int Nx
,Ny
,Nz
,delta
,shift
=-1,j
,nrj
,nns
,nn
=-1;
791 int icg
=-1,iicg
,cgsnr
,i0
,nri
,naaj
,min_icg
,icg_naaj
,jjcg
,cgj0
,jgid
;
792 int *grida
,*gridnra
,*gridind
;
794 real r2
,rs2
,rvdw2
,rcoul2
,XI
,YI
,ZI
;
797 rs2
= sqr(fr
->rlist
);
798 rvdw2
= sqr(fr
->rvdw
);
799 rcoul2
= sqr(fr
->rcoulomb
);
802 /* Short range buffers */
810 /* Long range LJC buffers */
811 snew(nl_lr_ljc
,ngid
);
814 /* Long range Coul buffers */
815 snew(nl_lr_coul
,ngid
);
817 for(j
=0; (j
<ngid
); j
++) {
818 snew(nl_sr
[j
],MAX_CG
);
820 snew(nl_lr_ljc
[j
],MAX_CG
);
822 snew(nl_lr_coul
[j
],MAX_CG
);
825 fprintf(debug
,"ns5_core: rs2 = %g, rvdw2 = %g, rcoul2 = %g (nm^2)\n",
831 svec
= fr
->shift_vec
;
836 gridind
= grid
->index
;
841 /* Loop over charge groups */
842 for(iicg
=fr
->cg0
; (iicg
< fr
->hcg
); iicg
++) {
843 icg
= cg_index
[iicg
];
844 /* Consistency check */
846 fatal_error(0,"icg = %d, iicg = %d, file %s, line %d",icg
,iicg
,__FILE__
,
849 nri
= cgsindex
[icg
+1]-i0
;
850 i_atoms
= &(cgsatoms
[i0
]);
852 /* Set the exclusions for the atoms in charge group icg using
855 setexcl(nri
,i_atoms
,&top
->atoms
.excl
,TRUE
,bexcl
);
857 /* Compute the number of charge groups that fall within the control
860 naaj
= calc_naaj(icg
,cgsnr
);
862 min_icg
= icg_naaj
-cgsnr
;
864 /* Changed iicg to icg, DvdS 990115
865 * (but see consistency check above, DvdS 990330)
867 ci2xyz(grid
,icg
,&cx
,&cy
,&cz
);
869 fprintf(log
,"icg=%5d, naaj=%5d, cx=%2d, cy=%2d, cz=%2d\n",
872 /* Loop over shift vectors in three dimensions */
873 for (tx
=-1; (tx
<=1); tx
++) {
874 /* Calculate range of cells in X direction that have the shift tx */
875 if (get_dx(cx
,Nx
,tx
,delta
,&dx0
,&dx1
))
877 for (ty
=-1; (ty
<=1); ty
++) {
878 /* Calculate range of cells in Y direction that have the shift ty */
879 if (get_dx(cy
,Ny
,ty
,delta
,&dy0
,&dy1
))
881 for (tz
=-1; (tz
<=1); tz
++) {
882 /* Calculate range of cells in Z direction that have the shift tz */
883 if (get_dx(cz
,Nz
,tz
,delta
,&dz0
,&dz1
))
886 /* Get shift vector */
887 shift
=XYZ2IS(tx
,ty
,tz
);
890 assert(shift
< SHIFTS
);
892 XI
= cgcm
[icg
][XX
]+svec
[shift
][XX
];
893 YI
= cgcm
[icg
][YY
]+svec
[shift
][YY
];
894 ZI
= cgcm
[icg
][ZZ
]+svec
[shift
][ZZ
];
895 for(nn
=0; (nn
<ngid
); nn
++) {
901 fprintf(log
,"shift: %2d, dx0,1: %2d,%2d, dy0,1: %2d,%2d, dz0,1: %2d,%2d\n",
902 shift
,dx0
,dx1
,dy0
,dy1
,dz0
,dz1
);
903 fprintf(log
,"cgcm: %8.3f %8.3f %8.3f\n",cgcm
[icg
][XX
],
904 cgcm
[icg
][YY
],cgcm
[icg
][ZZ
]);
905 fprintf(log
,"xi: %8.3f %8.3f %8.3f\n",XI
,YI
,ZI
);
907 for (dx
=dx0
; (dx
<=dx1
); dx
++) {
908 for (dy
=dy0
; (dy
<=dy1
); dy
++) {
909 for (dz
=dz0
; (dz
<=dz1
); dz
++) {
910 /* Find the grid-cell cj in which possible neighbours are */
911 cj
= xyz2ci(Ny
,Nz
,dx
,dy
,dz
);
913 /* Check out how many cgs (nrj) there in this cell */
916 /* Find the offset in the cg list */
920 for (j
=0; (j
<nrj
); j
++) {
921 jjcg
= grida
[cgj0
+j
];
923 /* check whether this guy is in range! */
924 if (((jjcg
>= icg
) && (jjcg
< icg_naaj
)) ||
925 ((jjcg
< min_icg
))) {
926 r2
=calc_dx2(XI
,YI
,ZI
,cgcm
[jjcg
]);
928 jgid
= gid
[cgsatoms
[cgsindex
[jjcg
]]];
930 if (nsr
[jgid
] >= MAX_CG
) {
931 put_in_list(bHaveLJ
,fr
->nWater
,
932 ngid
,md
,icg
,jgid
,nsr
[jgid
],nl_sr
[jgid
],
933 cgsindex
,cgsatoms
,bexcl
,
934 shift
,fr
,FALSE
,FALSE
);
937 nl_sr
[jgid
][nsr
[jgid
]++]=jjcg
;
939 else if (r2
< rvdw2
) {
940 if (nlr_ljc
[jgid
] >= MAX_CG
) {
941 do_longrange(log
,top
,fr
,ngid
,md
,icg
,jgid
,
943 nl_lr_ljc
[jgid
],bexcl
,shift
,x
,
945 lambda
,dvdlambda
,grps
,FALSE
,FALSE
,
949 nl_lr_ljc
[jgid
][nlr_ljc
[jgid
]++]=jjcg
;
952 if (nlr_coul
[jgid
] >= MAX_CG
) {
953 do_longrange(log
,top
,fr
,ngid
,md
,icg
,jgid
,
955 nl_lr_coul
[jgid
],bexcl
,shift
,x
,
957 lambda
,dvdlambda
,grps
,TRUE
,FALSE
,
961 nl_lr_coul
[jgid
][nlr_coul
[jgid
]++]=jjcg
;
970 /* CHECK whether there is anything left in the buffers */
971 for(nn
=0; (nn
<ngid
); nn
++) {
973 put_in_list(bHaveLJ
,fr
->nWater
,
974 ngid
,md
,icg
,nn
,nsr
[nn
],nl_sr
[nn
],
975 cgsindex
,cgsatoms
,bexcl
,shift
,fr
,FALSE
,FALSE
);
978 do_longrange(log
,top
,fr
,ngid
,md
,icg
,nn
,nlr_ljc
[nn
],
979 nl_lr_ljc
[nn
],bexcl
,shift
,x
,box_size
,nrnb
,
980 lambda
,dvdlambda
,grps
,FALSE
,FALSE
,bHaveLJ
);
982 if (nlr_coul
[nn
] > 0)
983 do_longrange(log
,top
,fr
,ngid
,md
,icg
,nn
,nlr_coul
[nn
],
984 nl_lr_coul
[nn
],bexcl
,shift
,x
,box_size
,nrnb
,
985 lambda
,dvdlambda
,grps
,TRUE
,FALSE
,bHaveLJ
);
990 setexcl(nri
,i_atoms
,&top
->atoms
.excl
,FALSE
,bexcl
);
992 /* Perform any left over force calculations */
993 for (nn
=0; (nn
<ngid
); nn
++) {
995 do_longrange(log
,top
,fr
,0,md
,icg
,nn
,nlr_ljc
[nn
],
996 nl_lr_ljc
[nn
],bexcl
,shift
,x
,box_size
,nrnb
,
997 lambda
,dvdlambda
,grps
,FALSE
,TRUE
,bHaveLJ
);
999 do_longrange(log
,top
,fr
,0,md
,icg
,nn
,nlr_coul
[nn
],
1000 nl_lr_coul
[nn
],bexcl
,shift
,x
,box_size
,nrnb
,
1001 lambda
,dvdlambda
,grps
,TRUE
,TRUE
,bHaveLJ
);
1003 /* Close off short range neighbourlists */
1004 close_neighbor_list(fr
,FALSE
,-1);
1012 static int rv_comp(const void *a
,const void *b
)
1018 diff
= sptr
[ia
][sdim
] - sptr
[ib
][sdim
];
1027 static void sort_charge_groups(t_commrec
*cr
,int cg_index
[],int slab_index
[],
1028 rvec cg_cm
[],int Dimension
)
1032 nrcg
= slab_index
[cr
->nprocs
];
1035 qsort(cg_index
,nrcg
,sizeof(cg_index
[0]),rv_comp
);
1038 fprintf(debug
,"Just sorted the cg_cm array on dimension %d\n",Dimension
);
1039 fprintf(debug
,"Index: Coordinates of cg_cm\n");
1040 for(i
=0; (i
<nrcg
); i
++) {
1041 cgind
= cg_index
[i
];
1042 fprintf(debug
,"%8d%10.3f%10.3f%10.3f\n",cgind
,
1043 cg_cm
[cgind
][XX
],cg_cm
[cgind
][YY
],cg_cm
[cgind
][ZZ
]);
1050 int search_neighbours(FILE *log
,t_forcerec
*fr
,
1051 rvec x
[],matrix box
,
1052 t_topology
*top
,t_groups
*grps
,
1053 t_commrec
*cr
,t_nsborder
*nsb
,
1054 t_nrnb
*nrnb
,t_mdatoms
*md
,
1055 real lambda
,real
*dvdlambda
)
1057 static bool bFirst
=TRUE
;
1058 static t_grid
*grid
=NULL
;
1059 static t_excl
*bexcl
;
1060 static bool *bHaveLJ
;
1061 static t_ns_buf
**ns_buf
=NULL
;
1062 static int *cg_index
=NULL
,*slab_index
=NULL
;
1063 static bool bSwitched
=FALSE
;
1065 t_block
*cgs
=&(top
->blocks
[ebCGS
]);
1073 /* Set some local variables */
1075 ngid
=top
->atoms
.grps
[egcENER
].nr
;
1077 for(m
=0; (m
<DIM
); m
++)
1078 box_size
[m
]=box
[m
][m
];
1080 /* First time initiation of arrays etc. */
1082 int icg
,nr_in_cg
,maxcg
;
1084 /* Compute largest charge groups size (# atoms) */
1086 for (icg
=0; (icg
< cgs
->nr
); icg
++)
1087 nr_in_cg
=max(nr_in_cg
,(int)(cgs
->index
[icg
+1]-cgs
->index
[icg
]));
1089 /* Verify whether largest charge group is <= max cg.
1090 * This is determined by the type of the local exclusion type
1091 * Exclusions are stored in bits. (If the type is not large
1092 * enough, enlarge it, unsigned char -> unsigned short -> unsigned long)
1094 maxcg
=sizeof(t_excl
)*8;
1095 if (nr_in_cg
> maxcg
)
1096 fatal_error(0,"Max #atoms in a charge group: %d > %d\n",
1099 snew(bexcl
,cgs
->nra
);
1102 if ((ptr
=getenv("NLIST")) != NULL
) {
1103 sscanf(ptr
,"%d",&NLJ_INC
);
1105 fprintf(log
,"%s: I will increment J-lists by %d\n",
1109 /* Check whether we have to do domain decomposition,
1110 * if so set local variables for the charge group index and the
1113 if (fr
->bDomDecomp
) {
1114 snew(slab_index
,cr
->nprocs
+1);
1115 for(i
=0; (i
<=cr
->nprocs
); i
++)
1116 slab_index
[i
] = i
*((real
) cgs
->nr
/((real
) cr
->nprocs
));
1117 fr
->cg0
= slab_index
[cr
->pid
];
1118 fr
->hcg
= slab_index
[cr
->pid
+1] - fr
->cg0
;
1120 fprintf(debug
,"Will use DOMAIN DECOMPOSITION, "
1121 "from charge group index %d to %d on cpu %d\n",
1122 fr
->cg0
,fr
->cg0
+fr
->hcg
,cr
->pid
);
1124 snew(cg_index
,cgs
->nr
+1);
1125 for(i
=0; (i
<=cgs
->nr
); i
++)
1130 init_grid(log
,grid
,fr
->ndelta
,box
,fr
->rlistlong
,cgs
->nr
);
1133 /* Create array that determines whether or not atoms have LJ */
1134 snew(bHaveLJ
,fr
->ntype
);
1135 for(i
=0; (i
<fr
->ntype
); i
++) {
1136 for(j
=0; (j
<fr
->ntype
); j
++) {
1137 bHaveLJ
[i
] = (bHaveLJ
[i
] ||
1139 ((BHAMA(fr
->nbfp
,fr
->ntype
,i
,j
) != 0) ||
1140 (BHAMB(fr
->nbfp
,fr
->ntype
,i
,j
) != 0) ||
1141 (BHAMC(fr
->nbfp
,fr
->ntype
,i
,j
) != 0)) :
1142 ((C6(fr
->nbfp
,fr
->ntype
,i
,j
) != 0) ||
1143 (C12(fr
->nbfp
,fr
->ntype
,i
,j
) != 0))));
1147 pr_ivec(debug
,0,"bHaveLJ",bHaveLJ
,fr
->ntype
);
1153 /* Reset the neighbourlists */
1154 reset_neighbor_list(fr
,FALSE
,-1);
1157 grid_first(log
,grid
,box
,fr
->rlistlong
);
1158 /* Check if box is big enough to do grid searching... */
1159 if ( !( (grid
->nrx
>= 2*grid
->delta
+1) &&
1160 (grid
->nry
>= 2*grid
->delta
+1) &&
1161 (grid
->nrz
>= 2*grid
->delta
+1) ) ) {
1163 fprintf(log
,"WARNING: Box too small for grid-search, "
1164 "switching to simple neighboursearch.\n");
1166 fatal_error(0,"TWIN-RANGE cut-off with Simple "
1167 "neighboursearching not implemented.\n"
1168 "Use grid neighboursearching, and make (rlong < 0.4 box)");
1173 fprintf(log
,"WARNING: Box large enough again for grid-search\n");
1180 /* Don't know why this all is... (DvdS 3/99) */
1185 int start
= fr
->cg0
;
1186 int end
= (cgs
->nr
+1)/2;
1190 sort_charge_groups(cr
,cg_index
,slab_index
,fr
->cg_cm
,fr
->Dimension
);
1193 fill_grid(log
,fr
->bDomDecomp
,cg_index
,
1194 grid
,box
,cgs
->nr
,fr
->cg0
,fr
->hcg
,fr
->cg_cm
);
1198 mv_grid(cr
,fr
->bDomDecomp
,cg_index
,grid
,nsb
->workload
);
1201 calc_elemnr(log
,fr
->bDomDecomp
,cg_index
,grid
,start
,end
,cgs
->nr
);
1203 grid_last(log
,fr
->bDomDecomp
,cg_index
,grid
,start
,end
,cgs
->nr
);
1206 check_grid(debug
,grid
);
1207 print_grid(debug
,grid
,fr
->bDomDecomp
,cg_index
);
1214 nsearch
= ns5_core(log
,fr
,cg_index
,box_size
,ngid
,top
,grps
,
1215 grid
,x
,bexcl
,nrnb
,md
,lambda
,dvdlambda
,bHaveLJ
);
1217 /* Only allocate this when necessary, saves 100 kb */
1218 if (ns_buf
== NULL
) {
1220 for(i
=0; (i
<ngid
); i
++)
1221 snew(ns_buf
[i
],SHIFTS
);
1223 nsearch
= ns_simple_core(fr
,top
,md
,box_size
,
1224 bexcl
,ngid
,ns_buf
,bHaveLJ
);
1232 inc_nrnb(nrnb
,eNR_NS
,nsearch
);
1233 /* inc_nrnb(nrnb,eNR_LR,fr->nlr); */