#=============================================== # TkAtom #=============================================== package TkAtom; use clib::TkFittingCommon; @ISA = qw(TkFittingCommon); use strict; use Utils; use IniFile; use CSV; use MultiColumnData; use Tk; use MyTk::GraphFrameArray; use Sci qw($pi $kB $R $NA $c $e $e0 $u0 $me $mp $mn $h $hbar); use Crystal::AtomType; my @Orbitals = qw(1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 6f); #============================================================ # 変数等取得関数 #============================================================ #============================================================ # コンストラクタ、デストラクタ #============================================================ #呼び出されることはない sub new { my ($module, $app) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; $this->SUPER::DESTROY(@_); } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ sub InsertToolBar { my ($this, $frame) = @_; } sub CreateLeftFrame { my ($this, $ConfigSide, @args) = @_; # return $this->SUPER::CreateLeftFrame(); return undef; } sub CreateSelectFilePane { my ($this) = @_; # return $this->SUPER::CreateSelectFilePane(); return undef; } sub CreateFileContentPane { return undef; } sub CreateWidgets { my ($this, $DoSuperOnly) = @_; $DoSuperOnly = 0 if(!defined $DoSuperOnly); my $App = $this->App(); my $args = $App->Args(); my $mw = $this->mw(); my $Program = "Atom2007"; my $ini = $this->{ini} = new IniFile; $this->{DataFile} = new MultiColumnData; $this->{IonName} = 'H'; $this->{CoordinationNumber} = 6; $this->{AtomicNumber} = 0; $this->{AtomJName} = ''; $this->{AtomName} = ''; $this->{AtomMass} = 0; $this->{IonCharge} = 0; $this->{AtomicRadius} = 0; $this->{IonRadius1} = 0; $this->{IonRadius2} = 0; $this->{IonizationPotential} = 0; $this->{ElectronAffinity} = 0; $this->SUPER::CreateWidgets(); return if($DoSuperOnly); $mw->SetTitle("$Program / TkPlot"); $this->App()->SetProgram("$Program / TkPlot"); #=================================================== # ペインを作製 #=================================================== my $EntryWidth = 12; my $Frame = $mw->MyFrame()->pack(-anchor => 'nw'); $this->{IonNameEntry} = $this->MakeLabelEntry($Frame, "Ion", "Ion:", \$this->{IonName}, "%s", $EntryWidth, "", 0, 0, "normal"); $this->{AtomicNumberEntry} = $this->MakeLabelEntry($Frame, "AtomicNumber", "An:", \$this->{AtomicNumber}, "%d", $EntryWidth, "", 0, 1, "normal"); $this->{CoordinationNumberEntry} = $this->MakeLabelEntry($Frame, "CoordinationNumber", "Cn:", \$this->{CoordinationNumber}, "%d", $EntryWidth, "", 0, 2, "normal"); # $this->{AtomJNameEntry} = $this->MakeLabelEntry($Frame, "AtomJName", "JName:", \$this->{AtomJName}, "%s", $EntryWidth, "", 1, 0, "normal"); # $this->{AtomJNameEntry}->configure(-font => ["MS UI Cothic", 12, "normal"]); # $this->{AtomJNameEntry}->configure(-font => ["Terminal", 12, "normal"]); $this->{AtomNameEntry} = $this->MakeLabelEntry($Frame, "AtomName", "Atom:", \$this->{AtomName}, "%s", $EntryWidth, "", 1, 0, "normal"); $this->{AtomMassEntry} = $this->MakeLabelEntry($Frame, "AtomMass", "M:", \$this->{AtomMass}, "%f", $EntryWidth, "", 1, 1, "normal"); $this->{IonChargeEntry} = $this->MakeLabelEntry($Frame, "IonCharge", "Z:", \$this->{IonCharge}, "%s", $EntryWidth, "", 1, 2, "normal"); $this->{AtomicRadiusEntry} = $this->MakeLabelEntry($Frame, "AtomicRadius", "R(atom):", \$this->{AtomicRadius}, "%f", $EntryWidth, "nm", 2, 0, "normal"); $this->{IonRadius1Entry} = $this->MakeLabelEntry($Frame, "IonRadius", "R(ion):", \$this->{IonRadius1}, "%f", $EntryWidth, "nm", 2, 1, "normal"); $this->{IonRadius2Entry} = $this->MakeLabelEntry($Frame, "IonRadius", "R(ion):", \$this->{IonRadius2}, "%s", $EntryWidth, "pm", 2, 2, "normal"); $this->{IonizationPotentialEntry} = $this->MakeLabelEntry($Frame, "IonizationPotential", "I:", \$this->{IonizationPotential}, "%f", $EntryWidth, "eV", 3, 0, "normal"); $this->{ElectronAffinityEntry} = $this->MakeLabelEntry($Frame, "ElectronAffinity", "A:", \$this->{ElectronAffinity}, "%f", $EntryWidth, "eV", 3, 1, "normal"); $Frame = $mw->MyFrame()->pack(-anchor => 'nw'); my $nc = 10; for(my $i = 0 ; $i < @Orbitals ; $i++) { my $line = int($i / $nc); my $ci = $i % $nc; my $Frame = $this->MakeLabelEntry($Frame, "Orbital$Orbitals[$i]", "$Orbitals[$i]:", $ini->pVariable("Orbital$Orbitals[$i]", 0), "%s", 3, "", $line, $ci); $this->{"Orbital$Orbitals[$i]Entry"} = $Frame->{Entry}; } $this->UpdateParameters(); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{CalSTOButton} = $Frame->MyButton( -text => '&STO', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'CalSTO'); }, )->pack(-side => 'left'); #ツールバーのOpenボタンをファイル読み込みにバインドする $mw->{OpenButton}->configure( -command => sub { $this->ChooseFile($this->{SampleCSVEntry}); }, ) if($mw->{OpenButton}); } sub Initialize { my ($this, $InitializeParameterFile, $InitializeData) = @_; $this->{DataFile} = new MultiColumnData; if($InitializeParameterFile) { $this->{ini}->{SampleCSVFile} = ''; } if($InitializeData) { $this->{pCalX} = undef; $this->{pCalY1} = undef; $this->{pCalY2} = undef; } } sub UpdateParameters { my ($this) = @_; if($this->{IonNameEntry}) { my $IonName = $this->{IonName}; if(!$IonName) { $this->{IonName} = AtomType::GetAtomName($this->{AtomicNumber}); } my $CN = $this->{CoordinationNumberEntry}; my ($AtomicNumber, $AtomName, $IonCharge) = AtomType::GetAtomInformation($IonName); $IonCharge = AtomType::ChargeToVal($IonCharge); my $IonRadius = AtomType::GetCationRadius($AtomName, $IonCharge, 0); my ($filepath, $AtomJName, $AtomEName, $AtomicMass, $FoundYear, $AtomicRadius, $MeltingPoint, $BoilingPoint, $Density, $HeatCapacity, $IonizationPotential, $ElectronAffinity) = AtomType::GetIonInfFromPeriodicTable2($AtomicNumber); my @radius = AtomType::GetIonRadius2($AtomName, $IonCharge, $this->{CoordinationNumber}); my ($AtmNum, $JName, $EName, $NameOrigin) = AtomType::GetIonInfFromPeriodicTable1($AtomName); my ($pShellName, $pn) = AtomType::GetElectronicConfiguraton($AtomicNumber - $IonCharge); if(defined $pn) { my $nArray = @$pn; for(my $i = 0 ; $i < $nArray ; $i++) { my $name = $pShellName->[$i]; my $n = $pn->[$i]; #print "name=$name, ", $this->{"Orbital${name}Entry"}, "\n"; $n = 0 if(!defined $n or $n eq ''); $this->{"Orbital${name}Entry"}->SetText($n) if($this->{"Orbital${name}Entry"}); } } $this->{AtomicNumber} = $AtomicNumber; $this->{AtomJName} = $AtomJName; $this->{AtomName} = $AtomName; $this->{IonCharge} = $IonCharge; $this->{AtomMass} = $AtomicMass; $this->{IonizationPotential} = $IonizationPotential; $this->{IonizationPotential} = 0.0 if(!defined $this->{IonizationPotential} or $this->{IonizationPotential} eq ''); $this->{ElectronAffinity} = $ElectronAffinity; $this->{ElectronAffinity} = 0.0 if(!defined $this->{ElectronAffinity} or $this->{ElectronAffinity} eq ''); $this->{IonRadius1} = $IonRadius; $this->{IonRadius1} = 0.0 if(!defined $this->{IonRadius1} or $this->{IonRadius1} eq ''); my $s = ''; for(my $i = 0 ; $i < @radius ; $i++) { $s .= "$radius[$i], "; } $this->{IonRadius2} = $s; $this->{AtomicRadius} = $AtomicRadius; $this->{AtomicRadius} = 0.0 if(!defined $this->{AtomicRadius} or $this->{AtomicRadius} eq ''); } if($this->{pEntryArray}) { for(my $i = 0 ; $i < @{$this->{pEntryArray}} ; $i++) { $this->{pEntryArray}->[$i]->Update(); } } } sub EntryFocusedIn { my ($this, $obj, $event, $type) = @_; #print "obj=$obj this=$this event=$event type: $type\n"; $this->{PrevEntry} = $obj->GetText(); } sub EntryFocusedOut { my ($this, $obj, $event, $type) = @_; #print "obj=$obj this=$this event=$event type: $type\n"; my $newentry = $obj->GetText(); return if(defined $newentry and defined $this->{PrevEntry} and $newentry eq $this->{PrevEntry}); if($event eq 'FocusOut') { if($type eq 'AtomicNumber') { $this->{IonName} = AtomType::GetAtomName($this->{AtomicNumber}); } if($type eq 'AtomMass') { for(my $i = 1 ; $i < 120 ; $i++) { my ($filepath, $AtomJName, $AtomEName, $AtomicMass, $FoundYear, $AtomicRadius, $MeltingPoint, $BoilingPoint, $Density, $HeatCapacity, $IonizationPotential, $ElectronAffinity) = AtomType::GetIonInfFromPeriodicTable2($i); #print "i=$i M=$AtomicMass ($this->{AtomMass})\n"; last if(!$AtomicMass); if($AtomicMass > $this->{AtomMass} - 0.5) { $this->{IonName} = AtomType::GetAtomName($i); last; } } } } $this->UpdateParameters(); } sub SelChangeListBox { my ($this, $type, $lb) = @_; #print "this:$this lb=$lb\n"; my $s = $lb->GetText(); if($type eq 'X' or $type eq 'Y1') { } $this->AssignGraphData(); $this->Draw(); } sub ButtonPressed { my ($this, $event, $type) = @_; my $App = $this->App(); #print "this=$this\n"; if($type eq 'CalSTO') { $this->CalSTO(); } elsif($type eq 'SaveParam') { $this->SaveParameterFile($this->{ini}->{ParameterFile}); return; } elsif($type eq 'EditParam') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{ParameterFile}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditSampleCSV') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{SampleCSVFile}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditSubstrateCSV') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{SubstrateCSVFile}; my $command = "$Editor $File"; system($command); return; } } #=================================================== # データ処理 #=================================================== sub CalSTO { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); my $App = $this->App(); my $IonName = $this->{IonName}; my ($AtomicNumber, $AtomName, $Charge) = AtomType::GetAtomInformation($IonName); $Charge = AtomType::ChargeToVal($Charge); $App->print("\nCalculate STO parameters\n"); $App->print(" Ion Name : $IonName\n"); $App->print(" Atom Name : $AtomName\n"); $App->print(" Charge : $Charge\n"); $App->print(" Atomic Number: $AtomicNumber\n"); my %n; for(my $i = 0 ; $i < @Orbitals ; $i++) { $n{$Orbitals[$i]} = $this->{"Orbital$Orbitals[$i]Entry"}->GetText(); } my @ne = ($n{'1s'}, $n{'2s'}+$n{'2p'}, $n{'3s'}+$n{'3p'}+$n{'3d'}, $n{'4s'}+$n{'4p'}+$n{'4d'}+$n{'4f'}, $n{'5s'}+$n{'5p'}+$n{'5d'}+$n{'5f'}); my $MaxN = 0.0; for(my $i = 0 ; $i < @ne ; $i++) { if($ne[$i] > 0.0) { $MaxN = $i+1; } } my $MaxNm1 = $MaxN - 1; my @nStar = (undef, 1, 2, 3, 3.7, 4.0, 4.2); my $nStar = $nStar[$MaxN]; $App->print(" Max n: $MaxN\n"); $App->print(" n* : $nStar\n"); my $Is_d = 0; if($n{"${MaxNm1}d"} > 0.0 and $n{"${MaxNm1}s"} == 0.0) { $Is_d = 1; } $App->print(" for d electron?: $Is_d\n"); #(i) z*=z-sとする。ここでzは核電荷、sは遮蔽定数 #(ii) 電子を(1s)(2s,2p)(3s,3p)(3d)・・・・・という群にわける。 my @nGroup = ($n{'1s'}, $n{'2s'}+$n{'2p'}, $n{'3s'}+$n{'3p'}, $n{'3d'}, $n{'4s'}+$n{'4p'}, $n{'4d'}+$n{'4f'}, $n{'5s'}+$n{'5p'}, $n{'5d'}+$n{'5f'}); my @GroupId = qw(1s 2sp 3sp 3d 4sp 4df 5sp 5df); my $nMax = 0; for(my $i = 0 ; $i < @nGroup ; $i++) { if($nGroup[$i] > 0.0) { $nMax = $i; } } $App->print(" n(max) for groups: $nMax [$GroupId[$nMax]]\n"); my $s = 0.0; #(iii) 考えている電子より主量子数nの大きい電子からのsへの寄与はゼロとする。 #(iv) 考えている電子の属する群の他の電子からはそれぞれ0.35とする。ただし、1s群の場合は0.30とする。 my $k = 0.35; if($nMax == 0) { # 1s群 $k = 0.30; } my $ne0 = 0; $ne0 = $nGroup[$nMax] - 1.0 if($nGroup[$nMax] >= 1.0); $s += $ne0 * $k; $App->print(" Add contribution of the nMax shell : $s [ne=$ne0, k=$k]\n"); #(v) 考えている電子がsまたはp電子なら、それよりnの一つ小さい電子からは0.85ずつ #ただし、d電子ならば、それより内側の電子からの寄与はすべて1.00とする。 if($nMax >= 1 and $nGroup[$nMax-1] > 1.0) { if($nMax == 3 or $nMax == 5 or $nMax == 7) { # d群 $k = 1.0; } else { $k = 0.85; } if($MaxNm1 == 1) { $ne0 = $n{'1s'}; } elsif($MaxNm1 == 2) { $ne0 = $n{'2s'} + $n{'2p'}; } elsif($MaxNm1 == 3) { $ne0 = $n{'3s'} + $n{'3p'} + $n{'3d'}; } elsif($MaxNm1 == 4) { $ne0 = $n{'4s'} + $n{'4p'} + $n{'4d'}; } elsif($MaxNm1 == 5) { $ne0 = $n{'5s'} + $n{'6p'} + $n{'6d'}; } elsif($MaxNm1 == 6) { $ne0 = $n{'6s'} + $n{'6p'} + $n{'6d'}; } $s += $ne0 * $k; } $App->print(" Add contribution of the inner shell: $s [ne=$ne0, k=$k]\n"); #もっと内側の電子からは1.00ずつ寄与する。ただし、d電子ならば、それより内側の電子からの寄与はすべて1.00とする。 $k = 1.0; $ne0 = 0.0; foreach my $orb (@Orbitals) { my ($nn) = ($orb =~ /(\d+)/); next if($nn >= $MaxNm1); $ne0 += $n{$orb}; } $s += $ne0 * $k; $App->print(" Add contribution of the cores : $s [ne=$ne0, k=$k]\n"); my $zStar = $AtomicNumber - $s; $App->print("Z : $AtomicNumber\n"); $App->print("Z* : $zStar\n"); my $Rmax = $nStar*$nStar / $zStar * Sci::a0() * 1.0e10; $App->print("Rmax : $Rmax (A)\n"); # $this->{CalX} = \@x; # $this->{CalY1} = \@y; # $this->AssignGraphData(0); # $this->Draw(); } sub CreateGraphFrame { my ($this, $canvas, $TargetData) = @_; $canvas = $this->Canvas(); my $App = $this->App(); my $font = $App->{'GraphFrameFont'}; my @font = split(/,/, $font) if($font); my $w = $canvas->width(); my $h = $canvas->height(); my $GraphFrameArray = $this->{'GraphFrameArray'} = new GraphFrameArray($this->mw()); $GraphFrameArray->SetCanvasSize($w, $h); $GraphFrameArray->AddGraphFrame(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); my $FramePosStr0 = $App->{"GraphFrame0Position"}; $GraphFrame0->SetPositionByStr($FramePosStr0); my $XScale0 = $GraphFrame0->GetXScale(0); my $YScale0 = $GraphFrame0->GetYScale(0); $XScale0->SetScaleStringVisible(1); $XScale0->SetCaptionVisible(1); $GraphFrame0->SetViewRange(0, 0, 1, 1); } sub AssignGraphData { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); my $GraphFrameArray = $this->GetGraphFrameArray(); my @GraphFrame; $GraphFrame[0] = $GraphFrameArray->GetGraphFrame(0); $GraphFrame[0]->ClearAllData(); my $XLabel = $this->{"ChooseXListBox"}->GetText(); my $Y1Label = $this->{"ChooseY1ListBox"}->GetText(); $GraphFrame[0]->SetXCaption($XLabel); $GraphFrame[0]->SetYCaption("$Y1Label"); my $pX = $this->{DataFile}->GetXData($XLabel) if($XLabel); my $pY1 = $this->{DataFile}->GetYData($Y1Label) if($Y1Label); my $nData = $this->{DataFile}->nData(); if($pX) { $GraphFrame[0]->AddGraphData($pX, $pY1, 2, "black", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "${Y1Label}") if($pY1); } my $iTarget = $this->{iTargetGraphFrame}; my $pCalX = $this->{CalX}; my $pCalY1 = $this->{CalY1}; if($pCalX) { $GraphFrame[$iTarget]->AddGraphData($pCalX, $pCalY1, 0, "black", "circle", 3, "", 1, "black", "XAutoSkip", "Energy", "${Y1Label}(cal)") if($pCalY1); if($iTarget >= 1) { $GraphFrame[$iTarget]->SetXCaption($XLabel); $GraphFrame[$iTarget]->SetYCaption("${Y1Label}(cal)"); } } $GraphFrame[0]->SetYScalePlotType('x'); if($ResetViewRange) { $GraphFrame[0]->CalMinMax(); $GraphFrame[0]->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } 1;