#!/usr/local/bin/perl # Script to extract nomrmal modes from the G90 output file. # The OUT file may be the result of single calculations with # link line (like example 6.15 in G90 manual) or a result of # a separate restart with FREQ keyword from checkpoint file. # The first task is to find out if OUT contains two runs # (geometry optimization followed by frequences) or just one. # Then if 2 runs, skip the portion of file up to and including # first @ (it ends the result summary portion for geometry optimization). # Then search for "Z-Matrix orientation:" string (if C1 symmetry # and for "Standard orientation:" if symmetry used. Skip # 4 lines and collect cartesian coordinates in the array # until you reach line of "--------------". Count the atoms. # Then search for the "Frequencies ---" string, which # starts first portion of the table of frequences and # normal modes. It looks like: # Frequencies --- 278.9971 314.8132 452.1797 864.0812 962.6147 # Reduced masses --- 1.0702 1.1263 2.7343 1.0824 2.1573 # Force constants --- 0.0491 0.0658 0.3294 0.4761 1.1778 # IR Intensities --- 16.3380 137.0003 14.8384 2.4492 9.6849 # Raman Activities --- 0.4115 2.3307 0.7819 0.2060 11.2770 # Depolarizations --- 0.7439 0.7405 0.4521 0.6779 0.2744 # Coord Atom Element: # 6 1 6 0.00129 -0.00502 0.07478 -0.03799 -0.05805 # 6 1 6 -0.00805 0.03163 0.11205 0.02176 -0.08881 # 6 1 6 0.00304 -0.01473 -0.15222 0.00036 0.19568 # etc. # The Coord column is probably the (frequency number - 1) for first column # but beats me. There are 5 columns in each portion. Skip first column. Next is # an atom number (X, Y, Z for each atom, correspond to succesive rows, I # presume), then the atomic number), then normal modes. These need to be # collected in arrays. The 2nd and 3rd column can be used for consistency # checking. There should be 3N rows in each portion of the matrix. # Then you search for another "Frequencies ---" and check if you have # all 5 columns or if this is a last portion with less columns. # There is a second version of this table in G90 output file, which # lists 3 frequences and XYZ modes for each atom, but normal modes # have only two digits after decimal point. # Now how the data are printed? They are printed as required by xmol # to display frequences. Each normal mode is printed as a separate file # with an extension nu1 ... nu(3N-6). The root of file name is taken from # as everything from the beginning of output file name from GAUSSIAN up to # first period. The OUT file name from G90 is given on the command line. # die "You did not give G90 output file name as argument\n" if $#ARGV < 0; die "You need only one parameter --- G90 output file name\n" if $#ARGV > 0; $G90OUT = $ARGV[0]; $G90OUT =~ /([\w\/+#-]+)/; $OUT_root = $1; @at_symbols = ('H ', 'He', 'Li', 'Be', 'B ', 'C ', 'N ', 'O ', 'F ', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P ', 'S ', 'Cl', 'Ar', 'K ', 'Ca', 'Ti', 'V ', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'X '); open(G90OUT,"<$G90OUT") || die "Could not open $G90OUT\n"; #check if 1 or 2 @ signes in the file. Check is symmetry $n_runs = 0; $symmetry = 1; #default is symmetry while() { $n_runs++ if /@/; $symmetry = 0 if /FULL\s+POINT\s+GROUP\s+C1/; } die "No @ sign found in the G90 output file\n" if $n_runs == 0; seek(G90OUT, 0, 1); #clean EOF status seek(G90OUT, 0, 0); #rewind G90OUT file if($n_runs == 2) { #skipp after 1st @ if 2 runs while ($_ = ) { last if ($_ =~ /@/); } } #now search for "Z-Matrix orientation:" line if no symmetry #or Standard orientation: is symmetry while () { if($symmetry == 0) { last if /Z-Matrix orientation:/; } else { last if /Standard orientation:/; } } #skip 4 lines for ($i = 0; $i < 4; $i++ ) { $line = ; } #now collect cartesian coordinates in an array $n_at = 0; while ($line = ) { last if ($line =~ /--------------------/); # when last line $n_at++; $line =~ /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/; die "Unstandard format of G90 output file\n" if $1 != $n_at; if($2 < $#at_symbols) { $at_symb[$n_at] = $at_symbols[$2-1]; } else { $at_symb[$n_at] = $at_symbols[$#at_symbols]; } $at_num[$n_at] = $2; $x_coor[$n_at] = $3; $y_coor[$n_at] = $4; $z_coor[$n_at] = $5; } #search for line: "Low frequencies ---" which starts frequences block while ($line = ) { last if ($line =~ /Low frequencies ---/); } $n_cols = 3*$n_at-6; #will be decremented by number of processed modes $n_col_num = 0; while($n_cols > 0) { if($n_cols >= 5) { $n_curr_cols = 5; } else { $n_curr_cols = $n_cols; } #open files for modes in the xmol format if($n_curr_cols >= 1) { $k = $n_col_num + 1; # Which frequency we are" $temp = sprintf("%d",$k); $NU1F = $OUT_root . '.nu' . $temp; open(NU1F,">$NU1F") || die "Could not open $NU1F\n"; } #open files for modes in the xmol format if($n_curr_cols >= 2) { $k = $n_col_num + 2; # Which frequency we are" $temp = sprintf("%d",$k); $NU2F = $OUT_root . '.nu' . $temp; open(NU2F,">$NU2F") || die "Could not open $NU2F\n"; } #open files for modes in the xmol format if($n_curr_cols >= 3) { $k = $n_col_num + 3; # Which frequency we are" $temp = sprintf("%d",$k); $NU3F = $OUT_root . '.nu' . $temp; open(NU3F,">$NU3F") || die "Could not open $NU3F\n"; } #open files for modes in the xmol format if($n_curr_cols >= 4) { $k = $n_col_num + 4; # Which frequency we are" $temp = sprintf("%d",$k); $NU4F = $OUT_root . '.nu' . $temp; open(NU4F,">$NU4F") || die "Could not open $NU4F\n"; } #open files for modes in the xmol format if($n_curr_cols >= 5) { $k = $n_col_num + 5; # Which frequency we are" $temp = sprintf("%d",$k); $NU5F = $OUT_root . '.nu' . $temp; open(NU5F,">$NU5F") || die "Could not open $NU5F\n"; } $search_expr = 'Frequencies ---' . ('\s+(\S+)' x $n_curr_cols); $i = 0; while ($line = ) { $i++; if($i > 10) { die "Could not find Frequencies --- in OUT file\n"; } if($line =~ /$search_expr/) { if($n_curr_cols >= 1) { $vib_freq[1] = $1; printf NU1F "%d\nNU=%f\n",$n_at, $vib_freq[1]; } if($n_curr_cols >= 2) { $vib_freq[2] = $2; printf NU2F "%d\nNU=%f\n",$n_at, $vib_freq[2]; } if($n_curr_cols >= 3) { $vib_freq[3] = $3; printf NU3F "%d\nNU=%f\n",$n_at, $vib_freq[3]; } if($n_curr_cols >= 4) { $vib_freq[4] = $4; printf NU4F "%d\nNU=%f\n",$n_at, $vib_freq[4]; } if($n_curr_cols >= 5) { $vib_freq[5] = $5; printf NU5F "%d\nNU=%f\n",$n_at, $vib_freq[5]; } last; } } $i = 0; while ($line = ) { $i++; if($i > 10) { die "Could not find Coord Atom Element: in OUT file\n"; } if($line =~ /Coord Atom Element:/) { last; } } $search_expr = '\S+\s+(\S+)\s+(\S+)' . ('\s+(\S+)' x $n_curr_cols); for ($n = 1; $n <= $n_at; $n++) { if($n_curr_cols >= 1) { printf(NU1F " %2s %11.5f %11.5f %11.5f", $at_symb[$n], $x_coor[$n], $y_coor[$n], $z_coor[$n]); } if($n_curr_cols >= 2) { printf(NU2F " %2s %11.5f %11.5f %11.5f", $at_symb[$n], $x_coor[$n], $y_coor[$n], $z_coor[$n]); } if($n_curr_cols >= 3) { printf(NU3F " %2s %11.5f %11.5f %11.5f", $at_symb[$n], $x_coor[$n], $y_coor[$n], $z_coor[$n]); } if($n_curr_cols >= 4) { printf(NU4F " %2s %11.5f %11.5f %11.5f", $at_symb[$n], $x_coor[$n], $y_coor[$n], $z_coor[$n]); } if($n_curr_cols >= 5) { printf(NU5F " %2s %11.5f %11.5f %11.5f", $at_symb[$n], $x_coor[$n], $y_coor[$n], $z_coor[$n]); } for ($i = 1; $i <= 3; $i++) { $line = ; if( !($line =~ $search_expr)) { die "Unstandard format of G90 OUTPUT file\n"; } if($n != $1) { die "Unstandard format of G90 OUTPUT file --- mode line\n"; } if($at_num[$n] != $2) { die "Unstandard format of G90 OUTPUT file --- at. num. wrong\n"; } if($n_curr_cols >= 1) { $f = $3; printf NU1F " %11.5f", $f; } if($n_curr_cols >= 2) { $f = $4; printf NU2F " %11.5f", $f; } if($n_curr_cols >= 3) { $f = $5; printf NU3F " %11.5f", $f; } if($n_curr_cols >= 4) { $f = $6; printf NU4F " %11.5f", $f; } if($n_curr_cols >= 5) { $f = $7; printf NU5F " %11.5f", $f; } } # for $i if($n_curr_cols >= 1) { printf NU1F "\n"; } if($n_curr_cols >= 2) { printf NU2F "\n"; } if($n_curr_cols >= 3) { printf NU3F "\n"; } if($n_curr_cols >= 4) { printf NU4F "\n"; } if($n_curr_cols >= 5) { printf NU5F "\n"; } } # for $n if($n_curr_cols >= 1) { close(NU1F); } if($n_curr_cols >= 2) { close(NU2F); } if($n_curr_cols >= 3) { close(NU3F); } if($n_curr_cols >= 4) { close(NU4F); } if($n_curr_cols >= 5) { close(NU5F); } $n_col_num += $n_curr_cols; $n_cols -= $n_curr_cols; } # while close(G90OUT);