Files
musrsim/trimsp/src/TrimSPGUI4/TrimSPGUI4.pm

1057 lines
32 KiB
Perl

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 = <INF>;
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 <http://www.gnu.org/licenses/>.
Copyright 2009-2013 by Zaher Salman.
<zaher.salman\@psi.ch>
";
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;