      program bruce

C***********************************************************
C
C This is the all-new, memory-friendly version of bruce, a
C program designed to work out the velocity & temperature
C fields of a rotating non-radially pulsating star. Originally,
C bruce went on to produce theoretical spectra using Keith Smith's
C tgprof3 routine. However, this routine requires about 150Mb
C in memory to run, which was unacceptable. Accordingly, bruce
C now does not write out any spectra information; instead, a
C set of files is written containing the temperature, (projected) velocity,
C gravity, area and mu (cos theta) of all the points on the stellar
C grid visible to the observer. Note that no more information
C is required to construct spectra; theta/phi information is
C unnessecary. These raw dump files have names specified by the
C convention <filestub>XXX where <filestub> is a user-specified
C prefix to the filename and XXX is the field number of the dump
C file (ie position in the run of field calculations). The
C parameters which bruce uses are read in from a file pointed
C to by the environment variable BRUCE_PARAMS. When this input
C file is parsed, a load of diagnostic information is printed out,
C along with useful bits and pieces like who is running the code.
C
C
C Started (original bruce):?
C Started (this bruce    ):21/9/95
C Last Modified           :29/11/00
C
C Modifications:
C
C  10/10/95 - The phi component of the observer vector had the wrong sign (
C             it was positive rather than negative), leading to very 
C             peculiar output. Fixed
C
C  11/10/95 - bmakeg now works out the number of visible points on the star,
C             which does not change with time. This is written out first to
C             all raw files so that kylie will 'know' how many quints to read
C             in - much better than waiting for eof. Also written out in the
C             header is the time of the calculation.
C           - the .kylie.com file is no longer used - instead, kylie is just 
C             supplied with a number of fields and a filestub and works it all
C             out from there. This is because
C           - the start_field and end_field commands are no longer implemented,
C             since they were a bit of a kludge
C           - raw files are not now $$$$$$.raw.XXX but $$$$$$XXX
C	    - I've increased the size of string from 40 to 80 coz it seemed a bit small
C
C  4/12/95  - Off-axis modes can now be produced. Basically, any off axis mode with
C             parameters l,m may be written as a sum of on-axis modes with parameters
C             l and m'=-l...+l. To use off-axis modes, firstly, the POLAR_AXIS_OFFSET
C             parameter must appear in the #Stellar command specifying the angle between
C             the rotation axis and the polar axis (in degrees). Then, one must define
C             a mode for every m' required in the sum above and include in each #Mode 
C             command the parameter OFFSET_M_VALUE specifying the value of m each mode
C             is supposed to make an off-axis mode for. Obviously, doing off-axis modes
C             requires many more mode definitions, so maxmde has been upped to 20.
C           - The off-axis calculations have an inherent problem: since they invariably
C             involve an m=0 mode, there are problems generating a W matrix for such a
C             mode. For m=0 modes, the W-matrix will contain l=0 terms which generate
C             singularities whilst doing the matrix generation - this causes the program to
C             crash. Consequentially, an explicit check is made to see if lsdeff is true or false,
C             and when it is false, the expansion vectors are set up properly, coping with m=0 modes,
C             (which the Lee & Saio theory cannot handle anyway), and blojob has been modified so
C             that off-axis modes and Lee & Saio modes are mutually exclusive. The expansion vectors
C             are set up using the new routine lsdvharm, which sets radvec and horvec to be the
C             spherical harmonic normalizing factor x delta(j_mode,j_vector); torvec is set to 0. 
C
C  6/12/95  - The off-axis calculation seems to be working (sort of). Note that to get an off-axis
C             mode, all of the contributing modes must have the same *corotating* frequency - not
C             the same observer's or super- period, as one may think. However, there is a possible
C             problem - I think there might be an anomalous 180 deg phase shift on the position
C             of the off-axis mode axis. To help correct this, bruce now AUTOMATICALLY writes
C             out auxilary file with the format $$$$$$XXX.aux which contain Theta, Phi, Inclination,
C             VRad, VProj and Temp. information, which may be used to construct a graphical image of the star
C             These new files have a new file handle ahandl
C
C           - New Note: The writing out of the aux files seems to work, and has confirmed that the angle
C             of the off-axis is out by 180 degs. I suspect this is because my routines do not adhere to
C             the Condon & Shortley phase convention, so they do now! Fingers crossed....and it works -whew!
C
C           - New note: R/REq is written out to the auxilary files, becuase of course the star is not a sphere,
C             rather an oblate spheroid. To allow the programs which deal with the aux files to mark the pole,
C             Rpole/REq is now also written out, in the header.
C
C  7/12/95  - Done some tidying up to the new off-axis code and the new auxilary files. The aux files no
C             longer have the field time written out in the header (it is unnecessary), and they are not
C             automatically written out; in the fields command, there is a new parameter WRITE_AUX_FILES
C             which instructs bruce to write out aux files with the naming convention above; if this parameter
C             is not present, aux files will not be written out. For the off-axis stuff, I have changed
C             the names of the commands to correspond to roAp models.
C
C  12/2/96  - Changed the format specifier in the output stuff for velocity coz it woz overflowing
C
C  15/4/96  - Added a routine (lsdgetmax) and some stuff in blojob so that by specifying the
C             PHYSICAL_AMPLITUDES fields option, the amplitudes are taken to be physical peak amplitudes
C             rather than mathematical amplitudes. This is achieved for each mode individually by
C             dividing the user's amplitude by the maximum physical amplitude of a pulsation with
C             mathematical amplitude 1. By maximum, I do max(Radial,Theta,Phi) at each colatitude, so
C             it is not maximum in the strictest sense of the word.
C
C  20/5/96  - Modified lsdgetmax. Originally, the velocities were normalized by the largest of the
C             radial, theta and phi velocities. However, this normalisation is not a smooth function
C             of K, and introduces structure where there is none. Accordingly, each mode is normalised
C             by the maximum velocity MODULUS over the stellar surface.
C
C  4/9/96   - Allowed the user to specify the degree of gravity darkening using the ZEIPEL_BETA parameter
C             in the #STELLAR command. The value defaults to 0.25
C
C  2/26/97  - The temperature effects have been modified to take into account the Lee&Saio stuff. Also,
C             the Lee&Saio: parameter has been changed to the MATRIX_DIMENSION: parameter,
C
C  5/5/97   - Removed all DEC Fortran stuff, and modified the source so that parameter
C             files are read in from standard input
C
C  18/7/97  - Moved all lsd routines to separate lsd library, and renamed lsdgetmax to bgetmax
C
C  31/7/97  - Version 2.71 released
C
C  12/8/97  - I discovered today that there is a small error in the bruce
C             user manual (section F.2 of my thesis). The parameter
C             "use_mode_parameter" in the #timings command description
C             should read "use_mode_period".
C
C  12/8/97  - I also found out (thanks to an observant user) today that the 
C             "stellar_mass" parameter led to a run-time error. Upon inspection,
C             I have discovered that the code dealing with it was broken, as
C             was the code for the "polar_mks_gravity", so I fixed everything.
C             Note that these bugs just stopped bruce from running - they didn't
C             lead to erroneous results.
C
C  23/12/98 - Added a new TIMINGS parameter INCLUDE_ENDPOINTS which signifies that start and end spectra
C             should be calculated at the start and end times, and equally spaced between, rather than
C             calculated at the mid-points of equal-sized time-chunks. The latter puts the start and end
C             spectra half a time-step in from the time endpoints, and is the "traditional" behaviour.
C
C  23/12/98 - Added a new TIMINGS parameter WRITE_TIMINGS_FILE which signifies that a space-separated
C             list of dump files and their times should be written to the file $$$$$$$.times
C
C  25/1/99  - Added a new TIMINGS parameter TIMINGS_FROM_FILE which allows the times of all the field
C             calculations to be specified in a file as a list. The argument of the parameter is the
C             file name. Note that this is separate from WRITE_TIMINGS_FILE, which is for writing
C             times OUT rather than reading them in. This parameter is exclusive with START_TIME,
C             FINISH_TIME, INCLUDE_ENDPOINTS and NUMBER_OF_FIELDS, since the file contains all
C             of this information. This change has made it necessary to now store all field times
C             in the array Times, which is set up in blojob.f.
C
C  25/1/99  - Version 2.8 released
C
C  18/2/99  - Added in stuff to indicate the maximum size of radius variations for each field
C             This required a new variable - dRMax
C
C  18/2/99  - Added in stuff to indicate the maximum size of temperature for each field
C             This required a new variable - dTMax
C
C  14/6/99  - Added a new MODE parameter HORIZONTAL_PHASE_SHIFT to allow phase shifts in the horizontal 
C             velocity fields to be modelled (this is primarily for simulations of wave leakage)
C
C  14/6/99  - Changed the reporting information written out, so that the effective temperature
C             (=(Luminosity/(Sigma*Area))**0.25) is printed instead of the equal volume radius
C
C  13/10/99 - Radically changed the reporting used in breprt() to use FORMAT statements rather than
C             character constants, in order to make the code more portable. Also moved various 
C             output statements around in this file
C
C  22/05/00 - Deleted the variable AAmode, and introduced a new one in its place - TAmode.
C             This gives the amplitude of fractional temperature perturbations (when combined
C             with the angular basis function RBasis). If it is zero, then the original
C             Buta & Smith (1979) expression is used to calculate the amplitude (the original
C             behaviour). The command language has been modified accordingly - instead of
C             using NA_AMPLITUDE_SHIFT, use TEMPERATURE_AMPLITUDE. Temperature perturbations 
C             can be turned off completely by *not* specifying the TEMPERATURE_EFFECTS
C             parameter
C
C  22/05/00 - The variable APmode (non-adiabatic temperature phase shift) has been renamed
C             to TPmode ("temperature-phase"), and the parameter NA_PHASE_SHIFT has been
C             renamed to TEMPERATURE_PHASE
C
C  22/05/00 - Changed the way the horizontal velocity fields are handled, to bring them in
C             line with the way temperature perturbations are handled. The new variable HAmode
C             gives the amplitude of horizontal velocity fields (when combined with the
C             angular basis functions). If it is zero, then the amplitude is taken from the
C             value of K. To set HAmode, use the HORIZONTAL_VELOCITY_AMPLITUDE parameter. Horizontal
C             velocity fields can be turned off completely by *not* specifying the 
C             HORIZONTAL_VELOCITY_FIELDS parameter. Note that this functionality replaces
C             that originally offfered by the K_VALUE_OVERRIDE parameter; the latter has
C             been deleted.
C
C  22/05/00 - Renamed the HORIZONTAL_PHASE_SHIFT parameter to HORIZONTAL_VELOCITY_PHASE, to
C             bring it in line with the way temperature perturbations are handled
C
C  25/05/00 - Removed the PERIOD_FROM_NU parameter, and replaced it by the NU parameter, which
C             just fundges the adopted value of NU; this involdes the new variable numode. If
C             numode is zero, the nu is calculated using the usual expression nu=2Omega/omega.
C             Rotational effects can be turned off completely by *not* specifying the
C             MATRIX_DIMENSION parameter
C
C  08/06/00 - Noticed that, somewhere along the way, TIMINGS_FROM_FILE (see above) has been
C             renamed to READ_TIMINGS_FILE - oops!
C
C  08/06/00 - Changed the way field calculations are reported in the output
C
C  19/06/00 - Version 2.83-1 released
C
C  24/07/00 - Altered the interpretation of TEMPERATURE_AMPLITUDE. Previously, it meant the
C             relative amplitude of temperature perturbations; now, it acts as a conversion
C             factor between the fractional radius and temperature perturbation amplitudes.
C             Basically, it is the equivalent of the dR/R coefficient in the Buta & Smith
C             adiabatic dT/T expression
C
C  03/08/00 - Discovered two errors in the lsdfdhor.f/lsdfdtor.f functions of the liblsd 
C             library. These functions calculate the derivatives with respect to theta
C             of the lsdfhor.f (horizontal displacement) and lsdftor.f (toroidal displacement)
C             functions, respectively. The first error led to incorret results for (l>0,m=0) modes,
C             whilst the second led to incorrect results for all (l-|m|>0) modes. I've verified
C             that the functions now work for l<=4 modes (and there is no reason to expect
C             that they won't work for ALL modes). The physical implications of the errors
C             were erroneous horizontal velocity field eigenfunctions. Thanks to Joris
C             De Ridder for spotting the problem. I guess this goes to show that BRUCE still
C             may have bugs!
C
C  03/08/00 - Version 2.83-2 released
C
C  20/09/00 - Put in stuff to include pressure perturbation terms. These are modeled by 
C             including gravity perturbations, such that the relative Lagrangian gravity
C             perturbation is equal to the relative Lagrangian pressure perturbation.
C             Pressure perturbations are switched on by putting a PRESSURE_EFFECTS
C             term in the #fields command. The amplitude and phase of the pressure
C             perturbations, relative to the fractional radius perturbations, may be set 
C             using the PRESSURE_AMPLITUDE and PRESSURE_PHASE parameters in the #mode
C             command (analogously to temperature perturbations). If neither of these
C             are set, then Dziembowski's (1971) outer boundary condition is used to
C             get the values. New variables introduced are PAmode, PPmode, PreEff and
C             others
C
C  29/11/00 - Discovered that the fix to lsdfdhor.f and lsdfdtor.f also needed to be made
C             to lsdfdrad.f (which is used in calculating surface area/normal perturbations).
C             This means that surface area/normal perturbations were incorrect for all m=0
C             modes, and also modes with (l-|m|>0). This problem was detected because calculations
C             for m=0 modes were giving NaNs for the projected surface area of grid points.
C             These NaNs, however, only occured on a Linux box (not an Alpha), since Linux
C             g77 does not initialise variables to zero.
C
C  29/11/00 - Realised that the lsdfdhor.f/lsdfdtor.f/lsdfdrad.f problems will have affected ALL
C             modes if the MATRIX_DIMENSION parameter was specified (ie, if rotational effects
C             were used). This is because, for a mode with given m, the Coriolis force mixes in
C             modes with all values of l, including the ones which were incorrectly calculated).
C             This realization doesn't require any bug-fixes, but means that the scope of the
C             problem is much larger than previously realised. 
C
C  30/11/00 - Version 2.84-1 released
C
C  24/01/01 - Found a problem with the way area perturbations are handled in the main program
C             (bruce.f). It seems there was a missing RecpPi (=1/sqrt(2*pi)) factor on the theta-
C             component of the area perturbations, which is definitely required. Shouldn't be
C             important to spectroscopy, but introduces errors (at about a 20% level) when one
C             is doing photometry
C
C  24/01/01 - Version 2.84-2 released in light of above bug
C
C**************************************************************
C
C This program, and all associated files, is Copyright (c) Richard Townsend 1995-2001.
C Please see the COPYING file for details of this copyright, and details of
C distributing and modifying bruce. Also see the file README.
C
C**************************************************************

C Turn of implicit typing

      implicit none

C Define the hard-wired parameters
 
      include "bruce.compar_define.inc"

C *** Start of Include block load ***

C Load in the Stellar parameters common block

      include "bruce.stepar_common.inc"

C Load in the equilibrium Stellar grid common block

      include "bruce.eqstgr_common.inc"

C Load in the Mode definition common block

      include "bruce.moddef_common.inc"

C Load in the File names common block

      include "bruce.filnam_common.inc"

C Load in the Field definition common block

      include "bruce.flddef_common.inc"

C Load in the Field switches common block

      include "bruce.fldswi_common.inc"

C LOad in the angles and constants include file

      include "angles.inc"

      include "constants.inc"

C *** End of Include Block Load ***

C Declare the variables used by the lee & Saio LSD routines

      double precision nu		        ! The rotation parameter of a given mode
      double precision DVec(DimMax)	        ! The diagonal components of the W-matrix & eigenvalues
      double precision SVec(DimMax)             ! The off-diagonal components of the W-matrix
      double precision Emat(DimMax,DimMax) 	! Matrix to hold the eigenvectors found
      double precision RadVec(DimMax,maxmde)	! Vector holding the radial expansion coeffs
      double precision HorVec(DimMax,maxmde)	! Vector holding the horizontal expansion coeffs
      double precision TorVec(DimMax,maxmde)	! Vector holding the toroidal expansion coeffs
      integer EgIndx(DimMax) 		        ! Array for sorting the eigenvalues
      integer ISign			        ! Counter for adjusting the sign of the eigenvectors
      double precision lsdFRad		        ! The function to return the Lee & Saio radial function
      double precision lsdFHor		        ! The function to return the Lee & Saio horizontal function
      double precision lsdFTor		        ! The function to return the Lee & Saio toroidal function
      double precision lsdFDRad		        ! The function to return d/dtheta of the Lee & Saio radial function
      double precision lsdFDHor		        ! The function to return d/dtheta of the Lee & Saio horizontal function
      double precision lsdFDTor		        ! The function to return d/dtheta of the Lee & Saio toroidal function
 

C Declare the variables used in the grid calculations

      double precision theta           ! The value of theta for some grid point
      double precision ctheta          ! Cosine of theta
      double precision stheta          ! Sine of theta
      double precision rtheta	       ! The reciprocal of stheta
      double precision phi             ! The value of phi for some grid point
      double precision cphi            ! Cosine of phi
      double precision sphi            ! Sine of phi
      double precision cosMP           ! Cosine of a number of mode parameters (phi-part of basis)
      double precision sinMP           ! Sine of a number of mode parameters (phi-part of basis)
      double precision TsinMP          ! Sine of a number of mode parameters (phi-part of basis) for Temperature
      double precision PsinMP          ! Sine of a number of mode parameters (phi-part of basis) for Pressure
      double precision HcosMP          ! Cosine of a number of mode parameters (phi-part of basis) for Horizontal Fields
      double precision HsinMP          ! Sine of a number of mode parameters (phi-part of basis) for Horizontal Fields
      double precision cnorm	       ! The colatitude normalisation factor (see later)
      double precision dcnorm	       ! The theta-derivative of cnorm
      double precision RBasis          ! The value of the radial basis function |lambda> at some theta
      double precision pVRad(maxmde)   ! The partial (theta-part) radial velocity for a given mode
      double precision pVThe(maxmde)   ! The partial (theta-part) theta velocity for a given mode
      double precision pVPhi(maxmde)   ! The partial (theta-part) phi velocity for a given mode
      double precision pFTemp(maxmde)  ! The partial (theta-part) fractional temp variation for a given mode
      double precision pFPres(maxmde)  ! The partial (theta-part) fractional pressure variation for a given mode
      double precision pARad(maxmde)   ! The partial (theta-part) absolute radius variation for a given mode
      double precision pARad2(maxmde)  ! The derivative with respect to theta of pARad
      double precision VRad,VRadC      ! The net radial velocity at a given grid point & conjugate
      double precision VThe,VTheC      ! The net theta velocity at a given grid point & conjugate
      double precision VPhi,VPhiC      ! The net phi velocity at a given grid point & conjugate
      double precision FTemp,FTempC    ! The net fractional temperature variation at a grid point & conj
      double precision FPres,FPresC    ! The net fractional pressure variation at a grid point & conj
      double precision ARad,ARadC      ! The net absolute radius variation at a given grid point & conj
      double precision ARad2,ARad2C    ! The derivative with respect to theta of ARad/ARadC
      double precision ARad3,ARad3C    ! The derivative with respect to theta of ARad/ARadC
      double precision ObsR,ObsRC      ! The radial component of the observer at a grid point & conj
      double precision ObsT,ObsTC      ! The theta component of the observer at a grid point & conj
      double precision ObsP,ObsPC      ! The phi component of the observer at a grid point & conj
      double precision cosMu,cosMuC    ! Cosine of the angle between a point & conj normal and the observer
      double precision MArea           ! The area `magnitude' - sin(theta)*d(theta)*d(phi)
      double precision AreaR           ! The radial component of the perturbed surface area vector
      double precision AreaT           ! The theta component of the perturbed surface area vector
      double precision AreaP           ! The phi component of the perturbed surface area vector
      double precision Area            ! The magnitude of the perturbed surface area vector
      double precision NormR           ! The radial component of the perturbed surface area normal
      double precision NormT           ! The theta component of the perturbed surface area normal
      double precision NormP           ! The phi component of the perturbed surface area normal
      double precision AProj           ! The projected area of a grid point
      double precision VProj           ! The projected velocity of a grid point
      double precision Temp            ! The perturbed temperature of a grid point
      double precision Grav            ! The perturbed gravity of a grid point
      double precision Lambda(maxmde)  ! The value of the eigenvalue used in temperature calculations

C Declare the variables used for general control

      logical ok                       ! Status flag for some of the subroutines called
      integer ferr                     ! The iostat variable for use with file errors
      integer fcount                   ! Counter to step through the field calculations
      integer gcount                   ! Counter to step through the partial grid points (ie theta)
      integer pcount                   ! Counter to step through phi at a given theta
      integer Mode                     ! Counter to step through the modes defined
      integer NGPhi		       ! Number of points in phi at a given colatitude
      double precision FTime           ! The time of a field calculations (hours after 0)
      double precision VMax	       ! The maximum velocity amplitude (scalar) found...
      double precision dRMax           ! The maximum radius displacement found...
      double precision dTMax           ! The maximum temperature perturbation found...
      double precision dGMax           ! The maximum gravity perturbation found...
      double precision pVmax	       ! The maximum projected velocity
      double precision pVmin	       ! The minimum projected velocity
      double precision TMax	       ! The maximum temperature
      double precision TMin 	       ! The minimum temperature
      double precision FTMax	       ! The maximum temperature for the whole run of fields
      double precision FTMin           ! The minimum temperature for the whole run of fields
      character*80 string              ! A string variable to hold titles etc...
      character*80 dfname	       ! A string to hold the dump filenames
      character*80 afname              ! A string to hold the aux filenames
      character*80 tfname              ! A string to hold the timings filename
      character*24 getlog	       ! The login name of the user
      character*24 fdate	       ! The date at which the routine is run
      integer getcwd		       ! The get cwd function
      integer ierrno		       ! The error returned by getcwd

C Declare the external, DEF Fortran-specific routines

      external getenv			! The external routine to read an environment variable
      external getlog			! The external function to read the login name
      external getcwd			! The external function to read the current dir
      external fdate

C Print out the introductory banner

      write(chandl,100) Version,Date
 100  format('Bruce Version ',A,' (',A,')')
      
C Call blojob to parse the standard input command file (which has file handle fhandl)

      call blojob(ok)

C Check all was ok...

      if(.not.ok) goto 9000

C Now we can set uo the model grid using bmakeg in much the same way

      call bmakeg(ok)

      if(.not.ok) goto 9000

C Finally, use breprt to print out a bit of diagnostic information

      call breprt

C Loop over the number of modes to find the W-matrix for each
C mode, diagonalise the matrix, and use the LSD library vector
C routines to get the vectors containing the expansion coefficients
C for each mode into the expansion coefficient array space.

C Blank line...

      write(chandl,'('' '')')

      do Mode=1,NModes,1

C First things first, depending on whether the mode has LSDEff .true.
C or .false., set up nu. Then do all of the usual Lee & Saio matrix generation stuff.
C If LSDEff is false, do the vector routines with emat as the identity and 1/dvec as l(l+1)

        if(LSDEff) then

           if(numode(Mode).eq.0.) then
              nu=2.D0*Omega/CFmode(Mode)
           else
              nu=numode(Mode)
           endif

C Do matrix stuff...

C Call the first of the Lee & Saio LSD routines to generate the W-matrix.
C If the generation is sucessful, continue, otherwise write out an error
C message.

          call lsdMakeW(Mmode(Mode),nu,parity(Mode),
     :                MatDim,DimMax,DVec,SVec,ok)

          if(.not.ok) then
            write(ehandl,'(''*** There was a problem generating'',
     :      '' the W-matrix for Mode #'',I2,'' - try adjusting'',
     :      '' the mode period'')') Mode
            goto 9000
          endif

C Use the NR routine tqli to find the eigenvalues and eigenvectors of the Matrix
C stored in DVec,SVec, putting them in DVec and EMat respectively

          call lsdTQLI(DVec,SVec,MatDim,DimMax,EMat)

C Call the lsd routine to get the eigenvalue indexing array. Basically,
C the jth element of EgIndx is where in DVec and EMat(the eigenvector matrix)
C the jth eigenvalue/vector occurs. Since we don't need to use SVec anymore,
C we can supply it to lsdFindE as the workspace required...

          call lsdFindE(Mmode(Mode),nu,MatDim,
     :                DimMax,DVec,SVec,EgIndx,
     :                parity(Mode))

C Now we have to do a little diddle. The eigenvector EMat(1,EqIndx(Jmode)) passed
C to all of the LSD routines is normalised to have a length of 1, but the 'direction'
C in which it is pointing is indeterminate - consider that if x is an eigenvector of M,
C then so is a*x, and if a is chosen so that a*x is a unit vector, the sign of a used
C is still arbitrary. To ensure that similar runs with different nu do not have a phase
C difference of pi (ie 180 degrees out of phase, due to this arbitrary sign), we alter
C the sign of the eigenvector EMat(1,EgIndx(Jmode)) so that the 'principal coefficient'
C is always greater than zero. The principal coefficient is EMat(1,EgIndx(Jmode)),
C which in the zero-rotation limit is 1, all other coefficients being zero. The
C principal coefficient determines how much of the unperturbed mode exists in a given
C perturbed mode.

          if(EMat(Jmode(Mode),EgIndx(Jmode(Mode))).lt.0.D0) then
            do ISign=1,MatDim
              EMat(ISign,EgIndx(Jmode(Mode)))=
     :       -EMat(ISign,EgIndx(Jmode(Mode)))
            enddo
          endif
 
C Now we convert the appropiate eigenvector, eigenvalue etc. into a set of
C vectors used as the expansion coefficients when the NRP functions are
C calculated as sums over associated legendre polynomials. Use of these vectors
C should speed up the routines considerably.

          call lsdVRad(RadVec(1,Mode),Mmode(Mode),MatDim,DimMax,
     :               EMat(1,EgIndx(Jmode(Mode))),
     :               parity(Mode))

          call lsdVHor(HorVec(1,Mode),Mmode(Mode),
     :               1.D0/DVec(EgIndx(Jmode(Mode))),
     :               MatDim,DimMax,
     :               EMat(1,EgIndx(Jmode(Mode))),
     :               parity(Mode))

          call lsdVTor(TorVec(1,Mode),Mmode(Mode),nu,
     :               1.D0/DVec(EgIndx(Jmode(Mode))),
     :               MatDim,DimMax,
     :               EMat(1,EgIndx(Jmode(Mode))),
     :               parity(Mode))

C Set up the lambda eigenvalue
 
          Lambda(Mode)=1.D0/DVec(EgIndx(Jmode(Mode)))

        else

C This is the part for LSDEff false - basically, it is very similar to the stuff above,
C but we nominally take emat to be the unit matrix and 1/dvec to be l(l+1). The routine
C lsdVharm sets up the vectors so that single spherical harmonics are used.

          call lsdVharm(Mmode(mode),Jmode(mode),MatDim,DimMax,
     :      RadVec(1,Mode),HorVec(1,Mode),TorVec(1,Mode),
     :      parity(Mode))

          Lambda(Mode)=LMode(Mode)*(LMode(Mode)+1.D0)

        endif

C Loop back around to do the next mode.

      enddo

C Open up the timings file (if required)

      if(WrtTim) then

        tfname=DmStub(1:index(DmStub,' ')-1)//'.times'

        open(unit=thandl,file=tfname,status='new',err=7500,iostat=ferr)

      endif

C OK, now we have got all we need to proceed with the field calculations.
C What follows is a number of nested loops. The outermost loop loops over
C the different field calculations (this is the loop over time). For each
C field calculation, the time of the calculation is first worked out. This
C time is taken to be in the middle of the `time-slot' allocated to each
C field calculation - for instance, of TStart=0 & TStart=3, a 3-field
C run would do calculations at times 0.5,1.5 and 2.5. Once we have got
C the time, we loop over theta on the stellar surface. Theta only varies from
C 0 to pi/2 (pole-to-equator), since the subsequent code has been written
C to take advantage of the parity about the equator inherent in each mode.
C At each theta, we loop over the modes to get the theta-part of Vr, Vtheta,
C and VPhi into an array, along with a number of other variables (see below)
C We then loop over phi - see below

C Set up FTMax and FTMin initially

      FTMax=-1.D20
      FTMin=1.D20

C Write the heading for the status information

      write(chandl,200) 'Calculation Results'
 200  format(/'%%%'/'% ',A/'%%%'/)

      write(chandl,201)
     : 'Fld#','t-Epoch','|V|_max',
     : 'Vp_max','Vp_min',
     : 'Tm_Max','Tm_Min',
     : '|dR/R|','|dT/T|','|d lg|',
     : 'Filename'
 201  format(1X,A4,1X,2(A7,1X),7(A6,1X),A/)

C Firstly, loop over the fields...

      do fcount=1,NField,1

C Get the time of this field calculation from the Times array

        FTime=Times(fcount)

C Get the title of the filename for this field calculation into dfname,
C and attempt to open up an output file.

        write(dfname,'(A,I3.3)') 
     :   DmStub(1:index(DmStub,' ')-1),fcount

        open(unit=dhandl,file=dfname,status='new',
     :   form='unformatted',err=8000,iostat=ferr)

C Now try to open an auxilary file with the same basic name, if WrtAux is .true.

        if(WrtAux) then
          write(afname,'(A,I3.3,A)')
     :     DmStub(1:index(DmStub,' ')-1),fcount,'.aux'

          open(unit=ahandl,file=afname,status='new',
     :     form='unformatted',err=8500,iostat=ferr)
        endif

C Write the name of the dump file, plus the time, to the timings file if WrtTim is
C .true.

        if(WrtTim) then
          write(thandl,*) dfname(1:index(dfname,' ')-1),FTime/3600.D0
        endif 

C With the output file opened, write out the number of visible grid points and also
C the time of the field calculation

        write(dhandl) GrdVis,real(FTime)

C Do the same for the aux file, writing the number of visible points, the inclination and
C the Polar radius, normalised by REq

        if(WrtAux) then
          write(ahandl) GrdVis,real(DIncl),
     :                  real(RPole/REq)
        endif

C Initialise the minimum / maximum values

        dRMax=-1.D20
        dTMax=-1.D20
        dGMax=-1.D20
        VMax=-1.D20
        pVMax=-1.D20
        pvMin=1.D20
        TMax=-1.D20
        TMin=1.D20

C Loop over each colatitude (theta) on the stellar grid by stepping gcount
C through the partial stellar grid

        do gcount=1,NGrid,1

C Work out theta for this grid point

          theta=(gcount-0.5D0)/dble(NGrid)*D90

C Loop over all of the modes to get the theta-part of Vr, Vtheta and Vphi for
C each mode, and store them in arrays. To do the calculations, we first set up
C ctheta with the value of cos(theta), & stheta with sin(theta). Then, for each
C mode, we first work out RBasis, the radial basis state. Using RBasis, we
C calculate the partial radial velocity field pVRad (which requires a phi part
C to get the real radial velocity) and the fractional radius variation pDRad.
C Note that RBasis is proportional to the fractional radius variation and not
C the absolute radius variation, whereas pVRad is proportional to the absolute
C radius variation, so we must multiply RBasis by Radius in working out pVRad;
C a similar multiplication occurs when we work out the horizontal velocity fields
C (which we do only if HorEff is .true.). Since the amplitude of the modes is
C defined in terms of the velocity amplitude, we must divide by some radius (chosen
C to be the polar radius Rpole) as well as by the angular frequency to get the
C fractional radius amplitude from the velocity amplitude. This normalisation
C is switchable by the ColNrm (colatitude normalize) flag

          ctheta=cos(theta)
          stheta=sin(theta)
          rtheta=1.D0/stheta

          if (ColNrm) then
            cnorm=RGrid(gcount)/Rpole
            dcnorm=dRGrid(gcount)/Rpole
          else
            cnorm=1.D0
            dcnorm=0.D0
          endif

          do Mode=1,NModes,1

C Set up the theta part of the radial basis state in RBasis

            RBasis=RecpPi*
     :        lsdFRad(Mmode(Mode),ctheta,MatDim,DimMax,
     :         RadVec(1,Mode),parity(Mode))

C Use RBasis to get the partial radial velocity pVRad:

            pVRad(Mode)=VAmode(Mode)*RBasis*cnorm*NAmode(Mode)

C Get the horizontal fields - if HAmode is zero, use Kmode for
C the amplitudes of the horizontal fields, otherwise use the
C value of HAmode

            if(HorEff) then

              pVThe(Mode)=RecpPi*VAmode(Mode)*(
     :         lsdFDHor(Mmode(Mode),ctheta,MatDim,DimMax,
     :          HorVec(1,Mode),parity(Mode)) +
     :         lsdFTor(Mmode(Mode),ctheta,MatDim,DimMax,
     :          TorVec(1,Mode),parity(Mode))*Mmode(Mode)*rtheta )*
     :         cnorm*NAmode(Mode)

              pVPhi(Mode)=-RecpPi*VAmode(Mode)*(
     :         lsdFHor(Mmode(Mode),ctheta,MatDim,DimMax,
     :          HorVec(1,Mode),parity(Mode))*Mmode(mode)*rtheta +
     :         lsdFDTor(Mmode(Mode),ctheta,MatDim,DimMax,
     :          TorVec(1,Mode),parity(Mode)) )*
     :          cnorm*NAmode(Mode)

C Do the amplitude scalings

              if(HAmode(Mode).eq.0.) then
                 pVThe(Mode)=pVThe(Mode)*Kmode(Mode)
                 pVPhi(Mode)=pVPhi(Mode)*Kmode(Mode)
              else
                 pVThe(Mode)=pVThe(Mode)*HAmode(Mode)
                 pVPhi(Mode)=pVPhi(Mode)*HAmode(Mode)
              endif

            else
              pVThe(Mode)=0.D0
              pVPhi(Mode)=0.D0
            endif

C If TmpEff is .true., set up the partial fractional temperature change
C in pDTemp. If TAmode is zero, use the Buta & Smith (1979) expression
C for the amplitude of temperature perturbations; otherwise, use the value
C of TAmode

            if(TmpEff) then
               if(TAmode(Mode).eq.0.) then
                  pFTemp(Mode)=(Gamma-1.D0)/Gamma *
     :                 (Kmode(Mode)*Lambda(Mode) -
     :                 4.D0 - 1.D0/Kmode(Mode))*
     :                 VAmode(mode)*NAmode(Mode)*
     :                 RBasis/(CFmode(Mode)*Rpole)
               else
                  pFTemp(Mode)=TAmode(Mode)*
     :                 VAmode(mode)*NAmode(Mode)*
     :                 RBasis/(CFmode(Mode)*Rpole)
               endif
            else
              pFTemp(Mode)=0.D0
            endif

C If PreEff is .true., set up the partial fractional pressure change
C in pFPres If PAmode is zero, use Dziembowski's (1971) expression for 
C the amplitude of pressure perturbations; otherwise, use the value 
C of PAmode.

            if(PreEff) then
               if(PAmode(Mode).eq.0.) then
                  pFPres(Mode)=
     :                 (Kmode(Mode)*Lambda(Mode) -
     :                 4.D0 - 1.D0/Kmode(Mode))*
     :                 VAmode(mode)*NAmode(Mode)*
     :                 RBasis/(CFmode(Mode)*Rpole)
               else
                  pFPres(Mode)=PAmode(Mode)*
     :                 VAmode(mode)*NAmode(Mode)*
     :                 RBasis/(CFmode(Mode)*Rpole)
               endif
            else
              pFPres(Mode)=0.D0
            endif

C If either SrfEff or NrmEff are .true., we are going to have to work out
C the perturbed area element vector later on. To do this, we need the absolute
C radius variation, plus the theta derivative of this, so we set these up in
C pARad and pARad2. As before, since this is an absolute rather than fractional
C quantity, we must multiply RBasis by Radius when we use it. If neither are
C .true., we do not bother setting pARad and pARad2 to be zero, because we
C do another explit check on SrfEff and NrmEff later on. Use dnorm = d/dtheta
C of cnorm

            if(SrfEff.or.NrmEff) then
              pARad(Mode)=VAmode(Mode)*NAmode(Mode)*
     :       RBasis*cnorm/
     :       CFmode(Mode) 
              pARad2(Mode)=dcnorm*VAmode(Mode)*NAmode(Mode)*
     :       RBasis/CFmode(Mode) + 
     :       cnorm*VAmode(Mode)*NAmode(Mode)*RecpPi*
     :       lsdFDRad(Mmode(Mode),ctheta,MatDim,DimMax,
     :        RadVec(1,Mode),parity(Mode))/CFmode(Mode)
            endif

C OK, loop back around to do the next mode...

          enddo

C Now we proceed to loop over phi to do all of the grid points at this colatitude.
C First we work out the number of grid points in the phi-direction at this theta,
C and DelPhi, the range in phi covered by each grid point at this colatitude - this
C is used if we have to use perturbed rather than unperturbed areas. Using this value
C work out MArea=sin(theta)dtheta dphi, which is also used in getting perturbed areas

          NGPhi=int(NEqtr*sin(theta))+1

          DelPhi=D360/NGPhi

          MArea=stheta*DelThe*DelPhi

C Now loop over the phi grid-points. The very first thing that we do is work out the
C vector pointing towards the observer in RTP (ObsR,ObsT,ObsP) at the grid point,
C and at the conjugate grid point (the same point but with theta ->
C pi-theta). Then, to work out whether either of this grid points is visible, we
C take the dot product of these vectors with the corresponding unperturbed surface
C normal vectors to get cosMu and cosMuC. We use the unperturbed surface normals
C rather than the perturbed ones since the only time they will differ in discrminating
C between visible and non-visible points is on points at the limb, which contribute
C very little to the spectra. If neither are visible, we loop back around to get the
C next phi point; otherwise, we we work out the net velocity fields
C (VRad,VThe,VPhi), the net fractional temperature variation (FTemp), the net absolute
C radius variation (ARad), the derivative with respect to theta of ARad (ARad2),
C and furthermore the derivative with respect to phi of ARad (ARad3),
C at the given grid point and at the conjugate point (we do both irrespective of which
C one is visible). We do the grid point and the conjugate point together to optimise on
C calculating trig functions, since they both share the same phi and time dependance.
C Furthermore, when we do the conjugate point, we take advantage of the well-defined
C parity of each mode to work out what the partial velocity fields etc. should be.
C The naming convention used is that a suffix C indicates a conjugate grid point value 
C Once all this is done, we individually test cosMu and CosMuC to see which of
C the point/conjugate point were visible. For visible ones, if either of SrfEff or NrmEff
C are true, we work out the three RTP components of the perturbed area element vector using
C the ARad/ARadC quantities, and convert these into a perturbed surface normal vector and a
C perturbed scalar area. Then, if NrmEff is .true., we modify cosMu/CosMuC; if SrfEff
C is .true., we get the projected perturbed area and bung it into AProj. Otherwise,
C we bung the projected grid (unperturbed) area into AProj. The projected velocity VProj
C is worked out - if GrvNrm is .true., the velocity fields act along/ || to the unperturbed
C surface normals(see below); otherwise, they act along RTP. The temperature of the point
C is worked out using the temperature grid and FTemp. All of these parameters are then
C written out to the output file, and we loop back for the next phi value. Phew!

          do pcount=1,NGPhi,1

C Work out the phi of this point, and trig functions associated with it

            phi=(pcount-0.5D0)/dble(NGPhi)*D360

            cphi=cos(phi)
            sphi=sin(phi)

C Work out the observers vector for the grid point and the vector for the conjugate grid
C point.

            ObsR=cDIncl*ctheta+sDIncl*stheta*cphi
            ObsT=-cDIncl*stheta+SDIncl*ctheta*cphi
            ObsP=-sDIncl*sphi

            ObsRC=-cDIncl*ctheta+sDIncl*stheta*cphi
            ObsTC=-cDIncl*stheta-SDIncl*ctheta*cphi
            ObsPC=-sDIncl*sphi

C Work out cosMu and cosMuC using the unperturbed surface normal vectors to work out the
C visibility of the grid point and its conjugate point. The - sign in the second expression
C is due to the fact that the surface normal grid is calculated only for the northern
C hemisphere, and must be corrected for use in the southern hemisphere, since the theta
C part of the surface normal vector is asymmetric about the equator

            cosMu =NRGrid(gcount)*ObsR+NTGrid(gcount)*ObsT
            cosMuC=NRGrid(gcount)*ObsRC-NTGrid(gcount)*ObsTC

C See if either of the points is visible; if so, get the fields at both points...

            if(cosMu.ge.0.D0.or.cosMuC.gt.0.D0) then

C Set up the net values for the grid point to be zero:

            VRad=0.D0
            VThe=0.D0
            VPhi=0.D0

            FTemp=0.D0
            FPres=0.D0

            ARad =0.D0
            ARad2=0.D0
            ARad3=0.D0

C Set up the net values for the conjugate grid point to be zero

            VRadC=0.D0
            VTheC=0.D0
            VPhiC=0.D0

            FTempC=0.D0
            FPresC=0.D0

            ARadC =0.D0
            ARad2C=0.D0
            ARad3C=0.D0

C Loop over the modes to work out the net values of the quantities above...

            do Mode=1,NModes,1

C Set up the trigonometric functions cosMP and sinMP which are the parts of
C the basis states which depend upon phi; we need both a cosine and a sine since
C there are phase shifts between the basis states due do complex numbers. TsinMP
C is similar to sinMP, but it is phase shifted by TPmode(Mode), which is the temperature
C phase-shift for the mode in question. Likewise, HcosMP and HsinMP are similar
C to cosMP and sinMP, but are phase shifted by HPmode(Mode), which is the horizontal 
C velocity field phase-shift. Finally, PsinMP is shifted by PPmode(Mode), which is
C the pressure phase-shift for the mode in question.

            cosMP=cos(Mmode(Mode)*(phi-Omega*FTime)
     :         +CFmode(Mode)*FTime+IPmode(Mode))

            sinMP=sin(Mmode(Mode)*(phi-Omega*FTime)
     :         +CFmode(Mode)*FTime+IPmode(Mode))

            TsinMP=sin(Mmode(Mode)*(phi-Omega*FTime)
     :         +CFmode(Mode)*FTime+IPmode(Mode)
     :         +TPmode(Mode))

            HcosMP=cos(Mmode(Mode)*(phi-Omega*FTime)
     :         +CFmode(Mode)*FTime+IPmode(Mode)
     :         +HPmode(Mode))

            HsinMP=sin(Mmode(Mode)*(phi-Omega*FTime)
     :         +CFmode(Mode)*FTime+IPmode(Mode)
     :         +HPmode(Mode))

            PsinMP=sin(Mmode(Mode)*(phi-Omega*FTime)
     :         +CFmode(Mode)*FTime+IPmode(Mode)
     :         +PPmode(Mode))

C Update the net values defined above for the grid point

            VRad=VRad+pVRad(Mode)*cosMP
            VThe=VThe+pVThe(Mode)*HcosMP
            VPhi=VPhi+pVPhi(Mode)*HsinMP

            FTemp=FTemp+pFTemp(Mode)*TsinMP
            FPres=FPres+pFPres(Mode)*PsinMP

            ARad =ARad +pARad(Mode) *sinMP
            ARad2=ARad2+pARad2(Mode)*sinMP
            Arad3=ARad3+pARad(Mode)*Mmode(Mode)*cosMP

C ...and, dependant on the parity of the mode, update the net values defined
C above for the conjugate grid point

            if(parity(Mode)) then

            VRadC=VRadC+pVRad(Mode)*cosMP
            VTheC=VTheC-pVThe(Mode)*HcosMP
            VPhiC=VPhiC+pVPhi(Mode)*HsinMP

            FTempC=FTempC+pFTemp(Mode)*TsinMP
            FPresC=FPresC+pFPres(Mode)*PsinMP

            ARadC =ARadC +pARad(Mode) *sinMP
            ARad2C=ARad2C-pARad2(Mode)*sinMP
            Arad3C=ARad3C+pARad(Mode)*Mmode(Mode)*cosMP

            else

            VRadC=VRadC-pVRad(Mode)*cosMP
            VTheC=VTheC+pVThe(Mode)*HcosMP
            VPhiC=VPhiC-pVPhi(Mode)*HsinMP

            FTempC=FTempC-pFTemp(Mode)*TsinMP
            FPresC=FPresC-pFPres(Mode)*PsinMP

            ARadC =ARadC -pARad(Mode) *sinMP
            ARad2C=ARad2C+pARad2(Mode)*sinMP
            Arad3C=ARad3C-pARad(Mode)*Mmode(Mode)*cosMP

            endif

C Loop back around to add in the bits and bobs for the next field.

            enddo

C Now that we have the net fields for the grid point and the conjugate 
C point, see if it was the grid point that was visible - if it was,
C work out the final parameters and write them out

            if(cosMu.ge.0.D0) then

C Now, for the grid point in question, if either SrfEff or NrmEff are
C true, we are going to need the perturbed area element vector. We work
C this out here, and convert it into a scalar perturbed area Area

            if(SrfEff.or.NrmEff) then
              AreaR=MArea*(RGrid(gcount)+ARad)**2
              AreaT=-MArea*(RGrid(gcount)+ARad)*
     :         (dRGrid(gcount)+ARad2)
              AreaP=-MArea*(RGrid(gcount)+ARad)*
     :         ARad3/stheta
              Area=dsqrt(AreaR**2+AreaT**2+AreaP**2)
              NormR=AreaR/Area
              NormT=AreaT/Area
              NormP=AreaP/Area
            endif

C If NrmEff is true, get the perturbed value of cosMu using the new Normal and the
C observer vector, overriding the old value of cosMu

            if(NrmEff) cosMu=NormR*ObsR+
     :                       NormT*ObsT+NormP*ObsP

C If SrfEff is true, put the projected perturbed area into AProj; otherwise,
C bung in the projected unperturbed area

            if(SrfEff) then
              AProj=cosMu*Area
            else
              AProj=cosMu*AGrid(gcount)
            endif 
             
C Work out the projected velocity, taking the velocity fields to act along the
C radial vector if GrvNrm is .false., or along the unperturbed surface normal vector
C if it is .true.; we use the unperturbed surface normal since the perturbed surface
C normals only pertain to the direction the surface element is facing and not the
C direction it is moving in (which is determined by the gravity vector, which
C we do not perturb). Also add in the velocity due to the stellar rotation.
C Note that the velocity convention is that a *positive* projected velocity
C represents a movement *towards* the observer...

            if(GrvFld) then
              VProj=(NRGrid(gcount)*VRad-
     :         NTGrid(gcount)*VThe)*ObsR +
     :              (NTGrid(gcount)*VRad+
     :         NRGrid(gcount)*VThe)*ObsT +
     :        (VPhi+Omega*RGrid(gcount)*stheta)*ObsP
            else
              VProj=VRad*ObsR+VThe*ObsT+
     :        (VPhi+Omega*Rgrid(gcount)*stheta)*ObsP
            endif

C Update VMax, dRMax, dTMax and dGMax

            VMax=max(VMax,dsqrt(VRad**2+VThe**2+VPhi**2))
            dRMax=max(dRMax,abs(ARad/RGrid(gcount)))
            dTMax=max(dTMax,abs(FTemp))
            dGMax=max(dGMax,abs(FPres))

C Work out the perturbed (or not as the case may be) temperature of the grid
C point, and bung it into Temp

            Temp=TGrid(gcount)+TGrid(gcount)*FTemp

C Work out the perturbed gravity of the grid point, and bung it in Grav. This
C expression assumes that the fractional gravity perturbation is proportional
C to the fractional pressure perturbation

            Grav=GGrid(gcount)+GGrid(gcount)*FPres

C OK, we have everything now, so write it to the output stream in TVAGC order

            write(dhandl) 
     :       real(Temp),
     :       real(Vproj),
     :       real(AProj),
     :       real(Grav),
     :       real(cosMu)

C Write out the auxilary information

            if(WrtAux) then
            write(ahandl)
     :       real(theta),
     :       real(phi),
     :       real(RGrid(gcount)/REq),
     :       real(VRad),
     :       real(VProj),
     :       real(Temp)
            endif

C Update pVMax etc

            pVMax=max(pVMax,VProj)
            pVMin=min(pVMin,VProj)
            TMax=max(TMax,Temp)
            TMin=min(TMin,Temp)

C This is the endif for seeing if the grid point was visible.

            endif

C We now check if the conjugate grid point was visible -much the same as above...

            if(cosMuC.ge.0.D0) then

C Now, for the conjugate grid point in question, if either SrfEff or NrmEff are
C true, we are going to need the perturbed area element vector. We work
C this out here, and convert it into a scalar perturbed area Area. Note that
C this expression differs slightly from the one for the (non-conjugate) grid
C point since dRGrid is defined in the northern hemisphere and is asymmetric
C about the equator 

            if(SrfEff.or.NrmEff) then
              AreaR=MArea*(RGrid(gcount)+ARadC)**2
              AreaT=-MArea*(RGrid(gcount)+ARadC)*
     :         (-dRGrid(gcount)+ARad2C)
              AreaP=-MArea*(RGrid(gcount)+ARadC)*
     :         ARad3C/stheta
              Area=dsqrt(AreaR**2+AreaT**2+AreaP**2)
              NormR=AreaR/Area
              NormT=AreaT/Area
              NormP=AreaP/Area
            endif

C If NrmEff is true, get the perturbed value of cosMuC using the new Normal and the conjugate
C observer vector, overriding the old value of cosMuC.

            if(NrmEff) cosMuC=NormR*ObsRC+
     :                        NormT*ObsTC+NormP*ObsPC

C If SrfEff is true, put the projected perturbed area into AProj; otherwise,
C bung in the projected unperturbed area

            if(SrfEff) then
              AProj=cosMuC*Area
            else
              AProj=cosMuC*AGrid(gcount)
            endif 
             
C Work out the projected velocity, taking the velocity fields to act along the
C radial vector if GrvNrm is .false., or along the unperturbed surface normal vector
C if it is .true.; we use the unperturbed surface normal since the perturbed surface
C normals only pertain to the direction the surface element is facing and not the
C direction it is moving in (which is determined by the gravity vector, which
C we do not perturb). Also add in the velocity due to the stellar rotation.
C Note that the velocity convention is that a *positive* projected velocity
C represents a movement *towards* the observer.
C This expression is slightly different from the one
C for the (non-conjugate) grid point due to the fact that NTGrid is defined for
C the northen hemisphere and is asymmetric about the equator.  

            if(GrvFld) then
              VProj=(NRGrid(gcount)*VRadC+
     :         NTGrid(gcount)*VTheC)*ObsRC +
     :              (-NTGrid(gcount)*VRadC+
     :         NRGrid(gcount)*VTheC)*ObsTC +
     :        (VPhiC+Omega*RGrid(gcount)*stheta)*ObsPC
            else
              VProj=VRadC*ObsRC+VTheC*ObsTC+
     :        (VPhiC+Omega*RGrid(gcount)*stheta)*ObsPC
            endif

C Update VMax, dRMax, dTMax and dGMax

            VMax=max(VMax,dsqrt(VRadC**2+VTheC**2+VPhiC**2))
            dRMax=max(dRMax,abs(ARadC/RGrid(gcount)))
            dTMax=max(dTMax,abs(FTempC))
            dGMax=max(dGMax,abs(FPresC))

C Work out the perturbed (or not as the case may be) temperature of the grid
C point, and bung it into Temp

            Temp=TGrid(gcount)+TGrid(gcount)*FTempC

C Work out the perturbed gravity of the grid point, and bung it in Grav. This
C expression assumes that the fractional gravity perturbation is proportional
C to the fractional pressure perturbation

            Grav=GGrid(gcount)+GGrid(gcount)*FPresC

C OK, we have everything now, so write it to the output stream in TVAGC order,
C if cosMuC is greater than zero.

            write(dhandl) 
     :       real(Temp),
     :       real(Vproj),
     :       real(AProj),
     :       real(Grav),
     :       real(cosMuC)

C Write out the auxillary information, remembering to use the co-theta (180-theta)

            if(WrtAux) then
            write(ahandl)
     :       real(D180-theta),
     :       real(phi),
     :       real(RGrid(gcount)/REq),
     :       real(VRadC),
     :       real(VProj),
     :       real(Temp)
            endif

C Update pVMax etc

            pVMax=max(pVMax,VProj)
            pVMin=min(pVMin,VProj)
            TMax=max(TMax,Temp)
            TMin=min(TMin,Temp)

C This is the endif for seeing if the conjugate grid point was visible.

            endif


C This is the endif for whether any grid point was visible...

            endif

C Loop back around to get the next phi grid point

          enddo

C Loop back around to get the next theta grid point

        enddo

C Close the current output file...

        close(dhandl,iostat=ferr,err=8000)

C Close the aux file (if it has been opened)
 
        if(WrtAux) then
          close(ahandl,iostat=ferr,err=8500)
        endif

C Write out a whole load of diagnostic information....

        write(chandl,202) 
     :  fcount,(FTime-Times(1))/3600.D0,
     :  VMax/1.D3,pVMax/1.D3,pVMin/1.D3,
     :  nint(TMax),nint(TMin),
     :  dRMax,dTMax,dGMax/log(10.),
     :  dfname
 202    format(1X,I4,1X,2(F7.2,1X),2(F6.1,1X),2(I6,1X),3(F6.4,1X),A12)

C Update FTMax and FTMin

       FTMax=max(FTMax,TMax)
       FTMin=min(FTMin,TMin)

C Loop back around to do then next field calculation
      
      enddo

C Close the timings file if WrtTim is .true.

      if(WrtTim) then
        close(thandl,iostat=ferr,err=7500)
      endif
     
C Jump to the end of the program to quit out...

      goto 9000

C Error jump-in for failure on the timings file

 7500 continue

      write(chandl,'(''*** An error was encountered whilst'',
     :'' trying to access the file '',A)') tfname
      goto 9000

C Error jump-in for failure on a dump file

 8000 continue

      write(chandl,'(''*** An error was encountered whilst'',
     :'' trying to access the file '',A)') dfname
      goto 9000

C Error jump-in for failure on an aux file
 
 8500 continue

      write(chandl,'(''*** An error was encountered whilst'',
     :'' trying to access the file '',A)') afname
      goto 9000

C End pof program jump-in point

 9000 continue

      end
 
