#!/bin/awk -f

# reads Amber building block definition file(s) and converts to Gromacs
# Version 1.1
# Copyright (c) 2002
# Anton Feenstra - Vrije Universiteit Amsterdam - The Netherlands

function fill_with_underscores(s, n) {
  ss=s;
  while (length(ss)<n)
    ss=ss"_";
  return ss;
}

# keep track of which section ('card') of the residue entry we are reading
# if tp<0, 'type' is incremented
function next_type(tp) {
  if (tp>=0)
    type=tp;
  else
    type ++;
  if (debug) printf("Start reading section: %d = %s\n", type, section[type]);
}

# read list of dihedrals as defined in the ff files (written by amber2gmxff)
function read_dihs(file, dihs) {
  ndihs=0;
  printf("Reading dihs from '%s'... ", file);
  while ( 0<getline <file ) {
    n=split($0,d);
    for(i=0; i<n; i++)
      dihs[ndihs,i]=d[i+1];
    ndihs++;
  }
  close(file);
  if (ndihs)
    printf("Read %d dihs\n", ndihs);
  else
    warning("could not read dihs");
  return ndihs;
}

# locate dihedrals in list and return number of matches
function find_dih(ai, aj, ak, al, ndihs, dihs, found_dihs) {
  nmatch=0;
  dih[0]=ai; dih[1]=aj; dih[2]=ak; dih[3]=al; 
  for(fi=0; fi<ndihs; fi++) {
    bMatch=1;
    if (debug) printf(".");
    for(fd=0; fd<=1; fd++) { # forward and backward comparison
      for(fj=0; fj<4 && bMatch; fj++)
	if (dihs[fi,fj]!="X")
	  if (fd==0) # forward comparison
	    bMatch = (dihs[fi,fj]==dih[fj]);
	  else       # backward comparison
	    bMatch = (dihs[fi,fj]==dih[3-fj]);
      if (bMatch) {
	for(fj=0; fj<4; fj++)
	  found_dihs[nmatch,fj]=dihs[fi,fj];
	nmatch++;
      }
    }
  }
  return nmatch;
}

# write list of dihedrals
function dump_dihs(ndihs, dihs) {
  for(i=0; i<ndihs; i++) {
    printf("dih %d:", i);
    for(j=0; j<4; j++)
      printf(" %s", dihs[i,j]);
    printf("\n");
  }
}

function anm2atp(anmi, nat, anms, atps) {
  anm=anmi; 
  gsub("-","",anm); 
  gsub("\\+","",anm); 
  for(ii=0; ii<nat; ii++)
    if (anm==anms[ii])
      return atps[ii];
}

function is_hydrogen(anr) {
  return index(isymbl[anr], "H")==1;
}

function swap_atoms(atnr1, atnr2) {
  # swap array entries:
  dum=igraph[atnr1]; igraph[atnr1]=igraph[atnr2]; igraph[atnr2]=dum;
  dum=isymbl[atnr1]; isymbl[atnr1]=isymbl[atnr2]; isymbl[atnr2]=dum;
  for(_j=0; _j<3; _j++)
    dum=zz[atnr1,_j]; zz[atnr1,_j]=zz[atnr2,_j];  zz[atnr2,_j] =dum;
  dum=theta[atnr1];  theta[atnr1] =theta[atnr2];  theta[atnr2] =dum;
  dum=chg[atnr1];    chg[atnr1]   =chg[atnr2];    chg[atnr2]   =dum;
  dum=allM[atnr1];   allM[atnr1]  =allM[atnr2];   allM[atnr2]  =dum;
  dum=allMtp[atnr1]; allMtp[atnr1]=allMtp[atnr2]; allMtp[atnr2]=dum;
  # swap atom number references in z-matrix definition:
  for(_i=0; _i<nat; _i++)
    for(_j=0; _j<nat; _j++)
      if      (zz[_i,_j]==atnr1) zz[_i,_j]=atnr2;
      else if (zz[_i,_j]==atnr2) zz[_i,_j]=atnr1;
}

function warning(s) {
  printf("WARNING: %s\n", s);
  nwarn++;
}

function print_warn() {
  if (nwarn)
    printf("\nThere were %d warnings\n\n", nwarn);
}

function fatal_error(s) {
  if (nwarn) printf("(%d warnings pending)\n", nwarn);
  printf("\nFATAL ERROR: %s\n\n", s);
  xxit=1;
  exit -1;
}

BEGIN {
  if (ARGC < 2) {
    print("Usage:");
    print("amber2gmxrtp [ffname=<name>] [debug=1] all##.in");
    print("");
    print("Reads Amber residue database file (all##.in) and");
    print("writes Gromacs residue topology file (ff<name>.rtp),");
    print("Gromacs hydrogen database file (ff<name>.hdb),");
#    print("and Gromacs termini database files (ff<name>-[cn].tdb).");
    print("NOTE: For the time being, termini are implemented as");
    print("additional residues in the ff<name>.rtp as entries with");
    print("residue names '<res>-C' or '<res>-N'.");
    print("Default for <name> in output files is 'amber'.");
    print("");
    print("Use 'debug=1' for extremely verbose output.");
    print("");
    xxit=1;
    exit;
  }
  if ( !ffname ) ffname="amber";
  ffrtp = "ff" ffname ".rtp";
  ffhdb = "ff" ffname ".hdb";
  ffctdb = "ff" ffname "-c.tdb";
  ffntdb = "ff" ffname "-n.tdb";
  ffpdihs = ffname "-dihedrals.txt";
  ffidihs = ffname "-impropers.txt";
  nptps=read_dihs(ffpdihs, pdihtps);
  nitps=read_dihs(ffidihs, idihtps);
  if (debug) dump_dihs(nptps, pdihtps);
  if (debug) dump_dihs(nitps, idihtps);
  warning("NOTE: .tdb not implemented yet (dummy files will be written).");
  printf("Sending output to: %s\n", ffrtp);
  printf("; Amber forcefield converted to Gromacs\n") > ffrtp;
  printf("; \n") > ffrtp;
  type=0;
  nres=0; # residues
  nM=0;
  bM=0;
  # declare sections and names (order corresponds to amber file format)
  section[tp_RES_TIT=0]="residue title";
  section[tp_OUT_FIL=1]="output file";
  section[tp_RES_NAM=2]="residue name";
  section[tp_GEO_TYP=3]="geometry type";
  section[tp_LOO_CUT=4]="loop cutoff";
  section[tp_ATOMS  =5]="atoms";
  section[tp_EXTRAS =6]="extras";
  section[tp_CHARGE =7]="charge";
  section[tp_LOOP   =8]="loop";
  section[tp_IMP_DIH=9]="improper";
  
  # database types (third number on first line):
  db_tp[db_tp_UNI    =1  ]="United-atom";
  db_tp[db_tp_UNI_NT =100]="United-atom, NH3+ terminal";
  db_tp[db_tp_UNI_CT =101]="United-atom, COO- terminal";
  db_tp[db_tp_ALL    =2  ]="All-atom";
  db_tp[db_tp_ALL_NT =200]="All-atom, NH3+ terminal";
  db_tp[db_tp_ALL_CT =201]="All-atom, COO- terminal";
  db_tp[db_tp_OPLS   =3  ]="OPLS United-atom";
  db_tp[db_tp_OPLS_NT=300]="OPLS United-atom, NH3+ terminal";
  db_tp[db_tp_OPLS_CT=301]="OPLS United-atom, COO- terminal";
  db_suf[db_tp_UNI]=db_suf[db_tp_ALL]=db_suf[db_tp_OPLS]="";
  db_suf[db_tp_UNI_NT]=db_suf[db_tp_ALL_NT]=db_suf[db_tp_OPLS_NT]="-N";
  db_suf[db_tp_UNI_CT]=db_suf[db_tp_ALL_CT]=db_suf[db_tp_OPLS_CT]="-C";
  db_pre[db_tp_UNI_NT]=db_pre[db_tp_ALL_NT]=db_pre[db_tp_OPLS_NT]=1;
  # marker for z-matrix entries that should be ignored:
  zz_NONE=-12345;
  
  # declare hydrogen database hydrogen addition types (Gromacs manual p 95)
  # atom orders:
  hotp[htp_o_IJK =0,0]=0; hotp[htp_o_IJK,1]=1; hotp[htp_o_IJK,2]=2;
  hotp[htp_o_JIK =1,0]=0; hotp[htp_o_JIK,1]=1; hotp[htp_o_JIK,2]=-1;
  hotp[htp_o_JKI =2,0]=0; hotp[htp_o_JKI,1]=-1; hotp[htp_o_JKI,2]=1;
  hotp[htp_o_JIKL=3,0]=0; hotp[htp_o_JIKL,1]=1;
  hotp[htp_o_JIKL,2]=-2; hotp[htp_o_JIKL,3]=-1;
  hotp[htp_o_I   =4,0]=0;
  hotp[htp_o_ACE =5,0]=0; hotp[htp_o_ACE,1]=-1; hotp[htp_o_ACE,2]=-2;
  # the actual hydrogen types:
  htp_n[htp_NONE   =-12345]=1;
  htp_n[htp_PLANE  =1]=3; htp_o[htp_PLANE  ]=htp_o_JIK;
  htp_n[htp_SINGLE =2]=3; htp_o[htp_SINGLE ]=htp_o_IJK;
  htp_n[htp_2PLANE =3]=3; htp_o[htp_2PLANE ]=htp_o_IJK;
  htp_n[htp_TTETRA =4]=3; htp_o[htp_TTETRA ]=htp_o_IJK;
  htp_n[htp_1TETRA =5]=4; htp_o[htp_1TETRA ]=htp_o_JIKL;
  htp_n[htp_2TETRA =6]=3; htp_o[htp_2TETRA ]=htp_o_JKI;
  htp_n[htp_WATER  =7]=1; htp_o[htp_WATER  ]=htp_o_I;
  htp_n[htp_CARBOX =8]=3; htp_o[htp_CARBOX ]=htp_o_IJK;
  htp_n[htp_CARBOXH=9]=3; htp_o[htp_CARBOXH]=htp_o_IJK;
  
  # write dummy .tdb files:
  print "[ null ]" > ffctdb;
  print "[ null ]" > ffntdb;
  
  # write empty xlateat.dat:
  print "0" > "xlateat.dat";
}

NR==1 {
  printf("Start reading file %s\n", FILENAME);
  printf("; from file %s\n", FILENAME) > ffrtp;
  idbgen = $1+0;
  irest  = $2+0;
  itypf  = $3+0;
  printf("; \n") > ffrtp;
  printf("; reading database: %s\n", db_tp[itypf]) > ffrtp;
  printf("; \n") > ffrtp;
  if (debug) print "dbgen:", idbgen, irest, itypf, db_suf[itypf];
  if (db_pre[itypf]) {
    warning("terminus: will ignore all bonds to preceding residue in this file");
  }
  next;
}

NR==2 {
  namdbf = $1;
  if (debug) print "dbname:", namdbf;
  next;
}

$1=="STOP" { # end of database file
  printf("Finished reading file %s\n", FILENAME);
  printf("; end of file %s\n", FILENAME) > ffrtp;
  NR=0;
  next;
}

$1=="DONE" {
  if (nat==0) fatal_error("no atoms for residue " resnm);
  if (nM) bM=1;
  # fix some exceptions:
  swap_first=0;
  kill_bond=0;
  if (resnm=="ACE" || resnm=="HOH") {
    # in 'ACE', HH31 comes before CH3, then HH32 and HH33 follow.
    # we need to change this to CH3, HH31-3.
    # in 'HOH', H1 comes before O. we need O, H1-2
    warning("EXCEPTION: swapping atoms "igraph[0]" and "igraph[1]" in residue "resnm);
    swap_first=1;
    # also, the bond to 'preceding' residue must go:
    warning("EXCEPTION: ignoring bond from "bonds[0,1]" to preceding residue in residue "resnm);
    kill_bond=1;
  }
  if (db_pre[itypf]) { # do we have no preceding residue (e.g. N-ter does not)
    kill_bond=1;
  }
  if (swap_first) {
    if (debug) print("SWAP FIRST");
    swap_atoms(0, 1);
  }
  if (kill_bond) {
    if (debug) print("KILL BOND");
    bonds[0,0]=-1;bonds[0,1]=-1;
    zz[0,0]=zz[0,1]=zz[0,2]=zz_NONE;
    zz[1,1]=zz[1,2]=zz_NONE;
    zz[2,2]=zz_NONE;
  }
  # write rtp
  printf("[ %s ]\n", resnmt) > ffrtp;
  printf(" [ atoms ]\n") > ffrtp;
  printf(";%4s %5s %8s %5s ; %s\n", "name", "type", "charge", "cg", "qtot") > ffrtp;
  cg=0;
  qt=0;
  for(i=0; i<nat; i++) {
    qt+=chg[i];
    printf("%5s %5s %8.3f %5d ; %g\n", igraph[i],isymbl[i], chg[i],cg++, qt) > ffrtp;
  }

  # write hdb
  nha=0;
  for(i=0; i<nat; i++) {
    if (is_hydrogen(i)) {
      hi[nha]=i-1;
      nhh[nha]=0;
      while (is_hydrogen(i) && i<nat) {
	i++;
	nhh[nha]++;
      }
      nha++;
    }
  }
  printf("%s\t%d\n", resnmt, nha) > ffhdb;
  for(i=0; i<nha; i++) {
    if (nhh[i]==3) { htp=htp_TTETRA; # three must be tetraeder
    } else if (theta[hi[i]+1]==109.5 ||
	       theta[hi[i]+1]==109.47 ) { # tetraedrical or OH
      if (nhh[i]==2) { 
	if (r[hi[i]+1]==1.01) htp=htp_TTETRA; # -NH2: (-NH3+ after deprotonation)
	else htp=htp_2TETRA; # C-CH2-C
      } else if (nhh[i]==1) { # either (tert)C-H or OH
	if (r[hi[i]+1]==0.96) htp=htp_SINGLE; # OH
	else htp=htp_1TETRA; # (tert)C-H
      }
    } else if (theta[hi[i]+1]==119.8 || # backbone N-H / arg N-H2
	       theta[hi[i]+1]==118.5 || # arginine N-H
	       ( theta[hi[i]+1]>=120.0 &&
		 theta[hi[i]+1]<=126.0 ) ) { # his/trp N-H's
      if (nhh[i]==1) htp=htp_PLANE;
      else if (nhh[i]==2) htp=htp_2PLANE;
    } else if (theta[hi[i]+1]==109.47 || # OH
	       theta[hi[i]+1]==118.5  || 
	       theta[hi[i]+1]==127.0  || # nucl ac.
	       theta[hi[i]+1]==117.7  || # nucl ac.
	       theta[hi[i]+1]==117.36 || # nucl ac.
	       theta[hi[i]+1]==116.77 || # nucl ac.
	       theta[hi[i]+1]==114.97 || # nucl ac.
	       theta[hi[i]+1]==107.0  || # nucl ac.
	       theta[hi[i]+1]==113.0  || 
	       theta[hi[i]+1]== 96.0 ) { # backbone N-H
      htp=htp_SINGLE;
    } else if (theta[hi[i]+1]==101.43) {
      htp=htp_WATER;
    } else if (theta[hi[i]+1]== 60.0) { # PRO-N (-NH2-)
      htp=htp_2TETRA;
    } else
      htp=htp_NONE;
    if (debug) printf("i:%d hi:%d(%s) nhh:%d htp:%d htpn:%d theta:%g r:%g\n", 
		      i, hi[i], igraph[hi[i]], nhh[i], htp, htp_n[htp], 
		      theta[hi[i]+1], r[hi[i]+1]);
    printf("\t%d\t%d", nhh[i], htp) > ffhdb;
    # more exceptions:
    if (resnm=="ACE" && htp==htp_TTETRA)
      htpo=htp_o_ACE;
    else
      htpo=htp_o[htp];
    for(j=0; j<htp_n[htp]; j++) {
      k=hotp[htpo,j];
      if (debug) printf("j:%d htp:%d htp_o:%d k:%d",
			j, htp, htpo, k);
      if (k==0) # atom 'i': bonded atom
	l = igraph[hi[i]];
      else if (k<0) { # atoms 'ijk': reference atoms upstream 
	l = "";
        # search other non-hydrogen z-matrix entries for 'this' atom number:
	for(jj=0; jj<3 && k<0; jj++)
	  for(ii=hi[i]+1; ii<nat && k<0; ii++) {
	    if (debug) printf("[ii:%d H:%d jj:%d zz:%d]", 
			      ii, is_hydrogen(ii), jj, zz[ii,jj]);
	    if (!is_hydrogen(ii) && zz[ii,jj]!=zz_NONE && zz[ii,jj]==hi[i]) {
	      if (debug) printf(":%s", igraph[ii]);
	      k++; # k<0, we count up to zero
	    }
	  }
	if (k==0)
	  l = igraph[ii-1];
	else {
	  if (nl) { # finally, check 'loops':
	    if (debug) printf(" nl:%d", nl);
	    for(ii=0; ii<nl; ii++)
	      for(jj=0; jj<2; jj++) {
		if (debug) printf(" %s", loops[ii,jj]);
		if (loops[ii,jj]==igraph[hi[i]])
		  l = loops[ii,1-jj];
	      }
	    if (debug) printf("\n");
	  }
	  if (l=="")
	    fatal_error("no bonded atom found for atom "igraph[hi[i]]" ("hi[i]+1") in residue "resnmt);
	}
      } else { # atoms 'ijk': reference atoms downstream (take from z-matrix)
	if (zz[hi[i],k-1]<0) # atom in previous residue, use 'allM':
	  l = "-"allM[nM+zz[hi[i],k-1]];
	else # atom in this residue:
	  l = igraph[zz[hi[i],k-1]];
      }
      if (debug) printf(" l:%s\n",l);
      printf("\t%s", l) > ffhdb;
    }
    printf("\n") > ffhdb;
  }
  # done hdb

  if (nat>1) { # bonds etc. do not make sense for a single atom:
  
    if (nb==0) fatal_error("no bonds for residue " resnmt);
    printf(" [ bonds ]\n") > ffrtp;
    printf(";%4s %5s\n", "ai", "aj") > ffrtp;
    ignb=0;
    for(i=0; i<nb; i++) {
      if (bonds[i,0]<0 && bonds[i,1]<0)
	ignb++;
      else {
	if (bonds[i,0]=="") bonds[i,0]="-"allM[nM-1];
	printf("%5s %5s\n", bonds[i,0], bonds[i,1]) > ffrtp;
      }
    }
    nb-=ignb;
    if (np>0) {
      bFirstPdih=1;
      for(i=0; i<np; i++) {
        # expand 'negative' atom id's:
	for(j=0; j<4; j++) {
	  atp = pdihsatp[i,j]+0;
	  if (atp<0) {
	    # fix atom name:
	    pdihs[i,j] = "-"allM[nM+atp];
	    # fix atom type:
	    pdihsatp[i,j] = allMtp[nM+atp];
	  }
	}
        # find number of pre-defined 4-atom based dihedral defines, if zero 
        # we use implicit (2-atom based) dihedrals (which need not be listed):
	n = find_dih(pdihsatp[i,0],pdihsatp[i,1],pdihsatp[i,2],pdihsatp[i,3], 
		     nptps, pdihtps, null);
	for(k=0; k<n || (n==0 && k==0); k++)
	  if ( n ) {
	    if (bFirstPdih) {
	      bFirstPdih=0;
	      printf(" [ dihedrals ]\n") > ffrtp;
	      printf(";%4s %5s %5s %5s\n", "ai", "aj", "ak", "al") > ffrtp;
	    }
	    for(j=0; j<4; j++)
	      printf("%5s ", pdihs[i,j]) > ffrtp;
	    printf("    ad") > ffrtp;
	    for(j=0; j<4; j++)
	      printf("_%2s", fill_with_underscores(pdihsatp[i,j],2) ) > ffrtp;
	    if ( n>0 ) printf("_%d", k+1) > ffrtp;
	    printf("\n") > ffrtp;
	  }
      }
    }
    if (ni) {
      printf(" [ impropers ]\n") > ffrtp;
      printf(";%4s %5s %5s %5s\n", "ai", "aj", "ak", "al") > ffrtp;
      for(i=0; i<ni; i++) {
	for(j=0; j<4; j++) {
	  if (idihs[i,j]=="-M") idihs[i,j]="-"allM[nM-1];
	  if (idihs[i,j]=="+M") idihs[i,j]="+"allM[0];
	  atps[j] = anm2atp(idihs[i,j], nat, igraph, isymbl);
	  printf("%5s ", idihs[i,j]) > ffrtp;
	}
	if (debug) {
	  printf("%s %s %s %s ", atps[0], atps[1], atps[2], atps[3]);
	  printf("%s %s %s %s ", idihs[i,0], idihs[i,1], idihs[i,2], idihs[i,3]);
	}
	n = find_dih(atps[0], atps[1], atps[2], atps[3], nitps, idihtps, fdihs);
	if (debug) printf("\n");
	if (n==1) {
	  printf("    ai") > ffrtp;
	  for(j=0; j<4; j++)
	    printf("_%2s", fill_with_underscores(fdihs[0,j],2) ) > ffrtp;
	} else
	  warning((n?"multiple ("n")":"no")" idih definition for "atps[0]" "atps[1]" "atps[2]" "atps[3]);
	printf("\n") > ffrtp;
	
      }
    }
  }
  printf("; end residue %s: %d atoms, %d bonds, %d pdihs, %d idihs\n", 
	 resnmt, nat, nb, np, ni) > ffrtp;
  printf("\n") > ffrtp;
  
  # clean up
  for(i in xlate) delete xlate[i];
  
  if (debug) print "done.";
  next_type(tp_RES_TIT);
  next;
}

type==tp_RES_TIT { # title
  # initialize per-residue variables
  nat=0;
  nb=0;
  nl=0;
  ni=0;
  np=0;
  # read this section
  title = $0; 
  gsub("   *", " ", title);
  if (debug) print "title:", title;
  printf("; %s\n", title) > ffrtp;
  printf("; \n") > ffrtp;
  next_type(-1);
  next;
}

type==tp_OUT_FIL { # file
  file = $0;
  if (debug) print "file:", file;
  next_type(-1);
  next;
}

type==tp_RES_NAM { # residue name
  resnm = $1;
  intx  = $2;
  kform = $3+0;
  if (debug) print "residue:", nres, resnm, intx, kform;
  if (length(resnm)>3) {
    warning("Residue name '"resnm"' more than three characters long");
  }
  # add possible suffix for terminus:
  resnmt=resnm db_suf[itypf];
  
  printf("Residue: %d %s (%s)\n", nres, title, resnmt);
  
  resnms[nres]=resnm;
  nres++;
  
  next_type(-1);
  next;
}

type==tp_GEO_TYP { # geometry
  ifixc  = $1;
  iomit  = $2;
  isymdu = $3;
  ipos   = $4;
  if (debug) print "geometry:", ifixc, iomit, isymdu, ipos;
  next_type(-1);
  next;
}

type==tp_LOO_CUT { # cut
  cut=$1+0;
  if (debug) print "cut:", cut;
  next_type(-1);
  next;
}

type==tp_ATOMS && NF==0 { # end of atoms
  ndum=0;
  next_type(-1);
  next;
}

type==tp_ATOMS { # atoms
  if ($2=="DUMM") {
    ndum++;
  } else {
    i         =  $1-ndum-1;
    igraph[i] =  $2;
    isymbl[i] =  $3;
    itree     =  $4;
    zz[i,0]   =  $5-ndum-1;
    zz[i,1]   =  $6-ndum-1;
    zz[i,2]   =  $7-ndum-1;
    r[i]      =  $8+0;
    theta[i]  =  $9+0;
    phi       = $10+0;
    chg[i]    = $11+0;
    nat++;
    # fix hydrogen atom numbering:
    if (is_hydrogen(i) && length(igraph[i])>length_heavy) {
      hnum++;
      igr=substr(igraph[i], 1, length_heavy) hnum;
      if (igr!=igraph[i]) {
	# store translated atom names:
	if (debug) print "Xlate:", i, "'"igraph[i]"'", "'"isymbl[i]"'", 
		     length_heavy, "'"igr"'";
	xlate[igraph[i]]=igr;
	igraph[i]=igr;
      }
    } else {
      length_heavy=length(igraph[i])
      hnum=0;
    }
    if (itree=="M" && !bM) {
      allM[nM]   = igraph[i];
      allMtp[nM] = isymbl[i];
      nM++;
    }
    # add bonds
    bonds[nb, 0]=igraph[zz[i,0]];
    bonds[nb, 1]=igraph[i];
    nb++;
    # angles are automatic
    # add proper dihs
    pdihs[np, 0]=igraph[i];
    pdihs[np, 1]=igraph[zz[i,0]];
    pdihs[np, 2]=igraph[zz[i,1]];
    pdihs[np, 3]=igraph[zz[i,2]];
    pdihsatp[np, 0]=isymbl[i];
    pdihsatp[np, 1]= zz[i,0]<0 ? zz[i,0] : isymbl[zz[i,0]];
    pdihsatp[np, 2]= zz[i,1]<0 ? zz[i,1] : isymbl[zz[i,1]];
    pdihsatp[np, 3]= zz[i,2]<0 ? zz[i,2] : isymbl[zz[i,2]];
    np++;
    if (debug) printf("atom: %d %s %s %s %d %d %d %g %g %g %g\n", 
		      i+1, igraph[i], isymbl[i], itree, 
		      zz[i,0], zz[i,1], zz[i,2], r[i], theta[i], phi, chg[i]);
  }
}

type==tp_EXTRAS { # extra's
  if (debug) print "extra:", $0;
  for(i=tp_CHARGE; i<=tp_IMP_DIH; i++) {
    if (toupper(section[i]) == $1) {
      next_type(i);
      next;
    }
  }
}

type>tp_EXTRAS && NF==0 { # end of an extra's section
  if (iq && iq!=nat)
    warning("ERROR: # charges ("iq") and # atoms ("nat") differ");
  iq=0;
  next_type(tp_EXTRAS);
  next;
}

type==tp_CHARGE { # charge
  for(i=1; i<=NF; i++) {
    chg[iq] = $i;
    iq++;
  }
  if (debug) print "charges:", iq;
}

type==tp_LOOP { # loop
  for(i=1; i<=2; i++) bonds[nb, i-1] = xlate[$i] ? xlate[$i] : $i;
  nb++;
  for(i=1; i<=2; i++) loops[nl, i-1] = xlate[$i] ? xlate[$i] : $i;
  nl++;
}

type==tp_IMP_DIH { # improper
  for(i=1; i<=4; i++) idihs[ni, i-1] = xlate[$i] ? xlate[$i] : $i;
  ni++;
}

END {
  if (xxit) exit;
  printf("Found %d residues\n", nres);
  print_warn();
  printf("; Found %d residues\n", nres) > ffrtp;
  system("luck");
}

#last line
