package Crystal; use Crystal::CrystalObject; @ISA = qw(CrystalObject); #公開したいサブルーチン @EXPORT = qw(); use strict; BEGIN { } sub new { my ($module) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; } sub ExpandToSuperLattice { my ($this,$nx,$ny,$nz,$crystal) = @_; my $LF="
\n"; print "

Expand to SuperLattice in Crystal.pm.

\n"; $nx = int($nx + 0.01); $ny = int($ny + 0.01); $nz = int($nz + 0.01); $nx = 1 if($nx < 1); $ny = 1 if($ny < 1); $nz = 1 if($nz < 1); my $nMult = $nx*$ny*$nz; $this->SetCrystalName($crystal->CrystalName()); $this->SetCAtomTypeList($crystal->GetCAtomTypeList()); $this->SetnAtomType($crystal->nAtomType()); $this->SetCAsymmetricAtomSiteList($crystal->GetCAsymmetricAtomSiteList()); $this->SetnAsymmetricAtomSite($crystal->nAsymmetricAtomSite()); $this->SetDensity($crystal->Density()); my ($a,$b,$c,$alpha,$beta,$gamma) = $crystal->LatticeParameters(); $this->SetLatticeParameters($a*$nx, $b*$ny, $c*$nz, $alpha, $beta, $gamma); my @ExpandedAtomSiteList = $crystal->GetCExpandedAtomSiteList(); my $nTotalExpandedAtomSite = $crystal->nTotalExpandedAtomSite(); #超格子へ展開する my @AtomSiteList; my $count = 0; for(my $i = 0 ; $i < $nTotalExpandedAtomSite ; $i++) { my $label = $ExpandedAtomSiteList[$i]->Label(); my $type = $ExpandedAtomSiteList[$i]->AtomName(); my ($x,$y,$z) = $ExpandedAtomSiteList[$i]->Position(1); my $occupancy = $ExpandedAtomSiteList[$i]->Occupancy(); my $id = $ExpandedAtomSiteList[$i]->IdAsymmetricAtomSite(); for(my $ix = 0 ; $ix < $nx ; $ix++) { for(my $iy = 0 ; $iy < $ny ; $iy++) { for(my $iz = 0 ; $iz < $nz ; $iz++) { my $x0 = ($x + $ix) / $nx; my $y0 = ($y + $iy) / $ny; my $z0 = ($z + $iz) / $nz; $AtomSiteList[$count] = new AtomSite(); $AtomSiteList[$count]->SetLabel($label); $AtomSiteList[$count]->SetAtomName($type); $AtomSiteList[$count]->SetPosition($x0, $y0, $z0); $AtomSiteList[$count]->SetOccupancy($occupancy); $AtomSiteList[$count]->SetIdAsymmetricAtomSite($id); $count++; } } } } #print "count: $count\n"; $this->{"nTotalExpandedAtomSite"} = $count; $this->{"RefExpandedAtomSiteList"} = \@AtomSiteList; #多重度を超格子の値に更新 my @nMultiplicityExpandedAtomSiteList = $crystal->GetCnMultiplicityExpandedAtomSiteList(); for(my $i = 0 ; $i < @nMultiplicityExpandedAtomSiteList ; $i++) { $nMultiplicityExpandedAtomSiteList[$i] *= $nMult; } $this->{"RefnExpandedAtomSite"} = \@nMultiplicityExpandedAtomSiteList; #多重度を、全原子に設定 for(my $i = 0 ; $i < @AtomSiteList ; $i++) { my $atom = $AtomSiteList[$i]; my $ia = $atom->Id() - 1; $atom->SetMultiplicity($nMultiplicityExpandedAtomSiteList[$ia]); $this->SetIsSelected($i, 0); } #IDをもとに部分占有原子を整理 #Occupancyに合わせて表示する原子数を選択する => IsSelectedに選択された原子を設定する。 #同じ位置にあるサイトの数 my @nIdenticalSite; #そのサイトを実際に占める原子の数 my %nOccupiedAtom; my %iIdenticalPartialAtomWithSameId; #ID=$idのサイトで、$j番目のサイト占める原子の名前 $AtomTypeInPartialAtom{"[$id][$j]"} my %AtomTypeInPartialAtom; #ID=$idのサイトで、$j番目のサイトを占める原子のID $AtomIdInPartialAtom{"[$id][$j]"} my %AtomIdInPartialAtom; #ID=$idのサイトで、$j番目のサイトを占める原子のIndex $AtomIndexInPartialAtom{"[$id][$j]"} my %AtomIndexInPartialAtom; #多重度 my @nSameIdSite; my %SameIdSiteIndex; #同じIDをもつサイトのindexを$SameIdSiteIndex{"[$idm1][$sid]"} に設定する for(my $i = 0 ; $i < @ExpandedAtomSiteList ; $i++){ my $atom = $ExpandedAtomSiteList[$i]; my $type = $atom->AtomName(); my ($x,$y,$z) = $atom->Position(1); my $occ = $atom->Occupancy(); my $mult = $atom->Multiplicity(); my $id = $atom->Id(); my $idm1 = $id-1; $nSameIdSite[$idm1]++; my $sid = $nSameIdSite[$idm1]-1; $SameIdSiteIndex{"[$idm1][$sid]"} = $i; #printf "#++%4d[%4s]: (%7.4f, %7.4f, %7.4f) [%6.4f] (mult=%3d: id=%2d)$LF", # $i+1, $type, $x, $y, $z, $occ, $mult, $id; } print "#Check number of atoms occupying the sites.$LF"; my @IsPrintedById; my @IsPrinted; for(my $i = 0 ; $i < @ExpandedAtomSiteList ; $i++) { my $PrintCount = 0; my $atom = $ExpandedAtomSiteList[$i]; my $type = $atom->AtomName(); my ($x,$y,$z) = $atom->Position(1); my $occ = $atom->Occupancy(); my $id = $atom->Id(); my $mult = $atom->Multiplicity(); my $idm1 = $id-1; #該当する等価な全てサイトのうち、何個の原子が存在するか $nOccupiedAtom{"[$i][$id]"} = int($mult * $occ + 0.01); my $nc = $nOccupiedAtom{"[$i][$id]"}; next if($IsPrintedById[$id]); next if($occ >= 0.999999); #print "+++A(i:$i): $type: occ=$occ: nMult=$mult: nAtom=$nc (id=$id)$LF"; #同じ位置にある原子のIDのリストを作る $iIdenticalPartialAtomWithSameId{"[$i][0]"} = $i; $IsPrinted[$i] = 1; $IsPrintedById[$id] = 1; #同じ位置にあるサイトの数を$cにいれる my $c = 1; for(my $j = $i+1 ; $j < @ExpandedAtomSiteList ; $j++) { next if($IsPrinted[$j]); my $atom2 = $ExpandedAtomSiteList[$j]; my $type2 = $atom2->AtomName();; my ($x2,$y2,$z2) = $atom2->Position(1); my $occ2 = $atom2->Occupancy(); my $id2 = $atom2->Id(); my $mult2 = $atom2->Multiplicity(); next if($occ2 >= 0.999999); my $dis = $this->GetNearestInterAtomicDistance( $x, $y, $z, $x2, $y2, $z2); next if($dis > 0.001); $iIdenticalPartialAtomWithSameId{"[$i][$c]"} = $j; #$i番目のサイトと同じ位置にあるID=$id2のサイト、実際にいくつの原子があるか $nOccupiedAtom{"[$i][$id2]"} = int($mult2 * $occ2 + 0.01); $IsPrinted[$j] = 1; $IsPrintedById[$id2] = 1; $c++; my $nc2 = $nOccupiedAtom{"[$i][$id2]"}; #print "+++***(j:$j)$type2: occ=$occ2: nMult=$mult2: nAtom=$nc2 (id=$id2)$LF"; } #$i番と同じ位置にあるサイトサイトの数を$cにいれる #$iは、0から始まる(ID-1に等しい) $nIdenticalSite[$i] = $c; } #結果の表示 for(my $id0 = 0 ; $id0 < @ExpandedAtomSiteList ; $id0++) { #$nIdenticalSiteは部分共有原子の$iのみで定義される。 #同じ位置にある原子の値は0なので、この条件文でスキップできる next if(!defined $nIdenticalSite[$id0]or $nIdenticalSite[$id0] <= 0); my $i = $iIdenticalPartialAtomWithSameId{"[$id0][0]"}; my $atom = $ExpandedAtomSiteList[$i]; my ($x0,$y0,$z0) = $atom->Position(1); my $Id = $atom->Id($i); my $occupancy = $atom->Occupancy($i); my $mult = $atom->Multiplicity($i); my $Idm1 = $Id-1; #$nIdenticalSiteは0から始まる配列 print "ID=$Id: nIdenticalSite = ", $nIdenticalSite[$id0], " at ($x0, $y0, $z0)$LF"; print "+++ i="; for(my $sn = 0 ; $sn < $nIdenticalSite[$id0] ; $sn++) { my $j = $iIdenticalPartialAtomWithSameId{"[$id0][$sn]"}; print "$j "; } print "$LF"; for(my $sn = 0 ; $sn < $nIdenticalSite[$id0] ; $sn++) { my $j = $iIdenticalPartialAtomWithSameId{"[$i][$sn]"}; next if(!defined($j) or $j eq ''); my $atom = $ExpandedAtomSiteList[$j]; my $Id2 = $atom->Id(); my $Id2m1 = $Id2-1; my $type2 = $atom->AtomName(); my ($x2,$y2,$z2) = $atom->Position(1); my $occ2 = $atom->Occupancy(); my $mult2 = $atom->Multiplicity(); my $nAtom2 = $nOccupiedAtom{"[$i][$Id2]"}; print "+++ i=$j(Id=$Id2): $type2 ($x2, $y2, $z2)" . " [occ=$occ2] [nMult=$mult2] [N=$nAtom2]$LF"; print "+++*** SameIdSiteIndex"; for(my $j = 0 ; $j < $mult ; $j++) { # my $idx = $this->SameIdSiteIndex($Id2m1, $j); my $idx = $SameIdSiteIndex{"[$Id2m1][$j]"}; printf "%3d ", $idx; } print "$LF"; } #$SameIdSiteIndex{"[$Id2][$j]"}から、実際に割り当てる原子を決める my $nSiteWithSameId0 = $atom->Multiplicity(); my $ResidualNum = $nSiteWithSameId0; my $nIdenticalSite0 = $nIdenticalSite[$i]; #print "nSiteWithSameId0: $nSiteWithSameId0, nIdenticalSite0: $nIdenticalSite0$LF"; for(my $sn = 0 ; $sn < $nIdenticalSite0 ; $sn++) { my $jatom = $iIdenticalPartialAtomWithSameId{"[$i][$sn]"}; #print "jatom=$jatom$LF"; my $atom0 = $ExpandedAtomSiteList[$jatom]; my $Id0 = $atom0->Id(); my $type = $atom0->AtomName(); my $nAtom = $nOccupiedAtom{"[$i][$Id0]"}; #print "j=$jatom: Id=$Id0: $type: nOccupiedAtom=$nAtom$LF"; for(my $is = 0 ; $is < $nAtom ; $is++) { my $r = int(rand($ResidualNum)); for(my $j = 0 ; $j < $nSiteWithSameId0 ; $j++) { next if(defined($AtomTypeInPartialAtom{"[$Id][$j]"})); $r--; if($r < 0) { #ID=$idの原子と同一のサイトで、$j番目のサイトをしめる原子 $AtomTypeInPartialAtom{"[$id][$j]"} $AtomTypeInPartialAtom{"[$Id][$j]"} = $type; $AtomIdInPartialAtom{"[$Id][$j]"} = $Id0; my $Id0m1 = $Id0 - 1; my $Index = $SameIdSiteIndex{"[$Id0m1][$j]"}; #表示する原子を設定する $this->SetIsSelected($Index, 1); $AtomIndexInPartialAtom{"[$Id][$j]"} = $Index; #print "Id0=$Id0, sn=$j, Idx=$Index$LF"; $ResidualNum--; last; } } } } } if(0) { print "Summary:$LF"; # my @ExpandedAtomSiteList = $this->GetCExpandedAtomSiteList(); for(my $i = 0 ; $i < @ExpandedAtomSiteList ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $name = $atom->AtomName(); my $occupancy = $atom->Occupancy(); #表示する原子を設定する $this->SetIsSelected($i, 1) if($occupancy >= 1); next if(!$this->IsSelected($i)); my ($x,$y,$z) = $atom->Position(1); my $Id = $atom->Id(); print "+++$i: $name (id=$Id): ($x, $y, $z) [$occupancy]$LF"; } } print "

Expand to Superlattice in Crystal.pm: End

\n"; print "$LF"; return $count; } sub SetOutputMode { my ($this, $mode) = @_; return $this->{'OutputMode'} = $mode; } sub OutputMode { my ($this) = @_; return $this->{'OutputMode'}; } sub SPGNameByOutputMode { my ($this) = @_; if($this->{OutputMode} eq 'expanded' or $this->{OutputMode} eq 'choose' ) { return "P 1"; } return $this->SPGName(); } sub iSPGByOutputMode { my ($this) = @_; if($this->{'OutputMode'} eq 'expanded' or $this->{'OutputMode'} eq 'choose' ) { return 1; } return $this->iSPG(); } sub iSetByOutputMode { my ($this) = @_; if($this->{'OutputMode'} eq 'expanded' or $this->{'OutputMode'} eq 'choose' ) { return 1; } return $this->iSet(); } sub LatticeParametersByOutputMode { my ($this, $UseAtomicUnit) = @_; if($this->{'OutputMode'} eq 'expanded' or $this->{'OutputMode'} eq 'choose' ) { my $SuperLattice = $this->{'CSuperLattice'}; return $SuperLattice->LatticeParameters($UseAtomicUnit) if($SuperLattice); return $this->LatticeParameters($UseAtomicUnit); } return $this->LatticeParameters($UseAtomicUnit); } sub LatticeVectorsByOutputMode { my ($this, $UseAtomicUnit) = @_; my $k = ($UseAtomicUnit)? 1.0 / 0.529177 : 1.0; #my $SPG = $this->GetCSpaceGroup(); #my $SPGName = $SPG->SPGName(); #print "SPG in Crystal.pm:[$SPGName]\n"; #exit; if($this->{'OutputMode'} eq 'expanded' or $this->{'OutputMode'} eq 'choose' ) { my $SuperLattice = $this->{'CSuperLattice'}; return $SuperLattice->LatticeVectors($UseAtomicUnit) if($SuperLattice); return $this->LatticeVectors($UseAtomicUnit); } return $this->LatticeVectors($UseAtomicUnit); } sub GetCExpandedAtomSiteListByOutputMode { my ($this,$UseAtomicUnit) = @_; if(defined $this->{'OutputMode'} and $this->{'OutputMode'} eq 'expanded') { my $SuperLattice = $this->{'CSuperLattice'}; return $SuperLattice->GetCExpandedAtomSiteList() if($SuperLattice); return $this->GetCExpandedAtomSiteList(); } elsif(defined $this->{'OutputMode'} and $this->{'OutputMode'} eq 'choose' ) { my $SuperLattice = $this->{'CSuperLattice'}; if($SuperLattice) { my @slist = $SuperLattice->GetCExpandedAtomSiteList(); my @tlist; for(my $i = 0 ; $i < @slist ; $i++) { my $atom = $slist[$i]; next if($atom->Occupancy() < 1.0 and !$atom->IsSelected() ); push(@tlist, $atom); } return @tlist; } return $this->GetCExpandedAtomSiteList(); } return $this->GetCAsymmetricAtomSiteList(); } sub CreateSuperLattice { my ($this, $nx, $ny, $nz) = @_; my $SuperLattice = new Crystal(); $SuperLattice->ExpandToSuperLattice($nx,$ny,$nz,$this); $this->{'CSuperLattice'} = $SuperLattice; return 1; } sub GetCSuperLattice { my ($this) = @_; return $this->{'CSuperLattice'}; } 1;