#=============================================== # Rietan #=============================================== package Rietan; use Exporter; @ISA = qw(Exporter); #公開したいサブルーチン @EXPORT = qw(); use strict; use File::Basename; use Cwd; use Math::Complex; use JFile; use Deps; use ProgVars; use GraphData; use Sci qw($pi $a0); use Sci::DiffractionPeakArray; use Crystal::SpaceGroup; my $DirectorySeparator = "\\"; my $SystemCharCode = "sjis"; #=============================================== # パス(読み込みDB) # Web関係変数 # CGI の仮想パス # プログラム名 #=============================================== my $HOME = $ENV{'HOME'}; my $WebRootDir = "d:\\MyWebs"; my $CGIPath = Deps::MakePath($WebRootDir, "cgi-bin", 1); #my $ProgramDir = "d:\\Programs"; my $RietanDir = ProgVars::RietanDir(); #Deps::MakePath($ProgramDir, "X線回折", 0); #$RietanDir = Deps::MakePath($RietanDir, "Rietan2000", 0); my $RietanProgramPath = Deps::MakePath($RietanDir, "Programs", 0); Jcode::convert(\$RietanProgramPath, $SystemCharCode) if($SystemCharCode); #my $RietanPath = Deps::MakePath($RietanProgramPath, "rietan.exe", 0); #my $RietanPath = Deps::MakePath($RietanProgramPath, "rietan20040701.exe", 0); my $RietanPath = Deps::MakePath($RietanProgramPath, "RIETAN_VENUS/rietan64.exe", 0); my $TeePath = Deps::MakePath($RietanProgramPath, "tee.exe", 0); my $DBDir = ProgVars::DBDir(); #my $DBDir = Deps::MakePath($WebRootDir, "Research", 0); # $DBDir = Deps::MakePath($DBDir, "Databases", 0); #Utils::InitHTML(); #print "

DBDir: $DBDir

\n"; my $CrystalDBDir = Deps::MakePath($WebRootDir, "Research", 0); $CrystalDBDir = Deps::MakePath($CrystalDBDir, "CrystalStructure", 0); my $CrystalRietanFileDir = Deps::MakePath($CrystalDBDir, "Rietan", 0); my $SpaceGroupDBPath = Deps::MakePath($DBDir, "SPGRA", 0); #my $SpaceGroupDBPath = Deps::MakePath($RietanProgramPath, "SPGRA", 0); # = Deps::MakePath($ProgramDir, "X線回折\\Rietan2000\\programs\\SPGRA", 0); my $ASFDCPath = Deps::MakePath($DBDir, "asfdc", 0); #print "

ASFDCPath $ASFDCPath

\n"; if($^O eq 'linux') { #unless(-d $RietanDir) { $RietanDir = "$HOME/rietan" ; $RietanProgramPath = "$HOME/rietan/bin"; $RietanPath = Deps::MakePath($RietanProgramPath, "rietan", 0); $TeePath = "tee"; $DBDir = $RietanProgramPath; $SpaceGroupDBPath = Deps::MakePath($RietanProgramPath, "spgra", 0); } #============================================================ # 変数等取得関数 #============================================================ sub ClearAll { my $this=shift; undef $this->{'FileType'}; undef $this->{'DataArray'}; undef $this->{'DiffractionPeakArray'}; } sub GetpDiffractionPeakArray { return shift->{'DiffractionPeakArray'}; } sub GetnDiffractionPeakArray { my $array = shift->GetpDiffractionPeakArray(); return scalar @$array; } sub FileType { return shift->{'FileType'}; } sub FileName { return shift->{'FileName'}; } sub SetFileName { my ($this,$f)=@_; return $this->{'FileName'} = $f; } sub DataArray { return shift->{'DataArray'}; } sub SetDataArray { my ($this, $DataArray) = @_; return $this->{'DataArray'} = $DataArray; } sub iLaueG { return shift->{'iLaueG'}; } sub iCenter { return shift->{'iCenter'}; } #============================================================ # コンストラクタ、デストラクタ #============================================================ sub new { my ($module) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ sub CheckFileType { my ($path) = @_; my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($path); #print "Path: $path\n"; if($ext =~ /^\.int$/i) { return "Rietan Intensity File"; } elsif($ext =~ /^\.ins$/i) { return "Rietan Input File"; } elsif($ext =~ /^\.lst$/i) { return "Rietan Output File"; } elsif($ext =~ /^\.asc$/i) { return "RINT2000 ASCIIFile"; } elsif($ext =~ /^\.txt$/i) { my $infile = new JFile; my $ret = $infile->Open($path, "r"); return undef unless($ret); my $line1 = $infile->ReadLine(); my $line2 = $infile->ReadLine(); my $line3 = $infile->ReadLine(); $infile->Close(); return "TOPAS Text File" if($line3 =~ /DIFFRAC/); return undef; } elsif($ext =~ /^\.pat$/i or $ext =~ /^\.itx$/i) { my $infile = new JFile; my $ret = $infile->Open($path, "r"); return undef unless($ret); my $line1 = $infile->ReadLine(); my $line2 = $infile->ReadLine(); my $line3 = $infile->ReadLine(); $infile->Close(); Utils::DelSpace($line1); Utils::DelSpace($line2); Utils::DelSpace($line3); #print "1: $line1\n"; #print "2: $line2\n"; #print "3: $line3\n"; if($line1 =~ /^IGOR/) { return "Rietan Pattern File (IGOR)" unless($line2 =~ /yobs/); return "Rietan Fitting Pattern File (IGOR)"; } else { if($line3 =~ /^\s*\d+\s+[\d\.]+\s*$/) { return "RietanFP Pattern File (RietPlot)"; } if($line2 =~ /^\s*\d+\s+[\d\.]+\s+[\d\.]+\s+\d+/) { return "Rietan Pattern File (RietPlot)"; } my @array = split(/\s+/, $line1); if(@array == 8) { return "Rietan Pattern File (gnuplot)"; } if(@array >= 10) { return "Rietan Fitting Pattern File"; } } return undef; } return undef; } sub ReadIGORPatternFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $title = $infile->ReadLine(); Utils::DelSpace($title); $infile->SkipTo("BEGIN"); my $IntData = new GraphData; my @Q; my @Int; my $line; my $c = 0; while($line = $infile->ReadLine()) { last if($line =~ /^END/); my @array = split(/\s+/, $line); my ($x, $y) = Utils::RemoveSpaceElement(@array); #print "line: $line x=$x y=$y\n"; $Q[$c] = $x + 0.0; $Int[$c] = $y + 0.0; $c++; } $IntData->SetTitle($title); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'Intensity'} = \@Int; $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); $infile->SkipTo("BEGIN"); # my $PeakData = new GraphData; my @Diffraction; $Diffraction[0] = new DiffractionPeakArray;; my @Q2; my @Q20; my @d; while($line = $infile->ReadLine()) { last if($line =~ /^END/); # my ($x1, $x0, $y, $d) = split(/\s+/, $line); # push(@Q2, $x1); # push(@Q20, $x0); # push(@d, $d); my @a = Utils::Split("\\s+", $line); # my $n = @a; #print "Q=$a[0]\n"; $Diffraction[0]->Add("", $a[0]+0.0, '', 0.0); } $infile->SkipTo("BEGIN"); for(my $i = 0 ; $i < $Diffraction[0]->nPeaks() ; $i++) { $line = $infile->ReadLine(); last if($line =~ /^END/); my ($h, $k, $l) = Utils::Split("\\s+", $line); my $s = "$h $k $l"; $Diffraction[0]->Sethkl($i, $s); } $infile->Close(); $this->{DiffractionPeakArray} = \@Diffraction; #print "DP: $this,$this->{DiffractionPeakArray}\n"; # $PeakData->SetTitle($title); # $PeakData->{'2Q'} = \@Q2; # $PeakData->{'x0'} = $PeakData->{'2Q0'} = \@Q20; # $PeakData->{'y0'} = $PeakData->{'d'} = \@d; # $PeakData->CalMinMax(); # $this->{'DataArray'}->AddGraphData($PeakData); return $filename; } sub ReadRietPlotFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $title = $infile->ReadLine(); Utils::DelSpace($title); Utils::DelQuote($title); my $line = $infile->ReadLine(); my ($nData, $Start, $Step, $nPeak) = ($line =~ /^\s*(\d+)\s+([\d\.]+)\s+([\d\.]+)\s+(\d+)/); #print "nData=$nData 2Q=$Start, $Step\n"; my $IntData = new GraphData; my @Q; my @Int; my $c = 0; while($line = $infile->ReadLine()) { last if($line =~ /^END/); my @array = split(/\s+/, $line); @array = Utils::RemoveSpaceElement(@array); for(my $i = 0 ; $i < @array ; $i++) { my $Q = $Start + $c*$Step; $Q[$c] = $Q; $Int[$c] = $array[$i] + 0.0; $c++; } last if($c >= $nData); } $IntData->SetTitle($title); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'Intensity'} = \@Int; $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); # my $PeakData = new GraphData; my @Diffraction; $Diffraction[0] = new DiffractionPeakArray; my @Q2; # $c = 0; while($line = $infile->ReadLine()) { last if($line =~ /^END/); # my @array = split(/\s+/, $line); # @array = Utils::RemoveSpaceElement(@array); my @a = Utils::Split("\\s+", $line); for(my $i = 0 ; $i < @a ; $i++) { # $Q2[$c] = $array[$i] + 0.0; # $c++; $Diffraction[0]->Add("", $a[$i]+0.0, '', 0.0); #print "Q=$a[$i]\n"; } } $infile->Close(); $this->{'DiffractionPeakArray'} = \@Diffraction; # $PeakData->SetTitle($title); # $PeakData->{'x0'} = $PeakData->{'2Q'} = \@Q2; # $PeakData->CalMinMax(); # $this->{'DataArray'}->AddGraphData($PeakData); return $filename; } sub ReadRietanFPRietPlotFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $title = $infile->ReadLine(); Utils::DelSpace($title); Utils::DelQuote($title); my $line = $infile->ReadLine(); #print "l1: $line"; my ($idx1, $Step, $nPeak, $idx2) = Utils::Split("\\s+", $line); $line = $infile->ReadLine(); #print "l2: $line"; my ($nData, $Start) = Utils::Split("\\s+", $line); print "nData=$nData 2Q=$Start, $Step nPeak=$nPeak\n"; my $IntData = new GraphData; my @Q; my @Obs; my @Cal; my @BG; my @Diff; my $c = 0; while(1) { $line = $infile->ReadLine(); my @array = Utils::Split("\\s+", $line); for(my $i = 0 ; $i < @array ; $i += 3) { my $Q = $Start + $c*$Step; $Q[$c] = $Q; $Obs[$c] = $array[$i ] + 0.0; $Cal[$c] = $array[$i+1] + 0.0; $BG[$c] = $array[$i+2] + 0.0; $Diff[$c] = $Obs[$c] - $Cal[$c]; $c++; } last if($c >= $nData); } $IntData->SetTitle($title); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'ObsIntensity'} = \@Obs; $IntData->{'y1'} = $IntData->{'CalIntensity'} = \@Cal; $IntData->{'y2'} = $IntData->{'BGIntensity'} = \@BG; $IntData->{'y3'} = $IntData->{'DiffIntensity'} = \@Diff; $IntData->CalMinMax(); $this->{DataArray}->AddGraphData($IntData); delete $this->{DiffractionPeakArray}; my @Diffraction; $Diffraction[0] = new DiffractionPeakArray; while($line = $infile->ReadLine()) { last if($line =~ /^END/); my @a = Utils::Split("\\s+", $line); for(my $i = 0 ; $i < @a ; $i++) { $Diffraction[0]->Add("$a[$i]", $a[$i]+0.0, '', 0.0); } } $infile->Close(); $this->{DiffractionPeakArray} = \@Diffraction; # $PeakData->SetTitle($title); # $PeakData->{'x0'} = $PeakData->{'2Q'} = \@Q2; # $PeakData->CalMinMax(); # $this->{'DataArray'}->AddGraphData($PeakData); return $filename; } sub ReadgnuplotFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $line; my $IntData = new GraphData; my @Q; my @Int; # my @hkl; # my @Q2a; # my @Q2b; # my @F; my @Diffraction; $Diffraction[0] = new DiffractionPeakArray; my $c = 0; while($line = $infile->ReadLine()) { last if($line =~ /^END/); my @array = split(/\s+/, $line); my ($Q, $Int, $h, $k, $l, $Q2a, $Q2b, $F) = Utils::RemoveSpaceElement(@array); $Q[$c] = $Q + 0.0; $Int[$c] = $Int + 0.0; if($F) { # $hkl[$c] = "$h $k $l"; # $Q2a[$c] = $Q2a; # $Q2b[$c] = $Q2b; # $F[$c] = $F; $Diffraction[0]->Add("$h $k $l", $Q2a+0.0, '', $F+0.0); } $c++; } $infile->Close(); $IntData->SetTitle(''); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'Intensity'} = \@Int; $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); $this->{'DiffractionPeakArray'} = \@Diffraction; # my $PeakData = new GraphData; # $PeakData->SetTitle(''); # $PeakData->{'x0'} = $PeakData->{'2Qa'} = \@Q2a; # $PeakData->{'2Qb'} = \@Q2a; # $PeakData->{'hkl'} = \@hkl; # $PeakData->{'F'} = \@F; # $PeakData->CalMinMax(); # $this->{'DataArray'}->AddGraphData($PeakData); return $filename; } sub ReadIntFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $title = $infile->ReadLine(); Utils::DelSpace($title); my $nData = $infile->ReadLine(); my $line; my $IntData = new GraphData; my @Q; my @Int; my $c = 0; while($line = $infile->ReadLine()) { last if($line =~ /^END/); my @array = split(/\s+/, $line); @array = Utils::RemoveSpaceElement(@array); $Q[$c] = $array[0]+0.0; $Int[$c] = $array[1]+0.0; $c++; } $IntData->SetTitle($title); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'Intensity'} = \@Int; $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); $infile->Close(); return $filename; } sub ReadIGORFittingPatternFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $line; my $IntData = new GraphData; my @Q; my @Obs; my @Cal; my @BG; my @Diff; my $c = 0; $infile->SkipTo("BEGIN"); while($line = $infile->ReadLine()) { last if($line =~ /^END/); my ($Q, $obs, $cal, $diff, $bg) = Utils::Split("\\s+", $line); $Q[$c] = $Q+0.0; $Obs[$c] = $obs+0.0; $Cal[$c] = $cal+0.0; $Diff[$c] = $diff+0.0; $BG[$c] = $bg+0.0; $c++; } $IntData->SetTitle(''); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'ObsIntensity'} = \@Obs; $IntData->{'y1'} = $IntData->{'CalIntensity'} = \@Cal; $IntData->{'y2'} = $IntData->{'BGIntensity'} = \@BG; $IntData->{'y3'} = $IntData->{'DiffIntensity'} = \@Diff; $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); $infile->SkipTo("BEGIN"); my @Diffraction; $Diffraction[0] = new DiffractionPeakArray;; my @Q2; my @Q20; my @d; while($line = $infile->ReadLine()) { last if($line =~ /^END/); my @a = Utils::Split("\\s+", $line); $Diffraction[0]->Add("", $a[0]+0.0, $a[1]+0.0, 0.0); } $infile->SkipTo("BEGIN"); for(my $i = 0 ; $i < $Diffraction[0]->nPeaks() ; $i++) { $line = $infile->ReadLine(); last if($line =~ /^END/); my ($h, $k, $l) = Utils::Split("\\s+", $line); my $s = "$h $k $l"; $Diffraction[0]->Sethkl($i, $s); } $infile->Close(); $this->{DiffractionPeakArray} = \@Diffraction; #print "*** pPeakArray=$this->{DiffractionPeakArray}\n"; return $filename; } sub ReadFittingPatternFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $line; my $IntData = new GraphData; my @Q; my @Obs; my @Cal; my @BG; my @Diff; my @Diffraction; my $c = 0; while($line = $infile->ReadLine()) { last if($line =~ /^END/); chomp($line); my ($l1, $l2) = ($line =~ /^(.{46})(.*)$/); my ($Q, $obs, $cal, $bg) = Utils::Split("\\s+", $l1); $Q[$c] = $Q+0.0; $BG[$c] = $bg+0.0; $Obs[$c] = $obs+0.0; $Cal[$c] = $cal+0.0; $Diff[$c] = $obs - $cal; #if($c < 20) { # print "$c: l1: $l1\n"; # print " l2: $l2\n"; #} my $ip = 0; while(1) { last if(length($l2) < 30); $line = $l2; ($l1, $l2) = ($line =~ /^(.{36})(.*)$/); #if($c < 20) { # print " l3: $l2\n"; #} my ($h, $k, $l, $Q2a, $Q2b, $F) = Utils::Split("\\s+", $l1); if(defined $F) { $Diffraction[$ip] = new DiffractionPeakArray unless(defined $Diffraction[$ip]); $Diffraction[$ip]->Add("$h $k $l", $Q2a+0.0, $Q2b+0.0, $F+0.0); } $ip++; } $c++; } $infile->Close(); $IntData->SetTitle(''); $IntData->{'x0'} = $IntData->{'2Q'} = \@Q; $IntData->{'y0'} = $IntData->{'ObsIntensity'} = \@Obs; $IntData->{'y1'} = $IntData->{'CalIntensity'} = \@Cal; $IntData->{'y2'} = $IntData->{'BGIntensity'} = \@BG; $IntData->{'y3'} = $IntData->{'DiffIntensity'} = \@Diff; $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); $this->{'DiffractionPeakArray'} = \@Diffraction; return $filename; } sub ReadTOPASTextFile { my ($this, $filename) = @_; my $infile = new JFile; my $ret = $infile->Open($filename, "r"); return undef unless($ret); $this->SetDataArray(new GraphDataArray); my $line = $infile->ReadLine(); $line = $infile->ReadLine(); my $title = ($line =~ /Title:(.*)$/); Utils::DelSpace($title); my $pos; while(1) { $line = $infile->ReadLine(); #print "l:$line"; if(!defined $line or $line !~ /^!/) { $infile->seek($pos, 0) if(defined $pos); last; } $pos = $infile->tell(); } my $nData = $infile->ReadLine(); my $IntData = new GraphData; my @Q; my @Int; my $c = 0; while($line = $infile->ReadLine()) { Utils::DelSpace($line); last if($line eq ''); my @array = Utils::Split("\\s+", $line); $Q[$c] = $array[0]+0.0; $Int[$c] = $array[1]+0.0; $c++; } $IntData->SetTitle($title); $IntData->{x0} = $IntData->{'2Q'} = \@Q; $IntData->{y0} = $IntData->{Intensity} = \@Int; $IntData->CalMinMax(); $this->{DataArray}->AddGraphData($IntData); $infile->Close(); return $filename; } sub ReadRINT2000ASCIIFile { my ($this, $filename) = @_; my ($drive, $dir, $fname, $ext, $lastdir, $filebody) = Deps::SplitFilePath($filename); my $in = new JFile($filename, "r"); return undef unless($in); my $line = $in->SkipTo("\\*SAMPLE "); my ($Sample) = ($line =~ /=\s*(\S+)/); $Sample = $filebody unless($Sample); Utils::DelSpace($Sample); #print "Sample: $Sample\n"; $in->rewind(); $line = $in->SkipTo("\\*START "); my ($start) = ($line =~ /=\s*(\S+)/); #print "Start: $start\n"; $in->rewind(); $line = $in->SkipTo("\\*STEP "); my ($step) = ($line =~ /=\s*(\S+)/); #print "Step: $step\n"; $in->rewind(); $line = $in->SkipTo("\\*COUNT "); my ($nData) = ($line =~ /=\s*(\S+)/); #print "nData: $nData\n"; my @Q2; my @Int; my $c = 0; while(!$in->eof()) { $line = $in->ReadLine(); last if($line =~ /\\*END/); last if($line =~ /\\*EOF/); my @a = Utils::Split("\\,\\s*", $line); for(my $i = 0 ; $i < @a ; $i++) { $Q2[$c] = $start + $c * $step; $Int[$c] = $a[$i]; $c++; last if($c >= $nData); } last if($c >= $nData); } $nData = $c; #print "nData: $nData\n"; $in->Close(); $this->SetDataArray(new GraphDataArray); my $IntData = new GraphData; $IntData->SetTitle($Sample); $IntData->{'x0'} = $IntData->{"2Q"} = \@Q2; $IntData->{'y0'} = $IntData->{Intensity} = \@Int; $IntData->{'x0_Name'} = "2Theta"; $IntData->SetXCaption("2Theta"); $IntData->{'y0_Name'} = $Sample; $IntData->SetYCaption("Intensity"); $IntData->CalMinMax(); $this->{'DataArray'}->AddGraphData($IntData); return $filename; } sub Read { my ($this, $filename) = @_; $this->ClearAll(); my $FileType = $this->{'FileType'} = Rietan::CheckFileType($filename); $this->SetFileName($filename); #print "Read: this=$this\n"; #print "aFileType: $FileType\n"; if($FileType eq "Rietan Intensity File") { return $this->ReadIntFile($filename); } elsif($FileType eq "Rietan Pattern File (IGOR)") { return $this->ReadIGORPatternFile($filename); } elsif($FileType eq "RietanFP Pattern File (RietPlot)") { return $this->ReadRietanFPRietPlotFile($filename); } elsif($FileType eq "Rietan Pattern File (RietPlot)") { return $this->ReadRietPlotFile($filename); } elsif($FileType eq "Rietan Pattern File (gnuplot)") { return $this->ReadgnuplotFile($filename); } elsif($FileType eq "Rietan Fitting Pattern File (IGOR)") { return $this->ReadIGORFittingPatternFile($filename); } elsif($FileType eq "Rietan Fitting Pattern File") { return $this->ReadFittingPatternFile($filename); } elsif($FileType eq "Rietan Input File") { return 1; } elsif($FileType eq "Rietan Output File") { return 1; } elsif($FileType eq 'TOPAS Text File') { return $this->ReadTOPASTextFile($filename); } elsif($FileType eq "RINT2000 ASCIIFile") { return $this->ReadRINT2000ASCIIFile($filename); } return undef } sub SetSampleName { my ($this, $name) = @_; return $this->{'SampleName'} = $name; } sub SampleName { my ($this) = @_; return $this->{'SampleName'}; } sub SPGDBPath { my ($this) = @_; return $SpaceGroupDBPath; } sub GetASFDCAtoms { my ($this, $asfdcfile) = @_; $asfdcfile = $ASFDCPath if(!defined $asfdcfile); my @Atoms; my $in = new JFile($asfdcfile, "r"); if(!$in) { print "Can not read [$asfdcfile].\n"; return undef; } while(!$in->eof()) { my $line1 = $in->ReadLine(); $in->ReadLine(); $in->ReadLine(); last if($in->eof()); my ($n) = Utils::Split("\\s+", $line1); push(@Atoms, $n); } $in->Close(); return @Atoms; } sub ReadASFParameters { my ($this, $AtomName, $asfdcfile, $XraySource) = @_; $asfdcfile = $ASFDCPath if(!defined $asfdcfile or $asfdcfile eq ''); #print "AtomName=[$AtomName] Path=[$ASFDCPath]\n"; my $in = new JFile($asfdcfile, "r"); if(!$in) { print "Can not read [$asfdcfile].\n"; exit; return undef; } my $ReadAtomName; while(!$in->eof()) { my $line = $in->ReadLine(); last if($in->eof()); my ($n) = Utils::Split("\\s+", $line); if(uc $n eq uc $AtomName) { #$line =~ /^\s*$AtomName\s/i) { $ReadAtomName = $line; last; } } #print "Atom: [$AtomName] $ReadAtomName"; my $line1 = $in->ReadLine(); my $line2 = $in->ReadLine(); my @a1 = Utils::Split("\\s+", $line1); if(@a1 <= 9) { # $a1[9] = 0.0; } my @a2 = Utils::Split("\\s+", $line2); if(@a2 == 11) { @a1 = ($a2[0], $a2[6], $a2[1], $a2[7], $a2[2], $a2[8], $a2[3], $a2[9], $a2[4], $a2[10], $a2[5]); $line2 = $in->ReadLine(); } else { @a1 = ($a1[0], $a1[1], $a1[2], $a1[3], $a1[4], $a1[5], $a1[6], $a1[7], 0.0, 1.0, $a1[8]); } # my @all = @a1; my @a3; if($line2 !~ /0\//) { @a3 = Utils::Split("[,\\s]+", $line2); # @all = (@a1, @a3); #print "a1=", join(', ', @a1), "\n"; #print "a3=", join(', ', @a3), "\n"; } $in->Close(); # return undef if(!defined $line2); if(!defined $line2) { print "Error in Rietan::ReadASFParameters: Can not find ASF for [$AtomName].\n"; exit; } my ($atomname) = ($ReadAtomName =~ /^(.[a-z]?)/); my ($AtomicNumber, $aname, $charge) = AtomType::GetAtomInformation($atomname); $this->{AtomicNumber} = $AtomicNumber; #print "[$ReadAtomName - $atomname] ($AtomicNumber, $aname, $charge)\n"; #print "ASF: $atomname: [$a1[0],$a1[1]] [$a1[2],$a1[3]] [$a1[4],$a1[5]] [$a1[6],$a1[7]] [$a1[8],$a1[9]] [$a1[10]]\n"; #print "S=$XraySource\n"; if(defined $XraySource) { my ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b) = @a1; my ($Crdf1, $Crdf2, $Fedf1, $Fedf2, $Codf1, $Codf2, $Cudf1,$Cudf2, $Modf1, $Modf2, $Agdf1, $Agdf2, $Kbdf1, $Kbdf2) = @a3; # my ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b, # $Crdf1, $Crdf2, $Fedf1, $Fedf2, $Codf1, $Codf2, $Cudf1,$Cudf2, # $Modf1, $Modf2, $Agdf1, $Agdf2, $Kbdf1, $Kbdf2) = @all; #print "S=$XraySource: atm=$atomname: Cu=$Cudf1, $Cudf2\n"; if($XraySource eq 'Cr' and defined $Crdf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Crdf1,$Crdf2); } elsif($XraySource eq 'Fe' and defined $Fedf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Fedf1,$Fedf2); } elsif($XraySource eq 'Co' and defined $Codf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Codf1,$Codf2); } elsif($XraySource eq 'Cu' and defined $Cudf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Cudf1,$Cudf2); } elsif($XraySource eq 'Mo' and defined $Modf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Modf1,$Modf2); } elsif($XraySource eq 'Ag' and defined $Agdf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Agdf1,$Agdf2); } elsif($XraySource eq 'Kb' and defined $Kbdf2) { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Kbdf1,$Kbdf2); } else { @a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b); } } else { } $this->{pASFDCParameters} = \@a1; $this->{ASFDCAtomName} = $AtomName; if(@a1 < 11) { print "Error in Rietan::ReadASFParameters: Can not find ASF for [$AtomName].\n"; exit; } return @a1; } # $s = sin Q / lambda (in nm) sub AtomicScatteringFactor { my ($this, $s) = @_; return $this->asf($s); } # $s = sin Q / lambda (in nm) sub asfElectron { my ($this, $s) = @_; $s = 1.0e-5 if($s <= 0.0); my $s2 = $s * $s; my $k = 1.0e-2 * 8.0 * $pi * $pi / ($a0 * 1.0e9); my $Z = $this->{AtomicNumber}; my $asfXray = $this->asf($s); return $k * ($Z - $asfXray) / $s2; } # $s = sin Q / lambda (in nm) sub asf { my ($this, $s) = @_; my $s2 = 0.01 * $s * $s; my $pP = $this->{pASFDCParameters}; my $n = 11; #@$pP; my $asf = $pP->[$n-1]; for(my $i = 0 ; $i < $n-1 ; $i += 2) { # last if(!defined $pP->[$i+1]); $asf += $pP->[$i] * exp(-$pP->[$i+1] * $s2); } if(defined $pP->[13]) { return cplx($asf + $pP->[12], $pP->[13]); } return $asf; } # $s = sin Q / lambda (in nm) sub HydrogenAtomicScatteringFactor { my ($this, $s) = @_; my $k = 4.0 * $pi * $pi * $a0 * $a0 * 1.0e18; my $a = 1.0 + $k * $s * $s; return 1.0 / $a / $a; } sub ReadSpaceGroup { my ($this, $ispg, $iset) = @_; return 0 unless(open(IN,"<$SpaceGroupDBPath")); while() { my $line = $_; my ($iSPG, $iSet, $LaueG, $nCentr, $nSym, $SPGName) = ($line =~ /^\s*?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\S.*)$/); #print "line: $line
"; #print "i: $iSPG ($iSet) - $ispg ($iset)
\n"; last if(!defined $iSPG or $iSPG < 1); unless($iSPG == $ispg and $iSet == $iset) { my $ICONDLine = ; for(my $i = 0 ; $i < $nSym ; $i++) { my $SymOp = ; } next; } #print "iSPG: $iSPG\n"; #print "iCenter: $nCentr\n"; $this->{iLaueG} = $LaueG; $this->{iCenter} = $nCentr; my $SPG = new SpaceGroup(); $SPG->SetSPGName($SPGName); $SPG->SetiSPG($iSPG); $SPG->SetiSet($iSet); $SPG->SetiLaueGroup($LaueG); $SPG->AnalyzeTranslation(); my $ICONDLine = ; my @ICOND = unpack("a2a2a2a2a2a2a2a2a2a2a2a2a2a2", $ICONDLine); $SPG->SetRietanDiffractinCondition(@ICOND); # for(my $i = 0 ; $i < 14 ; $i++) { # my $type = SpaceGroup::ICONDTypeStrByRietanIndex($i); # my $str = SpaceGroup::ICONDCondStrByRietanIndex($i); # printf " %3s: %s${LF}", $type, $str # if($ICOND[$i] > 0); # } for(my $i = 0 ; $i < $nSym ; $i++) { my $SymOp = ; Utils::DelSpace($SymOp); $SPG->AddSymmetryOperation($SymOp); #print "symop: $SymOp
\n"; # my @SymOpXYZ = split(/,\s*/, $SymOp); # my @XMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[0]); # my @YMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[1]); # my @ZMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[2]); } $SPG->ExpandSymmetryOperation($nCentr); close(IN); return $SPG; } close(IN); return 0; } sub ReadSpaceGroupFromSPGName { my ($this, $SPGName) = @_; $SPGName =~ s/\s//g; #print "b [$SPGName]
\n"; my ($count, $iSPG, $iSet) = $this->GetiSPGFromSPGName($SPGName); #print "b
"; return $this->ReadSpaceGroup($iSPG, $iSet); } sub GetiSPGFromSPGName { my ($this, $SPGName) = @_; #print "DB: [$SpaceGroupDBPath]\n"; return 0 unless(open(IN,"<$SpaceGroupDBPath")); my @list; my $count = 0; while() { my $line = $_; my ($iSPG,$iSet,$LaueG,$nCentr,$nSym,$SPG) = ($line =~ /^\s*?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\S.*)$/); last if(!defined $iSPG or $iSPG < 1); $count++; $SPG =~ s/\s//g; $SPGName =~ s/\s//g; #print "$count: $SPG : $SPGName
\n"; if(uc $SPG eq uc $SPGName) { close(IN); return ($count, $iSPG, $iSet); } my $ICONDLine = ; for(my $i = 0 ; $i < $nSym ; $i++) { my $SymOp = ; } } close(IN); return (-1, -1, -1); } sub GetSpaceGroupList { my ($this) = @_; return 0 unless(open(IN,"<$SpaceGroupDBPath")); my @list; my $count = 0; while() { my $line = $_; my ($iSPG,$iSet,$LaueG,$nCentr,$nSym,$SPG) = ($line =~ /^\s*?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\S.*)$/); last if($iSPG < 1); $count++; my $str = sprintf "%3d-%d (%s) [%d]", $iSPG, $iSet, $SPG, $count; push(@list, $str); my $ICONDLine = ; for(my $i = 0 ; $i < $nSym ; $i++) { my $SymOp = ; } } close(IN); return \@list; } sub FindNearestAtom { my ($this, $name, $charge) = @_; my @list; my $NearestName = ''; my $NearestCharge = 100; #print "name: $name, charge: $charge
"; # my $ASFDCPath = Deps::MakePath($DBDir, "asfdc", 0); unless(open(IN,$ASFDCPath)) { print "Can not read ($ASFDCPath).
\n"; return -1; } while() { my $line1 = $_; my $line2 = ; my $line3 = ; my ($aname) = ($line1 =~ /^(\S+)\s/); #print "aname: $aname "; if($aname =~ /^($name(\.v|[\d\+-]*))$/i) { #print "aname: $aname "; my ($c, $sign) = ($aname =~ /(\d*)([\+-])/); $c = 1 if($c eq ''); #print "aname: $aname c:$c s:$sign
"; if($sign eq '-') { $c = -$c; } if(abs($charge-$NearestCharge) >= abs($charge-$c)) { $NearestCharge = $c; $NearestName = $aname; #print "nearestname: $NearestName, charge: $NearestCharge
"; } push(@list, $aname); } } close(IN); return ($NearestName, @list); } sub FindIdenticalSpaceGroup { my ($this,$SPG) = @_; my $iSPG = $SPG->iSPG(); my $Crystal = new Crystal(); $Crystal->SetLatticeParameters(3, 4, 5, 80, 85, 75); $Crystal->SetCSpaceGroup($SPG); $Crystal->AddAtomSite("H1", "H", 0.1, 0.15, 0.2, 1.0); $Crystal->ExpandCoordinates(); my @AtomList = $Crystal->GetCExpandedAtomSiteList(); my $neq = @AtomList; print "+++*** neq=$neq
\n"; for(my $i = 1 ; $i < 100 ; $i++) { my $RSPG = $this->ReadSpaceGroup($iSPG, $i); last if($RSPG == 0); #my $ns = $RSPG->nSymmetryOperation(); #for(my $k = 0 ; $k < $ns ; $k++) { # my $symop = $RSPG->SymmetryOperation($k+1); # print "sym$k: $symop
\n"; #} my $RCrystal = new Crystal(); $RCrystal->SetLatticeParameters(3, 4, 5, 80, 85, 75); $RCrystal->SetCSpaceGroup($RSPG); $RCrystal->AddAtomSite("H1", "H", 0.1, 0.15, 0.2, 1.0); $RCrystal->ExpandCoordinates(); my @RAtomList = $RCrystal->GetCExpandedAtomSiteList(); my $Rneq = @RAtomList; #print "+++*** $i: Rneq=$Rneq
\n"; next if($Rneq != $neq); my $IsPassed = 1; for(my $j = 0 ; $j < $neq ; $j++) { my $atom0 = $AtomList[$j]; my ($x0, $y0, $z0) = $atom0->Position(1); my $IsPassed0 = 0; for(my $l = 0 ; $l < $neq ; $l++) { my $atom1 = $RAtomList[$l]; my ($x1, $y1, $z1) = $atom1->Position(1); my $dis = $Crystal->GetNearestInterAtomicDistance( $x0, $y0, $z0, $x1, $y1, $z1); #print "j=$j, l=$l: $dis: ($x0, $y0, $z0) - ($x1, $y1, $z1)
\n"; if($dis < 0.01) { $IsPassed0 = 1; last; } } if($IsPassed0 == 0) { $IsPassed = 0; last; } } next if($IsPassed == 0); return $RSPG; } return -1; } sub Execute { my ($this, $filepath, $Actgion, $Program) = @_; $Program = 'Rietan2000' if(!defined $Program); my $LF = "
\n"; if($Program eq 'RietanFP') { $RietanDir = ProgVars::RietanFPDir(); $RietanProgramPath = Deps::MakePath($RietanDir, ["RIETAN_VENUS"], 0); $RietanPath = Deps::MakePath($RietanProgramPath, "rietan.exe", 0); if($^O eq 'linux') { $RietanDir = "$HOME/rietan" ; $RietanProgramPath = "$HOME/rietan/bin"; $RietanPath = Deps::MakePath($RietanProgramPath, "rietan", 0); } } #ファイル名を(ベース名, ディレクトリ名, 拡張子)に分解 my @filenames = fileparse($filepath, "\.[^\.]+"); my $WorkingDir = $filenames[1]; my $inspath = "$filenames[0].ins"; my $intpath = "$filenames[0].int"; my $bkgpath = "$filenames[0].bkg"; my $patpath = "$filenames[0].pat"; my $lstpath = "$filenames[0].lst"; my $csvpath = "$filenames[0].csv"; print "[$patpath] was deleted.$LF" if(unlink("$WorkingDir$patpath")); print "[$lstpath] was deleted.$LF" if(unlink("$WorkingDir$lstpath")); print "[$csvpath] was deleted.$LF" if(unlink("$WorkingDir$csvpath")); $WorkingDir =~ s/[\\\/]$//; if($WorkingDir ne '' and $WorkingDir ne '.') { print "Change working directory to ($WorkingDir)$LF"; unless(-d $WorkingDir) { print " ($WorkingDir) does not exist.$LF$LF"; return 0; } chdir($WorkingDir); my $CurrentDirectory = cwd(); my $cd = $CurrentDirectory; $cd =~ s/\\/\//g; my $wd = $WorkingDir; $wd =~ s/\\/\//g; if(uc $cd ne uc $wd) { print " Can not change to ($wd).$LF"; print " Current directory is ($cd)$LF$LF"; return 0; } } print "Set Rietan=$RietanProgramPath$LF"; $ENV{"Rietan"} = $RietanProgramPath; my $command = "$RietanPath $inspath $intpath $bkgpath $patpath"; #"%RIETAN%\rietan.exe" "%SAMPLE%.ins" "%SAMPLE%.int" "%SAMPLE%.bkg" "%SAMPLE%.pat" #"%SAMPLE%.hkl" "%SAMPLE%.xyz" "%SAMPLE%.mem" "%SAMPLE%.ffe" "%SAMPLE%.fba" #"%SAMPLE%.ffi" "%SAMPLE%.ffo" "%SAMPLE%.vcs" | "%RIETAN%\tee.exe" "%SAMPLE%.lst" print "Execute: [$command]...$LF"; print "
\n";
	unless(open(OUT, ">$lstpath")) {
		print "Error in Rietan.pm:Execute: Can not write to [$lstpath].$LF";
		return;
	}
	unless(open(IN, "$command|")) {
		close(OUT);
		print "Error in Rietan.pm:Execute: Can not execute $RietanPath.$LF";
		return;
	}
	while() {
		print OUT $_;
		print $_;
	}
	close(IN);
	close(OUT);
	print "
\n"; print "Convert $patpath file to CSV file ($csvpath).$LF"; unless(open(IN,"<$patpath")) { print "Error in Rietan.pm:Execute: Can not read [$patpath].$LF"; return; } unless(open(OUT,">$csvpath")) { print "Error in Rietan.pm:Execute: Can not write to [$csvpath].$LF"; return; } my $line = ; #Title; Utils::DelSpace($line); print "Title: $line\n"; $line = ; my ($ndata, $start, $step, $npeak) = Utils::Split("\\s+", $line); print "nData: $ndata, Start angle: $start, Step: $step, nPeaks: $npeak$LF"; print OUT "2Theta,Intensity\n"; my $count = 0; while() { my @data = split(/\s+/, $_); for(my $i = 0 ; $i < @data ; $i++) { next if($data[$i] eq ''); my $angle = $start + $step * $count; $count++; print OUT "$angle,$data[$i]\n"; last if($count >= $ndata); } last if($count >= $ndata); } close(OUT); close(IN); print "$LF"; $inspath = Deps::MakePath($WorkingDir, $inspath, 0); $intpath = Deps::MakePath($WorkingDir, $intpath, 0); $patpath = Deps::MakePath($WorkingDir, $patpath, 0); $lstpath = Deps::MakePath($WorkingDir, $lstpath, 0); $csvpath = Deps::MakePath($WorkingDir, $csvpath, 0); return ($inspath, $intpath, $patpath, $lstpath, $csvpath); } sub SaveInsFile { my ($this, $Crystal, $filename, $IsExpandCoordinate, $IsChooseRandomly, $IsSimulation, $StartAngle, $EndAngle, $StepAngle, $Program) = @_; $Program = 'Rietan2000' if(!defined $Program); if(!defined $IsSimulation or lc $IsSimulation eq 'simulation' or $IsSimulation eq '1') { $IsSimulation = 1; } else { $IsSimulation = 0; } my $LF = "
\n"; print "IsSimulation: $IsSimulation\n"; print "Program $Program\n"; print "Angle: ($StartAngle - $EndAngle), $StepAngle\n"; $StartAngle = 5.0 if($StartAngle eq ''); $EndAngle = 120.0 if($EndAngle eq ''); $StepAngle = 0.02 if($StepAngle eq ''); my $RefineTemplateDir = ($Program eq 'Rietan2000')? ProgVars::RietanTemplateDir() : ProgVars::RietanFPTemplateDir(); #print "Temp: $RefineTemplateDir\n"; my $TemplatePath = Deps::MakePath($RefineTemplateDir, "Refinement-Template.ins", 0); if($IsSimulation) { $TemplatePath = Deps::MakePath($RefineTemplateDir, "Simulation-Template.ins", 0); } print "Template: $TemplatePath\n"; print "Save to [$filename]\n"; my $Content; unless(open(IN,"<$TemplatePath")) { print "Can not open template $TemplatePath.$LF$LF"; return; } while() { $Content .= $_; } close(IN); #Rietanに使える原子名をasfdcから取得 my @AtomTypeList = $Crystal->GetCAtomTypeList(); my $nAtomType = @AtomTypeList; my %RietanAtomName; print "Search atom/ion names available for Rietan.
\n"; for(my $i = 0 ; $i < $nAtomType ; $i++) { my $atom = $AtomTypeList[$i]; my $name = $atom->AtomNameOnly(); my $charge = $atom->Charge() + 0; my $namecharge = $name; if($charge > 0) { $namecharge = "$name$charge+"; } elsif($charge < 0) { my $c = -$charge; $namecharge = "$name$c-"; } $namecharge =~ s/1//g; my ($NearestName, @list) = $this->FindNearestAtom($name, $charge); $RietanAtomName{$name} = $NearestName; print "++ $NearestName is chosen for $namecharge from (@list)
\n"; } #一致する空間群を取得 print "Search space group number/origin set.
\n"; my $SPG = $Crystal->GetCSpaceGroup(); my $RSPG = $this->FindIdenticalSpaceGroup($SPG); if($RSPG <= 0) { print "Error in Rietan.pm::SaveInsFile: Identical space group was not found.$LF"; return -1; } my $SPGName = $RSPG->SPGName(); my $iSPG = $RSPG->iSPG(); my $iSet = $RSPG->iSet(); print "+++ Name: ($SPGName) [#$iSPG - $iSet]$LF"; #置換開始 my $SampleName = $this->SampleName(); $Content =~ s/{Title}/$SampleName/sig; $Content =~ s/{PHNAME1}/$SampleName/sig; print "T: $TemplatePath ($StartAngle, $EndAngle, $StepAngle)\n"; $Content =~ s/{StartAngle}/$StartAngle/sig; $Content =~ s/{EndAngle}/$EndAngle/sig; $Content =~ s/{StepAngle}/$StepAngle/sig; my $Atoms = ''; for(my $i = 0 ; $i < $nAtomType ; $i++) { my $atom = $AtomTypeList[$i]; my $atomname = $atom->AtomNameOnly(); my $name = $RietanAtomName{$atomname}; $Atoms .= " '$name'" if($Atoms !~ /$name/); } $Content =~ s/{Atoms}/$Atoms/sig; # my $iSPG = $Crystal->iSPGByOutputMode(); # my $iSet = $Crystal->iSetByOutputMode(); my $RietanSPG = "A-$iSPG"; $RietanSPG = "$RietanSPG-$iSet" if($iSet ne ''); $Content =~ s/{SPG}/$RietanSPG/sig; $Content =~ s/{SPGName}/$SPGName/sig; my ($a,$b,$c,$alpha,$beta,$gamma) = $Crystal->LatticeParametersByOutputMode(0); my $CELLQ; $CELLQ = "$a $b $c $alpha $beta $gamma"; $Content =~ s/{CELLQ}/$CELLQ/sig; my @ExpandedAtomSiteList = $Crystal->GetCExpandedAtomSiteListByOutputMode(); my $nExpandedAtomSite = @ExpandedAtomSiteList; my $ATOMCOORDS; my %AtomCount; for(my $i = 0 ; $i < $nExpandedAtomSite ; $i++) { my $atom = $ExpandedAtomSiteList[$i]; my $atomname = $atom->AtomName(); my $atomnameonly = $atom->AtomNameOnly(); my $name = $RietanAtomName{$atomnameonly}; my ($x,$y,$z) = $atom->Position(1); my $occupancy = $atom->Occupancy(); my $i1 = $i+1; $AtomCount{$atomname}++; my $c = $AtomCount{$atomname}; my $label = "$atomnameonly$c"; $ATOMCOORDS .= " $label/$name $occupancy $x $y $z 0.5000 01101\n"; } $Content =~ s/{ATOMCOORDS}/$ATOMCOORDS/sig; unless(open(OUT,">$filename")) { print "Can not write to $filename.$LF$LF"; return; } print OUT $Content; print OUT "\n"; close(OUT); return 1; } 1;