#!/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] : 'TB.in';
my (@lOrbName, @lmOrbName, %eta, @KList);
my %AtomOrbitals; # n, l, m
my %aii;          # e0
my (%kF, %kd, %rd, %rc, %ri, %ro);

#==============================================================
# Read files
#==============================================================
my $pParams     = &ReadInput($InputFile);
my $Rmax        = $pParams->{Rmax};
my $nrange      = $pParams->{nRange};

if($pParams->{Diagonalization} ne 'Math::MatrixReal' and !-f $pParams->{Diagonalization}) {
	print "Error: Can not find the diagonalization program [$pParams->{Diagonalization}].\n";
	exit;
}
if(!-f $pParams->{CIFFile}) {
	print "Error: Can not find the CIF file [$pParams->{CIFFile}].\n";
	exit;
}
if(!-f $pParams->{KPOINTSFile}) {
	print "Error: Can not find the KPOINTS file [$pParams->{KPOINTSFile}].\n";
	exit;
}
if(!-f $pParams->{DBFile}) {
	print "Error: Can not find the DB file [$pParams->{DBFile}].\n";
	exit;
}

&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();
if(!defined $kF{$atomname} and !defined $rc{$atomname} and !defined $ri{$atomname} and !defined $ro{$atomname}) {
	print "Error: Atomic data for [$atomname] is not given in [$pParams->{DBFile}].\n";
	exit;
}
	print "  $i: $atomname\n";
	print "     rd=$rd{$atomname}\n" if(defined $rd{$atomname});
	print "     kd=$ri{$atomname}\n" if(defined $kd{$atomname});
	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});
	print "     ro=$ro{$atomname}\n" if(defined $ro{$atomname});
	my $paii = $aii{$atomname};
	my $pao  = $AtomOrbitals{$atomname};
if(!defined $pao or !defined $pao) {
	print "Error: Atomic data for [$atomname] is not given in [$pParams->{DBFile}].\n";
	exit;
}

	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 [$atomname $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;
if($n == 1) {
	$kl[0] = {
		kx   => $pKPoints->[0][0],
		ky   => $pKPoints->[0][1],
		kz   => $pKPoints->[0][2],
		name => $pKPoints->[0][3],
	};
}
else {
	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;
if($n == 1) {
	my ($kx0, $ky0, $kz0, $name0) = @{$KList[0]};
printf "k[0]: (%8.4f, %8.4f, %8.4f, %s)\n", $kx0, $ky0, $kz0, $name0;
	push(@k, [$kx0, $ky0, $kz0, 0.0, "$name0"]);
}
else {
	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";
	}

	print "\n";
	print "Molecular orbitals:\n";
	my $EPS = ($pParams->{MOEPS} > 0.0)? $pParams->{MOEPS} : 0.01;
	for(my $i = 0 ; $i < $n ; $i++) {
		my $p = $pEV->[$i];
		printf "  E(%2i)=%8.4f: ", $i, $p->{E};
		for(my $j = 0 ; $j < $n ; $j++) {
			my $vR = $p->{VR}[$j];
			my $vI = $p->{VI}[$j];
			my $v  = sqrt($vR*$vR + $vI*$vI);
			next if(abs($v) < $EPS);

			my $sv = sprintf("%6.2f", abs($v));
			Utils::DelSpace($sv);

			my $iSite = $Orbitals[$j][0];
			my $atom  = $Orbitals[$j][1];
			my $orb   = $Orbitals[$j][2];

			if($vR > 0.0) {
				printf "+%s%s", $sv, "[${orb}$atom$iSite]";
			}
			else {
				printf "-%s%s", $sv, "[${orb}$atom$iSite]";
			}
		}
		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 @s = qw(s1 py1 pz1 px1 s2 py2 pz2 px2);

my (@g, @E, @hij);
my ($ph111, $ph1mm, $phm1m, $phmm1);
if($pParams->{UseZincBlendAnalyticalForm}) {

#==============================================
# 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);
#1st argで指定された変換行列  : $sT
#2nd argで選択された変換行列  : $T
#実空間座標(x,y,z)の変換行列  : $tRT = transpose(T)
#逆空間ベクトル(a*i)の変換行列: $RT  = transpose(T)
#逆空間座標(h k l)の変換行列  : $tR  = $T
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];
#	$hij[0][5] =  $Esp * $g[2];
	$hij[0][5] = -$Esp * $g[2];
#	$hij[0][6] =  $Esp * $g[3];
	$hij[0][6] = -$Esp * $g[3];
#	$hij[0][7] =  $Esp * $g[1];
	$hij[0][7] = -$Esp * $g[1];
	$hij[1][2] =  0.0;
	$hij[1][3] =  0.0;
#	$hij[1][4] = -$Esp * $g[2];
	$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;
#	$hij[2][4] = -$Esp * $g[3];
	$hij[2][4] =  $Esp * $g[3];
#	$hij[2][5] =  $Exy * $g[2]; #$g[2]
	$hij[2][5] =  $Exy * $g[1]; #$g[2]
	$hij[2][6] =  $Exx * $g[0];
#	$hij[2][7] =  $Exy * $g[1]; #$g[1]
	$hij[2][7] =  $Exy * $g[2]; #$g[1]
#	$hij[3][4] = -$Esp * $g[1];
	$hij[3][4] =  $Esp * $g[1];
	$hij[3][5] =  $Exy * $g[3];
#	$hij[3][6] =  $Exy * $g[1]; #$g[1];
	$hij[3][6] =  $Exy * $g[2]; #$g[1];
	$hij[3][7] =  $Exx * $g[0];
#  0   1   2   3  4   5   6   7
# s1 py1 pz1 px1 s2 py2 pz2 px2
	$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;
	}
}
}

}
else {
for(my $i = 0 ; $i < $nOrb ; $i++) {
for(my $j = 0 ; $j < $nOrb ; $j++) {
$hij[$i][$j] = 0;
}
}
}


#==============================================
# By summation
#==============================================
	my (@HijR, @HijI);
	for(my $i = 0  ; $i < $nOrb ; $i++) {
		for(my $j = 0 ; $j < $nOrb ; $j++) {
			$HijR[$j][$i] = 0.0;
			$HijI[$j][$i] = 0.0;
		}
	}

	for(my $idx1 = 0  ; $idx1 < $nOrb ; $idx1++) {
# [$isite, $atom, $n.$lmOrbName[$l][$l+$m], $n, $l, $m]);
		my $pOrbital1 = $Orbitals[$idx1];
		my $is1       = $pOrbital1->[0];
		my $name1     = $pOrbital1->[1];
		my $OrbName1  = $pOrbital1->[2];
		my $n1        = $pOrbital1->[3];
		my $l1        = $pOrbital1->[4];
		my $m1        = $pOrbital1->[5];
		my $pSite1    = $ExpandedAtomSiteList[$is1];
		my ($x1, $y1, $z1) = $pSite1->Position(1);
		my $pAtom1    = $AtomOrbitals{$name1};
my $IsPrintedHij = 0;
		for(my $idx2 = $idx1  ; $idx2 < $nOrb ; $idx2++) {
#print "Sites: $is1 - $is2\n";
			my $pOrbital2 = $Orbitals[$idx2];
			my $is2       = $pOrbital2->[0];
			my $name2     = $pOrbital2->[1];
			my $OrbName2  = $pOrbital2->[2];
			my $n2        = $pOrbital2->[3];
			my $l2        = $pOrbital2->[4];
			my $m2        = $pOrbital2->[5];
			my $pSite2    = $ExpandedAtomSiteList[$is2];
			my ($x2, $y2, $z2) = $pSite2->Position(1);
			my $pAtom2    = $AtomOrbitals{$name2};

my $IsPrinted = 0;
			for(my $iz = -$nrange ; $iz <= $nrange ; $iz++) {
			for(my $iy = -$nrange ; $iy <= $nrange ; $iy++) {
			for(my $ix = -$nrange ; $ix <= $nrange ; $ix++) {
				my $x2r = $x2 + $ix;
				my $y2r = $y2 + $iy;
				my $z2r = $z2 + $iz;
				my $dx  = $x2r - $x1;
				my $dy  = $y2r - $y1;
				my $dz  = $z2r - $z1;
				my $r = $Crystal->GetInterAtomicDistance($x1, $y1, $z1, $x2r, $y2r, $z2r);
				next if(abs($r) > $Rmax);

				my ($VS, $VP, $VD);
				if($r == 0.0) {
					if($idx1 == $idx2) {
if(!defined $aii{$name1}{$OrbName1}) {
print "Error: aii is not defined for $name1 $OrbName1\n";
exit;
}

						$HijR[$idx1][$idx2] += $aii{$name1}{$OrbName1};
print "Hij[$idx1][$idx2] = aii{$name1}{$OrbName1} = $HijR[$idx1][$idx2]\n" if($pParams->{PrintLevel} >= 1);
					}
					else {
						$HijR[$idx1][$idx2] = 0.0;
						$HijI[$idx1][$idx2] = 0.0;
print "Hij[$idx1][$idx2] = $HijR[$idx1][$idx2]\n" if($pParams->{PrintLevel} >= 1);
					}
				}
				else {
					($VS, $VP, $VD) = &Getbij($r, $name1, $l1, $name2, $l2);
if($pParams->{PrintLevel} >= 1 and !$IsPrinted) {
print "VS=$VS  VP=$VP  VD=$VD ($OrbName1-$OrbName2) r=$r\n";
$IsPrinted=1;
}
					my ($rx, $ry, $rz) = $Crystal->CalCartesianCoordinate($dx, $dy, $dz);
					my $lx  = $rx / $r;
					my $ly  = $ry / $r;
					my $lz  = $rz / $r;
					my $lx2 = $lx * $lx;
					my $ly2 = $ly * $ly;
					my $lz2 = $lz * $lz;
# Slater-Koster conversion
#['py', 'pz', 'px']: m = (-1,0,1)
					if($l1 == 0 and $l2 == 0) { #ss
						$b = $VS;
					}
					elsif($l1 == 0  and $l2 == 1 and $m2 == -1) { #sy
						$b =  $ly * $VS;
					}
					elsif($l1 == 1 and $m1 == -1 and $l2 == 0) { #ys
						$b = -$ly * $VS;
					}
					elsif($l1 == 0 and $l2 == 1 and $m2 == 0) { #sz
						$b =  $lz * $VS;
					}
					elsif($l1 == 1 and $m1 == 0 and $l2 == 0) { #zs
						$b = -$lz * $VS;
					}
					elsif($l1 == 0 and $l2 == 1 and $m2 == 1) { #sx
						$b =  $lx * $VS;
					}
					elsif($l1 == 1 and $m1 == 1 and $l2 == 0) { #xs
						$b = -$lx * $VS;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 1 and $m2 == -1)) { #yy
						$b = $ly2 * $VS + (1.0 - $ly2) * $VP;
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 1 and $m2 ==  0)) { #zz
						$b = $lz2 * $VS + (1.0 - $lz2) * $VP;
					}
					elsif(($l1 == 1 and $m1 ==  1 and $l2 == 1 and $m2 ==  1)) { #xx
						$b = $lx2 * $VS + (1.0 - $lx2) * $VP;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 1 and $m2 ==  0) or 
						  ($l1 == 1 and $m1 ==  0 and $l2 == 1 and $m2 == -1)) { #yz
						$b = $ly*$lz * ($VS - $VP);
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 1 and $m2 ==  0) or 
						  ($l1 == 1 and $m1 ==  0 and $l2 == 1 and $m2 == -1)) { #yz
						$b = $ly*$lz * ($VS - $VP);
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 1 and $m2 ==  1) or 
						  ($l1 == 1 and $m1 ==  1 and $l2 == 1 and $m2 == -1)) { #yx
						$b = $ly*$lx * ($VS - $VP);
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 1 and $m2 ==  1) or 
						  ($l1 == 1 and $m1 ==  1 and $l2 == 1 and $m2 ==  0)) { #zx
						$b = $lz*$lx * ($VS - $VP);
					}
					elsif(($l1 == 0 and $m1 ==  0 and $l2 == 2 and $m2 == -2) or
					      ($l1 == 2 and $m1 == -2 and $l2 == 0 and $m2 == 0)) { #sxy
						$b = sqrt(3.0)*$lx*$ly * $VS;
					}
					elsif(($l1 == 0 and $m1 ==  0 and $l2 == 2 and $m2 == -1) or
					      ($l1 == 2 and $m1 == -1 and $l2 == 0 and $m2 == 0)) { #syz
						$b = sqrt(3.0)*$ly*$lz * $VS;
					}
					elsif(($l1 == 0 and $m1 ==  0 and $l2 == 2 and $m2 ==  0) or
					      ($l1 == 2 and $m1 ==  0 and $l2 == 0 and $m2 == 0)) { #s3z2-r2
						$b = ($lz2 - 0.5*($lx2 + $ly2)) * $VS;
					}
					elsif(($l1 == 0 and $m1 ==  0 and $l2 == 2 and $m2 ==  1) or
					      ($l1 == 2 and $m1 ==  1 and $l2 == 0 and $m2 == 0)) { #szx
						$b = sqrt(3.0)*$lz*$lx * $VS;
					}
					elsif(($l1 == 0 and $m1 ==  0 and $l2 == 2 and $m2 ==  2) or
					      ($l1 == 2 and $m1 ==  2 and $l2 == 0 and $m2 == 0)) { #sx2-y2
						$b = 0.5 * sqrt(3.0) * ($lx2 - $ly2) * $VS;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 2 and $m2 == -2)) { #y xy
						$b =  sqrt(3.0) * $ly2*$lx * $VS + $lx*($1.0-2.0*$ly2) * $VP;
					}
					elsif(($l1 == 2 and $m1 == -2 and $l2 == 1 and $m2 == -1)) { #xy y
						$b =  sqrt(3.0) * $ly2*$lx * $VS + $lx*($1.0-2.0*$ly2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 2 and $m2 == -1)) { #y yz
						$b =  sqrt(3.0) * $ly2*$lz * $VS + $lz*(1.0-2.0*$ly2) * $VP;
					}
					elsif(($l1 == 2 and $m1 == -1 and $l2 == 1 and $m2 == -1)) { #yz y
						$b =  sqrt(3.0) * $ly2*$lz * $VS + $lz*(1.0-2.0*$ly2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 2 and $m2 ==  0)) { #y 3z2-r2
						$b =  $ly*($lz2-0.5*($lx2+$ly2)) * $VS - sqrt(3.0) * $ly*$lz2 * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  0 and $l2 == 1 and $m2 == -1)) { #3z2-r2 y
						$b =  $ly*($lz2-0.5*($lx2+$ly2)) * $VS - sqrt(3.0) * $ly*$lz2 * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 2 and $m2 ==  1)) { #y zx
						$b =  $lx*$ly*$lz * (sqrt(3.0) * $VS - 2.0 * $VP);
					}
					elsif(($l1 == 2 and $m1 ==  1 and $l2 == 1 and $m2 == -1)) { #zx y
						$b =  $lx*$ly*$lz * (sqrt(3.0) * $VS - 2.0 * $VP);
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 == -1 and $l2 == 2 and $m2 ==  2)) { #y x2-y2
						$b =  0.5*sqrt(3.0) * $ly*($lx2-$ly2) * $VS - $ly*(1.0+$lx2-$ly2) * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  2 and $l2 == 1 and $m2 == -1)) { #x2-y2 y
						$b =  0.5*sqrt(3.0) * $ly*($lx2-$ly2) * $VS - $ly*(1.0+$lx2-$ly2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 2 and $m2 == -2)) { #z xy
						$b =  $lx*$ly*$lz * (sqrt(3.0) * $VS - 2.0 * $VP);
					}
					elsif(($l1 == 2 and $m1 == -2 and $l2 == 1 and $m2 ==  0)) { #xy z
						$b =  $lx*$ly*$lz * (sqrt(3.0) * $VS - 2.0 * $VP);
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 2 and $m2 == -1)) { #z yz
						$b =  sqrt(3.0) * $lz2*$ly * $VS + $ly*(1.0-2.0*$lz2) * $VP;
					}
					elsif(($l1 == 2 and $m1 == -1 and $l2 == 1 and $m2 ==  0)) { #yz z
						$b = sqrt(3.0) * $lz2*$ly * $VS + $ly*(1.0-2.0*$lz2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 2 and $m2 ==  0)) { #z 3z2-r2
						$b =  $lz*($lz2-0.5*($lx2+$ly2)) * $VS + sqrt(3.0)*$lz*($lx2+$ly2) * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  0 and $l2 == 1 and $m2 ==  0)) { #3z2-r2 z
						$b =  $lz*($lz2-0.5*($lx2+$ly2)) * $VS + sqrt(3.0)*$lz*($lx2+$ly2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 2 and $m2 ==  1)) { #z zx
						$b =  sqrt(3.0)*$lz2*$lx * $VS + $lx*(1.0-2.0*$lz) * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  1 and $l2 == 1 and $m2 ==  0)) { #zx z
						$b =  sqrt(3.0)*$lz2*$lx * $VS + $lx*(1.0-2.0*$lz) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  0 and $l2 == 2 and $m2 ==  2)) { #z x2-y2
						$b =  0.5*sqrt(3.0)*$lz*($lx2-$ly2) * $VS - $lz*($lx2-$ly2) * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  2 and $l2 == 1 and $m2 ==  0)) { #x2-y2 z
						$b =  0.5*sqrt(3.0)*$lz*($lx2-$ly2) * $VS - $lz*($lx2-$ly2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  1 and $l2 == 2 and $m2 == -2)) { #x xy
						$b =  sqrt(3.0) * $lx2*$ly * $VS + $ly*(1.0-2.0*$lx2) * $VP;
					}
					elsif(($l1 == 2 and $m1 == -2 and $l2 == 1 and $m2 ==  1)) { #xy x
						$b =  sqrt(3.0) * $lx2*$ly * $VS + $ly*(1.0-2.0*$lx2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  1 and $l2 == 2 and $m2 == -1)) { #x yz
						$b =  $lx*$ly*$lz * (sqrt(3.0) * $VS - 2.0*$VP);
					}
					elsif(($l1 == 2 and $m1 == -1 and $l2 == 1 and $m2 ==  1)) { #yz x
						$b =  $lx*$ly*$lz * (sqrt(3.0) * $VS - 2.0*$VP);
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  1 and $l2 == 2 and $m2 ==  0)) { #x 3z2-r2
						$b =  $lx*($lz2-0.5*($lx2+$ly2)) * $VS - sqrt(3.0) * $lx*$lz2 * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  0 and $l2 == 1 and $m2 ==  1)) { #3z2-r2 x
						$b =  $lx*($lz2-0.5*($lx2+$ly2)) * $VS - sqrt(3.0) * $lx*$lz2 * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  1 and $l2 == 2 and $m2 ==  1)) { #x zx
						$b =  sqrt(3.0)*$lx2*$lz * $VS + $lz*(1.0-2.0*$lx2) * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  1 and $l2 == 1 and $m2 ==  1)) { #zx x
						$b =  sqrt(3.0)*$lx2*$lz * $VS + $lz*(1.0-2.0*$lx2) * $VP;
						$b = -$b;
					}
					elsif(($l1 == 1 and $m1 ==  1 and $l2 == 2 and $m2 ==  2)) { #x x2-y2
						$b =  0.5*sqrt(3.0)*$lx*($lx2-$ly2) * $VS + $lx*(1.0-$lx2+$ly2) * $VP;
					}
					elsif(($l1 == 2 and $m1 ==  2 and $l2 == 1 and $m2 ==  1)) { #x x2-y2
						$b =  0.5*sqrt(3.0)*$lx*($lx2-$ly2) * $VS + $lx*(1.0-$lx2+$ly2) * $VP;
						$b = -$b;
					}
#if($idx1 == 1 and $idx2 == 6) {
#print "$l1,$m1,$l2,$m2: ($ix,$iy,$iz): r=$r, b=$b (l=$lx,$ly,$lz) VS=$VS\n";
#exit;
#}
					my $phi  = $kx * $dx + $ky * $dy + $kz * $dz;
					my $ekrr = cos($pi2 * $phi);
					my $ekri = sin($pi2 * $phi);
					$HijR[$idx1][$idx2] += $ekrr * $b;
					$HijI[$idx1][$idx2] += $ekri * $b;

if($pParams->{UseZincBlendAnalyticalForm}) {
	if($lx > 0.0) {
		$ly = $ly/$lx;
		$lz = $lz/$lx;
		$lx = 1;
		}
	else {
		$ly = $ly/abs($lx);
		$lz = $lz/abs($lx);
		$lx = -1;
	}
	printf "Hij[$idx1][$idx2]=(%8.4f,%8.4f)  b=%8.4f  lxyz=%2.0f%2.0f%2.0f  ekr=(%8.4f, %8.4f)\n", 
			$HijR[$idx1][$idx2], $HijI[$idx1][$idx2], $b, $lx, $ly, $lz, $ekrr, $ekri;
			my $err = abs($hij[$idx1][$idx2] - ($HijR[$idx1][$idx2] + i*$HijI[$idx1][$idx2]));
	if($err > 0.01) {
		print "  AF:H[$idx1][$idx2]($s[$idx1]-$s[$idx2])=$hij[$idx1][$idx2] ($HijR[$idx1][$idx2], $HijI[$idx1][$idx2]) err=$err\n";
		print "     phi: 111=$ph111, 1mm=$ph1mm, m1m=$phm1m, mm1=$phmm1\n";
		print "     Error too large\n" if($err > 0.01);
		$IsPrintedHij = 1;
	}
}
else {
	printf "Hij[$idx1][$idx2]: r = %8.4f ($is1:$name1, $OrbName1)-($is2:$name2, $OrbName2, ixyz=$ix,$iy,$iz): VS=%8.4f VP=%8.4f\n",
			$r, $VS, $VP                                if($pParams->{PrintLevel} >= 1);
#printf "  Hij[%2d][%2d]=(%8.4f,%8.4f) = exp(2pi * i *%8.4f)) * %8.4f\n",
#		$idx1, $idx2, $HijR[$idx1][$idx2], $HijI[$idx1][$idx2], $phi, $b if($pParams->{PrintLevel} >= 1);
	printf "    [ekr=(%8.4f, %8.4f)  b=%8.4f (lxyz=%3.1f,%3.1f,%3.1f)]\n",
				$ekrr, $ekri,$b, $lx, $ly, $lz              if($pParams->{PrintLevel} >= 2);
#print "     x: ($x1,$y1,$z1)-($x2,$y2,$z2)/($x2r,$y2r,$z2r) = dx=($dx,$dy,$dz)\n";
	$IsPrintedHij = 1;
}

			}
			}
			}
}
#print "\n" if($IsPrintedHij);
		}
	}

	for(my $i = 0  ; $i < $nOrb ; $i++) {
		for(my $j = $i+1 ; $j < $nOrb ; $j++) {
			$HijR[$j][$i] =  $HijR[$i][$j];
			$HijI[$j][$i] = -$HijI[$i][$j];
		}
	}
#exit;

if($pParams->{UseZincBlendAnalyticalForm}) {
print "HijR($kx,$ky,$kz)=\n";
&PrintMatrix(\@HijR);
print "\n";
print "HijI($kx,$ky,$kz)=\n";
&PrintMatrix(\@HijI);
print "\n";

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 $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;
}
if(($l1 >= 1 or $l2 >= 1) and !defined $etaP) {
	print "Error: Can not find eta{$oname1${oname2}P}\n";
	exit;
}
if(($l1 >= 2 and $l2 >= 2) and !defined $etaD) {
	print "Error: Can not find eta{$oname1${oname2}D}\n";
	exit;
}
if($l1 >= 3 or $l2 >= 3) {
	print "Error: Orbital [l=$l1 or l=$l2] is not supported\n";
	exit;
}

# For sd, pd
	if($l1 < 2 and $l2 == 2) {
		my $c = $h2m * $rd{$name2}**1.5 / $d**3.5;
		return ($c*$etaS, $c*$etaP, $c*$etaD);
	}
	elsif($l1 == 2 and $l2 < 2) {
		my $c = $h2m * $rd{$name1}**1.5 / $d**3.5;
		return ($c*$etaS, $c*$etaP, $c*$etaD);
	}
# For dd
	elsif($l1 == 2 and $l2 == 2) {
		my $c = $h2m * (($rd{$name1}+$rd{$name2})/2.0)**3.0 / $d**5.0;
		return ($c*$etaS, $c*$etaP, $c*$etaD);
	}

# For ss, sp
	my $c = $h2m / $d / $d;
	return ($c*$etaS, $c*$etaP, $c*$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();
		next if($line =~ /^\s*#/);

		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();
		next if($line =~ /^\s*#/);

		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();
		next if($line =~ /^\s*#/);

		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 'kd') {
				$kd{$Atom} = $val;
			}
			elsif($key eq 'rc') {
				$rc{$Atom} = $val;
			}
			elsif($key eq 'ri') {
				$ri{$Atom} = $val;
			}
			elsif($key eq 'ro') {
				$ro{$Atom} = $val;
			}
			elsif($key eq 'rd') {
				$rd{$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";
}

