PROGRAM RODS *------------------------------------------------------------------------------ * Program to set up input for RENDER with CYLINDERs drawn between * each pair of atoms lying closer than 0.6 * (sum of VanderWaals radii). * This program is the same as SETUP, except for what is generated. * Input matrix or angles are taken from setup.matrix or setup.angles * (NB: same files as setup) * * Eric Swanson Oct 1991 * Modified to generate cylinders with half bond colors, where needed. * EAM Feb 1997 * -radius XX to set cylinder radius * EAM Sep 1997 * -default colors; option for coloring by B-value * -more generous output formats (FORMATs 130 and 140) * EAM Jun 1999 * -brad XX to set ball radius as fraction of Van der Waals radius * EAM Jul 1999 * don't draw bonds across alternate chain locations * *------------------------------------------------------------------------------ INCLUDE 'VERSION.incl' * * I/O units for colour/co-ordinate input, specs output, user output INTEGER INPUT, OUTPUT, NOISE PARAMETER (INPUT=5, OUTPUT=6, NOISE=0) PARAMETER (MAXCOL=5000, MAXATM=10000) REAL RGB(3,MAXCOL),VDW(MAXCOL) REAL SPAM(6,MAXATM) REAL CEN(3) CHARACTER*24 MASK(MAXCOL),TEST CHARACTER*80 ATOM(MAXATM),CARD LOGICAL MATCH C C flags include C -b (ball and stick) C -h (suppress header records in output) C -radius XX (set cylinder radius) C -brad XX (set ball radius as fraction of VdW) C character*64 options logical bflag, hflag, bcflag, brflag real cylrad, ballrad c c Read in 3x3 view matrix from file setup.matrix. c Matrix is applied before finding translation, center, and scale. c Afterwards the input matrix to RENDER is therefore the identity matrix. C common /matrix/ matrix, coords real matrix(3,3), coords(3) C C Default to CPK colors and VDW radii character*60 defcol(7) data defcol / & 'COLOUR#######C################ 0.625 0.625 0.625 1.70', & 'COLOUR#######N################ 0.125 0.125 1.000 1.60', & 'COLOUR#######O################ 0.750 0.050 0.050 1.50', & 'COLOUR#######S################ 1.000 1.000 0.025 1.85', & 'COLOUR#######H################ 1.000 1.000 1.000 1.20', & 'COLOUR#######P################ 0.400 1.000 0.400 1.80', & 'COLOUR######################## 1.000 0.000 1.000 2.00' & / c 3 format(a,a) c bflag = .FALSE. bcflag = .FALSE. hflag = .FALSE. brflag = .FALSE. cylrad = 0.2 ballrad= 0.2 narg = iargc() i = 1 500 continue call getarg( i, options ) if (options(1:2) .eq. '-h') hflag = .true. if (options(1:5) .eq. '-Bcol') then bcflag = .true. i = i + 1 if (i.gt.narg) goto 701 call getarg( i, options ) read (options,*,err=701) Bmin i = i + 1 if (i.gt.narg) goto 701 call getarg( i, options ) read (options,*,err=701) Bmax endif if (options(1:2) .eq. '-b') bflag = .true. if (options(1:2) .eq. '-r') then i = i + 1 if (i.gt.narg) goto 701 call getarg( i, options ) read (options,*,err=701) cylrad if (cylrad.le.0) stop 'illegal radius value' end if if (options(1:3) .eq. '-br') then i = i + 1 if (i.gt.narg) goto 701 call getarg( i, options ) read (options,*,err=701) ballrad if (ballrad.le.0) stop 'illegal ball radius value' bflag = .true. end if i = i + 1 if (i.le.narg) goto 500 c goto 799 701 write (noise,'(A)') & 'syntax: rods [-h] [-b] [-Bcolor Bmin Bmax] [-radius R]' call exit(-1) 799 continue c write (noise,*) 'Raster3D rods program ',VERSION if (bcflag) then write (noise,*) 'Atom colors will be assigned based on Biso' write (noise,*) ' from dark blue = Bmin =', Bmin write (noise,*) ' to light red = Bmax =', Bmax endif c C do i=1,3 do j=1,3 matrix(i,j)=0. enddo matrix(i,i)=1. enddo call view_matrix c if (.not. hflag) then WRITE(OUTPUT,'(A,A)') 'rods ',VERSION WRITE(OUTPUT,'(A)') '80 64 tiles in x,y' WRITE(OUTPUT,'(A)') ' 8 8 pixels (x,y) per tile' WRITE(OUTPUT,'(A)') '4 anti-aliasing' WRITE(OUTPUT,'(A)') '0 0 0 black background' WRITE(OUTPUT,'(A)') 'F no, shadowed rods look funny' WRITE(OUTPUT,'(A)') '25 Phong power' WRITE(OUTPUT,'(A)') '0.15 secondary light contribution' WRITE(OUTPUT,'(A)') '0.05 ambient light contribution' WRITE(OUTPUT,'(A)') '0.25 specular reflection component' WRITE(OUTPUT,'(A)') '4.0 eye position' WRITE(OUTPUT,'(A)') '1 1 1 main light source position' end if c ASPECT = 1280./1024. NCOL = 0 NATM = 0 10 CONTINUE READ(INPUT,'(A80)',END=50) CARD IF (CARD(1:4).EQ.'COLO') THEN NCOL = NCOL + 1 IF (NCOL.GT.MAXCOL) THEN WRITE(NOISE,*) 'Colour table overflow. Increase ', & 'MAXCOL and recompile.' STOP 10 ENDIF READ(CARD,'(6X,A24,3F8.3,F6.2)',ERR=49) & MASK(NCOL), (RGB(I,NCOL),I=1,3),VDW(NCOL) ELSEIF (CARD(1:4).EQ.'ATOM'.OR.CARD(1:4).EQ.'HETA') THEN NATM = NATM + 1 IF (NATM.GT.MAXATM) THEN WRITE(NOISE,*) 'Atom array overflow. Increase ', & 'MAXATM and recompile.' STOP 20 ENDIF ATOM(NATM) = CARD ELSEIF (CARD(1:3).EQ.'END') THEN GO TO 50 ENDIF GO TO 10 * Problems reading input record 49 continue write(noise,*) 'rods: Cannot parse input record ',CARD call exit(-1) * Come here when EOF or 'END' record is reached 50 CONTINUE IF (NATM.EQ.0) THEN WRITE(NOISE,*) 'No atoms in input.' STOP 30 ENDIF * Load default colors after any that were read in IF (NCOL.LT.MAXCOL-8) THEN DO i = 1,7 NCOL = NCOL + 1 READ(defcol(i),'(6X,A24,3F8.3,F6.2)') MASK(NCOL), & (RGB(J,NCOL),J=1,3), VDW(NCOL) ENDDO ENDIF * IF (NCOL.EQ.0) THEN WRITE(NOISE,*) 'No colours in input.' STOP 40 ENDIF XMAX = -1E20 XMIN = 1E20 YMAX = -1E20 YMIN = 1E20 ZMAX = -1E20 ZMIN = 1E20 DO 100 IATM=1,NATM CARD = ATOM(IATM) TEST = CARD(7:30) DO 80 ICOL=1,NCOL IF (MATCH(TEST,MASK(ICOL))) THEN c READ(CARD,'(30X,3F8.3)',err=49) X,Y,Z c EAM Oct88 READ(CARD,'(30X,3F8.3,6X,F8.2)',err=49) coords, Biso x = coords(1)*matrix(1,1) + coords(2)*matrix(2,1) 1 + coords(3)*matrix(3,1) y = coords(1)*matrix(1,2) + coords(2)*matrix(2,2) 1 + coords(3)*matrix(3,2) z = coords(1)*matrix(1,3) + coords(2)*matrix(2,3) 1 + coords(3)*matrix(3,3) c EAM Oct88 RAD = VDW(ICOL) SPAM(1,IATM) = X SPAM(2,IATM) = Y SPAM(3,IATM) = Z SPAM(4,IATM) = RAD SPAM(5,IATM) = ICOL SPAM(6,IATM) = Biso XMAX = MAX(XMAX,X+RAD) XMIN = MIN(XMIN,X-RAD) YMAX = MAX(YMAX,Y+RAD) YMIN = MIN(YMIN,Y-RAD) ZMAX = MAX(ZMAX,Z+RAD) ZMIN = MIN(ZMIN,Z-RAD) GO TO 100 ENDIF 80 CONTINUE WRITE(NOISE,*) 'No colour table mask matches this atom:' WRITE(NOISE,*) ATOM(IATM) STOP 90 100 CONTINUE XMID = (XMAX+XMIN)/2. YMID = (YMAX+YMIN)/2. ZMID = (ZMAX+ZMIN)/2. TX = -XMID TY = -YMID TZ = -ZMID IF (ASPECT.GE.1.) THEN * The X direction is wider than the Y XROOM = ASPECT YROOM = 1. ZROOM = 2. ELSE XROOM = 1. YROOM = ASPECT ZROOM = 2. ENDIF XSPAN = XMAX-XMIN YSPAN = YMAX-YMIN ZSPAN = ZMAX-ZMIN SCALE = MAX(XSPAN/XROOM,YSPAN/YROOM,ZSPAN/ZROOM) * Leave a little extra room as a border: SCALE = SCALE / 0.90 c if (.not. hflag) then WRITE(OUTPUT,120) TX,TY,TZ,SCALE 120 FORMAT('1 0 0 0 input co-ordinate + radius transformation'/ & '0 1 0 0'/ & '0 0 1 0'/ & 4F10.3) WRITE(OUTPUT,'(A)') '3 mixed object types' WRITE(OUTPUT,'(A)') '*' WRITE(OUTPUT,'(A)') '*' WRITE(OUTPUT,'(A)') '*' end if C C Here's the real loop. C Look for pairs closer to each other than 0.60 times the C sum of the vanderWaals radii. C Draw all cylinders with 0.2A cylindrical radius. C For ball and stick pictures, shrink vanderWaals radius C of balls by 0.20 C If two atoms of different colors are bonded, make half-bond C cylinders with each color. C CLOSE = 1.6 * 1.6 C IF (BFLAG) THEN DO 135 IATM=1,NATM RAD = SPAM(4,IATM) * ballrad ICOL = SPAM(5,IATM) if (bcflag) then call B2RGB( SPAM(6,IATM), Bmin, Bmax, RED, GREEN, BLUE ) RED = RED*RED GREEN = GREEN*GREEN BLUE = BLUE*BLUE else RED = RGB(1,ICOL) GREEN = RGB(2,ICOL) BLUE = RGB(3,ICOL) endif WRITE(OUTPUT,130) 2 SPAM(1,IATM),SPAM(2,IATM),SPAM(3,IATM),RAD, 3 RED,GREEN,BLUE C130 FORMAT(1H2,/,7f8.3) 130 FORMAT(1H2,/,7(1X,F8.3)) 135 CONTINUE ENDIF C DO 160 IATM=1,NATM DO 150 JATM=IATM+1,NATM DX = SPAM(1,IATM) - SPAM(1,JATM) DY = SPAM(2,IATM) - SPAM(2,JATM) DZ = SPAM(3,IATM) - SPAM(3,JATM) DIST = DX*DX + DY*DY + DZ*DZ CLOSE = 0.6 * (SPAM(4,IATM) + SPAM(4,JATM)) CLOSE = CLOSE**2 IF (ATOM(IATM)(17:17).NE.' ' .AND. ATOM(JATM)(17:17).NE.' ' & .AND. ATOM(IATM)(17:17).NE.ATOM(JATM)(17:17)) GOTO 150 c c 4-Feb-2000 also force chain ID's to be the same c IF (ATOM(IATM)(22:22).NE.' ' .AND. ATOM(JATM)(22:22).NE.' ' & .AND. ATOM(IATM)(22:22).NE.ATOM(JATM)(22:22)) GOTO 150 IF (DIST .LE. CLOSE) THEN if (bcflag) then ICOL = 1 JCOL = 2 call B2RGB( SPAM(6,IATM), Bmin, Bmax, RED, GREEN, BLUE ) RGB(1,ICOL) = RED*RED RGB(2,ICOL) = GREEN*GREEN RGB(3,ICOL) = BLUE*BLUE call B2RGB( SPAM(6,JATM), Bmin, Bmax, RED, GREEN, BLUE ) RGB(1,JCOL) = RED*RED RGB(2,JCOL) = GREEN*GREEN RGB(3,JCOL) = BLUE*BLUE else ICOL = SPAM(5,IATM) JCOL = SPAM(5,JATM) endif IF(ICOL.EQ.JCOL) THEN WRITE(OUTPUT,140) 1 SPAM(1,IATM),SPAM(2,IATM),SPAM(3,IATM),CYLRAD, 2 SPAM(1,JATM),SPAM(2,JATM),SPAM(3,JATM),CYLRAD, 3 RGB(1,ICOL),RGB(2,ICOL),RGB(3,ICOL) else if (bcflag) then write(output,140) 1 SPAM(1,IATM),SPAM(2,IATM),SPAM(3,IATM),CYLRAD, 2 SPAM(1,JATM),SPAM(2,JATM),SPAM(3,JATM),CYLRAD, 3 RGB(1,ICOL),RGB(2,ICOL),RGB(3,ICOL) write(output,141) 1 RGB(1,ICOL),RGB(2,ICOL),RGB(3,ICOL), 2 RGB(1,JCOL),RGB(2,JCOL),RGB(3,JCOL), 3 0, 0, 0 ELSE DO 136 K=1,3 136 CEN(K) = (SPAM(K,IATM)+SPAM(K,JATM))/2 WRITE(OUTPUT,140) 1 SPAM(1,IATM),SPAM(2,IATM),SPAM(3,IATM),CYLRAD, 2 CEN(1),CEN(2),CEN(3),CYLRAD, 3 RGB(1,ICOL),RGB(2,ICOL),RGB(3,ICOL) WRITE(OUTPUT,140) 1 CEN(1),CEN(2),CEN(3),CYLRAD, 2 SPAM(1,JATM),SPAM(2,JATM),SPAM(3,JATM),CYLRAD, 3 RGB(1,JCOL),RGB(2,JCOL),RGB(3,JCOL) ENDIF ENDIF C140 FORMAT(1H3,/,11f8.3) 140 FORMAT(1H3,/,2(1X,F8.3,1X,F8.3,1X,F8.3,1X,F7.3),3F7.3) 141 format(2H17,/3(1X,3F6.3)) 150 CONTINUE 160 CONTINUE C C C write (noise,'(/)') write (noise,156) 'X min max:', XMIN, XMAX write (noise,156) 'Y min max:', YMIN, YMAX write (noise,156) 'Z min max:', ZMIN, ZMAX write (noise,156) ' scale:', SCALE 156 format(1x,a,3f8.2) END LOGICAL FUNCTION MATCH (SUBJ, MASK) CHARACTER*24 SUBJ,MASK MATCH = .FALSE. DO 10 I = 1, 24 IF (SUBJ(I:I).NE.MASK(I:I) .AND. MASK(I:I).NE.'#') RETURN 10 CONTINUE MATCH = .TRUE. RETURN END subroutine view_matrix c common /matrix/ matrix, coords real matrix(3,3), coords(3) c real phiX, phiY, phiZ integer noise parameter (noise = 0) parameter (R2D = 180./3.1415927) open (unit=3, file='setup.matrix', status='OLD', err=100) read (3,*) ((matrix(i,j),i=1,3),j=1,3) write (noise,'(1x,3f9.5)') ((matrix(i,j),i=1,3),j=1,3) close (3) det = matrix(1,1) * matrix(2,2) * matrix(3,3) 1 + matrix(1,2) * matrix(2,3) * matrix(3,1) 2 + matrix(2,1) * matrix(3,2) * matrix(1,3) 3 - matrix(1,3) * matrix(2,2) * matrix(3,1) 4 - matrix(1,2) * matrix(2,1) * matrix(3,3) 5 - matrix(1,1) * matrix(2,3) * matrix(3,2) write (noise,'('' determinant ='',f8.3)') det phiX = atan2( -matrix(3,2), matrix(3,3) ) phiY = atan2( matrix(3,1), matrix(3,3) / cos(phiX) ) phiZ = atan2( -matrix(2,1), matrix(1,1) ) write (noise,3) ' View Angles from matrix',' ' write (noise,2) phiZ*R2D, phiY*R2D, phiX*R2D return 100 continue open (unit=3, file='setup.angles', status='OLD', err=200) read (3,*) phiZ, phiY, phiX close (3) write (noise,2) phiZ, phiY, phiX cx = cos(phiX/R2D) sx = sin(phiX/R2D) cy = cos(phiY/R2D) sy = sin(phiY/R2D) cz = cos(phiZ/R2D) sz = sin(phiZ/R2D) matrix(1,1) = cz*cy matrix(1,2) = sz*cx + cz*sy*sx matrix(1,3) = sz*sx - cz*sy*cx matrix(2,1) = -sz*cy matrix(2,2) = cz*cx - sx*sy*sz matrix(2,3) = cz*sx + sz*sy*cx matrix(3,1) = sy matrix(3,2) = -sx*cy matrix(3,3) = cx*cy write (noise,3) ' View Matrix from angles',' ' write (noise,'(1x,3f9.5)') ((matrix(i,j),i=1,3),j=1,3) return 200 continue 2 format(1x,' phiZ =',f8.2,' phiY =',f8.2,' phiX =',f8.2) 3 format(/a,a) write (noise,*) ' No view matrix or angles provided' return end CCC Return RGB triple that runs from dark blue at Bmin CC to light red at Bmax C subroutine B2RGB( Biso, Bmin, Bmax, R, G, B ) real Biso, Bmin, Bmax, R, G, B c real fraction, h, s, v c fraction = (Biso-Bmin) / (Bmax-Bmin) if (fraction.lt.0.) fraction = 0. if (fraction.gt.1.) fraction = 1. h = 240. * (1.-fraction) s = 0.8 v = 0.5 + fraction/2. call hsv2rgb( h, s, v, r, g, b ) return end CCC Color format conversion from Hue/Saturation/Value to Red/Green/Blue CC minimal (i.e. NO) error checking C subroutine hsv2rgb( h, s, v, r, g, b ) real h, s, v, r, g, b c real f, p, q, t integer i c i = h /60. f = h/60. - float(i) p = v * (1. - s) q = v * (1. - s*f) t = v * (1. - s*(1. - f)) if (i.eq.5) then r = v g = p b = q else if (i.eq.4) then r = t g = p b = v else if (i.eq.3) then r = p g = q b = v else if (i.eq.2) then r = p g = v b = t else if (i.eq.1) then r = q g = v b = p else r = v g = t b = p endif return end