1!!------ Forming basin for specific real space function, and integrate real space functions in the basins
2!!------ The method is adapted from J. Phys.: Condens. Matter 21 (2009) 084204
3!Grid must be ortho
4subroutine basinana
5use defvar
6use basinintmod
7use util
8implicit real*8(a-h,o-z)
9integer walltime1,walltime2
10integer :: igridmethod=3
11integer,allocatable :: attconvold(:),realattconv(:),usercluslist(:)
12character basinfilename*200,selectyn,c80tmp*80,ctmp1*20,ctmp2*20,ctmp3*20,ctmp4*20,c1000tmp*1000,c200tmp*200
13real*8 :: threslowvalatt=1D-5
14ishowattlab=1
15ishowatmlab=0
16ishowatt=1
17!Don't show topology analysis results to avoid confusion
18ishowCPlab=0
19ishowpathlab=1
20ishow3n3=0
21ishow3n1=0
22ishow3p1=0
23ishow3p3=0
24!When enter this module, we reset the whole state, which is signified by numatt. Because the user may calculate grid data at external functions,
25!and hence messed up grid setting (orgx/y/z,dx/y/z...), so all of the functions in this module that rely on grid setting will be totally wrong
26numatt=0
27
28call delvirorb(1)
29
30do while(.true.)
31    write(*,*)
32    write(*,*) "                 ============= Basin analysis ============="
33    write(*,*) "-10 Return to main menu"
34    if (numatt>0) write(*,*) "-6 Set parameter for attractor clustering or manually perform clustering"
35    if (numatt==0) write(*,*) "-6 Set parameter for attractor clustering"
36    if (numatt>0) write(*,*) "-5 Export basins as cube file"
37    if (numatt>0) write(*,*) "-4 Export attractors as pdb file"
38    if (numatt>0) write(*,*) "-3 Show information of attractors"
39    if (numatt>0) write(*,*) "-2 Measure distances, angles and dihedral angles between attractors or atoms"
40    if (igridmethod==1) write(*,*) "-1 Select the method for generating basins, current: On-grid"
41    if (igridmethod==2) write(*,*) "-1 Select the method for generating basins, current: Near-grid"
42    if (igridmethod==3) write(*,*) "-1 Select the method for generating basins, current: Near-grid with refinement"
43    if (numatt>0) write(*,*) " 0 Visualize attractors and basins"
44    if (numatt>0) then
45        write(*,*) " 1 Regenerate basins and relocate attractors"
46    else
47        write(*,*) " 1 Generate basins and locate attractors"
48    end if
49    if (numatt>0) then
50        write(*,*) " 2 Integrate real space functions in the basins"
51        write(*,*) " 3 Calculate electric multipole moments in the basins"
52        write(*,*) " 4 Calculate localization index and delocalization index for the basins"
53        write(*,*) " 5 Output orbital overlap matrix in basins to BOM.txt in current folder"
54!         write(*,*) " 6 Integrate real space functions in the basins with multi-level refinement"
55        if (ifuncbasin==1) then
56            write(*,*) " 7 Integrate real space functions in AIM basins with mixed type of grids"
57            write(*,*) " 8 Calculate electric multipole moments in AIM basins with mixed type of grids"
58            write(*,*) " 9 Obtain atomic contribution to population of external basins"
59        end if
60    end if
61    read(*,*) isel
62    if (numatt==0.and.(isel==-5.or.isel==-4.or.isel==-3.or.isel==-2.or.isel==0.or.isel==2.or.isel==3.or.isel==4.or.isel==5)) then
63        write(*,*) "Error: You should use option 1 to generate basins first!"
64        cycle
65    end if
66
67    if (isel==-10) then
68        idrawbasinidx=-10 !Don't display interbasin in any other GUI
69        ishowattlab=0 !Don't show attractors in other GUIs
70        ishowatt=1
71        return
72
73    else if (isel==-6) then
74        do while(.true.)
75            write(*,*) "0 Return"
76            write(*,"(a,f14.5,a)") " 1 Set relative value difference criterion, current:",valcritclus*100,"%"
77            write(*,"(a,i3)") " 2 Set the multiplier for distance criterion, current:",mergeattdist
78            if (numatt>=2) write(*,*) "3 Cluster specified attractors"
79            read(*,*) isel2
80            if (isel2==0) then
81                exit
82            else if (isel2==1) then
83                write(*,"(a)") " Input a value in percentage, e.g. 0.5"
84                write(*,"(a)") " Note: Inputting X means if the value difference between two attractors is less than X%, &
85                then they will be regarded as degenerate and may be clustered according to distance criterion"
86                read(*,*) valcritclus
87                valcritclus=valcritclus/100D0
88            else if (isel2==2) then
89                write(*,"(a)") " Input a value, e.g. 6"
90                write(*,"(a)") " Note: Inputting P means for any two attractors that have relative value difference less than the one set by option 1, &
91                if their interval is less than P*sqrt(dx^2+dy^2+dz^2), &
92                where dx,dy,dz are grid spacing in X,Y,Z,then they will be clustered together. If you want to nullify the clustering step after generating &
93                basins, simply set this value to 0"
94                read(*,*) mergeattdist
95            else if (isel2==3) then
96                if (numatt<2) then
97                    write(*,*) "Error: At least two attractors must be presented!"
98                    cycle
99                end if
100                write(*,*) "Input the attractors you want to cluster, e.g. 4,5,8,9,22,21"
101                read(*,"(a)") c1000tmp
102                call str2arr(c1000tmp,ntobeclus) !Find how many terms
103                if (allocated(attconvold)) deallocate(attconvold,realattconv,usercluslist)
104                allocate(attconvold(-2:numatt),realattconv(-2:numrealatt),usercluslist(ntobeclus))
105                realattconv(-2)=-2
106                realattconv(-1)=-1
107                realattconv(0)=0
108                call str2arr(c1000tmp,ntobeclus,usercluslist)
109                call sorti4(usercluslist)
110                attconvold=attconv
111                idesrealatt=usercluslist(1)
112                do itmp=2,ntobeclus
113                    irealatt=usercluslist(itmp)
114                    do jtmp=1,nrealatthas(irealatt)
115                        iatt=realatttable(irealatt,jtmp)
116                        attconv(iatt)=idesrealatt
117                    end do
118                end do
119                call clusdegenatt(1)
120                realattconv(1)=1
121                do itmp=1,numatt !Build conversion relationship between previous real attractors and new real attractors
122                    if (itmp/=1) then
123                        if (attconvold(itmp)/=attconvold(itmp-1)) realattconv(attconvold(itmp))=attconv(itmp)
124                    end if
125                end do
126                do iz=2,nz-1
127                    do iy=2,ny-1
128                        do ix=2,nx-1
129                            gridbas(ix,iy,iz)=realattconv(gridbas(ix,iy,iz))
130                        end do
131                    end do
132                end do
133                call detectinterbasgrd(6) !Detect interbasin grids
134                write(*,*) "Done!"
135                write(*,*)
136            end if
137        end do
138
139    else if (isel==-5) then !Outout cube file for basins for visualizing interbasin surface
140        write(*,*) "Input the index range of basin"
141        write(*,"(a)") " Inputting 4,6 will output basin 4,5,6 to basin0004.cub, basin0005.cub, basin0006.cub to current folder. Inputting 5,5 will only output basin 5"
142        write(*,"(a)") " Inputting 0,0, will output all basins into basins.cub, the grid value corresponds to basin index"
143        read(*,*) ilow,ihigh
144        if (ilow/=0) then
145            write(*,*) "If output internal region of the basin? (y/n)"
146            read(*,*) selectyn
147        end if
148        if (allocated(cubmattmp)) deallocate(cubmattmp)
149        allocate(cubmattmp(nx,ny,nz))
150        do ibas=ilow,ihigh
151            if (ilow/=0) then
152                write(basinfilename,"('basin',i4.4,'.cub')") ibas
153                write(*,"(' Outputting basin',i8,' as ',a)") ibas,trim(basinfilename)
154                cubmattmp=gridbas(:,:,:)
155                where(cubmattmp/=ibas)
156                    cubmattmp=0
157                elsewhere
158                    cubmattmp=1
159                end where
160                if (selectyn=='n') where (interbasgrid .eqv. .false.) cubmattmp=0
161            else
162                write(*,*) "Outputting basin.cub..."
163                write(basinfilename,"('basin.cub')")
164                cubmattmp=gridbas(:,:,:)
165            end if
166            open(10,file=basinfilename,status="replace")
167            write(10,"(' Generated by Multiwfn')")
168            write(10,"(' Totally ',i12,' grid points')") nx*ny*nz
169            write(10,"(i5,3f12.6)") ncenter,orgx,orgy,orgz
170            write(10,"(i5,3f12.6)") nx,dx,0.0,0.0
171            write(10,"(i5,3f12.6)") ny,0.0,dy,0.0
172            write(10,"(i5,3f12.6)") nz,0.0,0.0,dz
173            do icenter=1,ncenter
174                write(10,"(i5,4f12.6)") a(icenter)%index,a(icenter)%charge,a(icenter)%x,a(icenter)%y,a(icenter)%z
175            end do
176            do ix=1,nx
177                do iy=1,ny
178                    write(10,"(6(1PE13.5))",advance="no") cubmattmp(ix,iy,1:nz)
179                    write(10,*)
180                end do
181            end do
182            close(10)
183        end do
184        deallocate(cubmattmp)
185        if (ilow/=0) then
186            write(*,"(a)") " Done! Cube files for the selected basins have been outputted to current folder"
187            write(*,"(a)") " The value 1 and 0 in the files denote the corresponding point belongs and not belongs to the basin, &
188            respectively. You can plot such as the isosurface with isovalue=0.5 to visualize the basins"
189        else
190            write(*,"(a)") " Done! basin.cub has been outputted to current folder. The grid values correspond to basin index"
191        end if
192
193    else if (isel==-4) then
194        open(10,file="attractors.pdb",status="replace")
195        do iatt=1,numatt
196            write(10,"(a6,i5,1x,a4,1x,a3, 1x,a1,i4,4x,3f8.3,2f6.2,10x,a2)") "HETATM",iatt,' '//"C "//' ',"ATT",'A',attconv(iatt),attxyz(iatt,:)*b2a,1.0,0.0,"C "
197        end do
198        close(10)
199        write(*,*) "Done, all attractors have been exported to attractors.pdb in current folder"
200        write(*,*) "Note: The residue indices in the pdb file correspond to attractor indices"
201
202    else if (isel==-3) then
203        write(*,*) "  Attractor       X,Y,Z coordinate (Angstrom)            Value"
204        do irealatt=1,numrealatt
205            write(*,"(i8,3f14.8,1E18.9)") irealatt,realattxyz(irealatt,1:3)*b2a,realattval(irealatt)
206        end do
207        do irealatt=1,numrealatt
208            if (nrealatthas(irealatt)/=1) then
209                write(*,*)
210                write(*,"(' The members of degenerate attractor',i6,':')") irealatt
211                do itmp=1,nrealatthas(irealatt)
212                    iatt=realatttable(irealatt,itmp)
213                    write(*,"(i8,'  XYZ:',3f13.7,'  Value:',1E18.9)") iatt,attxyz(iatt,:)*b2a,attval(iatt)
214                end do
215            end if
216        end do
217
218    else if (isel==-2) then
219        write(*,*) "q = Quit. Selection method:"
220        write(*,*) "a? = Atom ?"
221        write(*,*) "c? = Attractor ? (If the attractor is degenerate, average coordinate is used)"
222        write(*,*) "d? = Attractor ? (Only for degenerate attractors, cycle each of its members)"
223        write(*,*) "For example:"
224        write(*,*) """a1 c3"" returns the distance between atom1 and att.3"
225        write(*,*) """a4 a2"" returns the distance between atom4 and atom2"
226        write(*,*) """c6 a2 a5"" returns the angle of att.6-atom2-atom5"
227        write(*,*) """c2 c4 a3 c7"" returns the dihedral angle of att.2-att.4-atom3-att.7"
228        write(*,*) """d3 a1"" returns the distance between members of att.3 and atom1"
229        write(*,"(a)") " ""d3 a1 c2"" returns the the angle of (members of att.3)--atom1--att.2, &
230        meanwhile outputs the vertical distance from (members of att.3) to the line linking atom1 and att.2"
231        do while(.true.)
232            read(*,"(a)") c80tmp
233            c80tmp=adjustl(c80tmp)
234            imeasure=0
235            do ichar=1,len_trim(c80tmp) !imeasure=1/2/3: measure distance,angle,dihedral
236                if (c80tmp(ichar:ichar)==','.or.c80tmp(ichar:ichar)==' ') imeasure=imeasure+1
237            end do
238            nelement=0 !Validate "d" selection
239            do ichar=1,len_trim(c80tmp)
240                if (c80tmp(ichar:ichar)=='d') nelement=nelement+1
241            end do
242            if (nelement/=0) then
243                if (c80tmp(1:1)/='d'.or.nelement>1) then
244                    write(*,*) "Error: ""d"" type of selection can only occur once and must be the first term"
245                    cycle
246                else if (imeasure==3) then
247                    write(*,*) "Error: Dihedral angle calculation doesn't support ""d"" type of selection"
248                    cycle
249                end if
250            end if
251
252            if (c80tmp(1:1)=='q') then
253                exit
254            else if (imeasure==1.or.imeasure==2.or.imeasure==3) then
255                if (imeasure==1) read(c80tmp,*) ctmp1,ctmp2 !Read two terms
256                if (imeasure==2) read(c80tmp,*) ctmp1,ctmp2,ctmp3 !Read three terms
257                if (imeasure==3) read(c80tmp,*) ctmp1,ctmp2,ctmp3,ctmp4 !Read four terms
258
259                if (ctmp1(1:1)=='a') then
260                    read(ctmp1(2:),*) iatm
261                    tmpx1=a(iatm)%x
262                    tmpy1=a(iatm)%y
263                    tmpz1=a(iatm)%z
264                else if (ctmp1(1:1)=='c') then
265                    read(ctmp1(2:),*) irealatt
266                    tmpx1=realattxyz(irealatt,1)
267                    tmpy1=realattxyz(irealatt,2)
268                    tmpz1=realattxyz(irealatt,3)
269                else if (ctmp1(1:1)=='d') then
270                    read(ctmp1(2:),*) irealattde
271                end if
272                if (ctmp2(1:1)=='a') then
273                    read(ctmp2(2:),*) iatm
274                    tmpx2=a(iatm)%x
275                    tmpy2=a(iatm)%y
276                    tmpz2=a(iatm)%z
277                else if (ctmp2(1:1)=='c') then
278                    read(ctmp2(2:),*) irealatt
279                    tmpx2=realattxyz(irealatt,1)
280                    tmpy2=realattxyz(irealatt,2)
281                    tmpz2=realattxyz(irealatt,3)
282                end if
283
284                if (imeasure==1) then
285                    if (ctmp1(1:1)/='d') then
286                        write(*,"(' The distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") &
287                        dsqrt((tmpx1-tmpx2)**2+(tmpy1-tmpy2)**2+(tmpz1-tmpz2)**2),dsqrt((tmpx1-tmpx2)**2+(tmpy1-tmpy2)**2+(tmpz1-tmpz2)**2)*b2a
288                    else if (ctmp1(1:1)=='d') then
289                        distmin=9999999
290                        distmax=-1
291                        distavg=0
292                        do itmp=1,nrealatthas(irealattde)
293                            iatt=realatttable(irealattde,itmp)
294                            tmpx1=attxyz(iatt,1)
295                            tmpy1=attxyz(iatt,2)
296                            tmpz1=attxyz(iatt,3)
297                            distnow=dsqrt((tmpx1-tmpx2)**2+(tmpy1-tmpy2)**2+(tmpz1-tmpz2)**2)
298                            distavg=distavg+distnow
299                            if (distnow<distmin) distmin=distnow
300                            if (distnow>distmax) distmax=distnow
301                        end do
302                        distavg=distavg/nrealatthas(irealattde)
303                        write(*,"(' Note: Attractor',i6,' has',i6,' members')") irealattde,nrealatthas(irealattde)
304                        write(*,"(' The minimum distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") distmin,distmin*b2a
305                        write(*,"(' The maximum distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") distmax,distmax*b2a
306                        write(*,"(' The average distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") distavg,distavg*b2a
307                    end if
308                end if
309
310                if (imeasure==2.or.imeasure==3) then !Analyze one more term, then print angle
311                    if (ctmp3(1:1)=='a') then
312                        read(ctmp3(2:),*) iatm
313                        tmpx3=a(iatm)%x
314                        tmpy3=a(iatm)%y
315                        tmpz3=a(iatm)%z
316                    else if (ctmp3(1:1)=='c') then
317                        read(ctmp3(2:),*) irealatt
318                        tmpx3=realattxyz(irealatt,1)
319                        tmpy3=realattxyz(irealatt,2)
320                        tmpz3=realattxyz(irealatt,3)
321                    end if
322                end if
323                if (imeasure==2) then
324                    if (ctmp1(1:1)/='d') then
325                        write(*,"(' The angle is',f12.6,' degree')") xyz2angle(tmpx1,tmpy1,tmpz1,tmpx2,tmpy2,tmpz2,tmpx3,tmpy3,tmpz3)
326                    else if (ctmp1(1:1)=='d') then
327                        angmin=180
328                        angmax=-1
329                        angavg=0
330                        distmin=999999
331                        distmax=-1
332                        distavg=0
333                        prjx=0
334                        prjy=0
335                        prjz=0
336                        do itmp=1,nrealatthas(irealattde)
337                            iatt=realatttable(irealattde,itmp)
338                            tmpx1=attxyz(iatt,1)
339                            tmpy1=attxyz(iatt,2)
340                            tmpz1=attxyz(iatt,3)
341                            angnow=xyz2angle(tmpx1,tmpy1,tmpz1,tmpx2,tmpy2,tmpz2,tmpx3,tmpy3,tmpz3)
342                            angavg=angavg+angnow
343                            if (angnow<angmin) angmin=angnow
344                            if (angnow>angmax) angmax=angnow
345                            distnow=potlinedis(tmpx1,tmpy1,tmpz1,tmpx2,tmpy2,tmpz2,tmpx3,tmpy3,tmpz3)
346                            distavg=distavg+distnow
347                            if (distnow<distmin) distmin=distnow
348                            if (distnow>distmax) distmax=distnow
349                            call pointprjline(tmpx1,tmpy1,tmpz1,tmpx2,tmpy2,tmpz2,tmpx3,tmpy3,tmpz3,prjxtmp,prjytmp,prjztmp)
350                            prjx=prjx+prjxtmp
351                            prjy=prjy+prjytmp
352                            prjz=prjz+prjztmp
353                        end do
354                        angavg=angavg/nrealatthas(irealattde)
355                        distavg=distavg/nrealatthas(irealattde)
356                        prjx=prjx/nrealatthas(irealattde)
357                        prjy=prjy/nrealatthas(irealattde)
358                        prjz=prjz/nrealatthas(irealattde)
359                        write(*,"(' Note: Attractor',i6,' has',i6,' members')") irealattde,nrealatthas(irealattde)
360                        write(*,"(' The minimum angle is',f12.6,' degree')") angmin
361                        write(*,"(' The maximum angle is',f12.6,' degree')") angmax
362                        write(*,"(' The average angle is',f12.6,' degree')") angavg
363                        write(*,"(' The minimum distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") distmin,distmin*b2a
364                        write(*,"(' The maximum distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") distmax,distmax*b2a
365                        write(*,"(' The average distance is',f12.6,' Bohr (',f12.6 ' Angstrom)')") distavg,distavg*b2a
366                        write(*,"(' The average X,Y,Z coordinate by projecting the members of ',a,' to the line linking ',a,' and ',a)") trim(ctmp1),trim(ctmp2),trim(ctmp3)
367                        write(*,"(3f14.8,'   Angstrom')") prjx*b2a,prjy*b2a,prjz*b2a
368                    end if
369                end if
370
371                if (imeasure==3) then !Analyze one more term, then print dihedral angle
372                    if (ctmp4(1:1)=='a') then
373                        read(ctmp4(2:),*) iatm
374                        tmpx4=a(iatm)%x
375                        tmpy4=a(iatm)%y
376                        tmpz4=a(iatm)%z
377                    else if (ctmp4(1:1)=='c') then
378                        read(ctmp4(2:),*) irealatt
379                        tmpx4=realattxyz(irealatt,1)
380                        tmpy4=realattxyz(irealatt,2)
381                        tmpz4=realattxyz(irealatt,3)
382                    end if
383                    write(*,"(' The dihedral angle is',f12.6,' degree')") xyz2dih(tmpx1,tmpy1,tmpz1,tmpx2,tmpy2,tmpz2,tmpx3,tmpy3,tmpz3,tmpx4,tmpy4,tmpz4)
384                end if
385            else
386                write(*,*) "Error: Invalid input"
387            end if
388        end do
389
390    else if (isel==-1) then
391        write(*,*) "1: On-grid method, Comput .Mat. Sci., 36, 354 (2006)"
392        write(*,*) "2: Near-grid method, J. Phys.: Condens. Matter, 21, 08420 (2009)"
393        write(*,*) "3: Near-grid method with boundary refinement step"
394        write(*,"(a)") " Note: Near-grid method (adapted by Tian Lu) is more accurate than On-grid method and thus is more recommended; with the boundary refinement step, the result will be better"
395        read(*,*) igridmethod
396
397    else if (isel==0) then
398        ioldtextheigh=textheigh
399        textheigh=40 !Default textheigh is too small
400        textheigh=ioldtextheigh
401
402    else if (isel==1) then
403        isourcedata=1 !Default status is calculating grid data here
404        if (allocated(cubmat)) then
405            write(*,"(a)") " Note: There has been a grid data in the memory, please select generating the basins by which manner"
406            write(*,*) "0 Return"
407            write(*,*) "1 Generate the basins by selecting a real space function"
408            write(*,*) "2 Generate the basins by using the grid data stored in memory"
409            read(*,*) isourcedata
410        end if
411        if (isourcedata==0) then
412            cycle
413        else if (isourcedata==1) then
414            write(*,*) "Select the real space function to be integrated"
415            call selfunc_interface(ifuncbasin)
416            call setgridforbasin(ifuncbasin)
417            if (allocated(cubmat)) deallocate(cubmat)
418            allocate(cubmat(nx,ny,nz))
419            call savecubmat(ifuncbasin,0,iorbsel)
420        else if (isourcedata==2) then
421            ifuncbasin=1 !I assume that the file loaded records electron density
422            write(*,"('The range of x is from ',f12.6,' to ',f12.6,' Bohr,' i5,' points')") ,orgx,orgx+(nx-1)*dx,nx
423            write(*,"('The range of y is from ',f12.6,' to ',f12.6,' Bohr,',i5,' points')") ,orgy,orgy+(ny-1)*dy,ny
424            write(*,"('The range of z is from ',f12.6,' to ',f12.6,' Bohr,',i5,' points')") ,orgz,orgz+(nz-1)*dz,nz
425            write(*,"('Total number of grid points is ',i10)") nx*ny*nz
426            write(*,"('Grid spacing in X,Y,Z (Bohr):',3f12.6)") dx,dy,dz
427        end if
428
429        allocate(grdposneg(nx,ny,nz)) !Record which grids have negative value
430        grdposneg=.true.
431        do iz=1,nz
432            do iy=1,ny
433                do ix=1,nx
434                    if (cubmat(ix,iy,iz)<0D0) then
435                        grdposneg(ix,iy,iz)=.false.
436                        cubmat(ix,iy,iz)=-cubmat(ix,iy,iz)
437                    end if
438                end do
439            end do
440        end do
441!         where (cubmat<0D0)  !DO NOT USE THIS, because I found that "where" will consuming vary large amount of memory!
442!             grdposneg=.false.
443!             cubmat=-cubmat !Invert negative values to positive, after basins are generated the values will be recovered
444!         end where
445        if (allocated(gridbas)) deallocate(gridbas)
446        allocate(gridbas(nx,ny,nz))
447        call setupmovevec
448        write(*,*)
449        write(*,*) "Generating basins, please wait..."
450        call walltime(walltime1)
451        CALL CPU_TIME(time_begin)
452        call generatebasin(igridmethod)
453        CALL CPU_TIME(time_end)
454        call walltime(walltime2)
455        write(*,"(' Generating basins took up CPU time',f12.2,'s, wall clock time',i10,'s')") time_end-time_begin,walltime2-walltime1
456        numunassign=count(gridbas(2:nx-1,2:ny-1,2:nz-1)==0)
457        write(*,"(' The number of unassigned grids:',i12)") numunassign
458        numgotobound=count(gridbas(2:nx-1,2:ny-1,2:nz-1)==-1)
459        write(*,"(' The number of grids travelled to box boundary:',i12)") numgotobound
460        where (grdposneg .eqv. .false.) cubmat=-cubmat !Recover original grid data
461        deallocate(grdposneg)
462
463        do iatt=1,numatt !Eliminate the attractors with very low value
464            if ( abs(cubmat(attgrid(iatt,1),attgrid(iatt,2),attgrid(iatt,3)))<threslowvalatt ) then
465                write(*,"(' Note: There are attractors having very low absolute value (<',1PE8.2,') and thus insignificant, how to deal with them?')") threslowvalatt
466                write(*,*) "1 Do nothing"
467                write(*,*) "2 Set corresponding grids as unassigned status"
468                write(*,*) "3 Assign corresponding grids to the nearest significant attractors"
469                write(*,*) "Hint: For most cases, option 3 is recommended"
470                read(*,*) isel2
471                call elimlowvalatt(threslowvalatt,isel2)
472                exit
473            end if
474        end do
475
476        !Generate actual coordinate of attractors, which will be used to plot in the local GUI, and in any other external GUIs
477        if (allocated(attxyz)) deallocate(attxyz,attval)
478        allocate(attxyz(numatt,3),attval(numatt))
479        do iatt=1,numatt
480            ix=attgrid(iatt,1)
481            iy=attgrid(iatt,2)
482            iz=attgrid(iatt,3)
483            attxyz(iatt,1)=orgx+(ix-1)*dx
484            attxyz(iatt,2)=orgy+(iy-1)*dy
485            attxyz(iatt,3)=orgz+(iz-1)*dz
486            attval(iatt)=cubmat(ix,iy,iz)
487        end do
488        !Currently attractors have been finally determined, one shouldn't perturb them further more
489
490        call clusdegenatt(0) !Cluster degenerate attractors as "real attractors" and calculate average coordinate and value for the real attractors
491
492        call detectinterbasgrd(6) !Detect interbasin grids
493        numinterbas=count(interbasgrid .eqv. .true.)
494        write(*,"(' The number of interbasin grids:',i12)") numinterbas
495
496    else if (isel==2) then
497        call integratebasin
498
499    else if (isel==3.or.isel==4.or.isel==5.or.isel==7.or.isel==-7.or.isel==8) then
500        if (.not.allocated(b)) then
501            write(*,"(a)") " Note: No GTF (gauss type function) information is available in your input file, please input the file &
502            containing GTF information of your system, such as .wfn/.wfx and .fch file. e.g. c:\abc.wfn"
503            read(*,"(a)") c200tmp
504            call readinfile(c200tmp,1)
505        end if
506        if (isel==3) then
507            call multipolebasin
508        else if (isel==4) then
509            call LIDIbasin(0)
510        else if (isel==5) then
511            call LIDIbasin(1)
512        else if (isel==7) then
513            write(*,*) "0 Return"
514            write(*,*) "1 Integrate a specific function with atomic-center + uniform grids"
515            write(*,*) "2 The same as 1, but with exact refinement of basin boundary"
516            write(*,*) "3 The same as 2, but with approximate refinement of basin boundary"
517            write(*,*) "Hint:"
518            write(*,*) "Accuracy: 2>=3>>1     Time spent: 2>3>>1     Memory requirement: 3>2=1"
519    !         write(*,*) "Robost: 1=2>3"
520            read(*,*) iseltmp
521            call integratebasinmix(iseltmp)
522        else if (isel==-7) then
523            call integratebasinmix_LSB
524        else if (isel==8) then
525            call integratebasinmix(10)
526        end if
527
528!     else if (isel==6) then
529!         call integratebasinrefine
530    else if (isel==9) then
531        call atmpopinbasin
532    end if
533end do
534
535end subroutine
536
537
538
539!!---- setup move vector and move length for the 26 neighbour
540subroutine setupmovevec
541use defvar
542use basinintmod
543vec26x=0
544vec26y=0
545vec26z=0
546!The nearest neighbours:
547len26(1:2)=dx
548vec26x(1)=1
549vec26x(2)=-1
550len26(3:4)=dy
551vec26y(3)=1
552vec26y(4)=-1
553len26(5:6)=dz
554vec26z(5)=1
555vec26z(6)=-1
556!On the edges:
557len26(7:10)=dsqrt(dx*dx+dy*dy)
558vec26x(7)=1
559vec26y(7)=1
560vec26x(8)=-1
561vec26y(8)=1
562vec26x(9)=-1
563vec26y(9)=-1
564vec26x(10)=1
565vec26y(10)=-1
566len26(11:14)=dsqrt(dx*dx+dz*dz)
567vec26x(11)=1
568vec26z(11)=1
569vec26x(12)=-1
570vec26z(12)=1
571vec26x(13)=-1
572vec26z(13)=-1
573vec26x(14)=1
574vec26z(14)=-1
575len26(15:18)=dsqrt(dy*dy+dz*dz)
576vec26y(15)=1
577vec26z(15)=1
578vec26y(16)=1
579vec26z(16)=-1
580vec26y(17)=-1
581vec26z(17)=-1
582vec26y(18)=-1
583vec26z(18)=1
584!At the vertices:
585len26(19:26)=dsqrt(dx*dx+dy*dy+dz*dz)
586vec26z(19:22)=1
587vec26x(19)=1
588vec26y(19)=1
589vec26x(20)=-1
590vec26y(20)=1
591vec26x(21)=-1
592vec26y(21)=-1
593vec26x(22)=1
594vec26y(22)=-1
595vec26z(23:26)=-1
596vec26x(23)=1
597vec26y(23)=-1
598vec26x(24)=1
599vec26y(24)=1
600vec26x(25)=-1
601vec26y(25)=1
602vec26x(26)=-1
603vec26y(26)=-1
604gridbas=0 !Unassigned state
605gridbas(1,:,:)=-2 !Set status for box boundary grids
606gridbas(nx,:,:)=-2
607gridbas(:,1,:)=-2
608gridbas(:,ny,:)=-2
609gridbas(:,:,1)=-2
610gridbas(:,:,nz)=-2
611end subroutine
612
613
614
615!!------- Generate basins from regular grid
616! igridmethod=1: On grid, Comput.Mat.Sci.,36,354    =2: Near-grid method (slower, but more accurate), see J.Phys.:Condens.Matter,21,084204
617! =3: Near-grid with refinement
618! The near-grid method is improved by Tian Lu, namely at later stage automatically switch to on-grid method to guarantee convergence
619subroutine generatebasin(igridmethod)
620use defvar
621use basinintmod
622implicit real*8(a-h,o-z)
623integer,parameter :: nmaxtrjgrid=3000
624integer igridmethod
625integer ntrjgrid !Recording trjgrid contains how many elements now
626integer trjgrid(nmaxtrjgrid,3) !The trajectory contains which grids, record their indices sequentially, trjgrid(i,1/2/3) = ix/iy/iz of the ith grid
627! real*8 trjval(nmaxtrjgrid),gradmaxval(nmaxtrjgrid) !******For debugging******
628if (allocated(attgrid)) deallocate(attgrid)
629allocate(attgrid(nint(nx*ny*nz/20D0),3)) !I think the number of attractors in general is impossible to exceeds nx*ny*nz/20
630numatt=0
631write(*,*) "  Attractor       X,Y,Z coordinate (Angstrom)                Value"
632!Cycle all grids, but the box boundary ones are ignored (due to gridbas=-2), since can't evalute its gradients in all directions by finite difference
633
634nsteplimit=min( nmaxtrjgrid,nint(dsqrt(dfloat(nx*nx+ny*ny+nz*nz))*2) )
635nstepdiscorr=nint(nsteplimit/2D0)
636if (igridmethod==1) then
6371    continue
638nthreads=getNThreads()
639!$OMP PARALLEL DO private(ix,iy,iz,ntrjgrid,inowx,inowy,inowz,trjgrid,valnow,imove,gradtmp,igradmax,gradmax,iatt,itrjgrid,idtmp) &
640!$OMP shared(gridbas,numatt,attgrid) schedule(DYNAMIC) NUM_THREADS(nthreads)
641    do iz=2,nz-1
642        do iy=2,ny-1
643            do ix=2,nx-1
644                if (gridbas(ix,iy,iz)/=0) cycle
645!                 if (interbasgrid(ix,iy,iz) .eqv. .false.) cycle
646                ntrjgrid=0
647                inowx=ix
648                inowy=iy
649                inowz=iz
650                do while(.true.) !Steepest ascent
651                    ntrjgrid=ntrjgrid+1
652                    if (ntrjgrid>nsteplimit) exit !Unconverged. The gridbas for these unassigned grids will still be 0
653                    trjgrid(ntrjgrid,1)=inowx
654                    trjgrid(ntrjgrid,2)=inowy
655                    trjgrid(ntrjgrid,3)=inowz
656                    !Test all 26 directions to find out the maximal gradient direction
657                    valnow=cubmat(inowx,inowy,inowz)
658                    do imove=1,26
659                        gradtmp=(cubmat(inowx+vec26x(imove),inowy+vec26y(imove),inowz+vec26z(imove))-valnow)/len26(imove)
660                        if (imove==1.or.gradtmp>gradmax) then
661                            igradmax=imove
662                            gradmax=gradtmp
663                        end if
664                    end do
665                    !Test if this is an attractor, if yes, assign all grid in this trajectory
666                    if (gradmax<=0) then !Equal sign is important, because when system has symmetry, adjacent grid may be degenerate about mirrow plane, now the ascent should be terminated
667                        if (valnow==0D0) exit !The region far beyond system, the value may be exactly zero due to cutoff of exponent, these grids shouldn't be regarded as attractors
668!$OMP CRITICAL
669cyciatt3:                do iatt=1,numatt
670                            if (inowx==attgrid(iatt,1).and.inowy==attgrid(iatt,2).and.inowz==attgrid(iatt,3)) then
671                                do itrjgrid=1,ntrjgrid
672                                    gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=iatt
673                                end do
674                                exit cyciatt3
675                            end if
676                            do imove=1,26
677                                if (inowx+vec26x(imove)==attgrid(iatt,1).and.inowy+vec26y(imove)==attgrid(iatt,2).and.inowz+vec26z(imove)==attgrid(iatt,3)) then
678                                    do itrjgrid=1,ntrjgrid
679                                        gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=iatt
680                                    end do
681                                    exit cyciatt3
682                                end if
683                            end do
684                        end do cyciatt3
685                        if (iatt>numatt) then !A new attractor, iatt=numatt+1 currently
686                            numatt=numatt+1
687                            do itrjgrid=1,ntrjgrid
688                                gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=numatt
689                            end do
690                            attgrid(numatt,1)=inowx
691                            attgrid(numatt,2)=inowy
692                            attgrid(numatt,3)=inowz
693                            if (grdposneg(inowx,inowy,inowz) .eqv. .true.) then
694                                write(*,"(i8,3f14.8,f20.8)") numatt,(orgx+(inowx-1)*dx)*b2a,(orgy+(inowy-1)*dy)*b2a,(orgz+(inowz-1)*dz)*b2a,cubmat(inowx,inowy,inowz)
695                            else !This grid should has negative value
696                                write(*,"(i8,3f14.8,f20.8)") numatt,(orgx+(inowx-1)*dx)*b2a,(orgy+(inowy-1)*dy)*b2a,(orgz+(inowz-1)*dz)*b2a,-cubmat(inowx,inowy,inowz)
697                            end if
698                        end if
699!$OMP end CRITICAL
700                        exit
701                    end if
702                    !Move to next grid
703                    inowx=inowx+vec26x(igradmax)
704                    inowy=inowy+vec26y(igradmax)
705                    inowz=inowz+vec26z(igradmax)
706                    !Test if this grid has already been assigned
707                    idtmp=gridbas(inowx,inowy,inowz)
708                    if (idtmp>0) then
709                        do itrjgrid=1,ntrjgrid
710                            gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=idtmp
711                        end do
712                        exit
713                    end if
714                    !Test if encountered box boundary
715                    if (inowx==1.or.inowx==nx.or.inowy==1.or.inowy==ny.or.inowz==1.or.inowz==nz) then
716                        do itrjgrid=1,ntrjgrid
717                            gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=-1
718                        end do
719                        exit
720                    end if
721                end do !End ascent
722            end do !End cycle x
723        end do !End cycle y
724    end do !End cycle z
725!$OMP END PARALLEL DO
726
727else if (igridmethod==2.or.igridmethod==3) then
728nthreads=getNThreads()
729!$OMP PARALLEL DO private(ix,iy,iz,corrx,corry,corrz,ntrjgrid,inowx,inowy,inowz,trjgrid,valnow,imove,gradtmp,igradmax,gradmax,iatt,&
730!$OMP itrjgrid,idtmp,icorrx,icorry,icorrz,gradx,grady,gradz,sclgrad,ineiidx) shared(gridbas,numatt,attgrid) schedule(DYNAMIC) NUM_THREADS(nthreads)
731    do iz=2,nz-1
732        do iy=2,ny-1
733            do ix=2,nx-1
734                if (gridbas(ix,iy,iz)/=0) cycle
735                ntrjgrid=0
736                inowx=ix
737                inowy=iy
738                inowz=iz
739                corrx=0D0 !Correction vector
740                corry=0D0
741                corrz=0D0
742                do while(.true.) !Steepest ascent
743                    ntrjgrid=ntrjgrid+1
744                    trjgrid(ntrjgrid,1)=inowx
745                    trjgrid(ntrjgrid,2)=inowy
746                    trjgrid(ntrjgrid,3)=inowz
747                    if (ntrjgrid>nsteplimit) then !These gridbas for these unconverged grids will still be 0
748!                         do itmp=1,ntrjgrid-1 !******For debugging******
749!                             write(*,"(i5,3i6,2f16.10)") itmp,trjgrid(itmp,1:3),trjval(itmp),gradmaxval(itmp)
750!                         end do
751                        exit
752                    end if
753                    !Test all 26 directions to find out the maximal gradient direction
754                    valnow=cubmat(inowx,inowy,inowz)
755                    do imove=1,26
756                        gradtmp=(cubmat(inowx+vec26x(imove),inowy+vec26y(imove),inowz+vec26z(imove))-valnow)/len26(imove)
757                        if (imove==1.or.gradtmp>gradmax) then
758                            igradmax=imove
759                            gradmax=gradtmp
760                        end if
761                    end do
762!                      write(*,"(3i5,2f14.8)") inowx,inowy,inowz,gradmax,valnow !Trace the trajectory !******For debugging******
763                    if (gradmax<=0D0) then !Equal sign is important, because when system has symmetry, adjacent grid may be degenerate about mirrow plane, now the ascent should be terminated
764                        if (valnow==0D0) exit !The region far beyond system, the value may be exactly zero due to cutoff of exponent, these grids shouldn't be regarded as attractors
765!$OMP CRITICAL
766cyciatt:                do iatt=1,numatt
767                            !Test if current grid is attractor iatt, is yes, assign all grid in this trajectory
768                            if (inowx==attgrid(iatt,1).and.inowy==attgrid(iatt,2).and.inowz==attgrid(iatt,3)) then
769                                do itrjgrid=1,ntrjgrid
770                                    gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=iatt
771                                end do
772                                exit cyciatt
773                            end if
774                            !Test if neighbour grid (+/-x,+/-y,+/-z) is attractor iatt, is yes, assign all grid in this trajectory
775                            !The reason I do this is because when the points are symmetric to Cartesian plane, many adjacent and degenerate attractors will occur,&
776                            !while this treatment can combine them as a single one
777                            do imove=1,26
778                                if (inowx+vec26x(imove)==attgrid(iatt,1).and.inowy+vec26y(imove)==attgrid(iatt,2).and.inowz+vec26z(imove)==attgrid(iatt,3)) then
779                                    do itrjgrid=1,ntrjgrid
780                                        gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=iatt
781                                    end do
782                                    exit cyciatt
783                                end if
784                            end do
785                        end do cyciatt
786                        !A new attractor
787                        if (iatt==numatt+1) then
788                            numatt=numatt+1
789                            do itrjgrid=1,ntrjgrid
790                                gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=numatt
791                            end do
792                            attgrid(numatt,1)=inowx
793                            attgrid(numatt,2)=inowy
794                            attgrid(numatt,3)=inowz
795                            if (grdposneg(inowx,inowy,inowz) .eqv. .true.) then
796                                write(*,"(i8,3f14.8,f20.8)") numatt,(orgx+(inowx-1)*dx)*b2a,(orgy+(inowy-1)*dy)*b2a,(orgz+(inowz-1)*dz)*b2a,cubmat(inowx,inowy,inowz)
797                            else !This grid should has negative value
798                                write(*,"(i8,3f14.8,f20.8)") numatt,(orgx+(inowx-1)*dx)*b2a,(orgy+(inowy-1)*dy)*b2a,(orgz+(inowz-1)*dz)*b2a,-cubmat(inowx,inowy,inowz)
799                            end if
800                        end if
801!$OMP end CRITICAL
802                        exit
803                    end if
804                    !Correction step may lead to oscillator when encountering circular ELF/LOL attractor, so if the current number of step is already large
805                    !(larger than half of upper limit of step number), then correction will be disabled (namely switch to on-grid method) to guarantee convergence.
806                    if ( ntrjgrid<nstepdiscorr .and. (abs(corrx)>(dx/2D0).or.abs(corry)>(dy/2D0).or.abs(corrz)>(dz/2D0)) ) then !This time we do correction step
807                        if (abs(corrx)>(dx/2D0)) then
808                            icorrx=nint(corrx/abs(corrx)) !Get sign of corrx
809                            inowx=inowx+icorrx
810                            corrx=corrx-icorrx*dx
811                        end if
812                        if (abs(corry)>(dy/2D0)) then
813                            icorry=nint(corry/abs(corry))
814                            inowy=inowy+icorry
815                            corry=corry-icorry*dy
816                        end if
817                        if (abs(corrz)>(dz/2D0)) then
818                            icorrz=nint(corrz/abs(corrz))
819                            inowz=inowz+icorrz
820                            corrz=corrz-icorrz*dz
821                        end if
822                    else !Move to next grid according to maximal gradient and then update correction vector
823                        !Calculate true gradient
824                        gradx=(cubmat(inowx+1,inowy,inowz)-cubmat(inowx-1,inowy,inowz))/(2*dx)
825                        grady=(cubmat(inowx,inowy+1,inowz)-cubmat(inowx,inowy-1,inowz))/(2*dy)
826                        gradz=(cubmat(inowx,inowy,inowz+1)-cubmat(inowx,inowy,inowz-1))/(2*dz)
827                        sclgrad=min(dx/abs(gradx),dy/abs(grady),dz/abs(gradz))
828                        inowx=inowx+vec26x(igradmax)
829                        inowy=inowy+vec26y(igradmax)
830                        inowz=inowz+vec26z(igradmax)
831                        corrx=corrx+gradx*sclgrad-vec26x(igradmax)*dx
832                        corry=corry+grady*sclgrad-vec26y(igradmax)*dy
833                        corrz=corrz+gradz*sclgrad-vec26z(igradmax)*dz
834!                         if (abs(corrx)>(dx/2D0).or.abs(corry)>(dy/2D0).or.abs(corrz)>(dz/2D0)) cycle
835                    end if
836                    !Test if this grid has already been assigned and all of the neighbours were also assigned to the same attractor
837                    idtmp=gridbas(inowx,inowy,inowz)
838                    if (idtmp>0) then
839                        do imove=1,26
840                            ineiidx=gridbas(inowx+vec26x(imove),inowy+vec26y(imove),inowz+vec26z(imove))
841                            if (ineiidx/=idtmp) exit
842                        end do
843                        if (imove==27) then
844                            do itrjgrid=1,ntrjgrid
845                                gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=idtmp
846                            end do
847                            exit
848                        end if
849                    end if
850                    !Test if encountered box boundary
851                    if (inowx==1.or.inowx==nx.or.inowy==1.or.inowy==ny.or.inowz==1.or.inowz==nz) then
852                        do itrjgrid=1,ntrjgrid
853                            gridbas(trjgrid(itrjgrid,1),trjgrid(itrjgrid,2),trjgrid(itrjgrid,3))=-1
854                        end do
855                        exit
856                    end if
857                end do !End ascent
858            end do !End cycle x
859        end do !End cycle y
860    end do !End cycle z
861!$OMP END PARALLEL DO
862
863    !!!!   Refining the basin boundary
864    if (igridmethod==3) then
865!         do itime=1,3 !Refine one time in general is sufficient
866        write(*,*) "Detecting boundary grids..."
867        call detectinterbasgrd(6) !It seems that using 26 directions to determine boundary grids doesn't bring evident benefit
868        write(*,"(' There are',i12,' grids at basin boundary')") count(interbasgrid .eqv. .true.)
869        write(*,*) "Refining basin boundary..."
870        !Below code is the adapted copy of above near-grid code
871nthreads=getNThreads()
872!$OMP PARALLEL DO private(ix,iy,iz,corrx,corry,corrz,ntrjgrid,inowx,inowy,inowz,valnow,imove,gradtmp,igradmax,gradmax,iatt,&
873!$OMP ineiidx,idtmp,icorrx,icorry,icorrz,gradx,grady,gradz,sclgrad) shared(gridbas,attgrid) schedule(DYNAMIC) NUM_THREADS(nthreads)
874        do iz=2,nz-1
875            do iy=2,ny-1
876                do ix=2,nx-1
877                    if (interbasgrid(ix,iy,iz) .eqv. .false.) cycle
878                    if (gridbas(ix,iy,iz)<=0) cycle !Ignored the ones unassigned or gone to box boundary
879                    ntrjgrid=0
880                    inowx=ix
881                    inowy=iy
882                    inowz=iz
883                    corrx=0D0 !Correction vector
884                    corry=0D0
885                    corrz=0D0
886                    do while(.true.) !Steepest ascent
887                        ntrjgrid=ntrjgrid+1
888                        if (ntrjgrid>nsteplimit) exit
889                        valnow=cubmat(inowx,inowy,inowz)
890                        do imove=1,26
891                            gradtmp=(cubmat(inowx+vec26x(imove),inowy+vec26y(imove),inowz+vec26z(imove))-valnow)/len26(imove)
892                            if (imove==1.or.gradtmp>gradmax) then
893                                igradmax=imove
894                                gradmax=gradtmp
895                            end if
896                        end do
897                        if (gradmax<=0) then !Equal sign is important, because when system has symmetry, adjacent grid may be degenerate about mirrow plane, now the ascent should be terminated
898cyciatt2:                    do iatt=1,numatt
899                                if (inowx==attgrid(iatt,1).and.inowy==attgrid(iatt,2).and.inowz==attgrid(iatt,3)) then
900                                    gridbas(ix,iy,iz)=iatt
901                                    exit cyciatt2
902                                end if
903                                do imove=1,26 !Test if neighbour grid (+/-x,+/-y,+/-z) is attractor iatt
904                                    if (inowx+vec26x(imove)==attgrid(iatt,1).and.inowy+vec26y(imove)==attgrid(iatt,2).and.inowz+vec26z(imove)==attgrid(iatt,3)) then
905                                        gridbas(ix,iy,iz)=iatt
906                                        exit cyciatt2
907                                    end if
908                                end do
909                            end do cyciatt2
910                            if (iatt>numatt) then
911                                write(*,*) "Warning: Found new attractor at refining process!"
912                            end if
913                            exit
914                        end if
915                        if ( ntrjgrid<nstepdiscorr .and. (abs(corrx)>(dx/2D0).or.abs(corry)>(dy/2D0).or.abs(corrz)>(dz/2D0)) ) then !This time we do correction step
916                            if (abs(corrx)>(dx/2D0)) then
917                                icorrx=nint(corrx/abs(corrx)) !Get sign of corrx
918                                inowx=inowx+icorrx
919                                corrx=corrx-icorrx*dx
920                            end if
921                            if (abs(corry)>(dy/2D0)) then
922                                icorry=nint(corry/abs(corry))
923                                inowy=inowy+icorry
924                                corry=corry-icorry*dy
925                            end if
926                            if (abs(corrz)>(dz/2D0)) then
927                                icorrz=nint(corrz/abs(corrz))
928                                inowz=inowz+icorrz
929                                corrz=corrz-icorrz*dz
930                            end if
931                        else !Move to next grid according to maximal gradient and then update correction vector
932                            gradx=(cubmat(inowx+1,inowy,inowz)-cubmat(inowx-1,inowy,inowz))/(2*dx)
933                            grady=(cubmat(inowx,inowy+1,inowz)-cubmat(inowx,inowy-1,inowz))/(2*dy)
934                            gradz=(cubmat(inowx,inowy,inowz+1)-cubmat(inowx,inowy,inowz-1))/(2*dz)
935                            sclgrad=min(dx/abs(gradx),dy/abs(grady),dz/abs(gradz))
936                            inowx=inowx+vec26x(igradmax)
937                            inowy=inowy+vec26y(igradmax)
938                            inowz=inowz+vec26z(igradmax)
939                            corrx=corrx+gradx*sclgrad-vec26x(igradmax)*dx
940                            corry=corry+grady*sclgrad-vec26y(igradmax)*dy
941                            corrz=corrz+gradz*sclgrad-vec26z(igradmax)*dz
942                        end if
943                        idtmp=gridbas(inowx,inowy,inowz)
944                        if (ntrjgrid>60.and.idtmp>0) then !If enable this doesn't affect result detectably, but enabling it will evidently reduce computational cost
945                            do imove=1,26
946                                ineiidx=gridbas(inowx+vec26x(imove),inowy+vec26y(imove),inowz+vec26z(imove))
947                                if (ineiidx/=idtmp) exit
948                            end do
949                            if (imove==27) then
950                                gridbas(ix,iy,iz)=idtmp
951                                exit
952                            end if
953                        end if
954                        if (inowx==1.or.inowx==nx.or.inowy==1.or.inowy==ny.or.inowz==1.or.inowz==nz) exit
955                    end do !End ascent
956                end do !End cycle x
957            end do !End cycle y
958        end do !End cycle z
959!$OMP END PARALLEL DO
960!         end do
961    end if
962
963end if
964end subroutine
965
966
967
968!!------- Eliminate low value attractors and the corresponding basin
969! imode=1 Do nothing
970! imode=2 Set corresponding grids as unassigned status
971! imode=3 Assign corresponding grids to the nearest significant attractors
972subroutine elimlowvalatt(threslowvalatt,imode)
973use defvar
974use basinintmod
975implicit real*8(a-h,o-z)
976integer imode
977real*8 threslowvalatt
978integer highvalatt(numatt)
979integer att2att(-2:numatt) !Convert indices of old attractors to new ones
980integer atttypelist(numatt)
981if (imode==1) then
982    return
983else
984    icounthigh=0
985    atttypelist=0
986    do iatt=1,numatt !Generate list
987        if (abs(cubmat(attgrid(iatt,1),attgrid(iatt,2),attgrid(iatt,3)))>=threslowvalatt) then
988            icounthigh=icounthigh+1
989            highvalatt(icounthigh)=iatt
990            atttypelist(iatt)=1 !high
991        end if
992    end do
993    nlowvalatt=numatt-icounthigh
994    if (imode==2) then
995        do iz=2,nz-1
996            do iy=2,ny-1
997                do ix=2,nx-1
998                    if (atttypelist(gridbas(ix,iy,iz))==0) gridbas(ix,iy,iz)=0
999                end do
1000            end do
1001        end do
1002    else if (imode==3) then
1003        do iz=2,nz-1
1004            rnowz=orgz+(iz-1)*dz
1005            do iy=2,ny-1
1006                rnowy=orgy+(iy-1)*dy
1007                do ix=2,nx-1
1008                    rnowx=orgx+(ix-1)*dx
1009                    if (atttypelist(gridbas(ix,iy,iz))==0) then !Find out which grid belongs to insignificant attractors
1010                        shortmaxsqr=1D20
1011                        do iatt=1,numatt !Will be attribute to the nearest significant attractors
1012                            if (atttypelist(iatt)==1) then
1013                                xatt=orgx+(attgrid(iatt,1)-1)*dx
1014                                yatt=orgy+(attgrid(iatt,2)-1)*dy
1015                                zatt=orgz+(attgrid(iatt,3)-1)*dz
1016                                disttmpsqr=(xatt-rnowx)**2+(yatt-rnowy)**2+(zatt-rnowz)**2
1017                                if (disttmpsqr<shortmaxsqr) then
1018                                    ishortmax=iatt
1019                                    shortmaxsqr=disttmpsqr
1020                                end if
1021                            end if
1022                        end do
1023                        gridbas(ix,iy,iz)=ishortmax
1024                    end if
1025                end do
1026            end do
1027        end do
1028    end if
1029    !Build conversion table between old and new attractors, so that the indices of attractors could be contiguous
1030    att2att=-3
1031    att2att(-2)=-2
1032    att2att(-1)=-1
1033    att2att(0)=0
1034    icount=0
1035    do iatt=1,numatt
1036        if (atttypelist(iatt)==0) cycle
1037        icount=icount+1
1038        att2att(iatt)=icount
1039    end do
1040    numatt=numatt-nlowvalatt
1041    !Update attgrid
1042    do iatt=1,numatt
1043        attgrid(iatt,:)=attgrid(highvalatt(iatt),:)
1044    end do
1045    !Final update of grid attribution
1046    do iz=2,nz-1
1047        do iy=2,ny-1
1048            do ix=2,nx-1
1049                gridbas(ix,iy,iz)=att2att(gridbas(ix,iy,iz))
1050            end do
1051        end do
1052    end do
1053    write(*,"(i6,' insignificant attractors have been eliminated')") nlowvalatt
1054end if
1055end subroutine
1056
1057
1058
1059!!------- !Detect interbasin grids for real attractors
1060!ndir can be 6 and 26, meaning if only primary 6 directions or all 26 directions are used to determine boundary grids
1061subroutine detectinterbasgrd(ndir)
1062use defvar
1063use basinintmod
1064implicit real*8(a-h,o-z)
1065integer ndir
1066if (allocated(interbasgrid)) deallocate(interbasgrid)
1067allocate(interbasgrid(nx,ny,nz))
1068interbasgrid=.false.
1069do iz=2,nz-1
1070    do iy=2,ny-1
1071        do ix=2,nx-1
1072            idxnow=gridbas(ix,iy,iz)
1073            do imove=1,ndir !To reduce the number of interbasin grids and thus speed up displaying, I don't use full 26 direction as criterion
1074                idxmove=gridbas(ix+vec26x(imove),iy+vec26y(imove),iz+vec26z(imove))
1075                if ((idxmove/=idxnow).and.idxmove/=-2) then !This is a grid between two or more basins, and is not adjacent to box boundary
1076                    interbasgrid(ix,iy,iz)=.true.
1077                    exit
1078                end if
1079            end do
1080        end do
1081    end do
1082end do
1083end subroutine
1084
1085
1086
1087!!------- Cluster degenerate and adjacent attractors together
1088!!Nearest neighbour method is used to cluster the attractors, see Leach book p493. Each cluster corresponds to a final attractor
1089!If imode=0, run the whole subroutine; if imode=1, then external attconv is provided, and only some code in this routine is used to make the index contiguous
1090subroutine clusdegenatt(imode)
1091use defvar
1092use basinintmod
1093implicit real*8(a-h,o-z)
1094integer imode
1095integer neleatt,eleatt(numatt) !eleatt(i)=j means the ith element in clustering stage corresponds to actual jth attractor. nclustlist is its total current elements
1096integer passlist(numatt) !if the ith element is 1, means i attractor has passed clustering stage
1097integer ncluster,ncluele(numatt),cluele(numatt,numatt) !cluele(i,4/5/9...) means cluster i has element 4,5,9..., ncluele(i) is current size of cluster i, ncluster is total number of cluster
1098real*8 attdismat(numatt,numatt),attvalmat(numatt,numatt) !Distance matrix and relative value difference matrix of the original attractors
1099distcrit=mergeattdist*dsqrt(dx*dx+dy*dy+dz*dz) !Distance criterion
1100irefined=0 !If 1, that means this combining process takes effects
1101idebugclusdegenatt=0 !If output debug information
1102
1103if (imode==1) goto 2
1104
1105if (allocated(attconv)) deallocate(attconv)
1106allocate(attconv(-2:numatt))
1107do iatt=-2,numatt !First assume that each attractor is a real attractor
1108    attconv(iatt)=iatt
1109end do
1110
1111!Generate difference matrix for distance and relative value
1112attdismat=0D0
1113attvalmat=0D0
1114do iatt=1,numatt
1115    valiatt=attval(iatt)
1116    xiatt=attxyz(iatt,1)
1117    yiatt=attxyz(iatt,2)
1118    ziatt=attxyz(iatt,3)
1119    do jatt=iatt+1,numatt
1120        valjatt=attval(jatt)
1121        xjatt=attxyz(jatt,1)
1122        yjatt=attxyz(jatt,2)
1123        zjatt=attxyz(jatt,3)
1124        distdiff=dsqrt( (xiatt-xjatt)**2+(yiatt-yjatt)**2+(ziatt-zjatt)**2 )
1125        attdismat(iatt,jatt)=distdiff
1126        valdiff=abs((valiatt-valjatt)/valiatt)
1127        attvalmat(iatt,jatt)=valdiff
1128        if (valdiff<valcritclus.and.distdiff<distcrit) irefined=1
1129!         write(10,"(2i5,f16.10)") iatt,jatt,attvalmat(iatt,jatt)
1130    end do
1131end do
1132attdismat=attdismat+transpose(attdismat)
1133attvalmat=attvalmat+transpose(attvalmat)
1134do iatt=1,numatt
1135    attdismat(iatt,iatt)=attdismat(iatt,iatt)/2D0
1136    attvalmat(iatt,iatt)=attvalmat(iatt,iatt)/2D0
1137end do
1138if (irefined==0) then !Nothing to do. Construct real attractor information and then directly return
1139    numrealatt=numatt
1140    if (allocated(nrealatthas)) deallocate(nrealatthas,realattval,realattxyz,realatttable)
1141    allocate(nrealatthas(numrealatt),realattval(numrealatt),realattxyz(numrealatt,3),realatttable(numrealatt,1))
1142    nrealatthas=1
1143    do iatt=1,numatt
1144        realattxyz(iatt,:)=attxyz(iatt,:)
1145        realattval(iatt)=attval(iatt)
1146        realatttable(iatt,1)=iatt
1147    end do
1148    return
1149else
1150    write(*,*) "Degenerate attractors detected, clustering them..."
1151    write(*,"(' Criterion for clustering: Interval <',f8.5,' Bohr, value difference <',f8.5,'%')") distcrit,valcritclus*100
1152end if
1153! do i=1,numatt !Print distance matrix
1154!     do j=1,numatt
1155!         write(10,*) i,j,attdismat(i,j)
1156!     end do
1157! end do
1158
1159!Clustering via nearest neighbour method, and accordingly update conversion list
1160passlist=0
1161do iatt=1,numatt
1162    if (passlist(iatt)==1) cycle
1163    if (count(attdismat(iatt,:)<distcrit)==1) then !This attractor has no neighbour
1164        if (passlist(iatt)==1) cycle
1165        cycle
1166    end if
1167    !Construct mapping table of attractor, capacity is neleatt
1168    neleatt=0 !The number of degenerate attractors in this batch
1169    do jatt=iatt,numatt
1170        if (attvalmat(iatt,jatt)<valcritclus) then
1171            neleatt=neleatt+1
1172            eleatt(neleatt)=jatt
1173            passlist(jatt)=1
1174        end if
1175    end do
1176    if (neleatt==1) cycle !Although this attractor has one or more neighbours, but no other attractor is degenerate with itself, so pass
1177    if (idebugclusdegenatt==1) then
1178        write(*,"(a,i5)") " Attractors in this time of clustering triggered by attractor:",iatt
1179        write(*,"(' The number of initial clusters:',i5,', corresponding to these attractor:')") neleatt
1180        write(*,"(15i5)") eleatt(1:neleatt)
1181    end if
1182
1183    !Start clustering. Now you should forget actual index of attractors. Only consider element 1,2,3...
1184    !Initialize, assume that each element in this batch of degenerate attractors is a cluster
1185    ncluster=neleatt
1186    ncluele(:)=1
1187    do iclu=1,ncluster
1188        cluele(iclu,1)=iclu
1189    end do
1190    ntimeclu=0
1191    do while(.true.) !Gradually clustering until closet distance between any cluster pair is larger than criteria
1192        ntimeclu=ntimeclu+1
1193        imergeclu=0
1194        do iclu=1,ncluster !Note that ncluster remain unchanged, eliminated cluster is simply emptyed but still reserve its index
1195            if (ncluele(iclu)==0) cycle !Has been incorporated to others
1196            shortmax=9999999D0
1197            ishortmax=0
1198            do jclu=iclu+1,ncluster
1199                if (ncluele(jclu)==0) cycle
1200                !Calculate shortest distance between cluster i and j
1201                shortmaxtmp=9999999D0
1202                do ieletmp=1,ncluele(iclu)
1203                    do jeletmp=1,ncluele(jclu)
1204                        iele=cluele(iclu,ieletmp)
1205                        jele=cluele(jclu,jeletmp)
1206                        distele=attdismat(eleatt(iele),eleatt(jele))
1207                        if (distele<shortmaxtmp) shortmaxtmp=distele
1208                    end do
1209                end do
1210                if (shortmaxtmp<shortmax) then !Find out the closest cluster to cluster iclu
1211                    shortmax=shortmaxtmp
1212                    ishortmax=jclu
1213                end if
1214            end do
1215!             write(*,"(i3,f16.6,4i5,i2)") ntimeclu,shortmax,iclu,ishortmax,abs(shortmax<distcrit)
1216            if (shortmax<distcrit) then !Combine cluster ishortmax to cluster iclu
1217                imergeclu=1
1218                newlen=ncluele(iclu)+ncluele(ishortmax)
1219                cluele(iclu,ncluele(iclu)+1:newlen)=cluele(ishortmax,1:ncluele(ishortmax))
1220                ncluele(iclu)=newlen
1221                ncluele(ishortmax)=0 !Empty
1222            end if
1223        end do
1224        if (imergeclu==0) exit !Between all cluster pair the shortmax is longer than distcrit, therefore exit
1225    end do
1226    do iclu=1,ncluster !Update attractor conversion list
1227        if (ncluele(iclu)==0) cycle
1228        if (idebugclusdegenatt==1) then
1229            write(*,"(' Clustering finished after',i5,' times of cycle')") ntimeclu
1230            write(*,"(' Cluster',i5,', deriving from  attractor',i5,', contains:')") iclu,eleatt(iclu)
1231             write(*,"(' Element:  ',15i5)") cluele(iclu,1:ncluele(iclu))
1232            write(*,"(' Attractor:',15i5)") eleatt(cluele(iclu,1:ncluele(iclu)))
1233        end if
1234        do itmp=1,ncluele(iclu)
1235            ielimele=cluele(iclu,itmp)
1236            ielimatt=eleatt(ielimele)
1237            itargetatt=eleatt(iclu)
1238            attconv(ielimatt)=itargetatt
1239        end do
1240    end do
1241end do
1242
1243! do iatt=1,numatt !Print conversion list just after clustering
1244!     write(*,*) iatt,attconv(iatt)
1245! end do
1246!Update attractor conversion list to make the attractor index contiguous, and hence get "real" attractor
1247!e.g. old conversion list, after slash is the new one
1248!   1           1/1
1249!   2           2/2
1250!   ...         2/2
1251!  13           2/2
1252!  14          14/3 <---After above clustering, 14,16,17 will convert to 14. The first new entry at right column always matched corresponding left column, this is guaranteed by above clustering code
1253!  15           2/2
1254!  16          14/3
1255!  17          14/3
1256!  18          18/4
12572 numrealatt=0
1258passlist=0 !Record which attractor has already been converted
1259do iatt=1,numatt
1260    if (passlist(iatt)==1) cycle
1261    numrealatt=numrealatt+1 !Of course, numrealatt always <=iatt, so will not unexpectly overlap data during update conversion list
1262    idestmp=attconv(iatt)
1263    do jatt=iatt,numatt
1264        if (attconv(jatt)==idestmp) then
1265            passlist(jatt)=1
1266            attconv(jatt)=numrealatt
1267        end if
1268    end do
1269end do
1270! do iatt=1,numatt !Print conversion list after reordered
1271!     write(*,*) iatt,attconv(iatt)
1272! end do
1273
1274call updaterealattprop
1275
1276if (imode==1) return
1277!Update basin attribution
1278do iz=2,nz-1
1279    do iy=2,ny-1
1280        do ix=2,nx-1
1281            gridbas(ix,iy,iz)=attconv(gridbas(ix,iy,iz))
1282        end do
1283    end do
1284end do
1285!Output final attractors
1286write(*,*) "The attractors after clustering:"
1287write(*,*) "   Index      Average X,Y,Z coordinate (Angstrom)               Value"
1288do irealatt=1,numrealatt
1289    write(*,"(i8,3f15.8,f20.8)") irealatt,realattxyz(irealatt,:)*b2a,realattval(irealatt)
1290end do
1291end subroutine
1292
1293
1294
1295!!------- Update real attractors' properties (average value, xyz, the number of members)
1296subroutine updaterealattprop
1297use defvar
1298use basinintmod
1299implicit real*8(a-h,o-z)
1300if (allocated(nrealatthas)) deallocate(nrealatthas,realattval,realattxyz,realatttable)
1301allocate(nrealatthas(numrealatt),realattval(numrealatt),realattxyz(numrealatt,3),realatttable(numrealatt,numatt))
1302nrealatthas=0
1303realattval=0D0
1304realattxyz=0D0
1305do iatt=1,numatt
1306    irealatt=attconv(iatt)
1307    nrealatthas(irealatt)=nrealatthas(irealatt)+1
1308    realatttable(irealatt,nrealatthas(irealatt))=iatt
1309    realattxyz(irealatt,:)=realattxyz(irealatt,:)+attxyz(iatt,:)
1310    realattval(irealatt)=realattval(irealatt)+attval(iatt)
1311end do
1312do irealatt=1,numrealatt
1313    realattval(irealatt)=realattval(irealatt)/nrealatthas(irealatt)
1314    realattxyz(irealatt,:)=realattxyz(irealatt,:)/nrealatthas(irealatt)
1315end do
1316end subroutine
1317
1318
1319
1320!!------------------ Set grid for generating basin, adapted from the subroutine "setgrid"
1321subroutine setgridforbasin(ifuncsel)
1322use defvar
1323implicit real*8 (a-h,o-z)
1324integer :: iselexttype=3,ifuncsel
1325real*8 :: molxlen,molylen,molzlen,tmpx,tmpy,tmpz,rhocrit=1D-6
1326real*8 :: gridextdist=5D0,enlarbox=2.1D0,spclowqual=0.2D0,spcmedqual=0.1D0,spchighqual=0.06D0,spclunaqual=0.04D0,tmparr6(6)
1327character c80tmp*80,cubefilename*200
1328if (.not.allocated(b)) iselexttype=2 !Unable to set box using rho
1329do while(.true.)
1330    if (iselexttype==1) then
1331        orgx=minval(a%x)-gridextdist
1332        orgy=minval(a%y)-gridextdist
1333        orgz=minval(a%z)-gridextdist
1334        endx=maxval(a%x)+gridextdist
1335        endy=maxval(a%y)+gridextdist
1336        endz=maxval(a%z)+gridextdist
1337    else if (iselexttype==2) then
1338        orgx=minval( a(:)%x-enlarbox*vdwr_tianlu(a(:)%index) )
1339        orgy=minval( a(:)%y-enlarbox*vdwr_tianlu(a(:)%index) )
1340        orgz=minval( a(:)%z-enlarbox*vdwr_tianlu(a(:)%index) )
1341        endx=maxval( a(:)%x+enlarbox*vdwr_tianlu(a(:)%index) )
1342        endy=maxval( a(:)%y+enlarbox*vdwr_tianlu(a(:)%index) )
1343        endz=maxval( a(:)%z+enlarbox*vdwr_tianlu(a(:)%index) )
1344    end if
1345    molxlen=endx-orgx
1346    molylen=endy-orgy
1347    molzlen=endz-orgz
1348    ntotlow=(nint(molxlen/spclowqual)+1)*(nint(molylen/spclowqual)+1)*(nint(molzlen/spclowqual)+1)
1349    ntotmed=(nint(molxlen/spcmedqual)+1)*(nint(molylen/spcmedqual)+1)*(nint(molzlen/spcmedqual)+1)
1350    ntothigh=(nint(molxlen/spchighqual)+1)*(nint(molylen/spchighqual)+1)*(nint(molzlen/spchighqual)+1)
1351    ntotluna=(nint(molxlen/spclunaqual)+1)*(nint(molylen/spclunaqual)+1)*(nint(molzlen/spclunaqual)+1)
1352
1353    write(*,*) "Please select a method for setting up grid"
1354    if (iselexttype==1) write(*,"(a,f10.5,a)") " -10 Set grid extension distance for mode 1~6, current: Fixed,",gridextdist," Bohr"
1355    if (iselexttype==2) write(*,"(a)") " -10 Set grid extension distance for mode 1~6, current: Adaptive"
1356    if (iselexttype==3) write(*,"(a)") " -10 Set grid extension distance for mode 1~6, current: Detect rho isosurface"
1357    if (iselexttype==1.or.iselexttype==2) then
1358        write(*,"(a,f4.2,a,i14)") " 1 Low quality grid, spacing=",spclowqual," Bohr, number of grids:    ",ntotlow
1359        write(*,"(a,f4.2,a,i14)") " 2 Medium quality grid, spacing=",spcmedqual," Bohr, number of grids: ",ntotmed
1360        write(*,"(a,f4.2,a,i14)") " 3 High quality grid, spacing=",spchighqual," Bohr, number of grids:   ",ntothigh
1361        write(*,"(a,f4.2,a,i14)") " 4 Lunatic quality grid, spacing=",spclunaqual," Bohr, number of grids:",ntotluna
1362    else
1363        write(*,"(a,f4.2,a,i14)") " 1 Low quality grid, spacing=",spclowqual," Bohr, cost: 1x"
1364        write(*,"(a,f4.2,a,i14)") " 2 Medium quality grid, spacing=",spcmedqual," Bohr, cost: 8x"
1365        write(*,"(a,f4.2,a,i14)") " 3 High quality grid, spacing=",spchighqual," Bohr, cost: 36x"
1366        write(*,"(a,f4.2,a,i14)") " 4 Lunatic quality grid, spacing=",spclunaqual," Bohr, cost: 120x"
1367    end if
1368    write(*,*) "5 Only input grid spacing, automatically set other parameters"
1369    write(*,*) "6 Only input the number of points in X,Y,Z, automatically set other parameters"
1370    write(*,*) "7 Input original point, translation vector and the number of points"
1371    write(*,*) "8 Set center position, grid spacing and box length"
1372    write(*,*) "9 Use grid setting of another cube file"
1373
1374    read(*,*) igridsel
1375    if (igridsel/=-10) then
1376        exit
1377    else
1378        write(*,*) "Please select the type of extension distance:"
1379        write(*,*) "1 Use fixed value in each direction"
1380        write(*,*) "2 Adaptively determined according to van der Waals radius"
1381        write(*,"(a,1PE7.1)") " 3 Detect rho to make the box just accommodate its isosurface, isoval: ",rhocrit
1382        write(*,*) "Hint: In general mode 3 is recommended, mode 1 should be avoided to be used"
1383        read(*,*) iselexttype
1384        if (iselexttype==1) then
1385            do while(.true.)
1386                write(*,*) "Input extension distance (Bohr) e.g. 6.5"
1387                read(*,*) gridextdist
1388                if (gridextdist>0D0) exit
1389                write(*,*) "Error: The value must be larger than 0!"
1390            end do
1391        else if (iselexttype==2) then
1392            do while(.true.)
1393                write(*,*) "Input the ratio for scaling vdW radii, e.g. 1.7"
1394                write(*,"(' Current value is',f12.6)") enlarbox
1395                read(*,*) enlarbox
1396                if (enlarbox>0D0) exit
1397                write(*,*) "Error: The value must be larger than 0!"
1398            end do
1399        else if (iselexttype==3) then
1400            write(*,*) "Select the isovalue of rho"
1401            write(*,*) "1: 0.0001       (10^-4)"
1402            write(*,*) "2: 0.00001      (10^-5)"
1403            write(*,*) "3: 0.000005   (5*10^-6)"
1404            write(*,*) "4: 0.000003   (3*10^-6)"
1405            write(*,*) "5: 0.000001     (10^-6) In general recommended"
1406            write(*,*) "6: 0.0000005  (5*10^-7)"
1407            write(*,*) "7: 0.0000001    (10^-7)"
1408            write(*,*) "8: 0.00000005 (5*10^-8)"
1409            write(*,*) "9: 0.00000001   (10^-8)"
1410            write(*,*) "10: Input by yourself"
1411            read(*,*) iselrho
1412            if (iselrho==1) rhocrit=1D-4
1413            if (iselrho==2) rhocrit=1D-5
1414            if (iselrho==3) rhocrit=5D-6
1415            if (iselrho==4) rhocrit=3D-6
1416            if (iselrho==5) rhocrit=1D-6
1417            if (iselrho==6) rhocrit=5D-7
1418            if (iselrho==7) rhocrit=1D-7
1419            if (iselrho==8) rhocrit=5D-8
1420            if (iselrho==9) rhocrit=1D-8
1421            if (iselrho==10) then
1422                write(*,*) "Input the value, e.g. 0.000005 or 5D-6"
1423                read(*,*) rhocrit
1424            end if
1425        end if
1426    end if
1427end do
1428
1429if (igridsel==1.or.igridsel==2.or.igridsel==3.or.igridsel==4.or.igridsel==5.or.igridsel==6) then
1430    if (iselexttype==1) then
1431        aug3D=gridextdist !Set aug3D, which only affects GUI display, so that the scope of the axis is wide enough to contain the whole grid region
1432    else if (iselexttype==2) then
1433        aug3D=maxval(enlarbox*vdwr_tianlu(a(:)%index))*1.35D0
1434    else if (iselexttype==3) then
1435        call detectboxrho(rhocrit) !determine orgx/y/z and endx/y/z
1436        molxlen=endx-orgx
1437        molylen=endy-orgy
1438        molzlen=endz-orgz
1439        tmparr6(1)=abs(orgx-minval(a%x))
1440        tmparr6(2)=abs(orgy-minval(a%y))
1441        tmparr6(3)=abs(orgz-minval(a%z))
1442        tmparr6(4)=abs(endx-maxval(a%x))
1443        tmparr6(5)=abs(endy-maxval(a%y))
1444        tmparr6(6)=abs(endz-maxval(a%z))
1445        aug3D=maxval(tmparr6)+1
1446    end if
1447end if
1448
1449!Note: orgx,orgy,orgz,endx,endy,endz as well as molx/y/zlen for igridsel==1~6 have already been set above
1450if (igridsel==1.or.igridsel==2.or.igridsel==3.or.igridsel==4.or.igridsel==5) then
1451    if (igridsel==1) dx=spclowqual
1452    if (igridsel==2) dx=spcmedqual
1453    if (igridsel==3) dx=spchighqual
1454    if (igridsel==4) dx=spclunaqual
1455    if (igridsel==5) then
1456        write(*,*) "Input the grid spacing (bohr)  e.g. 0.08"
1457        read(*,*) dx
1458    end if
1459    dy=dx
1460    dz=dx
1461    nx=nint(molxlen/dx)+1
1462    ny=nint(molylen/dy)+1
1463    nz=nint(molzlen/dz)+1
1464else if (igridsel==6) then
1465    write(*,*) "Input the number of grid points in X,Y,Z direction   e.g. 139,59,80"
1466    read(*,*) nx,ny,nz
1467    dx=molxlen/(nx-1)
1468    dy=molylen/(ny-1)
1469    dz=molzlen/(nz-1)
1470else if (igridsel==7) then
1471    write(*,*) "Input X,Y,Z coordinate of original point (Bohr) e.g. 0.1,4,-1"
1472    read(*,*) orgx,orgy,orgz
1473    write(*,*) "Input X,Y,Z component of translation vector (Bohr) e.g. 0.1,0.1,0.15"
1474    read(*,*) dx,dy,dz
1475    write(*,*) "Input the number of points in X,Y,Z direction e.g. 139,59,80"
1476    read(*,*) nx,ny,nz
1477    endx=orgx+dx*(nx-1)
1478    endy=orgy+dy*(ny-1)
1479    endz=orgz+dz*(nz-1)
1480else if (igridsel==8) then
1481    write(*,*) "Input X,Y,Z coordinate of box center (in Angstrom)"
1482    write(*,*) "or input such as a8 to take the coordinate of atom 8 as box center"
1483    write(*,*) "or input such as a3,a7 to take the midpoint of atom 3 and atom 7 as box center"
1484    read(*,"(a)") c80tmp
1485    if (c80tmp(1:1)=='a') then
1486        do ich=1,len_trim(c80tmp)
1487            if (c80tmp(ich:ich)==',') exit
1488        end do
1489        if (ich==len_trim(c80tmp)+1) then
1490            read(c80tmp(2:),*) itmp
1491            cenx=a(itmp)%x
1492            ceny=a(itmp)%y
1493            cenz=a(itmp)%z
1494        else
1495            read(c80tmp(2:ich-1),*) itmp
1496            read(c80tmp(ich+2:),*) jtmp
1497            cenx=(a(itmp)%x+a(jtmp)%x)/2D0
1498            ceny=(a(itmp)%y+a(jtmp)%y)/2D0
1499            cenz=(a(itmp)%z+a(jtmp)%z)/2D0
1500        end if
1501    else
1502        read(c80tmp,*) cenx,ceny,cenz
1503        cenx=cenx/b2a
1504        ceny=ceny/b2a
1505        cenz=cenz/b2a
1506    end if
1507    write(*,*) "Input the grid spacing (bohr)  e.g. 0.08"
1508    read(*,*) dx
1509    dy=dx
1510    dz=dx
1511    write(*,*) "Input the box lengths in X,Y,Z direction (Bohr) e.g. 8.0,8.0,13.5"
1512    read(*,*) molxlen,molylen,molzlen
1513    orgx=cenx-molxlen/2D0
1514    orgy=ceny-molylen/2D0
1515    orgz=cenz-molzlen/2D0
1516    endx=orgx+molxlen
1517    endy=orgy+molylen
1518    endz=orgz+molzlen
1519    nx=nint(molxlen/dx)+1
1520    ny=nint(molylen/dy)+1
1521    nz=nint(molzlen/dz)+1
1522else if (igridsel==9) then
1523    write(*,*) "Input filename of a cube file"
1524    do while(.true.)
1525        read(*,"(a)") cubefilename
1526        inquire(file=cubefilename,exist=alive)
1527        if (alive) then
1528            open(10,file=cubefilename,status="old")
1529            read(10,*)
1530            read(10,*)
1531            read(10,*) nouse,orgx,orgy,orgz
1532            read(10,*) nx,dx
1533            read(10,*) ny,rnouse,dy
1534            read(10,*) nz,rnouse,rnouse,dz
1535            close(10)
1536            exit
1537        else
1538            write(*,*) "Error: File cannot be found, input again"
1539        end if
1540    end do
1541    endx=orgx+dx*(nx-1)
1542    endy=orgy+dy*(ny-1)
1543    endz=orgz+dz*(nz-1)
1544end if
1545
1546!If system is symmetric to Cartesian plane, then slightly adjust grid setting, so that the distribution of grids are symmetric to Cartesian plane
1547!This treatment will make the integrals have much better symmetry
1548diffx=abs(orgx+endx)
1549diffy=abs(orgy+endy)
1550diffz=abs(orgz+endz)
1551if (igridsel>=1.and.igridsel<=6) then
1552    if (diffx<0.05D0) then !The system is symmetry to YZ plane
1553        distxmin=1D10
1554        do ix=1,nx
1555            rnowx=orgx+(ix-1)*dx
1556            if (rnowx>=0D0.and.rnowx<distxmin) distxmin=rnowx
1557        end do
1558        !1D-12 is a perturbation to avoid the grids are degenerate with respect to Cartesian plane, which results in cumbersome degenerate attractors
1559        !However if it is introduced, the integrals will not so close to symmetry
1560        orgx=orgx+(dx/2D0-distxmin) !+1D-15
1561    end if
1562    if (diffy<0.05D0) then !The system is symmetry to XZ plane
1563        distymin=1D10
1564        do iy=1,ny
1565            rnowy=orgy+(iy-1)*dy
1566            if (rnowy>=0D0.and.rnowy<distymin) distymin=rnowy
1567        end do
1568        orgy=orgy+(dy/2D0-distymin) !+1D-15
1569    end if
1570    if (diffz<0.05D0) then !The system is symmetry to XY plane
1571        distzmin=1D10
1572        do iz=1,nz
1573            rnowz=orgz+(iz-1)*dz
1574            if (rnowz>=0D0.and.rnowz<distzmin) distzmin=rnowz
1575        end do
1576        orgz=orgz+(dz/2D0-distzmin) !+1D-15
1577    end if
1578end if
1579
1580write(*,"(' Coordinate of origin in X,Y,Z is   ',3f12.6)") orgx,orgy,orgz
1581write(*,"(' Coordinate of end point in X,Y,Z is',3f12.6)") endx,endy,endz
1582write(*,"(' Spacing in X,Y,Z is',3f11.6)") dx,dy,dz
1583write(*,"(' Number of points in X,Y,Z is',3i5,'   Total',i10)") nx,ny,nz,nx*ny*nz
1584! do i=1,nx
1585!     write(c80tmp,"(D20.13)") orgx+(i-1)*dx
1586!     read(c80tmp,*) tmpval
1587!     write(*,*) i," x ",tmpval
1588! end do
1589! do i=1,ny
1590!     write(c80tmp,"(D20.13)") orgy+(i-1)*dy
1591!     read(c80tmp,*) tmpval
1592!     write(*,*) i," y ",tmpval
1593! end do
1594! do i=1,nz
1595!     write(c80tmp,"(D20.13)") orgz+dfloat(i-1)*dz
1596!     read(c80tmp,*) tmpval
1597!     write(*,*) i," z ",tmpval
1598! end do
1599! read(*,*)
1600end subroutine
1601
1602
1603!!-- Detect proper box (namely set orgx/y/z,endx/y/z) so that the box can just enclose the isosurface of rho=rhocrit
1604subroutine detectboxrho(rhocrit)
1605use defvar
1606use function
1607implicit real*8(a-h,o-z)
1608real*8 rhocrit
1609tmpfac=1.0D0
1610orgxtmp=minval( a(:)%x-tmpfac*vdwr_tianlu(a(:)%index) ) !Define a too small box, extend each side (to obtain orgx/y/z,endx/y/z) by detecting rho
1611orgytmp=minval( a(:)%y-tmpfac*vdwr_tianlu(a(:)%index) )
1612orgztmp=minval( a(:)%z-tmpfac*vdwr_tianlu(a(:)%index) )
1613endxtmp=maxval( a(:)%x+tmpfac*vdwr_tianlu(a(:)%index) )
1614endytmp=maxval( a(:)%y+tmpfac*vdwr_tianlu(a(:)%index) )
1615endztmp=maxval( a(:)%z+tmpfac*vdwr_tianlu(a(:)%index) )
1616scanstp=0.3D0 !Spacing of scan
1617nstpx=nint((endxtmp-orgxtmp)/scanstp)+1 !The number of detection grid in X direction
1618nstpy=nint((endytmp-orgytmp)/scanstp)+1 !The number of detection grid in Y direction
1619nstpz=nint((endztmp-orgztmp)/scanstp)+1 !The number of detection grid in Z direction
1620distmove=0.2D0
1621write(*,*) "Detecting proper box size..."
1622!Detect Z low. Scan XY plane, if rho at a point is larger than "rhocrit", lower down the plane by "distmove" and check again, until all points have rho<rhocrit
1623orgz=orgztmp
1624do while(.true.)
1625    iok=1
1626zl:do ix=1,nstpx
1627        rnowx=orgxtmp+(ix-1)*scanstp
1628        do iy=1,nstpy
1629            rnowy=orgytmp+(iy-1)*scanstp
1630            if (fdens(rnowx,rnowy,orgz)>rhocrit) then
1631                iok=0
1632                exit zl
1633            end if
1634        end do
1635    end do zl
1636    if (iok==1) exit
1637    orgz=orgz-0.2D0 !Lower down the layer
1638end do
1639!Detect Z high
1640endz=endztmp
1641do while(.true.)
1642    iok=1
1643zh:do ix=1,nstpx
1644        rnowx=orgxtmp+(ix-1)*scanstp
1645        do iy=1,nstpy
1646            rnowy=orgytmp+(iy-1)*scanstp
1647            if (fdens(rnowx,rnowy,endz)>rhocrit) then
1648                iok=0
1649                exit zh
1650            end if
1651        end do
1652    end do zh
1653    if (iok==1) exit
1654    endz=endz+0.2D0
1655end do
1656!Detect X low. Scan YZ plane
1657orgx=orgxtmp
1658do while(.true.)
1659    iok=1
1660xl:do iy=1,nstpy
1661        rnowy=orgytmp+(iy-1)*scanstp
1662        do iz=1,nstpz
1663            rnowz=orgztmp+(iz-1)*scanstp
1664            if (fdens(orgx,rnowy,rnowz)>rhocrit) then
1665                iok=0
1666                exit xl
1667            end if
1668        end do
1669    end do xl
1670    if (iok==1) exit
1671    orgx=orgx-0.2D0
1672end do
1673!Detect X high
1674endx=endxtmp
1675do while(.true.)
1676    iok=1
1677xh:do iy=1,nstpy
1678        rnowy=orgytmp+(iy-1)*scanstp
1679        do iz=1,nstpz
1680            rnowz=orgztmp+(iz-1)*scanstp
1681            if (fdens(endx,rnowy,rnowz)>rhocrit) then
1682                iok=0
1683                exit xh
1684            end if
1685        end do
1686    end do xh
1687    if (iok==1) exit
1688    endx=endx+0.2D0
1689end do
1690!Detect Y low. Scan XZ plane
1691orgy=orgytmp
1692do while(.true.)
1693    iok=1
1694yl:do ix=1,nstpx
1695        rnowx=orgxtmp+(ix-1)*scanstp
1696        do iz=1,nstpz
1697            rnowz=orgztmp+(iz-1)*scanstp
1698            if (fdens(rnowx,orgy,rnowz)>rhocrit) then
1699                iok=0
1700                exit yl
1701            end if
1702        end do
1703    end do yl
1704    if (iok==1) exit
1705    orgy=orgy-0.2D0
1706end do
1707!Detect Y high
1708endy=endytmp
1709do while(.true.)
1710    iok=1
1711yh:do ix=1,nstpx
1712        rnowx=orgxtmp+(ix-1)*scanstp
1713        do iz=1,nstpz
1714            rnowz=orgztmp+(iz-1)*scanstp
1715            if (fdens(rnowx,endy,rnowz)>rhocrit) then
1716                iok=0
1717                exit yh
1718            end if
1719        end do
1720    end do yh
1721    if (iok==1) exit
1722    endy=endy+0.2D0
1723end do
1724
1725end subroutine
1726
1727
1728
1729
1730!!------- Integrate a real space function in the basins already partitioned
1731subroutine integratebasin
1732use defvar
1733use util
1734use function
1735use basinintmod
1736implicit real*8(a-h,o-z)
1737real*8 intval(-1:numatt),basinvol(-1:numatt),intvalpriv(-1:numatt),basinvolpriv(-1:numatt)
1738integer walltime1,walltime2
1739character grdfilename*200
1740
1741write(*,*) "Please select integrand:"
1742write(*,*) "-2 Return"
1743write(*,*) "-1 The values of the grid data stored in an external file (.cub/.grd)"
1744write(*,*) "0 The values of the grid data stored in memory"
1745call selfunc_interface(ifuncint)
1746if (ifuncint==-1) then
1747    do while(.true.)
1748        write(*,*) "Input another .cub or .grd file name"
1749        read(*,"(a)") grdfilename
1750        inquire(file=grdfilename,exist=alive)
1751        if (alive) exit
1752        write(*,*) "File not found, input again"
1753        write(*,*)
1754    end do
1755    inamelen=len_trim(grdfilename)
1756    if (grdfilename(inamelen-2:inamelen)=="cub".or.grdfilename(inamelen-3:inamelen)=="cube") then
1757        call readcubetmp(grdfilename,inconsis)
1758    else if (grdfilename(inamelen-2:inamelen)=="grd") then
1759        call readgrdtmp(grdfilename,inconsis)
1760    end if
1761    if (inconsis==1) return
1762    write(*,*)
1763else if (ifuncint==-2) then
1764    return
1765end if
1766
1767call walltime(walltime1)
1768CALL CPU_TIME(time_begin)
1769write(*,*) "Integrating, please wait..."
1770intval=0D0
1771basinvol=0D0
1772ifinish=0
1773nthreads=getNThreads()
1774!$OMP PARALLEL private(ix,iy,iz,irealatt,rnowx,rnowy,rnowz,tmpval,intvalpriv,basinvolpriv) shared(intval,basinvol,ifinish) NUM_THREADS(nthreads)
1775intvalpriv=0D0
1776basinvolpriv=0D0
1777!$OMP do schedule(DYNAMIC)
1778do iz=2,nz-1
1779    do iy=2,ny-1
1780        do ix=2,nx-1
1781            rnowx=orgx+(ix-1)*dx
1782            rnowy=orgy+(iy-1)*dy
1783            rnowz=orgz+(iz-1)*dz
1784            if (ifuncint==-1) then
1785                tmpval=cubmattmp(ix,iy,iz)
1786            else if (ifuncint==0) then
1787                tmpval=cubmat(ix,iy,iz)
1788            else
1789                tmpval=calcfuncall(ifuncint,rnowx,rnowy,rnowz)
1790            end if
1791            irealatt=gridbas(ix,iy,iz)
1792            intvalpriv(irealatt)=intvalpriv(irealatt)+tmpval
1793            basinvolpriv(irealatt)=basinvolpriv(irealatt)+1
1794        end do
1795    end do
1796    ifinish=ifinish+1
1797    if (ifuncint>=1) write(*,"(' Finished:',i5,'/',i5)") ifinish,nz
1798end do
1799!$OMP end do
1800!$OMP CRITICAL
1801    intval=intval+intvalpriv
1802    basinvol=basinvol+basinvolpriv
1803!$OMP end CRITICAL
1804!$OMP END PARALLEL
1805dvol=dx*dy*dz
1806intval=intval*dvol
1807basinvol=basinvol*dvol !Basin volume
1808write(*,*) "  #Basin        Integral(a.u.)      Volume(a.u.^3)"
1809do irealatt=1,numrealatt
1810    write(*,"(i8,f22.10,f20.8)") irealatt,intval(irealatt),basinvol(irealatt)
1811end do
1812write(*,"(' Sum of above values:',f20.8)") sum(intval(1:numrealatt))
1813if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==0)) write(*,"(' Integral of unassigned grids:',f20.8)") intval(0)
1814if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==-1)) write(*,"(' Integral of the grids travelled to box boundary:',f20.8)") intval(-1)
1815
1816CALL CPU_TIME(time_end)
1817call walltime(walltime2)
1818write(*,"(' Integrating basins took up CPU time',f12.2,'s, wall clock time',i10,'s')") time_end-time_begin,walltime2-walltime1
1819end subroutine
1820
1821
1822
1823!!------- Obtain atomic population in a basin region (e.g. ELF bond basin) via AIM partition
1824subroutine atmpopinbasin
1825use defvar
1826use basinintmod
1827implicit real*8(a-h,o-z)
1828inquire(file="basin.cub",exist=alive)
1829if (alive .eqv. .false.) then
1830    write(*,*) "Error: basin.cub is not existed in current folder!"
1831    return
1832else
1833    if (allocated(cubmattmp)) deallocate(cubmattmp)
1834    call readcubetmp("basin.cub",inconsis)
1835    if (inconsis==1) then
1836        write(*,*) "Error: The grid setting of basin.cub is inconsistent with present grid data"
1837        return
1838    end if
1839end if
1840do while(.true.)
1841    write(*,*)
1842    write(*,*) "Study population of which atom? Input the index of corresponding attractor"
1843    write(*,*) "For example, 3"
1844    write(*,*) "Input 0 can exit"
1845    read(*,*) iatt
1846    if (iatt==0) then
1847        exit
1848    else if (iatt<0.or.iatm>numrealatt) then
1849        write(*,*) "Error: Attractor index exceeded valid range!"
1850        return
1851    end if
1852    write(*,*) "Study its population in which basin of the basin.cub file? e.g. 6"
1853    read(*,*) ibasin
1854    atmpop=0
1855    do iz=2,nz-1
1856        do iy=2,ny-1
1857            do ix=2,nx-1
1858                if (nint(cubmattmp(ix,iy,iz))==ibasin.and.gridbas(ix,iy,iz)==iatt) atmpop=atmpop+cubmat(ix,iy,iz)
1859            end do
1860        end do
1861    end do
1862    atmpop=atmpop*dx*dy*dz
1863    write(*,"(' Population of attractor',i4,' in external basin',i4,' is',f12.5)") iatt,ibasin,atmpop
1864end do
1865deallocate(cubmattmp)
1866end subroutine
1867
1868
1869
1870!!----------------- Calculate multipole moment in the basins
1871subroutine multipolebasin
1872use defvar
1873use basinintmod
1874use function
1875implicit real*8 (a-h,o-z)
1876do while(.true.)
1877    write(*,*) "Input the index of the basin in question, e.g. 5"
1878    write(*,"(a)") " Note: -1 means printing all basin results on screen, -2 means printing to multipol.txt in current folder. Input 0 can return"
1879    read(*,*) itmp
1880    if (itmp==-1.or.itmp==-2) then
1881        ibegin=1
1882        iend=numrealatt
1883        if (itmp==-2) then
1884            ioutid=10
1885            open(10,file="multipol.txt",status="replace")
1886        end if
1887    else if (itmp==0) then
1888        return
1889    else
1890        ibegin=itmp
1891        iend=itmp
1892        ioutid=6
1893    end if
1894    write(*,*) "Calculating, please wait..."
1895    write(ioutid,*) "Note: All units shown below are in a.u.!"
1896    write(ioutid,*)
1897
1898    dipelextot=0D0
1899    dipeleytot=0D0
1900    dipeleztot=0D0
1901    eleinttot=0D0
1902    do ibas=ibegin,iend
1903    !     xcen=0 !Use centroid of basin as center, but this is a bad idea
1904    !     ycen=0
1905    !     zcen=0
1906    !     nbasgrid=0
1907    !     do iz=2,nz-1
1908    !         do iy=2,ny-1
1909    !             do ix=2,nx-1
1910    !                 if (gridbas(ix,iy,iz)==ibas) then
1911    !                     nbasgrid=nbasgrid+1
1912    !                     rnowx=orgx+(ix-1)*dx
1913    !                     rnowy=orgy+(iy-1)*dy
1914    !                     rnowz=orgz+(iz-1)*dz
1915    !                     tmpdens=ELF_LOL(rnowx,rnowy,rnowz,"ELF")
1916    !                     xcen=xcen+rnowx*tmpdens
1917    !                     ycen=ycen+rnowy*tmpdens
1918    !                     zcen=zcen+rnowz*tmpdens
1919    !                 end if
1920    !             end do
1921    !         end do
1922    !     end do
1923    !     xcen=xcen/nbasgrid
1924    !     ycen=ycen/nbasgrid
1925    !     zcen=zcen/nbasgrid
1926        xcen=realattxyz(ibas,1)
1927        ycen=realattxyz(ibas,2)
1928        zcen=realattxyz(ibas,3)
1929        dvol=dx*dy*dz
1930    !     write(*,"(' The X,Y,Z of the center of the basin:')")
1931    !     write(*,"(3f14.8,' Bohr',/)") xcen,ycen,zcen
1932
1933        eleint=0D0
1934        xint=0D0
1935        yint=0D0
1936        zint=0D0
1937        xxint=0D0
1938        yyint=0D0
1939        zzint=0D0
1940        xyint=0D0
1941        yzint=0D0
1942        xzint=0D0
1943nthreads=getNThreads()
1944!$OMP PARALLEL private(ix,iy,iz,rnowx,rnowy,rnowz,tmpmul,rx,ry,rz,eleintp,xintp,yintp,zintp,xxintp,yyintp,zzintp,xyintp,yzintp,xzintp) NUM_THREADS(nthreads)
1945        eleintp=0D0
1946        xintp=0D0
1947        yintp=0D0
1948        zintp=0D0
1949        xxintp=0D0
1950        yyintp=0D0
1951        zzintp=0D0
1952        xyintp=0D0
1953        yzintp=0D0
1954        xzintp=0D0
1955!$OMP do schedule(DYNAMIC)
1956        do iz=2,nz-1
1957            rnowz=orgz+(iz-1)*dz
1958            do iy=2,ny-1
1959                rnowy=orgy+(iy-1)*dy
1960                do ix=2,nx-1
1961                    if (gridbas(ix,iy,iz)==ibas) then
1962                        rnowx=orgx+(ix-1)*dx
1963                        if (ifuncbasin==1) then
1964                            tmpmul=dvol*cubmat(ix,iy,iz) !The cubmat currently is just electron density
1965                        else
1966                            tmpmul=dvol*fdens(rnowx,rnowy,rnowz)
1967                        end if
1968                        rx=rnowx-xcen
1969                        ry=rnowy-ycen
1970                        rz=rnowz-zcen
1971                        eleintp=eleintp+tmpmul !monopole
1972                        xintp=xintp+rx*tmpmul
1973                        yintp=yintp+ry*tmpmul
1974                        zintp=zintp+rz*tmpmul
1975                        xxintp=xxintp+rx*rx*tmpmul
1976                        yyintp=yyintp+ry*ry*tmpmul
1977                        zzintp=zzintp+rz*rz*tmpmul
1978                        xyintp=xyintp+rx*ry*tmpmul
1979                        yzintp=yzintp+ry*rz*tmpmul
1980                        xzintp=xzintp+rx*rz*tmpmul
1981                    end if
1982                end do
1983            end do
1984        end do
1985!$OMP end do
1986!$OMP CRITICAL
1987        eleint=eleint+eleintp
1988        xint=xint+xintp
1989        yint=yint+yintp
1990        zint=zint+zintp
1991        xxint=xxint+xxintp
1992        yyint=yyint+yyintp
1993        zzint=zzint+zzintp
1994        xyint=xyint+xyintp
1995        yzint=yzint+yzintp
1996        xzint=xzint+xzintP
1997!$OMP end CRITICAL
1998!$OMP END PARALLEL
1999        if (itmp==-1.or.itmp==-2) write(ioutid,"(' Basin',i8)") ibas
2000        if (itmp==-2) write(*,"(' Outputting basin',i8)") ibas
2001        write(ioutid,"(' Basin electric monopole moment:',f12.6)") -eleint
2002        write(ioutid,"(' Basin electric dipole moment:')")
2003        write(ioutid,"('  X=',f12.6,'  Y=',f12.6,'  Z=',f12.6,'  Magnitude=',f12.6)") -xint,-yint,-zint,sqrt(xint**2+yint**2+zint**2)
2004        eleinttot=eleinttot+eleint
2005        dipelex=-eleint*xcen+(-xint) !Contribution to molecular total dipole moment
2006        dipeley=-eleint*ycen+(-yint)
2007        dipelez=-eleint*zcen+(-zint)
2008        dipelextot=dipelextot+dipelex
2009        dipeleytot=dipeleytot+dipeley
2010        dipeleztot=dipeleztot+dipelez
2011        write(ioutid,"(' Basin electron contribution to molecular dipole moment:')")
2012        write(ioutid,"('  X=',f12.6,'  Y=',f12.6,'  Z=',f12.6,'  Magnitude=',f12.6)") dipelex,dipeley,dipelez,sqrt(dipelex**2+dipeley**2+dipelez**2)
2013        write(ioutid,"(' Basin electric quadrupole moment (Cartesian form):')")
2014        rrint=xxint+yyint+zzint
2015        QXX=-(3*xxint-rrint)/2
2016        QYY=-(3*yyint-rrint)/2
2017        QZZ=-(3*zzint-rrint)/2
2018        write(ioutid,"(' QXX=',f12.6,'  QXY=',f12.6,'  QXZ=',f12.6)") QXX,-(3*xyint)/2,-(3*xzint)/2
2019        write(ioutid,"(' QYX=',f12.6,'  QYY=',f12.6,'  QYZ=',f12.6)") -(3*xyint)/2,QYY,-(3*yzint)/2
2020        write(ioutid,"(' QZX=',f12.6,'  QZY=',f12.6,'  QZZ=',f12.6)") -(3*xzint)/2,-(3*yzint)/2,QZZ
2021        write(ioutid,"( ' The magnitude of electric quadrupole moment (Cartesian form):',f12.6)") dsqrt(2D0/3D0*(QXX**2+QYY**2+QZZ**2))
2022        R20=-(3*zzint-rrint)/2D0 !Notice that the negative sign, because electrons carry negative charge
2023        R2n1=-dsqrt(3D0)*yzint
2024        R2p1=-dsqrt(3D0)*xzint
2025        R2n2=-dsqrt(3D0)*xyint
2026        R2p2=-dsqrt(3D0)/2D0*(xxint-yyint)
2027        write(ioutid,"(' Electric quadrupole moments (Spherical harmonic form):')")
2028        write(ioutid,"(' Q_2,0 =',f11.6,'   Q_2,-1=',f11.6,'   Q_2,1=',f11.6)") R20,R2n1,R2p1
2029        write(ioutid,"(' Q_2,-2=',f11.6,'   Q_2,2 =',f11.6)") R2n2,R2p2
2030        write(ioutid,"( ' Magnitude: |Q_2|=',f12.6)") dsqrt(R20**2+R2n1**2+R2p1**2+R2n2**2+R2p2**2)
2031        write(ioutid,*)
2032    end do
2033    if (itmp==-1.or.itmp==-2) then !Output overall properties, most users are not interested in them
2034        dipnucx=sum(a(:)%x*a(:)%charge)
2035        dipnucy=sum(a(:)%y*a(:)%charge)
2036        dipnucz=sum(a(:)%z*a(:)%charge)
2037        write(ioutid,"( ' Molecular net charge:',f12.6)") sum(a%charge)-eleinttot
2038        write(ioutid,"( ' Nuclear contribution to molecular dipole moment:')")
2039        write(ioutid,"(' X=',f12.6,' Y=',f12.6,' Z=',f12.6,' Norm=',f12.6)") dipnucx,dipnucy,dipnucz,sqrt(dipnucx**2+dipnucy**2+dipnucz**2)
2040        write(ioutid,"( ' Electron contribution to molecular dipole moment:')")
2041        write(ioutid,"(' X=',f12.6,' Y=',f12.6,' Z=',f12.6,' Norm=',f12.6)") dipelextot,dipeleytot,dipeleztot,sqrt(dipelextot**2+dipeleytot**2+dipeleztot**2)
2042        dipmolx=dipnucx+dipelextot
2043        dipmoly=dipnucy+dipeleytot
2044        dipmolz=dipnucz+dipeleztot
2045        write(ioutid,"( ' Molecular dipole moment:')")
2046        write(ioutid,"(' X=',f12.6,' Y=',f12.6,' Z=',f12.6,' Norm=',f12.6)") dipmolx,dipmoly,dipmolz,sqrt(dipmolx**2+dipmoly**2+dipmolz**2)
2047        write(ioutid,*)
2048    end if
2049    if (itmp==-2) then
2050        close(10)
2051        write(*,*) "Outputting finished!"
2052        write(*,*)
2053    end if
2054end do
2055end subroutine
2056
2057
2058!!------------------ Calculate localized index and delocalization index within and between basins
2059!Most of the codes are adapted from fuzzyana.f90
2060!itask==0 means calculate BOM and LI,DI, itask==1 means calculate and output BOM to BOM.txt in current folder
2061!BOM means overlap matrix of all occupied orbitals in basins
2062subroutine LIDIbasin(itask)
2063use defvar
2064use basinintmod
2065use function
2066use util
2067implicit real*8 (a-h,o-z)
2068real*8 DI(numrealatt,numrealatt),DIa(numrealatt,numrealatt),DIb(numrealatt,numrealatt) !Delocalization index matrix
2069real*8 LI(numrealatt),LIa(numrealatt),LIb(numrealatt) !Localization index array
2070real*8,allocatable :: BOM(:,:,:),BOMa(:,:,:),BOMb(:,:,:),BOMsum(:,:),BOMsuma(:,:),BOMsumb(:,:) !BOM(i,j,k) means overlap matrix of MO i,j in atom k space
2071real*8 :: BOMtmp(nmo,nmo),orbval(nmo)
2072character selectyn
2073integer itask
2074
2075!Allocate space for BOM
2076if (wfntype==0.or.wfntype==2.or.wfntype==3) then !RHF,ROHF,R-post-HF
2077    if (wfntype==3) then !R-post-HF, need to consider all orbitals
2078        nmatsize=nmo
2079    else !RHF,ROHF
2080        !High-lying virtual orbitals will be deleted, especially for .fch case (In fact, before entering this function, those >= LUMO+10 has already been discarded)
2081        !Notice that occupation number may be not contiguous, some low-lying orbital may have
2082        !zero occupation due to modification by users, so we can't simply use nelec to determine matrix size
2083        do nmatsize=nmo,1,-1
2084            if (MOocc(nmatsize)/=0) exit
2085        end do
2086        if (nmo-nmatsize>0) write(*,"(' Note: The highest',i6,' virtual orbitals will not be taken into account')") nmo-nmatsize
2087    end if
2088    if (allocated(BOM)) deallocate(BOM,BOMsum)
2089    allocate(BOM(nmatsize,nmatsize,numrealatt),BOMsum(nmatsize,nmatsize))
2090    BOM=0
2091    BOMsum=0
2092else if (wfntype==1.or.wfntype==4) then !UHF,U-post-HF
2093    do iendalpha=nmo,1,-1
2094        if (MOtype(iendalpha)==1) exit
2095    end do
2096    if (wfntype==4) then
2097        nmatsizea=iendalpha !Total number of alpha orbitals
2098        nmatsizeb=nmo-nmatsizea !Total number of beta orbitals
2099    else
2100        do nmatsizea=iendalpha,1,-1
2101            if (MOocc(nmatsizea)/=0D0) exit
2102        end do
2103        if (nint(nbelec)==0) then
2104            nmatsizeb=0
2105        else
2106            do nmatsizeb=nmo,iendalpha+1,-1
2107                if (MOocc(nmatsizeb)/=0D0) exit
2108            end do
2109            nmatsizeb=nmatsizeb-iendalpha
2110        end if
2111        if (iendalpha-nmatsizea>0) write(*,"('Note: The highest',i6,' alpha virtual orbitals will not be taken into account')") iendalpha-nmatsizea
2112        if (nmo-iendalpha-nmatsizeb>0) write(*,"('Note: The highest',i6,' beta virtual orbitals will not be taken into account')") nmo-iendalpha-nmatsizeb
2113    end if
2114    if (allocated(BOMa)) deallocate(BOMa,BOMb,BOMsuma,BOMsumb)
2115    allocate( BOMa(nmatsizea,nmatsizea,numrealatt),BOMb(nmatsizeb,nmatsizeb,numrealatt) )
2116    allocate( BOMsuma(nmatsizea,nmatsizea),BOMsumb(nmatsizeb,nmatsizeb) )
2117    BOMa=0
2118    BOMb=0
2119    BOMsuma=0
2120    BOMsumb=0
2121end if
2122
2123!Calculate BOM
2124dvol=dx*dy*dz
2125call walltime(nwalltime1)
2126if (wfntype==0.or.wfntype==2.or.wfntype==3) then !RHF,ROHF,R-post-HF
2127    do ibas=1,numrealatt
2128        write(*,"(' Generating orbital overlap matrix for basin',i6,'  of',i6,' ......')") ibas,numrealatt
2129nthreads=getNThreads()
2130!$OMP parallel shared(BOM) private(ix,iy,iz,rnowx,rnowy,rnowz,imo,jmo,BOMtmp,orbval) num_threads(nthreads)
2131        BOMtmp=0D0
2132!$OMP do schedule(DYNAMIC)
2133        do iz=2,nz-1
2134            do iy=2,ny-1
2135                do ix=2,nx-1
2136                    if (gridbas(ix,iy,iz)==ibas) then
2137                        rnowx=orgx+(ix-1)*dx
2138                        rnowy=orgy+(iy-1)*dy
2139                        rnowz=orgz+(iz-1)*dz
2140                        call orbderv(1,1,nmatsize,rnowx,rnowy,rnowz,orbval)
2141                        do imo=1,nmatsize
2142                            do jmo=imo,nmatsize
2143                                BOMtmp(imo,jmo)=BOMtmp(imo,jmo)+orbval(imo)*orbval(jmo)*dvol
2144                            end do
2145                        end do
2146                    end if
2147                end do
2148            end do
2149        end do
2150!$OMP end do
2151!$OMP CRITICAL
2152        BOM(:,:,ibas)=BOM(:,:,ibas)+BOMtmp(1:nmatsize,1:nmatsize)
2153!$OMP end CRITICAL
2154!$OMP end parallel
2155        BOM(:,:,ibas)=BOM(:,:,ibas)+transpose(BOM(:,:,ibas))
2156        do imo=1,nmatsize
2157            BOM(imo,imo,ibas)=BOM(imo,imo,ibas)/2D0
2158        end do
2159    end do
2160else if (wfntype==1.or.wfntype==4) then !UHF,U-post-HF
2161    do ibas=1,numrealatt
2162        !Alpha part
2163        write(*,"(' Generating orbital overlap matrix for basin',i6,'  of',i6,' ......')") ibas,numrealatt
2164nthreads=getNThreads()
2165!$OMP parallel shared(BOMa) private(ix,iy,iz,rnowx,rnowy,rnowz,imo,jmo,BOMtmp,orbval) num_threads(nthreads)
2166        BOMtmp=0D0
2167!$OMP do schedule(DYNAMIC)
2168        do iz=2,nz-1
2169            do iy=2,ny-1
2170                do ix=2,nx-1
2171                    if (gridbas(ix,iy,iz)==ibas) then
2172                        rnowx=orgx+(ix-1)*dx
2173                        rnowy=orgy+(iy-1)*dy
2174                        rnowz=orgz+(iz-1)*dz
2175                        call orbderv(1,1,nmatsizea,rnowx,rnowy,rnowz,orbval)
2176                        do imo=1,nmatsizea
2177                            do jmo=imo,nmatsizea
2178                                BOMtmp(imo,jmo)=BOMtmp(imo,jmo)+orbval(imo)*orbval(jmo)*dvol
2179                            end do
2180                        end do
2181                    end if
2182                end do
2183            end do
2184        end do
2185!$OMP end do
2186!$OMP CRITICAL
2187        BOMa(:,:,ibas)=BOMa(:,:,ibas)+BOMtmp(1:nmatsizea,1:nmatsizea)
2188!$OMP end CRITICAL
2189!$OMP end parallel
2190        BOMa(:,:,ibas)=BOMa(:,:,ibas)+transpose(BOMa(:,:,ibas))
2191        do imo=1,nmatsizea
2192            BOMa(imo,imo,ibas)=BOMa(imo,imo,ibas)/2D0
2193        end do
2194
2195        !Beta part
2196        if (nmatsizeb>0) then !If there is no beta orbital, then nmatsizeb=0, and we will do nothing
2197            MOinit=iendalpha+1
2198            MOend=iendalpha+nmatsizeb
2199!             write(*,*) MOinit,MOend,nmatsizeb
2200nthreads=getNThreads()
2201!$OMP parallel shared(BOMb) private(ix,iy,iz,rnowx,rnowy,rnowz,imo,imotmp,jmo,jmotmp,BOMtmp,orbval) num_threads(nthreads)
2202            BOMtmp=0D0
2203!$OMP do schedule(DYNAMIC)
2204            do iz=2,nz-1
2205                do iy=2,ny-1
2206                    do ix=2,nx-1
2207                        if (gridbas(ix,iy,iz)==ibas) then
2208                            rnowx=orgx+(ix-1)*dx
2209                            rnowy=orgy+(iy-1)*dy
2210                            rnowz=orgz+(iz-1)*dz
2211                            call orbderv(1,MOinit,MOend,rnowx,rnowy,rnowz,orbval)
2212                            do imo=MOinit,MOend
2213                                imotmp=imo-iendalpha !So that the index start from 1 to nbelec
2214                                do jmo=imo,MOend
2215                                    jmotmp=jmo-iendalpha
2216                                    BOMtmp(imotmp,jmotmp)=BOMtmp(imotmp,jmotmp)+orbval(imo)*orbval(jmo)*dvol
2217                                end do
2218                            end do
2219                        end if
2220                    end do
2221                end do
2222            end do
2223!$OMP end do
2224!$OMP CRITICAL
2225            BOMb(:,:,ibas)=BOMb(:,:,ibas)+BOMtmp(1:nmatsizeb,1:nmatsizeb)
2226!$OMP end CRITICAL
2227!$OMP end parallel
2228            BOMb(:,:,ibas)=BOMb(:,:,ibas)+transpose(BOMb(:,:,ibas))
2229            do imo=1,nmatsizeb
2230                BOMb(imo,imo,ibas)=BOMb(imo,imo,ibas)/2D0
2231            end do
2232        end if
2233    end do
2234end if
2235
2236write(*,*)
2237!Check sanity of BOM
2238if (wfntype==0.or.wfntype==2.or.wfntype==3) then !RHF,ROHF,R-post-HF
2239    do ibas=1,numrealatt
2240        BOMsum=BOMsum+BOM(:,:,ibas)
2241    end do
2242    BOMerror=identmaterr(BOMsum)/numrealatt
2243    write(*,"(' Error of BOM is',f14.8)") BOMerror
2244    if (BOMerror>0.02D0) write(*,"(a)") " Warning: The integration is not very accurate"
2245!     call showmatgau(BOMsum,"BOMsum",0,"f14.8",6)
2246else if (wfntype==1.or.wfntype==4) then !UHF,U-post-HF
2247    BOMerrorb=0D0
2248    do ibas=1,numrealatt
2249        BOMsuma=BOMsuma+BOMa(:,:,ibas)
2250        if (nmatsizeb>0) BOMsumb=BOMsumb+BOMb(:,:,ibas)
2251    end do
2252    BOMerrora=identmaterr(BOMsuma)/numrealatt
2253    if (nmatsizeb>0) BOMerrorb=identmaterr(BOMsumb)/numrealatt
2254    write(*,"(' Error of alpha BOM is',f14.8)") BOMerrora
2255    if (nmatsizeb>0) write(*,"(' Error of Beta BOM is ',f14.8)") BOMerrorb
2256    if (BOMerrora>0.02D0.or.BOMerrorb>0.02D0) write(*,"(a)") " Warning: The integration is not very accurate"
2257!     call showmatgau(BOMsumb,"BOMsumb",0,"f14.8",6)
2258end if
2259
2260!Output BOM
2261if (itask==1) then
2262    open(10,file="BOM.txt",status="replace")
2263    if (wfntype==0.or.wfntype==2.or.wfntype==3) then
2264        do ibas=1,numrealatt
2265            write(10,"('Orbital overlap matrix of basin',i6)") ibas
2266            call showmatgau(BOM(:,:,ibas),"",1,"f14.8",10)
2267            write(10,*)
2268        end do
2269    else if (wfntype==1.or.wfntype==4) then
2270        do ibas=1,numrealatt
2271            write(10,"('Alpha part of orbital overlap matrix of basin',i6)") ibas
2272            call showmatgau(BOMa(:,:,ibas),"",1,"f14.8",10)
2273            if (nmatsizeb>0) then
2274                write(10,"('Beta part of orbital overlap matrix of basin',i6)") ibas
2275                call showmatgau(BOMb(:,:,ibas),"",1,"f14.8",10)
2276            end if
2277            write(10,*)
2278        end do
2279    end if
2280    close(10)
2281    write(*,*)
2282    write(*,*) "Done, the matrices have been exported to BOM.txt in current folder"
2283    return
2284end if
2285
2286!Generate DI and LI
2287!RHF,R-post-HF, DI_A,B=2��[i,j]dsqrt(n_i*n_j)*S_i,j_A * S_i,j_B     where i and j are non-spin orbitals
2288write(*,*) "Generating LI and DI..."
2289if (any(MOocc<0)) then
2290    where(MOocc<0) MOocc=0
2291    write(*,"(a)") " Note: Some occupation numbers are negative. In order to make the calculation feasible, they have been set to zero"
2292    write(*,*) "Press ENTER to continue"
2293    read(*,*)
2294end if
2295if (wfntype==0.or.wfntype==3) then
2296    DI=0D0
2297    do ibas=1,numrealatt
2298        do jbas=ibas,numrealatt
2299            do iorb=1,nmatsize
2300                do jorb=1,nmatsize
2301                    DI(ibas,jbas)=DI(ibas,jbas)+dsqrt(MOocc(iorb)*MOocc(jorb))*BOM(iorb,jorb,ibas)*BOM(iorb,jorb,jbas)
2302                end do
2303            end do
2304        end do
2305        LI(ibas)=DI(ibas,ibas)
2306    end do
2307    DI=2*(DI+transpose(DI))
2308    do ibas=1,numrealatt !Diagonal terms are the sum of corresponding row or column
2309        DI(ibas,ibas)=0D0
2310        DI(ibas,ibas)=sum(DI(ibas,:))
2311    end do
2312else if (wfntype==2) then !ROHF
2313    DIa=0D0
2314    DIb=0D0
2315    do nmoclose=nmatsize,1,-1
2316        if (MOtype(nmoclose)==0) exit
2317    end do
2318    do ibas=1,numrealatt
2319        do jbas=ibas,numrealatt
2320            !Alpha
2321            do iorb=1,nmatsize !The number of close or alpha orbitals needed to be concerned
2322                occi=MOocc(iorb)
2323                if (MOtype(iorb)==0) occi=occi/2D0
2324                do jorb=1,nmatsize
2325                    occj=MOocc(jorb)
2326                    if (MOtype(jorb)==0) occj=occj/2D0
2327                    DIa(ibas,jbas)=DIa(ibas,jbas)+dsqrt(occi*occj)*BOM(iorb,jorb,ibas)*BOM(iorb,jorb,jbas)
2328                end do
2329            end do
2330            !Beta
2331            do iorb=1,nmoclose !The number of close orbitals needed to be concerned
2332                do jorb=1,nmoclose
2333                    DIb(ibas,jbas)=DIb(ibas,jbas)+dsqrt(MOocc(iorb)/2D0*MOocc(jorb)/2D0)*BOM(iorb,jorb,ibas)*BOM(iorb,jorb,jbas)
2334                end do
2335            end do
2336        end do
2337        LIa(ibas)=DIa(ibas,ibas)
2338        LIb(ibas)=DIb(ibas,ibas)
2339    end do
2340    DIa=2*(DIa+transpose(DIa))
2341    DIb=2*(DIb+transpose(DIb))
2342    do ibas=1,numrealatt !Diagonal terms are the sum of corresponding row or column
2343        DIa(ibas,ibas)=0D0
2344        DIb(ibas,ibas)=0D0
2345        DIa(ibas,ibas)=sum(DIa(ibas,:))
2346        DIb(ibas,ibas)=sum(DIb(ibas,:))
2347    end do
2348    !Combine alpha and Beta to total
2349    DI=DIa+DIb
2350    LI=LIa+LIb
2351!UHF,U-post-HF   DI(A,B)=2��[i,j]dsqrt(n_i*n_j)*S_i,j_A * S_i,j_B   where i and j are spin orbitals
2352else if (wfntype==1.or.wfntype==4) then
2353    !Alpha
2354    DIa=0D0
2355    do ibas=1,numrealatt
2356        do jbas=ibas,numrealatt
2357            do iorb=1,nmatsizea
2358                do jorb=1,nmatsizea
2359                    DIa(ibas,jbas)=DIa(ibas,jbas)+dsqrt(MOocc(iorb)*MOocc(jorb))*BOMa(iorb,jorb,ibas)*BOMa(iorb,jorb,jbas)
2360                end do
2361            end do
2362        end do
2363        LIa(ibas)=DIa(ibas,ibas)
2364    end do
2365    DIa=2*(DIa+transpose(DIa))
2366    !Beta
2367    if (nmatsizeb>0) then
2368        DIb=0D0
2369        MOinit=iendalpha+1 !Index range of beta orbitals
2370        MOend=iendalpha+nmatsizeb
2371        do ibas=1,numrealatt
2372            do jbas=ibas,numrealatt
2373                do iorb=MOinit,MOend
2374                    iorbtmp=iorb-iendalpha
2375                    do jorb=MOinit,MOend
2376                        jorbtmp=jorb-iendalpha
2377                        DIb(ibas,jbas)=DIb(ibas,jbas)+dsqrt(MOocc(iorb)*MOocc(jorb))*BOMb(iorbtmp,jorbtmp,ibas)*BOMb(iorbtmp,jorbtmp,jbas)
2378                    end do
2379                end do
2380            end do
2381            LIb(ibas)=DIb(ibas,ibas)
2382        end do
2383        DIb=2*(DIb+transpose(DIb))
2384    end if
2385    do ibas=1,numrealatt !Diagonal terms are the sum of corresponding row or column
2386        DIa(ibas,ibas)=0D0
2387        DIb(ibas,ibas)=0D0
2388        DIa(ibas,ibas)=sum(DIa(ibas,:))
2389        DIb(ibas,ibas)=sum(DIb(ibas,:))
2390    end do
2391    !Combine alpha and Beta to total
2392    DI=DIa+DIb
2393    LI=LIa+LIb
2394end if
2395
2396call walltime(nwalltime2)
2397write(*,"(' Calculation took up',i8,' seconds wall clock time',/)")  nwalltime2-nwalltime1
2398
2399!Output LI and DI
2400ioutid=6
2401100 write(ioutid,"(a,/)") " Note: Diagonal terms are the sum of corresponding row or column elements"
2402if (wfntype==1.or.wfntype==2.or.wfntype==4) then !UHF,ROHF,U-post-HF, output each spin component first
2403    !Alpha
2404    call showmatgau(DIa,"Delocalization index matrix for alpha spin",0,"f14.8",ioutid)
2405    write(ioutid,*)
2406    write(ioutid,*) "Localization index for alpha electron:"
2407    do ibas=1,numrealatt
2408        write(ioutid,"(i6,':',f7.3)",advance='no') ibas,LIa(ibas)
2409        if (mod(ibas,5)==0) write(ioutid,*)
2410    end do
2411    write(ioutid,*)
2412    write(ioutid,*)
2413    !Beta
2414    call showmatgau(DIb,"Delocalization index matrix for beta spin",0,"f14.8",ioutid)
2415    write(ioutid,*)
2416    write(ioutid,*) "Localization index for beta spin:"
2417    do ibas=1,numrealatt
2418        write(ioutid,"(i6,':',f7.3)",advance='no') ibas,LIb(ibas)
2419        if (mod(ibas,5)==0) write(ioutid,*)
2420    end do
2421    write(ioutid,*)
2422    write(ioutid,*)
2423end if
2424!Alpha+Beta
2425call showmatgau(DI,"Total delocalization index matrix",0,"f14.8",ioutid)
2426write(ioutid,*)
2427write(ioutid,*) "Total localization index:"
2428do ibas=1,numrealatt
2429    write(ioutid,"(i6,':',f7.3)",advance='no') ibas,LI(ibas)
2430    if (mod(ibas,5)==0) write(ioutid,*)
2431end do
2432if (ioutid==10) then
2433    write(*,*) "Done!"
2434    close(10)
2435    return
2436end if
2437write(*,*)
2438write(*,*)
2439write(*,*) "If also output the result to LIDI.txt in current folder? y/n"
2440read(*,*) selectyn
2441if (selectyn=='y'.or.selectyn=='Y') then
2442    open(10,file="LIDI.txt",status="replace")
2443    ioutid=10
2444    goto 100
2445end if
2446end subroutine
2447
2448
2449
2450!!------- Integrate a real space function in the basins with multi-level refinement, indenspensible for Laplacian
2451!DEPRECATED, since mixed type of grids perform better and faster
2452subroutine integratebasinrefine
2453use defvar
2454use util
2455use function
2456use basinintmod
2457implicit real*8(a-h,o-z)
2458character c200tmp*200
2459real*8 intval(-1:numatt),basinvol(-1:numatt),intvalpriv(-1:numatt),basinvolpriv(-1:numatt)
2460integer walltime1,walltime2
2461real*8 :: critlevel1=0.1D0,critlevel2=0.5D0,critlevel3=1D0
2462integer :: nrefine1=1,nrefine2=2,nrefine3=5,nrefine4=7
2463if (ifuncbasin/=1) then
2464    write(*,*) "Error: This function is only applicable to AIM basins!"
2465    return
2466end if
2467
2468do while(.true.)
2469    write(*,*) "-2 Return"
2470    write(*,*) "-1 Print and set parameters for multi-level refinement"
2471    call selfunc_interface(ifuncint)
2472    if (ifuncint==-2) then
2473        return
2474    else if (ifuncint==-1) then
2475        write(*,"(a)") " Note: A number n means each grid in corresponding value range will be transformed &
2476        as n^3 grids around it during the integration to gain a higher integration accuracy. n=1 means the grids will remain unchanged. &
2477        The ""value range"" referred here is the value range of the function used to generate basins"
2478        write(*,*) "The value range and the times of refinement:"
2479        write(*,"(' Smaller than ',f10.5,' :',i4)") critlevel1,nrefine1
2480        write(*,"(' Between',f10.5,' and ',f10.5,' :',i4)") critlevel1,critlevel2,nrefine2
2481        write(*,"(' Between',f10.5,' and ',f10.5,' :',i4)") critlevel2,critlevel3,nrefine3
2482        write(*,"(' Larger than  ',f10.5,' :',i4)") critlevel3,nrefine4
2483        write(*,*)
2484        write(*,*) "Please input three thresholds to define the four ranges, e.g. 0.1,0.5,1"
2485        write(*,*) "Note: Press ENTER button can retain current values unchanged"
2486        read(*,"(a)") c200tmp
2487        if (c200tmp/=' ') read(c200tmp,*) critlevel1,critlevel2,critlevel3
2488        write(*,*) "Input the times of refinement for the grids in the four ranges, e.g. 1,2,5,7"
2489        write(*,*) "Note: Press ENTER button can retain current values unchanged"
2490        read(*,"(a)") c200tmp
2491        if (c200tmp/=' ') read(c200tmp,*) nrefine1,nrefine2,nrefine3,nrefine4
2492        write(*,*) "Done!"
2493        write(*,*)
2494    end if
2495end do
2496
2497call walltime(walltime1)
2498CALL CPU_TIME(time_begin)
2499write(*,*) "Integrating, please wait..."
2500intval=0D0
2501basinvol=0D0
2502ifinish=0
2503nthreads=getNThreads()
2504!$OMP PARALLEL private(ix,iy,iz,ixref,iyref,izref,ndiv,irealatt,rnowx,rnowy,rnowz,rnowxtmp,rnowytmp,rnowztmp,orgxref,orgyref,orgzref,dxref,dyref,dzref,&
2505!$OMP tmpval,tmpvalrefine,intvalpriv,basinvolpriv,nrefine) shared(intval,basinvol,ifinish) NUM_THREADS(nthreads)
2506intvalpriv=0D0
2507basinvolpriv=0D0
2508!$OMP do schedule(DYNAMIC)
2509do iz=2,nz-1
2510    do iy=2,ny-1
2511        do ix=2,nx-1
2512            if (cubmat(ix,iy,iz)<critlevel1) then
2513                nrefine=nrefine1 !The number of point to represent each edge
2514            else if (cubmat(ix,iy,iz)<critlevel2) then
2515                nrefine=nrefine2
2516            else if (cubmat(ix,iy,iz)<critlevel3) then
2517                nrefine=nrefine3
2518            else
2519                nrefine=nrefine4
2520            end if
2521            ndiv=nrefine**3
2522            rnowx=orgx+(ix-1)*dx
2523            rnowy=orgy+(iy-1)*dy
2524            rnowz=orgz+(iz-1)*dz
2525            orgxref=rnowx-dx/2 !Take corner position as original point of microcycle
2526            orgyref=rnowy-dy/2
2527            orgzref=rnowz-dz/2
2528            dxref=dx/nrefine
2529            dyref=dy/nrefine
2530            dzref=dz/nrefine
2531            tmpval=0D0
2532            do ixref=1,nrefine
2533                do iyref=1,nrefine
2534                    do izref=1,nrefine
2535                        rnowxtmp=orgxref+(ixref-0.5D0)*dxref
2536                        rnowytmp=orgyref+(iyref-0.5D0)*dyref
2537                        rnowztmp=orgzref+(izref-0.5D0)*dzref
2538                        if (ifuncint==-1) then
2539                            tmpvalrefine=cubmattmp(ix,iy,iz)
2540                        else if (ifuncint==0) then
2541                            tmpvalrefine=cubmat(ix,iy,iz)
2542                        else
2543                            tmpvalrefine=calcfuncall(ifuncint,rnowxtmp,rnowytmp,rnowztmp)
2544                        end if
2545                        tmpval=tmpval+tmpvalrefine/ndiv
2546                    end do
2547                end do
2548            end do
2549            irealatt=gridbas(ix,iy,iz)
2550            intvalpriv(irealatt)=intvalpriv(irealatt)+tmpval
2551            basinvolpriv(irealatt)=basinvolpriv(irealatt)+1
2552        end do
2553    end do
2554    ifinish=ifinish+1
2555    write(*,"(' Finished:',i5,'/',i5)") ifinish,nz
2556end do
2557!$OMP end do
2558!$OMP CRITICAL
2559    intval=intval+intvalpriv
2560    basinvol=basinvol+basinvolpriv
2561!$OMP end CRITICAL
2562!$OMP END PARALLEL
2563dvol=dx*dy*dz
2564intval=intval*dvol
2565basinvol=basinvol*dvol !Basin volume
2566write(*,*) "  #Basin          Integral        Volume(a.u.^3)"
2567do irealatt=1,numrealatt
2568    write(*,"(i8,f22.10,f20.8)") irealatt,intval(irealatt),basinvol(irealatt)
2569end do
2570write(*,"(' Sum of above values:',f20.8)") sum(intval(1:numrealatt))
2571if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==0)) write(*,"(' Integral of unassigned grids:',f20.8)") intval(0)
2572if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==-1)) write(*,"(' Integral of the grids travelled to box boundary:',f20.8)") intval(-1)
2573
2574CALL CPU_TIME(time_end)
2575call walltime(walltime2)
2576write(*,"(' Integrating basins took up CPU time',f12.2,'s, wall clock time',i10,'s')") time_end-time_begin,walltime2-walltime1
2577end subroutine
2578
2579
2580
2581!!------- Integrate AIM basins using mixed atomic-center and uniform grids
2582! itype=1: Integrate specific real space function
2583! itype=2: Integrate specific real space function with exact refinement of basin boundary
2584! itype=3: Integrate specific real space function with approximate refinement of basin boundary by exact+linear interpolation
2585! itype=10: Produce electric multipole moments
2586!NNA and ECP are supported
2587!Notice that the grid generated must cover the whole space!
2588subroutine integratebasinmix(itype)
2589use defvar
2590use util
2591use function
2592use basinintmod
2593use topo
2594implicit real*8(a-h,o-z)
2595!p suffix means private variable for parallel mode
2596real*8 intval(-1:numrealatt,20),intvalp(-1:numrealatt,20) !Up to 20 functions can be evaluated and stored simultaneously
2597real*8 basinvol(-1:numrealatt),basinvolp(-1:numrealatt),basinvdwvol(-1:numrealatt),basinvdwvolp(-1:numrealatt) !vdW is used to obtain the basin volume enclosed by 0.001 isosurface of rho
2598real*8 trustrad(numrealatt),intbasinthread(numrealatt),intbasin(numrealatt)
2599real*8 dens,grad(3),hess(3,3),k1(3),k2(3),k3(3),k4(3),xarr(nx),yarr(ny),zarr(nz)
2600real*8,allocatable :: potx(:),poty(:),potz(:),potw(:)
2601real*8,allocatable :: rhogrid(:,:,:),rhogradgrid(:,:,:,:) !Used in shubin's 2nd project
2602real*8,allocatable :: prorhogrid(:,:,:) !Used in integrating deformation density
2603type(content),allocatable :: gridatt(:) !Record correspondence between attractor and grid
2604integer att2atm(numrealatt) !The attractor corresponds to which atom. If =0, means this is a NNA
2605real*8 eleint(-1:numrealatt),xint(-1:numrealatt),yint(-1:numrealatt),zint(-1:numrealatt),&
2606xxint(-1:numrealatt),yyint(-1:numrealatt),zzint(-1:numrealatt),xyint(-1:numrealatt),yzint(-1:numrealatt),xzint(-1:numrealatt)
2607real*8 eleintp(-1:numrealatt),xintp(-1:numrealatt),yintp(-1:numrealatt),zintp(-1:numrealatt),&
2608xxintp(-1:numrealatt),yyintp(-1:numrealatt),zzintp(-1:numrealatt),xyintp(-1:numrealatt),yzintp(-1:numrealatt),xzintp(-1:numrealatt)
2609integer walltime1,walltime2,radpotAIM,sphpotAIM
2610real*8 prodensgrad(0:4),gridval(100000,6) !Used for storing various information during integrating inside sphere
2611character c80tmp*80,selectyn
2612nbeckeiter=8
2613if (ifuncbasin/=1) then
2614    write(*,"(a)") " Error: This function is only applicable to AIM basins! That means in option 1, you should select electron density to construct the basins."
2615    return
2616end if
2617
2618if (ispecial==0) then
2619    if (itype==1.or.itype==2.or.itype==3) then
2620        write(*,*) "Please select integrand:"
2621        write(*,*) "-2 Return"
2622        write(*,*) "-1 Deformation density"
2623        call selfunc_interface(ifuncint)
2624        if (ifuncint==-2) then
2625            return
2626        else if (ifuncint==-1) then
2627            call setpromol
2628        end if
2629    end if
2630else if (ispecial==1) then
2631    continue !Don't let user to select integrand
2632else if (ispecial==2) then
2633    call setpromol !Don't let user to select integrand
2634    expcutoff=1 !Use full accuracy for shubin's 2nd project
2635end if
2636
2637call walltime(walltime1)
2638CALL CPU_TIME(time_begin)
2639intval=0D0
2640basinvol=0D0
2641basinvdwvol=0D0
2642eleint=0D0
2643xint=0D0
2644yint=0D0
2645zint=0D0
2646xxint=0D0
2647yyint=0D0
2648zzint=0D0
2649xyint=0D0
2650yzint=0D0
2651xzint=0D0
2652numcp=0
2653
2654att2atm=0
2655!Determine trust radius and then integrate in the trust sphere
2656!We use CPpos to record the center of the trust sphere
2657write(*,*) "Integrating in trust sphere..."
2658do iatt=1,numrealatt !Cycle each attractors
2659    !Refine the crude position of attractor by exact newton method
2660    do iatm=1,ncenter
2661        disttest=dsqrt( (realattxyz(iatt,1)-a(iatm)%x)**2+(realattxyz(iatt,2)-a(iatm)%y)**2+(realattxyz(iatt,3)-a(iatm)%z)**2 )
2662        if (disttest<0.3D0) then
2663            att2atm(iatt)=iatm
2664            write(*,"(' Attractor',i6,' corresponds to atom',i6,' (',a,')')") iatt,iatm,a(iatm)%name
2665            numcpold=numcp
2666            call findcp(a(iatm)%x,a(iatm)%y,a(iatm)%z,1,0)
2667            if (numcp==numcpold) then
2668                write(*,*) "Note: Unable to locate exact CP position! Use nuclear position"
2669                numcp=numcp+1
2670                CPpos(1,numcp)=a(iatm)%x
2671                CPpos(2,numcp)=a(iatm)%y
2672                CPpos(3,numcp)=a(iatm)%z
2673            end if
2674!             write(*,"(' Coordinate after refinement:',3f16.8)") CPpos(:,numcp)
2675            exit
2676        end if
2677    end do
2678    if (att2atm(iatt)==0) then
2679        write(*,"(a,i6,a)") " Warning: Unable to determine the attractor",iatt," belongs to which atom!"
2680        write(*,"(a)") " If this is a non-nuclear attractor, simply press ENTER button to continue. If you used pseudopotential &
2681        and this attractor corresponds to the cluster of all maxima of its valence electron, then input the index of this atom (e.g. 9). &
2682        Else you should input q to return and regenerate basins with smaller grid spacing"
2683        read(*,"(a)") c80tmp
2684        if (c80tmp=='q') then
2685            return
2686        else if (c80tmp==" ") then
2687            numcpold=numcp
2688            call findcp(realattxyz(iatt,1),realattxyz(iatt,2),realattxyz(iatt,3),1,0)
2689            if (numcp==numcpold) then
2690                write(*,*) "Unable to locate exact CP position! Exit..."
2691                return
2692            end if
2693        else !ECP, input the corresponding atom by user
2694            read(c80tmp,*) iatmtmp
2695            att2atm(iatt)=iatmtmp
2696            numcp=numcp+1
2697            CPpos(1,numcp)=a(iatmtmp)%x
2698            CPpos(2,numcp)=a(iatmtmp)%y
2699            CPpos(3,numcp)=a(iatmtmp)%z
2700        end if
2701    end if
2702
2703    !Determine trust radius and set integration points and weight
2704    radpotAIM=200
2705    parm=1
2706    isettrustrad=0
2707    nintgrid=0 !Then number of integration grids within trust radius
2708    if (allocated(gridatt)) deallocate(gridatt) !Used to record grids in trust sphere of this attractor
2709    allocate(gridatt(radpotAIM*500))
2710    do ish=1,radpotAIM !Cycle each radial shell. Radius distance is from near to far
2711        if (isettrustrad==1) exit !The trust radius has been finally determined in last shell cycle
2712        !Becke, namely the second-kind Gauss-Chebyshev
2713        itmp=radpotAIM+1-ish !Invert ish to make radr from near to far
2714        radx=cos(itmp*pi/(radpotAIM+1D0))
2715        radr=(1+radx)/(1-radx)*parm
2716        radw=2*pi/(radpotAIM+1)*parm**3 *(1+radx)**2.5D0/(1-radx)**3.5D0 *4*pi
2717!         !Handy, also known as Euler-Maclaurin. See: Murray, C. W.; Handy, N. C.; Laming, G. J. Mol Phys 1993, 78, 997
2718!         radx=dfloat(ish)/(radpotAIM+1D0)
2719!         radr=radx**2/(1-radx)**2*parm
2720!         radw=2*radx**5/dfloat(radpotAIM+1)/(1-radx)**7*parm**3 *4*pi
2721
2722        !Set Lebedev grids according to shell radius
2723        !For more inner shell, the distribution is more akin to spherically symmetric, therefore lower number of grids could be used
2724        if (att2atm(iatt)==0) then !NNA
2725            sphpotAIM=302
2726        else
2727            radtmp=covr(a(att2atm(iatt))%index)
2728            if (radr<0.2D0*radtmp) then
2729                sphpotAIM=26
2730            else if (radr<0.5D0*radtmp) then
2731                sphpotAIM=74
2732            else if (radr<0.8D0*radtmp) then
2733                sphpotAIM=146
2734            else
2735                sphpotAIM=194
2736            end if
2737        end if
2738        if (allocated(potx)) deallocate(potx,poty,potz,potw)
2739        allocate(potx(sphpotAIM),poty(sphpotAIM),potz(sphpotAIM),potw(sphpotAIM))
2740        call Lebedevgen(sphpotAIM,potx,poty,potz,potw)
2741        !Combine radial point and weights with angular part, and make them centered at current attractor
2742        gridatt( nintgrid+1:nintgrid+sphpotAIM )%x=radr*potx+CPpos(1,numcp)
2743        gridatt( nintgrid+1:nintgrid+sphpotAIM )%y=radr*poty+CPpos(2,numcp)
2744        gridatt( nintgrid+1:nintgrid+sphpotAIM )%z=radr*potz+CPpos(3,numcp)
2745        gridatt( nintgrid+1:nintgrid+sphpotAIM )%value=radw*potw
2746        !Find out trust radius for present attractor
2747        !If in a shell, the angle between "linking line between nucleus and a shell point" and "gradient vector of this point" &
2748        !is larger than 45 degree, then this shell is trust radius
2749        angmax=0
2750        if (att2atm(iatt)==0) then
2751            radinit=0
2752        else
2753            radrinit=0.15D0
2754            if (a(att2atm(iatt))%index>2) radrinit=0.5D0
2755        end if
2756        if (isettrustrad==0.and.radr>radrinit) then
2757            do isphpt=1,sphpotAIM
2758                xtmp=gridatt(nintgrid+isphpt)%x
2759                ytmp=gridatt(nintgrid+isphpt)%y
2760                ztmp=gridatt(nintgrid+isphpt)%z
2761                call calchessmat_dens(1,xtmp,ytmp,ztmp,dens,grad,hess) !Only value and gradient
2762                dirx=CPpos(1,numcp)-xtmp
2763                diry=CPpos(2,numcp)-ytmp
2764                dirz=CPpos(3,numcp)-ztmp
2765                angtmp=vecang(dirx,diry,dirz,grad(1),grad(2),grad(3))
2766                if (angtmp>angmax) angmax=angtmp
2767                if (angtmp>45) then
2768                    write(*,"(' The trust radius of attractor',i6,' is',f10.3,' Bohr',/)") iatt,trustrad(iatt)
2769                    isettrustrad=1 !The radius of last shell should be the final trust radius. Now exit
2770                    exit
2771                end if
2772            end do
2773            if (isettrustrad==0) trustrad(iatt)=radr !Passed this shell and temporarily set the radius as trust radius. Continue to enlarge the trust radius, until reached angmax>45 degree
2774        end if
2775        nintgrid=nintgrid+sphpotAIM
2776    end do
2777    if (isettrustrad==0) then !Trust radius was not set after run over all shells
2778        trustrad(iatt)=1000 !Infinite, for isolated atom
2779        if (ispecial==2) trustrad(iatt)=20 !For Shubin's 2nd project, should not be as large as 1000, because for a point very far from nucleus the relative entropy cannot be evaluated
2780        write(*,"(' The trust radius of attractor',i6,' is',f10.3,' Bohr',/)") iatt,trustrad(iatt)
2781    end if
2782
2783    !Use DFT integration algorithm to integrate the region inside trust radius
2784nthreads=getNThreads()
2785!$OMP PARALLEL private(ipt,ptx,pty,ptz,rx,ry,rz,dist,tmps,iter,switchwei,intvalp,&
2786!$OMP eleintp,xintp,yintp,zintp,xxintp,yyintp,zzintp,xyintp,yzintp,xzintp,tmpval,tmpval2,tmpval3,tmpval4) &
2787!$OMP shared(intval,gridval) NUM_THREADS(nthreads)
2788    intvalp=0D0
2789    eleintp=0D0
2790    xintp=0D0
2791    yintp=0D0
2792    zintp=0D0
2793    xxintp=0D0
2794    yyintp=0D0
2795    zzintp=0D0
2796    xyintp=0D0
2797    yzintp=0D0
2798    xzintp=0D0
2799!$OMP do schedule(DYNAMIC)
2800    do ipt=1,nintgrid
2801        ptx=gridatt(ipt)%x
2802        pty=gridatt(ipt)%y
2803        ptz=gridatt(ipt)%z
2804        rx=ptx-CPpos(1,numcp) !The relative distance between current point to corresponding attractor
2805        ry=pty-CPpos(2,numcp)
2806        rz=ptz-CPpos(3,numcp)
2807        !Calculate switching function
2808        dist=dsqrt(rx*rx+ry*ry+rz*rz)
2809        tmps=dist-trustrad(iatt)
2810        if (tmps>1) then
2811            switchwei=0
2812        else if (tmps<-1) then
2813            switchwei=1
2814        else
2815            do iter=1,nbeckeiter
2816                tmps=1.5D0*(tmps)-0.5D0*(tmps)**3
2817            end do
2818            switchwei=0.5D0*(1-tmps)
2819        end if
2820        gridval(ipt,3)=switchwei
2821!         if (dist>trustrad(iatt)) cycle !Discrete separation between atomic-center and uniform integration
2822        if (switchwei<1D-7) cycle !For saving computational time
2823
2824        if (itype==1.or.itype==2.or.itype==3) then !Integrate a function
2825            if (ifuncint==-1) then !Deformation density, store molecular density of present center temporarily
2826                gridval(ipt,1)=fdens(ptx,pty,ptz)
2827            else if (ispecial==0) then !Normal case
2828                tmpval=calcfuncall(ifuncint,ptx,pty,ptz)
2829                intvalp(iatt,1)=intvalp(iatt,1)+gridatt(ipt)%value*tmpval*switchwei
2830            else if (ispecial==1) then !For Shubin's project, simultaneously output many properties
2831                tmpval=infoentro(2,ptx,pty,ptz) !Shannon entropy density
2832                tmpval2=Fisherinfo(1,ptx,pty,ptz) !Fisher information density
2833                tmpval3=weizsacker(ptx,pty,ptz) !Steric energy
2834                tmpval4=fdens(ptx,pty,ptz) !Electron density
2835                intvalp(iatt,1)=intvalp(iatt,1)+gridatt(ipt)%value*tmpval*switchwei
2836                intvalp(iatt,2)=intvalp(iatt,2)+gridatt(ipt)%value*tmpval2*switchwei
2837                intvalp(iatt,3)=intvalp(iatt,3)+gridatt(ipt)%value*tmpval3*switchwei
2838                intvalp(iatt,4)=intvalp(iatt,4)+gridatt(ipt)%value*tmpval4*switchwei
2839            else if (ispecial==2) then !For Shubin's 2nd project
2840                call calchessmat_dens(1,ptx,pty,ptz,gridval(ipt,1),gridval(ipt,4:6),hess)
2841                gridval(ipt,2)=sum(gridval(ipt,4:6)**2)
2842            end if
2843        else if (itype==10) then !Calculate multipole moment
2844            tmpval=gridatt(ipt)%value*fdens(ptx,pty,ptz)*switchwei
2845            eleintp(iatt)=eleintp(iatt)+tmpval
2846            xintp(iatt)=xintp(iatt)+rx*tmpval
2847            yintp(iatt)=yintp(iatt)+ry*tmpval
2848            zintp(iatt)=zintp(iatt)+rz*tmpval
2849            xxintp(iatt)=xxintp(iatt)+rx*rx*tmpval
2850            yyintp(iatt)=yyintp(iatt)+ry*ry*tmpval
2851            zzintp(iatt)=zzintp(iatt)+rz*rz*tmpval
2852            xyintp(iatt)=xyintp(iatt)+rx*ry*tmpval
2853            yzintp(iatt)=yzintp(iatt)+ry*rz*tmpval
2854            xzintp(iatt)=xzintp(iatt)+rx*rz*tmpval
2855        end if
2856    end do
2857!$OMP end do
2858!$OMP CRITICAL
2859    if (itype==1.or.itype==2.or.itype==3) then
2860        intval=intval+intvalp
2861    else if (itype==10) then
2862        eleint=eleint+eleintp
2863        xint=xint+xintp
2864        yint=yint+yintp
2865        zint=zint+zintp
2866        xxint=xxint+xxintp
2867        yyint=yyint+yyintp
2868        zzint=zzint+zzintp
2869        xyint=xyint+xyintp
2870        yzint=yzint+yzintp
2871        xzint=xzint+xzintp
2872    end if
2873!$OMP end CRITICAL
2874!$OMP END PARALLEL
2875
2876    !Some special cases:
2877    if (ispecial==2) then !Shubin's 2nd project, integrate relative Shannon and Fisher information
2878        !Current gridval content: 1=rho, 2=gradrho^2, 3=switchwei, 4=gradrho_x, 5=gradrho_y, 6=gradrho_z
2879        call dealloall
2880        write(*,"(' Loading ',a,/)") trim(custommapname(att2atm(iatt)))
2881        call readwfn(custommapname(att2atm(iatt)),1)
2882        do ipt=1,nintgrid
2883            switchwei=gridval(ipt,3)
2884            if (switchwei<1D-7) cycle
2885            ptx=gridatt(ipt)%x
2886            pty=gridatt(ipt)%y
2887            ptz=gridatt(ipt)%z
2888            call calchessmat_dens(1,ptx,pty,ptz,prodensgrad(0),prodensgrad(1:3),hess)
2889            prodens=prodensgrad(0) !rho0_A
2890            prodensgrad2=sum(prodensgrad(1:3)**2)
2891            !Relative Shannon entropy, integrate rho*log(rho/rho0_A)]
2892            tmpval=gridval(ipt,1)*log(gridval(ipt,1)/prodens)
2893            intval(iatt,1)=intval(iatt,1)+gridatt(ipt)%value*tmpval*switchwei
2894            !Relative Fisher information (old and incorrect implementation)
2895            tmpval=gridval(ipt,2)/gridval(ipt,1)-prodensgrad2/prodens
2896            intval(iatt,2)=intval(iatt,2)+gridatt(ipt)%value*tmpval*switchwei
2897            !Relative Fisher information (new and correct implementation)
2898            tmpvalx=gridval(ipt,4)/gridval(ipt,1) - prodensgrad(1)/prodens
2899            tmpvaly=gridval(ipt,5)/gridval(ipt,1) - prodensgrad(2)/prodens
2900            tmpvalz=gridval(ipt,6)/gridval(ipt,1) - prodensgrad(3)/prodens
2901            tmpval=gridval(ipt,1)*(tmpvalx**2+tmpvaly**2+tmpvalz**2)
2902            intval(iatt,3)=intval(iatt,3)+gridatt(ipt)%value*tmpval*switchwei
2903        end do
2904        call dealloall
2905        call readinfile(firstfilename,1) !Retrieve to first loaded file(whole molecule) to calc real rho again
2906    else if (ifuncint==-1) then !Integrate deformation density
2907        gridval(:,2)=0D0
2908        do iatm=1,ncenter_org !Cycle each atom to calculate deformation density at all integration grid
2909            call dealloall
2910            call readwfn(custommapname(iatm),1)
2911            do ipt=1,nintgrid
2912                switchwei=gridval(ipt,3)
2913                if (switchwei<1D-7) cycle
2914                gridval(ipt,2)=gridval(ipt,2)+fdens(gridatt(ipt)%x,gridatt(ipt)%y,gridatt(ipt)%z)
2915            end do
2916        end do
2917        do ipt=1,nintgrid !Now gridval(ipt,1/2/3) records actual, promolecular density and weight at ipt
2918            defdens=gridval(ipt,1)-gridval(ipt,2)
2919            intval(iatt,1)=intval(iatt,1)+gridatt(ipt)%value*defdens*gridval(ipt,3)
2920        end do
2921        call dealloall
2922        call readinfile(firstfilename,1) !Retrieve to first loaded file(whole molecule) to calc real rho again
2923    end if
2924end do !End cycle attractors
2925
2926if (itype==1.or.itype==2.or.itype==3) then
2927    write(*,*) "Integration result inside trust spheres"
2928    if (ispecial/=2) then
2929        write(*,*) "  #Sphere       Integral(a.u.)"
2930        do iatt=1,numrealatt
2931            write(*,"(i8,f22.10)") iatt,intval(iatt,1)
2932        end do
2933        write(*,"(' Sum of above values:',f20.8)") sum(intval(1:numrealatt,1))
2934    else if (ispecial==2) then !Shubin's 2nd project
2935        write(*,*) "  #Sphere      Rel.Shannon         Rel.Fisher(old)     Rel.Fisher(new)"
2936        do iatt=1,numrealatt
2937            write(*,"(i8,3f20.10)") iatt,intval(iatt,1:3)
2938        end do
2939        write(*,"(' Sum of rel.Shannon:',f20.8)") sum(intval(1:numrealatt,1))
2940        write(*,"(' Sum of rel.Fisher(old): ',f20.8)") sum(intval(1:numrealatt,2))
2941        write(*,"(' Sum of rel.Fisher(new): ',f20.8)") sum(intval(1:numrealatt,3))
2942    end if
2943end if
2944
2945!Set coordinate of uniform grids
2946dvol=dx*dy*dz
2947do ix=1,nx
2948    xarr(ix)=orgx+(ix-1)*dx
2949end do
2950do iy=1,ny
2951    yarr(iy)=orgy+(iy-1)*dy
2952end do
2953do iz=1,nz
2954    zarr(iz)=orgz+(iz-1)*dz
2955end do
2956
2957!--------- Integrating uniform grids, basin boundary grids will be calculated in the later stage
2958!NOTE: For shubin's 2nd project or deformation density, do not integrate here. At next stage boundary grids will be updated, and then at the next stage,&
2959!they will be integrated by a special module. Because at each grid if we reload atomic .wfn file will be too time consuming
2960if (ispecial==2.or.ifuncint==-1) goto 10
2961write(*,*)
2962write(*,*) "Integrating uniform grids..."
2963ifinish=0
2964nthreads=getNThreads()
2965!$OMP PARALLEL private(ix,iy,iz,iatt,icp,rnowx,rnowy,rnowz,rx,ry,rz,tmpval,tmpval2,tmpval3,intvalp,basinvolp,basinvdwvolp,dist,tmps,iter,switchwei,&
2966!$OMP eleintp,xintp,yintp,zintp,xxintp,yyintp,zzintp,xyintp,xzintp,yzintp) shared(intval,basinvol,basinvdwvol,ifinish) NUM_THREADS(nthreads)
2967intvalp=0D0
2968basinvolp=0D0
2969basinvdwvolp=0D0
2970eleintp=0D0
2971xintp=0D0
2972yintp=0D0
2973zintp=0D0
2974xxintp=0D0
2975yyintp=0D0
2976zzintp=0D0
2977xyintp=0D0
2978yzintp=0D0
2979xzintp=0D0
2980!$OMP do schedule(DYNAMIC)
2981do iz=2,nz-1
2982    rnowz=zarr(iz)
2983    do iy=2,ny-1
2984        rnowy=yarr(iy)
2985        do ix=2,nx-1
2986            rnowx=xarr(ix)
2987            if ((itype==2.or.itype==3).and.interbasgrid(ix,iy,iz) .eqv. .true.) cycle !If refine boundary grid at next stage, we don't calculate them at present stage
2988!             if (iz==nint(nz/2D0)) write(1,"('C',3f14.8)") rnowx*b2a,rnowy*b2a,rnowz*b2a !Examine grid distribution
2989            iatt=gridbas(ix,iy,iz)
2990!             do icp=1,numcp
2991!                 dist=dsqrt( (rnowx-CPpos(1,icp))**2+(rnowy-CPpos(2,icp))**2+(rnowz-CPpos(3,icp))**2 )
2992!                 if (disttest<trustrad(icp)) cycle cycix !The function inside trust radius is integrated by DFT integration
2993!             end do
2994            rx=rnowx-CPpos(1,iatt) !The relative distance between current point to corresponding attractor
2995            ry=rnowy-CPpos(2,iatt)
2996            rz=rnowz-CPpos(3,iatt)
2997            !Calculate switching function at current grid
2998            dist=dsqrt(rx*rx+ry*ry+rz*rz)
2999            tmps=dist-trustrad(iatt)
3000            if (tmps>1) then
3001                switchwei=0
3002            else if (tmps<-1) then
3003                switchwei=1
3004            else
3005                do iter=1,nbeckeiter
3006                    tmps=1.5D0*(tmps)-0.5D0*(tmps)**3
3007                end do
3008                switchwei=0.5D0*(1-tmps)
3009            end if
3010            switchwei=1-switchwei
3011            basinvolp(iatt)=basinvolp(iatt)+1 !Calculate basin volume
3012            if (cubmat(ix,iy,iz)>0.001D0) basinvdwvolp(iatt)=basinvdwvolp(iatt)+1
3013            if (switchwei<1D-7) cycle !For saving time
3014            if (itype==1.or.itype==2.or.itype==3) then
3015                if (ispecial==0) then
3016                    if (ifuncint==1) then !Electron density on each grid has already been calculated
3017                        tmpval=cubmat(ix,iy,iz)
3018                    else
3019                        tmpval=calcfuncall(ifuncint,rnowx,rnowy,rnowz)
3020                    end if
3021                    intvalp(iatt,1)=intvalp(iatt,1)+tmpval*switchwei
3022                else if (ispecial==1) then !For RCY
3023                    tmpval=infoentro(2,rnowx,rnowy,rnowz) !Shannon entropy density, see JCP,126,191107 for example
3024                    tmpval2=Fisherinfo(1,rnowx,rnowy,rnowz) !Fisher information density, see JCP,126,191107 for example
3025                    tmpval3=weizsacker(rnowx,rnowy,rnowz) !Steric energy
3026                    tmpval4=fdens(rnowx,rnowy,rnowz) !Electron density
3027                    intvalp(iatt,1)=intvalp(iatt,1)+tmpval*switchwei
3028                    intvalp(iatt,2)=intvalp(iatt,2)+tmpval2*switchwei
3029                    intvalp(iatt,3)=intvalp(iatt,3)+tmpval3*switchwei
3030                    intvalp(iatt,4)=intvalp(iatt,4)+tmpval4*switchwei
3031                end if
3032            else if (itype==10) then
3033                tmpval=cubmat(ix,iy,iz)*switchwei
3034                eleintp(iatt)=eleintp(iatt)+tmpval
3035                xintp(iatt)=xintp(iatt)+rx*tmpval
3036                yintp(iatt)=yintp(iatt)+ry*tmpval
3037                zintp(iatt)=zintp(iatt)+rz*tmpval
3038                xxintp(iatt)=xxintp(iatt)+rx*rx*tmpval
3039                yyintp(iatt)=yyintp(iatt)+ry*ry*tmpval
3040                zzintp(iatt)=zzintp(iatt)+rz*rz*tmpval
3041                xyintp(iatt)=xyintp(iatt)+rx*ry*tmpval
3042                yzintp(iatt)=yzintp(iatt)+ry*rz*tmpval
3043                xzintp(iatt)=xzintp(iatt)+rx*rz*tmpval
3044            end if
3045        end do
3046    end do
3047    ifinish=ifinish+1
3048    if (ifuncint/=1) write(*,"(' Integrating uniform grids, finished:',i5,'/',i5)") ifinish,nz
3049end do
3050!$OMP end do
3051!$OMP CRITICAL
3052if (itype==1.or.itype==2.or.itype==3) then
3053    intval=intval+intvalp*dvol
3054    basinvol=basinvol+basinvolp*dvol
3055    basinvdwvol=basinvdwvol+basinvdwvolp*dvol
3056else if (itype==10) then
3057    eleint=eleint+eleintp*dvol
3058    xint=xint+xintp*dvol
3059    yint=yint+yintp*dvol
3060    zint=zint+zintp*dvol
3061    xxint=xxint+xxintp*dvol
3062    yyint=yyint+yyintp*dvol
3063    zzint=zzint+zzintp*dvol
3064    xyint=xyint+xyintp*dvol
3065    yzint=yzint+yzintp*dvol
3066    xzint=xzint+xzintp*dvol
3067end if
3068!$OMP end CRITICAL
3069!$OMP END PARALLEL
3070
307110 continue
3072!---- Exact refinement with/without multi-level splitting of boundary grids
3073if (itype==2.or.itype==3) then
3074    if (itype==3) then !Calculate grid data of gradient of electron density used to linear interpolation to obtain the value at any point
3075        write(*,*)
3076        call gengradmat
3077    end if
3078    write(*,*)
3079    nrk4lim=100
3080    nrk4gradswitch=40
3081    hsizeinit=0.25D0
3082    ifinish=0
3083nthreads=getNThreads()
3084!$OMP PARALLEL private(ix,iy,iz,iatt,rnowx,rnowy,rnowz,rx,ry,rz,tmpval,tmpval2,tmpval3,intvalp,basinvolp,basinvdwvolp,dist,tmps,iter,switchwei,&
3085!$OMP rnowxtmp,rnowytmp,rnowztmp,orgxref,orgyref,orgzref,dxref,dyref,dzref,ixref,iyref,izref,nrefine,ndiv,&
3086!$OMP k1,k2,k3,k4,dens,denshold,grad,hess,iattref,xtmp,ytmp,ztmp,irk4,hsize,ixtest,iytest,iztest,tmpdist) shared(intval,basinvol,basinvdwvol,ifinish) NUM_THREADS(nthreads)
3087    intvalp=0D0
3088    basinvolp=0D0
3089    basinvdwvolp=0D0
3090!$OMP do schedule(DYNAMIC)
3091    do iz=2,nz-1
3092        rnowz=zarr(iz)
3093        do iy=2,ny-1
3094            rnowy=yarr(iy)
3095            do ix=2,nx-1
3096                rnowx=xarr(ix)
3097                if (interbasgrid(ix,iy,iz) .eqv. .false.) cycle
3098!                 if (cubmat(ix,iy,iz)>0.001D0) then
3099!                     nrefine=2 !3 is the best
3100!                 else if (cubmat(ix,iy,iz)>0.001D0) then !0.0001 is the best
3101!                     nrefine=1
3102!                 else
3103!                     nrefine=1
3104!                 end if
3105                 nrefine=1
3106                ndiv=nrefine**3
3107                orgxref=rnowx-dx/2 !Take corner position as original point of microcycle
3108                orgyref=rnowy-dy/2
3109                orgzref=rnowz-dz/2
3110                dxref=dx/nrefine
3111                dyref=dy/nrefine
3112                dzref=dz/nrefine
3113                do ixref=1,nrefine
3114                    do iyref=1,nrefine
3115                        do izref=1,nrefine
3116                            rnowxtmp=orgxref+(ixref-0.5D0)*dxref !Coordinate of current refined grid
3117                            rnowytmp=orgyref+(iyref-0.5D0)*dyref
3118                            rnowztmp=orgzref+(izref-0.5D0)*dzref
3119                            if (cubmat(ix,iy,iz)<=0.001D0) then !Only refine the boundary inside vdW surface
3120                                iattref=gridbas(ix,iy,iz)
3121                            else
3122                                xtmp=rnowxtmp !This point will continuously move in the iteration
3123                                ytmp=rnowytmp
3124                                ztmp=rnowztmp
3125                                hsize=hsizeinit
3126                                densold=0D0
3127                                !** Tracing steepest ascent trajectory using 4-order Runge-Kutta (RK4)
3128        cycrk4:                    do irk4=1,nrk4lim
3129                                    !For full accuracy refinement, or the first step, or when interpolation gradient works worse,&
3130                                    !namely has not converge until nrk4gradswitch, use exactly evaluated gradient
3131                                    if (itype==2.or.irk4==1.or.irk4==2.or.irk4>nrk4gradswitch) then
3132                                        if (itype==3.and.irk4==nrk4gradswitch+1) then !Interpolated gradient doesn't work well, switch to full accuracy, reset the coordinate
3133                                            xtmp=rnowxtmp
3134                                            ytmp=rnowytmp
3135                                            ztmp=rnowztmp
3136                                            hsize=hsizeinit
3137                                        end if
3138                                        call calchessmat_dens(1,xtmp,ytmp,ztmp,dens,grad,hess) !Only value and gradient
3139                                        if (dens<densold-1D-10) then
3140                                            hsize=hsize*0.75D0 !Reduce step size if density decrease
3141                                        else if (dens>densold+1D-10) then
3142                                            hsize=hsizeinit !Recover to initial step size
3143                                        end if
3144                                        denshold=dens
3145                                        k1=grad/dsqrt(sum(grad**2))
3146                                        call calchessmat_dens(1,xtmp+hsize/2*k1(1),ytmp+hsize/2*k1(2),ztmp+hsize/2*k1(3),dens,grad,hess) !Only value and gradient
3147                                        k2=grad/dsqrt(sum(grad**2))
3148                                        call calchessmat_dens(1,xtmp+hsize/2*k2(1),ytmp+hsize/2*k2(2),ztmp+hsize/2*k2(3),dens,grad,hess) !Only value and gradient
3149                                        k3=grad/dsqrt(sum(grad**2))
3150                                        call calchessmat_dens(1,xtmp+hsize*k3(1),ytmp+hsize*k3(2),ztmp+hsize*k3(3),dens,grad,hess) !Only value and gradient
3151                                        k4=grad/dsqrt(sum(grad**2))
3152                                    else !Using the gradients evaluated by trilinear interpolation from pre-calculated grid data to save computational time
3153                                        call linintp3dvec(xtmp,ytmp,ztmp,grad) !Only value and gradient
3154!                                         if (dens<densold-1D-10) then
3155!                                             hsize=hsize*0.75D0
3156!                                         else if (dens>densold+1D-10) then
3157!                                             hsize=hsizeinit !Recover to initial step size
3158!                                         end if
3159!                                         denshold=dens
3160                                        k1=grad/dsqrt(sum(grad**2))
3161                                        call linintp3dvec(xtmp+hsize/2*k1(1),ytmp+hsize/2*k1(2),ztmp+hsize/2*k1(3),grad)
3162                                        k2=grad/dsqrt(sum(grad**2))
3163                                        call linintp3dvec(xtmp+hsize/2*k2(1),ytmp+hsize/2*k2(2),ztmp+hsize/2*k2(3),grad)
3164                                        k3=grad/dsqrt(sum(grad**2))
3165                                        call linintp3dvec(xtmp+hsize*k3(1),ytmp+hsize*k3(2),ztmp+hsize*k3(3),grad)
3166                                        k4=grad/dsqrt(sum(grad**2))
3167                                    end if
3168                                    xtmp=xtmp+hsize/6*(k1(1)+2*k2(1)+2*k3(1)+k4(1)) !Update current coordinate
3169                                    ytmp=ytmp+hsize/6*(k1(2)+2*k2(2)+2*k3(2)+k4(2))
3170                                    ztmp=ztmp+hsize/6*(k1(3)+2*k2(3)+2*k3(3)+k4(3))
3171                                    !Check if current position has entered trust radius of an attractor
3172                                    do iatttmp=1,numrealatt
3173                                        dist=dsqrt( (xtmp-CPpos(1,iatttmp))**2+(ytmp-CPpos(2,iatttmp))**2+(ztmp-CPpos(3,iatttmp))**2 )
3174                                        if (dist<trustrad(iatttmp)) then
3175                                            iattref=iatttmp
3176                                            exit cycrk4
3177                                        end if
3178                                    end do
3179                                    !Check if the closest grid and its 26 neighbours have the same attribution, if yes, employ its attribution then exit
3180                                    do ixtest=2,nx-1
3181                                        tmpdist=abs(xtmp-xarr(ixtest))
3182                                        if (tmpdist<dx/2D0) exit
3183                                    end do
3184                                    do iytest=2,ny-1
3185                                        tmpdist=abs(ytmp-yarr(iytest))
3186                                        if (tmpdist<dy/2D0) exit
3187                                    end do
3188                                    do iztest=2,nz-1
3189                                        tmpdist=abs(ztmp-zarr(iztest))
3190                                        if (tmpdist<dz/2D0) exit
3191                                    end do
3192                                    iattref=gridbas(ixtest,iytest,iztest)
3193                                    do imove=1,26
3194                                        if ( gridbas(ixtest+vec26x(imove),iytest+vec26y(imove),iztest+vec26z(imove))/=iattref ) exit
3195                                    end do
3196                                    if (imove==27) exit !Successfully passed neighbour test
3197                                end do cycrk4
3198                                if (irk4==nrk4lim+1) then !Didn't enter trust radius or didn't approach a grid who and whose neighbour have the same attribution
3199                                    write(*,*) "Warning: Exceeded the step limit of steepest ascent process!"
3200                                    iattref=gridbas(ix,iy,iz) !Use its original attribution
3201                                end if
3202!                                 write(*,*) irk4
3203                            end if
3204                            gridbas(ix,iy,iz)=iattref !Update attribution of boundary grids
3205                            !Calculate switching function at current grid
3206                            rx=rnowxtmp-CPpos(1,iattref) !The relative distance between current point to corresponding attractor
3207                            ry=rnowytmp-CPpos(2,iattref)
3208                            rz=rnowztmp-CPpos(3,iattref)
3209                            dist=dsqrt(rx*rx+ry*ry+rz*rz)
3210                            tmps=dist-trustrad(iattref)
3211                            if (tmps>1) then
3212                                switchwei=0
3213                            else if (tmps<-1) then
3214                                switchwei=1
3215                            else
3216                                do iter=1,nbeckeiter
3217                                    tmps=1.5D0*(tmps)-0.5D0*(tmps)**3
3218                                end do
3219                                switchwei=0.5D0*(1-tmps)
3220                            end if
3221                            switchwei=1-switchwei
3222                            basinvolp(iattref)=basinvolp(iattref)+1D0/ndiv !Calculate boundary basin volume
3223                            if (cubmat(ix,iy,iz)>0.001D0) basinvdwvolp(iattref)=basinvdwvolp(iattref)+1D0/ndiv
3224                            if (ispecial==2.or.ifuncint==-1) then
3225                                continue !Don't calculate function value, but only update attribution of boundary grids at this stage
3226                            else if (ispecial==0) then
3227                                tmpval=calcfuncall(ifuncint,rnowxtmp,rnowytmp,rnowztmp)
3228                                intvalp(iattref,1)=intvalp(iattref,1)+tmpval*switchwei/ndiv
3229                            else if (ispecial==1) then
3230                                tmpval=infoentro(2,rnowxtmp,rnowytmp,rnowztmp) !Shannon entropy density, see JCP,126,191107 for example
3231                                tmpval2=Fisherinfo(1,rnowxtmp,rnowytmp,rnowztmp) !Fisher information density, see JCP,126,191107 for example
3232                                tmpval3=weizsacker(rnowxtmp,rnowytmp,rnowztmp) !Steric energy
3233                                tmpval4=fdens(rnowxtmp,rnowytmp,rnowztmp) !Electron density
3234                                intvalp(iattref,1)=intvalp(iattref,1)+tmpval*switchwei/ndiv
3235                                intvalp(iattref,2)=intvalp(iattref,2)+tmpval2*switchwei/ndiv
3236                                intvalp(iattref,3)=intvalp(iattref,3)+tmpval3*switchwei/ndiv
3237                                intvalp(iattref,4)=intvalp(iattref,4)+tmpval4*switchwei/ndiv
3238                            end if
3239                        end do !End refine grid
3240                    end do
3241                end do
3242
3243            end do !End cycle ix grid
3244        end do
3245        ifinish=ifinish+1
3246        write(*,"(' Integrating grids at basin boundary, finished:',i5,'/',i5)") ifinish,nz
3247    end do
3248!$OMP end do
3249!$OMP CRITICAL
3250    intval=intval+intvalp*dvol
3251    basinvol=basinvol+basinvolp*dvol
3252    basinvdwvol=basinvdwvol+basinvdwvolp*dvol
3253!$OMP end CRITICAL
3254!$OMP END PARALLEL
3255    call detectinterbasgrd(6)
3256    write(*,*) "Basin boundary has been updated"
3257    numinterbas=count(interbasgrid .eqv. .true.)
3258    write(*,"(' The number of interbasin grids:',i12)") numinterbas
3259end if
3260
3261!Below are special modules for the cases when density of atom in free-state are involved
3262if (ispecial==2) then !Shubin's 2nd project, integrate relative Shannon and relative Fisher information
3263    allocate(rhogrid(nx,ny,nz),rhogradgrid(3,nx,ny,nz))
3264    ifinish=0
3265    write(*,*)
3266    write(*,*) "Calculating electron density and its gradient for actual system at each grid"
3267nthreads=getNThreads()
3268!$OMP PARALLEL DO SHARED(rhogrid,rhogradgrid,ifinish) PRIVATE(ix,iy,iz,ptx,pty,ptz) schedule(dynamic) NUM_THREADS(nthreads)
3269    do iz=2,nz-1
3270        ptz=zarr(iz)
3271        do iy=2,ny-1
3272            pty=yarr(iy)
3273            do ix=2,nx-1
3274                ptx=xarr(ix)
3275                call calchessmat_dens(1,ptx,pty,ptz,rhogrid(ix,iy,iz),rhogradgrid(:,ix,iy,iz),hess)
3276            end do
3277        end do
3278!$OMP CRITICAL
3279        ifinish=ifinish+1
3280        write(*,"(' Finished',i6,' /',i6)") ifinish,nz-1
3281!$OMP end CRITICAL
3282    end do
3283!$OMP end PARALLEL DO
3284    write(*,*)
3285    write(*,*) "Calculating electron density and its gradient for free-state atom at each grid"
3286    do iatt=1,numrealatt !Cycle each attractors
3287        write(*,"(' Processing ',a)") trim(custommapname(att2atm(iatt)))
3288        call dealloall
3289        call readwfn(custommapname(att2atm(iatt)),1)
3290!$OMP PARALLEL private(intvalp,ix,iy,iz,ptx,pty,ptz,rx,ry,rz,dist,tmps,switchwei,&
3291!$OMP rho,rhograd2,prodens,prodensgrad,prodensgrad2,tmpval1,tmpval2,tmpval3,tmpx,tmpy,tmpz) shared(intval) NUM_THREADS(nthreads)
3292        intvalp=0D0
3293!$OMP do schedule(DYNAMIC)
3294        do iz=2,nz-1
3295            ptz=zarr(iz)
3296            do iy=2,ny-1
3297                pty=yarr(iy)
3298                do ix=2,nx-1
3299                    ptx=xarr(ix)
3300                    if (gridbas(ix,iy,iz)==iatt) then
3301                        !Calculate switching function at current grid
3302                        rx=ptx-CPpos(1,iatt) !The relative distance between current point to corresponding attractor
3303                        ry=pty-CPpos(2,iatt)
3304                        rz=ptz-CPpos(3,iatt)
3305                        dist=dsqrt(rx*rx+ry*ry+rz*rz)
3306                        tmps=dist-trustrad(iatt)
3307                        if (tmps>1) then
3308                            switchwei=0
3309                        else if (tmps<-1) then
3310                            switchwei=1
3311                        else
3312                            do iter=1,nbeckeiter
3313                                tmps=1.5D0*(tmps)-0.5D0*(tmps)**3
3314                            end do
3315                            switchwei=0.5D0*(1-tmps)
3316                        end if
3317                        switchwei=1-switchwei
3318                        rho=rhogrid(ix,iy,iz)
3319                        rhograd2=sum(rhogradgrid(1:3,ix,iy,iz)**2)
3320                        call calchessmat_dens(1,ptx,pty,ptz,prodens,prodensgrad(1:3),hess)
3321                        prodensgrad2=sum(prodensgrad(1:3)**2)
3322                        !Relative Shannon entropy
3323                        tmpval1=rho*log(rho/prodens)
3324                        intvalp(iatt,1)=intvalp(iatt,1)+tmpval1*switchwei
3325                        !Relative Fisher information (old and incorrect form)
3326                        tmpval2=rhograd2/rho-prodensgrad2/prodens
3327                        intvalp(iatt,2)=intvalp(iatt,2)+tmpval2*switchwei
3328                        !Relative Fisher information (new and correct form)
3329                        tmpx=rhogradgrid(1,ix,iy,iz)/rho-prodensgrad(1)/prodens
3330                        tmpy=rhogradgrid(2,ix,iy,iz)/rho-prodensgrad(2)/prodens
3331                        tmpz=rhogradgrid(3,ix,iy,iz)/rho-prodensgrad(3)/prodens
3332                        tmpval3=(tmpx**2+tmpy**2+tmpz**2)*rho
3333                        intvalp(iatt,3)=intvalp(iatt,3)+tmpval3*switchwei
3334                    end if
3335                end do
3336            end do
3337        end do
3338!$OMP end do
3339!$OMP CRITICAL
3340        intval=intval+intvalp*dvol
3341!$OMP end CRITICAL
3342!$OMP END PARALLEL
3343    end do
3344    deallocate(rhogrid,rhogradgrid)
3345    call dealloall
3346    write(*,"(' Reloading ',a)") trim(firstfilename)
3347    call readinfile(firstfilename,1) !Retrieve to first loaded file(whole molecule)
3348else if (ifuncint==-1) then !Deformation density
3349    allocate(prorhogrid(nx,ny,nz))
3350    write(*,*)
3351    write(*,*) "Calculating promolecular density at each grid"
3352    prorhogrid=0D0
3353    do iatm=1,ncenter_org !Cycle each atom
3354        write(*,"(' Processing atom',i6,a,'...')") iatm,a_org(iatm)%name
3355        call dealloall
3356        call readwfn(custommapname(iatm),1)
3357nthreads=getNThreads()
3358!$OMP PARALLEL DO SHARED(prorhogrid) PRIVATE(ix,iy,iz) schedule(dynamic) NUM_THREADS(nthreads)
3359        do iz=2,nz-1
3360            do iy=2,ny-1
3361                do ix=2,nx-1
3362                    prorhogrid(ix,iy,iz)=prorhogrid(ix,iy,iz)+fdens(xarr(ix),yarr(iy),zarr(iz))
3363                end do
3364            end do
3365        end do
3366!$OMP end PARALLEL DO
3367    end do
3368    do iatt=1,numrealatt !Cycle each attractors
3369        do iz=2,nz-1
3370            do iy=2,ny-1
3371                do ix=2,nx-1
3372                    if (gridbas(ix,iy,iz)==iatt) then
3373                        !Calculate switching function at current grid
3374                        rx=xarr(ix)-CPpos(1,iatt) !The relative distance between current point to corresponding attractor
3375                        ry=yarr(iy)-CPpos(2,iatt)
3376                        rz=zarr(iz)-CPpos(3,iatt)
3377                        dist=dsqrt(rx*rx+ry*ry+rz*rz)
3378                        tmps=dist-trustrad(iatt)
3379                        if (tmps>1) then
3380                            switchwei=0
3381                        else if (tmps<-1) then
3382                            switchwei=1
3383                        else
3384                            do iter=1,nbeckeiter
3385                                tmps=1.5D0*(tmps)-0.5D0*(tmps)**3
3386                            end do
3387                            switchwei=0.5D0*(1-tmps)
3388                        end if
3389                        switchwei=1-switchwei
3390                        defdens=cubmat(ix,iy,iz)-prorhogrid(ix,iy,iz)
3391                        intval(iatt,1)=intval(iatt,1)+defdens*switchwei*dvol
3392                    end if
3393                end do
3394            end do
3395        end do
3396    end do
3397    deallocate(prorhogrid)
3398    call dealloall
3399    call readinfile(firstfilename,1) !Retrieve to first loaded file(whole molecule) to calc real rho again
3400end if
3401
3402!!----------- Output SUMMARY
3403if (itype==1.or.itype==2.or.itype==3) then !Integrate specific real space function(s)
3404    write(*,*)
3405    if (ifuncint==1) then
3406        write(*,*) "Total result:"
3407        write(*,*) "  #Basin        Integral(a.u.)      Vol(Bohr^3)    Vol(rho>0.001)"
3408        do iatt=1,numrealatt
3409            write(*,"(i8,f22.10,2f16.3)") iatt,intval(iatt,1),basinvol(iatt),basinvdwvol(iatt)
3410        end do
3411        write(*,"(' Sum of above integrals:',f20.8)") sum(intval(1:numrealatt,1))
3412        write(*,"(' Sum of basin volumes (rho>0.001):',f12.3,' Bohr^3')") sum(basinvdwvol(1:numrealatt))
3413        if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==0)) write(*,"(' Integral of unassigned grids:',f20.8)") intval(0,1)
3414        if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==-1)) write(*,"(' Integral of the grids travelled to box boundary:',f20.8)") intval(-1,1)
3415        write(*,*)
3416        rnormfac=sum(intval(1:numrealatt,1))/(nelec+nEDFelec) !The electrons represented by EDF must be taken into account!
3417        write(*,"(' Normalization factor of the integral of electron density is',f12.6)") rnormfac
3418        write(*,*) "The atomic charges after normalization and atomic volumes:"
3419        do iatm=0,ncenter
3420            do iatt=1,numrealatt
3421                if (att2atm(iatt)==iatm.and.iatm==0) then
3422                    write(*,"(i7,' (NNA)   Charge:',f12.6,'     Volume:',f10.3,' Bohr^3')") iatt,-intval(iatt,1)/rnormfac,basinvdwvol(iatt)
3423                else if (att2atm(iatt)==iatm.and.iatm/=0) then
3424                    if (nEDFelec==0) then !Normal case, all electron basis or using pseudopotential but not accompanied by EDF
3425                        write(*,"(i7,' (',a,')    Charge:',f12.6,'     Volume:',f10.3,' Bohr^3')") iatm,a(iatm)%name,a(iatm)%charge-intval(iatt,1)/rnormfac,basinvdwvol(iatt)
3426                    else !EDF is used, so using a(iatm)%index instead of a(iatm)%charge
3427                        write(*,"(i7,' (',a,')    Charge:',f12.6,'     Volume:',f10.3,' Bohr^3')") iatm,a(iatm)%name,a(iatm)%index-intval(iatt,1)/rnormfac,basinvdwvol(iatt)
3428                    end if
3429                end if
3430            end do
3431        end do
3432    else
3433        if (ispecial==0) then
3434            write(*,*) "Total result:"
3435            write(*,*) "    Atom       Basin       Integral(a.u.)   Vol(Bohr^3)   Vol(rho>0.001)"
3436            do iatm=0,ncenter
3437                do iatt=1,numrealatt
3438                    if (att2atm(iatt)==iatm.and.iatm==0) then
3439                        write(*,"('      NNA   ',i8,f20.8,2f14.3)") iatt,intval(iatt,1),basinvol(iatt),basinvdwvol(iatt)
3440                    else if (att2atm(iatt)==iatm.and.iatm/=0) then
3441                        write(*,"(i7,' (',a,')',i8,f20.8,2f14.3)") iatm,a(iatm)%name,iatt,intval(iatt,1),basinvol(iatt),basinvdwvol(iatt)
3442                    end if
3443                end do
3444            end do
3445            write(*,"(' Sum of above integrals:',f23.8)") sum(intval(1:numrealatt,1))
3446            write(*,"(' Sum of basin volumes (rho>0.001):',f12.3,' Bohr^3')") sum(basinvdwvol(1:numrealatt))
3447            if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==0)) write(*,"(' Integral of unassigned grids:',f20.8)") intval(0,1)
3448            if (any(gridbas(2:nx-1,2:ny-1,2:nz-1)==-1)) write(*,"(' Integral of the grids travelled to box boundary:',f20.8)") intval(-1,1)
3449        else if (ispecial==1) then
3450            write(*,*) "Total result:"
3451            write(*,*) "    Atom       Basin     Shannon       Fisher      Steric ene  Vol(rho>0.001)"
3452            do iatm=0,ncenter
3453                do iatt=1,numrealatt
3454                    if (att2atm(iatt)==iatm.and.iatm==0) then
3455                        write(*,"('      NNA   ',i8,3f14.7,f13.5)") iatt,intval(iatt,1),intval(iatt,1:3),basinvdwvol(iatt)
3456                    else if (att2atm(iatt)==iatm.and.iatm/=0) then
3457                        write(*,"(i7,' (',a,')',i8,3f14.7,f13.5)") iatm,a(iatm)%name,iatt,intval(iatt,1:3),basinvdwvol(iatt)
3458                    end if
3459                end do
3460            end do
3461            write(*,"(' Total Shannon entropy:   ',f23.8)") sum(intval(1:numrealatt,1))
3462            write(*,"(' Total Fisher information:',f23.8)") sum(intval(1:numrealatt,2))
3463            write(*,"(' Total steric energy:     ',f23.8)") sum(intval(1:numrealatt,3))
3464            write(*,"(' Sum of basin volumes (rho>0.001):',f12.3,' Bohr^3')") sum(basinvdwvol(1:numrealatt))
3465            rnormfac=sum(intval(1:numrealatt,4))/(nelec+nEDFelec) !The electrons represented by EDF must be taken into account!
3466            write(*,"(/,' Normalization factor of the integral of electron density is',f12.6)") rnormfac
3467            write(*,*) "The atomic charges after normalization and atomic volumes:"
3468            do iatm=0,ncenter
3469                do iatt=1,numrealatt
3470                    if (att2atm(iatt)==iatm.and.iatm==0) then
3471                        write(*,"(i7,' (NNA)   Charge:',f12.6,'     Volume:',f10.3,' Bohr^3')") iatt,-intval(iatt,1)/rnormfac,basinvdwvol(iatt)
3472                    else if (att2atm(iatt)==iatm.and.iatm/=0) then
3473                        if (nEDFelec==0) then !Normal case, all electron basis or using pseudopotential but not accompanied by EDF
3474                            write(*,"(i7,' (',a,')    Charge:',f12.6,'     Volume:',f10.3,' Bohr^3')") iatm,a(iatm)%name,a(iatm)%charge-intval(iatt,4)/rnormfac,basinvdwvol(iatt)
3475                        else !EDF is used, so using a(iatm)%index instead of a(iatm)%charge
3476                            write(*,"(i7,' (',a,')    Charge:',f12.6,'     Volume:',f10.3,' Bohr^3')") iatm,a(iatm)%name,a(iatm)%index-intval(iatt,4)/rnormfac,basinvdwvol(iatt)
3477                        end if
3478                    end if
3479                end do
3480            end do
3481        else if (ispecial==2) then
3482            write(*,*) "Total result:"
3483            write(*,*) "    Atom      Basin        Rel.Shannon     Rel.Fisher(old)     Rel.Fisher(new)"
3484            do iatm=1,ncenter
3485                do iatt=1,numrealatt
3486                    if (att2atm(iatt)==iatm) write(*,"(i7,' (',a,')',i7,3f20.8)") iatm,a(iatm)%name,iatt,intval(iatt,1:3)
3487                end do
3488            end do
3489            write(*,"(' Sum of relat_Shannon:     ',f23.8)") sum(intval(1:numrealatt,1))
3490            write(*,"(' Sum of relat_Fisher(old): ',f23.8)") sum(intval(1:numrealatt,2))
3491            write(*,"(' Sum of relat_Fisher(new): ',f23.8)") sum(intval(1:numrealatt,3))
3492        end if
3493    end if
3494    write(*,*)
3495else if (itype==10) then !Electric multipole moment
3496    ioutid=6
3497101    eleinttot=0D0
3498    dipelextot=0D0
3499    dipeleytot=0D0
3500    dipeleztot=0D0
3501    if (ioutid==6) write(*,*)
3502    write(ioutid,*) "Note: All units shown below are in a.u.!"
3503    write(ioutid,*)
3504    do iatm=0,ncenter
3505        do iatt=1,numrealatt
3506            if (att2atm(iatt)/=iatm) cycle
3507            if (iatm==0) then
3508                write(ioutid,"(' Result of NNA',i6)") iatt
3509            else
3510                write(ioutid,"(' Result of atom',i6,' (',a,')')") iatm,a(iatm)%name
3511            end if
3512            write(ioutid,"(' Basin electric monopole moment:',f12.6)") -eleint(iatt)
3513            write(ioutid,"(' Basin electric dipole moment:')")
3514            write(ioutid,"('  X=',f12.6,'  Y=',f12.6,'  Z=',f12.6,'  Magnitude=',f12.6)") -xint(iatt),-yint(iatt),-zint(iatt),sqrt(xint(iatt)**2+yint(iatt)**2+zint(iatt)**2)
3515            eleinttot=eleinttot+eleint(iatt)
3516            dipelex=-eleint(iatt)*CPpos(1,iatt)+(-xint(iatt)) !Contribution to molecular total dipole moment
3517            dipeley=-eleint(iatt)*CPpos(2,iatt)+(-yint(iatt))
3518            dipelez=-eleint(iatt)*CPpos(3,iatt)+(-zint(iatt))
3519            dipelextot=dipelextot+dipelex
3520            dipeleytot=dipeleytot+dipeley
3521            dipeleztot=dipeleztot+dipelez
3522            write(ioutid,"(' Basin electron contribution to molecular dipole moment:')")
3523            write(ioutid,"('  X=',f12.6,'  Y=',f12.6,'  Z=',f12.6,'  Magnitude=',f12.6)") dipelex,dipeley,dipelez,sqrt(dipelex**2+dipeley**2+dipelez**2)
3524            write(ioutid,"(' Basin electric quadrupole moment (Cartesian form):')")
3525            rrint=xxint(iatt)+yyint(iatt)+zzint(iatt)
3526            QXX=-(3*xxint(iatt)-rrint)/2
3527            QYY=-(3*yyint(iatt)-rrint)/2
3528            QZZ=-(3*zzint(iatt)-rrint)/2
3529            write(ioutid,"(' QXX=',f12.6,'  QXY=',f12.6,'  QXZ=',f12.6)") QXX,-(3*xyint(iatt))/2,-(3*xzint(iatt))/2
3530            write(ioutid,"(' QYX=',f12.6,'  QYY=',f12.6,'  QYZ=',f12.6)") -(3*xyint(iatt))/2,QYY,-(3*yzint(iatt))/2
3531            write(ioutid,"(' QZX=',f12.6,'  QZY=',f12.6,'  QZZ=',f12.6)") -(3*xzint(iatt))/2,-(3*yzint(iatt))/2,QZZ
3532            write(ioutid,"( ' The magnitude of electric quadrupole moment (Cartesian form):',f12.6)") dsqrt(2D0/3D0*(QXX**2+QYY**2+QZZ**2))
3533            R20=-(3*zzint(iatt)-rrint)/2D0 !Notice that the negative sign, because electrons carry negative charge
3534            R2n1=-dsqrt(3D0)*yzint(iatt)
3535            R2p1=-dsqrt(3D0)*xzint(iatt)
3536            R2n2=-dsqrt(3D0)*xyint(iatt)
3537            R2p2=-dsqrt(3D0)/2D0*(xxint(iatt)-yyint(iatt))
3538            write(ioutid,"(' Electric quadrupole moments (Spherical harmonic form):')")
3539            write(ioutid,"(' Q_2,0 =',f11.6,'   Q_2,-1=',f11.6,'   Q_2,1=',f11.6)") R20,R2n1,R2p1
3540            write(ioutid,"(' Q_2,-2=',f11.6,'   Q_2,2 =',f11.6)") R2n2,R2p2
3541            write(ioutid,"( ' Magnitude: |Q_2|=',f12.6)") dsqrt(R20**2+R2n1**2+R2p1**2+R2n2**2+R2p2**2)
3542            write(ioutid,*)
3543        end do
3544    end do
3545    !Output overall electric properties
3546    dipnucx=sum(a(:)%x*a(:)%charge)
3547    dipnucy=sum(a(:)%y*a(:)%charge)
3548    dipnucz=sum(a(:)%z*a(:)%charge)
3549    write(ioutid,"( ' Molecular net charge:',f12.6)") sum(a%charge)-eleinttot
3550    write(ioutid,"( ' Nuclear contribution to molecular dipole moment:')")
3551    write(ioutid,"(' X=',f12.6,' Y=',f12.6,' Z=',f12.6,' Norm=',f12.6)") dipnucx,dipnucy,dipnucz,sqrt(dipnucx**2+dipnucy**2+dipnucz**2)
3552    write(ioutid,"( ' Electron contribution to molecular dipole moment:')")
3553    write(ioutid,"(' X=',f12.6,' Y=',f12.6,' Z=',f12.6,' Norm=',f12.6)") dipelextot,dipeleytot,dipeleztot,sqrt(dipelextot**2+dipeleytot**2+dipeleztot**2)
3554    dipmolx=dipnucx+dipelextot
3555    dipmoly=dipnucy+dipeleytot
3556    dipmolz=dipnucz+dipeleztot
3557    write(ioutid,"( ' Molecular dipole moment:')")
3558    write(ioutid,"(' X=',f12.6,' Y=',f12.6,' Z=',f12.6,' Norm=',f12.6)") dipmolx,dipmoly,dipmolz,sqrt(dipmolx**2+dipmoly**2+dipmolz**2)
3559    if (ioutid==6) write(*,*)
3560    if (ioutid==10) then
3561        close(10)
3562        write(*,*) "Done!"
3563        return
3564    end if
3565end if
3566
3567CALL CPU_TIME(time_end)
3568call walltime(walltime2)
3569write(*,"(' Integrating basins took up CPU time',f12.2,'s, wall clock time',i10,'s')") time_end-time_begin,walltime2-walltime1
3570
3571if (itype==10) then
3572    write(*,*)
3573    write(*,*) "If also output the result to multipol.txt in current folder? y/n"
3574    read(*,*) selectyn
3575    if (selectyn=='y'.or.selectyn=='Y') then
3576        ioutid=10
3577        open(10,file="multipol.txt",status="replace")
3578        goto 101
3579    end if
3580end if
3581end subroutine
3582
3583
3584
3585
3586
3587!!------ Generate grid data of gradient of electron density, used to refine basin boundary
3588subroutine gengradmat
3589use defvar
3590use function
3591implicit real*8 (a-h,o-z)
3592real*8 wfnval(nmo),wfnderv(3,nmo),gradrho(3),EDFgrad(3),sumgrad2
3593if (allocated(cubmatvec)) then
3594    if (size(cubmatvec,2)==nx.and.size(cubmatvec,3)==ny.and.size(cubmatvec,4)==nz) return !Already generated
3595    deallocate(cubmatvec)
3596end if
3597allocate(cubmatvec(3,nx,ny,nz))
3598ifinish=0
3599nthreads=getNThreads()
3600!$OMP PARALLEL DO SHARED(cubmatvec,ifinish) PRIVATE(ix,iy,iz,tmpx,tmpy,tmpz,wfnval,wfnderv,gradrho,imo) schedule(dynamic) NUM_THREADS(nthreads)
3601do iz=1,nz
3602    tmpz=orgz+(iz-1)*dz
3603    do iy=1,ny
3604        tmpy=orgy+(iy-1)*dy
3605        do ix=1,nx
3606            tmpx=orgx+(ix-1)*dx
3607            call orbderv(2,1,nmo,tmpx,tmpy,tmpz,wfnval,wfnderv)
3608            gradrho=0D0
3609            do imo=1,nmo
3610                gradrho(:)=gradrho(:)+MOocc(imo)*wfnval(imo)*wfnderv(:,imo)
3611            end do
3612            cubmatvec(:,ix,iy,iz)=2*gradrho(:)
3613        end do
3614    end do
3615    ifinish=ifinish+1
3616    write(*,"(' Generating grid data of gradient, finished:',i5,'  /',i5)") ifinish,nz
3617end do
3618!$OMP END PARALLEL DO
3619end subroutine
3620