416 lines
11 KiB
Perl
Executable File
416 lines
11 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
use strict;
|
|
#use List::MoreUtils qw / pairwise/;
|
|
use File::Temp qw/ tempfile tempdir /;
|
|
use File::Copy;
|
|
use Getopt::Long;
|
|
|
|
my $conf = {"cleanup" => 0, "oute"=> "energy", "name" => "XYZ"};
|
|
my $RUN_PREFIX = ""; #"mpirun --host node10,node11 -np 8";
|
|
my $siesta = "siesta";
|
|
my $PSEUDODIR = "/home/gkolesov/run/Pseudo/GGA";
|
|
$PSEUDODIR = $ENV{PSEUDODIR} if $ENV{PSEUDODIR};
|
|
$PSEUDODIR = $ENV{SIESTA_PSEUDO} if $ENV{SIESTA_PSEUDO};
|
|
|
|
my @argv_orig = @ARGV;
|
|
GetOptions(
|
|
"c|cleanup!" => \$conf->{cleanup},
|
|
"v|verbose!" => \$conf->{verbose},
|
|
"n|dry!" => \$conf->{dry},
|
|
"o|oute=s" => \$conf->{oute},
|
|
"x|name=s" => \$conf->{name},
|
|
"e|cmd=s" => \$siesta,
|
|
"p|ppdir=s" => \$PSEUDODIR,
|
|
"r|runprefix=s" => \$RUN_PREFIX,
|
|
"h|help!" => \&print_usage_and_die,
|
|
);
|
|
|
|
|
|
if(@ARGV>0){
|
|
my $remotecmd = pop @argv_orig;
|
|
print STDERR "ARGV: @ARGV\n";
|
|
$remotecmd = "@ARGV" if @ARGV>1;
|
|
#$remotecmd = "node" unless defined $remotecmd;
|
|
|
|
exit( mysystem("$remotecmd runstruct_siesta @argv_orig") );
|
|
|
|
}
|
|
|
|
|
|
my $anumber = atom_number_table();
|
|
|
|
my ($lvec,$atoms) = parse_strout("str.out");
|
|
my $ddd =1;
|
|
|
|
# make_fdf("/tmp/y", $lvec, $atoms);
|
|
my $E=run_siesta($lvec,$atoms);
|
|
if($E==99999.){
|
|
open(my $fw, '>', 'error') || die "Can not open file for writing: $!";
|
|
close $fw;
|
|
}
|
|
|
|
print "E = $E\n" if $conf->{verbose};
|
|
unless($conf->{dry}){
|
|
open(my $fw, '>', $conf->{oute}) || die "Can not open file: $!";
|
|
print $fw $E;
|
|
close $fw;
|
|
}
|
|
|
|
sub make_fdf{
|
|
my ($fname,$lvec,$atoms) = @_;
|
|
|
|
my %h=();
|
|
my $k = 1;
|
|
foreach my $a (@$atoms){
|
|
$h{$a->{type}} = $k++ unless defined $h{$a->{type}};
|
|
}
|
|
|
|
my $acnt = scalar keys %h;
|
|
|
|
open(my $fw, '>', $fname) || die "Can not open file for writing: $!";
|
|
print $fw siesta_head();
|
|
print $fw "SystemLabel $conf->{name}\n";
|
|
print $fw "LatticeConstant 1.0 Ang\n";
|
|
print $fw "Number_of_species $acnt\n";
|
|
print $fw "NumberOfAtoms ",scalar @$atoms,"\n\n";
|
|
print $fw "%block Chemical_Species_label\n";
|
|
foreach my $t (sort {$h{$a} <=> $h{$b}} keys %h){
|
|
printf $fw " %-2d %-3d %s\n", $h{$t}, $anumber->{$t}, $t;
|
|
}
|
|
print $fw "%endblock Chemical_Species_label\n\n";
|
|
print $fw "%block LatticeVectors\n";
|
|
foreach my $v (@$lvec){
|
|
printf $fw " % -3.8f % -3.8f % -3.8f\n", @$v;
|
|
}
|
|
print $fw "%endblock LatticeVectors\n\n";
|
|
|
|
print $fw "%block AtomicCoordinatesAndAtomicSpecies\n";
|
|
foreach my $a (@$atoms){
|
|
printf $fw " % -3.8f % -3.8f % -3.8f %d\n", @{$a->{coord}},
|
|
$h{$a->{type}};
|
|
}
|
|
print $fw "%endblock AtomicCoordinatesAndAtomicSpecies\n";
|
|
|
|
close $fw;
|
|
}
|
|
|
|
|
|
|
|
|
|
sub get_energy{
|
|
my ($siestaout) = @_;
|
|
|
|
open(my $fh, $siestaout) || die "Can not open file: $!";
|
|
my $readtot = 0;
|
|
my $energy = 99999.;
|
|
while(<$fh>){
|
|
if($readtot){
|
|
if(/^siesta.*?Total\s*=\s*(\S+)/i){
|
|
$energy = $1;
|
|
last;
|
|
}
|
|
next;
|
|
}
|
|
$readtot=1 if /^siesta:\s*Final\s+energy/;
|
|
|
|
}
|
|
close $fh;
|
|
return $energy;
|
|
}
|
|
|
|
sub run_siesta{
|
|
my ($lvec,$atoms) = @_;
|
|
my $tdir = "siesta.$conf->{name}"; #tempdir(DIR => "./", CLEANUP => $conf->{cleanup});
|
|
mkdir $tdir || die "Can not mkdir $tdir : $!";
|
|
chdir $tdir || die "Can not chdir into dir : $!";
|
|
|
|
my $fname = "$conf->{name}.fdf";
|
|
my $siestaout = "siesta.out";
|
|
make_fdf($fname, $lvec, $atoms);
|
|
|
|
my %atype = map {$_->{type} => 1} @$atoms;
|
|
foreach my $a (keys %atype){
|
|
if(-e "$PSEUDODIR/$a.psf"){
|
|
copy("$PSEUDODIR/$a.psf", "$a.psf");
|
|
}
|
|
else{
|
|
die "No pseudopotential for element $a is found.\n";
|
|
}
|
|
}
|
|
|
|
my $cmd = "$RUN_PREFIX $siesta < $fname > $siestaout";
|
|
|
|
mysystem($cmd);
|
|
|
|
my $E = get_energy($siestaout);
|
|
|
|
|
|
chdir "../" || die "Can not chdir ../ : $!";
|
|
if($conf->{cleanup}){
|
|
system("/bin/rm -rf $tdir");
|
|
}
|
|
|
|
return $E;
|
|
|
|
}
|
|
|
|
|
|
sub mysystem{
|
|
if($conf->{dry} || $conf->{verbose}){
|
|
print STDOUT "@_\n";
|
|
return system("/bin/true",3) if $conf->{dry} && $conf->{verbose};
|
|
return 0 if $conf->{dry};
|
|
}
|
|
|
|
return system(@_);
|
|
}
|
|
|
|
|
|
sub parse_strout{
|
|
my ($file) = @_;
|
|
|
|
open(my $fh, $file) || die "Can not open file: $!";
|
|
my @cvec = map {$_=<$fh>; [split] } (0..2);
|
|
my @lvec = map {$_=<$fh>; [split] } (0..2);
|
|
|
|
my @clvec = map {cvec2cart($_,\@cvec)} @lvec;
|
|
|
|
my @atoms = ();
|
|
while(<$fh>){
|
|
my @t = split /[\s,]+/;
|
|
my $a = pop @t;
|
|
my $v = cvec2cart(\@t,\@cvec);
|
|
push @atoms, {type => $a, coord => $v};
|
|
|
|
}
|
|
close $fh;
|
|
|
|
return (\@clvec,\@atoms);
|
|
}
|
|
|
|
sub cvec2cart{
|
|
my ($v,$cvec) = @_;
|
|
local $^W = 0;
|
|
|
|
#my @t=pairwise { [map {$a *$_} @$b] } @$v,@$cvec;
|
|
my @t = ();
|
|
for(my $i=0; $i<@$v; $i++){
|
|
my $a = $v->[$i];
|
|
my $b = $cvec->[$i];
|
|
push @t, [map {$a * $_} @$b];
|
|
}
|
|
|
|
my @l = ();
|
|
for(my $i=0; $i<3; $i++){
|
|
do { $l[$i]+=$_->[$i] } foreach @t;
|
|
}
|
|
|
|
return \@l;
|
|
|
|
}
|
|
|
|
sub atom_number_table{
|
|
my %t = (
|
|
"H" => 1 ,
|
|
"He" => 2 ,
|
|
"Li" => 3 ,
|
|
"Be" => 4 ,
|
|
"B" => 5 ,
|
|
"C" => 6 ,
|
|
"N" => 7 ,
|
|
"O" => 8 ,
|
|
"F" => 9 ,
|
|
"Ne" => 10 ,
|
|
"Na" => 11 ,
|
|
"Mg" => 12 ,
|
|
"Al" => 13 ,
|
|
"Si" => 14 ,
|
|
"P" => 15 ,
|
|
"S" => 16 ,
|
|
"Cl" => 17 ,
|
|
"Ar" => 18 ,
|
|
"K" => 19 ,
|
|
"Ca" => 20 ,
|
|
"Sc" => 21 ,
|
|
"Ti" => 22 ,
|
|
"V" => 23 ,
|
|
"Cr" => 24 ,
|
|
"Mn" => 25 ,
|
|
"Fe" => 26 ,
|
|
"Co" => 27 ,
|
|
"Ni" => 28 ,
|
|
"Cu" => 29 ,
|
|
"Zn" => 30 ,
|
|
"Ga" => 31 ,
|
|
"Ge" => 32 ,
|
|
"As" => 33 ,
|
|
"Se" => 34 ,
|
|
"Br" => 35 ,
|
|
"Kr" => 36 ,
|
|
"Rb" => 37 ,
|
|
"Sr" => 38 ,
|
|
"Y" => 39 ,
|
|
"Zr" => 40 ,
|
|
"Nb" => 41 ,
|
|
"Mo" => 42 ,
|
|
"Tc" => 43 ,
|
|
"Ru" => 44 ,
|
|
"Rh" => 45 ,
|
|
"Pd" => 46 ,
|
|
"Ag" => 47 ,
|
|
"Cd" => 48 ,
|
|
"In" => 49 ,
|
|
"Sn" => 50 ,
|
|
"Sb" => 51 ,
|
|
"Te" => 52 ,
|
|
"I" => 53 ,
|
|
"Xe" => 54 ,
|
|
"Cs" => 55 ,
|
|
"Ba" => 56 ,
|
|
"La" => 57 ,
|
|
"Ce" => 58 ,
|
|
"Pr" => 59 ,
|
|
"Nd" => 60 ,
|
|
"Pm" => 61 ,
|
|
"Sm" => 62 ,
|
|
"Eu" => 63 ,
|
|
"Gd" => 64 ,
|
|
"Tb" => 65 ,
|
|
"Dy" => 66 ,
|
|
"Ho" => 67 ,
|
|
"Er" => 68 ,
|
|
"Tm" => 69 ,
|
|
"Yb" => 70 ,
|
|
"Lu" => 71 ,
|
|
"Hf" => 72 ,
|
|
"Ta" => 73 ,
|
|
"W" => 74 ,
|
|
"Re" => 75 ,
|
|
"Os" => 76 ,
|
|
"Ir" => 77 ,
|
|
"Pt" => 78 ,
|
|
"Au" => 79 ,
|
|
"Hg" => 80 ,
|
|
"Tl" => 81 ,
|
|
"Pb" => 82 ,
|
|
"Bi" => 83 ,
|
|
"Po" => 84 ,
|
|
"At" => 85 ,
|
|
"Rn" => 86 ,
|
|
"Fr" => 87 ,
|
|
"Ra" => 88 ,
|
|
"Ac" => 89 ,
|
|
"Th" => 90 ,
|
|
"Pa" => 91 ,
|
|
"U" => 92 ,
|
|
"Np" => 93 ,
|
|
"Pu" => 94 ,
|
|
"Am" => 95 ,
|
|
"Cm" => 96 ,
|
|
"Bk" => 97 ,
|
|
"Cf" => 98 ,
|
|
"Es" => 99 ,
|
|
"Fm" => 100,
|
|
"Md" => 101,
|
|
"No" => 102,
|
|
"Lr" => 103,
|
|
"Rf" => 104,
|
|
"Db" => 105,
|
|
"Sg" => 106,
|
|
"Bh" => 107,
|
|
"Hs" => 108,
|
|
"Mt" => 109,
|
|
"Ds" => 110,
|
|
"Rg" => 111,
|
|
"Cn" => 112,
|
|
"Uut" => 113,
|
|
"Fl" => 114,
|
|
"Uup" => 115,
|
|
"Lv" => 116,
|
|
"Uus" => 117,
|
|
"Uuo" => 118
|
|
);
|
|
return \%t;
|
|
}
|
|
|
|
sub siesta_head{
|
|
foreach my $head ("siesta.wrap", "../siesta.wrap","../../siesta.wrap"){
|
|
if(-f $head){
|
|
open(my $fh, $head) || die "Can not open $head: $!";
|
|
local $/ = undef;
|
|
my $t = <$fh>;
|
|
close $fh;
|
|
return $t;
|
|
}
|
|
}
|
|
|
|
return <<SHEAD;
|
|
DM.MixingWeight 0.01
|
|
DM.Tolerance 0.001
|
|
DM.NumberPulay 5
|
|
# DM.Require.Energy.Convergence .true.
|
|
# DM.Energy.Tolerance 0.01
|
|
PAO.BasisSize dz
|
|
SolutionMethod diagon
|
|
AtomicCoordinatesFormat Ang
|
|
MaxSCFIterations 1000
|
|
SpinPolarized False
|
|
MeshCutoff 4081.709348 eV
|
|
LatticeConstant 1.0 Ang
|
|
|
|
|
|
%block kgrid_Monkhorst_Pack
|
|
5 0 0 0.5
|
|
0 5 0 0.5
|
|
0 0 5 0.5
|
|
%endblock kgrid_Monkhorst_Pack
|
|
|
|
MD.TypeOfRun CG # Type of dynamics:
|
|
MD.VariableCell .false.
|
|
#MD.NumCGsteps 50
|
|
#MD.NumCGsteps 1
|
|
|
|
WriteKbands .false.
|
|
WriteBands .false.
|
|
UseSaveData True
|
|
DM.UseSaveDM True
|
|
SHEAD
|
|
}
|
|
|
|
sub print_usage_and_die{
|
|
print STDERR <<USAGE;
|
|
$0 [OPTION] [remotecmd host]
|
|
-v, --verbose
|
|
-n, --dry Dry mode. Doesn't actually do anything, just
|
|
says what it would do
|
|
-c, --cleanup Remove siesta working directory (default=false)
|
|
-o, --oute File to write energy value into (default=energy)
|
|
-x, --name Siesta system name label and file prefix (default=XYZ)
|
|
-e, --cmd Siesta executable name (default=siesta)
|
|
-p, --ppdir Pseudopotential directory; can be set also with
|
|
environment variables PSEUDODIR or SIESTA_PSEUDO
|
|
-r, --runprefix siesta run prefix, e.g. "mpirun -np 4"
|
|
-h, --help print this message
|
|
|
|
AUTHOR:
|
|
Grigori Kolesov gkolesov@uwyo.edu
|
|
|
|
EXAMPLE:
|
|
pollmach runstruct_siesta -e siesta.static -p ~/run/Pseudo/GGA
|
|
|
|
If siesta.wrap file exists in the current directory or in ../ , or in
|
|
../../ the script will use it as a siesta input fdf file (and will add the
|
|
geometry and atomic specie setup), otherwise the default at the bottom of
|
|
this script will be used.
|
|
|
|
Note that the siesta.wrap file should not contain LatticeConstant and
|
|
SystemLabel fields which are also setup by the script.
|
|
|
|
If the ~/.machines.rc file is set up and contains something like
|
|
ssh node1 sar -u 1 1 | getvalue "Average: all" + node -s node1
|
|
the script should be able to run siesta via "node" script / ssh.
|
|
|
|
USAGE
|
|
exit(0);
|
|
}
|