#!/usr/bin/perl

use lib 'd:/Programs/Perl/lib';
#use lib 'd:/MyWebs/cgi-bin/lib';

use lib '/home/tkamiya/bin/lib';
use lib '/home/tkamiya/bin';

use strict;
#use warnings;
use Math::MatrixReal;
use Math::Complex;

use Sci qw($pi $a0 $torad $todeg);# acos asin);
use Crystal::CIF;
use Crystal::Crystal;
use Crystal::BandStructure;

#==============================================================
# General parameters
#==============================================================
my $pi2 = 2.0 * $pi;
my $h2m = 7.62;  # eV A^2
my $e2  = 14.40; # eV A

my $InputFile   = ($ARGV[0])? $ARGV[0] : 'TBZB.in';
my (@lOrbName, @lmOrbName, %eta, @KList);
my %AtomOrbitals; # n, l, m
my %aii;          # e0
my (%kF, %rc, %ri);

#==============================================================
# Read files
#==============================================================
my $pParams     = &ReadInput($InputFile);
my $Rmax        = $pParams->{Rmax};
my $nrange      = $pParams->{nRange};
&ReadDB($pParams->{DBFile});
my ($n, $pKPoints) = &ReadKPOINTS($pParams->{KPOINTSFile});

#==============================================================
# Main routine
#==============================================================
print "#==========================================#\n";
print "# Harrison's Tight-Binding                 #\n";
print "#==========================================#\n";
print "\n";

#==============================================================
# Print input parameters
#==============================================================
print "# Control parameters\n";
my @keylist = qw(CrystalName CIFFile UseConventionalCell KPOINTSFile BandFile DBFile
				 Rmax nRange 
				 UseZincBlendAnalyticalForm Diagonalization DiagonalizationEPS 
				 PrintLevel SortEigenValues);
foreach my $key (@keylist) {
	printf "%-20s: $pParams->{$key}\n", $key;
}
print "\n";

#==============================================================
# Read CIF
#==============================================================
print "# Crystal structure\n";
print "Crystal structure read from [$pParams->{CIFFile}]\n";
my $Crystal = &ReadCIF($pParams->{CIFFile});

my $CrystalName = $Crystal->CrystalName();
print "  CrystalName: $CrystalName\n";
my ($aa,$ba,$c,$alpha,$beta,$gamma) = $Crystal->LatticeParameters();
printf "  cell: %9.6f %9.6f %9.6f   %9.6f %9.6f %9.6f \n", $aa, $ba, $c, $alpha, $beta, $gamma;
my ($a11, $a12, $a13, $a21, $a22, $a23, $a31, $a32, $a33) = $Crystal->LatticeVectors();
printf "  Vectors: (%9.6f %9.6f %9.6f)\n", $a11, $a12, $a13;
printf "           (%9.6f %9.6f %9.6f)\n", $a21, $a22, $a23;
printf "           (%9.6f %9.6f %9.6f)\n", $a31, $a32, $a33;
my ($g11, $g12, $g13, $g21, $g22, $g23, $g31, $g32, $g33) = $Crystal->Metrics();
my $vol                    = $Crystal->Volume();
my ($Ra,$Rb,$Rc,$Ralpha,$Rbeta,$Rgamma) = $Crystal->ReciprocalLatticeParameters();
my ($Ra11, $Ra12, $Ra13, $Ra21, $Ra22, $Ra23, $Ra31, $Ra32, $Ra33) = $Crystal->ReciprocalLatticeVectors();
my ($Rg11, $Rg12, $Rg13, $Rg21, $Rg22, $Rg23, $Rg31, $Rg32, $Rg33) = $Crystal->RMetrics();
my $Rvol                   = $Crystal->CalculateReciprocalVolume();
my $SPG                    = $Crystal->GetCSpaceGroup();
my $SPGName                = $SPG->SPGName();
my $iSPG                   = $SPG->iSPG();
my $LatticeSystem          = $SPG->LatticeSystem();
my @AtomTypeList           = $Crystal->GetCAtomTypeList();
my $nAtomType              = @AtomTypeList;
my @AtomSiteList           = $Crystal->GetCAsymmetricAtomSiteList();
my $nAsymmetricAtomSite    = @AtomSiteList;
my @ExpandedAtomSiteList   = $Crystal->GetCExpandedAtomSiteList();
my $nTotalExpandedAtomSite = $Crystal->nTotalExpandedAtomSite();

print "  nAtomType: $nAtomType\n";
for(my $i = 0 ; $i < $nAtomType ; $i++) {
	my $label        = $AtomTypeList[$i]->Label();
	my $atomname     = $AtomTypeList[$i]->AtomNameOnly();
	my $charge       = $AtomTypeList[$i]->Charge();
	my $AtomicNumber = $AtomTypeList[$i]->AtomicNumber();
	my $AtomicMass   = $AtomTypeList[$i]->AtomicMass();
	my $i1 = $i+1;
	print "    #$i1: $label : $atomname [$AtomicNumber] ($charge) ($AtomicMass)\n";
}

print "  nTotalExpandedAtomSite: $nTotalExpandedAtomSite\n";
for(my $i = 0 ; $i < $nTotalExpandedAtomSite ; $i++) {
	my $label     = $ExpandedAtomSiteList[$i]->Label();
	my $type      = $ExpandedAtomSiteList[$i]->AtomName();
	my ($x,$y,$z) = $ExpandedAtomSiteList[$i]->Position(1);
	my $occupancy = $ExpandedAtomSiteList[$i]->Occupancy();
	my $iAtomType = $Crystal->FindiAtomType($type);

	print "    $label ($type)[#$iAtomType]: ($x, $y, $z) [$occupancy]\n";
}
print "\n";

#==============================================================
# Print electronic parameters
#==============================================================
print "# Electronic parameters\n";
for(my $i = 0 ; $i < $nAtomType ; $i++) {
	my $atomname = $AtomTypeList[$i]->AtomNameOnly();
	print "  $i: $atomname\n";
	print "     kF=$kF{$atomname}\n" if(defined $kF{$atomname});
	print "     rc=$rc{$atomname}\n" if(defined $rc{$atomname});
	print "     ri=$ri{$atomname}\n" if(defined $ri{$atomname});
	my $paii = $aii{$atomname};
	my $pao  = $AtomOrbitals{$atomname};
	printf "     %2s %2s %2s [orbname]: E0 [eV]\n", 'n', 'l', 'm';
	for(my $i = 0 ; $i < @$pao ; $i++) {
		my $n        = $pao->[$i][0];
		my $l        = $pao->[$i][1];
		my $m        = $pao->[$i][2];
		my $orbname  = $pao->[$i][3];
		my $orbname2 = $n . $lmOrbName[$l][$l+$m];
		if($orbname ne $orbname2) {
			print "Error: Input orbit name [$orbname] is inconsistent with (n l m) = ($n $l $m) [$orbname2].\n";
			exit;
		}
		my $E0       = $paii->{$orbname};
		printf "     %2d %2d %2d [$orbname]: $E0\n", $n, $l, $m;
	}
}
print "\n";

#==============================================================
# Analyze Hij dimension
#==============================================================
print "# Hij information\n";
my @Orbitals;
for(my $isite = 0 ; $isite < $nTotalExpandedAtomSite ; $isite++) {
	my $pAtom = $ExpandedAtomSiteList[$isite];
	my $atom  = $pAtom->AtomNameOnly();
	my $pAtom = $AtomOrbitals{$atom};
	for(my $iorb = 0 ; $iorb < @$pAtom ; $iorb++) {
		my $n = $pAtom->[$iorb][0];
		my $l = $pAtom->[$iorb][1];
		my $m = $pAtom->[$iorb][2];
		push(@Orbitals, [$isite, $atom, $n.$lmOrbName[$l][$l+$m], $n, $l, $m]);
	}
}
my $nOrb = @Orbitals;

print "nOrbitals: $nOrb\n";
for(my $io = 0 ; $io < $nOrb ; $io++) {
	print "  $io: iSite=$Orbitals[$io][0]  $Orbitals[$io][1] $Orbitals[$io][2]\n";
}
print "\n";

#==============================================================
# Build k list
#==============================================================
print "# k points\n";
print "nK(target)=$n\n";
my $BS = new BandStructure;
my @kl;
for(my $i = 0 ; $i < @$pKPoints ; $i++) {
	$kl[$i] = {
		kx   => $pKPoints->[$i][0],
		ky   => $pKPoints->[$i][1],
		kz   => $pKPoints->[$i][2],
		name => $pKPoints->[$i][3],
	};
#print "k[$i]{name}=$kl[$i]{name}\n";
}
@$pKPoints = $BS->ReduceKList(\@kl);
#for(my $i = 0 ; $i < @$pKPoints ; $i++) {
#print "k[$i]{name}=$pKPoints->[$i]{name}\n";
#}
($n, $pKPoints) = $BS->DivideKList($Crystal, $pKPoints, $n);
#print "nK(adjusted)=$n\n";
for(my $i = 0 ; $i < @$pKPoints ; $i++) {
#print "k[$i]=($pKPoints->[$i]{kx}, $pKPoints->[$i]{ky}, $pKPoints->[$i]{kz}, $pKPoints->[$i]{name})\n";
	$KList[$i] = [$pKPoints->[$i]{kx}, $pKPoints->[$i]{ky}, $pKPoints->[$i]{kz}];
}
#exit;

printf "nK(adjusted)=%d\n", scalar @KList, "\n";
my @k;
my $ktot = 0.0;
for(my $i = 0 ; $i < @KList-1 ; $i++) {
	my ($kx0, $ky0, $kz0, $name0) = @{$KList[$i]};
	my ($kx1, $ky1, $kz1, $name1) = @{$KList[$i+1]};
printf "k[$i]: (%8.4f, %8.4f, %8.4f, %s)-(%8.4f, %8.4f, %8.4f, %s)\n",
		$kx0, $ky0, $kz0, $name0, $kx1, $ky1, $kz1, $name1;
	my $k2 = $Crystal->GetReciprocalDistanceFromK($kx0, $ky0, $kz0, $kx1, $ky1, $kz1);
	push(@k, [$kx0, $ky0, $kz0, $ktot, "$name0-$name1"]);
	$ktot += $k2;
	if($i == @KList-2) {
		push(@k, [$kx1, $ky1, $kz1, $ktot, "$name0-$name1"]);
	}
}
print "\n";
#exit;

#==============================================================
# Build Hij and diagonalization
#==============================================================
print "#============================================\n";
print "# Start diagonalization\n";
print "#============================================\n";
print "\n";

my $out = JFile->new($pParams->{BandFile}, 'w') or die "$!: Can not write to [$pParams->{BandFile}].\n";
$out->print("name,kx,ky,kz,k");
for(my $io = 0 ; $io < $nOrb ; $io++) {
	$out->print(",E$io");
}
$out->print("\n");

for(my $i = 0 ; $i < @k ; $i++) {
	my $p = $k[$i];
	my ($kx, $ky, $kz, $ktot, $kname) = @$p;
	print "#================================================\n";
	print "# k = ($kx, $ky, $kz): $kname\n";
	print "#================================================\n";
	print "\n";

	my ($pHijR, $pHijI) = &CalHij($kx, $ky, $kz);
	print "\n";

	if($pParams->{PrintLevel} >= 0) {
		print "HijR($kx,$ky,$kz)=\n";
		&PrintMatrix($pHijR);
		print "\n";
		print "HijI($kx,$ky,$kz)=\n";
		&PrintMatrix($pHijI);
		print "\n";
	}

	my $pEV = &Diagonalize($pHijR, $pHijI);
	&PrintEigenValues($pEV);
	print "\n";

	my $p = $k[$i];
	$out->print("$kname,$kx,$ky,$kz,$ktot");
	for(my $io = 0 ; $io < $nOrb ; $io++) {
		$out->print(",$pEV->[$io]{E}");
	}
	$out->print("\n");
}

$out->Close();

exit;

#================================================================
# Calculation subroutines
#================================================================
sub PrintEigenValues
{
	my ($pEV) = @_;

	my $n = @$pEV;

	print "\n";
	print "E (eV): Cij";
	for(my $i = 0 ; $i < $n ; $i++) {
		printf "  %-18s", "$Orbitals[$i][0]:$Orbitals[$i][1]$Orbitals[$i][2]";
	}
	print "\n";

	for(my $i = 0 ; $i < $n ; $i++) {
		my $p = $pEV->[$i];
		printf "  %8.4f:", $p->{E};
		for(my $j = 0 ; $j < $n ; $j++) {
			my $vR = $p->{VR}[$j];
			my $vI = $p->{VI}[$j];
			$vR = 0.0 if(abs($vR) < 1.0e-6);
			$vI = 0.0 if(abs($vI) < 1.0e-6);

			printf " (%8.4f,%8.4f)", $vR, $vI;
		}
		print "\n";
	}
}

sub Diagonalize
{
	my ($pHijR, $pHijI) = @_;

	my (@EV, @En, @VnR, @VnI);

	if($pParams->{Diagonalization} eq 'Math::MatrixReal') {
		for(my $i = 0 ; $i < $nOrb ; $i++) {
			for(my $j = $i ; $j < $nOrb ; $j++) {
				if(abs($pHijI->[$i][$j]) > 1.0e-3) {
					print "Error: Hij is not a real matrix: HijI[$i][$j] = $pHijI->[$i][$j]\n";
				}
			}
		}

		my $pHij = new Math::MatrixReal($nOrb, $nOrb);
		for(my $i = 0  ; $i < $nOrb ; $i++) {
			for(my $j = 0 ; $j < $nOrb ; $j++) {
				$pHij->assign($i+1, $j+1, $pHijR->[$j][$i]);
			}
		}

		my ($pEn, $pCnij) = $pHij->sym_diagonalize();

		for(my $i = 0  ; $i < $nOrb ; $i++) {
			$En[$i] = $pEn->element($i+1, 1);
			for(my $j = 0 ; $j < $nOrb ; $j++) {
				$VnR[$i][$j] = $pCnij->element($j+1, $i+1);
				$VnI[$i][$j] = 0.0;
			}
		}
	}
	else {
		my $MatrixIn = 'matrix.in';
		my $MatrixOut = 'matrix.out';

		unlink($MatrixIn);
		unlink($MatrixOut);

		&SaveMatrix($MatrixIn, $pHijR, $pHijI, $pParams->{DiagonalizationEPS});

		my $ret = system($pParams->{Diagonalization});
		if($ret != 0) {
			print "Error: Can not execute [$pParams->{Diagonalization}] with err=$ret.\n";
			exit;
		}

		my ($ii, $jj);
		my $in = JFile->new($MatrixOut, 'r') or die "$!: Can not read [$MatrixOut].\n";

		my $n = $in->ReadLine() + 0;
		$in->ReadLine();
		for(my $i = 0 ; $i < $n ; $i++) {
			($ii, $En[$i]) = Utils::Split("\\s+", $in->ReadLine());
if($i+1 != $ii) {
	print "Error in read [$MatrixOut]; index ", $i+1, " is different from the one in the file ii=$ii.\n";
	exit;
}
		}
		$in->ReadLine();
		for(my $i = 0 ; $i < $n ; $i++) {
			for(my $j = 0 ; $j < $n ; $j++) {
				($ii, $jj, $VnR[$j][$i], $VnI[$j][$i]) = Utils::Split("\\s+", $in->ReadLine());
if($i+1 != $ii or $j+1 != $jj) {
	print "Error in read [$MatrixOut]; index (", $i+1, ',', $j+1, ") is different from the one in the file ii=($ii,$jj).\n";
	exit;
}
#print "$i, $j ($VnR[$i][$j], $VnI[$i][$j])\n";
			}
		}
		$in->Close();
#exit;
	}

	for(my $i = 0 ; $i < $nOrb ; $i++) {
		$EV[$i] = {E => $En[$i], VR => $VnR[$i], VI => $VnI[$i]};
	}

	if($pParams->{SortEigenValues}) {
		@EV = sort { $a->{E} <=> $b->{E} } @EV;
	}

	return \@EV;
}

sub CalHij
{
	my ($kx, $ky, $kz) = @_;

my $UseAdjusted = 1;

	my @s = qw(s1 py1 pz1 px1 s2 py2 pz2 px2);
	my (@g, @E, @hij);
	my ($ph111, $ph1mm, $phm1m, $phmm1);

#==============================================
# From analyatical equations
#==============================================
#Reciprocal W: 0.250000   0.500000   0.750000  W
#Caltesian  W: 0.5   0.0   1.0   W
	my ($sT, $T, $tRT, $RT, $tR) = Crystal->GetLatticeConversionMatrix('FCCPrim', 'ConvertedlToOriginal', 'ai', 1);
print "T=\n";
print $T;
	my $hkl = new Math::MatrixReal(3, 1);
	$hkl = Math::MatrixReal->new_from_cols([ [$kx, $ky, $kz] ]);
	my $chkl = $T * $hkl;
	my ($kxc, $kyc, $kzc) = ($chkl->element(1,1), $chkl->element(2,1), $chkl->element(3,1));
print "k(Cartesian)=($kxc, $kyc, $kzc)\n";
	$ph111 =  $kxc * 0.25 + $kyc * 0.25 + $kzc * 0.25;
	$ph1mm =  $kxc * 0.25 - $kyc * 0.25 - $kzc * 0.25;
	$phm1m = -$kxc * 0.25 + $kyc * 0.25 - $kzc * 0.25;
	$phmm1 = -$kxc * 0.25 - $kyc * 0.25 + $kzc * 0.25;
	$g[0] = exp(i * $pi2 * $ph111) + exp(i * $pi2 * $ph1mm) + exp(i * $pi2 * $phm1m) + exp(i * $pi2 * $phmm1);
	$g[1] = exp(i * $pi2 * $ph111) + exp(i * $pi2 * $ph1mm) - exp(i * $pi2 * $phm1m) - exp(i * $pi2 * $phmm1);
	$g[2] = exp(i * $pi2 * $ph111) - exp(i * $pi2 * $ph1mm) + exp(i * $pi2 * $phm1m) - exp(i * $pi2 * $phmm1);
	$g[3] = exp(i * $pi2 * $ph111) - exp(i * $pi2 * $ph1mm) - exp(i * $pi2 * $phm1m) + exp(i * $pi2 * $phmm1);
for(my $i = 0 ; $i < @g ; $i++) {
print "g$i=$g[$i]\n";
}

	my $atomname0      = $ExpandedAtomSiteList[0]->AtomNameOnly();
	my ($x0, $y0, $z0) = $ExpandedAtomSiteList[0]->Position();
	my $atomname1      = $ExpandedAtomSiteList[1]->AtomNameOnly();
	my ($x1, $y1, $z1) = $ExpandedAtomSiteList[1]->Position();
	my $r = $Crystal->GetInterAtomicDistance($x0, $y0, $z0, $x1, $y1, $z1);

	my ($VssS, $VssP, $VssD) = &Getbij($r, $atomname0, 0, $atomname1, 0);
	my ($VspS, $VspP, $VspD) = &Getbij($r, $atomname0, 0, $atomname1, 1);
	my ($VppS, $VppP, $VppD) = &Getbij($r, $atomname0, 1, $atomname1, 1);

	my $Ess =  $VssS;
	my $Esp = -$VspS / sqrt(3.0);
	my $Exx =  $VppS / 3.0 + 2.0/3.0 * $VppP;
	my $Exy =  $VppS / 3.0 - $VppP / 3.0;
print "Ess=$VssS\n";
print "Esp=$Esp\n";
print "Exx=$Exx  Exy=$Exy\n";

	for(my $i = 0 ; $i < $nOrb ; $i++) {
		my $pOrbital = $Orbitals[$i];
		my $atomname = $pOrbital->[1];
		my $orbname  = $pOrbital->[2];
		my $E0   = $aii{$atomname}{$orbname};
print "$i: $E0, $atomname, $orbname\n";
		$hij[$i][$i] = $E0;
	}

	$hij[0][1] = 0.0;
	$hij[0][2] = 0.0;
	$hij[0][3] = 0.0;
	$hij[0][4] =  $Ess * $g[0];
if(!$UseAdjusted) {
	$hij[0][5] =  $Esp * $g[2];
}
else {
	$hij[0][5] = -$Esp * $g[2];
}
if(!$UseAdjusted) {
	$hij[0][6] =  $Esp * $g[3];
}
else {
	$hij[0][6] = -$Esp * $g[3];
}
if(!$UseAdjusted) {
	$hij[0][7] =  $Esp * $g[1];
}
else {
	$hij[0][7] = -$Esp * $g[1];
}
	$hij[1][2] =  0.0;
	$hij[1][3] =  0.0;
if(!$UseAdjusted) {
	$hij[1][4] = -$Esp * $g[2];
}
else {
	$hij[1][4] =  $Esp * $g[2];
}
	$hij[1][5] =  $Exx * $g[0];
	$hij[1][6] =  $Exy * $g[1];
	$hij[1][7] =  $Exy * $g[3];
	$hij[2][3] =  0.0;
if(!$UseAdjusted) {
	$hij[2][4] = -$Esp * $g[3];
}
else {
	$hij[2][4] =  $Esp * $g[3];
}
if(!$UseAdjusted) {
	$hij[2][5] =  $Exy * $g[2]; #$g[2]
}
else {
	$hij[2][5] =  $Exy * $g[1]; #$g[2]
}
	$hij[2][6] =  $Exx * $g[0];
if(!$UseAdjusted) {
	$hij[2][7] =  $Exy * $g[1]; #$g[1]
}
else {
	$hij[2][7] =  $Exy * $g[2]; #$g[1]
}
if(!$UseAdjusted) {
	$hij[3][4] = -$Esp * $g[1];
}
else {
	$hij[3][4] =  $Esp * $g[1];
}
	$hij[3][5] =  $Exy * $g[3];
if(!$UseAdjusted) {
	$hij[3][6] =  $Exy * $g[1]; #$g[1];
}
else {
	$hij[3][6] =  $Exy * $g[2]; #$g[1];
}
	$hij[3][7] =  $Exx * $g[0];
	$hij[4][5] =  0.0;
	$hij[4][6] =  0.0;
	$hij[4][7] =  0.0;
	$hij[5][6] =  0.0;
	$hij[5][7] =  0.0;
	$hij[6][7] =  0.0;

	for(my $i = 0 ; $i < $nOrb ; $i++) {
		for(my $j = $i+1 ; $j < $nOrb ; $j++) {
#			$hij[$j][$i] = ~$hij[$i][$j];
			$hij[$j][$i] = Re($hij[$i][$j]) - i * Im($hij[$i][$j]);
#print "[$i,$j]: $hij[$j][$i] <=> $hij[$i][$j]\n";
		}
	}

for(my $i = 0 ; $i < $nOrb ; $i++) {
for(my $j = 0 ; $j < $nOrb ; $j++) {
#print "$i,$j $hij[$i][$j]\n";
	if(!defined $hij[$i][$j]) {
		print "hij[$i][$j] is not defined\n";
		exit;
	}
}
}

	my (@HijR, @HijI);
	for(my $i = 0 ; $i < $nOrb ; $i++) {
		for(my $j = 0 ; $j < $nOrb ; $j++) {
			$HijR[$i][$j] = Re($hij[$i][$j]);
			$HijI[$i][$j] = Im($hij[$i][$j]);
#print "$i,$j: ($HijR[$i][$j], $HijI[$i][$j])\n";
		}
	}

	return (\@HijR, \@HijI);
}

sub Getbij
{
	my ($d, $name1, $l1, $name2, $l2) = @_;

	my $k      = $h2m / $d / $d;

	my $oname1 = $lOrbName[$l1];
	my $oname2 = $lOrbName[$l2];

	my $etaS = (defined $eta{"$oname1${oname2}S"})? $eta{"$oname1${oname2}S"} : $eta{"$oname2${oname1}S"};
	my $etaP = (defined $eta{"$oname1${oname2}P"})? $eta{"$oname1${oname2}P"} : $eta{"$oname2${oname1}P"};
	my $etaD = (defined $eta{"$oname1${oname2}D"})? $eta{"$oname1${oname2}D"} : $eta{"$oname2${oname1}D"};
#print "eta=($etaS, $etaP, $etaD) for $oname1$oname2\n";
if(!defined $etaS) {
	print "Error: Can not find eta{$oname1${oname2}S}\n";
	exit;
}

	return ($k*$etaS, $k*$etaP, $k*$etaD);
}

#==========================================================
# Other subroutines
#==========================================================
sub ReadDB
{
	my ($DBFile) = @_;

	my ($line, $key);
	my $in = JFile->new($DBFile, 'r') or die "$!: Can not read [$DBFile].\n";
	$in->rewind();
	$line = $in->SkipTo("lOrbName:");
	($key, @lOrbName) = Utils::Split("\\s+", $line);
#print "OrbName=", join(', ', @lOrbName, "\n");

	$in->rewind();
	$in->SkipTo("lmOrbName:");
	my $c = 0;
	while(1) {
		$line = $in->ReadLine();
		my @b;
		($key, @b) = Utils::Split("\\s+", $line);
		last if(!defined $b[0]);

		$lmOrbName[$c++] = \@b;
	}
#print "OrbName=\n";
#for(my $i = 0 ; $i < @lmOrbName ; $i++) {
#	my $p = $lmOrbName[$i];
#	print "  ", join(', ', @$p), "\n";
#}

	$in->rewind();
	$in->SkipTo("eta:");
	while(1) {
		$line = $in->ReadLine();
		Utils::DelSpace($line);
		my ($key, $val) = Utils::Split("\\s*=\\s*", $line);
		last if(!defined $key);

		$eta{$key} = $val;
	}
#foreach my $key (keys %eta) {
#print "eta: $key: $eta{$key}\n";
#}

	$in->rewind();
	$in->SkipTo("Atom specific");
	my $Atom = '';
	my $c    = 0;
	while(!$in->eof()) {
		$line = $in->ReadLine();
		if($line =~ /^\s*([A-Z][a-z]?):/) {
			$Atom = $1;
#print "atom: $Atom\n";
			$c = 0;
		}

		if($line =~ /(\S.*?)\s*=\s*(\S.*?)\s*$/i) {
			my $key = $1;
			my $val = $2;
			if($key eq 'kF') {
				$kF{$Atom} = $val;
			}
			elsif($key eq 'rc') {
				$rc{$Atom} = $val;
			}
			elsif($key eq 'ri') {
				$ri{$Atom} = $val;
			}
#print "  $key = $val\n";
		}
		elsif($line =~ /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/i) {
			my ($orb, $n, $l, $m, $E0) = ($1, $2, $3, $4, $5);
#print "  $orb: $n $l $m: $E0\n";
			next if(!defined $E0);
			$AtomOrbitals{$Atom}[$c] = [$n, $l, $m, $orb, $E0];
			$aii{$Atom}{$orb} = $E0;
			$c++;
		}
	}
	$in->Close();

if(0) {
foreach my $key (keys %kF) {
	print "  kF($key)=$kF{$key}\n";
}
foreach my $key (keys %rc) {
	print "  rc($key)=$kF{$key}\n";
}
foreach my $key (keys %ri) {
	print "  ri($key)=$ri{$key}\n";
}
foreach my $key (keys %aii) {
	my $p = $aii{$key};
	foreach my $key2 (keys %$p) {
		print "  aii($key)($key2)=$p->{$key2}\n";
	}
}
foreach my $key (keys %AtomOrbitals) {
	my $p = $AtomOrbitals{$key};
	for(my $i = 0 ; $i < @$p ; $i++) {
		print "  ($key): $p->[$i][0] $p->[$i][1] $p->[$i][2]\n";
	}
}
exit;
}

}

sub ReadCIF
{
	my ($CIFFile) = @_;

	my $cif = new CIF;
	$cif->Read($CIFFile) or die "$!: Can not read [$CIFFile]\n";
	my $Crystal = $cif->GetCCrystal();
	$Crystal->ExpandCoordinates();
	$Crystal->SetOutputMode('expanded');

	my $SPG     = $Crystal->GetCSpaceGroup();
	my $SPGName = $SPG->SPGName();
	if($pParams->{UseConventionalCell} or $SPGName !~ /^\s*[FIABC]/i) {
		return $Crystal;
	}
	else
	{
#Primitive Cellをつくる
		print "  Convert to Primitive Cell.\n";
		print "  SpaceGroup: $SPGName\n";

		my $T = new Math::MatrixReal(3, 3);
		if($SPGName =~ /^\s*F/i) {
			$T = Math::MatrixReal->new_from_cols( 
				[ [ 0.5, 0.5,   0], 
				  [ 0,   0.5, 0.5],
				  [ 0.5,   0, 0.5] ] );
			$T->transpose($T);
		}
		elsif($SPGName =~ /^\s*I/i) {
			$T = Math::MatrixReal->new_from_cols( 
				[ [-0.5, 0.5, 0.5], 
				  [ 0.5,-0.5, 0.5],
				  [ 0.5, 0.5,-0.5] ] );
			$T->transpose($T);
		}
		elsif($SPGName =~ /^\s*A/i) {
			$T = Math::MatrixReal->new_from_cols( 
				[ [ 1.0, 0.0, 0.0], 
				  [ 0.0, 0.5, 0.5],
				  [ 0.0,-0.5, 0.5] ] );
			$T->transpose($T);
		}
		elsif($SPGName =~ /^\s*B/i) {
			$T = Math::MatrixReal->new_from_cols( 
				[ [ 0.5, 0.0, 0.5], 
				  [ 0.0, 1.0, 0.0],
				  [-0.5, 0.0, 0.5] ] );
			$T->transpose($T);
		}
		elsif($SPGName =~ /^\s*C/i) {
			$T = Math::MatrixReal->new_from_cols( 
				[ [ 0.5, 0.5, 0.0], 
				  [-0.5, 0.5, 0.0],
				  [ 0.0, 0.0, 1.0] ] );
			$T->transpose($T);
		}

#実空間べクトル(ai)の変換行列
		print  "  Conversion matrix for real space vector: (a'i) = (Tij)(aj)\n";
		printf "  |%10.4f %10.4f %10.4f|\n", $T->element(1,1), $T->element(1,2), $T->element(1,3);
		printf "  |%10.4f %10.4f %10.4f|\n", $T->element(2,1), $T->element(2,2), $T->element(2,3);
		printf "  |%10.4f %10.4f %10.4f|\n", $T->element(3,1), $T->element(3,2), $T->element(3,3);
		print "\n";

		my ($a, $b, $c, $alpha, $beta, $gamma) = $Crystal->LatticeParameters();
		return $Crystal->ConvertLattice($T, 0, 1);
	}
}

sub ReadInput
{
	my ($InFile) = @_;

	my %p;
	my $in = JFile->new($InFile, 'r') or die "$!: Can not read [$InFile].\n";
	while(!$in->eof()) {
		my $line = $in->ReadLine();
		next if($line =~ /^\s*#/);

		my ($key, $val) = ($line =~ /^\s*(\S+)\s*=\s*(\S.*)\s*$/);
		next if(!defined $key);
		$p{$key} = $val;
	}
	$in->Close();
	return \%p;
}

sub ReadKPOINTS
{
	my ($InFile) = @_;
	
	my $in = JFile->new($InFile, 'r') or die "$!: Can not read [$InFile].\n";
	my $line = $in->ReadLine();
	my $n = $in->ReadLine() + 0;
	$line = $in->ReadLine();
	$line = $in->ReadLine();
	Utils::DelSpace($line);
	if($line !~ /R/i) {
		print "Error: KPOINTS should be given based on the reciprocal mode (mode=[$line]).\n";
		exit;
	}

	my ($kxp, $kyp, $kzp);
	my $c = 0;
	while(1) {
		last if($in->eof());
		$line = $in->ReadLine();
		my ($kx, $ky, $kz, $kname) = Utils::Split("\\s+", $line);
		next if(!defined $kz);

#print "l($kxp,$kyp,$kzp)/($kx,$ky,$kz):$line";
		if(!defined $kxp or ($kx != $kxp or $ky != $kyp or $kz != $kzp)) {
#print "c=$c\n";
			$KList[$c] = [$kx, $ky, $kz, $kname];
			$c++;
		}
		$kxp = $kx;
		$kyp = $ky;
		$kzp = $kz;
	}
#for(my $i = 0 ; $i < @KList ; $i++) {
#	my $p = $KList[$i];
#	print "$i: $p->[0], $p->[1], $p->[2], $p->[3]\n";
#}
	$in->Close();
	
	return ($n, \@KList);
}

sub SaveMatrix
{
	my ($MatrixIn, $pHijR, $pHijI, $EPS) = @_;
	
	my $n = @$pHijR;

	my $mtx = JFile->new($MatrixIn, 'w') or die "$!: Can not write to [$MatrixIn].\n";
	$mtx->print("$n $EPS\n");
	$mtx->print("i j HijR HijI\n");
	for(my $i = 0 ; $i < $n ; $i++) {
		for(my $j = 0 ; $j < $n ; $j++) {
			$mtx->print($i+1, " ", $j+1, "   $pHijR->[$i][$j]   $pHijI->[$i][$j]\n");
		}
	}
	$mtx->print("i j SijR SijI\n");
	for(my $i = 0 ; $i < $n ; $i++) {
		for(my $j = 0 ; $j < $n ; $j++) {
			my $S = ($i == $j)? 1 : 0;
			$mtx->print($i+1, " ", $j+1, "   $S   0.0\n");
		}
	}
	
	$mtx->Close();
}

sub PrintMatrix
{
	my ($pM) = @_;
	
	my $n = @$pM;
	for(my $i = 0 ; $i < $n ; $i++) {
		print "[";
		for(my $j = 0 ; $j < $n ; $j++) {
			my $v = $pM->[$i][$j];
			$v = 0.0 if(abs($v) < 1.0e-6);
			printf " %12.4g", $v;
		}
		print "]\n";
	}
}

sub PrintMatrixReal
{
	my ($pM, $n) = @_;
	
	for(my $i = 0 ; $i < $n ; $i++) {
		print "[";
		for(my $j = 0 ; $j < $n ; $j++) {
			my $v = $pM->element($i+1, $j+1);
			$v = 0.0 if(abs($v) < 1.0e-6);
			printf " %12.4g", $v;
		}
		print "]\n";
	}
}

sub PrintVectorReal
{
	my ($pM, $n) = @_;
	
	print "[";
	for(my $i = 0 ; $i < $n ; $i++) {
		printf " %12.4g", $pM->element($i+1, 1);
	}
	print "]\n";
}

