#=============================================== # TkEllipsometryBulkC12A7 #=============================================== package TkEllipsometryBulkC12A7; use clib::TkEllipsometry; @ISA = qw(TkEllipsometry); #公開したいサブルーチン #@EXPORT = qw(DelSpace Reduce01 MakePath RegExpQuote); use strict; sub CreateWidgets { my ($this, $DoSuperOnly) = @_; $DoSuperOnly = 0 if(!defined $DoSuperOnly); $this->{ini} = new IniFile(undef, 0, 0); $this->{dini} = new IniFile(undef, 0, 0); $this->{Ellipsometry} = new Ellipsometry; $this->{nLorentz} = 5 if(!defined $this->{nLorentz}); $this->{nDrude} = 1 if(!defined $this->{nDrude}); $this->SUPER::CreateWidgets(0); return if($DoSuperOnly); $this->mw()->SetTitle("EllipsometryFit2007 for C12A7/C12A7:e-(sub) / TkPlot"); } 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"}, ); } for(my $i = 0 ; $i < $this->{nDrude} ; $i++) { my $i1 = $i + 1; $C12A7e->AddDielectricModel( "Drude$i1", "Drude", "Ep", $ini->{"DrudeEp$i1"}, "tau", $ini->{"Drudetau$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; } } my $LayerModel = $this->{ChooseLayerModelListBox}->GetText(); my $iSubstrate = 1; $Layers->AddLayer($Air, -1.0, 0.0); if($LayerModel eq "C12A7/C12A7:e-(sub)") { $iSubstrate++; $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(); if($LayerModel eq "C12A7/C12A7:e-(sub)") { $optimize->AddParameters( "FilmThickness", $Layers->pLayerThickness(1), $dini->{FilmThicknesscheck}, $dini->{FilmThicknessscale}, $dini->{FilmThicknessmin}, $dini->{FilmThicknessmax}, sub { $Layers->SetLayerThickness(1, $_[0]); $ini->{FilmThickness} = $_[0]*1.0e9; }, ); } $optimize->AddParameters( "C12A7e-e1", $Layers->pVariable($iSubstrate, 'Constant1::e1inf'), $dini->{e1infcheck}, $dini->{e1infscale}, $dini->{e1infmin}, $dini->{e1infmax}, sub { $Layers->SetVariable($iSubstrate, 'Constant1::e1inf', $_[0]); $ini->{e1inf} = $_[0]; }, "C12A7e-e2", $Layers->pVariable($iSubstrate, 'Constant1::e2inf'), $dini->{e2infcheck}, $dini->{e2infscale}, $dini->{e2infmin}, $dini->{e2infmax}, sub { $Layers->SetVariable($iSubstrate, 'Constant1::e2inf', $_[0]); $ini->{e2inf} = $_[0]; }, "C12A7e-TLA", $Layers->pVariable($iSubstrate, 'TaucLorentz1::A'), $dini->{Acheck}, $dini->{Ascale}, $dini->{Amin}, $dini->{Amax}, sub { $Layers->SetVariable($iSubstrate, 'TaucLorentz1::A', $_[0]); $ini->{A} = $_[0]; }, "C12A7e-TLC", $Layers->pVariable($iSubstrate, 'TaucLorentz1::C'), $dini->{Ccheck}, $dini->{Cscale}, $dini->{Cmin}, $dini->{Cmax}, sub { $Layers->SetVariable($iSubstrate, 'TaucLorentz1::C', $_[0]); $ini->{C} = $_[0]; }, "C12A7e-TLEg", $Layers->pVariable($iSubstrate, 'TaucLorentz1::Eg'), $dini->{Egcheck}, $dini->{Egscale}, $dini->{Egmin}, $dini->{Egmax}, sub { $Layers->SetVariable($iSubstrate, 'TaucLorentz1::Eg', $_[0]); $ini->{Eg} = $_[0]; }, "C12A7e-TLEn0", $Layers->pVariable($iSubstrate, 'TaucLorentz1::En0'), $dini->{En0check}, $dini->{En0scale}, $dini->{En0min}, $dini->{En0max}, sub { $Layers->SetVariable($iSubstrate, '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($iSubstrate, "Lorentz${i1}::E0"), $dini->{"E0${i1}check"}, $dini->{"E0${i1}scale"}, $dini->{"E0${i1}min"}, $dini->{"E0${i1}max"}, sub { $Layers->SetVariable($iSubstrate, "Lorentz${i1}::E0", $_[0]); $ini->{"E0${i1}"} = $_[0]; }, "C12A7e-L${i1}Ne", $Layers->pVariable($iSubstrate, "Lorentz${i1}::Ne"), $dini->{"Ne${i1}check"}, $dini->{"Ne${i1}scale"}, $dini->{"Ne${i1}min"}, $dini->{"Ne${i1}max"}, sub { $Layers->SetVariable($iSubstrate, "Lorentz${i1}::Ne", $_[0]); $ini->{"Ne${i1}"} = $_[0]; $ini->{"A${i1}"} = $optics->CalLorentzAfromNe($ini->{"Ne${i1}"}, 1.0); }, "C12A7e-L${i1}G", $Layers->pVariable($iSubstrate, "Lorentz${i1}::G"), $dini->{"G${i1}check"}, $dini->{"G${i1}scale"}, $dini->{"G${i1}min"}, $dini->{"G${i1}max"}, sub { $Layers->SetVariable($iSubstrate, "Lorentz${i1}::G", $_[0]); $ini->{"G${i1}"} = $_[0]; }, ); } for(my $i = 0 ; $i < $this->{nDrude} ; $i++) { my $i1 = $i + 1; $optimize->AddParameters( "D${i1}Ep", $Layers->pVariable($iSubstrate, "Drude${i1}::Ep"), $dini->{"DrudeEp${i1}check"}, $dini->{"DrudeEp${i1}scale"}, $dini->{"DrudeEp${i1}min"}, $dini->{"DrudeEp${i1}max"}, sub { $Layers->SetVariable($iSubstrate, "Drude${i1}::Ep", $_[0]); $ini->{"DrudeEp${i1}"} = $_[0]; }, "D${i1}tau", $Layers->pVariable($iSubstrate, "Drude${i1}::tau"), $dini->{"Drudetau${i1}check"}, $dini->{"Drudetau${i1}scale"}, $dini->{"Drudetau${i1}min"}, $dini->{"Drudetau${i1}max"}, sub { $Layers->SetVariable($iSubstrate, "Drude${i1}::tau", $_[0]); $ini->{"Drudetau${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); # $this->{nS2} = 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); } 1;