#=============================================== # WIEN2k #=============================================== package WIEN2k; use Exporter; use Common; @ISA = qw(Exporter Common); #公開したいサブルーチン @EXPORT = qw(); use strict; use File::Basename; use JFile; use Sci::Science; use Sci::EnergyBand; use GraphData; use MyTk::GraphFrameArray; use Crystal::Crystal; use Crystal::AtomType; use Crystal::AtomSite; use Crystal::CIF; #============================================================ # 静的メンバー関数 #============================================================ sub GetStructFile { return Deps::ReplaceExtension($_[0], ".struct"); } sub GetSCFFile { return Deps::ReplaceExtension($_[0], ".scf"); } sub GetOutput2File { return Deps::ReplaceExtension($_[0], ".output2"); } sub GetINSPFile { return Deps::ReplaceExtension($_[0], ".insp"); } #============================================================ # 変数取得関数など #============================================================ sub ClearAll { my $this=shift; undef $this->{'FileType'}; undef $this->{'DataArray'}; } sub FileType { return shift->{'FileType'}; } sub FileName { return shift->{'FileName'}; } sub SetFileName { my ($this,$f)=@_; return $this->{'FileName'} = $f; } #sub DataArray { return shift->{'DataArray'}; } #sub SetDataArray { my ($this, $da) = @_; return $this->{'DataArray'} = $da; } #============================================================ # コンストラクタ、デストラクタ #============================================================ sub new { my ($module) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ sub CheckFileType { my ($path) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); #print "In WIEN2k::CheckFileType for $path\n"; if($ext =~ /^\.epsilon(up|dn)?$/i) { return "WIEN2k epsilon file"; } elsif($ext =~ /^\.spaghetti(up|dn)?_ene$/i) { return "WIEN2k spaghetti Band file"; } elsif($ext =~ /^\.int$/i or $ext =~ /^\.dos\d(ev)?(up|dn)?$/i) { my $in = new JFile($path, "r"); return undef unless($in); my $line1 = $in->ReadLine(); my $line2 = $in->ReadLine(); my $line3 = $in->ReadLine(); $in->Close(); #print "line2: $line2\n"; return "WIEN2k PDOS files" if($ext =~ /^\.int$/i and $line2 =~ /EMIN, DE, EMAX/); return "WIEN2k PDOS files" if($ext =~ /^\.dos\d(ev)?(up|dn)?$/i and $line3 =~ /# ENERGY /); } return undef; } sub ReadEpsilonFile { my ($this, $path) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); my $SampleName = $filebody; my @files; my $upfile = $path; my $dnfile; if($ext =~ /up/i) { $upfile = $path; $dnfile = $path; $dnfile =~ s/^(.*)up(.*?)$/$1dn$2/; } elsif($ext =~ /dn/i) { $dnfile = $path; $upfile = $path; $upfile =~ s/^(.*)dn(.*?)$/$1up$2/; } $files[0] = $upfile; $files[1] = $dnfile if($dnfile); $this->SetDataArray(new GraphDataArray); my $Data = new GraphData; $Data->SetTitle($SampleName); for(my $i = 0 ; $i < @files ; $i++) { my $fname = $files[$i]; print " Read [$fname]\n"; my @Energy; my @Rexx; my @Imxx; my @Rezz; my @Imzz; my $in = new JFile($fname, "rb"); unless($in) { print "Error: Could not read [$fname].\n"; last; } $in->SkipTo("^# Energy", 0); $in->ReadLine(); my $c = 0; while(!$in->eof()) { my $line = $in->ReadLine(); my @a = split(/\s+/, $line); @a = Utils::RemoveSpaceElement(@a); $Energy[$c] = $a[0]; $Rexx[$c] = $a[1]; $Imxx[$c] = $a[2]; $Rezz[$c] = $a[3]; $Imzz[$c] = $a[4]; $c++; } $in->Close(); my $spin = ' for up'; $spin = ' for down' if($i > 0); my $idx = $i * 4; $Data->{"x${idx}"} = \@Energy; $Data->{"x${idx}_Name"} = "Energy / eV"; $Data->{"y${idx}"} = \@Rexx; $Data->{"y${idx}_Name"} = "Re(eps)xx$spin"; $idx++; $Data->{"x${idx}"} = \@Energy; $Data->{"x${idx}_Name"} = "Energy / eV"; $Data->{"y${idx}"} = \@Imxx; $Data->{"y${idx}_Name"} = "Im(eps)xx$spin"; $idx++; $Data->{"x${idx}"} = \@Energy; $Data->{"x${idx}_Name"} = "Energy / eV"; $Data->{"y${idx}"} = \@Rezz; $Data->{"y${idx}_Name"} = "Re(eps)zz$spin"; $idx++; $Data->{"x${idx}"} = \@Energy; $Data->{"x${idx}_Name"} = "Energy / eV"; $Data->{"y${idx}"} = \@Imzz; $Data->{"y${idx}_Name"} = "Im(eps)zz$spin"; } $Data->CalMinMax(); $this->DataArray()->AddGraphData($Data); return $filename; } sub ReadIntFile { my ($this, $path, $idx) = @_; print " Read $path\n"; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); $this->SetSampleName($filename); my $int = new JFile($path, "r"); return undef unless($int); my $line1 = $int->ReadLine(); my $line2 = $int->ReadLine(); my $line3 = $int->ReadLine(); my @DOSName; my ($nDOS) = ($line3 =~ /(\d+)/); #print "nDOS: $nDOS\n"; for(my $i = 0 ; $i < $nDOS ; $i++) { my $line = $int->ReadLine(); my @a = ($line =~ /^\s*(\w+)\s+(\w+)\s+(.*)$/); Utils::DelSpace($a[2]); $DOSName[$i] = $a[2]; $DOSName[$i] = 'Total' if($DOSName[$i] =~ /^\s*total\s+atom,/); #print "D: $DOSName[$i]\n"; } $int->Close(); $this->{'nDOS'} = $nDOS; $this->{'DOSNameArray'} = \@DOSName; return 1; } sub ReadPDOSFilesWithIndex { my ($this, $pPathArray, $idx) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($pPathArray->[0]); $this->SetSampleName($filename); my $pDOSNameArray = $this->{'DOSNameArray'}; my $Data = $this->DataArray()->GetGraphData($idx); my $CurDOS = 0; my $iData = 0; my @DOSArray; my @Energy; for(my $i = 0 ; $i < @$pPathArray ; $i++) { my $fname = $pPathArray->[$i]; print " Read $fname\n"; # my @a; # $DOSArray[$i] = \@a; my $in = new JFile($fname, "r"); return undef unless($in); my $line = $in->ReadLine(); $line = $in->ReadLine(); $line = $in->ReadLine(); $iData = 0; my $nY = 0; while(!$in->eof()) { $line = $in->ReadLine(); # last if($in->eof()); my @a = Utils::Split("\\s+", $line); $nY = @a-1; next if($nY < 2); $Energy[$iData] = $a[0]; for(my $k = 0 ; $k < $nY ; $k++) { $DOSArray[$CurDOS+$k] = () if(!defined $DOSArray[$CurDOS+$k]); $DOSArray[$CurDOS+$k]->[$iData] = $a[$k+1]; } $iData++; } $in->Close(); $CurDOS += $nY; } my $nDOS = $CurDOS; $Data->SetTitle($filename); $Data->{'x0'} = \@Energy; $Data->{'x0_Name'} = "Energy / " . $this->{'EnergyUnit'}; for(my $i = 0 ; $i < $nDOS ; $i++) { $Data->{"y$i"} = $DOSArray[$i]; my $DOSName; if($pDOSNameArray and $pDOSNameArray->[$i]) { $Data->{"y${i}_Name"} = $pDOSNameArray->[$i]; } else { $Data->{"y${i}_Name"} = "DOS$i"; } } $Data->CalMinMax(); my ($xmin, $xmax, $ymin, $ymax) = $Data->GetMinMax(); #print "minmax: $xmin,$xmax,$ymin,$ymax\n"; return $filename; } sub ReadPDOSFiles { my ($this, $path) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); my $SampleName = $filename; my $SpinPolarized = 0; my $ReadInt = 1; my $ReadUp = 1; my $ReadDn = 1; my $Unit = 'eV'; my $ExtUp = 'ev'; my $ExtDn = 'ev'; if($ext =~ /int$/i or $ext =~ /ev$/i) { } elsif($ext =~ /ev(up|dn)$/i) { $SpinPolarized = 1; $ExtUp = 'evup'; $ExtDn = 'evdn'; } elsif($ext =~ /(up|dn)$/i) { $SpinPolarized = 1; $Unit = 'Ry'; $ExtUp = 'up'; $ExtDn = 'dn'; } else { $Unit = 'Ry'; $ExtUp = ''; $ExtDn = ''; } my $IntFileName; my @UpFileName; my @DnFileName; $IntFileName = Deps::ReplaceExtension($path, ".int"); $ReadInt = 0 unless(-f $IntFileName); $UpFileName[0] = Deps::ReplaceExtension($path, ".dos1$ExtUp"); $ReadUp = 0 unless(-f $UpFileName[0]); $DnFileName[0] = Deps::ReplaceExtension($path, ".dos1$ExtDn"); $ReadDn = 0 if(!($SpinPolarized and -f $DnFileName[0])); for(my $i = 1 ; $i < 5 ; $i++) { my $i1 = $i + 1; my $f; $f = Deps::ReplaceExtension($path, ".dos${i1}$ExtUp"); $UpFileName[$i] = $f if(-e $f); $f = Deps::ReplaceExtension($path, ".dos${i1}$ExtDn"); $DnFileName[$i] = $f if(-e $f); } $this->SetDataArray(new GraphDataArray); $this->{'EnergyUnit'} = $Unit; my $UpData = new GraphData; $this->DataArray()->AddGraphData($UpData); if($SpinPolarized) { my $DnData = new GraphData; $this->DataArray()->AddGraphData($DnData); } if($ReadInt) { $this->ReadIntFile($IntFileName); } if($ReadUp) { $this->ReadPDOSFilesWithIndex(\@UpFileName, 0); } if($ReadDn) { $this->ReadPDOSFilesWithIndex(\@DnFileName, 1); } return $filename; } sub MakeKListForFS { my ($this, $KListPath, $CheckPath, $Crystal, $Title, $UseSymmetry, $nx, $ny, $nz, $div, $emin, $emax, $K, $IsPrint) = @_; $UseSymmetry = 0 if(!defined $UseSymmetry); $nx = 5 if(!defined $nx); $ny = 5 if(!defined $ny); $nz = 5 if(!defined $nz); $K = 1.0 if(!defined $K); $IsPrint = 1 if(!defined $IsPrint); my @KIndex; my $out = new JFile; if(!$out->Open($KListPath, "w")) { print("Error: $!: Can not write to [$KListPath]\n") if($IsPrint); return (0); } my $check; if($CheckPath) { $check = new JFile(); if(!$check->Open($CheckPath, "w")) { print("$!: Can not write to [$CheckPath].\n") if($IsPrint); } } my $ra = $Crystal->GetMatrixConventionalToPrimitiveReciprocalCell(); if($IsPrint) { print("Primitive RLattice vector: ($ra->[0][0], $ra->[0][1], $ra->[0][2])\n"); print(" ($ra->[1][0], $ra->[1][1], $ra->[1][2])\n"); print(" ($ra->[2][0], $ra->[2][1], $ra->[2][2])\n"); } my $count = 1; my $BandName = ""; print("kx range: (0 - $nx)\n") if($IsPrint); for(my $ix = 0 ; $ix <= $nx ; $ix++) { for(my $iy = 0 ; $iy <= $ny ; $iy++) { my $BandNamePrinted = 0; for(my $iz = 0 ; $iz <= $nz ; $iz++) { if($iz == 0) { $BandName = sprintf("B%02d%02d", $ix+1, $iy+1); } else { $BandName = ""; } my ($IsConverted, $cix, $ciy, $ciz) = $Crystal->ConvertLatticeIndexByLatticeSystem($ix, $iy, $iz); if($UseSymmetry and $IsConverted) { next; } my $px = $K * $div * $ix / $nx; my $py = $K * $div * $iy / $ny; my $pz = $K * $div * $iz / $nz; my $x = $ra->[0][0] * $px + $ra->[1][0] * $py + $ra->[2][0] * $pz; my $y = $ra->[0][1] * $px + $ra->[1][1] * $py + $ra->[2][1] * $pz; my $z = $ra->[0][2] * $px + $ra->[1][2] * $py + $ra->[2][2] * $pz; # my $x = ($ra->[0][0] + $ra->[1][0] + $ra->[2][0]) * $K * $div * $ix / $nx; # my $y = ($ra->[0][1] + $ra->[1][1] + $ra->[2][1]) * $K * $div * $iy / $ny; # my $z = ($ra->[0][2] + $ra->[1][2] + $ra->[2][2]) * $K * $div * $iz / $nz; # my $x = $K * $div * $ix / $nx; # my $y = $K * $div * $iy / $ny; # my $z = $K * $div * $iz / $nz; if(!$BandNamePrinted) { $BandNamePrinted = 1; $out->printf("%5s %3d %3d %3d %3d%4.1f %4.1f %4.1f\n", $BandName, $x, $y, $z, $div, 1.0, $emin, $emax); } else { $out->printf("%5s %3d %3d %3d %3d%4.1f\n", $BandName, $x, $y, $z, $div, 1.0); } if($check) { $KIndex[$count-1] = sprintf("%03d%03d%03d", $ix, $iy, $iz); $check->printf("%05d: %2d %2d %2d\n", $count, $ix, $iy, $iz); } $count++; } } } if($check) { $check->Close(); } $out->printf("END\n\n"); $out->Close(); return (1, @KIndex); } sub ReadKListBandFile { my ($this, $path) = @_; print " Read [$path]\n"; undef $this->{'KPointNameArray'}; my @KPointNameArray; my $in = new JFile($path, "rb"); return undef unless($in); while(!$in->eof()) { my $line = $in->ReadLine(); last if($in->eof()); my $s = substr($line, 0, 10); Utils::DelSpace($s); next if($s eq ''); push(@KPointNameArray, $s); print " KPoint: $s\n"; } $in->Close(); $this->{'KPointNameArray'} = \@KPointNameArray; return 1; } sub ReadSpaghettiBandFileWithIndex { my ($this, $path, $idx) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); my $SampleName = $filebody; print " Read [$path]\n"; my @BandArray; my $in = new JFile($path, "rb"); return undef unless($in); my $line = $in->ReadLine(); my $iBand = 0; while(!$in->eof()) { my $ik = 0; my $band = $BandArray[$iBand] = new EnergyBand; #print "iBand: $iBand\n"; while(!$in->eof()) { $line = $in->ReadLine(); last if($line =~ /^\s*bandindex:/); last if($in->eof()); my @a = split(/\s+/, $line); my ($kx, $ky, $kz, $d, $e) = Utils::RemoveSpaceElement(@a); #print "ib=$iBand ik=$ik: $kx, $ky, $kz, $d, $e\n"; $band->AddByKDE($kx, $ky, $kz, $d, $e); } $iBand++; } # $this->SetDataArray(new GraphDataArray); my $Data = new GraphData; $Data->SetTitle($SampleName); my $band = $BandArray[0]; $Data->{"x0"} = $band->pDistance(); $Data->{"x0_Name"} = "k"; for(my $i = 0 ; ; $i++) { $band = $BandArray[$i]; last unless($band); $band->CalMinMax(); $Data->{"y$i"} = $band->pEnergy(); my ($ymin, $ymax) = $band->GetYMinMax(); my $s = "Band $i ($ymin - $ymax)"; #print "s: $s\n"; $Data->{"y${i}_Name"} = $s; } $Data->CalMinMax(); my ($pBandBoundaryDistance, $pBoundaryPositions) = $BandArray[0]->GetBandBoundary(); $this->DataArray()->{'BandBoundaryDistances'} = $pBandBoundaryDistance; $this->DataArray()->{'BandBoundaryPositions'} = $pBoundaryPositions; $this->DataArray()->AddGraphData($Data); return $filename; } sub ReadSpaghettiBandFile { my ($this, $path) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); my $SampleName = $filebody; $this->SetSampleName($SampleName); my $KListFile = Deps::ReplaceExtension($path, "klist_band"); $this->ReadKListBandFile($KListFile); $this->SetDataArray(new GraphDataArray); if($ext =~ /up/i) { my $upfile = $path; my $dnfile = $path; $dnfile =~ s/^(.*)up(.*?)$/$1dn$2/; $this->ReadSpaghettiBandFileWithIndex($upfile, 0); $this->ReadSpaghettiBandFileWithIndex($dnfile, 1); } elsif($ext =~ /dn/i) { my $dnfile = $path; my $upfile = $path; $upfile =~ s/^(.*)dn(.*?)$/$1up$2/; $this->ReadSpaghettiBandFileWithIndex($upfile, 0); $this->ReadSpaghettiBandFileWithIndex($dnfile, 1); } else { $this->ReadSpaghettiBandFileWithIndex($path, 0); } return $filename; } sub Read { my ($this, $filename) = @_; $this->ClearAll(); my $FileType = $this->{'FileType'} = WIEN2k::CheckFileType($filename); return undef unless($FileType); $this->SetFileName($filename); if($FileType eq "WIEN2k epsilon file") { return $this->ReadEpsilonFile($filename); } elsif($FileType eq "WIEN2k spaghetti Band file") { return $this->ReadSpaghettiBandFile($filename); } elsif($FileType eq "WIEN2k PDOS files") { return $this->ReadPDOSFiles($filename); } return undef; } sub SetSampleName { my ($this, $name) = @_; return $this->{'SampleName'} = $name; } sub SampleName { my ($this) = @_; return $this->{'SampleName'}; } sub ReadOrbitalSymmetriesFromQtlFile { my ($this, $filename) = @_; my $in = new JFile($filename, "r"); unless($in) { $this->print("Error: Can not read [$filename].\n"); return 0; } my $line = $in->ReadLine(); $line = $in->ReadLine(); $line = $in->ReadLine(); $line = $in->ReadLine(); my ($NAT) = ($line =~ /NAT=\s*(\d+)\s/); my @lines; for(my $i = 0 ; $i < $NAT ; $i++) { $lines[$i] = $in->ReadLine(); ($lines[$i]) = ($lines[$i] =~ /(tot,.*)\s/); # my $site = $AsymAtomSites[$i]; # my $atomname = $site->AtomNameOnly(); #$this->print("$i: $atomname: $lines[$i]\n"); #$this->print("$i: $lines[$i]\n"); } $in->Close(); return @lines; } sub ReadFermiEnergy { my ($this, $StructPath, $IsPrint, $IgnoreError) = @_; $IsPrint = 0 if(!defined $IsPrint); my $Output2Path = WIEN2k::GetOutput2File($StructPath); print("Output2 Path: $Output2Path\n") if($IsPrint); my $in = new JFile; if(!$in->Open($Output2Path, "r")) { print("Error: Can not read [$Output2Path]. \n") if($IsPrint); return undef if($IgnoreError); exit 0; } my $EF; while(1) { my $line = $in->SkipTo(":FER"); last if(!defined $line); ($EF) = ($line =~ /([\d\.eE\+\-]+)\s*$/); } $in->Close(); return $EF; } sub ReadSCFFileParameter { my ($this, $SCFFile, $Param) = @_; my $in = new JFile($SCFFile, "r"); unless($in) { print "Error in ReadTotalenergy: Can not read [$SCFFile].\n"; return -1; } my $LastVal; while(!$in->eof()) { my $line = $in->ReadLine(); last if($in->eof()); my ($val) = ($line =~ /^:$Param\s*?:\s*(\S.*)$/); next unless($val); $LastVal = $val; } $in->Close(); return $LastVal; } sub ReadStructFile { my ($this, $filename, $IsPrint, %arg) = @_; $IsPrint = 1 unless(defined $IsPrint); my $crystal = new Crystal(); my $in = new JFile($filename, "r"); return undef unless($in); my $line = $in->ReadLine(); Utils::DelSpace($line); $crystal->SetCrystalName($line); $crystal->SetSampleName($line); # LATTICE,NONEQUIV.ATOMS:4 129_P4/nmm #01234567890123456789012345678901234567890123456789 $line = $in->ReadLine(); #print "line: $line\n"; #$IsPrint=1; my $nAsymmetricAtom = substr($line, 27, 3); $this->print("nAsymmetricAtom: $nAsymmetricAtom\n") if($IsPrint); $line = substr($line, 30); my ($iSPG, $SPGName) = ($line =~ /^\s*(\d+)[_\s]+(.*)\s*$/); Utils::DelSpace($SPGName); Utils::DelSpace($iSPG); # $crystal->SetSpaceGroup($SPGName, $iSPG); #$this->print("SPG: $SPGName ($iSPG)\n") if($IsPrint); $line = $in->ReadLine(); my $unit = 1; # Angstrom $unit = Sci::a0() * 1.0e10 if($line |~ /unit=\s*ang/i); #0123456789012345678901234567890123456789012345678901234567890 # 7.897547 7.897547 17.634364 90.000000 90.000000 90.000000 $line = $in->ReadLine(); # my @latt = Utils::Split("\\s+", $line); my @latt; $latt[0] = substr($line, 0, 10); $latt[1] = substr($line, 10, 10); $latt[2] = substr($line, 20, 10); $latt[3] = substr($line, 30, 10); $latt[4] = substr($line, 40, 10); $latt[5] = substr($line, 50, 10); for(my $i = 0 ; $i < 3 ; $i++) { $latt[$i] *= $unit; } $crystal->SetLatticeParameters(@latt); $this->print("Latt: $latt[0] $latt[1] $latt[2] $latt[3] $latt[4] $latt[5]\n") if($IsPrint); $crystal->SetSpaceGroup($SPGName, $iSPG); $this->print("SPG: $SPGName ($iSPG)\n") if($IsPrint); my %AtomCount; for(my $i = 0 ; $i < $nAsymmetricAtom ; $i++) { #ATOM -1: X=0.25000000 Y=0.25000000 Z=0.13980000 $line = $in->SkipTo("ATOM"); my ($x, $y, $z) = ($line =~ /X=\s*(\S+?)\s+Y=\s*(\S+?)\s+Z=\s*(\S+?)\s/); # MULT= 2 ISPLIT=-2 $line = $in->ReadLine(); #print "lineMI: $line\n"; my ($mult, $iSplit) = ($line =~ /MULT=\s*(\d+)\s+ISPLIT=\s*([\+\-\d]+)/); #print "mult: $mult iSplit: $iSplit\n"; $crystal->{"MULT[$i]"} = $mult; $crystal->{"ISPLIT[$i]"} = $iSplit; for(my $j = 0 ; $j < $mult-1 ; $j++) { # -1: X=0.75000000 Y=0.75000000 Z=0.86020000 $in->ReadLine(); #print "lineM[$j]: $line\n"; } #La1 NPT= 781 R0=0.00001000 RMT= 2.2500 Z: 57.0 $line = $in->ReadLine(); #print "lineLa: $line\n"; my ($AtomName, $NPT, $R0, $RMT, $Z) = ($line =~ /(\S+).*NPT=\s*(\S+)\s*R0=(\S+)\s+RMT=\s*(\S+)\s*Z:\s*(\S+)/); $crystal->{"NPT[$i]"} = $NPT; $crystal->{"R0[$i]"} = $R0; $crystal->{"RMT[$i]"} = $RMT; $crystal->{"Z[$i]"} = $Z; #print "i=$i: NPT=$NPT R0=$R0 RMT=$RMT Z=$Z\n"; $AtomName =~ s/\d//g; $AtomCount{$AtomName}++; my $Label = $AtomName . $AtomCount{$AtomName}; $crystal->AddAtomType($AtomName); $crystal->AddAtomSite($Label, $AtomName, $x, $y, $z, 1.0); $this->print("$i: $Label: $AtomName ($x, $y, $z)\n") if($IsPrint); #01234567890123456789012345678901234567890123456789 #LOCAL ROT MATRIX: 1.0000000 0.0000000 0.0000000 # 0.0000000 1.0000000 0.0000000 # 0.0000000 0.0000000 1.0000000 my $line1 = $in->ReadLine(); my $line2 = $in->ReadLine(); my $line3 = $in->ReadLine(); my @a1 = (substr($line1, 20, 10), substr($line1, 30, 10), substr($line1, 40, 10)); my @a2 = (substr($line2, 20, 10), substr($line2, 30, 10), substr($line2, 40, 10)); my @a3 = (substr($line3, 20, 10), substr($line3, 30, 10), substr($line3, 40, 10)); #print "LRM[$i]: $a1[0],$a1[1],$a1[2]\n"; @a2 = Utils::Split("\\s+", substr($line2, 18)); #print " $a2[0],$a2[1],$a2[2]\n"; @a3 = Utils::Split("\\s+", substr($line3, 18)); #print " $a3[0],$a3[1],$a3[2]\n"; my $suffix = "LocalRotationMatrix[$i]"; # $this->{$suffix} = [ \@a1, \@a2, \@a3 ]; $crystal->{$suffix} = [ \@a1, \@a2, \@a3 ]; } $line = $in->SkipTo("NUMBER OF SYMMETRY OPERATIONS"); my ($nSym) = ($line =~ /^\s*(\d+)\s/); my $SPG = $crystal->GetCSpaceGroup(); print "nSym: $nSym\n" if($IsPrint); for(my $i = 0 ; $i < $nSym ; $i++) { $line = $in->ReadLine(); #print "$i: line: $line"; my ($a11, $a12, $a13, $t1) = ($line =~ /^(.{2})(.{2})(.{2})(.*)$/); #print " $a11,$a12,$a13,$t1\n"; $line = $in->ReadLine(); #print " line: $line"; my ($a21, $a22, $a23, $t2) = ($line =~ /^(.{2})(.{2})(.{2})(.*)$/); $line = $in->ReadLine(); #print "$i: line: $line"; my ($a31, $a32, $a33, $t3) = ($line =~ /^(.{2})(.{2})(.{2})(.*)$/); #print "($a11, $a12, $a13, $t1):"; my $s1 = SpaceGroupObject::BuildSymmetryOperationFromMatrix($a11, $a12, $a13, $t1); my $s2 = SpaceGroupObject::BuildSymmetryOperationFromMatrix($a21, $a22, $a23, $t2); my $s3 = SpaceGroupObject::BuildSymmetryOperationFromMatrix($a31, $a32, $a33, $t3); $this->print(" $i: ($s1, $s2, $s3)\n") if($IsPrint); $SPG->AddSymmetryOperation("$s1,$s2,$s3"); $in->ReadLine(); } #print "nS: ", $SPG->nSymmetryOperation(), "\n"; # $crystal->SetCSpaceGroup($SPG); $in->Close(); $crystal->ExpandCoordinates(); if($arg{tol}) { $SPG->SetLatticeSystem(undef, 2, $arg{tol}, $arg{tol}); #print "tol=$arg{tol}: LS=", $SPG->LatticeSystem(), "\n"; } return $crystal; } sub SaveINSPFile { my ($this, $StructPath, %args) = @_; my $INSPPath = WIEN2k::GetINSPFile($StructPath); print("INSP Path: $INSPPath\n") if($args{IsPrint}); if(-e $INSPPath) { print(".insp file [$INSPPath] exists. Skip.\n") if($args{IsPrint}); return 1; } my $EF = (defined $args{EF})? $args{EF} : $this->ReadFermiEnergy($StructPath); if(!defined $EF) { print("Error: Can not obtain Fermi energy.\n") if($args{IsPrint}); exit 0; } print(" EF: $EF eV\n") if($args{IsPrint}); if(!open(OUT, ">$INSPPath")) { print("Error: $!: Can not write to [$INSPPath].\n") if($args{IsPrint}); return 0; } print OUT <$filename")) { print "Can not write to $filename.\n\n"; return; } my $SampleName = $Crystal->SampleName(); $SampleName = $Crystal->CrystalName() unless($SampleName); $SampleName = $this->SampleName() unless($SampleName); print OUT "$SampleName\n"; my $SPGName = $Crystal->SPGNameByOutputMode(); my $iSPG = $Crystal->iSPGByOutputMode(); my $SPG = $Crystal->GetCSpaceGroup(); #print "nS2: ", $SPG->nSymmetryOperation(), "\n"; my $LatticeSystem = lc $SPG->LatticeSystem(); #print "LatticeSystem: $LatticeSystem\n"; my $WIEN2kSPGName = SpaceGroup::GetWIEN2kSPG($iSPG, 1); my @ExpandedAtomSiteList = $Crystal->GetCExpandedAtomSiteListByOutputMode(); my @AtomSiteList; if(!$IsExpandCoordinate and !$IsChooseRandomly) { # @AsymmetricAtomSiteList = $Crystal->GetCAsymmetricAtomSiteList(); @AtomSiteList = $Crystal->GetCExpandedAtomSiteList(); } my $nExpandedAtomSite = @ExpandedAtomSiteList; my $nAtomSite = @AtomSiteList; #print "nAtomSite: $nAtomSite\n"; #print "nExpandedAtomSite: $nExpandedAtomSite\n"; printf OUT "%3s LATTICE,NONEQUIV.ATOMS:%-4d%s\n", 'P ', $nExpandedAtomSite, $WIEN2kSPGName; my ($a,$b,$c,$alpha,$beta,$gamma) # = $Crystal->LatticeParametersByOutputMode(0); = $Crystal->LatticeParametersByOutputMode(1); # print OUT "MODE OF CALC=RELA unit=bohr\n"; print OUT "MODE OF CALC=RELA unit=ang\n"; printf OUT "%10.6f%10.6f%10.6f%10.6f%10.6f%10.6f\n", $a, $b, $c, $alpha, $beta, $gamma; #Occupancyが1のサイト my $count = 0; for(my $i = 0 ; $i < $nExpandedAtomSite ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $atomname = $atom->AtomNameOnly(); my $charge = $atom->Charge(); my $atomlabel = $atom->Label(); if($UseSameBasisForSameAtom) { $atomlabel = sprintf("%-2s%d", $atomname, 1); } else { $atomlabel = $atomname; } #print "la: $atomlabel . $atomname\n"; my ($x,$y,$z) = $atom->Position(1); my $occupancy = $atom->Occupancy(); my $mult = $atom->Multiplicity(); #print "mult: $mult\n"; $mult = 1 if($IsExpandCoordinate or $IsChooseRandomly); next if($occupancy < 0.9999); $count++; my $numAtom = $count; $numAtom = -$count if($LatticeSystem ne 'cubic'); printf OUT "ATOM%4d: X=%10.8f Y=%10.8f Z=%10.8f\n", $numAtom, $x, $y, $z; # $mult = 1; # $mult = $Crystal->{"MULT[$i]"}; my $iSplit = $Crystal->{"ISPLIT[$i]"}; $iSplit = 8 unless(defined $iSplit); printf OUT " MULT=%2d ISPLIT=%2d\n", $mult, $iSplit; $nAtomSite = 1 if($mult == 1); my $c = 0; for(my $j = 0 ; $j < $nAtomSite ; $j++) { my $atom2 = $AtomSiteList[$j]; next unless(defined $atom2); my $id2 = $atom2->IdAsymmetricAtomSite(); #print "i=$i: j=$j: id=$id2\n"; next if($id2 != $i+1); if($c == 0) { $c++; next; } ($x,$y,$z) = $atom2->Position(1); # printf OUT "ATOM%4d: X=%10.8f Y=%10.8f Z=%10.8f\n", printf OUT " %4d: X=%10.8f Y=%10.8f Z=%10.8f\n", $numAtom, $x, $y, $z; } $Crystal->{"NPT[$i]"} = 781 unless($Crystal->{"NPT[$i]"}); $Crystal->{"R0[$i]"} = 0.0 unless($Crystal->{"R0[$i]"}); $Crystal->{"RMT[$i]"} = 0.0 unless($Crystal->{"RMT[$i]"}); printf OUT "%-2s NPT= %4d R0=%10.8f RMT=%10.4f Z:%5.1f\n", $atomlabel, $Crystal->{"NPT[$i]"}, $Crystal->{"R0[$i]"}, $Crystal->{"RMT[$i]"}, # $atomname, $Crystal->{"NPT[$i]"}, $Crystal->{"R0[$i]"}, $Crystal->{"RMT[$i]"}, $Crystal->{"Z[$i]"}; my $suffix ="LocalRotationMatrix[$i]"; my $refMtx = $Crystal->{$suffix}; #print "refMtx: $refMtx\n"; if($refMtx) { printf OUT "LOCAL ROT MATRIX: %10.7f%10.7f%10.7f\n", $refMtx->[0][0], $refMtx->[0][1], $refMtx->[0][2]; printf OUT " %10.7f%10.7f%10.7f\n", $refMtx->[1][0], $refMtx->[1][1], $refMtx->[1][2]; printf OUT " %10.7f%10.7f%10.7f\n", $refMtx->[2][0], $refMtx->[2][1], $refMtx->[2][2]; } else { print OUT "LOCAL ROT MATRIX: 1.0000000 0.0000000 0.0000000\n"; print OUT " 0.0000000 1.0000000 0.0000000\n"; print OUT " 0.0000000 0.0000000 1.0000000\n"; } } #Occupancyが1未満のサイト if(@ExpandedAtomSiteList > $count and !$IsChooseRandomly and $InsertSharedAtomCausion) { print "

***Warning***: One line should be removed from $filename.

\n"; print OUT "*** Shared atoms: Remove this line for calculation: OCC="; for(my $i = 0 ; $i < @ExpandedAtomSiteList ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $occupancy = $atom->Occupancy(); next if($occupancy >= 0.9999); printf OUT "%lg ", $occupancy; } print OUT "\n"; } for(my $i = 0 ; $i < $nExpandedAtomSite ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $atomname = $atom->AtomNameOnly(); my $charge = $atom->Charge(); my $atomlabel = $atom->Label(); if($UseSameBasisForSameAtom) { $atomlabel = sprintf("%-2s%d", $atomname, 1); } else { $atomlabel = $atomname; } my ($x,$y,$z) = $atom->Position(1); my $occupancy = $atom->Occupancy(); my $mult = $atom->Multiplicity(); $mult = 1 if($IsExpandCoordinate or $IsChooseRandomly); next if($occupancy >= 0.9999); $count++; my $numAtom = $count; $numAtom = -$count if($LatticeSystem ne 'cubic'); printf OUT "ATOM%4d: X=%10.8f Y=%10.8f Z=%10.8f\n", $numAtom, $x, $y, $z; my $iSplit = $Crystal->{"ISPLIT[$i]"}; $iSplit = 8 unless(defined $iSplit); printf OUT " MULT=%2d ISPLIT=%2d\n", $mult, $iSplit; $nAtomSite = 1 if($mult == 1); my $c = 0; for(my $j = 1 ; $j < $nAtomSite ; $j++) { my $atom2 = $AtomSiteList[$j]; my $id2 = $atom2->IdAsymmetricAtomSite(); next if($id2 != $i); if($c == 0) { $c++; next; } ($x,$y,$z) = $atom2->Position(1); printf OUT "ATOM%4d: X=%10.8f Y=%10.8f Z=%10.8f\n", $numAtom, $x, $y, $z; } $Crystal->{"NPT[$i]"} = 781 unless($Crystal->{"NPT[$i]"}); $Crystal->{"R0[$i]"} = 0.0 unless($Crystal->{"R0[$i]"}); $Crystal->{"RMT[$i]"} = 0.0 unless($Crystal->{"RMT[$i]"}); printf OUT "%-2s NPT= %4d R0=%10.8f RMT=%10.4f Z:%5.1f\n", $atomlabel, $Crystal->{"NPT[$i]"}, $Crystal->{"R0[$i]"}, $Crystal->{"RMT[$i]"}, # $atomname, $Crystal->{"NPT[$i]"}, $Crystal->{"R0[$i]"}, $Crystal->{"RMT[$i]"}, $Crystal->{"Z[$i]"}; print OUT "LOCAL ROT MATRIX: 1.0000000 0.0000000 0.0000000\n"; print OUT " 0.0000000 1.0000000 0.0000000\n"; print OUT " 0.0000000 0.0000000 1.0000000\n"; } #対称操作 if($IsExpandCoordinate or $IsChooseRandomly) { print OUT " 0 NUMBER OF SYMMETRY OPERATIONS\n"; } else { my @SymmetryOperation = $SPG->ExpandSymmetryOperation(); my $nSymmetryOperation = @SymmetryOperation; printf OUT " %3d NUMBER OF SYMMETRY OPERATIONS\n", $nSymmetryOperation; for(my $i = 0 ; $i < $nSymmetryOperation ; $i++) { my $SymOp = $SymmetryOperation[$i]; Utils::DelSpace($SymOp); #print "Save $i: $SymOp\n"; my @SymOpXYZ = split(/,\s*/, $SymOp); my @XMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[0]); my @YMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[1]); my @ZMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[2]); printf OUT "%2.0f%2.0f%2.0f%10.7f \n", $XMatrix[0], $XMatrix[1], $XMatrix[2], $XMatrix[3]; printf OUT "%2.0f%2.0f%2.0f%10.7f \n", $YMatrix[0], $YMatrix[1], $YMatrix[2], $YMatrix[3]; printf OUT "%2.0f%2.0f%2.0f%10.7f \n", $ZMatrix[0], $ZMatrix[1], $ZMatrix[2], $ZMatrix[3]; printf OUT " %3d\n", $i+1; } } # &ListPartialOccupancyAtoms(); close(OUT); return 1; } sub SaveSymmetrizedStructFileFromCrystal { my ($this, $Crystal, $StructPath, $SymmetrizedStructPath, $SGROUPPath, $tol, $IsPrint) = @_; $SGROUPPath = 'sgroup' if(!defined $SGROUPPath); $tol = 1.0e-3 if(!defined $tol); $IsPrint = 1 if(!defined $IsPrint); if(!$this->SaveStructFile($Crystal, $StructPath)) { print("Error: Can not write to [$StructPath].\n") if($IsPrint); return 0; } return $this->SaveSymmetrizedStructFile($StructPath, $SymmetrizedStructPath, $SGROUPPath, $tol, $IsPrint); } sub SaveSymmetrizedStructFile { my ($this, $StructPath, $SymmetrizedStructPath, $SGROUPPath, $tol, $IsPrint) = @_; $SGROUPPath = 'sgroup' if(!defined $SGROUPPath); $tol = 1.0e-3 if(!defined $tol); $IsPrint = 1 if(!defined $IsPrint); my $cmd = "$SGROUPPath -wi $StructPath -wo $SymmetrizedStructPath -set-TOL=$tol"; if(Utils::Execute($cmd)) { print("Error: Execute [$cmd] failed.\n") if($IsPrint); return 0; } if(!-f $SymmetrizedStructPath) { print("Error: Can not create [$SymmetrizedStructPath].\n") if($IsPrint); return 0; } return 1; } sub SaveXYZFile { my ($this, $Crystal, $filename, $IsExpandCoordinate, $IsChooseRandomly) = @_; #ファイル作製開始 unless(open(OUT,">$filename")) { print "Can not write to $filename.\n\n"; return; } my $SampleName = $this->SampleName(); print OUT "$SampleName\n"; my @ExpandedAtomSiteList = $Crystal->GetCExpandedAtomSiteListByOutputMode(); my $nExpandedAtomSite = @ExpandedAtomSiteList; #Occupancyが1のサイト for(my $i = 0 ; $i < $nExpandedAtomSite ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $atomname = $atom->AtomNameOnly(); my $charge = $atom->Charge(); my ($x,$y,$z) = $atom->Position(1); my $occupancy = $atom->Occupancy(); my $mult = $atom->Multiplicity(); $mult = 1 if($IsExpandCoordinate or $IsChooseRandomly); next if($occupancy < 0.9999); printf OUT "%-2s %14.9f %14.9f %14.9f \n", $atomname, $x, $y, $z; } #Occupancyが1未満のサイト for(my $i = 0 ; $i < $nExpandedAtomSite ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $atomname = $atom->AtomNameOnly(); my $charge = $atom->Charge(); my ($x,$y,$z) = $atom->Position(1); my $occupancy = $atom->Occupancy(); my $mult = $atom->Multiplicity(); $mult = 1 if($IsExpandCoordinate or $IsChooseRandomly); next if($occupancy >= 0.9999); printf OUT "%-2s %14.9f %14.9f %14.9f \n", $atomname, $x, $y, $z; } close(OUT); return 1; } sub BuildScript { my ($this, $Task, $Parallel, $UseComplex, $SP, $SO, $Orb) = @_; # $UseComplex = 1 if($SP or $SO); my $P = ""; $P = " -p" if($Parallel); my $OptComplex = ""; $OptComplex = " -c" if($UseComplex); my $OptSO = ""; $OptSO = " -so" if($SO); my $OptOrb = ""; $OptOrb = " -orb" if($Orb); my @lines; if($Task =~ /SCF/i) { push(@lines, "x lapw0$P"); if($Orb) { if($SP) { # push(@lines, "x orb$OptComplex -up$P"); # push(@lines, "x orb$OptComplex -dn$P"); push(@lines, "x orb -up$P"); push(@lines, "x orb -dn$P"); } else { # push(@lines, "x orb$OptComplex$P"); push(@lines, "x orb$P"); } } if($SP) { # push(@lines, "x lapw1$OptComplex -up$P"); # push(@lines, "x lapw1$OptComplex -dn$P"); push(@lines, "x lapw1 -up$P"); push(@lines, "x lapw1 -dn$P"); } else { # push(@lines, "x lapw1$OptComplex$P"); push(@lines, "x lapw1$P"); } if($SO) { # push(@lines, "x lapwso$OptComplex -up$OptOrb$P"); push(@lines, "x lapwso$OptOrb$P"); } if($SP) { push(@lines, "x lapw2$OptComplex -up$OptSO$P"); push(@lines, "x lapw2$OptComplex -dn$OptSO$P"); # push(@lines, "x lcore$OptComplex -up$P"); # push(@lines, "x lcore$OptComplex -dn$P"); push(@lines, "x lcore -up$P"); push(@lines, "x lcore -dn$P"); } else { push(@lines, "x lapw2$OptComplex$OptSO$P"); # push(@lines, "x lcore$OptComplex$P"); push(@lines, "x lcore$P"); } if($Orb) { if($SP) { push(@lines, "x lapwdm -up$OptComplex$OptSO$P"); push(@lines, "x lapwdm -dn$OptComplex$OptSO$P"); } else { push(@lines, "x lapwdm -up$OptComplex$OptSO$P"); } } push(@lines, "x mixer"); } elsif($Task =~ /Band/i) { if($Orb) { if($SP) { # push(@lines, "x orb -band$OptComplex -up$P"); # push(@lines, "x orb -band$OptComplex -dn$P"); push(@lines, "x orb -band -up$P"); push(@lines, "x orb -band -dn$P"); } else { # push(@lines, "x orb$OptComplex$P"); push(@lines, "x orb$P"); } } if($SP) { # push(@lines, "x lapw1 -band$OptComplex -up$P"); # push(@lines, "x lapw1 -band$OptComplex -dn$P"); push(@lines, "x lapw1 -band -up$P"); push(@lines, "x lapw1 -band -dn$P"); } else { # push(@lines, "x lapw1 -band$OptComplex$P"); push(@lines, "x lapw1 -band$P"); } if($SO) { # push(@lines, "x lapwso$OptComplex -up$OptOrb$P"); # push(@lines, "x spaghetti$OptComplex -so$OptOrb$P"); push(@lines, "x lapwso$OptOrb$P"); if($SP) { push(@lines, "x spaghetti -up -so$OptOrb$P"); } else { push(@lines, "x spaghetti -so$OptOrb$P"); } } else { if($SP) { push(@lines, "x spaghetti -up$OptOrb$P"); push(@lines, "x spaghetti -dn$OptOrb$P"); } else { push(@lines, "x spaghetti$OptOrb$P"); } } } elsif($Task =~ /DOS/i) { if($SP) { push(@lines, "x lapw2 -qtl$OptComplex -up$OptSO$P"); push(@lines, "x lapw2 -qtl$OptComplex -dn$OptSO$P"); } else { push(@lines, "x lapw2 -qtl$OptComplex$OptSO$P"); } if($SO) { if($SP) { push(@lines, "x tetra -up -so$OptComplex$OptSO$P"); push(@lines, "x tetra -dn -so$OptComplex$OptSO$P"); } else { push(@lines, "x tetra -so$OptComplex$OptSO$P"); } } else { if($SP) { push(@lines, "x tetra -up$OptComplex$OptSO$P"); push(@lines, "x tetra -dn$OptComplex$OptSO$P"); } else { push(@lines, "x tetra$OptComplex$OptSO$P"); } } } return @lines; } 1;