#!/usr/bin/perl use strict; # top2psf - a tool designed to take a GROMACS topology and construct a .psf file for use with VMD. # The purpose of this tool is to make use of bond information in, e.g. coarse grain structures. # # The program takes a GROMACS topology file as its input. # # PLEASE NOTE: This program is written very specifically for MARTINI topologies (i.e., the # pattern matching expects the layout to be based on the order of the topology and the # comments therein. # # Version 1.0 (10/19/2009) # # Written by Justin Lemkul (jalemkul[at]vt[dot]edu) # Distributed under the GNU General Public License # unless(@ARGV) { print "Usage: $0 -i (topology filename) -o (output filename)\n"; exit; } # define input hash my %options = @ARGV; # open input my $input; if (defined($options{"-i"})) { $input = $options{"-i"}; } else { print "No input defined.\n"; exit; } # store the input topology in an array open(IN, $input) or die "Cannot open $input: $!\n"; my @topology_in = ; close(IN); # open output my $output; if (defined($options{"-o"})) { $output = $options{"-o"}; } else { print "No output defined.\n"; exit; } # Determine how many atoms and residues are in the protein my $last_res; my $last_atom; for (my $i=0; $i>$output") or die "Cannot open $output: $!\n"; print OUT "PSF\n"; print OUT "\n"; printf OUT "%8d !NTITLE\n", 10; printf OUT "%8s topology generated by top2psf\n", "REMARKS"; printf OUT "%8s topology $input\n", "REMARKS"; printf OUT "%8s topology from GROMACS\n", "REMARKS"; printf OUT "%8s segment P1 { first NTER\; last CTER\; auto angles dihedrals }\n", "REMARKS"; printf OUT "%8s patch NTER P1:1\n", "REMARKS"; printf OUT "%8s patch CTER P1:%d\n", "REMARKS", $last_res; printf OUT "%8s\n", "REMARKS"; printf OUT "%8s\n", "REMARKS"; printf OUT "%8s\n", "REMARKS"; printf OUT "%8s\n", "REMARKS"; printf OUT "\n"; # Print out the header of the atoms section printf OUT "%8d !NATOM\n", $last_atom; # Idea is to run thru the array (topology file), matching the directives (atoms, bonds, etc) for (my $i=0; $i>atoms") or die "Cannot open atoms for writing: $!\n"; for (my $j=$i; $j>bonds") or die "Cannot open bonds for writing: $!\n"; for (my $j=$i; $j>angles") or die "Cannot open angles for writing: $!\n"; for (my $j=$i; $j>dihedrals") or die "Cannot open dihedrals for writing: $!\n"; # dihedrals are the last entry in a MARTINI topology # impropers first, then propers - will need to split this later for (my $j=$i; $j; close(NEW_ATOM_IN); shift(@atoms); # get rid of [ atoms ] directive header my $atom_num; my $res_num; my $res_name; my $atom_name; my $atom_type; my $charge; my $mass; foreach $_ (@atoms) { my @info = split(" ", $_); $atom_num = $info[0]; $atom_type = $info[1]; $res_num = $info[2]; $res_name = $info[3]; $atom_name = $info[4]; $charge = $info[6]; $mass = $info[7]; printf OUT "%8d P1 %4d%7s %-4s %-3s%12.6f%14.4f%12d\n", $atom_num, $res_num, $res_name, $atom_name, $atom_type, $charge, $mass, 0; } # space between atoms and bonds section print OUT "\n"; # Write bonds section to .psf file open(NEW_BOND_IN, "; close(NEW_BOND_IN); shift(@bonds); # get rid of [ bonds ] directive header shift(@bonds); # get rid of comment line # clean up comments, newlines, and [ constraints ] directive within [ bonds ] section for (my $i=0; $i>bonds_fix") or die "Cannot open bonds_fix for writing: $!\n"; chomp(@bonds); # remove newlines # clean up array, remove function types my @bonds_clean; foreach $_ (@bonds) { chop($_); push(@bonds_clean, $_); } # The checks in this section may not be entirely necessary, since the @bonds array # was cleaned previously. In any case, it works, so I won't mess with it. for (my $i=0; $i; close(BONDS_FIX); foreach $_ (@bonds_fix) { print OUT $_; } # Add space between bonds and angles print OUT "\n"; open(NEW_ANGLE_IN, "; close(NEW_ANGLE_IN); shift(@angles); # remove [ angles ] directive shift(@angles); # remove column headers my $number_of_angles = scalar(@angles); printf OUT "%8d !NTHETA: angles\n", $number_of_angles; # assemble the angle lines open(NEW_ANGLE_OUT, ">>angles_fix") or die "Cannot open angles_fix for writing: $!\n"; chomp(@angles); # remove newlines # clean up array, remove function types my @angles_clean; foreach $_ (@angles) { chop($_); push(@angles_clean, $_); } for (my $i=0; $i; close(ANGLES_FIX); foreach $_ (@angles_fix) { print OUT $_; } # print space between angle and dihedral section print OUT "\n"; open(NEW_DIH_IN, "; close(NEW_DIH_IN); shift(@dihedrals); # remove [ dihedrals ] directive shift(@dihedrals); # remove comment lines # This part is very MARTINI-specific, since the [ dihedrals ] directive is formatted # differently from the standard GROMACS setup. Normally, there are two [ dihedrals ] # directives, but in MARTINI there is only one, with comment lines separating the # impropers from the propers. my $improper_count = 0; open(IMPROPERS, ">>impropers") or die "Cannot open impropers for writing: $!\n"; for (my $j=0; $j>propers") or die "Cannot open propers for writing: $!\n"; for (my $k=0; $k>propers_fix") or die "Cannot open propers_fix for writing: $!\n"; chomp(@dihedrals); # remove newlines # clean up array, remove function types my @dihedrals_clean; foreach $_ (@dihedrals) { chop($_); push(@dihedrals_clean, $_); } for (my $i=0; $i; close(PROPERS_FIX); foreach $_ (@propers_fix) { print OUT $_; } # Print space between dihedrals and impropers section print OUT "\n"; open(NEW_IMPROPER, "; close(NEW_IMPROPER); my $number_of_impropers = scalar(@impropers); printf OUT "%8d !NIMPHI: impropers\n", $number_of_impropers; # assemble the angle lines open(NEW_IMPROPER_OUT, ">>impropers_fix") or die "Cannot open impropers_fix for writing: $!\n"; chomp(@impropers); # remove newlines # clean up array, remove function types my @impropers_clean; foreach $_ (@impropers) { chop($_); push(@impropers_clean, $_); } for (my $i=0; $i; close(IMPROPERS_FIX); foreach $_ (@impropers_fix) { print OUT $_; } # Now, some other sections that don't actually depend on the topology print OUT "\n"; printf OUT "%8d !NDON: donors\n", 0; print OUT "\n\n"; printf OUT "%8d !NACC: acceptors\n", 0; print OUT "\n\n"; printf OUT "%8d !NNB\n", 0; print OUT "\n\n"; printf OUT "%8d%8d !NGRP\n", 1, 0; printf OUT "%8d%8d%8d\n", 0, 0, 0; close(OUT); # Clean up unlink "atoms"; unlink "bonds"; unlink "bonds_fix"; unlink "angles"; unlink "angles_fix"; unlink "dihedrals"; unlink "impropers"; unlink "impropers_fix"; unlink "propers"; unlink "propers_fix";