package TrimSPGUI4; use strict; use warnings; use QtCore4; use QtGui4; use QtCore4::isa qw( Qt::MainWindow ); # This is redundant #use QtCore4::isa qw( Qt::Widget ); use QtCore4::debug qw(ambiguous); use QtCore4::slots test => [], ToggleScanSingle => [], findDensity => [], PrepLayers => [], ProjSmartDefaults => [], helpAboutAction => [], helpContentsAction => [], CollectValues => [], CreateInpFile => [], GUIPath => [], TrimBin => [], StartSequenceOne => [], DirectoryBrowse => [], ConfirmQuit => [], PlotProfiles => [], PlotFraction => [], PlotMean => [], OpenFile => [], SaveFile => [], SaveFileAs => []; use Ui_TrimSPGUI4; sub NEW { my ( $class, $parent ) = @_; $class->SUPER::NEW($parent); this->{ui} = Ui_TrimSPGUI4->setupUi(this); } # Function: return widget attribute given its type and name sub child { # Take type and name from input my ( $object, $name ) = @_; my $Attrib = this->findChildren($object,$name); if (@$Attrib) { $Attrib = @$Attrib[0]; } else { $Attrib = 0; } # print "name = $name and attrib = $Attrib\n"; # Return handle on widget return($Attrib); } # Function: Returns a hash with all the values collected from the GUI. sub CollectValues { my %All=(); $All{"numLayer"}= this->{ui}->numLayer->value(); # Collect layers parameters for (my $i=1;$i<=$All{"numLayer"};$i++) { my $LComp = "L".$i."Comp"; my $Lrho="L".$i."rho"; my $Ld="L".$i."d"; $All{"$LComp"}=this->{ui}->layerTable->item($i-1,0)->text(); $All{"$Lrho"}=this->{ui}->layerTable->item($i-1,1)->text(); $All{"$Ld"}=this->{ui}->layerTable->item($i-1,2)->text(); } # Collect projectile parameters $All{"projComboBox"}=this->{ui}->projComboBox->currentIndex(); $All{"numberProj"}=this->{ui}->numberProj->text(); if ($All{"numberProj"}==0) { $All{"numberProj"}=10000; this->{ui}->numberProj->setText("10000"); } $All{"z0"}=this->{ui}->z0->text(); $All{"dz"}=this->{ui}->dz->text(); $All{"valEnergy"}=this->{ui}->valEnergy->text(); $All{"sigEnergy"}=this->{ui}->sigEnergy->text(); $All{"valAngle"}=this->{ui}->valAngle->text(); $All{"sigAngle"}=this->{ui}->sigAngle->text(); $All{"ranSeed"}=this->{ui}->ranSeed->text(); # Format projectile parameters $All{"numberProj"}=sprintf("%8d",$All{"numberProj"}); $All{"z0"}=sprintf("%6.2f",$All{"z0"}); $All{"dz"}=sprintf("%6.2f",$All{"dz"}); $All{"valEnergy"}=sprintf("%11.2f",$All{"valEnergy"}); $All{"sigEnergy"}=sprintf("%8.2f",$All{"sigEnergy"}); $All{"valAngle"}=sprintf("%8.2f",$All{"valAngle"}); $All{"sigAngle"}=sprintf("%8.2f",$All{"sigAngle"}); $All{"ranSeed"}=sprintf("%6.0f.",$All{"ranSeed"}); # Collect the additional parameters $All{"parEF"}=this->{ui}->parEF->text(); $All{"parESB"}=this->{ui}->parESB->text(); $All{"parSHEATH"}=this->{ui}->parSHEATH->text(); $All{"parERC"}=this->{ui}->parERC->text(); $All{"parRD"}=this->{ui}->parRD->text(); $All{"parCA"}=this->{ui}->parCA->text(); $All{"parKK0"}=this->{ui}->parKK0->text(); $All{"parKK0R"}=this->{ui}->parKK0R->text(); $All{"parKDEE1"}=this->{ui}->parKDEE1->text(); $All{"parKDEE2"}=this->{ui}->parKDEE2->text(); $All{"parIPOT"}=this->{ui}->parIPOT->text(); $All{"parIPOTR"}=this->{ui}->parIPOTR->text(); $All{"parIRL"}=this->{ui}->parIRL->text(); # format additional parameters $All{"parEF"}=sprintf("%8.2f",$All{"parEF"}); $All{"parESB"}=sprintf("%8.2f",$All{"parESB"}); $All{"parSHEATH"}=sprintf("%8.2f",$All{"parSHEATH"}); $All{"parERC"}=sprintf("%8.2f",$All{"parERC"}); $All{"parRD"}=sprintf("%5.0f.",$All{"parRD"}); $All{"parCA"}=sprintf("%6.2f",$All{"parCA"}); $All{"parKK0"}=sprintf("%3d",$All{"parKK0"}); $All{"parKK0R"}=sprintf("%3d",$All{"parKK0R"}); $All{"parKDEE1"}=sprintf("%3d",$All{"parKDEE1"}); $All{"parKDEE2"}=sprintf("%3d",$All{"parKDEE2"}); $All{"parIPOT"}=sprintf("%3d",$All{"parIPOT"}); $All{"parIPOTR"}=sprintf("%3d",$All{"parIPOTR"}); $All{"parIRL"}=sprintf("%2d",$All{"parIRL"}); # Filenames etc. The filename should not have white spaces $All{"fileNamePrefix"}=this->{ui}->fileNamePrefix->text(); $All{"fileNamePrefix"}=~ s/\s+//g; $All{"workPath"}=this->{ui}->workPath->text(); # Scan parameters only if selected $All{"scanSeq"}=this->{ui}->scanSeq->isChecked(); $All{"comboScan"}=this->{ui}->comboScan->currentIndex(); $All{"scandL"}=this->{ui}->scandL->value(); $All{"radioList"}=this->{ui}->radioList->isChecked(); $All{"radioLoop"}=this->{ui}->radioLoop->isChecked(); $All{"scanList"}=this->{ui}->scanList->text(); # Remove any white spaces $All{"scanList"} =~ s/\s+//g; $All{"scanListdz"}=this->{ui}->scanListdz->text(); # Remove any white spaces $All{"scanListdz"} =~ s/\s+//g; # These should be numeric $All{"scanFrom"}=this->{ui}->scanFrom->text(); $All{"scanTo"}=this->{ui}->scanTo->text(); $All{"scanStep"}=this->{ui}->scanStep->text(); $All{"scanFrom"}=1*$All{"scanFrom"}; $All{"scanTo"}=1*$All{"scanTo"}; $All{"scanStep"}=1*$All{"scanStep"}; # Return values to caller return(\%All); } # Subroutine: Toggle between scan/single run mode and setup scans tab sub ToggleScanSingle { # First collect some information my %All=(); $All{"scanSeq"}=this->{ui}->scanSeq->isChecked(); $All{"comboScan"}=this->{ui}->comboScan->currentIndex(); $All{"numLayer"}=this->{ui}->numLayer->text(); # Set numLayer as a maximum value for scandL this->{ui}->scandL->setMaximum($All{"numLayer"}); $All{"scandL"}=this->{ui}->scandL->text(); $All{"radioList"}=this->{ui}->radioList->isChecked(); $All{"radioLoop"}=this->{ui}->radioLoop->isChecked(); # Enable everything this->{ui}->valEnergy->setDisabled(0); this->{ui}->sigEnergy->setDisabled(0); this->{ui}->valAngle->setDisabled(0); this->{ui}->sigAngle->setDisabled(0); this->{ui}->numberProj->setDisabled(0); this->{ui}->scandL->setHidden(1); if ($All{"comboScan"}==5) { this->{ui}->scandL->setHidden(0); this->{ui}->scandL->setDisabled(0); } # Enable depth increment for Energy scan if ($All{"radioList"}) { this->{ui}->scanList->setDisabled(0); this->{ui}->scanFrom->setDisabled(1); this->{ui}->scanTo->setDisabled(1); this->{ui}->scanStep->setDisabled(1); if ($All{"comboScan"}==0) { this->{ui}->dzListLabel->setHidden(0); this->{ui}->scanListdz->setHidden(0); this->{ui}->dzListLabel->setDisabled(0); this->{ui}->scanListdz->setDisabled(0); this->{ui}->dzListLabel->setText("Corresponding depth increment (optional)"); # Enable energy change sigma angle scans } elsif ($All{"comboScan"}==3) { this->{ui}->dzListLabel->setHidden(0); this->{ui}->scanListdz->setHidden(0); this->{ui}->dzListLabel->setDisabled(0); this->{ui}->scanListdz->setDisabled(0); this->{ui}->dzListLabel->setText("Corresponding energy"); } else { # Otherwise keep it hidden this->{ui}->dzListLabel->setHidden(1); this->{ui}->scanListdz->setHidden(1); this->{ui}->dzListLabel->setDisabled(1); this->{ui}->scanListdz->setDisabled(1); } } elsif ($All{"radioLoop"}) { this->{ui}->scanList->setDisabled(1); this->{ui}->scanFrom->setDisabled(0); this->{ui}->scanTo->setDisabled(0); this->{ui}->scanStep->setDisabled(0); this->{ui}->dzListLabel->setHidden(1); this->{ui}->scanListdz->setHidden(1); this->{ui}->dzListLabel->setDisabled(1); this->{ui}->scanListdz->setDisabled(1); } # Start by enabling everything on the first tab this->{ui}->valEnergy->setDisabled(0); this->{ui}->sigEnergy->setDisabled(0); this->{ui}->valAngle->setDisabled(0); this->{ui}->sigAngle->setDisabled(0); this->{ui}->numberProj->setDisabled(0); # Also layer thicknesses for (my $i=1;$i<=$All{"numLayer"};$i++) { my $LayerThickAttrib = this->{ui}->layerTable->item($i-1,2); # $LayerThickAttrib->setDisabled(1); } if ($All{"scanSeq"}) { # Change title of tab to say enabled this->{ui}->tabs->setTabText(2,"Scans (Enabled)"); # If scanning layer thickness make sure it is actually defined if ($All{"scandL"} > $All{"numLayer"}) { Qt::MessageBox::warning(this, "Warning!","Define layers first!"); } # Disable the appropriate box in the first tab. if ($All{"comboScan"}==0) { this->{ui}->valEnergy->setDisabled(1); } elsif ($All{"comboScan"}==1) { this->{ui}->sigEnergy->setDisabled(1); } elsif ($All{"comboScan"}==2) { this->{ui}->valAngle->setDisabled(1); } elsif ($All{"comboScan"}==3) { this->{ui}->sigAngle->setDisabled(1); } elsif ($All{"comboScan"}==4) { this->{ui}->numberProj->setDisabled(1); } elsif($All{"comboScan"}==5) { my $LayerThickAttrib = this->{ui}->layerTable->item($All{"scandL"}-1,2); # $LayerThickAttrib->setDisabled(1); } } else { # Otherwise the title of the tab says disabled this->{ui}->tabs->setTabText(2,"Scans (Disabled)"); } } # Subroutine: Add/remove layers in the table as required sub PrepLayers { my %All=(); # Get number of layers to define $All{"numLayer"}=this->{ui}->numLayer->value(); # Set appropriate number of rows this->{ui}->layerTable->setRowCount($All{"numLayer"}); # Insert item if it does not exist (needed only for automatic density # update) my $cell = this->{ui}->layerTable->item($All{"numLayer"}-1,1); if (!$cell) { $cell = Qt::TableWidgetItem(); this->{ui}->layerTable->setItem($All{"numLayer"}-1,1,$cell); } } # Subroutine: Set sane default values for projectile energy # distribution and angles sub ProjSmartDefaults { my %All=(); # Get typeof projectile $All{"projComboBox"}=this->{ui}->projComboBox->currentIndex(); if ($All{"projComboBox"}==0) { # For a muon set Sigma E=450 eV and Sigman angle=15 degrees by default this->{ui}->sigEnergy->setText("450"); this->{ui}->sigAngle->setText("15"); } else { # For Li8 (or ions) set Sigma E=0 eV and Sigam angle=0 degrees by default this->{ui}->sigEnergy->setText("0"); this->{ui}->sigAngle->setText("0"); } } # Function: Create and return input file for the Trim.SP simulation # binary sub CreateInpFile { use Chem; # The proper way I think is not to have scan sequences implimented # here but rather call this multiple times to generate the scan To # resolve this, the function CreateInpFile will expect a unique # thickness for each layer, one energy value, one energy sigma and one # projectile number. These will be stored in keys L1/2/3/4/5/6/7d, E, # SigE and NProj, respectively. # Chemical formulas will be parsed on the fly for each layer. However, # we will check if all the layers have inputs for composition, # thickness and density. If not fail and crash :) # Values of Z,A as well as other needed parameters are obtained from # Chem.pm. # This is the form of the begining of the input file: my $TemplateFile= " ProjZ ProjAM valEnergy sigEnergy valAngle sigAngle parEF parESB parSHEATH parERC numberProj ranSeed ranSeed ranSeed z0 parRD dz parCA parKK0 parKK0R parKDEE1 parKDEE2 parIPOT parIPOTR parIRL"; # Then comes the number of layers (new format) for example 4 layers: # N_Layers=4 $TemplateFile=$TemplateFile."\n"."N_Layers=numLayer"."\n"; # Then loop over the layers and for each give the following structure my $TemplateLayer= "L1d L1rho L1CK L1ELZ1 L1ELZ2 L1ELZ3 L1ELZ4 L1ELZ5 L1ELW1 L1ELW2 L1ELW3 L1ELW4 L1ELW5 L1ELC1 L1ELC2 L1ELC3 L1ELC4 L1ELC5 L1ELE1 L1ELE2 L1ELE3 L1ELE4 L1ELE5 L10301 L10302 L10303 L10304 L10305 0.0000 0.0000 0.0000 0.0000 0.0000 L1ELST11 L1ELST21 L1ELST31 L1ELST41 L1ELST51 L1ELST12 L1ELST22 L1ELST32 L1ELST42 L1ELST52 L1ELST13 L1ELST23 L1ELST33 L1ELST43 L1ELST53 L1ELST14 L1ELST24 L1ELST34 L1ELST44 L1ELST54 L1ELST15 L1ELST25 L1ELST35 L1ELST45 L1ELST55 "; # Get values from form my %All = %{CollectValues()}; my $projectile=this->{ui}->projComboBox->currentText(); $All{"ProjZ"}=sprintf("%6.2f",Chem::Zof($projectile)); $All{"ProjAM"}=sprintf("%6.2f",Chem::Massof($projectile)); # This is the flag for checking layers my $Check=0; my $Layer=""; my $Li=""; # Loop over layers an create appropriate values for (my $i=1;$i<=$All{"numLayer"};$i++){ $Li = "L".$i; $Layer = $TemplateLayer; $Layer =~ s/L1/$Li/g; $TemplateFile=$TemplateFile.$Layer; $Check=0; # Composition of layers my $LComp="L".$i."Comp"; my $Comp = this->{ui}->layerTable->item($i-1,0)->text(); $All{$LComp} = $Comp; my %LElComp=Chem::parse_formula($Comp); foreach my $key (keys %LElComp) { if ($key eq "") { $Check++; } } if ($Comp eq "") {$Check++;} # Write composition to results file header # Densities of layers my $Lrho="L".$i."rho"; my $rho = this->{ui}->layerTable->item($i-1,1)->text(); $All{$Lrho}=sprintf("%6.2f",$rho); if ($rho eq "") {$Check++;} # Thickness of layers my $Ld ="L".$i."d"; my $d = this->{ui}->layerTable->item($i-1,2)->text(); $All{$Ld}=sprintf("%8.2f",$d); if ($d eq "") {$Check++;} # Sanity check, is the layer supposed to have value? are they all there? if ($Check!=0) { my $ErrMsg="Error: Layer $i is empty or bad chemical formula.\nPleach check!\n"; print STDERR $ErrMsg; my $HelpWindow = Qt::MessageBox::information( this, "Error!",$ErrMsg); return("ERROR"); } my $tmp = "L".$i."CK"; $All{$tmp}=sprintf("%6.2f",1.0); my $Sum = 0; foreach (keys %LElComp) { $Sum=$Sum+$LElComp{$_}; } if ($Sum==0) {$Sum=1;} my @Els = keys %LElComp; for (my $NEl=1;$NEl<=5;$NEl++) { my $El = ""; if ($#Els >= $NEl-1) { $El = $Els[$NEl-1]; } my $LEkey = "L".$i."EL"; my $ElZ = Chem::Zof($El); my $ElW = Chem::Massof($El); my $ElE = Chem::Elastof($El); my $ElC = 0; my $El030 = 30; if ($El) { $ElC = $LElComp{$El}/$Sum; } else { $El030 = 0.0; } $All{$LEkey."Z".$NEl}=sprintf("%8.4f",$ElZ); $All{$LEkey."W".$NEl}=sprintf("%8.4f",$ElW); $All{$LEkey."C".$NEl}=sprintf("%8.4f",$ElC); $All{$LEkey."E".$NEl}=sprintf("%8.4f",$ElE); $All{"L".$i."030".$NEl}=sprintf("%8.4f",$El030); my $ElST = Chem::Stopicru($El); my @ElSTs = split (/,/,$ElST); my $j=1; foreach (@ElSTs) { $LEkey = "L".$i."ELST".$NEl.$j; $j++; $All{$LEkey}=sprintf("%11.6f",$_); } } } foreach my $key (keys %All) { if ($All{$key} ne ""){ $TemplateFile =~ s/$key/$All{$key}/; # Seed repeats three times if ($key eq "ranSeed") { $TemplateFile =~ s/$key/$All{$key}/g;} } } return($TemplateFile); } # This subroutine is used to define diffirent variables sub TrimBin { my $file=Qt::FileDialog::getOpenFileName( this, "Select the Trim.SP binary file", $ENV{'TRIMBIN'}, "Trim.SP binary (.* *.* *)"); # If the user gave a valid filename try to read it if ($file eq "") { $file=$ENV{'TRIMBIN'}; } else { $ENV{'TRIMBIN'}=$file; } this->{ui}->trimbin->setText($file); return($file); } # This subroutine is used to define diffirent variables sub GUIPath { my $FileBrowser = Qt::FileDialog::getExistingDirectory( this, "Chose the directory where the TrimSP GUI is.", $ENV{'PERLLIB'}, 1); # If nothing is returned keep as is if ($FileBrowser eq "") { $FileBrowser=$ENV{'PERLLIB'}; } else { $ENV{'PERLLIB'}=$FileBrowser; } this->{ui}->pathTrimGUI->setText($FileBrowser); # Return a string with the directory name return($FileBrowser); } # Subroutine: Start the simulation with the current parameters sub StartSequenceOne { my %All = %{CollectValues()}; my @SValues=(); my @SdzValues=(); my $cmd=""; my @called = caller; print "pck=".$called[0]." fln=".$called[1]." line=".$called[2]; if (!$ENV{'TRIMBIN'}) { # If trim.sp binary is not defined give warning and return my $Warning = Qt::MessageBox::information( this, "Warning!", "Warning:\n TrimSP binary is not found.\n Define using the Configuration tab."); return(0); } # Cleanup from old files if (-e "ausgabe1.inp") { system("rm -f ausgabe*"); } my $Progress=0; $All{"SdzFlag"}=0; if ($All{"scanSeq"}) { # For multiple runs or a scan if ($All{"radioList"}) { @SValues=split(/,/,$All{"scanList"}); @SdzValues=split(/,/,$All{"scanListdz"}); if ($#SValues == $#SdzValues) {$All{"SdzFlag"}=1;} } elsif ($All{"radioLoop"}) { for (my $Val=$All{"scanFrom"};$Val<=$All{"scanTo"};$Val=$Val+$All{"scanStep"}) { @SValues=(@SValues,$Val); } } my $ScanName = ""; my $ScanAttrib = ""; if ($All{"comboScan"}==0) { $ScanName = "E"; $ScanAttrib = child("Qt::LineEdit","valEnergy"); } elsif ($All{"comboScan"}==1) { $ScanName = "SigE"; $ScanAttrib = child("Qt::LineEdit","sigEnergy"); } elsif ($All{"comboScan"}==2) { $ScanName = "Angle"; $ScanAttrib = child("Qt::LineEdit","valAngle"); } elsif ($All{"comboScan"}==3) { $ScanName = "SigAngle"; $ScanAttrib = child("Qt::LineEdit","sigAngle"); } elsif ($All{"comboScan"}==4) { $ScanName = "N"; $ScanAttrib = child("Qt::LineEdit","numberProj"); } elsif ($All{"comboScan"}==5) { $ScanName = "Ld".$All{"scandL"}; $ScanAttrib = this->{ui}->layerTable->item($All{"scandL"}-1,2); } my $iScan=0; foreach (@SValues) { $ScanAttrib->setText($_); if ( $All{"SdzFlag"} == 1) { if ($All{"comboScan"}==0) { this->{ui}->dz->setText($SdzValues[$iScan]); } elsif ($All{"comboScan"}==3) { this->valEnergy->setText($SdzValues[$iScan]); } } my $eingabe1=CreateInpFile(); if ($eingabe1 eq "ERROR") {return(0);} my $FILENAME=$All{"fileNamePrefix"}."_".$ScanName.$_; open (INPF,q{>}, "$FILENAME.inp" ); print INPF $eingabe1; close(INPF); # Use Linux version $Progress=$Progress+90/$#SValues; this->{ui}->progress->setValue($Progress); this->{ui}->progress->update(); $cmd = "cp $FILENAME.inp eingabe1.inp; ".$ENV{'TRIMBIN'}; my $pid = fork(); die "Unable to fork: $!" unless defined($pid); if (!$pid) { # child exec($cmd); die "Unable to exec: $!"; } while (wait () != -1){} #system($cmd); foreach ("err","out","rge") { system("mv -f ausgabe1.$_ $FILENAME.$_"); } $iScan++; print "iScan=".$iScan."\n"; } } else { # For a single run my $eingabe1=CreateInpFile(); if ($eingabe1 eq "ERROR") {return(0);} my $FILENAME=$All{"fileNamePrefix"}; open (INPF,q{>}, "$FILENAME.inp" ); print INPF $eingabe1; close(INPF); $Progress=20; this->{ui}->progress->setValue($Progress); this->{ui}->progress->update(); # Use Linux version $cmd = "cp $FILENAME.inp eingabe1.inp; ".$ENV{'TRIMBIN'}; my $pid = fork(); die "Unable to fork: $!" unless defined($pid); if (!$pid) { # child exec($cmd); die "Unable to exec: $!"; } while (wait () != -1){} #system($cmd); foreach ("err","out","rge") { system("mv -f ausgabe1.$_ $FILENAME.$_"); } $Progress=90; this->{ui}->progress->setValue($Progress); this->{ui}->progress->update(); sleep(10); } # Move the fort.33 file into the subdirectory and change its name $cmd="rm -f eingabe1.inp; mv -f fort.33 ".$All{"workPath"}."/".$All{"fileNamePrefix"}."_Seq_Results.dat"; system($cmd); $Progress=100; this->{ui}->progress->setValue($Progress); this->{ui}->progress->update(); undef %All; undef $cmd; # print "at end\n"; # sleep(10); return(0); } # Subroutine: Select or create work directory sub DirectoryBrowse { my $Path = this->{ui}->workPath->text(); my $FileBrowser = Qt::FileDialog::getExistingDirectory( this, "Choose a directory", $Path, 1); if ($FileBrowser ne "") { this->{ui}->workPath->setText($FileBrowser); } # Create a subdirectory where all input/output files are saved my $cmd=""; if (-d $FileBrowser) { # Directory exists, do nothing } else { $cmd="mkdir $FileBrowser"; system($cmd); } # Change work directory accordingly chdir ("$FileBrowser"); } # Subroutine: Quit dialog with confirmation sub ConfirmQuit { my $Ans = Qt::MessageBox::question( this, "Quit?","Are you sure you want to quit?","&Yes","&No","",0,1); if ($Ans==0) { # Then quit Qt::Application::exit( 0 ); } # Otherwize go back } # From here it is all menu actions # Subroutine: Open a configuration file sub OpenFile { # Types of different input my %Types = (); $Types{"numLayer"}="Qt::SpinBox"; $Types{"projComboBox"}="Qt::ComboBox"; $Types{"scanSeq"}="Qt::RadioButton"; $Types{"comboScan"}="Qt::ComboBox"; $Types{"scandL"}="Qt::SpinBox"; $Types{"radioList"}="Qt::RadioButton"; $Types{"scanListdz"}="Qt::LineEdit"; $Types{"radioLoop"}="Qt::RadioButton"; $Types{"scanSeq"}="Qt::GroupBox"; my $file=Qt::FileDialog::getOpenFileName( this, "Choose an initialization file", ".", "Initialization file (.* *.*)"); # If the user gave a valid filename try to read it if ($file ne "") { open (INF,q{<},"$file" ); my @lines = ; close(INF); # Remove comment lines, empty lines and lines starting with "[" @lines = grep {!/^\#/} @lines; @lines = grep {/\S/} @lines; @lines = grep {!/^\[/} @lines; @lines = grep {/\s+/} @lines; @lines = &ConvertCFG(@lines); my $Attrib=""; foreach my $line (@lines) { # Remove white spaces $line =~ s/\s+//g; my @InitPar = split (/=/,$line); # Check it is not empty or title line if ($InitPar[0] || $InitPar[1]) { if (!$Types{$InitPar[0]}) { # No type is found, probably table cell? $Types{$InitPar[0]}="Qt::LineEdit"; } # Get widget by name $Attrib = child($Types{$InitPar[0]},$InitPar[0]); # if the widget exists if ($Attrib){ if ($Types{$InitPar[0]} eq "Qt::SpinBox") { $Attrib->setValue($InitPar[1]); } elsif ($Types{$InitPar[0]} eq "Qt::RadioButton" || $Types{$InitPar[0]} eq "Qt::GroupBox") { if($InitPar[1]) { $Attrib->setChecked(1); } else { $Attrib->setChecked(0); } } elsif ($Types{$InitPar[0]} eq "Qt::ComboBox") { $Attrib->setCurrentIndex($InitPar[1]); } else { $Attrib->setText($InitPar[1]); } } else { # child not found probably table cell # Identify layers parameters and convert to row column my $col = $InitPar[0]; my $row = $InitPar[0]; # Flag takes 1 for table item and zero if not my $flag = 0; $col =~ s/\d//g; $row =~ s/[^0-9]//g; if ($col eq "LComp") { $col = 0; $flag = 1; } elsif ($col eq "Lrho") { $col = 1; $flag = 1; } elsif ($col eq "Ld") { $col = 2; $flag = 1; } if ($flag) { my $cell = this->{ui}->layerTable->item($row-1,$col); if (!$cell) { $cell = Qt::TableWidgetItem(); this->{ui}->layerTable->setItem($row-1,$col,$cell); } this->{ui}->layerTable->item($row-1,$col)->setText($InitPar[1]); } } } } } } # Subroutine: Create configuration file sub GenInitFile { my %All = %{CollectValues()}; my $InitFile=" [Layers] numLayer=$All{'numLayer'}"; for (my $i=1;$i<=$All{"numLayer"};$i++){ my $Li="L".$i; my $LComp=$Li."Comp"; my $Lrho=$Li."rho"; my $Ld=$Li."d"; $InitFile=$InitFile." $LComp=$All{$LComp} $Lrho=$All{$Lrho} $Ld=$All{$Ld} "; } $InitFile=$InitFile." [ProjectileParameters] projComboBox=$All{'projComboBox'} numberProj=$All{'numberProj'} z0=$All{'z0'} dz=$All{'dz'} valEnergy=$All{'valEnergy'} sigEnergy=$All{'sigEnergy'} valAngle=$All{'valAngle'} sigAngle=$All{'sigAngle'} ranSeed=$All{'ranSeed'} [Files] fileNamePrefix=$All{'fileNamePrefix'} workPath=$All{'workPath'} [ScanSequence] scanSeq=$All{'scanSeq'} comboScan=$All{'comboScan'} radioList=$All{'radioList'} scanList=$All{'scanList'} scanListdz=$All{'scanListdz'} radioLoop=$All{'radioLoop'} scanFrom=$All{'scanFrom'} scanTo=$All{'scanTo'} scanStep=$All{'scanStep'} "; return($InitFile); } # Subroutine: Save configuration file to TrimSP.cfg sub SaveFile { my $InitFile=GenInitFile(); # Save to default file name "TriumSP.cfg" my $file = "TrimSP.cfg"; open (OUTF,q{>},"$file" ); print OUTF $InitFile; close(OUTF); } # Subroutine: Save As configuration file sub SaveFileAs { my $InitFile=GenInitFile(); # Save to selected file name my $file=Qt::FileDialog::getSaveFileName( this, "Choose a filename to save", "TrimSP.cfg", "TrimSP GUI Initialization file (*.cfg)"); # If the user gave a filename then save to it if ($file ne "") { open (OUTF,q{>},"$file" ); print OUTF $InitFile; close(OUTF); } } # Subroutine: Convert old configuration file to new format sub ConvertCFG { # Get cleaned lines my @lines = @_; # Backward compatibility: NL to numLayer my %BackSubs = ("NL","numLayer", "NProj","numberProj", "E","valEnergy", "SigE","sigEnergy", "Angle","valAngle", "SigAngle","sigAngle", "Seed","ranSeed", "FNPre","fileNamePrefix", "Path","workPath", "ScanSeq","scanSeq", "ScanList","scanList", "ListRadio","radioList", "ScanListdz","scanListdz", "LoopRadio","radioLoop", "SFrom","scanFrom", "STo","scanTo", "SStep","scanStep" ); # Go over all elements of %BackSubs and substitute foreach my $key (keys %BackSubs) { @lines = map {s/^$key=/$BackSubs{$key}=/; $_;} @lines; } # deal with ProjType %BackSubs = ("ProjType=Muon","projComboBox=0", "ProjType=Li8","projComboBox=1", "ProjType=B12","projComboBox=2", "ProjType=H","projComboBox=3" ); # Go over all elements of %BackSubs and substitute foreach my $key (keys %BackSubs) { @lines = map {s/^$key/$BackSubs{$key}/; $_;} @lines; } # deal with scan radios %BackSubs = ("ERadio=1","comboScan=0", "SigERadio=1","comboScan=1", "AngleRadio=1","comboScan=2", "SigAngleRadio=1","comboScan=3", "NProjRadio=1","comboScan=4", ); # Go over all elements of %BackSubs and substitute foreach my $key (keys %BackSubs) { @lines = map {s/^$key/$BackSubs{$key}/; $_;} @lines; } return(@lines); } # Subroutine: Plot implantation profiles using root macro sub PlotProfiles { my $Path=this->{ui}->workPath->text(); my $files_ref=Qt::FileDialog::getOpenFileNames( this, "Select RGE files to plot", $Path, "RGE Files (*.rge)"); my @files_tmp = @$files_ref; # Do "natural" sorting on the file name list # This will produce (hopefully) a plot with largest needed depth scale my @files = grep {s/(^|\D)0+(\d)/$1$2/g,1} sort grep {s/(\d+)/sprintf"%06.6d",$1/ge,1} @files_tmp; # my @files = @files_tmp; my $filenames=join(",",@files); if ($filenames ne "" ) { my $TrimPath = $ENV{'PERLLIB'}; # Now that we have the file list send it to root macro for plotting. my $cmd='root -n -l "'.$TrimPath.'/../plotRge.C(\"'.$filenames.'\")"&'; my $pid = fork(); die "Unable to fork: $!" unless defined($pid); if (!$pid) { # child exec($cmd); die "Unable to exec: $!"; } # my $pid=system($cmd); } } # Subroutine: Plot implantation fractions in the different layers # using a root macro sub PlotFraction { my $Path=this->{ui}->workPath->text(); my $file=Qt::FileDialog::getOpenFileName( this, "Choose a sequence data file", $Path, "Implantation sequence file (*.dat)"); if ($file ne "" ) { my $TrimPath = $ENV{'PERLLIB'}; # Now that we have the file name send it to root macro for plotting. my $cmd='root -n -l "'.$TrimPath.'/../plotFrc.C(\"'.$file.'\")"&'; my $pid = fork(); die "Unable to fork: $!" unless defined($pid); if (!$pid) { # child exec($cmd); die "Unable to exec: $!"; } # my $pid=system($cmd); } } # Subroutine: Plot mean depth and straggeling using a root macro sub PlotMean { my $Path=this->{ui}->workPath->text(); my $file=Qt::FileDialog::getOpenFileName( this, "Choose a sequence data file", $Path, "Implantation sequence file (*.dat)"); if ($file ne "" ) { my $TrimPath = $ENV{'PERLLIB'}; # Now that we have the file name send it to root macro for plotting. my $cmd='root -n -l "'.$TrimPath.'/../plotMean.C(\"'.$file.'\")"&'; my $pid = fork(); die "Unable to fork: $!" unless defined($pid); if (!$pid) { # child exec($cmd); die "Unable to exec: $!"; } # my $pid=system($cmd); } } # Subroutine: Help window contents sub helpContentsAction { my $HelpText=" This is a GUI that uses the Trim.SP simulation binary to calculate the implantation profiles of implanted projectiles in a multilayer thin film structure. Usage: Initially define your multilayer structure in the 'Layers' tab. This can be formed of a maximum of 7 layers. Each layer is defined by giving its chemical formula, its density in units of g/cm^3, and its thickness in Ångström. Next, choose the type of projectile to be implanted in the structure from the drop-down menu. Set the 'Number of projectiles' to be implanted, were a higher number will give better statistics. Finally define the rest of the projectile parameters such as implantation energy, energy spread, etc. In the 'File names prefix' give a string which will be used to construct the input/output file names of the simulation. These files will be collected and saved in the subdirectory provided in 'Save in subdirectory' box. The 'Additional Parameters' tab allows you to change additional parameters in the simulation. Change these only if you know what you are doing, and have read the original documentation of the Trim.SP simulation. The 'Scans' tabs provides the ability to change the value of a certain parameter in the simulation, such as implantation energy, spread in energy, number of implanted projectiles, and the thickness of one layer. The values of this parameter can be changed by a regualr step size ('Loop' checkbox and parameters), or following a set of values ('List of values' checkbox and the comma separated values). In the second case, in addition to the scanned parameter, the user may be given an option to change another parameter. For example, when scanning through a list of energies, the user may give a corresponding depth increment for each energy value. Copyright 2009-2013 (C) by Zaher Salman. Last modified 29 Jan. 2013 "; my $HelpWindow = Qt::MessageBox::information( this, "TrimSP GUI Help Window",$HelpText); } # Subroutine: About window contents sub helpAboutAction { my $HelpText="TrimSPGUI is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. TrimSPGUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TrimSPGUI. If not, see . Copyright 2009-2013 by Zaher Salman. "; my $HelpWindow = Qt::MessageBox::about( this, "About TrimSP GUI",$HelpText); } # Subroutine: Find density of material from database sub findDensity { use Chem; # This is needed only for changes in the first column my $layerTable = this->{ui}->layerTable; my $col = $layerTable->currentColumn(); my $row = $layerTable->currentRow(); if ($col == 0) { # Get sender name to know which layer my $sender = $layerTable->currentItem(); # Get the compound formula my $Compound = $sender->text(); # See if you have the density my $Density=Chem::Densities($Compound); # If the density is in the database submit it if ($Density ne "" ) { $layerTable->item($row,$col+1)->setText($Density); } } } # Subroutine: keep for tests and debugging sub test { my $att = child("Qt::LineEdit","z0"); my $test2= $att->text(); my $test=this->{ui}->numberProj->text(); # print "numberProj=$test and z0=$test2\n"; } 1;