Новосибирский институт органической химии им. Н.Н. Ворожцова СО РАН

Лаборатория изучения механизмов органических реакций

fchk2xyz


#!/usr/bin/perl -ws

our ($h,$help);
(my $program = $0) =~ s/^.*[\/\\]//;

if ($h || $help) {
  print <<H;

Gaussian fchk to xyz convertor (for IRC tasks)

Usage: $0 checkpoint.fchk > IRC.xyz

H
  exit;
}

die "Usage: $0 checkpoint.fchk > IRC.xyz\n" unless @ARGV==1;

# atom names (periodic table)
@atname = qw (XX
        H                                                  He
        Li Be                               B  C  N  O  F  Ne
        Na Mg                               Al Si P  S  Cl Ar
        K  Ca Sc Ti V  Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr
        Rb Sr Y  Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I  Xe
        Cs Ba La
                Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu
                 Hf Ta W  Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn
        Fr Ra Ac
                Th Pa U  Np Pu Am Cm Bk Cf Es Fm Md No Lr
       );

#use Data::Dump 'pp';

#my %chk = read_fchk('STDIN', 'Number of atoms', 'Atomic numbers');
my %chk = read_fchk($ARGV[0]);
#pp keys(%chk);

my $N = $chk{'Number of atoms'};
my @atom = map {$atname[$_]} @{$chk{'Atomic numbers'}};
my $IRC_steps = $chk{'IRC Number of geometries'}[0];

my $charge = $chk{Charge} if $chk{Charge} != 0;
my $mult = $chk{Multiplicity} if $chk{Multiplicity} != 1;

my @energy = @{$chk{'IRC point       1 Results for each geome'}};
my @coord = @{$chk{'IRC point       1 Geometries'}};
my @grad = @{$chk{'IRC point       1 Gradient at each geome'}};

my @mols;
if (grep {m/^IRC/} keys %chk) {
  for (my $i=0; $i<$IRC_steps; $i++) {
    $mols[$i][0]{Energy} = $energy[2*$i];
    $mols[$i][0]{Rx_Coord} = $energy[2*$i+1];
    $mols[$i][0]{Charge} = $charge if $charge;
    $mols[$i][0]{Mult} = $mult if $mult;
    $mols[$i][0]{Gradient} = sqrt(sum(map {$_*$_} @grad[$i*$N*3..($i+1)*$N*3-1]));
    for (my $j=1; $j<=$N; $j++) {
      $mols[$i][$j][0] = $atom[$j-1];
      $mols[$i][$j][1] = $coord[3*($N*$i+$j-1)]*0.529177249;
      $mols[$i][$j][2] = $coord[3*($N*$i+$j-1)+1]*0.529177249;
      $mols[$i][$j][3] = $coord[3*($N*$i+$j-1)+2]*0.529177249;
    }
  }

  my (@mol_p,@mol_m);
  foreach my $mol (@mols) {
    if ($mol->[0]{Rx_Coord}<0) {
      push @mol_m, $mol;
    } 
    else {
      push @mol_p, $mol;
    }
  }
  @mols = (reverse(@mol_m), @mol_p);
}
else {
  warn "No IRC data found\n";
}

#pp @mols;
write_molden(@mols) if @mols;


sub read_fchk {
  my %chk;
  my $file = shift;
  open L, '<', $file or die "Can't open $file: $!\n";
  while (<L>) {
    my ($item,$IR,$is_array,$rest) = unpack("A43 A1 x3 A2 A*", $_);
    next if $item =~ /^ /;
    next if $IR !~ /[IR]/;
    $item =~ s/\s+$//;
    if ($is_array eq 'N=') {
      my $n = 0+$rest;
      my @a;
      while (@a < $n) {
        push @a, split(' ', <L>);
      }
      die "Bad for $item\n" if @a != $n;
      $chk{$item} = \@a;
    }
    else {
      $rest =~ s/^\s+//;
      $chk{$item} = $rest;
    }
  }
  close L;
  return %chk;
}

sub write_molden {
  my $fh;
  unless (ref $_[-1]) {
    my $file = pop @_;
    open $fh, '>', $file or do {warn "Can't write to $file: $!\n"; return};
  }
  else {
    $fh = 'STDOUT';
  }
  foreach my $mol (@_) {;
    my $N = $#{$mol};
    print $fh " $N\n";
    printf $fh " Energy %.8f", $mol->[0]{Energy} if defined $mol->[0]{Energy};
    printf $fh "  Rx_Coord %.4f", $mol->[0]{Rx_Coord} if defined $mol->[0]{Rx_Coord};
    printf $fh "  Gradient %.8f", $mol->[0]{Gradient} if defined $mol->[0]{Gradient};
    print  $fh "  Charge $mol->[0]{Charge}" if defined $mol->[0]{Charge};
    print  $fh "  Mult $mol->[0]{Mult}" if defined $mol->[0]{Mult};
    print  $fh "  Symmetry $mol->[0]{Symmetry}" if $mol->[0]{Symmetry};
    print  $fh "\n";
    for (my $i=1; $i<=$N; $i++) {
      printf $fh " %-2s %12.8f %12.8f %12.8f\n", @{$mol->[$i]};
    }
  }
  close $fh if $fh ne 'STDOUT';
}

sub sum {
  my $sum = 0;
  foreach (@_) {
    $sum += $_;
  }
  return $sum;
}