-
Notifications
You must be signed in to change notification settings - Fork 2
/
routines.f90
3036 lines (2539 loc) · 87.4 KB
/
routines.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
module routines
implicit none
public
contains
function cross(a,b) result(res)
implicit none
real, dimension(3) :: a, b
real, dimension(3) :: res
res(1) = a(2)*b(3) - a(3)*b(2)
res(2) = a(3)*b(1) - a(1)*b(3)
res(3) = a(1)*b(2) - a(2)*b(1)
end function cross
real function inner_prod(A,B)
implicit none
real,dimension(3) :: A, B
integer :: i
inner_prod = 0.0
do i = 1,3
inner_prod = inner_prod+A(i)*B(i)
end do
end function inner_prod
real function norm(A)
implicit none
real, dimension(3) :: A
norm = sqrt(real(inner_prod(A,A)))
end function norm
real function atang(d)
!! atan function taking into account NaN and Infinity issues
implicit none
real :: d, pi
pi = 4.0*atan(1.0)
!! if d = NaN (not even equal to itself) then it comes from 1/0
if (d /= d) then
atang = 0.0
!! is infinity
elseif ( d**2+1 == d ) then
atang = pi/2.0
!! is -infinity
elseif (d**2+1 == -d ) then
atang = -pi/2.0
else
atang = atan(d)
endif
end function atang
subroutine find_neighbour_list(nat,connect,indices,isite,neigh_list)
!! find just the list of indices that are first neighbours to isite
implicit none
integer, intent(in) :: nat
integer, dimension(nat,nat), intent(in) :: connect
integer, dimension(nat), intent(in) :: indices
integer, intent(in) :: isite
integer, dimension(12), intent(out) :: neigh_list
integer :: i, k, nb, con
neigh_list(:) = 0
k = 0
nb = sum( connect( isite, :) ) !! nb is the total number of connections of isite
do i = 1, nat
con = connect(isite,i)
k = k + con
if( con .ne. 0 ) neigh_list(k) = indices(i)
if( k .eq. nb ) exit !! k is all neighbours
end do
end subroutine find_neighbour_list
subroutine find_neighbour_coords(nat,coords,connect,isite,nn,neigh)
!! find the coordinates of all first neighbours to isite, from the connectivity
implicit none
integer, intent(in) :: nat
real, dimension(nat,3), intent(in) :: coords
integer, dimension(nat,nat), intent(in) :: connect
integer, intent(in) :: isite
integer, intent(in) :: nn !! number of neighbours of isite
real, dimension(12,3), intent(out) :: neigh
integer :: i, k, con
neigh(:,:) = 0.0
k = 0
!write(*,*) 'nn',nn
do i = 1, nat
con = connect(isite, i)
k = k + con
if ( con .ne. 0 ) neigh(k,:) = con * coords(i,:)
!write(*,*) k
if ( k .eq. nn ) exit
end do
end subroutine find_neighbour_coords
subroutine find_neighbour_matrix(nat,coords,connect,indices,neigh,neigh_list)
!! find the nearest neighbours, by chemistry there are maximum 12
implicit none
integer, intent(in) :: nat
real, dimension(nat,3),intent(in) :: coords
integer, dimension(nat), intent(in) :: indices
integer, parameter :: n=12
real, dimension(n,3), intent(out) :: neigh
integer, dimension(nat,nat),intent(in) :: connect
integer, dimension(12),intent(out) :: neigh_list
integer :: nb
integer :: k, i
!write(*,*) '>>>>> find neigh'
!write(*,*) ' coords begin neigh'
!do i = 1, size(coords,1)
! write(*,*) coords(i,:)
!end do
!write(*,*)
neigh(:,:) = 0.0
neigh_list(:) = 0
k = 0
nb = sum( connect(1,:) ) !! is the total number of connections (=neighbors)
!write(*,*) nb
do i = 1, nat !! loop through whole connect
k = k + connect(1, (i) )
if ( connect(1,(i)) == 0 ) cycle
!write(*,*) connect(1,(i)),coords((i),:)
neigh(k,:) = connect(1,(i))*coords((i),:)
neigh_list(k) = indices(i)
if ( k == nb ) exit !! k is all the neighbors
end do
!write(*,*) 'found neigh'
!do i = 1,12
! write(*,*) neigh(i,:)
!end do
!write(*,*) '>>>> end find neigh'
end subroutine find_neighbour_matrix
subroutine pssbl_basis_1(nat,map_coords,neigh,nn,A)
implicit none
integer, intent(in) :: nat
real, dimension(nat,3),intent(in) :: map_coords
integer, intent(in) :: nn ! number of nonzero neighbours
real, dimension(12,3),intent(in) :: neigh
integer, dimension(nn,nn), intent(out) :: A ! matrix of possible basis vector indices
real, dimension(3) :: r_i, r_j
real :: nrm_i, nrm_j, proj_ij, collin
real :: tolerance !! for collinearity
integer :: i,j
tolerance = 0.9 !! in units of collinearity (0 to 1) -- if collinearity of two
!! vectors is below tolerance, they are accepted as possible basis.
!! Collinearity = 1 --> vectors are collinear
!! collinearity = 0 --> vectors are orthogonal
A(:,:) = 0
!! find the matrix of possible basis vector indeces, format:
!! first row gives possible second vector index when the first
!! 'neighbor' vector is first basis vector. the position in the row gives
!! the index of the second basis vector in the 'neighbor' matrix.
do i = 1, 12
r_i = neigh(i,:)
nrm_i = norm( r_i )
if ( nrm_i == 0.0 ) cycle
do j = 1, 12
if ( i == j ) cycle
r_j = neigh(j,:)
nrm_j = norm( r_j )
if ( nrm_j == 0.0 ) cycle
proj_ij = inner_prod( r_i, r_j )
collin = proj_ij / (nrm_i * nrm_j )
A(i,j) = nint(0.5*erfc( abs(collin) - tolerance ))
end do
end do
end subroutine pssbl_basis_1
subroutine pssbl_basis(nat,map_coords,neigh,nn,lab,A)
implicit none
integer, intent(in) :: nat
real, dimension(nat,3),intent(in) :: map_coords
integer, intent(in) :: nn ! number of nonzero neighbours
real, dimension(12,3),intent(in) :: neigh
integer, dimension(nat),intent(in) :: lab
integer, dimension(nn,nn), intent(out) :: A ! matrix of possible basis vector indices
real, dimension(3) :: r_me, r_i, r_j
real, dimension(3,3) :: basis
real :: nrm_i, nrm_j, proj_ij, collin
real :: tolerance !! for collinearity
integer :: i,j,n, r_me_ind, ii
! real, allocatable :: coords_copy(:,:)
tolerance = 0.9 !! in units of collinearity (0 to 1) -- if collinearity of two
!! vectors is below tolerance, they are accepted as possible basis.
!! Collinearity = 1 --> vectors are collinear
!! collinearity = 0 --> vectors are orthogonal
A(:,:) = 0
! allocate(coords_copy(1:size(map_coords,1),1:3))
! do i = 1, size(neigh,1)
! write(*,*) neigh(i,:)
! end do
! r_me_ind = minloc(lab(:), 1)
!write(*,*) ' r_me_ind in canon', r_me_ind
! r_me = map_coords( lab(r_me_ind), :)
!write(*,*) ' r_me',r_me
!! find the matrix of possible basis vector indeces, format:
!! first row gives possible second vector index when the first
!! 'neighbor' vector is first basis vector. the position in the row gives
!! the index of the second basis vector in the 'neighbor' matrix.
do i = 1, 12
r_i = neigh(i,:)
nrm_i = norm( r_i )
if ( nrm_i == 0.0 ) cycle
do j = 1, 12
if ( i == j ) cycle
r_j = neigh(j,:)
nrm_j = norm( r_j )
if ( nrm_j == 0.0 ) cycle
proj_ij = inner_prod( r_i, r_j )
collin = proj_ij / (nrm_i * nrm_j )
!write(*,*) i,j, 1-abs(nint(collin+tolerance)), collin, (0.5*erfc(abs(collin) - tolerance))
! A(i,j) = 1 - abs( nint( collin+tolerance ) )
A(i,j) = nint(0.5*erfc( abs(collin) - tolerance ))
end do
end do
!write(*,*) 'A'
! do i = 1, nn
!write(*,*) A(i,:)
!end do
end subroutine pssbl_basis
subroutine get_angle(r1,r2,theta)
!! get angle from vector r1 to r2
implicit none
real,intent(in) :: r1(3), r2(3)
real, intent(out) :: theta
real :: nrm1, nrm2, proj
nrm1 = norm(r1)
nrm2 = norm(r2)
proj = inner_prod( r1, r2 )
theta = acos( proj / ( nrm1*nrm2 ) )
end subroutine get_angle
subroutine get_atan2(neigh,thetayx,thetaxz,thetazy)
!! get all combinations of atan2 angles of r2 - r1
real, intent(in) :: neigh(:,:)
real, intent(out) :: thetayx, thetaxz, thetazy
integer :: i, j
real, dimension(3) :: R
do i = 1, 12
if ( norm( neigh(i, :) ) == 0.0 ) cycle
do j = 1, 12
if( norm( neigh(j, :) ) == 0.0 ) cycle
R = neigh(j, :) - neigh(i,:)
if ( norm( R ) == 0.0 ) cycle
thetayx = atan2( R(2), R(1) )
thetaxz = atan2( R(1), R(3) )
thetazy = atan2( R(3), R(2) )
! write(*,*) 'i, j, yx, xz, zy'
! write(*,*) i, j, thetayx, thetaxz, thetazy
end do
end do
end subroutine get_atan2
subroutine generate_connect(nat,coords,types,n_col,color_cutoff,connect)
!! generate just the connectivity matrix from coords
implicit none
integer, intent(in) :: nat
real, dimension(nat,3), intent(in) :: coords
integer, dimension(nat), intent(in) :: types
integer, intent(in) :: n_col
real, dimension(n_col,n_col), intent(in) :: color_cutoff
integer, dimension(nat,nat), intent(out) :: connect
integer :: i, j, k
real :: dij
do i = 1, nat
do j = i+1, nat
dij = 0.0
do k = 1, 3
dij = dij + (coords(j,k)-coords(i,k))**2
end do
dij = sqrt(dij)
connect(i,j) = NINT( 0.5*erfc(dij-color_cutoff( types(i),types(j) )))
connect(j,i) = connect(i,j)
end do
end do
end subroutine generate_connect
subroutine make_connectivity(nat, coords, types,&
color_cutoff, connect, lab, color,&
ntyp, maxtyp, sorted_from_global_color )
implicit none
integer, intent(in) :: nat
real, intent(inout) :: coords(:,:)
integer, intent(inout) :: types(:)
real, intent(in) :: color_cutoff(:,:)
integer, allocatable, intent(out) :: connect(:,:)
integer, allocatable, intent(out) :: lab(:), color(:)
integer, intent(out) :: ntyp, maxtyp
integer, allocatable, intent(out) :: sorted_from_global_color(:)
integer, allocatable :: global_from_sorted_color(:)
real :: dij
integer :: i, j, k
integer :: n_col
allocate( connect(1:nat, 1:nat) )
connect(:,:) = 0
allocate(lab(1:nat))
lab(:) = 0
allocate(color(1:nat))
color(:) = 0
allocate(sorted_from_global_color(1:nat))
allocate(global_from_sorted_color(1:nat))
n_col = size(color_cutoff,1)
call generate_connect(nat,coords,types, n_col , color_cutoff, connect )
!write(*,*) 'before sort types',types
!write(*,*) 'before sort color',color
call sort_property(nat,types,color,global_from_sorted_color,sorted_from_global_color)
!write(*,*) 'after sort color',color
!write(*,*) 'after sort types',types
!write(*,*) 'maxval types',maxval(types)
maxtyp = maxval(types)
ntyp = 0
do i = 1, size(color)
if(color(i) == 0) ntyp = ntyp + 1
end do
!write(*,*) 'ntyp',ntyp
!write(*,*) 'global from sorted',global_from_sorted_color
!write(*,*) 'sorted from global',sorted_from_global_color
do i=1,nat
lab(i)=global_from_sorted_color(i)-1
enddo
!! call sort_to_order_typ(nat,types,sorted_from_global_color)
!! call sort_to_order(nat,coords,sorted_from_global_color)
!write(*,*) 'end of make conn'
!do i=1, nat
! write(*,*) types(i),coords(i,:)
!end do
! deallocate(connect)
! deallocate(lab)
! deallocate(color)
! deallocate(sorted_from_global_color)
deallocate(global_from_sorted_color)
end subroutine make_connectivity
subroutine sort_property(n,vertex_property,color,&
unsorted_from_sorted,sorted_from_unsorted)
implicit none
integer, intent(inout):: vertex_property(1:n)
integer, intent(out) :: sorted_from_unsorted(1:n), unsorted_from_sorted(1:n)
integer, intent(out) :: color(1:n)
integer, allocatable :: copy_vertex_property(:)
integer :: i,j,k, temp, n
!write(*,*) "from sort_property index"
n=size(vertex_property,1)
!write(*,*) "n=", n
allocate(copy_vertex_property(1:n))
copy_vertex_property(:)=vertex_property(:)
do j=1,n
sorted_from_unsorted(j)=0
unsorted_from_sorted(j)=0
enddo
do i=1,n
do j=1,n-1
if(vertex_property(j)>vertex_property(j+1)) then
temp=vertex_property(j)
vertex_property(j)=vertex_property(j+1)
vertex_property(j+1)=temp
endif
enddo
enddo
k=1
do i=1,n
if ( k > n) exit
do j=1,n
if (k > n) exit
if((vertex_property(k)==copy_vertex_property(j)).and.&
(sorted_from_unsorted(j)==0)) then
sorted_from_unsorted(j)=k
unsorted_from_sorted(k)=j
k=k+1
endif
enddo
enddo
!write(*,*) "original vertex color, actual vertex color, sorted from unsorted"
!write(*,*) ""
!do i=1,n
!write(*,*) copy_vertex_property(i), vertex_property(i),sorted_from_unsorted(i), &
! unsorted_from_sorted(i)
!enddo
color(:)=vertex_property(:)
do i=1,n-1
if(vertex_property(i)/=vertex_property(i+1)) color(i)=0
enddo
color(n)=0
!do i=1,n
! write(*,*) "ooo", vertex_property(i), color(i)
!enddo
deallocate(copy_vertex_property)
end subroutine
subroutine rotate(A,x,y,z)
!! rotation matrix: R A = A'
!! x, y, z are rotation angles around each axis
implicit none
real, dimension(3), intent(inout) :: A
real, intent(in) :: z, x, y
real, dimension(3,3) :: R
R(1,1) = cos(z)*cos(y) - cos(x)*sin(z)*sin(y)
R(1,2) = -cos(z)*sin(y) - cos(x)*sin(z)*cos(y)
R(1,3) = sin(z)*sin(x)
R(2,1) = sin(z)*cos(y) + cos(x)*cos(z)*sin(y)
R(2,2) = -sin(z)*sin(y) + cos(x)*cos(z)*cos(y)
R(2,3) = -cos(z)*sin(x)
R(3,1) = sin(y)*sin(x)
R(3,2) = cos(y)*sin(x)
R(3,3) = cos(x)
A = matmul(R,A)
end subroutine rotate
subroutine set_color_cutoff(color_cutoff,n_color)
!! set the color_cutoff matrix
!! first line is not read!!
implicit none
integer,intent(in) :: n_color !! is the maximum number of colors,
!! is the size of color_cutoff matrix
real, dimension(n_color,n_color), intent(out) :: color_cutoff
integer :: i, j
real :: dij
open(unit=555,file='neighbor_table.dat',status='old',action='read')
color_cutoff(:,:) = 0.0
read(555,*)
do while(.true.)
read(555,*,end=200) i, j, dij
color_cutoff(i,j) = dij
color_cutoff(j,i) = dij
end do
200 continue
end subroutine set_color_cutoff
! subroutine gen_basis(nat,coords,basis)
! !! find a "typical vector" of the system,
! !! sum of all contributions of each components is the typical vector's component in
! !! that direction. Then find typical rotation around each axis and apply it to the
! !! typical vector around each corresponding axis separately. This should give 4 vectors:
! !! namely, the typical one, the one rotated around z, y, and x. Could check which
! !! combination is ok for basis.
! !! unused, philosophy of basis has been changed
! implicit none
! integer, intent(in) :: nat
! real, intent(in) :: coords(:,:)
! real, intent(out) :: basis(3,3)
! real :: typical(3), typical_o(3)
! real :: dum, pi2, thetaz, thetax, thetay
! integer :: i
!!! pi/2
! pi2 = 2.0*atan(1.0)
!!! sum all components in the cluster
! do i=1, nat
! typical(1) = typical(1) + coords(i,1)
! typical(2) = typical(2) + coords(i,2)
! typical(3) = typical(3) + coords(i,3)
! end do
! typical = typical/norm(typical)
! typical_o(:) = typical(:)
! !! find rotation in the xy plane (around z axis):
! !! theta = pi/2 - sum_i ( atan( y_i / x_i ) ) ( what about abs(atan()) ;; and 1/nat?)
! thetaz = 0.0
! do i=1,nat
! dum = coords(i,2) / coords(i,1)
! dum = pi2 - atang(dum)
! thetaz = thetaz+dum
! end do
! !! find rotation in the yz plane (around x axis):
! !! theta = pi/2 - sum_i ( atan( z_i / y_i ) ) ( what about abs(atan()) ;; and 1/nat?)
! thetax = 0.0
! do i=1,nat
! dum = coords(i,3) / coords(i,2)
! dum = pi2 - atang(dum)
! thetax = thetax+dum
! end do
!
! !! find rotation in the xz plane (around y axis):
! !! theta = pi/2 - sum_i ( atan( z_i / x_i ) ) ( what about abs(atan()) ;; and 1/nat?)
! thetay = 0.0
! do i=1,nat
! dum = coords(i,3) / coords(i,1)
! dum = pi2 - atang(dum)
! thetay = thetay+dum
! end do
! !! rotate typical around each axis
! call rotate(typical,0.0,0.0,thetaz)
! basis(1,:) = typical(:)
! typical = typical_o
! call rotate(typical,thetax,0.0,0.0)
! basis(2,:) = typical(:)
! typical = typical_o
! call rotate(typical,0.0,thetay,0.0)
! basis(3,:) = typical(:)
! typical = typical_o
! end subroutine gen_basis
subroutine order_by_distance(nat,coords,A)
!! generates an order list stored in first element of A. second is the distance.
!! does not actually impose any order.
implicit none
integer, intent(in) :: nat
real, intent(in) :: coords(:,:)
real, allocatable, intent(out) :: A(:,:)
integer :: i
real :: dum
allocate(A(1:nat,1:2))
A(:,:) = 0.0
! do i =1, ev_init_nat
! write(*,*) (A(i,j),j=1,2)
! end do
do i=1,nat
dum = ( coords(1,1) - coords(i,1) )**2 +&
( coords(1,2) - coords(i,2) )**2 +&
( coords(1,3) - coords(i,3) )**2
A(i,2) = dum**0.5
A(i,1) = int(i)
end do
! do i =1, ev_init_nat
! write(*,*) (A(i,j),j=1,2)
! end do
!call Pancake_sort(A(:,4))
call sort_row(A)
! write(*,*)
! do i =1, ev_init_nat
! write(*,*) (A(i,j),j=1,2)
! end do
end subroutine order_by_distance
subroutine sort_row(A)
! sorts rows in matrix A, by the second element, from low to high
implicit none
real,intent(inout) :: A(:,:)
real:: buf(2)
integer :: nsize, irow, krow
nsize = size(A,1)
do irow = 1, nsize
krow = minloc( A( irow:nsize, 2 ), dim=1 ) + irow - 1
buf( : ) = A( irow, : )
A( irow, : ) = A( krow, : )
A( krow, : ) = buf( : )
enddo
end subroutine sort_row
subroutine Pancake_sort(a)
real, intent(in out) :: a(:)
integer :: i, maxpos
write(*,*) a
do i = size(a), 2, -1
! Find position of max number between index 1 and i
maxpos = maxloc(a(1:i), 1)
! is it in the correct position already?
if (maxpos == i) cycle
! is it at the beginning of the array? If not flip array section so it is
if (maxpos /= 1) then
a(1:maxpos) = a(maxpos:1:-1)
write(*,*) a
end if
! Flip array section to get max number to correct position
a(1:i) = a(i:1:-1)
write(*,*) a
end do
end subroutine Pancake_sort
subroutine sort_to_order(nat,coords,canon_labels)
! sort vectors in a cluster into the canonical order
implicit none
integer, intent(in) :: nat
real, dimension(:,:),intent(inout) :: coords
integer, dimension(nat), intent(in) :: canon_labels
real, dimension(nat,3) :: coords_copy
integer :: i
do i = 1, nat
coords_copy(i,:) = coords(i,:)
end do
do i = 1, nat
coords(i,:) = coords_copy( canon_labels( i ), : )
end do
end subroutine sort_to_order
subroutine sort_to_order_typ(nat,types,canon_labels)
! sort types in a cluster into the canonical order
implicit none
integer, intent(in) :: nat
integer, dimension(nat),intent(inout) :: types
integer, dimension(nat), intent(in) :: canon_labels
real, dimension(nat) :: types_copy
integer :: i
types_copy(:) = types(:)
do i = 1, nat
types(i) = types_copy( canon_labels( i ) )
end do
end subroutine sort_to_order_typ
subroutine gram_schmidt(bases)
!! orthonormalizes the three vectors given in 'basis' matrix
!! -------------------
!! on input, vector 'bases' matrix contains noncollinear vectors
implicit none
real, dimension(3,3), intent(inout) :: bases
integer :: i,j
real, dimension(3) :: A,B,C
A = bases(1,:)
!write(*,*) 'from GS'
B = bases(2,:)
C = bases(3,:)
!write(*,*) 'A',A
!write(*,*) 'B',B
!write(*,*) 'C',C
bases(1,:) = A(:)/norm(A(:))
!write(*,*) 'bases1',bases(1,:)
bases(2,:) = B(:)
bases(2,:) = bases(2,:) - inner_prod(B(:),bases(1,:))*bases(1,:)
bases(2,:) = bases(2,:) / norm(bases(2,:))
!write(*,*) 'bases2',bases(2,:)
! bases(3,:) = cross(bases(1,:),bases(2,:))
! bases(3,:) = bases(3,:) / norm(bases(3,:))
bases(3,:) = C(:)
bases(3,:) = bases(3,:) - inner_prod(C(:),bases(2,:))*bases(2,:)! -&
! inner_prod(C(:),bases(1,:))*bases(1,:)
!! apparently this normalization causes trouble (not anymore!)
!write(*,*) 'bases3',bases(3,:)
bases(3,:) = bases(3,:) / norm(bases(3,:))
!write(*,*) 'bases3',bases(3,:)
end subroutine gram_schmidt
subroutine find_noncollinear_vectors(n,coords,vectors, vector_indeces)
!! finds the first three noncollinear vectors from the 'coords' list - these vectors
!! are then used to form the orthonormal basis
implicit none
integer, intent(in) :: n
real, dimension(n,3),intent(in) :: coords
real, dimension(3,3),intent(out) :: vectors
integer, dimension(3), intent(out) :: vector_indeces
integer :: i,ii, j, second_idx, third_idx
real :: proj, proj2,n1n2,n3n2, margin
real, dimension(3) :: partial_vec
!!!! this has to do with precision used
margin = 1.0e-1
! write(*,*) 'coords from routine'
! do ii=1, n
! write(*,*) coords(ii,:)
! end do
!! first vector is the first in list
vectors(1,:) = coords(1,:)
vector_indeces(1) = 1
!write(*,*) 'found first vector:'
!write(*,*) vectors(1,:)
second_idx = 0
third_idx = 0
!! finding the second vector
!! vectors are collinear when scalar productof two vectors equals the product of their
!! norms.
do i = 2, n
!! projection (1, i)
proj = inner_prod( vectors(1,:), coords(i,:) )
!write(*,*) 'proj 1,',i,proj
!! norm( 1 ) * norm( i )
n1n2 = norm( vectors(1,:) ) * norm( coords(i,:) )
!write(*,*) 'n1n2',n1n2
!write(*,*) 'proj-n1n2',abs(proj)-n1n2
if( abs( abs( proj ) - n1n2) .gt. margin ) then
second_idx = i
exit
endif
end do
vectors(2,:) = coords(second_idx,:)
vector_indeces(2) = second_idx
!write(*,*) 'chosen second idx from routine',second_idx
!write(*,*) vectors(2,:)
!! finding third vector, should be non-collinear to first and second vector
234 continue
do i =second_idx, n
!! projection (1, i)
proj = inner_prod( vectors(1,:), coords(i,:) )
!! projection (2, i)
proj2 = inner_prod( vectors(2,:), coords(i,:) )
!! norm( 1 ) * norm( i )
n1n2 = norm( vectors(1,:) ) * norm( coords(i, :) )
!! norm( 2 ) * norm( i )
n3n2 = norm( vectors(2,:) ) * norm( coords(i, :) )
if((abs(abs(proj)-n1n2) .gt. margin) .and. &
(abs(abs(proj2)-n3n2) .gt. margin)) then
third_idx = i
exit
endif
end do
!write(*,*) 'chosen third idx from routine', third_idx
vectors(3,:) = coords( third_idx, : )
vector_indeces(3) = third_idx
!! sanity check third vector ( do partial GS ), reusing variables-dont trust names
partial_vec(:) = vectors(3,:) - inner_prod( vectors(3,:),vectors(1,:) )*vectors(1,:)
proj = inner_prod( partial_vec(:), vectors(2,:) )
n1n2 = norm(partial_vec)*norm(vectors(2,:))
!write(*,*) 'sanity check vectors'
!write(*,*) 'vector3',vectors(3,:)
!write(*,*) 'vector2',vectors(2,:)
!write(*,*) 'vector1',vectors(1,:)
!write(*,*) 'partial vec 3- (3,1)1',partial_vec
!write(*,*) 'proj',proj
!write(*,*) 'n1n2',n1n2
if ( abs ( abs(proj) - n1n2 ) .lt. margin ) then
second_idx = second_idx + 1
goto 234
endif
partial_vec(:) = vectors(3,:) - inner_prod( vectors(3,:),vectors(2,:) )*vectors(2,:)
proj = inner_prod( partial_vec(:), vectors(1,:) )
n1n2 = norm(partial_vec)*norm(vectors(1,:))
if ( abs ( abs(proj) - n1n2 ) .lt. margin ) then
second_idx = second_idx + 1
goto 234
endif
end subroutine
subroutine read_line(fd, line, end_of_file)
!--------------------
! read a line, makes possible to use # for comment lines, skips empty lines,
! is pretty much a copy from QE.
!---------
! fd ==> file descriptor
! line ==> what it reads
implicit none
integer, intent(in) :: fd
character(len=*), intent(out) :: line
logical, optional, intent(out) :: end_of_file
logical :: tend
tend = .false.
101 read(fd,fmt='(A256)',END=111) line
if(line == ' ' .or. line(1:1) == '#') go to 101
go to 105
111 tend = .true.
go to 105
105 continue
if( present(end_of_file)) then
end_of_file = tend
endif
end subroutine read_line
subroutine get_nsites(fd_sites,nsites)
!---------------------
! get the total number of sites
!---------------------
! fd_sites ==> file descriptor of the sites file
! nsites ==> output number of sites
implicit none
integer, intent(in) :: fd_sites
integer, intent(out) :: nsites
logical :: eof
character(len=64) :: line
eof=.false.
do while (.not.eof)
call read_line(fd_sites,line,eof)
line = trim(adjustl(line))
if(line(1:6)=='nsites') then
line=trim(adjustl(line(7:)))
if (line(1:1)=='=') line=trim(adjustl(line(2:)))
read(line,*) nsites
eof=.true.
endif
end do
rewind(fd_sites)
end subroutine get_nsites
subroutine get_nevt(fd_events,nevt)
!-------------------
! get total number of events
!-------------------
! fd_events ==> file descriptor of events file
! nevt ==> number of events
implicit none
integer, intent(in) :: fd_events
integer, intent(out) :: nevt
logical :: eof
character(len=64) :: line
eof = .false.
do while ( .not. eof )
call read_line( fd_events, line, eof )
line = trim ( adjustl ( line ) )
if ( line(1:4) == 'nevt' ) then
line = trim ( adjustl ( line(5:) ) )
if (line(1:1)=='=') line=trim(adjustl(line(2:))) !! cut away the '=' if present
read(line,*) nevt
eof = .true.
endif
end do
rewind(fd_events)
end subroutine get_nevt
subroutine get_center_of_topology(coords,cot)
implicit none
real, dimension(:,:), intent(in) :: coords
real, dimension(3), intent(out) :: cot
integer :: nsites, i
nsites = size(coords,1)
cot(:) = 0.0
do i=1, nsites
cot(1) = cot(1) + coords(i,1)
cot(2) = cot(2) + coords(i,2)
cot(3) = cot(3) + coords(i,3)
end do
cot = cot/nsites
end subroutine get_center_of_topology
subroutine count_nbvertex(n,coords,isite,Rcut,nbvertex)
implicit none
integer, intent(in) :: n ! number of all coords
real, dimension(n,3) :: coords ! the coords
integer, intent(in) :: isite ! site index around which to count
real, intent(in) :: Rcut ! range
integer, intent(out) :: nbvertex ! the output number of vertices in range
real :: dist
integer :: i
nbvertex = 1
do i=1,n
if (i==isite) cycle
dist = ( coords(isite,1) - coords(i,1) )**2 +&
( coords(isite,2) - coords(i,2) )**2 +&
( coords(isite,3) - coords(i,3) )**2
dist = sqrt(dist)
nbvertex = nbvertex + NINT(0.5*erfc(dist - Rcut))
! write(*,*) 'distance',dist, nint(0.5*erfc(dist-Rcut)),nbvertex
end do
!write(*,*) 'nbvertex',nbvertex
end subroutine count_nbvertex
subroutine count_nbvertex_pbc(nat,coords,isite,Rcut,lat,nbvertex)
implicit none
integer, intent(in) :: nat ! number of all coords
real, dimension(nat,3), intent(in) :: coords ! the coords
real, dimension(nat,3) :: coords_copy ! the coords
integer, intent(in) :: isite ! site index around which to count
real, intent(in) :: Rcut ! range
real, dimension(3,3), intent(in) :: lat
integer, intent(out) :: nbvertex ! the output number of vertices in range
real :: dist
integer :: i
do i = 1, nat
coords_copy(i,:) = coords(i,:) - coords(isite,:)
end do
do i = 1, nat
call cart_to_crist(coords_copy(i,:),lat)
call periodic(coords_copy(i,:))
call crist_to_cart(coords_copy(i,:),lat)
end do
nbvertex = 0
do i=1,nat
! if (i==isite) cycle
dist = ( coords_copy(isite,1) - coords_copy(i,1) )**2 +&
( coords_copy(isite,2) - coords_copy(i,2) )**2 +&
( coords_copy(isite,3) - coords_copy(i,3) )**2
dist = sqrt(dist)
! nbvertex = nbvertex + NINT(0.5*erfc(dist - Rcut))
if( dist .le. Rcut ) nbvertex = nbvertex + 1
! if( dist .le. Rcut ) write(*,*) 'dist',dist,'idx',i,nbvertex
! write(*,*) 'distance',dist, nint(0.5*erfc(dist-Rcut)),nbvertex
end do
!write(*,*) 'nbvertex',nbvertex
end subroutine count_nbvertex_pbc
subroutine map_site(isite,Rcut,&
nat,coords,types,&
nbvertex,map_coords,map_types,map_indices)
implicit none
!! extract coords within some Rcut of current site isite,
!! and write them in basis of this (first atom)
integer :: i,k,j !! counter
real :: dist
real, dimension(3) :: COM
integer, intent(in) :: nat !! number of all coords