module mode_da !This mode is used to calculate the dislocation analysis algorithm for both CG and atomistic regions use parameters use io use elements use neighbors implicit none integer :: num_d_points integer, allocatable :: is_slipped(:,:,:) real(kind=dp), allocatable :: disl_line(:,:), disl_data(:) private :: write_xyz public contains subroutine da(arg_pos) !This is the main calling subroutine for the dislocation analysis code integer, intent(out) :: arg_pos real(kind=dp), dimension(6) :: temp_box_bd integer :: ppos character(len=100) :: outfile !Now call the dislocation analysis code for the coarse-grained elements call parse_command(arg_pos) call read_in(1, (/0.0_dp,0.0_dp,0.0_dp/), temp_box_bd) !Now allocate the necessary variables if(allocated(is_slipped)) deallocate(is_slipped) allocate(is_slipped(max_basisnum, max_ng_node, ele_num)) if(allocated(disl_line)) deallocate(disl_line) num_d_points=0 allocate(disl_line(3,1024)) allocate(disl_data(1024)) call cga_da !Now create the output file num and write out to xyz format ppos = scan(trim(infiles(1)),".", BACK= .true.) if ( ppos > 0 ) then outfile = 'da_'//infiles(1)(1:ppos)//'vtk' else outfile = 'da_'//infiles(1)//'.vtk' end if call write_da_vtk(outfile) ppos = scan(trim(infiles(1)),".", BACK= .true.) if ( ppos > 0 ) then outfile = 'da_'//infiles(1)(1:ppos)//'xyz' else outfile = 'da_'//infiles(1)//'.xyz' end if call write_da_xyz(outfile) return end subroutine da subroutine parse_command(arg_pos) !This subroutine parses the arguments for mode command integer, intent(out) :: arg_pos integer :: i, arglen character(len = 100) :: textholder logical :: file_exists !Read the input file call get_command_argument(2,textholder, arglen) if (arglen == 0) stop "Missing file for dislocation analysis" call get_in_file(textholder) arg_pos = 3 return end subroutine parse_command subroutine cga_da integer :: i, j, k, l, ibasis, nei, close_neighbors(2,4,6), far_neighbor(4,6), minindex, minindices(2), linevec(3) integer :: face_types(ele_num*6), face_ele(6*ele_num), diff_pair(2,6) real(kind = dp) :: face_centroids(3, ele_num*6), r(3), rc, vnode(3, max_basisnum, 4), vnorm, & max_node_dist, ndiff, rmax(3), rmin(3), rnorm, v1(3), v2(3), v1norm, v2norm, theta1, theta2, & diff_mag(6), diffvec(3) real(kind=dp), allocatable :: disl_line_temp(:,:), disl_data_temp(:) logical :: is_edge !Initialize variables l = 0 max_node_dist = 0 !Now save the close and far neighbors of the nodes. This is done to attempt to figure out the character of the dislocation !by comparing how the burgers vector is distributed over the face. do j = 1, 6 close_neighbors(1, 1, j) = cubic_faces(4, j) close_neighbors(2, 1, j) = cubic_faces(2, j) far_neighbor(1,j) = cubic_faces(3,j) close_neighbors(1, 2, j) = cubic_faces(1, j) close_neighbors(2, 2, j) = cubic_faces(3, j) far_neighbor(2,j) = cubic_faces(4,j) close_neighbors(1, 3, j) = cubic_faces(2, j) close_neighbors(2, 3, j) = cubic_faces(4, j) far_neighbor(3,j) = cubic_faces(1,j) close_neighbors(1, 4, j) = cubic_faces(3, j) close_neighbors(2, 4, j) = cubic_faces(1, j) far_neighbor(4,j) = cubic_faces(2,j) end do !First calculate all of the face centroids do i = 1, ele_num do j = 1, 6 r(:) = 0.0_dp rmax= -Huge(1.0) rmin= Huge(1.0) do k = 1, 4 do ibasis = 1, basisnum(lat_ele(i)) r = r + r_node(:, ibasis, cubic_faces(k,j), i) rmax= max(rmax, r_node(:, ibasis, cubic_faces(k,j), i)) rmin= min(rmin, r_node(:, ibasis, cubic_faces(k,j), i)) end do end do rnorm=norm2(rmax-rmin) max_node_dist = max(max_node_dist, rnorm) r = r/(basisnum(lat_ele(i))*4) !add the face centroids, the type, and map the elements faces to the face arrays l = l + 1 face_centroids(:, l) = r face_types(l) = j face_ele(l) = i end do end do !Now set the cut off distance as half the distance from opposite nodes in the largest element rc = 0.5*max_node_dist call calc_NN(l, face_centroids(:,1:l), rc) !Now loop overall the faces and make sure the nearest neighbor is the opposite type. If it isn't than we dscard it is_slipped = 0 do i = 1, l nei = nn(i) !Skip if it's 0 or the closest face belongs to the same element if ((nei == 0).or.(face_ele(i) == face_ele(nei))) cycle !Check the face types, the way that the faces are laid out in the cubic_faces array face 1's opposite is 6 and ! face 2's opposite is 5 and etc vnode = 0 if(face_types(i) == (7-face_types(nei))) then vnorm = 0 do j = 1, 4 do ibasis = 1, basisnum(lat_ele(face_ele(i))) !Compute the vectors between all nodes at the face. vnode(:,ibasis,j) = r_node(:,ibasis, cubic_faces(j,face_types(i)), face_ele(i)) - & r_node(:,ibasis, cubic_faces(j,face_types(nei)), face_ele(nei)) end do end do !Now calculate the maximum difference between nodes vnorm = 0 do j = 1, 4 do k=j,4 v1=vnode(:,1,j) - vnode(:,1,k) v1norm=norm2(v1) if (vnorm < v1norm) then vnorm = v1norm diffvec= v1 end if end do end do !Now calculate the difference between the largest norm and the smallest norm, if it's larger than 0.5 then mark it !as slipped. This value probably can be converted to a variable value that depends on the current lattice parameter !I think 0.5 works ok though. if (vnorm>0.5_dp) then print *, "Element number ", face_ele(i), " is dislocated along face ", face_types(i), & " with neighbor ", face_ele(nei), " with max displacement of ", vnorm l=0 do j = 1, 4 is_slipped(:, cubic_faces(j,face_types(i)), face_ele(i)) = 1 !This portion of the code is used to determine what the character of the dislocation most likely is !effectively how this works is we look for the two nodes with the most similar burgers vector. !The vector between these two nodes is close to the line direction and as a result we can probably estimate !if it's close to edge, screw, or if it's pretty fairly mixed. do k = j+1, 4 l=l+1 diff_mag(l) = norm2(vnode(:, 1, j)-vnode(:,1,k)) diff_pair(1,l)=cubic_faces(j, face_types(i)) diff_pair(2,l)=cubic_faces(k, face_types(i)) end do end do minindex = minloc(diff_mag,1) !Now figure out if the min difference between nodes is associated with a 112 direction is_edge = .false. do j = 1,6 if((diff_pair(1,minindex) == oneonetwopairs(1,j)).and.(diff_pair(2,minindex)==oneonetwopairs(2,j))) then is_edge=.true. exit else if((diff_pair(2,minindex)==oneonetwopairs(1,j)).and.(diff_pair(1,minindex)==oneonetwopairs(2,j)))then is_edge=.true. exit end if end do if(is_edge) then print *, 'Dislocation has primarily edge character' else print *, 'Dislocation has primarily screw character' end if if( i < nei) then num_d_points=num_d_points+2 if(num_d_points > size(disl_line,2)) then allocate(disl_line_temp(3,size(disl_line,2)+1024)) disl_line_temp=0.0_dp disl_line_temp(:, 1:size(disl_line,2))=disl_line call move_alloc(disl_line_temp, disl_line) end if if(num_d_points/2 > size(disl_data)) then allocate(disl_data_temp(size(disl_data)+1024)) disl_data_temp=0 disl_data_temp(1:size(disl_data)) = disl_data call move_alloc(disl_data_temp, disl_data) end if print *, num_d_points/2, vnorm disl_data(num_d_points/2)=vnorm disl_line(:,num_d_points-1) =r_node(:, 1, diff_pair(1,minindex), face_ele(i)) disl_line(:,num_d_points) =r_node(:, 1, diff_pair(2,minindex), face_ele(i)) end if end if end if end do end subroutine cga_da subroutine write_da_vtk(outfile) character (len=*), intent(in) :: outfile integer :: i open(unit=11, file=outfile, action='write', status='replace', position='rewind') write(11, '(a)') '# vtk DataFile Version 4.0.1' write(11, '(a)') 'Dislocation line analyzed via cacmb dislocation analysis' write(11, '(a)') 'ASCII' write(11, '(a)') 'DATASET UNSTRUCTURED_GRID' write(11, *) 'POINTS', num_d_points, 'float' !Write the points to the file do i = 1, num_d_points write(11, '(3f23.15)') disl_line(:, i) end do write(11,*) 'CELLS', num_d_points/2, num_d_points/2*3 do i=1, num_d_points, 2 write(11,'(3i16)') 2, i-1, i end do write(11,*) 'CELL_TYPES', num_d_points/2 do i=1, num_d_points, 2 write(11,'(i16)') 3 end do write(11,*) 'CELL_DATA', num_d_points/2 write(11, '(a)') 'SCALARS burgers_vec, float' write(11, '(a)') 'LOOKUP_TABLE default' do i=1, num_d_points, 2 write(11, '(f23.15)') disl_data((i+1)/2) end do close(11) end subroutine write_da_vtk subroutine write_da_xyz(outfile) !This subroutine write the element positions to a .xyz file and marks whether they are slipped or not character(len=*), intent(in) :: outfile integer :: i, ibasis, inod, outn open(unit=11, file=outfile, action='write', status='replace', position='rewind') !Write number of node_atoms write(11, '(i16)') node_atoms !Write comment write(11, '(a)') "is_slipped x y z" !Write nodal positions outn = 0 do i = 1, ele_num do inod = 1, ng_node(lat_ele(i)) do ibasis = 1, basisnum(lat_ele(i)) write(11, '(1i16, 3f23.15)') is_slipped(ibasis,inod,i), r_node(:,ibasis,inod,i) outn = outn + 1 end do end do end do if(outn /= node_atoms) then print *, "outn", outn, " doesn't equal node_atoms ", node_atoms end if close(11) end subroutine write_da_xyz end module