MakeSlab.psm1

Function Merge-ToSlab{
[CmdletBinding()]
Param(
[Parameter(Mandatory="True", Position=0)][string]$FirstPOSCAR,
[Parameter(Mandatory="True", Position=1)][string]$SecondPOSCAR)
Write-Host "Only Cubic and Tetragonal POSCARs are supported.
Make sure your POSCARs DO NOT have non-zero xz,yz,zx,zy elements,
If so, first rotate POSCAR using Vesta."
 -ForegroundColor Yellow
$data1=(Get-Content $FirstPOSCAR)
$data2=(Get-Content $SecondPOSCAR)
$lc1=[float]$data1[1] ; $lc2=[float]$data2[1] #lattice constants
$x1=[array]($data1[2].split()|Where-Object {$_})
$y1=[array]($data1[3].split()|Where-Object {$_})
$z1=[array]($data1[4].split()|Where-Object {$_})
$x2=[array]($data2[2].split()|Where-Object {$_})
$y2=[array]($data2[3].split()|Where-Object {$_})
$z2=[array]($data2[4].split()|Where-Object {$_})
if([float]$x1[2] -ne 0 -or [float]$y1[2] -ne 0 -or [float]$z1[0] -ne 0 -or [float]$z1[1] -ne 0){
  Write-Host "First POSCAR $FirstPOSCAR has any non-zero xz,yz,zx,zy elements, Can't proceed" -ForegroundColor Red
  break}
if([float]$x2[2] -ne 0 -or [float]$y2[2] -ne 0 -or [float]$z2[0] -ne 0 -or [float]$z2[1] -ne 0){
  Write-Host "Second $SecondPOSCAR has any non-zero xz,yz,zx,zy elements, Can't proceed" -ForegroundColor Red
  break}
#getting volume and cross-sectional area to find modified (0,0,z) for second POSCAR
$V2=([Math]::Pow($lc2,3))*(([float]$x2[0])*([float]$y2[1])*([float]$z2[2]));
$Axy1=([Math]::Pow($lc1,2))*(([float]$x1[0])*([float]$y1[1]))
$z2_new=[float]$V2/$Axy1 #Make x y same, change z for second slab
$totalZ=[float](($lc1*[float]$z1[2])+$z2_new)
$factor1=($lc1*[float]$z1[2])/$totalZ
$factor2=[float]$z2_new/$totalZ
$elem_1= $data1[5].Split()|Where-Object {$_}
$total_1=[array]$data1[6].Split()|Where-Object {$_}; 
$elem_2= $data2[5].Split()|Where-Object {$_}
$total_2=[array]$data2[6].Split()|Where-Object {$_}
$max_elem_index=[int]([Math]::Max($total_1.Count,$total_2.Count)-1)
$total_slab=Foreach($i in 0..$max_elem_index){[int]$total_1[$i]+[int]$total_2[$i]}  #index_out_of_range doesnt make problem here.
$diff_elem=(Compare-Object -ReferenceObject $elem_1 -DifferenceObject $elem_2 -PassThru)
$Elements="$elem_1 $diff_elem" #creates elements in slab
$outfile=New-Item -Path ./POSCAR_New.vasp -Force
$POSACR_init=@"
$($data1[0].Trim()+'/'+$data2[0].Trim())
$("{0:n16}" -f ($lc1*$x1[0]))
$("{0,24:N16}" -f 1) $("{0,24:N16}" -f ($x1[1]/$x1[0])) $("{0,24:N16}" -f 0)
$("{0,24:N16}" -f ($y1[0]/$x1[0])) $("{0,24:N16}" -f ($y1[1]/$x1[0])) $("{0,24:N16}" -f 0)
$("{0,24:N16}" -f 0) $("{0,24:N16}" -f 0) $("{0,24:N16}" -f ($totalZ/($lc1*$x1[0])))
  $Elements
  $total_slab
Direct
"@
  #here-string for Z-only yet.
$POSACR_init|Set-Content $outfile
#save data in array
if($data1[7].StartsWith('S') -or $data2[7].StartsWith('S')){$shift=8;$ii=9}Else{$shift=7;$ii=8} #see if slective dynamics there.
$N1=[int]((,$shift+$total_1)|Measure-Object -Sum).Sum
$N2=[int]((,$shift+$total_2)|Measure-Object -Sum).Sum
$arr1=$data1[$ii..$N1]; $arr2=$data2[$ii..$N2];
#Loops of getting data
$start1=0;$stop1=[int]$total_1[0]-1
$start2=0;$stop2=[int]$total_2[0]-1
ForEach($index in 0..$max_elem_index){
if($index -lt $total_1.Count){
ForEach($i in $start1..$stop1){ #Array1
if($i -lt $(($total_1|Measure-Object -Sum).Sum)){
[array]$value=$arr1[$i].Split()|Where-Object {$_}
$value_new=([float]$value[2])*$factor1
$line="{0,24:N16}" -f ([float]$value[0]) + "{0,24:N16}" -f ([float]$value[1]) + "{0,24:N16}" -f ($value_new)
$line|Add-Content $outfile
}}
$start1+=[int]$total_1[$index]; 
$stop1=$start1+ [int]$total_1[$index+1]-1
}
if($index -lt $total_2.Count){
ForEach($i in $start2..$stop2){ #Array2
if($i -lt $(($total_2|Measure-Object -Sum).Sum)){
[array]$value=$arr2[$i].Split()|Where-Object {$_}
$value_new=([float]$value[2])*$factor2+$factor1
$line="{0,24:N16}" -f ([float]$value[0]) + "{0,24:N16}" -f ([float]$value[1]) + "{0,24:N16}" -f ($value_new)
$line|Add-Content $outfile
}}
$start2+=[int]$total_2[$index]; 
$stop2=$start2+ [int]$total_2[[int]($index+1)]-1
}
}
Write-Host "File [POSCAR_New.vasp] created." -ForegroundColor Green
}
Function Enable-SelectiveDynamics{
[CmdletBinding()]
Param(
[Parameter(Mandatory="True", Position=0)][string]$InputPOSCAR,
[Parameter(Position=1)][array]$SelectSitesNumber=@())
$data=Get-Content $InputPOSCAR
if($data[7].StartsWith('S')){$shift=8;$ii=9}Else{$shift=7;$ii=8} #see if slective dynamics there.
$N=([array]$data[6].Split()|Where-Object {$_}|Measure-Object -Sum).Sum+$shift
$data_New=$data[$ii..$N];
$outFile=New-Item ./POSCAR_eSD.vasp -Force
$($data[0..6])|Set-Content $outFile
$POSCAR_init=@"
Selective dynamics
Direct
"@

$POSCAR_init|Add-Content $outFile
ForEach($i in 0..($data_New.Count-1)){
if ($SelectSitesNumber.Contains($($i-(-1)))){$pattern=" T T T";
}Else{$pattern=" F F F"}
$value=($data_New[$i].Replace('F','').Replace('T','').TrimEnd())
"$value $pattern"|Add-Content $outFile}
Write-Host "File [POSCAR_eSD.vasp] is created." -ForegroundColor Green
}

Function Select-SitesInLayers{
[CmdletBinding()]
Param(
[Parameter(Mandatory="True", Position=0)][string]$InputPOSCAR,
[Parameter(Mandatory="True", Position=1)][array]$Array_2Decimal=@())
$data=Get-Content $InputPOSCAR
$SelectLayersPosition=@($Array_2Decimal)
if($data[7].StartsWith('S')){$shift=8;$ii=9}Else{$shift=7;$ii=8} #see if slective dynamics there.
$N=([array]$data[6].Split()|Where-Object {$_}|Measure-Object -Sum).Sum+$shift
$data_New=$data[$ii..$N];
$X=@();$Y=@();$Z=@(); #arrays of elements in 3D
ForEach($i in 0..($data_New.Count-1)){
[array]$value=($data_New[$i].Split()|Where-Object {$_});
[string]$value2=$value[2];[string]$value1=$value[1];[string]$value0=$value[0];
[string]$nV2=(($value2.split('.')[0],$value2.split('.')[1].Substring(0,2)) -join '.')
[string]$nV1=(($value1.split('.')[0],$value1.split('.')[1].Substring(0,2)) -join '.')
[string]$nV0=(($value0.split('.')[0],$value0.split('.')[1].Substring(0,2)) -join '.')
if ($SelectLayersPosition -contains $nV0){$X+=$($i+1)}
if ($SelectLayersPosition -contains $nV1){$Y+=$($i+1)}
if ($SelectLayersPosition -contains $nV2){$Z+=$($i+1)}
}
[pscustomobject]@{XY_PlaneSites=[array]($Z|Sort-Object);YZ_PlaneSites=[array]($X|Sort-Object);ZX_PlaneSites=[array]($Y|Sort-Object)} #output custom Object
}

Function Disable-SelectiveDynamics{
[CmdletBinding()]
Param([Parameter(Mandatory="True",Position=0)][string]$InputPOSCAR)
$read1=(Get-Content $InputPOSCAR|Where-Object {$_ -notmatch 'elective'})[0..6]
$read2=(Get-Content $InputPOSCAR|Select-Object -Skip 7|Where-Object {$_ -notmatch 'elective'}).Replace('F','').Replace('T','').TrimEnd()|Where-Object {$_}
$outFile =New-Item POSCAR_dSD.vasp -Force
($read1,$read2)|Set-Content $outFile -Force
Write-Host "File [POSCAR_dSD.vasp] created."
}

Function Show-LayersInfo{
[CmdletBinding()]
Param([Parameter(Mandatory="True",Position=0)][string]$InputPOSCAR)
$data=(Get-Content $InputPOSCAR|Where-Object {$_ -notmatch 'elective'})
$nAtoms=[int]($data[6].Split(" ")|Where-Object {$_}|Measure-Object -sum).sum
$coords=$data[8..($nAtoms+7)]
$z_coord=@();$x_coord=@();$y_coord=@();
Foreach($coord in $coords){
[array]$value=$coord.split()|Where-Object {$_}
[string]$value2=$value[2];[string]$value1=$value[1];[string]$value0=$value[0];
$z_coord+=(($value2.split('.')[0],$value2.split('.')[1].Substring(0,2)) -join '.')
$y_coord+=(($value1.split('.')[0],$value1.split('.')[1].Substring(0,2)) -join '.')
$x_coord+=(($value0.split('.')[0],$value0.split('.')[1].Substring(0,2)) -join '.')
}
[pscustomobject]@{
  X_AtLayers=[array]($x_coord|Select-Object -Unique|Sort-Object); 
  Y_AtLayers=[array]($y_coord|Select-Object -Unique|Sort-Object); 
  Z_AtLayers=[array]($z_coord|Select-Object -Unique|Sort-Object)} #output custom Object
}
Export-ModuleMember -Function 'Merge-ToSlab'
Export-ModuleMember -Function 'Enable-SelectiveDynamics'
Export-ModuleMember -Function 'Select-SitesInLayers'
Export-ModuleMember -Function 'Disable-SelectiveDynamics'
Export-ModuleMember -Function 'Show-LayersInfo'