#!/bin/csh # This is a C-shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "csh file". To overwrite # existing files, type "csh file -c". You may unpack by hand by # following the "CUT_HERE_CUT_HERE..." lines, but check for any lines # which begin with "X" and remove the "X" If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 1)." # Contents: ITERATE.cmn MANIFEST Makefile Makefile_save README # ciftbx.cmf ciftbx.cmn ciftbx.cmv ciftbx.f ciftbx.sys clearfp.f # clearfp_sun.f cryst1-2-cif.awk hash_funcs.f iterate.csh.m4 # iterate.f iterate.html.m4 # Wrapped by yaya@epsilon.pair.com on Fri Oct 18 17:36:57 1996 setenv PATH /bin:/usr/bin:/usr/ucb if ( -e 'ITERATE.cmn' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'ITERATE.cmn'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'ITERATE.cmn' (319 characters)" #___________ THE FILE 'ITERATE.cmn' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'ITERATE.cmn' <<"CUT_HERE_CUT_HERE_CUT_HERE" common /files/ iunt0,iunt1,iunt2,iunt3,iunt10 common /qenv/ querst,ostyle,istyle common /qcifl/ cifres common /qcifs/ cifeid,cifsgs,hm character*80 querst,ostyle,istyle character*4 cifeid character*11 cifsgs character*1 hm logical cifres include 'ciftbx.cmv' "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'ITERATE.cmn' ENDS TWO LINES BEFORE THIS ___________ if ( 319 != `wc -c <'ITERATE.cmn'` ) then echo "cshar: 'ITERATE.cmn' unpacked with wrong size" endif # end of 'ITERATE.cmn' endif if ( -e 'MANIFEST' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'MANIFEST'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'MANIFEST' (1103 characters)" #___________ THE FILE 'MANIFEST' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'MANIFEST' <<"CUT_HERE_CUT_HERE_CUT_HERE" File Name Archive # Description ----------------------------------------------------------- ITERATE.cmn 1 include file for iterate.f MANIFEST 1 This file Makefile 1 Command file for make Makefile_save 1 Clean safety copy of Makefile README 1 Instructions on installtion and use ciftbx.cmf 1 functions include file used by ciftbx ciftbx.cmn 1 include file used by ciftbx (=.cmf+.cmv) ciftbx.cmv 1 variables file used by ciftbx ciftbx.f 1 CIF toolbox used by iterate.f ciftbx.sys 1 include file used by ciftbx clearfp.f 1 dummy routine called by ciftbx clearfp_sun.f 1 alternative to clearfp.f for SUN cryst1-2-cif.awk 1 awk script to extract cells from PDB hash_funcs.f 1 subroutines used by ciftbx iterate.csh.m4 1 m4 source of iterate.csh iterate.f 1 source of program iterate iterate.html.m4 1 m4 source of iterate.html "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'MANIFEST' ENDS TWO LINES BEFORE THIS ___________ if ( 1103 != `wc -c <'MANIFEST'` ) then echo "cshar: 'MANIFEST' unpacked with wrong size" endif # end of 'MANIFEST' endif if ( -e 'Makefile' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'Makefile'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'Makefile' (3920 characters)" #___________ THE FILE 'Makefile' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'Makefile' <<"CUT_HERE_CUT_HERE_CUT_HERE" # # Makefile for ITERATE # # Herbert J. Bernstein, Bernstein + Sons # Lawrence C. Andrews, Thuridion, Inc. # # 29 Sep 1996 # # # Modify the following definitions for your system # # HTTPDSERVER is the name of the server on which the # installation is being made # # ************************************************* # *** YOU MUST CHANGE THIS DEFINITION TO PERMIT *** # *** REMOTE ACCESS *** # ************************************************* # HTTPDSERVER = localhost # The following are normal defaults for a system manager # installation assuming an NCSA httpd default installation # # BINDEST is the installation directory for the executable # of ITERATE BINDEST = /usr/local/bin # # CGIBIN is the installation directory for the cgi-bin script # iterate.csh CGIBIN = /usr/local/etc/httpd/cgi-bin # # CGIBINEXT is the external name of the directory for the # cgi-bin script iterate.csh CGIBINEXT = /cgi-bin # # HTDOCS is the installation directory for the HTML document # iterate.html HTDOCS = /usr/local/etc/httpd/htdocs # # For a user installation you need the system manager to have # permitted cgi-bin execution from the directory given # The following lines, with the "??????" replaced by a valid # user name are a possible start on user installation definitions # #USERNAME = ?????? #BINDEST = /home/$(USERNAME)/bin #CGIBIN = /home/$(USERNAME)/public_html/cgi-bin #CGIBINEXT = /~$(USERNAME)/cgi-bin #HTDOCS = /home/$(USERNAME)/public_html # # Default compile flag definition to select debug mode under unix FFLAGS = -g # # For IBM AIX xlf compilation with full optimization try this #FFLAGS = -O3 -qstrict #FC = xlf # HTFLAGS = -DFULLHTDOCS=$(CGIPATH) # # For use of wwwcount2.3 #HTFLAGS = -DFULLHTDOCS=$(CGIPATH) -DWWWCOUNT=TRUE # # # You should not have to edit below this line #******************************************************************** # # CGIPATH = http://$(HTTPDSERVER)$(CGIBINEXT)/iterate.csh BINPATH = $(BINDEST)/ITERATE # all: edit # edit: @/bin/echo "**************************************" @/bin/echo "* You must edit Makefile before *" @/bin/echo "* installing ITERATE *" @/bin/echo "* Then: *" @/bin/echo "* make edit_done *" @/bin/echo "* make all *" @/bin/echo "**************************************" # edit_done: ITERATE iterate.html iterate.csh touch edit # clean: -rm edit -rm iterate.html -rm ITERATE -rm iterate.csh -rm *.bak # iterate.html: iterate.html.m4 Makefile m4 $(HTFLAGS) < iterate.html.m4 > iterate.html # iterate.csh: iterate.csh.m4 Makefile m4 -DBINPATH=$(BINPATH) < iterate.csh.m4 > iterate.csh # install: ITERATE iterate.csh iterate.html iterate.cshar iterate.shar -mkdir -p $(BINDEST) -mkdir -p $(CGIBIN) -mkdir -p $(HTDOCS) chmod 755 ITERATE chmod 755 iterate.csh cp ITERATE $(BINDEST) cp iterate.csh $(CGIBIN) cp iterate.html $(HTDOCS) cp iterate.cshar $(HTDOCS) cp iterate.shar $(HTDOCS) # ciftbx.o: ciftbx.f ciftbx.sys ciftbx.cmn ciftbx.cmf ciftbx.cmv clearfp.f hash_funcs.o: hash_funcs.f iterate.o: iterate.f ITERATE.cmn ciftbx.cmn ciftbx.cmf ciftbx.cmv ITERATE: ITERATE.cmn iterate.o ciftbx.o hash_funcs.o $(FC) $(FFLAGS) -o ITERATE iterate.o ciftbx.o hash_funcs.o iterate.shar: MANIFEST README Makefile Makefile_save iterate.f ITERATE.cmn \ ciftbx.f ciftbx.cmn ciftbx.sys ciftbx.cmf ciftbx.cmv hash_funcs.f \ iterate.html.m4 iterate.csh.m4 cryst1-2-cif.awk clearfp.f \ clearfp_sun.f -rm iterate.shar makekit -s5000k -m mv Part01 iterate.shar iterate.cshar: MANIFEST README Makefile Makefile_save iterate.f ITERATE.cmn \ ciftbx.f ciftbx.cmn ciftbx.sys ciftbx.cmf ciftbx.cmv hash_funcs.f \ iterate.html.m4 iterate.csh.m4 cryst1-2-cif.awk clearfp.f \ clearfp_sun.f -rm iterate.cshar makekit -c -s5000k -m mv Part01 iterate.cshar "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'Makefile' ENDS TWO LINES BEFORE THIS ___________ if ( 3920 != `wc -c <'Makefile'` ) then echo "cshar: 'Makefile' unpacked with wrong size" endif # end of 'Makefile' endif if ( -e 'Makefile_save' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'Makefile_save'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'Makefile_save' (3920 characters)" #___________ THE FILE 'Makefile_save' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'Makefile_save' <<"CUT_HERE_CUT_HERE_CUT_HERE" # # Makefile for ITERATE # # Herbert J. Bernstein, Bernstein + Sons # Lawrence C. Andrews, Thuridion, Inc. # # 29 Sep 1996 # # # Modify the following definitions for your system # # HTTPDSERVER is the name of the server on which the # installation is being made # # ************************************************* # *** YOU MUST CHANGE THIS DEFINITION TO PERMIT *** # *** REMOTE ACCESS *** # ************************************************* # HTTPDSERVER = localhost # The following are normal defaults for a system manager # installation assuming an NCSA httpd default installation # # BINDEST is the installation directory for the executable # of ITERATE BINDEST = /usr/local/bin # # CGIBIN is the installation directory for the cgi-bin script # iterate.csh CGIBIN = /usr/local/etc/httpd/cgi-bin # # CGIBINEXT is the external name of the directory for the # cgi-bin script iterate.csh CGIBINEXT = /cgi-bin # # HTDOCS is the installation directory for the HTML document # iterate.html HTDOCS = /usr/local/etc/httpd/htdocs # # For a user installation you need the system manager to have # permitted cgi-bin execution from the directory given # The following lines, with the "??????" replaced by a valid # user name are a possible start on user installation definitions # #USERNAME = ?????? #BINDEST = /home/$(USERNAME)/bin #CGIBIN = /home/$(USERNAME)/public_html/cgi-bin #CGIBINEXT = /~$(USERNAME)/cgi-bin #HTDOCS = /home/$(USERNAME)/public_html # # Default compile flag definition to select debug mode under unix FFLAGS = -g # # For IBM AIX xlf compilation with full optimization try this #FFLAGS = -O3 -qstrict #FC = xlf # HTFLAGS = -DFULLHTDOCS=$(CGIPATH) # # For use of wwwcount2.3 #HTFLAGS = -DFULLHTDOCS=$(CGIPATH) -DWWWCOUNT=TRUE # # # You should not have to edit below this line #******************************************************************** # # CGIPATH = http://$(HTTPDSERVER)$(CGIBINEXT)/iterate.csh BINPATH = $(BINDEST)/ITERATE # all: edit # edit: @/bin/echo "**************************************" @/bin/echo "* You must edit Makefile before *" @/bin/echo "* installing ITERATE *" @/bin/echo "* Then: *" @/bin/echo "* make edit_done *" @/bin/echo "* make all *" @/bin/echo "**************************************" # edit_done: ITERATE iterate.html iterate.csh touch edit # clean: -rm edit -rm iterate.html -rm ITERATE -rm iterate.csh -rm *.bak # iterate.html: iterate.html.m4 Makefile m4 $(HTFLAGS) < iterate.html.m4 > iterate.html # iterate.csh: iterate.csh.m4 Makefile m4 -DBINPATH=$(BINPATH) < iterate.csh.m4 > iterate.csh # install: ITERATE iterate.csh iterate.html iterate.cshar iterate.shar -mkdir -p $(BINDEST) -mkdir -p $(CGIBIN) -mkdir -p $(HTDOCS) chmod 755 ITERATE chmod 755 iterate.csh cp ITERATE $(BINDEST) cp iterate.csh $(CGIBIN) cp iterate.html $(HTDOCS) cp iterate.cshar $(HTDOCS) cp iterate.shar $(HTDOCS) # ciftbx.o: ciftbx.f ciftbx.sys ciftbx.cmn ciftbx.cmf ciftbx.cmv clearfp.f hash_funcs.o: hash_funcs.f iterate.o: iterate.f ITERATE.cmn ciftbx.cmn ciftbx.cmf ciftbx.cmv ITERATE: ITERATE.cmn iterate.o ciftbx.o hash_funcs.o $(FC) $(FFLAGS) -o ITERATE iterate.o ciftbx.o hash_funcs.o iterate.shar: MANIFEST README Makefile Makefile_save iterate.f ITERATE.cmn \ ciftbx.f ciftbx.cmn ciftbx.sys ciftbx.cmf ciftbx.cmv hash_funcs.f \ iterate.html.m4 iterate.csh.m4 cryst1-2-cif.awk clearfp.f \ clearfp_sun.f -rm iterate.shar makekit -s5000k -m mv Part01 iterate.shar iterate.cshar: MANIFEST README Makefile Makefile_save iterate.f ITERATE.cmn \ ciftbx.f ciftbx.cmn ciftbx.sys ciftbx.cmf ciftbx.cmv hash_funcs.f \ iterate.html.m4 iterate.csh.m4 cryst1-2-cif.awk clearfp.f \ clearfp_sun.f -rm iterate.cshar makekit -c -s5000k -m mv Part01 iterate.cshar "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'Makefile_save' ENDS TWO LINES BEFORE THIS ___________ if ( 3920 != `wc -c <'Makefile_save'` ) then echo "cshar: 'Makefile_save' unpacked with wrong size" endif # end of 'Makefile_save' endif if ( -e 'README' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'README'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'README' (14837 characters)" #___________ THE FILE 'README' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'README' <<"CUT_HERE_CUT_HERE_CUT_HERE" README for ITERATE 29 Sep 96 Herbert J. Bernstein, Bernstein + Sons Lawrence C. Andrews, Thuridion, Inc. NOTICE Some of the software and documents included within this software package are the intellectual property of various parties, and placement in this package does not in anyway imply that any such rights have in any way been waived or diminished. With respect to any software or documents for which a copyright exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT. Even though the authors of the various documents and software found here have made a good faith effort to ensure that the documents are correct and that the software performs according to its documentation, and we would greatly appreciate hearing of any problems you may encounter, the programs and documents any files created by the programs are provided **AS IS** without any warrantee as to correctness, merchantability or fitness for any particular or general use. THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE PROGRAMS OR DOCUMENTS. INSTALLATION Before installation, ensure that you have a complete kit as shown in the file MANIFEST. If you think Makefile has been corrupted, make a fresh copy from Makefile_save. The files ciftbx.f, ciftbx.cmn, ciftbx.cmf, ciftbx.cmv, ciftbx.sys and hash_funcs.f are from the CIFtbx2 kit. They are needed in order to read and write CIFs. If you need an update to CIFtbx2, see http://ndbserver.rutgers.edu/software/ciftbx The complete ITERATE suite consists of a the fortran program ITERATE, an html web page iterate.html, and a cgi-bin script iterate.csh. The web page and script need some definitions for each system. They are built from m4 macro documents by make, using a command file Makefile, which must contain the appropriate definitions. In order to install the program, you need to edit the file Makefile, setting the following parameters appropriately for your system: HTTPDSERVER is the name of the server on which the installation is being made. YOU MUST CHANGE THIS DEFINITION TO PERMIT REMOTE ACCESS. The default definition is: HTTPDSERVER = localhost BINDEST is the installation directory for the executable of ITERATE. CGIBIN is the installation directory for the cgi-bin script iterate.csh CGIBINEXT is the external name of the directory for the cgi-bin script iterate.csh. HTDOCS is the installation directory for the HTML document iterate.html. The following are normal defaults for a system manager installation assuming an NCSA httpd default installation. BINDEST = /usr/local/bin CGIBIN = /usr/local/etc/httpd/cgi-bin CGIBINEXT = /cgi-bin HTDOCS = /usr/local/etc/httpd/htdocs For a user installation you need the system manager to have permitted cgi-bin execution from the directory given. The following lines, with the "??????" replaced by a valid user name are a possible start on user installation definitions USERNAME = ?????? BINDEST = /home/$(USERNAME)/bin CGIBIN = /home/$(USERNAME)/public_html/cgi-bin CGIBINEXT = /~$(USERNAME)/cgi-bin HTDOCS = /home/$(USERNAME)/public_html The default compile flag definition to select debug mode under unix is FFLAGS = -g For IBM AIX xlf compilation with full optimization try this FFLAGS = -O3 -qstrict FC = xlf The following flag normally does not need to be changed. HTFLAGS = -DFULLHTDOCS=$(CGIPATH) However, for use with wwwcount2.3 HTFLAGS = -DFULLHTDOCS=$(CGIPATH) -DWWWCOUNT=TRUE Once you have completed your edit, then make edit_done make all If you are the system manager and have set the definitions appropriately, then you can use make install to install the program, web page and cgi-bin script. OPERATION The program may be operated as a stand-alone program, reading data from stdin, writing output to stdout and messages to stderr. Three environment variables control the operation of the program in stand-alone mode: ITERATE_QUERY set to NO if the program is to run a single pass OUTPUT_STYLE set to CIF if the output is to be a CIF INPUT_STYLE set to CIF if the input is to be a CIF If the input is a CIF, the following tokens are expected: _cell.entry_id a character string to associate with the cell _cell.space_group_name_H-M a space group symbol (used only for centering) _cell.length_a the length in Angstroms of cell edge a with esd _cell.length_b the length in Angstroms of cell edge b with esd _cell.length_c the length in Angstroms of cell edge c with esd _cell.angle_alpha the cell angle alpha in degrees with esd _cell.angle_beta the cell angle beta in degrees with esd _cell.angle_gamma the cell angle gamma in degrees with esd When esd's are given they should be given as parenthesized digits, as in _cell.length_a 100.5(3) for a cell edge of 100.5 +/- .3 When no esd's are given the program forces in minimal defaults. If the input is not a CIF, then the information to be provided is a lattice centering symbol (P, F, etc.), then a line with three cell edge lengths and angles, and finally a line with with three edge length esd's in Angstroms (not final digits) and cell angle esd's in degrees. If the output is a cif, the following tokens are used: data_G6_SEARCH loop_ _cell.entry_id _cell.id _cell.space_group_name_H-M _cell.Bravais_lattice_symbol _cell.length_a _cell.length_b _cell.length_c _cell.angle_alpha _cell.angle_beta _cell.angle_gamma _cell.unreduced_length_a _cell.unreduced_length_b _cell.unreduced_length_c _cell.unreduced_angle_alpha _cell.unreduced_angle_beta _cell.unreduced_angle_gamma The last six are used to report the centered, rather than primitive cell. SAMPLE WEB PAGE G6 Bravais Lattice Determination Interface by Lawrence C. Andrews, Thuridion, Inc., andrews@thuridion.com and Herbert J. Bernstein, Bernstein+Sons, yaya@aip.org ______ _____ Output Style: [text] Select the crystal lattice centering:[P (primitive)...........] Specify the cell edge lengths and angles: _cell.length_a _________ _cell.angle_alpha _________ _cell.length_b _________ _cell.angle_beta _________ _cell.length_c _________ _cell.angle_gamma _________ Specify the cell edge length esd's and angle esd's: _cell.length_a_esd _________ _cell.angle_alpha_esd _________ _cell.length_b_esd _________ _cell.angle_beta_esd _________ _cell.length_c_esd _________ _cell.angle_gamma_esd _________ _________________________________________________________________ _________________________________________________________________ What Does This Web Page Do? In simple terms, what this page does is to find the cells which are "close" to the cell given, in order to help find the Bravais lattice of highest symmetry consistent with the cell. A central problem in the solution of every crystal structure is to determine the correct Bravais lattice of the crystal. The Bravais lattices as they are usually listed are: aP triclinic (anorthic) primitive mP monoclinic primitive mS monoclinic side-centered (usually C-centered) oP orthorhombic primitive oS orthorhombic side-centered oF orthorhombic face-centered oI orthorhombic body-centered hP hexagonal primitive hR hexagonal rhombohedrally-centered tP tetragonal primitive tI tetragonal body-centered cP cubic primitive cF cubic face-centered cI cubic body-centered Failure to find the highest correct symmetry has several consequences, the worst of which is that the structure may not be solved. The least of the consequences is that Richard Marsh may publish a paper that points out the error, corrects it, and finds a better solution to the structure. Many methods have been described for finding the correct Bravais lattice. A summary of the published methods was published in the paper that described the G6 formalism (which is used in the program on this web page). "Lattices and Reduced Cells as Points in 6-Space and Selection of Bravais Lattice Type by Projections." Lawrence C. Andrews and Herbert J. Bernstein, Acta Crystallographica, A44, 1009-1018 (1988). The program on this Web page implements a search in G6 for the various Bravais lattices that the user's cell may fit. For each lattice type, the best metric match is reported. If the higher symmetry type is actually correct, then that is likely to be the best cell from which to start further refinement. However, the possibility exists that one of the rejected cells (which did not match as well) was actually the correct one to use. The reason for this ambiguity is experimental error and its propagation in the transformations of the lattices in the program. Fortunately, the rejected cells are usually quite similar to the accepted one. A note on standard deviations: First, even in the best of circumstances, standard deviations of unit cell dimensions from 4-circle diffractometer data are always underestimated (by at least a factor of 2). In addition, the points chosen for the determination are often not well distributed (for example all in the first octant of orthorhombic lattices). These less than optimal choices cause substantial systematic error. The experimental errors are amplified in the mathematical conversions between various lattices that any lattice search program must perform. It is not a rare occurrence for angles to be incorrect by 0.5 degrees in initial unit cell determinations. Note: Even in most well determined unit cells, the actual errors in the edge lengths is 0.2 to 0.5 parts per thousand. (Note that reproducibility of the measurements is substantially better, leading to the illusion that diffractometers produce excellent unit cell parameters). Use of standard deviations that are too small is a common reason for failure of Bravais lattice searches. For small molecules, 0.1 Angstroms is a reasonable error for the edge lengths, for proteins, 0.4 to 0.5 (or even more for preliminary measurements). Accurate unit cell parameters must by determined by a number of more complex methods and must include extrapolation to remove systematic effects. For an excellent summary, see "Xray Structure Determination", G.H.Stout and L.H.Jensen, Wiley, 1989. SAMPLE TEXT OUTPUT # G6 Lattice Identification # Centering: P # Cell: 10. 10. 10. 90. 90. 90. # Sigmas: .15 .15 .15 .2 .2 .2 # Results of ITERATE Run # Input Lattice Symbol P # INPUT CELL AND ERRORS INPUT VECTOR AND ERRORS # 10.000 .150 100.000 3.00 # 10.000 .150 100.000 3.00 # 10.000 .150 100.000 3.00 # 90.000 .200 .000 .70 # 90.000 .200 .000 .70 # 90.000 .200 .000 .70 # INPUT VECTOR SIZE AND ERROR AND RATIO 173.21 5.33 .03 # REDUCED CELL # Red. Cell 10.000 10.000 10.000 90.000 90.000 90.000 # Red. Vector 100.00 100.00 100.00 .00 .00 .00 1 cP # .00 = Distance Projected Internat. Tables#( 3) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # primitive 10.000 # transformation from 3-space original cell # to final primitive cell # 1.000 .000 .000 # .000 1.000 .000 # .000 .000 1.000 4 tP # .00 = Distance Projected Internat. Tables#(11) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # primitive 10.000 10.000 # transformation from 3-space original cell # to final primitive cell # 1.000 .000 .000 # .000 1.000 .000 # .000 .000 1.000 10 hR # .00 = Distance Projected Internat. Tables#( 2) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # as rhomboh. 10.000 alpha 90.000 # transformation from 3-space original cell # to final primitive cell # 1.000 -1.000 .000 # -1.000 .000 1.000 # -1.000 -1.000 -1.000 12 oP # .00 = Distance Projected Internat. Tables#(32) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # primitive 10.000 10.000 10.000 # transformation from 3-space original cell # to final primitive cell # 1.000 .000 .000 # .000 1.000 .000 # .000 .000 1.000 14 oS # .00 = Distance Projected Internat. Tables#(13) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # side-centered 14.142 14.142 10.000 # transformation from 3-space original cell # to final centered cell # 1.000 1.000 .000 # -1.000 1.000 .000 # .000 .000 1.000 20 mP # .00 = Distance Projected Internat. Tables#(33) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # primitive 10.000 10.000 10.000 beta 90.000 # transformation from 3-space original cell # to final primitive cell # 1.000 .000 .000 # .000 1.000 .000 # .000 .000 1.000 22 mS # .00 = Distance Projected Internat. Tables#(10) # Vector 100.0 100.0 100.0 .0 .0 .0 # cell 10.00 10.00 10.00 90.00 90.00 90.00 # side-centered 14.142 14.142 10.000 beta 90.000 # transformation from 3-space original cell # to final centered cell # 1.000 1.000 .000 # -1.000 1.000 .000 # .000 .000 1.000 "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'README' ENDS TWO LINES BEFORE THIS ___________ if ( 14837 != `wc -c <'README'` ) then echo "cshar: 'README' unpacked with wrong size" endif # end of 'README' endif if ( -e 'ciftbx.cmf' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'ciftbx.cmf'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'ciftbx.cmf' (3675 characters)" #___________ THE FILE 'ciftbx.cmf' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'ciftbx.cmf' <<"CUT_HERE_CUT_HERE_CUT_HERE" C C >>>>>> Function declararations 'ciftbx.cmf' C C C These external declarations are needed complete C the user definitions in ciftbx.cmn C C C Logical function init_ logical init_ C Logical function dict_ logical dict_ C Logical function ocif_ logical ocif_ C Logical function data_ logical data_ C Logical function test_ logical test_ C Logical function bkmrk_ logical bkmrk_ C Logical function find_ logical find_ C Logical function name_ logical name_ C Logical function numb_ logical numb_ C Logical function numd_ logical numd_ C Logical function char_ logical char_ C Logical function cmnt_ logical cmnt_ C Logical function pfile_ logical pfile_ C Logical function pdata_ logical pdata_ C Logical function pchar_ logical pchar_ C Logical function pcmnt_ logical pcmnt_ C Logical function pnumb_ logical pnumb_ C Logical function pnumd_ logical pnumd_ C Logical function ptext_ logical ptext_ C Logical function ploop_ logical ploop_ C Logical function prefx_ logical prefx_ C C logical function init_ external init_ C logical function dict_ external dict_ C logical function ocif_ external ocif_ C logical function data_ external data_ C logical function test_ external test_ C logical function bkmrk_ external bkmrk_ C logical function find_ external find_ C logical function name_ external name_ C logical function numb_ external numb_ C logical function numd_ external numd_ C logical function char_ external char_ C logical function cmnt_ external cmnt_ C logical function pfile_ external pfile_ C logical function pdata_ external pdata_ C logical function pchar_ external pchar_ C logical function pcmnt_ external pcmnt_ C logical function pnumb_ external pnumb_ C logical function pnumd_ external pnumd_ C logical function ptext_ external ptext_ C logical function ploop_ external ploop_ C logical function prefx_ external prefx_ "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'ciftbx.cmf' ENDS TWO LINES BEFORE THIS ___________ if ( 3675 != `wc -c <'ciftbx.cmf'` ) then echo "cshar: 'ciftbx.cmf' unpacked with wrong size" endif # end of 'ciftbx.cmf' endif if ( -e 'ciftbx.cmn' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'ciftbx.cmn'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'ciftbx.cmn' (203 characters)" #___________ THE FILE 'ciftbx.cmn' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'ciftbx.cmn' <<"CUT_HERE_CUT_HERE_CUT_HERE" C C >>>>>> Common and Function declararations 'ciftbx.cmn' C C These declarations must be included in ciftbx user C applications. C include 'ciftbx.cmv' include 'ciftbx.cmf' "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'ciftbx.cmn' ENDS TWO LINES BEFORE THIS ___________ if ( 203 != `wc -c <'ciftbx.cmn'` ) then echo "cshar: 'ciftbx.cmn' unpacked with wrong size" endif # end of 'ciftbx.cmn' endif if ( -e 'ciftbx.cmv' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'ciftbx.cmv'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'ciftbx.cmv' (4220 characters)" #___________ THE FILE 'ciftbx.cmv' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'ciftbx.cmv' <<"CUT_HERE_CUT_HERE_CUT_HERE" C C >>>>>> Common declararations 'ciftbx.cmn' C C These declarations must be included in ciftbx user C applications. C C C Parameters to control sizes C C Maximum number of characters in C data names integer NUMCHAR PARAMETER (NUMCHAR=48) C Maximum number of characters in C a line integer MAXBUF PARAMETER (MAXBUF=200) C C C Align loop active flag (true/false) logical align_ C Set loop tabs flag (true/false) logical tabl_ C Input tab expansion flag (true/false) logical tabx_ C Output tab expansion flag (true/false) logical ptabx_ C Text active flag (true/false) logical text_ C Loop active flag (true/false) logical loop_ C Save frame active flag (true/false) logical save_ C Save frame output flag (true/false) logical saveo_ C Alias use flag (true/false) logical alias_ C Alias output mapping flag (true/false) logical aliaso_ C Length of current data item in strg_ integer long_ C Loop block number of current item integer list_ C Length of current filename in file_ integer longf_ C Integer limit on esd's (9, 19, 29, etc.) integer esdlim_ C User setable input line value integer line_ C Record number of last input line integer recn_ C Record number of last last line integer precn_ C Character position of data name integer posnam_ C Character position of data value integer posval_ C Character position of decimal point integer posdec_ C Character position of end of field integer posend_ C Character position of output data name integer pposnam_ C Character position of output data value integer pposval_ C Character position of output decimal point integer pposdec_ C Character position of end of output field integer pposend_ C Name of current data block character bloc_*(NUMCHAR) C Character image of current data item character strg_*(MAXBUF) C File name of current CIF character file_*(MAXBUF) C Data item type character type_*4 C Data type (May be more precise than type_) character*(NUMCHAR) dictype_ C Data category character*(NUMCHAR) diccat_ C Data alias root name character*(NUMCHAR) dicname_ C Input CIF tag name character*(NUMCHAR) tagname_ C Quoted input string flag character quote_*1 C Quoted output string flag character pquote_*1 C common/tbuc/ strg_,bloc_,file_,type_,dictype_,diccat_, * dicname_,tagname_,quote_,pquote_ C common/tbui/ list_,long_,longf_,line_,esdlim_,recn_,precn_, * posnam_,posval_,posdec_,posend_, * pposnam_,pposval_,pposdec_,pposend_ C common/tbul/ loop_,text_,align_,save_,saveo_,aliaso_,alias_, * tabl_,tabx_,ptabx_ "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'ciftbx.cmv' ENDS TWO LINES BEFORE THIS ___________ if ( 4220 != `wc -c <'ciftbx.cmv'` ) then echo "cshar: 'ciftbx.cmv' unpacked with wrong size" endif # end of 'ciftbx.cmv' endif if ( -e 'ciftbx.f' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'ciftbx.f'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'ciftbx.f' (125819 characters)" #___________ THE FILE 'ciftbx.f' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'ciftbx.f' <<"CUT_HERE_CUT_HERE_CUT_HERE" C C C \ | / /##| @@@@ @ @@@@@ | | @@@ C \|/ STAR /###| @ @ @ __|__ | @ @ C ----*---- /####| @ @ @@@@ | |___ __ __ @ C /|\ /#####| @ @ @ | | \ \/ @ C / | \ |#####| @@@@ @ @ \___/ \___/ __/\__ @@@@@ C |#####|________________________________________________ C ||#####| ___________________ | C __/|_____||#####|________________|&&&&&&&&&&&&&&&&&&&|| | C<\\\\\\\\_ |_____________________________|&&&& Sep 26 96 &&&&|| | C \| ||#####|________________|&&&&&&&&&&&&&&&&&&&||__________| C |#####| C |#####| Version 2.5.1 Release C |#####| C /#######\ C |#########| C ==== C || C An extended tool box of fortran routines for manipulating CIF data. C || C || CIFtbx Version 2 C || by C || C || Sydney R. Hall (syd@crystal.uwa.edu.au) C || Crystallography Centre C || University of Western Australia C || Nedlands 6009, AUSTRALIA C || C || and C || C || Herbert J. Bernstein (yaya@bernstein-plus-sons.com) C || Bernstein + Sons C || 5 Brewster Lane C || Bellport, NY 11713, U.S.A. C || C The latest program source and information is available from: C || C Em: syd@crystal.uwa.edu.au ,-_|\ Sydney R. Hall C sendcif@crystal.uwa.edu.au / \ Crystallography Centre C Fx: +61 9 380 1118 || --> *_,-._/ University of Western Australia C Ph: +61 9 380 2725 || v Nedlands 6009, AUSTRALIA C || C || C_____________________||_____________________________________________________ C C This is a version of CIFtbx which has been extended to work with DDL 2 C and mmCIF as well as with DDL 1.4 and core CIF dictionaries. CIFtbx C version 1 was written by Sydney R. Hall (see Hall, S. R., "CIF Applications C IV. CIFtbx: a Tool Box for Manipulating CIFs," J. Appl. Cryst (1993). 26, C 482-494. The revisions for version 2 were done by Herbert J. Bernstein C and Sydney R. Hall (see Hall, S. R. and Bernstein, H. J., "CIFtbx 2: C Extended Tool Box for Manipulating CIFs," J. Appl. Cryst., to appear.) C C___________________________________________________________________________ C C C GENERAL TOOLS C C C init_ Sets the device numbers of files. (optional) C [logical function always returned .true.] C C Set input CIF device (def=1) C C Set output CIF device (def=2) C C Set direct access formatted C scratch device number (def=3) C C Set error message device (def=6) C C C C dict_ Requests a CIF dictionary be used for various data checks. C [logical function returned as .true. if the name dictionary C was opened; and if the check codes are recognisable. The C data item names used in the first dictionary loaded are C considered to be preferred by the user to aliases found C in dictionaries loaded in later calls] C C A CIF dictionary in DDL format C or blank if just setting flags C or resetting the dictionary C C The codes specifying the types of C checks to be applied to the CIF. C C 'valid' data name validation check. C 'dtype' data item data type check. C 'reset' switch off checking flags C 'close' close existing dictionaries C C___________________________________________________________________________ C C C CIF ACCESS TOOLS ("the get_ing commands") C C C C ocif_ Opens the CIF containing the required data. C [logical function returned .true. if CIF opened] C C A blank name signals that the C currently open input CIF file C will be read. C C C C data_ Identifies the data block containing the data to be requested. C [logical function returned .true. if block found] C C A blank name signals that the next C encountered block is used (the block C name is stored in the variable bloc_). C C C bkmrk_ Saves or restores the current position so that data from C elsewhere in the cif can be examined. C [logical function returned as .true. on save if there was C room in internal storage to hold the current position, .true. C on restore if the bookmark number used was valid. If the C argument is zero, the call is to save the position and return C the bookmark number in the argument. If the argument is C non-zero, the call is to restore the position saved for the C bookmark number given. The bookmark and the argument are C cleared. The position set on return allow reprocessing of C the data item or loop row last processed when the bookmark C was placed. C C NOTE: All bookmarks are cleared by a call to data_] C C Bookmark number C C C find_ Find the location of the requested item in the CIF. C [The argument "name" may be a data item name, blank C for the next such item. The argument "type" may be C blank for unrestricted acceptance of any non-comment C string (use cmnt_ to see comments), including loop headers, C "name" to accept only the name itself and "valu" C to accept only the value, or "head" to position to the C head of the CIF. Except when the "head" is requested, C the position is left after the data item provided. If the C item found is of type "name", posnam_ is set, otherwise, C posval_] C C A blank name signals that the next C item of the type specified is needed C C blank, 'head', 'name' or 'valu' C C Returned string is of length long_. C C C C test_ Identify the data attributes of the named data item. C [logical function returned as .true. if the item is present or C .false. if it is not. The data attributes are stored in the C common variables list_, type_, dictype_, diccat_ and dicname_. C The values in dictype_, diccat_ and dicname_ are valid C whether or not the data item is found in the input CIF, as C long as the named data item is found in the dictionaries C declared by calls to dict_. The data item name found C in the input CIF is stored in tagname_. The appropriate C column numbers are stored in posnam_, posval_, posend_ and (for C numbers) in posdec_. The quoation mark, if any, used is C stored in quote_. C C list_ is an integer variable containing the sequential number C of the loop block in the data block. If the item is not within C a loop structure this value will be zero. C C type_ is a character*4 variable with the possible values: C 'numb' for number data C 'char' for character data C 'text' for text data C 'null' if data missing or '?' or '.' C C dictype_ is a character*(NUMCHAR) variable with the type code C given in the dictionary entry for the named data item. If C no dictionary was used, or no type code was specified, this C field will simply agree with type_. If a dictionary was used, C this type may be more specific than the one given by type_. C C diccat_ is a character*(NUMCHAR) variable with the category C of the named data item, or '(none)' C C dicname_ is a character*(NUMCHAR) variable with the name of C the data item which is found in the dictionary for the C named data item. If alias_ is .true., this name may C differ from the name given in the call to test_. If alias_ C is .false. or no preferred alias is found, dicname_ agrees with C the data item name. C C tagname_ is a character*(NUMCHAR) variable with the name C of the data item as found in the input CIF. It will be C blank if the data item name requested is not found in the C input CIF and may differ from the data item name provided C by the user if the name used in the input CIF is an C alias of the data item name and alias_ is .true. C C posnam_, posval_, posend_ and posdec_ are integer variables C which may be examined if information about the horizontal C position of the name and data read are needed. posnam_ is the C starting column of the data name found (most often 1). C posval_ is the starting column of the data value. If the C field is numeric, then posdec_ will contain the effective C column number of the decimal point. For whole numbers, the C effective position of the decimal point is one column to the C right of the field. posend_ contains the ending column of the C data value. C C quote_ is a character*1 varibale which may be examined to C determine if a quotation character was used on character data.] C C Name of the data item to be tested. C C C C name_ Get the NEXT data name in the current data block. C [logical function returned as .true. if a new data name exists C in the current data block, and .false. when the end of the data C block is reached.] C C Returned name of next data item in block. C C C C numb_ Extracts the number and its standard deviation (if appended). C [logical function returned as .true. if number present. If C .false. arguments 2 and 3 are unaltered. If the esd is not C attached to the number argument 3 is unaltered.] C C Name of the number sought. C C Returned number. C C Returned standard deviation. C C C C numd_ Extracts the number and its standard deviation (if appended) C as double precision variables. C [logical function returned as .true. if number present. If C .false. arguments 2 and 3 are unaltered. If the esd is not C attached to the number argument 3 is unaltered.] C C Name of the number sought. C C C Returned number. C C C Returned standard deviation. C C C C char_ Extracts character and text strings. C [logical function returned as .true. if the string is present. C Note that if the character string is text this function is C called repeatedly until the logical variable text_ is .false.] C C Name of the string sought. C C Returned string is of length long_. C C C cmnt_ Extracts the next comment from the data block. C [logical function returned as .true. if a comment is present. C The initial comment character "#" is _not_ included in the C returned string. A completely blank line is treated as C a comment.] C C Returned string is of length long_. C C C C purge_ Closes existing data files and clears tables and pointers. C [subroutine call] C C____________________________________________________________________________ C C C C CIF CREATION TOOLS ("the put_ing commands") C C C C pfile_ Create a file with the specified file name. C [logical function returned as .true. if the file is opened. C The value will be .false. if the file already exists.] C C Blank for use of currently open file C C C C pdata_ Put a data block command into the created CIF. C [logical function returned as .true. if the block is created. C The value will be .false. if the block name already exists. C Produces a save frame instead of a data block if the C variable saveo_ is true during the call. No block duplicate C check is made for a save frame.] C C C C C C ploop_ Put a loop_ data name into the created CIF. C [logical function returned as .true. if the invocation C conforms with the CIF logical structure. If pposval_ C is non-zero, the "loop_" header is positioned to C that column. If pposnam_ is non-zero, the data name is C positioned to that column.] C C If the name is blank on the first call C of a loop, only the "loop_" is placed. C C C C pchar_ Put a character string into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure.] C C If the name is blank, do not output name. C C A character string of MAXBUF chars or less. C C C C pcmnt_ Puts a comment into the created CIF. C [logical function returned as .true. The comment character C "#" should not be included in the string. A blank comment C is presented as a blank line without the leading "#"]. C C A character string of MAXBUF chars or less. C C C pnumb_ Put a single precision number and its esd into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure. C The number of esd digits is controlled by the variable C esdlim_] C C If the name is blank, do not output name. C C Number to be inserted. C C Esd number to be appended in parentheses. C C C pnumd_ Put a double precision number and its esd into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure. C The number of esd digits is controlled by the variable C esdlim_] C C If the name is blank, do not output name. C C C Number to be inserted. C C C Esd number to be appended in parentheses. C C C C ptext_ Put a character string into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure.] C ptext_ is invoked repeatedly until the text is finished. Only C the first invocation will insert a data name. C C If the name is blank, do not output name. C C A character string of MAXBUF chars or less. C C C prefx_ Puts a prefix onto subsequent lines of the created CIF. C [logical function returned as .true. The second argument C may be zero to suppress a previously used prefix, or C greater than the non-blank length of the string to force C a left margin. Any change in the length of the prefix C string flushes pending partial output lines, but does _not_ C force completion of pending text blocks or loops. C This function allows the CIF output functions to be used C within what appear to be text fields to support annotation C of a CIF. ] C C A character string of MAXBUF chars or less. C C The length of the prefix string to use. C C C C C close_ Close the creation CIF. MUST be used if pfile_ is used. C [subroutine call] C C C____________________________________________________________________________ C C C C....The CIF tool box also provides variables for data access control: C C C alias_ Logical variable: if left .true. then all calls to C CIFtbx functions may use aliases of data item names. C The preferred synonym from the dictionary will be C subsituted internally, provided aliased data names were C supplied by an input dictionary (via dict_). The C default is .true., but alias_ may be set to .false. C in an application. C C aliaso_ Logical variable: if set .true. then cif output C routines will convert aliases to the names to preferred C synonyms from the dictionary. The default is .false., but C aliaso_ may be set to .true. in an application. The C setting of aliaso_ is independent of the setting of C alias_. C C align_ Logical variable signals alignment of loop_ lists during C the creation of a CIF. The default is .true. C C bloc_ Character*(NUMCHAR) variable: the current block name. C C dictype_ Character*(NUMCHAR) variable: the precise data type code C (see test_) C C diccat_ Character*(NUMCHAR) variable: the category (see test_) C C dicname_ Character*(NUMCHAR) variable: the root alias (see test_) C C esdlim_ Integer variable: Specifies the upper limit of esd's C produced by pnumb_, and, implicitly, the lower limit. C The default value is 19, which limits esd's to the range C 2-19. Typical values of esdlim_ might be 9 (limiting C esd's to the range 1-9), 19, or 29 (limiting esd's C to the range 3-29) C C file_ Character*(MAXBUF) variable: the filename of the current file. C C line_ Integer variable: Specifies the input/output line limit C for processing a CIF. The default value is 80 characters. C This may be set by the program. The max value is MAXBUF C which has a default value of 200. C C list_ Integer variable: the loop block number (see test_). C C long_ Integer variable: the length of the data string in strg_. C C longf_ Integer variable: the length of the filename in file_. C C loop_ Logical variable signals if another loop packet is present. C C pposdec_ Integer variable giving the position of the decimal point C for the next number to be written. C C pposend_ Integer variable giving the ending column of the next C number or quoted character value to be written. Used to C pad with zeros or blanks. C C pposnam_ Integer variable giving the starting column of the next C name or comment or data block to be written. C C pposval_ Integer variable giving the starting column of the next C data value to be written by pchar_, pnumb_ or pnumd_. C Also used to set the position of the initial "loop_" C in a ploop_ call or to set the position of a terminal "save_" C for a save frame in a pdata_ call for which saveo_ is .true. C C posdec_ Integer variable giving the position of the decimal point C for the last number read. C C posend_ Integer variable giving the ending column of the last C data value read, not including a terminal quote. C C posnam_ Integer variable giving the starting column of the last C name or comment or data block read. C C posval_ Integer variable giving the starting column of the last C data value read. Also reports the column of the C terminal "save_" of a save frame. C C pquote_ Character variable giving the quotation symbol to be C used for the next string written. C C precn_ Integer variable: Reports the record number of the last C line written to the output cif. Set to zero by init_. Also C set to zero by pfile_ and close_ if the output cif file name C was not blank. C C ptabx_ Logical variable signals tab character expansion to blanks C during the creation of a CIF. The default is .true. C C quote_ Character variable giving the quotation symbol found C delimiting the last string read. C C recn_ Integer variable: Reports the record number of the last C line read from the direct access copy of the input cif. C C save_ Logical variable signals that the current data block C is actually a save-frame (.true. for a save-frame). C C saveo_ Logical variable signals that the output data block from C pdata_ is actually a save-frame (.true. for a save-frame). C C strg_ Character*(MAXBUF) variable: the current data item. C C tabl_ Logical variable signals tab-stop alignment of output C during the creation of a CIF. The default is .true. C C tabx_ Logical variable signals tab character expansion to blanks C during the reading of a CIF. The default is .true. C C text_ Logical variable signals if another text line is present. C C type_ Character*4 variable: the data type code (see test_). C C C C_____________________________________________________________________________ C C C >>>>>> Set the device numbers. C function init_(devcif,devout,devdir,deverr) C logical init_ include 'ciftbx.sys' integer devcif,devout,devdir,deverr integer ii,kdig real ytest double precision ztest C init_=.true. cifdev=devcif outdev=devout dirdev=devdir errdev=deverr recn_=0 precn_=0 C C recompute decimal single precision precision C This is found by computing the smallest power of C 10 which, when added to 1, produces a change C and then backing off by 1 C decprc = .1 do ii = 1,6 ytest = 1.+decprc/10. if (ytest.eq.1.) go to 100 decprc = decprc/10. enddo 100 continue decprc=decprc*10. C C recompute decimal double precision precision C kdig = 1 dpprc = .1D0 do ii = 1,15 ztest = 1.D0+dpprc/10. if (ztest.eq.1.D0) go to 200 dpprc = dpprc/10.D0 kdig = kdig+1 enddo 200 continue dpprc=dpprc*10.D0 write(ndpfmt,'(5h(d30.,i2,1h))') kdig-1 C C recompute decimal single precision minimum power of ten C decmin = .1 do ii = 1,37 ytest = decmin/10. if (ytest.eq.0.) go to 300 decmin = decmin/10. enddo 300 continue C C recompute decimal double precision minimum power of 10 C and its log base 10 (minexp) C dpmin = .1D0 minexp = -1 do ii = 1,307 ztest = dpmin/10. if (ztest.eq.0.D0) go to 400 dpmin = dpmin/10.D0 minexp = minexp-1 enddo 400 continue call clearfp return end C C C C C C >>>>>> Read a CIF dictionary and prepare for checks C function dict_(fname,checks) C logical dict_ logical ocif_ logical data_ logical char_ integer lastnb include 'ciftbx.sys' character locase*(MAXBUF) character fname*(*),checks*(*) character temp*24,codes(4)*5,name*(MAXBUF),bxname*(NUMCHAR) character bcname*(NUMCHAR),biname*(NUMCHAR),bname*(NUMCHAR) character baname*(NUMCHAR),ganame*(NUMCHAR),btname*(NUMCHAR) character batag*(NUMCHAR) integer lbcname,lbaname,lbtname,lbname integer kdict,kadict,ifind,jfind,iafind integer i,j,nmatch,mycat,ksmatch,ii C C Control flags for matching categories, names and types C C icloop is the loop number of the block for the C current category C ictype is the type of the current category C 0 - none found yet C 1 - _item.category.id C 2 - _category C 3 - _category.id C inloop is the loop number of the block for the C current name C intype is the type of the current name C 0 - none found yet C 1 - _item.name C 2 - _name C ialoop is the loop number of the block for the C current alias C iatype is the type for the current alias C 0 - none found yet C 1 - _item_aliases.alias_name C itloop is the loop number of the block for the C current type C ittype is the type of the current type C 0 - none found yet C 1 - _item_type.code C 2 - _type C integer icloop,ictype,inloop,intype,ialoop,iatype, * itloop,ittype C character*4 map_type(12),map_to(12),mapped character*(NUMCHAR) dt(2),ct(3),nt(2),at(1),tt(2) data map_type * /'floa','int ','yyyy','symo','ucha','ucod','name','idna', * 'any ','code','line','ulin'/ data map_to * /'numb','numb','char','char','char','char','char','char', * 'char','char','char','char'/ data dt * /'_dictionary.title ', * '_dictionary_name '/ data ct * /'_item.category_id ', * '_category ', * '_category.id '/ data nt * /'_item.name ', * '_name '/ data at * /'_item_aliases.alias_name '/ data tt * /'_item_type.code ', * '_type '/ C data codes /'valid','dtype','reset','close'/ C C....... Are the codes OK C temp=checks i=0 120 i=i+1 if(i.ge.24) goto 190 if(temp(i:i).eq.' ') goto 120 do 150 j=1,4 if(temp(i:i+4).eq.codes(j)) goto 170 150 continue dict_=.false. goto 500 170 i=i+4 if(j.eq.1) vcheck='yes' if(j.eq.2) tcheck='yes' if(j.eq.3) then vcheck = 'no ' tcheck = 'no ' goto 170 endif if(j.eq.4) then vcheck = 'no ' tcheck = 'no ' ndcname = 0 ndict = 0 if(nname.gt.0) then do 180 i = 1,nname dtype(i)=' ' dxtyp(i)=' ' cindex(i)=0 ddict(i)=0 180 continue endif dict_=.true. goto 500 endif goto 120 C C if no category names have been loaded, clean up C the hash table for dictionary category names C 190 if(ndcname.eq.0) then call hash_init(dcname,dcchain,NUMDICT,ndcname,dchash, * NUMHASH) endif C C if no dictionary names have been loaded, clean up C the hash table for dictionary names C if(ndict.eq.0) then call hash_init(dicnam,dicchain,NUMDICT,ndict,dichash, * NUMHASH) endif C C....... Open and store the dictionary C dict_=.true. if(fname.eq.' ') goto 500 if(nname.gt.0) call err(' Dict_ must precede ocif_') dict_=ocif_(fname) if(.not.dict_) goto 500 dictfl='yes' C C....... Loop over data blocks; extract _name's, _type etc. C 200 if(.not.data_(' ')) goto 400 if(bloc_(1:1).eq.'_') then bname=locase(bloc_) else bname='_'//locase(bloc_) endif lbname=lastnb(bname) C C see if this is a dictionary defining block C do i = 1,2 if(char_(dt(i),name)) goto 200 enddo C Cdbg WRITE(6,*) ndict,bloc_ C C Analyze loop structure for categories, names and types C C C initalize loop info C icloop = -1 inloop = -1 ialoop = -1 itloop = -1 ictype = 0 intype = 0 iatype = 0 ittype = 0 bcname = ' ' lbcname = 1 baname = ' ' batag = ' ' lbaname = 1 btname = ' ' lbtname = 1 biname=bloc_ mycat=0 loop_=.false. loopnl=0 nmatch=0 ksmatch=0 C C Process categories C do i = 1,3 if(char_(ct(i),name)) then if(ictype.ne.0) * call warn(' Multiple DDL 1 and 2 category definitions ') ictype = i if(loop_) icloop = loopnl bcname=locase(name(1:long_)) lbcname=long_ call hash_store(bcname, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,mycat) if(mycat.eq.0) then call err(' Dictionary category names > NUMDICT ') endif C C if this is not a loop of categories, we expect a match C against the block name C if(.not.loop_) then if(ictype.eq.1) then if(bname(1:lbcname+2).ne. * '_'//bcname(1:lbcname)//'.') then call warn(' Category id does not match block name') endif else if(ictype.eq.2) then if(bcname.ne.'dictionary_definition') then if(bname(1:lbcname+2).ne. * '_'//bcname(1:lbcname)//'_') then if(bname(1:lbcname+2).ne. * '_'//bcname(1:lbcname)//' ') then call warn(' Category id does not match block name') endif endif endif endif endif endif endif loop_ = .false. loopnl = 0 enddo C C Process names do i = 1,2 if(char_(nt(i),name)) then if(intype.ne.0) * call warn(' Multiple DDL 1 and 2 name definitions ') intype = i bxname=locase(name(1:long_)) if(loop_) inloop = loopnl endif loop_ = .false. loopnl=0 enddo if(intype.eq.0.and.ictype.ne.3) * call warn (' No name defined in block') loop_ = .false. if(char_(at(1),name)) then iatype=1 baname = locase(name(1:long_)) batag = name(1:long_) lbaname = long_ if(loop_) ialoop = loopnl endif loop_ = .false. loopnl=0 if(ictype.ne.3) then do i=1,2 if(char_(tt(i),name)) then if(ittype.ne.0) * call warn(' Multiple DDL 1 and 2 type definitions ') ittype = i btname = locase(name(1:long_)) if(loop_) itloop = loopnl endif loop_ = .false. loopnl=0 enddo endif C C Now test for consistent combinations C if(inloop.ne.-1) then if(icloop.ne.-1.and.icloop.ne.inloop) * call warn( * ' Categories and names in different loops') if(iatype.ne.0.and.ialoop.ne.inloop) then if(ialoop.eq.-1) then if(bxname.ne.bname) * call warn( * ' One alias, looped names, linking to first') else call warn( * ' Aliases and names in different loops ' * //' only using first alias ') endif endif if(itloop.ne.-1.and.itloop.ne.inloop) * call warn( * ' Types and names in different loops') else if(icloop.ne.-1) * call warn( * ' Multiple categories for one name') if(itloop.ne.-1) * call warn( * ' Multiple types for one name') endif C C This is the main loop C if(intype.eq.0) go to 200 250 if(.not.char_(nt(intype),name)) goto 200 kdict=ndict+1 call hash_store(locase(name(1:long_)),dicnam,dicchain, * NUMDICT,ndict,dichash,NUMHASH,ifind) if(ifind.eq.0) call err(' Cifdic names > NUMDICT') if(ifind.eq.kdict)dictag(ifind)=name(1:long_) if(dicnam(ifind).eq.bname) nmatch=ifind if(dicnam(ifind)(1:lbname).eq.bname) ksmatch=ifind Cdbg if(dicnam(ifind).ne.bname) Cdbg * call warn (' Name mismatch: '//dicnam(ifind)//bname) if(inloop.ge.0)then C C We are in a loop of names. If it is the same loop as C for categories, we need to extract the matching category C if(inloop.eq.icloop) then mycat=0 if(char_(ct(ictype),name)) then bcname=locase(name(1:long_)) lbcname=long_ call hash_store(bcname, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,mycat) if(mycat.eq.0) then call err(' Dictionary category names > NUMDICT ') endif endif endif C C If it is the same loop as for types, we need to extract C the matching type C if(inloop.eq.itloop) then btname=' ' if(char_(ct(ittype),name)) then btname=locase(name(1:long_)) lbtname=long_ endif endif C C If it is the same loop as for aliases, we need to extract C the matching alias C if(inloop.eq.ialoop) then baname=' ' batag=' ' if(char_(at(1),name)) then baname = locase(name(1:long_)) batag = name(1:long_) lbaname = long_ endif endif endif C C now we have a name stored in dicnam at location ifind C the index of the category in mycat, the type in btname, C the alias in baname C C First verify match between the name and category, if C we have one, or extract from the block name C if (mycat.eq.0) then if (dcindex(ifind).eq.0) then if (dicnam(ifind).eq.bloc_) then call excat(dicnam(ifind),bcname,lbcname) Cdbg call warn(' Extracting category name from block name ' Cdbg * //bloc_(1:max(1,lastnb(bloc_)))) if(bcname(1:1).ne.' ') then ictype = 1 call hash_store(bcname, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,mycat) if(mycat.eq.0) then call err(' Dictionary category names > NUMDICT ') endif else call warn(' No category defined in block ' * //bloc_(1:max(1,lastnb(bloc_)))//' and name ' * //dicnam(ifind)(1:max(1,lastnb(dicnam(ifind)))) * //' does not match') endif endif endif else if (bcname(1:lbcname).ne.'dictionary_definition') then if (dicnam(ifind)(1:lbcname+1).ne.'_'//bcname(1:lbcname) * .or.( dicnam(ifind)(lbcname+2:lbcname+2).ne.'_' .and. * dicnam(ifind)(lbcname+2:lbcname+2).ne.'.' .and. * dicnam(ifind)(lbcname+2:lbcname+2).ne.' ' )) then call warn(' Item name '// * dicnam(ifind)(1:max(1,lastnb(dicnam(ifind))))//' '// * ' does not match category name '//bcname(1:lbcname)) endif endif endif C C We will need the type in what follows. cifdic.m96 defines C some higher level types. We map them to primitive types C mapped = btname(1:4) do i = 1,12 if (btname(1:4).eq.map_type(i)) mapped = map_to(i) enddo if (mapped.ne.'char' .and. * mapped.ne.'text' .and. * mapped.ne.' ' .and. * mapped.ne.'null' .and. * mapped.ne.'numb' ) then if (tcheck .eq. 'yes') call warn (' Item type '// * btname(1:max(1,lastnb(btname)))//' not recognized') endif C C There are two cases to consider, one if the name is new to C the dictionary, the other, if it is not C if(ifind.eq.kdict) then aroot(ifind)=0 alias(ifind)=0 dcindex(ifind)=mycat dictyp(ifind)=mapped dicxtyp(ifind)=btname else if(dcindex(ifind).ne.mycat) then if(dcindex(ifind).eq.0) then jfind=ifind if (aroot(ifind).ne.0) jfind=ifind 255 continue dcindex(jfind)=mycat jfind=alias(jfind) if(jfind.ne.0) goto 255 else if(mycat.ne.0.and. * (vcheck.eq.'yes'.or.tcheck.eq.'yes')) * call warn(' Attempt to redefine category for item') endif endif if(dictyp(ifind).ne.mapped .or. * dicxtyp(ifind).ne.btname) then if(dictyp(ifind).eq.' ') then jfind=ifind if (aroot(ifind).ne.0) jfind=ifind 256 continue dictyp(jfind)=mapped dicxtyp(jfind)=btname jfind=alias(jfind) if(jfind.ne.0) go to 256 else if(mapped.ne.' '.and.tcheck.eq.'yes') * call warn(' Attempt to redefine type for item') endif endif endif C C now deal with alias, if any. C if(baname.ne.' ') then kadict=ndict+1 call hash_store(baname(1:lbaname),dicnam,dicchain, * NUMDICT,ndict,dichash,NUMHASH,iafind) if(iafind.eq.0) call err(' Cifdic names > NUMDICT') if(iafind.eq.kadict) then dictag(iafind) =batag aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind alias(iafind) =0 alias(ifind) =iafind dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) else if(aroot(iafind).ne.0) then if(aroot(iafind).eq.ifind .or. * aroot(iafind).eq.aroot(ifind)) then call warn(' Duplicate definition of same alias') else call warn(' Conflicting definition of alias') endif else if((dcindex(iafind).eq.0.or. * dcindex(iafind).eq.dcindex(ifind)).and. * (dictyp(iafind).eq.' '.or. * (dictyp(iafind).eq.dictyp(ifind) .and. * dicxtyp(iafind).eq.dicxtyp(ifind)))) then dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) endif aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind alias(ifind) =iafind endif endif endif if(inloop.ge.0) then baname = ' ' batag = ' ' endif C if(inloop.ge.0.and.loop_) go to 250 if(nmatch.eq.0) then if (ksmatch.eq.0.or.inloop.lt.0) then call warn(' No name in the block matches the block name') endif endif C C check for aliases C we execute this loop only in the case of unlooped name C with looped alias C if(inloop.lt.0.and.ialoop.ge.0) then loop_=.false. loopnl=0 ganame=baname 260 if(.not.char_(at(iatype),name)) goto 200 baname=locase(name(1:long_)) batag=name(1:long_) lbaname=long_ if(baname.eq.ganame) then if(loop_) go to 260 go to 200 endif if(baname.ne.' ') then kadict=ndict+1 call hash_store(baname(1:lbaname),dicnam,dicchain, * NUMDICT,ndict,dichash,NUMHASH,iafind) if(iafind.eq.0) call err(' Cifdic names > NUMDICT') if(iafind.eq.kadict) then dictag(iafind) =batag aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind alias(iafind) =0 alias(ifind) =iafind dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) ifind=iafind else if(aroot(iafind).ne.0) then if(aroot(iafind).eq.ifind .or. * aroot(iafind).eq.aroot(ifind)) then call warn(' Duplicate definition of same alias') else call warn(' Conflicting definition of alias') endif else if((dcindex(iafind).eq.0.or. * dcindex(iafind).eq.dcindex(ifind)).and. * (dictyp(iafind).eq.' '.or. * (dictyp(iafind).eq.dictyp(ifind) .and. * dicxtyp(iafind).eq.dicxtyp(ifind)))) then dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) ifind=iafind endif aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind alias(ifind) =iafind endif endif endif if(loop_) go to 260 endif go to 200 C 400 bloc_=' ' if (ndcname.ne.0) then do ii = 1,ndict if (aroot(ii).eq.0.and.dcindex(ii).eq.0) * call warn(' No category specified for name '// * dicnam(ii)(1:max(1,lastnb(dicnam(ii))))) enddo endif do ii = 1,ndict if (dicxtyp(ii).eq.' ') then dicxtyp(ii) = 'null' dictyp(ii) = 'null' if (tcheck.eq.'yes') * call warn(' No type specified for name '// * dicnam(ii)(1:max(1,lastnb(dicnam(ii))))) endif enddo close(dirdev) nrecd=0 dictfl='no ' 500 continue if(tcheck.eq.'yes') vcheck='yes' Cdbg WRITE(6,'(i5,3x,a,2x,a)') (i,dicnam(i),dictyp(i),i=1,ndict) return end C C C C C C >>>>>> Find position of last non_blank in a string C function lastnb(str) C integer lastnb include 'ciftbx.sys' character*(*) str integer lenn,ii lenn = len(str) do 100 ii=lenn,1,-1 if(str(ii:ii).eq.' ') goto 100 if(str(ii:ii).ne.tab) goto 120 100 continue ii=1 120 lastnb = ii return end C C C C C C >>>>>> Extract the item.category_id from a save frame name C subroutine excat(sfname,bcname,lbcname) C character*(*) sfname,bcname integer lbcname,ii,ic,lastnb,lenn C C Note that this logic works only for item.category_id C not for category.id C lenn = lastnb(sfname) bcname = ' ' lbcname = 1 if (lenn.eq.0.or.sfname(1:1).ne.'_') return do ii = 1,lenn-2 ic = 1+lenn-ii if (sfname(ic:ic).eq.'.') then bcname = sfname(2:ic-1) lbcname = ic-2 return endif enddo return end C C C C C C >>>>>> Open a CIF and copy its contents into a direct access file. C function ocif_(fname) C logical ocif_ integer lastnb include 'ciftbx.sys' logical test character fname*(*) integer case,i C save_=.false. jchar=MAXBUF lastch=0 if(line_.gt.MAXBUF) call err(' Input line_ value > MAXBUF') if(nrecd.ne.0) close(dirdev) nrecd=0 lrecd=0 case=ichar('a')-ichar('A') tab=char(05) if(case.lt.0) goto 100 tab=char(09) bloc_=' ' C C....... Make sure the CIF is available to open C 100 file_=fname do 120 i=1,MAXBUF if(file_(i:i).eq.' ') goto 140 120 continue 140 longf_=i-1 if (longf_.gt.0) then inquire(file=file_(1:longf_),exist=test) ocif_=test if(.not.ocif_) goto 200 else file_ = ' ' longf_ = 1 ocif_ = .true. endif C C....... Open up the CIF and a direct access formatted file as scratch C if (file_(1:1).ne.' ') * open(unit=cifdev,file=fname,status='OLD',access='SEQUENTIAL', * form='FORMATTED') open(unit=dirdev,status='SCRATCH',access='DIRECT', * form='FORMATTED',recl=MAXBUF) C C....... Copy the CIF to the direct access file C 160 read(cifdev,'(a,a)',end=180) buffer nrecd=nrecd+1 irecd=nrecd if (lastnb(buffer(1:MAXBUF)).gt.line_) * call warn(' Input line length exceeds line_') write(dirdev,'(a)',rec=nrecd) buffer Cdbg WRITE(6,'(i5,1x,a)') nrecd,buffer(1:70) goto 160 C 180 lrecd=0 jrecd=0 jrect=-1 irecd=0 recn_=0 if (file_(1:1).ne.' ') close(cifdev) 200 return end C C C C C C >>>>>> Close off direct access file of the current CIF C and reset all data name tables and pointers C subroutine purge_ C include 'ciftbx.sys' C if(nrecd.ne.0) close(dirdev) recn_=0 save_=.false. jchar=MAXBUF lastch=0 nrecd=0 lrecd=0 irecd=0 nname=0 nhash=0 iname=0 loopct=0 loopnl=0 loop_=.false. text_=.false. return end C C C C C C >>>>>> Store the data names and pointers for the requested data block C function data_(name) C logical data_ integer lastnb include 'ciftbx.sys' character name*(*),flag*4,temp*(NUMCHAR),ltype*4 character ctemp*(NUMCHAR) character locase*(MAXBUF),isbuf*(MAXBUF) integer ndata,idata,nitem,npakt,i,ii,j,k,kchar,krecd integer fcatnum,lctemp,isrecd,isjchr,islast integer pnname,itpos,ipp,ipj C jchar=MAXBUF nname=0 ndata=0 nhash=0 nitem=0 idata=0 iname=0 loopct=0 loopnl=0 ltype=' ' posnam_=0 posval_=0 posdec_=0 posend_=0 data_=.false. loop_=.false. text_=.false. do ii = 1,MAXBOOK ibkmrk(1,ii)=-1 enddo irecd=lrecd lrecd=nrecd if(name(1:1).ne.' ') irecd=0 call hash_init(dname,dchain,NUMBLOCK,nname,dhash, * NUMHASH) call hash_init(cname,cchain,NUMBLOCK,ncname,chash, * NUMHASH) isrecd=irecd isjchr=jchar islast=lastch isbuf=' ' if(lastch.gt.0)isbuf(1:lastch)=buffer(1:lastch) C C....... Find the requested data block in the file C 100 call getstr isjchr=jchar if(irecd.ne.isrecd) then isrecd=irecd islast=lastch isbuf=' ' if(lastch.gt.0)isbuf(1:lastch)=buffer(1:lastch) endif if(type_.eq.'fini') goto 500 if(type_.ne.'text') goto 120 110 call getlin(flag) if(buffer(1:1).ne.';') goto 110 jchar=2 goto 100 120 continue if(type_.eq.'save') then if(long_.lt.6) then if(.not.save_) * call err(' Save frame terminator found out of context ') save_=.false. goto 100 else if(save_) * call err(' Prior save frame not terminated ') save_=.true. if(name.eq.' ') goto 150 if(strg_(6:long_).ne.name) goto 100 goto 150 endif endif if(type_.ne.'data') goto 100 if(name.eq.' ') goto 150 if(strg_(6:long_).ne.name) goto 100 150 data_=.true. bloc_=strg_(6:long_) itpos=jchar-long_ if(tabx_) then itpos=0 do ipp=1,jchar-long_ itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posnam_=itpos C C....... Get the next token and identify C 200 call getstr Cdbg if(dictfl.eq.'no ') Cdbg * WRITE(6,*) ltype,type_,loop_,nitem,ndata,idata,iname,nname C if(ltype.ne.'name') goto 201 if(type_.eq.'numb') goto 203 if(type_.eq.'char') goto 203 if(type_.eq.'text') goto 203 if(type_.eq.'null') goto 203 if(type_.eq.'name'.and.loop_) goto 204 call err(' Illegal tag/value construction') 201 if(ltype.ne.'valu') goto 204 if(type_.eq.'numb') goto 202 if(type_.eq.'char') goto 202 if(type_.eq.'text') goto 202 if(type_.eq.'null') goto 202 goto 204 202 if(nitem.gt.0) goto 205 call err(' Illegal tag/value construction') 203 ltype='valu' goto 205 204 ltype=type_ C 205 if(type_.eq.'name') goto 206 if(type_.eq.'loop') goto 210 if(type_.eq.'data') goto 210 if(type_.eq.'save') goto 210 if(type_.ne.'fini') goto 220 206 if(loop_) goto 270 210 if(nitem.eq.0) goto 215 C C....... End of loop detected; save pointers C npakt=idata/nitem if(npakt*nitem.ne.idata) call err(' Item miscount in loop') loopni(loopct)=nitem loopnp(loopct)=npakt nitem=0 idata=0 215 if(type_.eq.'name') goto 270 if(type_.eq.'data') goto 300 if(type_.eq.'save') goto 300 if(type_.eq.'fini') goto 300 C C....... Loop_ line detected; incr loop block counter C loop_=.true. loopct=loopct+1 if(loopct.gt.NUMLOOP) call err(' Number of loop_s > NUMLOOP') loorec(loopct)=irecd loopos(loopct)=jchar-long_ if(quote_.ne.' ') loopos(loopct)=jchar-long_-1 itpos=0 do ipp=1,loopos(loopct) itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo loopox(loopct)=itpos goto 200 C C....... This is the data item; store char position and length C 220 if(loop_ .and. nitem.eq.0) * call err(' Illegal tag/value construction') loop_=.false. C i=nname if(nitem.gt.0) i=i-nitem+mod(idata,nitem)+1 if(i.lt.1) call err(' Illegal tag/value construction') if(dtype(i).ne.'test') goto 223 if(dictfl.eq.'yes') goto 223 if(tcheck.eq.'no ') goto 223 C>>>> if(long_.eq.1.and.strg_(1:1).eq.'?') goto 223 C>>>> if(long_.eq.1.and.strg_(1:1).eq.'.') goto 223 if(type_.eq.'null') goto 223 if(type_.eq.'numb') goto 223 call warn( ' Numb type violated '//dname(i)) 223 if(nitem.le.0) goto 224 idata=idata+1 if(dtype(i).eq.'null') dtype(i)=type_ if(dtype(i).eq.'numb' .and. * (type_.eq.'char'.or.type_.eq.'text')) dtype(i)='char' 224 if(nname.eq.ndata) goto 230 ndata=ndata+1 if(iloop(ndata).gt.1) goto 225 krecd=irecd kchar=jchar-long_-1 if(quote_.ne.' ')kchar=kchar-1 225 continue if(dtype(ndata).eq.' ') dtype(ndata)=type_ drecd(ndata)=krecd dchar(ndata)=kchar if(nloop(ndata).gt.0) goto 230 nloop(ndata)=0 iloop(ndata)=long_ C C....... Skip text lines if present C 230 if(type_.ne.'text') goto 200 if(nloop(ndata).eq.0) dchar(ndata)=0 if(nloop(ndata).eq.0) iloop(ndata)=long_ 250 call getlin(flag) if(buffer(1:1).eq.';') then jchar=2 goto 200 endif if(flag.eq.'fini') call err(' Unexpected end of data') goto 250 C C....... This is a data name; store name and loop parameters C 270 temp=locase(strg_(1:long_)) k=0 if(dictfl.ne.'yes' .and. ndict.gt.0) then call hash_find(temp, * dicnam,dicchain,NUMDICT,ndict,dichash,NUMHASH,k) if(k.ne.0) then if(alias_ .and. aroot(k).ne.0) temp=dicnam(aroot(k)) endif endif pnname=nname call hash_store(temp, * dname,dchain,NUMBLOCK,nname,dhash, * NUMHASH,j) if(j.eq.pnname+1) then dtag(j)=strg_(1:long_) if(k.ne.0) dtag(j)=dictag(k) trecd(j)=irecd tchar(j)=jchar-long_ if(quote_.ne.' ') tchar(j)=jchar-long_-1 itpos=0 do ipp=1,tchar(j) itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo xchar(j)=itpos endif if(j.eq.0) * call err(' Number of data names > NUMBLOCK') if(k.ne.0)temp=dicnam(k) if(j.ne.pnname+1) then call warn(' Duplicate data item '// * temp(1:max(1,lastnb(temp)))) goto 200 endif dtype(nname)=' ' dxtyp(nname)=' ' cindex(nname)=0 ddict(nname)=0 ctemp='(none)' lctemp=6 C if(dictfl.eq.'yes' .or. vcheck.eq.'no ') goto 290 j=k if(j.ne.0) then ddict(nname)=j cindex(nname)=dcindex(j) dxtyp(nname)=dicxtyp(j) dtype(nname)=dictyp(j) if(vcheck.eq.'no ') goto 280 if(dictyp(j).eq.'numb') then dtype(nname)='test' endif if(cindex(nname).ne.0) then ctemp=dcname(cindex(nname)) lctemp=lastnb(ctemp) goto 290 endif goto 280 endif call warn(' Data name '// * temp(1:max(1,lastnb(temp))) * //' not in dictionary!') 280 call excat(temp,ctemp,lctemp) if (ctemp.eq.' '.or.'_'//ctemp.eq.temp) then ctemp = '(none)' lctemp= 6 if (ndcname.ne.0.and.vcheck.eq.'yes') * call warn(' No category defined for ' * //temp) else call hash_find(ctemp, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,j) if(j.ne.0) then cindex(nname) = j else ipj=ncname call hash_store(ctemp(1:lctemp), * cname,cchain,NUMBLOCK,ncname,chash,NUMHASH,j) if (j.eq.0) * call err(' Number of categories > NUMBLOCK ') cindex(nname) = -j if (ndcname.gt.0.and.j.eq.ipj+1.and.vcheck.eq.'yes') * call warn(' Category '// * ctemp(1:lctemp)//' first implicitly defined in cif ') endif endif C 290 lloop(nname)=0 nloop(nname)=0 iloop(nname)=0 if (nitem.eq.0) fcatnum=cindex(nname) if(.not.loop_) goto 200 nitem=nitem+1 if(nitem.gt.NUMITEM) * call err(' Items per loop packet > NUMITEM') nloop(nname)=loopct iloop(nname)=nitem if (fcatnum.ne.cindex(nname)) then temp = '(none)' if (fcatnum.gt.0) temp=dcname(fcatnum) if (fcatnum.lt.0) temp=cname(-fcatnum) if (ctemp(1:lctemp).ne.temp(1:lastnb(temp))) * call warn (' Heterogeneous categories in loop '// * ctemp(1:lastnb(ctemp))//' vs '// * temp(1:lastnb(temp))) fcatnum=cindex(nname) endif goto 200 300 continue C C....... Are names checked against dictionary? C if(dictfl.eq.'yes') goto 500 if(vcheck.eq.'no '.or.ndict.eq.0) goto 500 do 350 i=1,nname if(dtype(i).eq.'test') dtype(i)='numb' 350 continue C C....... End of data block; tidy up loop storage C 500 lrecd=irecd-1 if(type_.eq.'save'.and.long_.lt.6) then itpos=jchar-long_ if(tabx_) then itpos=0 do ipp=1,jchar-long_ itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posval_=itpos endif irecd=isrecd jchar=isjchr lastch=islast recn_=irecd buffer=' ' if(lastch.gt.0)buffer=isbuf(1:lastch) jrecd=irecd loop_=.false. loopct=0 if(ndata.ne.nname) call err(' Syntax construction error') C Cdbg WRITE(6,'(a)') Cdbg * ' data name type recd char loop leng' Cdbg WRITE(6,'(a,1x,a,4i5)') (dname(i),dtype(i),drecd(i),dchar(i), Cdbg * nloop(i),iloop(i),i=1,nname) Cdbg WRITE(6,'(3i5)') (i,loopni(i),loopnp(i),i=1,loopct) C return end C C C C C C C >>>>>> Get the attributes of data item associated with data name C function test_(temp) C logical test_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) character otestf*3 character locase*(MAXBUF) C otestf=testfl testfl='yes' name=locase(temp) test_=.true. if(otestf.eq.'no ') goto 100 if(name.eq.nametb) goto 200 100 call getitm(name) 200 list_ =loopnl if(type_.eq.'null') test_=.false. return end C C C C C C >>>>>> Set or Reference a bookmark C function bkmrk_(mark) C logical bkmrk_ include 'ciftbx.sys' C integer mark,ii,nitem character*4 flag bkmrk_=.true. if(mark.eq.0) then do ii=1,MAXBOOK if(ibkmrk(1,ii).lt.0) goto 100 enddo bkmrk_=.false. call warn(' More than MAXBOOK bookmarks requested') return 100 mark=ii ibkmrk(1,ii)=iname ibkmrk(2,ii)=irecd ibkmrk(3,ii)=jchar if(iname.gt.0) then ibkmrk(2,ii) = trecd(iname) ibkmrk(3,ii) = tchar(iname) endif ibkmrk(4,ii)=0 if(iname.gt.0) then if(nloop(iname).ne.0.and. * loopnl.eq.nloop(iname).and.loopct.ne.0) then nitem=loopni(nloop(iname)) ibkmrk(2,ii)=looprd(1) ibkmrk(3,ii)=max(0,loopch(1)-1) ibkmrk(4,ii)=loopct endif endif else if(ibkmrk(1,mark).lt.0) then bkmrk_=.false. return endif iname=ibkmrk(1,mark) irecd=ibkmrk(2,mark) loopct=ibkmrk(4,mark) loop_=.false. text_=.false. loopnl=-1 testfl='no ' if(iname.gt.0) then if(nloop(iname).ne.0.and.loopct.ne.0) then nitem=loopni(nloop(iname)) looprd(nitem+1)=ibkmrk(2,mark) loopch(nitem+1)=ibkmrk(3,mark) do ii = 1,nitem lloop(ii+iname-iloop(iname))=loopct-1 enddo loopct=loopct-1 if(lloop(iname).gt.0) then loop_=.true. loopnl=nloop(iname) endif endif endif jchar=MAXBUF if(irecd.gt.0) then irecd=irecd-1 call getlin(flag) jchar=ibkmrk(3,mark) endif ibkmrk(1,mark)=-1 mark=0 endif return end C C C C C C C >>>>>> Find the location of the requested item in the CIF C The argument "name" may be a data item name, blank C for the next such item. The argument "type" may be C blank for unrestricted acceptance of any non-comment C string (use cmnt_ to see comments), including loop headers, C "name" to accept only the name itself and "valu" C to accept only the value, or "head" to position to the C head of the CIF. Except when the "head" is requested, C the position is left after the data item provided. C function find_(name,type,strg) C logical find_ include 'ciftbx.sys' character name*(*),type*(*),strg*(*),flag*4 character jjbuf*(MAXBUF) integer jjchar,jjrecd,jjlast,jjlrec,jjjrec C find_ = .false. strg = ' ' long_ = 0 jjchar = jchar jjrecd = lrecd jjlast = lastch jjlrec = lrecd jjjrec = jrecd jjbuf = ' ' if(lastch.gt.0) jjbuf(1:lastch)=buffer(1:lastch) if(type.eq.'head') then lrecd = nrecd irecd=0 jchar=MAXBUF+1 call getlin(flag) if(flag.eq.'fini') goto 300 find_=.true. lrecd=jjlrec return endif if(name.ne.' ') then testfl='no ' call getitm(name) if(iname.eq.0) goto 300 if(type.eq.'valu') then list_=loopnl strg=strg_(1:long_) find_=.true. return endif if(type.eq.'name'.or.loopnl.eq.0) then irecd=trecd(iname)-1 call getlin(flag) jchar=tchar(iname) posnam_=jchar+1 call getstr strg=strg_(1:long_) recn_=irecd find_=.true. return endif if(type.eq.' ') then irecd=loorec(loopnl)-1 call getlin(flag) jchar=loopos(loopnl) call getstr posval_=loopos(loopnl) if(tabx_) posval_=loopox(loopnl) strg=strg_(1:long_) recn_=irecd find_=.true. return endif call err(' Call to find_ with invalid arguments') endif if(name.eq.' ') then 200 call getstr if(type_.eq.'fini') goto 300 if(type.ne.' '.and. * (type_.eq.'data'.or.type_.eq.'save')) goto 300 if(type.eq.'name'.and.type_.ne.'name') goto 200 if(type.eq.'valu'.and. * type_.ne.'numb'.and.type_.ne.'text' * .and.type_.ne.'char'.and.type_.ne.'null') goto 200 find_=.true. strg=strg_(1:long_) if(type_.eq.'name') then posnam_=jchar-long_ else posval_=jchar-long_ if(quote_.ne.' ') posval_=posval_-1 endif recn_=irecd return endif C C Search failed, restore pointers C 300 irecd = jjrecd lastch = jjlast lrecd = jjlrec jchar = jjchar buffer = ' ' if(lastch.gt.0)buffer(1:lastch)=jjbuf(1:lastch) jrecd = jjjrec if(jrecd.ne.irecd) jrecd=-1 recn_ = irecd C return end C C C C C C C >>>>>> Get the next data name in the data block C function name_(temp) C logical name_ include 'ciftbx.sys' character temp*(*) C name_=.false. temp=' ' iname=iname+1 if(iname.gt.nname) goto 100 name_=.true. temp=dtag(iname) if(ddict(iname).ne.0) temp=dictag(ddict(iname)) 100 return end C C C C C C C >>>>>> Extract a number data item and its standard deviation C This version return single precision numbers C function numb_(temp,numb,sdev) C logical numb_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) character locase*(MAXBUF) real numb,sdev C name=locase(temp) if(testfl.eq.'no ') goto 100 if(name.eq.nametb) goto 150 C 100 call getitm(name) C 150 numb_=.false. if(type_.ne.'numb') goto 200 numb_=.true. numb =numbtb if(sdevtb.ge.0.0) sdev=sdevtb C 200 testfl='no ' return end C C C C C C C >>>>>> Extract a number data item and its standard deviation C This version returns double precision numbers C function numd_(temp,numb,sdev) C logical numd_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) character locase*(MAXBUF) double precision numb,sdev C name=locase(temp) if(testfl.eq.'no ') goto 100 if(name.eq.nametb) goto 150 C 100 call getitm(name) C 150 numd_=.false. if(type_.ne.'numb') goto 200 numd_=.true. numb =numbtb if(sdevtb.ge.0.0) sdev=sdevtb C 200 testfl='no ' return end C C C C C C C >>>>>> Extract a character data item. C function char_(temp,strg) C logical char_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) character strg*(*),flag*4 character locase*(MAXBUF) integer icpos,itpos,ixpos,ixtpos,ipp,iepos,ispos C name=locase(temp) if(testfl.eq.'yes') goto 100 if(.not.text_) goto 120 if(name.ne.nametb) goto 120 char_=.false. text_=.false. strg=' ' long_=0 call getlin(flag) if(flag.eq.'fini') goto 200 if(buffer(1:1).eq.';') then jchar=2 goto 200 endif quote_=' ' jchar=lastch+1 long_=lastch strg_(1:long_)=buffer(1:long_) goto 150 C 100 if(name.eq.nametb) goto 150 C 120 call getitm(name) if(type_.eq.'null') then char_=.false. text_=.false. strg_=' ' long_=0 goto 200 endif C 150 char_=.true. text_=.false. if(tabx_) then call detab icpos=jchar-long_ if(quote_.ne.' ') icpos=icpos-1 iepos=icpos+long_-1 itpos=0 do ipp=1,icpos itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo ispos=itpos 160 ixpos=index(buffer(icpos:iepos),tab) ixtpos=itpos+ixpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 icpos=icpos+ixpos itpos=ixtpos+1 if(icpos.le.iepos) goto 160 else strg = * bufntb(ispos:min(MAXBUF,itpos+iepos-icpos)) long_=min(MAXBUF,itpos+iepos-icpos)-ispos+1 if(ispos.eq.1.and.strg(1:1).eq.';') * strg(1:1) = ' ' endif else strg=strg_(1:long_) endif if(type_.eq.'char') goto 200 char_=.false. if(type_.ne.'text') goto 200 char_=.true. call getlin(flag) jchar=MAXBUF+1 if(flag.eq.'fini') goto 200 if(buffer(1:1).eq.';')then jchar=2 goto 200 endif irecd=irecd-1 text_=.true. C 200 testfl='no ' return end C C C C C C C >>>>>> Extract a comment field. C function cmnt_(strg) C logical cmnt_ integer lastnb include 'ciftbx.sys' character strg*(*),flag*4,c*1, * jjbuf*(MAXBUF) integer jjchar,jjrecd,jjlast,jjlrec,jjjrec integer ipp,itpos,ixpos C jjchar = jchar jjrecd = irecd jjlast = lastch jjlrec = lrecd jjjrec = jrecd jjbuf=' ' if(lastch.gt.0)jjbuf(1:lastch)=buffer(1:lastch) lrecd = nrecd if(bloc_.eq.' ') then if(irecd.eq.0) jchar=MAXBUF endif strg=' ' long_=0 cmnt_=.false. goto 105 100 jchar=jchar+1 105 if(jchar.le.lastch) goto 140 C C....... Read a new line C 110 call getlin(flag) if(flag.eq.'fini') then strg='fini' jchar=MAXBUF+1 long_=4 cmnt_=.false. return endif jchar=1 strg=char(0) long_=1 posnam_=0 goto 220 140 if(lastch.eq.1.and.buffer(1:1).eq.' ') go to 200 C C....... Process this character in the line C 150 c=buffer(jchar:jchar) if(c.eq.' ') goto 100 if(c.eq.tab.and.(.not.tabx_)) goto 190 if(c.eq.tab) goto 100 if(c.eq.'#') goto 200 goto 300 C C For a tab, when not expanding to blanks, accept C that single character as a comment C 190 long_=1 strg=tab posnam_=jchar jchar=jchar+1 goto 220 C C....... Accept the remainder of the line as a comment C 200 long_=lastch-jchar itpos=jchar if(tabx_) then itpos=0 do ipp=1,jchar itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif 210 posnam_=itpos if(long_.gt.0) then if(tabx_) then call detab ixpos= lastnb(bufntb) strg = bufntb(itpos+1:ixpos) else strg = buffer(jchar+1:lastch) endif endif if(long_.le.0) then strg=' ' long_=1 endif jchar=MAXBUF+1 220 lrecd=jjlrec cmnt_=.true. return C C....... Found a non-comment field, restore pointers C 300 irecd = jjrecd lastch = jjlast lrecd = jjlrec jchar = jjchar buffer=' ' if(lastch.gt.0)buffer(1:lastch)=jjbuf(1:lastch) jrecd=jjjrec if(jrecd.ne.irecd) jrecd=-1 recn_=irecd return end C C C C C C >>>>> Convert name string to lower case C function locase(name) C include 'ciftbx.sys' character locase*(MAXBUF) character temp*(MAXBUF),name*(*) character low*26,cap*26,c*1 integer i,j data cap /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data low /'abcdefghijklmnopqrstuvwxyz'/ C temp=name do 100 i=1,MAXBUF c=temp(i:i) if(c.eq.' ') goto 200 if(c.eq.tab) goto 200 j=index(cap,c) if(j.ne.0) temp(i:i)=low(j:j) 100 continue 200 locase=temp return end C C C C C C >>>>>> Get the data item associated with the tag. C subroutine getitm(name) C include 'ciftbx.sys' SAVE character name*(*) character flag*4 integer iitem,nitem,npakt integer kchar,loopi,i,j,itpos,ipp C C....... Find requested dataname in hash list C nametb=name posnam_=0 posval_=0 posdec_=0 posend_=0 quote_=' ' if(name(1:1).eq.'_') goto 100 type_='null' dictype_='null' diccat_='(none)' dicname_=name tagname_=' ' strg_=' ' long_=1 goto 1000 100 call hash_find(nametb, * dname,dchain,NUMBLOCK,nname,dhash,NUMHASH, * iname) if(iname.gt.0) goto 180 if(dictfl.ne.'yes') then call hash_find(nametb, * dicnam,dicchain,NUMDICT,ndict,dichash,NUMHASH,j) if(j.ne.0) then dictype_=dicxtyp(j) if(dcindex(j).ne.0) diccat_=dcname(dcindex(j)) dicname_=nametb if(aroot(j).ne.0) then dicname_=dictag(aroot(j)) call hash_find(dicnam(aroot(j)), * dname,dchain,NUMBLOCK,nname,dhash,NUMHASH, * iname) if(iname.gt.0) goto 180 endif type_='null' tagname_=' ' strg_=' ' long_=1 go to 1000 endif endif 160 continue type_='null' dictype_='null' diccat_='(none)' dicname_=name long_=1 goto 1000 C C 180 tagname_=dtag(iname) if(ddict(iname).ne.0) tagname_=dictag(ddict(iname)) posnam_=tchar(iname) if(tabx_)posnam_=xchar(iname) if(nloop(iname).le.0) goto 500 C C....... Process loop packet if first item request C if(nloop(iname).ne.loopnl) goto 200 if(lloop(iname).lt.loopct) goto 300 if(loop_) goto 230 200 loop_=.true. loopct=0 loopnl=nloop(iname) nitem=loopni(loopnl) npakt=loopnp(loopnl) irecd=drecd(iname)-1 call getlin(flag) jchar=max(0,dchar(iname)-1) Cdbg if(jchar.lt.0) write(6,'(7H dchar ,i5)') jchar do 220 i=1,nitem 220 lloop(i+iname-iloop(iname))=0 goto 240 C C....... Read a packet of loop items C 230 nitem=loopni(loopnl) npakt=loopnp(loopnl) irecd=looprd(nitem+1)-1 call getlin(flag) jchar=loopch(nitem+1) Cdbg if(jchar.lt.0) write(6,'(7H loopch,i5)') jchar 240 iitem=0 250 iitem=iitem+1 if(iitem.le.nitem) goto 255 loopch(iitem)=jchar looprd(iitem)=irecd goto 270 255 call getstr loopch(iitem)=jchar-long_ if(quote_.ne.' ')loopch(iitem)=jchar-long_-1 loopln(iitem)=long_ looprd(iitem)=irecd if(buffer(1:1).ne.';') goto 250 260 call getlin(flag) if(buffer(1:1).ne.';') goto 260 jchar=2 goto 250 270 loopct=loopct+1 if(loopct.lt.npakt) goto 300 loop_=.false. C C....... Point to the loop data item C 300 lloop(iname)=lloop(iname)+1 loopi=iloop(iname) irecd=looprd(loopi)-1 call getlin(flag) long_=loopln(loopi) kchar=loopch(loopi) goto 550 C C....... Point to the non-loop data item C 500 irecd=drecd(iname)-1 call getlin(flag) kchar=dchar(iname)+1 long_=iloop(iname) loop_=.false. loopct=0 loopnl=0 C C....... Place data item into variable string and make number C 550 type_=dtype(iname) dictype_=dxtyp(iname) diccat_='(none)' if(cindex(iname).gt.0) diccat_=dcname(cindex(iname)) if(cindex(iname).lt.0) diccat_=cname(-cindex(iname)) if(diccat_.eq.' ') diccat_='(none)' dicname_=dtag(iname) if(ddict(iname).ne.0) then if (aroot(ddict(iname)).ne.0) then dicname_=dictag(aroot(ddict(iname))) endif endif strg_(1:long_)=buffer(kchar:kchar+long_-1) itpos=kchar if(tabx_) then itpos=0 do ipp=1,kchar itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posval_=itpos posend_=itpos+long_-1 jchar=kchar+long_ if(jchar.le.MAXBUF) then if(buffer(jchar:jchar).ne.' ' .and. * buffer(jchar:jchar).ne.tab) jchar=jchar+1 endif quote_=' ' if(kchar.gt.1) then if(buffer(kchar-1:kchar-1).ne.' ' .and. * buffer(kchar-1:kchar-1).ne.tab) then quote_=buffer(kchar-1:kchar-1) endif endif if(type_.eq.'char' .and. kchar.eq.1 .and. * buffer(1:1).eq.';') type_='text' if(type_.eq.'text') then if(buffer(1:1).eq.';') then strg_(1:1)=' ' else type_='char' endif endif if(type_.eq.'numb') then call ctonum if(posdec_.gt.0) posdec_=posval_+posdec_-1 endif if(quote_.ne.' ') goto 1000 if(long_.eq.1.and.strg_(1:1).eq.'?') type_='null' if(long_.eq.1.and.strg_(1:1).eq.'.') type_='null' C 1000 return end C C C C C C C C >>>>>> Read the next string from the file C subroutine getstr C include 'ciftbx.sys' integer i,j,jj(11),im logical quoted character c*1,num*21,flag*4 data num/'0123456789+-.()EDQedq'/ C quoted=.false. quote_=' ' if(irecd.gt.0.and. * jchar.eq.1.and.lastch.gt.0) goto 140 100 jchar=jchar+1 if(jchar.le.lastch) goto 150 C C....... Read a new line C 110 call getlin(flag) type_='fini' dictype_=type_ diccat_='(none)' dicname_=' ' Cdbg write(6,'(/5i5,a)') Cdbg * irecd,jrecd,lrecd,nrecd,lastch, buffer(1:lastch) if(flag.eq.'fini') goto 500 C C....... Test if the new line is the start of a text sequence C 140 if(buffer(1:1).ne.';') goto 150 type_='text' jchar=lastch+1 long_=lastch strg_(1:long_)=buffer(1:long_) strg_(1:1)=' ' goto 500 C C....... Process this character in the line C 150 c=buffer(jchar:jchar) if(c.eq.' ') goto 100 if(c.eq.tab) goto 100 if(c.eq.'#') goto 110 if(c.eq.'''') goto 300 if(c.eq.'"') goto 300 if(c.ne.'_') goto 200 type_='name' goto 210 C C....... Span blank delimited token; test if a number or a character C 200 type_='numb' im=0 do 205 i=1,11 205 jj(i)=0 210 do 250 i=jchar,lastch if(buffer(i:i).eq.' ') goto 400 if(buffer(i:i).eq.tab) goto 400 if(type_.ne.'numb') goto 250 j=index(num,buffer(i:i)) if(j.eq.0) type_='char' if(j.le.10) then im=im+1 goto 250 endif if(j.gt.13.and.im.eq.0) type_='char' jj(j-10)=jj(j-10)+1 250 continue i=lastch+1 if(type_.ne.'numb') goto 400 do 270 j=1,5 if((jj(j).gt.1.and.j.gt.2) .or. * jj(j).gt.2) type_='char' 270 continue goto 400 C C....... Span quote delimited token; assume character C 300 type_='char' quoted=.true. jchar=jchar+1 do 320 i=jchar,lastch if(buffer(i:i).ne.c) goto 320 if(i+1.ge.lastch) goto 400 if(buffer(i+1:i+1).eq.' ') goto 400 if(buffer(i+1:i+1).eq.tab) goto 400 320 continue Cdbg write(6,'(a,4i5,a)') Cdbg * '**** ',irecd,lastch,i,jchar,buffer(jchar:i) call warn(' Quoted string not closed') C C....... Store the string for the getter C 400 long_=i-jchar strg_(1:long_)=buffer(jchar:i-1) jchar=i quote_=' ' if(quoted) then quote_=buffer(jchar:jchar) jchar =jchar+1 endif Cdbg write(6,'(5x,8i5,5x,a)') Cdbg * irecd,jrecd,lrecd,nrecd,lastch,i,jchar,long_,strg_(1:long_) if(type_.ne.'char'.or.quoted) goto 500 if(strg_(1:5).eq.'data_') type_='data' if(strg_(1:5).eq.'loop_') type_='loop' if(long_.eq.1.and.strg_(1:1).eq.'?') type_='null' if(long_.eq.1.and.strg_(1:1).eq.'.') type_='null' if(strg_(1:5).eq.'save_') type_='save' C 500 return end C C C C C C C >>>>>> Convert a character string into a number and its esd C C Q C D+ C E- C + + C number string -xxxx.xxxx-xxx(x) C component count CCNT 11111222223333444 C (with at least 1 digit in the mantissa) C subroutine ctonum C integer lastnb include 'ciftbx.sys' character test*22,c*1 integer*4 m,nchar integer*4 ccnt,expn,msin,esin,ndec,ids,nmd double precision numb,sdev,ntemp,mant data test /'0123456789+.-()EDQedq '/ C numbtb=0.D0 sdevtb=-1.D0 numb=1.D0 sdev=0.D0 ccnt=0 mant=0.D0 expn=0. msin=+1 esin=+1 ndec=0 ids=0 nmd=0 type_='char' posdec_=0 if(long_.eq.1.and. * index('0123456789',strg_(1:1)).eq.0) goto 500 C C....... Loop over the string and identify components C C The scan works in phases C ccnt = 0 processing looking for first digit C ccnt = 1 processing before decimal point C ccnt = 2 processing after decimal point C ccnt = 3 processing exponent C ccnt = 4 processing standard deviation C do 400 nchar=1,long_ C c=strg_(nchar:nchar) m=index(test,c) if(m.eq.0) goto 500 if(m.gt.10) goto 300 C C....... Process the digits C if(ccnt.eq.0) ccnt=1 if(ccnt.eq.2) ndec=ndec+1 if(ccnt.gt.2) goto 220 ntemp=m-1 mant=mant*10.D0+ntemp nmd=nmd+1 if(ccnt.eq.1.and.mant.ne.0.D0) ids=ids+1 goto 400 220 if(ccnt.gt.3) goto 240 expn=expn*10+m-1 goto 400 240 ntemp=m-1 sdev=sdev*10.D0+ntemp sdevtb=1.D0 goto 400 C C....... Process the characters . + - ( ) E D Q C 300 if(c.ne.'.') goto 320 if(ccnt.gt.1) goto 500 posdec_=nchar ccnt=2 goto 400 C 320 if(nmd.eq.0.and.m.gt.13) goto 500 if(c.ne.'(') goto 340 if(posdec_.eq.0) posdec_=nchar ccnt=4 goto 400 C 340 if(posdec_.eq.0.and.ccnt.gt.0) posdec_=nchar if(c.eq.' ') goto 400 if(m.gt.13) m = 11 if(ccnt.eq.3) goto 500 if(ccnt.gt.0) goto 360 ccnt=1 msin=12-m goto 400 360 ccnt=3 esin=12-m C 400 continue if(posdec_.eq.0) posdec_=lastnb(strg_(1:long_))+1 C C....... String parsed; construct the numbers C expn=expn*esin-ndec if(expn+ids.gt.-minexp) then call warn(' Exponent overflow in numeric input') expn=-minexp-ids endif if(expn.lt.minexp) then call warn(' Exponent underflow in numeric input') expn=minexp endif if(expn.lt.0) numb=1./10.D0**abs(expn) if(expn.gt.0) numb=10.D0**expn if(sdevtb.gt.0.0) sdevtb=numb*sdev ntemp=msin numbtb=numb*mant*ntemp type_='numb' C 500 return end C C C C C C C >>>>>> Read a new line from the direct access file C subroutine getlin(flag) C integer lastnb include 'ciftbx.sys' character flag*4 C irecd=irecd+1 jchar=1 if(irecd.eq.jrecd) goto 200 if(irecd.le.lrecd) goto 100 buffer=' ' lastch=0 jchar=MAXBUF+1 jrecd=-1 flag='fini' goto 200 100 read(dirdev,'(a)',rec=irecd) buffer recn_=irecd lastch=max(1,lastnb(buffer)) jrecd=irecd flag=' ' 200 return end C C C C C C C >>>>>> Detab buffer into bufntb C subroutine detab C include 'ciftbx.sys' integer icpos,itpos,ixpos,ixtpos if(jrecd.eq.jrect) return icpos=1 itpos=1 bufntb=' ' if(lastch.gt.0) then 100 ixpos=index(buffer(icpos:lastch),tab) ixtpos=ixpos+itpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 if(ixpos.gt.1) then bufntb(itpos:ixtpos)= * buffer(icpos:ixpos+icpos-2) else bufntb(itpos:ixtpos)=' ' endif itpos=ixtpos+1 icpos=ixpos+icpos goto 100 else bufntb(itpos:max(MAXBUF,itpos+lastch-icpos))= * buffer(icpos:lastch) endif endif jrect=jrecd return end C C C C C C C >>>>>> Write error message and exit. C subroutine err(mess) character*(*) mess call cifmsg('error',mess) stop end C C C C C C C >>>>>> Write warning message and continue. C subroutine warn(mess) character*(*) mess call cifmsg('warning',mess) return end C C C C C C C >>>>>> Write a message to the error device C subroutine cifmsg(flag,mess) C integer lastnb include 'ciftbx.sys' character*(*) flag character*(*) mess character*(MAXBUF) tline character*5 btype integer ll,ls,ltry,ii,i C btype = 'data_' if(save_) btype = 'save_' tline= ' ciftbx '//flag//': ' * //file_(1:longf_)//' '//btype * //bloc_(1:max(1,lastnb(bloc_)))//' line:' ll = max(1,lastnb(tline)) write(errdev,'(a,i7)')tline(1:ll),irecd ll=len(mess) ls=1 100 if(ll-ls.le.79) then write(errdev,'(1X,a)') mess(ls:ll) return else ltry = min(ll,ls+79) do ii = ls+1,ltry i = ltry-ii+ls+1 if(mess(i:i).eq.' ') then write(errdev,'(1X,a)') mess(ls:i-1) ls=i+1 if(ls.le.ll) go to 100 return endif enddo write(errdev,'(1X,a)') mess(ls:ltry) ls=ltry+1 if(ls.le.ll) go to 100 return endif end C C C C C >>>>>> Create a named file. C function pfile_(fname) C logical pfile_ include 'ciftbx.sys' logical test integer i character fname*(*) C C....... Test if a file by this name is already open. C if(pfilef.eq.'yes') call close_ pfilef='no ' file_=fname do 120 i=1,MAXBUF if(file_(i:i).eq.' ') goto 140 120 continue 140 if (i.gt.1) then inquire(file=file_(1:i-1),exist=test) pfile_=.false. longf_ = i-1 if(test) goto 200 else file_ = ' ' pfile_ = .true. longf_ = 1 endif C C....... Open up a new CIF C if (file_(1:1) .ne. ' ') then open(unit=outdev,file=fname,status='NEW',access='SEQUENTIAL', * form='FORMATTED') precn_=0 endif pfile_=.true. pfilef='yes' nbloc=0 pchar=1+lprefx pcharl=0 obuf=prefx obuf(pchar:MAXBUF)=' ' 200 return end C C C C C C >>>>>> Store a data block command in the CIF C Call with blank name to close current block only C function pdata_(name) C logical pdata_ include 'ciftbx.sys' character name*(*),temp*(MAXBUF) character dbloc(100)*(NUMCHAR) integer i C pdata_=.true. if(ploopn.ne.0) call eoloop if(ptextf.eq.'yes') call eotext if(psaveo) then pchar=-1 if(pposval_.ne.0) then pchar=lprefx+1 call putstr(' ') pchar=lprefx+pposval_ pposval_=0 endif call putstr('save_') psaveo=.false. endif C C....... Check for duplicate data name C temp=name if(temp.eq.' ') goto 200 if(saveo_) goto 130 pdata_=.false. do 120 i=1,nbloc if(temp.eq.dbloc(i)) goto 200 120 continue C C....... Save block name and put data_ statement C nbloc=nbloc+1 if(nbloc.le.100) dbloc(nbloc)=temp 130 pchar=-1 temp='data_'//name if(saveo_) temp='save_'//name psaveo=saveo_ if(pposnam_.gt.0) then pchar=lprefx+1 call putstr(' ') pchar=lprefx+pposnam_ pposnam_=0 endif call putstr(temp) pchar=lprefx pdata_=.true. C 200 return end C C C C C C C >>>>>> Put a number into the CIF, perhaps with an esd appended C function pnumb_(name,numb,sdev) C logical pnumb_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR) real numb,sdev double precision dnumb,dsdev,dprec C pnumb_=.true. flag =.true. tflag =.true. temp=name if(ptextf.eq.'yes') call eotext C if(name(1:1).eq.' ') goto 120 if(vcheck.eq.'no ') goto 100 call dcheck(temp,'numb',flag,tflag) if (aliaso_.and.xdchk.ne.0) then if (aroot(xdchk).ne.0) * temp=dictag(aroot(xdchk)) endif pnumb_=flag 100 if(ploopn.ne.0) call eoloop pchar=-1 if(pposnam_.ne.0)pchar=pposnam_+lprefx call putstr(temp) C 120 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' dprec=decprc dnumb=numb dsdev=sdev call putnum(dnumb,dsdev,dprec) if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not in dictionary') endif if(.not.tflag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not correct type') endif C 150 pposnam_=0 pposval_=0 pposdec_=0 pposend_=0 return end C C C C C C C >>>>>> Put a double precision number into the CIF, perhaps C with an esd appended C function pnumd_(name,numb,sdev) C logical pnumd_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR) double precision numb,sdev C pnumd_=.true. flag =.true. tflag =.true. temp=name if(ptextf.eq.'yes') call eotext C if(name(1:1).eq.' ') goto 120 if(vcheck.eq.'no ') goto 100 call dcheck(temp,'numb',flag,tflag) if (aliaso_.and.xdchk.ne.0) then if (aroot(xdchk).ne.0) * temp=dictag(aroot(xdchk)) endif pnumd_=flag 100 if(ploopn.ne.0) call eoloop pchar=-1 if(pposnam_.ne.0)pchar=pposnam_+lprefx call putstr(temp) C 120 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' call putnum(numb,sdev,dpprc) if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not in dictionary') endif if(.not.tflag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not correct type') endif C 150 pposnam_=0 pposval_=0 pposdec_=0 pposend_=0 return end C C C C C C C >>>>>> Put a character string into the CIF. C function pchar_(name,string) C logical pchar_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR),string*(*) character line*(MAXBUF),strg*(MAXBUF) integer i,j C pchar_=.true. flag =.true. tflag =.true. temp =name if(ptextf.eq.'yes') call eotext C if(name(1:1).eq.' ') goto 110 if(vcheck.eq.'no ') goto 100 call dcheck(temp,'char',flag,tflag) if (aliaso_.and.xdchk.ne.0) then if (aroot(xdchk).ne.0) * temp=dictag(aroot(xdchk)) endif pchar_=flag 100 if(ploopn.ne.0) call eoloop pchar=-1 if(pposnam_.gt.0) pchar=posnam_+lprefx call putstr(temp) C 110 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' line=string do 120 i=MAXBUF,2,-1 if(line(i:i).ne.' ') goto 130 120 continue 130 if(pposval_.ne.0.and.pposend_.ge.pposval_) * i=max(i,pposend_-pposval_+1) if(pquote_.ne.' ') goto 150 do 140 j=i,1,-1 if(line(j:j).eq.' ') goto 150 140 continue if((line(1:1).eq.'_' * .or. line(i:i).eq.'_' * .or. line(1:1).eq.'''' * .or. line(1:1).eq.'"' * .or. line(1:1).eq.';') * .and.line(1:i).ne.'''.''' * .and.line(1:i).ne.'''?''' * .and.line(1:i).ne.'"."' * .and.line(1:i).ne.'"?"') goto 150 strg=line(1:i) goto 200 150 if(pquote_.eq.';') goto 190 if(pquote_.eq.'''') goto 165 if(pquote_.eq.'"') goto 185 do 160 j=1,i if(line(j:j).eq.'''') goto 170 160 continue 165 strg=''''//line(1:i)//'''' i=i+2 pquote_='''' goto 200 170 do 180 j=1,i if(line(j:j).eq.'"') goto 190 180 continue 185 strg='"'//line(1:i)//'"' i=i+2 pquote_='"' goto 200 190 pchar=-1 strg='; '//line(1:i) i=i+2 ptextf='yes' call putstr(strg(1:i)) pchar=-1 ptextf='no ' call putstr(';') pchar=lprefx call putstr(' ') call warn(' Converted pchar_ output to text for: ' * //strg(3:i)) goto 210 C 200 if(pposval_.ne.0) then pchar=pposval_+lprefx if(pquote_.ne.' ') pchar=pchar-1 endif call putstr(strg(1:i)) 210 if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not in dictionary') endif if((.not.tflag).and.line(1:i).ne.'.'.and. * line(1:i).ne.'?'.and.pquote_.eq.' ') then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not correct type') endif 250 pposval_=0 pposdec_=0 pposnam_=0 pposend_=0 pquote_=' ' return end C C C C C C >>>>>> Put a comment in the output CIF C function pcmnt_(string) C logical pcmnt_ include 'ciftbx.sys' character string*(*), temp*(MAXBUF) C if(ptextf.eq.'yes') call eotext if(pposnam_.ne.0) pchar=pposnam_+lprefx if(string.eq.' '.or. * (string.eq.char(0)) .or. * (string.eq.tab.and.(.not.ptabx_))) then if(string.eq.' ') pchar=-1 call putstr(string) if(string.eq.' ') call putstr(char(0)) else temp='#'//string call putstr(temp) call putstr(char(0)) endif pcmnt_=.true. pposnam_=0 if(string.ne.tab)pchar=lprefx+1 return end C C C C C C C C >>>>>> Put a text sequence into the CIF. C function ptext_(name,string) C logical ptext_ integer lastnb include 'ciftbx.sys' logical flag,tflag integer ll character name*(*),temp*(NUMCHAR),string*(*),store*(NUMCHAR) character temp2*(MAXBUF) data store/' '/ C ptext_=.true. flag =.true. tflag =.true. ll=lastnb(string) if(ploopf.eq.'yes') ploopc=0 ploopf='no ' temp=name if(ptextf.eq.'no ') goto 100 if(temp.eq.store) goto 150 call eotext C 100 if(name(1:1).ne.' ') goto 110 if(ptextf.eq.'yes') goto 150 goto 130 C 110 if(ploopn.ne.0) call eoloop if(vcheck.eq.'no ') goto 120 call dcheck(name,'char',flag,tflag) if (aliaso_.and.xdchk.ne.0) then if (aroot(xdchk).ne.0) * temp=dictag(aroot(xdchk)) endif ptext_=flag 120 pchar=-1 if(pposnam_.ne.0) pchar=pposnam_+lprefx call putstr(temp) if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not in dictionary') endif if(.not.tflag) then if(.not.tabl_) pchar=lprefx+57 call putstr('#< not correct type') endif 130 ptextf='yes' store=temp if(string(1:1).eq.' '.and.ll.gt.1) then pchar=-1 temp2=';'//string(2:ll) call putstr(temp2) pchar=-1 return endif pchar=-1 call putstr(';') pchar=-1 if(string.eq.' ') return 150 pchar=-1 call putstr(string(1:max(1,ll))) pchar=-1 pposnam_=0 pposval_=0 pposdec_=0 pposend_=0 return end C C C C C C C >>>>>> Put a loop_ data name into the CIF. C function ploop_(name) C logical ploop_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR) C ploop_=.true. flag =.true. if(ptextf.eq.'yes') call eotext if(ploopf.eq.'no ') call eoloop temp=' ' if(name(1:1).eq.' ') goto 100 C if(tabl_.and.pposnam_.eq.0) then temp=' '//name else temp=name endif if(vcheck.eq.'no ') goto 100 call dcheck(name,' ',flag,tflag) if (aliaso_.and.xdchk.ne.0) then if (aroot(xdchk).ne.0) then if(tabl_.and.pposnam_.eq.0) then temp=' '//dictag(aroot(xdchk)) else temp=dictag(aroot(xdchk)) endif endif endif ploop_=flag 100 if(ploopn.ne.0) goto 120 ploopf='yes' pchar=-1 if(pposval_.ne.0) then pchar=lprefx+1 call putstr(' ') pchar=pposval_+lprefx else if(pposnam_.ne.0) then pchar=lprefx+1 call putstr(' ') pchar=pposnam_+lprefx+1 endif endif call putstr('loop_') pchar=-1 if(name(1:1).eq.' ') then ploopn=-1 return endif 120 if(pposnam_.ne.0) pchar=pposnam_+lprefx call putstr(temp) if(flag) goto 130 if(.not.tabl_) pchar=lprefx+57 call putstr('#< not in dictionary') 130 pchar=lprefx+1 ploopn=max(ploopn,0)+1 C 150 return end C C C C C C >>>>>> Create or clear a prefix string C Any change in the length of the prefix string flushes C pending text, if any, loops and partial output lines C function prefx_(strg,lstrg) C logical prefx_ include 'ciftbx.sys' character strg*(*) integer lstrg,mxline C mxline=MAXBUF if(line_.gt.0) mxline=min(line_,MAXBUF) if(lstrg.ne.lprefx.and.pcharl.gt.0) then pchar=-1 call putstr(' ') endif if (lstrg.le.0) then prefx=' ' if(pchar.ge.lprefx+1)pchar=pchar-lprefx lprefx=0 else if(lstrg.gt.mxline) then call warn(' Prefix string truncated') endif prefx=strg if(pchar.ge.lprefx+1)pchar=pchar-lprefx+lstrg obuf(1:min(mxline,lstrg))=prefx lprefx=lstrg if(mxline-lprefx.lt.NUMCHAR) then call warn(' Output prefix may force line overflow') endif endif prefx_=.true. return end C C C C C C C >>>>>> Close the CIF C subroutine close_ C include 'ciftbx.sys' C if(ptextf.eq.'yes') call eotext if(ploopn.ne.0) call eoloop if(pcharl.ge.lprefx+1) then pchar=-1 call putstr(' ') endif if (file_(1:1) .ne. ' ') then close(outdev) precn_=0 endif return end C C C C C C >>>>>> Put the string into the output CIF buffer C subroutine putstr(string) C integer lastnb include 'ciftbx.sys' SAVE character string*(*),temp*(MAXBUF),bfill*(MAXBUF) character temp2*(MAXBUF) integer i,ii,mxline,ioffst,ifree,icpos,itpos integer ixpos,ixtpos,it,im,kbin,kpass logical pflush,waslop data waslop /.false./ C bfill = ' ' mxline=MAXBUF if(line_.gt.0) mxline=min(line_,MAXBUF) temp=string temp2=temp pflush=.false. if(pchar.lt.0) pflush=.true. C do 100 i=MAXBUF,1,-1 if(temp(i:i).eq.' ') goto 100 if(ptabx_.and.temp(i:i).eq.tab) goto 100 goto 110 100 continue i=0 it=i C C....... Organise the output of loop_ items C 110 if(i.eq.0) goto 130 if(i.eq.1.and.string.eq.tab) goto 130 if(i.eq.1.and.string.eq.char(0)) then pcharl=MAXBUF goto 200 endif if(temp(1:1).eq.'#') goto 130 if(ploopf.eq.'yes') goto 130 if(ptextf.eq.'yes') goto 130 if(ploopn.le.0) goto 130 ploopc=ploopc+1 if(align_.or.tabl_) then if(ploopc.gt.ploopn) then if(pcharl.gt.lprefx) pflush=.true. ploopc=1 if(pchar.gt.0) pchar=lprefx+1 endif if(pchar.lt.0) goto 130 if(tabl_) then kbin=(mxline-lprefx)/8 if(ploopn.lt.kbin) then if(kbin/(ploopn+1).gt.1) then pchar=9+lprefx+ * (ploopc-1)*8*(kbin/(ploopn+1)) else pchar=1+lprefx+ * (ploopc-1)*8*(kbin/ploopn) endif else if(ploopc.le.kbin) then pchar=1+lprefx+(ploopc-1)*8 else kpass=(ploopc-kbin-1)/(kbin-1)+1 pchar=2*kpass+1+lprefx+ * mod(ploopc-kbin-1,kbin-1)*8 endif endif else if(ptabx_) then icpos=1 itpos=1 120 ixpos=index(temp(icpos:i),tab) ixtpos=(pchar+itpos-1+ixpos) ixtpos=((ixtpos+7)/8)*8 if(ixpos.gt.0) then if(ixpos.gt.1) then temp2(itpos:ixtpos-pchar+1)=temp(icpos:ixpos-1) else temp2(itpos:ixtpos-pchar+1)=' ' endif icpos=ixpos+1 itpos=ixtpos+2-pchar if(icpos.le.i) goto 120 it=itpos-1 else temp2(itpos:itpos+i-icpos)=temp(icpos:i) it=itpos+i-icpos endif endif if((pchar+i).gt.mxline+1.or. * (ptabx_.and.pchar+it.gt.mxline+1)) then if(pcharl.gt.lprefx)pflush=.true. pchar=lprefx+1 endif endif else if(ploopc.le.ploopn) goto 130 ploopc=1 endif C C....... Is the buffer full and needs flushing? C 130 if(i.eq.1.and.string.eq.tab) then if(pcharl.gt.lprefx) then if(obuf(pcharl:pcharl).eq.' ') pcharl=pcharl-1 endif endif if(pchar.le.pcharl.and.pcharl.gt.lprefx) pflush=.true. pchar=max(lprefx+1,pchar) if((ploopf.eq.'yes'.or.ploopn.le.0).and.tabl_) * pchar=((pchar-lprefx+6)/8)*8+1+lprefx if(ptabx_) then icpos=1 itpos=1 135 ixpos=index(temp(icpos:i),tab) ixtpos=(pchar+itpos-1+ixpos) ixtpos=((ixtpos+7)/8)*8 if(ixpos.gt.0) then if(ixpos.gt.1) then temp2(itpos:ixtpos-pchar+1)=temp(icpos:ixpos-1) else temp2(itpos:ixtpos-pchar+1)=' ' endif icpos=ixpos+1 itpos=ixtpos+2-pchar if(icpos.le.i) goto 135 it=itpos-1 else temp2(itpos:itpos+i-icpos)=temp(icpos:i) it=itpos+i-icpos endif endif if((pchar+i).gt.mxline+1.or. * (ptabx_.and.pchar+it.gt.mxline+1)) then pflush=.true. pchar=mxline+1-i pchar=max(lprefx+1,pchar) endif if(.not.pflush) goto 150 140 if(pcharl.gt.lprefx) then if(waslop.or.(.not.tabl_)) goto 145 ioffst=0 pcharl=max(lastnb(obuf(1:pcharl)),lprefx+1) ifree=mxline-pcharl if(ifree.gt.0) then im=numtab+2 if(numtab.gt.0.and.numtab.le.MAXTAB) then if(obuf(itabp(numtab):itabp(numtab)).eq.'#') * im=im-1 endif if(ifree.ge.16.and.im.lt.4.and. * (obuf(1+lprefx:1+lprefx).ne.'#' * .and.obuf(1+lprefx:1+lprefx).ne.';' * .and.obuf(1+lprefx:1+lprefx).ne.'_' * .and.obuf(1+lprefx:1+lprefx).ne.' ' * .and.obuf(1+lprefx:5+lprefx).ne.'data_' * .and.obuf(1+lprefx:5+lprefx).ne.'save_' * .and.obuf(1+lprefx:5).ne.'loop_')) then temp(1+lprefx:pcharl)=obuf(1+lprefx:pcharl) obuf(1+lprefx:pcharl+8)= * bfill(1:8)//temp(1+lprefx:pcharl) ioffst = 8 ifree=ifree-8 pcharl=pcharl+8 endif do ii=1,min(MAXTAB,numtab) icpos=itabp(ii)+ioffst if(icpos.gt.pcharl) goto 145 if(im.lt.4) then itpos=(max(icpos-lprefx, * ii*(mxline-lprefx)/im)+6)/8 itpos=itpos*8+1+lprefx else itpos=(max(icpos-lprefx, * ii*(mxline-lprefx)/im)+4)/6 itpos=itpos*6+1+lprefx endif if((obuf(icpos:icpos).eq.''''.or. * obuf(icpos:icpos).eq.'"').and. * itpos.gt.icpos) itpos=itpos-1 if(itpos-icpos.gt.ifree) itpos=icpos+ifree if(itpos.gt.icpos) then temp(1:pcharl-icpos+1)= * obuf(icpos:pcharl) if(i.lt.numtab) then ixpos=itabp(ii+1)+ioffst if(ixpos.gt.icpos+itpos-icpos+1) then if(obuf(ixpos-(itpos-icpos+1):ixpos-1).eq. * bfill(1:itpos-icpos+1)) then temp(ixpos-itpos+1:pcharl-itpos+1)= * obuf(ixpos:pcharl) pcharl=pcharl-(itpos-icpos) endif endif endif obuf(icpos:pcharl+itpos-icpos)= * bfill(1:itpos-icpos)//temp(1:pcharl-icpos+1) ifree=ifree-(itpos-icpos) ioffst=ioffst+itpos-icpos pcharl=pcharl+itpos-icpos endif if(ifree.le.0) goto 145 enddo endif 145 pcharl=max(1,lastnb(obuf)) write(outdev,'(a)') obuf(1:pcharl) else if(precn_.gt.0) then if(lprefx.gt.0) then write(outdev,'(a)') obuf(1:lprefx) else write(outdev,'(a)') endif else precn_=precn_-1 endif endif waslop=.false. precn_=precn_+1 do ii = 1,MAXTAB itabp(ii)=0 enddo numtab=0 if(lprefx.gt.0) then obuf=prefx(1:lprefx) else obuf=' ' endif C C....... Load the next item into the buffer C 150 pcharl=pchar+i if(ptabx_) pcharl=pchar+it waslop= ploopf.eq.'no '.and.ploopn.gt.0.and.align_ if(i.eq.0) then if(pcharl.eq.lprefx+1.and. * obuf(lprefx+1:lprefx+1).eq.' ') pcharl=pcharl-1 pchar=pcharl+1 goto 200 endif if(ptabx_) then obuf(pchar:pcharl)=temp2(1:it) else if(string.eq.tab) pcharl=pcharl-1 obuf(pchar:pcharl)=string(1:i) endif if(pchar.gt.1+lprefx) then numtab=numtab+1 if(numtab.le.MAXTAB) itabp(numtab)=pchar endif pchar=pcharl+1 if(pchar.gt.mxline+2) then call warn(' Output CIF line longer than line_') endif C 200 return end C C C C C C >>>>>> Convert the number and esd to string nnnn(m), limited C by relative precision prec C subroutine putnum(numb,sdev,prec) C include 'ciftbx.sys' character string*30,temp*30,c*1,sfmt*8 double precision numb,sdev,prec,xxnumb,xsdev,slog integer i,iexp,ifp,ii,jj,j,jlnz,jn,kexp,m,ixsdev,islog integer kdecp,ibexp C kdecp=0 if (sdev.gt.abs(numb)*prec) then if (esdlim_.ne.esdcac) then C C determine the number of digits set by esdlim_ C if (esdlim_.lt.9 .or.esdlim_.gt.99999) then call warn(' Invalid value of esdlim_ reset to 19') esdlim_ = 19 endif C C determine the number of esd digits C esddig = 1.+alog10(float(esdlim_)) esdcac = esdlim_ endif C C determine kexp, the power of 10 necessary C to present sdev as an integer in the range C (esdlim_/10,esdlim_] C slog = dlog10(sdev) islog = slog+1000. islog = islog-1000 kexp = -islog+esddig C C Adjust exponent kexp, so that sdev*10**kexp C is in the interval (esdlim_/10,esdlim_] C 20 if (kexp.lt.minexp) then call warn(' Underflow of esd') ixsdev = 0 go to 30 endif if (kexp.gt.-minexp) then call warn(' Overflow of esd') ixsdev = 99999 go to 30 endif xsdev = sdev*10.D0**kexp ixsdev = xsdev+.5 if (ixsdev.gt.esdlim_) then kexp = kexp -1 go to 20 endif if (ixsdev.lt.(esdlim_+5)/10) then kexp = kexp+1 go to 20 endif C C We need to present the number to the same scaling C at first, but will adjust to avoid Ennn notation C if possible C 30 xxnumb = dabs(numb)*10.d0**kexp+.5 if(xxnumb*prec .gt.1.D0) then call warn(' ESD less than precision of machine') ixsdev=0 endif if(numb.lt.0.d0) xxnumb = -xxnumb write(string,ndpfmt)xxnumb C C Extract the power of 10 C iexp = 0 ibexp = 0 do ii = 0,4 i = 30-ii c = string(i:i) m = index('0123456789',c) if (m.gt.0) then iexp = iexp+(m-1)*10**(ii-ibexp) else if (c.eq.' ') then ibexp = ibexp+1 else if (c.eq.'-') iexp=-iexp goto 40 endif endif enddo call err(' Internal error in putnum') C C Scan the rest of the string shifting the C decimal point to get an integer C 40 ifp = 0 j=1 do ii = 1,i-1 c = string(ii:ii) if (c.ne.' ')then m=index('0123456789+-',c) if(m.ne.0) then temp(j:j)=c if(j.gt.1.or.c.ne.'0')j=j+1 if(j.eq.3.and.temp(1:2).eq.'-0')j=j-1 if(ifp.ne.0)then iexp=iexp-1 if(iexp.le.0) goto 50 endif else if(c.eq.'.') then ifp=1 if(iexp.le.0) goto 50 endif endif endif enddo C C The string from 1 to j-1 has an integer C If iexp < 0, we present a 0. If iexp > 0 C we pad with zeros C 50 if(j.eq.1.or.iexp.lt.0) then temp(1:1)='0' j=2 iexp = 0 endif if (iexp.gt.0) then do ii = 1,iexp temp(j:j)='0' j=j+1 enddo iexp=0 endif string=temp(1:j-1) C C We have the number for which the presentation C would be nnnnnE-kexp. If kexp is gt 0, we can C decrease it and introduce a decimal point C jj=0 if(index('0123456789',temp(1:1)).eq.0) jj=1 if(kexp.gt.0.and.kexp.lt.j-jj+8) then if(kexp.lt.j-1) then string=temp(1:j-1-kexp)//'.'// * temp(j-kexp:j-1) kexp = 0 j=j+1 else if(jj.ne.0)string(1:1)=temp(1:1) string(1+jj:1+jj)='.' do ii=1,kexp-(j-1-jj) string(1+jj+ii:1+jj+ii)='0' enddo string(2+jj+(kexp-(j-1-jj)):30)= * temp(1+jj:j-1) j=j+1+kexp-(j-1-jj) kexp=0 endif endif kdecp=index(string(1:j-1),'.') if(kdecp.eq.0) kdecp=j if(kexp.ne.0) then write(temp(1:5),'(i5)') -kexp string(j:j)='E' j=j+1 do ii=1,5 c=temp(ii:ii) if(c.ne.' ') then string(j:j)=c j=j+1 endif enddo endif C C if there is a standard deviation C append it in parentheses C if(ixsdev.ne.0) then write(temp(1:5),'(i5)') ixsdev string(j:j)='(' j=j+1 do ii=1,5 c=temp(ii:ii) if(c.ne.' ') then string(j:j)=c j=j+1 endif enddo string(j:j)=')' j=j+1 endif else C C There is no standard deviation, just write numb C But limit to the digits implied by prec C slog = dlog10(min(.1D0,max(prec,dpprc))) islog = slog+1000.5 islog = islog-1000 kexp = -islog write(sfmt,'(5h(D30.,i2,1h))') kexp write(temp,sfmt)numb C C Now have the number in the form C [sign][0].nnnnnnnnDeee C which, while sufficient, is not neat C we reformat for the case 0<=eee<=kexp C C C Extract the power of 10 C iexp = 0 ibexp = 0 do ii = 0,4 i = 30-ii c = temp(i:i) m = index('0123456789',c) if (m.gt.0) then iexp = iexp+(m-1)*10**(ii-ibexp) else if (c.eq.' ') then ibexp = ibexp+1 else if (c.eq.'-') iexp=-iexp goto 140 endif endif enddo call err(' Internal error in putnum') C C Scan the rest of the string shifting the C decimal point to get a number with exponent 0, C if possible C 140 ifp = 0 j=1 do ii = 1,i-1 jn=ii c = temp(ii:ii) if (c.ne.' ')then m=index('0123456789+-',c) if(m.ne.0) then string(j:j)=c if(j.gt.1.or.c.ne.'0')j=j+1 if(j.eq.3.and.string(1:2).eq.'-0')j=j-1 if(ifp.ne.0)then iexp=iexp-1 if(iexp.le.0) goto 150 endif else if(c.eq.'.') then ifp = -1 if(iexp.le.0) goto 150 endif endif endif enddo 150 string(j:j)='.' ifp = j j = j+1 jlnz = j-1 155 do ii = jn+1,i-1 c = temp(ii:ii) if (c.ne.' ')then m=index('0123456789',c) if(m.ne.0) then string(j:j)=c j=j+1 if(m.ne.1)jlnz=j if(m.eq.1.and.ifp.ge.1.and. * pposdec_.ne.0.and.pposend_.ne.0) then if(j-1-ifp-min(iexp,0).le.pposend_-pposdec_) * jlnz=j endif else goto 160 endif endif enddo 160 j=jlnz if(j.eq.1) then string(1:1)='0' j=2 endif if(iexp.lt.0.and.iexp.gt.-7.and.ifp.lt.j-1.and. * ifp.ne.0.and.j-ifp-iexp.le.kexp) then temp(1:ifp)=string(1:ifp) do ii = 1,-iexp temp(ifp+ii:ifp+ii) = '0' enddo temp(ifp-iexp+1:j-iexp-1) = string(ifp+1:j-1) j = j-iexp iexp=0 string(1:j-1) = temp(1:j-1) endif kdecp=index(string(1:j-1),'.') if(kdecp.eq.0) kdecp=j if(iexp.ne.0) then write(temp(1:5),'(i5)')iexp string(j:j)='E' j=j+1 do ii=1,5 c=temp(ii:ii) if(c.ne.' ') then string(j:j)=c j=j+1 endif enddo endif endif C if(j.lt.1) then string(1:1)='0' j=2 endif if(kdecp.lt.1)kdecp=j if(pposdec_.ne.0) then pchar=lprefx+pposdec_-kdecp+1 else if(pposval_.ne.0)pchar=lprefx+pposval_ endif call putstr(string(1:j-1)) return end C C C C C C >>>>>> Check dictionary for data name validation C subroutine dcheck(name,type,flag,tflag) C include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR), * locase*(MAXBUF),type*4 C flag=.true. tflag=.true. temp=locase(name) call hash_find(temp, * dicnam,dicchain,NUMDICT,ndict,dichash,NUMHASH,xdchk) if(xdchk.eq.0) goto 150 if(tcheck.eq.'no ') goto 200 if(type.eq.dictyp(xdchk)) goto 200 if(type.eq.' ') goto 200 if(dictyp(xdchk).eq.'text' .and. type.eq.'char') goto 200 tflag=.false. goto 200 150 flag=.false. 200 continue return end C C C C C C >>>>>> End of text string C subroutine eotext C include 'ciftbx.sys' C if(ptextf.ne.'yes') then call warn(' Out-of-sequence call to end text block') return endif ptextf='no ' pchar=-1 call putstr(';') call putstr(char(0)) return end C C C C C C >>>>>> End of loop detected; check integrity and tidy up pointers C subroutine eoloop C include 'ciftbx.sys' integer i C if(ploopn.eq.0) goto 200 if(ploopn.eq.-1) then call putstr('_DUMMY') ploopn=1 ploopc=0 call warn( * ' Missing: missing loop_ name set as _DUMMY') endif if(ploopn.eq.ploopc) goto 200 do 150 i=ploopc+1,ploopn 150 call putstr('DUMMY') call warn( * ' Missing: missing loop_ items set as DUMMY') C 200 ploopc=0 ploopn=0 return end C C C C C C C >>>>>> Set common default values C block data C include 'ciftbx.sys' data cifdev /1/ data outdev /2/ data dirdev /3/ data errdev /6/ data loopct /0/ data nhash /0/ data ndict /0/ data nname /0/ data nbloc /0/ data ploopn /0/ data ploopc /0/ data ploopf /'no '/ data ptextf /'no '/ data pfilef /'no '/ data testfl /'no '/ data vcheck /'no '/ data tcheck /'no '/ data align_ /.true./ data tabl_ /.true./ data tabx_ /.true./ data ptabx_ /.true./ data text_ /.false./ data loop_ /.false./ data ndcname /0/ data ncname /0/ data save_ /.false./ data saveo_ /.false./ data alias_ /.true./ data aliaso_ /.false./ data dchash /NUMHASH*0/ data dichash /NUMHASH*0/ data dhash /NUMHASH*0/ data dcchain /NUMDICT*0/ data aroot /NUMDICT*0/ data cindex /NUMBLOCK*0/ data line_ /80/ data lastch /0/ data dictype_ /' '/ data dicname_ /' '/ data diccat_ /' '/ data tagname_ /' '/ data prefx /' '/ data lprefx /0/ data esdlim_ /19/ data esdcac /19/ data esddig /2/ data esdfmt /'(e12.2)'/ data edpfmt /'(d12.2)'/ data ndpfmt /'(d30.14)'/ data decprc /1.e-6/ data dpprc /1.d-14/ data decmin /1.e-37/ data dpmin /1.d-307/ data minexp /-307/ data itabp /MAXTAB*0/ data jrect /-1/ data numtab /0/ data recn_ /0/ data precn_ /0/ data posnam_ /0/ data posval_ /0/ data posdec_ /0/ data posend_ /0/ data pposnam_ /0/ data pposval_ /0/ data pposdec_ /0/ data pposend_ /0/ data quote_ /' '/ data pquote_ /' '/ data ibkmrk /MAXBOOK*-1,MAXBOOK*-1, * MAXBOOK*-1,MAXBOOK*-1/ end C C C change the following include to include 'clearfp_sun.f' C for use on a SUN C include 'clearfp.f' "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'ciftbx.f' ENDS TWO LINES BEFORE THIS ___________ if ( 125819 != `wc -c <'ciftbx.f'` ) then echo "cshar: 'ciftbx.f' unpacked with wrong size" endif # end of 'ciftbx.f' endif if ( -e 'ciftbx.sys' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'ciftbx.sys'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'ciftbx.sys' (12073 characters)" #___________ THE FILE 'ciftbx.sys' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'ciftbx.sys' <<"CUT_HERE_CUT_HERE_CUT_HERE" C C C >>>>>> Common declararations 'ciftbx.sys' C C For inclusion in 'ciftbx.f' C C Include all user common definitions, but not functions include 'ciftbx.cmv' C C Define parameters controlling the sizes of things C integer NUMDICT,NUMHASH,NUMBLOCK,NUMLOOP,NUMITEM,NUMIP1,MAXTAB, * MAXBOOK C C Number of entries in dictionary tables PARAMETER (NUMDICT=2500) C Number of hash table entries (a modest prime) PARAMETER (NUMHASH=53) C Number of entries in data block tables PARAMETER (NUMBLOCK=500) C Number of loops in a data block PARAMETER (NUMLOOP=50) C Number of items in a loop PARAMETER (NUMITEM=50) C Maximum number of tabs in output cif line PARAMETER (MAXTAB=10) C Maximum number of simultaneous bookmarks PARAMETER (MAXBOOK=1000) C C Derived value for loop arrays PARAMETER (NUMIP1=NUMITEM+1) C C Flag if test_ last called (yes/no ) character testfl*3 C Name of current data item character nametb*(NUMCHAR) C Tab character for this machine character tab*1 C Character buffer for reading lines character buffer*(MAXBUF) C Character buffer for tab-expanded lines character bufntb*(MAXBUF) C Dictionary validation check character vcheck*3 C Dictionary data type check character tcheck*3 C Dictionary flag character dictfl*3 C Dictionary names character dicnam(NUMDICT)*(NUMCHAR) C Dictionary names with upper/lower case character dictag(NUMDICT)*(NUMCHAR) C Dictionary data types character dictyp(NUMDICT)*4 C Data names in data block character dname(NUMBLOCK)*(NUMCHAR) C Data names in data block with u/l case character dtag(NUMBLOCK)*(NUMCHAR) C Data type of data item character dtype(NUMBLOCK)*4 C Flag signalling output CIF open character pfilef*3 C Flag signalling loop_ being loaded character ploopf*3 C Flag signalling text being loaded character ptextf*3 C Output string buffer character obuf*(MAXBUF) C Output prefix string character prefx*(MAXBUF) C Dictionary category names character dcname(NUMDICT)*(NUMCHAR) C Category names in use character cname(NUMBLOCK)*(NUMCHAR) C Dictionary extended types character dicxtyp(NUMDICT)*(NUMCHAR) C Datablock extended types character dxtyp(NUMBLOCK)*(NUMCHAR) C Format for single precision esd's character*13 esdfmt C Format for double precision esd's character*13 edpfmt C Format for writing double precision numbers character*8 ndpfmt C Record number containing data item integer drecd(NUMBLOCK) C Character position of item in record integer dchar(NUMBLOCK) C Record number containing tag of item integer trecd(NUMBLOCK) C Character position of tag of item in record integer tchar(NUMBLOCK) C Character position of tag of item in record C tab-expanded integer xchar(NUMBLOCK) C Loop block number (0 for non-loop) integer nloop(NUMBLOCK) C Item count in loop packet integer iloop(NUMBLOCK) C Loop line counter; initially zero integer lloop(NUMBLOCK) C Number of items per packet in each loop integer loopni(NUMLOOP) C Number of packets per loop integer loopnp(NUMLOOP) C Record number of loop header integer loorec(NUMLOOP) C Character position of loop header integer loopos(NUMLOOP) C Character position of loop header C tab-expanded integer loopox(NUMLOOP) C Number of last non-blank chars in input integer lastch C Number of items in current loop packet integer ploopc C Number of items in output loop packet integer ploopn C Number of current loop block integer loopnl C Count of packets in current loop integer loopct C Number of data names in hash table integer nhash C Number of data names in data block integer nname C Current number of data name in block integer iname C Number of dictionary names integer ndict C Number of records in CIF integer nrecd C Record number of requested line integer irecd C Record number of current line integer jrecd C Record number of tab-expanded line integer jrect C Last record number of current block integer lrecd C Character pointer of current input line integer jchar C Character pointer of output CIF line C next location to store integer pchar C Character pointer of output CIF line C last location stored integer pcharl C Number of data block names stored integer nbloc C Device number of input CIF integer cifdev C Device number of direct access file integer dirdev C Device number of error message file integer errdev C Device number of output CIF integer outdev C Cached copy of esdlim_ integer esdcac C Cached esd digits integer esddig C Number of Dictionary Category names stored integer ndcname C Bookmark data integer ibkmrk(4,MAXBOOK) C Indices of Dictionary Category C names for items integer dcindex(NUMDICT) C Hash Table for Dic. Category names integer dchash(NUMHASH) C Chain pointers for hash searches C of Dictionary Category names integer dcchain(NUMDICT) C Hash table for Dictionary name integer dichash(NUMHASH) C Chain pointers for hash search of C Dictionary names integer dicchain(NUMDICT) C Block hash table integer dhash(NUMHASH) C Category hash table integer chash(NUMHASH) C Chain pointers for hash search of C block names integer dchain(NUMBLOCK) C Chain pointers for hash search of C categories integer cchain(NUMBLOCK) C Number of Category names stored integer ncname C Character starting position of loop items integer loopch(NUMIP1) C String length of loop items integer loopln(NUMIP1) C Record number of loop items integer looprd(NUMIP1) C Indices of Category C names for items integer cindex(NUMBLOCK) C Dictionary pointer from data block integer ddict(NUMBLOCK) C Alias links, 0 for no alias or index C of item name in dicnam which C is the root of its definitions integer aroot(NUMDICT) C Alias links, 0 for no next alias or C index of next alias in dicnam integer alias(NUMDICT) C dcheck result from dicnam integer xdchk C minimum exponent for DP calculations integer minexp C length of output prefix string integer lprefx C Potential tabs in output line integer itabp(MAXTAB) C Count of potential tabs integer numtab C Returned number double precision numbtb C Returned standard deviation double precision sdevtb C Decimal double precision precision double precision dpprc C Decimal double precision minimum power of 10 double precision dpmin C Decimal single precision precision real decprc C Decimal single precision minimum power of 10 real decmin C Internal save of saveo_ logical psaveo C common/tbxc/ buffer,dname,dtype,tab,dicnam,dictag,dictyp, * dictfl,dtag,nametb,testfl,vcheck,tcheck,pfilef, * ploopf,ptextf,dcname,cname,dicxtyp,dxtyp,esdfmt, * edpfmt,ndpfmt,prefx,obuf,bufntb C common/tbxi/ nrecd,drecd,trecd,irecd,lrecd,dchar,tchar,xchar, * ndict,outdev,nloop,iloop,lloop,loopct,loopni, * loopnp,loopnl,nname,nhash,cifdev,dirdev,errdev, * jchar,pchar,iname,ploopn,ploopc,nbloc,jrecd, * lastch,esdcac,esddig,ndcname,dcindex,ncname, * cindex,aroot,alias,dchash,dcchain,dichash, * dicchain,dhash,dchain,ddict,xdchk,loopch,loopln, * looprd,minexp,lprefx,itabp,numtab,pcharl,loopos, * loopox,loorec,jrect,ibkmrk,chash,cchain C common/tbxdp/numbtb,sdevtb,dpprc,dpmin C common/tbxr/ decprc,decmin C common/tbxl/ psaveo C "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'ciftbx.sys' ENDS TWO LINES BEFORE THIS ___________ if ( 12073 != `wc -c <'ciftbx.sys'` ) then echo "cshar: 'ciftbx.sys' unpacked with wrong size" endif # end of 'ciftbx.sys' endif if ( -e 'clearfp.f' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'clearfp.f'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'clearfp.f' (383 characters)" #___________ THE FILE 'clearfp.f' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'clearfp.f' <<"CUT_HERE_CUT_HERE_CUT_HERE" subroutine clearfp C C This is a null version of a C subroutine to clear IEEE floating point exceptions C for inexact and underflow under SUN OS 4 f77 C For most other systems, no action is needed. C C character*1 out C ii = ieee_flags('clear','exception','underflow',out) C ii = ieee_flags('clear','execption','inexact',out) return end "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'clearfp.f' ENDS TWO LINES BEFORE THIS ___________ if ( 383 != `wc -c <'clearfp.f'` ) then echo "cshar: 'clearfp.f' unpacked with wrong size" endif # end of 'clearfp.f' endif if ( -e 'clearfp_sun.f' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'clearfp_sun.f'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'clearfp_sun.f' (298 characters)" #___________ THE FILE 'clearfp_sun.f' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'clearfp_sun.f' <<"CUT_HERE_CUT_HERE_CUT_HERE" subroutine clearfp C C subroutine to clear IEEE floating point exceptions C for inexact and underflow under SUN OS 4 f77 C character*1 out ii = ieee_flags('clear','exception','underflow',out) ii = ieee_flags('clear','execption','inexact',out) return end "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'clearfp_sun.f' ENDS TWO LINES BEFORE THIS ___________ if ( 298 != `wc -c <'clearfp_sun.f'` ) then echo "cshar: 'clearfp_sun.f' unpacked with wrong size" endif # end of 'clearfp_sun.f' endif if ( -e 'cryst1-2-cif.awk' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'cryst1-2-cif.awk'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'cryst1-2-cif.awk' (1788 characters)" #___________ THE FILE 'cryst1-2-cif.awk' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'cryst1-2-cif.awk' <<"CUT_HERE_CUT_HERE_CUT_HERE" # # cryst1-2-cif.awk # # simple awk script to convert a file with PDB CRYST1 records # to a CIF for input to iterate. Extracted from pdb2cif # by Bourne, Bernstein and Bernstein. See # http://ndbserver.rutgers.edu/software/pdb2cif # # Warning -- this script assumes the entry id is in columns 73-76 # If this is not true, then you make get a blank entry_id # BEGIN { printf ("\n data_cells\n\n loop_\n") printf ("_cell.entry_id\n") printf ("_cell.length_a\n") printf ("_cell.length_b\n") printf ("_cell.length_c\n") printf ("_cell.angle_alpha\n") printf ("_cell.angle_beta\n") printf ("_cell.angle_gamma\n") printf ("_cell.volume\n") printf ("_cell.Z_PDB\n") printf ("_cell.space_group_name_H-M # not defined in dictionary\n\n\n") } #========================================================================== # keyword CRYST1 # # { if ($1 == "CRYST1") { # # Contains a b c alpha beta gamma SG Z # # calculate cell volume { ca = cos(substr( ($0),34, 7) * 0.0174532) cb = cos(substr( ($0),41, 7) * 0.0174532) cc = cos(substr( ($0),48, 7) * 0.0174532) cz = (1.0 - (ca*ca - cb*cb - cc*cc) + (2.0*ca*cb*cc)) vol = (substr( ($0), 7, 9) *\ substr( ($0),16, 9) *\ substr( ($0),25, 9) * (sqrt(cz))) } # localize space group and Z { sg = substr( ($0), 56, 11) Z = substr( ($0), 67, 4 ) } if (vol-1 > .01) { printf (" %s",substr( ($0), 73, 4)) printf (" %9.3f", substr( ($0), 7, 9)) printf (" %9.3f", substr( ($0),16, 9)) printf (" %9.3f", substr( ($0),25, 9)) printf (" %7.2f", substr( ($0),34, 7)) printf (" %7.2f", substr( ($0),41, 7)) printf (" %7.2f\n", substr( ($0),48, 7)) printf (" %10.1f", vol) printf (" %3d ", Z) printf (" '%11s'\n", sg) } } } END {} "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'cryst1-2-cif.awk' ENDS TWO LINES BEFORE THIS ___________ if ( 1788 != `wc -c <'cryst1-2-cif.awk'` ) then echo "cshar: 'cryst1-2-cif.awk' unpacked with wrong size" endif # end of 'cryst1-2-cif.awk' endif if ( -e 'hash_funcs.f' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'hash_funcs.f'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'hash_funcs.f' (7064 characters)" #___________ THE FILE 'hash_funcs.f' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'hash_funcs.f' <<"CUT_HERE_CUT_HERE_CUT_HERE" C C hash_funcs.f -- a library of hash table management routines C C by C C Herbert J. Bernstein C Bernstein + Sons C P.O. Box 177, Bellport, NY 11713-0177, USA C Phone/Fax 1-516-286-1999 C email: yaya@aip.org C C work on these routines done in part at Brookhaven National C Laboratory, under contract to the U.S. Department of Energy C C------------------------------------------------------------------------------- C C Routines C C hash_init Initializes a hash table controlled list C call hash_init(data_structure_args) C C hash_find Searches for a string in a list C call hash_find(name,data_structure_args,ifind) C C hash_store Inserts as new string in a list C call hash_store(name,data_structure_args,ifind) C C hash_value Integer function returns index into hash_list C ih = hash_value(name,hash_length) C C The necessary data_structure_args for these routines are C name_list -- an array of character strings C character*(*) name_list(list_length) C chain_list -- chain pointers for searches C integer chain_list(list_length) C list_length -- the size of the list arrays C integer list_length C num_list -- number of entries in the list C integer num_list C hash_table -- the initial hashed pointers C integer hash_table C hash_length -- the size of the hash table C integer hash_length C C C The two remaining arguments are C name -- string to search for C character*(*) name C ifind -- return value, 0 for not found (hash_find) C or list full (hash_store), otherwise C the index in name_list of the entry C C The relationship among the arrays used is: C C hash_table is an array (preferably of a modest prime C dimension) which starts containing all zeros, which are C replaced by pointers to entries in name_list, based C values returned by hash_value ranging from 1 to hash_length. C Each name is placed in name_list. A initial zero is placed C in the matching entry in chain_list, when the first entry C is made. When a new entry with the same hash_value must be C placed a pointer is inserted into chain_list to hook the C values together. C subroutine hash_init(name_list,chain_list,list_length,num_list, * hash_table,hash_length) C C initialization routine for a hash table controlled list C name_list -- a list of character strings C chain_list -- chain pointers for searches C list_length -- the size of the list arrays C num_list -- number of entries in the list C hash_table -- the initial hashed pointers C hash_length -- the size of the hash table C character*(*) name_list(list_length) integer hash_length,list_length,num_list,i integer chain_list(list_length) integer hash_table(hash_length) num_list=0 do i = 1,hash_length hash_table(i)=0 enddo return end subroutine * hash_find(name,name_list,chain_list,list_length,num_list, * hash_table,hash_length,ifind) C C search routine for a hash table controlled list C name -- string to find C name_list -- a list of character strings C chain_list -- chain pointers for searches C list_length -- the size of the list arrays C num_list -- number of entries in the list C hash_table -- the initial hashed pointers C hash_length -- the size of the hash table C ifind -- returned index or 0 C character*(*) name integer hash_length character*(*) name_list(list_length) integer chain_list(list_length) integer hash_table(hash_length) integer hash_value integer ifind,list_length,num_list,ih,ip ifind=0 ih=hash_value(name,hash_length) ip=hash_table(ih) 100 if (ip.eq.0) return if (name_list(ip).eq.name) then ifind=ip return else ip=chain_list(ip) go to 100 endif end subroutine * hash_store(name,name_list,chain_list,list_length,num_list, * hash_table,hash_length,ifind) C C store routine for a hash table controlled list C name -- string to find C name_list -- a list of character strings C chain_list -- chain pointers for searches C list_length -- the size of the list arrays C num_list -- number of entries in list C hash_table -- the initial hashed pointers C hash_length -- the size of the hash table C ifind -- index of entry or 0 (table full) C character*(*) name character*(*) name_list(list_length) integer hash_length integer chain_list(list_length) integer hash_table(hash_length) integer hash_value integer ifind,list_length,num_list,ih,ip,iq ifind=0 ih = hash_value(name,hash_length) ip=hash_table(ih) iq=0 100 if (ip.eq.0) go to 200 if (name_list(ip).eq.name) then ifind=ip return else iq=ip ip=chain_list(ip) go to 100 endif 200 if (num_list.lt.list_length) then num_list=num_list+1 name_list(num_list)=name chain_list(num_list)=0 if (iq.eq.0) then hash_table(ih)=num_list else chain_list(iq)=num_list endif ifind=num_list return else ifind = 0 return endif end integer function hash_value(name,hash_length) C C function to return a hash value of string name to fit C a hash table of length hash_length character*(*) name integer hash_length,id,ii,i,ic,lenn lenn = len(name) hash_value=1 id = 0 do ii = 1,lenn i = 1+lenn-ii ic = ichar(name(i:i)) if (ic.ge.65) then hash_value=mod(hash_value*(ic-64),hash_length)+1 id = id+1 if (id.gt.3) return endif enddo return end "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'hash_funcs.f' ENDS TWO LINES BEFORE THIS ___________ if ( 7064 != `wc -c <'hash_funcs.f'` ) then echo "cshar: 'hash_funcs.f' unpacked with wrong size" endif # end of 'hash_funcs.f' endif if ( -e 'iterate.csh.m4' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'iterate.csh.m4'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'iterate.csh.m4' (1292 characters)" #___________ THE FILE 'iterate.csh.m4' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'iterate.csh.m4' <<"CUT_HERE_CUT_HERE_CUT_HERE" #!/bin/csh # iterate.csh # # Herbert J. Bernstein, Bernstein + Sons # Lawrence C. Andrews, Thuridion, Inc. # # 29 September 1996 # # This is a service script for the iterate.html web page # It must be placed in an appropriate cgi-bin directory on # the server pointed to by iterate.html # # # To operate correctly, the programs tr and sed must be in the # default path and the /bin/echo version of echo must follow # system V conventions sufficiently to produce an empty line # call, below # /bin/echo "Content-type: text/html" /bin/echo echo "" echo "G6 Lattice Identification" echo "" echo "" echo "" tr '\&' '\n' |sed "s/^./set &/" > /tmp/outstr$$ #cat /tmp/outstr$$ source /tmp/outstr$$ rm /tmp/outstr$$ echo "

# G6 Lattice Identification

" echo $Centering > /tmp/instr$$ echo "

# Centering: " $Centering echo $A $B $C $Alpha $Beta $Gamma >>/tmp/instr$$ echo "

# Cell: " $A $B $C $Alpha $Beta $Gamma echo $sigA $sigB $sigC $sigAlpha $sigBeta $sigGamma >>/tmp/instr$$ echo "

# Sigmas: " $sigA $sigB $sigC $sigAlpha $sigBeta $sigGamma echo "

# Results of ITERATE Run

" setenv ITERATE_QUERY NO setenv OUTPUT_STYLE $OutputStyle echo "
"
BINPATH() < /tmp/instr$$
rm /tmp/instr$$
#cat /tmp/instr$$ 
echo "
" echo "" "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'iterate.csh.m4' ENDS TWO LINES BEFORE THIS ___________ if ( 1292 != `wc -c <'iterate.csh.m4'` ) then echo "cshar: 'iterate.csh.m4' unpacked with wrong size" endif chmod +x 'iterate.csh.m4' # end of 'iterate.csh.m4' endif if ( -e 'iterate.f' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'iterate.f'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'iterate.f' (101777 characters)" #___________ THE FILE 'iterate.f' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'iterate.f' <<"CUT_HERE_CUT_HERE_CUT_HERE" C ITERATE -- Program for G6 Bravais Lattice Determination C C by C C Lawrence C. Andrews, Thuridion, Inc., C andrews@thuridion.com C C and C C Herbert J. Bernstein, Bernstein+Sons, C yaya@bernstein-plus-sons.com C C This program finds the cells which are "close" to the cell given, C in order to help find the Bravais lattice of highest symmetry C consistent with the cell. C C A central problem in the solution of every crystal structure C is to determine the correct Bravais lattice of the crystal. C The Bravais lattices as they are usually listed are: C C aP triclinic (anorthic) primitive C mP monoclinic primitive C mS monoclinic side-centered (usually C-centered) C oP orthorhombic primitive C oS orthorhombic side-centered C oF orthorhombic face-centered C oI orthorhombic body-centered C hP hexagonal primitive C hR hexagonal rhombohedrally-centered C tP tetragonal primitive C tI tetragonal body-centered C cP cubic primitive C cF cubic face-centered C cI cubic body-centered C C C Failure to find the highest correct symmetry has several consequences, C the worst of which is that the structure may not be solved. The C least of the consequences is that Richard Marsh may publish a paper C that points out the error, corrects it, and finds a better solution C to the structure. Many methods have been described for finding the C correct Bravais lattice. A summary of the published methods was C published in the paper that described the G6 formalism (which is used C in this program). C C "Lattices and Reduced Cells as Points in 6-Space and Selection of C Bravais Lattice Type by Projections", Lawrence C. Andrews and C Herbert J. Bernstein, Acta Crystallographica, A44, 1009-1018 (1988). C C This program accepts cell parameters and esd's and produces a list C of cells "close" to the cell given C C**********************************************************************C SUBROUTINE BADCAL (A,B) CHARACTER *6 A,B C----------------------------------------------------------------------C include 'ITERATE.cmn' WRITE (*,*) ' '//hm//' BAD SUBROUTINE CALL TO ',B WRITE (*,*) ' '//hm//' CALLING NAME =',A STOP END CC*********************************************************************** C SUBROUTINE CPYVN (N,V1,V2) C REAL V1(N),V2(N) C C----------------------------------------------------------------------- C DO 1000 I=1,N C 1000 V2(I) = V1(I) C END C*********************************************************************** subroutine bldprj (maxprj,nproj,itdesg,chrlat,pjn,prj,test) C This function builds the projectors of Paciorek and Bonin, J. Appl. C Cryst., 25, (5) pp 632-637. Internal checks of the correctness of C the projectors are made before it exits. C C The output values are just transferred from the stored parameters C in data statements. Note that if ngtype is negative, then the C projector is not output. This is because those are ones that C are easy to find later by searching. Either they are cases where C two projectors are exactly the same subspace (and therefore the C same projector) or else they are just simple exchange of axes C (which are dealt with in mkrefl in program iterate). If the routine C is extracted for other uses, then it may be correct to set the C values all positive. C maxprj sets the maximum number of projectors to build C nproj is the actual number that bldprj constructs C itdesg is the numeric designation of the Niggli type in the C International Tables for Crystallography C chrlat is the returned 2 character designators for the lattice C type (also call Pearson symbols) C pjn is the normalizer of the projector -- the integer values C stored in the returned matrix need to be divided by the C normalizer to make the actual projector C prj the integer part of the projector -- divide by the normalizer C (pjn) to get the actual projector include 'ITERATE.cmn' real pjn(maxprj) real prj(36,MAXPRJ) integer itdesg(maxprj) character *2 chrlat(maxprj) integer ngtype(42) real projct(36,42) real zprj(6,6,42) equivalence (projct,zprj) real pjnorm(42) character *2 lattyp(42) character *6 test data ngtype(1) /3/ data lattyp(1) /'cP'/ data pjnorm(1) /3./ data( projct(i,1),i=1,36) / 1 1,1,1,0,0,0, 2 1,1,1,0,0,0, 3 1,1,1,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,0 / data ngtype(2) /5/ data lattyp(2) /'cI'/ data pjnorm(2) /39./ data (projct(i,2),i=1,36) / 1 9, 9, 9,-6,-6,-6, 2 9, 9, 9,-6,-6,-6, 3 9, 9, 9,-6,-6,-6, 4 -6,-6,-6, 4, 4, 4, 5 -6,-6,-6, 4, 4, 4, 6 -6,-6,-6, 4, 4, 4 / data ngtype(3) /1/ data lattyp(3) /'cF'/ data pjnorm(3) /6./ data (projct(i,3),i=1,36) / 1 1,1,1,1,1,1, 2 1,1,1,1,1,1, 3 1,1,1,1,1,1, 4 1,1,1,1,1,1, 5 1,1,1,1,1,1, 6 1,1,1,1,1,1 / data ngtype(4) /11/ data lattyp(4) /'tP'/ data pjnorm(4) /2./ data (projct(i,4),i=1,36) / 1 1,1,0,0,0,0, 2 1,1,0,0,0,0, 3 0,0,2,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,0 / data ngtype(5) /-21/ data lattyp(5) /'tP'/ data pjnorm(5) /2./ data (projct(i,5),i=1,36) / 1 2,0,0,0,0,0, 2 0,1,1,0,0,0, 3 0,1,1,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,0 / data ngtype(6) /15/ data lattyp(6) /'tI'/ data pjnorm(6) /4./ data (projct(i,6),i=1,36) / 1 1, 1, 0,-1,-1, 0, 2 1, 1, 0,-1,-1, 0, 3 0, 0, 4, 0, 0, 0, 4 -1,-1, 0, 1, 1, 0, 5 -1,-1, 0, 1, 1, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(7) /6/ data lattyp(7) /'tI'/ data pjnorm(7) /26./ data (projct(i,7),i=1,36) / 1 6, 6, 6,-4,-4,-4, 2 6, 6, 6,-4,-4,-4, 3 6, 6, 6,-4,-4,-4, 4 -4,-4,-4, 7, 7,-6, 5 -4,-4,-4, 7, 7,-6, 6 -4,-4,-4,-6,-6,20 / data ngtype(8) /-7/ data lattyp(8) /'tI'/ data pjnorm(8) /26./ data (projct(i,8),i=1,36) / 1 6, 6, 6,-4,-4,-4, 2 6, 6, 6,-4,-4,-4, 3 6, 6, 6,-4,-4,-4, 4 -4,-4,-4,20,-6,-6, 5 -4,-4,-4,-6, 7, 7, 6 -4,-4,-4,-6, 7, 7 / data ngtype(9) /18/ data lattyp(9) /'tI'/ data pjnorm(9) /26./ data (projct(i,9),i=1,36) / 1 8, 0, 0, 4, 8, 8, 2 0,13,13, 0, 0, 0, 3 0,13,13, 0, 0, 0, 4 4, 0, 0, 2, 4, 4, 5 8, 0, 0, 4, 8, 8, 6 8, 0, 0, 4, 8, 8 / data ngtype(10) /12/ data lattyp(10) /'hP'/ data pjnorm(10) /3./ data (projct(i,10),i=1,36) / 1 1, 1, 0, 0, 0,-1, 2 1, 1, 0, 0, 0,-1, 3 0, 0, 3, 0, 0, 0, 4 0, 0, 0, 0, 0, 0, 5 0, 0, 0, 0, 0, 0, 6 -1,-1, 0, 0, 0, 1 / data ngtype(11) /-22/ data lattyp(11) /'hP'/ data pjnorm(11) /3./ data (projct(i,11),i=1,36) / 1 3, 0, 0, 0, 0, 0, 2 0, 1, 1,-1, 0, 0, 3 0, 1, 1,-1, 0, 0, 4 0,-1,-1, 1, 0, 0, 5 0, 0, 0, 0, 0, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(12) /9/ data lattyp(12) /'hR'/ data pjnorm(12) /5./ data (projct(i,12),i=1,36) / 1 1,1,0,1,1,1, 2 1,1,0,1,1,1, 3 0,0,5,0,0,0, 4 1,1,0,1,1,1, 5 1,1,0,1,1,1, 6 1,1,0,1,1,1 / data ngtype(13) /2/ data lattyp(13) /'hR'/ data pjnorm(13) /3./ data (projct(i,13),i=1,36) / 1 1,1,1,0,0,0, 2 1,1,1,0,0,0, 3 1,1,1,0,0,0, 4 0,0,0,1,1,1, 5 0,0,0,1,1,1, 6 0,0,0,1,1,1 / data ngtype(14) /-4/ data lattyp(14) /'hR'/ data pjnorm(14) /3./ data (projct(i,14),i=1,36) / 1 1,1,1,0,0,0, 2 1,1,1,0,0,0, 3 1,1,1,0,0,0, 4 0,0,0,1,1,1, 5 0,0,0,1,1,1, 6 0,0,0,1,1,1 / data ngtype(15) /24/ data lattyp(15) /'hR'/ data pjnorm(15) /53./ data (projct(i,15),i=1,36) / 1 27, 3, 3, 6,-18,-18, 2 3, 18, 18,-17, -2, -2, 3 3, 18, 18,-17, -2, -2, 4 6,-17,-17, 19, -4, -4, 5 -18, -2, -2, -4, 12, 12, 6 -18, -2, -2, -4, 12, 12 / data ngtype(16) /32/ data lattyp(16) /'oP'/ data pjnorm(16) /1./ data (projct(i,16),i=1,36) / 1 1,0,0,0,0,0, 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,0 / data ngtype(17) /36/ data lattyp(17) /'oS'/ data pjnorm(17) /2./ data (projct(i,17),i=1,36) / 1 1, 0, 0, 0,-1, 0, 2 0, 2, 0, 0, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0, 0, 0, 0, 0, 0, 5 -1, 0, 0, 0, 1, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(18) /-38/ data lattyp(18) /'oS'/ data pjnorm(18) /2./ data (projct(i,18),i=1,36) / 1 1, 0, 0, 0, 0,-1, 2 0, 2, 0, 0, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0, 0, 0, 0, 0, 0, 5 0, 0, 0, 0, 0, 0, 6 -1, 0, 0, 0, 0, 1 / data ngtype(19) /13/ data lattyp(19) /'oS'/ data pjnorm(19) /2./ data (projct(i,19),i=1,36) / 1 1,1,0,0,0,0, 2 1,1,0,0,0,0, 3 0,0,2,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,2 / data ngtype(20) /-23/ data lattyp(20) /'oS'/ data pjnorm(20) /2./ data (projct(i,20),i=1,36) / 1 2,0,0,0,0,0, 2 0,1,1,0,0,0, 3 0,1,1,0,0,0, 4 0,0,0,2,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,0 / data ngtype(21) /-40/ data lattyp(21) /'oS'/ data pjnorm(21) /2./ data (projct(i,21),i=1,36) / 1 2, 0, 0, 0, 0, 0, 2 0, 1, 0,-1, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0,-1, 0, 1, 0, 0, 5 0, 0, 0, 0, 0, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(22) /16/ data lattyp(22) /'oF'/ data pjnorm(22) /10./ data (projct(i,22),i=1,36) / 1 3, 3, 0,-2,-2,-2, 2 3, 3, 0,-2,-2,-2, 3 0, 0,10, 0, 0, 0, 4 -2,-2, 0, 3, 3,-2, 5 -2,-2, 0, 3, 3,-2, 6 -2,-2, 0,-2,-2, 8 / data ngtype(23) /26/ data lattyp(23) /'oF'/ data pjnorm(23) /13./ data (projct(i,23),i=1,36) / 1 4, 0, 0, 2, 4, 4, 2 0,13, 0, 0, 0, 0, 3 0, 0,13, 0, 0, 0, 4 2, 0, 0, 1, 2, 2, 5 4, 0, 0, 2, 4, 4, 6 4, 0, 0, 2, 4, 4 / data ngtype(24) /8/ data lattyp(24) /'oI'/ data pjnorm(24) /13./ data (projct(i,24),i=1,36) / 1 3, 3, 3,-2,-2,-2, 2 3, 3, 3,-2,-2,-2, 3 3, 3, 3,-2,-2,-2, 4 -2,-2,-2,10,-3,-3, 5 -2,-2,-2,-3,10,-3, 6 -2,-2,-2,-3,-3,10 / data ngtype(25) /19/ data lattyp(25) /'oI'/ data pjnorm(25) /6./ data (projct(i,25),i=1,36) / 1 2,0,0,0,2,2, 2 0,3,3,0,0,0, 3 0,3,3,0,0,0, 4 0,0,0,6,0,0, 5 2,0,0,0,2,2, 6 2,0,0,0,2,2 / data ngtype(26) /42/ data lattyp(26) /'oI'/ data pjnorm(26) /2./ data (projct(i,26),i=1,36) / 1 1, 0, 0, 0,-1, 0, 2 0, 1, 0,-1, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0,-1, 0, 1, 0, 0, 5 -1, 0, 0, 0, 1, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(27) /33/ data lattyp(27) /'mP'/ data pjnorm(27) /1./ data (projct(i,27),i=1,36) / 1 1,0,0,0,0,0, 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,1,0, 6 0,0,0,0,0,0 / data ngtype(28) /-35/ data lattyp(28) /'mP'/ data pjnorm(28) /1./ data (projct(i,28),i=1,36) / 1 1,0,0,0,0,0, 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 0,0,0,1,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,0 / data ngtype(29) /-34/ data lattyp(29) /'mP'/ data pjnorm(29) /1./ data (projct(i,29),i=1,36) / 1 1,0,0,0,0,0, 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 0,0,0,0,0,0, 5 0,0,0,0,0,0, 6 0,0,0,0,0,1 / data ngtype(30) /39/ data lattyp(30) /'mS'/ data pjnorm(30) /2./ data (projct(i,30),i=1,36) / 1 1, 0, 0, 0, 0,-1, 2 0, 2, 0, 0, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0, 0, 0, 2, 0, 0, 5 0, 0, 0, 0, 0, 0, 6 -1, 0, 0, 0, 0, 1 / data ngtype(31) /-41/ data lattyp(31) /'mS'/ data pjnorm(31) /2./ data (projct(i,31),i=1,36) / 1 2, 0, 0, 0, 0, 0, 2 0, 1, 0,-1, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0,-1, 0, 1, 0, 0, 5 0, 0, 0, 0, 2, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(32) /-37/ data lattyp(32) /'mS'/ data pjnorm(32) /2./ data (projct(i,32),i=1,36) / 1 1, 0, 0, 0,-1, 0, 2 0, 2, 0, 0, 0, 0, 3 0, 0, 2, 0, 0, 0, 4 0, 0, 0, 2, 0, 0, 5 -1, 0, 0, 0, 1, 0, 6 0, 0, 0, 0, 0, 0 / data ngtype(33) /10/ data lattyp(33) /'mS'/ data pjnorm(33) /2./ data (projct(i,33),i=1,36) / 1 1,1,0,0,0,0, 2 1,1,0,0,0,0, 3 0,0,2,0,0,0, 4 0,0,0,1,1,0, 5 0,0,0,1,1,0, 6 0,0,0,0,0,2 / data ngtype(34) /-14/ data lattyp(34) /'mS'/ data pjnorm(34) /2./ data (projct(i,34),i=1,36) / 1 1,1,0,0,0,0, 2 1,1,0,0,0,0, 3 0,0,2,0,0,0, 4 0,0,0,1,1,0, 5 0,0,0,1,1,0, 6 0,0,0,0,0,2 / data ngtype(35) /-20/ data lattyp(35) /'mS'/ data pjnorm(35) /2./ data (projct(i,35),i=1,36) / 1 2,0,0,0,0,0, 2 0,1,1,0,0,0, 3 0,1,1,0,0,0, 4 0,0,0,2,0,0, 5 0,0,0,0,1,1, 6 0,0,0,0,1,1 / data ngtype(36) /-25/ data lattyp(36) /'mS'/ data pjnorm(36) /2./ data (projct(i,36),i=1,36) / 1 2,0,0,0,0,0, 2 0,1,1,0,0,0, 3 0,1,1,0,0,0, 4 0,0,0,2,0,0, 5 0,0,0,0,1,1, 6 0,0,0,0,1,1 / data ngtype(37) /28/ data lattyp(37) /'mS'/ data pjnorm(37) /10./ data (projct(i,37),i=1,36) / 1 5, 0, 0, 0, 5, 0, 2 0,10, 0, 0, 0, 0, 3 0, 0,10, 0, 0, 0, 4 0, 0, 0, 2, 0, 4, 5 5, 0, 0, 0, 5, 0, 6 0, 0, 0, 4, 0, 8 / data ngtype(38) /-30/ data lattyp(38) /'mS'/ data pjnorm(38) /10./ data (projct(i,38),i=1,36) / 1 10, 0, 0, 0, 0, 0, 2 0, 5, 0, 5, 0, 0, 3 0, 0,10, 0, 0, 0, 4 0, 5, 0, 5, 0, 0, 5 0, 0, 0, 0, 2, 4, 6 0, 0, 0, 0, 4, 8 / data ngtype(39) /-29/ data lattyp(39) /'mS'/ data pjnorm(39) /10./ data (projct(i,39),i=1,36) / 1 5, 0, 0, 0, 0, 5, 2 0,10, 0, 0, 0, 0, 3 0, 0,10, 0, 0, 0, 4 0, 0, 0, 2, 4, 0, 5 0, 0, 0, 4, 8, 0, 6 5, 0, 0, 0, 0, 5 / data ngtype(40) /43/ data lattyp(40) /'mI'/ data pjnorm(40) /20./ data (projct(i,40),i=1,36) / 1 11, 1, 0, 1,-9,-4, 2 1,11, 0,-9, 1,-4, 3 0, 0,20, 0, 0, 0, 4 1,-9, 0,11, 1,-4, 5 -9, 1, 0, 1,11,-4, 6 -4,-4, 0,-4,-4,16 / data ngtype(41) /17/ data lattyp(41) /'mI'/ data pjnorm(41) /10./ data (projct(i,41),i=1,36) / 1 3, 3, 0,-2,-2,-2, 2 3, 3, 0,-2,-2,-2, 3 0, 0,10, 0, 0, 0, 4 -2,-2, 0, 8,-2,-2, 5 -2,-2, 0,-2, 8,-2, 6 -2,-2, 0,-2,-2, 8 / data ngtype(42) /27/ data lattyp(42) /'mI'/ data pjnorm(42) /3./ data (projct(i,42),i=1,36) / 1 1,0,0,0,1,1, 2 0,3,0,0,0,0, 3 0,0,3,0,0,0, 4 0,0,0,3,0,0, 5 1,0,0,0,1,1, 6 1,0,0,0,1,1 / C----------------------------------------------------------------------- nprob = 0 if (test .ne. 'BLDPRJ') then write (*,*) * ' '//hm//' test string was not BLDPRJ in that routine' stop endif C check the projectors for internal correctness do 4000 iproj=1,42 C there are only 42 niggli lattice types (ignoring triclinic) if (ngtype(iproj).gt.43) then write (*,*) * ' '//hm//' bad ngtype ',iproj,ngtype(iproj) nprob = nprob + 1 endif C check that the lattice type is present if (lattyp(iproj).eq.' ') then write (*,*) ' '//hm//' blank lattyp ',iproj nprob = nprob + 1 endif C check that the normalizers are in the range in Paciorek and Bonin if (pjnorm(iproj) .le. 0 .or. pjnorm(iproj).gt. 60) then write (*,*) ' '//hm//' bad pjnorm ',iproj,' ',pjnorm(iproj) nprob = nprob + 1 endif C check that the projectors are symmetrical matrices do 1000 i=1,5 do 1000 j=i+1,6 if (zprj(j,i,iproj) .ne. zprj(i,j,iproj)) then write (*,*) ' '//hm//' bad projector ',iproj,' ',i,' ',j write (*,*) zprj(j,i,iproj),' ',zprj(i,j,iproj) nprob = nprob + 1 endif 1000 continue do 2000 i=1,36 C check that the actual projector has no value greater than 1.0 if (abs(projct(i,iproj)/(pjnorm(iproj))).gt. 1.00001) then write (*,*) ' '//hm//' bad projector, value > 1.0 ' write (*,*) ' '//hm,iproj,' pjnorm ',pjnorm(iproj), 2 ' i ',i,' ',projct(i,iproj) write (*,*) nprob = nprob + 1 endif 2000 continue C check that the projector is positive definite do 3500 i=1,3 sum = 0.0 do 3000 j=1,6 sum = sum + abs(zprj(i,j,iproj)) 3000 continue if (sum .le. 0) then write (*,*) ' '//hm//' zero xyz row, ',iproj nprob = nprob + 1 endif 3500 continue 4000 continue C actually output the projectors NPROJ = 0 do 5100 i=1,MIN(MAXPRJ,42) IF (NGTYPE(I) .GT. 0) THEN NPROJ = NPROJ + 1 itdesg(NPROJ) = ngtype(i) chrlat(NPROJ) = lattyp(i) pjn(NPROJ) = pjnorm(i) do 5000 ii=1,36 prj(ii,nproj) = projct(ii,i) 5000 continue ENDIF 5100 continue if (nprob .gt. 0) then write (*,*) ' '//hm//' ', * nprob,' problems were found with projectors' stop endif itemp = projct(1,1) projct(1,1) = itemp end C**********************************************************************C SUBROUTINE BLDTRE (MXTREE,NVEC,X,IDIN,TREE,TEST) C BLDTRE is called once for each point to be loaded into its internal C data structure (TREE). It builds the tree structure of Kalantari C and McDonald (IEEE Transactions on Software Engineering, v. SE-9, C pp. 631-634,1983) for the extremely fast retrieval of coordinates. C MXTREE is the largest index that is allowed in the array TREE. C TREE must be the order of 9-10 times the number of points to be C included. C X is an input point's coordinates. C IDIN is an arbitrary integer input, which will often be an array C index to be retrieved later. BLDTRE does not examine IDIN. C TEST must be the string 'BLDTRE' -- it is used to make sure C that the number of formal parameters is correct. C TREE is used by NEARST and by INSPHR to find the nearest neighbor C to a probe point. To initialize (or reinitialize) a TREE, set C TREE(1) equal to 0.0 include 'ITERATE.cmn' CHARACTER*6 TEST LOGICAL DEBUG REAL TREE(MXTREE) INTEGER RMAX DATA LINK,RMAX,ID,ICHILD /1,2,3,4/ DATA DEBUG /.false./ C----------------------------------------------------------------------C IF (TEST .NE. 'BLDTRE' .AND. TEST .NE. 'bldtre') 2 CALL BADCAL (TEST,'BLDTRE') C THE NODE SIZE IS 4 PLUS THE SIZE OF THE VECTOR NODSIZ = 4+NVEC IPOINT = 2 IF (TREE(1) .GT. 0) THEN IFREE = TREE(1) ELSE IFREE = 2 ENDIF tree(ifree) = 0 1000 CONTINUE IF (DEBUG) WRITE (*,*) 2 ' '//hm//' AFTER 1000 IN BLDTRE, IPOINT,TREE(IPOINT) ', 3 IPOINT,TREE(IPOINT) IF (DEBUG) WRITE (*,*) ' '//hm//' IFREE,TREE(1),TREE(2) ', 2 IFREE,INT(TREE(1)),INT(TREE(2)) IF (TREE(IPOINT) .EQ. 0) THEN IF (DEBUG) WRITE (*,*) * ' '//hm//' A NEW NODE IS BEING ALLOCATED' IPOINT = IFREE TREE(IPOINT) = -1 TREE(IPOINT+LINK) = -1 TREE(IPOINT+ID) = IDIN CALL CPYVN (NVEC,X,TREE(IPOINT+ICHILD)) TREE(1) = IFREE + NODSIZ RETURN ELSEIF (TREE(IPOINT) .EQ. -1) THEN IF (DEBUG) WRITE (*,*) * ' '//hm//' RIGHT CHILD OF NODE IS BEING FILLED' TREE(IPOINT) = IFREE TREE(IFREE+LINK) = -1 TREE (IFREE+RMAX) = -1.0 TREE(IFREE+ID) = IDIN CALL CPYVN (NVEC,X,TREE(IFREE+ICHILD)) IFREE = IFREE + NODSIZ TREE(1) = IFREE RETURN ELSE IRIGHT = TREE(IPOINT) DL = TREELN (NVEC,X,TREE(IPOINT+ICHILD)) DR = TREELN (NVEC,X,TREE(IRIGHT+ICHILD)) IF (DEBUG) WRITE (*,*) ' '//hm//' DL,DR ',DL,DR IF (DR .GT. DL) THEN IF (DEBUG) WRITE (*,*) * ' '//hm//' ',DR,DL,IPOINT,LINK,RMAX IF (TREE(IPOINT+LINK) .LE. 0) THEN TREE(IPOINT+RMAX) = DL TREE(IPOINT+LINK) = IFREE IPOINT = IFREE ELSE TREE(IPOINT+RMAX) = 2 MAX(DL,TREE(IPOINT+RMAX)) IPOINT = TREE(IPOINT+LINK) ENDIF ELSE IF (TREE(IRIGHT+LINK) .LE. 0) THEN TREE(IRIGHT+RMAX) = DR TREE(IRIGHT+LINK) = IFREE IPOINT = IFREE ELSE TREE(IRIGHT+RMAX) = 2 MAX(DR,TREE(IRIGHT+RMAX)) IPOINT = TREE(IRIGHT+LINK) ENDIF ENDIF GO TO 1000 ENDIF END C*********************************************************************** SUBROUTINE CHKVEC(V) C Check that a g6 vector represents a valid cell. Currently, it only C checks that the cell edges are real include 'ITERATE.cmn' REAL V(6) C----------------------------------------------------------------------- NBAD = 0 DO 1000 I=1,3 IF(V(I).LE. 0.0) THEN WRITE (*,*) ' '//hm//' BAD VECTOR, I=',I,' ',V(I) NBAD = NBAD + 1 ENDIF 1000 CONTINUE IF (NBAD .GT. 0) STOP END C**********************************************************************C SUBROUTINE CPYVN (NVEC,X,Y) C----COPY A VECTOR X INTO A VECTOR Y DIMENSION X(NVEC), Y(NVEC) C----------------------------------------------------------------------C DO 1000 I=1,NVEC Y(I) = X(I) 1000 CONTINUE END C*********************************************************************** SUBROUTINE CTOG6 (CV,CVE,G,GE,SIZE,ERRSIZ,RATIO,TEST) C Convert from a unit cell (edge lengths and angles) to a g6 vector, C also computing the errors in the g6 vector. The length of the vector C and the error in the length of the vector is what iterate is really C going to use. include 'ITERATE.cmn' CHARACTER *6 TEST REAL COSI(4:6) REAL C(6),CV(6),CE(6),CVE(6),G(6),GE(6) C----------------------------------------------------------------------- IF (TEST .NE. 'CTOG6 ') THEN WRITE (*,*) ' '//hm//' TEST IS WRONG IN CTOG6' STOP ENDIF RAD = ATAN2(0.0,-1.0) / 180.0 DO 1000 I=1,6 C(I) = CV(I) CE(I) = CVE(I) 1000 CONTINUE DO 1100 I=4,6 C(I) = C(I) * RAD CE(I) = CE(I) * RAD 1100 CONTINUE DO 1500 I=1,3 J = I + 3 G(I) = C(I)*C(I) COSI(J) = COS(C(J)) IF (C(I).NE.0.0) THEN G(J)=2.0*C(1)*C(2)*C(3)*COSI(J)/C(I) ELSE G(J) = 0.0 ENDIF GE(I) = 2.*ABS(C(I)*CE(I)) C WRITE (*,*) ' '//hm//' GE(I) ',I,' ',GE(I) 1500 CONTINUE DO 2000 I=1,3 J = I + 3 IF (J.EQ.4) THEN I1 = 2 I2 = 3 ELSEIF (J.EQ.5) THEN I1 = 1 I2 = 3 ELSE I1 = 1 I2 = 2 ENDIF GE(J) = 2.0*SQRT(G(I1)*(COSI(J)*CE(I2))**2 + 2 G(I2)*(COSI(J)*CE(I1))**2 + 3 G(I1)*G(I2)*(SIN(C(J))*CE(J))**2) C C NOTE THE UNITS IMBALANCE ABOVE C C WRITE (*,*) ' '//hm//' GE(J) ',J,' ',GE(J) 2000 CONTINUE SIZE = 0.0 ERRSIZ = 0.0 DO 3000 I=1,6 SIZE = SIZE + G(I)*G(I) ERRSIZ = ERRSIZ + GE(I)*GE(I) 3000 CONTINUE SIZE = SQRT(SIZE) ERRSIZ = SQRT(ERRSIZ) RATIO = ERRSIZ / SIZE END C*********************************************************************** FUNCTION DOTVN (N,V1,V2) C compute a dot product REAL V1(N),V2(N) C----------------------------------------------------------------------- DOTVN = 0.0 DO 1000 I=1,N DOTVN = DOTVN + V1(I)*V2(I) 1000 CONTINUE END C*********************************************************************** SUBROUTINE DRMV6 (V1,M,V2) REAL V1(6),V2(6) REAL M(36) DOUBLE PRECISION SUM C----------------------------------------------------------------------- DO 3000 I=1,6 SUM = 0.0D0 DO 2000 J=1,6 SUM = SUM + DBLE(M(6*(I-1)+J))*DBLE(V1(J)) 2000 CONTINUE V2(I) = SUM 3000 CONTINUE END C*********************************************************************** logical function G6TOC (G,C,TEST) C compute the normal unit cell parameters from a given g6 vector include 'ITERATE.cmn' CHARACTER *6 TEST REAL G(6),C(6) C----------------------------------------------------------------------- IF (TEST .NE. 'G6TOC ') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN G6TOC' STOP ENDIF g6toc = .true. DO 900 I=1,3 IF (G(I) .LE. 0.0) THEN WRITE (*,*) ' '//hm//' G(I)<=0, I=',I,' ',G(I) g6toc = .false. ENDIF 900 CONTINUE DO 1000 I=1,3 1000 C(I) = SQRT(G(I)) AC = 0.5*G(4)/C(2)/C(3) IF (ABS(AC) .LE. 1.0) THEN C(4) = 57.296*ACOS(AC) ELSE C(4) = 0.0 WRITE (*,*) ' '//hm//' ARG>1.0 C(4) ',AC,1.0-ABS(AC) g6toc = .false. ENDIF AC = 0.5*G(5)/C(1)/C(3) IF (ABS(AC) .LE. 1.0) THEN C(5) = 57.296*ACOS(AC) ELSE C(5) = 0.0 WRITE (*,*) ' '//hm//' ARG>1.0 C(5) ',AC,1.0-ABS(AC) g6toc = .false. ENDIF AC = 0.5*G(6)/C(1)/C(2) IF (ABS(AC) .LE. 1.0) THEN C(6) = 57.296*ACOS(AC) ELSE C(6) = 0.0 WRITE (*,*) ' '//hm//' ARG>1.0 C(6) ',AC,1.0-ABS(AC) g6toc = .false. ENDIF END C*********************************************************************** subroutine g6tor3 (g6,m3) C compute the normal unit cell parameters from a given g6 vector include 'ITERATE.cmn' logical pcmnt_ integer i,j real g6(6,6),m3(3,3) C----------------------------------------------------------------------- do 2000 i=1,3 do 1000 j=1,3 if (g6(i,j) .lt. -1.0e-6) then if (ostyle.ne.'CIF ') then write (*,*) * ' '//hm//' negative element in upper left of g6' else cifres=pcmnt_(' negative square in g6 matrix') endif elseif (g6(i,j) .lt. 1.0e-6) then m3(i,j) = 0.0 else m3(i,j) = sqrt(g6(i,j)) endif 1000 continue 2000 continue do 3000 i=1,3 call gtr3sn(m3(i,1),m3(i,2),m3(i,3), g6(i,4),g6(i,5),g6(i,6)) 3000 continue if (abs(g6(5,5)) .gt. 1.0e-6) then if (g6(5,5)*(m3(1,1)*m3(3,3)+m3(1,3)*m3(3,1)) .lt. 0.0) then do 4000 i= 1,3 m3(3,i) = -m3(3,i) 4000 continue endif elseif (abs(g6(5,4)) .gt. 1.0e-6) then if (g6(5,4)*(m3(1,2)*m3(3,3)+m3(1,3)*m3(3,2)) .lt. 0.0) then do 4100 i= 1,3 m3(3,i) = -m3(3,i) 4100 continue endif elseif (abs(g6(5,6)) .gt. 1.0e-6) then if (g6(5,6)*(m3(1,1)*m3(3,2)+m3(1,2)*m3(3,1)) .lt. 0.0) then do 4200 i= 1,3 m3(3,i) = -m3(3,i) 4200 continue endif endif if (abs(g6(6,6)) .gt. 1.0e-6) then if (g6(6,6)*(m3(1,1)*m3(2,2)+m3(1,2)*m3(2,1)) .lt. 0.0) then do 5000 i= 1,3 m3(2,i) = -m3(2,i) 5000 continue endif elseif (abs(g6(6,5)) .gt. 1.0e-6) then if (g6(6,5)*(m3(1,1)*m3(2,3)+m3(1,3)*m3(2,1)) .lt. 0.0) then do 5100 i= 1,3 m3(2,i) = -m3(2,i) 5100 continue endif elseif (abs(g6(6,4)) .gt. 0.0) then if (g6(6,4)*(m3(1,2)*m3(2,3)+m3(1,3)*m3(2,2)) .lt. 0.0) then do 5200 i= 1,3 m3(2,i) = -m3(2,i) 5200 continue endif endif end subroutine gtr3sn(e1,e2,e3, g4,g5,g6) if (e1 .ne. 0.0) then e2 = unitsn(g6)*e2 e3 = unitsn(g5)*e3 elseif (e3 .ne. 0.0) then e3 = unitsn(g4)*e3 endif end C*********************************************************************** LOGICAL FUNCTION INPCEL (LATSYM,CV,CE,eof) C get the input lattice type, cell, and errors in the cell parameters include 'ITERATE.cmn' logical char_ logical numb_ EXTERNAL OKCELL LOGICAL OKCELL CHARACTER *1 LATSYM REAL CV(6),CE(6) logical eof C----------------------------------------------------------------------- eof = .false. inpcel = .true. cifeid = '.' cifsgs = 'P' 1000 CONTINUE IF (querst.ne.'NO') * WRITE (*,*) ' '//hm//' Input Xtal Lattice Centering ' if (istyle.ne.'CIF ') then READ (*,'(A1)',end=9000) LATSYM else cifres = char_('_cell.entry_id',cifeid) if (.not.cifres) cifeid = '.' cifres = char_('_cell.space_group_name_H-M',cifsgs) LATSYM = 'P' if(cifres) LATSYM=cifsgs(1:1) if(cifsgs.eq.' ') cifsgs = 'P' endif IF (LATSYM .GE. 'a' .AND. LATSYM .LE. 'z') 2 LATSYM = CHAR(ICHAR(LATSYM)-ICHAR('a')+ICHAR('A')) IF (querst.ne.'NO') * WRITE (*,*) ' '//hm//' Input Cell Parameters' if (istyle.ne.'CIF ') then READ (*,*,end=9000) CV else do ii = 1,6 CE(II) = 0. enddo cifres = numb_('_cell.length_a',cv(1),ce(1)) if (.not.cifres) goto 9000 cifres = numb_('_cell.length_b',cv(2),ce(2)) cifres = numb_('_cell.length_c',cv(3),ce(3)) cifres = numb_('_cell.angle_alpha',cv(4),ce(4)) cifres = numb_('_cell.angle_beta',cv(5),ce(5)) cifres = numb_('_cell.angle_gamma',cv(6),ce(6)) endif INPCEL = OKCELL(LATSYM,CV,' TALK') IF (.NOT. INPCEL) GO TO 1000 IF (querst.ne.'NO') * WRITE (*,*) * ' '//hm//' Input Standard Deviations of Cell Parameters' if (istyle.ne.'CIF ') then READ (*,*,end=9000) CE endif DO II = 1,6 CE(II) = MAX(CE(II),ABS(CV(II))*5.E-7,1.E-4) ENDDO return 9000 eof=.true. inpcel = .false. END C**********************************************************************C FUNCTION INSPHR (MXTREE,NVEC,X,RADMAX,TREE, 2 MXLIST,NLIST,LIST,IDLIST,TEST) C After the TREE has been constructed using BLDTRE, C INSPHR is used to retrieve all of the points within C RADMAX of the point X. MXTREE is the maximum size of C TREE. The indices of the found points are returned in C the array LIST; NLIST are returned, up to a maximum of C MXLIST. For instance, TREE(LIST(3)) is the vector of C the third point found in the list. IDLIST contains the C corresponding list of the input ID's. If no points are C found within RADMAX of X, then INSPHR and NLIST are C returned as 0; otherwise they are returned as the C number of points found. If more than MXLIST points were C found, then NLIST is returned equal to MXLIST, and C INSPHR is returned equal to -MXLIST. TEST must be the C string 'INSPHR'. C See also BLDTRE and NEARST. include 'ITERATE.cmn' CHARACTER*6 TEST LOGICAL DEBUG INTEGER ISTAK(1000) REAL TREE(MXTREE) INTEGER LIST(MXLIST),IDLIST(MXLIST) INTEGER RMAX DATA DEBUG /.FALSE./ DATA LINK,RMAX,ID,ICHILD /1,2,3,4/ DATA RIGHT,LEFT,END /111,112,113/ C----------------------------------------------------------------------C IF (TEST .NE. 'INSPHR' .AND. TEST .NE. 'insphr') 2 CALL BADCAL (TEST,'INSPHR') ISTKP = 0 NLIST = 0 IPOINT = 2 CURMIN = RADMAX DIR = LEFT DIRPRV = RIGHT IPREV = IPOINT -1 if (tree(1).le.0.0) go to 8000 1000 CONTINUE IF (IPREV .EQ. IPOINT .AND. DIRPRV .EQ. DIR) THEN WRITE (*,*) ' '//hm//' INTERNAL ERROR IN INSPHR ' WRITE (*,*) * ' '//hm//' TREE POINTER DIDN''T CHANGE',IPOINT,' ',DIR STOP ELSEIF (IPOINT .EQ. 0) THEN WRITE (*,*) * ' '//hm//' INTERNAL ERROR IN INSPHR, IPOINT = 0' STOP ENDIF IPREV = IPOINT DIRPRV = DIR IF (DEBUG) WRITE (*,*) * ' '//hm//' IN INSPHR 1000, IPOINT = ',IPOINT IF (TREE(IPOINT) .EQ. 0) THEN IF (DEBUG) WRITE (*,*) * ' '//hm//' AT AN END WITH IPOINT = ',IPOINT DIR = END ELSEIF (DIR .EQ. RIGHT) THEN IRIGHT = TREE(IPOINT) IF (DEBUG) WRITE (*,*) * ' '//hm//' WENT RIGHT WITH IPOINT ', IPOINT DR = TREELN (NVEC,TREE(IRIGHT+ICHILD),X) IF (DR .LT. CURMIN) THEN NLIST = NLIST + 1 IF (NLIST .GT. MXLIST) GO TO 8000 LIST(NLIST) = IRIGHT + ICHILD IDLIST(NLIST) = TREE(IRIGHT+ID) ENDIF IF (TREE(IRIGHT+LINK) .LE. 0) THEN IF (DEBUG) WRITE (*,*) * ' '//hm//' ON RIGHT BRANCH, UNSTACK A POINT' DIR = END ELSEIF (TREE(IRIGHT+RMAX)+CURMIN .GT. DR) THEN IPOINT = TREE(IRIGHT+LINK) DIR = LEFT ELSE DIR = END ENDIF ELSE IF (DEBUG) WRITE (*,*) ' '//hm//' WENT LEFT, IPOINT ',IPOINT DIR = LEFT IF (TREE(IPOINT) .GT. 0) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' STACK ONE ' CALL TRSTCK (IPOINT,ISTAK,ISTKP) ENDIF DL = TREELN (NVEC,TREE(IPOINT+ICHILD),X) IF (DL .LT. CURMIN) THEN NLIST = NLIST + 1 IF (NLIST .GT. MXLIST) GO TO 8000 LIST(NLIST) = IPOINT+ICHILD IDLIST(NLIST) = TREE(IPOINT+ID) ENDIF IF (TREE(IPOINT+LINK) .LE. 0) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' NO LEFT LINK, GO BACK' DIR = END ELSEIF (TREE(IPOINT+RMAX) .LT. 0.0) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' NO DESCENDING LEFT TREE' DIR = END ELSEIF (TREE(IPOINT+RMAX)+CURMIN .GT. DL) THEN IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' GOING TO GO DOWN ONE LEVEL ', 3 ' IPOINT AND UPDATE ',IPOINT,' ',INT(TREE(IPOINT+LINK)) IPOINT = TREE(IPOINT+LINK) ELSE IF (DEBUG) WRITE (*,*) ' '//hm//' NO CLOSER POINTS ON LEFT ' IF (DEBUG) WRITE (*,*) ' '//hm//' CURMIN,TREE(IPOINT+RMAX), 2 DL ',CURMIN,TREE(IPOINT+RMAX),DL DIR = END ENDIF ENDIF IF (DIR .EQ. END) THEN IF (IUNSTK(IPOINT,ISTAK,ISTKP) .LE. 0) GO TO 8000 DIR = RIGHT ENDIF GO TO 1000 8000 CONTINUE IF (NLIST .LE. MXLIST) THEN INSPHR = NLIST ELSE INSPHR = -MXLIST NLIST = MXLIST ENDIF END C**********************************************************************C FUNCTION IUNSTK(NEXT,ISTAK,ISTKP) C helper function for INSPHR and NEARST include 'ITERATE.cmn' INTEGER ISTAK(1000) LOGICAL DEBUG DATA DEBUG /.FALSE./ C----------------------------------------------------------------------C IF (DEBUG) WRITE (*,*) ' '//hm//' IUNSTK,NEXT ',NEXT IF (ISTKP .GT. 0) THEN NEXT = ISTAK(ISTKP) ISTKP = ISTKP-1 ELSE NEXT = 0 ENDIF IUNSTK = NEXT END C*********************************************************************** SUBROUTINE MKNORM (VI,Mnorm,VOUT,TEST) C converts an input g6 vector to "normalized" form (Gruber's C terminology) or "standard presentation" (Andrews and Bernstein's C terminology) and the corresponding transformation matrix include 'ITERATE.cmn' CHARACTER *6 TEST REAL VIN(6),VI(6),VOUT(6) real Mnorm(36),MAT(36),M1(36),MAT3(9) LOGICAL AGAIN C----------------------------------------------------------------------- IF (TEST .NE. 'MKNORM') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN MKNORM' STOP ENDIF CALL CPYVN(6,VI,VIN) CALL RUNTMN(6,Mnorm) NCYCLE = 0 1000 CONTINUE NCYCLE = NCYCLE + 1 AGAIN =.FALSE. CALL ZEROS (36,MAT) IF ( (ABS(VIN(1)).GT.ABS(VIN(2))) .OR. 2 (VIN(1).EQ.VIN(2) .AND. ABS(VIN(4)).GT.ABS(VIN(5))) ) THEN MAT(2) = 1 MAT(7) = 1 MAT(15) = 1 MAT(23) = 1 MAT(28) = 1 MAT(36) = 1 AGAIN = .TRUE. ELSEIF ( (ABS(VIN(2)).GT.ABS(VIN(3))) .OR. 2 (VIN(2).EQ.VIN(3) .AND. ABS(VIN(5)).GT.ABS(VIN(6))) ) THEN MAT(1) = 1 MAT(14) = 1 MAT(9) = 1 MAT(22) = 1 MAT(35) = 1 MAT(30) = 1 AGAIN = .TRUE. ENDIF IF (AGAIN) THEN CALL mm6(MAT,Mnorm,M1) CALL CPYVN(36,M1,Mnorm) CALL RMV6(VIN,MAT,VOUT) CALL CPYVN(6,VOUT,VIN) ENDIF IF (AGAIN .AND. NCYCLE.LT.4) GO TO 1000 NUMNEG = 0 DO 2000 I=4,6 IF (VIN(I).LT.0.0) NUMNEG = NUMNEG + 1 2000 CONTINUE CALL RUNTMN(3,MAT3) DO 4000 I=4,6 IF (NUMNEG.EQ.1) THEN IF(VIN(I).GE.0.) MAT(3*(I-4)+I-3) = -1. C MAT(6*(I-1)+I) = -SIGN(1.0,VIN(I)) ELSEIF (NUMNEG.EQ.2) THEN IF(VIN(I).LT.0.) MAT(3*(I-4)+I-3) = -1. C MAT(6*(I-1)+I) = SIGN(1.0,VIN(I)) ENDIF 4000 CONTINUE call r3tog6(MAT3,MAT) CALL mm6(MAT,Mnorm,M1) CALL CPYVN(36,M1,Mnorm) CALL RMV6(VIN,MAT,VOUT) CALL CPYVN(6,VOUT,VIN) END C*********************************************************************** SUBROUTINE MKPRIM (LATSYM,GIN,M,GOUT,TEST) C converts and input g6 vector to one corresponding to a primitive C lattice and the corresponding transformation matrix include 'ITERATE.cmn' CHARACTER *6 TEST CHARACTER LATSYM REAL GIN(6),GOUT(6) REAL M(36) C----------------------------------------------------------------------- IF (TEST .NE. 'MKPRIM') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN MKPRIM' STOP ENDIF CALL ZEROS (36,M) IF (LATSYM .EQ. 'P') THEN CALL RUNTMN(6,M) ELSEIF (LATSYM .EQ. 'I') THEN M(1) = 1 M(8) = 1 DO 1000 I=13,18 1000 M(I) = 0.25 M(20) = 1 M(22) = 0.5 M(24) = 0.5 M(25) = 1 M(29) = 0.5 M(30) = 0.5 M(36) = 1 ELSEIF (LATSYM .EQ. 'F') THEN M(1) = 0.25 M(2) = 0.25 M(6) = 0.25 M(7) = 0.25 M(9) = 0.25 M(11) = 0.25 M(14) = 0.25 M(15) = 0.25 M(16) = 0.25 M(21) = 0.5 DO 2000 I=22,24 2000 M(I)= 0.25 M(26) = 0.5 DO 2100 I=28,30 2100 M(I) = 0.25 M(31) = 0.5 DO 2200 I=34,36 2200 M(I) = 0.25 ELSEIF (LATSYM .EQ. 'A') THEN M(1) = 1 M(8) = 1 M(14) = 0.25 M(15) = 0.25 M(16) = 0.25 M(20) = 1 M(22) = 0.5 M(29) = 0.5 M(30) = 0.5 M(36) = 1 ELSEIF (LATSYM .EQ. 'B') THEN M(1) = 1 M(8) = 1 M(13) = 0.25 M(15) = 0.25 M(17) = 0.25 M(22) = 0.5 M(24) = 0.5 M(25) = 1 M(29) = 0.5 M(36) = 1 ELSEIF (LATSYM .EQ. 'C') THEN M(1) = 1 M(7) = 0.25 M(8) = 0.25 M(12) = 0.25 M(15) = 1 M(22) = 0.5 M(23) = 0.5 M(29) = 1 M(31) = 1 M(36) = 0.5 ELSEIF (LATSYM .EQ. 'R') THEN DO 2300 I=1,36 2300 M(I) = 1./9. M(1) = 4./9. M(5) = 2./9. M(6) = 2./9. M(11) = -1./9. M(12) = -1./9. M(14) = 4./9. M(16) = -2./9. M(17) = -1./9. M(18) = 2./9. M(19) = 2./9. M(20) = -4./9. M(21) = 2./9. M(22) = -1./9. M(23) = -2./9. M(25) = -4./9. M(26) = -4./9. M(27) = 2./9. M(28) = -1./9. M(30) = -5./9. M(31) = -4./9. M(32) = 2./9. M(33) = 2./9. M(34) = 2./9. ELSE WRITE (*,*) ' '//hm//' DID NOT FIND LATTICE SYMBOL ',LATSYM STOP ENDIF CALL RMV6(GIN,M,GOUT) END C CALL MKREFL (RATIO,MXTREE,TREE,NVMAX,V,MATREF,NV,GRED,'MKREFL') C*********************************************************************** SUBROUTINE mm6(M1,M2,M3) SUBROUTINE MKREFL 2 (DEBUG,RATIO,MXTREE,TREE,NVMAX,V,MATREF,NV,GRED,TEST) C MKREFL performs the iterations to search out the various C representations of a single lattice by a set of different unit cells. C There are many ways to do this iteration, and this one may well C not be optimal. It has been found to work well in practice as long C as cutoffs are not too strict. It is clear that, in general, it does C not find all of the possible unit cells within a particular radius C in g6. include 'ITERATE.cmn' PARAMETER (MXSWTC=2) CHARACTER *6 TEST REAL TREE(MXTREE), V(6,NVMAX), GRED(6) REAL VT(6),VTT(6) real mt2k(36),mti2k(36),mt1k(36) real REFL(36,24) real SWTCH(36,MXSWTC) real MATREF(36,NVMAX) LOGICAL DEBUG C----------------------------------------------------------------------- DATA (SWTCH(I,1),I=1,36)/ 1 1,0,0, 0,0,0, 2 0,1,0, 0,0,0, 3 1,0,1, 0,1,0, 4 0,0,0, 1,0,1, 5 2,0,0, 0,1,0, 6 0,0,0, 0,0,1 / DATA (SWTCH(I,2),I=1,36)/ 1 1,0,0, 0,0,0, 2 0,1,0, 0,0,0, 3 1,1,1, 1,1,1, 4 0,2,0, 1,0,1, 5 2,0,0, 0,1,1, 6 0,0,0, 0,0,1 / DATA (REFL(I,1),I=1,36) / 2 1,0,0,0,0,0, 3 0,1,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,1,0,0, 6 0,0,0,0,1,0, 7 0,0,0,0,0,1 / DATA (REFL(I,2),I=1,36) / 2 1,0,0,0,0,0, 3 0,1,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,-1,0,0, 6 0,0,0,0,-1,0, 7 0,0,0,0,0,1 / DATA (REFL(I,3),I=1,36) / 2 1,0,0,0,0,0, 3 0,1,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,1,0,0, 6 0,0,0,0,-1,0, 7 0,0,0,0,0,-1 / DATA (REFL(I,4),I=1,36) / 2 1,0,0,0,0,0, 3 0,1,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,-1,0,0, 6 0,0,0,0,1,0, 7 0,0,0,0,0,-1 / DATA (REFL(I,5),I=1,36) / 2 0,1,0,0,0,0, 3 1,0,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,0,1,0, 6 0,0,0,1,0,0, 7 0,0,0,0,0,1 / DATA (REFL(I,6),I=1,36) / 2 0,1,0,0,0,0, 3 1,0,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,0,-1,0, 6 0,0,0,-1,0,0, 7 0,0,0,0,0,1 / DATA (REFL(I,7),I=1,36) / 2 0,1,0,0,0,0, 3 1,0,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,0,-1,0, 6 0,0,0,1,0,0, 7 0,0,0,0,0,-1 / DATA (REFL(I,8),I=1,36) / 2 0,1,0,0,0,0, 3 1,0,0,0,0,0, 4 0,0,1,0,0,0, 5 0,0,0,0,1,0, 6 0,0,0,-1,0,0, 7 0,0,0,0,0,-1 / DATA (REFL(I,9),I=1,36) / 2 1,0,0,0,0,0, 3 0,0,1,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,1,0,0, 6 0,0,0,0,0,1, 7 0,0,0,0,1,0 / DATA (REFL(I,10),I=1,36) / 2 1,0,0,0,0,0, 3 0,0,1,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,-1,0,0, 6 0,0,0,0,0,-1, 7 0,0,0,0,1,0 / DATA (REFL(I,11),I=1,36) / 2 1,0,0,0,0,0, 3 0,0,1,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,-1,0,0, 6 0,0,0,0,0,1, 7 0,0,0,0,-1,0 / DATA (REFL(I,12),I=1,36) / 2 1,0,0,0,0,0, 3 0,0,1,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,1,0,0, 6 0,0,0,0,0,-1, 7 0,0,0,0,-1,0 / DATA (REFL(I,13),I=1,36) / 2 0,0,1,0,0,0, 3 0,1,0,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,0,1, 6 0,0,0,0,1,0, 7 0,0,0,1,0,0 / DATA (REFL(I,14),I=1,36) / 2 0,0,1,0,0,0, 3 0,1,0,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,0,-1, 6 0,0,0,0,-1,0, 7 0,0,0,1,0,0 / DATA (REFL(I,15),I=1,36) / 2 0,0,1,0,0,0, 3 0,1,0,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,0,-1, 6 0,0,0,0,1,0, 7 0,0,0,-1,0,0 / DATA (REFL(I,16),I=1,36) / 2 0,0,1,0,0,0, 3 0,1,0,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,0,1, 6 0,0,0,0,-1,0, 7 0,0,0,-1,0,0 / DATA (REFL(I,17),I=1,36) / 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,1,0, 6 0,0,0,0,0,1, 7 0,0,0,1,0,0 / DATA (REFL(I,18),I=1,36) / 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,-1,0, 6 0,0,0,0,0,-1, 7 0,0,0,1,0,0 / DATA (REFL(I,19),I=1,36) / 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,-1,0, 6 0,0,0,0,0,1, 7 0,0,0,-1,0,0 / DATA (REFL(I,20),I=1,36) / 2 0,1,0,0,0,0, 3 0,0,1,0,0,0, 4 1,0,0,0,0,0, 5 0,0,0,0,1,0, 6 0,0,0,0,0,-1, 7 0,0,0,-1,0,0 / DATA (REFL(I,21),I=1,36) / 2 0,0,1,0,0,0, 3 1,0,0,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,0,0,1, 6 0,0,0,1,0,0, 7 0,0,0,0,1,0 / DATA (REFL(I,22),I=1,36) / 2 0,0,1,0,0,0, 3 1,0,0,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,0,0,-1, 6 0,0,0,-1,0,0, 7 0,0,0,0,1,0 / DATA (REFL(I,23),I=1,36) / 2 0,0,1,0,0,0, 3 1,0,0,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,0,0,-1, 6 0,0,0,1,0,0, 7 0,0,0,0,-1,0 / DATA (REFL(I,24),I=1,36) / 2 0,0,1,0,0,0, 3 1,0,0,0,0,0, 4 0,1,0,0,0,0, 5 0,0,0,0,0,1, 6 0,0,0,-1,0,0, 7 0,0,0,0,-1,0 / IF (TEST .NE. 'MKREFL') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN MKREFL' STOP ENDIF TREE(1) = 0 TREE(2) = 0 NV = 0 DMIN = 0.1*SQRT(DOTVN(6,GRED,GRED))*RATIO GRMIN = GRED(1)**2+GRED(2)**2+GRED(3)**2 DO 4000 ICYCLE=1,MXSWTC+1 DO 2000 IREFL=1,24 CALL RMV6(GRED,REFL(1,IREFL),VT) C# C# C accumulate matrices starting from the reduced vector call cpyvn (36,refl(1,irefl),mt2k) C# C# C There is a theoretical upper bound on how much the sum of the C edge lengths can change (3.0) in a single transformation. So C by allowing their square to only change by a factor of 9.0 C (incremented to allow for error), we can limit the search. IF (VT(1)**2+VT(2)**2+VT(3)**2.GT. 10.0*GRMIN) THEN IF (DEBUG)WRITE (*,*) ' '//hm//' REJECT 1 ',GRMIN,VT ELSEIF (ABS(VT(4)**2/VT(2)/VT(3)) .GT. 1.2 .OR. 2 ABS(VT(5)**2/VT(1)/VT(3)) .GT. 1.2 .OR. 3 ABS(VT(6)**2/VT(1)/VT(2)) .GT. 1.2 ) THEN IF (DEBUG) WRITE (*,*) * ' '//hm//' REJECT 2 ',VT(4)**2/VT(2)/VT(3), 2 VT(5)**2/VT(1)/VT(3), 3 VT(6)**2/VT(1)/VT(2) ELSE C set things up so that on the first cycle, the original vector C is stored, and nothing else happens. after that, the rest of the C switch matrices are used (from the 4000 loop). IF (ICYCLE.EQ.1) THEN MXINNR = 1 C# C# call cpyvn (36,mt2k,mti2k) C# C# ELSE MXINNR = 24 CALL RMV6(VT,SWTCH(1,ICYCLE-1),VTT) C# C# call mm6(swtch(1,icycle-1),mt2k,mti2k) C# C# CALL CPYVN(6,VTT,VT) ENDIF DO 1000 INNER=1,MXINNR IF (ICYCLE.GT.1) THEN CALL RMV6(VT,REFL(1,INNER),VTT) CALL CPYVN(6,VTT,VT) C# C# call mm6(refl(1,inner),mti2k,mt1k) call cpyvn (36,mt1k,mti2k) C# C# else call cpyvn (36,mti2k,mt1k) ENDIF NV1 = NV + 1 IF (NEARST(DEBUG, 2 MXTREE,6,VT,DMIN,TREE,NV1,ID,'NEARST') .EQ. 0) 3 THEN NV = NV + 1 CALL BLDTRE (MXTREE,6,VT,NV,TREE,'BLDTRE') CALL CPYVN(6,VT,V(1,NV)) C# C# call cpyvn(36,mt1k,matref(1,nv)) C# C# IF (NV .EQ. NVMAX) GO TO 8000 ENDIF 1000 CONTINUE ENDIF 2000 CONTINUE 4000 CONTINUE 8000 CONTINUE if (debug) then WRITE (*,*) ' '//hm//' NV IN MKREFL ',NV endif END C*********************************************************************** SUBROUTINE mm6(M1,M2,M3) C multiply two matrices (6x6), both in a linear array REAL M1(36),M2(36),M3(36) C----------------------------------------------------------------------- CALL ZEROS (36,M3) DO 3000 I36=1,36 IROW = (I36+5)/6 ICOL = MOD(I36-1,6)+1 K = ICOL-6 DO 2000 J=6*IROW-5,6*IROW K = K + 6 M3(I36) = M3(I36) + M1(J)*M2(K) 1000 CONTINUE 2000 CONTINUE 3000 CONTINUE END C*********************************************************************** LOGICAL FUNCTION NEARRD (A,R,SIG) C test whether a cell (really a g6 vector) is nearly Buerger reduced include 'ITERATE.cmn' REAL A(6),R(6), B(6) LOGICAL DEBUG DATA DEBUG /.FALSE./ C R IS THE REDUCED CELL VECTOR C check that the vector is near to reduced C----------------------------------------------------------------------- DO 1000 I=1,3 IF (A(I) .LT. 1.0) THEN NEARRD = .FALSE. RETURN ENDIF 1000 CONTINUE DO 2000 I=1,6 B(I) = A(I) 2000 CONTINUE IF (B(1) .GT. B(2)) THEN BT = B(1) B(1) = B(2) B(2) = BT BT = B(4) B(4) = B(5) B(5) = BT ENDIF IF (B(2) .GT. B(3)) THEN BT = B(2) B(2) = B(3) B(3) = BT BT = B(5) B(5) = B(6) B(6) = BT ENDIF IF (B(1) .GT. B(2)) THEN BT = B(1) B(1) = B(2) B(2) = BT BT = B(4) B(4) = B(5) B(5) = BT ENDIF NEARRD = .TRUE. DO 4000 I=1,3 IF (B(I)-R(I) .GT. 5.0*SIG) THEN IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' NOT NEAR BUERGER ',I,B(I),R(I) NEARRD = .FALSE. RETURN ENDIF 4000 CONTINUE IF (ABS(B(4))/SQRT(B(2)*B(3)) .GT. 1.0+5.0*SIG) THEN IF (DEBUG) WRITE (*,*)' '//hm//' ALPHA BAD ' NEARRD = .FALSE. RETURN ELSEIF (ABS(B(5))/SQRT(B(1)*B(3)) .GT. 1.0+5.0*SIG) THEN IF (DEBUG) WRITE (*,*)' '//hm//' BETA BAD ' NEARRD = .FALSE. RETURN ELSEIF (ABS(B(6))/SQRT(B(1)*B(2)) .GT. 1.0+5.0*SIG) THEN IF (DEBUG) WRITE (*,*)' '//hm//' GAMMA BAD ' NEARRD = .FALSE. RETURN ENDIF END C**********************************************************************C FUNCTION NEARST (debug,MXTREE,NVEC,X,RADMAX,TREE,IP,IDOUT,TEST) C The parameters are the same as those of INSPHR, except C that only the nearest point is found. If no points are C found within RADMAX of X, then IP and NEARST are C returned as 0; otherwise they are returned as the index C in TREE of the coordinates of the vector of the point C closest to X. TEST must be the string 'NEARST'. ID is C returned as the ID of the nearest point (if the value C input as IDIN in BLDTRE was the index) C See also BLDTRE and INSPHR include 'ITERATE.cmn' CHARACTER*6 TEST LOGICAL DEBUG parameter (maxstk=1000) INTEGER ISTAK(maxstk) REAL TREE(MXTREE) C DATA DEBUG /.FALSE./ DATA LINK,RMAX,ID,ICHILD /1,2,3,4/ DATA RIGHT,LEFT,END /111,112,113/ C----------------------------------------------------------------------C IF (TEST .NE. 'NEARST' .AND. TEST .NE. 'nearst') 2 CALL BADCAL (TEST,'NEARST') ISTKP = 0 IP = 0 IPOINT = 2 CURMIN = RADMAX DIR = LEFT DIRPRV = RIGHT IPREV = IPOINT -1 if (tree(1).le.0.0) go to 8000 1000 CONTINUE IPREV = IPOINT DIRPRV = DIR IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' IN NEARST 1000, IPOINT = ',IPOINT IF (TREE(IPOINT) .EQ. 0) THEN IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' AT AN END WITH IPOINT = ',IPOINT DIR = END ELSEIF (DIR .EQ. RIGHT) THEN IRIGHT = TREE(IPOINT) IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' WENT RIGHT WITH IPOINT ', IPOINT DR = TREELN (NVEC,TREE(IRIGHT+ICHILD),X) IF (DR .LT. CURMIN) THEN CURMIN = DR IP = IRIGHT + ICHILD IDOUT = TREE(IRIGHT+ID) ENDIF IF (TREE(IRIGHT+LINK) .LE. 0) THEN IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' ON RIGHT BRANCH, UNSTACK A POINT' DIR = END ELSEIF (TREE(IRIGHT+RMAX)+CURMIN .GT. DR) THEN IPOINT = TREE(IRIGHT+LINK) DIR = LEFT ELSE DIR = END ENDIF ELSE IF (DEBUG) WRITE (*,*) ' '//hm//' WENT LEFT, IPOINT ',IPOINT DIR = LEFT IF (TREE(IPOINT) .GT. 0) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' STACK ONE ' CALL TRSTCK(IPOINT,ISTAK,ISTKP) ENDIF DL = TREELN (NVEC,TREE(IPOINT+ICHILD),X) IF (DL .LT. CURMIN) THEN CURMIN = DL IP = IPOINT+ICHILD IDOUT = TREE(IPOINT+ID) ENDIF IF (TREE(IPOINT+LINK) .LE. 0) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' NO LEFT LINK, GO BACK' DIR = END ELSEIF (TREE(IPOINT+RMAX) .LT. 0.0) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' NO DESCENDING LEFT TREE' DIR = END ELSEIF (TREE(IPOINT+RMAX)+CURMIN .GT. DL) THEN IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' GOING TO GO DOWN ONE LEVEL ', 3 ' IPOINT AND UPDATE ',IPOINT,' ',INT(TREE(IPOINT+LINK)) IPOINT = TREE(IPOINT+LINK) ELSE IF (DEBUG) WRITE (*,*) ' '//hm//' NO CLOSER POINTS ON LEFT ' IF (DEBUG) WRITE (*,*) ' '//hm//' CURMIN,TREE(IPOINT+RMAX), 2 DL ',CURMIN,TREE(IPOINT+RMAX),DL DIR = END ENDIF ENDIF IF (DIR .EQ. END) THEN if (debug) write (*,*) ' '//hm// 2 ' call unstk ',ipoint,istkp,maxstk IF (IUNSTK(IPOINT,ISTAK,ISTKP) .LE. 0) GO TO 8000 DIR = RIGHT ENDIF GO TO 1000 8000 CONTINUE NEARST = IP END C*********************************************************************** LOGICAL FUNCTION OKCELL (LATSYM,CV,talk) C okcell determines if a particular cell makes sense. The variable C talk is used to determine if output is printed. include 'ITERATE.cmn' logical pcmnt_ PARAMETER (NLATT=16) CHARACTER *1 SYMLST(NLATT) CHARACTER *1 LATSYM REAL CV(6) character *(*) talk DATA SYMLST /'P','A','B','C','I','F','R','H', 2 'p','a','b','c','i','f','r','h'/ C----------------------------------------------------------------------- OKCELL = .TRUE. IF (CV(4).GT.175.0 .OR. CV(5).GT.175.0 .OR. CV(6).GT.175.0) THEN if (talk .eq. ' TALK') 2 WRITE (*,*) * ' '//hm//' THE LATTICE ANGLES MUST BE LESS THAN 175 DEGREES' OKCELL = .FALSE. ENDIF IF (CV(4).LT.5.0 .OR. CV(5).LT.5.0 .OR. CV(6).LT.5.0) THEN if (talk .eq. ' TALK') 2 WRITE (*,*) * ' '//hm//' THE LATTICE ANGLES MUST EXCEED 5.0 DEGREES' OKCELL = .FALSE. ENDIF DO 1000 I=1,NLATT IF (LATSYM.EQ.SYMLST(I)) THEN GO TO 1100 ENDIF 1000 CONTINUE if (talk .eq. ' TALK') 2 WRITE (*,*) * ' '//hm//' XTAL CENTERING SYMBOL ',LATSYM,' IS NOT IMPLEMENTED' OKCELL = .FALSE. 1100 CONTINUE IF (CV(4).GE.CV(5)+CV(6)) THEN if (talk .eq. ' TALK') 2 WRITE (*,*) * ' '//hm//' ERROR, ALPHA EXCEEDS BETA PLUS GAMMA' OKCELL = .FALSE. ENDIF IF (CV(5).GE.CV(4)+CV(6)) THEN if (talk .eq. ' TALK') 2 WRITE (*,*) ' '//hm//' ERROR, BETA EXCEEDS ALPHA PLUS GAMMA' OKCELL = .FALSE. ENDIF IF (CV(6).GE.CV(4)+CV(5)) THEN if (talk .eq. ' TALK') 2 WRITE (*,*) ' '//hm//' ERROR, GAMMA EXCEEDS ALPHA PLUS BETA' OKCELL = .FALSE. ENDIF IF (CV(4)+CV(5)+CV(6) .GT. 355.0) THEN if (talk .eq. ' TALK') then WRITE (*,*) ' '//hm// 2 ' THE SUM OF THE CELL ANGLES MUST BE LESS THAN' WRITE (*,*) ' '//hm//' 355.0 DEGREES' endif OKCELL = .FALSE. ENDIF DO 2000 I=1,3 IF (CV(I) .LT. 1.0) THEN WRITE (*,*) ' '//hm//' THE AXIAL LENGTHS MUST EXCEED 1.0' OKCELL = .FALSE. ENDIF 2000 CONTINUE IF (LATSYM .EQ. 'R' .OR. LATSYM .EQ. 'r' .OR. * LATSYM .EQ. 'H' .OR. LATSYM .EQ. 'h') THEN IF (ABS(CV(4)-90.).GT.1. .OR. * ABS(CV(5)-90.).GT.1. .OR. * ABS(CV(6)-120.).GT.1. .OR. * ABS(CV(1)-CV(2)).GT..5) THEN IF (LATSYM.EQ.'R' .OR. LATSYM.EQ.'r') THEN if (talk .eq. ' TALK') then if (ostyle.ne.'CIF ') then WRITE (*,*) ' '//hm//' RHOMBOHEDRAL CENTERING REQUIRES' WRITE (*,*) ' '//hm// 2 ' A HEXAGONAL CELL (A=B, ALPHA=BETA=90,' WRITE (*,*) ' '//hm//' GAMMA =120)' else cifres=pcmnt_(' Non-hexagonal R lattice '//cifeid) endif endif IF (ABS(CV(1)-CV(2)) .LT. .5 .AND. * ABS(CV(2)-CV(3)) .LT. .5 .AND. * ABS(CV(1)-CV(3)) .LT. .5 .AND. * ABS(CV(4)-CV(5)) .LT. 1. .AND. * ABS(CV(5)-CV(6)) .LT. 1. .AND. * ABS(CV(4)-CV(6)) .LT. 1.) THEN LATSYM = 'P' if (ostyle.ne.'CIF ') then WRITE (*,*) ' '//hm// 2 ' PROCESSING AS PRMITIVE RHOMBOHEDRAL' else cifres=pcmnt_(' Processing as primitve rhombohedral') endif ELSE OKCELL = .FALSE. ENDIF ELSE if (talk .eq. ' TALK') then if (ostyle.ne.'CIF ') then WRITE (*,*) ' '//hm//' A HEXAGONAL CELL REQUIRES' WRITE (*,*) ' '//hm//' A=B, ALPHA=BETA=90,GAMMA =120' else cifres=pcmnt_(' non-hexagonal cell '//cifeid) endif endif OKCELL = .FALSE. ENDIF ENDIF IF (LATSYM .EQ. 'H' .OR. LATSYM .EQ. 'h') THEN WRITE(*,*) ' '//hm//' PROCESSING H AS P' LATSYM = 'P' ENDIF ENDIF RETURN END subroutine r3tog6(e3,g6) C give a 3-space transformation matrix, determine the corresponding one C in g6 real e3(9),g6(36) C----------------------------------------------------------------------- C------------------------ C upper left 3x3 block C------------------------ g6(1)=e3(1)**2 g6(2)=e3(2)**2 g6(3)=e3(3)**2 g6(7)=e3(4)**2 g6(8)=e3(5)**2 g6(9)=e3(6)**2 g6(13)=e3(7)**2 g6(14)=e3(8)**2 g6(15)=e3(9)**2 C------------------------ C upper right 3x3 block C------------------------ g6(4)=e3(2)*e3(3) g6(5)=e3(1)*e3(3) g6(6)=e3(1)*e3(2) g6(10)=e3(5)*e3(6) g6(11)=e3(4)*e3(6) g6(12)=e3(4)*e3(5) g6(16)=e3(8)*e3(9) g6(17)=e3(7)*e3(9) g6(18)=e3(7)*e3(8) C------------------------ C lower left 3x3 block C------------------------ g6(19)=2*e3(4)*e3(7) g6(20)=2*e3(5)*e3(8) g6(21)=2*e3(6)*e3(9) g6(25)=2*e3(1)*e3(7) g6(26)=2*e3(2)*e3(8) g6(27)=2*e3(3)*e3(9) g6(31)=2*e3(1)*e3(4) g6(32)=2*e3(2)*e3(5) g6(33)=2*e3(3)*e3(6) C------------------------ C lower right 3x3 block C------------------------ g6(22)=e3(5)*e3(9) + e3(8)*e3(6) g6(23)=e3(4)*e3(9) + e3(7)*e3(6) g6(24)=e3(4)*e3(8) + e3(4)*e3(5) g6(28)=e3(2)*e3(9) + e3(8)*e3(3) g6(29)=e3(1)*e3(9) + e3(7)*e3(3) g6(30)=e3(1)*e3(8) + e3(7)*e3(2) g6(34)=e3(2)*e3(6) + e3(5)*e3(3) g6(35)=e3(1)*e3(6) + e3(4)*e3(3) g6(36)=e3(1)*e3(5) + e3(4)*e3(2) end C*********************************************************************** PROGRAM RED include 'ITERATE.cmn' logical init_ logical data_ logical ocif_ logical pdata_ logical pfile_ logical ploop_ logical pnumb_ logical pcmnt_ logical pchar_ INTEGER MAXPRJ PARAMETER (MAXPRJ=42) PARAMETER (NVMAX=1000) PARAMETER (MXTREE=11*NVMAX) INTEGER ITDESG(MAXPRJ) CHARACTER *2 CHRLAT(MAXPRJ) REAL PJNORM(MAXPRJ) C common /cmprjn/ pjnorm real PRJ(36,MAXPRJ) C common /cmprj/ prj REAL P(36),AP(36) REAL CV(6),CE(6),G(6),GE(6),TG(6),AG(6),COUT(6) REAL MPRIM(36) real m3ptrd(9) real MRED(36) REAL GOUT(6),GRED(6),CRED(6) LOGICAL INPCEL LOGICAL NEARRD EXTERNAL INPCEL CHARACTER LATSYM REAL TREE(MXTREE) C common /cmtree/ tree REAL V(6,NVMAX) C common /cmv/ v real MATREF(36,NVMAX),m1(36),m2(36) real retcel(6),m3(9),m3t(9),m3ti(9) REAL VBEST(6),AVBEST(6) REAL DOTVN EXTERNAL DOTVN INTEGER NPROJ,I,J REAL RATIO,SIZE,ERRSIZ character*8 cellst(6) logical eof,dbgmkr logical g6toc, test logical debug data debug /.FALSE./ C----------------------------------------------------------------------- CALL GETENV('ITERATE_QUERY',querst) CALL GETENV('OUTPUT_STYLE',ostyle) CALL GETENV('INPUT_STYLE',istyle) if(istyle.eq.'CIF '.or.ostyle.eq.'CIF ') then cifres = init_(5,6,21,0) endif if(istyle.eq.'CIF ') then querst = 'NO' cifres = ocif_(' ') cifres = data_(' ') endif hm = ' ' if (ostyle.eq.'CIF ') then hm = '#' tabl_ = .false. cifres = pfile_(' ') cifres = pdata_('G6_SEARCH') cifres = ploop_('_cell.entry_id') cifres = ploop_('_cell.id') cifres = ploop_('_cell.space_group_name_H-M') cifres = ploop_('_cell.Bravais_lattice_symbol') cifres = ploop_('_cell.length_a') cifres = ploop_('_cell.length_b') cifres = ploop_('_cell.length_c') cifres = ploop_('_cell.angle_alpha') cifres = ploop_('_cell.angle_beta') cifres = ploop_('_cell.angle_gamma') cifres = ploop_('_cell.unreduced_length_a') cifres = ploop_('_cell.unreduced_length_b') cifres = ploop_('_cell.unreduced_length_c') cifres = ploop_('_cell.unreduced_angle_alpha') cifres = ploop_('_cell.unreduced_angle_beta') cifres = ploop_('_cell.unreduced_angle_gamma') endif do 1 i=2,mxtree tree(i) = 2**30 1 continue iunt0 = 0 iunt1 = 1 iunt2 = 2 iunt3 = 3 iunt10 = 10 dbgmkr = .false. IF (querst.ne.'NO') THEN WRITE (*,*) ' '//hm//' BEFORE BLDPRJ' ENDIF CALL BLDPRJ (MAXPRJ,NPROJ,ITDESG,CHRLAT,PJNORM,PRJ,'BLDPRJ') C write (*,*) ' '//hm//' nproj = ',nproj C loop until the input contains no more data 1000 continue IF (INPCEL(LATSYM,CV,CE,eof)) THEN CALL CTOG6(CV,CE,G,GE,SIZE,ERRSIZ,RATIO,'CTOG6 ') if (ostyle.ne.'CIF ') then WRITE (*,'(A,A)') ' '//hm//' Input Lattice Symbol ', 2 latsym WRITE (*,*) WRITE (*,'('' '//hm//' INPUT CELL AND ERRORS '', 2 '' INPUT VECTOR AND ERRORS'')') WRITE (*,*) else cifres = pchar_(' ',cifeid) cifres = pchar_(' ','.') cifres = pchar_(' ',cifsgs) cifres = pchar_(' ',latsym) endif CALL WRCLV6 (CV,CE,G,GE,'WRCLV6') if (ostyle.ne.'CIF ') then WRITE (*,*) else do ii = 1,6 cifres = pchar_(' ','.') enddo endif CALL WRSIZE (SIZE,ERRSIZ,RATIO,'WRSIZE') CALL MKPRIM (LATSYM,G,MPRIM,GOUT,'MKPRIM') call cpyvn (36,mprim,m1) CALL CHKVEC(GOUT) CALL RUNTMN(6,MRED) CALL REDUCE (GOUT,MRED,GRED,'REDUCE') call mm6 (mred,m1,m2) CALL CHKVEC(GRED) test = G6TOC (GRED,CRED,'G6TOC ') SIZE = SQRT(DOTVN(6,GRED,GRED)) ERRSIZ = RATIO * SIZE if (ostyle.ne.'CIF ') then WRITE (*,*) WRITE (*,'('' '//hm//' REDUCED CELL '')') WRITE (*,'('' '//hm//' Red. Cell '',6F10.3)')CRED WRITE (*,'('' '//hm//' Red. Vector '',6F9.2)') GRED endif CALL MKREFL (dbgmkr,RATIO,MXTREE,TREE,NVMAX, 2 V,MATREF,NV,GRED,'MKREFL') if (querst .ne. 'NO') then if(ostyle.ne.'CIF ')write (*,*) ' '//hm//' nv=',nv endif do 1200 iv=1,nv call mm6(matref(1,iv),m2,m1) call cpyvn (36,m1,matref(1,iv)) 1200 continue if (debug) then do 1300 iv=1,nv write (*,'(1x,a3,i5,6f8.3)') * ' '//hm//' ',iv,(v(ip,iv),ip=1,6) 1300 continue endif C after reducing the input cell and iterating to find various C nearly reduced cells, test the found cells using the projectors C of Paciorek and Bonin nmatch = 0 DO 4000 I=1,NPROJ nrej = 0 DBEST = 1.0E20 DBESTO = DBEST nbest = 0 C subtract the projector from the unit matrix (to give the "prep") C which when multiplied times a vector gives the vector component C not in the subspace defined by the projector DO 3100 J=1,36 P(J) = REAL(PRJ(J,I))/PJNORM(I) 3100 AP(J) = -P(J) DO 3200 J=1,36,7 AP(J) = 1.0 + AP(J) 3200 CONTINUE DO 3300 IV=1,NV CALL RMV6 (V(1,IV),AP,AG) CALL RMV6 (V(1,IV),P,TG) DTEST = DOTVN(6,AG,AG)/dotvn(6,tg,tg) IF (DTEST .GE. DBEST) THEN ELSEIF (TG(1) .LT. 1.0) THEN ELSEIF (TG(2) .LT. 1.0) THEN ELSEIF (TG(3) .LT. 1.0) THEN ELSEIF (TG(1)*TG(2)*TG(3) + 0.125*TG(6)*TG(4)*TG(5) 2 + 0.125*TG(5)*TG(6)*TG(4) - 0.25*TG(5)*TG(2)*TG(5) 3 - 0.25*TG(1)*TG(4)*TG(4) - 0.25*TG(6)*TG(6)*TG(3) 4 .LE. 0.0) THEN C if the metric tensor is negative, the cell is bad NREJ = NREJ + 1 IF (DEBUG) WRITE (*,*) ' '//hm//' FAILED METRIC TENSOR' ELSEIF (.NOT. NEARRD(V(1,IV),GRED,ERRSIZ)) THEN IF (DEBUG) WRITE (*,*) ' '//hm//' FAILED NEARRD' ELSE DBEST = DTEST CALL CPYVN(6,TG,VBEST) CALL CPYVN(6,AG,AVBEST) NBEST = IV IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' NBEST,DBEST ',NBEST,DBEST ENDIF 3300 CONTINUE 3400 CONTINUE C output those cases that are acceptable cutoff = amax1(10.0,amin1(errsiz,999.0)) if (nbest .ne. 0) dbest = sqrt(DOTVN(6,AVBEST,AVBEST)) IF (nbest .ne. 0 .and. DBEST .LE. cutoff) THEN nmatch = nmatch + 1 if(ostyle.ne.'CIF ') then WRITE (*,*) WRITE (*,*) write (*,'(1x,I3,A,A,A,F7.2,A,A,A,I2,A)') 2 i,' ',chrlat(i),' '//hm//' ',dbest, 3 ' = Distance Projected',' ', 4 'Internat. Tables#(',itdesg(i),')' else cifres = pchar_(' ',cifeid) cifres = pnumb_(' ',float(i),0.) cifres = pchar_(' ',cifsgs) cifres = pchar_(' ',chrlat(i)) endif if(ostyle.ne.'CIF') then WRITE (*,'('' '//hm//' Vector '',6F8.1)') 2 VBEST endif if (G6TOC (VBEST,COUT,'G6TOC ')) then if(ostyle.ne.'CIF ') then WRITE (*,'(2x,'''//hm// 2 ' cell'',/12x,2(3F8.2,'' ''))') COUT else do ii = 1,6 if(cout(ii).ge.0.)itemp = cout(ii)*100.+.5 if(cout(ii).lt.0.)itemp = cout(ii)*100.-.5 cifres = pnumb_(' ',float(itemp)/100.,0.) enddo endif call g6tor3 (matref(1,nbest),m3t) call inver (m3t,m3ti) call unredc (itdesg(i),' ',vbest,retcel,m3,cellst) if(ostyle.eq.'CIF ') then do ii = 1,6 cifres = pchar_(' ',cellst(ii)) enddo endif call trnspz (m3,m3t) call wrcent(chrlat(i),retcel) if (debug) then write (*,'(3(1x,'' '//hm//' '',10x,3i3,/))') * (int(m3(im3)),im3=1,9) write (*,*) write (*,*) ' '//hm//' matref ,nbest = ', 2 nbest,' of ',nv write (*,'(6(1x,'' '//hm// 2 ' '',3x,3f8.3,2x,3f8.3/))') 3 (matref(im,nbest),im=1,36) endif call g6tor3 (matref(1,nbest),m3ptrd) call matmul (m3t,m3ptrd,m3ti) if(ostyle.ne.'CIF ') then write (*,*)' '//hm//' transformation from ', 2 '3-space original cell' if (index('PR',chrlat(i)(2:2)) .ne. 0) then write (*,*) ' '//hm//' to final primitive cell' else write (*,*) ' '//hm//' to final centered cell' endif write (*,'(3(1x,'' '//hm//' '',8x,3f7.3/))') m3ti else cifres= pcmnt_(char(0)) endif endif ENDIF 4000 CONTINUE ENDIF if (nmatch .eq. 0) then if(ostyle.ne.'CIF ') then WRITE (*,*) ' '//hm// 2 '*****************************************' 3 //'*************' write (*,*) ' '//hm// 2 ' NO MATCHES WERE FOUND WITH THE SPECIFIED ' 3 //'UNCERTAINTIES' WRITE (*,*) ' '//hm// 2 '*****************************************' 3 //'*************' else cifres = pcmnt_(char(0)) cifres = pcmnt_( * ' NO MATCHES WERE FOUND WITH THE SPECIFIED UNCERTAINTIES') endif endif IF (querst.ne.'NO') THEN if (.not. eof) THEN if(ostyle.ne.'CIF ') then WRITE (*,*) WRITE (*,*) else cifres = pcmnt_(char(0)) cifres = pcmnt_(' ') endif go to 1000 endif ENDIF if (istyle.eq.'CIF ') then if(loop_) goto 1000 endif if (ostyle.eq.'CIF ' .or. istyle.eq.'CIF ') then call close_ endif END C*********************************************************************** SUBROUTINE REDUCE (VI,M,VOUT,TEST) C for a given input vector, determine the reduced vector and the C transformation from one to the other include 'ITERATE.cmn' CHARACTER *6 TEST REAL VI(6),VIN(6), VOUT(6) LOGICAL AGAIN real M(36),M1(36),M2(36),mnorm(36) REAL ZEROS(6) DATA ZEROS /6*0.0/ C----------------------------------------------------------------------- IF (TEST .NE. 'REDUCE') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN REDUCE' STOP ENDIF CALL CPYVN(6,VI,VIN) NCYCLE = 0 1000 CONTINUE LAST = 0 CALL MKNORM (VIN,Mnorm,VOUT,'MKNORM') call mm6 (mnorm,m,m2) CALL CPYVN(36,m2,m) CALL CPYVN(6,VOUT,VIN) CALL RUNTMN (6,M1) IF (ABS(VIN(4)) .GT. ABS(VIN(2))) THEN M1(14) = 1.0 M1(16) = -SIGN (1.0,VIN(4)) M1(20) = -2.0*SIGN(1.0,VIN(4)) M1(30) = M1(16) AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 5 ELSEIF (ABS(VIN(5)) .GT. ABS(VIN(1))) THEN M1(13) = 1 M1(17) = -SIGN (1.0,VIN(5)) M1(24) = M1(17) M1(25) = 2*M1(17) AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 6 ELSEIF (ABS(VIN(6)) .GT. ABS(VIN(1))) THEN M1(7) = 1 M1(12) = -SIGN(1.0,VIN(6)) M1(23) = M1(12) M1(31) = 2*M1(12) AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 7 ELSEIF (VIN(4)+VIN(5)+VIN(6)+ABS(VIN(1))+ABS(VIN(2)) .LT. 0.0) 2 THEN DO 2000 I=13,18 2000 M1(I) = 1 M1(20) = 2 M1(24) = 1 M1(25) = 2 M1(30) = 1 AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 8 ELSEIF ( (VIN(4).EQ.VIN(2) .AND. 2.0*VIN(5).LT.VIN(6)) .OR. 2 (VIN(4).EQ.-ABS(VIN(2)) .AND. VIN(6).LT. 0.0) ) 3 THEN M1(14) = 1 M1(16) = -SIGN(1.0,VIN(4)) M1(20) = 2*M1(16) M1(30) = M1(16) AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 15 ELSEIF ( (VIN(5).EQ.VIN(1) .AND. 2.0*VIN(4).LT.VIN(6)) .OR. 2 (VIN(5).EQ.-ABS(VIN(1)) .AND. VIN(6).LT.0.0) ) 3 THEN M1(13) = 1 M1(17) = -SIGN(1.0,VIN(5)) M1(24) = M1(17) M1(25) = 2*M1(17) AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 16 ELSEIF ( (VIN(6).EQ.VIN(1) .AND. 2.0*VIN(4).LT.VIN(5)) .OR. 2 (VIN(6).EQ.-VIN(1) .AND. VIN(5).LT.0.0) ) THEN M1(7) = 1 M1(12) = -SIGN(1.0,VIN(6)) M1(23) = M1(12) M1(31) = 2*M1(12) AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 17 ELSEIF ( (VIN(4)+VIN(5)+VIN(6)+ABS(VIN(1))+ABS(VIN(2)).EQ.0.0) 2 .AND. ( 2.0*(ABS(VIN(1))+VIN(5))+VIN(6).GT.0.0) ) THEN DO 3000 I=13,18 3000 M1(I) = 1 M1(20) = 2 M1(24) = 1 M1(25) = 2 M1(30) = 1 AGAIN = .TRUE. CALL mm6(M1,M,M2) CALL CPYVN (36,M2,M) CALL RMV6(VIN,M1,VOUT) LAST = 18 ELSE AGAIN = .FALSE. CALL CPYVN (6,VIN,VOUT) call cpyvn (36,m2,m) ENDIF CALL MKNORM (VOUT,Mnorm,VIN,'MKNORM') CALL mm6 (mnorm,m,m2) CALL CPYVN(36,M2,M) CALL CPYVN(6,VIN,VOUT) IF (VIN(1).LT. 0.0 .OR. VIN(2).LT.0.0 .OR. VIN(3).LT.0.0) THEN WRITE (*,*) ' '//hm//' NEG. SQ. AXIS ',NCYCLE CALL WRVEC6(VIN,ZEROS,'WRVEC6') CALL WRVEC6(VOUT,ZEROS,'WRVEC6') if (istyle.ne.'CIF ') READ (*,*) ENDIF NCYCLE = NCYCLE + 1 IF (NCYCLE .LT. 25 .AND. AGAIN) GO TO 1000 END C*********************************************************************** SUBROUTINE RMV6 (V1,M,V2) REAL V1(6),V2(6) REAL M(36) C----------------------------------------------------------------------- DO 3000 I=1,6 SUM = 0.0 DO 2000 J=1,6 SUM = SUM + M(6*(I-1)+J)*V1(J) 2000 CONTINUE V2(I) = SUM 3000 CONTINUE END function root (a) if (a.ge.0.0) then root = sqrt(a) else root = 0 endif end C*********************************************************************** SUBROUTINE RUNTMN (N,M) INTEGER N REAL M(N,N) C----------------------------------------------------------------------- DO 1000 I=1,N DO 1000 J=1,N 1000 M(I,J) = 0.0 DO 2000 I=1,N 2000 M(I,I) = 1.0 END function sqr (a) sqr = a*a end C**********************************************************************C FUNCTION TREELN (NVEC,A,B) C-----GET THE SEPARATION BETWEEN THE ENDS OF TWO VECTORS C used by bldtre, insphr and nearst DIMENSION A(NVEC),B(NVEC) C----------------------------------------------------------------------C SUM = 0.0 DO 1000 I=1,NVEC SUM = SUM + (A(I)-B(I))**2 1000 CONTINUE TREELN = SQRT(SUM) END C**********************************************************************C SUBROUTINE TRSTCK (NEXT,ISTAK,ISTKP) C helper routine for NEARST and INSPHR include 'ITERATE.cmn' INTEGER ISTAK(1000) LOGICAL DEBUG DATA DEBUG /.FALSE./ C----------------------------------------------------------------------C IF (DEBUG) WRITE (*,*) ' '//hm// 2 ' IN TRSTCK, STACK POINTER,IPOINT ', 3 ISTKP,NEXT ISTKP = ISTKP + 1 ISTAK(ISTKP) = NEXT END C**********************************************************************C subroutine unitmx(n,a) C produce a unit matrix of order n real a(n,n) C----------------------------------------------------------------------- do 1000 i=1,n do 1000 j=1,n 1000 a(i,j) = 0.0 do 2000 i=1,n 2000 a(i,i) = 1.0 end C**********************************************************************C function unitsn (a) C----------------------------------------------------------------------- if (a.ge.0.0) then unitsn = 1 else unitsn = -1 endif end C**********************************************************************C subroutine unredc (itcase,rfcase,v,cell,m,cellst) C given a g6 vector and a particular bravais lattice (designated either C by itcase or rfcase, that is by the International tables or by Niggli C and Roof's designations), compute the standard (often non-reduced) C unit cell real m(9),v(6),cell(6) character *3 rfcase character *8 cellst(6),ctemp integer itcase real redv(6),altcel(6),v1(3),v2(3),v3(3),a(3),b(3),c(3),vtemp(3) C----------------------------------------------------------------------- PI = 4.0*ATAN(1.0) MAXINT = 32768.0 do 1000 I=1,6 Cell(I) = Maxint altcel(i) = maxint cellst(i) = '.' 1000 continue do 1100 I = 1,9 M(I) = 0.0 1100 continue do 1200 I=1,6 redv(I) = root(v(I)) 1200 continue redv(4) = v(4)/(redv(2)*redv(3)) redv(5) = v(5)/(redv(1)*redv(3)) redv(6) = v(6)/(redv(1)*redv(2)) IF (itcase .eq. 3 .or. rfcase .EQ. '44A') THEN Cell(1) = redv(1) CALL UNITMX(3,M) ELSEIF (itcase .eq. 5 .or. rfcase .EQ. '44B') THEN Cell(1) = root(4.0/3.0*v(1)) CALL UNITMX(3,M) M(7) = 1.0 M(2) = 1.0 M(6) = 1.0 ELSEIF (itcase .eq. 1 .or. rfcase .EQ. '44C') THEN Cell(1) = root(2*v(1)) do 4400 i = 1,9 M(I) = 1.0 4400 CONTINUE M(4) = -1.0 M(8) = -1.0 M(3) = -1.0 ELSEIF (itcase .eq. 11 .or. rfcase .EQ. '45A') THEN Cell(1) = redv(1) Cell(3) = redv(3) CALL UNITMX(3,M) ELSEIF (itcase .eq. 21 .or. rfcase .eq. '45B') THEN Cell(1) = redv(2) Cell(3) = redv(1) M(4) = 1.0 M(8) = 1.0 M(3) = 1.0 ELSEIF (itcase .eq. 15 .or. rfcase .eq. '45C') THEN Cell(1) = redv(1) Cell(3) = root(4*v(3)-2*v(1)) M(1) = 1.0 M(5) = 1.0 M(9) = 2.0 M(3) = 1.0 M(6) = 1.0 ELSEIF (itcase .eq. 6 .or. rfcase .eq. '45D') THEN Cell(1) = root(2*v(1)+v(6)) Cell(3) = root(2*v(1)+v(4)) do 4500 I= 1,9 M(I) = 1.0 4500 CONTINUE do 4510 I = 1,9,4 M(I) = 0.0 4510 CONTINUE ELSEIF (itcase .eq. 7 .or. rfcase .eq. '45d') THEN Cell(1) = root(2*v(1)+v(6)) Cell(3) = root(2*v(1)+v(4)) do 4550 I=1,9,4 M(I) = 1.0 4550 CONTINUE M(4) = 0.0 M(8) = 0.0 M(3) = 0.0 ELSEIF (itcase .eq. 18 .or. rfcase .eq. '45E') THEN Cell(1) = redv(1) Cell(3) = root( 2*v(3)-0.5*v(1)) M(4) = -1.0 M(7) = 1.0 M(2) = 1.0 M(5) = -1.0 M(8) = -1.0 M(3) = 1.0 ELSEIF (itcase .eq. 12 .or. rfcase .eq. '48A') THEN Cell(1) = redv(1) Cell(3) = redv(3) CALL UNITMX(3,M) ELSEIF (itcase .eq. 22 .or. rfcase .eq. '48B') THEN Cell(1) = redv(3) Cell(3) = redv(1) M(4) = 1.0 M(8) = 1.0 M(3) = 1.0 ELSEIF (itcase .eq. 9 .or. rfcase .eq. '49B') THEN Cell(1) = redv(3) Cell(4) = 1-2*Sqr(redv(1)/(2*redv(3))) altcel(1) = redv(1) altcel(3) = root(9*v(3)-3*v(1)) M(1) = 1.0 M(2) = -1.0 M(5) = 1.0 M(3) = -1.0 M(6) = -1.0 M(9) = 3.0 ELSEIF (itcase .eq. 2 .or. itcase .eq. 4 2 .or. rfcase .eq. '49x') THEN Cell(1) = redv(1) Cell(4) = v(4)/(2*v(1)) altcel(1) = root(0.5*v(3)-0.25*v(4)) altcel(3) = root(9*v(1)-3*Sqr(altcel(1))) M(1) = 1.0 M(4) = -1.0 M(2) = -1.0 M(8) = 1.0 do 4900 I= 3,9,3 M(I) = -1.0 4900 CONTINUE ELSEIF (itcase .eq. 24 .or. rfcase .eq. '49E') THEN Cell(1) = redv(3) Cell(4) = v(4)/(2*v(2)) altcel(1) = root(0.5*v(3)-0.25*v(4)) altcel(3) = redv(1) M(1) = 1.0 M(4) = 2.0 M(7) = 1.0 M(5) = -1.0 M(8) = 1.0 M(3) = 1.0 ELSEIF (itcase .eq. 32 .or. rfcase .eq. '50C') THEN do 5000 I=1,3 Cell(I) = redv(I) 5000 CONTINUE CALL UNITMX(3,M) ELSEIF (itcase .eq. 36 .or. rfcase .eq. '50A') THEN Cell(1) = redv(1) Cell(2) = root(4*v(3)-v(1)) Cell(3) = redv(2) M(1) = 1.0 M(2) = -1.0 M(8) = -2.0 M(6) = 1.0 ELSEIF (itcase .eq. 38 .or. rfcase .eq. '50B') THEN Cell(1) = redv(1) Cell(3) = redv(3) Cell(2) = root(4*v(2)-v(1)) M(1) = 1.0 M(2) = -1.0 M(5) = -2.0 M(9) = 1.0 ELSEIF (itcase .eq. 13 .or. rfcase .eq. '50D') THEN Cell(1) = root(2*v(1)+v(6)) Cell(2) = root(2*v(1)-v(6)) Cell(3) = redv(3) M(1) = 1.0 M(4) = 1.0 M(2) = -1.0 M(5) = 1.0 M(9) = 1.0 ELSEIF (itcase .eq. 23 .or. rfcase .eq. '50E') THEN Cell(1) = root(2*v(3)+v(4)) Cell(2) = root(2*v(3)-v(4)) Cell(3) = redv(1) M(4) = 1.0 M(7) = 1.0 M(5) = -1.0 M(8) = 1.0 M(3) = 1.0 ELSEIF (itcase .eq. 40 .or. rfcase .eq. '50F') THEN Cell(1) = redv(2) Cell(2) = root(4*v(3)-v(2)) Cell(3) = redv(1) M(4) = 1.0 M(5) = -1.0 M(8) = -2.0 M(3) = -1.0 ELSEIF (itcase .eq. 16 .or. rfcase .eq. '51A') THEN Cell(1) = root(2*v(1)+v(6)) Cell(2) = root(2*v(1)-v(6)) Cell(3) = root(4*v(3)-Sqr(Cell(1))) M(1) = 1.0 M(4) = -1.0 M(5) = 1.0 M(5) = 1.0 M(8) = 2.0 M(3) = -1.0 M(6) = -1.0 ELSEIF (itcase .eq. 26 .or. rfcase .eq. '51B') THEN Cell(1) = redv(1) Cell(2) = root(4*v(2)-v(1)) Cell(3) = root(4*v(3)-v(1)) M(1) = -1.0 M(4) = 2.0 M(2) = -1.0 M(8) = 2.0 M(3) = 1.0 ELSEIF (itcase .eq. 8 .or. rfcase .eq. '52A') THEN Cell(1) = root(2*v(1)+v(6)) Cell(2) = root(2*v(1)+v(5)) Cell(3) = root(2*v(1)+v(4)) M(1) = 1.0 M(7) = 1.0 M(2) = 1.0 M(5) = 1.0 M(6) = 1.0 M(9) = 1.0 ELSEIF (itcase .eq. 19 .or. rfcase .eq. '52B') THEN Cell(1) = redv(1) Cell(2) = root(2*v(2)-v(4)) Cell(3) = root(2*v(3)+v(4)-v(1)) M(1) = -1.0 M(2) = -1.0 M(5) = 1.0 M(8) = 1.0 M(6) = -1.0 M(9) = 1.0 ELSEIF (itcase .eq. 42 .or. rfcase .eq. '52C') THEN Cell(1) = redv(1) Cell(2) = redv(2) Cell(3) = root(4*v(3)-v(1)-v(2)) M(1) = 1.0 M(5) = 1.0 M(3) = -1.0 M(6) = -1.0 M(9) = -2.0 ELSEIF (itcase .eq. 33 .or. rfcase .eq. '53A') THEN Cell(1) = redv(1) Cell(2) = redv(2) Cell(3) = redv(3) Cell(5) = v(5)/(2*Cell(1)*Cell(3)) CALL UNITMX(3,M) ELSEIF (itcase .eq. 35 .or. rfcase .eq. '53B') THEN Cell(1) = redv(2) Cell(2) = redv(1) Cell(3) = redv(3) Cell(5) = v(4)/(2*Cell(1)*Cell(3)) M(4) = 1.0 M(2) = 1.0 M(9) = 1.0 ELSEIF (itcase .eq. 34 .or. rfcase .eq. '53C') THEN Cell(1) = redv(1) Cell(2) = redv(3) Cell(3) = redv(2) Cell(5) = v(6)/(2*Cell(1)*Cell(3)) M(1) = 1.0 M(8) = 1.0 M(6) = 1.0 ELSEIF (itcase .eq. 39 .or. rfcase .eq. '54A') THEN Cell(1) = root(4*v(2)-v(1)) Cell(2) = redv(1) Cell(3) = redv(3) Cell(5) = v(4)/(Cell(1)*Cell(3)) M(1) = 1.0 M(4) = 2.0 M(2) = 1.0 M(9) = 1.0 ELSEIF (itcase .eq. 41 .or. rfcase .eq. '54B') THEN Cell(1) = root(4*v(3)-v(2)) Cell(2) = redv(2) Cell(3) = redv(1) Cell(5) = v(5)/(Cell(1)*Cell(3)) M(4) = 1.0 M(7) = 2.0 M(5) = 1.0 M(3) = 1.0 ELSEIF (itcase .eq. 37 .or. rfcase .eq. '54C') THEN Cell(1) = root(4*v(3)-v(1)) Cell(2) = redv(1) Cell(3) = redv(2) Cell(5) = v(4)/(Cell(1)*Cell(3)) M(1) = 1.0 M(7) = 2.0 M(2) = 1.0 M(6) = 1.0 ELSEIF (itcase .eq. 10 .or. itcase .eq. 14 2 .or. rfcase .eq. '55A') THEN call v2cart(v,v1,v2,v3) call vecsum(v1,v2,A) call vecdif(v2,v1,B) call cpyvec(v3,c) Cell(1) = Sqrt(Dot(A,A)) Cell(2) = Sqrt(Dot(B,B)) Cell(3) = Sqrt(Dot(C,C)) Cell(5) = -ABS(Dot(A,C)/Cell(1)/Cell(3)) IF (Cell(1) .EQ. Cell(2)) THEN CALL UNITMX(3,M) M(4) = 1.0 M(2) = -1.0 ELSE M(4) = 1.0 M(7) = 1.0 M(5) = -1.0 M(8) = 1.0 M(3) = 1.0 ENDIF ELSEIF (itcase .eq. 20 .or. itcase .eq. 25 2 .or. rfcase .eq. '55B') THEN call v2cart(v,v1,v2,v3) call vecsum(v3,v2,A) call vecdif(v3,v2,B) call cpyvec (v1,c) Cell(1) = Sqrt(Dot(A,A)) Cell(2) = Sqrt(Dot(B,B)) Cell(3) = Sqrt(Dot(C,C)) Cell(5) = -ABS(Dot(A,C)/Cell(1)/Cell(3)) IF ((v(4).LT.0.0) .AND. (v(5).GE.0.0) .AND. (V(6).LT.0.0)) THEN M(4) = 1.0 M(7) = 1.0 M(5) = 1.0 M(8) = -1.0 M(3) = -1.0 ELSE M(4) = 1.0 M(7) = 1.0 M(5) = -1.0 M(8) = 1.0 M(3) = 1.0 ENDIF ELSEIF (itcase .eq. 28 .or. rfcase .eq. '56A') THEN call v2cart(v,A,C,v3) do 5600 I=1,3 v3(I)=2*v3(I) 5600 continue call vecdif(v3,A,B) Cell(1)=Sqrt(Dot(A,A)) Cell(2)=Sqrt(Dot(B,B)) Cell(3)=Sqrt(Dot(C,C)) Cell(5)=-ABS(Dot(A,C)/Cell(1)/Cell(3)) M(1) = -1.0 M(2) = -1.0 M(8) = 2.0 M(6) = 1.0 ELSEIF (itcase .eq. 30 .or. rfcase .eq. '56B') THEN call v2cart (v,C,A,v3) do 5620 I=1,3 v3(I)=2*v3(I) 5620 continue call vecdif(v3,A,B) Cell(1)=Sqrt(Dot(A,A)) Cell(2)=Sqrt(Dot(B,B)) Cell(3)=Sqrt(Dot(C,C)) Cell(5)=-ABS(Dot(A,C)/Cell(1)/Cell(3)) M(4) = -1.0 M(5) = -1.0 M(8) = 2.0 M(3) = 1.0 ELSEIF (itcase .eq. 29 .or. rfcase .eq. '56C') THEN call v2cart (v,A,v2,C) do 5640 I=1,3 v2(I)=2*v2(I) 5640 continue call vecdif(v2,A,B) Cell(1)=Sqrt(Dot(A,A)) Cell(2)=Sqrt(Dot(B,B)) Cell(3)=Sqrt(Dot(C,C)) Cell(5)=-ABS(Dot(A,C)/Cell(1)/Cell(3)) M(1) = -1.0 M(2) = -1.0 M(5) = 2.0 M(9) = 1.0 ELSEIF (itcase .eq. 43 .or. rfcase .eq. '57A') THEN call v2cart(v,A,C,v3) do 5700 I=1,3 v3(I)=2*v3(I) 5700 continue call vecsum(v3,C,v3) call vecsum(v3,A,B) Cell(1)=Sqrt(Dot(A,A)) Cell(2)=Sqrt(Dot(B,B)) Cell(3)=Sqrt(Dot(C,C)) Cell(5)=-ABS(Dot(A,C)/Cell(1)/Cell(3)) M(1) = 1.0 M(2) = 1.0 M(5) = 1.0 M(8) = 2.0 M(6) = 1.0 ELSEIF (itcase .eq. 17 .or. rfcase .eq. '57B') THEN call v2cart(v,v1,v2,v3) call vecsum(v1,v2,B) call vecsum(v3,v2,C) call vecsum(v3,v1,A) Cell(1)=Sqrt(Dot(A,A)) Cell(2)=Sqrt(Dot(B,B)) Cell(3)=Sqrt(Dot(C,C)) Cell(5)=-ABS(Dot(A,C)/Cell(1)/Cell(3)) M(4) = 1.0 M(7) = 1.0 M(2) = 1.0 M(5) = 1.0 M(3) = 1.0 M(9) = 1.0 ELSEIF (itcase .eq. 27 .or. rfcase .eq. '57C') THEN call v2cart(v,B,v2,v3) call vecsum(v2,v3,vtemp) call vecdif(vtemp,B,C) call vecdif(v2,v3,A) Cell(1)=Sqrt(Dot(A,A)) Cell(2)=Sqrt(Dot(B,B)) Cell(3)=Sqrt(Dot(C,C)) Cell(5)=-ABS(Dot(A,C)/Cell(1)/Cell(3)) M(4) = 1.0 M(7) = -1.0 M(2) = 1.0 M(3) = -1.0 M(6) = 1.0 M(9) = 1.0 ENDIF do 8000 I = 4,6 IF (Cell(I) .NE. Maxint) THEN Cell(I) = 180.0/PI*acos(Cell(I)) write(cellst(i),'(f8.2)') cell(i) ENDIF 8000 CONTINUE do 8100 i = 1,3 if(cell(i).ne.Maxint) * write(cellst(i),'(f8.2)') cell(i) 8100 CONTINUE do 8500 I = 4,6 IF (altcel(I) .NE. Maxint) THEN altcel(I) = 180.0/PI*acos(altcel(I)) ENDIF 8500 CONTINUE do 8600 I = 1,6 do 8700 II = 1,8 if (cellst(I)(II:II).ne.' ') goto 8800 8700 continue cellst(I)='.' return 8800 ctemp = cellst(I)(II:8) cellst(I)=ctemp 8600 continue return END C**********************************************************************C subroutine v2Cart(v ,v1,v2,v3 ) C Compute the 3-space Cartesianizing transformation matrix corresponding C to a particular g6 vector. The base vectors of the transformation C are returned real v(6),v1(3),v2(3),v3(3),cell(6) real mat8 C----------------------------------------------------------------------- Cell(1) = Root(v(1)) Cell(2) = Root(v(2)) Cell(3) = Root(v(3)) Cell(4) = 0.5*v(4)/(Cell(2)*Cell(3)) Cell(5) = 0.5*v(5)/(Cell(1)*Cell(3)) Cell(6) = 0.5*v(6)/(Cell(1)*Cell(2)) SinAl = Sqrt(1-Sqr(Cell(4))) SinBe = Sqrt(1-Sqr(Cell(5))) SinGa = Sqrt(1-Sqr(Cell(6))) v1(1) = Cell(1) v1(2) = 0 v1(3) = 0 v2(1) = Cell(2) * Cell(6) v2(2) = Cell(2) * SinGa v2(3) = 0 v3(1) = Cell(3) * Cell(5) Mat8 = (Cell(4)-Cell(5)*Cell(6)) / SinGa v3(2) = Mat8 * Cell(3) v3(3) = Cell(3)*Sqrt( Sqr(SinBe)-Sqr(Mat8) ) end C*********************************************************************** SUBROUTINE WRCELL (C,CE,TEST) include 'ITERATE.cmn' REAL C(6),CE(6) CHARACTER *6 TEST C----------------------------------------------------------------------- IF (TEST .NE. 'WRCELL') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN WRCELL' STOP ENDIF SUM = 0.0 DO 1000 I=1,6 1000 SUM = SUM + CE(I) if (ostyle.ne.'CIF ') then IF (SUM .EQ. 0) THEN WRITE (*,'(1x,a3,1X,6F10.3)') ' '//hm//' ',C ELSE DO 3000 I=1,6 IF (CE(I) .GT. 0.0) THEN WRITE (*,'(1x,a3,1X,F10.3,3X,F10.3)') * ' '//hm//' ',C(I),CE(I) ELSE WRITE (*,'(1x,a3,1X,F10.3,3X,F10.3)') ' '//hm//' ',C(I) ENDIF 3000 CONTINUE ENDIF WRITE (*,*) endif END C*********************************************************************** subroutine wrcent(lat,retcel) include 'ITERATE.cmn' character *2 lat real retcel(6) character *79 line C----------------------------------------------------------------------- if (lat(2:2) .eq. 'P') then line = ' primitive' elseif (lat(2:2) .eq. 'S') then line = ' side-centered ' elseif (lat(2:2) .eq. 'I') then line = ' body-centered ' elseif (lat(2:2) .eq. 'F') then line = ' face-centered ' elseif (lat(2:2) .eq. 'R') then line = ' as rhomboh. ' endif write (line(16:),'(f10.3)') retcel(1) if (lat(1:1) .eq. 'm') then write (line(26:),'(f10.3)') retcel(2) write (line(36:),'(f10.3)') retcel(3) write (line(49:),'(a)') 'beta' write (line(56:),'(f10.3)') retcel(5) elseif (lat(1:1) .eq. 'o') then write (line(26:),'(f10.3)') retcel(2) write (line(36:),'(f10.3)') retcel(3) elseif (lat(1:1) .eq. 't') then write (line(26:),'(f10.3)') retcel(3) elseif (lat .eq. 'hR') then write (line(29:),'(a)') 'alpha' write (line(36:),'(f10.3)') retcel(4) elseif (lat(1:1) .eq. 'h') then write (line(26:),'(f10.3)') retcel(3) elseif (lat(1:1) .eq. 'c') then endif if (ostyle.ne.'CIF ') write (*,'(a)') ' '//hm//' '//line end C*********************************************************************** SUBROUTINE WRMATR (N,A) include 'ITERATE.cmn' REAL A(N,N) C----------------------------------------------------------------------- DO 1000 I=1,N WRITE (*,*) ' '//hm,(A(J,I),J=1,N) 1000 CONTINUE END C*********************************************************************** SUBROUTINE WRSIZE (SIZE,ERRSIZ,RATIO,TEST) include 'ITERATE.cmn' CHARACTER *6 TEST C----------------------------------------------------------------------- IF (TEST .NE. 'WRSIZE') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN WRSIZE' STOP ENDIF if (ostyle.ne.'CIF ') WRITE 2 (*,'('' '//hm// 3 ' INPUT VECTOR SIZE AND ERROR AND RATIO '',3F10.2)') 4 SIZE,ERRSIZ,RATIO END C*********************************************************************** SUBROUTINE WRVEC6(V,VE,TEST) include 'ITERATE.cmn' REAL V(6),VE(6) CHARACTER *6 TEST C----------------------------------------------------------------------- IF (TEST .NE. 'WRVEC6') THEN WRITE (*,*) ' '//hm//' TEST WAS WRONG IN WRVEC6' STOP ENDIF SUM = 0.0 DO 1000 I=1,6 1000 SUM = SUM + ABS(VE(I)) if (ostyle.ne.'CIF ') then IF (SUM .EQ. 0) THEN WRITE (*,'(1x,a3,1X,6F10.2)') ' '//hm//' ',V ELSE DO 3000 I=1,6 WRITE (*,'(1x,a3,1X,F10.3,3X,F10.3)') ' '//hm//' ' 2 ,V(I),VE(I) 3000 CONTINUE ENDIF WRITE (*,*) endif END C**********************************************************************C SUBROUTINE ZEROS (N,V) REAL V(N) C----------------------------------------------------------------------C DO 1000 I=1,N 1000 V(I) = 0.0 END C**********************************************************************C SUBROUTINE INVER (A,B) C----INVERT A THREE BY THREE MATRIX REAL X(9) DIMENSION A(9),B(9) DIMENSION IDATA1(3),IDATA2(3) DATA IDATA1 /4,7,1/ DATA IDATA2 /7,1,4/ C----------------------------------------------------------------------C J = 0 DO 1000 I=1,9,3 J = J + 1 ID1 = IDATA1(J) ID2 = IDATA2(J) CALL CROSS(A(ID1),A(ID2),X(I)) 1000 CONTINUE DETA = DET(A) IF (ABS(DETA) .LE. 1.0E-20) THEN DETA = SIGN(1.0E-20,DETA) ELSE DETA = 1.0 / DETA ENDIF CALL CONMAT (X,DETA,X) CALL TRNSPZ(X,B) END C**********************************************************************C SUBROUTINE VECSUM (X,Y,Z) C----ADD TWO VECTORS AND RETURN THE SUM IN Z DIMENSION X(3), Y(3), Z(3) C----------------------------------------------------------------------C DO 1000 I=1,3 Z(I) = X(I) + Y(I) 1000 CONTINUE END C**********************************************************************C SUBROUTINE VECDIF (X,Y,Z) C----SUBTRACT TWO VECTORS AND RETURN THE RESULT IN Z DIMENSION X(3), Y(3), Z(3) C----------------------------------------------------------------------C DO 1000 I=1,3 Z(I) = X(I) - Y(I) 1000 CONTINUE END C**********************************************************************C SUBROUTINE CPYVEC (X,Y) C----COPY A VECTOR X INTO A VECTOR Y DIMENSION X(3), Y(3) C----------------------------------------------------------------------C DO 1000 I=1,3 Y(I) = X(I) 1000 CONTINUE END C**********************************************************************C FUNCTION DOT (X,Y) C----COMPUTE AND RETURN THE DOT PRODUCT OF X AND Y DIMENSION X(3),Y(3) C----------------------------------------------------------------------C DOT = 0.0 DO 1000 I=1,3 DOT = DOT + X(I) * Y(I) 1000 CONTINUE END C**********************************************************************C SUBROUTINE TRNSPZ (A,B) C----PUT THE TRANSPOSE OF A INTO B DIMENSION A(9), B(9) C----------------------------------------------------------------------C J = 0 DO 1000 I=1,9,3 J = J + 1 CALL UNVEC (A(I),B(J),B(J+3),B(J+6)) 1000 CONTINUE END C**********************************************************************C SUBROUTINE MATMUL (A,B,C) C----MULTIPLY TWO MATRICIES REAL X(9) DIMENSION A(9), B(9), C(9) C----GET THE TRANSPOSE OF B INTO X C----------------------------------------------------------------------C CALL TRNSPZ (B,X) IJ = 0 DO 2000 I=1,9,3 DO 2000 J=1,9,3 IJ = IJ + 1 C(IJ) = DOT(A(I),X(J)) 2000 CONTINUE END C**********************************************************************C SUBROUTINE CROSS (X,Y,Z) C----COMPUTE Z = X CROSS Y DIMENSION X(3),Y(3),Z(3) C----------------------------------------------------------------------C Z(1) = X(2)*Y(3) - Y(2)*X(3) Z(2) =-X(1)*Y(3) + Y(1)*X(3) Z(3) = X(1)*Y(2) - Y(1)*X(2) END C**********************************************************************C FUNCTION DET(A) C----RETURN THE VALUE OF THE DETERMINANT OF A MATRIX REAL X(3) DIMENSION A(9) C----------------------------------------------------------------------C CALL CROSS (A(1),A(4),X) DET = DOT (X,A(7)) END C**********************************************************************C SUBROUTINE CONMAT(AMAT,X,BMAT) DIMENSION AMAT(9),BMAT(9) C----------------------------------------------------------------------C DO 1000 I=1,9 BMAT(I) = X * AMAT(I) 1000 CONTINUE END C**********************************************************************C SUBROUTINE UNVEC (X,F,G,H) C----RETURN THE VECTOR COMPONENTS AS SCALARS DIMENSION X(3) C----------------------------------------------------------------------C F = X(1) G = X(2) H = X(3) END C**********************************************************************C SUBROUTINE WRCLV6 (C,CE,V,VE,TEST) include 'ITERATE.cmn' logical pnumb_ CHARACTER *6 TEST REAL C(6),CE(6),V(6),VE(6) C----------------------------------------------------------------------C if (test .ne. 'WRCLV6') then write (*,*) ' '//hm// 2 ' test string was not WRCLV6 in that routine' stop endif if (ostyle.ne.'CIF ') then DO 3000 I=1,6 WRITE (*,'(1x,a3,1X,F10.3,3X,F8.3,8X,f10.3,3x,f8.2))') 2 ' '//hm//' ',C(I),CE(I),V(I),VE(I) 3000 CONTINUE WRITE (*,*) else do ii = 1,6 cifres = pnumb_(' ',c(ii),0.) enddo endif END "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'iterate.f' ENDS TWO LINES BEFORE THIS ___________ if ( 101777 != `wc -c <'iterate.f'` ) then echo "cshar: 'iterate.f' unpacked with wrong size" endif # end of 'iterate.f' endif if ( -e 'iterate.html.m4' && ${1} != "-c" ) then echo "cshar: Will not clobber existing file 'iterate.html.m4'" sed "s/^X//" >'/dev/null' <<"CUT_HERE_CUT_HERE_CUT_HERE" else echo "cshar: Extracting 'iterate.html.m4' (7843 characters)" #___________ THE FILE 'iterate.html.m4' BEGINS TWO LINES AFTER THIS __________ sed "s/^X//" >'iterate.html.m4' <<"CUT_HERE_CUT_HERE_CUT_HERE" WWW G6 Bravais Lattice Determination

G6 Bravais Lattice Determination Interface

by

Lawrence C. Andrews, Thuridion, Inc., andrews@thuridion.com and
Herbert J. Bernstein, Bernstein+Sons, yaya@bernstein-plus-sons.com


Please read the NOTICE below before use of this web page


Output Style:

Select the crystal lattice centering:

Specify the cell edge lengths and angles:


_cell.length_a _cell.angle_alpha
_cell.length_b _cell.angle_beta
_cell.length_c _cell.angle_gamma

Specify the cell edge length esd's and angle esd's:


_cell.length_a_esd _cell.angle_alpha_esd
_cell.length_b_esd _cell.angle_beta_esd
_cell.length_c_esd _cell.angle_gamma_esd


NOTICE

Some of the software and documents included within this software package are the intellectual property of various parties, and placement in this package does not in anyway imply that any such rights have in any way been waived or diminished.

With respect to any software or documents for which a copyright exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.

Even though the authors of the various documents and software found here have made a good faith effort to ensure that the documents are correct and that the software performs according to its documentation, and we would greatly appreciate hearing of any problems you may encounter, the programs and documents any files created by the programs are provided **AS IS** without any warrantee as to correctness, merchantability or fitness for any particular or general use.

THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE PROGRAMS OR DOCUMENTS.


Access to the source of ITERATE

This program and related scripts are available as a self-extracting shell-script archive or as a self-extracting C-shell-script archive.

What Does This Web Page Do?

In simple terms, what this page does is to find the cells which are "close" to the cell given, in order to help find the Bravais lattice of highest symmetry consistent with the cell.

A central problem in the solution of every crystal structure is to determine the correct Bravais lattice of the crystal. The Bravais lattices as they are usually listed are:

aP triclinic (anorthic) primitive
mP monoclinic primitive
mS monoclinic side-centered (usually C-centered)
oP orthorhombic primitive
oS orthorhombic side-centered
oF orthorhombic face-centered
oI orthorhombic body-centered
hP hexagonal primitive
hR hexagonal rhombohedrally-centered
tP tetragonal primitive
tI tetragonal body-centered
cP cubic primitive
cF cubic face-centered
cI cubic body-centered

Failure to find the highest correct symmetry has several consequences, the worst of which is that the structure may not be solved. The least of the consequences is that Richard Marsh may publish a paper that points out the error, corrects it, and finds a better solution to the structure. Many methods have been described for finding the correct Bravais lattice. A summary of the published methods was published in the paper that described the G6 formalism (which is used in the program on this web page).

"Lattices and Reduced Cells as Points in 6-Space and Selection of Bravais Lattice Type by Projections." Lawrence C. Andrews and Herbert J. Bernstein, Acta Crystallographica, A44, 1009-1018 (1988).

The program on this Web page implements a search in G6 for the various Bravais lattices that the user's cell may fit. For each lattice type, the best metric match is reported. If the higher symmetry type is actually correct, then that is likely to be the best cell from which to start further refinement. However, the possibility exists that one of the rejected cells (which did not match as well) was actually the correct one to use. The reason for this ambiguity is experimental error and its propagation in the transformations of the lattices in the program. Fortunately, the rejected cells are usually quite similar to the accepted one.

A note on standard deviations: First, even in the best of circumstances, standard deviations of unit cell dimensions from 4-circle diffractometer data are always underestimated (by at least a factor of 2). In addition, the points chosen for the determination are often not well distributed (for example all in the first octant of orthorhombic lattices). These less than optimal choices cause substantial systematic error. The experimental errors are amplified in the mathematical conversions between various lattices that any lattice search program must perform. It is not a rare occurrence for angles to be incorrect by 0.5 degrees in initial unit cell determinations.

Note: Even in most well determined unit cells, the actual errors in the edge lengths is 0.2 to 0.5 parts per thousand. (Note that reproducibility of the measurements is substantially better, leading to the illusion that diffractometers produce excellent unit cell parameters). Use of standard deviations that are too small is a common reason for failure of Bravais lattice searches. For small molecules, 0.1 Angstroms is a reasonable error for the edge lengths, for proteins, 0.4 to 0.5 (or even more for preliminary measurements). Accurate unit cell parameters must by determined by a number of more complex methods and must `include' extrapolation to remove systematic effects. For an excellent summary, see "Xray Structure Determination", G.H.Stout and L.H.Jensen, Wiley, 1989. "CUT_HERE_CUT_HERE_CUT_HERE" #___________ THE FILE 'iterate.html.m4' ENDS TWO LINES BEFORE THIS ___________ if ( 7843 != `wc -c <'iterate.html.m4'` ) then echo "cshar: 'iterate.html.m4' unpacked with wrong size" endif # end of 'iterate.html.m4' endif echo "cshar: End of archive 1 (of 1)." cp /dev/null ark1isdone set MISSING="" foreach I ( 1 ) if ( ! -e ark${I}isdone ) then set MISSING="${MISSING} ${I}" endif end if ( "${MISSING}" == "" ) then echo You have the archive. rm -f ark{1,2,3,4,5,6,7,8,9}isdone else echo You still need to unpack the following archives: echo " " ${MISSING} endif ## End of C-shell archive. exit 0