Skip to content

Instantly share code, notes, and snippets.

@exergonic
Created May 25, 2015 15:15
Show Gist options
  • Save exergonic/fd3675aa3f4318481b1f to your computer and use it in GitHub Desktop.
Save exergonic/fd3675aa3f4318481b1f to your computer and use it in GitHub Desktop.
Systematic Assignment of Archetypal Organic Functional Groups
c-----------------------------------------------------------------------
c-----------------------------------------------------------------------
c Copyright (c) 2014 by Billy Wayne McCann, Ben Hay
c Chemical Sciences Division
c Chemical Separations Group
c Oak Ridge National Lab
c All rights reserved
c-----------------------------------------------------------------------
c-----------------------------------------------------------------------
c
c ASSIGNCLASS
c
c
c This subroutine determines the class and subclass of a dihedral
c as well as the driver atom of a fragment. Classes and subclasses
c are determined by the fragment's bond topology, e.g. trigonal
c pyramidal, trigonal planar, tetrahedral, etc. While each subclass
c is meant to be as inclusive as possible, sometimes distinctions
c must be made between two members of the same class. For example,
c the XPX angle of a phosphine is much small than the XNX angle of an
c amine. This leads to a qualitatively different rotational
c potential energy surface. Therefore the identity of the link atom
c must be tested.
c
c The driver atom refers to the atom which was used in constructing
c the rotational potential energy surface. This atom must be
c correctly identified in this subroutine.
c
c A bond is formed by connecting a member of one class with
c a member of another class. The actual values of the dihedral
c angles were determined by forming test molecules and doing
c rotational PES's using Allinger's (MM3) force field or density
c functional theory (wB97XD/6-31+G**). These values are stored
c in the CONSTANTS file, referenced by class and subclass.
c
c-----------------------------------------------------------------------
c
c LIST OF CLASSES AND SUBCLASSES
c
c Note that unless otherwise specified R is any non-H atom and X is
c any atom. Refer to user manual for three dimensional depicitons.
c
c Class 1 - Tetrahedral - B, C, Si, N, P, As
c subclass 1: -RH2X
c subclass 2: -RHX2
c subclass 3: -RX3 or -RH3
c Class 2 - Trigonal Planar (alkene-like)
c subclass 1: -R(H)=R(H)(X) where X is trans
c subclass 2: -R(H)=R(H)(X) where X is cis, or C(H)=CX2
c subclass 3: -R(X)=R(H)(X) where X is trans, or C(X)=CH2
c subclass 4: -R(X)=R(H)(X) where X is cis, or C(X)=CX2
c Class 3 - Trigonal Planar - Ring
c subclass 1: -(arene) two ortho H
c subclass 2: -(arene) one ortho H and one ortho X
c subclass 3: -(arene) two ortho X
c Class 4 - Amide-like - Beta Carbonyl
c subclass 1: -N(H)C(=O)X attaching cis to carbonyl
c subclass 2: -N(H)C(=O)X attaching trans to carbonyl
c subclass 3: -N(R)C(=O)X attaching cis to carbonyl
c subclass 4: -N(R)C(=O)X attaching trans to carbonyl
c Class 5 - Ether-like
c subclass 1: -OR
c subclass 2: -OH
c subclass 3: -XR -X not Oxygen
c subclass 4: -XH -X not Oxygen
c Class 6 - Pyramidal Amine
c subclass 1: -NH2
c subclass 2: -NHR, attachment down
c subclass 3: -NHR, attachment up
c subclass 4: -NR2
c Class 7 - Amide-like
c subclass 1: -C(=O)N(H)(R), where R is cis to carbonyl
c subclass 2: -C(=O)N(R)(X), where R is trans to carbonyl
c subclass 3: -C(=N-O)NH2, amidoxime
c Class 8 - Oxides
c subclass 1: Phosphine Oxide : -P(=O)X2
c subclass 2: Sulfoxide : -S(=O)X -- S (driver on +y axis)
c subclass 3: Sulfoxide : -S(=O)X -- R (driver on -y axis)
c subclass 4: Sulfone : -S(=O)2X
c Class 9 - Phosphines
c subclass 1: -PH2
c subclass 2: -PHX -- S (X on -y axis)
c subclass 3: -PHX -- R (X on +y axis)
c subclass 4: -PX2
c Class 10 - Aldehyde-like
c subclass 1: -X(=O)H
c subclass 2: -X(=S)H
c subclass 3: -X=XHX (H cis to loser atom)
c subclass 4: -X=XX (second X trans to loser atom)
c Class 11 - Ketone-like
c subclass 1: -X(=X-X)R (second X trans to loser atom)
c subclass 2: -X(=O)R
c subclass 3: -X(=X)R
c Class 12 - Ketimine-like
c subclass 1: -X=XR2
c Class 13 - Planar Ring - unsubstituted ortho positions
c subclass 1: 1 ortho unsubstituted ; one H substituted
c subclass 2: 2 ortho unsubstituted
c subclass 3: 1 ortho unsubstituted ; one substituted - not H
c Class 14 - Borane-like (trigonal planar)
c subclass 1: -XH2
c subclass 2: -XRH
c subclass 3: -XR2
c Class 15 - No torsional preference or Unknown
c subclass 1: Linear, Metallic, Hypervalent, or unknown
c Class 16 - Terminal case
c subclass 1: Coordinating atom attached to only a loser atom
c Class 17 - Phosphinates
c subclass 1: trialkylphosphinates
c subclass 2: dialkylphosphinic acids
c subclass 3: dialkylphosphinate anions
c Class 18 - Phosphonates
c subclass 1: trialkylphosphonate
c subclass 2: dialkylphosphonic acids
c subclass 3: dialkylphosphonate anions
c Class 19 - Phosphates // AS YET DO NOT APPLY TO HOSTDESIGNER
c subclass 1: trialkylphosphate
c subclass 2: dialkylphosphoric acids
c subclass 3: dialkylphosphate anions
c
c-----------------------------------------------------------------------
c
c NOTE
c
c If you want to add another type of bond, then you will have
c to (1) define a new class/subclass, (2) run it against all of
c the existing classes to determine dihedral assignments, and
c (3) edit the routine to add the new stuff.
c
c CAUTION: Three arrays in constants.i must be updated if you
c add more classes. These are as follows:
c
c nrotval(#classes,#subclasses,#classes,#subclasses)
c rotval(#classes,#subclasses,#classes,#subclasses,#minima)
c roten(#classes,#subclasses,#classes,#subclasses,#minima)
c
c At this time #classes=19, #subclasses=4, and #minima=7
c
c The number of minima is also defined in params.i as MAXTORVAL
c Currently set at 7.
c
c-----------------------------------------------------------------------
c
c META
c
c This subroutine is called by readhosta.F (line 563) and readhostb.F
c (line 396) as
c
c call assignclass(xa(1,1,i),ya(1,1,i),za(1,1,i),n12a,i12a,
c & atlaba,iguesta,torrefa(i),ibondera(i),loosera(i),
c & classa(i),sclassa(i))
c
c from readhosta.F. From readhostb.F, change the 'a' suffixes to b.
c Compare this to the dummy variable which are used in this subroutine
c
c subroutine assignclass(x, y, z, n12, i12, itype, atlab, guest,
c & ii, jj, kk, class, sub)
c
c Therefore the actual --> dummy variable mappings are:
c xa(1,1,i) --> x
c ya(1,1,i) --> y
c za(1,1,i) --> z
c n12a --> n12
c i12a --> i12
c itypea --> itype
c atlaba --> atlab
c iguesta --> guest
c torrefa(i) --> ii
c ibondera(j) --> jj
c loosera(i) --> kk
c classa(i) --> class
c sclassa(i) --> sub
c
c-----------------------------------------------------------------------
c
c P A S S E D V A R I A B L E S:
c
c real x, y, z coordinates of the atoms
c integer n12 array of number attached atoms
c integer i12 array of attached atoms
c char atlab atom labels
c integer guest guest flags
c integer ii serial number of driver atom i
c integer jj serial number of attach atom j
c integer kk serial number of the dummy atom to be lost
c integer class the class of the rotor
c integer sub the subclass of the rotor
c integer alt_ii alternative driver atom to be used when
c a host is mirrored. only necessary for
c asymmetric trigonal pyramidal hosts.
c
c-----------------------------------------------------------------------
c
c B E G I N
c
c-----------------------------------------------------------------------
subroutine assignclass(n_atoms, x, y, z, n12, i12, atlab,
& guest, ii, jj, kk, class, sub, alt_ii)
implicit none
include 'include/params.i'
integer n_atoms ! number of atoms in structure
integer r_atoms ! number of real atoms
integer i, j ! indexing variables
integer ii ! serial # of driver atom
integer alt_ii ! serial # of alternative driver atom
integer jj ! serial # of attaching atom
integer kk ! serial # of loser atom
integer numhyd ! # of H's connected to an atom
integer numox ! # of O's connected to an atom
integer numdubox ! # of O's double bonded to an atom
integer numether ! # of ethers bonded to an atom
integer numalcohol ! # of alcohol bonded to an atom
integer numoth ! # of "other atoms" connected ''
integer hatt(n_atoms) ! serial #'s of numhyd's
integer oxatt(n_atoms) ! serial #'s of numox's
integer duboxatt(n_atoms) ! serial #'s of numdubox's
integer etheratt(n_atoms) ! serial #'s of numether's
integer alcoholatt(n_atoms) ! serial #'s of numalcohol's
integer othatt(n_atoms) ! serial #'s of numoth's
integer guest(MAXATOMD) ! status of whether an atom is a
! guest: 1 = yes, it is a guest.
! 0 = no, it is not a guest
integer guest_arr(n_atoms) ! array of serial # of guest atom
integer dummy_arr(n_atoms) ! array of serial # of dummy atoms
integer class, sub ! class and subclass of rotor
integer n12(MAXATOMD), i12(MAXVALA,n_atoms) ! connectivity matrices
integer n12r(n_atoms), i12r(MAXVALA,n_atoms) ! real connectivity
! matrices
integer valency ! coordination # of jj
real x(MAXATOMD), y(MAXATOMD), z(MAXATOMD) ! atomic coordinates
real dx(5),dy(5),dz(5) ! "temp" atomic coordinates
real dihed, ang, phi ! dihedral angle, angle, dihedral angle
character*2 atlab(n_atoms) ! periodic table atom labels
character*2 linkatom ! atom label of jj
! variables concerning rings
integer rings ! number of rings in molecule
integer nring(MAXRINGS) ! number of atoms in ring
integer iring(n_atoms,MAXRINGS) ! serial numbers in ring
real xlist(n_atoms) ! used for constructing a list of xyz
real ylist(n_atoms) ! coordinates
real zlist(n_atoms)
integer atlist(n_atoms) ! used in constructing array of
! atoms attached to any other atom
c variables concerning alpha positions
integer numalpha ! number of alplha atoms
integer ialpha(n_atoms) ! serial numbers of alpha atoms
integer ialpha1 ! serial number of 1st alpha
character*2 alphalab(n_atoms) ! label of alphas
c variables concerning beta positions
integer numbeta ! indexer for counting betas
integer nbeta(n_atoms) ! number of beta atoms connected
! to a certain alpha
integer ibeta(n_atoms,n_atoms) ! serial numbers of beta atoms
integer ibeta1
! connected to a certain alpha
logical has_cisbeta ! true if alpha has a cis beta
logical cisbeta_isH ! true if cis beta is Hydrogen
integer ibetacis ! serial # of cis beta
character*2 betacis ! atom label of cis beta
c True if ring is flat
logical flat ! true if ring is flat
logical ismetal ! True if link atom is a meta
c Debugging
c debug1 -> debugging the passed variables
c debug2 -> print out class, subclass, and driver
c debug3 -> verbose printing of many steps of assigning class etc.
logical debug1, debug2, debug3
integer numguests ! number of guests in the host complex
integer numdummies ! number of dummies in atom arrays
c-----------------------------------------------------------------------
c END OF VARIABLE DECLARATIONS
c-----------------------------------------------------------------------
c-----------------------------------------------------------------------
c Initialize some variables.
c-----------------------------------------------------------------------
debug1 = .false.
debug2 = .false.
debug3 = .false.
ismetal = .false.
dummy_arr = 0
guest_arr = 0
numguests = 0
numdummies = 0
alt_ii = 0
c-----------------------------------------------------------------------
c
c When debugging, print a line of hashes to separate assignments
c which are written to the screen.
c
if (debug1.or.debug3) then
write(*,5)
end if
5 format(/,"####################################################",/)
c-----------------------------------------------------------------------
c create connectivity arrays without dummies or guests
c-----------------------------------------------------------------------
c
c Count the number of guest and dummy atoms.
c Put their serial numbers into arrays for some testing below.
c
do i = 1, n_atoms
if (guest(i).eq.1) then
numguests = numguests + 1
guest_arr(numguests) = i
elseif (atlab(i).eq.'Du') then
numdummies = numdummies + 1
dummy_arr(numdummies) = i
end if
end do
c
c For debugging purposes, list the guests and dummies.
c
if (debug3) then
write(*,*) "Numguests is ", numguests
write(*,*) "Guests are ", guest_arr(:)
write(*,*)
write(*,*) "Numdummies is ", numdummies
write(*,*) "Dummies are ", dummy_arr(:)
end if
c
c Remove any line corresponding to a guest atom or dummy from the
c connectivity matrix. Because guests are the final entries in
c the z-matrix, simply remove the final (numguests) from n_atoms.
c This create a "real" connectivity matrix (i12r).
c
r_atoms = n_atoms - numguests
i12r = 0
n12r = 0
do i = 1, r_atoms
i12r(:,i) = i12(:,i)
end do
c
c Now, scan through the new connectivity matrix to find entries
c which are either guests or dummy atoms. If one is found, zero out
c its entry in the "real" connectivity matrix (i12r) and decrement
c the coordination number by one to create a "real" coordination
c number array (n12r).
c
do i = 1, r_atoms
do j = 1, n12(i)
if (guest(i12r(j,i)).eq.1 ! if it's a guest
& .or. atlab(i12r(j,i)).eq.'Du') then ! or if it's a dummy
i12r(j,i) = 0 ! zero the entry
n12r(i) = n12(i) - 1 ! decrement valency
else
n12r(i) = n12(i) ! move entry to "real" matrix
end if
end do
end do
c
c Display the old and new connectivity arrays for debugging purposes
c
if (debug3) then
write(*,*) "n12,n12r,i12,i12r after removing guests/dummies:"
do i = 1, n_atoms
write(*,'(1X,A11,I3,A11)') "========== ",i," ==========="
write(*,*)
write(*,*) "n12 = ",n12(i)
write(*,*)
write(*,*) "n12r = ",n12r(i)
write(*,*)
write(*,10) "i12(:,",i,") = ", i12(:,i)
write(*,*)
write(*,10) "i12r(:,",i,") = ", i12r(:,i)
write(*,*)
end do
end if
10 format (1X,A7,I1,A4,10I4)
c-----------------------------------------------------------------------
c DISPLAY NEW FRAGMENT INFORMATION (DEBUG)
c Display fragment information to verify that the host file has
c been read correctly and that the new connectivity arrays are
c correct.
c-----------------------------------------------------------------------
if (debug1) then
write(*,*) '========= FRAGMENT INFO ================='
write(*,*)
write(*,*) 'Label | Serial# | Guest? | Valency | Connected To'
do i=1, r_atoms
write(*,'(5X,A2)',advance='no') atlab(i)
write(*,'(4X,I2)',advance='no') i
write(*,'(8X,I2)',advance='no') guest(i)
write(*,'(8X,I2)',advance='no') n12r(i)
do j=1, n12r(i)
write(*,20,advance='no') atlab(i12r(j,i))
end do
write(*,*)
end do
write(*,30) 'Total number of atoms is = ', r_atoms
write(*,30) 'Loser atom is serial number = ', kk
write(*,40) ' which has label = ', atlab(kk)
write(*,40) 'Attach atom (jj) = ', atlab(jj)
write(*,30) 'jj serial number = ', jj
write(*,30) 'jj coordination number = ', n12r(jj)
write(*,50) 'jj connectivity', atlab(i12r(1:n12r(jj),jj))
write(*,*) '========================================'
write(*,*)
write(*,*) "Coordinate matrix"
write(*,60) 'X','Y','Z'
do i=1, n_atoms
write(*,*) i, atlab(i), x(i), y(i), z(i)
end do
write(*,*)
write(*,*) '========================================'
end if
20 format (8X,A2,1X,I1)
30 format (1X,A31,1X,I3)
40 format (1X,A31,2X,A3)
50 format (1X,A15,18X,4(A3,1X))
60 format (22X,A1,15X,A1,14X,A1)
c-----------------------------------------------------------------------
c END PRIMARY DEBUG
c-----------------------------------------------------------------------
c-----------------------------------------------------------------------
c BEGIN MAIN BODY
c The primary test is the valency and geometry of the link
c atom (jj). If jj is a metal or is hypervalent, it is considered
c to be the "general" case, 15-1. Subsequent tests include the
c identity of the element name of jj, as well as the nature of the
c atoms alpha to it and sometimes its betas (the atoms connected to
c the alphas). Generally, the cases fall into tetrahedral, trigonal
c pyramidal, acyclic trigonal planar, cyclic trigonal planar
c (arene-like), bent, linear, and terminal.
c-----------------------------------------------------------------------
c
c Valency is the coordination number of the link atom (jj).
c
valency = n12r(jj)
c
c A new variable, linkatom, containing the whitespace-trimmed name
c of jj.
c
linkatom = trim(atlab(jj))
c-----------------------------------------------------------------------
c METAL OR NONMETAL
c-----------------------------------------------------------------------
c
c determine if linkatom is a metal. Aluminum is kept due to its
c resemblance to boron and carbon for trivalent and tetravalent
c geometries, respectively.
c
select case (linkatom)
case ('B','Al','C','N','O','F','Si','P','S','Cl','As','Se', 'Br',
& 'Te','I','At')
ismetal = .false.
case default
ismetal = .true.
end select
c
c if metal, place into 'general' class and make driver atom
c the first atom with angle .lt. 160. This choice of angle is
c somewhat arbitrary, being midway between bent 120 and linear 180.
c
if (ismetal.or.(valency.ge.5)) then
do i=1, valency
if (i12r(i,jj).eq.kk) cycle ! ignore loser atom (kk)
call findangle(x(kk),y(kk),z(kk),
& x(jj),y(jj),z(jj),
& x(i12r(i,jj)),y(i12r(i,jj)),z(i12r(i,jj)),
& ang)
if (ang.lt.160.0) then
ii = i12r(i,jj)
exit
end if
end do
class = 15
sub = 1
if (debug2) write(*,*) '==>', class, sub, ii
return
end if
c-----------------------------------------------------------------------
c VALENCY OF 4
c-----------------------------------------------------------------------
if (valency.eq.4) then
if (debug3) write(*,*) "=== Valency of 4 detected ==="
c
c Initialize variables used for counting atom types connected to
c the attach atom (jj).
c
numhyd = 0
numdubox = 0
numox = 0
numoth = 0
numether = 0
numalcohol = 0
c
c Inspect all atoms connected to the link atom (jj).
c The identity and/or the topology of these atoms determines the
c dihedral class and subclass.
c
do i=1, valency
c
c Be sure to keep the loser atom, kk, among the substituents. It's
c identity doesn't determine the rotor type.
c
if (i12r(i,jj).eq.kk) cycle
c
c First, look for monovalent atoms. Double bonded oxygens, sulfurs,
c phosphoruses, etc. will be found here. While the variable names
c are 'numdubox', 'duboxatt', etc., all signifying oxygen atoms,
c this naming is for convenience only.
c
if (n12r(i12r(i,jj)).eq.1) then
c
c Don't count hydrogens with among other monovalent atoms. They are
c handled differently, below.
c
if (atlab(i12r(i,jj)).ne.'H ') then
numdubox = numdubox + 1
duboxatt(numdubox) = i12r(i,jj)
else
c
c Hydrogens
c
numhyd = numhyd + 1
hatt(numhyd) = i12r(i,jj)
end if
c
c Divalent atoms possess similar dihedral profiles to monovalent
c ones *if* its second substituent (not jj) is trans to the loser
c atom (jj).
c
else if (n12r(i12r(i,jj)).eq.2) then
c
c Find the beta atom
c
do j=1, 2
if (i12r(j,i12r(i,jj)).eq.jj) cycle
ibeta1 = i12r(j,i12r(i,jj))
end do
if (atlab(ibeta1).eq.'H ') then
numalcohol = numalcohol + 1
alcoholatt(numalcohol) = ibeta1
else
numether = numether + 1
etheratt(numether) = ibeta1
end if
c
c Determine it's torsion angle with respect to the loser atom (jj)
c
call torsionval(x,y,z,kk,jj,i12r(i,jj), ibeta1, dihed)
if (dihed.ge.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (debug3) write(*,*) "Dihedral is ", dihed
c
c If it's trans, count this as an 'oxygen'. named ox only for
c convenience
c
if (dihed.ge.90.0e0) then
numox = numox + 1
oxatt(numox) = i12r(i,jj)
c
c If not, make it an "other atom" (othatt).
c
else
if (debug3) write(*,*) "Numoth = ", numoth
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end if
c
c Everything else
c
else
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end if
end do
if (debug3) then
write(*,*) "numhyd = ", numhyd
write(*,*) "numoth = ", numoth
write(*,*) "numox = ", numox
write(*,*) "numbudox = ", numdubox
end if
c
c Determine linker atom atomic type. Determining the atom type is
c important to distinguish between e.g. sulfones and phosphine
c oxides, which have different dihedral potential energy surfaces
c for some substituents.
c
select case (linkatom)
c
c Determine case for boron, carbon, nitrogen.
c These tetrahedral elements are simpler to classify than those
c for which double bonds must be tested, e.g. phosphorus and sulfur,
c which are handled below.
c
case ('B','C','N')
if (debug3) then
write(*,*) "Tetravalent Boron, Carbon, or Nitrogen"
end if
c
c Determine class, subclass, and driver based upon number of H's
c
select case (numhyd)
case (3) ! 3 hydrogens
class = 1
sub = 3
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
case (2) ! 2 hydrogens
class = 1
sub = 1
if (numoth.eq.1) then
ii = othatt(1)
else if (numox.eq.1) then
ii = oxatt(1)
end if
if (debug2) write(*,*) class, sub, ii
return
case (1) ! 1 hydrogen
class = 1
sub = 2
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
case (0) ! 0 hydrogens
class = 1 ! 3 hydrogens and 0 hydrogens have the same
sub = 3 ! dihedral potential energy surface
if (numox.ge.1) then
ii = oxatt(1)
else
ii = othatt(1)
end if
if (debug2) write(*,*) class, sub, ii
return
end select
c
c Determine case for phosphorus, arsenic, or silicon
c The doubly bonded oxygen is the driver. Alcohols and ether
c substituents determine the class and subclass
c 17 - phosphinate
c 1) trialkyl phosphinate - one dubox and one ether
c 2) dialkyl phosphinic acid - one dubox, one alcohol
c 3) dialkylphosphinate anion - two dubox
c 18 - phosphonate
c 1) trialkylphosphonate - 1 dubox, 2 ethers
c 2) dialkylphosphonic acid - 1 dubox, 1 alcohol, 1 ether
c 3) dialkylphosphonate anion - 2 dubox, 1 ether
c 19 - phosphate
c As of now, phosphates aren't applicable. Since there are no
c ether links in the LIBRARY, connecting a phosphorus to an
c alcohol will not happen. This may change in the future.
c
case ('P','As','Si')
c
c If there's a monovalent atom or a divent atom with a trans beta,
c (oxatt) make it the driver.
c
if (numdubox.eq.2) then
if (numether.eq.1) then
class = 18
sub = 3
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
else
class = 17
sub = 3
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
end if
else if (numdubox.eq.1) then
if (numether.eq.1) then
class = 17
sub = 1
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
else if (numether.eq.2) then
class = 18
sub = 1
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
else if ((numalcohol.eq.1).and.(numether.eq.1)) then
class = 18
sub = 2
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
else if (numalcohol.eq.1) then
class = 17
sub = 2
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
else
class = 8
sub = 1
ii = duboxatt(1)
if (debug2) write(*,*) class, sub, ii
return
end if
c
c If none are found, classify it as a generic tetrahedral
c
else if (numhyd.eq.3) then
class = 1
sub = 3
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
else if (numhyd.eq.2) then
class = 1
sub = 1
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
else if (numhyd.eq.1) then
class = 1
sub = 2
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
else if (numhyd.eq.0) then
class = 1
sub = 3
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
else
class = 15
sub = 1
ii = othatt(1)
end if
c
c Cases for Sulfur, Selenium, and Tellurium. Again, the most
c important case is the case in which there is oxygen attached.
c
case ('S', 'Se', 'Te')
c
c Monovalent non-hydrogens.
c
if (numdubox.gt.0) then
class = 8
sub = 4
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
c
c Divalent atoms with second connection trans.
c
else if (numox.gt.0) then
class = 8
sub = 4
c
c Determine which is driver.
c
select case (numox)
case (3) ! 3 oxygens
ii = oxatt(1)
if (debug2) write(*,*) class, sub, ii
return
case (2) ! 2 oxygens
c
c Make the non-oxygen the driver to achieve symmetric surface.
c
if (numhyd.ge.1) then
ii = hatt(1)
else
ii = othatt(1)
end if
if (debug2) write(*,*) class, sub, ii
return
case (1) ! 1 oxygen
ii = oxatt(1)
if (debug2) write(*,*) class, sub, ii
return
end select
else
c
c If there were no oxygens, then assign sulfur, selenium, and
c tellurium as one would the other tetravalent organic species.
c
select case (numhyd)
case (3) ! 3 hydrogens
class = 1
sub = 3
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
case (2) ! 2 hydrogens
class = 1
sub = 1
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
case (1) ! 1 hydrogen
class = 1
sub = 2
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
case (0) ! 0 hydrogens
class = 1
sub = 3
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
end select
end if
end select
c
c If the dihedral type for a tetravalent linker atom hasn't yet
c been found, default to class 15-1 and make the driver atom the
c first atom which isn't the loser atom.
c
numoth = 0
do i=1,valency
if (i12r(i,jj).eq.kk) cycle
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end do
class = 15
sub = 1
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
end if ! end of if valency .eq. 4 block
c-----------------------------------------------------------------------
c COORDINATION OF 3
c-----------------------------------------------------------------------
if (valency.eq.3) then
c
c A valency of three can represent many different rotor groups. The
c three main categories are trigonal planar cyclic, trigonal planar
c non-cyclic, and trigonal pyramidal (trigonal pyramidal rings have
c no special treatment; instead they are treated as a simple
c trigonal pyramidal.
c
c Pyramidal cases are straightforward to test. Planar cases require
c extensive testing of the ortho positions and their substituents,
c which are tested for
c 1. no substitution (lone pair)
c 2. hydrogen substituted
c 3. monovalent non-hydrogen substituted (ketone, etc.)
c 4. other (rotational minima acquired using a methyl group)
c
c Because of the amount of testing involved with planar cases,
c planar cyclics and planar non-cyclics are given their own
c subroutines.
c
if (debug3) write(*,*) "=== Valency of 3 detected ==="
c
c Create an array of alpha atom serial numbers, without the
c loser atom or dummies
c
numalpha = 0
do i = 1, n12r(jj)
if (i12r(i,jj).eq.kk) cycle
numalpha = numalpha + 1
ialpha(numalpha) = i12r(i,jj)
end do
if (debug3) then
c
c For debugging purposes, create an atom list of jj and its alphas.
c
do i=1, 3
atlist(i) = i12r(i,jj)
end do
atlist(4) = jj
write(*,*) "Atom list used to determine if trigonal ",
& "host is planar is ", atlab(atlist(1:4))
end if
c
c Create an xyz list from the attach atom and it's alpha atoms.
c This xyz list will be used to determine the planarity of the
c attach atom (jj).
c
do i=1, 3
xlist(i) = x(i12r(i,jj))
ylist(i) = y(i12r(i,jj))
zlist(i) = z(i12r(i,jj))
end do
xlist(4) = x(jj)
ylist(4) = y(jj)
zlist(4) = z(jj)
c
c Determine if attach atom is planar. A tolerance of 0.2 Angstrom
c is employed. Below this threshold is planar. This value was
c determined using the Cambridge Crystal Structure Database using
c trivalent nitrogen as a test.
c
call distance2plane(xlist, ylist, zlist, flat, debug3)
if (debug3) write(*,*) "Results of planarity test = ", flat
c
c Are there rings in the system?
c
call findrings(r_atoms,n12r,i12r,jj,r_atoms,rings,
& nring, iring)
c
c Ensure that no alpha atom has four substituents.
c In that case, it is a (partially) saturated ring which will be
c treated as an alkene.
c
if (flat.and.(rings.gt.0)
& .and.(n12r(ialpha(1)).le.3)
& .and.(n12r(ialpha(2)).le.3)) then
if (debug3) write(*,*) "Host has a planar ring"
c
c Perform assignments for flat rings.
c
call assign_arene(r_atoms, jj, valency, kk, n12r,
& i12r, atlab, class, sub, ii, debug3)
c
c assign_arene subroutine returns class, sub, and ii therefore ...
c
if (debug2) write(*,*) class, sub, ii
return
end if
c-----------------------------------------------------------------------
c ACYCLIC TRIGONAL PLANAR
c-----------------------------------------------------------------------
c
c Perform tests in subroutine.
c
if(flat.and.(rings.eq.0)) then
call assign_trigplanar(r_atoms,x,y,z,jj,kk,n12r,i12r,
& atlab,class,sub,ii,ialpha,debug2)
return
end if
c-----------------------------------------------------------------------
c TRIGONAL PYRAMIDAL CASE
c-----------------------------------------------------------------------
c
c For trigonal pyramidal cases, atom types must be tested because
c e.g. P and N have very different bond angles, yield distinct
c rotational potential energy surfaces.
c The general case simply looks for Hydrogens and non-Hydrogens.
c This is acceptable for all trigonal pyramidal cases except Sulfur,
c Selenium, and Tellurium, many of which are double bonded to
c e.g. Oxygen. There are no examples of trivalent, pyramidal Silicon
c bonded to a monovalent atom.
c
if (.not.flat) then
c
c Count number of hydrogens and non-hydrogens
c
numhyd = 0
numoth = 0
do i=1, valency
if (i12r(i,jj).eq.kk) cycle
if (atlab(i12r(i,jj)).eq.'H ') then
numhyd = numhyd + 1
hatt(numhyd) = i12r(i,jj)
else
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end if
end do
c
c In the pyramidal case, we have nonsymmetric rotational
c potential surfaces. This means that we have to do some extra work
c to determine which group is the driver when the R groups are the
c same and which subclass to assign when they are different.
c
c Orient the group such that the two R groups are on the z-axis,
c one at the origin and one on the positive z axis.
c
c If R groups are different, one C and one H, then the H goes
c to the origin and the C goes to the positive z axis.
c
c Atom numbering used in orientation is as follows:
c
c 1 = dummy
c 2 = R at origin
c 3 = R at + z-axis
c 4 = central pyramidal atom
c 5 = loser atom
c
c
c Group 16 elements need to be tested for double bonded oxygens,
c which affects their assignments differently than others.
c Do not include them in this sectin of assignments.
c
if(linkatom.ne.'S'
& .and.linkatom.ne.'Te'
& .and.linkatom.ne.'Se') then
c
c Please dummy at origin
c
dx(1) = 0.0
dy(1) = 0.0
dz(1) = 0.0
c
c Assign jj and kk coordinates
c
dx(4) = x(jj)
dy(4) = y(jj)
dz(4) = z(jj)
dx(5) = x(kk)
dy(5) = y(kk)
dz(5) = z(kk)
c
c Determine symmetric and assymetric cases, determined by the
c number of hydrogens
c
select case (numhyd)
case (2) ! 2 hydrogens
dx(2) = x(hatt(1))
dy(2) = y(hatt(1))
dz(2) = z(hatt(1))
dx(3) = x(hatt(2))
dy(3) = y(hatt(2))
dz(3) = z(hatt(2))
case (1) ! 1 hydrogen
dx(2) = x(hatt(1))
dy(2) = y(hatt(1))
dz(2) = z(hatt(1))
dx(3) = x(othatt(1))
dy(3) = y(othatt(1))
dz(3) = z(othatt(1))
case (0) ! 0 hydrogens
dx(2) = x(othatt(1))
dy(2) = y(othatt(1))
dz(2) = z(othatt(1))
dx(3) = x(othatt(2))
dy(3) = y(othatt(2))
dz(3) = z(othatt(2))
end select
c
c Align the loser atom (kk) along the z-axis.
c
call alignz(5,dx,dy,dz,2,3,1)
c
c Now we rotate on the z-axis to place the central atom, d4,
c in the xz plane. Requires the use of a dummy atom, d1.
c
dx(1) = 1.0
dy(1) = 0.0
dz(1) = 0.0
call finddihedral(dx,dy,dz,1,2,3,4,phi)
ang = 0.0
call setdihedral(1,5,dx,dy,ang,phi)
end if
c
c The sign of the y coordinate of the loser atom, the fifth atom in
c the dx,dy,dz arrays, provides the criterion for assignments
c
c Symmetric:
c y value positive, ii = hatt(2) or catt(2) (this is the down form)
c y value negative, ii = hatt(1) or catt(1) (this is the up form)
c two hydrogens, subclass = 1
c two carbons, subclass = 4
c
c Asymmetric:
c y value positive, subclass = 2 (this is down form)
c y value negative, subclass = 3 (this is up form)
c in either event, ii = catt(1)
c
c
c Perform assignments based upon link atom element identity
c
select case (linkatom)
c
c Nitrogen
c
case ('N')
class = 6 ! pyramidal nitrogen is always class 6
c
c Assign based upon the number of hydrogens.
c
select case (numhyd)
case (0) ! 0 hydrogens
sub = 4
if (dy(5) .gt. 0.00e0) then
ii = othatt(2)
alt_ii = othatt(1)
else
ii = othatt(1)
alt_ii = othatt(2)
end if
if (debug2) write(*,*) class, sub, ii, alt_ii
return
case (1) ! 1 hydrogen
ii = othatt(1)
if (dy(5) .gt. 0.00e0) then
sub = 2
else
sub = 3
end if
if (debug2) write(*,*) class, sub, ii
return
case (2) ! 2 hydrogens
sub = 1
if (dy(5) .gt. 0.00e0) then
ii = hatt(2)
alt_ii = hatt(1)
else
ii = hatt(1)
alt_ii = hatt(2)
end if
if (debug2) write(*,*) class, sub, ii, alt_ii
return
end select ! end of nitrogen tests
c
c Phosphorus or Arsenic
c
case ('P', 'As')
class = 9 ! always class 9
select case (numhyd)
case (0) ! 0 hydrogens
sub = 4
if (dy(5) .gt. 0.00e0) then
ii = othatt(1)
alt_ii = othatt(2)
else
ii = othatt(2)
alt_ii = othatt(1)
end if
if (debug2) write(*,*) class, sub, ii, alt_ii
return
case (1) ! 1 hydrogen
ii = othatt(1)
if (dy(5) .gt. 0.00e0) then
sub = 3
else
sub = 2
end if
if (debug2) write(*,*) class, sub, ii
return
case (2) ! 2 hydrogens
sub = 1
if (dy(5) .gt. 0.00e0) then
ii = hatt(1)
alt_ii = hatt(2)
else
ii = hatt(2)
alt_ii = hatt(1)
end if
if (debug2) write(*,*) class, sub, ii, alt_ii
return
end select ! end of P or At tests
c
c Sulfur, Selenium, Tellurium
c
case ('S', 'Se', 'Te')
class = 8
c
c Search for monovalent non-hydrogens (dubox) and their protonated
c forms (numox, must be trans to loser). All others go into numoth.
c
numdubox = 0
numox = 0
numoth = 0
do i=1, valency
if (i12r(i,jj).eq.kk) cycle
c
c Monovalent nonhydrogens
c
if (n12r(i12r(i,jj)).eq.1
& .and.atlab(i12r(i,jj)).ne.'H ') then
numdubox = numdubox + 1
duboxatt(numdubox) = i12r(i,jj)
c
c Divalent atoms possess similar dihedral profiles to monovalent
c ones *if* its second substituent (not jj) is trans to the loser
c atom (jj).
c
else if (n12r(i12r(i,jj)).eq.2) then
c
c Find the beta atom
c
do j=1, 2
if (i12r(j,i12r(i,jj)).eq.jj) cycle
ibeta1 = i12r(j,i12r(i,jj))
end do
c
c Determine it's torsion
c
call torsionval(x,y,z,kk,jj,i12r(i,jj),
& ibeta1, dihed)
if (dihed.ge.180.0e0) then
dihed = 360.0e0 - dihed
end if
c
c If it's trans, count this as an 'oxygen'. named ox only for
c convenience
c
if (dihed.ge.90.0e0) then
numox = numox + 1
oxatt(numox) = i12r(i,jj)
else
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end if
else
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end if
end do
c
c Chirality test. Atom numbering used in orientation is as follows:
c
c 1 = dummy
c 2 = double bonded oxygen
c 3 = R at + z-axis
c 4 = central pyramidal atom
c 5 = loser atom
c
dx(1) = 0.0
dy(1) = 0.0
dz(1) = 0.0
c
c Because the link atom (jj) has two substituents (not counting kk)
c they will either be two dubox (not likely), one dubox + one oxatt,
c or a combination of dubox, oxatt, or othatt.
c In the following if block, if there is no duboxatt's and no
c oxatt's, then there must be two othatt's, and so the following
c tests hold in all cases.
c
c For assigning the driver atom (ii), asymmetric cases are assigned
c immediately. Symmetric cases must undergo the chirality test.
c Since in some cases drivers aren't assigned, set ii = -1 and then
c test for it below.
c
ii = -1
if (numdubox.eq.1) then
dx(2) = x(duboxatt(1))
dy(2) = y(duboxatt(1))
dz(2) = z(duboxatt(1))
dx(3) = x(othatt(1))
dy(3) = y(othatt(1))
dz(3) = z(othatt(1))
ii = duboxatt(1)
else if ((numdubox.eq.1).and.(numox.eq.1)) then
dx(2) = x(duboxatt(1))
dy(2) = y(duboxatt(1))
dz(2) = z(duboxatt(1))
dx(3) = x(oxatt(1))
dy(3) = y(oxatt(1))
dz(3) = z(oxatt(1))
ii = duboxatt(1)
else if (numdubox.eq.2) then
dx(2) = x(duboxatt(1))
dy(2) = y(duboxatt(1))
dz(2) = z(duboxatt(1))
dx(3) = x(duboxatt(2))
dy(3) = y(duboxatt(2))
dz(3) = z(duboxatt(2))
else if (numox.eq.2) then
dx(2) = x(oxatt(1))
dy(2) = y(oxatt(1))
dz(2) = z(oxatt(1))
dx(3) = x(oxatt(2))
dy(3) = y(oxatt(2))
dz(3) = z(oxatt(2))
else if (numox.eq.1) then
dx(2) = x(oxatt(1))
dy(2) = y(oxatt(1))
dz(2) = z(oxatt(1))
dx(3) = x(othatt(1))
dy(3) = y(othatt(1))
dz(3) = z(othatt(1))
ii = oxatt(1)
else
dx(2) = x(othatt(1))
dy(2) = y(othatt(1))
dz(2) = z(othatt(1))
dx(3) = x(othatt(2))
dy(3) = y(othatt(2))
dz(3) = z(othatt(2))
end if
dx(4) = x(jj)
dy(4) = y(jj)
dz(4) = z(jj)
dx(5) = x(kk)
dy(5) = y(kk)
dz(5) = z(kk)
call alignz(5,dx,dy,dz,2,3,1)
c
c Now we rotate on the z-axis to place the central atom, d4,
c in the xz plane. Requires the use of a dummy atom, d1.
c
dx(1) = 1.0
dy(1) = 0.0
dz(1) = 0.0
call finddihedral(dx,dy,dz,1,2,3,4,phi)
ang = 0.0
call setdihedral(1,5,dx,dy,ang,phi)
c
c The class has already been assigned (all of these cases are for
c class 8, specifically S, Se, Te). Determine the subclass based
c upon the loser atom's y value. If ii.eq.-1, then it was never
c assigned in the above if clause. Test for ii.eq.-1 and assign the
c driver atom (ii) if needed.
c
if (dy(5).gt.0.00e0) then
sub = 2
if (ii.eq.-1) then
if (numdubox.eq.2) then
ii = duboxatt(2)
else if (numox.eq.2) then
ii = oxatt(2)
else if (numoth.eq.2) then
ii = othatt(2)
end if
end if
else
sub = 3
if (ii.eq.-1) then
if (numdubox.eq.2) then
ii = duboxatt(1)
else if (numox.eq.2) then
ii = oxatt(1)
else if (numoth.eq.2) then
ii = othatt(1)
end if
end if
end if
if (debug2) write(*,*) class, sub, ii
return
c
c The class and subclass haven't been found. Return the general case.
c
class = 15
sub = 1
if (numoth.ge.1) then
ii = othatt(1)
else
ii = hatt(1)
end if
if (debug2) write(*,*) class, sub, ii
return
end select ! end of selecting based upon element
end if ! end of trigonal pyramidal block
end if ! end of valency .eq. 3 block
c-----------------------------------------------------------------------
c COORDINATION OF 2.
c-----------------------------------------------------------------------
c
c Divalent atoms may be linear or bent. Therefore a measurement of
c the angle between the loser, the attach atom, and it's sole
c substituent must be tested. Angles less than 150 degrees will be
c considered bent. Otherwise, it is considered linear.
c
if (valency .eq. 2) then
if (debug3) write(*,*) "=== Valency of 2 detected ==="
c
c Find alpha atom serial number (not counting loser kk)
c
do i=1,2
if (i12r(i,jj).eq.kk) cycle
ialpha1 = i12r(i,jj)
end do
if (debug3) then
write(*,*) 'ialpha1 is ', ialpha1
write(*,*) 'which is a ', atlab(ialpha1)
end if
c
c Find the angle between the loser atom, the attach atom, and the
c substituent
c
call findangle(x(jj),y(jj),z(jj),x(kk),y(kk),z(kk),
& x(ialpha1),y(ialpha1),z(ialpha1),ang)
if (debug3) then
write(*,*) 'Angle for valency 2 was found to be ', ang
end if
c
c Consider a bond angle >= 150 linear.
c
if (ang.ge.150.0e0) then ! is linear
c
c If angle is equal to 180.0, slightly adjust the position of
c the link atom (jj), so that the dihedral isn't undefined.
c
if (ang.eq.180.0e0) then
x(ialpha1) = x(ialpha1) + 0.02
y(ialpha1) = y(ialpha1) + 0.02
end if
class = 15
sub = 1
ii = ialpha1
if (debug2) write(*,*) class, sub, ii
return
end if
c
c The angle isn't "linear", therefore further characterization is
c needed. Find nature of atoms attached to attach atom (jj).
c
c Count hyrogens and not-hydrogens and create arrays of their
c serial numbers.
c
numhyd = 0
numoth = 0
do i=1, 2
if (i12r(i,jj).eq.kk) cycle
if (atlab(i12r(i,jj)).eq.'H ') then
numhyd = numhyd + 1
hatt(numhyd) = i12r(i,jj)
else
numoth = numoth + 1
othatt(numoth) = i12r(i,jj)
end if
end do
c
c Oxygens have a much larger angle than other divalent atoms. Test
c for it.
c
select case (linkatom)
case('O')
if (numhyd.gt.0) then
class = 5
sub = 2
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
else
class = 5
sub = 1
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
end if
case('S','Se','Te')
if (numhyd.gt.0) then
class = 5
sub = 4
ii = hatt(1)
if (debug2) write(*,*) class, sub, ii
return
else
class = 5
sub = 3
ii = othatt(1)
if (debug2) write(*,*) class, sub, ii
return
end if
c
c Nitrogen, Phosphorus, Arsenic are assumed to be double bonded
c to alpha atom, which will also have beta atom(s). Therefore,
c the dihedral angle of kk, jj, alpha1, beta1 need to be determined.
c
case('N','P','As')
c
c Determine number of betas on alpha atom and their serial numbers
c
numbeta = 0
do i=1, n12r(ialpha1)
if (i12r(i,ialpha1).eq.jj) cycle
numbeta = numbeta + 1
ibeta(numbeta,1) = i12r(i,ialpha1)
end do
if (debug3) then
write(*,*) "Found ",numbeta, " beta atoms"
write(*,*) "which are ", ibeta(1:numbeta,1)
end if
c
c Determine if any beta is cis.
c
has_cisbeta = .false.
do i=1, numbeta
call torsionval(x, y, z, kk, jj, ialpha1,
& ibeta(i,1), dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (debug3) then
write(*,*) 'Dihedral angle of beta ', ibeta(i,1),
& ' is ', dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then ! cis
if (debug3) then
write(*,*) "Beta atom", ibeta(i,1),"is cis"
end if
has_cisbeta = .true.
ibetacis = ibeta(i,1)
if (atlab(ibetacis).eq.'H ') then
cisbeta_isH = .true.
end if
if (debug3) then
write(*,*) "ibetacis is ", ibetacis
write(*,*) "betacis is ", betacis
end if
exit ! found a cis, break from do loop
end if
end do
c
c if there's a beta atom which is cis to the loser atom, then it's
c either a 10-3 rotor or a 12-1 rotor.
c # cisbeta == H --> 10-3 else --> 12-1
c If there isn't a cis beta atom, it's a 10-4 rotor.
c
if (has_cisbeta) then ! there is a cis sub
if (cisbeta_isH) then ! the cis sub' is H
class = 10
sub = 3
ii = ialpha1
if (debug2) write(*,*) class, sub, ii
return
else ! the cis sub' isn't H
class = 12
sub = 1
ii = ialpha1
if (debug2) write(*,*) class, sub, ii
return
end if
else ! there is no cis sub'
class = 10
sub = 4
ii = ialpha1
if (debug2) write(*,*) class, sub, ii
return
end if
case default
class = 15
sub = 1
ii = ialpha1
if (debug2) write(*,*) class, sub, ii
return
end select
end if ! end of if valency = 2
c-----------------------------------------------------------------------
c Valency of 1. Terminal case.
c-----------------------------------------------------------------------
if (valency.eq.1) then
class = 16
sub = 1
ii = 1
if (debug2) write(*,*) class, sub, ii
return
end if
c-----------------------------------------------------------------------
c Valency of 0. Mission Abort.
c-----------------------------------------------------------------------
if (valency .eq. 0) then
write(*,*) "*** ABORTING FROM ASSIGNCLASS.F. ***"
write(*,*) "*** Linker atom has valency of zero!! ***"
stop
end if
c-----------------------------------------------------------------------
c Made it to the end without assigning a rotor type.
c-----------------------------------------------------------------------
stop "Could not determine rotor type"
end subroutine
c-----------------------------------------------------------------------
c SUBROUTINE TO ASSIGN FLAT RING CLASS AND SUBCLASS
c
c The rotational potential energy surface of flat rings is
c determined by the nature of the ortho atoms. In this subroutine,
c the ortho positions are characterized as:
c 1. unsubstituted: is divalent
c 2. hydrogen substituted
c 3. non-hydrogen substituted
c
c Both ortho positions are analyzed and the result may be any
c combination of the above.
c-----------------------------------------------------------------------
subroutine assign_arene(numatoms, attachatom, atomval, loseratom,
& valence_arr, serial_arr, atlabels,
& dihed_class, subclass, driver, debug)
implicit none
integer numatoms ! = r_atoms
integer i ! indexing variable
integer attachatom ! = jj
integer atomval ! = valency (n12r(jj))
integer loseratom ! = kk
integer valence_arr(numatoms) ! = n12r
integer serial_arr(10, numatoms) ! = i12r
character*2 atlabels(numatoms) ! = atlab
integer dihed_class ! = class
integer subclass ! = sub
integer driver ! = ii
c
c Variables concerning alpha positions
c
integer numortho ! number of alplha atoms
integer iortho(3) ! ortho atom serial numbers
integer iortho1 ! serial number of 1st ortho
integer iortho2 ! serial number of 2nd ortho
c
c Logical variables used to characterize ortho positions
c
logical ortho1hyd, ortho2hyd ! true if H attached at ortho
logical ortho1unsub, ortho2unsub ! true if ortho unsubstituted
logical ortho1sub, ortho2sub ! true if ortho substituted
logical debug
c
c Find serial numbers of ortho positions, their coordination numbers
c , and the number of H's attached to them.
c
numortho = 0
do i=1, atomval
if (serial_arr(i,attachatom).eq.loseratom) cycle
numortho = numortho + 1
iortho(numortho) = serial_arr(i,attachatom)
end do
iortho1 = iortho(1)
iortho2 = iortho(2)
if (debug) then
write(*,*) 'ortho subsitutents = ', numortho
write(*,*) 'Serial number of them are = ', iortho(1:numortho)
write(*,*) 'ortho1 is = ', iortho1
write(*,*) 'ortho2 is = ', iortho2
write(*,*) 'coordination of ortho1 = ',
& valence_arr(iortho1)
write(*,*) 'connection of ortho1 = ',
& atlabels(serial_arr(1:valence_arr(iortho1),
& iortho1))
write(*,*) 'coordination of ortho2 = ',
& valence_arr(iortho2)
write(*,*) 'connection of ortho2 = ',
& atlabels(serial_arr(1:valence_arr(iortho2),
& iortho2))
write(*,*)
end if
c
c Initialize all ortho related variables to false.
c
ortho1hyd = .false.
ortho2hyd = .false.
c
c Ortho is considered unsubstitued if it has a connectivity of
c two or if its 3rd substituent is hydrogen
c
ortho1unsub = .false.
ortho2unsub = .false.
c
c Ortho positions considered substituted only if its substituent
c isn't hydrogen.
c
ortho1sub = .false.
ortho2sub = .false.
c
c Test the valency of the ortho positions. Valencies of two means
c that it's unsubstituted. Valencies of three will be tested for an
c Hydrogen. If there's no hydrogen, it's considered substituted,
c i.e. orthoXunsub = .false. and orthoXsub = .true.
c
select case (valence_arr(iortho1))
case(2)
ortho1unsub = .true.
case(3)
c
c Loop through the atom labels of the serial number array, looking
c for 'H ' for Hydrogen.
c
do i=1,3
if (atlabels(serial_arr(i,iortho1)) .eq. 'H ') then
ortho1hyd = .true.
ortho1unsub = .true.
end if
end do
end select
select case (valence_arr(iortho2))
case(2)
ortho2unsub = .true.
case(3)
do i=1,3
if (atlabels(serial_arr(i,iortho2)).eq.'H ') then
ortho2hyd = .true.
ortho2unsub = .true.
end if
end do
end select
c
c Invert the logical value of orthoXsub for easier testing below.
c
ortho1sub = .not.ortho1unsub
ortho2sub = .not.ortho2unsub
if (debug) then
write(*,*) 'Is ortho1 unsubd? ', ortho1unsub
write(*,*) 'Is ortho1 subd? ', ortho1sub
write(*,*) 'H on ortho1? ', ortho1hyd
write(*,*) 'Is ortho2 unsubd? ', ortho2unsub
write(*,*) 'Is ortho2 subd? ', ortho2sub
write(*,*) 'H on ortho2? ', ortho2hyd
end if
c
c Begin Assignment of Flat Rings
c
if (ortho1hyd.and.ortho2hyd) then
c
c Hydrogens on both ortho positions
c
dihed_class = 3
subclass = 1
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Because the assignment of which ortho is ortho1 and which is
c ortho2 is arbitrary, asymmetric cases must be tested twice
c
elseif (ortho1hyd.and.ortho2sub) then
c
c Ortho1 is hydrogen substituted; ortho2 is substituted
c
dihed_class = 3
subclass = 2
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Opposite of previous
c
elseif (ortho2hyd.and.ortho1sub) then
dihed_class = 3
subclass = 2
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Both ortho's substituted.
c
elseif (ortho1sub.and.ortho2sub) then
dihed_class = 3
subclass = 3
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Ortho1 has is not substituted at all; Ortho2 has a Hydrogen
c
elseif (ortho1unsub.and.ortho2hyd) then
dihed_class = 13
subclass = 1
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Reverse of previous.
c
elseif (ortho2unsub.and.ortho1hyd) then
dihed_class = 13
subclass = 1
driver = iortho2
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Both ortho's unsubstituted.
c
elseif (ortho1unsub .and. ortho2unsub) then
dihed_class = 13
subclass = 2
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Both ortho's unsubstituted.
c
elseif (ortho1unsub .and. ortho2sub) then
dihed_class = 13
subclass = 3
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Otho2 is unsubstituted; ortho1 is substituted.
c
elseif (ortho2unsub .and. ortho1sub) then
dihed_class = 13
subclass = 3
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
c
c Tests have been exhausted, yet the rotor hasn't been assigned.
c Default to general class, 15-1.
c
else
dihed_class = 15
subclass = 1
driver = iortho1
if (debug) write(*,*) dihed_class, subclass, driver
return
end if
end subroutine assign_arene
c-----------------------------------------------------------------------
c SUBROUTINE TO ASSIGN TRIGONAL PLANAR CLASS AND SUBCLASS
c
c The rotational potential energy surface of flat rings is
c determined by the nature of the alpha atoms. In this subroutine,
c the alpha positions are characterized primarily by their valency
c minus one (this accounts for the alpha atom being bonded back to
c the attach atom (jj)).
c 1. Unsubstituted:
c a) Hydrogen attached directly to attach atom (jj), such as a
c aldehyde.
c b) Monovalent atom, such as a double bonded oxygen or a
c halogen.
c 2. hydrogen substituted
c 3. non-hydrogen substituted
c
c Both ortho positions are analyzed and the result may be any
c combination of the above.
c-----------------------------------------------------------------------
subroutine assign_trigplanar(r_atoms,x,y,z,jj,kk,n12r,i12r,
& atlab, class, sub, ii, ialpha, debug)
implicit none
integer r_atoms
real x(r_atoms)
real y(r_atoms)
real z(r_atoms)
integer ii ! driver atom
integer jj ! attach atom
integer kk ! loser atom
integer n12r(r_atoms)
integer i12r(10, r_atoms)
character*2 atlab(r_atoms)
integer class
integer sub
integer ialpha(2)
logical debug
integer ialpha1 ! serial # of alpha1 atom
integer ialpha2 ! serial # of alpha2 atom
integer numbeta ! dumb indexer of beta atoms
integer nbeta(2) ! array containing number of betas
! on each alpha
integer nbeta1 ! number of betas on alpha1
integer nbeta2 ! number of betas on alpha2
integer ibeta(r_atoms,r_atoms) ! array containing serial #s of
! of beta atoms on each alpha
integer ibeta1(r_atoms) ! serial #s of beta atoms on alpha1
integer ibeta2(r_atoms) ! serial #s of beta atoms on alpha2
logical has_cisbeta1 ! true if a beta1 is cis to kk
logical has_cisbeta2 ! true if a beta2 is cis to kk
logical beta1_isH ! true if there is a beta2 H atom
logical beta2_isH ! true if there is a beta2 H atom
logical cisbeta1_isH ! true if beta1 H atom is cis
logical cisbeta2_isH ! true if beta2 H atom is cis
integer icisbeta1 ! serial number of the cis beta1
! atom
integer icisbeta2 ! serial number of the cis beta2
! atom
integer itransbeta1 ! serial # of trans beta on alpha1
integer itransbeta2 ! serial # of trans beta on alpha2
real dihed ! used in dihedral angle calc's
integer i, j ! dumb indexing variables
has_cisbeta1 = .false.
has_cisbeta2 = .false.
beta1_isH = .false.
beta2_isH = .false.
cisbeta1_isH = .false.
cisbeta2_isH = .false.
icisbeta1 = 0
icisbeta2 = 0
itransbeta1 = 0
itransbeta2 = 0
c
c Because a certain alpha atom may only be connected back to jj, it
c may have 0 beta atoms. In that case, the 2 dimensional ibeta array
c will not be initialized. Therefore, initialize it manually and if
c the alpha atom(s) have betas then they will be placed in the
c array.
c
ibeta = 0
c
c now, create arrays containing the number of beta atoms on the two
c alpha atoms, not counting the attach atom jj. Also, create an
c array of the serial numbers of the beta atoms on the alphas.
c
do i = 1, 2
nbeta(i) = n12r(ialpha(i)) - 1 ! subtract one to account
! for bonding to jj
if (nbeta(i).eq.0) cycle ! beta is only connected to jj
! done't create beta arrays
numbeta = 0
do j=1, n12r(ialpha(i)) ! elsewise, not all betas are sampled
if (i12r(j,ialpha(i)).eq.jj) cycle ! keep jj from array
numbeta = numbeta + 1
ibeta(numbeta,i) = i12r(j,ialpha(i))
end do
end do
c
c if the link atom is attached to a hydrogen, make it alpha1
c for easier testing. otherwise, make alpha1 the alpha with
c the lowest number of substituents. if number of substituents
c is equal for both alphas, make alpha1 simply ialpha(1).
c
if (atlab(ialpha(1)).eq.'H ') then
ialpha1 = ialpha(1)
nbeta1 = nbeta(1)
ibeta1 = ibeta(:,1)
ialpha2 = ialpha(2)
nbeta2 = nbeta(2)
ibeta2 = ibeta(:,2)
elseif (atlab(ialpha(2)).eq.'H ') then
ialpha1 = ialpha(2)
nbeta1 = nbeta(2)
ibeta1 = ibeta(:,2)
ialpha2 = ialpha(1)
nbeta2 = nbeta(1)
ibeta2 = ibeta(:,1)
elseif (n12r(ialpha(1)).le.n12r(ialpha(2))) then
ialpha1 = ialpha(1)
nbeta1 = nbeta(1)
ibeta1 = ibeta(:,1)
ialpha2 = ialpha(2)
nbeta2 = nbeta(2)
ibeta2 = ibeta(:,2)
else
ialpha1 = ialpha(2)
nbeta1 = nbeta(2)
ibeta1 = ibeta(:,2)
ialpha2 = ialpha(1)
nbeta2 = nbeta(1)
ibeta2 = ibeta(:,1)
end if
c
c The end result is that fewer cases need to be tested. For example,
c if there are two betas on alpha 1, then there is no need to test
c for 1 beta on alpha 2.
c
if (debug) then
write(*,*)
write(*,*)'========== ALPHA & BETA INFO ============='
write(*,*)
write(*,'(A21,A2)') 'alpha1 is ', atlab(ialpha1)
write(*,'(A21,I2)') '# betas on alpha1 = ', nbeta1
write(*,*)
write(*,'(A21,A2)') 'alpha2 is ', atlab(ialpha2)
write(*,'(A21,I2)') '# betas on alpha2 = ', nbeta2
write(*,*)
write(*,*) '========================================='
write(*,*)
end if
c
c Begin logic tree by determining the coordination numbers of the
c alpha atom with the fewest substituents
c
select case (nbeta1) ! how many betas on alpha1 ?
case (0) ! zero betas on alpha1
if (debug) write(*,*) "0 betas on ialpha1"
if (atlab(ialpha1).eq.'H ') then ! if alpha1 beta is an H
if (debug) write(*,*) "ialpha1 is an H."
select case (nbeta2) ! how many betas on alpha2?
case(0) ! zero betas on alpha2
if (debug) write(*,*) "0 betas on ialpha2."
select case (atlab(ialpha2)) ! atom label of ibeta2
case ('H ')
if (debug) write(*,*) "ialpha2 is an H."
c
c Both alpha atoms are hydrogen.
c
class = 14
sub = 1
ii = ialpha2
if (debug) write(*,*) class, sub, ii
return
case ('O ')
if (debug) write(*,*) "ialpha2 is an O."
c
c One alpha is an H and the other is an oxygen. ==> Aldehyde
c
class = 10
sub = 1
ii = ialpha2
if (debug) write(*,*) class, sub, ii
return
case default
c
c One alpha is an H, and the other is only connected to the attach
c atom jj, but it isn't another H and it isn't an aldehyde. Assign
c it to be a "sulfaldehyde".
c
class = 10
sub = 2
ii = ialpha2
if (debug) write(*,*) class, sub, ii
return
end select ! end of ibeta2 atom label testing
case (1) ! 1 beta on alpha2
if (debug) write(*,*) "Alpha2 has 1 beta."
c
c alpha2 is connected to 1 other atom. test if it other atom
c is cis to the loser atom.
c
call torsionval(x,y,z,kk,jj,ialpha2,ibeta2(1),dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
if (debug) write (*,*) "Beta atom is cis"
has_cisbeta2 = .true.
icisbeta2 = ibeta2(1)
if (atlab(ibeta2(1)).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
if (has_cisbeta2) then
if (cisbeta2_isH) then
class = 2
sub = 1
ii = ialpha2
if (debug) write(*,*) class, sub, ii
return
else
class = 2
sub = 2
ii = ialpha2
if (debug) write(*,*) class, sub, ii
return
end if
else ! beta 2 is trans
class = 10
sub = 1
ii = ialpha2
if (debug) write(*,*) class, sub, ii
return
end if
! end of case 1, where alpha2 has 1 beta
case (2) ! alpha 2 has 2 betas
if (debug) write(*,*) "YESSS! Alpha 2 has 2 betas."
c
c Inspect the first beta atom connected to alpha 2. It is either
c cis or trans.
c
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if(atlab(icisbeta2).eq.'H ') then
cisbeta2_isH = .true.
if (debug) write(*,*) 'Yeehaw! It be H'
end if
else
itransbeta2 = ibeta2(i)
end if
end do
if (cisbeta2_isH) then
class = 2
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
elseif (n12r(icisbeta2).eq.1) then
class = 4
sub = 1
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
elseif (n12r(itransbeta2).eq.1 .and.
& atlab(itransbeta2).ne.'H ') then
class = 4
sub = 2
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 2
sub = 2
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (3) ! alpha 2 has 3 betas
c
c With a hydrogen for alpha 1 and a tertiary alpha 2, this is
c similar to methyl borane.
c
if (debug) write(*,*) "alpha 2 has 3 betas."
class = 14
sub = 2
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
case default
class = 15
sub = 1
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
end select
c
c End of if alpha1 beta is an H
c
c There are zero betas on alpha 1, but it isn't an H. Could be a
c carbonyl, halide, etc.
c
else
select case (nbeta2)
c
c Begin intial assessment based upon the number of betas on alpha2
c
case (0) ! 0 betas on alpha 2
if (debug) write(*,*) "Alpha 2 has 0 betas."
class = 13
sub = 2
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
case (1) ! 1 beta on alpha 2
if (debug) write(*,*) "Alpha 2 has 1 beta."
c
c alpha2 is connected to 1 other atom. test if it is cis
c to the loser atom
c
call torsionval(x,y,z,kk,jj,ialpha2,ibeta2(1),dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.0e0) then
if (debug) write(*,*) "Beta 2 atom is cis"
has_cisbeta2 = .true.
if (atlab(ibeta2(1)).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
if (has_cisbeta2) then
if (cisbeta2_isH) then
class = 13
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 13
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
else
class = 13
sub = 2
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (2) ! alpha 2 has two betas
if (debug) write(*,*) "Krikey! Alpha2 has 2 betas."
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if (atlab(icisbeta2).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
end do
if (cisbeta2_isH) then
class = 7
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 7
sub = 2
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (3) ! alpha 2 has three betas
if (debug) write(*,*) "Alpha2 has 3 betas."
if (atlab(ialpha1).eq.'O ') then
class = 11
sub = 2
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 11
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case default
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end select
end if ! end of case 0
case (1) ! alpha 1 has 1 beta atom
if (debug) write(*,*) "Jeepers! Alpha 1 has 1 beta"
c
c Having only one beta, the first test is whether or not it is cis.
c
call torsionval(x,y,z,kk,jj,ialpha1,ibeta1(1),dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.0e0) then
has_cisbeta1 = .true.
if (atlab(ibeta1(1)).eq.'H ') then
cisbeta1_isH = .true.
end if
end if
if (cisbeta1_isH) then ! beta on alpha 1 is a cis H
if (debug) write(*,*) "OMG! Alpha 1 has a cis hydrogen"
select case (nbeta2) ! how many betas on alpha 2?
case (1) ! 1 beta on alpha 2 (no need to test for case 0)
if (debug) write(*,*) "Dude like, Alpha 2 has 1 beta."
call torsionval(x,y,z,kk,jj,ialpha2,ibeta2(1),dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.0e0) then
has_cisbeta2 = .true.
if (atlab(ibeta2(1)).eq.'H ') then
cisbeta2_isH = .true.
if (debug) write(*,*) 'Whoah. Cis beta2 H'
end if
end if
if (has_cisbeta2) then
if (cisbeta2_isH) then
class = 3
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 3
sub = 2
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
end if
else ! beta on alpha2 is trans.
class = 13
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (2) ! 2 betas on alpha 2
if (debug) write(*,*) "Wow, man. Alpha 2 has 2 betas."
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if (atlab(icisbeta2).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
end do
if (cisbeta2_isH) then
class = 3
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 3
sub = 2
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (3) ! 3 betas on alpha 2
if (debug) write(*,*) "Alpha2 has 3 betas."
class = 2
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
case default ! alpha 2 has 4 or more betas
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end select ! end of selecting case for beta on alpha
! one is a cis hydrogen
elseif (has_cisbeta1) then ! alpha 1 has a cis beta but
! it's not a hydrogen
if (debug) write(*,*) "Um, cisbeta 1 not Hydro, bro..."
select case (nbeta2)
case (1) ! 1 beta on alpha 2 (no need to test for case 0)
if (debug) write(*,*) "Batman: Alpha 2 has 1 beta."
call torsionval(x,y,z,kk,jj,ialpha2,ibeta2(1),dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.0e0) then
has_cisbeta2 = .true.
if (atlab(ibeta2(1)).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
if (has_cisbeta2) then
if (cisbeta2_isH) then
class = 3
sub = 2
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 3
sub = 3
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
end if
else ! beta on alpha2 is trans.
class = 13
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (2) ! 2 betas on alpha 2
if (debug) write(*,*) "Alpha2 double up dem betas."
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if (atlab(ibeta2(i)).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
end do
if (cisbeta2_isH) then
class = 3
sub = 2
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 3
sub = 3
ii = ialpha2
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (3) ! 3 betas on alpha 2
if (debug) write(*,*) "alpha2 has 3 betas."
class = 2
sub = 4
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
case default ! alpha 2 has 4 or more betas
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end select ! end of selecting case for beta on alpha
! one is a cis hydrogen
else ! beta 1 is trans to the leaving atom
c
c further classification based on the number of beta atoms
c connected to alpha 2.
c
select case (nbeta2)
case (1) ! 1 beta on alpha 2
if (debug) write(*,*) "Alpha 2 has 1 betas."
call torsionval(x,y,z,kk,jj,ialpha2,ibeta2(1),dihed)
if (dihed.gt.180.0e0) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.0e0) then
has_cisbeta2 = .true.
if (atlab(ibeta2(1)).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
if (has_cisbeta2) then ! beta 2 is cis
if (cisbeta2_isH) then ! cis beta 2 is hydrogen
class = 13
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 13
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
else ! beta on alpha 2 is trans.
class = 13
sub = 2
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
case (2) ! alpha 2 has 2 betas, one of which is cis
! find the cis beta
if (debug) write(*,*) "Ooooo. Alpha 2 has 2 betas."
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if (atlab(icisbeta2).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
end do
if (cisbeta2_isH) then
if (atlab(ibeta1(1)).eq.'O '.and.
& atlab(ialpha1).eq.'N ') then
class = 7
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
else
class = 13
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
else
class = 13
sub = 3
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
end if
! end of case in which alpha 2 has 2 betas
case (3) ! alpha 2 has 3 betas
if (debug) write(*,*) "Derp. Alpha 2 has 3 betas."
class = 11
sub = 1
ii = ialpha1
if (debug) write(*,*) "===>",class, sub, ii
return
case default
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
end select
c
c End of assignment based upon substitution of number of betas on
c alpha 2.
c
end if
c
c End of assignment based upon torsion value of betas on alpha 1.
c
case (2) ! alpha 1 has 2 beta atoms
if (debug) write(*,*) "BOOM! Alpha 1 has 2 betas."
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha1,
& ibeta1(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta1 = ibeta1(i)
if (atlab(icisbeta1).eq.'H ') then
cisbeta1_isH = .true.
end if
else
itransbeta1 = ibeta1(1)
end if
end do
if (cisbeta1_isH) then
select case (nbeta2) ! how many betas on alpha 2 ?
case (2) ! 2 betas on alpha 2
if (debug) write(*,*) "Fooey. Alpha 2 has 2 betas."
! find out which one is cis
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if (atlab(icisbeta2).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
end do
if (cisbeta2_isH) then
class = 3
sub = 1
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
else
class = 3
sub = 2
ii = ialpha2
if (debug) write(*,*) '===>',class, sub, ii
return
end if
case (3) ! 3 betas on alpha 2
if (debug) write(*,*) "ialpha2 has 3 betas."
class = 2
sub = 3
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
case default
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
end select
! end of assignments based upon alpha 1 being an H
else ! cis beta on alpha 1 isn't H
select case (nbeta2)
case (2) ! 2 betas on alpha 2. find out which one is cis
if (debug) write(*,*) "ialpha2 has 2 betas."
do i = 1, 2
call torsionval(x,y,z,kk,jj,ialpha2,
& ibeta2(i), dihed)
if (dihed.gt.180e00) then
dihed = 360.0e0 - dihed
end if
if (dihed.ge.0.0e0.and.dihed.le.90.e0) then
icisbeta2 = ibeta2(i)
if (atlab(icisbeta2).eq.'H ') then
cisbeta2_isH = .true.
end if
end if
end do
if (cisbeta2_isH) then
class = 3
sub = 2
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
else
class = 3
sub = 3
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
end if
case (3) ! 3 betas on alpha 2
if (debug) write(*,*) "alpha2 has 3 betas."
if (n12r(icisbeta1).eq.1) then
class = 4
sub = 3
ii = ialpha1
write(*,*) '==>', class, sub, ii
return
else if (n12r(itransbeta1).eq.1) then
class = 4
sub = 4
ii = ialpha1
write(*,*) '==>', class, sub, ii
return
else
class = 2
sub = 4
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
end if
case default
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
end select
! end of selecting based on betas on alpha 2
end if ! end of testing nature of cis beta on alpha 2
! end of case in which alpha 2 has two betas
case (3) ! 3 betas on alpha 1
if (debug) write(*,*) "Alpha1 has 3 betas."
class = 14
sub = 3
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
c
c There are no classes/subclasses with alpha atoms having more than
c three substituents. If the subroutine has gotten to this point,
c then this is the case. Assign to the "general" class/subclass.
c Arbitrarily make alpha1 the driver.
c
case default
class = 15
sub = 1
ii = ialpha1
if (debug) write(*,*) '===>',class, sub, ii
return
end select
end subroutine assign_trigplanar
c-----------------------------------------------------------------------
c FINDANGLE
c-----------------------------------------------------------------------
c
c Subroutine to find the angle between three points. Nine reals are
c given to the subroutine, there being three reals for every point
c corresponding to its x, y, and z coordinates. The angle is found
c and returned as 'ang'.
c
subroutine findangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, ang)
real x1,y1,z1,x2,y2,z2,x3,y3,z3,ang ! coordinates and angle
real vect1(3), vect2(3) ! vectors creates by coordinates
real magvect1, magvect2 ! magnitude of vectors
real pi
pi = acos(-1.0e0)
c
c Vector created by points 1 and 2.
c
vect1 = [x2-x1, y2-y1, z2-z1]
c
c Vector created by points 1 and 3.
c
vect2 = [x3-x1, y3-y1, z3-z1]
c
c Magnitudes of the two vectors.
c
magvect1 = sqrt(vect1(1)*vect1(1) + vect1(2)*vect1(2) +
& vect1(3)*vect1(3))
magvect2 = sqrt(vect2(1)*vect2(1) + vect2(2)*vect2(2) +
& vect2(3)*vect2(3))
c
c The angle is the arc-cosine of the dot product of the two
c (normalized) vectors.
c
ang = acos((dot_product(vect1, vect2))/(magvect1*magvect2))
c
c Convert to dregrees
c
ang = (180.0/pi)*ang ! convert to degrees
return
end subroutine findangle
c
c-----------------------------------------------------------------------
c DISTANCE2PLANE
c-----------------------------------------------------------------------
c
c This subroutine finds the distance between a point and a plane. It
c is used to measure the planarity of trigonal moeities. Returns
c either .true. or .false., stored in the variable 'flat', which is
c determined by the distance. If the distance is below 'threshold',
c it is considered to be flat
c The plane is created by the first three coordinates. The point of
c interest is the fourth.
c Algebra adapted from
c http://mathworld.wolfram.com/Point-PlaneDistance.html
c
subroutine distance2plane(x, y, z, flat, debug)
real x(4), y(4), z(4)
real distance ! distance of jj from plane
real threshhold ! threshhold for testing planarity
real vect1(3), vect2(3), normvect(3) ! vectors
real magnormvect ! magnitude of normal vector
real unitvect(3) ! unit vector of normal vector
logical flat ! true if below threshhold
logical debug
threshhold = 0.20e0 ! below this threshhold is considered flat
if (debug) then
write(*,*)
write(*,*) "X array --> ", x
write(*,*) "Y array --> ", y
write(*,*) "Z array --> ", z
write(*,*)
end if
c
c Create the two vectors which will be used to find the normal to
c the plane.
c
vect1 = [x(3)-x(1), y(3)-y(1), z(3)-z(1)]
vect2 = [x(2)-x(1), y(2)-y(1), z(2)-z(1)]
if (debug) then
write(*,*)
write(*,*) "Vector 1 is ", vect1
write(*,*) "Vector 2 is ", vect2
write(*,*)
end if
c
c Compute their normal (cross product).
c
normvect = [vect1(2)*vect2(3) - vect1(3)*vect2(2),
& vect1(3)*vect2(1) - vect1(1)*vect2(3),
& vect1(1)*vect2(2) - vect1(2)*vect2(1)]
if (debug) write(*,*) "The normal vector is", normvect
c
c Compute the magnitude of the normal.
c
magnormvect = sqrt(dot_product(normvect, normvect))
if (debug) write(*,*) "The magnitude of the normal vector is",
& magnormvect
c
c Turn it into a unit vector.
c
unitvect = normvect / magnormvect
if (debug) write(*,*) "The unit vector is", unitvect
c
c The distance from the plane to the point is the projection of the
c vector created between the point of interest off of the plane and
c and any point on the plane onto the unit normal vector.
c The first point in the plane [x(1), y(1), z(1)] is used.
distance = dot_product(unitvect,
& [x(4)-x(1),y(4)-y(1),z(4)-z(1)])
c
c Don't want negative distances as an artifact of the directionality
c of the unit vector
c
distance = abs(distance)
if (debug) write(*,*) "The distance from the point to ",
& "the plane is ", distance
if (distance.le.threshhold) then
flat = .true.
else
flat = .false.
end if
return
end subroutine distance2plane
c-----------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment