#!/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 <