#=============================================== # TkEllipsometry #=============================================== package TkEllipsometry; use TkFittingCommon; @ISA = qw(TkFittingCommon); #公開したいサブルーチン #@EXPORT = qw(DelSpace Reduce01 MakePath RegExpQuote); use strict; use Utils; use IniFile; use CSV; use MyTk::GraphFrameArray; use GraphData; use Sci::Science; use Sci::Material; use Sci::Ellipsometry; use Sci::MultiLayer; use Sci::OpticalMaterial; my $pi = Sci::pi(); my $kB = Sci::kB(); my $c = Sci::c(); my $e = Sci::e(); my $e0 = Sci::e0(); my $me = Sci::me(); my $mp = Sci::mp(); my $mn = Sci::mn(); my $h = Sci::h(); my $hbar = Sci::hbar(); my $torad = Sci::torad(); my $todeg = Sci::todeg(); #============================================================ # 変数等取得関数 #============================================================ #============================================================ # コンストラクタ、デストラクタ #============================================================ #呼び出されることはない sub new { my ($class, $app, @a) = @_; # my ($module, $app, $canvas) = @_; my $self = TkFittingCommon->new($app, @a); my $this = bless $self, $class; # my $this = {}; # bless $this; $this->SetApplication($app) if($app); # $this->SetCanvas($canvas) if($canvas); return $this; } sub DESTROY { my $this = shift; $this->SUPER::DESTROY(@_); } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ 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, $mode) = @_; $DoSuperOnly = 0 if(!defined $DoSuperOnly); my $App = $this->App(); my $args = $App->Args(); my $mw = $this->mw(); $this->{nLorentz} = 5 if(!defined $this->{nLorentz}); $this->{nDrude} = 1 if(!defined $this->{nDrude}); $this->{ini} = new IniFile(undef, 0, 0); $this->{dini} = new IniFile(undef, 0, 0); $this->InitializeParameters($this->{ini}, $this->{dini}); $this->{Ellipsometry} = new Ellipsometry; $this->SUPER::CreateWidgets(); return if($DoSuperOnly); $mw->SetTitle("EllipsometryFit2007 / TkPlot"); $this->App()->SetProgram("EllipsometryFit2007 / TkPlot"); #=================================================== # ペインを作製 #=================================================== my $EntryWidth = 12; my $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'Param', 'Param:', $this->{ini}->pVariable("ParameterFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseParameterFile"); $this->{SaveParamButton} = $Frame->MyButton( -text => '&Save', -takefocus => 1, -command => [ \&ButtonPressed, $this, 'RButtonDown', 'SaveParam' ], )->pack(-side => 'left'); $this->{EditParamButton} = $Frame->MyButton( -text => 'ed', -takefocus => 1, -command => [ \&ButtonPressed, $this, 'RButtonDown', 'EditParam' ], )->pack(-side => 'left'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'SampleCSV', 'Sample:', $this->{ini}->pVariable("SampleCSVFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseSampleFile"); $this->{EditDataButton} = $Frame->MyButton( -text => 'ed', -takefocus => 1, -command => [ \&ButtonPressed, $this, 'RButtonDown', 'EditSampleCSV' ], )->pack(-side => 'left'); if(0) { $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'SubstrateCSV', 'Substrate:', $this->{ini}->pVariable("SubstrateCSVFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseSubstrateFile"); $this->{EditDataButton} = $Frame->MyButton( -text => 'ed', -takefocus => 1, -command => [ \&ButtonPressed, $this, 'RButtonDown', 'EditSubstrateCSV' ], )->pack(-side => 'left'); } $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); my $lsb1 = $this->{ChooseXListBox} = $Frame->MyBrowseEntry( -label => "X:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb1->configure(-browsecmd => [\&SelChangeListBox, $this, "X", $this->{ChooseXListBox}]); my $lsb2 = $this->{ChooseY1ListBox} = $Frame->MyBrowseEntry( -label => "Y1:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb2->configure(-browsecmd => [\&SelChangeListBox, $this, "Y1", $this->{ChooseY1ListBox}]); my $lsb3 = $this->{ChooseY2ListBox} = $Frame->MyBrowseEntry( -label => "Y2:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 2, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb3->configure(-browsecmd => [\&SelChangeListBox, $this, "Y2", $this->{ChooseY2ListBox}]); $Frame = $mw->MyLabFrame( -label => 'Fitting1', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); my $lsb4 = $this->{ChooseLSQMethodListBox} = $Frame->MyBrowseEntry( -label => "LSQ Method:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => ['Amoeba::Simplex', 'PDL::Simplex', 'ModifiedNewton'], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb4->configure(-browsecmd => [\&SelChangeListBox, $this, "LSQMethod", $this->{ChooseLSQMethodListBox}]); my $lsb5 = $this->{ChooseFitToListBox} = $Frame->MyBrowseEntry( -label => "Fit to:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => ['Eps', 'PsiDelta', 'IsIcII', 'IsIcIII'], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $Frame = $mw->MyLabFrame( -label => 'Fitting2', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeLabelEntry($Frame, "FitEmin", "Emin:", $this->{ini}->pVariable('FitEmin', ''), "%s", $EntryWidth, "eV", 0, 0); $this->MakeLabelEntry($Frame, "FitEmax", "Emax:", $this->{ini}->pVariable('FitEmax', ''), "%s", $EntryWidth, "eV", 0, 1); $this->MakeLabelEntry($Frame, "nSkipData", "nSkip:", $this->{ini}->pVariable('nSkipData', 2), "%d", $EntryWidth, "", 0, 2); $this->MakeLabelEntry($Frame, "EPS", "EPS:", $this->{ini}->pVariable('EPS', 1.0e-5), "%12.4g", $EntryWidth, "", 1, 0); $this->MakeLabelEntry($Frame, "nMaxIter", "MaxIter:", $this->{ini}->pVariable('nMaxIter', 1000), "%d", $EntryWidth, "", 1, 1); $this->MakeLabelEntry($Frame, "nSaveSpectraInterval", "SaveIntvl:", $this->{ini}->pVariable('nSaveSpectraInterval', 10), "%d", $EntryWidth, "", 1, 2); $Frame = $mw->MyLabFrame( -label => 'Ellipsometry', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeLabelEntry($Frame, "Angle", "Angle:", $this->{ini}->pVariable('Angle', 70.0), "%8.4f", $EntryWidth, "deg", 0, 0); my $FilmLabel = ($mode eq "BulkWithSurfaceLayer")? 'Surface layer' : 'Film'; $Frame = $mw->MyLabFrame( -label => $FilmLabel, -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeCheckEntry($Frame, "FilmThickness", "Thickness:", $this->{dini}->pVariable('FilmThicknesscheck', 1), $this->{ini}->pVariable('FilmThickness', 100.0), "%12.6g", $EntryWidth, "nm", 0, 0); my $lsb6 = $this->{ChooseLayerModelListBox} = $Frame->MyBrowseEntry( -label => "Layer Model:", -state => "readonly", -takefocus => 1, -width => 10, -Selections => ["C12A7:e-(sub)", "C12A7/C12A7:e-(sub)"], -SelIndex => 0, )->grid(-row => 0, -column => 5, -columnspan => 1, -sticky => 'e' ); $lsb6->configure(-browsecmd => [\&SelChangeListBox, $this, "LayerModel", $this->{ChooseLayerModelListBox}]); if($mode eq 'BulkWithSurfaceLayer') { $this->MakeCheckEntry($Frame, "SurfaceEps1", "e1:", $this->{dini}->pVariable('SurfaceEps1check', 1), $this->{ini}->pVariable('SurfaceEps1', 4.0), "%12.6g", $EntryWidth, "", 1, 0); $this->MakeCheckEntry($Frame, "SurfaceEps2", "e2:", $this->{dini}->pVariable('SurfaceEps2check', 0), $this->{ini}->pVariable('SurfaceEps2', 0.0), "%12.6g", $EntryWidth, "", 1, 1); } $Frame = $mw->MyLabFrame( -label => 'Dielectric background', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeCheckEntry($Frame, "e1inf", "e1:", $this->{dini}->pVariable('e1infcheck', 1) , $this->{ini}->pVariable('e1inf', 0.155), "%12.6g", $EntryWidth, "e0", 0, 0); $this->MakeCheckEntry($Frame, "e2inf", "e2:", $this->{dini}->pVariable('e2infcheck', 0) , $this->{ini}->pVariable('e2inf', 0.0 ), "%12.6g", $EntryWidth, "e0", 0, 1); $Frame = $mw->MyLabFrame( -label => 'Tauc-Lorentz', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeCheckEntry($Frame, "A", "A:", $this->{dini}->pVariable('Acheck', 1) , $this->{ini}->pVariable('A', 122.8), "%12.6g", $EntryWidth, "", 0, 0); $this->MakeCheckEntry($Frame, "C", "C:", $this->{dini}->pVariable('Ccheck', 1) , $this->{ini}->pVariable('C', 10.8), "%12.6g", $EntryWidth, "", 0, 1); $this->MakeCheckEntry($Frame, "Eg", "Eg:", $this->{dini}->pVariable('Egcheck', 1) , $this->{ini}->pVariable('Eg', 4.4), "%12.6g", $EntryWidth, "eV", 1, 0); $this->MakeCheckEntry($Frame, "En0", "En0:", $this->{dini}->pVariable('En0check', 1) , $this->{ini}->pVariable('En0', 155.9), "%12.6g", $EntryWidth, "eV", 1, 1); if($this->{nLorentz} > 0) { $Frame = $mw->MyLabFrame( -label => "Lorentz", -labelside => 'acrosstop', )->pack(-anchor => 'nw'); } for(my $i = 0 ; $i < $this->{nLorentz} ; $i++) { my $i1 = $i + 1; $this->MakeCheckEntry($Frame, "E0${i1}", "E0:", $this->{dini}->pVariable("E0${i1}check", 1) , $this->{ini}->pVariable("E0${i1}", 2.64), "%12.6g", $EntryWidth, "eV", $i, 0); $this->MakeCheckEntry($Frame, "Ne${i1}", "Ne:", $this->{dini}->pVariable("Ne${i1}check", 1) , $this->{ini}->pVariable("Ne${i1}", 2e26), "%12.6g", $EntryWidth, "m-3", $i, 1); $this->MakeCheckEntry($Frame, "G${i1}", "G:", $this->{dini}->pVariable("G${i1}check", 1) , $this->{ini}->pVariable("G${i1}", 2.64), "%12.6g", $EntryWidth, "eV", $i, 2); } if($this->{nDrude} > 0) { $Frame = $mw->MyLabFrame( -label => "Drude", -labelside => 'acrosstop', )->pack(-anchor => 'nw'); } for(my $i = 0 ; $i < $this->{nDrude} ; $i++) { my $i1 = $i + 1; $this->MakeCheckEntry($Frame, "DrudeEp${i1}", "Ep:", $this->{dini}->pVariable("DrudeEp${i1}check", 1) , $this->{ini}->pVariable("DrudeEp${i1}", 0.5), "%12.6g", $EntryWidth, "eV", $i, 1); $this->MakeCheckEntry($Frame, "Drudetau${i1}", "tau:", $this->{dini}->pVariable("Drudetau${i1}check", 1) , $this->{ini}->pVariable("Drudetau${i1}", 1.0e-14), "%12.6g", $EntryWidth, "s", $i, 2); } $this->UpdateParameters(); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{RecalcButton} = $Frame->MyButton( -text => 'Re&calc', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'Recalc'], )->pack(-side => 'left'); $this->{FitButton} = $Frame->MyButton( -text => '&Fit', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'Fit'], )->pack(-side => 'left'); $this->{SaveForSCOUTButton} = $Frame->MyButton( -text => 'Save for &SCOUT', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'SaveForSCOUT'], )->pack(-side => 'left'); if($mode eq 'BulkWithSurfaceLayer') { $this->{PbPButton} = $Frame->MyButton( -text => 'PointByPoint', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'PbP'], )->pack(-side => 'left'); } $this->{SaveLayersButton} = $Frame->MyButton( -text => 'Save Layers', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'SaveLayers'], )->pack(-side => 'left'); #ツールバーのOpenボタンをファイル読み込みにバインドする $mw->{OpenButton}->configure( -command => sub { $this->ChooseFile('SampleCSVFile', $this->{SPEFileFileEntry}); }, ) if($mw->{OpenButton}); } sub ButtonPressed { my ($this, $event, $type) = @_; my $App = $this->App(); #print "this=$this event=$event\n"; if($type eq 'Recalc') { $this->Recalc(); $this->CreateGraphFrame(); $this->AssignGraphData(1); $this->Draw(); } elsif($type eq 'SaveForSCOUT') { $this->SaveForSCOUT(); } elsif($type eq 'SaveLayers') { $this->SaveLayers(); } elsif($type eq 'Fit') { $this->Fit(); $this->Recalc(); # $this->CreateGraphFrame(); $this->AssignGraphData(0); $this->Draw(); return; } elsif($type eq 'PointByPoint') { $this->PointByPoint(); $this->Recalc(); # $this->CreateGraphFrame(); $this->AssignGraphData(0); $this->Draw(); return; } elsif($type eq 'SaveComponents') { $this->SaveComponents(); return; } 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 =~ /^EditSample(\d+)CSV$/) { my $d = $1; my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{"Sample${d}CSVFile"}; my $command = "$Editor $File"; system($command); return; } elsif($type =~ /^EditComponent(\d+)CSV$/) { my $d = $1; my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{"Component${d}CSVFile"}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditSample1CSV') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{Sample1CSVFile}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditSample2CSV') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{Sample2CSVFile}; 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; } else { no strict; $this->$type(); use strict; } } #=================================================== # データ処理 #=================================================== sub SaveForSCOUT { my ($this) = @_; my $App = $this->App(); my $optics = new Optics; my $ini = $this->{ini}; return if(!defined $this->{Ellipsometry}); my $pE = $this->{Ellipsometry}->GetData('eV'); my $pPsi = $this->{Ellipsometry}->GetData('Psi'); my $pDelta = $this->{Ellipsometry}->GetData('Delta'); my $pn = $this->{Ellipsometry}->GetData('n'); my $pk = $this->{Ellipsometry}->GetData('k'); my $nData = $this->{Ellipsometry}->nData(); my $path = $this->ChooseSaveFile(); return if(!defined $path); my $out = new JFile; if(!$out->Open($path, "w")) { $App->print("Error: Can not write to [$path].\n"); return undef; } $out->print("E(eV),wl(nm),Psi,Delta,tan(Psi),tan(Delta),n,k,e1,e2,alpha(cm-1),sigma(S/cm)\n"); for(my $i = 0 ; $i < $nData ; $i++) { my $E = $pE->[$i]; my $wl = Optics::eVTonm($E); my $Psi = $pPsi->[$i]; $Psi -= 360.0 if($Psi >= 180.0); my $tanPsi = Sci::tan($Psi*$torad); my $Delta = $pDelta->[$i]; $Delta -= 360.0 if($Delta >= 180.0); my $tanDelta = Sci::tan($Delta*$torad); my ($n, $k); if($pn) { $n = $pn->[$i]; $k = $pk->[$i]; } else { ($n, $k) = $this->{Ellipsometry}->PsiDeltaToNK($Psi, $Delta); } my ($e1, $e2) = $this->{Ellipsometry}->NKToEps($n, $k); my $alpha = Optics::KToAlpha($wl, $k); my $sigma = Optics::EpsToConductivity($E, $e2); $out->print("$E,$wl,$Psi,$Delta,$tanPsi,$tanDelta,$n,$k,$e1,$e2,$alpha,$sigma\n"); } $out->Close(); $path = "$path.txt"; $App->print("Parameters are stored in [$path].\n"); $out = new JFile; if(!$out->Open($path, "w")) { $App->print("Error: Can not write to [$path].\n"); return undef; } $out->print("[Background]\n"); $out->print("e1 : $ini->{e1inf}\n"); $out->print("e2 : $ini->{e2inf}\n"); $out->print("[Tauc-Lorentz]\n"); $out->print("A : $ini->{A}\n"); $out->print("C : $ini->{C}\n"); my $EgK = Optics::eVToKiser($ini->{Eg}); $out->print("Eg : $ini->{Eg} eV $EgK cm-1\n"); $EgK = Optics::eVToKiser($ini->{En0}); $out->print("En0: $ini->{En0} eV $EgK cm-1\n"); $out->print("\n"); for(my $i = 1 ; ; $i++) { last if(!defined $ini->{"Ne$i"}); $out->print("[Lorentz$i]\n"); $EgK = Optics::eVToKiser($ini->{"E0$i"}); $out->print("E0 : ", $ini->{"E0$i"}, "eV $EgK cm-1\n"); my $A = $optics->CalLorentzAfromNe($ini->{"Ne$i"}, 1.0); $out->print("Ne : ", $ini->{"Ne$i"}, "cm-3 A=$A\n"); $EgK = Optics::eVToKiser($ini->{"G$i"}); $out->print("G : ", $ini->{"G$i"}, "eV $EgK cm-1"); $out->print("\n"); } for(my $i = 1 ; ; $i++) { last if(!defined $ini->{"DrudeEp$i"}); $out->print("[Drude$i]\n"); $EgK = Optics::eVToKiser($ini->{"DrudeEp$i"}); $out->print("Ep : ", $ini->{"DrudeEp$i"}, "eV $EgK cm-1\n"); my $EgeV = Optics::HzToeV(1.0 / $ini->{"Drudetau$i"}); $EgK = Optics::eVToKiser($EgeV); $out->print("tau: ", $ini->{"Drudetau$i"}, "s $EgeV eV $EgK cm-1\n"); $out->print("\n"); } $out->Close(); } sub SaveLayers { my ($this) = @_; my $App = $this->App(); my $ini = $this->{ini}; my $Angle = $ini->{Angle}; $App->print("\nSave Total and Layers optical data\n"); my $BasePath = $ini->{ParameterFile}; $BasePath = $ini->{Sample1CSVFile} if(!$BasePath); $BasePath = $ini->{SampleCSVFile} if(!$BasePath); my ($drive, $directory, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($BasePath); my $BaseDir = "$drive$directory"; $App->print(" Base dir: $BaseDir\n"); my $el = $this->{Ellipsometry}; my $pObsE = $el->GetData('.*eV.*', '.*E.*'); my $pObsEps1 = $el->GetData('e1'); my $pObsEps2 = $el->GetData('e2'); my $pObsR = $el->GetData('R.*'); my $pObsT = $el->GetData('T.*'); my $nData = @$pObsE; $this->BuildLayerModel(0, 0); my $Layers = $this->{Layers}; my $nLayer = $Layers->nLayer(); if($pObsEps1 and $pObsEps2) { my $TotalFile = Deps::MakePath($BaseDir, "Total.csv", 0); $App->print(" Save Total data to [$TotalFile].\n"); my $out = new JFile($TotalFile, "w"); if($out) { $out->print("E(eV),wl(nm),e1(obs),e2(obs),e1(cal),e2(cal),n(cal),k(cal),alpha(cal/cm-1)\n"); for(my $i = 0 ; $i < $nData ; $i++) { my $E = $pObsE->[$i]; next if($E < $ini->{FitEmin} or $ini->{FitEmax} < $E); my $wl = Optics::eVTonm($E); my ($Psi, $Delta) = $Layers->CalPsiDelta($E); my ($e1, $e2) = $el->PsiDeltaToEps($Psi, $Delta, $Angle); my ($n, $k) = $el->EpsToNK($e1,$e2); my $alpha = Optics::KToAlpha($wl, $k); $out->print("$E,$wl,$pObsEps1->[$i],$pObsEps2->[$i],$e1,$e2,$n,$k,$alpha\n"); } $out->Close(); } else { $App->print(" Error: Can not write to [$TotalFile].\n"); } } elsif($pObsR and $pObsT) { my $TotalFile = Deps::MakePath($BaseDir, "Total.csv", 0); $App->print(" Save Total data to [$TotalFile].\n"); my $out = new JFile($TotalFile, "w"); if($out) { $out->print("E(eV),wl(nm),T(obs),R(obs),T(cal),R(cal)\n"); for(my $i = 0 ; $i < $nData ; $i++) { my $E = $pObsE->[$i]; next if($E < $ini->{FitEmin} or $ini->{FitEmax} < $E); my $wl = Optics::eVTonm($E); my ($rs123, $rp123, $ts123, $tp123, $Rtots, $Rtotp, $Ttots, $Ttotp) = $Layers->CalFresnelCoefficient($E); my $Tcal = ($Ttots + $Ttotp) / 2.0; my $Rcal = ($Rtots + $Rtotp) / 2.0; $out->print("$E,$wl,$pObsT->[$i],$pObsR->[$i],$Tcal,$Rcal\n"); } $out->Close(); } else { $App->print(" Error: Can not write to [$TotalFile].\n"); } } for(my $l = 0 ; $l < $nLayer ; $l++) { my $pLayer = $Layers->pLayer($l); my $name = $pLayer->Name(); my $LayerFile = Deps::MakePath($BaseDir, "Layer${l}-$name.csv", 0); $App->print(" Save Layer$l data to [$LayerFile].\n"); my $out = new JFile($LayerFile, "w"); if($out) { $out->print("E(eV),wl(nm),e1(cal),e2(cal),n(cal),k(cal),alpha(cal/cm-1)\n"); for(my $i = 0 ; $i < $nData ; $i++) { my $E = $pObsE->[$i]; next if($E < $ini->{FitEmin} or $ini->{FitEmax} < $E); my $wl = Optics::eVTonm($E); my ($e1, $e2) = $pLayer->CalEps($E); my ($n, $k) = $el->EpsToNK($e1,$e2); my $alpha = Optics::KToAlpha($wl, $k); $out->print("$E,$wl,$e1,$e2,$n,$k,$alpha\n"); } $out->Close(); } else { $App->print(" Error: Can not write to [$LayerFile].\n"); } } if($this->{PbPE}) { my $PointByPointFile = Deps::MakePath($BaseDir, "PointByPoint.csv", 0); $App->print(" Save PointByPoint data to [$PointByPointFile].\n"); my $pE = $this->{PbPE}; my $pe1 = $this->{PbPe1}; my $pe2 = $this->{PbPe2}; my $pR = $this->{PbPR}; my $pT = $this->{PbPT}; my $pS2 = $this->{PbPS2}; my $out = new JFile($PointByPointFile, "w"); if($out) { $out->print("E(eV),wl(nm),e1(PbP),e2(PbP),n(PbP),k(PbP),alpha(PbP/cm-1),T(PbP),R(PbP),S2\n"); for(my $i = 0 ; $i < @$pE ; $i++) { my $E = $pE->[$i]; next if($E < $ini->{FitEmin} or $ini->{FitEmax} < $E); my $wl = Optics::eVTonm($E); my ($e1, $e2) = ($pe1->[$i], $pe2->[$i]); my ($n, $k) = $el->EpsToNK($e1,$e2); my $alpha = Optics::KToAlpha($wl, $k); $out->print("$E,$wl,$e1,$e2,$n,$k,$alpha,$pT->[$i],$pR->[$i],$pS2->[$i]\n"); } $out->Close(); } else { $App->print(" Error: Can not write to [Save].\n"); } } } sub BuildLayerModel { my ($this, $IsPrint, $BuildOptimize) = @_; $IsPrint = 1 if(!defined $IsPrint); $BuildOptimize = 1 if(!defined $BuildOptimize); my $ini = $this->{ini}; my $dini = $this->{dini}; my $el = $this->{Ellipsometry}; my $optics = new Optics; my $Layers = new MultiLayer; $Layers->SetIncidentAngle($ini->{Angle}); my $pObsE = $el->GetData('.*eV.*', '.*E.*'); my $pObsPsi = $el->GetData('Psi'); my $pObsDelta = $el->GetData('Delta'); my $pObsEps1 = $el->GetData('e1'); my $pObsEps2 = $el->GetData('e2'); my $nData = @$pObsE; my $nE = $nData; $ini->{FitEmin} = $pObsE->[0] if($ini->{FitEmin} eq ''); $ini->{FitEmax} = $pObsE->[$nData-1] if($ini->{FitEmax} eq ''); my $Emin = $ini->{FitEmin}; my $Emax = $ini->{FitEmax}; my $Estep = $pObsE->[1] - $pObsE->[0]; $Estep = 0.05 if(!defined $Estep); $nData = int( ($Emax - $Emin) / $Estep + 1.001); my $Air = new OpticalMaterial("air"); my $C12A7 = new OpticalMaterial("Specify", "C12A7"); my $C12A7e = new OpticalMaterial("Specify", "C12A7e"); my $MgO = new OpticalMaterial("Specify", "MgO"); #print "e1=$ini->{e1inf}\n"; $C12A7->AddDielectricModel( "Constant1", "Constant", "e1inf", $ini->{e1inf}, "e2inf", $ini->{e2inf}, ); $C12A7->AddDielectricModel( "TaucLorentz1", "TaucLorentz", "A", $ini->{A}, "Eg", $ini->{Eg}, "En0", $ini->{En0}, "C", $ini->{C} ); $C12A7e->AddDielectricModel( "Constant1", "Constant", "e1inf", $ini->{e1inf}, "e2inf", $ini->{e2inf}, ); $C12A7e->AddDielectricModel( "TaucLorentz1", "TaucLorentz", "A", $ini->{A}, "Eg", $ini->{Eg}, "En0", $ini->{En0}, "C", $ini->{C} ); for(my $i = 0 ; $i < $this->{nLorentz} ; $i++) { my $i1 = $i + 1; $C12A7e->AddDielectricModel( "Lorentz$i1", "Lorentz", "Ne", $ini->{"Ne$i1"}, "E0", $ini->{"E0$i1"}, "G", $ini->{"G$i1"}, ); } if($ini->{SubstrateCSVFile}) { my @ret = $MgO->AddDielectricModel( "MgO", "EFile", "Path", $ini->{SubstrateCSVFile}, ); if(@ret == 0) { print "Error: Can not read [$ini->{SubstrateCSVFile}].\n"; return; } } $Layers->AddLayer($Air, -1.0, 0.0); $Layers->AddLayer($C12A7, $ini->{FilmThickness}*1.0e-9, 1.0); $Layers->AddLayer($C12A7e, -1.0, 0.0); $this->{Layers} = $Layers; if($IsPrint) { $this->App()->print("Layers:\n"); my $nLayer = $Layers->nLayer(); for(my $i = 0 ; $i < $nLayer ; $i++) { my $pLayer = $Layers->pLayer($i); my $name = $pLayer->Name(); my $d = $Layers->LayerThickness($i) * 1.0e9; # nm $this->App()->print("$i: $name ($d nm)\n"); } } #========================================================= # フィッティング設定 #========================================================= return if(!$BuildOptimize); my $optimize = new Optimize(); $optimize->AddParameters( "FilmThickness", $Layers->pLayerThickness(1), $dini->{FilmThicknesscheck}, $dini->{FilmThicknessscale}, $dini->{FilmThicknessmin}, $dini->{FilmThicknessmax}, sub { $Layers->SetLayerThickness(1, $_[0]); $ini->{FilmThickness} = $_[0]*1.0e9; }, "C12A7e-e1", $Layers->pVariable(2, 'Constant1::e1inf'), $dini->{e1infcheck}, $dini->{e1infscale}, $dini->{e1infmin}, $dini->{e1infmax}, sub { $Layers->SetVariable(2, 'Constant1::e1inf', $_[0]); $ini->{e1inf} = $_[0]; }, "C12A7e-e2", $Layers->pVariable(2, 'Constant1::e2inf'), $dini->{e2infcheck}, $dini->{e2infscale}, $dini->{e2infmin}, $dini->{e2infmax}, sub { $Layers->SetVariable(2, 'Constant1::e2inf', $_[0]); $ini->{e2inf} = $_[0]; }, "C12A7e-TLA", $Layers->pVariable(2, 'TaucLorentz1::A'), $dini->{Acheck}, $dini->{Ascale}, $dini->{Amin}, $dini->{Amax}, sub { $Layers->SetVariable(2, 'TaucLorentz1::A', $_[0]); $ini->{A} = $_[0]; }, "C12A7e-TLC", $Layers->pVariable(2, 'TaucLorentz1::C'), $dini->{Ccheck}, $dini->{Cscale}, $dini->{Cmin}, $dini->{Cmax}, sub { $Layers->SetVariable(2, 'TaucLorentz1::C', $_[0]); $ini->{C} = $_[0]; }, "C12A7e-TLEg", $Layers->pVariable(2, 'TaucLorentz1::Eg'), $dini->{Egcheck}, $dini->{Egscale}, $dini->{Egmin}, $dini->{Egmax}, sub { $Layers->SetVariable(2, 'TaucLorentz1::Eg', $_[0]); $ini->{Eg} = $_[0]; }, "C12A7e-TLEn0", $Layers->pVariable(2, 'TaucLorentz1::En0'), $dini->{En0check}, $dini->{En0scale}, $dini->{En0min}, $dini->{En0max}, sub { $Layers->SetVariable(2, 'TaucLorentz1::En0', $_[0]); $ini->{En0} = $_[0]; }, ); for(my $i = 0 ; $i < $this->{nLorentz} ; $i++) { my $i1 = $i + 1; $optimize->AddParameters( "C12A7e-L${i1}E0", $Layers->pVariable(2, "Lorentz${i1}::E0"), $dini->{"E0${i1}check"}, $dini->{"E0${i1}scale"}, $dini->{"E0${i1}min"}, $dini->{"E0${i1}max"}, sub { $Layers->SetVariable(2, "Lorentz${i1}::E0", $_[0]); $ini->{"E0${i1}"} = $_[0]; }, "C12A7e-L${i1}Ne", $Layers->pVariable(2, "Lorentz${i1}::Ne"), $dini->{"Ne${i1}check"}, $dini->{"Ne${i1}scale"}, $dini->{"Ne${i1}min"}, $dini->{"Ne${i1}max"}, sub { $Layers->SetVariable(2, "Lorentz${i1}::Ne", $_[0]); $ini->{"Ne${i1}"} = $_[0]; $ini->{"A${i1}"} = $optics->CalLorentzAfromNe($ini->{"Ne${i1}"}, 1.0); }, "C12A7e-L${i1}G", $Layers->pVariable(2, "Lorentz${i1}::G"), $dini->{"G${i1}check"}, $dini->{"G${i1}scale"}, $dini->{"G${i1}min"}, $dini->{"G${i1}max"}, sub { $Layers->SetVariable(2, "Lorentz${i1}::G", $_[0]); $ini->{"G${i1}"} = $_[0]; }, ); } $this->{Optimize} = $optimize; } sub Recalc { my ($this) = @_; $this->UpdateParameters(); $this->BuildLayerModel(0, 0); my $el = $this->{Ellipsometry}; my $Layers = $this->{Layers}; my $pObsE = $el->GetData('.*eV.*', '.*E.*'); my $pObsPsi = $el->GetData('Psi'); my $pObsDelta = $el->GetData('Delta'); my $pObsEps1 = $el->GetData('e1'); my $pObsEps2 = $el->GetData('e2'); my $FitTo = $this->{ChooseFitToListBox}->GetText(); my ($pE, $pe1, $pe2, $pPsi, $pDelta, $pIs, $pIc, $S2) = $this->CalEpsPsiDelta($Layers, $pObsE, $pObsPsi, $pObsDelta, $pObsEps1, $pObsEps2, $FitTo); $this->{pEArray} = $pE; $this->{pe1Array} = $pe1; $this->{pe2Array} = $pe2; $this->{pPsiArray} = $pPsi; $this->{pDeltaArray} = $pDelta; $this->{pIsArray} = $pIs; $this->{pIcArray} = $pIc; $this->App()->print("Recalc: S2=$S2\n"); $this->SetS2($S2); return $S2; } sub Fit { my ($this) = @_; my $ini = $this->{ini}; my $dini = $this->{dini}; $this->UpdateParameters(); $this->BuildLayerModel(0, 1); my $optimize = $this->{Optimize}; my $Method = $this->{ChooseLSQMethodListBox}->GetText(); my $FitTo = $this->{ChooseFitToListBox}->GetText(); print "Method: $Method\n"; print "Fit to: $FitTo\n"; print "nMaxIter: $ini->{nMaxIter}\n"; my $el = $this->{Ellipsometry}; my $pObsE = $el->GetData('.*eV.*', '.*E.*'); my $pObsPsi = $el->GetData('Psi'); my $pObsDelta = $el->GetData('Delta'); my $pObsEps1 = $el->GetData('e1'); my $pObsEps2 = $el->GetData('e2'); #========================================================= # 最適化の実行 #========================================================= $optimize->SetnS2Calculation(0); my ($OptVars, $MinVal) = $optimize->Optimize( $Method, undef, undef, undef, $ini->{EPS}, $ini->{nMaxIter}, $ini->{iPrintLevel}, sub { $this->CalS2($FitTo, $pObsE, $pObsPsi, $pObsDelta, $pObsEps1, $pObsEps2, @_); }, undef, sub { Optimize::BuildDifferentialMatrixes(@_); }, ); print "\nOptimized at:\n"; $optimize->PrintParameters(1); $optimize->RecoverParameters($OptVars); $this->SetS2($MinVal); $this->UpdateParameters(); } sub CalS2 { my ($this, $FitTo, $pObsE, $pObsPsi, $pObsDelta, $pObsEps1, $pObsEps2, $pVars, $iPrintLevel) = @_; #print "pVars=", join(',', @$pVars); my $optimize = $this->{Optimize}; my $ini = $this->{ini}; $optimize->RecoverParameters($pVars); # $this->UpdateParameters(); $this->BuildLayerModel(0, 0); my ($pE, $pe1, $pe2, $pPsi, $pDelta, $pIs, $pIc, $S2) = $this->CalEpsPsiDelta($this->{Layers}, $pObsE, $pObsPsi, $pObsDelta, $pObsEps1, $pObsEps2, $FitTo); $optimize->IncrementnS2(); my $nS2 = $optimize->nS2Calculation(); my $nS2Interval = $ini->{nSaveSpectraInterval}; print "S2[$nS2] = $S2 / "; $S2 += $optimize->CalPenalty(1.0e10, $pVars, 1); print "$S2\n"; $optimize->PrintParameters(1, $pVars, $S2); if($nS2Interval > 0 and $nS2 % $nS2Interval == 0) { $this->Recalc(); # $this->CreateGraphFrame(); $this->AssignGraphData(0); $this->Draw(); } $this->mw()->update(); return $S2; } sub CalEpsPsiDelta { my ($this, $Layers, $pObsE, $pObsPsi, $pObsDelta, $pObsEps1, $pObsEps2, $FitTo) = @_; my $ini = $this->{ini}; my $el = $this->{Ellipsometry}; my $Angle = $ini->{Angle}; $el->SetIncidentAngle($Angle); my $nData = @$pObsE; my (@E, @e1, @e2, @Psi, @Delta, @Is, @Ic); my $S2 = 0.0; my $c = 0; for(my $i = 0 ; $i < $nData ; $i++) { next if($ini->{nSkipData} > 0 and $i % $ini->{nSkipData} != 0); my $E = $pObsE->[$i]; next if($E < $ini->{FitEmin} or $ini->{FitEmax} < $E); my ($Psi, $Delta) = $Layers->CalPsiDelta($E); my ($e1c, $e2c) = $el->PsiDeltaToEps($Psi, $Delta, $Angle); $E[$c] = $E; $e1[$c] = $e1c; $e2[$c] = $e2c; $Psi[$c] = $Psi; $Delta[$c] = $Delta; #print "E=$E, e=($e1c,$e2c), Psi=($Psi,$Delta)\n"; if(!defined $pObsPsi) { $c++; next; } if($FitTo eq 'Eps') { $S2 += ($pObsEps1->[$i] - $e1c)**2 + ($pObsEps2->[$i] - $e2c)**2; } elsif($FitTo eq 'PsiDelta') { my $dPsi = $pObsPsi->[$i] - $Psi; my $dDelta = $pObsDelta->[$i] - $Delta; $dPsi -= 90.0 if($dPsi > 90.0); $dPsi += 90.0 if($dPsi < 0.0); $dDelta -= 360.0 if($dDelta > 180.0); $dDelta += 360.0 if($dDelta <= -180.0); $S2 += $dPsi*$dPsi + $dDelta*$dDelta; } elsif($FitTo eq 'IsIcII') { my ($Iso, $Ico) = $el->PsiDeltaToIsIcConfigrationII($pObsPsi->[$i], $pObsDelta->[$i]); ($Is[$c], $Ic[$c]) = $el->PsiDeltaToIsIcConfigrationII($Psi, $Delta); #print "Is=($Iso,$pIs->[$i],$Is[$c])\n"; #print "Ic=($Ico,$pIc->[$i],$Ic[$c])\n"; my $ds = $Iso - $Is[$c]; my $dc = $Ico - $Ic[$c]; $S2 += $ds*$ds + $dc*$dc; } elsif($FitTo eq 'IsIcIII') { my ($Iso, $Ico) = $el->PsiDeltaToIsIcConfigrationIII($pObsPsi->[$i], $pObsDelta->[$i]); ($Is[$c], $Ic[$c]) = $el->PsiDeltaToIsIcConfigrationIII($Psi, -$Delta); my $ds = $Iso - $Is[$c]; my $dc = $Ico - $Ic[$c]; $S2 += $ds*$ds + $dc*$dc; } else { print "Error: Invalid Fitting Target [$FitTo].\n"; exit; } $c++; } $S2 = sqrt($S2 / $c); return (\@E, \@e1, \@e2, \@Psi, \@Delta, \@Is, \@Ic, $S2); } sub SaveParameterFile { my ($this, $filepath) = @_; $this->{ini}->{Method} = $this->{ChooseLSQMethodListBox}->GetText() if($this->{ChooseLSQMethodListBox}); $this->{ini}->{FitTo} = $this->{ChooseFitToListBox}->GetText() if($this->{ChooseFitToListBox}); $this->{ini}->{LayerModel} = $this->{ChooseLayerModelListBox}->GetText() if($this->{ChooseLayerModelListBox}); $this->{ini}->{Model} = $this->{ChooseModelListBox}->GetText() if($this->{ChooseModelListBox}); $this->{ini}->{X} = $this->{ChooseXListBox}->GetText() if($this->{ChooseXListBox}); $this->{ini}->{Y1} = $this->{ChooseY1ListBox}->GetText() if($this->{ChooseY1ListBox}); $this->{ini}->{Y2} = $this->{ChooseY2ListBox}->GetText() if($this->{ChooseY2ListBox}); if(!defined $filepath or $filepath eq '') { $filepath = $this->{ini}->{Sample1CSVFile}; $filepath = $this->{ini}->{SampleCSVFile} if(!defined $filepath or $filepath eq ''); $filepath = $this->{ini}->{SubstrateCSVFile} if(!defined $filepath or $filepath eq ''); $filepath = 'save.prm' if(!defined $filepath or $filepath eq ''); $filepath =~ s/\.csv$/\.prm/i; $filepath = Deps::ExtractFileName($filepath); $filepath = $this->ChooseSaveFile($filepath, '*.prm'); if($filepath) { my $ext = Deps::ExtractExtention($filepath); if(!defined $ext or $ext eq '') { $filepath = Deps::ReplaceExtension($filepath, ".prm"); } $this->{ini}->{ParameterFile} = $filepath; } else { return; } } $this->{ini}->SetIniFile($filepath, undef, 1); $this->App()->print("\nSaveParameterFile:\n"); $this->ComposeParameters($this->{dini}, $this->{ini}); $this->{ini}->WriteAll(); $this->DecomposeParameters($this->{ini}, $this->{dini}); } sub Initialize { my ($this, $InitializeParameterFile, $InitializeData) = @_; $this->{Ellipsometry} = new Ellipsometry; $this->{Optimize} = undef; $this->{Layers} = undef; if($InitializeParameterFile) { $this->{ini}->{SampleCSVFile} = ''; $this->{ini}->{SubstrateCSVFile} = ''; if(defined $this->{ini}->{nComponents}) { for(my $i = 1 ; $i <= $this->{ini}->{nComponents} ; $i++) { my $v = 1.0; $v = 0.0 if($i > 1); $this->{ini}->{"Vf$i"} = $v; $this->{ini}->{"Component${i}CSVFile"} = ''; } $this->{ini}->{KVf} = 1000.0; if(defined $this->{ChooseEMAModelListBox}) { $this->{ChooseEMAModelListBox}->SetCurSel(0); } } } if($InitializeData) { $this->{pEArray} = undef; $this->{pe1Array} = undef; $this->{pe2Array} = undef; $this->{pPsiArray} = undef; $this->{pDeltaArray} = undef; $this->{pIsArray} = undef; $this->{pIcArray} = undef; $this->{PbPE} = undef; $this->{PbPe1} = undef; $this->{PbPe2} = undef; $this->{PbPR} = undef; $this->{PbPT} = undef; } } sub ReadParameterFile { my ($this, $filepath) = @_; my $DirectorySeparator = Deps::DirectorySeparator(); my $RegSeparator = Utils::RegExpQuote($DirectorySeparator); my $ini = $this->{ini}; my $dini = $this->{dini}; $this->Initialize(1, 1); $this->App()->print("\nRead paramter from [$filepath].\n"); $this->{ini}->ReadAll($filepath); $this->{ini}->{ParameterFile} = $filepath; $this->DecomposeParameters($ini, $dini); $this->{ChooseLSQMethodListBox}->SetText($this->{ini}->{Method}) if($this->{ChooseLSQMethodListBox}); $this->{ChooseFitToListBox}->SetText($this->{ini}->{FitTo}) if($this->{ChooseFitToListBox}); $this->{ChooseLayerModelListBox}->SetText($this->{ini}->{LayerModel}) if($this->{ChooseLayerModelListBox}); $this->{ChooseModelListBox}->SetText($this->{ini}->{Model}) if($this->{ChooseModelListBox} and $this->{ini}->{Model}); $this->{ChooseXListBox}->SetText($this->{ini}->{X}) if($this->{ChooseXListBox} and $this->{ini}->{X}); $this->{ChooseY1ListBox}->SetText($this->{ini}->{Y1}) if($this->{ChooseY1ListBox} and $this->{ini}->{Y1}); $this->{ChooseY2ListBox}->SetText($this->{ini}->{Y2}) if($this->{ChooseY2ListBox} and $this->{ini}->{Y2}); if($this->{ini}->{SampleCSVFile}) { # my $ret = $this->ReadSampleDataFile($this->{ini}->{SampleCSVFile}, 1, 0); my $ret; if(-e $this->{ini}->{SampleCSVFile}) { $ret = $this->ReadSampleDataFile($this->{ini}->{SampleCSVFile}, 1, 0, 0); } unless($ret) { my ($drive0, $directory0, $filename0, $ext0, $lastdir0, $filebody0) = Deps::SplitFilePath($this->{ini}->{ParameterFile}); my ($drive1, $directory1, $filename1, $ext1, $lastdir1, $filebody1) = Deps::SplitFilePath($filepath); $this->{ini}->{SampleCSVFile} =~ s/\//$DirectorySeparator/g; my $RelPath = Utils::MakeRelativePath($this->{ini}->{SampleCSVFile}, "$drive0$directory0"); $RelPath =~ s/^\.$RegSeparator/$drive1$directory1/; if(-e $RelPath) { $ret = $this->ReadSampleDataFile($RelPath, 1, 0, 0); } unless($ret) { ($drive0, $directory0, $filename0, $ext0, $lastdir0, $filebody0) = Deps::SplitFilePath($filepath); ($drive1, $directory1, $filename1, $ext1, $lastdir1, $filebody1) = Deps::SplitFilePath($this->{ini}->{SampleCSVFile}); my $f = Deps::MakePath("$drive0$directory0", $filename1, 0); $ret = $this->ReadSampleDataFile($f, 1, 0, 0); return undef unless($ret); $this->{ini}->{SampleCSVFile} = $f; } else { $this->{ini}->{SampleCSVFile} = $RelPath; } } # return undef unless($ret); } if($this->{ini}->{SubstrateCSVFile}) { my $ret = $this->ReadSubstrateDataFile($this->{ini}->{SubstrateCSVFile}, 1, 0); return undef unless($ret); } return 1; } sub ReadSampleDataFile { my ($this, $filepath, $IsPrint) = @_; my $App = $this->App(); #print "type=$type\n"; $this->Initialize(0, 1); $this->{Path} = $filepath; my ($nData, $pLabelArray, @pDataArray) = $this->{Ellipsometry}->Read($filepath); if(!defined $nData) { $App->print("Error: Can not read [$filepath].\n"); return $this->{Path} = undef; } my $nDataArray = $this->{Ellipsometry}->nDataArray(); #print "nDataArray: $nDataArray\n"; $this->{"ChooseXListBox"}->DeleteAllItem(); $this->{"ChooseY1ListBox"}->DeleteAllItem(); $this->{"ChooseY2ListBox"}->DeleteAllItem(); for(my $i = 0 ; $i < $nDataArray ; $i++) { #print "$i: $pLabelArray->[$i]\n"; $this->{"ChooseXListBox"}->AddItem($pLabelArray->[$i]); $this->{"ChooseY1ListBox"}->AddItem($pLabelArray->[$i]); $this->{"ChooseY2ListBox"}->AddItem($pLabelArray->[$i]); } $this->{"ChooseXListBox"}->SetCurSel('.*E.*', '.*eV.*'); $this->{"ChooseY1ListBox"}->SetCurSel('e1', 'n', 'Psi'); $this->{"ChooseY2ListBox"}->SetCurSel('e2', 'k', 'Delta'); $this->CreateGraphFrame(); $this->AssignGraphData(); return $filepath; } sub ReadSubstrateDataFile { my ($this, $filepath, $IsPrint) = @_; my $App = $this->App(); #print "type=$type\n"; $this->{Layers} = undef; $this->{Optimize} = undef; $this->{Substrate} = new Ellipsometry; $this->{SubstratePath} = $filepath; my ($nData, $pLabelArray, @pDataArray) = $this->{Substrate}->Read($filepath); if(!defined $nData) { $App->print("Error: Can not read [$filepath].\n"); return $this->{SubstratePath} = undef; } # $this->CreateGraphFrame(); # $this->AssignGraphData(); return $filepath; } 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 $FileType = $this->FileType(); # return undef unless($FileType); # my $pDataArray = $this->DataArray(); # return unless($pDataArray); my $GraphFrameArray = $this->{'GraphFrameArray'} = new GraphFrameArray($this->mw()); $GraphFrameArray->SetCanvasSize($w, $h); $GraphFrameArray->AddGraphFrame(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); my $FramePosStr0 = $App->{"GraphFrame0Position"}; my $XScale0 = $GraphFrame0->GetXScale(0); my $YScale0 = $GraphFrame0->GetYScale(0); $GraphFrame0->SetPositionByStr($FramePosStr0); $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 $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); $GraphFrame0->ClearAllData(); my $XLabel = $this->{"ChooseXListBox"}->GetText(); $XLabel = 'X' if(!$XLabel); my $Y1Label = $this->{"ChooseY1ListBox"}->GetText(); $Y1Label = 'Y1' if(!$Y1Label); my $Y2Label = $this->{"ChooseY2ListBox"}->GetText(); $Y2Label = 'Y2' if(!$Y2Label); $GraphFrame0->SetXCaption($XLabel); $GraphFrame0->SetYCaption("$Y1Label,$Y2Label"); my $pX = $this->{Ellipsometry}->GetData($XLabel, '.*E.*', '.*eV.*'); my $pY1 = $this->{Ellipsometry}->GetData($Y1Label); my $pY2 = $this->{Ellipsometry}->GetData($Y2Label); my $nData = $this->{Ellipsometry}->nData(); if($pX) { $GraphFrame0->AddGraphData($pX, $pY1, 2, "black", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "${Y1Label}(obs)") if($pY1); $GraphFrame0->AddGraphData($pX, $pY2, 2, "red", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "${Y2Label}(obs)") if($pY2); } my $pCalE = $this->{pEArray}; my $pCalY1 = $this->{"p${Y1Label}Array"}; my $pCalY2 = $this->{"p${Y2Label}Array"}; if($pCalE) { $GraphFrame0->AddGraphData($pCalE, $pCalY1, 0, "black", "circle", 3, "", 1, "black", "XAutoSkip", "Energy", "${Y1Label}(cal)") if($pCalY1); # 1, "black", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "${Y1Label}(cal)") if($pCalY1); $GraphFrame0->AddGraphData($pCalE, $pCalY2, 0, "red", "circle", 3, "", 1, "red", "XAutoSkip", "Energy", "${Y2Label}(cal)") if($pCalY2); # 1, "red", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "${Y2Label}(cal)") if($pCalY2); } $GraphFrame0->SetYScalePlotType('x'); if($ResetViewRange) { $GraphFrame0->CalMinMax(); $GraphFrame0->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } sub AdjustViewRange { my ($this) = @_; my $GraphFrameArray = $this->GetGraphFrameArray(); my $pGraphFrame = $GraphFrameArray->GetpGraphFrameArray(); my $FileType = $this->FileType(); if($FileType =~ /(Ids)/i) { } } sub SelChangeListBox { my ($this, $type, $lb) = @_; #print "this:$this lb=$lb\n"; my $s = $lb->GetText(); if($type eq 'LayerModel') { if($s eq "C12A7:e-(sub)") { # $this->{SurfaceThicknessButton}->SetText("Surface thickness:"); } elsif($s eq "C12A7/C12A7:e-(sub)") { # $this->{SurfaceThicknessButton}->SetText("Interface thickness:"); } else { } } $this->CreateGraphFrame(); $this->AssignGraphData(); $this->Draw(); } sub InitializeParameters { my ($this, $ini, $dini) = @_; $this->AddParameters($ini, $dini, "Scale", 1.0, 0, 0.1, 0.0, ''); $this->AddParameters($ini, $dini, "RScale", 1.0, 0, 0.1, 0.0, ''); $this->AddParameters($ini, $dini, "Rayleighl0", 0.0, 0, 1000.0, 0.0, ''); $this->AddParameters($ini, $dini, "SurfaceThickness", 0.0, 0, 1.0e-9, 0.0, ''); $this->AddParameters($ini, $dini, "SurfaceVf", 1.0, 0, 0.1, 0.0, 1.0); $this->AddParameters($ini, $dini, "FilmThickness", 100.0, 0, 100.0e-9, 0.0, ''); $this->AddParameters($ini, $dini, "SubstrateThickness", 0.5, 0, 0.1e-3, 0.0, ''); $this->AddParameters($ini, $dini, "SurfaceEps1", 4.0, 0, 0.1, 0.0, ''); $this->AddParameters($ini, $dini, "SurfaceEps2", 0.0, 0, 0.001, 0.0, ''); $this->AddParameters($ini, $dini, "e1inf", 2.25, 1, 0.2, '', ''); $this->AddParameters($ini, $dini, "e2inf", 0.0, 0, 0.2, 0.0, ''); $this->AddParameters($ini, $dini, "Caucy2", 0.0, 0, 1000.0, '', ''); $this->AddParameters($ini, $dini, "Caucy4", 0.0, 0, 1000.0, '', ''); $this->AddParameters($ini, $dini, "A", 0.0, 0, 0.5, 0.0, ''); $this->AddParameters($ini, $dini, "C", 5.0, 0, 0.5, 0.0, ''); $this->AddParameters($ini, $dini, "Eg", 3.0, 0, 0.1, 0.0, ''); $this->AddParameters($ini, $dini, "En0", 15.0, 0, 0.1, 0.0, ''); for(my $i = 1 ; $i <= $this->{nLorentz} ; $i++) { $this->AddParameters($ini, $dini, "E0$i", 2.6, 0, 0.1, 0.0, ''); $this->AddParameters($ini, $dini, "Ne$i", 0.0, 0, 1.0e26, 0.0, ''); $this->AddParameters($ini, $dini, "G$i", 0.4, 0, 0.1, 0.0, ''); } for(my $i = 1 ; $i <= $this->{nDrude} ; $i++) { $this->AddParameters($ini, $dini, "DrudeEp$i", 0.0, 0, 0.1, 0.0, ''); $this->AddParameters($ini, $dini, "Drudetau$i", 1.0e-14, 0, 1.0e-15, 0.0, ''); } } sub ReadArgs { my ($this) = @_; my $App = $this->App(); $App->AddArgument("--nFilmLayers", "--nFilmLayers=[>=1]: Specify number of film layers", 2); $App->AddArgument("--nLorentz", "--nLorentz=[>=0] : Specify number of Lorentz functions", 3); $App->AddArgument("--nDrude", "--nDrude=[>=0] : Specify number of Drude functions", 1); $this->SUPER::ReadArgs(); } 1;