|
|
|
@ -12,7 +12,7 @@ module opt_group
|
|
|
|
|
implicit none
|
|
|
|
|
|
|
|
|
|
integer :: group_ele_num, group_atom_num, remesh_size,normal, dim1, dim2, random_num, group_type, notsize, insert_type, &
|
|
|
|
|
insert_site, num_species
|
|
|
|
|
insert_site, num_species, group_atom_types, exclude_num, exclude_types(10)
|
|
|
|
|
character(len=15) :: type, gshape!Type indicates what element type is selected and shape is the group shape
|
|
|
|
|
character(len=2) :: species_type(10)
|
|
|
|
|
real(kind=dp) :: block_bd(6), centroid(3), vertices(3,3),disp_vec(3), radius, bwidth, shell_thickness, insert_conc, &
|
|
|
|
@ -39,6 +39,7 @@ module opt_group
|
|
|
|
|
insert_type = 0
|
|
|
|
|
random_num=0
|
|
|
|
|
group_type=0
|
|
|
|
|
group_atom_types=0
|
|
|
|
|
notsize=0
|
|
|
|
|
displace=.false.
|
|
|
|
|
delete=.false.
|
|
|
|
@ -47,6 +48,7 @@ module opt_group
|
|
|
|
|
flip = .false.
|
|
|
|
|
group_nodes=.false.
|
|
|
|
|
num_species = 0
|
|
|
|
|
exclude_num = 0
|
|
|
|
|
|
|
|
|
|
if(allocated(element_index)) deallocate(element_index)
|
|
|
|
|
if(allocated(atom_index)) deallocate(atom_index)
|
|
|
|
@ -87,10 +89,10 @@ module opt_group
|
|
|
|
|
call displace_group
|
|
|
|
|
end if
|
|
|
|
|
if(insert_type > 0) then
|
|
|
|
|
print *, "Insert command has been dropped"
|
|
|
|
|
stop 1
|
|
|
|
|
!print *, "Insert command has been dropped"
|
|
|
|
|
!stop 1
|
|
|
|
|
call get_group
|
|
|
|
|
! call insert_group
|
|
|
|
|
call insert_group
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
if(num_species > 0) then
|
|
|
|
@ -470,6 +472,24 @@ module opt_group
|
|
|
|
|
refine=.true.
|
|
|
|
|
case('refinefill')
|
|
|
|
|
refinefill=.true.
|
|
|
|
|
case('selecttype')
|
|
|
|
|
arg_pos = arg_pos + 1
|
|
|
|
|
call get_command_argument(arg_pos, textholder, arglen)
|
|
|
|
|
if (arglen==0) stop "Missing select type"
|
|
|
|
|
call atommass(textholder, mass)
|
|
|
|
|
call add_atom_type(mass, group_atom_types)
|
|
|
|
|
case('excludetypes')
|
|
|
|
|
arg_pos=arg_pos + 1
|
|
|
|
|
call get_command_argument(arg_pos, textholder, arglen)
|
|
|
|
|
if(arglen==0) stop "Missing number of atoms to exclude"
|
|
|
|
|
read(textholder, *) exclude_num
|
|
|
|
|
do i=1,exclude_num
|
|
|
|
|
arg_pos = arg_pos + 1
|
|
|
|
|
call get_command_argument(arg_pos, textholder, arglen)
|
|
|
|
|
if(arglen==0) stop "Missing exclude atom types"
|
|
|
|
|
call atommass(textholder, mass)
|
|
|
|
|
call add_atom_type(mass, exclude_types(i))
|
|
|
|
|
end do
|
|
|
|
|
case('remesh')
|
|
|
|
|
arg_pos = arg_pos + 1
|
|
|
|
|
call get_command_argument(arg_pos, textholder, arglen)
|
|
|
|
@ -619,7 +639,7 @@ module opt_group
|
|
|
|
|
select case(trim(adjustl(type)))
|
|
|
|
|
case('atoms','all')
|
|
|
|
|
do i = 1, atom_num
|
|
|
|
|
if(in_group(r_atom(:,i)).neqv.flip) then
|
|
|
|
|
if(in_group(type_atom(i), r_atom(:,i)).neqv.flip) then
|
|
|
|
|
group_atom_num = group_atom_num + 1
|
|
|
|
|
if (group_atom_num > size(atom_index)) then
|
|
|
|
|
allocate(resize_array(size(atom_index) + 1024))
|
|
|
|
@ -687,8 +707,19 @@ module opt_group
|
|
|
|
|
!This command is used to refine the group to full atomistics
|
|
|
|
|
|
|
|
|
|
integer :: i, j, ie, type_interp(max_basisnum*max_esize**3), add_atom_num, orig_atom_num
|
|
|
|
|
real(kind=dp) :: r_interp(3, max_basisnum*max_esize**3)
|
|
|
|
|
real(kind=dp) :: r_interp(3, max_basisnum*max_esize**3), data_interp(10, max_basisnum*max_esize**3), &
|
|
|
|
|
vel_interp(3, max_basisnum*max_esize**3)
|
|
|
|
|
real(kind=dp), allocatable :: vel_tmp(:,:)
|
|
|
|
|
logical :: refine_dat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (allocated(force_node)) then
|
|
|
|
|
refine_dat=.true.
|
|
|
|
|
else
|
|
|
|
|
refine_dat=.false.
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
print *, size(data_interp)
|
|
|
|
|
!Refining to atoms
|
|
|
|
|
if(group_ele_num > 0) then
|
|
|
|
|
orig_atom_num = atom_num
|
|
|
|
@ -698,17 +729,38 @@ module opt_group
|
|
|
|
|
do i = 1, group_ele_num
|
|
|
|
|
ie = element_index(i)
|
|
|
|
|
!Get the interpolated atom positions
|
|
|
|
|
call interpolate_atoms(type_ele(ie), size_ele(ie), lat_ele(ie), r_node(:,:,:,ie), type_interp, r_interp)
|
|
|
|
|
if (refine_dat) then
|
|
|
|
|
call interpolate_atoms(type_ele(i), size_ele(i), lat_ele(i), r_node(:,:,:,i), type_interp, r_interp, &
|
|
|
|
|
energy_node(:,:,i), force_node(:,:,:,i), virial_node(:,:,:,i), data_interp)
|
|
|
|
|
else
|
|
|
|
|
call interpolate_atoms(type_ele(ie), size_ele(ie), lat_ele(ie), r_node(:,:,:,ie), type_interp, r_interp)
|
|
|
|
|
end if
|
|
|
|
|
if(allocated(vel_atom)) then
|
|
|
|
|
call interpolate_vel(type_ele(i), size_ele(i), lat_ele(i), vel_node(:,:,:,i), vel_interp)
|
|
|
|
|
end if
|
|
|
|
|
!Loop over all interpolated atoms and add them to the system, we apply periodic boundaries
|
|
|
|
|
!here as well to make sure they are in the box
|
|
|
|
|
do j = 1, basisnum(lat_ele(ie))*size_ele(ie)**3
|
|
|
|
|
call apply_periodic(r_interp(:,j))
|
|
|
|
|
call add_atom(0,type_interp(j), r_interp(:,j))
|
|
|
|
|
if(refine_dat) then
|
|
|
|
|
call add_atom_data(atom_num, data_interp(1, j), data_interp(2:4, j), data_interp(5:10, j))
|
|
|
|
|
end if
|
|
|
|
|
if(allocated(vel_atom)) then
|
|
|
|
|
if(size(vel_atom, 2) < size(type_atom)) then
|
|
|
|
|
allocate(vel_tmp(3, size(type_atom)))
|
|
|
|
|
vel_tmp=0.0_dp
|
|
|
|
|
vel_tmp(:, 1:size(vel_atom,2)) = vel_atom
|
|
|
|
|
call move_alloc(vel_tmp, vel_atom)
|
|
|
|
|
end if
|
|
|
|
|
vel_atom(:, atom_num) = vel_interp(:,j)
|
|
|
|
|
end if
|
|
|
|
|
end do
|
|
|
|
|
end do
|
|
|
|
|
!Once all atoms are added we delete all of the elements
|
|
|
|
|
call delete_elements(group_ele_num, element_index)
|
|
|
|
|
print *, group_ele_num, " elements of group are refined to ", atom_num -orig_atom_num, " atoms."
|
|
|
|
|
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
end subroutine refine_group
|
|
|
|
@ -745,7 +797,7 @@ module opt_group
|
|
|
|
|
ravg = ravg + rfill(:,ibasis, 1)/basisnum(lat_ele(ie))
|
|
|
|
|
end do
|
|
|
|
|
|
|
|
|
|
if( in_group(ravg)) then
|
|
|
|
|
if( in_group(0,ravg)) then
|
|
|
|
|
nump_ele = nump_ele - 1
|
|
|
|
|
end if
|
|
|
|
|
end do
|
|
|
|
@ -1118,77 +1170,79 @@ module opt_group
|
|
|
|
|
|
|
|
|
|
end subroutine change_group_type
|
|
|
|
|
|
|
|
|
|
! subroutine insert_group
|
|
|
|
|
! !This code inserts atoms into interstitial sites. This only works on atoms within the group due to the limitations with the
|
|
|
|
|
! !Coarse-graining methodology which doesn't allow for concentration fluctuations.
|
|
|
|
|
! real(kind=dp) interstitial_sites(3,14), rand, rinsert(3)
|
|
|
|
|
! integer :: add_num, i, j, rindex, sindex, ia, rlo, rhi
|
|
|
|
|
! integer, allocatable :: used_sites(:,:)
|
|
|
|
|
!
|
|
|
|
|
! !First save all of the displacement vectors from a lattice site to interstitial site
|
|
|
|
|
! !The first 6 are the octohedral sites and the next 8 are the tetrahedral sites
|
|
|
|
|
! interstitial_sites= reshape( (/ -0.5_dp, 0.0_dp, 0.0_dp, &
|
|
|
|
|
! 0.5_dp, 0.0_dp, 0.0_dp, &
|
|
|
|
|
! 0.0_dp,-0.5_dp, 0.0_dp, &
|
|
|
|
|
! 0.0_dp, 0.5_dp, 0.0_dp, &
|
|
|
|
|
! 0.0_dp, 0.0_dp,-0.5_dp, &
|
|
|
|
|
! 0.0_dp, 0.0_dp, 0.5_dp, &
|
|
|
|
|
! -0.25_dp,-0.25_dp,-0.25_dp, &
|
|
|
|
|
! -0.25_dp,-0.25_dp, 0.25_dp, &
|
|
|
|
|
! -0.25_dp, 0.25_dp,-0.25_dp, &
|
|
|
|
|
! -0.25_dp, 0.25_dp, 0.25_dp, &
|
|
|
|
|
! 0.25_dp,-0.25_dp,-0.25_dp, &
|
|
|
|
|
! 0.25_dp,-0.25_dp, 0.25_dp, &
|
|
|
|
|
! 0.25_dp, 0.25_dp,-0.25_dp, &
|
|
|
|
|
! 0.25_dp, 0.25_dp, 0.25_dp /), &
|
|
|
|
|
! shape(interstitial_sites))
|
|
|
|
|
!
|
|
|
|
|
! !First we calculate the number of atoms needed based on the number of atoms in the group and the concentration
|
|
|
|
|
! interstitial_sites=interstitial_sites*insert_lattice
|
|
|
|
|
!
|
|
|
|
|
! add_num = (insert_conc*group_atom_num)/(1-insert_conc)
|
|
|
|
|
! allocate(used_sites(2,add_num))
|
|
|
|
|
!
|
|
|
|
|
! print *, "Inserting ", add_num, " atoms as atom type ", insert_type
|
|
|
|
|
!
|
|
|
|
|
! !Now set up the random number generator for the desired interstitial type
|
|
|
|
|
! select case(insert_site)
|
|
|
|
|
! case(1)
|
|
|
|
|
! rlo=1
|
|
|
|
|
! rhi=6
|
|
|
|
|
! case(2)
|
|
|
|
|
! rlo=7
|
|
|
|
|
! rhi = 14
|
|
|
|
|
! case(3)
|
|
|
|
|
! rlo=1
|
|
|
|
|
! rhi=14
|
|
|
|
|
! end select
|
|
|
|
|
!
|
|
|
|
|
! !Now add the atoms
|
|
|
|
|
! i = 1
|
|
|
|
|
! addloop:do while ( i < add_num)
|
|
|
|
|
! call random_number(rand)
|
|
|
|
|
! rindex = int(1+rand*(group_atom_num-1))
|
|
|
|
|
! ia=atom_index(rindex)
|
|
|
|
|
! call random_number(rand)
|
|
|
|
|
! sindex = int(rlo+rand*(rhi-rlo))
|
|
|
|
|
! do j = 1, i
|
|
|
|
|
! if((ia == used_sites(1,i)).and.(sindex == used_sites(2,i))) cycle addloop
|
|
|
|
|
! end do
|
|
|
|
|
! rinsert = r_atom(:,ia) + matmul(sub_box_ori(:,:,sbox_atom(ia)),interstitial_sites(:,sindex))
|
|
|
|
|
! sbox = sbox_atom(ia)
|
|
|
|
|
! call add_atom(0, insert_type, sbox, rinsert)
|
|
|
|
|
! used_sites(1,i) = ia
|
|
|
|
|
! used_sites(2,i) = sindex
|
|
|
|
|
! i = i + 1
|
|
|
|
|
! end do addloop
|
|
|
|
|
! end subroutine insert_group
|
|
|
|
|
subroutine insert_group
|
|
|
|
|
!This code inserts atoms into interstitial sites. This only works on atoms within the group due to the limitations with the
|
|
|
|
|
!Coarse-graining methodology which doesn't allow for concentration fluctuations.
|
|
|
|
|
real(kind=dp) interstitial_sites(3,14), rand, rinsert(3)
|
|
|
|
|
integer :: add_num, i, j, rindex, sindex, ia, rlo, rhi
|
|
|
|
|
integer, allocatable :: used_sites(:,:)
|
|
|
|
|
|
|
|
|
|
!First save all of the displacement vectors from a lattice site to interstitial site
|
|
|
|
|
!The first 6 are the octohedral sites and the next 8 are the tetrahedral sites
|
|
|
|
|
interstitial_sites= reshape( (/ -0.5_dp, 0.0_dp, 0.0_dp, &
|
|
|
|
|
0.5_dp, 0.0_dp, 0.0_dp, &
|
|
|
|
|
0.0_dp,-0.5_dp, 0.0_dp, &
|
|
|
|
|
0.0_dp, 0.5_dp, 0.0_dp, &
|
|
|
|
|
0.0_dp, 0.0_dp,-0.5_dp, &
|
|
|
|
|
0.0_dp, 0.0_dp, 0.5_dp, &
|
|
|
|
|
-0.25_dp,-0.25_dp,-0.25_dp, &
|
|
|
|
|
-0.25_dp,-0.25_dp, 0.25_dp, &
|
|
|
|
|
-0.25_dp, 0.25_dp,-0.25_dp, &
|
|
|
|
|
-0.25_dp, 0.25_dp, 0.25_dp, &
|
|
|
|
|
0.25_dp,-0.25_dp,-0.25_dp, &
|
|
|
|
|
0.25_dp,-0.25_dp, 0.25_dp, &
|
|
|
|
|
0.25_dp, 0.25_dp,-0.25_dp, &
|
|
|
|
|
0.25_dp, 0.25_dp, 0.25_dp /), &
|
|
|
|
|
shape(interstitial_sites))
|
|
|
|
|
|
|
|
|
|
!First we calculate the number of atoms needed based on the number of atoms in the group and the concentration
|
|
|
|
|
interstitial_sites=interstitial_sites*insert_lattice
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!Now set up the random number generator for the desired interstitial type
|
|
|
|
|
select case(insert_site)
|
|
|
|
|
case(1)
|
|
|
|
|
rlo=1
|
|
|
|
|
rhi=6
|
|
|
|
|
case(2)
|
|
|
|
|
rlo=7
|
|
|
|
|
rhi = 14
|
|
|
|
|
case(3)
|
|
|
|
|
rlo=1
|
|
|
|
|
rhi=14
|
|
|
|
|
end select
|
|
|
|
|
|
|
|
|
|
if ((insert_conc > 1).or.(insert_conc < 0)) stop "Insert concentration should be between 0 and 1"
|
|
|
|
|
add_num = (insert_conc*group_atom_num)
|
|
|
|
|
allocate(used_sites(2,add_num))
|
|
|
|
|
|
|
|
|
|
print *, "Inserting ", add_num, " atoms as atom type ", insert_type
|
|
|
|
|
|
|
|
|
|
!Now add the atoms
|
|
|
|
|
i = 1
|
|
|
|
|
addloop:do while ( i < add_num)
|
|
|
|
|
call random_number(rand)
|
|
|
|
|
rindex = int(1+rand*(group_atom_num-1))
|
|
|
|
|
ia=atom_index(rindex)
|
|
|
|
|
call random_number(rand)
|
|
|
|
|
sindex = int(rlo+rand*(rhi-rlo))
|
|
|
|
|
do j = 1, i
|
|
|
|
|
if((ia == used_sites(1,i)).and.(sindex == used_sites(2,i))) cycle addloop
|
|
|
|
|
end do
|
|
|
|
|
rinsert = r_atom(:,ia) + matmul(box_ori,interstitial_sites(:,sindex))
|
|
|
|
|
call add_atom(0, insert_type, rinsert)
|
|
|
|
|
used_sites(1,i) = ia
|
|
|
|
|
used_sites(2,i) = sindex
|
|
|
|
|
i = i + 1
|
|
|
|
|
end do addloop
|
|
|
|
|
end subroutine insert_group
|
|
|
|
|
|
|
|
|
|
subroutine alloy_group
|
|
|
|
|
!This subroutine randomizes the atom types to reach desired concentrations, this only operates on atoms
|
|
|
|
|
integer :: i, j, ia, type_map(10), added_types(num_species)
|
|
|
|
|
real(kind=dp) :: rand, mass, old_fractions(num_species)
|
|
|
|
|
character(len=2) :: sorted_species_type(10)
|
|
|
|
|
logical :: species_mapped(10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print *, "Alloying group with desired fractions", s_fractions(1:num_species)
|
|
|
|
@ -1196,10 +1250,13 @@ module opt_group
|
|
|
|
|
!First we sort the fractions
|
|
|
|
|
call quicksort(s_fractions(1:num_species))
|
|
|
|
|
|
|
|
|
|
species_mapped = .false.
|
|
|
|
|
do i = 1,num_species
|
|
|
|
|
do j=1, num_species
|
|
|
|
|
if (is_equal(s_fractions(i), old_fractions(j))) then
|
|
|
|
|
if (is_equal(s_fractions(i), old_fractions(j)) .and. .not. species_mapped(j)) then
|
|
|
|
|
sorted_species_type(i)=species_type(j)
|
|
|
|
|
species_mapped(j) = .true.
|
|
|
|
|
exit
|
|
|
|
|
end if
|
|
|
|
|
end do
|
|
|
|
|
end do
|
|
|
|
@ -1230,8 +1287,9 @@ module opt_group
|
|
|
|
|
return
|
|
|
|
|
end subroutine alloy_group
|
|
|
|
|
|
|
|
|
|
function in_group(r)
|
|
|
|
|
function in_group(atype, r)
|
|
|
|
|
!This subroutine determines if a point is within the group boundaries
|
|
|
|
|
integer, intent(in) :: atype
|
|
|
|
|
real(kind=dp), intent(in) :: r(3)
|
|
|
|
|
real(kind=dp) :: rnorm
|
|
|
|
|
|
|
|
|
@ -1276,6 +1334,19 @@ module opt_group
|
|
|
|
|
case('all')
|
|
|
|
|
in_group = .true.
|
|
|
|
|
end select
|
|
|
|
|
|
|
|
|
|
if(group_atom_types> 0) then
|
|
|
|
|
in_group = in_group.and.(atype== group_atom_types)
|
|
|
|
|
elseif(exclude_num > 0) then
|
|
|
|
|
if(in_group) then
|
|
|
|
|
do i=1,exclude_num
|
|
|
|
|
if (atype == exclude_types(i)) then
|
|
|
|
|
in_group=.false.
|
|
|
|
|
exit
|
|
|
|
|
end if
|
|
|
|
|
end do
|
|
|
|
|
end if
|
|
|
|
|
end if
|
|
|
|
|
end function in_group
|
|
|
|
|
|
|
|
|
|
function in_group_ele(esize, elat, rn)
|
|
|
|
@ -1299,13 +1370,13 @@ module opt_group
|
|
|
|
|
r_center(:)= r_center(:) + rn(:,ibasis,inod)/basisnum(elat)
|
|
|
|
|
end do
|
|
|
|
|
|
|
|
|
|
if((in_group(rn(:, ibasis, inod)).neqv.flip).and.(size_ele(i)/=notsize)) then
|
|
|
|
|
if((in_group(0,rn(:, ibasis, inod)).neqv.flip).and.(size_ele(i)/=notsize)) then
|
|
|
|
|
node_in_out(inod) = 2
|
|
|
|
|
exit nodeloop
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
gshape ='sphere'
|
|
|
|
|
if((in_group(rn(:, ibasis, inod)).neqv.flip).and.(esize/=notsize)) then
|
|
|
|
|
if((in_group(0,rn(:, ibasis, inod)).neqv.flip).and.(esize/=notsize)) then
|
|
|
|
|
node_in_out(inod) = 1
|
|
|
|
|
else
|
|
|
|
|
node_in_out(inod) = 0
|
|
|
|
@ -1327,7 +1398,7 @@ module opt_group
|
|
|
|
|
end do
|
|
|
|
|
end do
|
|
|
|
|
|
|
|
|
|
if ((in_group(r_center).neqv.flip).and.(esize/= notsize)) then
|
|
|
|
|
if ((in_group(0,r_center).neqv.flip).and.(esize/= notsize)) then
|
|
|
|
|
in_group_ele=.true.
|
|
|
|
|
return
|
|
|
|
|
end if
|
|
|
|
@ -1336,7 +1407,7 @@ module opt_group
|
|
|
|
|
r_center(:) = 0.0_dp
|
|
|
|
|
do inod = 1, ng_node(elat)
|
|
|
|
|
do ibasis = 1, basisnum(elat)
|
|
|
|
|
if ((in_group(rn(:,ibasis,inod)).neqv.flip).and.(esize/=notsize)) then
|
|
|
|
|
if ((in_group(0,rn(:,ibasis,inod)).neqv.flip).and.(esize/=notsize)) then
|
|
|
|
|
in_group_ele=.true.
|
|
|
|
|
return
|
|
|
|
|
end if
|
|
|
|
|