SUBROUTINE XASYMM(RPNMX,RPNN,RPNX,RPN,RPNL,RPNDB,RPNMLT,RPNTYP, & RPNDOM,RPNLEV,DEPTH) C C Routine parses an ASYMm statement that defines C the asymmetric unit for maps. The expression C is converted into a RPN command stack. C C Author: Axel T. Brunger C IMPLICIT NONE C I/O INCLUDE 'cns.inc' INCLUDE 'comand.inc' C INTEGER RPNMX, RPNX CHARACTER*(*) RPN(4,RPNMX) INTEGER RPNL(4,RPNMX), RPNN DOUBLE COMPLEX RPNDB(4,RPNMX) INTEGER RPNMLT(RPNMX), RPNLEV(RPNMX) CHARACTER*2 RPNTYP(RPNMX), RPNDOM(RPNMX) INTEGER DEPTH C local INTEGER I CHARACTER*11 PROM LOGICAL ERR C C definition of the functions EXTERNAL XDOFUNC C C definition of the structure factor operands EXTERNAL XDOOPER C C definition of function, operand, operation types and domains EXTERNAL XDOTYPE C CHARACTER*2 TYPE, DOMAIN C begin PROM='ASYMmetric>' C ERR=.FALSE. C C opening parenthesis CALL NEXTDO(PROM) IF (WD(1:1).EQ.'=') CALL NEXTDO(PROM) IF (WD(1:1).EQ.'?') THEN WRITE(6,'(A)')' Definition of asymmetric unit (in RPN notation).' WRITE(6,'(2A)') & ' level | command | type | #args | ', & ' constants' DO I=1,RPNN WRITE(6,'(A,I3,1X,13A,I2,4(A,F5.1,F5.1),A)') ' ', & RPNLEV(I),'[',RPN(1,I)(1:4),';', & RPN(2,I)(1:4),';',RPN(3,I)(1:4),';',RPN(4,I)(1:4),'] ', & RPNTYP(I),' ',RPNDOM(I),' ',RPNMLT(I), & ' [',DBLE(RPNDB(1,I)),DIMAG(RPNDB(1,I)), & ' ;',DBLE(RPNDB(2,I)),DIMAG(RPNDB(2,I)), & ' ;',DBLE(RPNDB(3,I)),DIMAG(RPNDB(3,I)), & ' ;',DBLE(RPNDB(4,I)),DIMAG(RPNDB(4,I)),']' END DO ELSE C IF (WD(1:1).NE.'(') THEN CALL DSPERR(PROM,'"(" expected') ERR=.TRUE. END IF C IF (.NOT.ERR) THEN C C parse the selection (it is ok to use Hermitian symmetry here C since we're not going to interpret structure factor or map C operands) CALL EXRPN(PROM,RPNMX,RPNN,RPNX,RPN,RPNL,RPNDB,RPNMLT,RPNTYP, & RPNDOM,RPNLEV,TYPE,DOMAIN,DEPTH,XDOFUNC,XDOOPER,XDOTYPE, & .TRUE.,ERR,0,' ',' ',0,' ',' ') CALL NEXTDO(PROM) IF (WD(1:1).NE.')'.AND..NOT.ERR) THEN CALL DSPERR(PROM, & 'item cannot be interpreted or ")" expected.') ERR=.TRUE. END IF IF (TYPE.NE.'LO'.AND..NOT.ERR) THEN CALL WRNDIE(-5,PROM, & 'Data type mismatch. Selection must be a logical expression.') ERR=.TRUE. END IF END IF C IF (ERR) THEN RPNN=0 DEPTH=1 END IF C END IF C RETURN END C====================================================================== SUBROUTINE XASUDEF(MAPR,NA,NB,NC,NAP,NBP,NCP,NAPP,NBPP,NCPP, & MAASY,MBASY,MCASY,NAASY,NBASY,NCASY, & XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY,QHERM, & XRCELL,ADEPTH, & ARPNMX,ARPNN,ARPNX,ARPN,ARPNL,ARPNDB,ARPNMLT, & HPRHOMA,NRHO,NMASK,XRSYGP,XRSYIV) C C Defines an asymmetric unit for maps. C C The extent of the map in P1 is defined by the C range A=1,...,NA, B=1,...,NB, C=1,...,NC. C The asymmetric unit is defined by the range C A=MAASY,..,NAASY, B=MBASY,..,NBASY, C=MCASY,..,NCASY for all elements C for which RHOMASK unequal 0. Special positions C are indicated by RHOMASK > 1. C C Author: Axel T. Brunger C IMPLICIT NONE C I/O INCLUDE 'cns.inc' INCLUDE 'timer.inc' INCLUDE 'heap.inc' INCLUDE 'funct.inc' INCLUDE 'comand.inc' DOUBLE PRECISION MAPR INTEGER NA, NB, NC, NAP, NBP, NCP, NAPP, NBPP, NCPP INTEGER MAASY, MBASY, MCASY, NAASY, NBASY, NCASY INTEGER XRNSYM, XRMSYM, XRSYTH INTEGER XRSYMM(XRMSYM,3,4), XRITSY(XRMSYM,3,3) LOGICAL QHERM DOUBLE PRECISION XRCELL(9) INTEGER ADEPTH, ARPNMX, ARPNN, ARPNX CHARACTER*(*) ARPN(4,*) INTEGER ARPNL(4,*) DOUBLE COMPLEX ARPNDB(4,*) INTEGER ARPNMLT(*) INTEGER HPRHOMA, NRHO, NMASK INTEGER XRSYGP(XRMSYM,XRMSYM),XRSYIV(XRMSYM) C local LOGICAL ERR C variable stack pointers INTEGER VLEVEL, VSTACK, TSTACK C other pointers INTEGER TEMPA, TEMPB, TEMPC, TAS, TBS, TCS C min/max functions INTEGER NASYMM, MASYMM, KASYMM PARAMETER (MASYMM=6, KASYMM=5) DOUBLE PRECISION ASYMM(MASYMM,KASYMM,4) INTEGER IASYMM(MASYMM) C timer DOUBLE PRECISION SECS, SECS2 DOUBLE PRECISION ZERO PARAMETER (ZERO=0.0D0) C C begin IF (MAPR.EQ.ZERO) THEN CALL WRNDIE(-5,'XASUDEF','MAPResolution not specified.') ELSE ERR=.FALSE. C C C define the grid for the maps of the crystal at C the specified resolution (MAPR) CALL XMAPGRD(MAPR,NA,NB,NC,NAP,NBP,NCP,NAPP,NBPP,NCPP, & XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY,QHERM, & XRCELL) C C check symmetry operators CALL XSYMCHK(XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY,ERR, & XRSYGP,XRSYIV) C IF (.NOT.ERR) THEN C IF (ARPNN.EQ.0) THEN MAASY=0 NAASY=NA-1 MBASY=0 NBASY=NB-1 MCASY=0 NCASY=NC-1 NASYMM=0 C IF (XRNSYM.GT.1) THEN WRITE(6,'(A)') & ' %XASUDEF-warning: no asymmetric unit for maps specified.' WRITE(6,'(A)') & ' %XASUDEF-warning: excessive memory and CPU usage may occur.' END IF C WRITE(6,'(A)') ' Maps will be stored in P1:' WRITE(6,'(6(A,I6))') ' A=',MAASY,',...,',NAASY, & ' B=',MBASY,',...,',NBASY,' C=',MCASY,',...,',NCASY C ELSE C C first pass: get brick size and other expressions. VSTACK=ALLHP(IREAL8(ADEPTH*4)) TSTACK=ALLHP(INTEG4(ADEPTH)) CALL XASUEVA(ARPNMX,ARPNN,ARPNX,ARPN,ARPNL,ARPNDB,ARPNMLT, & MAASY,NAASY,MBASY,NBASY,MCASY,NCASY, & NA,NB,NC,VLEVEL,ADEPTH,HEAP(VSTACK),HEAP(TSTACK), & NASYMM,MASYMM,KASYMM,ASYMM,IASYMM,ERR) CALL FREHP(TSTACK,INTEG4(ADEPTH)) CALL FREHP(VSTACK,IREAL8(ADEPTH*4)) C WRITE(6,'(A)') ' Minimum brick that covers asymmetric unit:' WRITE(6,'(6(A,I6))') ' A=',MAASY,',...,',NAASY, & ' B=',MBASY,',...,',NBASY,' C=',MCASY,',...,',NCASY END IF END IF C C IF (.NOT.ERR) THEN C C allocate space RHOMASK: number of points in brick NRHO=(NAASY-MAASY+1)*(NBASY-MBASY+1)*(NCASY-MCASY+1) HPRHOMA=ALLHP(INTEG4(NRHO)) C C second pass: use the min/max functions IF (TIMER.GT.0) CALL VCPU(SECS) C initialize the RHOMASK array to 1 CALL FILL4(HEAP(HPRHOMA),NRHO,1) CALL XASUMMM(MAASY,MBASY,MCASY,NAASY,NBASY,NCASY, & HEAP(HPRHOMA),NASYMM,MASYMM,KASYMM,ASYMM,IASYMM) IF (TIMER.GT.0) THEN CALL VCPU(SECS2) WRITE(6,'(A,F10.4)') & ' XASUDEF: CPU-time: fill RHOMASK=',SECS2-SECS END IF C C The asymmetric unit as specified in the International C tables may contain redundant points at the boundary C planes. Furthermore, we have to mark special positions. IF (TIMER.GT.0) CALL VCPU(SECS) TEMPA=ALLHP(INTEG4(NAASY-MAASY+1)) TEMPB=ALLHP(INTEG4(NAASY-MAASY+1)) TEMPC=ALLHP(INTEG4(NAASY-MAASY+1)) TAS=ALLHP(INTEG4(4*NA+NAASY-MAASY+1)) TBS=ALLHP(INTEG4(4*NB+NBASY-MBASY+1)) TCS=ALLHP(INTEG4(4*NC+NCASY-MCASY+1)) CALL XASUCHK(NA,NB,NC,MAASY,MBASY,MCASY,NAASY,NBASY,NCASY, & HEAP(HPRHOMA),NMASK,XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY, & HEAP(TEMPA),HEAP(TEMPB),HEAP(TEMPC), & HEAP(TAS),HEAP(TBS),HEAP(TCS)) CALL FREHP(TCS,INTEG4(4*NC+NCASY-MCASY+1)) CALL FREHP(TBS,INTEG4(4*NB+NBASY-MBASY+1)) CALL FREHP(TAS,INTEG4(4*NA+NAASY-MAASY+1)) CALL FREHP(TEMPC,INTEG4(NAASY-MAASY+1)) CALL FREHP(TEMPB,INTEG4(NAASY-MAASY+1)) CALL FREHP(TEMPA,INTEG4(NAASY-MAASY+1)) IF (TIMER.GT.0) THEN CALL VCPU(SECS2) WRITE(6,'(A,F10.4)') & ' XASUDEF: CPU-time: boundary, special pos. check=',SECS2-SECS END IF END IF END IF C RETURN END C====================================================================== SUBROUTINE XMAPGRD(MAPR,NA,NB,NC,NAP,NBP,NCP,NAPP,NBPP,NCPP, & XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY,QHERM, & XRCELL) C Defines grid and sublattice at the specified map resolution. C C Author: Axel T. Brunger C IMPLICIT NONE C I/O INCLUDE 'timer.inc' INCLUDE 'xfft.inc' DOUBLE PRECISION MAPR INTEGER NA, NB, NC, NAP, NBP, NCP, NAPP, NBPP, NCPP INTEGER XRNSYM, XRMSYM, XRSYTH INTEGER XRSYMM(XRMSYM,3,4), XRITSY(XRMSYM,3,3) LOGICAL QHERM DOUBLE PRECISION XRCELL(9) C local DOUBLE PRECISION DBPREC DOUBLE COMPLEX DBCOMP LOGICAL DONE C begin C C Determine the extent of a density map in P1 at the C specified resolution (MAPR) and grid size parameter (FFT GRID...). C The sublattice size is also determined. C DONE=.FALSE. C DO WHILE (.NOT.DONE) IF (QMEMAUTO.AND.MEMORY.LT.DEFMEMA) THEN MEMORY=DEFMEMA WRITE(6,'(A,I10)') & ' %XMAPASU-AUTOmem: increasing memory allocation to ',MEMORY END IF C CALL XFGRID2(MAPR,NA,NB,NC,NAP,NBP,NCP,NAPP,NBPP,NCPP, & XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY,QHERM, & XRCELL) C IF (QMEMAUTO) THEN IF (NAPP*NBPP*NCPP.GT.6) THEN MEMORY=INT(MEMORY*NAPP*NBPP*NCPP/6.0D0) IF (WRNLEV.GE.5) THEN WRITE(6,'(A,I10)') & ' %XMAPASU-AUTOmem: increasing memory allocation to ',MEMORY END IF ELSE DONE=.TRUE. END IF ELSE DONE=.TRUE. END IF END DO C IF (WRNLEV.GE.5) THEN WRITE(6,'(6(A,I4),A)') & ' XMAPASU: using grid [',NA,',',NB,',',NC,'] and sublattice [', & NAP,',',NBP,',',NCP,']' END IF C DBPREC=NA CALL DECLAR( 'NA','DP',' ',DBCOMP,DBPREC) DBPREC=NB CALL DECLAR( 'NB','DP',' ',DBCOMP,DBPREC) DBPREC=NC CALL DECLAR( 'NC','DP',' ',DBCOMP,DBPREC) C IF (NAPP*NBPP*NCPP.GT.12.AND.WRNLEV.GE.5) THEN WRITE(6,'(A)') & ' *****************************************************' CALL WRNDIE(+1,'XFFT','Warning: Extreme factorization of FFT.') WRITE(6,'(A,I6,/,A)') & ' %XMAPASU: Factorization of FFT=',NAPP*NBPP*NCPP, & ' %XMAPASU: This may cause excessive CPU time usage.' WRITE(6,'(A,I12,A)') & ' %XMAPASU: Recommendation: MEMOry=', & INT(MEMORY*NAPP*NBPP*NCPP/12.D0),' or larger.' WRITE(6,'(A)') & ' *****************************************************' END IF C RETURN END C====================================================================== SUBROUTINE XFGRID2(MAPR,NA,NB,NC,NAP,NBP,NCP,NAPP,NBPP,NCPP, & XRNSYM,XRMSYM,XRSYTH,XRSYMM,XRITSY,QHERM, & XRCELL) C C determine integers NAPP, NAP, NBPP, NBP, NCPP, NCP such that C 1) NA > a/(grid*MAPR) C NB > b/(grid*MAPR) C NC > c/(grid*MAPR) C 2) NA, NB, NC as small as possible C 3) NAP*NAPP=NA, NBP*NBPP=NB, NCP*NCPP=NC, C 4) NAP*NBP*NCP,...,) | ] C C [ | min(,...,) ] C C :== < | <= C C :== - | | | * | + | C - | / | C := constant C :== x,y,z C C Restrictions: C 1. all must be linear in x, y, z C 2. max. of four arguments for min, max functions. C C C The brick determined by these a expresssions is determined C (maasy, naasy; mbasy, nbasy; mcasy, ncasy). C C A data structure is defined that represents the min, max C functions. C C Author: Axel T. Brunger C C IMPLICIT NONE C input/output INCLUDE 'consta.inc' INTEGER RPNMX, RPNN, RPNX CHARACTER*(*) RPN(4,*) INTEGER RPNL(4,*) DOUBLE COMPLEX RPNDB(4,*) INTEGER RPNMLT(*) INTEGER MAASY, NAASY, MBASY, NBASY, MCASY, NCASY INTEGER NA, NB, NC INTEGER VLEVEL, VMAX DOUBLE PRECISION VSTACK(VMAX,4) INTEGER TSTACK(*) INTEGER NASYMM, MASYMM, KASYMM DOUBLE PRECISION ASYMM(MASYMM,KASYMM,4) INTEGER IASYMM(MASYMM) LOGICAL ERR C local INTEGER RPNI, TOL, I C parameters DOUBLE PRECISION ZERO, ONE PARAMETER (ZERO=0.0D0, ONE=1.0D0) INTEGER SCONS, SX, SY, SZ, SMIX, SMIN, SMAX PARAMETER (SCONS=1, SX=2, SY=3, SZ=4, SMIX=5, SMIN=10, SMAX=20) C begin C C initialize variable stack level VLEVEL=0 C C initialize min max function data structure NASYMM=0 C C reset error ERR=.FALSE. C C initialize brick size MAASY=-NA NAASY=+NA MBASY=-NB NBASY=+NB MCASY=-NC NCASY=+NC C DO RPNI=1,RPNN C contants IF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'CONS') THEN VLEVEL=VLEVEL+1 VSTACK(VLEVEL,SCONS)=DBLE(RPNDB(1,RPNI)) VSTACK(VLEVEL,SX)=ZERO VSTACK(VLEVEL,SY)=ZERO VSTACK(VLEVEL,SZ)=ZERO TSTACK(VLEVEL)=SCONS C change sign ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'CHS'.AND. & TSTACK(VLEVEL).LE.SMIX) THEN VSTACK(VLEVEL,SCONS)=-VSTACK(VLEVEL,SCONS) VSTACK(VLEVEL,SX)=-VSTACK(VLEVEL,SX) VSTACK(VLEVEL,SY)=-VSTACK(VLEVEL,SY) VSTACK(VLEVEL,SZ)=-VSTACK(VLEVEL,SZ) C plus ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'+'.AND. & TSTACK(VLEVEL).LE.SMIX.AND.TSTACK(VLEVEL-1).LE.SMIX) THEN VLEVEL=VLEVEL-1 VSTACK(VLEVEL,SCONS)=VSTACK(VLEVEL,SCONS)+VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SX)=VSTACK(VLEVEL,SX)+VSTACK(VLEVEL+1,SX) VSTACK(VLEVEL,SY)=VSTACK(VLEVEL,SY)+VSTACK(VLEVEL+1,SY) VSTACK(VLEVEL,SZ)=VSTACK(VLEVEL,SZ)+VSTACK(VLEVEL+1,SZ) IF (TSTACK(VLEVEL).NE.TSTACK(VLEVEL+1)) THEN TSTACK(VLEVEL)=SMIX END IF C minus ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'-'.AND. & TSTACK(VLEVEL).LE.SMIX.AND.TSTACK(VLEVEL-1).LE.SMIX) THEN VLEVEL=VLEVEL-1 VSTACK(VLEVEL,SCONS)=VSTACK(VLEVEL,SCONS)-VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SX)=VSTACK(VLEVEL,SX)-VSTACK(VLEVEL+1,SX) VSTACK(VLEVEL,SY)=VSTACK(VLEVEL,SY)-VSTACK(VLEVEL+1,SY) VSTACK(VLEVEL,SZ)=VSTACK(VLEVEL,SZ)-VSTACK(VLEVEL+1,SZ) IF (TSTACK(VLEVEL).NE.TSTACK(VLEVEL+1)) THEN TSTACK(VLEVEL)=SMIX END IF C multiply: arg * constant ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'*' & .AND.TSTACK(VLEVEL).EQ.SCONS) THEN VLEVEL=VLEVEL-1 VSTACK(VLEVEL,SCONS)=VSTACK(VLEVEL,SCONS)*VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SX)=VSTACK(VLEVEL,SX)*VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SY)=VSTACK(VLEVEL,SY)*VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SZ)=VSTACK(VLEVEL,SZ)*VSTACK(VLEVEL+1,SCONS) C multiply: constant * arg ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'*' & .AND.TSTACK(VLEVEL-1).EQ.SCONS) THEN VLEVEL=VLEVEL-1 VSTACK(VLEVEL,SX)=VSTACK(VLEVEL+1,SX)*VSTACK(VLEVEL,SCONS) VSTACK(VLEVEL,SY)=VSTACK(VLEVEL+1,SY)*VSTACK(VLEVEL,SCONS) VSTACK(VLEVEL,SZ)=VSTACK(VLEVEL+1,SZ)*VSTACK(VLEVEL,SCONS) VSTACK(VLEVEL,SCONS)=VSTACK(VLEVEL+1,SCONS)*VSTACK(VLEVEL,SCONS) TSTACK(VLEVEL)=TSTACK(VLEVEL+1) C divide ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'/' & .AND.TSTACK(VLEVEL).EQ.SCONS) THEN VLEVEL=VLEVEL-1 IF (ABS(VSTACK(VLEVEL+1,SCONS)).LT.RSMALL) THEN CALL WRNDIE(-5,'XASEVAL', & 'Divide by zero in asymmetric unit expression.') ERR=.TRUE. ELSE VSTACK(VLEVEL,SCONS)=VSTACK(VLEVEL,SCONS)/VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SX)=VSTACK(VLEVEL,SX)/VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SY)=VSTACK(VLEVEL,SY)/VSTACK(VLEVEL+1,SCONS) VSTACK(VLEVEL,SZ)=VSTACK(VLEVEL,SZ)/VSTACK(VLEVEL+1,SCONS) END IF C multiple-argument functions C ELSEIF (RPN(1,RPNI)(1:RPNL(1,RPNI)).EQ.'MAX') THEN IF (NASYMM.GE.MASYMM) THEN CALL WRNDIE(-5,'XASEVAL', & 'MASYMM exceeded. Too many expressions for asymmetric unit.') ERR=.TRUE. ELSEIF (KASYMM.LE.RPNMLT(RPNI)) THEN CALL WRNDIE(-5,'XASEVAL', & 'MASYMM exceeded. Too many arguments for MAX function.') ERR=.TRUE. ELSE NASYMM=NASYMM+1 VLEVEL=VLEVEL-RPNMLT(RPNI)+1 TSTACK(VLEVEL)=SMAX DO I=1,RPNMLT(RPNI) C C negate the expression, e.g., max(y) -x