C
C Subroutine file 'model.for' to specify a seismic model.
C
C Date: 2006, February 21
C Coded by Ludek Klimes
C
C.......................................................................
C
C This file consists of the following external procedures:
C     MODEL1..Subroutine designed to read the input data for the
C             description of the model and to store them in the memory.
C             Subroutine MODEL1 reads the input data (1)-(8) listed
C             below itself, then calls subroutine SRFC1 (included in the
C             subroutine file 'srfc.for') to read the input data (9) for
C             smooth surfaces, and finally calls subroutine PARM1
C             (included in the subroutine file 'parm.for') to read the
C             input data (10) for the parameters of the medium.
C             MODEL1
C     NSRFC...Integer function returning the number of surfaces covering
C             structural interfaces.
C             NSRFC
C     BLOCK...Subroutine designed to determine the mutual position of a
C             point and a simple and a complex block.  Just calls more
C             general subroutine BLOCKS which does the job.
C             BLOCK
C     BLOCKS..Subroutine designed to determine the mutual position of a
C             point and a simple and a complex block.  A more general
C             version of subroutine BLOCK, designed especially to work
C             with curves situated at structural interfaces.
C             BLOCKS
C     ISIDE...Auxiliary function to subroutine BLOCKS.
C             ISIDE
C     INTERF..Auxiliary subroutine to subroutine BLOCKS.
C             INTERF
C     SEPAR...Subroutine determining the surface separating two given
C             simple blocks.
C             SEPAR
C     VELOC...Subroutine transforming the values of a medium parameters
C             into velocities and loss factors.
C             VELOC
C     FPOWER..Subroutine evaluating the value and, possibly, the three
C             first and six second partial derivatives of a function,
C             if the value and the three first and six second partial
C             derivatives of the POWER-th power of the function are
C             known.  Particularly, this is an auxiliary subroutine
C             to the subroutine VELOC.
C             FPOWER
C
C Note:
C     The lines denoted by '*V' in the first two columns of file
C     'model.for' in subroutines VELOC and FPOWER are designed to
C     calculate the model variations with respect to the model
C     parameters.
C     File 'modelv.for', intended for the model inversion, is created
C     from 'model.for' by replacing each '*V' in the first two columns
C     by spaces using program 'clean.for'.  Subroutines VAR4 and VAR5
C     of file 'var.for' may then be called to handle the variations.
C
C.......................................................................
C
C                                                    
C Input data MODEL for the specification of the model:
C     The data are read in by the list directed input (free format).  In
C     the list of input data below, each numbered paragraph indicates
C     the beginning of a new input operation (new READ statement).  If
C     the first letter of the symbolic name of the input variable is
C     I-N, the corresponding value in input data must be of the type
C     INTEGER.  Otherwise (except TEXTM), the input parameter is of the
C     type REAL.
C (1) TEXTM
C     The string containing the name of the model.  Only the first 80
C     characters of the string are significant.
C (2) KOORS,NEXPV,NEXPQ,IVERT,/
C     KOORS...Specifies the type of the coordinate system:
C             KOORS.LE.0: Cartesian coordinates (default).
C             KOORS.EQ.1: polar spherical coordinates in radians,
C               (X1,X2,X3)=(colatitude,longitude,radius).
C             KOORS.GE.2: geographic spherical coordinates in radians,
C               (X1,X2,X3)=(longitude,latitude,radius).
C             KOORS.EQ.3: polar spherical coordinates in specified
C               angular units,
C               (X1,X2,X3)=(colatitude,longitude,elevation).
C               The angular units are specified by parameter CIRCLE of
C               input data (2A).
C               The elevation is measured from the reference radius
C               specified by parameter RADIUS of input data (2A).
C             KOORS.GE.4: geographic spherical coordinates in specified
C               angular units,
C               (X1,X2,X3)=(longitude,latitude,elevation).
C               The angular units are specified by parameter CIRCLE of
C               input data (2A).
C               The elevation is measured from the reference radius
C               specified by parameter RADIUS of input data (2A).
C             If the coordinate system is right-handed (recommended),
C             all vectorial products are evaluated using the right-hand
C             rule, otherwise using the left-hand rule.
C             KOORS is passed to the subroutines of file 'metric.for'
C             by means of invocation of subroutine METR1 and presently
C             represents the only input data for the coordinate system.
C             Note that possible future additional data for the
C             coordinate system should be read by subroutine METR1 and
C             should be contained within input data (2A).
C             metric.for
C     NEXPV,NEXPQ... The default values are highly recommended!
C             Velocities powered to NEXPV and loss factors powered to
C             NEXPQ are reported by the subroutines evaluating isotropic
C             material parameters.
C             For example, unit values of NEXPV and NEXPQ indicate that
C             velocities and loss factors are the output parameters
C             of the subroutines evaluating isotropic material
C             parameters, indices equal -1 indicate reciprocal values of
C             these quantities, i.e.  slownesses and quality factors.
C             When using the basic submitted version of the subroutine
C             file 'parm.for', the default values of NEXPV=1, NEXPQ=1
C             are highly recommended.  Other values make sense only if a
C             user is submitting his own subroutines to evaluate
C             isotropic material parameters which, e.g., output the
C             slowness instead of the velocity.  In such a case,
C             switching NEXPV from 1 to -1 may avoid the modification
C             of the user's subroutines.
C     IVERT...Orientation of the vertical axis:
C             IVERT=0: unknown (default),
C             IVERT=+1: X1 vertical, pointing upwards,
C             IVERT=-1: X1 vertical, pointing downwards,
C             IVERT=+2: X2 vertical, pointing upwards,
C             IVERT=-2: X2 vertical, pointing downwards,
C             IVERT=+3: X3 vertical, pointing upwards,
C             IVERT=-3: X3 vertical, pointing downwards,
C             Has no influence on the calculations, and need not be
C             specified.  If it is non-zero, it may be considered for
C             plotting purposes.
C     /...    Obligatory slash at the end of line for future extensions.
C     Default: KOORS=0, NEXPV=1, NEXPQ=1, IVERT=0.
C (2A) Additional data for the coordinate system.
C     No data (2A) are present if KOORS=0, KOORS=1 or KOORS=2.
C     The data are read by subroutine METR1.  For their description
C     refer to file metric.for.
C (3) X1MIN,X1MAX,X2MIN,X2MAX,X3MIN,X3MAX
C     Boundaries of the model.
C (4) NSRFC
C     Number of smooth surfaces in the model.  The surfaces are indexed
C     sequentially in any order by positive integers ISRFC from 1 to
C     NSRFC.
C     It is recommended to define only surfaces covering structural
C     interfaces (model surfaces) in this data set.  Auxiliary surfaces
C     related to particular source-receiver configurations, numerical
C     procedures, etc., should preferably be defined in other data sets.
C (5) NSB
C     Number of simple blocks in the model, defined in this data set.
C     The defined blocks are indexed sequentially by positive integers
C     ISB from 1 to NSB in the same order as they are specified in data
C     (6).  Intersecting simple blocks are allowed but not recommended.
C     All material simple blocks in the model must be defined.
C     Free-space blocks need not be defined in this data set but it is
C     recommended to define the free-space simple blocks in order to
C     speed up the determination of a free space during computations.
C     Defined free-space blocks also enhance the possibility to check
C     for the model consistency.  If the free-space simple blocks are
C     not, for some reason, defined here, they may be defined in the
C     additional data file designed just for the consistency check by
C     program modchk.for
C (6) NSB input operations (READ statements):
C     For each simple block with index ISB, the indices of the surfaces
C     forming the set F(+) and the indices of the surfaces forming the
C     set F(-).  The indices of surfaces from F(+) must be positive, the
C     indices of surfaces from F(-) must be indicated by negative signs.
C     The indices may be specified in an arbitrary order and must be
C     terminated by a slash.
C (7) NCB
C     Number of material complex blocks in the model.  The material
C     complex blocks are indexed sequentially by positive integers ICB
C     from 1 to NCB.  The free-space complex block is not indexed and
C     consists of all simple blocks not contained in the material
C     complex blocks.  Space covered by no simple block is also deemed
C     to be a free space.
C (8) NCB input operations (READ statements):
C     For each material complex block, the indices of material simple
C     blocks forming the complex block.  The indices may be specified
C     in an arbitrary order and must be terminated by a slash.
C     Each material simple block must appear exactly once within these
C     data lines.  Simple blocks defined by data (6) but not listed here
C     are deemed to be free-space simple blocks.
C (9) The data specifying NSRFC functions F(X1,X2,X3) describing the
C     smooth surfaces in the model. The data are read by subroutine
C     SRFC1.  For their description refer to subroutine SRFC1 (included
C     in the subroutine file 'srfc.for').
C     srfc.for: Input data
C (10) The data specifying the distribution of parameters of the model
C     in all NCB material complex blocks.  The data are read by
C     subroutine PARM1.  For their description refer to subroutine
C     PARM1 (included in the subroutine file 'parm.for').
C     parm.for: Input data
C For an example refer to the sample input data for the model.
C Example of data set MODEL
C
C                                                     
C Input data in the form of SEP
C parameter or history file:
C     NEGPAR=integer... Flag whether the negative values of material
C             parameters are allowed:
C             NEGPAR=0: Negative values of material parameters or zero
C               P-wave velocity are reported as errors.
C             NEGPAR=1: Negative values of material parameters or zero
C               P-wave velocity are not reported as errors.
C             Default: NEGPAR=0
C
C.......................................................................
C
C Storage in the memory:
C     The input data (1) to (8) describing the structure of the model
C     are stored in common blocks /MODELT/ and /MODELC/ defined in the
C     include file 'model.inc'.
C     model.inc
C
C=======================================================================
C
C     
C
      SUBROUTINE MODEL1(LUN)
      INTEGER LUN
C
C Subroutine MODEL1 reads the input data (1)-(8) for the description
C of the model and stores them in common blocks /MODELT/ and /MODELC/.
C Then it calls subroutine SRFC1 (included in the subroutine file
C 'srfc.for') to read the input data (9) for smooth surfaces and to
C store them in the memory.  Finally, it calls subroutine PARM1
C (included in the subroutine file 'parm.for') to read the input data
C (10) for the parameters of the medium and to store them in the memory.
C
C Input:
C     LUN...  Logical unit number of the external input device
C             containing the input data.
C The input parameter is not altered.
C
C No output.
C
C Common blocks /MODELT/ and /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C All the storage locations of the common blocks are defined in this
C subroutine.
C
C Subroutines and external functions required:
      EXTERNAL RSEP3I,METR1,SRFC1,PARM1
C     RSEP3I...File 'sep.for'.
C     METR1...File 'metric.for'.
C     SRFC1 and subsequent routines... File 'srfc.for' and subsequent
C             files (like 'val.for' and 'fit.for').
C     PARM1 and subsequent routines... File 'parm.for' and subsequent
C             files (like 'val.for' and 'fit.for').
C
C Date: 2006, February 21
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage locations:
      INTEGER I,J,L
      REAL AUX
C
      READ(LUN,*) TEXTM
      I=0
      NEXPV=1
      NEXPQ=1
      IVERT=0
      READ(LUN,*) I,NEXPV,NEXPQ,IVERT
      CALL METR1(I,LUN)
      READ(LUN,*) BOUNDM
      DO 10, I=1,3
        IF (BOUNDM(2*I).NE.BOUNDM(2*I-1)) THEN
          IF (ABS(BOUNDM(2*I)).GT.100.*ABS(BOUNDM(2*I)-BOUNDM(2*I-1)))
     *      THEN
C           316
            CALL WARN('316 in MODEL: Large value of coordinates')
C           The absolute value of coordinates is too large compared with
C           the dimension of the model (the interval between the minimum
C           and the maximum coordinate).   This may cause too large
C           rounding errors.  The coordinates should be comparable
C           in order of magnitude with the dimension of the model.
          ENDIF
        ENDIF
   10 CONTINUE
      READ(LUN,*) NSRFCS
C
C     Simple blocks:
C     Number of simple blocks
      READ(LUN,*) NSB
C     Initializing memory for indices of surfaces bounding simple blocks
      L=NSB+1
      DO 11 I=L,MSB
        KSB(I)=0
   11 CONTINUE
C     Reading indices of surfaces bounding simple blocks:
      DO 14 J=1,NSB
        READ(LUN,*) (KSB(I),I=L,MSB)
        DO 12 I=L,MSB
          IF(IABS(KSB(I)).GT.NSRFCS) THEN
C           311
            CALL ERROR('311 in MODEL: Block bounded by wrong interface')
C           Index of the surface bounding the simple block is greater
C           than the specified number of surfaces.
          ELSE IF(KSB(I).EQ.0) THEN
            KSB(J)=I-1
            L=I
            GO TO 13
          END IF
   12   CONTINUE
        GO TO 99
   13   CONTINUE
   14 CONTINUE
C
C     Complex blocks:
C     Number of complex blocks
      READ(LUN,*) NCB
C     Initializing memory for indices of simple blocks forming c. blocks
      L=NCB+1
      DO 21 I=L,MCB
        KCB(I)=0
   21 CONTINUE
C     Reading indices of simple blocks forming complex blocks
      DO 24 J=1,NCB
        READ(LUN,*) (KCB(I),I=L,MCB)
        DO 22 I=L,MCB
          IF(KCB(I).LT.0.OR.KCB(I).GT.NSB) THEN
C           312
            CALL ERROR
     *            ('312 in MODEL: C. block composed of wrong s. block.')
C           Complex block composed of wrong simple block:
C           Index of a simple block composing the complex block is
C           greater than the specified number of simple blocks.
          ELSE IF(KCB(I).EQ.0) THEN
            KCB(J)=I-1
            L=I
            GO TO 23
          END IF
   22   CONTINUE
        GO TO 99
   23   CONTINUE
   24 CONTINUE
C
C     Smooth surfaces:
      CALL SRFC1(LUN,NSRFCS)
C
C     Material parameters:
      CALL PARM1(LUN,NCB)
      CALL RSEP3I('NEGPAR',NEGPAR,0)
      RETURN
C
   99 CONTINUE
C       310
        CALL ERROR('310 in MODEL1: Insufficient memory in /MODELC/')
C       Insufficient memory for the input data in common block /MODELC/.
C       The dimensions MSB or MCB of arrays KSB or KCB, respectively,
C       must be enlarged.
C       Refer to include file model.inc
      END
C
C=======================================================================
C
C     
C
      INTEGER FUNCTION NSRFC()
C
C Integer function NSRFC is designed to return the number of surfaces
C covering structural interfaces.
C
C No input.
C
C Output:
C     NSRFC...Number of surfaces covering structural interfaces.
C
C Common block /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C None of the storage locations of the common block are altered.
C
C No subroutines and external functions required.
C
C Date: 1989, December 19
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     No auxiliary storage locations.
C
      NSRFC=NSRFCS
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE BLOCK(COOR,ISRF1,ISB1,ISRF2,ISB2,ICB2)
      REAL COOR(3)
      INTEGER ISRF1,ISB1,ISB2,ICB2,ISRF2
C
C This subroutine searches for the simple block and the complex block in
C which a given point is situated.  This routine may be also used to
C determine the index of a block touching a specified block at a given
C point situated on the boundary of the specified block (the situation
C which may occur when a ray impinges on a boundary of a block).
C Another function of the routine is to determine the index of the
C surface bounding a given simple block and separating it from the given
C point.
C
C Input:
C     COOR... Array containing coordinates X1, X2, X3 of a given point.
C     ISRF1...Controls the possible determination of the simple block
C             touching block ISB1 at the given point.
C             ISRF1.EQ.0:  The simple block touching ISB1 at the given
C               point need not be determined.  This is the most frequent
C               option, used, e.g., if the given point is not situated
C               at a structural interface or if the simple block
C               touching ISB1 is already known.
C             ISRF1.NE.0:  Index of the surface at which the given point
C               is situated and which separates simple block ISB1 from
C               another block to be determined and returned in ISB2.
C               Since the given point may be situated on either side of
C               the surface, surface IABS(ISRF1) is skipped in the list
C               of surfaces limiting simple blocks when determining the
C               position of the given point with respect to simple
C               blocks.  The sign of ISRF1 is ignored.
C               This option cannot be used together with ISB1.EQ.0.
C     ISB1... Index of the simple block which position with respect to
C             the given point will be checked.
C             ISB1.EQ.0:  No simple block given.  The simple block in
C               which the given point is situated will be determined
C               and returned in ISB2.  ISRF2 will be set to zero.
C               The determination starts with initial estimate ISBOLD,
C               continuing with ISBOLD+1, ISBOLD-1, ISBOLD+2, ISBOLD-2,
C               etc.  Here ISBOLD is the simple block returned in ISB2
C               during the last invocation of this subroutine with
C               ISB1.EQ.0 on input and ISB2.NE.0 on output.  ISBOLD=1
C               before such an invocation.
C             ISB1.GT.0:  The position of the given point with
C               respect to simple block ISB1 will be examined.
C               If the point is situated in ISB1, the output value
C                 of ISRF2 is set to 0.
C               If the point is situated in ISB1 and ISRF1.EQ.0,
C                 the output value of ISB2 is set to ISB1.
C               If the point is situated in ISB1 and ISRF1.NE.0,
C                 the simple block containing the given point,
C                 separated from block ISB1 by surface ISRF1 and not
C                 separated from block ISB1 by another surface will be
C                 determined and returned in ISB2.
C               If the point is not situated in ISB1, the surface
C                 separating the point from ISB1 is output in ISRF2.
C                 In addition, the simple block containing the given
C                 point, separated from block ISB1 by surface ISRF2 and
C                 not separated from block ISB1 by another surface will
C                 be determined and returned in ISB2.
C               The determination starts with initial estimate ISB1,
C               continuing with ISB1+1, ISB1-1, ISB1+2, ISB1-2, etc.
C None of the input parameters are altered.
C
C Output:
C     ISRF2...For the given point not situated inside block ISB1 or
C             at its boundary, ISRF2 has the meaning of the index of
C             one of the surfaces bounding simple block ISB1 and
C             separating the given point from simple block ISB1,
C             supplemented by a sign '+' or '-' for the simple block
C             ISB1 situated at the positive or negative side of the
C             surface, respectively.  If the point is separated from
C             simple block ISB1 by several surfaces, the first one of
C             the surfaces, for which ISB2 (see description of ISB2
C             below) will be positive, is preferred.  Roughly speaking,
C             surface ISRF2 at which simple block ISB1 touches simple
C             block containing the given point is preferred.
C             ISRF2=0 if ISB1=0 or if the given point is situated inside
C             block ISB1 or at its boundary.
C             If ISRF1.NE.0, the position with respect to surface
C             IABS(ISRF1) is not checked.
C     ISB2... Index of the simple block containing the given point.
C             If ISB1.EQ.0:
C               ISB2 is the index of the simple block containing the
C               given point.
C               The first simple block of ISBOLD, ISBOLD+1, ISBOLD-1,
C               ISBOLD+2, ISBOLD-2, etc., containing the given point,
C               is returned in ISB2.  Here ISBOLD is the simple block
C               returned in ISB2 during the previous invocation of this
C               subroutine with ISB1.EQ.0.  ISBOLD=1 during such the
C               first invocation.
C             If ISB1.NE.0:
C               If ISRF1.EQ.0 and ISRF2.EQ.0, ISB2 must not be
C                 separated from simple block ISB1 by any surface.
C                 A surface "separates" two simple blocks if both blocks
C                 are bounded by the surface and are situated at its
C                 opposite sides.
C               If ISRF1.NE.0 and ISRF2.EQ.0, ISB2 must be separated
C                 from simple block ISB1 by surface IABS(ISRF1) and
C                 must not be separated by another surface.
C               If ISRF2.NE.0, ISB2 must be separated from simple block
C                 ISB1 by surface ISRF2 and must not be separated by
C                 another surface.
C               The first simple block of ISB1, ISB1+1, ISB1-1,
C               ISB1+2, ISB1-2, etc., having the above properties, is
C               returned in ISB2.
C             If there is no simple block of the above properties,
C             ISB2=0.
C     ICB2... Index of the complex block in which simple block ISB2 is
C             situated.  ICB2=0 if ISB2=0 or if simple block ISB2 is not
C             situated in any material complex block.
C
C Examples:
C     For each point of a set of discrete points, we wish to determine
C             simple block ISB and complex block ICB in which the point
C             is situated.
C     (a)     We thus use
C               CALL BLOCK(COOR,0,0,I,ISB,ICB)
C     When tracing a curve (e.g., a ray), we wish rather to find each
C             crossed interface than only to determine the simple blocks
C             at discrete points along the curve.
C     (b)     If the previous point along the curve is situated in
C             simple block ISB, we use
C             CALL BLOCK(COOR,0,ISB,ISRF1,ISBNEW,ICBNEW)
C             and get ISRF1.EQ.0 if no surface limiting simple block ISB
C             has been crossed.
C     (c)     If ISRF1.NE.0, IABS(ISRF1) is the surface which has been
C             crossed.  We should determine the point of intersection of
C             the curve with surface IABS(ISRF1).  Then we use
C             CALL BLOCK(COOR,ISRF1,ISB,ISRF2,ISB2,ICB2)
C             to find simple block ISB2 and complex block ICB2 at the
C             other side of surface ISRF1.  If ISRF2.EQ.0, the blocks
C             are successfully determined.  If ISRF2.NE.0, surface
C             IABS(ISRF2) has also been crossed and we have to repeat
C             step (c) with ISRF1=ISRF2.
C     When tracing a curve along surface ISRFA, we call subroutine
C             BLOCKS instead of BLOCK, with analogous arguments:
C     (b')    ISRF(1)=0
C             ISRF(2)=ISRFA
C             CALL BLOCKS(COOR,2,ISRF,ISB,ISRF1,ISBNEW,ICBNEW)
C     (c')    ISRF(1)=ISRF1
C             ISRF(2)=ISRFA
C             CALL BLOCKS(COOR,2,ISRF,ISB,ISRF2,ISB2,ICB2)
C     Analogously, when tracing the curve of intersection of surfaces
C             ISRFA and ISRFB, we call subroutine BLOCKS in the
C             following way:
C     (b")    ISRF(1)=0
C             ISRF(2)=ISRFA
C             ISRF(3)=ISRFB
C             CALL BLOCKS(COOR,3,ISRF,ISB,ISRF1,ISBNEW,ICBNEW)
C     (c")    ISRF(1)=ISRF1
C             ISRF(2)=ISRFA
C             ISRF(3)=ISRFB
C             CALL BLOCKS(COOR,3,ISRF,ISB,ISRF2,ISB2,ICB2)
C
C Subroutines and external functions required:
      EXTERNAL BLOCKS
C     BLOCKS... This file.
C
C Date: 1999, March 20
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
      INTEGER ISRF(1)
C
      ISRF(1)=ISRF1
      CALL BLOCKS(COOR,1,ISRF,ISB1,ISRF2,ISB2,ICB2)
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE BLOCKS(COOR,NSRF1,ISRF,ISB1,ISRF2,ISB2,ICB2)
      REAL COOR(3)
      INTEGER NSRF1,ISRF(NSRF1),ISB1,ISRF2,ISB2,ICB2
C
C This subroutine is a generalization of subroutine BLOCK to follow
C points along structural interfaces and edges.  Subroutine BLOCKS
C searches for the simple block and the complex block in which a given
C point is situated.  The given point may be situated in the vicinity
C of one or more structural interfaces.  In such case, blocks at the
C proper side of the interface(s) will be searched for.  This routine
C may also be used to determine the index of a block touching a
C specified block at a given point situated on the boundary of the
C specified block (the situation which may occur when a ray impinges on
C a boundary of a block).  Another function of the routine is to
C determine the index of the surface bounding a given simple block and
C separating it from the given point.
C
C Input:
C     COOR... Array containing coordinates X1, X2, X3 of a given point.
C     NSRF1...Number of surface indices specified in array ISRF.
C             There must be NSRF1.GE.1.  For ISB1.EQ.0., there must be
C             NSRF1.EQ.1 and ISRF(1).EQ.0.
C     ISRF... Array containing the indices of the surfaces at which the
C             given point is situated.  Since the given point may be
C             situated on either side of the surfaces, the surfaces
C             listed in array ISRF are skipped in the list of surfaces
C             limiting simple blocks when determining the position of
C             the given point with respect to simple blocks.
C             The signs of the indices in array ISRF are ignored.
C             ISRF(1):  Controls the possible determination of the
C               simple block touching block ISB1 at the given point.
C               ISRF(1).EQ.0:  The simple block touching ISB1 at the
C                 given point need not be determined.  This is the most
C                 frequent option, used, e.g., if the given point is not
C                 situated at a structural interface or if the simple
C                 block touching ISB1 is already known.
C               ISRF(1).NE.0:  Index of the surface at which the given
C                 point is situated and which separates simple block
C                 ISB1 from another block to be determined.  Refer to
C                 the description of output parameter ISB2.
C                 This option cannot be used together with ISB1.EQ.0.
C             ISRF(2) to ISRF(NSRF1):  Indices of the surfaces at
C               which the given point is situated, other than ISRF(1).
C               These indices are designed to specify the surface along
C               which a curve is traced, or the surfaces which curve of
C               intersection is traced.
C     ISB1... Index of the simple block which position with respect to
C             the given point will be checked.
C             ISB1.EQ.0:  No simple block given.  The simple block in
C               which the given point is situated will be determined
C               and returned in ISB2.  ISRF2 will be set to zero.
C               The determination starts with initial estimate ISBOLD,
C               continuing with ISBOLD+1, ISBOLD-1, ISBOLD+2, ISBOLD-2,
C               etc.  Here ISBOLD is the simple block returned in ISB2
C               during the last invocation of this subroutine with
C               ISB1.EQ.0 and ISB2.NE.0.  ISBOLD=1 before such an
C               invocation.
C             ISB1.GT.0:  The position of the given point with
C               respect to simple block ISB1 will be examined.
C               If the point is situated in ISB1, the output value
C                 of ISRF2 is set to 0.
C               If the point is situated in ISB1 and ISRF(1).EQ.0,
C                 the output value of ISB2 is set to ISB1.
C               If the point is situated in ISB1 and ISRF(1).NE.0,
C                 the simple block containing the given point,
C                 separated from block ISB1 by surface ISRF(1) and not
C                 separated from block ISB1 by another surface will be
C                 determined and returned in ISB2.
C               If the point is not situated in ISB1, the surface
C                 separating the point from ISB1 is output in ISRF2.
C                 In addition, the simple block containing the given
C                 point, separated from block ISB1 by surface ISRF2 and
C                 not separated from block ISB1 by another surface will
C                 be determined and returned in ISB2.
C               The determination starts with initial estimate ISB1,
C               continuing with ISB1+1, ISB1-1, ISB1+2, ISB1-2, etc.
C None of the input parameters are altered.
C
C Output:
C     ISRF2...For the given point not situated inside block ISB1 or
C             at its boundary, ISRF2 has the meaning of the index of
C             one of the surfaces bounding simple block ISB1 and
C             separating the given point from simple block ISB1,
C             supplemented by a sign '+' or '-' for the simple block
C             ISB1 situated at the positive or negative side of the
C             surface, respectively.  If the point is separated from
C             simple block ISB1 by several surfaces, the first one with
C             positive ISB2 (see below) is preferred.
C             ISRF2=0 if ISB1=0 or if the given point is situated inside
C             block ISB1 or at its boundary.
C             Note that surfaces ISRF(1) to ISRF(NSRF1) are skipped
C             when determining the position of the given point with
C             respect to simple blocks.
C     ISB2... Index of the simple block containing the given point.
C             If ISB1.EQ.0:
C               ISB2 is the index of the simple block containing the
C               given point.
C               The first simple block of ISBOLD, ISBOLD+1, ISBOLD-1,
C               ISBOLD+2, ISBOLD-2, etc., containing the given point,
C               is returned in ISB2.  Here ISBOLD is the simple block
C               returned in ISB2 during the previous invocation of this
C               subroutine with ISB1.EQ.0.  ISBOLD=1 during such the
C               first invocation.
C             If ISB1.NE.0:
C               If ISRF(1).EQ.0 and ISRF2.EQ.0, ISB2 must not be
C                 separated from simple block ISB1 by any surface.
C                 A surface "separates" two simple blocks if both blocks
C                 are bounded by the surface and are situated at its
C                 opposite sides.
C               If ISRF(1).NE.0 and ISRF2.EQ.0, ISB2 must be separated
C                 from simple block ISB1 by surface IABS(ISRF(1)) and
C                 must not be separated by another surface.
C               If ISRF2.NE.0, ISB2 must be separated from simple block
C                 ISB1 by surface ISRF2 and must not be separated by
C                 another surface.
C               The first simple block of ISB1, ISB1+1, ISB1-1,
C               ISB1+2, ISB1-2, etc., having the above properties, is
C               returned in ISB2.
C             If there is no simple block of the above properties,
C             ISB2=0.
C     ICB2... Index of the complex block in which simple block ISB2 is
C             situated.  ICB2=0 if ISB2=0 or if simple block ISB2 is not
C             situated in any material complex block.
C
C Common block /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C None of the storage locations of the common block are altered.
C
C Subroutines and external functions required:
      EXTERNAL ISIDE,INTERF,SRFC2
      INTEGER ISIDE
C     ISIDE,INTERF... This file.
C     SRFC2 and subsequent routines... File 'srfc.for' and subsequent
C             files (like 'val.for' and 'fit.for').
C
C Date: 1999, March 20
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage locations:
      INTEGER MSEPAR
      PARAMETER (MSEPAR=20)
      INTEGER NSEPAR,KSEPAR(MSEPAR),JSEPAR,ISEPAR,ISIDE1,I,J,K,II(1)
      INTEGER ISBOLD,ISB0,ISRF1
      SAVE ISBOLD
      DATA ISBOLD/1/
C
C.......................................................................
C
      ISRF1=ISRF(1)
C
C     Checking input values:
      IF(ISRF1.LT.-NSRFCS.OR.ISRF1.GT.NSRFCS) THEN
C       313
        CALL ERROR('313 in BLOCK: Wrong index of surface')
C       Absolute value of the input parameter ISRFC1 (index of the
C       surface) is greater than the number NSRFC of the surfaces
C       covering structural interfaces.
      END IF
      IF(ISB1.LT.0.OR.ISB1.GT.NSB) THEN
C       314
        CALL ERROR('314 in BLOCK: Wrong index of simple block')
C       Parameter ISB1 (index of the simple block) is either
C       negative or greater than the number NSB of simple blocks.
      END IF
      IF(ISB1.EQ.0) THEN
        IF(NSRF1.NE.1.OR.ISRF1.NE.0) THEN
C         315
          CALL ERROR('315 in BLOCK: No simple block specified')
C         If no simple block ISB1 is specified, NSRF1 must be 1 and
C         ISRF1=ISRF(1) must be 0.
        END IF
      END IF
C
C     Initial simple block ISB0:
      IF(ISB1.EQ.0) THEN
        ISB0=ISBOLD
      ELSE
        ISB0=ISB1
      END IF
C
C     Position of the given point with respect to simple block ISB0:
      ISRF2=0
      CALL INTERF(COOR,NSRF1,ISRF,ISB0,MSEPAR,NSEPAR,KSEPAR)
      IF(NSEPAR.EQ.0) THEN
C       The point is inside simple block ISB0:
        IF(ISRF1.EQ.0) THEN
          ISB2=ISB0
          GO TO 90
        ELSE
          NSEPAR=1
          KSEPAR(1)=ISRF1
        END IF
      ELSE
        IF(ISB1.EQ.0) THEN
          NSEPAR=1
        ELSE
          ISRF2=KSEPAR(1)
        END IF
      END IF
C
C     Search for the simple block in which the given point is situated:
      DO 20 JSEPAR=1,NSEPAR
        IF(ISB1.NE.0) THEN
          ISEPAR=IABS(KSEPAR(JSEPAR))
          ISIDE1=-ISIDE(ISEPAR,ISB1)
        END IF
C       Loop over simple blocks
        DO 19 J=1,MAX0(ISB0-1,NSB-ISB0)
          DO 18 ISB2=ISB0+J,ISB0-J,-2*J
            IF(ISB2.GT.0.AND.ISB2.LE.NSB) THEN
C             Selecting simple block ISB2 according to ISB1
              IF(ISB1.NE.0) THEN
C               Loop for surfaces bounding block ISB1
                DO 11 I=KSB(ISB1-1)+1,KSB(ISB1)
C                 Skipping simple blocks separated from ISB1 by another
C                 surface than ISEPAR
                  K=KSB(I)
                  IF(IABS(K).NE.ISEPAR) THEN
                    IF(ISIDE(K,ISB1).EQ.-ISIDE(K,ISB2)) THEN
                      GO TO 17
                    END IF
                  END IF
   11           CONTINUE
C               Skipping simple blocks not separated from ISB1 by ISEPAR
                IF(ISIDE(ISEPAR,ISB2).NE.ISIDE1) THEN
                  GO TO 17
                END IF
              END IF
C             Determining the position of the given point with respect
C             to the simple block
              CALL INTERF(COOR,NSRF1,ISRF,ISB2,1,I,II)
              IF(I.EQ.0) THEN
                IF(ISB1.EQ.0) THEN
                  ISBOLD=ISB2
                ELSE
                  ISRF2=KSEPAR(JSEPAR)
                END IF
                GO TO 90
              END IF
   17         CONTINUE
            END IF
   18     CONTINUE
   19   CONTINUE
   20 CONTINUE
C     No simple block has been found:
      ISB2=0
      ICB2=0
      RETURN
C
C     Determination of the complex block:
   90 CONTINUE
      DO 92 J=1,NCB
        DO 91 I=KCB(J-1)+1,KCB(J)
          IF(KCB(I).EQ.ISB2) THEN
            ICB2=J
            RETURN
          END IF
   91   CONTINUE
   92 CONTINUE
C     No complex block:
      ICB2=0
      RETURN
      END
C
C=======================================================================
C
C     
C
      INTEGER FUNCTION ISIDE(ISRF,ISB)
      INTEGER ISRF,ISB
C
C This is an auxiliary function to the subroutine BLOCKS.
C This function determines the mutual position of a surface and a simple
C block.
C
C Input:
C     ISRF... Index of the surface.  The sign is ignored.
C     ISB...  Index of the simple block.
C None of the input parameters are altered.
C
C Output:
C     ISIDE...ISIDE=-1: The simple block is bounded by the surface and
C               is situated on its negative side.
C             ISIDE= 1: The simple block is bounded by the surface and
C               is situated on its positive side.
C             ISIDE= 2: The simple block is not bounded by the surface.
C
C Common block /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C None of the storage locations of the common block are altered.
C
C No subroutines and external functions required.
C
C Date: 1989, December 19
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage locations:
      INTEGER IS,LS,MS
C
      LS=KSB(ISB-1)+1
      MS=KSB(ISB)
C
C     Loop for surfaces bounding simple block ISB:
      DO 1 IS=LS,MS
        IF(IABS(KSB(IS)).EQ.IABS(ISRF)) THEN
          ISIDE=ISIGN(1,KSB(IS))
          RETURN
        END IF
    1 CONTINUE
C
      ISIDE=2
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE INTERF(COOR,NSRF1,ISRF1,ISB,MSRF2,NSRF2,ISRF2)
      REAL COOR(3)
      INTEGER NSRF1,ISRF1(NSRF1),ISB,MSRF2,NSRF2,ISRF2(MSRF2)
C
C This is an auxiliary subroutine to the subroutine BLOCKS.
C This subroutine determines the position of a given point with respect
C to a given simple block.
C
C Input:
C     COOR... Array containing coordinates X1, X2, X3 of a given point.
C     NSRF1...Number of surface indices specified in array ISRF1.
C             Must be NSRF1.GE.1.
C     ISRF1...Array containing the indices of the surfaces at which the
C             given point is situated.  Since the given point may be
C             situated on either side of the surfaces, the surfaces
C             listed in array ISRF1 are skipped in the list of surfaces
C             limiting the simple block when determining the position of
C             the given point with respect to the simple block.
C             The signs of the indices in array ISRF1 are ignored.
C             Zero indices are allowed and have no neaning.
C     ISB...  Index of the given simple block.
C     MSRF2...Dimension of array ISRF2.
C None of the input parameters are altered.
C
C Output:
C     NSRF2...Number of surfaces separating the given point from simple
C             block ISB.
C             NSRF2=0  if the given point is situated inside simple
C             block ISB.
C     ISRF2...Indices of surfaces separating the given point from simple
C             block ISB, supplemented by sign '+' or '-' for simple
C             block ISB situated at the positive or negative side of the
C             surface, respectively.
C             The first MSRF2 such surfaces from the list of surfaces
C             limiting the simple block are reported.
C
C Common block /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C None of the storage locations of the common block are altered.
C
C Subroutines and external functions required:
      EXTERNAL SRFC2
C     SRFC2 and subsequent routines... File 'srfc.for' and subsequent
C              files (like 'val.for' and 'fit.for').
C
C Date: 1999, March 20
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage locations:
      INTEGER IS,JS,KS,I
      REAL F(10)
C     F...    Auxiliary array to contain the value and partial
C             derivatives F, F1, F3, F11, F12, F22, F13, F23, F33 of the
C             function describing surfaces at the given point.
C
C     Speed-up storage locations:
      INTEGER MOLD
      PARAMETER (MOLD=20)
      INTEGER NOLD,IOLD(MOLD)
      REAL COLD(3)
      SAVE COLD,NOLD,IOLD
      DATA COLD/3*-999999./
C
C.......................................................................
C
C     Already examined surfaces:
      IF(COOR(1).NE.COLD(1).OR.
     *   COOR(2).NE.COLD(2).OR.COOR(3).NE.COLD(3)) THEN
        NOLD=0
      END IF
C
C     Loop for surfaces bounding simple block ISB:
      NSRF2=0
      DO 9 IS=KSB(ISB-1)+1,KSB(ISB)
        KS=KSB(IS)
        JS=IABS(KS)
C       Skipping surfaces of array ISRF1
        DO 1 I=1,NSRF1
          IF(JS.EQ.IABS(ISRF1(I))) THEN
            GO TO 8
          END IF
    1   CONTINUE
C       Surfaces already examined
        DO 2 I=1,NOLD
          IF(JS.EQ.IABS(IOLD(I))) THEN
            IF(IOLD(I)*KS.LT.0) THEN
              NSRF2=NSRF2+1
              ISRF2(NSRF2)=KS
              IF(NSRF2.GE.MSRF2) THEN
                RETURN
              END IF
            END IF
            GO TO 8
          END IF
    2   CONTINUE
C       The surface has to be examined
        CALL SRFC2(JS,COOR,F)
        IF(NOLD.LT.MOLD) THEN
          IF(F(1).LT.0.) THEN
            NOLD=NOLD+1
            IOLD(NOLD)=-JS
          ELSE IF(F(1).GT.0.) THEN
            NOLD=NOLD+1
            IOLD(NOLD)= JS
          END IF
        END IF
        IF(F(1)*FLOAT(KS).LT.0.) THEN
          NSRF2=NSRF2+1
          ISRF2(NSRF2)=KS
          IF(NSRF2.GE.MSRF2) THEN
            RETURN
          END IF
        END IF
    8   CONTINUE
    9 CONTINUE
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE SEPAR(ISB1,ISB2,NSRF,ISRF)
      INTEGER ISB1,ISB2,NSRF,ISRF
C
C Subroutine determining the surface separating given simple blocks,
C i.e., the surface limiting the simple blocks, which are situated one
C at the positive side of the surface and the other at the negative side
C of the surface.
C
C Input:
C     ISB1,ISB2... Indices of given simple blocks.
C None of the input parameters are altered.
C
C Output:
C     NSRF... Number of surfaces separating the simple blocks.
C     ISRF... Index of a surface separating the simple blocks,
C             supplemented by sign minus if simple block ISB1 is
C             situated at its negative side.
C             If NSRF.EQ.0:  ISRF contains unchanged input value.
C             If NSRF.GT.1:  ISRF is one of the surfaces separating the
C               simple blocks.
C
C Common block /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C None of the storage locations of the common block are altered.
C
C No subroutines and external functions required.
C
C Date: 1999, May 18
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage locations:
      INTEGER I1,I2,KSBI2
C
      NSRF=0
C
C     Loop for surfaces bounding simple block ISB2
      DO 2 I2=KSB(ISB2-1)+1,KSB(ISB2)
        KSBI2=-KSB(I2)
C       Loop for surfaces bounding simple block ISB1
        DO 1 I1=KSB(ISB1-1)+1,KSB(ISB1)
          IF(KSB(I1).EQ.KSBI2) THEN
            NSRF=NSRF+1
            IF(NSRF.EQ.1) THEN
              ISRF=KSB(I1)
            END IF
          END IF
    1   CONTINUE
    2 CONTINUE
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE VELOC(IWAVE,UP,US,QP,QS,VP,VS,VD,QL)
      INTEGER IWAVE
      REAL UP(10),US(10),QP,QS,VP,VS,VD(10),QL
C
C This subroutine transforms the values of parameters of the medium into
C velocities and loss factors.
C
C Input:
C     IWAVE...Type of wave.
C             IWAVE.GE.0: P wave,
C             IWAVE.LT.0: S wave.
C     UP,US...Powers of P and S wave velocities and their first and
C             second partial derivatives (the exponent of the powers is
C             NEXPV, see 'Input data for the model'), in order U, U1,
C             U2, U3, U11, U12, U22, U13, U23, U33.
C     QP,QS...Powers of the loss factors of P and S waves (the exponent
C             of the powers is NEXPQ, see 'Input data for the model').
C None of the input parameters are altered.
C
C Output:
C     VP,VS...P and S wave velocities.
C     VD...   Velocity and its first and second partial derivatives
C             corresponding to the wave specified by IWAVE,
C             in order V, V1, V2, V3, V11, V12, V22, V13, V23, V33.
C     QL...   Loss factor corresponding to the wave specified by IWAVE.
C
C Common block /MODELC/:
      INCLUDE 'model.inc'
C     model.inc
C None of the storage locations of the common block are altered.
C
C Subroutines and external functions required:
      EXTERNAL FPOWER
C     FPOWER...This file.
C
C Date: 2005, June 1
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage location:
      REAL POWER,AUX1(1),AUX2(1)
C
      POWER=FLOAT(NEXPV)
      IF(IWAVE.GE.0) THEN
        CALL FPOWER(10,UP,POWER,VD)
*V      CALL VAR5(1,1)
        VP=VD(1)
        CALL FPOWER(1,US,POWER,AUX2)
        VS=AUX2(1)
        AUX1(1)=QP
      ELSE
        CALL FPOWER(1,UP,POWER,AUX2)
        VP=AUX2(1)
        CALL FPOWER(10,US,POWER,VD)
*V      CALL VAR5(2,2)
        VS=VD(1)
        AUX1(1)=QS
      END IF
      CALL FPOWER(1,AUX1,FLOAT(NEXPQ),AUX2)
      QL=AUX2(1)
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE FPOWER(N,FINP,POWER,FOUT)
      INTEGER N
      REAL FINP(N),POWER,FOUT(N)
C
C This subroutine evaluates the value and, possibly, the three first and
C six second partial derivatives of a function if the value and the
C three first and six second partial derivatives of the POWER-th power
C of the function are known.
C
C Input:
C     N...    For N=1: only the function value is evaluated. The
C               derivatives are ignored.
C             For N=4: the value and the three first partial derivatives
C               are evaluated.
C             For N=10: the value and the three first and six second
C               partial derivatives are evaluated.
C     FINP... Array containing the value, the first and second partial
C             derivatives of the POWER-th power of the function to be
C             evaluated, in the order F, F1, F2, F3, F11, F12, F22, F13,
C             F23, F33.  For N=1, only the function value is required.
C     POWER...The specified function is equal to the POWER-th power of
C             the corresponding physical quantity.
C             POWER=0: Zero output array FOUT is generated.
C None of the input parameters are altered (except FINP if this
C parameter and FOUT are identical in the calling sequence).
C
C Output:
C     FOUT... Array containing the value, the first and second partial
C             derivatives of the evaluated function, in the order F, F1,
C             F2, F3, F11, F12, F22, F13, F23, F33.  This parameter may
C             coincide with FINP, in which case FINP is destroyed on
C             output.  Note that this coincidence is an exception to
C             ANSI standard of FORTRAN 77.
C
C No subroutines and external functions required.
C
C Date: 1999, January 15
C Coded by Ludek Klimes
C
C-----------------------------------------------------------------------
C
C     Auxiliary storage locations:
      INTEGER I
      REAL F,AUX1,AUX2
C
      IF(POWER.EQ.0.) THEN
        DO 1 I=1,N
          FOUT(I)=0.
    1   CONTINUE
      ELSE IF(0.999.LT.POWER.AND.POWER.LT.1.001) THEN
        DO 2 I=1,N
          FOUT(I)=FINP(I)
    2   CONTINUE
*V      CALL VAR4(0,1.)
      ELSE IF(FINP(1).LT.0.) THEN
C       317
        CALL ERROR('317 in FPOWER: Negative material parameter')
C       Nonunit power of a material parameter is not allowed to be
C       negative.  The negative value may be caused by oscillatory
C       character of interpolated positive values.
      ELSE IF(FINP(1).EQ.0.) THEN
        IF(POWER.LT.0.) THEN
C         318
          CALL ERROR('318 in FPOWER: Zero inverse material parameter')
C         Negative power of a material parameter cannot be zero.
        ELSE
          FOUT(1)=0.
          DO 3 I=2,N
            IF(FINP(I).NE.0.) THEN
C             319
              CALL ERROR('319 in FPOWER: Zero material parameter')
C             Nonunit power of zero material parameter is not allowed to
C             have nonzero derivatives.
            END IF
            FOUT(I)=0.
    3     CONTINUE
        END IF
      ELSE
        IF(-1.001.LT.POWER.AND.POWER.LT.-0.999) THEN
          F=1./FINP(1)
        ELSE
          F=FINP(1)**(1./POWER)
        END IF
        FOUT(1)=F
        IF(N.GT.1) THEN
          AUX1= F/(FINP(1)*POWER)
          AUX2= (POWER-1.)/F
          FOUT(2)=AUX1*FINP(2)
          FOUT(3)=AUX1*FINP(3)
          FOUT(4)=AUX1*FINP(4)
          IF(N.GT.4) THEN
            FOUT(5)=AUX1*FINP(5)-AUX2*FOUT(2)*FOUT(2)
            FOUT(6)=AUX1*FINP(6)-AUX2*FOUT(2)*FOUT(3)
            FOUT(7)=AUX1*FINP(7)-AUX2*FOUT(3)*FOUT(3)
            FOUT(8)=AUX1*FINP(8)-AUX2*FOUT(2)*FOUT(4)
            FOUT(9)=AUX1*FINP(9)-AUX2*FOUT(3)*FOUT(4)
            FOUT(10)=AUX1*FINP(10)-AUX2*FOUT(4)*FOUT(4)
          END IF
*V        CALL VAR4(0,AUX1)
*V        CALL VAR4(2,-AUX2*FOUT(2))
*V        CALL VAR4(3,-AUX2*FOUT(3))
*V        CALL VAR4(4,-AUX2*FOUT(4))
        END IF
      END IF
      RETURN
      END
C
C=======================================================================
C