aoterodelaroza/critic2

integration results differ within twice run

Ceasea opened this issue · 9 comments

Hi @aoterodelaroza

I run "yt nnm" twice in one Critic2 environment.
I found integration results of the two "yt nnm" are different.

Working flow is

Critic2 # enter command line mode
crystal CHGCAR
load CHGCAR
yt nnm # first run
yt nnm # second run

The two "yt nnm" provided different integration results.
(Maybe it's weird to run twice "yt nnm", but I did.)
'>.<'

My CHGCAR

CHGCAR.tar.gz

My compilier

GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0

My compiling information

critic2 (development), commit (config) no-git
compile host: Linux ceasea-VirtualBox 4.15.0-47-generic #50-Ubuntu SMP Wed Mar 13 10:40:37 UTC 2019 i686 i686 i686 GNU/Linux
compile date: 2019年 07月 11日 星期四 16:32:59 CST
using f77: gfortran -g -O2
f90: gfortran -g -O2 -ffree-form -ffree-line-length-none -fopenmp
c: gcc -g -O2 -Iqhull/
ldflags:
debug?: no
compiled dat: /usr/local/share/critic2
datadir: /usr/local/share/critic2
dic file: /usr/local/share/critic2/cif/cif_core.dic
...was found?: T

Thanks for the report. I think I know why that happens. In your crystal, you have NNMs (which could originate spuriously from using the pseudo-density to calculate the basins). When you run YT for the first time, those NNMs are added to the critical point list for the field as maxima, and therefore act as "atoms" in the second run.

In general, whenever YT finds a new attractor it is assigned to the nearest atom using a distance criterion (the RATOM keyword (1 bohr by default). This is done to prevent noisy densities from spawning great very many maxima that would both slow down the calculation and make the output a lot more confusing. In addition, every maximum in the critical point list of the field is listed in the YT output, even if it integrated to zero. This is done to avoid "losing" atoms in the process.

In your case, the difference between the two runs arises from the fact that, in the first run, your list of maxima contains only the Al atom whereas in the second run it contains the Al and all the maxima found in the first run. Since you have so many maxima and the system is so small, I would suggest using:

YT NNM NOATOMS

In this way, you will get the raw output from YT and there will be no accumulation of basin properties based on distance criteria. If you do that, you'll see that the run gives the same result both times.

I'm not sure if this is a bug, since YT is doing what it was designed to do. However, I do agree that it is unsettling that two runs on the same thing give different results.

! Pre-allocate atoms as maxima
allocate(bas%xattr(3,s%c%ncel))
bas%xattr = 0d0
if (bas%atexist) then
bas%nattr = s%c%ncel
do i = 1, s%c%ncel
bas%xattr(:,i) = s%c%atcel(i)%x
end do
else
bas%nattr = 0
end if

This code is from yt@proc.f90 from line 63 to line 73.

bas%xattr, which stores the coordinations of maxima, and bas%nattr, which stores the number of
maxima, are both initialized at the beginning of yt proc. ( if I was wrong, correct me)

I was wondering if the result of the first run would influence in the second one since bas%xattr and bas%nattr are initialized, or I was missing some important code in other files?

That is correct. Both bas%nattr and bas%xattr are initialized to the number of atoms. And the maxima of YT are saved to the field CP list in integration@proc.f90, routine int_reorder_gridout. But right now I don't see right now the code where it recieves the CPs from the reference field. Hmmm. I'll take a look at the end of today and come back to you.

This is the part of the code that does the deed (in integration@proc.f90, int_reorder_gridout):

if (bas%atexist) then
    do i = 1, nattr0
       nid = ff%c%identify_atom(bas%xattr(:,i),icrd_crys,distmax=bas%ratom)
       if (nid > 0) then
          assigned(i) = nid
       else
          ! maybe the closest point is a known nnm
          call ff%nearest_cp(bas%xattr(:,i),nid,dist,type=ff%typnuc)
          if (dist < bas%ratom) then
             assigned(i) = nid
          end if
       end if
    end do
end if

In the second pass, maxima can still not be assigned to adjacent atoms (because ratom = 1bohr and you only have Al) but they can be assigned to the NNMs found in the first run, and so they are.

The bas%atexists can be made .false. by using the NOATOM keyword, as mentioned above.

Hi @aoterodelaroza,

Combining your explanation, I read the code and found the problem, and solved the problem basically in my tests.
I have pulled a request.

Hi @aoterodelaroza
I have checked new version.
The problem is solved. Thanks.